akhaliq HF Staff commited on
Commit
2855846
·
verified ·
1 Parent(s): ed21e2c

Upload index.js with huggingface_hub

Browse files
Files changed (1) hide show
  1. index.js +205 -67
index.js CHANGED
@@ -1,76 +1,214 @@
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
+ // index.js
2
+ class SupertonicTTS {
3
+ constructor() {
4
+ this.tts = null;
5
+ this.currentAudio = null;
6
+ this.isGenerating = false;
7
+ this.device = 'cpu';
8
+
9
+ this.initElements();
10
+ this.bindEvents();
11
+ this.checkWebGPU();
 
 
 
 
 
 
 
 
 
 
 
 
 
12
  }
13
 
14
+ initElements() {
15
+ this.textInput = document.getElementById('textInput');
16
+ this.generateBtn = document.getElementById('generateBtn');
17
+ this.playBtn = document.getElementById('playBtn');
18
+ this.downloadBtn = document.getElementById('downloadBtn');
19
+ this.regenerateBtn = document.getElementById('regenerateBtn');
20
+ this.audioPlayer = document.getElementById('audioPlayer');
21
+ this.deviceToggle = document.getElementById('deviceToggle');
22
+ this.deviceText = document.getElementById('deviceText');
23
+ this.status = document.getElementById('status');
24
+ this.audioSection = document.getElementById('audioSection');
25
+ this.charCount = document.getElementById('charCount');
26
+ }
27
 
28
+ bindEvents() {
29
+ this.textInput.addEventListener('input', () => this.updateCharCount());
30
+ this.generateBtn.addEventListener('click', () => this.generateSpeech());
31
+ this.playBtn.addEventListener('click', () => this.playAudio());
32
+ this.downloadBtn.addEventListener('click', () => this.downloadAudio());
33
+ this.regenerateBtn.addEventListener('click', () => this.regenerate());
34
+ this.deviceToggle.addEventListener('change', (e) => this.toggleDevice(e.target.checked));
35
+ this.audioPlayer.addEventListener('ended', () => this.updatePlayButton(true));
36
+ }
37
 
38
+ async checkWebGPU() {
39
+ if (navigator.gpu) {
40
+ this.deviceText.textContent = 'GPU Available';
41
+ this.deviceToggle.disabled = false;
42
+ } else {
43
+ this.deviceText.textContent = 'GPU Not Supported';
44
+ }
45
+ }
46
 
47
+ toggleDevice(enabled) {
48
+ this.device = enabled ? 'webgpu' : 'cpu';
49
+ this.deviceText.textContent = enabled ? 'GPU Mode' : 'CPU Mode';
50
+ if (this.tts) {
51
+ this.showStatus('Device changed. Please regenerate audio.', 'info');
52
+ }
53
+ }
54
 
55
+ updateCharCount() {
56
+ const length = this.textInput.value.length;
57
+ this.charCount.textContent = `${length}/500`;
58
+ this.generateBtn.disabled = !this.textInput.value.trim() || length > 500 || this.isGenerating;
59
+ }
60
 
61
+ async initTTS() {
62
+ try {
63
+ this.showStatus('Loading Supertonic TTS model...', 'loading');
64
+
65
+ const options = {
66
+ dtype: 'fp32'
67
+ };
68
+
69
+ if (this.device === 'webgpu') {
70
+ options.device = 'webgpu';
71
+ }
72
+
73
+ // Note: For demo purposes, we'll use speaker_embeddings as a placeholder
74
+ // In production, host actual speaker files or use default
75
+ this.tts = await window.pipeline('text-to-speech', 'onnx-community/Supertonic-TTS-ONNX', options);
76
+
77
+ this.showStatus('Model loaded successfully! Ready to generate speech.', 'success');
78
+ this.generateBtn.disabled = false;
79
+ } catch (error) {
80
+ console.error('Failed to load TTS model:', error);
81
+ this.showStatus(`Failed to load model: ${error.message}. Retrying in CPU mode...`, 'error');
82
+ // Fallback to CPU
83
+ try {
84
+ this.tts = await window.pipeline('text-to-speech', 'onnx-community/Supertonic-TTS-ONNX', { dtype: 'fp32' });
85
+ this.showStatus('Model loaded in CPU mode!', 'success');
86
+ this.generateBtn.disabled = false;
87
+ } catch (fallbackError) {
88
+ this.showStatus('Failed to load model. Please refresh and try again.', 'error');
89
+ }
90
+ }
91
+ }
92
+
93
+ async generateSpeech() {
94
+ if (this.isGenerating) return;
95
+
96
+ const text = this.textInput.value.trim();
97
+ if (!text) {
98
+ this.showStatus('Please enter some text to convert to speech.', 'error');
99
+ return;
100
+ }
101
+
102
+ this.isGenerating = true;
103
+ this.generateBtn.disabled = true;
104
+ this.setButtonLoading(true);
105
+
106
+ try {
107
+ this.showStatus('Generating speech...', 'loading');
108
+
109
+ // Generate audio - note: speaker_embeddings path simplified for demo
110
+ // In production, host actual speaker embedding files
111
+ const audio = await this.tts(text, {
112
+ speaker_embeddings: 'https://huggingface.co/datasets/Supertonic/Supertonic-TTS-ONNX/resolve/main/voices/F1.bin'
113
+ });
114
+
115
+ // Convert to playable audio
116
+ this.currentAudio = audio;
117
+
118
+ // Create blob URL for audio player
119
+ const audioBlob = await audio.save();
120
+ const audioUrl = URL.createObjectURL(audioBlob);
121
+ this.audioPlayer.src = audioUrl;
122
+
123
+ this.audioSection.classList.remove('hidden');
124
+ this.downloadBtn.disabled = false;
125
+ this.updatePlayButton(true);
126
+
127
+ this.showStatus('Speech generated successfully! Click play to listen.', 'success');
128
+
129
+ } catch (error) {
130
+ console.error('TTS generation failed:', error);
131
+ this.showStatus(`Generation failed: ${error.message}`, 'error');
132
+ } finally {
133
+ this.isGenerating = false;
134
+ this.setButtonLoading(false);
135
+ this.generateBtn.disabled = false;
136
+ }
137
+ }
138
+
139
+ playAudio() {
140
+ if (this.audioPlayer.paused) {
141
+ this.audioPlayer.play();
142
+ this.updatePlayButton(false);
143
+ } else {
144
+ this.audioPlayer.pause();
145
+ this.updatePlayButton(true);
146
+ }
147
+ }
148
 
149
+ updatePlayButton(isPaused) {
150
+ const icon = this.playBtn.querySelector('svg');
151
+ if (isPaused) {
152
+ icon.innerHTML = '<path d="M8 5v14l11-7z"/>';
153
+ this.playBtn.title = 'Play audio';
154
+ } else {
155
+ icon.innerHTML = '<path d="M6 19h4V5H6v14zm8-14v14h4V5h-4z"/>';
156
+ this.playBtn.title = 'Pause audio';
157
+ }
158
+ }
159
+
160
+ async downloadAudio() {
161
+ if (this.currentAudio) {
162
+ const audioBlob = await this.currentAudio.save();
163
+ const url = URL.createObjectURL(audioBlob);
164
+ const a = document.createElement('a');
165
+ a.href = url;
166
+ a.download = 'supertonic-speech.wav';
167
+ document.body.appendChild(a);
168
+ a.click();
169
+ document.body.removeChild(a);
170
+ URL.revokeObjectURL(url);
171
+ }
172
+ }
173
+
174
+ regenerate() {
175
+ this.textInput.value = '';
176
+ this.audioSection.classList.add('hidden');
177
+ this.downloadBtn.disabled = true;
178
+ this.currentAudio = null;
179
+ this.audioPlayer.src = '';
180
+ this.updateCharCount();
181
+ }
182
+
183
+ setButtonLoading(loading) {
184
+ const spinner = this.generateBtn.querySelector('.spinner');
185
+ const btnText = this.generateBtn.querySelector('.btn-text');
186
+ if (loading) {
187
+ spinner.style.display = 'inline-block';
188
+ btnText.textContent = 'Generating...';
189
+ } else {
190
+ spinner.style.display = 'none';
191
+ btnText.textContent = 'Generate Speech';
192
+ }
193
+ }
194
+
195
+ showStatus(message, type) {
196
+ this.status.textContent = message;
197
+ this.status.className = `status ${type}`;
198
+ this.status.classList.remove('hidden');
199
+
200
+ if (type !== 'loading') {
201
+ setTimeout(() => {
202
+ this.status.classList.add('hidden');
203
+ }, 5000);
204
+ }
205
+ }
206
  }
207
+
208
+ // Initialize app when DOM is loaded
209
+ document.addEventListener('DOMContentLoaded', () => {
210
+ const app = new SupertonicTTS();
211
+
212
+ // Auto-initialize TTS model
213
+ setTimeout(() => app.initTTS(), 100);
214
+ });