Files
Assistant/cmd/creator-web/static/assets/chat.js
m 790fcc0cea
CI / test (push) Successful in 15s
CI / test (pull_request) Successful in 14s
DEV-000062 human intent project context
2026-08-17 14:42:24 +03:00

108 lines
3.9 KiB
JavaScript

const loginView = document.querySelector("#login-view");
const chatView = document.querySelector("#chat-view");
const loginForm = document.querySelector("#login-form");
const loginError = document.querySelector("#login-error");
const messages = document.querySelector("#messages");
const chatForm = document.querySelector("#chat-form");
const messageInput = document.querySelector("#message");
const sendButton = document.querySelector("#send");
const logoutButton = document.querySelector("#logout");
const activeFocus = document.querySelector("#active-focus");
let token = sessionStorage.getItem("domovoy.chat.token") || "";
let conversationID = sessionStorage.getItem("domovoy.chat.conversation") || "";
function showChat() {
loginView.hidden = true;
chatView.hidden = false;
if (!messages.children.length) {
appendMessage("assistant", "Я рядом. Напишите обычное сообщение, без внутренних идентификаторов.");
}
messageInput.focus();
}
function showLogin() {
chatView.hidden = true;
loginView.hidden = false;
}
function appendMessage(kind, text, meta = "") {
const node = document.createElement("div");
node.className = `message ${kind}`;
node.textContent = text;
if (meta) {
const small = document.createElement("small");
small.textContent = meta;
node.appendChild(small);
}
messages.appendChild(node);
messages.scrollTop = messages.scrollHeight;
}
function updateActiveFocus(value, provenance = "") {
if (!activeFocus) return;
activeFocus.textContent = value ? `фокус: ${value}${provenance ? ` · ${provenance}` : ""}` : "фокус: не выбран";
}
async function api(path, options = {}) {
const headers = {"Content-Type": "application/json", ...(options.headers || {})};
if (token) headers.Authorization = `Bearer ${token}`;
const response = await fetch(path, {...options, headers});
if (!response.ok) throw new Error(await response.text());
return response.json();
}
loginForm.addEventListener("submit", async (event) => {
event.preventDefault();
loginError.textContent = "";
const username = document.querySelector("#username").value;
const password = document.querySelector("#password").value;
try {
const result = await api("/api/session", {method: "POST", body: JSON.stringify({username, password})});
token = result.Token || result.token;
sessionStorage.setItem("domovoy.chat.token", token);
showChat();
} catch {
loginError.textContent = "Вход не выполнен";
}
});
chatForm.addEventListener("submit", async (event) => {
event.preventDefault();
const text = messageInput.value.trim();
if (!text) return;
appendMessage("user", text);
messageInput.value = "";
sendButton.disabled = true;
try {
const result = await api("/api/chat/messages", {method: "POST", body: JSON.stringify({conversation_id: conversationID, message: text})});
conversationID = result.conversation_id;
sessionStorage.setItem("domovoy.chat.conversation", conversationID);
updateActiveFocus(result.active_focus, result.project_provenance);
const semanticMeta = [result.speech_act, `cognition=${result.cognition}`];
if (result.clarification) semanticMeta.push(`clarification=${result.clarification}`);
appendMessage("assistant", result.reply_text || "Сообщение записано.", semanticMeta.join("; "));
} catch {
appendMessage("assistant", "Чат сейчас недоступен. Сообщение не принято runtime.");
} finally {
sendButton.disabled = false;
messageInput.focus();
}
});
logoutButton.addEventListener("click", () => {
token = "";
conversationID = "";
sessionStorage.removeItem("domovoy.chat.token");
sessionStorage.removeItem("domovoy.chat.conversation");
messages.replaceChildren();
updateActiveFocus("");
showLogin();
});
if (token) {
showChat();
} else {
showLogin();
}