13.08.2026 20:25 перед внедрением коррекции поведения ИИ при использовании инструментов (создание флагов мусорных сообщений для очистки)
This commit is contained in:
+33
-8
@@ -1,4 +1,4 @@
|
||||
// Вспомогательная функция для автоматического изменения высоты текстового поля (1-3 строки)
|
||||
// Вспомогательная функция для автоматического изменения высоты текстового поля
|
||||
function updateInputHeight(el) {
|
||||
if (!el) return;
|
||||
el.style.height = "24px";
|
||||
@@ -36,6 +36,15 @@ function clearAttachedFile() {
|
||||
if (previewContainer) previewContainer.classList.add("hidden");
|
||||
}
|
||||
|
||||
// Функция симуляции отправки системной команды по кнопке
|
||||
function sendQuickAction(actionText) {
|
||||
const input = document.getElementById("user-input");
|
||||
if (input) {
|
||||
input.value = actionText;
|
||||
sendMessage();
|
||||
}
|
||||
}
|
||||
|
||||
async function sendMessage(e) {
|
||||
if (e && e.preventDefault) e.preventDefault();
|
||||
|
||||
@@ -48,6 +57,9 @@ async function sendMessage(e) {
|
||||
|
||||
if (!text && !selectedFile) return;
|
||||
|
||||
// Удаляем старые активные плашки кнопок, чтобы не висели предыдущие подтверждения
|
||||
document.querySelectorAll('.confirm-action-bar').forEach(el => el.remove());
|
||||
|
||||
let userDisplayHtml = escapeHtml(text);
|
||||
if (selectedFile) {
|
||||
userDisplayHtml = `<div class="font-bold border-b border-indigo-400/40 pb-1 mb-1 text-[11px] flex items-center gap-1.5">
|
||||
@@ -107,12 +119,32 @@ async function sendMessage(e) {
|
||||
const assistantTitle = isGuest ? "Локальная нейросеть (Гость)" : "ИИ-Ассистент SCUD Orion AI";
|
||||
const replyText = data.reply || "Пустой ответ от нейросети";
|
||||
|
||||
// Кнопки генерируем СТРОГО если бэкенд вернул флаг data.needs_confirmation === true
|
||||
let buttonsHtml = "";
|
||||
if (data.needs_confirmation === true) {
|
||||
buttonsHtml = `
|
||||
<div class="confirm-action-bar mt-3 pt-2.5 border-t border-slate-200 flex items-center justify-end gap-2">
|
||||
<button type="button" onclick="sendQuickAction('отмена')"
|
||||
class="bg-slate-100 hover:bg-slate-200 active:bg-slate-300 text-slate-700 font-semibold px-3 py-1.5 rounded-xl text-xs transition border border-slate-300 flex items-center gap-1.5 shadow-sm">
|
||||
<i class="fa-solid fa-xmark text-red-500"></i>
|
||||
<span>Отменить</span>
|
||||
</button>
|
||||
<button type="button" onclick="sendQuickAction('подтверждаю')"
|
||||
class="bg-emerald-600 hover:bg-emerald-700 active:bg-emerald-800 text-white font-semibold px-3.5 py-1.5 rounded-xl text-xs transition flex items-center gap-1.5 shadow-md">
|
||||
<i class="fa-solid fa-check"></i>
|
||||
<span>Подтвердить</span>
|
||||
</button>
|
||||
</div>
|
||||
`;
|
||||
}
|
||||
|
||||
const botMsgHtml = `
|
||||
<div class="bg-white border border-slate-200 rounded-2xl p-3.5 shadow-sm max-w-2xl mb-3">
|
||||
<p class="text-[11px] font-bold text-indigo-600 uppercase tracking-wider mb-1">
|
||||
<i class="fa-solid fa-robot mr-1"></i> ${assistantTitle}
|
||||
</p>
|
||||
<p class="text-slate-800 text-xs sm:text-sm whitespace-pre-wrap leading-relaxed">${escapeHtml(replyText)}</p>
|
||||
${buttonsHtml}
|
||||
</div>
|
||||
`;
|
||||
chatWindow.insertAdjacentHTML("beforeend", botMsgHtml);
|
||||
@@ -156,13 +188,11 @@ document.addEventListener("DOMContentLoaded", () => {
|
||||
const dropZone = document.getElementById("chat-window")?.parentElement;
|
||||
const dropOverlay = document.getElementById("drop-overlay");
|
||||
|
||||
// --- 1. УМНАЯ НАВИГАЦИЯ СТРЕЛКАМИ В МНОГОСТРОЧНОМ ТЕКСТЕ ---
|
||||
if (input) {
|
||||
let historyIndex = -1;
|
||||
let localHistory = JSON.parse(localStorage.getItem("scud_chat_input_history") || "[]");
|
||||
|
||||
input.addEventListener("keydown", (e) => {
|
||||
// Отправка по Enter без Shift
|
||||
if (e.key === "Enter" && !e.shiftKey) {
|
||||
e.preventDefault();
|
||||
const text = input.value.trim();
|
||||
@@ -179,12 +209,10 @@ document.addEventListener("DOMContentLoaded", () => {
|
||||
return;
|
||||
}
|
||||
|
||||
// Стрелка ВВЕРХ
|
||||
if (e.key === "ArrowUp") {
|
||||
const textBeforeCursor = input.value.substring(0, input.selectionStart);
|
||||
const isFirstLine = !textBeforeCursor.includes("\n");
|
||||
|
||||
// Переключаем историю ТОЛЬКО когда курсор на 1-й строке И уперся в самое начало (позиция 0)
|
||||
if (isFirstLine && input.selectionStart === 0 && localHistory.length > 0) {
|
||||
if (historyIndex < localHistory.length - 1) {
|
||||
e.preventDefault();
|
||||
@@ -199,12 +227,10 @@ document.addEventListener("DOMContentLoaded", () => {
|
||||
}
|
||||
}
|
||||
|
||||
// Стрелка ВНИЗ
|
||||
if (e.key === "ArrowDown") {
|
||||
const textAfterCursor = input.value.substring(input.selectionEnd);
|
||||
const isLastLine = !textAfterCursor.includes("\n");
|
||||
|
||||
// Переключаем историю ТОЛЬКО когда курсор на последней строке И уперся в самый конец
|
||||
if (isLastLine && input.selectionEnd === input.value.length && historyIndex >= 0) {
|
||||
e.preventDefault();
|
||||
if (historyIndex > 0) {
|
||||
@@ -221,7 +247,6 @@ document.addEventListener("DOMContentLoaded", () => {
|
||||
});
|
||||
}
|
||||
|
||||
// --- 2. ОБРАБОТКА DRAG-AND-DROP ФАЙЛОВ ---
|
||||
if (dropZone && dropOverlay) {
|
||||
["dragenter", "dragover", "dragleave", "drop"].forEach(eventName => {
|
||||
dropZone.addEventListener(eventName, (e) => {
|
||||
|
||||
Reference in New Issue
Block a user