akhaliq HF Staff commited on
Commit
7754c6d
·
verified ·
1 Parent(s): 339b646

Upload index.js with huggingface_hub

Browse files
Files changed (1) hide show
  1. index.js +196 -60
index.js CHANGED
@@ -1,76 +1,212 @@
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
+ // Main application logic for the chatbot
2
+ class ChatbotApp {
3
+ constructor() {
4
+ this.generator = null;
5
+ this.messages = [
6
+ { role: "system", content: "You are a helpful assistant." }
7
+ ];
8
+ this.isGenerating = false;
9
+ this.init();
10
+ }
11
 
12
+ async init() {
13
+ // Initialize UI elements
14
+ this.loadingScreen = document.getElementById('loadingScreen');
15
+ this.chatContainer = document.getElementById('chatContainer');
16
+ this.messagesArea = document.getElementById('messagesArea');
17
+ this.messageInput = document.getElementById('messageInput');
18
+ this.sendButton = document.getElementById('sendButton');
19
+ this.progressBar = document.getElementById('progressBar');
20
+ this.progressText = document.getElementById('progressText');
21
+
22
+ // Set up event listeners
23
+ this.sendButton.addEventListener('click', () => this.sendMessage());
24
+ this.messageInput.addEventListener('keydown', (e) => this.handleKeyPress(e));
25
+ this.messageInput.addEventListener('input', () => this.adjustTextareaHeight());
26
+
27
+ // Load the model
28
+ await this.loadModel();
29
+ }
30
 
31
+ async loadModel() {
32
+ try {
33
+ // Import transformers.js
34
+ const { pipeline, TextStreamer, env } = await import('https://cdn.jsdelivr.net/npm/@huggingface/transformers');
35
+
36
+ // Configure environment
37
+ env.allowLocalModels = false;
38
+ env.allowRemoteModels = true;
39
+
40
+ // Create a text generation pipeline
41
+ this.generator = await pipeline(
42
+ "text-generation",
43
+ "onnx-community/gemma-3-270m-it-ONNX",
44
+ {
45
+ dtype: "fp32",
46
+ progress_callback: (info) => {
47
+ if (info.status === 'downloading') {
48
+ const progress = Math.round((info.loaded / info.total) * 100);
49
+ this.updateProgress(progress);
50
+ }
51
+ }
52
+ }
53
+ );
54
 
55
+ // Model loaded successfully
56
+ this.loadingScreen.classList.add('hidden');
57
+ this.chatContainer.classList.remove('hidden');
58
+ this.messageInput.focus();
 
59
 
60
+ } catch (error) {
61
+ console.error('Error loading model:', error);
62
+ this.showError('Failed to load model. Please refresh the page and try again.');
63
+ }
64
+ }
65
 
66
+ updateProgress(progress) {
67
+ this.progressBar.style.width = `${progress}%`;
68
+ this.progressText.textContent = `${progress}%`;
69
+ }
70
 
71
+ showError(message) {
72
+ this.loadingScreen.innerHTML = `
73
+ <div class="text-center">
74
+ <div class="inline-flex items-center justify-center w-16 h-16 mb-4 bg-red-100 rounded-full">
75
+ <svg class="w-8 h-8 text-red-500" fill="none" stroke="currentColor" viewBox="0 0 24 24">
76
+ <path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" + "d="M12 8v4m0 4h.01M21 12a9 9 0 11-18 0 9 9 0 0118 0z"></path>
77
+ </svg>
78
+ </div>
79
+ <h2 class="text-xl font-semibold text-gray-900 mb-2">Error</h2>
80
+ <p class="text-gray-500">${message}</p>
81
+ <button onclick="location.reload()" class="mt-4 px-4 py-2 bg-purple-500 text-white rounded-lg hover:bg-purple-600 transition-colors">
82
+ Retry
83
+ </button>
84
+ </div>
85
+ `;
86
+ }
87
 
88
+ handleKeyPress(e) {
89
+ if (e.key === 'Enter' && !e.shiftKey) {
90
+ e.preventDefault();
91
+ this.sendMessage();
92
+ }
93
+ }
94
 
95
+ adjustTextareaHeight() {
96
+ this.messageInput.style.height = 'auto';
97
+ this.messageInput.style.height = Math.min(this.messageInput.scrollHeight, 120) + 'px';
98
+ }
99
 
100
+ async sendMessage() {
101
+ const message = this.messageInput.value.trim();
102
+ if (!message || this.isGenerating) return;
103
+
104
+ // Add user message to UI
105
+ this.addMessageToUI('user', message);
106
+ this.messages.push({ role: "user", content: message });
107
+
108
+ // Clear input
109
+ this.messageInput.value = '';
110
+ this.adjustTextareaHeight();
111
+
112
+ // Disable send button
113
+ this.isGenerating = true;
114
+ this.sendButton.disabled = true;
115
+ this.sendButton.innerHTML = `
116
+ <svg class="w-5 h-5 animate-spin" fill="none" stroke="currentColor" viewBox="0 0 24 24">
117
+ <path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" + "d="M4 4v5h.582m15.356 2A8.001 8.001 0 004.582 9m0 0H9m11 11v-5h-.581m0 0a8.003 8.003 0 01-15.357-2m15.357 2H15">
118
+ </path>
119
+ </svg>
120
+ `;
121
+
122
+ // Add assistant message placeholder
123
+ const assistantMessageId = this.addMessageToUI('assistant', '', true);
124
+
125
+ try {
126
+ // Generate response with streaming
127
+ let fullResponse = '';
128
+ const streamer = new this.generator.tokenizer.TextStreamer(this.generator.tokenizer, {
129
+ skip_prompt: true,
130
+ skip_special_tokens: true,
131
+ callback_function: (text) => {
132
+ fullResponse += text;
133
+ this.updateMessage(assistantMessageId, fullResponse);
134
  }
135
+ });
136
 
137
+ const output = await this.generator(this.messages, {
138
+ max_new_tokens: 512,
139
+ do_sample: false,
140
+ streamer: streamer,
141
+ });
142
 
143
+ const response = output[0].generated_text.at(-1).content;
144
+ this.messages.push({ role: "assistant", content: response });
145
+
146
+ } catch (error) {
147
+ console.error('Error generating response:', error);
148
+ this.updateMessage(assistantMessageId, 'Sorry, I encountered an error. Please try again.');
149
+ } finally {
150
+ // Re-enable send button
151
+ this.isGenerating = false;
152
+ this.sendButton.disabled = false;
153
+ this.sendButton.innerHTML = `
154
+ <svg class="w-5 h-5" fill="none" stroke="currentColor" viewBox="0 0 24 24">
155
+ <path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M12 19l9 2-9-18-9 18 9-2zm0 0v-8"></path>
156
+ </svg>
157
+ `;
158
+ this.messageInput.focus();
159
+ }
160
+ }
161
 
162
+ addMessageToUI(role, content, isStreaming = false) {
163
+ const messageId = Date.now();
164
+ const messageDiv = document.createElement('div');
165
+ messageDiv.className = 'flex items-start space-x-3';
166
+ messageDiv.id = `message-${messageId}`;
167
+
168
+ if (role === 'user') {
169
+ messageDiv.innerHTML = `
170
+ <div class="w-8 h-8 bg-gray-300 rounded-full flex items-center justify-center flex-shrink-0">
171
+ <svg class="w-5 h-5 text-gray-600" fill="none" stroke="currentColor" viewBox="0 0 24 24">
172
+ <path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" + "d="M16 7a4 4 0 11-8 0 4 4 0 018 0zM12 14a7 7 0 00-7 7h14a7 7 0 00-7-7z"></path>
173
+ </svg>
174
+ </div>
175
+ <div class="bg-gray-100 rounded-lg shadow-sm p-4 max-w-md">
176
+ <p class="text-gray-800 whitespace-pre-wrap">${content}</p>
177
+ </div>
178
+ `;
179
+ } else {
180
+ messageDiv.innerHTML = `
181
+ <div
182
+ class="w-8 h-8 bg-gradient-to-br from-purple-500 to-pink-500 rounded-full flex items-center justify-center flex-shrink-0">
183
+ <svg class="w-5 h-5 text-white" fill="none" stroke="currentColor" viewBox="0 0 24 24">
184
+ <path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" + "d="M9.663 17h4.673M12 3v1m6.364 1.636l-.707.707M21 12h-1M4 12H3m3.343-5.657l-.707-.707m2.828 9.9a5 5 0 117.072 0l-.548.547A3.374 3.374 0 0014 18.469V19a2 2 0 11-4 0v-.531c0-.895-.356-1.754-.988-2.386l-.548-.547z">
185
+ </path>
186
+ </svg>
187
+ </div>
188
+ <div class="bg-white rounded-lg shadow-sm p-4 max-w-md">
189
+ <p class="text-gray-800 whitespace-pre-wrap">${isStreaming ? '<span class="animate-pulse">▋</span>' : content}</p>
190
+ </div>
191
+ `;
192
+ }
193
 
194
+ this.messagesArea.appendChild(messageDiv);
195
+ this.messagesArea.scrollTop = this.messagesArea.scrollHeight;
196
+ return messageId;
197
+ }
 
198
 
199
+ updateMessage(messageId, content) {
200
+ const messageElement = document.getElementById(`message-${messageId}`);
201
+ if (messageElement) {
202
+ const contentElement = messageElement.querySelector('.bg-white p, .bg-gray-100 p');
203
+ contentElement.innerHTML = content + '<span class="animate-pulse">▋</span>';
204
+ this.messagesArea.scrollTop = this.messagesArea.scrollHeight;
205
  }
206
+ }
207
+ }
208
+
209
+ // Initialize the app when DOM is loaded
210
+ document.addEventListener('DOMContentLoaded', () => {
211
+ new ChatbotApp();
212
+ });