kawasumi commited on
Commit
2c082ce
Β·
verified Β·
1 Parent(s): b960bac

Update index.html

Browse files
Files changed (1) hide show
  1. index.html +230 -19
index.html CHANGED
@@ -1,19 +1,230 @@
1
- <!doctype html>
2
- <html>
3
- <head>
4
- <meta charset="utf-8" />
5
- <meta name="viewport" content="width=device-width" />
6
- <title>My static Space</title>
7
- <link rel="stylesheet" href="style.css" />
8
- </head>
9
- <body>
10
- <div class="card">
11
- <h1>Welcome to your static Space!</h1>
12
- <p>You can modify this app directly by editing <i>index.html</i> in the Files and versions tab.</p>
13
- <p>
14
- Also don't forget to check the
15
- <a href="https://huggingface.co/docs/hub/spaces" target="_blank">Spaces documentation</a>.
16
- </p>
17
- </div>
18
- </body>
19
- </html>
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <!DOCTYPE html>
2
+ <html lang="ja">
3
+ <head>
4
+ <meta charset="UTF-8">
5
+ <meta name="viewport" content="width=device-width, initial-scale=1.0">
6
+ <title>Tema_Q-X-Chat</title>
7
+ <style>
8
+ :root { --background-color: #fff; --header-bg: #fff; --chat-bg: #fff; --input-bg: #f5f5f5; --input-shadow: rgba(0, 0, 0, 0.1); --user-message-bg: #0084ff; --user-message-color: #fff; --bot-message-bg: #f5f5f5; --bot-message-color: #000; --text-color: #000; --send-button-bg: #000; --send-button-color: #fff; --send-button-disabled-bg: #ccc; --send-button-stop-bg: #d32f2f; --new-chat-button-bg: #999; --new-chat-button-color: #fff; --code-bg: #2d2d2d; --code-color: #f8f8f2; }
9
+ [data-theme="dark"] { --background-color: #1e1e1e; --header-bg: #2a2a2a; --chat-bg: #1e1e1e; --input-bg: #333; --input-shadow: rgba(0, 0, 0, 0.3); --user-message-bg: #005bb5; --user-message-color: #fff; --bot-message-bg: #444; --bot-message-color: #ddd; --text-color: #ddd; --send-button-bg: #555; --send-button-color: #fff; --send-button-disabled-bg: #666; --send-button-stop-bg: #e57373; --new-chat-button-bg: #666; --new-chat-button-color: #fff; --code-bg: #1a1a1a; --code-color: #f8f8f2; }
10
+ body { font-family: Arial, sans-serif; margin: 0; padding: 0; background-color: var(--background-color); color: var(--text-color); display: flex; flex-direction: column; height: 100vh; overflow: hidden; -webkit-overflow-scrolling: touch; touch-action: manipulation; }
11
+ .header { background-color: var(--header-bg); padding: 10px; display: flex; justify-content: flex-end; align-items: center; flex-shrink: 0; position: fixed; top: 0; right: 0; width: 100%; z-index: 20; }
12
+ #new-chat-button, #theme-toggle-button { background-color: var(--new-chat-button-bg); color: var(--new-chat-button-color); border: none; border-radius: 50%; width: 32px; height: 32px; cursor: pointer; display: flex; align-items: center; justify-content: center; margin-left: 10px; font-size: 20px; }
13
+ #theme-toggle-button img { width: 20px; height: 20px; object-fit: contain; }
14
+ .chat-container { flex: 1; width: 100%; max-width: 100%; display: flex; flex-direction: column; background-color: var(--chat-bg); position: relative; overflow: hidden; padding-top: 52px; }
15
+ .chat-messages { flex: 1; padding: 10px; padding-bottom: 100px; overflow-y: auto; -webkit-overflow-scrolling: touch; touch-action: pan-y; }
16
+ .message { margin-bottom: 10px; display: flex; flex-direction: column; }
17
+ .message.user { align-items: flex-end; }
18
+ .message.bot { align-items: flex-start; }
19
+ .message-content { max-width: 80%; padding: 8px 12px; border-radius: 6px; font-size: 16px; line-height: 1.6; }
20
+ .message.user .message-content { background-color: var(--user-message-bg); color: var(--user-message-color); white-space: pre-wrap; word-wrap: break-word; }
21
+ .message.bot .message-content { background-color: var(--bot-message-bg); color: var(--bot-message-color); white-space: pre-wrap; word-wrap: break-word; text-align: left; }
22
+ .status-info { font-size: 11px; color: #888; margin-top: 4px; padding-left: 12px; font-family: monospace; }
23
+ [data-theme="dark"] .status-info { color: #aaa; }
24
+ .message.bot pre { background-color: var(--code-bg); padding: 12px; border-radius: 6px; overflow-x: auto; margin: 10px 0; white-space: pre; }
25
+ .message.bot code { font-family: Consolas, Monaco, 'Andale Mono', 'Ubuntu Mono', monospace; color: var(--code-color); font-size: 14px; }
26
+ .message.bot :not(pre) > code { background-color: var(--code-bg); padding: 2px 5px; border-radius: 3px; font-size: 90%; white-space: pre-wrap; }
27
+ .input-container { position: fixed; bottom: 20px; left: 50%; transform: translateX(-50%); width: 90%; max-width: 600px; z-index: 10; }
28
+ .input-wrapper { display: flex; align-items: center; background-color: var(--input-bg); border-radius: 20px; padding: 8px 12px; box-shadow: 0 2px 5px var(--input-shadow); min-height: 40px; }
29
+ #user-input { flex: 1; padding: 8px; border: none; background: transparent; font-size: 16px; outline: none; resize: none; min-height: 24px; max-height: 120px; overflow-y: auto; line-height: 1.4; white-space: pre-wrap; word-wrap: break-word; align-self: center; color: var(--text-color); }
30
+ #send-button { width: 30px; height: 30px; background-color: var(--send-button-bg); color: var(--send-button-color); border: none; border-radius: 50%; font-size: 16px; cursor: pointer; display: flex; align-items: center; justify-content: center; flex-shrink: 0; align-self: center; transition: background-color 0.2s; }
31
+ #send-button:disabled { background-color: var(--send-button-disabled-bg); cursor: not-allowed; }
32
+ #send-button.stop-mode { background-color: var(--send-button-stop-bg); font-size: 12px; }
33
+ #welcome-text { position: absolute; top: 50%; left: 50%; transform: translate(-50%, -50%); font-size: 40px; color: var(--text-color); z-index: 5; pointer-events: none; }
34
+ </style>
35
+ </head>
36
+ <body data-theme="light">
37
+ <div class="header">
38
+ <button id="theme-toggle-button" title="γƒ€γƒΌγ‚―γƒ’γƒΌγƒ‰εˆ‡γ‚Šζ›Ώγˆ"><img src="1.png" alt="γƒ©γ‚€γƒˆγƒ’γƒΌγƒ‰" id="theme-icon"></button>
39
+ <button id="new-chat-button" title="ζ–°γ—γ„γƒγƒ£γƒƒγƒˆγ‚’ι–‹ε§‹">↻</button>
40
+ </div>
41
+ <div class="chat-container">
42
+ <div class="chat-messages" id="chat-messages"></div>
43
+ <div id="welcome-text">Tema_Q-X</div>
44
+ <div class="input-container">
45
+ <div class="input-wrapper">
46
+ <textarea id="user-input" placeholder="ヒデルをロード中..." disabled></textarea>
47
+ <button id="send-button" disabled>↑</button>
48
+ </div>
49
+ </div>
50
+ </div>
51
+
52
+ <script type="module">
53
+ import { CreateMLCEngine } from "https://esm.run/@mlc-ai/web-llm";
54
+
55
+ const chatMessages = document.getElementById('chat-messages');
56
+ const userInput = document.getElementById('user-input');
57
+ const sendButton = document.getElementById('send-button');
58
+ const welcomeText = document.getElementById('welcome-text');
59
+ const themeToggleButton = document.getElementById('theme-toggle-button');
60
+ const newChatButton = document.getElementById('new-chat-button');
61
+ const body = document.body;
62
+ const themeIcon = document.getElementById('theme-icon');
63
+
64
+ let engine;
65
+ let isGenerating = false;
66
+ let messages = [];
67
+
68
+ async function initWebLLM() {
69
+ const modelId = "Tema-Q-X-MLC";
70
+
71
+ const appConfig = {
72
+ model_list: [{
73
+ model_id: modelId,
74
+ model: "https://huggingface.co/kawasumi/Tema-Q-R4.2-MLC/resolve/main/",
75
+ model_lib: "https://raw.githubusercontent.com/mlc-ai/binary-mlc-llm-libs/main/web-llm-models/v0_2_80/gemma-2-9b-it-q4f16_1-ctx4k_cs1k-webgpu.wasm",
76
+ }]
77
+ };
78
+
79
+ const statusDiv = addMessage("Tema Q-X ヒデルロード中...", "bot");
80
+
81
+ try {
82
+ engine = await CreateMLCEngine(modelId, {
83
+ appConfig,
84
+ initProgressCallback: (report) => {
85
+ statusDiv.textContent = `ロード中: ${report.text} (${(report.progress * 100).toFixed(1)}%)`;
86
+ }
87
+ });
88
+ statusDiv.parentElement.remove();
89
+ userInput.placeholder = "パッセージをε…₯εŠ›...";
90
+ userInput.disabled = false;
91
+ checkInput();
92
+ } catch (err) {
93
+ statusDiv.textContent = "エラー: ヒデルロード倱敗。ブラウアコンソールを璺θͺγ—てください。";
94
+ console.error(err);
95
+ }
96
+ }
97
+
98
+ function parseMarkdown(text) {
99
+ if (!text) return '';
100
+ let html = text
101
+ .replace(/&/g, "&amp;")
102
+ .replace(/</g, "&lt;")
103
+ .replace(/>/g, "&gt;")
104
+ .replace(/"/g, "&quot;")
105
+ .replace(/'/g, "&#039;");
106
+ html = html.replace(/^### (.*$)/gm, '<h3>$1</h3>');
107
+ html = html.replace(/^## (.*$)/gm, '<h2>$1</h2>');
108
+ html = html.replace(/^# (.*$)/gm, '<h1>$1</h1>');
109
+ html = html.replace(/^\s*[-*+]\s/gm, 'β€’ ');
110
+ html = html.replace(/```(\w*)?\n?([\s\S]*?)```/g, (m, lang, code) => `<pre><code>${code.trim()}</code></pre>`);
111
+ html = html.replace(/`([^`]+)`/g, '<code>$1</code>');
112
+ html = html.replace(/\*\*(.*?)\*\*/g, '<strong>$1</strong>');
113
+ html = html.replace(/\*(.*?)\*/g, '<em>$1</em>');
114
+ return html;
115
+ }
116
+
117
+ function setGeneratingState(generating) {
118
+ isGenerating = generating;
119
+ sendButton.textContent = generating ? 'β– ' : '↑';
120
+ sendButton.classList.toggle('stop-mode', generating);
121
+ sendButton.disabled = false;
122
+ if (!generating) checkInput();
123
+ }
124
+
125
+ async function sendMessage() {
126
+ if (isGenerating) {
127
+ await engine.interruptGenerate?.();
128
+ setGeneratingState(false);
129
+ return;
130
+ }
131
+
132
+ const message = userInput.value.trim();
133
+ if (!message || !engine) return;
134
+
135
+ userInput.value = '';
136
+ userInput.style.height = 'auto';
137
+ welcomeText.style.display = 'none';
138
+ checkInput();
139
+
140
+ addMessage(message, 'user');
141
+ messages.push({ role: "user", content: message });
142
+
143
+ const botContentDiv = addMessage('', 'bot');
144
+ const statusDiv = document.createElement('div');
145
+ statusDiv.className = 'status-info';
146
+ botContentDiv.parentNode.appendChild(statusDiv);
147
+
148
+ let fullBotText = '';
149
+ setGeneratingState(true);
150
+
151
+ try {
152
+ const completion = await engine.chat.completions.create({
153
+ messages,
154
+ stream: true,
155
+ temperature: 0.7,
156
+ });
157
+
158
+ for await (const chunk of completion) {
159
+ const curText = chunk.choices[0]?.delta.content || "";
160
+ fullBotText += curText;
161
+ botContentDiv.innerHTML = parseMarkdown(fullBotText);
162
+
163
+ if (chunk.usage?.extra?.decode_tokens_per_s) {
164
+ const tps = chunk.usage.extra.decode_tokens_per_s.toFixed(1);
165
+ statusDiv.textContent = `${tps} tokens/s | ${chunk.usage.total_tokens ?? 0} tokens`;
166
+ }
167
+ chatMessages.scrollTop = chatMessages.scrollHeight;
168
+ }
169
+ messages.push({ role: "assistant", content: fullBotText });
170
+ } catch (error) {
171
+ botContentDiv.innerHTML += '<br><span style="color:red;">γ‚¨γƒ©γƒΌγŒη™Ίη”Ÿγ—γΎγ—γŸγ€‚</span>';
172
+ console.error(error);
173
+ } finally {
174
+ setGeneratingState(false);
175
+ }
176
+ }
177
+
178
+ function addMessage(text, sender) {
179
+ const messageDiv = document.createElement('div');
180
+ messageDiv.classList.add('message', sender);
181
+ const contentDiv = document.createElement('div');
182
+ contentDiv.classList.add('message-content');
183
+ if (sender === 'user') contentDiv.textContent = text;
184
+ else contentDiv.innerHTML = parseMarkdown(text);
185
+ messageDiv.appendChild(contentDiv);
186
+ chatMessages.appendChild(messageDiv);
187
+ chatMessages.scrollTop = chatMessages.scrollHeight;
188
+ return contentDiv;
189
+ }
190
+
191
+ function checkInput() {
192
+ if (!isGenerating) sendButton.disabled = userInput.value.trim().length === 0;
193
+ }
194
+
195
+ userInput.addEventListener('input', function() {
196
+ this.style.height = 'auto';
197
+ this.style.height = this.scrollHeight + 'px';
198
+ checkInput();
199
+ });
200
+
201
+ userInput.addEventListener('keydown', (e) => {
202
+ if (e.key === 'Enter' && !e.shiftKey) {
203
+ e.preventDefault();
204
+ if (!isGenerating && !sendButton.disabled) sendMessage();
205
+ }
206
+ });
207
+
208
+ sendButton.addEventListener('click', sendMessage);
209
+
210
+ newChatButton.addEventListener('click', async () => {
211
+ if (isGenerating) await engine.interruptGenerate?.();
212
+ chatMessages.innerHTML = '';
213
+ messages = [];
214
+ welcomeText.style.display = 'block';
215
+ userInput.value = '';
216
+ setGeneratingState(false);
217
+ if (engine) await engine.resetChat();
218
+ });
219
+
220
+ themeToggleButton.addEventListener('click', () => {
221
+ const isLight = body.getAttribute('data-theme') === 'light';
222
+ body.setAttribute('data-theme', isLight ? 'dark' : 'light');
223
+ themeIcon.src = isLight ? '2.png' : '1.png';
224
+ themeIcon.alt = isLight ? 'ダークヒード' : 'γƒ©γ‚€γƒˆγƒ’γƒΌγƒ‰';
225
+ });
226
+
227
+ initWebLLM();
228
+ </script>
229
+ </body>
230
+ </html>