Silverst0ne commited on
Commit
47dad9f
·
verified ·
1 Parent(s): 7603aa6

Upload app.py with huggingface_hub

Browse files
Files changed (1) hide show
  1. app.py +389 -0
app.py ADDED
@@ -0,0 +1,389 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ === index.html ===
2
+ <!DOCTYPE html>
3
+ <html lang="en">
4
+ <head>
5
+ <meta charset="UTF-8">
6
+ <meta name="viewport" content="width=device-width, initial-scale=1.0">
7
+ <title>AI Chat Interface</title>
8
+ <link rel="stylesheet" href="style.css">
9
+ </head>
10
+ <body>
11
+ <div class="app-container">
12
+ <header class="header">
13
+ <h1>AI Chatbot</h1>
14
+ <div class="device-selector">
15
+ <label for="device-select">Execution Device:</label>
16
+ <select id="device-select">
17
+ <option value="cpu">CPU</option>
18
+ <option value="webgpu" id="webgpu-option">GPU (WebGPU)</option>
19
+ </select>
20
+ </div>
21
+ </header>
22
+ <main class="chat-container" role="main" aria-label="Chat interface">
23
+ <div id="messages" class="messages" aria-live="polite" role="log"></div>
24
+ <div class="loading-indicator" id="loading" aria-hidden="true">Typing...</div>
25
+ </main>
26
+ <footer class="input-container">
27
+ <form id="chat-form" role="form" aria-label="Send message">
28
+ <textarea
29
+ id="user-input"
30
+ placeholder="Type your message here..."
31
+ aria-label="Message input"
32
+ rows="1"
33
+ ></textarea>
34
+ <button type="submit" id="send-btn" aria-label="Send message">Send</button>
35
+ </form>
36
+ </footer>
37
+ </div>
38
+ <script type="module" src="index.js"></script>
39
+ </body>
40
+ </html>
41
+
42
+ === index.js ===
43
+ // index.js content here
44
+ import { pipeline } from 'https://cdn.jsdelivr.net/npm/@huggingface/[email protected]';
45
+
46
+ class Chatbot {
47
+ constructor() {
48
+ this.messagesContainer = document.getElementById('messages');
49
+ this.userInput = document.getElementById('user-input');
50
+ this.chatForm = document.getElementById('chat-form');
51
+ this.sendBtn = document.getElementById('send-btn');
52
+ this.loading = document.getElementById('loading');
53
+ this.deviceSelect = document.getElementById('device-select');
54
+ this.webgpuOption = document.getElementById('webgpu-option');
55
+
56
+ this.pipe = null;
57
+ this.currentDevice = 'cpu';
58
+ this.conversationHistory = ''; // Simple history for prompt
59
+
60
+ this.init();
61
+ }
62
+
63
+ async init() {
64
+ const supportsWebGPU = !!navigator.gpu;
65
+ if (!supportsWebGPU) {
66
+ this.webgpuOption.disabled = true;
67
+ this.webgpuOption.title = 'WebGPU not supported in this browser';
68
+ }
69
+
70
+ this.deviceSelect.addEventListener('change', (e) => {
71
+ this.currentDevice = e.target.value;
72
+ this.initializePipeline();
73
+ });
74
+
75
+ this.chatForm.addEventListener('submit', (e) => this.handleSubmit(e));
76
+ this.userInput.addEventListener('keypress', (e) => {
77
+ if (e.key === 'Enter' && !e.shiftKey) {
78
+ e.preventDefault();
79
+ this.handleSubmit(e);
80
+ }
81
+ });
82
+
83
+ // Auto-resize textarea
84
+ this.userInput.addEventListener('input', () => {
85
+ this.userInput.style.height = 'auto';
86
+ this.userInput.style.height = Math.min(this.userInput.scrollHeight, 120) + 'px';
87
+ });
88
+
89
+ await this.initializePipeline();
90
+ this.addMessage('bot', 'Hello! I am an AI chatbot powered by transformers.js. How can I help you today?');
91
+ }
92
+
93
+ async initializePipeline() {
94
+ try {
95
+ this.pipe = await pipeline('text-generation', 'distilgpt2', {
96
+ device: this.currentDevice === 'webgpu' ? 'webgpu' : undefined
97
+ });
98
+ console.log(`Pipeline initialized on ${this.currentDevice}`);
99
+ } catch (error) {
100
+ console.error('Failed to initialize pipeline:', error);
101
+ this.addMessage('bot', 'Error: Failed to load the AI model. Please try refreshing the page.');
102
+ if (this.currentDevice === 'webgpu') {
103
+ this.currentDevice = 'cpu';
104
+ this.deviceSelect.value = 'cpu';
105
+ await this.initializePipeline();
106
+ }
107
+ }
108
+ }
109
+
110
+ async handleSubmit(e) {
111
+ e.preventDefault();
112
+ const message = this.userInput.value.trim();
113
+ if (!message || !this.pipe) return;
114
+
115
+ this.userInput.value = '';
116
+ this.userInput.style.height = 'auto';
117
+
118
+ this.addMessage('user', message);
119
+ this.showLoading(true);
120
+
121
+ try {
122
+ // Build prompt with simple history
123
+ const prompt = this.conversationHistory ? `${this.conversationHistory}\nUser: ${message}\nAssistant:` : `User: ${message}\nAssistant:`;
124
+ const response = await this.pipe(prompt, {
125
+ max_new_tokens: 50,
126
+ temperature: 0.7,
127
+ do_sample: true,
128
+ pad_token_id: 50256 // For distilgpt2
129
+ });
130
+
131
+ const botMessage = response[0].generated_text.split('Assistant:').pop().trim();
132
+ this.conversationHistory = `${prompt} ${botMessage}`;
133
+ this.addMessage('bot', botMessage);
134
+ } catch (error) {
135
+ console.error('Error generating response:', error);
136
+ this.addMessage('bot', 'Sorry, I encountered an error while generating a response.');
137
+ } finally {
138
+ this.showLoading(false);
139
+ }
140
+ }
141
+
142
+ addMessage(sender, text) {
143
+ const messageDiv = document.createElement('div');
144
+ messageDiv.className = `message ${sender}`;
145
+ messageDiv.setAttribute('role', 'log');
146
+ messageDiv.setAttribute('aria-label', `${sender === 'user' ? 'You' : 'Assistant'}: ${text}`);
147
+ messageDiv.textContent = text;
148
+ this.messagesContainer.appendChild(messageDiv);
149
+ this.messagesContainer.scrollTop = this.messagesContainer.scrollHeight;
150
+ }
151
+
152
+ showLoading(show) {
153
+ this.loading.style.display = show ? 'block' : 'none';
154
+ if (show) {
155
+ this.messagesContainer.scrollTop = this.messagesContainer.scrollHeight;
156
+ }
157
+ }
158
+ }
159
+
160
+ // Initialize the chatbot when the DOM is loaded
161
+ document.addEventListener('DOMContentLoaded', () => {
162
+ new Chatbot();
163
+ });
164
+
165
+ === style.css ===
166
+ /* style.css content here */
167
+ * {
168
+ margin: 0;
169
+ padding: 0;
170
+ box-sizing: border-box;
171
+ }
172
+
173
+ body {
174
+ font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif;
175
+ background-color: #f5f5f5;
176
+ color: #333;
177
+ line-height: 1.6;
178
+ }
179
+
180
+ .app-container {
181
+ display: flex;
182
+ flex-direction: column;
183
+ height: 100vh;
184
+ max-width: 800px;
185
+ margin: 0 auto;
186
+ background: white;
187
+ box-shadow: 0 0 10px rgba(0, 0, 0, 0.1);
188
+ }
189
+
190
+ .header {
191
+ display: flex;
192
+ justify-content: space-between;
193
+ align-items: center;
194
+ padding: 1rem;
195
+ background-color: #007bff;
196
+ color: white;
197
+ }
198
+
199
+ .header h1 {
200
+ font-size: 1.5rem;
201
+ }
202
+
203
+ .device-selector {
204
+ display: flex;
205
+ align-items: center;
206
+ gap: 0.5rem;
207
+ }
208
+
209
+ .device-selector label {
210
+ font-size: 0.9rem;
211
+ }
212
+
213
+ .device-selector select {
214
+ padding: 0.25rem;
215
+ border: none;
216
+ border-radius: 4px;
217
+ background: white;
218
+ color: #333;
219
+ }
220
+
221
+ .chat-container {
222
+ flex: 1;
223
+ display: flex;
224
+ flex-direction: column;
225
+ padding: 1rem;
226
+ overflow: hidden;
227
+ }
228
+
229
+ .messages {
230
+ flex: 1;
231
+ overflow-y: auto;
232
+ padding: 1rem 0;
233
+ display: flex;
234
+ flex-direction: column;
235
+ gap: 1rem;
236
+ }
237
+
238
+ .message {
239
+ max-width: 70%;
240
+ padding: 0.75rem 1rem;
241
+ border-radius: 18px;
242
+ word-wrap: break-word;
243
+ animation: fadeIn 0.3s ease-in;
244
+ }
245
+
246
+ .message.user {
247
+ align-self: flex-end;
248
+ background-color: #007bff;
249
+ color: white;
250
+ }
251
+
252
+ .message.bot {
253
+ align-self: flex-start;
254
+ background-color: #e9ecef;
255
+ color: #333;
256
+ }
257
+
258
+ .loading-indicator {
259
+ display: none;
260
+ align-self: flex-start;
261
+ padding: 0.75rem 1rem;
262
+ background-color: #e9ecef;
263
+ border-radius: 18px;
264
+ font-style: italic;
265
+ color: #666;
266
+ }
267
+
268
+ .input-container {
269
+ padding: 1rem;
270
+ border-top: 1px solid #ddd;
271
+ background: white;
272
+ }
273
+
274
+ #chat-form {
275
+ display: flex;
276
+ gap: 0.5rem;
277
+ }
278
+
279
+ #user-input {
280
+ flex: 1;
281
+ padding: 0.75rem;
282
+ border: 1px solid #ddd;
283
+ border-radius: 20px;
284
+ resize: none;
285
+ font-size: 1rem;
286
+ outline: none;
287
+ transition: border-color 0.3s;
288
+ }
289
+
290
+ #user-input:focus {
291
+ border-color: #007bff;
292
+ }
293
+
294
+ #send-btn {
295
+ padding: 0.75rem 1.5rem;
296
+ background-color: #007bff;
297
+ color: white;
298
+ border: none;
299
+ border-radius: 20px;
300
+ cursor: pointer;
301
+ font-size: 1rem;
302
+ transition: background-color 0.3s;
303
+ }
304
+
305
+ #send-btn:hover:not(:disabled) {
306
+ background-color: #0056b3;
307
+ }
308
+
309
+ #send-btn:disabled {
310
+ background-color: #ccc;
311
+ cursor: not-allowed;
312
+ }
313
+
314
+ @keyframes fadeIn {
315
+ from { opacity: 0; transform: translateY(10px); }
316
+ to { opacity: 1; transform: translateY(0); }
317
+ }
318
+
319
+ /* Responsive design */
320
+ @media (max-width: 600px) {
321
+ .header {
322
+ flex-direction: column;
323
+ gap: 0.5rem;
324
+ text-align: center;
325
+ }
326
+
327
+ .device-selector {
328
+ justify-content: center;
329
+ }
330
+
331
+ .message {
332
+ max-width: 85%;
333
+ }
334
+
335
+ .input-container {
336
+ padding: 0.5rem;
337
+ }
338
+
339
+ #chat-form {
340
+ flex-direction: column;
341
+ }
342
+
343
+ #send-btn {
344
+ align-self: stretch;
345
+ }
346
+ }
347
+
348
+ /* Accessibility improvements */
349
+ @media (prefers-reduced-motion: reduce) {
350
+ .message {
351
+ animation: none;
352
+ }
353
+ }
354
+
355
+ @media (prefers-color-scheme: dark) {
356
+ body {
357
+ background-color: #121212;
358
+ color: #e0e0e0;
359
+ }
360
+
361
+ .app-container {
362
+ background: #1e1e1e;
363
+ box-shadow: 0 0 10px rgba(255, 255, 255, 0.1);
364
+ }
365
+
366
+ .header {
367
+ background-color: #0d6efd;
368
+ }
369
+
370
+ .message.bot {
371
+ background-color: #333;
372
+ color: #e0e0e0;
373
+ }
374
+
375
+ .loading-indicator {
376
+ background-color: #333;
377
+ color: #b0b0b0;
378
+ }
379
+
380
+ #user-input {
381
+ background-color: #333;
382
+ color: #e0e0e0;
383
+ border-color: #555;
384
+ }
385
+
386
+ #user-input:focus {
387
+ border-color: #0d6efd;
388
+ }
389
+ }