akhaliq HF Staff commited on
Commit
73abbf9
·
verified ·
1 Parent(s): a55f7d9

Upload index.js with huggingface_hub

Browse files
Files changed (1) hide show
  1. index.js +215 -67
index.js CHANGED
@@ -1,76 +1,224 @@
1
- import { pipeline } from 'https://cdn.jsdelivr.net/npm/@huggingface/transformers@3.4.1';
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.7.3';
2
+
3
+ class Chatbot {
4
+ constructor() {
5
+ this.generator = null;
6
+ this.messages = [];
7
+ this.isProcessing = false;
8
+ this.useWebGPU = false;
9
+ this.initElements();
10
+ this.initEventListeners();
11
+ this.initModel();
 
 
 
 
 
 
 
 
 
 
 
 
 
12
  }
13
 
14
+ initElements() {
15
+ this.chatMessages = document.getElementById('chatMessages');
16
+ this.userInput = document.getElementById('userInput');
17
+ this.sendButton = document.getElementById('sendButton');
18
+ this.clearButton = document.getElementById('clearButton');
19
+ this.loadingIndicator = document.getElementById('loadingIndicator');
20
+ this.initLoader = document.getElementById('initLoader');
21
+ this.deviceToggle = document.getElementById('deviceToggle');
22
+ this.deviceLabel = document.getElementById('deviceLabel');
23
+ this.charCount = document.getElementById('charCount');
24
+ }
25
 
26
+ initEventListeners() {
27
+ this.sendButton.addEventListener('click', () => this.sendMessage());
28
+ this.clearButton.addEventListener('click', () => this.clearChat());
29
+
30
+ this.userInput.addEventListener('keydown', (e) => {
31
+ if (e.key === 'Enter' && !e.shiftKey) {
32
+ e.preventDefault();
33
+ this.sendMessage();
34
+ }
35
+ });
36
+
37
+ this.userInput.addEventListener('input', () => {
38
+ this.updateCharCount();
39
+ this.autoResize();
40
+ });
41
+
42
+ this.deviceToggle.addEventListener('change', async (e) => {
43
+ if (!this.isProcessing) {
44
+ this.useWebGPU = e.target.checked;
45
+ this.deviceLabel.textContent = this.useWebGPU ? 'GPU' : 'CPU';
46
+ await this.reinitModel();
47
+ } else {
48
+ e.target.checked = !e.target.checked;
49
+ this.showNotification('Please wait for the current process to complete');
50
+ }
51
+ });
52
+
53
+ // Check WebGPU support
54
+ this.checkWebGPUSupport();
55
+ }
56
 
57
+ async checkWebGPUSupport() {
58
+ if (!navigator.gpu) {
59
+ this.deviceToggle.disabled = true;
60
+ this.deviceLabel.textContent = 'CPU (GPU not available)';
61
+ }
62
+ }
63
+
64
+ updateCharCount() {
65
+ const count = this.userInput.value.length;
66
+ this.charCount.textContent = `${count} / 1000`;
67
+ }
68
 
69
+ autoResize() {
70
+ this.userInput.style.height = 'auto';
71
+ const maxHeight = 120;
72
+ const newHeight = Math.min(this.userInput.scrollHeight, maxHeight);
73
+ this.userInput.style.height = newHeight + 'px';
74
+ }
75
 
76
+ async initModel() {
77
+ try {
78
+ this.initLoader.style.display = 'flex';
79
+
80
+ const options = { dtype: "fp32" };
81
+ if (this.useWebGPU && navigator.gpu) {
82
+ options.device = 'webgpu';
83
+ }
84
+
85
+ this.generator = await pipeline(
86
+ "text-generation",
87
+ "onnx-community/MobileLLM-R1-140M-ONNX",
88
+ options
89
+ );
90
+
91
+ this.sendButton.disabled = false;
92
+ this.showNotification('Model loaded successfully!', 'success');
93
+ } catch (error) {
94
+ console.error('Error loading model:', error);
95
+ this.showNotification('Failed to load model. Please refresh and try again.', 'error');
96
+ } finally {
97
+ this.initLoader.style.display = 'none';
98
+ }
99
+ }
100
 
101
+ async reinitModel() {
102
+ this.initLoader.style.display = 'flex';
103
+ this.sendButton.disabled = true;
104
+ await this.initModel();
105
+ }
 
 
 
106
 
107
+ async sendMessage() {
108
+ const message = this.userInput.value.trim();
109
+ if (!message || this.isProcessing || !this.generator) return;
110
+
111
+ this.isProcessing = true;
112
+ this.sendButton.disabled = true;
113
+
114
+ // Add user message to chat
115
+ this.addMessage(message, 'user');
116
+ this.messages.push({ role: "user", content: message });
117
+
118
+ // Clear input
119
+ this.userInput.value = '';
120
+ this.updateCharCount();
121
+ this.autoResize();
122
+
123
+ // Show loading
124
+ this.loadingIndicator.classList.remove('hidden');
125
+
126
+ try {
127
+ // Create container for streaming response
128
+ const responseContainer = this.addMessage('', 'assistant', true);
129
+ const messageContent = responseContainer.querySelector('.message-content');
130
+
131
+ // Custom streamer to update UI
132
+ const streamer = new TextStreamer(this.generator.tokenizer, {
133
+ skip_prompt: true,
134
+ skip_special_tokens: true,
135
+ callback_function: (text) => {
136
+ messageContent.textContent += text;
137
+ this.scrollToBottom();
138
+ }
139
+ });
140
+
141
+ // Generate response
142
+ const output = await this.generator(this.messages, {
143
+ max_new_tokens: 512,
144
+ do_sample: false,
145
+ streamer: streamer,
146
+ });
147
+
148
+ const assistantMessage = output[0].generated_text.at(-1).content;
149
+ this.messages.push({ role: "assistant", content: assistantMessage });
150
+
151
+ } catch (error) {
152
+ console.error('Error generating response:', error);
153
+ this.addMessage('Sorry, I encountered an error. Please try again.', 'error');
154
+ } finally {
155
+ this.loadingIndicator.classList.add('hidden');
156
+ this.isProcessing = false;
157
+ this.sendButton.disabled = false;
158
+ this.userInput.focus();
159
+ }
160
+ }
161
+
162
+ addMessage(content, type, isStreaming = false) {
163
+ // Remove welcome message if it exists
164
+ const welcomeMessage = this.chatMessages.querySelector('.welcome-message');
165
+ if (welcomeMessage) {
166
+ welcomeMessage.remove();
167
+ }
168
+
169
+ const messageDiv = document.createElement('div');
170
+ messageDiv.className = `message ${type}`;
171
+
172
+ const avatar = document.createElement('div');
173
+ avatar.className = 'avatar';
174
+ avatar.textContent = type === 'user' ? '👤' : type === 'error' ? '⚠️' : '🤖';
175
+
176
+ const messageContent = document.createElement('div');
177
+ messageContent.className = 'message-content';
178
+ messageContent.textContent = content;
179
+
180
+ messageDiv.appendChild(avatar);
181
+ messageDiv.appendChild(messageContent);
182
+
183
+ this.chatMessages.appendChild(messageDiv);
184
+ this.scrollToBottom();
185
+
186
+ return messageDiv;
187
+ }
188
+
189
+ scrollToBottom() {
190
+ this.chatMessages.scrollTop = this.chatMessages.scrollHeight;
191
+ }
192
+
193
+ clearChat() {
194
+ this.messages = [];
195
+ this.chatMessages.innerHTML = `
196
+ <div class="welcome-message">
197
+ <div class="welcome-icon">🤖</div>
198
+ <h2>Welcome to AI Assistant</h2>
199
+ <p>I'm powered by MobileLLM, a lightweight language model. Ask me anything!</p>
200
+ </div>
201
+ `;
202
+ }
203
+
204
+ showNotification(message, type = 'info') {
205
+ const notification = document.createElement('div');
206
+ notification.className = `notification ${type}`;
207
+ notification.textContent = message;
208
+ document.body.appendChild(notification);
209
+
210
+ setTimeout(() => {
211
+ notification.classList.add('show');
212
+ }, 10);
213
+
214
+ setTimeout(() => {
215
+ notification.classList.remove('show');
216
+ setTimeout(() => notification.remove(), 300);
217
+ }, 3000);
218
+ }
219
  }
220
+
221
+ // Initialize chatbot when DOM is ready
222
+ document.addEventListener('DOMContentLoaded', () => {
223
+ new Chatbot();
224
+ });