diff --git a/apps/opik-frontend/src/components/shared/TraceDetailsPanel/TraceDataViewer/InputOutputTab.tsx b/apps/opik-frontend/src/components/shared/TraceDetailsPanel/TraceDataViewer/InputOutputTab.tsx index b2143505f..dc0f0afab 100644 --- a/apps/opik-frontend/src/components/shared/TraceDetailsPanel/TraceDataViewer/InputOutputTab.tsx +++ b/apps/opik-frontend/src/components/shared/TraceDetailsPanel/TraceDataViewer/InputOutputTab.tsx @@ -1,4 +1,6 @@ -import React from "react"; +import React, { useMemo } from "react"; +import get from "lodash/get"; +import isString from "lodash/isString"; import { Span, Trace } from "@/types/traces"; import { Accordion, @@ -8,6 +10,37 @@ import { } from "@/components/ui/accordion"; import SyntaxHighlighter from "@/components/shared/SyntaxHighlighter/SyntaxHighlighter"; +export type ImageContent = { + type: "image_url"; + image_url: { + url: string; + }; +}; + +const isImageContent = (content?: Partial) => { + try { + return content?.type === "image_url" && isString(content?.image_url?.url); + } catch (error) { + return false; + } +}; + +function extractImageUrls(messages: unknown) { + if (!Array.isArray(messages)) return []; + + const images: string[] = []; + + messages.forEach((message) => { + const imageContent: ImageContent[] = Array.isArray(message?.content) + ? message.content.filter(isImageContent) + : []; + + images.push(...imageContent.map((content) => content.image_url.url)); + }); + + return images; +} + type InputOutputTabProps = { data: Trace | Span; }; @@ -15,12 +48,43 @@ type InputOutputTabProps = { const InputOutputTab: React.FunctionComponent = ({ data, }) => { + const imagesUrls = useMemo( + () => extractImageUrls(get(data, ["input", "messages"], [])), + [data], + ); + + const hasImages = imagesUrls.length > 0; + + const openTabs = useMemo(() => { + return hasImages ? ["images", "input", "output"] : ["input", "output"]; + }, [hasImages]); + return ( - + + {hasImages && ( + + Images + +
+ {imagesUrls.map((imageUrl, index) => { + return ( +
+ {`image-${index}`} +
+ ); + })} +
+
+
+ )} Input