akhaliq HF Staff commited on
Commit
10a881a
·
verified ·
1 Parent(s): 6973a62

Upload index.js with huggingface_hub

Browse files
Files changed (1) hide show
  1. index.js +223 -56
index.js CHANGED
@@ -1,76 +1,243 @@
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
+ class AppleChatbot {
2
+ constructor() {
3
+ this.generator = null;
4
+ this.messages = [];
5
+ this.isGenerating = false;
6
+ this.messageHistory = [
7
+ { role: "system", content: "You are a helpful assistant. Be concise, friendly, and helpful in your responses." }
8
+ ];
9
+
10
+ this.initElements();
11
+ this.initEventListeners();
12
+ this.initWorker();
13
+ }
14
+
15
+ initElements() {
16
+ this.elements = {
17
+ messagesContainer: document.getElementById('messages'),
18
+ messageInput: document.getElementById('message-input'),
19
+ sendButton: document.getElementById('send-button'),
20
+ clearButton: document.getElementById('clear-chat'),
21
+ loadingOverlay: document.getElementById('loading-overlay'),
22
+ modelStatus: document.getElementById('model-status'),
23
+ loadingProgress: document.getElementById('loading-progress'),
24
+ progressFill: document.getElementById('progress-fill'),
25
+ typingIndicator: document.getElementById('typing-indicator'),
26
+ welcomeMessage: document.querySelector('.welcome-message'),
27
+ promptChips: document.querySelectorAll('.prompt-chip')
28
+ };
29
+ }
30
 
31
+ initEventListeners() {
32
+ // Send message on Enter (Shift+Enter for new line)
33
+ this.elements.messageInput.addEventListener('keydown', (e) => {
34
+ if (e.key === 'Enter' && !e.shiftKey) {
35
+ e.preventDefault();
36
+ this.sendMessage();
37
+ }
38
+ });
39
 
40
+ // Auto-resize textarea
41
+ this.elements.messageInput.addEventListener('input', () => {
42
+ this.elements.messageInput.style.height = 'auto';
43
+ this.elements.messageInput.style.height = this.elements.messageInput.scrollHeight + 'px';
44
+ });
45
 
46
+ // Send button click
47
+ this.elements.sendButton.addEventListener('click', () => this.sendMessage());
 
 
48
 
49
+ // Clear chat button
50
+ this.elements.clearButton.addEventListener('click', () => this.clearChat());
51
+
52
+ // Prompt chips
53
+ this.elements.promptChips.forEach(chip => {
54
+ chip.addEventListener('click', () => {
55
+ const prompt = chip.getAttribute('data-prompt');
56
+ this.elements.messageInput.value = prompt;
57
+ this.elements.messageInput.style.height = 'auto';
58
+ this.elements.messageInput.style.height = this.elements.messageInput.scrollHeight + 'px';
59
+ this.elements.messageInput.focus();
60
+ });
61
  });
62
+ }
63
+
64
+ initWorker() {
65
+ this.worker = new Worker('worker.js');
66
+
67
+ this.worker.onmessage = (e) => {
68
+ const { type, data } = e.data;
69
+
70
+ switch(type) {
71
+ case 'progress':
72
+ this.updateProgress(data);
73
+ break;
74
+ case 'model-loaded':
75
+ this.onModelLoaded(data);
76
+ break;
77
+ case 'error':
78
+ this.onError(data);
79
+ break;
80
+ }
81
+ };
82
+ }
83
+
84
+ updateProgress(data) {
85
+ const { loaded, total, status } = data;
86
+ const progress = total > 0 ? (loaded / total) * 100 : 0;
87
+
88
+ this.elements.loadingProgress.textContent = status;
89
+ this.elements.progressFill.style.width = `${progress}%`;
90
+ }
91
+
92
+ onModelLoaded(data) {
93
+ this.generator = data.generator;
94
+ this.elements.loadingOverlay.classList.add('hidden');
95
+ this.elements.modelStatus.textContent = 'Gemma 270M - Ready';
96
+ this.elements.messageInput.disabled = false;
97
+ this.elements.sendButton.disabled = false;
98
+ this.elements.messageInput.focus();
99
+ }
100
+
101
+ onError(error) {
102
+ console.error('Error:', error);
103
+ this.elements.loadingProgress.textContent = 'Error loading model. Please refresh the page.';
104
+ this.elements.modelStatus.textContent = 'Error loading model';
105
+ }
106
+
107
+ async sendMessage() {
108
+ const message = this.elements.messageInput.value.trim();
109
+ if (!message || this.isGenerating) return;
110
+
111
+ // Hide welcome message on first message
112
+ if (this.elements.welcomeMessage) {
113
+ this.elements.welcomeMessage.style.display = 'none';
114
+ }
115
 
116
+ // Add user message
117
+ this.addMessage(message, 'user');
118
+ this.messageHistory.push({ role: "user", content: message });
 
 
119
 
120
+ // Clear input
121
+ this.elements.messageInput.value = '';
122
+ this.elements.messageInput.style.height = 'auto';
123
 
124
+ // Show typing indicator
125
+ this.showTypingIndicator();
126
 
127
+ try {
128
+ this.isGenerating = true;
129
+ this.elements.sendButton.disabled = true;
130
+
131
+ // Generate response using streaming
132
+ const streamer = new window.Transformers.TextStreamer(this.generator.tokenizer, {
133
+ skip_prompt: true,
134
+ skip_special_tokens: true,
135
+ callback_function: (text) => {
136
+ this.updateAssistantMessage(text);
137
+ }
138
+ });
139
+
140
+ const output = await this.generator(this.messageHistory, {
141
+ max_new_tokens: 512,
142
+ do_sample: false,
143
+ streamer: streamer,
144
  });
145
 
146
+ // Add complete assistant message to history
147
+ const assistantResponse = output[0].generated_text.at(-1).content;
148
+ this.messageHistory.push({ role: "assistant", content: assistantResponse });
149
+
150
+ } catch (error) {
151
+ console.error('Generation error:', error);
152
+ this.addMessage('Sorry, I encountered an error. Please try again.', 'assistant');
153
+ } finally {
154
+ this.isGenerating = false;
155
+ this.elements.sendButton.disabled = false;
156
+ this.hideTypingIndicator();
157
+ }
158
+ }
159
+
160
+ addMessage(content, role) {
161
+ const messageDiv = document.createElement('div');
162
+ messageDiv.className = `message ${role}`;
163
+
164
+ const avatar = document.createElement('div');
165
+ avatar.className = 'message-avatar';
166
+
167
+ if (role === 'user') {
168
+ avatar.innerHTML = `
169
+ <svg width="24" height="24" viewBox="0 0 24 24" fill="none">
170
+ <circle cx="12" cy="8" r="3" stroke="currentColor" stroke-width="2" />
171
+ <path d="M16 14v1a3 3 0 01-3 3H11a3 3 0 01-3-3v-1" stroke="currentColor" stroke-width="2" stroke-linecap="round" />
172
+ </svg>
173
+ `;
174
+ } else {
175
+ avatar.innerHTML = `
176
+ <svg width="24" height="24" viewBox="0 0 24 24" fill="none">
177
+ <circle cx="12" cy="12" r="10" stroke="currentColor" stroke-width="2" />
178
+ <path d="M8 12h8M12 8v8" stroke="currentColor" stroke-width="2" stroke-linecap="round" />
179
+ </svg>
180
+ `;
181
+ }
182
+
183
+ const contentDiv = document.createElement('div');
184
+ contentDiv.className = 'message-content';
185
+ contentDiv.textContent = content;
186
+
187
+ messageDiv.appendChild(avatar);
188
+ messageDiv.appendChild(contentDiv);
189
+
190
+ this.elements.messagesContainer.appendChild(messageDiv);
191
+ this.scrollToBottom();
192
 
193
+ return messageDiv;
194
+ }
195
+
196
+ updateAssistantMessage(text) {
197
+ if (!this.currentAssistantMessage) {
198
+ this.hideTypingIndicator();
199
+ this.currentAssistantMessage = this.addMessage('', 'assistant');
200
+ }
201
 
202
+ const contentDiv = this.currentAssistantMessage.querySelector('.message-content');
203
+ contentDiv.textContent = text;
204
+ this.scrollToBottom();
 
 
 
 
205
  }
206
 
207
+ showTypingIndicator() {
208
+ this.elements.typingIndicator.classList.remove('hidden');
209
+ this.scrollToBottom();
210
+ }
211
 
212
+ hideTypingIndicator() {
213
+ this.elements.typingIndicator.classList.add('hidden');
214
+ }
215
 
216
+ clearChat() {
217
+ // Clear messages
218
+ const messages = this.elements.messagesContainer.querySelectorAll('.message');
219
+ messages.forEach(msg => msg.remove());
 
 
 
 
 
 
220
 
221
+ // Reset history
222
+ this.messageHistory = [
223
+ { role: "system", content: "You are a helpful assistant. Be concise, friendly, and helpful in your responses." }
224
+ ];
 
225
 
226
+ // Show welcome message
227
+ if (this.elements.welcomeMessage) {
228
+ this.elements.welcomeMessage.style.display = 'block';
229
  }
230
+
231
+ // Clear current message reference
232
+ this.currentAssistantMessage = null;
233
+ }
234
+
235
+ scrollToBottom() {
236
+ this.elements.messagesContainer.scrollTop = this.elements.messagesContainer.scrollHeight;
237
+ }
238
+ }
239
+
240
+ // Initialize the chatbot when DOM is ready
241
+ document.addEventListener('DOMContentLoaded', () => {
242
+ new AppleChatbot();
243
+ });