diff --git a/app/favicon.ico b/app/favicon.ico index 718d6fe..869186a 100644 Binary files a/app/favicon.ico and b/app/favicon.ico differ diff --git a/app/layout.tsx b/app/layout.tsx index f7fa87e..2b637a9 100644 --- a/app/layout.tsx +++ b/app/layout.tsx @@ -3,32 +3,32 @@ import { Geist, Geist_Mono } from "next/font/google"; import "./globals.css"; const geistSans = Geist({ - variable: "--font-geist-sans", - subsets: ["latin"], + variable: "--font-geist-sans", + subsets: ["latin"], }); const geistMono = Geist_Mono({ - variable: "--font-geist-mono", - subsets: ["latin"], + variable: "--font-geist-mono", + subsets: ["latin"], }); export const metadata: Metadata = { - title: "Create Next App", - description: "Generated by create next app", + title: "Next-AI-Drawio", + description: "An AI-powered drawing tool that integrates with draw.io", }; export default function RootLayout({ - children, + children, }: Readonly<{ - children: React.ReactNode; + children: React.ReactNode; }>) { - return ( - - - {children} - - - ); + return ( + + + {children} + + + ); } diff --git a/components/chatPanel.tsx b/components/chatPanel.tsx index 1388de0..e2795a4 100644 --- a/components/chatPanel.tsx +++ b/components/chatPanel.tsx @@ -1,28 +1,47 @@ -"use client" +"use client"; -import type React from "react" -import { useRef, useEffect, useState } from "react" -import Image from "next/image" +import type React from "react"; +import { useRef, useEffect, useState } from "react"; +import Image from "next/image"; -import { Card, CardContent, CardFooter, CardHeader, CardTitle } from "@/components/ui/card" -import { ScrollArea } from "@/components/ui/scroll-area" -import { Button } from "@/components/ui/button" -import { useChat } from '@ai-sdk/react'; -import { ChatInput } from "@/components/chat-input" -import { convertToLegalXml } from "@/lib/utils" +import { + Card, + CardContent, + CardFooter, + CardHeader, + CardTitle, +} from "@/components/ui/card"; +import { ScrollArea } from "@/components/ui/scroll-area"; +import { Button } from "@/components/ui/button"; +import { useChat } from "@ai-sdk/react"; +import { ChatInput } from "@/components/chat-input"; +import { convertToLegalXml } from "@/lib/utils"; interface ChatPanelProps { onDisplayChart: (xml: string) => void; onFetchChart: () => Promise; } -export default function ChatPanel({ onDisplayChart, onFetchChart }: ChatPanelProps) { +export default function ChatPanel({ + onDisplayChart, + onFetchChart, +}: ChatPanelProps) { // Add a step counter to track updates const stepCounterRef = useRef(0); // Add state for file attachments const [files, setFiles] = useState(undefined); // Remove the currentXmlRef and related useEffect - const { messages, input, handleInputChange, handleSubmit, status, error, setInput, setMessages, data } = useChat({ + const { + messages, + input, + handleInputChange, + handleSubmit, + status, + error, + setInput, + setMessages, + data, + } = useChat({ maxSteps: 5, async onToolCall({ toolCall }) { console.log("Tool call:", toolCall); @@ -36,19 +55,19 @@ export default function ChatPanel({ onDisplayChart, onFetchChart }: ChatPanelPro }, onError: (error) => { console.error("Chat error:", error); - } - }) - const messagesEndRef = useRef(null) + }, + }); + const messagesEndRef = useRef(null); // Scroll to bottom when messages change useEffect(() => { if (messagesEndRef.current) { - messagesEndRef.current.scrollIntoView({ behavior: "smooth" }) + messagesEndRef.current.scrollIntoView({ behavior: "smooth" }); } console.log("Data updated:", data); - }, [messages]) + }, [messages]); const onFormSubmit = async (e: React.FormEvent) => { - e.preventDefault() + e.preventDefault(); if (input.trim() && status !== "streaming") { try { // Fetch chart data before setting input @@ -66,10 +85,10 @@ export default function ChatPanel({ onDisplayChart, onFetchChart }: ChatPanelPro ${input} """ ` - ) + ); handleSubmit(e, { experimental_attachments: files, - }) + }); // Clear files after submission setFiles(undefined); @@ -77,21 +96,21 @@ export default function ChatPanel({ onDisplayChart, onFetchChart }: ChatPanelPro console.error("Error fetching chart data:", error); } } - } + }; // Helper function to handle file changes const handleFileChange = (newFiles: FileList | undefined) => { setFiles(newFiles); - } + }; // Helper function to render tool invocations const renderToolInvocation = (toolInvocation: any) => { const callId = toolInvocation.toolCallId; switch (toolInvocation.toolName) { - case 'display_diagram': { + case "display_diagram": { switch (toolInvocation.state) { - case 'partial-call': { + case "partial-call": { const currentXml = toolInvocation.args?.xml || ""; // Increment the step counter @@ -100,12 +119,20 @@ export default function ChatPanel({ onDisplayChart, onFetchChart }: ChatPanelPro // Determine whether to show details based on a simple threshold // Rather than comparing lengths (which can cause re-renders) - if (stepCounterRef.current >= 20 && stepCounterRef.current % 20 === 0) { + if ( + stepCounterRef.current >= 20 && + stepCounterRef.current % 20 === 0 + ) { onDisplayChart(convertToLegalXml(currentXml)); } return ( -
-
Generating diagram...
+
+
+ Generating diagram... +
Tool: display_diagram
@@ -115,22 +142,37 @@ export default function ChatPanel({ onDisplayChart, onFetchChart }: ChatPanelPro
); } - case 'call': + case "call": return ( -
-
Displaying diagram...
+
+
+ Displaying diagram... +
Tool: display_diagram
- Args: {JSON.stringify(toolInvocation.args, null, 2)} + Args:{" "} + {JSON.stringify( + toolInvocation.args, + null, + 2 + )}
); - case 'result': + case "result": return ( -
-
Diagram generated
+
+
+ Diagram generated +
Result: {toolInvocation.result}
@@ -146,64 +188,105 @@ export default function ChatPanel({ onDisplayChart, onFetchChart }: ChatPanelPro return ( - - Chat with Diagram Generator + + Next-AI-Drawio {messages.length === 0 ? (
-

Start a conversation to generate or modify diagrams.

-

Try: "Create a flowchart for user authentication"

+

+ Start a conversation to generate or modify + diagrams. +

+

+ Try: "Create a flowchart for user + authentication" +

) : ( 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 - )} + {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) => ( -
-
- {attachment.name + {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}... + Using tool:{" "} + { + (message as any).function_call + .name + } + ...
)} @@ -231,5 +314,5 @@ export default function ChatPanel({ onDisplayChart, onFetchChart }: ChatPanelPro /> - ) + ); } diff --git a/public/file.svg b/public/file.svg deleted file mode 100644 index 004145c..0000000 --- a/public/file.svg +++ /dev/null @@ -1 +0,0 @@ - \ No newline at end of file diff --git a/public/globe.svg b/public/globe.svg deleted file mode 100644 index 567f17b..0000000 --- a/public/globe.svg +++ /dev/null @@ -1 +0,0 @@ - \ No newline at end of file diff --git a/public/next.svg b/public/next.svg deleted file mode 100644 index 5174b28..0000000 --- a/public/next.svg +++ /dev/null @@ -1 +0,0 @@ - \ No newline at end of file diff --git a/public/vercel.svg b/public/vercel.svg deleted file mode 100644 index 7705396..0000000 --- a/public/vercel.svg +++ /dev/null @@ -1 +0,0 @@ - \ No newline at end of file diff --git a/public/window.svg b/public/window.svg deleted file mode 100644 index b2b2a44..0000000 --- a/public/window.svg +++ /dev/null @@ -1 +0,0 @@ - \ No newline at end of file