akhaliq HF Staff commited on
Commit
28ba546
·
verified ·
1 Parent(s): ec7cabf

Upload index.js with huggingface_hub

Browse files
Files changed (1) hide show
  1. index.js +147 -67
index.js CHANGED
@@ -1,76 +1,156 @@
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.audio = null;
6
+ this.isGenerating = false;
7
+ this.device = 'cpu';
8
+
9
+ this.initElements();
10
+ this.bindEvents();
11
+ this.checkWebGPUSupport();
 
 
 
 
 
 
 
 
 
 
 
 
 
12
  }
13
 
14
+ initElements() {
15
+ this.textInput = document.getElementById('text-input');
16
+ this.generateBtn = document.getElementById('generate-btn');
17
+ this.playBtn = document.getElementById('play-btn');
18
+ this.stopBtn = document.getElementById('stop-btn');
19
+ this.deviceSelect = document.getElementById('device-select');
20
+ this.status = document.getElementById('status');
21
+ this.audioPlayer = document.getElementById('audio-player');
22
+ this.downloadSection = document.getElementById('download-section');
23
+ this.downloadLink = document.getElementById('download-link');
24
+ this.loadingSpinner = this.generateBtn.querySelector('.loading-spinner');
25
+ this.btnText = this.generateBtn.querySelector('.btn-text');
26
+ }
27
 
28
+ bindEvents() {
29
+ this.generateBtn.addEventListener('click', () => this.generateSpeech());
30
+ this.playBtn.addEventListener('click', () => this.playAudio());
31
+ this.stopBtn.addEventListener('click', () => this.stopAudio());
32
+ this.deviceSelect.addEventListener('change', (e) => {
33
+ this.device = e.target.value;
34
+ this.status.textContent = `Switched to ${this.device.toUpperCase()} mode`;
35
+ });
36
+ }
37
 
38
+ async checkWebGPUSupport() {
39
+ if (!navigator.gpu) {
40
+ this.deviceSelect.querySelector('option[value="webgpu"]').disabled = true;
41
+ this.deviceSelect.value = 'cpu';
42
+ this.device = 'cpu';
43
+ this.status.textContent = 'WebGPU not supported - using CPU mode';
44
+ }
45
+ }
46
 
47
+ async initModel() {
48
+ try {
49
+ this.setStatus('Loading Supertonic TTS model...', 'loading');
50
+
51
+ const deviceOptions = this.device === 'webgpu' ? { device: 'webgpu' } : {};
52
+
53
+ this.tts = await window.pipeline('text-to-speech', 'onnx-community/Supertonic-TTS-ONNX', {
54
+ dtype: 'fp32',
55
+ ...deviceOptions
56
+ });
57
+
58
+ this.setStatus('Model loaded successfully! Ready to generate speech.', 'success');
59
+ return true;
60
+ } catch (error) {
61
+ console.error('Failed to load model:', error);
62
+ this.setStatus(`Failed to load model: ${error.message}`, 'error');
63
+ return false;
64
+ }
65
+ }
66
 
67
+ async generateSpeech() {
68
+ if (this.isGenerating) return;
69
+
70
+ const inputText = this.textInput.value.trim();
71
+ if (!inputText) {
72
+ this.setStatus('Please enter some text to convert to speech.', 'warning');
73
+ return;
74
+ }
75
+
76
+ if (!this.tts) {
77
+ const modelLoaded = await this.initModel();
78
+ if (!modelLoaded) return;
79
+ }
80
+
81
+ this.isGenerating = true;
82
+ this.updateGenerateButton(false);
83
+ this.setStatus('Generating speech... This may take a moment on first run.', 'loading');
84
+
85
+ try {
86
+ // Note: Supertonic TTS typically requires speaker embeddings
87
+ // For demo, we'll try without or use a placeholder
88
+ // In production, you'd need to bundle speaker embeddings
89
+ const audio = await this.tts(inputText, {
90
+ speaker_embeddings: null // Placeholder - real app would load actual embeddings
91
+ });
92
+
93
+ // Convert to playable audio
94
+ this.audio = audio;
95
+ await this.saveAudio(audio);
96
+
97
+ this.setStatus('Speech generated successfully! Click play to listen.', 'success');
98
+ this.enableAudioControls();
99
+ } catch (error) {
100
+ console.error('TTS generation failed:', error);
101
+ this.setStatus(`Generation failed: ${error.message}`, 'error');
102
+ } finally {
103
+ this.isGenerating = false;
104
+ this.updateGenerateButton(true);
105
+ }
106
+ }
107
 
108
+ async saveAudio(audio) {
109
+ try {
110
+ // Save as WAV blob
111
+ const wavBlob = await audio.save('speech.wav');
112
+ this.audioPlayer.src = URL.createObjectURL(wavBlob);
113
+
114
+ // Create download link
115
+ this.downloadLink.href = URL.createObjectURL(wavBlob);
116
+ this.downloadSection.style.display = 'block';
117
+ } catch (error) {
118
+ console.error('Failed to save audio:', error);
119
+ this.setStatus('Audio generated but download failed.', 'warning');
120
+ }
121
+ }
122
+
123
+ playAudio() {
124
+ this.audioPlayer.play();
125
+ this.playBtn.disabled = true;
126
+ this.stopBtn.disabled = false;
127
+ }
128
 
129
+ stopAudio() {
130
+ this.audioPlayer.pause();
131
+ this.audioPlayer.currentTime = 0;
132
+ this.playBtn.disabled = false;
133
+ this.stopBtn.disabled = true;
134
+ }
135
+
136
+ enableAudioControls() {
137
+ this.playBtn.disabled = false;
138
+ this.stopBtn.disabled = true;
139
+ }
140
+
141
+ updateGenerateButton(enabled) {
142
+ this.generateBtn.disabled = !enabled;
143
+ this.loadingSpinner.style.display = enabled ? 'none' : 'inline-block';
144
+ this.btnText.textContent = enabled ? 'Generate Speech' : 'Generating...';
145
+ }
146
+
147
+ setStatus(message, type = 'info') {
148
+ this.status.textContent = message;
149
+ this.status.className = `status ${type}`;
150
+ }
 
 
 
 
151
  }
152
+
153
+ // Initialize app when DOM is loaded
154
+ document.addEventListener('DOMContentLoaded', () => {
155
+ new SupertonicTTS();
156
+ });