anatoli72 commited on
Commit
ee03e2f
·
verified ·
1 Parent(s): 0345d90

Create static/index.html

Browse files
Files changed (1) hide show
  1. static/index.html +143 -0
static/index.html ADDED
@@ -0,0 +1,143 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
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>🤖 Puter AI Chat</title>
7
+ <style>
8
+ :root { --bg: #0f172a; --card: #1e293b; --text: #e2e8f0; --accent: #3b82f6; --user: #2563eb; --ai: #334155; }
9
+ body { margin: 0; font-family: system-ui, -apple-system, sans-serif; background: var(--bg); color: var(--text); display: flex; flex-direction: column; height: 100vh; }
10
+ header { padding: 1rem; background: var(--card); display: flex; gap: 1rem; align-items: center; border-bottom: 1px solid #334155; flex-wrap: wrap; }
11
+ select, button { padding: 0.5rem 1rem; border-radius: 0.5rem; border: none; cursor: pointer; }
12
+ select { background: #334155; color: white; }
13
+ button { background: var(--accent); color: white; font-weight: 600; }
14
+ button:disabled { opacity: 0.5; cursor: not-allowed; }
15
+ #chat { flex: 1; overflow-y: auto; padding: 1rem; display: flex; flex-direction: column; gap: 0.75rem; }
16
+ .msg { max-width: 80%; padding: 0.75rem 1rem; border-radius: 1rem; line-height: 1.5; white-space: pre-wrap; }
17
+ .user { align-self: flex-end; background: var(--user); }
18
+ .ai { align-self: flex-start; background: var(--ai); }
19
+ footer { padding: 1rem; background: var(--card); display: flex; gap: 0.5rem; border-top: 1px solid #334155; }
20
+ input { flex: 1; padding: 0.75rem; border-radius: 0.5rem; border: none; background: #334155; color: white; }
21
+ input:focus { outline: 2px solid var(--accent); }
22
+ .loading { display: inline-block; width: 1rem; height: 1rem; border: 2px solid #fff; border-radius: 50%; border-top-color: transparent; animation: spin 1s linear infinite; }
23
+ @keyframes spin { to { transform: rotate(360deg); } }
24
+ .error { color: #f87171; }
25
+ </style>
26
+ </head>
27
+ <body>
28
+ <header>
29
+ <span>🤖 Puter AI Chat</span>
30
+ <select id="model">
31
+ <option value="claude-sonnet-4-5">Claude 4.5</option>
32
+ <option value="gemini-2.5-flash-lite">Gemini 2.5</option>
33
+ <option value="grok-4-1-fast">Grok 4.1</option>
34
+ <option value="gpt-4o">GPT-4o</option>
35
+ </select>
36
+ <button id="clear">🗑️ Очистить</button>
37
+ <button id="save">💾 Сохранить диалог</button>
38
+ <button id="load">📂 Загрузить диалог</button>
39
+ </header>
40
+ <div id="chat"></div>
41
+ <footer>
42
+ <input id="input" placeholder="Введите сообщение..." autocomplete="off">
43
+ <button id="send">➤</button>
44
+ </footer>
45
+
46
+ <script>
47
+ const chat = document.getElementById('chat');
48
+ const input = document.getElementById('input');
49
+ const send = document.getElementById('send');
50
+ const model = document.getElementById('model');
51
+ const clear = document.getElementById('clear');
52
+ const save = document.getElementById('save');
53
+ const load = document.getElementById('load');
54
+ let history = [];
55
+
56
+ function addMsg(role, text, isError = false) {
57
+ const div = document.createElement('div');
58
+ div.className = `msg ${role}`;
59
+ if (isError) div.style.backgroundColor = '#7f1a1a';
60
+ div.textContent = text;
61
+ chat.appendChild(div);
62
+ chat.scrollTop = chat.scrollHeight;
63
+ }
64
+
65
+ async function sendMessage() {
66
+ const text = input.value.trim();
67
+ if (!text) return;
68
+ input.value = '';
69
+ addMsg('user', text);
70
+ history.push({ role: 'user', content: text });
71
+
72
+ send.disabled = true;
73
+ const loadingDiv = document.createElement('div');
74
+ loadingDiv.className = 'msg ai';
75
+ loadingDiv.innerHTML = '<span class="loading"></span> Думаю...';
76
+ chat.appendChild(loadingDiv);
77
+ chat.scrollTop = chat.scrollHeight;
78
+
79
+ try {
80
+ const res = await fetch('/api/chat', {
81
+ method: 'POST',
82
+ headers: { 'Content-Type': 'application/json' },
83
+ body: JSON.stringify({ model: model.value, messages: history })
84
+ });
85
+ if (!res.ok) {
86
+ const errData = await res.text();
87
+ throw new Error(`Ошибка ${res.status}: ${errData}`);
88
+ }
89
+ const data = await res.json();
90
+ chat.removeChild(loadingDiv);
91
+ addMsg('ai', data.reply);
92
+ history.push({ role: 'assistant', content: data.reply });
93
+ } catch (e) {
94
+ chat.removeChild(loadingDiv);
95
+ addMsg('ai', `❌ ${e.message}`, true);
96
+ } finally {
97
+ send.disabled = false;
98
+ input.focus();
99
+ }
100
+ }
101
+
102
+ function clearChat() {
103
+ history = [];
104
+ chat.innerHTML = '';
105
+ addMsg('ai', '🗑️ Чат очищен. Начинайте новый диалог.');
106
+ }
107
+
108
+ function saveDialog() {
109
+ const data = { model: model.value, history };
110
+ localStorage.setItem('puter_chat_backup', JSON.stringify(data));
111
+ addMsg('ai', '💾 Диалог сохранён в localStorage.', false);
112
+ }
113
+
114
+ function loadDialog() {
115
+ const raw = localStorage.getItem('puter_chat_backup');
116
+ if (!raw) {
117
+ addMsg('ai', '❌ Нет сохранённого диалога.', true);
118
+ return;
119
+ }
120
+ try {
121
+ const data = JSON.parse(raw);
122
+ model.value = data.model;
123
+ history = data.history;
124
+ chat.innerHTML = '';
125
+ for (const msg of history) {
126
+ addMsg(msg.role, msg.content);
127
+ }
128
+ addMsg('ai', '📂 Диалог загружен.', false);
129
+ } catch(e) {
130
+ addMsg('ai', '❌ Ошибка загрузки.', true);
131
+ }
132
+ }
133
+
134
+ send.onclick = sendMessage;
135
+ input.onkeydown = e => { if (e.key === 'Enter' && !e.shiftKey) sendMessage(); };
136
+ clear.onclick = clearChat;
137
+ save.onclick = saveDialog;
138
+ load.onclick = loadDialog;
139
+
140
+ addMsg('ai', '👋 Привет! Выбери модель и начни диалог. Диалог автоматически не сохраняется, но ты можешь сохранить его кнопкой.');
141
+ </script>
142
+ </body>
143
+ </html>