akhaliq HF Staff commited on
Commit
c502257
·
verified ·
1 Parent(s): adcae9a

Upload index.js with huggingface_hub

Browse files
Files changed (1) hide show
  1. index.js +213 -56
index.js CHANGED
@@ -1,76 +1,233 @@
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
+ // DOM Elements
4
+ const messagesContainer = document.getElementById('messages');
5
+ const userInput = document.getElementById('userInput');
6
+ const sendBtn = document.getElementById('sendBtn');
7
  const status = document.getElementById('status');
8
+ const loadingOverlay = document.getElementById('loadingOverlay');
9
+ const loadingText = document.getElementById('loadingText');
10
+ const progressFill = document.getElementById('progressFill');
11
+ const progressText = document.getElementById('progressText');
12
+
13
+ // State
14
+ let generator = null;
15
+ let conversationHistory = [
16
+ { role: "system", content: "You are a helpful, friendly, and knowledgeable AI assistant. Provide clear, concise, and
17
+ accurate responses." }
18
+ ];
19
+ let isGenerating = false;
20
+
21
+ // Initialize the application
22
+ async function initializeApp() {
23
+ try {
24
+ updateLoadingStatus('Loading AI model...', 0);
25
+
26
+ // Create a text generation pipeline with progress callback
27
+ generator = await pipeline(
28
+ "text-generation",
29
+ "onnx-community/Llama-3.2-1B-Instruct-q4f16",
30
+ {
31
+ dtype: "q4f16",
32
+ device: "webgpu",
33
+ progress_callback: (progress) => {
34
+ if (progress.status === 'progress') {
35
+ const percent = Math.round((progress.loaded / progress.total) * 100);
36
+ updateLoadingStatus(`Loading ${progress.file}...`, percent);
37
+ } else if (progress.status === 'done') {
38
+ updateLoadingStatus('Initializing model...', 95);
39
+ }
40
+ }
41
+ }
42
+ );
43
 
44
+ updateLoadingStatus('Ready!', 100);
45
 
46
+ // Hide loading overlay after a short delay
47
+ setTimeout(() => {
48
+ loadingOverlay.classList.add('hidden');
49
+ enableChat();
50
+ }, 500);
51
 
52
+ } catch (error) {
53
+ console.error('Error initializing model:', error);
54
+ updateLoadingStatus('Error loading model. Please refresh the page.', 0);
55
+ status.textContent = 'Failed to load AI model. Please refresh.';
56
+ status.style.color = '#FF3B30';
57
+ }
58
+ }
59
 
60
+ function updateLoadingStatus(text, percent) {
61
+ loadingText.textContent = text;
62
+ progressFill.style.width = `${percent}%`;
63
+ progressText.textContent = `${percent}%`;
64
+ }
65
+
66
+ function enableChat() {
67
+ userInput.disabled = false;
68
+ sendBtn.disabled = false;
69
+ status.textContent = 'Ready to chat';
70
+ userInput.focus();
71
+ }
72
+
73
+ function addMessage(role, content) {
74
+ // Remove welcome message if it exists
75
+ const welcomeMessage = messagesContainer.querySelector('.welcome-message');
76
+ if (welcomeMessage) {
77
+ welcomeMessage.remove();
78
+ }
79
 
80
+ const messageDiv = document.createElement('div');
81
+ messageDiv.className = `message ${role}`;
82
 
83
+ const contentDiv = document.createElement('div');
84
+ contentDiv.className = 'message-content';
85
+ contentDiv.textContent = content;
86
 
87
+ messageDiv.appendChild(contentDiv);
88
+ messagesContainer.appendChild(messageDiv);
89
+
90
+ // Scroll to bottom
91
+ messagesContainer.scrollTop = messagesContainer.scrollHeight;
92
+
93
+ return contentDiv;
94
+ }
95
+
96
+ function addTypingIndicator() {
97
+ const messageDiv = document.createElement('div');
98
+ messageDiv.className = 'message assistant';
99
+ messageDiv.id = 'typing-indicator';
100
+
101
+ const contentDiv = document.createElement('div');
102
+ contentDiv.className = 'message-content';
103
+
104
+ const typingDiv = document.createElement('div');
105
+ typingDiv.className = 'typing-indicator';
106
+ typingDiv.innerHTML = `
107
+ <div class="typing-dot"></div>
108
+ <div class="typing-dot"></div>
109
+ <div class="typing-dot"></div>
110
+ `;
111
+
112
+ contentDiv.appendChild(typingDiv);
113
+ messageDiv.appendChild(contentDiv);
114
+ messagesContainer.appendChild(messageDiv);
115
+
116
+ messagesContainer.scrollTop = messagesContainer.scrollHeight;
117
+
118
+ return messageDiv;
119
+ }
120
+
121
+ function removeTypingIndicator() {
122
+ const indicator = document.getElementById('typing-indicator');
123
+ if (indicator) {
124
+ indicator.remove();
125
+ }
126
+ }
127
+
128
+ async function generateResponse(userMessage) {
129
+ if (isGenerating) return;
130
+
131
+ isGenerating = true;
132
+ sendBtn.disabled = true;
133
+ userInput.disabled = true;
134
+ status.textContent = 'Thinking...';
135
+
136
+ // Add user message to conversation history
137
+ conversationHistory.push({ role: "user", content: userMessage });
138
+
139
+ // Show typing indicator
140
+ const typingIndicator = addTypingIndicator();
141
+
142
+ try {
143
+ let assistantMessage = '';
144
+ let messageElement = null;
145
+
146
+ // Create a custom streamer with callback
147
+ const streamer = new TextStreamer(generator.tokenizer, {
148
+ skip_prompt: true,
149
+ skip_special_tokens: true,
150
+ callback_function: (text) => {
151
+ // Remove typing indicator on first token
152
+ if (!messageElement) {
153
+ removeTypingIndicator();
154
+ messageElement = addMessage('assistant', '');
155
+ }
156
+
157
+ // Append the new text
158
+ assistantMessage += text;
159
+ messageElement.textContent = assistantMessage;
160
+
161
+ // Scroll to bottom
162
+ messagesContainer.scrollTop = messagesContainer.scrollHeight;
163
+ }
164
+ });
165
+
166
+ // Generate response with streaming
167
+ const output = await generator(conversationHistory, {
168
+ max_new_tokens: 512,
169
+ do_sample: false,
170
+ temperature: 0.7,
171
+ streamer: streamer,
172
  });
173
 
174
+ // Get the final response
175
+ const finalResponse = output[0].generated_text.at(-1).content;
176
 
177
+ // Update conversation history
178
+ conversationHistory.push({ role: "assistant", content: finalResponse });
 
 
179
 
180
+ // Ensure the final message is displayed
181
+ if (messageElement) {
182
+ messageElement.textContent = finalResponse;
 
 
 
 
183
  }
184
 
185
+ status.textContent = 'Ready to chat';
186
+
187
+ } catch (error) {
188
+ console.error('Error generating response:', error);
189
+ removeTypingIndicator();
190
+ addMessage('assistant', 'Sorry, I encountered an error. Please try again.');
191
+ status.textContent = 'Error occurred';
192
+ } finally {
193
+ isGenerating = false;
194
+ sendBtn.disabled = false;
195
+ userInput.disabled = false;
196
+ userInput.focus();
197
+ }
198
+ }
199
+
200
+ function handleSend() {
201
+ const message = userInput.value.trim();
202
+
203
+ if (!message || isGenerating) return;
204
+
205
+ // Add user message to UI
206
+ addMessage('user', message);
207
 
208
+ // Clear input
209
+ userInput.value = '';
210
+ userInput.style.height = 'auto';
211
 
212
+ // Generate response
213
+ generateResponse(message);
214
+ }
 
 
 
 
 
 
 
215
 
216
+ // Event Listeners
217
+ sendBtn.addEventListener('click', handleSend);
 
 
 
218
 
219
+ userInput.addEventListener('keydown', (e) => {
220
+ if (e.key === 'Enter' && !e.shiftKey) {
221
+ e.preventDefault();
222
+ handleSend();
223
  }
224
+ });
225
+
226
+ // Auto-resize textarea
227
+ userInput.addEventListener('input', () => {
228
+ userInput.style.height = 'auto';
229
+ userInput.style.height = userInput.scrollHeight + 'px';
230
+ });
231
+
232
+ // Initialize the app
233
+ initializeApp();