akhaliq HF Staff commited on
Commit
d78a515
·
verified ·
1 Parent(s): 2b21360

Upload index.js with huggingface_hub

Browse files
Files changed (1) hide show
  1. index.js +184 -61
index.js CHANGED
@@ -1,76 +1,199 @@
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 chatMessages = document.getElementById('chatMessages');
5
+ const userInput = document.getElementById('userInput');
6
+ const sendButton = document.getElementById('sendButton');
7
+ const modelStatus = document.getElementById('modelStatus');
8
+ const statusText = document.getElementById('statusText');
9
+ const progressFill = document.getElementById('progressFill');
10
+
11
+ // State
12
+ let generator = null;
13
+ let conversationHistory = [
14
+ { role: "system", content: "You are a helpful, friendly AI assistant. Provide clear, concise, and accurate responses." }
15
+ ];
16
+ let isGenerating = false;
17
+
18
+ // Initialize the application
19
+ async function init() {
20
+ try {
21
+ updateStatus('Loading AI model...', 0);
22
+
23
+ // Create text generation pipeline with progress tracking
24
+ generator = await pipeline(
25
+ "text-generation",
26
+ "onnx-community/Llama-3.2-1B-Instruct-q4f16",
27
+ {
28
+ dtype: "q4f16",
29
+ device: "webgpu",
30
+ progress_callback: (progress) => {
31
+ if (progress.status === 'progress') {
32
+ const percentage = Math.round((progress.loaded / progress.total) * 100);
33
+ updateStatus(`Loading model: ${progress.file}`, percentage);
34
+ }
35
+ }
36
+ }
37
+ );
38
+
39
+ updateStatus('Model ready!', 100);
40
+
41
+ // Enable input after model is loaded
42
+ setTimeout(() => {
43
+ modelStatus.classList.add('ready');
44
+ userInput.disabled = false;
45
+ sendButton.disabled = false;
46
+ userInput.focus();
47
+ }, 500);
48
+
49
+ } catch (error) {
50
+ console.error('Error initializing model:', error);
51
+ updateStatus('Error loading model. Please refresh the page.', 0);
52
+ statusText.style.color = '#FF3B30';
53
+ }
54
+ }
55
 
56
+ // Update status display
57
+ function updateStatus(message, progress) {
58
+ statusText.textContent = message;
59
+ progressFill.style.width = `${progress}%`;
60
+ }
61
 
62
+ // Add message to chat
63
+ function addMessage(role, content, isStreaming = false) {
64
+ const messageDiv = document.createElement('div');
65
+ messageDiv.className = `message ${role}`;
66
+
67
+ const avatar = document.createElement('div');
68
+ avatar.className = 'message-avatar';
69
+ avatar.textContent = role === 'user' ? '👤' : '🤖';
70
+
71
+ const contentDiv = document.createElement('div');
72
+ contentDiv.className = 'message-content';
73
+
74
+ if (isStreaming) {
75
+ contentDiv.innerHTML = `
76
+ <div class="typing-indicator">
77
+ <div class="typing-dot"></div>
78
+ <div class="typing-dot"></div>
79
+ <div class="typing-dot"></div>
80
+ </div>
81
+ `;
82
+ } else {
83
+ contentDiv.innerHTML = formatMessage(content);
84
+ }
85
 
86
+ messageDiv.appendChild(avatar);
87
+ messageDiv.appendChild(contentDiv);
 
 
88
 
89
+ // Remove welcome message if it exists
90
+ const welcomeMessage = chatMessages.querySelector('.welcome-message');
91
+ if (welcomeMessage) {
92
+ welcomeMessage.remove();
93
+ }
94
 
95
+ chatMessages.appendChild(messageDiv);
96
+ chatMessages.scrollTop = chatMessages.scrollHeight;
 
 
 
97
 
98
+ return contentDiv;
99
+ }
100
 
101
+ // Format message content
102
+ function formatMessage(text) {
103
+ // Simple formatting for line breaks
104
+ return text
105
+ .split('\n')
106
+ .map(line => line.trim() ? `<p>${escapeHtml(line)}</p>` : '')
107
+ .join('');
108
+ }
109
 
110
+ // Escape HTML to prevent XSS
111
+ function escapeHtml(text) {
112
+ const div = document.createElement('div');
113
+ div.textContent = text;
114
+ return div.innerHTML;
115
+ }
116
+
117
+ // Handle message sending
118
+ async function sendMessage() {
119
+ const message = userInput.value.trim();
120
+ if (!message || isGenerating || !generator) return;
121
+
122
+ // Add user message
123
+ addMessage('user', message);
124
+ conversationHistory.push({ role: "user", content: message });
125
+
126
+ // Clear input
127
+ userInput.value = '';
128
+ userInput.style.height = 'auto';
129
+
130
+ // Disable input while generating
131
+ isGenerating = true;
132
+ userInput.disabled = true;
133
+ sendButton.disabled = true;
134
+
135
+ try {
136
+ // Add assistant message placeholder with typing indicator
137
+ const assistantContentDiv = addMessage('assistant', '', true);
138
+ let fullResponse = '';
139
+
140
+ // Create streamer for real-time output
141
+ const streamer = new TextStreamer(generator.tokenizer, {
142
+ skip_prompt: true,
143
+ skip_special_tokens: true,
144
+ callback_function: (text) => {
145
+ fullResponse += text;
146
+ assistantContentDiv.innerHTML = formatMessage(fullResponse);
147
+ chatMessages.scrollTop = chatMessages.scrollHeight;
148
+ }
149
+ });
150
+
151
+ // Generate response
152
+ const output = await generator(conversationHistory, {
153
+ max_new_tokens: 512,
154
+ do_sample: true,
155
+ temperature: 0.7,
156
+ top_p: 0.9,
157
+ streamer: streamer
158
  });
159
 
160
+ // Get the final generated text
161
+ const finalResponse = output[0].generated_text.at(-1).content;
162
+
163
+ // Update conversation history
164
+ conversationHistory.push({ role: "assistant", content: finalResponse });
165
 
166
+ // Ensure final response is displayed
167
+ assistantContentDiv.innerHTML = formatMessage(finalResponse);
 
 
168
 
169
+ } catch (error) {
170
+ console.error('Error generating response:', error);
171
+ addMessage('assistant', 'Sorry, I encountered an error. Please try again.');
172
+ } finally {
173
+ // Re-enable input
174
+ isGenerating = false;
175
+ userInput.disabled = false;
176
+ sendButton.disabled = false;
177
+ userInput.focus();
178
+ }
179
  }
180
 
181
+ // Auto-resize textarea
182
+ userInput.addEventListener('input', function() {
183
+ this.style.height = 'auto';
184
+ this.style.height = Math.min(this.scrollHeight, 120) + 'px';
185
+ });
186
+
187
+ // Handle Enter key
188
+ userInput.addEventListener('keydown', (e) => {
189
+ if (e.key === 'Enter' && !e.shiftKey) {
190
+ e.preventDefault();
191
+ sendMessage();
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
192
  }
193
+ });
194
+
195
+ // Send button click
196
+ sendButton.addEventListener('click', sendMessage);
197
+
198
+ // Initialize app when page loads
199
+ init();