-
Notifications
You must be signed in to change notification settings - Fork 522
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Merge pull request #870 from Portkey-AI/feat/mutator-hooks
Feat: Mutator Hooks
- Loading branch information
Showing
13 changed files
with
926 additions
and
123 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,95 @@ | ||
import { | ||
HookEventType, | ||
PluginContext, | ||
PluginHandler, | ||
PluginParameters, | ||
} from '../types'; | ||
import { getCurrentContentPart, post, setCurrentContentPart } from '../utils'; | ||
import { VERSION } from './version'; | ||
|
||
export const handler: PluginHandler = async ( | ||
context: PluginContext, | ||
parameters: PluginParameters, | ||
eventType: HookEventType | ||
) => { | ||
let transformedData = { | ||
request: { | ||
json: null, | ||
}, | ||
response: { | ||
json: null, | ||
}, | ||
}; | ||
|
||
try { | ||
if (!parameters.credentials?.domain) { | ||
return { | ||
error: `'parameters.credentials.domain' must be set`, | ||
verdict: true, | ||
data: null, | ||
}; | ||
} | ||
|
||
if (!parameters.credentials?.apiKey) { | ||
return { | ||
error: `'parameters.credentials.apiKey' must be set`, | ||
verdict: true, | ||
data: null, | ||
}; | ||
} | ||
|
||
const url = `https://redact.${parameters.credentials.domain}/v1/redact_structured`; | ||
|
||
const { content } = getCurrentContentPart(context, eventType); | ||
|
||
if (!content) { | ||
return { | ||
error: { message: 'request or response json is empty' }, | ||
verdict: true, | ||
data: null, | ||
transformedData, | ||
}; | ||
} | ||
|
||
const requestOptions = { | ||
headers: { | ||
'Content-Type': 'application/json', | ||
'User-Agent': 'portkey-ai-plugin/' + VERSION, | ||
Authorization: `Bearer ${parameters.credentials.apiKey}`, | ||
}, | ||
}; | ||
const request = { | ||
data: content, | ||
...(Array.isArray(content) && content[0]?.type === 'text' | ||
? { jsonp: ['$[*].text'] } | ||
: {}), | ||
}; | ||
|
||
const response = await post(url, request, requestOptions); | ||
|
||
if (response.result?.count > 0 && response.result.redacted_data) { | ||
setCurrentContentPart( | ||
context, | ||
eventType, | ||
transformedData, | ||
response.result.redacted_data | ||
); | ||
} | ||
|
||
return { | ||
error: null, | ||
verdict: true, | ||
data: { | ||
summary: response.summary, | ||
}, | ||
transformedData, | ||
}; | ||
} catch (e) { | ||
return { | ||
error: e as Error, | ||
verdict: true, | ||
data: null, | ||
transformedData, | ||
}; | ||
} | ||
}; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,94 @@ | ||
import { | ||
HookEventType, | ||
PluginContext, | ||
PluginHandler, | ||
PluginParameters, | ||
} from '../types'; | ||
import { getCurrentContentPart, setCurrentContentPart } from '../utils'; | ||
import { findAllLongestPositions, postPatronus } from './globals'; | ||
import { maskEntities } from './redactPii'; | ||
|
||
const redactPhi = async (text: string, credentials: any) => { | ||
const evaluator = 'phi'; | ||
|
||
const evaluationBody: any = { | ||
output: text, | ||
}; | ||
|
||
const result: any = await postPatronus( | ||
evaluator, | ||
credentials, | ||
evaluationBody | ||
); | ||
const evalResult = result.results[0]; | ||
|
||
const positionsData = evalResult.evaluation_result.additional_info; | ||
if ( | ||
Array.isArray(positionsData?.positions) && | ||
positionsData.positions.length > 0 | ||
) { | ||
const longestPosition = findAllLongestPositions(positionsData); | ||
if (longestPosition?.positions && longestPosition.positions.length > 0) { | ||
const maskedText = maskEntities(text, longestPosition.positions); | ||
return maskedText; | ||
} | ||
} | ||
return text; | ||
}; | ||
|
||
export const handler: PluginHandler = async ( | ||
context: PluginContext, | ||
parameters: PluginParameters, | ||
eventType: HookEventType | ||
) => { | ||
const transformedData: Record<string, any> = { | ||
request: { | ||
json: null, | ||
}, | ||
response: { | ||
json: null, | ||
}, | ||
}; | ||
|
||
try { | ||
const { content, textArray } = getCurrentContentPart(context, eventType); | ||
|
||
if (!content) { | ||
return { | ||
error: { message: 'request or response json is empty' }, | ||
verdict: true, | ||
data: null, | ||
transformedData, | ||
}; | ||
} | ||
|
||
const transformedTextPromise = textArray.map((text) => | ||
redactPhi(text, parameters.credentials) | ||
); | ||
|
||
const transformedText = await Promise.all(transformedTextPromise); | ||
|
||
setCurrentContentPart( | ||
context, | ||
eventType, | ||
transformedData, | ||
null, | ||
transformedText | ||
); | ||
|
||
return { | ||
error: null, | ||
verdict: true, | ||
data: null, | ||
transformedData, | ||
}; | ||
} catch (e: any) { | ||
delete e.stack; | ||
return { | ||
error: e as Error, | ||
verdict: true, | ||
data: null, | ||
transformedData, | ||
}; | ||
} | ||
}; |
Oops, something went wrong.