diff --git a/www/app/(app)/transcripts/useTranscriptChat.ts b/www/app/(app)/transcripts/useTranscriptChat.ts new file mode 100644 index 00000000..5eb22ecd --- /dev/null +++ b/www/app/(app)/transcripts/useTranscriptChat.ts @@ -0,0 +1,103 @@ +"use client"; + +import { useEffect, useState, useRef } from "react"; +import { WEBSOCKET_URL } from "../../lib/apiClient"; + +export type Message = { + id: string; + role: "user" | "assistant"; + text: string; + timestamp: Date; +}; + +export type UseTranscriptChat = { + messages: Message[]; + sendMessage: (text: string) => void; + isStreaming: boolean; + currentStreamingText: string; +}; + +export const useTranscriptChat = (transcriptId: string): UseTranscriptChat => { + const [messages, setMessages] = useState([]); + const [isStreaming, setIsStreaming] = useState(false); + const [currentStreamingText, setCurrentStreamingText] = useState(""); + const wsRef = useRef(null); + const streamingTextRef = useRef(""); + const isMountedRef = useRef(true); + + useEffect(() => { + isMountedRef.current = true; + const url = `${WEBSOCKET_URL}/v1/transcripts/${transcriptId}/chat`; + const ws = new WebSocket(url); + wsRef.current = ws; + + ws.onopen = () => { + console.log("Chat WebSocket connected"); + }; + + ws.onmessage = (event) => { + if (!isMountedRef.current) return; + + const msg = JSON.parse(event.data); + + switch (msg.type) { + case "token": + setIsStreaming(true); + streamingTextRef.current += msg.text; + setCurrentStreamingText(streamingTextRef.current); + break; + + case "done": + setMessages((prev) => [ + ...prev, + { + id: Date.now().toString(), + role: "assistant", + text: streamingTextRef.current, + timestamp: new Date(), + }, + ]); + streamingTextRef.current = ""; + setCurrentStreamingText(""); + setIsStreaming(false); + break; + + case "error": + console.error("Chat error:", msg.message); + setIsStreaming(false); + break; + } + }; + + ws.onerror = (error) => { + console.error("WebSocket error:", error); + }; + + ws.onclose = () => { + console.log("Chat WebSocket closed"); + }; + + return () => { + isMountedRef.current = false; + ws.close(); + }; + }, [transcriptId]); + + const sendMessage = (text: string) => { + if (!wsRef.current) return; + + setMessages((prev) => [ + ...prev, + { + id: Date.now().toString(), + role: "user", + text, + timestamp: new Date(), + }, + ]); + + wsRef.current.send(JSON.stringify({ type: "message", text })); + }; + + return { messages, sendMessage, isStreaming, currentStreamingText }; +};