"use client"; import { AnimatePresence } from "framer-motion"; import React, { useEffect, useState } from "react"; import QueryInput from "../home/queryinput"; import { cn } from "@repo/ui/lib/utils"; import { motion } from "framer-motion"; import { useRouter } from "next/navigation"; import { ChatHistory } from "@repo/shared-types"; import { Accordion, AccordionContent, AccordionItem, AccordionTrigger, } from "@repo/ui/shadcn/accordion"; import Markdown from "react-markdown"; import remarkGfm from "remark-gfm"; import remarkMath from "remark-math"; import rehypeKatex from "rehype-katex"; import rehypeHighlight from "rehype-highlight"; import { code, p } from "./markdownRenderHelpers"; import { codeLanguageSubset } from "@/lib/constants"; import { z } from "zod"; import { toast } from "sonner"; import Link from "next/link"; import { sources } from "next/dist/compiled/webpack/webpack"; function ChatWindow({ q, spaces, }: { q: string; spaces: { id: string; name: string }[]; }) { const [layout, setLayout] = useState<"chat" | "initial">("initial"); const [chatHistory, setChatHistory] = useState([ { question: q, answer: { parts: [ // { // text: `It seems like there might be a typo in your question. Could you please clarify or provide more context? If you meant "interesting," please let me know what specific information or topic you find interesting, and I can help you with that.`, // }, ], sources: [], }, }, ]); const router = useRouter(); const getAnswer = async (query: string, spaces: string[]) => { const sourcesFetch = await fetch( `/api/chat?q=${query}&spaces=${spaces}&sourcesOnly=true`, { method: "POST", body: JSON.stringify({ chatHistory }), }, ); // TODO: handle this properly const sources = await sourcesFetch.json(); const sourcesZod = z.object({ ids: z.array(z.string()), metadata: z.array(z.any()), }); const sourcesParsed = sourcesZod.safeParse(sources); if (!sourcesParsed.success) { console.log(sources); console.error(sourcesParsed.error); toast.error("Something went wrong while getting the sources"); return; } setChatHistory((prevChatHistory) => { const newChatHistory = [...prevChatHistory]; const lastAnswer = newChatHistory[newChatHistory.length - 1]; if (!lastAnswer) return prevChatHistory; const filteredSourceUrls = new Set( sourcesParsed.data.metadata.map((source) => source.url), ); const uniqueSources = sourcesParsed.data.metadata.filter((source) => { if (filteredSourceUrls.has(source.url)) { filteredSourceUrls.delete(source.url); return true; } return false; }); lastAnswer.answer.sources = uniqueSources.map((source) => ({ title: source.title ?? "Untitled", type: source.type ?? "page", source: source.url ?? "https://supermemory.ai", content: source.content ?? "No content available", numChunks: sourcesParsed.data.metadata.filter( (f) => f.url === source.url, ).length, })); return newChatHistory; }); const resp = await fetch(`/api/chat?q=${query}&spaces=${spaces}`, { method: "POST", body: JSON.stringify({ chatHistory }), }); const reader = resp.body?.getReader(); let done = false; let result = ""; while (!done && reader) { const { value, done: d } = await reader.read(); done = d; setChatHistory((prevChatHistory) => { const newChatHistory = [...prevChatHistory]; const lastAnswer = newChatHistory[newChatHistory.length - 1]; if (!lastAnswer) return prevChatHistory; lastAnswer.answer.parts.push({ text: new TextDecoder().decode(value) }); return newChatHistory; }); } console.log(result); }; useEffect(() => { if (q.trim().length > 0) { getAnswer( q, spaces.map((s) => s.id), ); setTimeout(() => { setLayout("chat"); }, 300); } else { router.push("/home"); } }, []); return (
{layout === "initial" ? (
) : (
{chatHistory.map((chat, idx) => (

{chat.question}

0 || chat.answer.parts.length === 0 ? "flex" : "hidden"}`} > Related Memories {/* TODO: fade out content on the right side, the fade goes away when the user scrolls */} {/* Loading state */} {chat.answer.sources.length > 0 || (chat.answer.parts.length === 0 && ( <> {[1, 2, 3, 4].map((_, idx) => (
))} ))} {chat.answer.sources.map((source, idx) => (
{source.type} {source.numChunks > 1 && ( {source.numChunks} chunks )}
{source.title}
{source.content.length > 100 ? source.content.slice(0, 100) + "..." : source.content}
))}
{/* Summary */}
Summary
{chat.answer.parts.length === 0 && (
)} {chat.answer.parts.map((part) => part.text).join("")}
))}
)}
); } export default ChatWindow;