Update templates/index.html
Browse files- templates/index.html +241 -60
templates/index.html
CHANGED
|
@@ -71,7 +71,7 @@
|
|
| 71 |
}
|
| 72 |
|
| 73 |
.chat-container {
|
| 74 |
-
height: calc(100vh -
|
| 75 |
display: flex;
|
| 76 |
flex-direction: column;
|
| 77 |
padding: 20px;
|
|
@@ -109,6 +109,16 @@
|
|
| 109 |
border-bottom-left-radius: 4px;
|
| 110 |
}
|
| 111 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 112 |
.message-header {
|
| 113 |
font-size: 12px;
|
| 114 |
opacity: 0.8;
|
|
@@ -122,6 +132,9 @@
|
|
| 122 |
padding: 20px;
|
| 123 |
border-top: 1px solid rgba(0, 0, 0, 0.05);
|
| 124 |
background: white;
|
|
|
|
|
|
|
|
|
|
| 125 |
}
|
| 126 |
|
| 127 |
.input-group {
|
|
@@ -129,6 +142,44 @@
|
|
| 129 |
gap: 10px;
|
| 130 |
}
|
| 131 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 132 |
#user-input {
|
| 133 |
flex: 1;
|
| 134 |
border: 1px solid var(--gray);
|
|
@@ -224,11 +275,16 @@
|
|
| 224 |
font-weight: 600;
|
| 225 |
color: var(--primary);
|
| 226 |
margin-bottom: 8px;
|
|
|
|
|
|
|
| 227 |
}
|
| 228 |
.solution-text {
|
| 229 |
font-weight: 600;
|
| 230 |
color: var(--secondary);
|
|
|
|
| 231 |
margin-bottom: 8px;
|
|
|
|
|
|
|
| 232 |
}
|
| 233 |
|
| 234 |
.solution-step {
|
|
@@ -245,6 +301,48 @@
|
|
| 245 |
font-weight: bold;
|
| 246 |
}
|
| 247 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 248 |
.sources-badge {
|
| 249 |
display: inline-flex;
|
| 250 |
align-items: center;
|
|
@@ -464,47 +562,6 @@
|
|
| 464 |
margin-top: 15px;
|
| 465 |
color: var(--primary);
|
| 466 |
}
|
| 467 |
-
|
| 468 |
-
/* В разделе стилей */
|
| 469 |
-
.notes-text {
|
| 470 |
-
font-weight: 600;
|
| 471 |
-
color: #f39c12; /* оранжевый для примечаний */
|
| 472 |
-
margin-top: 15px;
|
| 473 |
-
margin-bottom: 8px;
|
| 474 |
-
border-left: 3px solid #f39c12;
|
| 475 |
-
padding-left: 10px;
|
| 476 |
-
}
|
| 477 |
-
|
| 478 |
-
.sources-title {
|
| 479 |
-
font-weight: 600;
|
| 480 |
-
color: #3f37c9;
|
| 481 |
-
margin-top: 15px;
|
| 482 |
-
margin-bottom: 8px;
|
| 483 |
-
}
|
| 484 |
-
|
| 485 |
-
.note-item {
|
| 486 |
-
padding-left: 20px;
|
| 487 |
-
position: relative;
|
| 488 |
-
margin-bottom: 6px;
|
| 489 |
-
font-style: italic;
|
| 490 |
-
}
|
| 491 |
-
|
| 492 |
-
.note-item:before {
|
| 493 |
-
content: "•";
|
| 494 |
-
position: absolute;
|
| 495 |
-
left: 8px;
|
| 496 |
-
color: #f39c12;
|
| 497 |
-
}
|
| 498 |
-
|
| 499 |
-
.source-reference {
|
| 500 |
-
display: inline-block;
|
| 501 |
-
background: rgba(67, 97, 238, 0.1);
|
| 502 |
-
color: var(--primary);
|
| 503 |
-
padding: 2px 8px;
|
| 504 |
-
border-radius: 4px;
|
| 505 |
-
font-size: 0.9em;
|
| 506 |
-
margin-right: 5px;
|
| 507 |
-
}
|
| 508 |
|
| 509 |
@media (max-width: 768px) {
|
| 510 |
.app-container {
|
|
@@ -556,6 +613,14 @@
|
|
| 556 |
<i class="fas fa-paper-plane"></i>
|
| 557 |
</button>
|
| 558 |
</div>
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 559 |
</div>
|
| 560 |
</div>
|
| 561 |
</div>
|
|
@@ -580,6 +645,8 @@
|
|
| 580 |
const chatContainer = document.getElementById('chat-container');
|
| 581 |
const userInput = document.getElementById('user-input');
|
| 582 |
const sendBtn = document.getElementById('send-btn');
|
|
|
|
|
|
|
| 583 |
const logsContainer = document.getElementById('logs-container');
|
| 584 |
const statusIndicator = document.getElementById('status-indicator');
|
| 585 |
const statusDot = statusIndicator.querySelector('.status-dot');
|
|
@@ -592,6 +659,7 @@
|
|
| 592 |
let currentBotMessage = null;
|
| 593 |
let processingLog = [];
|
| 594 |
let responseBuffer = '';
|
|
|
|
| 595 |
|
| 596 |
// Функция добавления временной метки
|
| 597 |
function getTimestamp() {
|
|
@@ -630,6 +698,27 @@
|
|
| 630 |
`;
|
| 631 |
chatContainer.appendChild(messageDiv);
|
| 632 |
chatContainer.scrollTop = chatContainer.scrollHeight;
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 633 |
}
|
| 634 |
|
| 635 |
// Создание сообщения бота с индикатором набора
|
|
@@ -721,24 +810,31 @@
|
|
| 721 |
|
| 722 |
// Форматирование контента
|
| 723 |
function formatContent(content) {
|
| 724 |
-
|
| 725 |
-
|
| 726 |
-
|
| 727 |
-
|
| 728 |
-
|
| 729 |
-
|
| 730 |
-
|
| 731 |
-
|
| 732 |
-
|
| 733 |
-
|
| 734 |
-
|
| 735 |
-
|
| 736 |
-
|
| 737 |
-
|
| 738 |
-
|
| 739 |
-
|
| 740 |
-
|
| 741 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 742 |
|
| 743 |
// Добавление ссылок на источники
|
| 744 |
function addSourceLinks() {
|
|
@@ -852,6 +948,9 @@
|
|
| 852 |
if (type === 'log' || type === 'processing_log') {
|
| 853 |
addLog(content, 'info');
|
| 854 |
}
|
|
|
|
|
|
|
|
|
|
| 855 |
else if (type === 'response_start') {
|
| 856 |
// Начало ответа - создаем индикатор набора
|
| 857 |
createBotThinkingMessage();
|
|
@@ -981,11 +1080,93 @@
|
|
| 981 |
});
|
| 982 |
}
|
| 983 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 984 |
// Обработчики событий
|
| 985 |
sendBtn.addEventListener('click', sendMessage);
|
| 986 |
userInput.addEventListener('keypress', (e) => {
|
| 987 |
if (e.key === 'Enter') sendMessage();
|
| 988 |
});
|
|
|
|
|
|
|
| 989 |
|
| 990 |
// Закрытие соединений при уходе со страницы
|
| 991 |
window.addEventListener('beforeunload', () => {
|
|
|
|
| 71 |
}
|
| 72 |
|
| 73 |
.chat-container {
|
| 74 |
+
height: calc(100vh - 240px);
|
| 75 |
display: flex;
|
| 76 |
flex-direction: column;
|
| 77 |
padding: 20px;
|
|
|
|
| 109 |
border-bottom-left-radius: 4px;
|
| 110 |
}
|
| 111 |
|
| 112 |
+
.status-message {
|
| 113 |
+
background: rgba(243, 156, 18, 0.1);
|
| 114 |
+
border-left: 3px solid var(--warning);
|
| 115 |
+
align-self: center;
|
| 116 |
+
max-width: 90%;
|
| 117 |
+
text-align: center;
|
| 118 |
+
padding: 12px 20px;
|
| 119 |
+
margin: 10px 0;
|
| 120 |
+
}
|
| 121 |
+
|
| 122 |
.message-header {
|
| 123 |
font-size: 12px;
|
| 124 |
opacity: 0.8;
|
|
|
|
| 132 |
padding: 20px;
|
| 133 |
border-top: 1px solid rgba(0, 0, 0, 0.05);
|
| 134 |
background: white;
|
| 135 |
+
display: flex;
|
| 136 |
+
flex-direction: column;
|
| 137 |
+
gap: 15px;
|
| 138 |
}
|
| 139 |
|
| 140 |
.input-group {
|
|
|
|
| 142 |
gap: 10px;
|
| 143 |
}
|
| 144 |
|
| 145 |
+
.action-buttons {
|
| 146 |
+
display: flex;
|
| 147 |
+
gap: 10px;
|
| 148 |
+
justify-content: flex-end;
|
| 149 |
+
}
|
| 150 |
+
|
| 151 |
+
.action-btn {
|
| 152 |
+
padding: 8px 15px;
|
| 153 |
+
border-radius: 8px;
|
| 154 |
+
font-size: 14px;
|
| 155 |
+
display: flex;
|
| 156 |
+
align-items: center;
|
| 157 |
+
gap: 5px;
|
| 158 |
+
transition: var(--transition);
|
| 159 |
+
}
|
| 160 |
+
|
| 161 |
+
.action-btn:hover {
|
| 162 |
+
transform: translateY(-2px);
|
| 163 |
+
}
|
| 164 |
+
|
| 165 |
+
.btn-repeat {
|
| 166 |
+
background: rgba(67, 97, 238, 0.1);
|
| 167 |
+
color: var(--primary);
|
| 168 |
+
}
|
| 169 |
+
|
| 170 |
+
.btn-repeat:hover {
|
| 171 |
+
background: rgba(67, 97, 238, 0.15);
|
| 172 |
+
}
|
| 173 |
+
|
| 174 |
+
.btn-new {
|
| 175 |
+
background: rgba(231, 76, 60, 0.1);
|
| 176 |
+
color: var(--danger);
|
| 177 |
+
}
|
| 178 |
+
|
| 179 |
+
.btn-new:hover {
|
| 180 |
+
background: rgba(231, 76, 60, 0.15);
|
| 181 |
+
}
|
| 182 |
+
|
| 183 |
#user-input {
|
| 184 |
flex: 1;
|
| 185 |
border: 1px solid var(--gray);
|
|
|
|
| 275 |
font-weight: 600;
|
| 276 |
color: var(--primary);
|
| 277 |
margin-bottom: 8px;
|
| 278 |
+
border-left: 3px solid var(--primary);
|
| 279 |
+
padding-left: 10px;
|
| 280 |
}
|
| 281 |
.solution-text {
|
| 282 |
font-weight: 600;
|
| 283 |
color: var(--secondary);
|
| 284 |
+
margin-top: 15px;
|
| 285 |
margin-bottom: 8px;
|
| 286 |
+
border-left: 3px solid var(--secondary);
|
| 287 |
+
padding-left: 10px;
|
| 288 |
}
|
| 289 |
|
| 290 |
.solution-step {
|
|
|
|
| 301 |
font-weight: bold;
|
| 302 |
}
|
| 303 |
|
| 304 |
+
.notes-text {
|
| 305 |
+
font-weight: 600;
|
| 306 |
+
color: #f39c12;
|
| 307 |
+
margin-top: 15px;
|
| 308 |
+
margin-bottom: 8px;
|
| 309 |
+
border-left: 3px solid #f39c12;
|
| 310 |
+
padding-left: 10px;
|
| 311 |
+
}
|
| 312 |
+
|
| 313 |
+
.sources-title {
|
| 314 |
+
font-weight: 600;
|
| 315 |
+
color: #3f37c9;
|
| 316 |
+
margin-top: 15px;
|
| 317 |
+
margin-bottom: 8px;
|
| 318 |
+
border-left: 3px solid #3f37c9;
|
| 319 |
+
padding-left: 10px;
|
| 320 |
+
}
|
| 321 |
+
|
| 322 |
+
.note-item {
|
| 323 |
+
padding-left: 20px;
|
| 324 |
+
position: relative;
|
| 325 |
+
margin-bottom: 6px;
|
| 326 |
+
font-style: italic;
|
| 327 |
+
}
|
| 328 |
+
|
| 329 |
+
.note-item:before {
|
| 330 |
+
content: "•";
|
| 331 |
+
position: absolute;
|
| 332 |
+
left: 8px;
|
| 333 |
+
color: #f39c12;
|
| 334 |
+
}
|
| 335 |
+
|
| 336 |
+
.source-reference {
|
| 337 |
+
display: inline-block;
|
| 338 |
+
background: rgba(67, 97, 238, 0.1);
|
| 339 |
+
color: var(--primary);
|
| 340 |
+
padding: 2px 8px;
|
| 341 |
+
border-radius: 4px;
|
| 342 |
+
font-size: 0.9em;
|
| 343 |
+
margin-right: 5px;
|
| 344 |
+
}
|
| 345 |
+
|
| 346 |
.sources-badge {
|
| 347 |
display: inline-flex;
|
| 348 |
align-items: center;
|
|
|
|
| 562 |
margin-top: 15px;
|
| 563 |
color: var(--primary);
|
| 564 |
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 565 |
|
| 566 |
@media (max-width: 768px) {
|
| 567 |
.app-container {
|
|
|
|
| 613 |
<i class="fas fa-paper-plane"></i>
|
| 614 |
</button>
|
| 615 |
</div>
|
| 616 |
+
<div class="action-buttons">
|
| 617 |
+
<button id="repeat-btn" class="action-btn btn-repeat">
|
| 618 |
+
<i class="fas fa-redo"></i> Повторить ответ
|
| 619 |
+
</button>
|
| 620 |
+
<button id="new-chat-btn" class="action-btn btn-new">
|
| 621 |
+
<i class="fas fa-plus"></i> Новый диалог
|
| 622 |
+
</button>
|
| 623 |
+
</div>
|
| 624 |
</div>
|
| 625 |
</div>
|
| 626 |
</div>
|
|
|
|
| 645 |
const chatContainer = document.getElementById('chat-container');
|
| 646 |
const userInput = document.getElementById('user-input');
|
| 647 |
const sendBtn = document.getElementById('send-btn');
|
| 648 |
+
const repeatBtn = document.getElementById('repeat-btn');
|
| 649 |
+
const newChatBtn = document.getElementById('new-chat-btn');
|
| 650 |
const logsContainer = document.getElementById('logs-container');
|
| 651 |
const statusIndicator = document.getElementById('status-indicator');
|
| 652 |
const statusDot = statusIndicator.querySelector('.status-dot');
|
|
|
|
| 659 |
let currentBotMessage = null;
|
| 660 |
let processingLog = [];
|
| 661 |
let responseBuffer = '';
|
| 662 |
+
let lastUserMessage = '';
|
| 663 |
|
| 664 |
// Функция добавления временной метки
|
| 665 |
function getTimestamp() {
|
|
|
|
| 698 |
`;
|
| 699 |
chatContainer.appendChild(messageDiv);
|
| 700 |
chatContainer.scrollTop = chatContainer.scrollHeight;
|
| 701 |
+
lastUserMessage = message;
|
| 702 |
+
}
|
| 703 |
+
|
| 704 |
+
// Добавление статусного сообщения
|
| 705 |
+
function addStatusMessage(message) {
|
| 706 |
+
if (welcomeState && welcomeState.parentElement === chatContainer) {
|
| 707 |
+
chatContainer.innerHTML = '';
|
| 708 |
+
}
|
| 709 |
+
|
| 710 |
+
const messageDiv = document.createElement('div');
|
| 711 |
+
messageDiv.className = 'message status-message';
|
| 712 |
+
messageDiv.innerHTML = `
|
| 713 |
+
<div class="typing-indicator">
|
| 714 |
+
<div class="typing-dot"></div>
|
| 715 |
+
<div class="typing-dot"></div>
|
| 716 |
+
<div class="typing-dot"></div>
|
| 717 |
+
<span class="typing-text">${escapeHtml(message)}</span>
|
| 718 |
+
</div>
|
| 719 |
+
`;
|
| 720 |
+
chatContainer.appendChild(messageDiv);
|
| 721 |
+
chatContainer.scrollTop = chatContainer.scrollHeight;
|
| 722 |
}
|
| 723 |
|
| 724 |
// Создание сообщения бота с индикатором набора
|
|
|
|
| 810 |
|
| 811 |
// Форматирование контента
|
| 812 |
function formatContent(content) {
|
| 813 |
+
// Заменяем разделы на стилизованные блоки
|
| 814 |
+
content = content.replace(/\*\*Проблема:\*\*/g,
|
| 815 |
+
'<div class="problem-text">Проблема:</div>');
|
| 816 |
+
content = content.replace(/\*\*Решение:\*\*/g,
|
| 817 |
+
'<div class="solution-text">Решение:</div>');
|
| 818 |
+
content = content.replace(/\*\*Примечания:\*\*/g,
|
| 819 |
+
'<div class="notes-text">Примечания:</div>');
|
| 820 |
+
content = content.replace(/\*\*Источники информации:\*\*/g,
|
| 821 |
+
'<div class="sources-title">Источники информации:</div>');
|
| 822 |
+
content = content.replace(/\*\*(.*?)\*\*/g, '<strong>$1</strong>');
|
| 823 |
+
|
| 824 |
+
// Обработка шагов решения
|
| 825 |
+
content = content.replace(/(\d+)\.\s+(.*?)(?=\n\d+\.|\n\*\*|$)/gs,
|
| 826 |
+
'<div class="solution-step">$1. $2</div>');
|
| 827 |
+
|
| 828 |
+
// Обработка примечаний
|
| 829 |
+
content = content.replace(/-\s+(.*?)(?=\n-|\n\*\*|$)/gs,
|
| 830 |
+
'<div class="note-item">$1</div>');
|
| 831 |
+
|
| 832 |
+
// Обработка ссылок на источники
|
| 833 |
+
content = content.replace(/\[([^\]]+)\]\(([^)]+)\)/g,
|
| 834 |
+
'<a href="$2" target="_blank" class="source-link">$1</a>');
|
| 835 |
+
|
| 836 |
+
return content;
|
| 837 |
+
}
|
| 838 |
|
| 839 |
// Добавление ссылок на источники
|
| 840 |
function addSourceLinks() {
|
|
|
|
| 948 |
if (type === 'log' || type === 'processing_log') {
|
| 949 |
addLog(content, 'info');
|
| 950 |
}
|
| 951 |
+
else if (type === 'status') {
|
| 952 |
+
addStatusMessage(content);
|
| 953 |
+
}
|
| 954 |
else if (type === 'response_start') {
|
| 955 |
// Начало ответа - создаем индикатор набора
|
| 956 |
createBotThinkingMessage();
|
|
|
|
| 1080 |
});
|
| 1081 |
}
|
| 1082 |
|
| 1083 |
+
// Повтор последнего ответа
|
| 1084 |
+
function repeatLastResponse() {
|
| 1085 |
+
if (isProcessing) return;
|
| 1086 |
+
|
| 1087 |
+
if (lastUserMessage) {
|
| 1088 |
+
// Добавляем сообщение пользователя
|
| 1089 |
+
addUserMessage(lastUserMessage);
|
| 1090 |
+
|
| 1091 |
+
// Обновляем статус
|
| 1092 |
+
isProcessing = true;
|
| 1093 |
+
statusText.textContent = 'Обработка запроса...';
|
| 1094 |
+
statusDot.style.background = 'var(--warning)';
|
| 1095 |
+
statusIndicator.classList.add('warning');
|
| 1096 |
+
statusIndicator.classList.remove('success');
|
| 1097 |
+
|
| 1098 |
+
// Очищаем предыдущие данные
|
| 1099 |
+
currentSources = [];
|
| 1100 |
+
processingLog = [];
|
| 1101 |
+
responseBuffer = '';
|
| 1102 |
+
currentBotMessage = null;
|
| 1103 |
+
|
| 1104 |
+
// Подключаемся к потоку данных
|
| 1105 |
+
connectStream();
|
| 1106 |
+
|
| 1107 |
+
// Отправляем запрос на сервер
|
| 1108 |
+
fetch('/repeat', {
|
| 1109 |
+
method: 'POST'
|
| 1110 |
+
})
|
| 1111 |
+
.then(res => res.json())
|
| 1112 |
+
.then(data => {
|
| 1113 |
+
if (data.status === 'repeating') {
|
| 1114 |
+
addLog("🔄 Повторяю последний ответ...", 'info');
|
| 1115 |
+
}
|
| 1116 |
+
})
|
| 1117 |
+
.catch(err => {
|
| 1118 |
+
addLog(`❌ Ошибка повторения: ${err.message}`, 'error');
|
| 1119 |
+
isProcessing = false;
|
| 1120 |
+
statusText.textContent = 'Ошибка соединения';
|
| 1121 |
+
statusDot.style.background = 'var(--danger)';
|
| 1122 |
+
statusIndicator.classList.add('danger');
|
| 1123 |
+
statusIndicator.classList.remove('warning');
|
| 1124 |
+
|
| 1125 |
+
setTimeout(() => {
|
| 1126 |
+
statusText.textContent = 'Подключено';
|
| 1127 |
+
statusDot.style.background = 'var(--success)';
|
| 1128 |
+
statusIndicator.classList.add('success');
|
| 1129 |
+
statusIndicator.classList.remove('danger');
|
| 1130 |
+
}, 2000);
|
| 1131 |
+
});
|
| 1132 |
+
}
|
| 1133 |
+
}
|
| 1134 |
+
|
| 1135 |
+
// Начать новый диалог
|
| 1136 |
+
function startNewChat() {
|
| 1137 |
+
if (isProcessing) return;
|
| 1138 |
+
|
| 1139 |
+
fetch('/new_session', {
|
| 1140 |
+
method: 'POST'
|
| 1141 |
+
})
|
| 1142 |
+
.then(res => res.json())
|
| 1143 |
+
.then(data => {
|
| 1144 |
+
if (data.status === 'new_session') {
|
| 1145 |
+
// Очищаем чат
|
| 1146 |
+
chatContainer.innerHTML = '';
|
| 1147 |
+
const welcomeClone = welcomeState.cloneNode(true);
|
| 1148 |
+
chatContainer.appendChild(welcomeClone);
|
| 1149 |
+
|
| 1150 |
+
// Сбрасываем состояние
|
| 1151 |
+
currentSources = [];
|
| 1152 |
+
lastUserMessage = '';
|
| 1153 |
+
currentBotMessage = null;
|
| 1154 |
+
|
| 1155 |
+
addLog("🆕 Начат новый диалог", 'info');
|
| 1156 |
+
}
|
| 1157 |
+
})
|
| 1158 |
+
.catch(err => {
|
| 1159 |
+
addLog(`❌ Ошибка создания нового диалога: ${err.message}`, 'error');
|
| 1160 |
+
});
|
| 1161 |
+
}
|
| 1162 |
+
|
| 1163 |
// Обработчики событий
|
| 1164 |
sendBtn.addEventListener('click', sendMessage);
|
| 1165 |
userInput.addEventListener('keypress', (e) => {
|
| 1166 |
if (e.key === 'Enter') sendMessage();
|
| 1167 |
});
|
| 1168 |
+
repeatBtn.addEventListener('click', repeatLastResponse);
|
| 1169 |
+
newChatBtn.addEventListener('click', startNewChat);
|
| 1170 |
|
| 1171 |
// Закрытие соединений при уходе со страницы
|
| 1172 |
window.addEventListener('beforeunload', () => {
|