145 lines
5.1 KiB
JavaScript
145 lines
5.1 KiB
JavaScript
let selectedFile = null;
|
|
|
|
function handleFileSelect(e) {
|
|
const file = e.target.files[0];
|
|
if (!file) return;
|
|
|
|
if (file.size > 15 * 1024 * 1024) {
|
|
alert("Файл слишком большой. Максимальный размер: 15 МБ");
|
|
e.target.value = "";
|
|
return;
|
|
}
|
|
|
|
selectedFile = file;
|
|
const fileNameEl = document.getElementById("file-name-display");
|
|
const fileSizeEl = document.getElementById("file-size-display");
|
|
const previewContainer = document.getElementById("file-preview-container");
|
|
|
|
if (fileNameEl) fileNameEl.innerText = file.name;
|
|
if (fileSizeEl) fileSizeEl.innerText = `(${(file.size / 1024).toFixed(1)} KB)`;
|
|
if (previewContainer) previewContainer.classList.remove("hidden");
|
|
}
|
|
|
|
function clearAttachedFile() {
|
|
selectedFile = null;
|
|
const fileInput = document.getElementById("file-input");
|
|
const previewContainer = document.getElementById("file-preview-container");
|
|
if (fileInput) fileInput.value = "";
|
|
if (previewContainer) previewContainer.classList.add("hidden");
|
|
}
|
|
|
|
async function sendMessage(e) {
|
|
if (e && e.preventDefault) e.preventDefault();
|
|
|
|
const input = document.getElementById("user-input");
|
|
const chatWindow = document.getElementById("chat-window");
|
|
const sendBtn = document.getElementById("send-btn");
|
|
|
|
if (!input || !chatWindow) return;
|
|
const text = input.value.trim();
|
|
|
|
if (!text && !selectedFile) return;
|
|
|
|
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">
|
|
<i class="fa-solid fa-file"></i> ${escapeHtml(selectedFile.name)}
|
|
</div>` + userDisplayHtml;
|
|
}
|
|
|
|
const userMsgHtml = `
|
|
<div class="flex justify-end mb-3">
|
|
<div class="bg-indigo-600 text-white rounded-2xl px-4 py-2.5 max-w-2xl text-xs sm:text-sm shadow-sm">
|
|
${userDisplayHtml}
|
|
</div>
|
|
</div>
|
|
`;
|
|
chatWindow.insertAdjacentHTML("beforeend", userMsgHtml);
|
|
|
|
input.value = "";
|
|
input.style.height = "auto";
|
|
chatWindow.scrollTop = chatWindow.scrollHeight;
|
|
|
|
if (sendBtn) {
|
|
sendBtn.disabled = true;
|
|
sendBtn.classList.add("opacity-50");
|
|
}
|
|
|
|
const token = typeof API_TOKEN !== 'undefined' && API_TOKEN ? API_TOKEN : localStorage.getItem("scud_api_auth_token");
|
|
const isGuest = typeof IS_GUEST !== 'undefined' ? IS_GUEST : (localStorage.getItem("scud_is_guest") === "true");
|
|
|
|
const endpoint = isGuest ? "/api/v1/chat/guest" : "/api/v1/chat";
|
|
|
|
// Формируем единый FormData без дублирования
|
|
const formData = new FormData();
|
|
formData.append("session_id", "web_session_main");
|
|
formData.append("message", text || "Проанализируй прикрепленный файл");
|
|
|
|
if (selectedFile instanceof File) {
|
|
formData.append("file", selectedFile, selectedFile.name);
|
|
}
|
|
|
|
const headers = {};
|
|
if (!isGuest && token) {
|
|
headers["Authorization"] = "Bearer " + token;
|
|
}
|
|
|
|
try {
|
|
const res = await fetch(endpoint, {
|
|
method: "POST",
|
|
headers: headers,
|
|
body: formData
|
|
});
|
|
|
|
if (res.status === 401 && !isGuest) {
|
|
if (typeof logout === 'function') logout();
|
|
return;
|
|
}
|
|
|
|
const data = await res.json();
|
|
const assistantTitle = isGuest ? "Локальная нейросеть (Гость)" : "ИИ-Ассистент SCUD Orion AI";
|
|
const replyText = data.reply || "Пустой ответ от нейросети";
|
|
|
|
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>
|
|
</div>
|
|
`;
|
|
chatWindow.insertAdjacentHTML("beforeend", botMsgHtml);
|
|
chatWindow.scrollTop = chatWindow.scrollHeight;
|
|
|
|
clearAttachedFile();
|
|
|
|
if (!isGuest && typeof loadTasks === 'function') {
|
|
loadTasks();
|
|
}
|
|
|
|
} catch (err) {
|
|
console.error("[Chat Error]", err);
|
|
const errorHtml = `
|
|
<div class="bg-red-50 border border-red-200 rounded-2xl p-3.5 max-w-2xl text-red-700 text-xs sm:text-sm mb-3">
|
|
Ошибка связи с сервером.
|
|
</div>
|
|
`;
|
|
chatWindow.insertAdjacentHTML("beforeend", errorHtml);
|
|
chatWindow.scrollTop = chatWindow.scrollHeight;
|
|
} finally {
|
|
if (sendBtn) {
|
|
sendBtn.disabled = false;
|
|
sendBtn.classList.remove("opacity-50");
|
|
}
|
|
}
|
|
}
|
|
|
|
function escapeHtml(text) {
|
|
if (!text) return "";
|
|
return text
|
|
.replace(/&/g, "&")
|
|
.replace(/</g, "<")
|
|
.replace(/>/g, ">")
|
|
.replace(/"/g, """)
|
|
.replace(/'/g, "'");
|
|
} |