108 lines
3.7 KiB
JavaScript
108 lines
3.7 KiB
JavaScript
import { sessionId, setSessionId, setCurrentPersona, currentPersona, dom, setRpgEnabled } from './state.js';
|
||
import { clearMessages, addMessage, initChat } from './chat.js';
|
||
import { highlightPersona, personaIndex } from './personas.js';
|
||
|
||
function escapeTitle(t) {
|
||
const d = document.createElement('div');
|
||
d.textContent = t;
|
||
return d.innerHTML;
|
||
}
|
||
|
||
export async function loadSessions() {
|
||
const res = await fetch('/sessions/');
|
||
const sessions = await res.json();
|
||
dom.sessionList.innerHTML = '';
|
||
|
||
sessions.forEach(s => {
|
||
const item = document.createElement('div');
|
||
item.className = 'session-item' + (s.session_id === sessionId ? ' active' : '');
|
||
const personaName = personaIndex.get(s.persona_id)?.name || s.persona_id || 'default';
|
||
item.innerHTML = `
|
||
<div class="s-title">${escapeTitle(s.title || 'Новый чат')}</div>
|
||
<div class="s-companion">С: ${escapeTitle(personaName)}</div>
|
||
<div class="s-meta">${s.message_count} сообщ.</div>
|
||
<button class="s-del" type="button">🗑</button>
|
||
`;
|
||
item.addEventListener('click', () => switchSession(s.session_id));
|
||
item.querySelector('.s-del').addEventListener('click', async (e) => {
|
||
e.stopPropagation();
|
||
await fetch(`/sessions/${s.session_id}`, { method: 'DELETE' });
|
||
if (s.session_id === sessionId) createNewChat();
|
||
else loadSessions();
|
||
});
|
||
dom.sessionList.appendChild(item);
|
||
});
|
||
}
|
||
|
||
export async function switchSession(id) {
|
||
setSessionId(id);
|
||
clearMessages();
|
||
await loadSessions();
|
||
await loadChatHistory(id);
|
||
}
|
||
|
||
export async function loadChatHistory(id) {
|
||
const sessionRes = await fetch(`/sessions/${id}`);
|
||
if (sessionRes.ok) {
|
||
const s = await sessionRes.json();
|
||
dom.headerTitle.textContent = s.title || 'Новый чат';
|
||
if (s.persona_id) {
|
||
setCurrentPersona(s.persona_id);
|
||
highlightPersona(s.persona_id);
|
||
}
|
||
if (dom.rpgToggle) {
|
||
const enabled = !!s.rpg_enabled;
|
||
dom.rpgToggle.checked = enabled;
|
||
setRpgEnabled(enabled);
|
||
}
|
||
}
|
||
|
||
// system blob
|
||
try {
|
||
const blobRes = await fetch(`/chat/system/${id}`);
|
||
if (blobRes.ok) {
|
||
const blob = await blobRes.json();
|
||
const parts = [];
|
||
if (blob.system_prompt) parts.push(blob.system_prompt);
|
||
if (blob.status_quo) parts.push(`--- Status quo ---\n${blob.status_quo}\n---`);
|
||
if (blob.facts_json) parts.push(`facts_json: ${blob.facts_json}`);
|
||
if (blob.plot_arc_json) parts.push(`plot_arc_json: ${blob.plot_arc_json}`);
|
||
dom.systemBlobContent.textContent = parts.filter(Boolean).join('\n\n') || '—';
|
||
}
|
||
} catch { /* ignore */ }
|
||
|
||
const histRes = await fetch(`/chat/history/${id}`);
|
||
if (!histRes.ok) return;
|
||
|
||
const messages = await histRes.json();
|
||
clearMessages();
|
||
messages.filter(m => m.role !== 'system').forEach(m => {
|
||
addMessage(
|
||
m.role === 'user' ? 'user' : 'assistant',
|
||
m.content,
|
||
m.image_prompt,
|
||
m.image_path ? `/static/${m.image_path}` : null,
|
||
);
|
||
});
|
||
}
|
||
|
||
export async function createNewChat() {
|
||
setSessionId('sess_' + Math.random().toString(36).slice(2, 10));
|
||
clearMessages();
|
||
dom.headerTitle.textContent = 'Новый чат';
|
||
highlightPersona(currentPersona);
|
||
await initChat();
|
||
loadSessions();
|
||
}
|
||
|
||
export async function initSessions() {
|
||
await loadSessions();
|
||
if (sessionId) {
|
||
const check = await fetch(`/sessions/${sessionId}`);
|
||
if (check.ok) await switchSession(sessionId);
|
||
else createNewChat();
|
||
} else {
|
||
createNewChat();
|
||
}
|
||
}
|