import { ActionIcon, Box, Group, HoverCard, JsonInput, List, Stack, Tabs, Textarea, useMantineTheme, } from "@mantine/core"; import { trpc } from "../../../trpc/client"; import { useEffect, useState } from "react"; import { defaultParameters, defaultSystemPrompt, useStore, } from "../../../state"; import { usePageContext } from "vike-react/usePageContext"; import { useData } from "vike-react/useData"; import type { Data } from "./+data"; import type { CommittedMessage, DraftMessage } from "../../../types"; import Markdown from "react-markdown"; import { IconTrash, IconEdit, IconCheck, IconX } from "@tabler/icons-react"; export default function ChatPage() { const pageContext = usePageContext(); const conversationId = pageContext.routeParams.id; const conversationTitle = useStore( (state) => state.conversations.find((c) => c.id === conversationId)?.title ); const messages = useStore((state) => state.messages); const message = useStore((state) => state.message); const systemPrompt = useStore((state) => state.systemPrompt); const parameters = useStore((state) => state.parameters); const facts = useStore((state) => state.facts); const factTriggers = useStore((state) => state.factTriggers); const loading = useStore((state) => state.loading); const setConversationId = useStore((state) => state.setConversationId); const setConversationTitle = useStore((state) => state.setConversationTitle); const setMessages = useStore((state) => state.setMessages); const setMessage = useStore((state) => state.setMessage); const setSystemPrompt = useStore((state) => state.setSystemPrompt); const setParameters = useStore((state) => state.setParameters); const setFacts = useStore((state) => state.setFacts); const setFactTriggers = useStore((state) => state.setFactTriggers); const removeFact = useStore((state) => state.removeFact); const removeFactTrigger = useStore((state) => state.removeFactTrigger); const setLoading = useStore((state) => state.setLoading); // State for editing facts const [editingFactId, setEditingFactId] = useState(null); const [editingFactContent, setEditingFactContent] = useState(""); // State for editing fact triggers const [editingFactTriggerId, setEditingFactTriggerId] = useState< string | null >(null); const [editingFactTriggerContent, setEditingFactTriggerContent] = useState(""); // Handle clicking outside to cancel editing useEffect(() => { function handleClickOutside(event: MouseEvent) { if (editingFactId && event.target instanceof Element) { const editingElement = event.target.closest(".editing-fact"); if (!editingElement) { setEditingFactId(null); } } if (editingFactTriggerId && event.target instanceof Element) { const editingElement = event.target.closest(".editing-fact-trigger"); if (!editingElement) { setEditingFactTriggerId(null); } } } document.addEventListener("mousedown", handleClickOutside); return () => { document.removeEventListener("mousedown", handleClickOutside); }; }, [editingFactId, editingFactTriggerId]); const { conversation, messages: initialMessages, facts: initialFacts, factTriggers: initialFactTriggers, } = useData(); useEffect(() => { setConversationId(conversationId); }, [conversationId, setConversationId]); useEffect(() => { if (conversation?.id && conversation?.title) { setConversationId(conversation.id); setConversationTitle(conversation.title); } }, [ conversation?.id, conversation?.title, setConversationId, setConversationTitle, ]); useEffect(() => { setMessages(initialMessages); }, [initialMessages, setMessages]); useEffect(() => { setFacts(initialFacts); }, [initialFacts, setFacts]); useEffect(() => { setFactTriggers(initialFactTriggers); }, [initialFactTriggers, setFactTriggers]); async function handleDeleteFact(factId: string) { removeFact(factId); await trpc.chat.facts.deleteOne.mutate({ factId }); } async function handleUpdateFact(factId: string, content: string) { // Update the local state first setFacts( facts.map((fact) => (fact.id === factId ? { ...fact, content } : fact)) ); // Then update the database await trpc.chat.facts.update.mutate({ factId, content }); } async function handleDeleteFactTrigger(factTriggerId: string) { removeFactTrigger(factTriggerId); await trpc.chat.factTriggers.deleteOne.mutate({ factTriggerId }); } async function handleUpdateFactTrigger( factTriggerId: string, content: string ) { // Update the local state first setFactTriggers( factTriggers.map((factTrigger) => factTrigger.id === factTriggerId ? { ...factTrigger, content } : factTrigger ) ); // Then update the database await trpc.chat.factTriggers.update.mutate({ factTriggerId, content }); } return ( <>
Conversation #{conversationId} - { setConversationTitle(e.target.value); }} onBlur={(e) => { trpc.chat.conversations.updateTitle.mutate({ id: conversationId, title: e.target.value, }); }} />
Message System Prompt Parameters Facts Fact Triggers