Skip to content

Commit 54a9044

Browse files
authored
refactor: Content filter helper function (#441)
1 parent ec6a0a4 commit 54a9044

21 files changed

+700
-480
lines changed

Diff for: .changeset/afraid-cooks-shave.md

+6
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
---
2+
'@sap-ai-sdk/orchestration': minor
3+
---
4+
5+
[Compatibility Note] Deprecate `buildAzureContentFilter()` function.
6+
Use `buildAzureContentSafetyFilter()` function instead.

Diff for: packages/orchestration/README.md

+39-25
Original file line numberDiff line numberDiff line change
@@ -265,24 +265,42 @@ Use the orchestration client with filtering to restrict content that is passed t
265265

266266
This feature allows filtering both the [input](https://help.sap.com/docs/sap-ai-core/sap-ai-core-service-guide/input-filtering) and [output](https://help.sap.com/docs/sap-ai-core/sap-ai-core-service-guide/output-filtering) of a model based on content safety criteria.
267267

268-
```ts
269-
import {
270-
OrchestrationClient,
271-
buildAzureContentFilter
272-
} from '@sap-ai-sdk/orchestration';
268+
#### Azure Content Filter
269+
270+
Use `buildAzureContentSafetyFilter()` function to build an Azure content filter for both input and output.
271+
Each category of the filter can be assigned a specific severity level, which corresponds to an Azure threshold value.
272+
273+
| Severity Level | Azure Threshold Value |
274+
| ----------------------- | --------------------- |
275+
| `ALLOW_SAFE` | 0 |
276+
| `ALLOW_SAFE_LOW` | 2 |
277+
| `ALLOW_SAFE_LOW_MEDIUM` | 4 |
278+
| `ALLOW_ALL` | 6 |
273279

274-
const filter = buildAzureContentFilter({ Hate: 2, Violence: 4 });
280+
```ts
281+
import { OrchestrationClient, ContentFilters } from '@sap-ai-sdk/orchestration';
282+
const llm = {
283+
model_name: 'gpt-4o',
284+
model_params: { max_tokens: 50, temperature: 0.1 }
285+
};
286+
const templating = {
287+
template: [{ role: 'user', content: '{{?input}}' }]
288+
};
289+
290+
const filter = buildAzureContentSafetyFilter({
291+
Hate: 'ALLOW_SAFE_LOW',
292+
Violence: 'ALLOW_SAFE_LOW_MEDIUM'
293+
});
275294
const orchestrationClient = new OrchestrationClient({
276-
llm: {
277-
model_name: 'gpt-4o',
278-
model_params: { max_tokens: 50, temperature: 0.1 }
279-
},
280-
templating: {
281-
template: [{ role: 'user', content: '{{?input}}' }]
282-
},
295+
llm,
296+
templating,
283297
filtering: {
284-
input: filter,
285-
output: filter
298+
input: {
299+
filters: [filter]
300+
},
301+
output: {
302+
filters: [filter]
303+
}
286304
}
287305
});
288306

@@ -296,23 +314,19 @@ try {
296314
}
297315
```
298316

317+
#### Error Handling
318+
299319
Both `chatCompletion()` and `getContent()` methods can throw errors.
300320

301-
- **axios errors**:
321+
- **Axios Errors**:
302322
When the chat completion request fails with a `400` status code, the caught error will be an `Axios` error.
303-
The property `error.response.data.message` may provide additional details about the failure's cause.
323+
The property `error.response.data.message` provides additional details about the failure.
304324

305-
- **output content filtered**:
306-
The method `getContent()` can throw an error if the output filter filters the model output.
325+
- **Output Content Filtered**:
326+
The `getContent()` method can throw an error if the output filter filters the model output.
307327
This can occur even if the chat completion request responds with a `200` HTTP status code.
308328
The `error.message` property indicates if the output was filtered.
309329

310-
Therefore, handle errors appropriately to ensure meaningful feedback for both types of errors.
311-
312-
`buildAzureContentFilter()` is a convenience function that creates an Azure content filter configuration based on the provided inputs.
313-
The Azure content filter supports four categories: `Hate`, `Violence`, `Sexual`, and `SelfHarm`.
314-
Each category can be configured with severity levels of 0, 2, 4, or 6.
315-
316330
### Data Masking
317331

318332
You can anonymize or pseudonomize the prompt using the data masking capabilities of the orchestration service.

Diff for: packages/orchestration/src/index.ts

+5-2
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,9 @@ export type {
88
StreamOptions,
99
DocumentGroundingServiceConfig,
1010
DocumentGroundingServiceFilter,
11-
LlmModelParams
11+
LlmModelParams,
12+
AzureContentFilter,
13+
AzureFilterThreshold
1214
} from './orchestration-types.js';
1315

1416
export { OrchestrationStreamResponse } from './orchestration-stream-response.js';
@@ -21,8 +23,9 @@ export { OrchestrationClient } from './orchestration-client.js';
2123

2224
export {
2325
buildAzureContentFilter,
26+
buildAzureContentSafetyFilter,
2427
buildDocumentGroundingConfig
25-
} from './orchestration-utils.js';
28+
} from './util/index.js';
2629

2730
export { OrchestrationResponse } from './orchestration-response.js';
2831

Diff for: packages/orchestration/src/internal.ts

+1-1
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
11
export * from './orchestration-client.js';
2-
export * from './orchestration-utils.js';
2+
export * from './util/index.js';
33
export * from './orchestration-types.js';
44
export * from './orchestration-response.js';

Diff for: packages/orchestration/src/orchestration-client.test.ts

+20-6
Original file line numberDiff line numberDiff line change
@@ -9,12 +9,12 @@ import {
99
parseMockResponse
1010
} from '../../../test-util/mock-http.js';
1111
import { OrchestrationClient } from './orchestration-client.js';
12+
import { OrchestrationResponse } from './orchestration-response.js';
1213
import {
13-
buildAzureContentFilter,
14+
constructCompletionPostRequestFromJsonModuleConfig,
1415
constructCompletionPostRequest,
15-
constructCompletionPostRequestFromJsonModuleConfig
16-
} from './orchestration-utils.js';
17-
import { OrchestrationResponse } from './orchestration-response.js';
16+
buildAzureContentSafetyFilter
17+
} from './util/index.js';
1818
import type { CompletionPostResponse } from './client/api/schema/index.js';
1919
import type {
2020
OrchestrationModuleConfig,
@@ -162,8 +162,22 @@ describe('orchestration service client', () => {
162162
]
163163
},
164164
filtering: {
165-
input: buildAzureContentFilter({ Hate: 4, SelfHarm: 2 }),
166-
output: buildAzureContentFilter({ Sexual: 0, Violence: 4 })
165+
input: {
166+
filters: [
167+
buildAzureContentSafetyFilter({
168+
Hate: 'ALLOW_SAFE_LOW_MEDIUM',
169+
SelfHarm: 'ALLOW_SAFE_LOW'
170+
})
171+
]
172+
},
173+
output: {
174+
filters: [
175+
buildAzureContentSafetyFilter({
176+
Sexual: 'ALLOW_SAFE',
177+
Violence: 'ALLOW_SAFE_LOW_MEDIUM'
178+
})
179+
]
180+
}
167181
}
168182
};
169183
const prompt = {

Diff for: packages/orchestration/src/orchestration-client.ts

+1-1
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@ import { OrchestrationResponse } from './orchestration-response.js';
77
import {
88
constructCompletionPostRequest,
99
constructCompletionPostRequestFromJsonModuleConfig
10-
} from './orchestration-utils.js';
10+
} from './util/index.js';
1111
import type {
1212
HttpResponse,
1313
CustomRequestConfig

Diff for: packages/orchestration/src/orchestration-completion-post-request-from-json.test.ts

+1-1
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
import { constructCompletionPostRequestFromJsonModuleConfig } from './orchestration-utils.js';
1+
import { constructCompletionPostRequestFromJsonModuleConfig } from './util/module-config.js';
22

33
describe('construct completion post request from JSON', () => {
44
it('should construct completion post request from JSON', () => {

Diff for: packages/orchestration/src/orchestration-completion-post-request.test.ts

+18-4
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
import {
22
constructCompletionPostRequest,
3-
buildAzureContentFilter
4-
} from './orchestration-utils.js';
3+
buildAzureContentSafetyFilter
4+
} from './util/index.js';
55
import type { CompletionPostRequest } from './client/api/schema/index.js';
66
import type {
77
OrchestrationModuleConfig,
@@ -169,7 +169,14 @@ describe('construct completion post request', () => {
169169
const config: OrchestrationModuleConfig = {
170170
...defaultConfig,
171171
filtering: {
172-
input: buildAzureContentFilter({ Hate: 4, SelfHarm: 0 })
172+
input: {
173+
filters: [
174+
buildAzureContentSafetyFilter({
175+
Hate: 'ALLOW_SAFE_LOW_MEDIUM',
176+
SelfHarm: 'ALLOW_SAFE'
177+
})
178+
]
179+
}
173180
}
174181
};
175182
const expectedCompletionPostRequest: CompletionPostRequest = {
@@ -209,7 +216,14 @@ describe('construct completion post request', () => {
209216
const config: OrchestrationModuleConfig = {
210217
...defaultConfig,
211218
filtering: {
212-
output: buildAzureContentFilter({ Hate: 4, SelfHarm: 0 })
219+
output: {
220+
filters: [
221+
buildAzureContentSafetyFilter({
222+
Hate: 'ALLOW_SAFE_LOW_MEDIUM',
223+
SelfHarm: 'ALLOW_SAFE'
224+
})
225+
]
226+
}
213227
}
214228
};
215229

Diff for: packages/orchestration/src/orchestration-types.ts

+50
Original file line numberDiff line numberDiff line change
@@ -63,6 +63,17 @@ export interface OrchestrationModuleConfig {
6363
llm: LlmModuleConfig;
6464
/**
6565
* Filtering module configuration.
66+
* Construct filter configuration for both input and output filters using convenience functions.
67+
* @example
68+
* ```ts
69+
* filtering: {
70+
* input: {
71+
* filters: [
72+
* buildAzureContentSafetyFilter({ Hate: 'ALLOW_SAFE', Violence: 'ALLOW_SAFE_LOW_MEDIUM' })
73+
* ]
74+
* }
75+
* }
76+
* ```
6677
*/
6778
filtering?: FilteringModuleConfig;
6879
/**
@@ -151,3 +162,42 @@ export interface DocumentGroundingServiceConfig {
151162
*/
152163
output_param: string;
153164
}
165+
166+
/**
167+
* Filter configuration for Azure content safety Filter.
168+
*/
169+
export interface AzureContentFilter {
170+
/**
171+
* The filter category for hate content.
172+
*/
173+
Hate?: AzureFilterThreshold;
174+
/**
175+
* The filter category for self-harm content.
176+
*/
177+
SelfHarm?: AzureFilterThreshold;
178+
/**
179+
* The filter category for sexual content.
180+
*/
181+
Sexual?: AzureFilterThreshold;
182+
/**
183+
* The filter category for violence content.
184+
*/
185+
Violence?: AzureFilterThreshold;
186+
}
187+
188+
/**
189+
* A descriptive constant for Azure content safety filter threshold.
190+
* @internal
191+
*/
192+
export const supportedAzureFilterThresholds = {
193+
ALLOW_SAFE: 0,
194+
ALLOW_SAFE_LOW: 2,
195+
ALLOW_SAFE_LOW_MEDIUM: 4,
196+
ALLOW_ALL: 6
197+
} as const;
198+
199+
/**
200+
* The Azure threshold level supported for each azure content filter category.
201+
*
202+
*/
203+
export type AzureFilterThreshold = keyof typeof supportedAzureFilterThresholds;

0 commit comments

Comments
 (0)