152 lines
6.2 KiB
JavaScript
152 lines
6.2 KiB
JavaScript
/* ai.js — AI/LLM функции: проверка, генерация, объяснение, ассистент */
|
||
|
||
function llmGeneratedWarning(lang) {
|
||
var text = 'Сделано LLM. Не доверяй, проверяй!';
|
||
switch (lang) {
|
||
case 'php':
|
||
return '// ' + text;
|
||
case 'nodejs':
|
||
case 'go':
|
||
return '// ' + text;
|
||
case 'ruby':
|
||
case 'python':
|
||
default:
|
||
return '# ' + text;
|
||
}
|
||
}
|
||
|
||
function addLLMWarning(code, lang) {
|
||
var body = String(code || '').replace(/^\s+/, '');
|
||
var warning = llmGeneratedWarning(lang);
|
||
if (!body) return warning;
|
||
if (body.indexOf(warning) === 0) return body;
|
||
if (lang === 'php' && body.indexOf('<?php') === 0) {
|
||
var rest = body.slice(5);
|
||
rest = rest.replace(/^\r?\n/, '');
|
||
return '<?php\n' + warning + '\n' + rest;
|
||
}
|
||
return warning + '\n' + body;
|
||
}
|
||
|
||
async function aiCheck(codeId, langId, resultId) {
|
||
var code = document.getElementById(codeId).value.trim();
|
||
var lang = (document.getElementById(langId) ? document.getElementById(langId).value : '') || 'python';
|
||
var resEl = document.getElementById(resultId);
|
||
if (!code) { resEl.style.display = 'block'; resEl.style.background = 'var(--bg-alt)'; resEl.textContent = 'Введите код для проверки.'; return; }
|
||
var btnId = codeId === 'c-code' ? 'c-ai-btn' : 'e-ai-btn';
|
||
var btn = document.getElementById(btnId);
|
||
btn.disabled = true;
|
||
btn.textContent = '⏳ Проверяю...';
|
||
resEl.style.display = 'block';
|
||
resEl.style.background = 'var(--bg-alt)';
|
||
resEl.style.color = 'var(--fg)';
|
||
resEl.textContent = 'Проверяю код линтером...';
|
||
try {
|
||
var data = await requestJSON(API_BASE + '/ai/check', 'POST', { language: lang, code: code });
|
||
resEl.style.background = data.ok ? '#1a3a1a' : '#3a1a1a';
|
||
resEl.style.color = data.ok ? '#8f8' : '#f88';
|
||
resEl.textContent = data.result || '(пустой ответ)';
|
||
} catch (e) {
|
||
resEl.style.background = '#3a2a00';
|
||
resEl.style.color = '#ffa';
|
||
resEl.textContent = 'Ошибка: ' + e.message;
|
||
} finally {
|
||
btn.disabled = false;
|
||
btn.textContent = '🔍 Проверить синтаксис линтером';
|
||
}
|
||
}
|
||
|
||
var _assistantOpen = true;
|
||
|
||
function toggleAssistant() {
|
||
_assistantOpen = !_assistantOpen;
|
||
document.getElementById('assistant-body').style.display = _assistantOpen ? 'flex' : 'none';
|
||
document.getElementById('assistant-toggle-icon').textContent = _assistantOpen ? '▲' : '▼';
|
||
}
|
||
|
||
async function askAssistant() {
|
||
var inp = document.getElementById('assistant-input');
|
||
var msgs = document.getElementById('assistant-messages');
|
||
var q = inp.value.trim();
|
||
if (!q) return;
|
||
inp.value = '';
|
||
msgs.textContent += '\n\n👤 ' + q + '\n⏳ ...';
|
||
msgs.scrollTop = msgs.scrollHeight;
|
||
try {
|
||
var r = await fetch('/console/api/ai/ask', {
|
||
method: 'POST',
|
||
headers: { 'Content-Type': 'application/json', ...authHeaders() },
|
||
body: JSON.stringify({ mode: 'chat', question: q })
|
||
});
|
||
var d = await r.json();
|
||
msgs.textContent = msgs.textContent.replace('⏳ ...', '🤖 ' + (d.answer || d.error || 'Нет ответа'));
|
||
} catch (e) {
|
||
msgs.textContent = msgs.textContent.replace('⏳ ...', '❌ Ошибка: ' + e.message);
|
||
}
|
||
msgs.scrollTop = msgs.scrollHeight;
|
||
}
|
||
|
||
function showGenPrompt(prefix) {
|
||
prefix = prefix || 'cc';
|
||
var el = document.getElementById(prefix + '-gen-prompt');
|
||
el.style.display = 'flex';
|
||
document.getElementById(prefix + '-gen-desc').focus();
|
||
}
|
||
|
||
async function aiGenerate(prefix) {
|
||
prefix = prefix || 'cc';
|
||
var name = (document.getElementById(prefix + '-name').value || '').trim() || 'my-func';
|
||
var lang = document.getElementById(prefix + '-lang').value || 'python';
|
||
var desc = (document.getElementById(prefix + '-gen-desc').value || '').trim();
|
||
if (!desc) { document.getElementById(prefix + '-gen-desc').focus(); return; }
|
||
var btn = document.getElementById(prefix + '-gen-btn');
|
||
var resEl = document.getElementById(prefix + '-ai-result');
|
||
btn.disabled = true; btn.textContent = '⏳ Генерирую...';
|
||
resEl.style.display = 'block'; resEl.style.background = 'var(--bg-alt)'; resEl.style.color = 'var(--fg)';
|
||
resEl.textContent = 'Запрашиваю у LLM...';
|
||
try {
|
||
var d = await requestJSON('/console/api/ai/ask', 'POST', {
|
||
mode: 'codegen',
|
||
language: lang,
|
||
name: name,
|
||
description: desc
|
||
});
|
||
var code = (d.answer || '').replace(/^```[\w]*\n?/, '').replace(/\n?```$/, '');
|
||
document.getElementById(prefix + '-code').value = addLLMWarning(code, lang);
|
||
document.getElementById(prefix + '-gen-prompt').style.display = 'none';
|
||
resEl.style.background = '#1a3a1a'; resEl.style.color = '#8f8';
|
||
resEl.textContent = 'Код сгенерирован и вставлен.';
|
||
} catch (e) {
|
||
resEl.style.background = '#3a2a00'; resEl.style.color = '#ffa';
|
||
resEl.textContent = 'Ошибка: ' + e.message;
|
||
} finally {
|
||
btn.disabled = false; btn.textContent = '✨ Сгенерировать код LLM';
|
||
}
|
||
}
|
||
|
||
async function aiExplain(codeId, langId, resultId) {
|
||
var code = (document.getElementById(codeId).value || '').trim();
|
||
var lang = (document.getElementById(langId) ? document.getElementById(langId).value : '') || 'python';
|
||
var resEl = document.getElementById(resultId);
|
||
var btnId = codeId === 'c-code' ? 'c-exp-btn' : 'e-exp-btn';
|
||
var btn = document.getElementById(btnId);
|
||
if (!code) { resEl.style.display = 'block'; resEl.style.background = 'var(--bg-alt)'; resEl.textContent = 'Введите код.'; return; }
|
||
btn.disabled = true; btn.textContent = '⏳ Объясняю...';
|
||
resEl.style.display = 'block'; resEl.style.background = 'var(--bg-alt)'; resEl.style.color = 'var(--fg)';
|
||
resEl.textContent = 'Запрашиваю у LLM...';
|
||
try {
|
||
var d = await requestJSON('/console/api/ai/ask', 'POST', {
|
||
mode: 'explain',
|
||
language: lang,
|
||
code: code
|
||
});
|
||
resEl.style.background = '#1a2a3a'; resEl.style.color = '#8cf';
|
||
resEl.textContent = d.answer || '(пустой ответ)';
|
||
} catch (e) {
|
||
resEl.style.background = '#3a2a00'; resEl.style.color = '#ffa';
|
||
resEl.textContent = 'Ошибка: ' + e.message;
|
||
} finally {
|
||
btn.disabled = false; btn.textContent = '📖 LLM: Что делает?';
|
||
}
|
||
}
|