document.addEventListener("DOMContentLoaded", () => {
let mediaRecorder, audioChunks = [], audioStream, currentChatId = null;
const recordBtn = document.getElementById("record-btn");
const stopBtn = document.getElementById("stop-btn");
const sendBtn = document.getElementById("send-btn");
const userInput = document.getElementById("user-input");
const chatBox = document.getElementById("chat-box");
const audioFileInput = document.getElementById("audio-file");
const newChatBtn = document.getElementById("new-chat-btn");
const chatList = document.getElementById("chat-list");
const currentChatTitle = document.getElementById("current-chat-title");
const fileInfo = document.getElementById("file-info");
const fileName = document.getElementById("file-name");
const clearFileBtn = document.getElementById("clear-file");
// Emotion Map (скопирован из profile.html)
const emotionMap = {
'joy': '😊 Радость',
'neutral': '😐 Нейтрально',
'anger': '😠 Злость',
'sadness': '😢 Грусть',
'surprise': '😲 Удивление'
};
// Инициализация при загрузке
initializeChats();
function initializeChats() {
const savedChatId = localStorage.getItem('currentChatId');
fetch("/get_chats")
.then(response => response.json())
.then(chats => {
renderChatList(chats);
if (savedChatId && chats.some(c => c.chat_id === savedChatId)) {
loadChat(savedChatId);
} else if (chats.length > 0) {
loadChat(chats[0].chat_id);
} else {
showEmptyChatUI();
}
})
.catch(error => {
console.error("Ошибка загрузки чатов:", error);
showEmptyChatUI();
});
}
function showEmptyChatUI() {
if (chatBox) chatBox.innerHTML = '
${chat.title}
${formatDate(chat.created_at)}
Привет! Отправьте текст или голосовое сообщение для анализа эмоций.
';
initializeChats();
localStorage.setItem('currentChatId', data.chat_id);
})
.catch(console.error);
}
function loadChat(chatId) {
fetch(`/load_chat/${chatId}`)
.then(response => response.json())
.then(data => {
if (data.error) throw new Error(data.error);
currentChatId = chatId;
currentChatTitle.textContent = data.title;
updateActiveChat(chatId);
chatBox.innerHTML = "";
data.messages.forEach(msg => {
appendMessage(msg.sender, msg.content);
});
localStorage.setItem('currentChatId', chatId);
})
.catch(error => {
console.error("Ошибка загрузки чата:", error);
appendMessage("bot", `❌ Ошибка: ${error.message}`);
});
}
function updateActiveChat(chatId) {
document.querySelectorAll(".chat-item").forEach(item => {
item.classList.toggle("active", item.dataset.chatId === chatId);
});
}
sendBtn?.addEventListener("click", sendMessage);
userInput?.addEventListener("keypress", (e) => {
if (e.key === "Enter") sendMessage();
});
async function sendMessage() {
const text = userInput?.value.trim();
if (!text || !currentChatId) return;
appendAndSaveMessage("user", text);
userInput.value = "";
try {
const response = await fetch("/analyze", {
method: "POST",
headers: { "Content-Type": "application/json" },
body: JSON.stringify({ text, chat_id: currentChatId })
});
const data = await response.json();
appendAndSaveMessage("bot", `Эмоция: ${data.emotion} (${(data.confidence * 100).toFixed(1)}%)`);
} catch (error) {
console.error("Ошибка:", error);
appendAndSaveMessage("bot", `❌ Ошибка: ${error.message}`);
}
}
// Обработчики аудио
if (audioFileInput) {
audioFileInput.addEventListener("change", handleAudioUpload);
}
if (clearFileBtn) {
clearFileBtn.addEventListener("click", clearAudioFile);
}
function handleAudioUpload() {
const file = audioFileInput?.files[0];
if (file) {
fileName.textContent = file.name;
fileInfo.style.display = 'flex';
sendAudioFile(file);
}
}
function clearAudioFile() {
audioFileInput.value = '';
fileInfo.style.display = 'none';
}
async function sendAudioFile(file) {
if (!currentChatId) return;
appendAndSaveMessage("user", "Загружен аудиофайл...");
try {
const formData = new FormData();
formData.append("audio", file);
formData.append("chat_id", currentChatId);
const response = await fetch("/analyze_audio", {
method: "POST",
body: formData
});
const data = await response.json();
if (data.transcribed_text) {
appendAndSaveMessage("user", `Распознанный текст: ${data.transcribed_text}`);
}
appendAndSaveMessage("bot", `Эмоция: ${data.emotion} (${(data.confidence * 100).toFixed(1)}%)`);
clearAudioFile();
} catch (error) {
console.error("Ошибка:", error);
appendAndSaveMessage("bot", `❌ Ошибка: ${error.message}`);
}
}
// Запись голоса
if (recordBtn) recordBtn.addEventListener("click", startRecording);
if (stopBtn) stopBtn.addEventListener("click", stopRecording);
async function startRecording() {
try {
audioStream = await navigator.mediaDevices.getUserMedia({ audio: true });
mediaRecorder = new MediaRecorder(audioStream);
audioChunks = [];
mediaRecorder.ondataavailable = e => audioChunks.push(e.data);
mediaRecorder.onstop = async () => {
const audioBlob = new Blob(audioChunks, { type: "audio/wav" });
sendAudioBlob(audioBlob);
};
mediaRecorder.start();
if (recordBtn) recordBtn.disabled = true;
if (stopBtn) stopBtn.disabled = false;
appendMessage("user", "Запись начата...");
} catch (error) {
console.error("Ошибка записи:", error);
appendMessage("bot", "❌ Не удалось получить доступ к микрофону");
}
}
function stopRecording() {
if (mediaRecorder?.state === "recording") {
mediaRecorder.stop();
if (recordBtn) recordBtn.disabled = false;
if (stopBtn) stopBtn.disabled = true;
if (audioStream) audioStream.getTracks().forEach(track => track.stop());
}
}
async function sendAudioBlob(audioBlob) {
if (!currentChatId) return;
appendAndSaveMessage("user", "Отправлено голосовое сообщение...");
try {
const formData = new FormData();
formData.append("audio", audioBlob, "recording.wav");
formData.append("chat_id", currentChatId);
const response = await fetch("/analyze_audio", {
method: "POST",
body: formData
});
const data = await response.json();
if (data.transcribed_text) {
appendAndSaveMessage("user", `Распознанный текст: ${data.transcribed_text}`);
}
appendAndSaveMessage("bot", `Эмоция: ${data.emotion} (${(data.confidence * 100).toFixed(1)}%)`);
} catch (error) {
console.error("Ошибка:", error);
appendAndSaveMessage("bot", `❌ Ошибка: ${error.message}`);
}
}
function appendMessage(sender, text) {
const message = document.createElement("div");
message.className = `message ${sender}-message`;
message.innerHTML = text;
if (chatBox) {
chatBox.appendChild(message);
chatBox.scrollTop = chatBox.scrollHeight;
}
}
function appendAndSaveMessage(sender, text) {
appendMessage(sender, text);
if (currentChatId) {
fetch("/save_message", {
method: "POST",
headers: {
"Content-Type": "application/json",
"X-CSRFToken": getCSRFToken()
},
body: JSON.stringify({
chat_id: currentChatId,
sender: sender,
content: text
})
}).catch(console.error);
}
}
// Telegram анализ
document.getElementById('telegram-upload-form')?.addEventListener('submit', async function(e) {
e.preventDefault();
const fileInput = document.getElementById('telegram-file');
const file = fileInput.files[0];
if (!file) {
alert('Пожалуйста, выберите файл');
return;
}
try {
const formData = new FormData();
formData.append('file', file);
const response = await fetch('/analyze_telegram_chat', {
method: 'POST',
body: formData
});
const result = await response.json();
if (result.error) {
throw new Error(result.error);
}
alert('Анализ завершен успешно!');
updateTelegramAnalytics(); // Обновляем графики
} catch (error) {
console.error('Ошибка загрузки файла:', error);
alert(`Ошибка: ${error.message}`);
}
});
// Функция скользящего среднего
function movingAverage(data, windowSize) {
const result = [];
for (let i = 0; i < data.length; i++) {
const start = Math.max(0, i - windowSize + 1);
const slice = data.slice(start, i + 1);
const avg = slice.reduce((sum, val) => sum + val, 0) / slice.length;
result.push(avg);
}
return result;
}
// Цвета эмоций
function getEmotionColor(emotion) {
const colors = {
'😊 Радость': '#00b894',
'😢 Грусть': '#0984e3',
'😠 Злость': '#d63031',
'😲 Удивление': '#fdcb6e',
'😨 Страх': '#a29bfe',
'😐 Нейтрально': '#636e72'
};
return colors[emotion] || '#4a4ae8';
}
// Иконки эмоций
function getEmotionIcon(emotion) {
const icons = {
'😊 Радость': 'fa-smile',
'😢 Грусть': 'fa-sad-tear',
'😠 Злость': 'fa-angry',
'😲 Удивление': 'fa-surprise',
'😨 Страх': 'fa-flushed',
'😐 Нейтрально': 'fa-meh'
};
return icons[emotion] || 'fa-comment';
}
// Основная функция анализа Telegram
// Основная функция анализа Telegram
async function updateTelegramAnalytics(range = 'month') {
try {
const response = await fetch('/get_telegram_analysis');
const analyses = await response.json();
if (!analyses || analyses.length === 0) {
document.getElementById('emotion-timeline').innerHTML =
'