jurmy24's picture
feat: add viewer code
72f0edb
raw
history blame
3.36 kB
import { useState, useCallback, useEffect } from "react";
import { useMutation } from "@tanstack/react-query";
import { v4 as uuidv4 } from "uuid";
// Generate a conversation ID to help backend keep track of the chat history
const getConversationId = () => {
const storedId = localStorage.getItem("chat_conversation_id");
if (storedId) return storedId;
const newId = uuidv4();
localStorage.setItem("chat_conversation_id", newId);
return newId;
};
export interface ChatMessage {
sender: string;
text: string;
imageUrl?: string;
}
export const useChatApi = () => {
const [conversationId] = useState(getConversationId);
const [isStreaming, setIsStreaming] = useState(false);
// Use mutation for the API call
const chatMutation = useMutation({
mutationFn: async (prompt: string) => {
const controller = new AbortController();
const signal = controller.signal;
const response = await fetch("http://127.0.0.1:8000/prompt", {
method: "POST",
headers: {
"Content-Type": "application/json",
},
body: JSON.stringify({
session_id: conversationId,
prompt: prompt,
}),
signal,
});
if (!response.ok) {
throw new Error("Network response was not ok");
}
return { response, controller };
},
});
// Process the streaming response
const streamResponse = useCallback(
async (
response: Response,
onChunk: (chunk: string) => void,
onImage?: (imageUrl: string) => void
) => {
if (!response.body) {
throw new Error("Response body is null");
}
setIsStreaming(true);
const reader = response.body.getReader();
const decoder = new TextDecoder();
let buffer = "";
try {
while (true) {
const { done, value } = await reader.read();
if (done) {
break;
}
// Decode the chunk
const text = decoder.decode(value, { stream: true });
buffer += text;
// Process SSE format: "data: {json}\n\n"
const lines = buffer.split("\n\n");
buffer = lines.pop() || "";
for (const line of lines) {
if (line.startsWith("data: ")) {
const jsonStr = line.slice(6);
try {
const data = JSON.parse(jsonStr);
// Check if there's text content
if (data.text) {
onChunk(data.text);
}
// Check if there's an image URL
if (data.image_url) {
onImage?.(data.image_url);
}
} catch (e) {
console.error("Error parsing SSE JSON:", e);
}
}
}
}
} catch (error) {
console.error("Error reading stream:", error);
} finally {
setIsStreaming(false);
}
},
[]
);
// Cleanup function to abort any pending requests
useEffect(() => {
return () => {
if (chatMutation.data?.controller) {
chatMutation.data.controller.abort();
}
};
}, [chatMutation.data]);
return {
sendMessage: chatMutation.mutate,
streamResponse,
isLoading: chatMutation.isPending || isStreaming,
error: chatMutation.error,
};
};