diff --git a/c1-chat-artifact/src/app/page.tsx b/c1-chat-artifact/src/app/page.tsx index e36274f..59e070c 100644 --- a/c1-chat-artifact/src/app/page.tsx +++ b/c1-chat-artifact/src/app/page.tsx @@ -1,16 +1,166 @@ "use client"; -import { C1Chat, ArtifactViewMode } from "@thesysai/genui-sdk"; +import { useState } from "react"; +import { C1Component, ThemeProvider, useArtifact } from "@thesysai/genui-sdk"; import "@crayonai/react-ui/styles/index.css"; +import { nanoid } from "nanoid"; export default function Home() { + const [query, setQuery] = useState(""); + const [c1Response, setC1Response] = useState(""); + const [isStreaming, setIsStreaming] = useState(false); + const [abortController, setAbortController] = + useState(null); + + const { renderArtifact, isArtifactActive } = useArtifact(); + + const handleSubmit = async (customQuery?: string) => { + const userQuery = customQuery || query; + if (!userQuery.trim() || isStreaming) return; + + // Abort any ongoing request + if (abortController) { + abortController.abort(); + } + + const controller = new AbortController(); + setAbortController(controller); + setIsStreaming(true); + setC1Response(""); + + try { + const response = await fetch("/api/chat", { + method: "POST", + headers: { "Content-Type": "application/json" }, + body: JSON.stringify({ + prompt: { role: "user", content: userQuery, id: nanoid() }, + threadId: "single-thread", + responseId: nanoid(), + }), + signal: controller.signal, + }); + + if (!response.ok) { + throw new Error(`HTTP error! status: ${response.status}`); + } + + const reader = response.body?.getReader(); + const decoder = new TextDecoder(); + + if (!reader) { + throw new Error("No response body"); + } + + let accumulatedResponse = ""; + + while (true) { + const { done, value } = await reader.read(); + if (done) break; + + const chunk = decoder.decode(value, { stream: true }); + accumulatedResponse += chunk; + setC1Response(accumulatedResponse); + } + } catch (error: any) { + if (error.name !== "AbortError") { + console.error("Error fetching response:", error); + setC1Response("Error: Failed to get response from the server."); + } + } finally { + setIsStreaming(false); + setAbortController(null); + } + }; + + const handleStop = () => { + if (abortController) { + abortController.abort(); + setAbortController(null); + setIsStreaming(false); + } + }; + return ( - +
+ {/* Main Content Area */} +
+
+
+

+ Artifact Assistant +

+
+ setQuery(e.target.value)} + onKeyDown={(e) => { + if (e.key === "Enter" && !e.shiftKey) { + e.preventDefault(); + handleSubmit(); + } + }} + placeholder="Ask me to create presentations or reports..." + className="flex-1 px-4 py-3 rounded-lg border border-gray-300 dark:border-gray-600 + bg-white dark:bg-gray-700 text-gray-900 dark:text-gray-100 + focus:outline-none focus:ring-2 focus:ring-blue-500 focus:border-transparent + placeholder-gray-500 dark:placeholder-gray-400" + disabled={isStreaming} + /> + {isStreaming ? ( + + ) : ( + + )} +
+
+ + {c1Response && ( +
+ + setC1Response(message)} + onAction={({ llmFriendlyMessage, humanFriendlyMessage }) => { + console.log("Action triggered:", { + humanFriendlyMessage, + llmFriendlyMessage, + }); + setQuery(llmFriendlyMessage); + handleSubmit(llmFriendlyMessage); + }} + /> + +
+ )} +
+
+ + {/* Artifact Side Panel */} + {isArtifactActive && ( +
+
{renderArtifact()}
+
+ )} +
); }