akhaliq HF Staff commited on
Commit
d25692c
·
verified ·
1 Parent(s): da7d310

Upload index.js with huggingface_hub

Browse files
Files changed (1) hide show
  1. index.js +313 -62
index.js CHANGED
@@ -1,76 +1,327 @@
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
+ import { pipeline, TextStreamer } from 'https://cdn.jsdelivr.net/npm/@huggingface/[email protected]';
3
 
4
+ class AppleChatbot {
5
+ constructor() {
6
+ this.generator = null;
7
+ this.isGenerating = false;
8
+ this.messages = [];
9
+ this.settings = {
10
+ maxTokens: 512,
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"><path d="M20 21v-2a4 4 0 0 0-4-4H8a4 4 0 0 0-4 4v2" /><circle cx="12" cy="7" r="4" /></svg>'
210
+ : '<svg width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"><path d="M12 2L2 7V17L12 22L22 17V7L12 2Z" /></svg>';
211
+
212
+ const messageContent = document.createElement('div');
213
+ messageContent.className = 'message-content';
214
+
215
+ const messageText = document.createElement('div');
216
+ messageText.className = 'message-text';
217
+ messageText.textContent = content;
218
+
219
+ const messageTime = document.createElement('div');
220
+ messageTime.className = 'message-time';
221
+ messageTime.textContent = this.getCurrentTime();
222
+
223
+ messageContent.appendChild(messageText);
224
+ messageContent.appendChild(messageTime);
225
+ messageDiv.appendChild(avatar);
226
+ messageDiv.appendChild(messageContent);
227
+
228
+ this.messagesList.appendChild(messageDiv);
229
+
230
+ // Scroll to bottom
231
+ this.chatContainer.scrollTop = this.chatContainer.scrollHeight;
232
+ }
233
+
234
+ showTypingIndicator() {
235
+ const messageDiv = document.createElement('div');
236
+ messageDiv.className = 'message assistant';
237
+
238
+ const avatar = document.createElement('div');
239
+ avatar.className = 'message-avatar';
240
+ avatar.innerHTML = '<svg width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"><path d="M12 2L2 7V17L12 22L22 17V7L12 2Z" /></svg>';
241
+
242
+ const messageContent = document.createElement('div');
243
+ messageContent.className = 'message-content';
244
+
245
+ const typingIndicator = document.createElement('div');
246
+ typingIndicator.className = 'message-text typing-indicator';
247
+ typingIndicator.innerHTML = `
248
+ <div class="typing-dot"></div>
249
+ <div class="typing-dot"></div>
250
+ <div class="typing-dot"></div>
251
+ `;
252
+
253
+ const messageTime = document.createElement('div');
254
+ messageTime.className = 'message-time';
255
+ messageTime.textContent = 'Typing...';
256
+
257
+ messageContent.appendChild(typingIndicator);
258
+ messageContent.appendChild(messageTime);
259
+ messageDiv.appendChild(avatar);
260
+ messageDiv.appendChild(messageContent);
261
+
262
+ this.messagesList.appendChild(messageDiv);
263
+ this.chatContainer.scrollTop = this.chatContainer.scrollHeight;
264
+
265
+ return messageDiv;
266
+ }
267
+
268
+ getCurrentTime() {
269
+ const now = new Date();
270
+ const hours = now.getHours().toString().padStart(2, '0');
271
+ const minutes = now.getMinutes().toString().padStart(2, '0');
272
+ return `${hours}:${minutes}`;
273
+ }
274
+
275
+ clearChat() {
276
+ if (confirm('Are you sure you want to clear all messages?')) {
277
+ // Keep only the welcome message
278
+ this.messagesList.innerHTML = `
279
+ <div class="message assistant">
280
+ <div class="message-avatar">
281
+ <svg width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">
282
+ <path d="M12 2L2 7V17L12 22L22 17V7L12 2Z" />
283
+ </svg>
284
+ </div>
285
+ <div class="message-content">
286
+ <div class="message-text">
287
+ Hello! I'm your AI assistant powered by Gemma-3. How can I help you today?
288
+ </div>
289
+ <div class="message-time">${this.getCurrentTime()}</div>
290
+ </div>
291
+ </div>
292
+ `;
293
+ this.messages = [];
294
+ this.messageInput.focus();
295
+ }
296
+ }
297
+
298
+ openSettings() {
299
+ document.getElementById('settingsModal').classList.add('active');
300
+ document.getElementById('maxTokens').value = this.settings.maxTokens;
301
+ document.getElementById('maxTokensValue').textContent = this.settings.maxTokens;
302
+ document.getElementById('temperature').value = this.settings.temperature;
303
+ document.getElementById('temperatureValue').textContent = this.settings.temperature;
304
+ document.getElementById('streaming').checked = this.settings.streaming;
305
+ }
306
+
307
+ closeSettings() {
308
+ document.getElementById('settingsModal').classList.remove('active');
309
+ }
310
+
311
+ saveSettings() {
312
+ this.settings.maxTokens = parseInt(document.getElementById('maxTokens').value);
313
+ this.settings.temperature = parseFloat(document.getElementById('temperature').value);
314
+ this.settings.streaming = document.getElementById('streaming').checked;
315
+ this.closeSettings();
316
+ }
317
+
318
+ showError(message) {
319
+ this.loadingStatus.textContent = message;
320
+ this.loadingStatus.style.color = 'var(--error)';
321
+ }
322
  }
323
+
324
+ // Initialize the chatbot when the page loads
325
+ document.addEventListener('DOMContentLoaded', () => {
326
+ new AppleChatbot();
327
+ });