doyeqkl commited on
Commit
70eb3ca
·
verified ·
1 Parent(s): a615d4a

Create static/index.html

Browse files
Files changed (1) hide show
  1. static/index.html +146 -0
static/index.html ADDED
@@ -0,0 +1,146 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <!DOCTYPE html>
2
+ <html lang="ru">
3
+ <head>
4
+ <meta charset="UTF-8">
5
+ <meta name="viewport" content="width=device-width, initial-scale=1.0">
6
+ <title>Qwen Turbo AI</title>
7
+ <!-- Подключаем библиотеку для Markdown (жирный текст, код) -->
8
+ <script src="https://cdn.jsdelivr.net/npm/marked/marked.min.js"></script>
9
+ <style>
10
+ :root {
11
+ --bg-color: #212121;
12
+ --chat-bg: #2f2f2f;
13
+ --user-msg-bg: #303030; /* Темный */
14
+ --ai-msg-bg: #212121;
15
+ --accent: #10a37f;
16
+ --text: #ececec;
17
+ }
18
+ body { margin: 0; font-family: 'Segoe UI', Roboto, sans-serif; background: var(--bg-color); color: var(--text); display: flex; flex-direction: column; height: 100vh; }
19
+
20
+ /* Заголовок */
21
+ header { padding: 15px; background: #171717; border-bottom: 1px solid #333; display: flex; align-items: center; justify-content: space-between; }
22
+ h1 { margin: 0; font-size: 1.2rem; }
23
+
24
+ /* Чат */
25
+ #chat-container { flex: 1; overflow-y: auto; padding: 20px; display: flex; flex-direction: column; gap: 20px; scroll-behavior: smooth; }
26
+
27
+ .message { display: flex; gap: 15px; max-width: 800px; margin: 0 auto; width: 100%; }
28
+ .avatar { width: 30px; height: 30px; border-radius: 5px; display: flex; align-items: center; justify-content: center; font-weight: bold; font-size: 0.9rem; flex-shrink: 0; }
29
+ .user-avatar { background: #555; }
30
+ .ai-avatar { background: var(--accent); }
31
+
32
+ .content { line-height: 1.6; font-size: 1rem; padding-top: 4px; overflow-wrap: break-word; width: 100%; }
33
+ .content p { margin-top: 0; }
34
+ .content pre { background: #000; padding: 10px; border-radius: 5px; overflow-x: auto; }
35
+
36
+ /* Поле ввода */
37
+ #input-area { background: #171717; padding: 20px; border-top: 1px solid #333; }
38
+ .input-wrapper { max-width: 800px; margin: 0 auto; position: relative; }
39
+
40
+ textarea { width: 100%; background: #40414f; border: 1px solid #555; color: white; padding: 12px 45px 12px 15px; border-radius: 10px; resize: none; outline: none; height: 50px; font-family: inherit; font-size: 1rem; box-sizing: border-box; }
41
+ textarea:focus { border-color: var(--accent); }
42
+
43
+ button#send-btn { position: absolute; right: 10px; bottom: 10px; background: transparent; border: none; cursor: pointer; color: #ccc; }
44
+ button#send-btn:hover { color: white; }
45
+
46
+ /* Настройки (поиск) */
47
+ .controls { max-width: 800px; margin: 0 auto 10px; display: flex; gap: 15px; font-size: 0.9rem; color: #aaa; }
48
+ .checkbox-wrapper { display: flex; align-items: center; gap: 5px; cursor: pointer; }
49
+ .checkbox-wrapper input { cursor: pointer; accent-color: var(--accent); }
50
+
51
+ /* Анимация курсора */
52
+ .typing::after { content: '▋'; animation: blink 1s infinite; margin-left: 2px; }
53
+ @keyframes blink { 0%, 100% { opacity: 1; } 50% { opacity: 0; } }
54
+ </style>
55
+ </head>
56
+ <body>
57
+
58
+ <header>
59
+ <h1>🤖 Qwen Turbo AI</h1>
60
+ <div style="font-size: 0.8rem; color: #777;">Powered by HuggingFace</div>
61
+ </header>
62
+
63
+ <div id="chat-container">
64
+ <!-- Приветственное сообщение -->
65
+ <div class="message">
66
+ <div class="avatar ai-avatar">AI</div>
67
+ <div class="content">Привет! Я быстрый ИИ на базе Qwen 2.5. Могу искать информацию в интернете. Чем помочь?</div>
68
+ </div>
69
+ </div>
70
+
71
+ <div id="input-area">
72
+ <div class="controls">
73
+ <label class="checkbox-wrapper">
74
+ <input type="checkbox" id="web-search"> 🌐 Поиск в интернете (Tavily)
75
+ </label>
76
+ </div>
77
+ <div class="input-wrapper">
78
+ <textarea id="user-input" placeholder="Введите сообщение..." onkeydown="handleKey(event)"></textarea>
79
+ <button id="send-btn" onclick="sendMessage()">➤</button>
80
+ </div>
81
+ </div>
82
+
83
+ <script>
84
+ const chatContainer = document.getElementById('chat-container');
85
+ const userInput = document.getElementById('user-input');
86
+ const webSearch = document.getElementById('web-search');
87
+
88
+ let history = []; // Храним историю диалога
89
+
90
+ function handleKey(e) {
91
+ if (e.key === 'Enter' && !e.shiftKey) {
92
+ e.preventDefault();
93
+ sendMessage();
94
+ }
95
+ }
96
+
97
+ async function sendMessage() {
98
+ const text = userInput.value.trim();
99
+ if (!text) return;
100
+
101
+ // 1. Добавляем сообщение пользователя
102
+ appendMessage('user', text);
103
+ userInput.value = '';
104
+
105
+ // 2. Создаем пустой блок для ответа ИИ
106
+ const aiContentDiv = appendMessage('ai', '');
107
+ aiContentDiv.classList.add('typing'); // Курсор мигает
108
+
109
+ // Формируем историю для отправки
110
+ const messagesToSend = [...history, { role: "user", content: text }];
111
+
112
+ try {
113
+ // 3. Отправляем запрос
114
+ const response = await fetch('/v1/chat/completions', {
115
+ method: 'POST',
116
+ headers: { 'Content-Type': 'application/json' },
117
+ body: JSON.stringify({
118
+ messages: messagesToSend,
119
+ stream: true,
120
+ use_search: webSearch.checked
121
+ })
122
+ });
123
+
124
+ // 4. Читаем поток (Streaming)
125
+ const reader = response.body.getReader();
126
+ const decoder = new TextDecoder();
127
+ let fullText = "";
128
+
129
+ while (true) {
130
+ const { done, value } = await reader.read();
131
+ if (done) break;
132
+
133
+ const chunk = decoder.decode(value, { stream: true });
134
+ const lines = chunk.split('\n');
135
+
136
+ for (const line of lines) {
137
+ if (line.startsWith('data: ')) {
138
+ const jsonStr = line.slice(6);
139
+ if (jsonStr === '[DONE]') break;
140
+
141
+ try {
142
+ const json = JSON.parse(jsonStr);
143
+ const delta = json.choices[0].delta.content;
144
+ if (delta) {
145
+ fullText += delta;
146
+ // Рендерим Markdown на лету