fix(tts): clamp generated summaries (#1187)
* fix(tts): clamp generated summaries * fix(tts): preserve non-finite summary limits * test(tts): stub fetch without vitest globals --------- Co-authored-by: Isaac Sanchez <isanchez-hawkins@arize.com>
This commit is contained in:
committed by
GitHub
co-authored by
Isaac Sanchez
parent
bb5a6fb83b
commit
222d1b7f51
@@ -115,6 +115,13 @@ function sanitizeByMode(text, mode) {
|
|||||||
return sanitizeForTTS(text);
|
return sanitizeForTTS(text);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function clampToMaxLength(text, maxLength) {
|
||||||
|
if (!text) return '';
|
||||||
|
const limit = Number.isFinite(maxLength) ? Math.max(0, Math.floor(maxLength)) : Infinity;
|
||||||
|
if (text.length <= limit) return text;
|
||||||
|
return text.slice(0, limit).trim();
|
||||||
|
}
|
||||||
|
|
||||||
function extractZenOutputText(data) {
|
function extractZenOutputText(data) {
|
||||||
if (!data || typeof data !== 'object') return null;
|
if (!data || typeof data !== 'object') return null;
|
||||||
const output = data.output;
|
const output = data.output;
|
||||||
@@ -252,11 +259,12 @@ export async function summarizeText({ text, threshold = 200, maxLength = 500, ze
|
|||||||
const finalSummary = mode === 'note'
|
const finalSummary = mode === 'note'
|
||||||
? (sanitized && sanitized !== sanitizeForNote(text) ? sanitized : distillNoteFallback(text, maxLength))
|
? (sanitized && sanitized !== sanitizeForNote(text) ? sanitized : distillNoteFallback(text, maxLength))
|
||||||
: sanitized;
|
: sanitized;
|
||||||
|
const clippedSummary = clampToMaxLength(finalSummary, maxLength);
|
||||||
return {
|
return {
|
||||||
summary: finalSummary,
|
summary: clippedSummary,
|
||||||
summarized: true,
|
summarized: true,
|
||||||
originalLength: text.length,
|
originalLength: text.length,
|
||||||
summaryLength: finalSummary.length,
|
summaryLength: clippedSummary.length,
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -2,9 +2,15 @@ import { afterEach, describe, expect, it, vi } from 'vitest';
|
|||||||
|
|
||||||
import { summarizeText } from './summarization.js';
|
import { summarizeText } from './summarization.js';
|
||||||
|
|
||||||
|
const originalFetch = globalThis.fetch;
|
||||||
|
|
||||||
|
function stubFetch(fetchMock) {
|
||||||
|
globalThis.fetch = fetchMock;
|
||||||
|
}
|
||||||
|
|
||||||
describe('text summarization zen requests', () => {
|
describe('text summarization zen requests', () => {
|
||||||
afterEach(() => {
|
afterEach(() => {
|
||||||
vi.unstubAllGlobals();
|
globalThis.fetch = originalFetch;
|
||||||
});
|
});
|
||||||
|
|
||||||
it('uses responses endpoint for gpt models', async () => {
|
it('uses responses endpoint for gpt models', async () => {
|
||||||
@@ -17,7 +23,7 @@ describe('text summarization zen requests', () => {
|
|||||||
}],
|
}],
|
||||||
}),
|
}),
|
||||||
}));
|
}));
|
||||||
vi.stubGlobal('fetch', fetchMock);
|
stubFetch(fetchMock);
|
||||||
|
|
||||||
const result = await summarizeText({
|
const result = await summarizeText({
|
||||||
text: 'Long text '.repeat(30),
|
text: 'Long text '.repeat(30),
|
||||||
@@ -43,7 +49,7 @@ describe('text summarization zen requests', () => {
|
|||||||
choices: [{ message: { content: 'Chat summary' } }],
|
choices: [{ message: { content: 'Chat summary' } }],
|
||||||
}),
|
}),
|
||||||
}));
|
}));
|
||||||
vi.stubGlobal('fetch', fetchMock);
|
stubFetch(fetchMock);
|
||||||
|
|
||||||
const result = await summarizeText({
|
const result = await summarizeText({
|
||||||
text: 'Long text '.repeat(30),
|
text: 'Long text '.repeat(30),
|
||||||
@@ -61,4 +67,52 @@ describe('text summarization zen requests', () => {
|
|||||||
);
|
);
|
||||||
expect(result.summary).toBe('Chat summary');
|
expect(result.summary).toBe('Chat summary');
|
||||||
});
|
});
|
||||||
|
|
||||||
|
it('clamps successful model summaries to the requested max length', async () => {
|
||||||
|
const fetchMock = vi.fn(async () => ({
|
||||||
|
ok: true,
|
||||||
|
json: async () => ({
|
||||||
|
output: [{
|
||||||
|
type: 'message',
|
||||||
|
content: [{ type: 'output_text', text: 'This response is too long' }],
|
||||||
|
}],
|
||||||
|
}),
|
||||||
|
}));
|
||||||
|
stubFetch(fetchMock);
|
||||||
|
|
||||||
|
const result = await summarizeText({
|
||||||
|
text: 'Long text '.repeat(30),
|
||||||
|
threshold: 0,
|
||||||
|
maxLength: 12,
|
||||||
|
zenModel: 'gpt-5-nano',
|
||||||
|
mode: 'notification',
|
||||||
|
});
|
||||||
|
|
||||||
|
expect(result.summary).toBe('This respons');
|
||||||
|
expect(result.summaryLength).toBe(12);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('does not clamp successful model summaries for non-finite max lengths', async () => {
|
||||||
|
const fetchMock = vi.fn(async () => ({
|
||||||
|
ok: true,
|
||||||
|
json: async () => ({
|
||||||
|
output: [{
|
||||||
|
type: 'message',
|
||||||
|
content: [{ type: 'output_text', text: 'Full response' }],
|
||||||
|
}],
|
||||||
|
}),
|
||||||
|
}));
|
||||||
|
stubFetch(fetchMock);
|
||||||
|
|
||||||
|
const result = await summarizeText({
|
||||||
|
text: 'Long text '.repeat(30),
|
||||||
|
threshold: 0,
|
||||||
|
maxLength: Infinity,
|
||||||
|
zenModel: 'gpt-5-nano',
|
||||||
|
mode: 'notification',
|
||||||
|
});
|
||||||
|
|
||||||
|
expect(result.summary).toBe('Full response');
|
||||||
|
expect(result.summaryLength).toBe(13);
|
||||||
|
});
|
||||||
});
|
});
|
||||||
|
|||||||
Reference in New Issue
Block a user