86 lines
2.1 KiB
JavaScript
86 lines
2.1 KiB
JavaScript
|
|
// Pure vanilla JS – no Svelte imports
|
|||
|
|
const BASE = import.meta.env.VITE_API_URL ?? 'http://localhost:8000';
|
|||
|
|
|
|||
|
|
export const chatStore = (() => {
|
|||
|
|
let chatId = $state(null); // null until first message
|
|||
|
|
let messages = $state([]);
|
|||
|
|
let input = $state('');
|
|||
|
|
let loading = $state(false);
|
|||
|
|
|
|||
|
|
/* ── helpers ── */
|
|||
|
|
async function createChat() {
|
|||
|
|
const res = await fetch(`${BASE}/chats`, { method: 'POST' });
|
|||
|
|
const { id } = await res.json();
|
|||
|
|
return id;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
async function sendUserMessage(text) {
|
|||
|
|
await fetch(`${BASE}/chats/${chatId}/messages`, {
|
|||
|
|
method: 'POST',
|
|||
|
|
headers: { 'Content-Type': 'application/json' },
|
|||
|
|
body: JSON.stringify({ message: text })
|
|||
|
|
});
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
function streamAssistantReply() {
|
|||
|
|
const source = new EventSource(`${BASE}/chats/${chatId}/stream`);
|
|||
|
|
let botMsg = { id: Date.now(), text: '', me: false, sender: 'bot' };
|
|||
|
|
messages = [...messages, botMsg];
|
|||
|
|
|
|||
|
|
source.onmessage = (ev) => {
|
|||
|
|
console.log(ev.data);
|
|||
|
|
if (ev.data === '[DONE]') {
|
|||
|
|
source.close();
|
|||
|
|
loading = false;
|
|||
|
|
return;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
messages = messages.map((m, i) =>
|
|||
|
|
i === messages.length - 1 ? { ...m, text: m.text + ev.data } : m
|
|||
|
|
);
|
|||
|
|
};
|
|||
|
|
|
|||
|
|
source.onerror = () => {
|
|||
|
|
source.close();
|
|||
|
|
loading = false;
|
|||
|
|
};
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
async function send() {
|
|||
|
|
const text = input.trim();
|
|||
|
|
if (!text || loading) return;
|
|||
|
|
|
|||
|
|
// add user bubble immediately
|
|||
|
|
messages = [...messages, { id: Date.now(), text, me: true, sender: 'user' }];
|
|||
|
|
input = '';
|
|||
|
|
loading = true;
|
|||
|
|
|
|||
|
|
try {
|
|||
|
|
if (!chatId) chatId = await createChat();
|
|||
|
|
await sendUserMessage(text);
|
|||
|
|
streamAssistantReply();
|
|||
|
|
} catch {
|
|||
|
|
messages = [
|
|||
|
|
...messages,
|
|||
|
|
{ id: Date.now(), text: 'Sorry, something went wrong.', me: false, sender: 'bot' }
|
|||
|
|
];
|
|||
|
|
loading = false;
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
function handleKey(e) {
|
|||
|
|
if (e.key === 'Enter' && !e.shiftKey) {
|
|||
|
|
e.preventDefault();
|
|||
|
|
send();
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
return {
|
|||
|
|
get messages() { return messages; },
|
|||
|
|
get input() { return input; },
|
|||
|
|
set input(v) { input = v; },
|
|||
|
|
get loading() { return loading; },
|
|||
|
|
send,
|
|||
|
|
handleKey
|
|||
|
|
};
|
|||
|
|
})();
|