akhaliq HF Staff commited on
Commit
adafeaa
·
verified ·
1 Parent(s): 1e55429

Upload index.js with huggingface_hub

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