/** * Copyright 2024 Google LLC * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ import "./logger.scss"; import { Part } from "@google/generative-ai"; import cn from "classnames"; import { ReactNode } from "react"; import { useLoggerStore } from "../../lib/store-logger"; import SyntaxHighlighter from "react-syntax-highlighter"; import { vs2015 as dark } from "react-syntax-highlighter/dist/esm/styles/hljs"; import { ClientContentMessage, isClientContentMessage, isInterrupted, isModelTurn, isServerContentMessage, isToolCallCancellationMessage, isToolCallMessage, isToolResponseMessage, isTurnComplete, ModelTurn, ServerContentMessage, StreamingLog, ToolCallCancellationMessage, ToolCallMessage, ToolResponseMessage, } from "../../multimodal-live-types"; const formatTime = (d: Date) => d.toLocaleTimeString().slice(0, -3); const LogEntry = ({ log, MessageComponent, }: { log: StreamingLog; MessageComponent: ({ message, }: { message: StreamingLog["message"]; }) => ReactNode; }): JSX.Element => (
  • {formatTime(log.date)} {log.type} {log.count && {log.count}}
  • ); const PlainTextMessage = ({ message, }: { message: StreamingLog["message"]; }) => {message as string}; type Message = { message: StreamingLog["message"] }; const AnyMessage = ({ message }: Message) => (
    {JSON.stringify(message, null, "  ")}
    ); function tryParseCodeExecutionResult(output: string) { try { const json = JSON.parse(output); return JSON.stringify(json, null, " "); } catch (e) { return output; } } const RenderPart = ({ part }: { part: Part }) => part.text && part.text.length ? (

    {part.text}

    ) : part.executableCode ? (
    executableCode: {part.executableCode.language}
    {part.executableCode.code}
    ) : part.codeExecutionResult ? (
    codeExecutionResult: {part.codeExecutionResult.outcome}
    {tryParseCodeExecutionResult(part.codeExecutionResult.output)}
    ) : (
    Inline Data: {part.inlineData?.mimeType}
    ); const ClientContentLog = ({ message }: Message) => { const { turns, turnComplete } = (message as ClientContentMessage) .clientContent; return (

    User

    {turns.map((turn, i) => (
    {turn.parts .filter((part) => !(part.text && part.text === "\n")) .map((part, j) => ( ))}
    ))} {!turnComplete ? turnComplete: false : ""}
    ); }; const ToolCallLog = ({ message }: Message) => { const { toolCall } = message as ToolCallMessage; return (
    {toolCall.functionCalls.map((fc, i) => (
    Function call: {fc.name}
    {JSON.stringify(fc, null, " ")}
    ))}
    ); }; const ToolCallCancellationLog = ({ message }: Message): JSX.Element => (
    {" "} ids:{" "} {(message as ToolCallCancellationMessage).toolCallCancellation.ids.map( (id) => ( "{id}" ), )}
    ); const ToolResponseLog = ({ message }: Message): JSX.Element => (
    {(message as ToolResponseMessage).toolResponse.functionResponses.map( (fc) => (
    Function Response: {fc.id}
    {JSON.stringify(fc.response, null, " ")}
    ), )}
    ); const ModelTurnLog = ({ message }: Message): JSX.Element => { const serverContent = (message as ServerContentMessage).serverContent; const { modelTurn } = serverContent as ModelTurn; const { parts } = modelTurn; return (

    Model

    {parts .filter((part) => !(part.text && part.text === "\n")) .map((part, j) => ( ))}
    ); }; const CustomPlainTextLog = (msg: string) => () => ( ); export type LoggerFilterType = "conversations" | "tools" | "none"; export type LoggerProps = { filter: LoggerFilterType; }; const filters: Record boolean> = { tools: (log: StreamingLog) => isToolCallMessage(log.message) || isToolResponseMessage(log.message) || isToolCallCancellationMessage(log.message), conversations: (log: StreamingLog) => isClientContentMessage(log.message) || isServerContentMessage(log.message), none: () => true, }; const component = (log: StreamingLog) => { if (typeof log.message === "string") { return PlainTextMessage; } if (isClientContentMessage(log.message)) { return ClientContentLog; } if (isToolCallMessage(log.message)) { return ToolCallLog; } if (isToolCallCancellationMessage(log.message)) { return ToolCallCancellationLog; } if (isToolResponseMessage(log.message)) { return ToolResponseLog; } if (isServerContentMessage(log.message)) { const { serverContent } = log.message; if (isInterrupted(serverContent)) { return CustomPlainTextLog("interrupted"); } if (isTurnComplete(serverContent)) { return CustomPlainTextLog("turnComplete"); } if (isModelTurn(serverContent)) { return ModelTurnLog; } } return AnyMessage; }; export default function Logger({ filter = "none" }: LoggerProps) { const { logs } = useLoggerStore(); const filterFn = filters[filter]; return (
      {logs.filter(filterFn).map((log, key) => { return ( ); })}
    ); }