akhaliq HF Staff commited on
Commit
2deea22
·
verified ·
1 Parent(s): 0f2b742

Upload index.js with huggingface_hub

Browse files
Files changed (1) hide show
  1. index.js +241 -57
index.js CHANGED
@@ -1,76 +1,260 @@
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
+ import { pipeline, TextStreamer } from 'https://cdn.jsdelivr.net/npm/@huggingface/transformers@3.8.0';
2
 
3
+ // Global variables
4
+ let generator = null;
5
+ let conversationHistory = [];
6
+ let isGenerating = false;
 
7
 
8
+ // DOM elements
9
+ const messagesContainer = document.getElementById('messagesContainer');
10
+ const userInput = document.getElementById('userInput');
11
+ const sendButton = document.getElementById('sendButton');
12
+ const clearButton = document.getElementById('clearButton');
13
+ const statusText = document.getElementById('statusText');
14
+ const progressContainer = document.getElementById('progressContainer');
15
+ const progressBar = document.getElementById('progressBar');
16
 
17
+ // Initialize the application
18
+ async function initialize() {
19
+ try {
20
+ updateStatus('Loading model... This may take 1-2 minutes on first load.', true);
21
 
22
+ // Create a text generation pipeline with progress tracking
23
+ generator = await pipeline(
24
+ "text-generation",
25
+ "onnx-community/Llama-3.2-1B-Instruct-q4f16",
26
+ {
27
+ dtype: "q4f16",
28
+ device: "webgpu",
29
+ progress_callback: (progress) => {
30
+ if (progress.status === 'downloading') {
31
+ const percent = Math.round((progress.loaded / progress.total) * 100);
32
+ updateProgress(percent);
33
+ updateStatus(`Downloading model: ${progress.file} (${percent}%)`, true);
34
+ } else if (progress.status === 'loading') {
35
+ updateStatus(`Loading model into memory...`, true);
36
+ }
37
+ }
38
+ }
39
+ );
40
+
41
+ updateStatus('✓ Model loaded successfully! Ready to chat.', false);
42
+ enableInput();
43
+
44
+ // Initialize conversation with system message
45
+ conversationHistory = [
46
+ { role: "system", content: "You are a helpful, friendly, and knowledgeable AI assistant. Provide clear, concise, and
47
+ accurate responses." }
48
+ ];
49
+
50
+ } catch (error) {
51
+ console.error('Initialization error:', error);
52
+ updateStatus(`❌ Error loading model: ${error.message}`, false);
53
+ showError('Failed to load the model. Please refresh the page and try again.');
54
+ }
55
+ }
56
+
57
+ // Update status bar
58
+ function updateStatus(message, showProgress) {
59
+ statusText.textContent = message;
60
+ progressContainer.style.display = showProgress ? 'block' : 'none';
61
+ }
62
+
63
+ // Update progress bar
64
+ function updateProgress(percent) {
65
+ progressBar.style.width = `${percent}%`;
66
+ }
67
+
68
+ // Enable input controls
69
+ function enableInput() {
70
+ userInput.disabled = false;
71
+ sendButton.disabled = false;
72
+ userInput.focus();
73
+ }
74
+
75
+ // Disable input controls
76
+ function disableInput() {
77
+ userInput.disabled = true;
78
+ sendButton.disabled = true;
79
+ }
80
+
81
+ // Add message to chat
82
+ function addMessage(role, content, isStreaming = false) {
83
+ const messageDiv = document.createElement('div');
84
+ messageDiv.className = `message ${role}`;
85
+
86
+ const contentDiv = document.createElement('div');
87
+ contentDiv.className = 'message-content';
88
+
89
+ const roleLabel = document.createElement('strong');
90
+ roleLabel.textContent = role === 'user' ? 'You:' : 'Assistant:';
91
+
92
+ const messageText = document.createElement('p');
93
+ messageText.textContent = content;
94
+
95
+ contentDiv.appendChild(roleLabel);
96
+ contentDiv.appendChild(messageText);
97
+ messageDiv.appendChild(contentDiv);
98
+
99
+ messagesContainer.appendChild(messageDiv);
100
+ messagesContainer.scrollTop = messagesContainer.scrollHeight;
101
+
102
+ return messageText;
103
+ }
104
+
105
+ // Add typing indicator
106
+ function addTypingIndicator() {
107
+ const messageDiv = document.createElement('div');
108
+ messageDiv.className = 'message assistant';
109
+ messageDiv.id = 'typingIndicator';
110
+
111
+ const contentDiv = document.createElement('div');
112
+ contentDiv.className = 'message-content';
113
+
114
+ const indicator = document.createElement('div');
115
+ indicator.className = 'typing-indicator';
116
+ indicator.innerHTML = '<span></span><span></span><span></span>';
117
 
118
+ contentDiv.appendChild(indicator);
119
+ messageDiv.appendChild(contentDiv);
120
+ messagesContainer.appendChild(messageDiv);
121
+ messagesContainer.scrollTop = messagesContainer.scrollHeight;
122
+ }
123
+
124
+ // Remove typing indicator
125
+ function removeTypingIndicator() {
126
+ const indicator = document.getElementById('typingIndicator');
127
+ if (indicator) {
128
+ indicator.remove();
129
+ }
130
+ }
131
+
132
+ // Generate response
133
+ async function generateResponse(userMessage) {
134
+ if (!generator || isGenerating) return;
135
+
136
+ isGenerating = true;
137
+ disableInput();
138
+
139
+ // Add user message to history and UI
140
+ conversationHistory.push({ role: "user", content: userMessage });
141
+ addMessage('user', userMessage);
142
 
143
+ // Show typing indicator
144
+ addTypingIndicator();
145
+
146
+ try {
147
+ let assistantResponse = '';
148
+ const messageElement = document.createElement('p');
149
+
150
+ // Create streamer with callback
151
+ const streamer = new TextStreamer(generator.tokenizer, {
152
+ skip_prompt: true,
153
+ skip_special_tokens: true,
154
+ callback_function: (text) => {
155
+ assistantResponse += text;
156
+ removeTypingIndicator();
157
+
158
+ // Update or create message element
159
+ if (!messageElement.parentElement) {
160
+ const messageDiv = document.createElement('div');
161
+ messageDiv.className = 'message assistant';
162
+
163
+ const contentDiv = document.createElement('div');
164
+ contentDiv.className = 'message-content';
165
+
166
+ const roleLabel = document.createElement('strong');
167
+ roleLabel.textContent = 'Assistant:';
168
+
169
+ contentDiv.appendChild(roleLabel);
170
+ contentDiv.appendChild(messageElement);
171
+ messageDiv.appendChild(contentDiv);
172
+ messagesContainer.appendChild(messageDiv);
173
+ }
174
 
175
+ messageElement.textContent = assistantResponse;
176
+ messagesContainer.scrollTop = messagesContainer.scrollHeight;
177
+ }
178
+ });
179
 
180
+ // Generate response
181
+ const output = await generator(conversationHistory, {
182
+ max_new_tokens: 512,
183
+ do_sample: false,
184
+ streamer: streamer,
185
  });
186
 
187
+ // Add assistant response to history
188
+ const finalResponse = output[0].generated_text.at(-1).content;
189
+ conversationHistory.push({ role: "assistant", content: finalResponse });
190
 
191
+ updateStatus('✓ Model loaded successfully! Ready to chat.', false);
 
 
 
192
 
193
+ } catch (error) {
194
+ console.error('Generation error:', error);
195
+ removeTypingIndicator();
196
+ addMessage('assistant', `Sorry, I encountered an error: ${error.message}`);
197
+ updateStatus('❌ Error generating response', false);
198
+ } finally {
199
+ isGenerating = false;
200
+ enableInput();
201
  }
202
+ }
203
+
204
+ // Handle send button click
205
+ async function handleSend() {
206
+ const message = userInput.value.trim();
207
+ if (!message || isGenerating) return;
208
+
209
+ userInput.value = '';
210
+ userInput.style.height = 'auto';
211
+ await generateResponse(message);
212
+ }
213
+
214
+ // Handle clear button click
215
+ function handleClear() {
216
+ if (confirm('Are you sure you want to clear the conversation?')) {
217
+ // Keep only system message
218
+ conversationHistory = conversationHistory.slice(0, 1);
219
 
220
+ // Clear UI
221
+ messagesContainer.innerHTML = '';
222
+ addMessage('assistant', "Hello! I'm your AI assistant powered by Gemma. How can I help you today?");
223
 
224
+ userInput.value = '';
225
+ userInput.focus();
226
+ }
227
+ }
228
 
229
+ // Show error message
230
+ function showError(message) {
231
+ const errorDiv = document.createElement('div');
232
+ errorDiv.className = 'message assistant';
233
+ errorDiv.innerHTML = `
234
+ <div class="message-content" style="background: #fee; color: #c33;">
235
+ <strong>Error:</strong>
236
+ <p>${message}</p>
237
+ </div>
238
+ `;
239
+ messagesContainer.appendChild(errorDiv);
240
+ }
241
 
242
+ // Event listeners
243
+ sendButton.addEventListener('click', handleSend);
244
+ clearButton.addEventListener('click', handleClear);
 
 
245
 
246
+ userInput.addEventListener('keydown', (e) => {
247
+ if (e.key === 'Enter' && !e.shiftKey) {
248
+ e.preventDefault();
249
+ handleSend();
250
  }
251
+ });
252
+
253
+ // Auto-resize textarea
254
+ userInput.addEventListener('input', function() {
255
+ this.style.height = 'auto';
256
+ this.style.height = Math.min(this.scrollHeight, 150) + 'px';
257
+ });
258
+
259
+ // Initialize on load
260
+ initialize();