KennyOry commited on
Commit
a87f480
·
verified ·
1 Parent(s): 07f4322

Update templates/index.html

Browse files
Files changed (1) hide show
  1. templates/index.html +241 -60
templates/index.html CHANGED
@@ -71,7 +71,7 @@
71
  }
72
 
73
  .chat-container {
74
- height: calc(100vh - 200px);
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
- content = content.replace(/\*\*Проблема:\*\*/g,
726
- '<div class="problem-text">Проблема:</div>');
727
- content = content.replace(/\*\*Решение:\*\*/g,
728
- '<div class="solution-text">Решение:</div>');
729
- content = content.replace(/\*\*Примечания:\*\*/g,
730
- '<div class="notes-text">Примечания:</div>');
731
- content = content.replace(/\*\*Источники:\*\*/g,
732
- '<div class="sources-title">Источники:</div>');
733
- content = content.replace(/\*\*(.*?)\*\*/g, '<strong>$1</strong>');
734
-
735
- // Обработка ссылок на источники
736
- content = content.replace(/\[([^\]]+)\]\(([^)]+)\)/g,
737
- '<a href="$2" target="_blank" class="source-link">$1</a>');
738
-
739
- return content;
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', () => {