Skip to content

Feature/redaction: Ability to add redaction rules to process the LLM output #4101

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Draft
wants to merge 2 commits into
base: main
Choose a base branch
from
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
12 changes: 12 additions & 0 deletions packages/server/src/Interface.ts
Original file line number Diff line number Diff line change
Expand Up @@ -354,3 +354,15 @@ export interface IVariableOverride {

// DocumentStore related
export * from './Interface.DocumentStore'

export enum RedactionRuleType {
REMOVE = 'remove',
REPLACE = 'replace',
ASTERISK = 'asterisk'
}
export interface RedactionRule {
phrase: string
isRegexp: boolean
type: RedactionRuleType
replacement: string
}
74 changes: 56 additions & 18 deletions packages/server/src/utils/buildChatflow.ts
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,9 @@ import {
IVariable,
INodeOverrides,
IVariableOverride,
MODE
MODE,
RedactionRule,
RedactionRuleType
} from '../Interface'
import { InternalFlowiseError } from '../errors/internalFlowiseError'
import { databaseEntities } from '.'
Expand Down Expand Up @@ -653,26 +655,62 @@ export const executeFlow = async ({
resultText = result.text
/* Check for post-processing settings */
if (chatflowConfig?.postProcessing?.enabled === true) {
let moderatedResponse = resultText
try {
const postProcessingFunction = JSON.parse(chatflowConfig?.postProcessing?.customFunction)
const nodeInstanceFilePath = componentNodes['customFunction'].filePath as string
const nodeModule = await import(nodeInstanceFilePath)
const nodeData = {
inputs: { javascriptFunction: postProcessingFunction },
outputs: { output: 'output' }
//first run redaction rules
if (chatflowConfig.postProcessing.redactionRules) {
const redactionRules: RedactionRule[] = JSON.parse(chatflowConfig.postProcessing.redactionRules)
for (const rule of redactionRules) {
switch (rule.type) {
case RedactionRuleType.REMOVE:
if (rule.isRegexp) {
const regex = new RegExp(rule.phrase, 'g')
moderatedResponse = moderatedResponse.replace(regex, '')
} else {
moderatedResponse = moderatedResponse.replace(rule.phrase, '')
}
break
case RedactionRuleType.REPLACE:
if (rule.isRegexp) {
const regex = new RegExp(rule.phrase, 'g')
moderatedResponse = moderatedResponse.replace(regex, rule.replacement)
} else {
moderatedResponse = moderatedResponse.replace(rule.phrase, rule.replacement)
}
break
case RedactionRuleType.ASTERISK:
if (rule.isRegexp) {
const regex = new RegExp(rule.phrase, 'g')
moderatedResponse = moderatedResponse.replace(regex, '***')
} else {
moderatedResponse = moderatedResponse.replace(rule.phrase, '***')
}
break
}
}
}
const options: ICommonObject = {
chatflowid: chatflow.id,
sessionId,
chatId,
input: question,
rawOutput: resultText,
appDataSource,
databaseEntities,
logger
//second - apply custom function
if (chatflowConfig?.postProcessing?.customFunction) {
const postProcessingFunction = JSON.parse(chatflowConfig?.postProcessing?.customFunction)
const nodeInstanceFilePath = componentNodes['customFunction'].filePath as string
const nodeModule = await import(nodeInstanceFilePath)
const nodeData = {
inputs: { javascriptFunction: postProcessingFunction },
outputs: { output: 'output' }
}
const options: ICommonObject = {
chatflowid: chatflow.id,
sessionId,
chatId,
input: question,
rawOutput: moderatedResponse,
appDataSource,
databaseEntities,
logger
}
const customFuncNodeInstance = new nodeModule.nodeClass()
moderatedResponse = await customFuncNodeInstance.init(nodeData, question, options)
}
const customFuncNodeInstance = new nodeModule.nodeClass()
let moderatedResponse = await customFuncNodeInstance.init(nodeData, question, options)
result.text = moderatedResponse
resultText = result.text
} catch (e) {
Expand Down
Loading