feat: память сессии — контекст диалога, кнопка Сброс
This commit is contained in:
+17
-3
@@ -21,6 +21,7 @@
|
|||||||
<div id="controls">
|
<div id="controls">
|
||||||
<button id="btnRecord">🎙 Записать</button>
|
<button id="btnRecord">🎙 Записать</button>
|
||||||
<button id="btnPlay" disabled>▶ Прослушать</button>
|
<button id="btnPlay" disabled>▶ Прослушать</button>
|
||||||
|
<button id="btnReset">🗑 Сброс</button>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div id="status"></div>
|
<div id="status"></div>
|
||||||
@@ -37,7 +38,7 @@
|
|||||||
|
|
||||||
let mediaRecorder, chunks = [], userBlob = null;
|
let mediaRecorder, chunks = [], userBlob = null;
|
||||||
let isRecording = false, micAnalyser = null, micAnimId = null;
|
let isRecording = false, micAnalyser = null, micAnimId = null;
|
||||||
let audioContext = null;
|
let audioContext = null, sessionSid = null;
|
||||||
|
|
||||||
function setStatus(msg) { status.textContent = msg; }
|
function setStatus(msg) { status.textContent = msg; }
|
||||||
|
|
||||||
@@ -133,10 +134,12 @@
|
|||||||
const cRes = await fetch('/api/chat', {
|
const cRes = await fetch('/api/chat', {
|
||||||
method: 'POST',
|
method: 'POST',
|
||||||
headers: { 'Content-Type': 'application/json' },
|
headers: { 'Content-Type': 'application/json' },
|
||||||
body: JSON.stringify({ model: 'gpt-oss-120b', message: text }),
|
body: JSON.stringify({ model: 'gpt-oss-120b', message: text, sid: sessionSid }),
|
||||||
signal: (() => { const ac = new AbortController(); setTimeout(() => ac.abort(), 60000); return ac.signal; })(),
|
signal: (() => { const ac = new AbortController(); setTimeout(() => ac.abort(), 120000); return ac.signal; })(),
|
||||||
});
|
});
|
||||||
const cData = await cRes.json();
|
const cData = await cRes.json();
|
||||||
|
if (cData.sid) sessionSid = cData.sid;
|
||||||
|
const cData = await cRes.json();
|
||||||
chat.innerHTML += '<div class="bot">🤖 GPT-OSS: ' + (cData.response || cData.error || 'Ошибка') + '</div>';
|
chat.innerHTML += '<div class="bot">🤖 GPT-OSS: ' + (cData.response || cData.error || 'Ошибка') + '</div>';
|
||||||
chat.scrollTop = chat.scrollHeight;
|
chat.scrollTop = chat.scrollHeight;
|
||||||
setStatus('✅ Готово');
|
setStatus('✅ Готово');
|
||||||
@@ -149,6 +152,17 @@
|
|||||||
userBlob = null;
|
userBlob = null;
|
||||||
btnPlay.disabled = true;
|
btnPlay.disabled = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
document.getElementById('btnReset').onclick = async () => {
|
||||||
|
await fetch('/api/reset', {
|
||||||
|
method: 'POST',
|
||||||
|
headers: { 'Content-Type': 'application/json' },
|
||||||
|
body: JSON.stringify({ sid: sessionSid }),
|
||||||
|
});
|
||||||
|
sessionSid = null;
|
||||||
|
chat.innerHTML = '';
|
||||||
|
setStatus('🧹 История очищена');
|
||||||
|
};
|
||||||
</script>
|
</script>
|
||||||
</body>
|
</body>
|
||||||
</html>
|
</html>
|
||||||
@@ -40,29 +40,63 @@ app.post('/api/whisper', upload.single('audio'), async (req, res) => {
|
|||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
|
// ====== Session memory ======
|
||||||
|
const sessions = {}; // sessionId → messages[]
|
||||||
|
|
||||||
|
app.get('/api/history', (req, res) => {
|
||||||
|
const sid = req.query.sid || 'default';
|
||||||
|
res.json({ messages: sessions[sid] || [] });
|
||||||
|
});
|
||||||
|
|
||||||
app.post('/api/chat', async (req, res) => {
|
app.post('/api/chat', async (req, res) => {
|
||||||
try {
|
try {
|
||||||
const { model, message } = req.body;
|
const { model, message, sid, history } = req.body;
|
||||||
const m = MODELS[model];
|
const m = MODELS[model];
|
||||||
if (!m) return res.status(400).json({ error: 'Unknown model' });
|
if (!m) return res.status(400).json({ error: 'Неизвестная модель' });
|
||||||
|
|
||||||
|
// Собираем историю: system + предыдущие сообщения + новое
|
||||||
|
const id = sid || 'default';
|
||||||
|
const msgs = history || sessions[id] || [];
|
||||||
|
const fullMessages = [
|
||||||
|
{ role: 'system', content: m.system },
|
||||||
|
...msgs,
|
||||||
|
{ role: 'user', content: message || 'Привет' },
|
||||||
|
];
|
||||||
|
|
||||||
|
// Обрезаем чтобы не выйти за лимит токенов
|
||||||
|
while (JSON.stringify(fullMessages).length > 32000 && fullMessages.length > 2)
|
||||||
|
fullMessages.splice(1, 2);
|
||||||
|
|
||||||
const r = await fetch(`${API_BASE}/v1/chat/completions`, {
|
const r = await fetch(`${API_BASE}/v1/chat/completions`, {
|
||||||
method: 'POST',
|
method: 'POST',
|
||||||
headers: { Authorization: `Bearer ${API_KEY}`, 'Content-Type': 'application/json' },
|
headers: { Authorization: `Bearer ${API_KEY}`, 'Content-Type': 'application/json' },
|
||||||
body: JSON.stringify({
|
body: JSON.stringify({
|
||||||
model: m.id, temperature: m.temp, max_tokens: m.tokens,
|
model: m.id, temperature: m.temp, max_tokens: m.tokens,
|
||||||
messages: [
|
messages: fullMessages,
|
||||||
{ role: 'system', content: m.system },
|
|
||||||
{ role: 'user', content: message || 'Привет' },
|
|
||||||
],
|
|
||||||
}),
|
}),
|
||||||
});
|
});
|
||||||
const data = await r.json();
|
const data = await r.json();
|
||||||
res.json({ response: data.choices?.[0]?.message?.content || 'Нет ответа' });
|
const response = data.choices?.[0]?.message?.content || 'Нет ответа';
|
||||||
|
|
||||||
|
// Сохраняем историю
|
||||||
|
sessions[id] = [
|
||||||
|
...msgs,
|
||||||
|
{ role: 'user', content: message },
|
||||||
|
{ role: 'assistant', content: response },
|
||||||
|
];
|
||||||
|
|
||||||
|
res.json({ response, sid: id });
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
res.status(500).json({ error: e.message });
|
res.status(500).json({ error: e.message });
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
|
app.post('/api/reset', (req, res) => {
|
||||||
|
const sid = req.body.sid || 'default';
|
||||||
|
delete sessions[sid];
|
||||||
|
res.json({ ok: true });
|
||||||
|
});
|
||||||
|
|
||||||
app.get('/', (_req, res) => res.sendFile(path.join(__dirname, 'public', 'index.html')));
|
app.get('/', (_req, res) => res.sendFile(path.join(__dirname, 'public', 'index.html')));
|
||||||
|
|
||||||
app.listen(PORT, () => console.log(`Say:${PORT}`));
|
app.listen(PORT, () => console.log(`Say:${PORT}`));
|
||||||
Reference in New Issue
Block a user