diff --git a/components/chat-input.tsx b/components/chat-input.tsx index 30e11eb..db6503b 100644 --- a/components/chat-input.tsx +++ b/components/chat-input.tsx @@ -24,7 +24,6 @@ import { DialogFooter, DialogHeader, DialogTitle, - DialogTrigger, } from "@/components/ui/dialog"; import Image from "next/image"; diff --git a/components/chat-message-display.tsx b/components/chat-message-display.tsx new file mode 100644 index 0000000..aef8c88 --- /dev/null +++ b/components/chat-message-display.tsx @@ -0,0 +1,194 @@ +"use client"; + +import type React from "react"; +import { useRef, useEffect } from "react"; +import Image from "next/image"; +import { ScrollArea } from "@/components/ui/scroll-area"; +import ExamplePanel from "./chat-example-panel"; +import { Message } from "ai"; +import { convertToLegalXml } from "@/lib/utils"; + +interface ChatMessageDisplayProps { + messages: Message[]; + error?: Error | null; + setInput: (input: string) => void; + setFiles: (files: FileList | undefined) => void; + onDisplayChart: (xml: string) => void; + stepCounterRef: React.MutableRefObject; +} + +export function ChatMessageDisplay({ + messages, + error, + setInput, + setFiles, + onDisplayChart, + stepCounterRef, +}: ChatMessageDisplayProps) { + const messagesEndRef = useRef(null); + + useEffect(() => { + if (messagesEndRef.current) { + messagesEndRef.current.scrollIntoView({ behavior: "smooth" }); + } + }, [messages]); + + const renderToolInvocation = (toolInvocation: any) => { + const callId = toolInvocation.toolCallId; + + switch (toolInvocation.toolName) { + case "display_diagram": { + switch (toolInvocation.state) { + case "partial-call": { + const currentXml = toolInvocation.args?.xml || ""; + + // Increment the step counter + stepCounterRef.current += 1; + + // Determine whether to show details based on a simple threshold + if ( + stepCounterRef.current >= 50 && + stepCounterRef.current % 20 === 0 + ) { + onDisplayChart(convertToLegalXml(currentXml)); + } + return ( +
+
+ Generating diagram... +
+
+ Tool: display_diagram +
+ onDisplayChart +
+
+
+ ); + } + case "call": + return ( +
+
+ Displaying diagram... +
+
+ Tool: display_diagram +
+ Args:{" "} + {JSON.stringify( + toolInvocation.args, + null, + 2 + )} +
+
+
+ ); + case "result": + return null; + } + break; + } + default: + return null; + } + }; + + return ( + + {messages.length === 0 ? ( + + ) : ( + messages.map((message) => ( +
+
+ {message.parts + ? message.parts.map((part, index) => { + switch (part.type) { + case "text": + return ( +
+ {part.text} +
+ ); + case "tool-invocation": + return renderToolInvocation( + part.toolInvocation + ); + default: + return null; + } + }) + : message.content} +
+ + {message?.experimental_attachments + ?.filter((attachment) => + attachment?.contentType?.startsWith("image/") + ) + .map((attachment, index) => ( +
+
+ { +
+
+ ))} + + {(message as any).function_call && ( +
+
+ Using tool:{" "} + {(message as any).function_call.name} + ... +
+
+ )} +
+ )) + )} + {error && ( +
+ Error: {error.message} +
+ )} +
+ + ); +} diff --git a/components/chat-panel.tsx b/components/chat-panel.tsx index 0b55666..59473b8 100644 --- a/components/chat-panel.tsx +++ b/components/chat-panel.tsx @@ -2,7 +2,6 @@ import type React from "react"; import { useRef, useEffect, useState } from "react"; -import Image from "next/image"; import { Card, @@ -11,11 +10,9 @@ import { CardHeader, CardTitle, } from "@/components/ui/card"; -import { ScrollArea } from "@/components/ui/scroll-area"; import { useChat } from "@ai-sdk/react"; import { ChatInput } from "@/components/chat-input"; -import { convertToLegalXml } from "@/lib/utils"; -import ExamplePanel from "./chat-example-panel"; +import { ChatMessageDisplay } from "./chat-message-display"; interface ChatPanelProps { onDisplayChart: (xml: string) => void; onFetchChart: () => Promise; @@ -33,7 +30,6 @@ export default function ChatPanel({ const stepCounterRef = useRef(0); // Add state for file attachments const [files, setFiles] = useState(undefined); - // Add state to control visibility of prompt examples panel // Add state for showing the history dialog const [showHistory, setShowHistory] = useState(false); @@ -101,185 +97,20 @@ export default function ChatPanel({ setShowHistory(false); }; - // Helper function to render tool invocations - const renderToolInvocation = (toolInvocation: any) => { - const callId = toolInvocation.toolCallId; - - switch (toolInvocation.toolName) { - case "display_diagram": { - switch (toolInvocation.state) { - case "partial-call": { - const currentXml = toolInvocation.args?.xml || ""; - - // Increment the step counter - stepCounterRef.current += 1; - // Log the current step - - // Determine whether to show details based on a simple threshold - // Rather than comparing lengths (which can cause re-renders) - if ( - stepCounterRef.current >= 50 && - stepCounterRef.current % 20 === 0 - ) { - onDisplayChart(convertToLegalXml(currentXml)); - } - return ( -
-
- Generating diagram... -
-
- Tool: display_diagram -
- onDisplayChart -
-
-
- ); - } - case "call": - return ( -
-
- Displaying diagram... -
-
- Tool: display_diagram -
- Args:{" "} - {JSON.stringify( - toolInvocation.args, - null, - 2 - )} -
-
-
- ); - case "result": - return null; - } - break; - } - default: - return null; - } - }; - return ( Next-AI-Drawio - - {messages.length === 0 ? ( - - ) : ( - messages.map((message) => ( -
-
- {/* Render message content based on parts if available */} - {message.parts - ? message.parts.map((part, index) => { - switch (part.type) { - case "text": - return ( -
- {part.text} -
- ); - case "tool-invocation": - return renderToolInvocation( - part.toolInvocation - ); - default: - return null; - } - }) - : // Fallback to simple content for older format - message.content} -
- - {/* Display image attachments */} - {message?.experimental_attachments - ?.filter((attachment) => - attachment?.contentType?.startsWith( - "image/" - ) - ) - .map((attachment, index) => ( -
-
- { -
-
- ))} - - {/* Legacy support for function_call format */} - {(message as any).function_call && ( -
-
- Using tool:{" "} - { - (message as any).function_call - .name - } - ... -
-
- )} -
- )) - )} - {error && ( -
- Error: {error.message} -
- )} -
- +