import { currentPersona, setCurrentPersona, sessionId } from './state.js'; import { initChat } from './chat.js'; export function highlightPersona(personaId) { document.querySelectorAll('.persona-card').forEach(c => { c.classList.toggle('active', c.dataset.id === personaId); }); } export async function loadPersonas() { const res = await fetch('/personas/'); const personas = await res.json(); const bar = document.getElementById('personaBar'); bar.innerHTML = ''; personas.forEach(p => { const card = document.createElement('div'); card.className = 'persona-card' + (p.persona_id === currentPersona ? ' active' : ''); card.dataset.id = p.persona_id; const isCard = p.persona_id.startsWith('card_'); card.innerHTML = ` ${p.emoji} ${p.name} ${p.custom ? `` : ''} ${isCard ? `` : ''} `; card.addEventListener('click', () => selectPersona(p.persona_id)); card.querySelector('.del-btn')?.addEventListener('click', async (e) => { e.stopPropagation(); await fetch(`/personas/${p.persona_id}`, { method: 'DELETE' }); if (currentPersona === p.persona_id) await selectPersona('default'); loadPersonas(); }); card.querySelector('.edit-btn')?.addEventListener('click', async (e) => { e.stopPropagation(); const cardId = p.persona_id.slice(5); const r = await fetch(`/characters/${cardId}`); const data = await r.json(); document.getElementById('editCardId').value = cardId; document.getElementById('editName').value = data.name || ''; document.getElementById('editDescription').value = data.description || ''; document.getElementById('editPersonality').value = data.personality || ''; document.getElementById('editScenario').value = data.scenario || ''; document.getElementById('editFirstMes').value = data.first_mes || ''; document.getElementById('editMesExample').value = data.mes_example || ''; document.getElementById('editAppearance').value = data.appearance_tags || ''; document.getElementById('editLora').value = data.lora_name || ''; document.getElementById('editLoraWeight').value = data.lora_weight ?? 0.8; document.getElementById('cardEditOverlay').classList.add('open'); }); bar.appendChild(card); }); const addBtn = document.createElement('button'); addBtn.type = 'button'; addBtn.className = 'persona-add'; addBtn.innerHTML = '➕Создать'; addBtn.addEventListener('click', () => document.getElementById('modalOverlay').classList.add('open')); bar.appendChild(addBtn); const importBtn = document.createElement('button'); importBtn.type = 'button'; importBtn.className = 'card-import-btn'; importBtn.innerHTML = '📥Chub'; importBtn.addEventListener('click', () => document.getElementById('cardModalOverlay').classList.add('open')); bar.appendChild(importBtn); } export async function selectPersona(personaId) { setCurrentPersona(personaId); highlightPersona(personaId); if (sessionId) { await fetch(`/sessions/${sessionId}`, { method: 'PATCH', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify({ persona_id: personaId }), }); await initChat(); } } export function initPersonaModals() { document.getElementById('modalCancel').addEventListener('click', () => { document.getElementById('modalOverlay').classList.remove('open'); }); document.getElementById('cardModalCancel').addEventListener('click', () => { document.getElementById('cardModalOverlay').classList.remove('open'); }); document.getElementById('cardEditCancel').addEventListener('click', () => { document.getElementById('cardEditOverlay').classList.remove('open'); }); document.getElementById('modalSave').addEventListener('click', async () => { const data = { persona_id: document.getElementById('pId').value.trim(), name: document.getElementById('pName').value.trim(), emoji: document.getElementById('pEmoji').value.trim() || '🤖', description: document.getElementById('pDesc').value.trim(), prompt: document.getElementById('pPrompt').value.trim(), sd_enabled: document.getElementById('pSdEnabled').checked, lora_name: document.getElementById('pLora').value.trim(), appearance_tags: document.getElementById('pAppearance').value.trim(), }; if (!data.persona_id || !data.name || !data.prompt) { alert('Заполни ID, имя и промт'); return; } await fetch('/personas/', { method: 'POST', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify(data), }); document.getElementById('modalOverlay').classList.remove('open'); await loadPersonas(); await selectPersona(data.persona_id); }); document.getElementById('cardEditSave').addEventListener('click', async () => { const cardId = document.getElementById('editCardId').value; const body = { name: document.getElementById('editName').value.trim() || undefined, description: document.getElementById('editDescription').value.trim() || undefined, personality: document.getElementById('editPersonality').value.trim() || undefined, scenario: document.getElementById('editScenario').value.trim() || undefined, first_mes: document.getElementById('editFirstMes').value.trim() || undefined, mes_example: document.getElementById('editMesExample').value.trim() || undefined, appearance_tags: document.getElementById('editAppearance').value.trim() || undefined, lora_name: document.getElementById('editLora').value.trim() || undefined, lora_weight: parseFloat(document.getElementById('editLoraWeight').value) || undefined, }; const res = await fetch(`/characters/${cardId}`, { method: 'PATCH', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify(body), }); if (!res.ok) { alert('Ошибка сохранения'); return; } document.getElementById('cardEditOverlay').classList.remove('open'); await loadPersonas(); }); document.getElementById('cardModalImport').addEventListener('click', async () => { const fileInput = document.getElementById('cardFile'); if (!fileInput.files?.length) { alert('Выберите файл карточки (JSON или PNG)'); return; } const form = new FormData(); form.append('file', fileInput.files[0]); form.append('lora_name', document.getElementById('cardLora').value.trim()); form.append('lora_weight', document.getElementById('cardLoraWeight').value || '0.8'); const res = await fetch('/characters/import', { method: 'POST', body: form }); const data = await res.json(); if (!res.ok) { alert(data.detail || 'Ошибка импорта'); return; } document.getElementById('cardModalOverlay').classList.remove('open'); fileInput.value = ''; await loadPersonas(); await selectPersona(data.persona_id); }); }