akhaliq HF Staff commited on
Commit
54a96bb
·
verified ·
1 Parent(s): 7589406

Upload index.js with huggingface_hub

Browse files
Files changed (1) hide show
  1. index.js +322 -56
index.js CHANGED
@@ -1,76 +1,342 @@
1
- import { pipeline } from 'https://cdn.jsdelivr.net/npm/@huggingface/[email protected]';
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
2
 
3
- // Reference the elements that we will need
4
- const status = document.getElementById('status');
5
- const fileUpload = document.getElementById('upload');
6
- const imageContainer = document.getElementById('container');
7
- const example = document.getElementById('example');
8
 
9
- const EXAMPLE_URL = 'https://huggingface.co/datasets/Xenova/transformers.js-docs/resolve/main/city-streets.jpg';
 
 
 
 
 
 
10
 
11
- // Create a new object detection pipeline
12
- status.textContent = 'Loading model...';
13
- const detector = await pipeline('object-detection', 'Xenova/detr-resnet-50');
14
- status.textContent = 'Ready';
15
 
16
- example.addEventListener('click', (e) => {
17
- e.preventDefault();
18
- detect(EXAMPLE_URL);
19
  });
20
 
21
- fileUpload.addEventListener('change', function (e) {
22
- const file = e.target.files[0];
23
- if (!file) {
24
- return;
25
- }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
26
 
27
- const reader = new FileReader();
 
28
 
29
- // Set up a callback when the file is loaded
30
- reader.onload = e2 => detect(e2.target.result);
31
 
32
- reader.readAsDataURL(file);
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
33
  });
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
34
 
 
35
 
36
- // Detect objects in the image
37
- async function detect(img) {
38
- imageContainer.innerHTML = '';
39
- imageContainer.style.backgroundImage = `url(${img})`;
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
40
 
41
- status.textContent = 'Analysing...';
42
- const output = await detector(img, {
43
- threshold: 0.5,
44
- percentage: true,
45
- });
46
- status.textContent = '';
47
- output.forEach(renderBox);
48
  }
49
 
50
- // Render a bounding box and label on the image
51
- function renderBox({ box, label }) {
52
- const { xmax, xmin, ymax, ymin } = box;
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
53
 
54
- // Generate a random color for the box
55
- const color = '#' + Math.floor(Math.random() * 0xFFFFFF).toString(16).padStart(6, 0);
 
 
 
 
 
 
56
 
57
- // Draw the box
58
- const boxElement = document.createElement('div');
59
- boxElement.className = 'bounding-box';
60
- Object.assign(boxElement.style, {
61
- borderColor: color,
62
- left: 100 * xmin + '%',
63
- top: 100 * ymin + '%',
64
- width: 100 * (xmax - xmin) + '%',
65
- height: 100 * (ymax - ymin) + '%',
66
- })
67
 
68
- // Draw label
69
- const labelElement = document.createElement('span');
70
- labelElement.textContent = label;
71
- labelElement.className = 'bounding-box-label';
72
- labelElement.style.backgroundColor = color;
 
73
 
74
- boxElement.appendChild(labelElement);
75
- imageContainer.appendChild(boxElement);
 
 
76
  }
 
 
 
 
 
 
 
 
 
