Skip to content

Commit 3e0bf76

Browse files
awkoyYaroslav Boiko
andauthored
[OPIK-1986] Fix prettify function to work correctly with the demo projects (#2762)
* [OPIK-1986] fix prettify func to work with demo project * [OPIK-1986] demo project prettifier --------- Co-authored-by: Yaroslav Boiko <yaroslavboiko@ip-192-168-1-15.ec2.internal>
1 parent 82257a4 commit 3e0bf76

File tree

2 files changed

+136
-0
lines changed

2 files changed

+136
-0
lines changed

apps/opik-frontend/src/lib/traces.test.ts

Lines changed: 85 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -185,4 +185,89 @@ describe("prettifyMessage", () => {
185185
prettified: true,
186186
});
187187
});
188+
189+
it("handles Demo project blocks structure with text content", () => {
190+
const message = {
191+
role: "assistant",
192+
blocks: [
193+
{
194+
block_type: "text",
195+
text: "Opik is a tool that has been specifically designed to support high volumes of traces, making it suitable for monitoring production applications, particularly LLM applications.",
196+
},
197+
],
198+
};
199+
const result = prettifyMessage(message, { type: "output" });
200+
expect(result).toEqual({
201+
message:
202+
"Opik is a tool that has been specifically designed to support high volumes of traces, making it suitable for monitoring production applications, particularly LLM applications.",
203+
prettified: true,
204+
});
205+
});
206+
207+
it("handles Demo project blocks structure with multiple text blocks", () => {
208+
const message = {
209+
role: "assistant",
210+
blocks: [
211+
{
212+
block_type: "text",
213+
text: "First paragraph content.",
214+
},
215+
{
216+
block_type: "text",
217+
text: "Second paragraph content.",
218+
},
219+
],
220+
};
221+
const result = prettifyMessage(message, { type: "output" });
222+
expect(result).toEqual({
223+
message: "First paragraph content.\n\nSecond paragraph content.",
224+
prettified: true,
225+
});
226+
});
227+
228+
it("handles Demo project blocks structure with mixed block types, extracting only text blocks", () => {
229+
const message = {
230+
role: "assistant",
231+
blocks: [
232+
{
233+
block_type: "image",
234+
url: "https://example.com/image.jpg",
235+
},
236+
{
237+
block_type: "text",
238+
text: "This is the text content.",
239+
},
240+
{
241+
block_type: "code",
242+
language: "python",
243+
code: "print('hello')",
244+
},
245+
],
246+
};
247+
const result = prettifyMessage(message, { type: "output" });
248+
expect(result).toEqual({
249+
message: "This is the text content.",
250+
prettified: true,
251+
});
252+
});
253+
254+
it("handles Demo project nested blocks structure under output property", () => {
255+
const message = {
256+
output: {
257+
role: "assistant",
258+
blocks: [
259+
{
260+
block_type: "text",
261+
text: "Opik's morning routine before diving into LLM evaluations involves logging, viewing, and evaluating LLM traces using the Opik platform and LLM as a Judge evaluators. This allows for the identification and fixing of issues in the LLM application.",
262+
},
263+
],
264+
},
265+
};
266+
const result = prettifyMessage(message, { type: "output" });
267+
expect(result).toEqual({
268+
message:
269+
"Opik's morning routine before diving into LLM evaluations involves logging, viewing, and evaluating LLM traces using the Opik platform and LLM as a Judge evaluators. This allows for the identification and fixing of issues in the LLM application.",
270+
prettified: true,
271+
});
272+
});
188273
});

apps/opik-frontend/src/lib/traces.ts

Lines changed: 51 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -318,6 +318,53 @@ const prettifyLangChainLogic = (
318318
}
319319
};
320320

321+
/**
322+
* Prettifies Demo project's blocks-based message format.
323+
*
324+
* Handles two formats:
325+
* - Direct: { blocks: [{ block_type: "text", text: "..." }] }
326+
* - Nested: { output: { blocks: [{ block_type: "text", text: "..." }] } }
327+
*/
328+
const prettifyDemoProjectLogic = (
329+
message: object | string | undefined,
330+
config: PrettifyMessageConfig,
331+
): string | undefined => {
332+
const extractTextFromBlocks = (blocks: unknown[]): string | undefined => {
333+
const textBlocks = blocks.filter(
334+
(block): block is { block_type: string; text: string } =>
335+
isObject(block) &&
336+
"block_type" in block &&
337+
block.block_type === "text" &&
338+
"text" in block &&
339+
isString(block.text) &&
340+
block.text.trim() !== "",
341+
);
342+
343+
return textBlocks.length > 0
344+
? textBlocks.map((block) => block.text).join("\n\n")
345+
: undefined;
346+
};
347+
348+
// Handle direct blocks structure: { blocks: [...] }
349+
if (isObject(message) && "blocks" in message && isArray(message.blocks)) {
350+
return extractTextFromBlocks(message.blocks);
351+
}
352+
353+
// Handle nested blocks structure: { output: { blocks: [...] } }
354+
if (
355+
config.type === "output" &&
356+
isObject(message) &&
357+
"output" in message &&
358+
isObject(message.output) &&
359+
"blocks" in message.output &&
360+
isArray(message.output.blocks)
361+
) {
362+
return extractTextFromBlocks(message.output.blocks);
363+
}
364+
365+
return undefined;
366+
};
367+
321368
const prettifyGenericLogic = (
322369
message: object | string | undefined,
323370
config: PrettifyMessageConfig,
@@ -394,6 +441,10 @@ export const prettifyMessage = (
394441
processedMessage = prettifyLangChainLogic(message, config);
395442
}
396443

444+
if (!isString(processedMessage)) {
445+
processedMessage = prettifyDemoProjectLogic(message, config);
446+
}
447+
397448
if (!isString(processedMessage)) {
398449
processedMessage = prettifyGenericLogic(message, config);
399450
}

0 commit comments

Comments
 (0)