import { createChat, sendUserMessage, openStream, fetchModels } from "./chatApi.svelte.js"; const STORAGE_KEY = "chatHistory"; function loadHistory() { try { return JSON.parse(localStorage.getItem(STORAGE_KEY) || "[]"); } catch { return []; } } function saveHistory(list) { localStorage.setItem(STORAGE_KEY, JSON.stringify(list)); } export const chatStore = (() => { let chatId = $state(null); let messages = $state([]); let loading = $state(false); let input = $state(""); let model = $state("qwen/qwen3-235b-a22b-2507"); // default let models = $state([]); let loadingModels = $state(true); // public helpers const history = $derived(loadHistory()); function pushHistory(id, title, msgs) { console.log(`push history: ${id} - ${title}`); const h = history.filter((c) => c.id !== id); h.unshift({ id, title, messages: msgs }); saveHistory(h.slice(0, 50)); // keep last 50 } async function selectChat(id) { if (id === chatId) return; chatId = id; const stored = loadHistory().find((c) => c.id === id); messages = stored?.messages || []; loading = true; loading = false; // Update URL with GET parameter const url = new URL(window.location.href); if (id) { url.searchParams.set('chat', id); } else { url.searchParams.delete('chat'); } window.history.replaceState({}, "", url); } async function createAndSelect() { const { id } = await createChat(model); console.log(id); selectChat(id); return id; } async function send() { if (!input.trim()) return; if (!chatId) await createAndSelect(); const userMsg = { id: crypto.randomUUID(), role: "user", text: input }; messages = [...messages, userMsg]; pushHistory(chatId, userMsg.text.slice(0, 30), messages); loading = true; const { message_id } = await sendUserMessage(chatId, input, model); input = ""; let assistantMsg = { id: message_id, role: "assistant", text: "" }; messages = [...messages, assistantMsg]; const es = openStream(chatId, message_id); es.onmessage = (e) => { assistantMsg = { ...assistantMsg, text: assistantMsg.text + e.data }; messages = [...messages.slice(0, -1), assistantMsg]; }; es.onerror = () => { es.close(); loading = false; }; es.addEventListener("done", (e) => { console.log(e); es.close(); loading = false; pushHistory(chatId, userMsg.text.slice(0, 30), messages); }); } async function loadModels() { loadingModels = true; models = await fetchModels(); loadingModels = false; // Set default model if available and not already set if (models.length > 0 && !model) { model = models[0].id || models[0]; } } function handleKey(e) { if (e.key === "Enter" && !e.shiftKey) { e.preventDefault(); send(); } } // initial route handling - use GET parameter instead of path const params = new URLSearchParams(window.location.search); const chatIdFromUrl = params.get('chat'); const storedHistory = loadHistory(); if (chatIdFromUrl && !storedHistory.find((c) => c.id === chatIdFromUrl)) { createAndSelect(); } else if (chatIdFromUrl) { selectChat(chatIdFromUrl); } // Load models on initialization loadModels(); return { get chatId() { return chatId; }, get messages() { return messages; }, get loading() { return loading; }, get input() { return input; }, set input(v) { input = v; }, get model() { return model; }, set model(v) { model = v; }, get models() { return models; }, get loadingModels() { return loadingModels; }, get history() { return loadHistory(); }, selectChat, send, handleKey, createAndSelect, loadModels, }; })();