1
+ // Main application logic for Apple Style Chatbot
2
+ class AppleChatbot {
3
+ constructor() {
4
+ this.generator = null;
5
+ this.isGenerating = false;
6
+ this.messages = [];
7
+ this.settings = {
8
+ maxTokens: 512,
9
+ temperature: 0.7,
10
+ streaming: true
11
+ };
12
+ this.init();
13
+ }
14
+
15
+ async init() {
16
+ // Initialize UI elements
17
+ this.loadingScreen = document.getElementById('loadingScreen');
18
+ this.chatContainer = document.getElementById('chatContainer');
19
+ this.inputArea = document.getElementById('inputArea');
20
+ this.messagesList = document.getElementById('messagesList');
21
+ this.messageInput = document.getElementById('messageInput');
22
+ this.sendBtn = document.getElementById('sendBtn');
23
+ this.clearBtn = document.getElementById('clearBtn');
24
+ this.settingsBtn = document.getElementById('settingsBtn');
25
+ this.progressFill = document.getElementById('progressFill');
26
+ this.loadingStatus = document.getElementById('loadingStatus');
27
+ this.charCount = document.getElementById('charCount');
28
+
29
+ // Setup event listeners
30
+ this.setupEventListeners();
31
+
32
+ // Load model using Web Worker
33
+ await this.loadModel();
34
+ }
35
+
36
+ setupEventListeners() {
37
+ // Send button
38
+ this.sendBtn.addEventListener('click', () => this.sendMessage());
39
+
40
+ // Enter key to send (Shift+Enter for new line)
41
+ this.messageInput.addEventListener('keydown', (e) => {
42
+ if (e.key === 'Enter' && !e.shiftKey) {
43
+ e.preventDefault();
44
+ this.sendMessage();
45
+ }
46
+ });
47
 
48
+ // Character count
49
+ this.messageInput.addEventListener('input', (e) => {
50
+ const length = e.target.value.length;
51
+ this.charCount.textContent = `${length} / 1000`;
52
+ this.sendBtn.disabled = length === 0 || this.isGenerating;
53
 
54
+ // Auto-resize textarea
55
+ e.target.style.height = 'auto';
56
+ e.target.style.height = Math.min(e.target.scrollHeight, 120) + 'px';
57
+ });
58
+
59
+ // Clear button
60
+ this.clearBtn.addEventListener('click', () => this.clearChat());
61
 
62
+ // Settings
63
+ this.settingsBtn.addEventListener('click', () => this.openSettings());
64
+ document.getElementById('closeSettings').addEventListener('click', () => this.closeSettings());
65
+ document.getElementById('saveSettings').addEventListener('click', () => this.saveSettings());
66
 
67
+ // Settings inputs
68
+ document.getElementById('maxTokens').addEventListener('input', (e) => {
69
+ document.getElementById('maxTokensValue').textContent = e.target.value;
70
  });
71
 
72
+ document.getElementById('temperature').addEventListener('input', (e) => {
73
+ document.getElementById('temperatureValue').textContent = e.target.value;
74
+ });
75
+
76
+ // Close modal on backdrop click
77
+ document.getElementById('settingsModal').addEventListener('click', (e) => {
78
+ if (e.target.id === 'settingsModal') {
79
+ this.closeSettings();
80
+ }
81
+ });
82
+ }
83
+
84
+ async loadModel() {
85
+ try {
86
+ // Create Web Worker for model loading
87
+ const worker = new Worker('worker.js');
88
+
89
+ worker.onmessage = async (e) => {
90
+ const { type, data } = e.data;
91
+
92
+ switch (type) {
93
+ case 'progress':
94
+ this.updateProgress(data.progress, data.status);
95
+ break;
96
+
97
+ case 'model_loaded':
98
+ // Model is loaded, initialize the generator
99
+ await this.initializeGenerator();
100
+ break;
101
+ }
102
+ };
103
+
104
+ // Start loading the model
105
+ worker.postMessage({ type: 'load_model' });
106
+
107
+ } catch (error) {
108
+ console.error('Error loading model:', error);
109
+ this.showError('Failed to load AI model. Please refresh the page and try again.');
110
+ }
111
+ }
112
+
113
+ updateProgress(progress, status) {
114
+ this.progressFill.style.width = `${progress}%`;
115
+ this.loadingStatus.textContent = status;
116
+ }
117
+
118
+ async initializeGenerator() {
119
+ try {
120
+ // Initialize the text generation pipeline
121
+ this.generator = await pipeline(
122
+ 'text-generation',
123
+ 'onnx-community/gemma-3-270m-it-ONNX',
124
+ { dtype: 'fp32' }
125
+ );
126
+
127
+ // Hide loading screen and show chat
128
+ this.loadingScreen.style.display = 'none';
129
+ this.chatContainer.style.display = 'block';
130
+ this.inputArea.style.display = 'block';
131
+
132
+ // Focus on input
133
+ this.messageInput.focus();
134
+
135
+ } catch (error) {
136
+ console.error('Error initializing generator:', error);
137
+ this.showError('Failed to initialize AI model. Please refresh the page and try again.');
138
+ }
139
+ }
140
+
141
+ async sendMessage() {
142
+ const text = this.messageInput.value.trim();
143
+ if (!text || this.isGenerating || !this.generator) return;
144
+
145
+ // Add user message
146
+ this.addMessage('user', text);
147
+ this.messages.push({ role: 'user', content: text });
148
+
149
+ // Clear input
150
+ this.messageInput.value = '';
151
+ this.charCount.textContent = '0 / 1000';
152
+ this.sendBtn.disabled = true;
153
+ this.messageInput.style.height = 'auto';
154
 
155
+ // Show typing indicator
156
+ const typingMessage = this.showTypingIndicator();
157
 
158
+ try {
159
+ this.isGenerating = true;
160
 
161
+ // Generate response
162
+ const response = await this.generateResponse();
163
+
164
+ // Remove typing indicator
165
+ typingMessage.remove();
166
+
167
+ // Add assistant response
168
+ this.addMessage('assistant', response);
169
+ this.messages.push({ role: 'assistant', content: response });
170
+
171
+ } catch (error) {
172
+ console.error('Error generating response:', error);
173
+ typingMessage.remove();
174
+ this.addMessage('assistant', 'Sorry, I encountered an error while generating a response. Please try again.');
175
+ } finally {
176
+ this.isGenerating = false;
177
+ this.sendBtn.disabled = false;
178
+ this.messageInput.focus();
179
+ }
180
+ }
181
+
182
+ async generateResponse() {
183
+ if (!this.generator) throw new Error('Generator not initialized');
184
+
185
+ const generationParams = {
186
+ max_new_tokens: this.settings.maxTokens,
187
+ do_sample: this.settings.temperature > 0,
188
+ temperature: this.settings.temperature,
189
+ };
190
+
191
+ // Add streamer if streaming is enabled
192
+ if (this.settings.streaming) {
193
+ generationParams.streamer = new TextStreamer(this.generator.tokenizer, {
194
+ skip_prompt: true,
195
+ skip_special_tokens: true,
196
  });
197
+ }
198
+
199
+ // Generate response
200
+ const output = await this.generator(this.messages, generationParams);
201
+
202
+ // Extract the assistant's response
203
+ const lastMessage = output[0].generated_text.at(-1);
204
+ return lastMessage ? lastMessage.content : 'I apologize, but I couldn\'t generate a response.';
205
+ }
206
+
207
+ addMessage(role, content) {
208
+ const messageDiv = document.createElement('div');
209
+ messageDiv.className = `message ${role}`;
210
+
211
+ const avatar = document.createElement('div');
212
+ avatar.className = 'message-avatar';
213
+ avatar.innerHTML = role === 'user'
214
+ ? '<svg width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">
215
+ <path d="M20 21v-2a4 4 0 0 0-4-4H8a4 4 0 0 0-4 4v2" />
216
+ <circle cx="12" cy="7" r="4" />
217
+ </svg>'
218
+ : '<svg width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">
219
+ <path d="M12 2L2 7V17L12 22L22 17V7L12 2Z" />
220
+ </svg>';
221
+
222
+ const messageContent = document.createElement('div');
223
+ messageContent.className = 'message-content';
224
+
225
+ const messageText = document.createElement('div');
226
+ messageText.className = 'message-text';
227
+ messageText.textContent = content;
228
+
229
+ const messageTime = document.createElement('div');
230
+ messageTime.className = 'message-time';
231
+ messageTime.textContent = this.getCurrentTime();
232
+
233
+ messageContent.appendChild(messageText);
234
+ messageContent.appendChild(messageTime);
235
+ messageDiv.appendChild(avatar);
236
+ messageDiv.appendChild(messageContent);
237
 
238
+ this.messagesList.appendChild(messageDiv);
239
 
240
+ // Scroll to bottom
241
+ this.chatContainer.scrollTop = this.chatContainer.scrollHeight;
242
+ }
243
+
244
+ showTypingIndicator() {
245
+ const messageDiv = document.createElement('div');
246
+ messageDiv.className = 'message assistant';
247
+
248
+ const avatar = document.createElement('div');
249
+ avatar.className = 'message-avatar';
250
+ avatar.innerHTML = '<svg width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">
251
+ <path d="M12 2L2 7V17L12 22L22 17V7L12 2Z" />
252
+ </svg>';
253
+
254
+ const messageContent = document.createElement('div');
255
+ messageContent.className = 'message-content';
256
+
257
+ const typingIndicator = document.createElement('div');
258
+ typingIndicator.className = 'message-text typing-indicator';
259
+ typingIndicator.innerHTML = `
260
+ <div class="typing-dot"></div>
261
+ <div class="typing-dot"></div>
262
+ <div class="typing-dot"></div>
263
+ `;
264
+
265
+ const messageTime = document.createElement('div');
266
+ messageTime.className = 'message-time';
267
+ messageTime.textContent = 'Typing...';
268
+
269
+ messageContent.appendChild(typingIndicator);
270
+ messageContent.appendChild(messageTime);
271
+ messageDiv.appendChild(avatar);
272
+ messageDiv.appendChild(messageContent);
273
+
274
+ this.messagesList.appendChild(messageDiv);
275
+ this.chatContainer.scrollTop = this.chatContainer.scrollHeight;
276
+
277
+ return messageDiv;
278
+ }
279
 
280
+ getCurrentTime() {
281
+ const now = new Date();
282
+ const hours = now.getHours().toString().padStart(2, '0');
283
+ const minutes = now.getMinutes().toString().padStart(2, '0');
284
+ return `${hours}:${minutes}`;
 
 
285
  }
286
 
287
+ clearChat() {
288
+ if (confirm('Are you sure you want to clear all messages?')) {
289
+ // Keep only the welcome message
290
+ this.messagesList.innerHTML = `
291
+ <div class="message assistant">
292
+ <div class="message-avatar">
293
+ <svg width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">
294
+ <path d="M12 2L2 7V17L12 22L22 17V7L12 2Z" />
295
+ </svg>
296
+ </div>
297
+ <div class="message-content">
298
+ <div class="message-text">
299
+ Hello! I'm your AI assistant powered by Gemma-3. How can I help you today?
300
+ </div>
301
+ <div class="message-time">${this.getCurrentTime()}</div>
302
+ </div>
303
+ </div>
304
+ `;
305
+ this.messages = [];
306
+ this.messageInput.focus();
307
+ }
308
+ }
309
 
310
+ openSettings() {
311
+ document.getElementById('settingsModal').classList.add('active');
312
+ document.getElementById('maxTokens').value = this.settings.maxTokens;
313
+ document.getElementById('maxTokensValue').textContent = this.settings.maxTokens;
314
+ document.getElementById('temperature').value = this.settings.temperature;
315
+ document.getElementById('temperatureValue').textContent = this.settings.temperature;
316
+ document.getElementById('streaming').checked = this.settings.streaming;
317
+ }
318
 
319
+ closeSettings() {
320
+ document.getElementById('settingsModal').classList.remove('active');
321
+ }
 
 
 
 
 
 
 
322
 
323
+ saveSettings() {
324
+ this.settings.maxTokens = parseInt(document.getElementById('maxTokens').value);
325
+ this.settings.temperature = parseFloat(document.getElementById('temperature').value);
326
+ this.settings.streaming = document.getElementById('streaming').checked;
327
+ this.closeSettings();
328
+ }
329
 
330
+ showError(message) {
331
+ this.loadingStatus.textContent = message;
332
+ this.loadingStatus.style.color = 'var(--error)';
333
+ }
334
  }
335
+
336
+ // Import transformers.js classes
337
+ const { pipeline, TextStreamer } = window.transformers;
338
+
339
+ // Initialize the chatbot when the page loads
340
+ document.addEventListener('DOMContentLoaded', () => {
341
+ new AppleChatbot();
342
+ });