GitHub Action commited on
Commit
d3f86d8
·
1 Parent(s): 47efcbd

Sync from GitHub: ffdd28283d24c66d2e788d9b4a630d7d9f76b0a1

Browse files
This view is limited to 50 files because it contains too many changes.   See raw diff
Files changed (50) hide show
  1. .gitattributes +6 -0
  2. .gitignore.backup +280 -0
  3. .gitignore.hf +40 -0
  4. CLAUDE.md +142 -0
  5. MANIFEST.in +1 -0
  6. QUICKSTART.md +116 -0
  7. README.md +75 -1
  8. README_SPACE.md +86 -0
  9. TECHNICAL_SPECS.md +337 -0
  10. app.py +9 -0
  11. frontend/package-lock.json +0 -0
  12. frontend/package.json +37 -0
  13. frontend/postcss.config.js +6 -0
  14. frontend/src/app.css +93 -0
  15. frontend/src/app.html +13 -0
  16. frontend/src/routes/+layout.svelte +185 -0
  17. frontend/src/routes/+page.svelte +499 -0
  18. frontend/src/routes/api/auth/token/+server.js +46 -0
  19. frontend/src/routes/auth/callback/+page.svelte +99 -0
  20. frontend/static/assets/hf-logo.png +3 -0
  21. frontend/static/assets/hf-studio-logo.png +3 -0
  22. frontend/static/samples/harvard.wav +3 -0
  23. frontend/svelte.config.js +18 -0
  24. frontend/tailwind.config.js +44 -0
  25. frontend/vite.config.js +10 -0
  26. hfstudio/__init__.py +17 -0
  27. hfstudio/__main__.py +4 -0
  28. hfstudio/cli.py +32 -0
  29. hfstudio/server.py +217 -0
  30. hfstudio/static/_app/env.js +1 -0
  31. hfstudio/static/_app/immutable/assets/0.DkRYx-5s.css +1 -0
  32. hfstudio/static/_app/immutable/chunks/9DiovRey.js +1 -0
  33. hfstudio/static/_app/immutable/chunks/BHHrQo_1.js +1 -0
  34. hfstudio/static/_app/immutable/chunks/Dh5qNFGZ.js +3 -0
  35. hfstudio/static/_app/immutable/chunks/IHki7fMi.js +1 -0
  36. hfstudio/static/_app/immutable/entry/app.DrVe4Aen.js +2 -0
  37. hfstudio/static/_app/immutable/entry/start.CYVq8xer.js +1 -0
  38. hfstudio/static/_app/immutable/nodes/0.BWfnr5bB.js +1 -0
  39. hfstudio/static/_app/immutable/nodes/1.DRlzjau5.js +1 -0
  40. hfstudio/static/_app/immutable/nodes/2.BSR-L-2e.js +16 -0
  41. hfstudio/static/_app/immutable/nodes/3.VqKPhUiT.js +1 -0
  42. hfstudio/static/_app/version.json +1 -0
  43. hfstudio/static/assets/hf-logo.png +3 -0
  44. hfstudio/static/assets/hf-studio-logo.png +3 -0
  45. hfstudio/static/index.html +35 -0
  46. hfstudio/static/samples/harvard.wav +3 -0
  47. package-lock.json +6 -0
  48. pyproject.toml +63 -0
  49. requirements.txt +8 -0
  50. requirements_space.txt +8 -0
.gitattributes CHANGED
@@ -7,3 +7,9 @@
7
  *.mp4 filter=lfs diff=lfs merge=lfs -text
8
  *.webm filter=lfs diff=lfs merge=lfs -text
9
  *.pdf filter=lfs diff=lfs merge=lfs -text
 
 
 
 
 
 
 
7
  *.mp4 filter=lfs diff=lfs merge=lfs -text
8
  *.webm filter=lfs diff=lfs merge=lfs -text
9
  *.pdf filter=lfs diff=lfs merge=lfs -text
10
+ hfstudio/static/assets/hf-studio-logo.png filter=lfs diff=lfs merge=lfs -text
11
+ hfstudio/static/assets/hf-logo.png filter=lfs diff=lfs merge=lfs -text
12
+ frontend/static/assets/hf-studio-logo.png filter=lfs diff=lfs merge=lfs -text
13
+ frontend/static/assets/hf-logo.png filter=lfs diff=lfs merge=lfs -text
14
+ hfstudio/static/samples/harvard.wav filter=lfs diff=lfs merge=lfs -text
15
+ frontend/static/samples/harvard.wav filter=lfs diff=lfs merge=lfs -text
.gitignore.backup ADDED
@@ -0,0 +1,280 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ # Python
2
+ __pycache__/
3
+ *.py[cod]
4
+ *$py.class
5
+ *.so
6
+ .Python
7
+ build/
8
+ develop-eggs/
9
+ dist/
10
+ downloads/
11
+ eggs/
12
+ .eggs/
13
+ lib/
14
+ lib64/
15
+ parts/
16
+ sdist/
17
+ var/
18
+ wheels/
19
+ share/python-wheels/
20
+ *.egg-info/
21
+ .installed.cfg
22
+ *.egg
23
+ MANIFEST
24
+
25
+ # PyInstaller
26
+ *.manifest
27
+ *.spec
28
+
29
+ # Installer logs
30
+ pip-log.txt
31
+ pip-delete-this-directory.txt
32
+
33
+ # Unit test / coverage reports
34
+ htmlcov/
35
+ .tox/
36
+ .nox/
37
+ .coverage
38
+ .coverage.*
39
+ .cache
40
+ nosetests.xml
41
+ coverage.xml
42
+ *.cover
43
+ *.py,cover
44
+ .hypothesis/
45
+ .pytest_cache/
46
+ cover/
47
+
48
+ # Translations
49
+ *.mo
50
+ *.pot
51
+
52
+ # Django stuff:
53
+ *.log
54
+ local_settings.py
55
+ db.sqlite3
56
+ db.sqlite3-journal
57
+
58
+ # Flask stuff:
59
+ instance/
60
+ .webassets-cache
61
+
62
+ # Scrapy stuff:
63
+ .scrapy
64
+
65
+ # Sphinx documentation
66
+ docs/_build/
67
+
68
+ # PyBuilder
69
+ .pybuilder/
70
+ target/
71
+
72
+ # Jupyter Notebook
73
+ .ipynb_checkpoints
74
+
75
+ # IPython
76
+ profile_default/
77
+ ipython_config.py
78
+
79
+ # pyenv
80
+ .python-version
81
+
82
+ # pipenv
83
+ Pipfile.lock
84
+
85
+ # poetry
86
+ poetry.lock
87
+
88
+ # pdm
89
+ .pdm.toml
90
+
91
+ # PEP 582
92
+ __pypackages__/
93
+
94
+ # Celery stuff
95
+ celerybeat-schedule
96
+ celerybeat.pid
97
+
98
+ # SageMath parsed files
99
+ *.sage.py
100
+
101
+ # Environments
102
+ .env
103
+ .venv
104
+ env/
105
+ venv/
106
+ ENV/
107
+ env.bak/
108
+ venv.bak/
109
+
110
+ # Spyder project settings
111
+ .spyderproject
112
+ .spyproject
113
+
114
+ # Rope project settings
115
+ .ropeproject
116
+
117
+ # mkdocs documentation
118
+ /site
119
+
120
+ # mypy
121
+ .mypy_cache/
122
+ .dmypy.json
123
+ dmypy.json
124
+
125
+ # Pyre type checker
126
+ .pyre/
127
+
128
+ # pytype static type analyzer
129
+ .pytype/
130
+
131
+ # Cython debug symbols
132
+ cython_debug/
133
+
134
+ # Node.js
135
+ node_modules/
136
+ npm-debug.log*
137
+ yarn-debug.log*
138
+ yarn-error.log*
139
+ lerna-debug.log*
140
+ .pnpm-debug.log*
141
+
142
+ # Diagnostic reports (https://nodejs.org/api/report.html)
143
+ report.[0-9]*.[0-9]*.[0-9]*.[0-9]*.json
144
+
145
+ # Runtime data
146
+ pids
147
+ *.pid
148
+ *.seed
149
+ *.pid.lock
150
+
151
+ # Directory for instrumented libs generated by jscoverage/JSCover
152
+ lib-cov
153
+
154
+ # Coverage directory used by tools like istanbul
155
+ coverage
156
+ *.lcov
157
+
158
+ # nyc test coverage
159
+ .nyc_output
160
+
161
+ # Grunt intermediate storage (https://gruntjs.com/creating-plugins#storing-task-files)
162
+ .grunt
163
+
164
+ # Bower dependency directory (https://bower.io/)
165
+ bower_components
166
+
167
+ # node-waf configuration
168
+ .lock-wscript
169
+
170
+ # Compiled binary addons (https://nodejs.org/api/addons.html)
171
+ build/Release
172
+
173
+ # Dependency directories
174
+ jspm_packages/
175
+
176
+ # Snowpack dependency directory (https://snowpack.dev/)
177
+ web_modules/
178
+
179
+ # TypeScript cache
180
+ *.tsbuildinfo
181
+
182
+ # Optional npm cache directory
183
+ .npm
184
+
185
+ # Optional eslint cache
186
+ .eslintcache
187
+
188
+ # Optional stylelint cache
189
+ .stylelintcache
190
+
191
+ # Microbundle cache
192
+ .rpt2_cache/
193
+ .rts2_cache_cjs/
194
+ .rts2_cache_es/
195
+ .rts2_cache_umd/
196
+
197
+ # Optional REPL history
198
+ .node_repl_history
199
+
200
+ # Output of 'npm pack'
201
+ *.tgz
202
+
203
+ # Yarn Integrity file
204
+ .yarn-integrity
205
+
206
+ # dotenv environment variable files
207
+ .env.development.local
208
+ .env.test.local
209
+ .env.production.local
210
+ .env.local
211
+
212
+ # parcel-bundler cache (https://parceljs.org/)
213
+ .cache
214
+ .parcel-cache
215
+
216
+ # Next.js build output
217
+ .next
218
+ out
219
+
220
+ # Nuxt.js build / generate output
221
+ .nuxt
222
+ dist
223
+
224
+ # Gatsby files
225
+ .cache/
226
+ public
227
+
228
+ # Vuepress build output
229
+ .vuepress/dist
230
+
231
+ # Vuepress v2.x temp and cache directory
232
+ .temp
233
+ .cache
234
+
235
+ # Docusaurus cache and generated files
236
+ .docusaurus
237
+
238
+ # Serverless directories
239
+ .serverless/
240
+
241
+ # FuseBox cache
242
+ .fusebox/
243
+
244
+ # DynamoDB Local files
245
+ .dynamodb/
246
+
247
+ # TernJS port file
248
+ .tern-port
249
+
250
+ # Stores VSCode versions used for testing VSCode extensions
251
+ .vscode-test
252
+
253
+ # yarn v2
254
+ .yarn/cache
255
+ .yarn/unplugged
256
+ .yarn/build-state.yml
257
+ .yarn/install-state.gz
258
+ .pnp.*
259
+
260
+ # SvelteKit
261
+ .svelte-kit
262
+
263
+ # Vite
264
+ .vite
265
+
266
+ # IDE
267
+ .vscode/
268
+ .idea/
269
+ *.swp
270
+ *.swo
271
+ *~
272
+
273
+ # OS
274
+ .DS_Store
275
+ .DS_Store?
276
+ ._*
277
+ .Spotlight-V100
278
+ .Trashes
279
+ ehthumbs.db
280
+ Thumbs.db
.gitignore.hf ADDED
@@ -0,0 +1,40 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ # Node.js dependencies and build artifacts
2
+ frontend/node_modules/
3
+ frontend/.svelte-kit/
4
+ frontend/build/
5
+
6
+ # Python cache
7
+ __pycache__/
8
+ *.pyc
9
+ *.pyo
10
+ *.pyd
11
+ .Python
12
+ env/
13
+ venv/
14
+ .env
15
+ .venv
16
+ pip-log.txt
17
+ pip-delete-this-directory.txt
18
+
19
+ # Build artifacts
20
+ dist/
21
+ build/
22
+ *.egg-info/
23
+
24
+ # IDE and editor files
25
+ .vscode/
26
+ .idea/
27
+ *.swp
28
+ *.swo
29
+ *~
30
+
31
+ # OS files
32
+ .DS_Store
33
+ Thumbs.db
34
+
35
+ # Git
36
+ .git/
37
+ .gitignore
38
+
39
+ # Don't ignore the built static files for the Space
40
+ !hfstudio/static/
CLAUDE.md ADDED
@@ -0,0 +1,142 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ # CLAUDE.md
2
+
3
+ This file provides guidance to Claude Code (claude.ai/code) when working with code in this repository.
4
+
5
+ ## Development Commands
6
+
7
+ ### Quick Start (Recommended)
8
+ ```bash
9
+ ./run_dev.sh
10
+ ```
11
+ This single script starts both frontend (port 11111) and backend (port 11110) with auto-browser opening.
12
+
13
+ ### Manual Development Setup
14
+
15
+ **Frontend (Svelte):**
16
+ ```bash
17
+ cd frontend
18
+ npm install
19
+ npm run dev # Development server on :11111
20
+ npm run build # Production build
21
+ npm run check # Type checking
22
+ ```
23
+
24
+ **Backend (FastAPI):**
25
+ ```bash
26
+ cd backend
27
+ pip install -r requirements.txt
28
+ python -m hfstudio.cli --dev # Development server on :11110
29
+ # OR
30
+ pip install -e .
31
+ hfstudio --dev
32
+ ```
33
+
34
+ ### Port Configuration
35
+ - Frontend: 11111 (configured in `vite.config.js`)
36
+ - Backend: 7860 (configured in `cli.py`)
37
+ - CORS is configured for these specific ports in `server.py`
38
+
39
+ ## Architecture Overview
40
+
41
+ ### Frontend Structure (SvelteKit + TailwindCSS)
42
+ - **Single Page App**: Main interface in `src/routes/+page.svelte`
43
+ - **Layout**: Global layout with sidebar in `src/routes/+layout.svelte`
44
+ - **Design System**: HuggingFace brand colors (`#FFD21E`, `#FF9D00`) used throughout
45
+ - **State Management**: Local component state with reactive variables
46
+ - **Audio Handling**: Custom HTML5 audio element with manual progress tracking
47
+
48
+ ### Key UI Components
49
+ - **Three-panel layout**: Sidebar (56 units) + Main content + Settings panel (80 units)
50
+ - **Fixed bottom button**: Generate button positioned absolutely at page bottom
51
+ - **Mini audio player**: Compact controls in generated audio card
52
+ - **Full audio player**: Expanded controls with ElevenLabs-style design
53
+ - **Custom pause icon**: CSS-only filled bars instead of outline
54
+
55
+ ### Backend Structure (FastAPI)
56
+ - **Main server**: `server.py` with CORS configured for development ports
57
+ - **CLI interface**: `cli.py` with typer for command-line control
58
+ - **Pydantic models**: TTSRequest, TTSResponse, Voice, Model
59
+ - **Current implementation**: Mock TTS generation using placeholder audio
60
+
61
+ ### API Endpoints
62
+ ```
63
+ GET / - Health check
64
+ GET /api/status - Mode and availability info
65
+ GET /api/voices - Available voice list
66
+ GET /api/models - Available model list
67
+ POST /api/tts/generate - Generate speech from text
68
+ ```
69
+
70
+ ## Design Patterns & Conventions
71
+
72
+ ### Frontend Patterns
73
+ - **HF Brand Integration**: Uses official logo (`/assets/hf-logo.png`) and gradient colors
74
+ - **Responsive Controls**: All sliders use custom `.slider-hf` class with HF colors
75
+ - **Audio State Management**: Manual synchronization between UI state and HTML5 audio element
76
+ - **Progressive Enhancement**: Settings always visible, no hidden toggles
77
+
78
+ ### Backend Patterns
79
+ - **Development Mode**: Auto-reload enabled with `--dev` flag
80
+ - **Mock Implementation**: Currently returns `/samples/harvard.wav` for testing
81
+ - **CORS Configuration**: Explicitly configured for development ports
82
+
83
+ ### Styling Conventions
84
+ - **TailwindCSS**: Primary styling framework
85
+ - **Custom CSS**: Limited to audio sliders and pause icon in `app.css`
86
+ - **Color Scheme**: Light theme with HF amber/orange accents
87
+ - **Typography**: System fonts with careful spacing
88
+
89
+ ## Key Implementation Details
90
+
91
+ ### Audio System
92
+ The app uses a hidden HTML5 `<audio>` element controlled by custom UI:
93
+ - Real audio playback through bound `audioElement`
94
+ - Manual progress tracking via `timeupdate` events
95
+ - Auto-play when generation completes
96
+ - Custom pause icon using CSS pseudo-elements
97
+
98
+ ### Voice & Model Data
99
+ ```javascript
100
+ // Current models (in +page.svelte)
101
+ const models = [
102
+ { id: 'chatterbox', name: 'Chatterbox', badge: 'recommended' },
103
+ { id: 'kokoro', name: 'Kokoro', badge: 'faster but lower quality' }
104
+ ];
105
+
106
+ // Current voices with descriptions
107
+ const voices = [
108
+ { id: 'novia', name: 'Novia', description: 'Warm, conversational voice' },
109
+ // ... etc
110
+ ];
111
+ ```
112
+
113
+ ### Configuration Files
114
+ - **Frontend env**: `.env` with `PUBLIC_API_URL=http://localhost:11110`
115
+ - **Vite config**: Custom port (11111) and host settings
116
+ - **TailwindCSS**: Custom colors and slider styling
117
+ - **Backend requirements**: FastAPI, numpy, soundfile for audio processing
118
+
119
+ ### Static Assets
120
+ - **Logo**: HuggingFace logo at `/assets/hf-logo.png`
121
+ - **Sample audio**: Harvard sample at `/samples/harvard.wav` for testing
122
+ - **Favicon**: Uses HF logo
123
+
124
+ ## Development Workflow
125
+
126
+ ### Making UI Changes
127
+ 1. Edit components in `frontend/src/routes/+page.svelte`
128
+ 2. Layout changes go in `frontend/src/routes/+layout.svelte`
129
+ 3. Global styles in `frontend/src/app.css`
130
+ 4. Hot reload shows changes instantly
131
+
132
+ ### Adding API Features
133
+ 1. Add Pydantic models in `server.py`
134
+ 2. Create new endpoints following existing patterns
135
+ 3. Update CORS origins if needed
136
+ 4. Test at `http://localhost:11110/docs`
137
+
138
+ ### Troubleshooting
139
+ - **Port conflicts**: Change ports in `vite.config.js` and `cli.py`
140
+ - **CORS issues**: Update `allow_origins` in `server.py`
141
+ - **Audio not playing**: Check audio file exists at `/samples/harvard.wav`
142
+ - **Dependencies**: Run `npm install` in frontend, `pip install -r requirements.txt` in backend
MANIFEST.in ADDED
@@ -0,0 +1 @@
 
 
1
+ include frontend/package.json
QUICKSTART.md ADDED
@@ -0,0 +1,116 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ # HFStudio - Quick Start Guide
2
+
3
+ ## 🚀 Running Locally for Development
4
+
5
+ ### Prerequisites
6
+ - Node.js 18+ and npm
7
+ - Python 3.8+
8
+
9
+ ### Option 1: Quick Start (Recommended)
10
+ ```bash
11
+ # Run both frontend and backend
12
+ ./run_dev.sh
13
+ ```
14
+
15
+ This will:
16
+ - Start the backend API server on http://localhost:11110
17
+ - Start the frontend dev server on http://localhost:11111
18
+ - Install dependencies automatically
19
+
20
+ ### Option 2: Manual Setup
21
+
22
+ #### Terminal 1 - Backend
23
+ ```bash
24
+ cd backend
25
+
26
+ # Install dependencies
27
+ pip install -r requirements.txt
28
+
29
+ # Run the server
30
+ python -m hfstudio.cli --dev
31
+
32
+ # Or install as package and run
33
+ pip install -e .
34
+ hfstudio --dev
35
+ ```
36
+
37
+ Backend will run on http://localhost:11110
38
+ - API docs: http://localhost:11110/docs
39
+ - ReDoc: http://localhost:11110/redoc
40
+
41
+ #### Terminal 2 - Frontend
42
+ ```bash
43
+ cd frontend
44
+
45
+ # Install dependencies
46
+ npm install
47
+
48
+ # Run dev server
49
+ npm run dev
50
+ ```
51
+
52
+ Frontend will run on http://localhost:11111
53
+
54
+ ## 📁 Project Structure
55
+ ```
56
+ hfstudio/
57
+ ├── frontend/ # Svelte UI (port 11111)
58
+ │ └── src/
59
+ │ ├── routes/ # Page components
60
+ │ └── app.css # Tailwind styles
61
+ ├── backend/ # Python API (port 11110)
62
+ │ └── hfstudio/
63
+ │ ├── server.py # FastAPI server
64
+ │ └── cli.py # CLI interface
65
+ └── run_dev.sh # Dev startup script
66
+ ```
67
+
68
+ ## 🎨 UI Features
69
+ - **Text Input**: Large textarea for text-to-speech input
70
+ - **Voice Selection**: Choose from available voices
71
+ - **Model Selection**: Switch between TTS models
72
+ - **Parameter Controls**: Adjust speed, stability, similarity
73
+ - **Mode Toggle**: Switch between API and Local execution
74
+ - **Audio Player**: Play and download generated speech
75
+
76
+ ## 🔧 Development Tips
77
+
78
+ ### Frontend Changes
79
+ - Edit files in `frontend/src/`
80
+ - Hot reload is enabled - changes appear instantly
81
+ - Tailwind classes are available
82
+
83
+ ### Backend Changes
84
+ - Edit files in `backend/hfstudio/`
85
+ - With `--dev` flag, server auto-reloads on changes
86
+ - Test API endpoints at http://localhost:11110/docs
87
+
88
+ ### Adding New Features
89
+ 1. Frontend components go in `frontend/src/lib/components/`
90
+ 2. API endpoints go in `backend/hfstudio/server.py`
91
+ 3. TTS models will go in `backend/hfstudio/models/`
92
+
93
+ ## 🐛 Troubleshooting
94
+
95
+ ### Port Already in Use
96
+ ```bash
97
+ # Change frontend port
98
+ cd frontend
99
+ npm run dev -- --port 11112
100
+
101
+ # Change backend port
102
+ cd backend
103
+ python -m hfstudio.cli --port 11112
104
+ ```
105
+
106
+ ### Missing Dependencies
107
+ ```bash
108
+ # Frontend
109
+ cd frontend && npm install
110
+
111
+ # Backend
112
+ cd backend && pip install -r requirements.txt
113
+ ```
114
+
115
+ ### CORS Issues
116
+ Make sure both servers are running and check the CORS configuration in `backend/hfstudio/server.py`
README.md CHANGED
@@ -9,4 +9,78 @@ app_file: app.py
9
  pinned: false
10
  ---
11
 
12
- Check out the configuration reference at https://huggingface.co/docs/hub/spaces-config-reference
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
9
  pinned: false
10
  ---
11
 
12
+ # HFStudio 🎙️
13
+
14
+ A local and API-based Text-to-Speech studio for creating high-quality speech from text.
15
+
16
+ ## Features
17
+
18
+ - 🎯 **Multiple TTS Models**: Support for various TTS engines
19
+ - 🎭 **Voice Selection**: Choose from different voice models
20
+ - ⚡ **Real-time Generation**: Fast speech synthesis
21
+ - 🔧 **Parameter Control**: Fine-tune speed, stability, and similarity
22
+ - 🎵 **Audio Preview**: Built-in audio player with controls
23
+ - 🔐 **HuggingFace Integration**: Sign in with your HF account
24
+
25
+ ## Quick Start
26
+
27
+ This Space runs HFStudio automatically. Simply:
28
+
29
+ 1. **Open the Space** - The web interface will load automatically
30
+ 2. **Sign In** (optional) - Click "Sign In with Hugging Face" for full features
31
+ 3. **Enter Text** - Type or paste the text you want to convert to speech
32
+ 4. **Choose Voice** - Select from available voice models
33
+ 5. **Adjust Settings** - Tune speed, stability, and other parameters
34
+ 6. **Generate** - Click "Generate speech" to create audio
35
+ 7. **Play & Download** - Use the built-in player to preview your audio
36
+
37
+ ## Local Installation
38
+
39
+ Want to run HFStudio locally? Install via pip:
40
+
41
+ ```bash
42
+ pip install hfstudio
43
+ hfstudio
44
+ ```
45
+
46
+ Then visit `http://localhost:7860` in your browser.
47
+
48
+ ## Development
49
+
50
+ This Space is automatically synced from the [GitHub repository](https://github.com/yourusername/hfstudio).
51
+
52
+ To contribute or run locally for development:
53
+
54
+ ```bash
55
+ git clone https://github.com/yourusername/hfstudio
56
+ cd hfstudio
57
+ ./run_dev.sh # Starts both frontend and backend
58
+ ```
59
+
60
+ ## API Usage
61
+
62
+ HFStudio also provides a REST API for integration:
63
+
64
+ ```python
65
+ import requests
66
+
67
+ # Generate speech
68
+ response = requests.post('https://abidlabs-hfstudio.hf.space/api/tts/generate',
69
+ json={
70
+ "text": "Hello, world!",
71
+ "voice_id": "sarah",
72
+ "model_id": "coqui-tts"
73
+ }
74
+ )
75
+
76
+ audio_data = response.json()
77
+ print(f"Audio URL: {audio_data['audio_url']}")
78
+ ```
79
+
80
+ ## License
81
+
82
+ MIT License - see [LICENSE](LICENSE) for details.
83
+
84
+ ---
85
+
86
+ Built with ❤️ using [SvelteKit](https://kit.svelte.dev/) and [FastAPI](https://fastapi.tiangolo.com/)
README_SPACE.md ADDED
@@ -0,0 +1,86 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ ---
2
+ title: Hfstudio
3
+ emoji: 🏆
4
+ colorFrom: green
5
+ colorTo: purple
6
+ sdk: gradio
7
+ sdk_version: 5.49.1
8
+ app_file: app.py
9
+ pinned: false
10
+ ---
11
+
12
+ # HFStudio 🎙️
13
+
14
+ A local and API-based Text-to-Speech studio for creating high-quality speech from text.
15
+
16
+ ## Features
17
+
18
+ - 🎯 **Multiple TTS Models**: Support for various TTS engines
19
+ - 🎭 **Voice Selection**: Choose from different voice models
20
+ - ⚡ **Real-time Generation**: Fast speech synthesis
21
+ - 🔧 **Parameter Control**: Fine-tune speed, stability, and similarity
22
+ - 🎵 **Audio Preview**: Built-in audio player with controls
23
+ - 🔐 **HuggingFace Integration**: Sign in with your HF account
24
+
25
+ ## Quick Start
26
+
27
+ This Space runs HFStudio automatically. Simply:
28
+
29
+ 1. **Open the Space** - The web interface will load automatically
30
+ 2. **Sign In** (optional) - Click "Sign In with Hugging Face" for full features
31
+ 3. **Enter Text** - Type or paste the text you want to convert to speech
32
+ 4. **Choose Voice** - Select from available voice models
33
+ 5. **Adjust Settings** - Tune speed, stability, and other parameters
34
+ 6. **Generate** - Click "Generate speech" to create audio
35
+ 7. **Play & Download** - Use the built-in player to preview your audio
36
+
37
+ ## Local Installation
38
+
39
+ Want to run HFStudio locally? Install via pip:
40
+
41
+ ```bash
42
+ pip install hfstudio
43
+ hfstudio
44
+ ```
45
+
46
+ Then visit `http://localhost:7860` in your browser.
47
+
48
+ ## Development
49
+
50
+ This Space is automatically synced from the [GitHub repository](https://github.com/yourusername/hfstudio).
51
+
52
+ To contribute or run locally for development:
53
+
54
+ ```bash
55
+ git clone https://github.com/yourusername/hfstudio
56
+ cd hfstudio
57
+ ./run_dev.sh # Starts both frontend and backend
58
+ ```
59
+
60
+ ## API Usage
61
+
62
+ HFStudio also provides a REST API for integration:
63
+
64
+ ```python
65
+ import requests
66
+
67
+ # Generate speech
68
+ response = requests.post('https://abidlabs-hfstudio.hf.space/api/tts/generate',
69
+ json={
70
+ "text": "Hello, world!",
71
+ "voice_id": "sarah",
72
+ "model_id": "coqui-tts"
73
+ }
74
+ )
75
+
76
+ audio_data = response.json()
77
+ print(f"Audio URL: {audio_data['audio_url']}")
78
+ ```
79
+
80
+ ## License
81
+
82
+ MIT License - see [LICENSE](LICENSE) for details.
83
+
84
+ ---
85
+
86
+ Built with ❤️ using [SvelteKit](https://kit.svelte.dev/) and [FastAPI](https://fastapi.tiangolo.com/)
TECHNICAL_SPECS.md ADDED
@@ -0,0 +1,337 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ # HFStudio Technical Specifications
2
+
3
+ ## Project Overview
4
+ HFStudio is a web-based text-to-speech application that provides both local and API-based TTS capabilities, inspired by ElevenLabs Studio but with support for local model execution.
5
+
6
+ ## Core Features
7
+
8
+ ### 1. Text-to-Speech Engine
9
+ - **Input**: Multi-line text area for user input
10
+ - **Output**: Generated audio playback with download capability
11
+ - **Models**: Support for multiple TTS models (local and API-based)
12
+ - **Voice Selection**: Dropdown/list for available voices
13
+ - **Audio Controls**: Play, pause, download generated audio
14
+
15
+ ### 2. Execution Modes
16
+ - **API Mode**: Connect to remote TTS services (HuggingFace, OpenAI, etc.)
17
+ - **Local Mode**: Run TTS models locally using downloaded models
18
+ - **Mode Toggle**: Clear UI toggle between API and Local execution
19
+ - **Local Setup Instructions**: Display installation command when local mode selected
20
+
21
+ ### 3. Voice Configuration
22
+ - **Speed Control**: Slider (0.5x - 2.0x speed)
23
+ - **Stability**: Slider for voice consistency (when applicable)
24
+ - **Similarity**: Slider for voice matching (when applicable)
25
+ - **Style/Emotion**: Optional controls for voice style
26
+
27
+ ### 4. User Interface Layout
28
+ - **Left Sidebar**: Navigation and feature selection
29
+ - Home/Text-to-Speech (default)
30
+ - Settings
31
+ - History (future feature)
32
+ - **Main Content Area**: Text input and controls
33
+ - **Right Panel**: Voice/model selection and parameters
34
+
35
+ ## Technology Stack
36
+
37
+ ### Frontend
38
+ - **Framework**: SvelteKit
39
+ - **Styling**: TailwindCSS
40
+ - **Components**:
41
+ - Shadcn-svelte for UI components
42
+ - Audio player: Native HTML5 or Wavesurfer.js
43
+ - **State Management**: Svelte stores
44
+ - **Build Tool**: Vite
45
+
46
+ ### Backend (Python Package)
47
+ - **Framework**: FastAPI for API server
48
+ - **TTS Libraries**:
49
+ - Transformers (HuggingFace models)
50
+ - Coqui TTS
51
+ - Optional: Piper, Bark
52
+ - **Audio Processing**: librosa, soundfile
53
+ - **CLI**: Click or Typer for command-line interface
54
+
55
+ ### API Integration
56
+ - **HuggingFace Inference API**
57
+ - **OpenAI TTS API** (optional)
58
+ - **Custom model endpoints**
59
+
60
+ ## Project Structure
61
+
62
+ ```
63
+ hfstudio/
64
+ ├── frontend/ # Svelte frontend
65
+ │ ├── src/
66
+ │ │ ├── routes/
67
+ │ │ │ ├── +layout.svelte
68
+ │ │ │ ├── +page.svelte
69
+ │ │ │ └── api/
70
+ │ │ ├── lib/
71
+ │ │ │ ├── components/
72
+ │ │ │ │ ├── Sidebar.svelte
73
+ │ │ │ │ ├── TextInput.svelte
74
+ │ │ │ │ ├── VoiceSelector.svelte
75
+ │ │ │ │ ├── AudioPlayer.svelte
76
+ │ │ │ │ ├── ModeToggle.svelte
77
+ │ │ │ │ └── ParameterControls.svelte
78
+ │ │ │ ├── stores/
79
+ │ │ │ │ ├── app.js
80
+ │ │ │ │ └── audio.js
81
+ │ │ │ └── api/
82
+ │ │ │ └── client.js
83
+ │ │ └── app.html
84
+ │ ├── package.json
85
+ │ ├── vite.config.js
86
+ │ └── tailwind.config.js
87
+
88
+ ├── backend/ # Python backend
89
+ │ ├── hfstudio/
90
+ │ │ ├── __init__.py
91
+ │ │ ├── __main__.py
92
+ │ │ ├── server.py # FastAPI app
93
+ │ │ ├── cli.py # CLI interface
94
+ │ │ ├── models/
95
+ │ │ │ ├── __init__.py
96
+ │ │ │ ├── base.py
97
+ │ │ │ ├── local.py
98
+ │ │ │ └── api.py
99
+ │ │ ├── voices/
100
+ │ │ │ ├── __init__.py
101
+ │ │ │ └── manager.py
102
+ │ │ └── utils/
103
+ │ │ ├── __init__.py
104
+ │ │ └── audio.py
105
+ │ ├── requirements.txt
106
+ │ └── setup.py
107
+
108
+ ├── README.md
109
+ └── docker-compose.yml # Optional containerization
110
+ ```
111
+
112
+ ## API Endpoints
113
+
114
+ ### REST API
115
+ ```
116
+ POST /api/tts/generate
117
+ Body: {
118
+ text: string,
119
+ voice_id: string,
120
+ model_id: string,
121
+ parameters: {
122
+ speed: float,
123
+ stability: float,
124
+ similarity: float,
125
+ style: string
126
+ },
127
+ mode: "api" | "local"
128
+ }
129
+ Response: {
130
+ audio_url: string,
131
+ duration: float,
132
+ format: string
133
+ }
134
+
135
+ GET /api/voices
136
+ Response: {
137
+ voices: [{
138
+ id: string,
139
+ name: string,
140
+ preview_url: string,
141
+ supported_models: string[]
142
+ }]
143
+ }
144
+
145
+ GET /api/models
146
+ Response: {
147
+ models: [{
148
+ id: string,
149
+ name: string,
150
+ type: "local" | "api",
151
+ status: "available" | "downloadable" | "api-only"
152
+ }]
153
+ }
154
+
155
+ GET /api/status
156
+ Response: {
157
+ mode: "api" | "local",
158
+ local_available: boolean,
159
+ api_configured: boolean
160
+ }
161
+ ```
162
+
163
+ ## Component Specifications
164
+
165
+ ### 1. ModeToggle Component
166
+ ```svelte
167
+ Props:
168
+ - mode: "api" | "local"
169
+ - onModeChange: function
170
+
171
+ Features:
172
+ - Visual toggle switch
173
+ - Installation hint for local mode
174
+ - Status indicator (green/yellow/red)
175
+ ```
176
+
177
+ ### 2. TextInput Component
178
+ ```svelte
179
+ Props:
180
+ - value: string
181
+ - maxLength: number (default: 5000)
182
+ - placeholder: string
183
+
184
+ Features:
185
+ - Character counter
186
+ - Auto-resize
187
+ - Clear button
188
+ ```
189
+
190
+ ### 3. VoiceSelector Component
191
+ ```svelte
192
+ Props:
193
+ - voices: Voice[]
194
+ - selectedVoice: string
195
+ - onSelect: function
196
+
197
+ Features:
198
+ - Search/filter
199
+ - Voice preview
200
+ - Favorite voices
201
+ ```
202
+
203
+ ### 4. AudioPlayer Component
204
+ ```svelte
205
+ Props:
206
+ - audioUrl: string
207
+ - duration: number
208
+
209
+ Features:
210
+ - Play/pause
211
+ - Progress bar
212
+ - Volume control
213
+ - Download button
214
+ - Waveform visualization (optional)
215
+ ```
216
+
217
+ ## Local Package (hfstudio)
218
+
219
+ ### Installation
220
+ ```bash
221
+ pip install hfstudio
222
+ ```
223
+
224
+ ### CLI Usage
225
+ ```bash
226
+ # Start the server
227
+ hfstudio
228
+
229
+ # Start with custom port
230
+ hfstudio --port 8080
231
+
232
+ # Download models for offline use
233
+ hfstudio download-models
234
+
235
+ # List available models
236
+ hfstudio list-models
237
+ ```
238
+
239
+ ### Python API
240
+ ```python
241
+ from hfstudio import TTSEngine
242
+
243
+ # Initialize engine
244
+ engine = TTSEngine(mode="local")
245
+
246
+ # Generate speech
247
+ audio = engine.generate(
248
+ text="Hello, world!",
249
+ voice="default",
250
+ model="coqui/tts-vits"
251
+ )
252
+
253
+ # Save audio
254
+ audio.save("output.wav")
255
+ ```
256
+
257
+ ## Configuration
258
+
259
+ ### Frontend (.env)
260
+ ```env
261
+ PUBLIC_API_URL=http://localhost:8000
262
+ PUBLIC_DEFAULT_MODE=api
263
+ ```
264
+
265
+ ### Backend (config.yaml)
266
+ ```yaml
267
+ server:
268
+ host: 0.0.0.0
269
+ port: 8000
270
+ cors_origins:
271
+ - http://localhost:5173
272
+ - http://localhost:3000
273
+
274
+ models:
275
+ local:
276
+ cache_dir: ~/.hfstudio/models
277
+ default: "coqui/tts-vits"
278
+ api:
279
+ huggingface_token: ${HF_TOKEN}
280
+ openai_key: ${OPENAI_API_KEY}
281
+
282
+ audio:
283
+ output_format: "wav"
284
+ sample_rate: 22050
285
+ bitrate: 128
286
+ ```
287
+
288
+ ## Development Workflow
289
+
290
+ ### Phase 1: MVP
291
+ 1. Basic Svelte frontend with text input and generate button
292
+ 2. FastAPI backend with single TTS model support
293
+ 3. Mode toggle (UI only, local mode shows installation message)
294
+ 4. Basic audio playback
295
+
296
+ ### Phase 2: Core Features
297
+ 1. Multiple voice support
298
+ 2. Parameter controls (speed, stability, similarity)
299
+ 3. Local model execution
300
+ 4. Audio download functionality
301
+
302
+ ### Phase 3: Enhanced Features
303
+ 1. History/saved generations
304
+ 2. Voice cloning (if supported by models)
305
+ 3. Batch processing
306
+ 4. Audio format options
307
+
308
+ ### Phase 4: Polish
309
+ 1. Waveform visualization
310
+ 2. Real-time generation (streaming)
311
+ 3. Voice preview
312
+ 4. Keyboard shortcuts
313
+
314
+ ## Performance Requirements
315
+ - **API Response Time**: < 2s for typical requests
316
+ - **Local Generation**: < 5s for 100 words
317
+ - **Frontend Load Time**: < 1s
318
+ - **Audio Streaming**: Start playback within 500ms
319
+
320
+ ## Security Considerations
321
+ - API key management (environment variables)
322
+ - CORS configuration
323
+ - Rate limiting
324
+ - Input sanitization
325
+ - File size limits for audio generation
326
+
327
+ ## Testing Strategy
328
+ - Frontend: Vitest for unit tests, Playwright for E2E
329
+ - Backend: Pytest for unit and integration tests
330
+ - Load testing: Locust or K6
331
+ - Audio quality: Manual testing with various inputs
332
+
333
+ ## Deployment Options
334
+ 1. **Standalone**: User runs both frontend and backend locally
335
+ 2. **Docker**: Containerized deployment
336
+ 3. **Cloud**: Separate frontend (Vercel/Netlify) and backend (Railway/Fly.io)
337
+ 4. **Desktop**: Electron wrapper (future consideration)
app.py ADDED
@@ -0,0 +1,9 @@
 
 
 
 
 
 
 
 
 
 
1
+ #!/usr/bin/env python3
2
+ """
3
+ HuggingFace Space entry point for HFStudio
4
+ """
5
+ import uvicorn
6
+ from hfstudio.server import app
7
+
8
+ if __name__ == "__main__":
9
+ uvicorn.run(app, host="0.0.0.0", port=7860)
frontend/package-lock.json ADDED
The diff for this file is too large to render. See raw diff
 
frontend/package.json ADDED
@@ -0,0 +1,37 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ {
2
+ "name": "hfstudio-frontend",
3
+ "version": "0.1.1",
4
+ "private": true,
5
+ "scripts": {
6
+ "dev": "vite dev",
7
+ "build": "vite build",
8
+ "preview": "vite preview",
9
+ "check": "svelte-kit sync && svelte-check --tsconfig ./tsconfig.json",
10
+ "check:watch": "svelte-kit sync && svelte-check --tsconfig ./tsconfig.json --watch"
11
+ },
12
+ "devDependencies": {
13
+ "@sveltejs/adapter-auto": "^3.0.0",
14
+ "@sveltejs/kit": "^2.0.0",
15
+ "@sveltejs/vite-plugin-svelte": "^3.0.0",
16
+ "autoprefixer": "^10.4.16",
17
+ "postcss": "^8.4.32",
18
+ "svelte": "^4.2.7",
19
+ "svelte-check": "^3.6.0",
20
+ "tailwindcss": "^3.3.0",
21
+ "typescript": "^5.0.0",
22
+ "vite": "^5.0.3"
23
+ },
24
+ "type": "module",
25
+ "dependencies": {
26
+ "@fortawesome/free-solid-svg-icons": "^6.5.1",
27
+ "@sveltejs/adapter-static": "^3.0.10",
28
+ "bits-ui": "^0.21.0",
29
+ "clsx": "^2.0.0",
30
+ "lucide-svelte": "^0.303.0",
31
+ "mode-watcher": "^0.2.0",
32
+ "svelte-sonner": "^0.3.19",
33
+ "tailwind-merge": "^2.2.0",
34
+ "tailwind-variants": "^0.1.19",
35
+ "wavesurfer.js": "^7.6.0"
36
+ }
37
+ }
frontend/postcss.config.js ADDED
@@ -0,0 +1,6 @@
 
 
 
 
 
 
 
1
+ export default {
2
+ plugins: {
3
+ tailwindcss: {},
4
+ autoprefixer: {},
5
+ },
6
+ }
frontend/src/app.css ADDED
@@ -0,0 +1,93 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ @tailwind base;
2
+ @tailwind components;
3
+ @tailwind utilities;
4
+
5
+ @layer base {
6
+ :root {
7
+ --background: 0 0% 100%;
8
+ --foreground: 240 10% 3.9%;
9
+ --card: 0 0% 100%;
10
+ --card-foreground: 240 10% 3.9%;
11
+ --popover: 0 0% 100%;
12
+ --popover-foreground: 240 10% 3.9%;
13
+ --primary: 240 5.9% 10%;
14
+ --primary-foreground: 0 0% 98%;
15
+ --secondary: 240 4.8% 95.9%;
16
+ --secondary-foreground: 240 5.9% 10%;
17
+ --muted: 240 4.8% 95.9%;
18
+ --muted-foreground: 240 3.8% 46.1%;
19
+ --accent: 240 4.8% 95.9%;
20
+ --accent-foreground: 240 5.9% 10%;
21
+ --destructive: 0 84.2% 60.2%;
22
+ --destructive-foreground: 0 0% 98%;
23
+ --border: 240 5.9% 90%;
24
+ --input: 240 5.9% 90%;
25
+ --ring: 240 5.9% 10%;
26
+ --radius: 0.5rem;
27
+ }
28
+
29
+ .dark {
30
+ --background: 240 10% 3.9%;
31
+ --foreground: 0 0% 98%;
32
+ --card: 240 10% 3.9%;
33
+ --card-foreground: 0 0% 98%;
34
+ --popover: 240 10% 3.9%;
35
+ --popover-foreground: 0 0% 98%;
36
+ --primary: 0 0% 98%;
37
+ --primary-foreground: 240 5.9% 10%;
38
+ --secondary: 240 3.7% 15.9%;
39
+ --secondary-foreground: 0 0% 98%;
40
+ --muted: 240 3.7% 15.9%;
41
+ --muted-foreground: 240 5% 64.9%;
42
+ --accent: 240 3.7% 15.9%;
43
+ --accent-foreground: 0 0% 98%;
44
+ --destructive: 0 62.8% 30.6%;
45
+ --destructive-foreground: 0 0% 98%;
46
+ --border: 240 3.7% 15.9%;
47
+ --input: 240 3.7% 15.9%;
48
+ --ring: 240 4.9% 83.9%;
49
+ }
50
+ }
51
+
52
+ body {
53
+ @apply bg-background text-foreground;
54
+ }
55
+
56
+ /* Custom slider styles with HF brand colors */
57
+ .slider-hf::-webkit-slider-thumb {
58
+ @apply appearance-none w-4 h-4 rounded-full cursor-pointer;
59
+ background: linear-gradient(45deg, #FFD21E, #FF9D00);
60
+ box-shadow: 0 1px 3px rgba(0, 0, 0, 0.1);
61
+ }
62
+
63
+ .slider-hf::-moz-range-thumb {
64
+ @apply w-4 h-4 rounded-full cursor-pointer border-0;
65
+ background: linear-gradient(45deg, #FFD21E, #FF9D00);
66
+ box-shadow: 0 1px 3px rgba(0, 0, 0, 0.1);
67
+ }
68
+
69
+ /* Custom pause icon with filled bars */
70
+ .pause-filled {
71
+ display: inline-flex;
72
+ align-items: center;
73
+ justify-content: center;
74
+ width: 14px;
75
+ height: 14px;
76
+ }
77
+
78
+ .pause-filled::before,
79
+ .pause-filled::after {
80
+ content: '';
81
+ width: 2px;
82
+ height: 10px;
83
+ background-color: currentColor;
84
+ border-radius: 1px;
85
+ }
86
+
87
+ .pause-filled::before {
88
+ margin-right: 2px;
89
+ }
90
+
91
+ .pause-filled::after {
92
+ margin-left: 2px;
93
+ }
frontend/src/app.html ADDED
@@ -0,0 +1,13 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <!doctype html>
2
+ <html lang="en">
3
+ <head>
4
+ <meta charset="utf-8" />
5
+ <link rel="icon" href="/assets/hf-logo.png" />
6
+ <meta name="viewport" content="width=device-width, initial-scale=1" />
7
+ <title>HFStudio - Text to Speech</title>
8
+ %sveltekit.head%
9
+ </head>
10
+ <body data-sveltekit-preload-data="hover">
11
+ <div style="display: contents">%sveltekit.body%</div>
12
+ </body>
13
+ </html>
frontend/src/routes/+layout.svelte ADDED
@@ -0,0 +1,185 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <script>
2
+ import '../app.css';
3
+ import { Home, Settings, History, Github, Menu } from 'lucide-svelte';
4
+ import { onMount } from 'svelte';
5
+
6
+ let currentPage = 'tts';
7
+ let sidebarOpen = true;
8
+ let isLoggedIn = false;
9
+ let username = '';
10
+
11
+ onMount(() => {
12
+ // Check if user is logged in
13
+ checkLoginStatus();
14
+
15
+ // Re-check login status when page becomes visible (e.g., after OAuth redirect)
16
+ document.addEventListener('visibilitychange', () => {
17
+ if (!document.hidden) {
18
+ checkLoginStatus();
19
+ }
20
+ });
21
+
22
+ // Listen for storage changes (e.g., when token is set from OAuth callback)
23
+ window.addEventListener('storage', checkLoginStatus);
24
+
25
+ // Also check periodically to catch cases where localStorage changes in same tab
26
+ const interval = setInterval(checkLoginStatus, 1000);
27
+
28
+ return () => {
29
+ window.removeEventListener('storage', checkLoginStatus);
30
+ clearInterval(interval);
31
+ };
32
+ });
33
+
34
+ function checkLoginStatus() {
35
+ const token = localStorage.getItem('hf_access_token');
36
+ if (token) {
37
+ // Fetch user info from HuggingFace API
38
+ fetchUserInfo(token);
39
+ } else {
40
+ isLoggedIn = false;
41
+ username = '';
42
+ }
43
+ }
44
+
45
+ async function fetchUserInfo(token) {
46
+ try {
47
+ // For OAuth tokens, we need to use the OAuth API endpoint
48
+ const isOAuthToken = token.startsWith('hf_oauth_');
49
+ const apiUrl = isOAuthToken
50
+ ? 'https://huggingface.co/oauth/userinfo'
51
+ : 'https://huggingface.co/api/whoami';
52
+
53
+ const response = await fetch(apiUrl, {
54
+ headers: {
55
+ 'Authorization': `Bearer ${token}`
56
+ }
57
+ });
58
+
59
+ if (response.ok) {
60
+ const userData = await response.json();
61
+ isLoggedIn = true;
62
+ const fullName = userData.name || userData.login || 'User';
63
+ username = fullName.split(' ')[0]; // Extract first name only
64
+ } else {
65
+ // Token might be invalid, remove it
66
+ localStorage.removeItem('hf_access_token');
67
+ isLoggedIn = false;
68
+ username = '';
69
+ }
70
+ } catch (error) {
71
+ // Token might be invalid, remove it
72
+ localStorage.removeItem('hf_access_token');
73
+ isLoggedIn = false;
74
+ username = '';
75
+ }
76
+ }
77
+
78
+ function handleAuthAction() {
79
+ if (isLoggedIn) {
80
+ // Logout
81
+ localStorage.removeItem('hf_access_token');
82
+ sessionStorage.removeItem('oauth_state');
83
+ isLoggedIn = false;
84
+ username = '';
85
+ } else {
86
+ // Login
87
+ const clientId = 'cdf32a17-e40f-4a84-b683-f66aa1105793';
88
+ const redirectUri = 'http://localhost:11111/auth/callback';
89
+ const scope = 'read-repos';
90
+ const state = Math.random().toString(36).substring(2, 15);
91
+ const authUrl = `https://huggingface.co/oauth/authorize?client_id=${clientId}&redirect_uri=${encodeURIComponent(redirectUri)}&scope=${scope}&response_type=code&state=${state}`;
92
+
93
+ sessionStorage.setItem('oauth_state', state);
94
+ window.location.href = authUrl;
95
+ }
96
+ }
97
+ </script>
98
+
99
+ <div class="flex h-screen bg-white">
100
+ <!-- Sidebar -->
101
+ <aside class="w-56 border-r border-gray-200 bg-white flex-shrink-0 {sidebarOpen ? '' : 'hidden'}">
102
+ <div class="p-4 border-b border-gray-200">
103
+ <div class="flex items-center gap-3">
104
+ <img src="/assets/hf-studio-logo.png" alt="HF Logo" class="w-8 h-8" />
105
+ <h1 class="text-xl font-semibold">HFStudio<sup class="text-xs text-gray-500 ml-1">BETA</sup></h1>
106
+ </div>
107
+ </div>
108
+
109
+ <nav class="p-2 text-sm">
110
+ <div class="mt-2 mb-1 px-2 text-xs font-medium text-gray-500 uppercase">
111
+ Tasks
112
+ </div>
113
+
114
+ <button
115
+ class="w-full flex items-center gap-2 px-2 py-1.5 rounded-md hover:bg-gray-100 transition-colors text-left
116
+ {currentPage === 'tts' ? 'bg-gray-100' : ''}"
117
+ on:click={() => currentPage = 'tts'}
118
+ >
119
+ <span>🎙️</span>
120
+ <span>Text to Speech</span>
121
+ </button>
122
+
123
+ <button
124
+ class="w-full flex items-center gap-2 px-2 py-1.5 rounded-md text-left opacity-40 cursor-not-allowed"
125
+ disabled
126
+ >
127
+ <span>🎵</span>
128
+ <span>Voice Cloning</span>
129
+ </button>
130
+
131
+ <button
132
+ class="w-full flex items-center gap-2 px-2 py-1.5 rounded-md text-left opacity-40 cursor-not-allowed"
133
+ disabled
134
+ >
135
+ <span>🎧</span>
136
+ <span>Speech to Text</span>
137
+ </button>
138
+
139
+ <button
140
+ class="w-full flex items-center gap-2 px-2 py-1.5 rounded-md text-left opacity-40 cursor-not-allowed"
141
+ disabled
142
+ >
143
+ <span>🎼</span>
144
+ <span>Sound Effects</span>
145
+ </button>
146
+
147
+ <button
148
+ class="w-full flex items-center gap-2 px-2 py-1.5 rounded-md text-left opacity-40 cursor-not-allowed"
149
+ disabled
150
+ >
151
+ <span>🎸</span>
152
+ <span>Music Generation</span>
153
+ </button>
154
+
155
+ <button
156
+ class="w-full flex items-center gap-2 px-2 py-1.5 rounded-md text-left opacity-40 cursor-not-allowed"
157
+ disabled
158
+ >
159
+ <span>🔊</span>
160
+ <span>Audio Enhancement</span>
161
+ </button>
162
+
163
+ </nav>
164
+
165
+ <!-- Sign in with Hugging Face at bottom -->
166
+ <div class="absolute bottom-4 left-2 right-2 w-52">
167
+ <button
168
+ on:click={handleAuthAction}
169
+ class="w-full px-6 py-3 bg-black text-white rounded-lg font-medium hover:bg-gray-800 transition-colors shadow-sm flex items-center justify-center gap-2 text-sm"
170
+ >
171
+ <img src="/assets/hf-logo.png" alt="HF Logo" class="w-5 h-5" />
172
+ {#if isLoggedIn}
173
+ <span>Sign Out, {username}</span>
174
+ {:else}
175
+ <span>Sign In</span>
176
+ {/if}
177
+ </button>
178
+ </div>
179
+ </aside>
180
+
181
+ <!-- Main content -->
182
+ <main class="flex-1 overflow-auto">
183
+ <slot />
184
+ </main>
185
+ </div>
frontend/src/routes/+page.svelte ADDED
@@ -0,0 +1,499 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <script>
2
+ import { Play, Download, Loader2, AlertCircle, ChevronDown, Copy, RefreshCw, Share, MoreHorizontal, Settings, Sliders, Pause, SkipBack, SkipForward } from 'lucide-svelte';
3
+
4
+ let text = `Adam was playing outside when he heard a tiny meow! He looked around. Meow! There it was again! He tiptoed toward the bushes. Pushing the leaves aside, he gasped. A fluffy, orange kitten with big, curious eyes stared up at him. "Oh no! Where is your home?" Adam asked. The kitten just blinked and let out a tiny mew!
5
+
6
+ "Mama! I found a lost kitten!" Adam called as he carried the little furball inside. The kitten sniffed around, then jumped up—boing!—right onto the couch. "Oh!" Mama laughed. "Let's give it some milk while we find its owner." The kitten licked the milk happily and purred, prrrr! Adam giggled. "I think he likes it here!"
7
+
8
+ That evening, there was a knock at the door. A little girl stood there, eyes wide. "Have you seen my kitten, Biscuit?" she asked. Adam smiled and pointed. The kitten ran to her, mew mew mew! The girl hugged Biscuit tightly. "Thank you!" she said. As she left, Adam waved. "Goodbye, Biscuit!" he whispered. And in the quiet, he could still hear a happy prrrr!`;
9
+ let selectedVoice = 'Novia';
10
+ let selectedModel = 'Chatterbox';
11
+ let mode = 'api'; // 'api' or 'local'
12
+ let modelDropdownOpen = false;
13
+ let isGenerating = false;
14
+ let audioUrl = null;
15
+ let speed = 1.0;
16
+ let stability = 0.5;
17
+ let similarity = 0.75;
18
+ let styleExaggeration = 0;
19
+ let showSettings = true;
20
+ let isPlaying = false;
21
+ let currentTime = 0;
22
+ let duration = 0;
23
+ let audioTitle = '';
24
+ let audioElement = null;
25
+
26
+ const models = [
27
+ { id: 'chatterbox', name: 'Chatterbox', badge: 'recommended' },
28
+ { id: 'kokoro', name: 'Kokoro', badge: 'faster but lower quality' },
29
+ ];
30
+
31
+ const voices = [
32
+ { id: 'novia', name: 'Novia', description: 'Warm, conversational voice' },
33
+ { id: 'sarah', name: 'Sarah', description: 'Clear, professional tone' },
34
+ { id: 'alex', name: 'Alex', description: 'Friendly, approachable voice' },
35
+ { id: 'emma', name: 'Emma', description: 'Calm, soothing delivery' },
36
+ ];
37
+
38
+ async function generateSpeech() {
39
+ if (!text.trim()) return;
40
+
41
+ isGenerating = true;
42
+ audioUrl = null;
43
+ currentTime = 0;
44
+ isPlaying = false;
45
+
46
+ // Create title from first part of text
47
+ audioTitle = text.length > 30 ? text.substring(0, 30) + '...' : text;
48
+
49
+ // Simulate API call
50
+ setTimeout(() => {
51
+ audioUrl = '/samples/harvard.wav';
52
+ isGenerating = false;
53
+ }, 2000);
54
+ }
55
+
56
+ function togglePlayPause() {
57
+ if (audioElement) {
58
+ if (isPlaying) {
59
+ audioElement.pause();
60
+ } else {
61
+ audioElement.play();
62
+ }
63
+ }
64
+ }
65
+
66
+ function handleAudioLoad() {
67
+ if (audioElement) {
68
+ duration = audioElement.duration;
69
+ // Auto-play when audio loads
70
+ audioElement.play();
71
+ }
72
+ }
73
+
74
+ function handleTimeUpdate() {
75
+ if (audioElement) {
76
+ currentTime = audioElement.currentTime;
77
+ }
78
+ }
79
+
80
+ function handlePlay() {
81
+ isPlaying = true;
82
+ }
83
+
84
+ function handlePause() {
85
+ isPlaying = false;
86
+ }
87
+
88
+ function formatTime(seconds) {
89
+ const mins = Math.floor(seconds / 60);
90
+ const secs = Math.floor(seconds % 60);
91
+ return `${mins}:${secs.toString().padStart(2, '0')}`;
92
+ }
93
+
94
+ function downloadAudio() {
95
+ if (audioUrl) {
96
+ const a = document.createElement('a');
97
+ a.href = audioUrl;
98
+ a.download = 'speech.wav';
99
+ a.click();
100
+ }
101
+ }
102
+
103
+ function shareAudio() {
104
+ // Share functionality would go here
105
+ console.log('Share audio');
106
+ }
107
+
108
+ function handleKeyDown(event) {
109
+ if (event.key === 'Enter' && !event.shiftKey) {
110
+ event.preventDefault();
111
+ generateSpeech();
112
+ }
113
+ }
114
+
115
+ function handleClickOutside(event) {
116
+ if (!event.target.closest('.model-dropdown')) {
117
+ modelDropdownOpen = false;
118
+ }
119
+ }
120
+
121
+ function clearText() {
122
+ text = '';
123
+ audioUrl = null;
124
+ }
125
+ </script>
126
+
127
+ <div class="flex flex-col h-full" on:click={handleClickOutside}>
128
+ <!-- Header -->
129
+ <header class="border-b border-gray-200 bg-white">
130
+ <div class="flex items-center justify-between px-4 py-2">
131
+ <div class="flex items-center gap-3">
132
+ <!-- Mode toggle -->
133
+ <div class="flex items-center bg-gray-100 rounded-md p-0.5">
134
+ <button
135
+ class="px-3 py-1 text-sm font-medium rounded transition-colors {mode === 'api' ? 'bg-white shadow-sm' : 'text-gray-600'}"
136
+ on:click={() => mode = 'api'}
137
+ >
138
+ API
139
+ </button>
140
+ <button
141
+ class="px-3 py-1 text-sm font-medium rounded transition-colors {mode === 'local' ? 'bg-white shadow-sm' : 'text-gray-600'}"
142
+ on:click={() => mode = 'local'}
143
+ >
144
+ Local
145
+ </button>
146
+ </div>
147
+ </div>
148
+
149
+ <div class="flex items-center gap-2">
150
+ <button class="p-2 hover:bg-gray-50 rounded-md" title="Settings">
151
+ <Settings size={18} class="text-gray-600" />
152
+ </button>
153
+ <button class="p-2 hover:bg-gray-50 rounded-md" title="Share">
154
+ <Share size={18} class="text-gray-600" />
155
+ </button>
156
+ <button class="p-2 hover:bg-gray-50 rounded-md" title="More">
157
+ <MoreHorizontal size={18} class="text-gray-600" />
158
+ </button>
159
+ </div>
160
+ </div>
161
+ </header>
162
+
163
+ <!-- Main content area -->
164
+ <div class="flex-1 flex">
165
+ <!-- Main content area -->
166
+ <div class="flex-1 flex flex-col p-6">
167
+ {#if mode === 'local'}
168
+ <div class="mb-4 p-3 bg-blue-50 border border-blue-200 rounded-lg flex items-start gap-2">
169
+ <AlertCircle size={18} class="text-blue-600 mt-0.5 flex-shrink-0" />
170
+ <div class="text-sm">
171
+ <p class="font-medium text-blue-900">To run locally:</p>
172
+ <code class="text-xs bg-blue-100 px-1.5 py-0.5 rounded">pip install hfstudio</code>
173
+ <span class="text-blue-700"> and run </span>
174
+ <code class="text-xs bg-blue-100 px-1.5 py-0.5 rounded">hfstudio</code>
175
+ <span class="text-blue-700"> from your terminal</span>
176
+ </div>
177
+ </div>
178
+ {/if}
179
+
180
+ <!-- Text input area -->
181
+ <div class="flex-1 pb-24">
182
+ <textarea
183
+ bind:value={text}
184
+ class="w-full h-full p-6 bg-white resize-none border-0 focus:outline-none text-gray-900 text-base leading-relaxed"
185
+ placeholder="Enter text to convert to speech..."
186
+ />
187
+
188
+ {#if text}
189
+ <button
190
+ on:click={clearText}
191
+ class="absolute top-4 right-6 text-sm text-gray-400 hover:text-gray-600"
192
+ >
193
+ Clear
194
+ </button>
195
+ {/if}
196
+ </div>
197
+
198
+ <!-- Fixed bottom generate button -->
199
+ <div class="fixed bottom-0 left-56 right-80 p-4 bg-white border-t border-gray-200">
200
+ <div class="flex items-center justify-between mb-3">
201
+ <span class="text-sm text-gray-500">{text.length} / 5,000 characters</span>
202
+ </div>
203
+ <button
204
+ on:click={generateSpeech}
205
+ disabled={isGenerating || !text.trim()}
206
+ class="w-full px-6 py-3 bg-gradient-to-r from-amber-400 to-orange-500 text-white rounded-lg font-medium hover:from-amber-500 hover:to-orange-600 disabled:opacity-50 disabled:cursor-not-allowed flex items-center justify-center gap-2 shadow-sm"
207
+ >
208
+ {#if isGenerating}
209
+ <Loader2 size={20} class="animate-spin" />
210
+ Generating...
211
+ {:else}
212
+ <Play size={20} />
213
+ Generate speech
214
+ {/if}
215
+ </button>
216
+ </div>
217
+
218
+ <!-- Generated audio section -->
219
+ {#if audioUrl}
220
+ <div class="p-4 border border-gray-200 rounded-lg bg-white">
221
+ <!-- Audio title and voice info -->
222
+ <div class="flex items-center gap-3 mb-4">
223
+ <div class="w-2 h-2 bg-green-500 rounded-full"></div>
224
+ <div class="flex-1">
225
+ <h3 class="font-medium text-gray-900 text-sm">{audioTitle}</h3>
226
+ <p class="text-xs text-gray-500">{selectedVoice} • Created 1 second ago</p>
227
+ </div>
228
+ <!-- Mini action buttons -->
229
+ <div class="flex items-center gap-2">
230
+ <button
231
+ on:click={shareAudio}
232
+ class="flex items-center gap-1.5 px-3 py-1.5 text-sm border border-gray-200 rounded-md hover:bg-gray-50 transition-colors"
233
+ >
234
+ <Share size={14} class="text-gray-600" />
235
+ <span class="text-gray-700">Share</span>
236
+ </button>
237
+ <button
238
+ on:click={downloadAudio}
239
+ class="flex items-center gap-1.5 px-3 py-1.5 text-sm border border-gray-200 rounded-md hover:bg-gray-50 transition-colors"
240
+ >
241
+ <span class="text-gray-700">Download</span>
242
+ <Download size={14} class="text-gray-600" />
243
+ </button>
244
+ </div>
245
+ </div>
246
+
247
+ <!-- Mini audio controls -->
248
+ <div class="flex items-center gap-3 mb-4">
249
+ <!-- Play/Pause button -->
250
+ <button
251
+ on:click={togglePlayPause}
252
+ class="w-8 h-8 bg-black rounded-full flex items-center justify-center hover:bg-gray-800 transition-colors"
253
+ >
254
+ {#if isPlaying}
255
+ <div class="pause-filled text-white"></div>
256
+ {:else}
257
+ <Play size={14} class="text-white ml-0.5" />
258
+ {/if}
259
+ </button>
260
+
261
+ <!-- Progress bar -->
262
+ <div class="flex-1 flex items-center gap-2">
263
+ <span class="text-xs text-gray-500 font-mono">{formatTime(currentTime)}</span>
264
+ <div class="flex-1 h-1 bg-gray-200 rounded-full cursor-pointer">
265
+ <div
266
+ class="h-full bg-gradient-to-r from-amber-400 to-orange-500 rounded-full transition-all"
267
+ style="width: {(currentTime / duration) * 100}%"
268
+ ></div>
269
+ </div>
270
+ <span class="text-xs text-gray-500 font-mono">{formatTime(duration)}</span>
271
+ </div>
272
+ </div>
273
+
274
+ <!-- Full audio player controls -->
275
+ <div class="flex items-center gap-4 mb-4">
276
+ <!-- Skip back button -->
277
+ <button class="p-2 hover:bg-gray-100 rounded-full" title="Skip back">
278
+ <SkipBack size={20} class="text-gray-600" />
279
+ </button>
280
+
281
+ <!-- Play/Pause button -->
282
+ <button
283
+ on:click={togglePlayPause}
284
+ class="w-12 h-12 bg-black rounded-full flex items-center justify-center hover:bg-gray-800 transition-colors"
285
+ >
286
+ {#if isPlaying}
287
+ <div class="pause-filled text-white scale-150"></div>
288
+ {:else}
289
+ <Play size={20} class="text-white ml-0.5" />
290
+ {/if}
291
+ </button>
292
+
293
+ <!-- Skip forward button -->
294
+ <button class="p-2 hover:bg-gray-100 rounded-full" title="Skip forward">
295
+ <SkipForward size={20} class="text-gray-600" />
296
+ </button>
297
+
298
+ <!-- Progress bar -->
299
+ <div class="flex-1 flex items-center gap-3">
300
+ <span class="text-xs text-gray-500 font-mono">{formatTime(currentTime)}</span>
301
+ <div class="flex-1 h-1 bg-gray-200 rounded-full">
302
+ <div
303
+ class="h-full bg-gradient-to-r from-amber-400 to-orange-500 rounded-full transition-all"
304
+ style="width: {(currentTime / duration) * 100}%"
305
+ ></div>
306
+ </div>
307
+ <span class="text-xs text-gray-500 font-mono">{formatTime(duration)}</span>
308
+ </div>
309
+
310
+ <!-- Action buttons -->
311
+ <div class="flex items-center gap-2">
312
+ <button
313
+ on:click={shareAudio}
314
+ class="flex items-center gap-2 px-3 py-1.5 text-sm border border-gray-200 rounded-md hover:bg-gray-50"
315
+ >
316
+ <Share size={14} />
317
+ Share
318
+ </button>
319
+ <button
320
+ on:click={downloadAudio}
321
+ class="p-2 hover:bg-gray-100 rounded-md"
322
+ title="Download"
323
+ >
324
+ <Download size={16} class="text-gray-600" />
325
+ </button>
326
+ <button class="p-2 hover:bg-gray-100 rounded-md" title="More options">
327
+ <MoreHorizontal size={16} class="text-gray-600" />
328
+ </button>
329
+ </div>
330
+ </div>
331
+
332
+ <!-- Hidden audio element -->
333
+ {#if audioUrl}
334
+ <audio
335
+ bind:this={audioElement}
336
+ src={audioUrl}
337
+ on:loadedmetadata={handleAudioLoad}
338
+ on:timeupdate={handleTimeUpdate}
339
+ on:play={handlePlay}
340
+ on:pause={handlePause}
341
+ style="display: none;"
342
+ />
343
+ {/if}
344
+ </div>
345
+ {/if}
346
+ </div>
347
+
348
+ <!-- Right panel -->
349
+ <div class="w-80 border-l border-gray-200 bg-white p-4 overflow-y-auto">
350
+ <!-- Model selector -->
351
+ <div class="mb-6 relative model-dropdown">
352
+ <h3 class="font-medium text-gray-900 mb-3">Model</h3>
353
+ <button
354
+ on:click={() => modelDropdownOpen = !modelDropdownOpen}
355
+ class="w-full p-3 border border-gray-200 rounded-lg bg-white text-sm focus:outline-none focus:ring-2 focus:ring-amber-400 focus:border-transparent appearance-none bg-no-repeat bg-right pr-10 shadow-sm text-left flex items-center justify-between"
356
+ >
357
+ <span>
358
+ {#each models as model}
359
+ {#if model.name === selectedModel}
360
+ {model.name}{#if model.badge}&nbsp;<span class="text-xs text-gray-500">({model.badge})</span>{/if}
361
+ {/if}
362
+ {/each}
363
+ </span>
364
+ <ChevronDown size={16} class="text-gray-500" />
365
+ </button>
366
+
367
+ {#if modelDropdownOpen}
368
+ <div class="absolute top-full left-0 right-0 mt-1 bg-white border border-gray-200 rounded-lg shadow-lg z-10">
369
+ {#each models as model}
370
+ <button
371
+ class="w-full px-3 py-2 text-left hover:bg-gray-50 transition-colors text-sm {model.name === selectedModel ? 'bg-gray-100' : ''}"
372
+ on:click={() => {
373
+ selectedModel = model.name;
374
+ modelDropdownOpen = false;
375
+ }}
376
+ >
377
+ {model.name}{#if model.badge}&nbsp;<span class="text-xs text-gray-500">({model.badge})</span>{/if}
378
+ </button>
379
+ {/each}
380
+ </div>
381
+ {/if}
382
+ </div>
383
+
384
+ <div class="mb-6">
385
+ <div class="mb-3">
386
+ <h3 class="font-medium text-gray-900">Voice</h3>
387
+ </div>
388
+
389
+ <div class="space-y-1">
390
+ {#each voices as voice}
391
+ <button
392
+ class="w-full flex items-center justify-between p-2 rounded-md hover:bg-gray-50 transition-colors text-left
393
+ {voice.name === selectedVoice ? 'bg-gray-100' : ''}"
394
+ on:click={() => selectedVoice = voice.name}
395
+ >
396
+ <div class="flex items-center gap-2">
397
+ <div class="w-8 h-8 bg-gradient-to-br from-amber-400 to-orange-500 rounded-full flex items-center justify-center text-white text-xs font-medium">
398
+ {voice.name[0]}
399
+ </div>
400
+ <span class="text-sm font-medium">{voice.name}</span>
401
+ </div>
402
+ <div class="text-xs text-gray-500">
403
+ {voice.description}
404
+ </div>
405
+ </button>
406
+ {/each}
407
+
408
+ <!-- Clone voice option -->
409
+ <button
410
+ class="w-full flex items-center justify-between p-2 rounded-md opacity-50 cursor-not-allowed text-left"
411
+ disabled
412
+ >
413
+ <div class="flex items-center gap-2">
414
+ <div class="w-8 h-8 bg-gray-400 rounded-full flex items-center justify-center text-white text-xs font-medium">
415
+ +
416
+ </div>
417
+ <span class="text-sm font-medium text-gray-600">Clone your voice</span>
418
+ </div>
419
+ <div class="text-xs text-gray-400">
420
+ (coming soon)
421
+ </div>
422
+ </button>
423
+ </div>
424
+ </div>
425
+
426
+ <div class="space-y-4 pt-4 border-t border-gray-200">
427
+ <!-- Speed control -->
428
+ <div>
429
+ <div class="flex justify-between mb-1">
430
+ <label class="text-sm font-medium text-gray-700">Speed</label>
431
+ <span class="text-sm text-gray-500">{speed.toFixed(1)}x</span>
432
+ </div>
433
+ <input
434
+ type="range"
435
+ bind:value={speed}
436
+ min="0.5"
437
+ max="2"
438
+ step="0.1"
439
+ class="w-full h-1.5 bg-gray-200 rounded-lg appearance-none cursor-pointer slider-hf"
440
+ />
441
+ <div class="flex justify-between text-xs text-gray-400 mt-1">
442
+ <span>0.5x</span>
443
+ <span>2.0x</span>
444
+ </div>
445
+ </div>
446
+
447
+ <!-- Stability control -->
448
+ <div>
449
+ <div class="flex justify-between mb-1">
450
+ <label class="text-sm font-medium text-gray-700">Stability</label>
451
+ <span class="text-sm text-gray-500">{(stability * 100).toFixed(0)}%</span>
452
+ </div>
453
+ <input
454
+ type="range"
455
+ bind:value={stability}
456
+ min="0"
457
+ max="1"
458
+ step="0.01"
459
+ class="w-full h-1.5 bg-gray-200 rounded-lg appearance-none cursor-pointer slider-hf"
460
+ />
461
+ </div>
462
+
463
+ <!-- Similarity control -->
464
+ <div>
465
+ <div class="flex justify-between mb-1">
466
+ <label class="text-sm font-medium text-gray-700">Similarity</label>
467
+ <span class="text-sm text-gray-500">{(similarity * 100).toFixed(0)}%</span>
468
+ </div>
469
+ <input
470
+ type="range"
471
+ bind:value={similarity}
472
+ min="0"
473
+ max="1"
474
+ step="0.01"
475
+ class="w-full h-1.5 bg-gray-200 rounded-lg appearance-none cursor-pointer slider-hf"
476
+ />
477
+ </div>
478
+
479
+ <!-- Style control -->
480
+ <div>
481
+ <div class="flex justify-between mb-1">
482
+ <label class="text-sm font-medium text-gray-700">Style</label>
483
+ <span class="text-sm text-gray-500">
484
+ {styleExaggeration === 0 ? 'None' : 'Exaggerated'}
485
+ </span>
486
+ </div>
487
+ <input
488
+ type="range"
489
+ bind:value={styleExaggeration}
490
+ min="0"
491
+ max="1"
492
+ step="1"
493
+ class="w-full h-1.5 bg-gray-200 rounded-lg appearance-none cursor-pointer slider-hf"
494
+ />
495
+ </div>
496
+ </div>
497
+ </div>
498
+ </div>
499
+ </div>
frontend/src/routes/api/auth/token/+server.js ADDED
@@ -0,0 +1,46 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import { json } from '@sveltejs/kit';
2
+
3
+ export async function POST({ request }) {
4
+ try {
5
+ const { code } = await request.json();
6
+ console.log('Received OAuth code:', code);
7
+
8
+ // Forward request to backend
9
+ console.log('Forwarding to backend at http://localhost:7860/api/auth/token');
10
+ const response = await fetch('http://localhost:7860/api/auth/token', {
11
+ method: 'POST',
12
+ headers: {
13
+ 'Content-Type': 'application/json',
14
+ },
15
+ body: JSON.stringify({ code }),
16
+ });
17
+
18
+ console.log('Backend response status:', response.status);
19
+
20
+ if (!response.ok) {
21
+ const errorText = await response.text();
22
+ console.error('Backend error response:', errorText);
23
+ throw new Error(`Backend error (${response.status}): ${errorText}`);
24
+ }
25
+
26
+ const tokenData = await response.json();
27
+ console.log('Successfully received token data');
28
+ return json(tokenData);
29
+
30
+ } catch (error) {
31
+ console.error('OAuth token exchange error:', error);
32
+
33
+ // Check if it's a network error (backend not running)
34
+ if (error.message.includes('fetch') || error.code === 'ECONNREFUSED') {
35
+ return json(
36
+ { error: 'Backend server is not running. Please start the backend with: cd backend && python -m hfstudio.cli --dev' },
37
+ { status: 503 }
38
+ );
39
+ }
40
+
41
+ return json(
42
+ { error: `Failed to exchange authorization code: ${error.message}` },
43
+ { status: 500 }
44
+ );
45
+ }
46
+ }
frontend/src/routes/auth/callback/+page.svelte ADDED
@@ -0,0 +1,99 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <script>
2
+ import { onMount } from 'svelte';
3
+ import { goto } from '$app/navigation';
4
+ import { page } from '$app/stores';
5
+
6
+ let status = 'Processing...';
7
+ let error = null;
8
+
9
+ onMount(async () => {
10
+ try {
11
+ const code = $page.url.searchParams.get('code');
12
+ const state = $page.url.searchParams.get('state');
13
+ const errorParam = $page.url.searchParams.get('error');
14
+ const errorDescription = $page.url.searchParams.get('error_description');
15
+
16
+ if (errorParam) {
17
+ error = errorDescription || errorParam;
18
+ status = 'Authentication failed';
19
+ return;
20
+ }
21
+
22
+ if (!code) {
23
+ error = 'No authorization code received';
24
+ status = 'Authentication failed';
25
+ return;
26
+ }
27
+
28
+ // Verify state parameter (optional but recommended)
29
+ const storedState = sessionStorage.getItem('oauth_state');
30
+ if (storedState && state !== storedState) {
31
+ error = 'Invalid state parameter';
32
+ status = 'Authentication failed';
33
+ return;
34
+ }
35
+
36
+ // Exchange code for access token
37
+ const tokenResponse = await fetch('/api/auth/token', {
38
+ method: 'POST',
39
+ headers: {
40
+ 'Content-Type': 'application/json',
41
+ },
42
+ body: JSON.stringify({ code }),
43
+ });
44
+
45
+ if (!tokenResponse.ok) {
46
+ const errorText = await tokenResponse.text();
47
+ console.error('Token exchange failed:', errorText);
48
+ throw new Error(`Failed to exchange code for token: ${errorText}`);
49
+ }
50
+
51
+ const tokenData = await tokenResponse.json();
52
+
53
+ // Store access token (in a real app, you'd want secure storage)
54
+ localStorage.setItem('hf_access_token', tokenData.access_token);
55
+
56
+ status = 'Successfully authenticated!';
57
+
58
+ // Redirect back to main app after a short delay
59
+ setTimeout(() => {
60
+ goto('/');
61
+ }, 2000);
62
+
63
+ } catch (err) {
64
+ error = err.message;
65
+ status = 'Authentication failed';
66
+ }
67
+ });
68
+ </script>
69
+
70
+ <svelte:head>
71
+ <title>Authenticating with Hugging Face - HFStudio</title>
72
+ </svelte:head>
73
+
74
+ <div class="min-h-screen flex items-center justify-center bg-gray-50">
75
+ <div class="max-w-md w-full bg-white rounded-lg shadow-md p-6">
76
+ <div class="text-center">
77
+ <img src="/assets/hf-logo.png" alt="HF Logo" class="w-12 h-12 mx-auto mb-4" />
78
+ <h1 class="text-xl font-semibold mb-2">HFStudio Authentication</h1>
79
+
80
+ {#if error}
81
+ <div class="text-red-600 mb-4">
82
+ <p class="font-medium">{status}</p>
83
+ <p class="text-sm mt-1">{error}</p>
84
+ </div>
85
+ <button
86
+ on:click={() => goto('/')}
87
+ class="px-4 py-2 bg-gradient-to-r from-amber-400 to-orange-500 text-white rounded-lg hover:from-amber-500 hover:to-orange-600 transition-colors"
88
+ >
89
+ Return to HFStudio
90
+ </button>
91
+ {:else}
92
+ <div class="text-gray-600 mb-4">
93
+ <div class="animate-spin w-8 h-8 border-2 border-amber-400 border-t-transparent rounded-full mx-auto mb-2"></div>
94
+ <p>{status}</p>
95
+ </div>
96
+ {/if}
97
+ </div>
98
+ </div>
99
+ </div>
frontend/static/assets/hf-logo.png ADDED

Git LFS Details

  • SHA256: 9cf16f4f32604eaf76dabbdf47701eea5a768ebcc7296acc1d1758181f71db73
  • Pointer size: 131 Bytes
  • Size of remote file: 185 kB
frontend/static/assets/hf-studio-logo.png ADDED

Git LFS Details

  • SHA256: 7a33aae62a750e8ee190c7e993e17d9ddc0a54b213ea0823d14fcf1b366dc269
  • Pointer size: 130 Bytes
  • Size of remote file: 66.8 kB
frontend/static/samples/harvard.wav ADDED
@@ -0,0 +1,3 @@
 
 
 
 
1
+ version https://git-lfs.github.com/spec/v1
2
+ oid sha256:971b4163670445c415c6b0fb6813c38093409ecac2f6b4d429ae3574d24ad470
3
+ size 3249924
frontend/svelte.config.js ADDED
@@ -0,0 +1,18 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import adapter from '@sveltejs/adapter-static';
2
+ import { vitePreprocess } from '@sveltejs/vite-plugin-svelte';
3
+
4
+ /** @type {import('@sveltejs/kit').Config} */
5
+ const config = {
6
+ preprocess: vitePreprocess(),
7
+ kit: {
8
+ adapter: adapter({
9
+ pages: 'build',
10
+ assets: 'build',
11
+ fallback: 'index.html',
12
+ precompress: false,
13
+ strict: true
14
+ })
15
+ }
16
+ };
17
+
18
+ export default config;
frontend/tailwind.config.js ADDED
@@ -0,0 +1,44 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ /** @type {import('tailwindcss').Config} */
2
+ export default {
3
+ content: ['./src/**/*.{html,js,svelte,ts}'],
4
+ theme: {
5
+ extend: {
6
+ colors: {
7
+ border: "hsl(var(--border))",
8
+ input: "hsl(var(--input))",
9
+ ring: "hsl(var(--ring))",
10
+ background: "hsl(var(--background))",
11
+ foreground: "hsl(var(--foreground))",
12
+ primary: {
13
+ DEFAULT: "hsl(var(--primary))",
14
+ foreground: "hsl(var(--primary-foreground))",
15
+ },
16
+ secondary: {
17
+ DEFAULT: "hsl(var(--secondary))",
18
+ foreground: "hsl(var(--secondary-foreground))",
19
+ },
20
+ destructive: {
21
+ DEFAULT: "hsl(var(--destructive))",
22
+ foreground: "hsl(var(--destructive-foreground))",
23
+ },
24
+ muted: {
25
+ DEFAULT: "hsl(var(--muted))",
26
+ foreground: "hsl(var(--muted-foreground))",
27
+ },
28
+ accent: {
29
+ DEFAULT: "hsl(var(--accent))",
30
+ foreground: "hsl(var(--accent-foreground))",
31
+ },
32
+ popover: {
33
+ DEFAULT: "hsl(var(--popover))",
34
+ foreground: "hsl(var(--popover-foreground))",
35
+ },
36
+ card: {
37
+ DEFAULT: "hsl(var(--card))",
38
+ foreground: "hsl(var(--card-foreground))",
39
+ },
40
+ },
41
+ },
42
+ },
43
+ plugins: [],
44
+ }
frontend/vite.config.js ADDED
@@ -0,0 +1,10 @@
 
 
 
 
 
 
 
 
 
 
 
1
+ import { sveltekit } from '@sveltejs/kit/vite';
2
+ import { defineConfig } from 'vite';
3
+
4
+ export default defineConfig({
5
+ plugins: [sveltekit()],
6
+ server: {
7
+ port: 11111,
8
+ host: true
9
+ }
10
+ });
hfstudio/__init__.py ADDED
@@ -0,0 +1,17 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ """HFStudio - Local and API-based Text-to-Speech Studio"""
2
+
3
+ import json
4
+ import os
5
+ from pathlib import Path
6
+
7
+ def _get_version():
8
+ """Read version from frontend/package.json"""
9
+ # Get the project root (one level up from this package)
10
+ package_root = Path(__file__).parent.parent
11
+ package_json_path = package_root / "frontend" / "package.json"
12
+
13
+ with open(package_json_path, 'r') as f:
14
+ package_data = json.load(f)
15
+ return package_data['version']
16
+
17
+ __version__ = _get_version()
hfstudio/__main__.py ADDED
@@ -0,0 +1,4 @@
 
 
 
 
 
1
+ from hfstudio.cli import main
2
+
3
+ if __name__ == "__main__":
4
+ main()
hfstudio/cli.py ADDED
@@ -0,0 +1,32 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import typer
2
+ import uvicorn
3
+ from rich.console import Console
4
+ from rich.panel import Panel
5
+
6
+ console = Console()
7
+
8
+ def main(
9
+ port: int = typer.Option(7860, "--port", "-p", help="Port to run the server on"),
10
+ host: str = typer.Option("0.0.0.0", "--host", help="Host to run the server on"),
11
+ dev: bool = typer.Option(False, "--dev", help="Run in development mode"),
12
+ ):
13
+ """Start the HFStudio server"""
14
+
15
+ console.print(Panel.fit(
16
+ "[bold green]HFStudio Server[/bold green]\n"
17
+ f"Running on http://{host if host != '0.0.0.0' else 'localhost'}:{port}\n"
18
+ f"API docs: http://localhost:{port}/docs",
19
+ title="🎙️ HFStudio",
20
+ border_style="green"
21
+ ))
22
+
23
+ uvicorn.run(
24
+ "hfstudio.server:app",
25
+ host=host,
26
+ port=port,
27
+ reload=dev,
28
+ log_level="info" if not dev else "debug"
29
+ )
30
+
31
+ if __name__ == "__main__":
32
+ typer.run(main)
hfstudio/server.py ADDED
@@ -0,0 +1,217 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ from fastapi import FastAPI, HTTPException, Request
2
+ from fastapi.middleware.cors import CORSMiddleware
3
+ from fastapi.responses import FileResponse, HTMLResponse
4
+ from fastapi.staticfiles import StaticFiles
5
+ from pydantic import BaseModel
6
+ from typing import Optional, Dict, Any
7
+ import base64
8
+ import io
9
+ import numpy as np
10
+ import soundfile as sf
11
+ import httpx
12
+ import os
13
+ from pathlib import Path
14
+
15
+ app = FastAPI(title="HFStudio API", version="0.1.0")
16
+
17
+ # Get the static files directory
18
+ static_dir = Path(__file__).parent / "static"
19
+
20
+ # Mount static files
21
+ if static_dir.exists():
22
+ app.mount("/static", StaticFiles(directory=str(static_dir)), name="static")
23
+ app.mount("/_app", StaticFiles(directory=str(static_dir / "_app")), name="app")
24
+ app.mount("/assets", StaticFiles(directory=str(static_dir / "assets")), name="assets")
25
+ app.mount("/samples", StaticFiles(directory=str(static_dir / "samples")), name="samples")
26
+
27
+ # Configure CORS
28
+ app.add_middleware(
29
+ CORSMiddleware,
30
+ allow_origins=["http://localhost:7860", "http://localhost:11111", "http://localhost:3000"],
31
+ allow_credentials=True,
32
+ allow_methods=["*"],
33
+ allow_headers=["*"],
34
+ )
35
+
36
+ # Models
37
+ class TTSRequest(BaseModel):
38
+ text: str
39
+ voice_id: str = "default"
40
+ model_id: str = "coqui-tts"
41
+ parameters: Dict[str, Any] = {}
42
+ mode: str = "api" # "api" or "local"
43
+
44
+ class TTSResponse(BaseModel):
45
+ audio_url: str
46
+ duration: float
47
+ format: str = "wav"
48
+
49
+ class Voice(BaseModel):
50
+ id: str
51
+ name: str
52
+ preview_url: Optional[str] = None
53
+ supported_models: list[str] = []
54
+
55
+ class Model(BaseModel):
56
+ id: str
57
+ name: str
58
+ type: str # "local" or "api"
59
+ status: str # "available", "downloadable", "api-only"
60
+
61
+ class OAuthTokenRequest(BaseModel):
62
+ code: str
63
+
64
+ class OAuthTokenResponse(BaseModel):
65
+ access_token: str
66
+ token_type: str
67
+ scope: str
68
+
69
+ # Routes
70
+ @app.get("/")
71
+ async def root():
72
+ """Serve the SvelteKit single-page application"""
73
+ index_path = static_dir / "index.html"
74
+ if index_path.exists():
75
+ return FileResponse(str(index_path), media_type="text/html")
76
+ else:
77
+ return {"message": "HFStudio API is running"}
78
+
79
+ @app.get("/api/status")
80
+ async def get_status():
81
+ return {
82
+ "mode": "api",
83
+ "local_available": False,
84
+ "api_configured": True
85
+ }
86
+
87
+ @app.get("/api/voices")
88
+ async def get_voices():
89
+ voices = [
90
+ Voice(id="liam", name="Liam", supported_models=["coqui-tts", "bark"]),
91
+ Voice(id="sarah", name="Sarah", supported_models=["coqui-tts", "bark"]),
92
+ Voice(id="alex", name="Alex", supported_models=["coqui-tts", "bark"]),
93
+ Voice(id="emma", name="Emma", supported_models=["coqui-tts", "bark"]),
94
+ ]
95
+ return {"voices": voices}
96
+
97
+ @app.get("/api/models")
98
+ async def get_models():
99
+ models = [
100
+ Model(id="eleven-multilingual-v2", name="Eleven Multilingual v2", type="api", status="api-only"),
101
+ Model(id="coqui-tts", name="Coqui TTS", type="local", status="available"),
102
+ Model(id="bark", name="Bark", type="local", status="downloadable"),
103
+ ]
104
+ return {"models": models}
105
+
106
+ @app.post("/api/tts/generate")
107
+ async def generate_tts(request: TTSRequest):
108
+ try:
109
+ # For now, generate a simple sine wave as placeholder audio
110
+ duration = min(len(request.text) * 0.05, 10) # Rough estimate
111
+ sample_rate = 22050
112
+ t = np.linspace(0, duration, int(sample_rate * duration))
113
+
114
+ # Generate a simple tone
115
+ frequency = 440 # A4 note
116
+ audio = np.sin(2 * np.pi * frequency * t) * 0.3
117
+
118
+ # Add some variation
119
+ audio += np.sin(2 * np.pi * frequency * 1.5 * t) * 0.1
120
+ audio += np.sin(2 * np.pi * frequency * 2 * t) * 0.05
121
+
122
+ # Convert to int16
123
+ audio = (audio * 32767).astype(np.int16)
124
+
125
+ # Create WAV in memory
126
+ buffer = io.BytesIO()
127
+ sf.write(buffer, audio, sample_rate, format='WAV')
128
+ buffer.seek(0)
129
+
130
+ # Convert to base64
131
+ audio_base64 = base64.b64encode(buffer.read()).decode('utf-8')
132
+ audio_url = f"data:audio/wav;base64,{audio_base64}"
133
+
134
+ return TTSResponse(
135
+ audio_url=audio_url,
136
+ duration=duration,
137
+ format="wav"
138
+ )
139
+ except Exception as e:
140
+ raise HTTPException(status_code=500, detail=str(e))
141
+
142
+ @app.post("/api/auth/token")
143
+ async def exchange_oauth_token(request: OAuthTokenRequest):
144
+ """Exchange OAuth authorization code for access token"""
145
+ try:
146
+ # HuggingFace OAuth token endpoint
147
+ token_url = "https://huggingface.co/oauth/token"
148
+
149
+ # OAuth app credentials
150
+ client_id = "cdf32a17-e40f-4a84-b683-f66aa1105793"
151
+ client_secret = "f590cb2d-6eac-4cef-a0cb-d0116825295c"
152
+ redirect_uri = "http://localhost:11111/auth/callback"
153
+
154
+ # Prepare token exchange request
155
+ token_data = {
156
+ "client_id": client_id,
157
+ "client_secret": client_secret,
158
+ "code": request.code,
159
+ "grant_type": "authorization_code",
160
+ "redirect_uri": redirect_uri,
161
+ }
162
+
163
+ # Exchange code for token
164
+ async with httpx.AsyncClient() as client:
165
+ response = await client.post(
166
+ token_url,
167
+ data=token_data,
168
+ headers={"Accept": "application/json"}
169
+ )
170
+
171
+ if response.status_code != 200:
172
+ raise HTTPException(
173
+ status_code=400,
174
+ detail=f"Token exchange failed: {response.text}"
175
+ )
176
+
177
+ token_response = response.json()
178
+
179
+ return OAuthTokenResponse(
180
+ access_token=token_response["access_token"],
181
+ token_type=token_response.get("token_type", "Bearer"),
182
+ scope=token_response.get("scope", "")
183
+ )
184
+
185
+ except httpx.RequestError as e:
186
+ raise HTTPException(status_code=500, detail=f"Network error: {str(e)}")
187
+ except Exception as e:
188
+ raise HTTPException(status_code=500, detail=str(e))
189
+
190
+ # Catch-all route to serve the SvelteKit app (excluding API routes)
191
+ @app.get("/{path:path}")
192
+ async def serve_spa(path: str):
193
+ """Serve the SvelteKit single-page application for non-API routes"""
194
+ # Skip API routes
195
+ if path.startswith("api/") or path.startswith("docs") or path.startswith("openapi.json"):
196
+ raise HTTPException(status_code=404, detail="Not found")
197
+
198
+ # For any non-API route, serve the index.html
199
+ index_path = static_dir / "index.html"
200
+ if index_path.exists():
201
+ return FileResponse(str(index_path), media_type="text/html")
202
+ else:
203
+ # Fallback if no built frontend
204
+ return HTMLResponse("""
205
+ <html>
206
+ <head><title>HFStudio</title></head>
207
+ <body>
208
+ <h1>HFStudio Backend</h1>
209
+ <p>The backend is running, but the frontend hasn't been built yet.</p>
210
+ <p>Visit <a href="/docs">/docs</a> for the API documentation.</p>
211
+ </body>
212
+ </html>
213
+ """)
214
+
215
+ if __name__ == "__main__":
216
+ import uvicorn
217
+ uvicorn.run(app, host="0.0.0.0", port=7860)
hfstudio/static/_app/env.js ADDED
@@ -0,0 +1 @@
 
 
1
+ export const env={}
hfstudio/static/_app/immutable/assets/0.DkRYx-5s.css ADDED
@@ -0,0 +1 @@
 
 
1
+ *,:before,:after{--tw-border-spacing-x: 0;--tw-border-spacing-y: 0;--tw-translate-x: 0;--tw-translate-y: 0;--tw-rotate: 0;--tw-skew-x: 0;--tw-skew-y: 0;--tw-scale-x: 1;--tw-scale-y: 1;--tw-pan-x: ;--tw-pan-y: ;--tw-pinch-zoom: ;--tw-scroll-snap-strictness: proximity;--tw-gradient-from-position: ;--tw-gradient-via-position: ;--tw-gradient-to-position: ;--tw-ordinal: ;--tw-slashed-zero: ;--tw-numeric-figure: ;--tw-numeric-spacing: ;--tw-numeric-fraction: ;--tw-ring-inset: ;--tw-ring-offset-width: 0px;--tw-ring-offset-color: #fff;--tw-ring-color: rgb(59 130 246 / .5);--tw-ring-offset-shadow: 0 0 #0000;--tw-ring-shadow: 0 0 #0000;--tw-shadow: 0 0 #0000;--tw-shadow-colored: 0 0 #0000;--tw-blur: ;--tw-brightness: ;--tw-contrast: ;--tw-grayscale: ;--tw-hue-rotate: ;--tw-invert: ;--tw-saturate: ;--tw-sepia: ;--tw-drop-shadow: ;--tw-backdrop-blur: ;--tw-backdrop-brightness: ;--tw-backdrop-contrast: ;--tw-backdrop-grayscale: ;--tw-backdrop-hue-rotate: ;--tw-backdrop-invert: ;--tw-backdrop-opacity: ;--tw-backdrop-saturate: ;--tw-backdrop-sepia: ;--tw-contain-size: ;--tw-contain-layout: ;--tw-contain-paint: ;--tw-contain-style: }::backdrop{--tw-border-spacing-x: 0;--tw-border-spacing-y: 0;--tw-translate-x: 0;--tw-translate-y: 0;--tw-rotate: 0;--tw-skew-x: 0;--tw-skew-y: 0;--tw-scale-x: 1;--tw-scale-y: 1;--tw-pan-x: ;--tw-pan-y: ;--tw-pinch-zoom: ;--tw-scroll-snap-strictness: proximity;--tw-gradient-from-position: ;--tw-gradient-via-position: ;--tw-gradient-to-position: ;--tw-ordinal: ;--tw-slashed-zero: ;--tw-numeric-figure: ;--tw-numeric-spacing: ;--tw-numeric-fraction: ;--tw-ring-inset: ;--tw-ring-offset-width: 0px;--tw-ring-offset-color: #fff;--tw-ring-color: rgb(59 130 246 / .5);--tw-ring-offset-shadow: 0 0 #0000;--tw-ring-shadow: 0 0 #0000;--tw-shadow: 0 0 #0000;--tw-shadow-colored: 0 0 #0000;--tw-blur: ;--tw-brightness: ;--tw-contrast: ;--tw-grayscale: ;--tw-hue-rotate: ;--tw-invert: ;--tw-saturate: ;--tw-sepia: ;--tw-drop-shadow: ;--tw-backdrop-blur: ;--tw-backdrop-brightness: ;--tw-backdrop-contrast: ;--tw-backdrop-grayscale: ;--tw-backdrop-hue-rotate: ;--tw-backdrop-invert: ;--tw-backdrop-opacity: ;--tw-backdrop-saturate: ;--tw-backdrop-sepia: ;--tw-contain-size: ;--tw-contain-layout: ;--tw-contain-paint: ;--tw-contain-style: }*,:before,:after{box-sizing:border-box;border-width:0;border-style:solid;border-color:#e5e7eb}:before,:after{--tw-content: ""}html,:host{line-height:1.5;-webkit-text-size-adjust:100%;-moz-tab-size:4;-o-tab-size:4;tab-size:4;font-family:ui-sans-serif,system-ui,sans-serif,"Apple Color Emoji","Segoe UI Emoji",Segoe UI Symbol,"Noto Color Emoji";font-feature-settings:normal;font-variation-settings:normal;-webkit-tap-highlight-color:transparent}body{margin:0;line-height:inherit}hr{height:0;color:inherit;border-top-width:1px}abbr:where([title]){-webkit-text-decoration:underline dotted;text-decoration:underline dotted}h1,h2,h3,h4,h5,h6{font-size:inherit;font-weight:inherit}a{color:inherit;text-decoration:inherit}b,strong{font-weight:bolder}code,kbd,samp,pre{font-family:ui-monospace,SFMono-Regular,Menlo,Monaco,Consolas,Liberation Mono,Courier New,monospace;font-feature-settings:normal;font-variation-settings:normal;font-size:1em}small{font-size:80%}sub,sup{font-size:75%;line-height:0;position:relative;vertical-align:baseline}sub{bottom:-.25em}sup{top:-.5em}table{text-indent:0;border-color:inherit;border-collapse:collapse}button,input,optgroup,select,textarea{font-family:inherit;font-feature-settings:inherit;font-variation-settings:inherit;font-size:100%;font-weight:inherit;line-height:inherit;letter-spacing:inherit;color:inherit;margin:0;padding:0}button,select{text-transform:none}button,input:where([type=button]),input:where([type=reset]),input:where([type=submit]){-webkit-appearance:button;background-color:transparent;background-image:none}:-moz-focusring{outline:auto}:-moz-ui-invalid{box-shadow:none}progress{vertical-align:baseline}::-webkit-inner-spin-button,::-webkit-outer-spin-button{height:auto}[type=search]{-webkit-appearance:textfield;outline-offset:-2px}::-webkit-search-decoration{-webkit-appearance:none}::-webkit-file-upload-button{-webkit-appearance:button;font:inherit}summary{display:list-item}blockquote,dl,dd,h1,h2,h3,h4,h5,h6,hr,figure,p,pre{margin:0}fieldset{margin:0;padding:0}legend{padding:0}ol,ul,menu{list-style:none;margin:0;padding:0}dialog{padding:0}textarea{resize:vertical}input::-moz-placeholder,textarea::-moz-placeholder{opacity:1;color:#9ca3af}input::placeholder,textarea::placeholder{opacity:1;color:#9ca3af}button,[role=button]{cursor:pointer}:disabled{cursor:default}img,svg,video,canvas,audio,iframe,embed,object{display:block;vertical-align:middle}img,video{max-width:100%;height:auto}[hidden]:where(:not([hidden=until-found])){display:none}:root{--background: 0 0% 100%;--foreground: 240 10% 3.9%;--card: 0 0% 100%;--card-foreground: 240 10% 3.9%;--popover: 0 0% 100%;--popover-foreground: 240 10% 3.9%;--primary: 240 5.9% 10%;--primary-foreground: 0 0% 98%;--secondary: 240 4.8% 95.9%;--secondary-foreground: 240 5.9% 10%;--muted: 240 4.8% 95.9%;--muted-foreground: 240 3.8% 46.1%;--accent: 240 4.8% 95.9%;--accent-foreground: 240 5.9% 10%;--destructive: 0 84.2% 60.2%;--destructive-foreground: 0 0% 98%;--border: 240 5.9% 90%;--input: 240 5.9% 90%;--ring: 240 5.9% 10%;--radius: .5rem}.visible{visibility:visible}.fixed{position:fixed}.absolute{position:absolute}.relative{position:relative}.bottom-0{bottom:0}.bottom-4{bottom:1rem}.left-0{left:0}.left-2{left:.5rem}.left-56{left:14rem}.right-0{right:0}.right-2{right:.5rem}.right-6{right:1.5rem}.right-80{right:20rem}.top-4{top:1rem}.top-full{top:100%}.z-10{z-index:10}.mx-auto{margin-left:auto;margin-right:auto}.mb-1{margin-bottom:.25rem}.mb-2{margin-bottom:.5rem}.mb-3{margin-bottom:.75rem}.mb-4{margin-bottom:1rem}.mb-6{margin-bottom:1.5rem}.ml-0\.5{margin-left:.125rem}.ml-1{margin-left:.25rem}.mt-0\.5{margin-top:.125rem}.mt-1{margin-top:.25rem}.mt-2{margin-top:.5rem}.flex{display:flex}.contents{display:contents}.hidden{display:none}.h-1{height:.25rem}.h-1\.5{height:.375rem}.h-12{height:3rem}.h-2{height:.5rem}.h-5{height:1.25rem}.h-8{height:2rem}.h-full{height:100%}.h-screen{height:100vh}.min-h-screen{min-height:100vh}.w-12{width:3rem}.w-2{width:.5rem}.w-5{width:1.25rem}.w-52{width:13rem}.w-56{width:14rem}.w-8{width:2rem}.w-80{width:20rem}.w-full{width:100%}.max-w-md{max-width:28rem}.flex-1{flex:1 1 0%}.flex-shrink-0{flex-shrink:0}.scale-150{--tw-scale-x: 1.5;--tw-scale-y: 1.5;transform:translate(var(--tw-translate-x),var(--tw-translate-y)) rotate(var(--tw-rotate)) skew(var(--tw-skew-x)) skewY(var(--tw-skew-y)) scaleX(var(--tw-scale-x)) scaleY(var(--tw-scale-y))}@keyframes spin{to{transform:rotate(360deg)}}.animate-spin{animation:spin 1s linear infinite}.cursor-not-allowed{cursor:not-allowed}.cursor-pointer{cursor:pointer}.resize-none{resize:none}.appearance-none{-webkit-appearance:none;-moz-appearance:none;appearance:none}.flex-col{flex-direction:column}.items-start{align-items:flex-start}.items-center{align-items:center}.justify-center{justify-content:center}.justify-between{justify-content:space-between}.gap-1\.5{gap:.375rem}.gap-2{gap:.5rem}.gap-3{gap:.75rem}.gap-4{gap:1rem}.space-y-1>:not([hidden])~:not([hidden]){--tw-space-y-reverse: 0;margin-top:calc(.25rem * calc(1 - var(--tw-space-y-reverse)));margin-bottom:calc(.25rem * var(--tw-space-y-reverse))}.space-y-4>:not([hidden])~:not([hidden]){--tw-space-y-reverse: 0;margin-top:calc(1rem * calc(1 - var(--tw-space-y-reverse)));margin-bottom:calc(1rem * var(--tw-space-y-reverse))}.overflow-auto{overflow:auto}.overflow-y-auto{overflow-y:auto}.rounded{border-radius:.25rem}.rounded-full{border-radius:9999px}.rounded-lg{border-radius:.5rem}.rounded-md{border-radius:.375rem}.border{border-width:1px}.border-0{border-width:0px}.border-2{border-width:2px}.border-b{border-bottom-width:1px}.border-l{border-left-width:1px}.border-r{border-right-width:1px}.border-t{border-top-width:1px}.border-amber-400{--tw-border-opacity: 1;border-color:rgb(251 191 36 / var(--tw-border-opacity, 1))}.border-blue-200{--tw-border-opacity: 1;border-color:rgb(191 219 254 / var(--tw-border-opacity, 1))}.border-gray-200{--tw-border-opacity: 1;border-color:rgb(229 231 235 / var(--tw-border-opacity, 1))}.border-t-transparent{border-top-color:transparent}.bg-black{--tw-bg-opacity: 1;background-color:rgb(0 0 0 / var(--tw-bg-opacity, 1))}.bg-blue-100{--tw-bg-opacity: 1;background-color:rgb(219 234 254 / var(--tw-bg-opacity, 1))}.bg-blue-50{--tw-bg-opacity: 1;background-color:rgb(239 246 255 / var(--tw-bg-opacity, 1))}.bg-gray-100{--tw-bg-opacity: 1;background-color:rgb(243 244 246 / var(--tw-bg-opacity, 1))}.bg-gray-200{--tw-bg-opacity: 1;background-color:rgb(229 231 235 / var(--tw-bg-opacity, 1))}.bg-gray-400{--tw-bg-opacity: 1;background-color:rgb(156 163 175 / var(--tw-bg-opacity, 1))}.bg-gray-50{--tw-bg-opacity: 1;background-color:rgb(249 250 251 / var(--tw-bg-opacity, 1))}.bg-green-500{--tw-bg-opacity: 1;background-color:rgb(34 197 94 / var(--tw-bg-opacity, 1))}.bg-white{--tw-bg-opacity: 1;background-color:rgb(255 255 255 / var(--tw-bg-opacity, 1))}.bg-gradient-to-br{background-image:linear-gradient(to bottom right,var(--tw-gradient-stops))}.bg-gradient-to-r{background-image:linear-gradient(to right,var(--tw-gradient-stops))}.from-amber-400{--tw-gradient-from: #fbbf24 var(--tw-gradient-from-position);--tw-gradient-to: rgb(251 191 36 / 0) var(--tw-gradient-to-position);--tw-gradient-stops: var(--tw-gradient-from), var(--tw-gradient-to)}.to-orange-500{--tw-gradient-to: #f97316 var(--tw-gradient-to-position)}.bg-right{background-position:right}.bg-no-repeat{background-repeat:no-repeat}.p-0\.5{padding:.125rem}.p-2{padding:.5rem}.p-3{padding:.75rem}.p-4{padding:1rem}.p-6{padding:1.5rem}.px-1\.5{padding-left:.375rem;padding-right:.375rem}.px-2{padding-left:.5rem;padding-right:.5rem}.px-3{padding-left:.75rem;padding-right:.75rem}.px-4{padding-left:1rem;padding-right:1rem}.px-6{padding-left:1.5rem;padding-right:1.5rem}.py-0\.5{padding-top:.125rem;padding-bottom:.125rem}.py-1{padding-top:.25rem;padding-bottom:.25rem}.py-1\.5{padding-top:.375rem;padding-bottom:.375rem}.py-2{padding-top:.5rem;padding-bottom:.5rem}.py-3{padding-top:.75rem;padding-bottom:.75rem}.pb-24{padding-bottom:6rem}.pr-10{padding-right:2.5rem}.pt-4{padding-top:1rem}.text-left{text-align:left}.text-center{text-align:center}.font-mono{font-family:ui-monospace,SFMono-Regular,Menlo,Monaco,Consolas,Liberation Mono,Courier New,monospace}.text-base{font-size:1rem;line-height:1.5rem}.text-sm{font-size:.875rem;line-height:1.25rem}.text-xl{font-size:1.25rem;line-height:1.75rem}.text-xs{font-size:.75rem;line-height:1rem}.font-medium{font-weight:500}.font-semibold{font-weight:600}.uppercase{text-transform:uppercase}.leading-relaxed{line-height:1.625}.text-blue-600{--tw-text-opacity: 1;color:rgb(37 99 235 / var(--tw-text-opacity, 1))}.text-blue-700{--tw-text-opacity: 1;color:rgb(29 78 216 / var(--tw-text-opacity, 1))}.text-blue-900{--tw-text-opacity: 1;color:rgb(30 58 138 / var(--tw-text-opacity, 1))}.text-gray-400{--tw-text-opacity: 1;color:rgb(156 163 175 / var(--tw-text-opacity, 1))}.text-gray-500{--tw-text-opacity: 1;color:rgb(107 114 128 / var(--tw-text-opacity, 1))}.text-gray-600{--tw-text-opacity: 1;color:rgb(75 85 99 / var(--tw-text-opacity, 1))}.text-gray-700{--tw-text-opacity: 1;color:rgb(55 65 81 / var(--tw-text-opacity, 1))}.text-gray-900{--tw-text-opacity: 1;color:rgb(17 24 39 / var(--tw-text-opacity, 1))}.text-red-600{--tw-text-opacity: 1;color:rgb(220 38 38 / var(--tw-text-opacity, 1))}.text-white{--tw-text-opacity: 1;color:rgb(255 255 255 / var(--tw-text-opacity, 1))}.opacity-40{opacity:.4}.opacity-50{opacity:.5}.shadow-lg{--tw-shadow: 0 10px 15px -3px rgb(0 0 0 / .1), 0 4px 6px -4px rgb(0 0 0 / .1);--tw-shadow-colored: 0 10px 15px -3px var(--tw-shadow-color), 0 4px 6px -4px var(--tw-shadow-color);box-shadow:var(--tw-ring-offset-shadow, 0 0 #0000),var(--tw-ring-shadow, 0 0 #0000),var(--tw-shadow)}.shadow-md{--tw-shadow: 0 4px 6px -1px rgb(0 0 0 / .1), 0 2px 4px -2px rgb(0 0 0 / .1);--tw-shadow-colored: 0 4px 6px -1px var(--tw-shadow-color), 0 2px 4px -2px var(--tw-shadow-color);box-shadow:var(--tw-ring-offset-shadow, 0 0 #0000),var(--tw-ring-shadow, 0 0 #0000),var(--tw-shadow)}.shadow-sm{--tw-shadow: 0 1px 2px 0 rgb(0 0 0 / .05);--tw-shadow-colored: 0 1px 2px 0 var(--tw-shadow-color);box-shadow:var(--tw-ring-offset-shadow, 0 0 #0000),var(--tw-ring-shadow, 0 0 #0000),var(--tw-shadow)}.transition-all{transition-property:all;transition-timing-function:cubic-bezier(.4,0,.2,1);transition-duration:.15s}.transition-colors{transition-property:color,background-color,border-color,text-decoration-color,fill,stroke;transition-timing-function:cubic-bezier(.4,0,.2,1);transition-duration:.15s}body{background-color:hsl(var(--background));color:hsl(var(--foreground))}.slider-hf::-webkit-slider-thumb{height:1rem;width:1rem;cursor:pointer;-webkit-appearance:none;-moz-appearance:none;appearance:none;border-radius:9999px;background:linear-gradient(45deg,#ffd21e,#ff9d00);box-shadow:0 1px 3px #0000001a}.slider-hf::-moz-range-thumb{height:1rem;width:1rem;cursor:pointer;border-radius:9999px;border-width:0px;background:linear-gradient(45deg,#ffd21e,#ff9d00);box-shadow:0 1px 3px #0000001a}.pause-filled{display:inline-flex;align-items:center;justify-content:center;width:14px;height:14px}.pause-filled:before,.pause-filled:after{content:"";width:2px;height:10px;background-color:currentColor;border-radius:1px}.pause-filled:before{margin-right:2px}.pause-filled:after{margin-left:2px}.hover\:bg-gray-100:hover{--tw-bg-opacity: 1;background-color:rgb(243 244 246 / var(--tw-bg-opacity, 1))}.hover\:bg-gray-50:hover{--tw-bg-opacity: 1;background-color:rgb(249 250 251 / var(--tw-bg-opacity, 1))}.hover\:bg-gray-800:hover{--tw-bg-opacity: 1;background-color:rgb(31 41 55 / var(--tw-bg-opacity, 1))}.hover\:from-amber-500:hover{--tw-gradient-from: #f59e0b var(--tw-gradient-from-position);--tw-gradient-to: rgb(245 158 11 / 0) var(--tw-gradient-to-position);--tw-gradient-stops: var(--tw-gradient-from), var(--tw-gradient-to)}.hover\:to-orange-600:hover{--tw-gradient-to: #ea580c var(--tw-gradient-to-position)}.hover\:text-gray-600:hover{--tw-text-opacity: 1;color:rgb(75 85 99 / var(--tw-text-opacity, 1))}.focus\:border-transparent:focus{border-color:transparent}.focus\:outline-none:focus{outline:2px solid transparent;outline-offset:2px}.focus\:ring-2:focus{--tw-ring-offset-shadow: var(--tw-ring-inset) 0 0 0 var(--tw-ring-offset-width) var(--tw-ring-offset-color);--tw-ring-shadow: var(--tw-ring-inset) 0 0 0 calc(2px + var(--tw-ring-offset-width)) var(--tw-ring-color);box-shadow:var(--tw-ring-offset-shadow),var(--tw-ring-shadow),var(--tw-shadow, 0 0 #0000)}.focus\:ring-amber-400:focus{--tw-ring-opacity: 1;--tw-ring-color: rgb(251 191 36 / var(--tw-ring-opacity, 1))}.disabled\:cursor-not-allowed:disabled{cursor:not-allowed}.disabled\:opacity-50:disabled{opacity:.5}
hfstudio/static/_app/immutable/chunks/9DiovRey.js ADDED
@@ -0,0 +1 @@
 
 
1
+ var I=Object.defineProperty;var R=(t,n,e)=>n in t?I(t,n,{enumerable:!0,configurable:!0,writable:!0,value:e}):t[n]=e;var N=(t,n,e)=>R(t,typeof n!="symbol"?n+"":n,e);function w(){}function W(t,n){for(const e in n)t[e]=n[e];return t}function O(t){return t()}function T(){return Object.create(null)}function $(t){t.forEach(O)}function P(t){return typeof t=="function"}function ht(t,n){return t!=t?n==n:t!==n||t&&typeof t=="object"||typeof t=="function"}let b;function mt(t,n){return t===n?!0:(b||(b=document.createElement("a")),b.href=n,t===b.href)}function G(t){return Object.keys(t).length===0}function J(t,...n){if(t==null){for(const r of n)r(void 0);return w}const e=t.subscribe(...n);return e.unsubscribe?()=>e.unsubscribe():e}function pt(t,n,e){t.$$.on_destroy.push(J(n,e))}function yt(t,n,e,r){if(t){const i=q(t,n,e,r);return t[0](i)}}function q(t,n,e,r){return t[1]&&r?W(e.ctx.slice(),t[1](r(n))):e.ctx}function gt(t,n,e,r){if(t[2]&&r){const i=t[2](r(e));if(n.dirty===void 0)return i;if(typeof i=="object"){const o=[],c=Math.max(n.dirty.length,i.length);for(let l=0;l<c;l+=1)o[l]=n.dirty[l]|i[l];return o}return n.dirty|i}return n.dirty}function $t(t,n,e,r,i,o){if(i){const c=q(n,e,r,o);t.p(c,i)}}function xt(t){if(t.ctx.length>32){const n=[],e=t.ctx.length/32;for(let r=0;r<e;r++)n[r]=-1;return n}return-1}function bt(t){const n={};for(const e in t)e[0]!=="$"&&(n[e]=t[e]);return n}function vt(t,n){const e={};n=new Set(n);for(const r in t)!n.has(r)&&r[0]!=="$"&&(e[r]=t[r]);return e}let E=!1;function K(){E=!0}function Q(){E=!1}function V(t,n,e,r){for(;t<n;){const i=t+(n-t>>1);e(i)<=r?t=i+1:n=i}return t}function X(t){if(t.hydrate_init)return;t.hydrate_init=!0;let n=t.childNodes;if(t.nodeName==="HEAD"){const u=[];for(let s=0;s<n.length;s++){const f=n[s];f.claim_order!==void 0&&u.push(f)}n=u}const e=new Int32Array(n.length+1),r=new Int32Array(n.length);e[0]=-1;let i=0;for(let u=0;u<n.length;u++){const s=n[u].claim_order,f=(i>0&&n[e[i]].claim_order<=s?i+1:V(1,i,x=>n[e[x]].claim_order,s))-1;r[u]=e[f]+1;const a=f+1;e[a]=u,i=Math.max(a,i)}const o=[],c=[];let l=n.length-1;for(let u=e[i]+1;u!=0;u=r[u-1]){for(o.push(n[u-1]);l>=u;l--)c.push(n[l]);l--}for(;l>=0;l--)c.push(n[l]);o.reverse(),c.sort((u,s)=>u.claim_order-s.claim_order);for(let u=0,s=0;u<c.length;u++){for(;s<o.length&&c[u].claim_order>=o[s].claim_order;)s++;const f=s<o.length?o[s]:null;t.insertBefore(c[u],f)}}function Y(t,n){if(E){for(X(t),(t.actual_end_child===void 0||t.actual_end_child!==null&&t.actual_end_child.parentNode!==t)&&(t.actual_end_child=t.firstChild);t.actual_end_child!==null&&t.actual_end_child.claim_order===void 0;)t.actual_end_child=t.actual_end_child.nextSibling;n!==t.actual_end_child?(n.claim_order!==void 0||n.parentNode!==t)&&t.insertBefore(n,t.actual_end_child):t.actual_end_child=n.nextSibling}else(n.parentNode!==t||n.nextSibling!==null)&&t.appendChild(n)}function wt(t,n,e){E&&!e?Y(t,n):(n.parentNode!==t||n.nextSibling!=e)&&t.insertBefore(n,e||null)}function Z(t){t.parentNode&&t.parentNode.removeChild(t)}function Et(t,n){for(let e=0;e<t.length;e+=1)t[e]&&t[e].d(n)}function tt(t){return document.createElement(t)}function nt(t){return document.createElementNS("http://www.w3.org/2000/svg",t)}function j(t){return document.createTextNode(t)}function Nt(){return j(" ")}function At(){return j("")}function Ct(t,n,e,r){return t.addEventListener(n,e,r),()=>t.removeEventListener(n,e,r)}function et(t,n,e){e==null?t.removeAttribute(n):t.getAttribute(n)!==e&&t.setAttribute(n,e)}function St(t,n){for(const e in n)et(t,e,n[e])}function jt(t){return t.dataset.svelteH}function kt(t){return t===""?null:+t}function rt(t){return Array.from(t.childNodes)}function it(t){t.claim_info===void 0&&(t.claim_info={last_index:0,total_claimed:0})}function B(t,n,e,r,i=!1){it(t);const o=(()=>{for(let c=t.claim_info.last_index;c<t.length;c++){const l=t[c];if(n(l)){const u=e(l);return u===void 0?t.splice(c,1):t[c]=u,i||(t.claim_info.last_index=c),l}}for(let c=t.claim_info.last_index-1;c>=0;c--){const l=t[c];if(n(l)){const u=e(l);return u===void 0?t.splice(c,1):t[c]=u,i?u===void 0&&t.claim_info.last_index--:t.claim_info.last_index=c,l}}return r()})();return o.claim_order=t.claim_info.total_claimed,t.claim_info.total_claimed+=1,o}function L(t,n,e,r){return B(t,i=>i.nodeName===n,i=>{const o=[];for(let c=0;c<i.attributes.length;c++){const l=i.attributes[c];e[l.name]||o.push(l.name)}o.forEach(c=>i.removeAttribute(c))},()=>r(n))}function Dt(t,n,e){return L(t,n,e,tt)}function Tt(t,n,e){return L(t,n,e,nt)}function ct(t,n){return B(t,e=>e.nodeType===3,e=>{const r=""+n;if(e.data.startsWith(r)){if(e.data.length!==r.length)return e.splitText(r.length)}else e.data=r},()=>j(n),!0)}function Ht(t){return ct(t," ")}function Mt(t,n){n=""+n,t.data!==n&&(t.data=n)}function Ot(t,n){t.value=n??""}function Pt(t,n,e,r){e==null?t.style.removeProperty(n):t.style.setProperty(n,e,"")}function ut(t,n,{bubbles:e=!1,cancelable:r=!1}={}){return new CustomEvent(t,{detail:n,bubbles:e,cancelable:r})}function qt(t,n){const e=[];let r=0;for(const i of n.childNodes)if(i.nodeType===8){const o=i.textContent.trim();o===`HEAD_${t}_END`?(r-=1,e.push(i)):o===`HEAD_${t}_START`&&(r+=1,e.push(i))}else r>0&&e.push(i);return e}function Bt(t,n){return new t(n)}let g;function y(t){g=t}function _(){if(!g)throw new Error("Function called outside component initialization");return g}function Lt(t){_().$$.before_update.push(t)}function Ut(t){_().$$.on_mount.push(t)}function zt(t){_().$$.after_update.push(t)}function Ft(t){_().$$.on_destroy.push(t)}function It(){const t=_();return(n,e,{cancelable:r=!1}={})=>{const i=t.$$.callbacks[n];if(i){const o=ut(n,e,{cancelable:r});return i.slice().forEach(c=>{c.call(t,o)}),!o.defaultPrevented}return!0}}function Rt(t,n){return _().$$.context.set(t,n),n}function Wt(t){return _().$$.context.get(t)}function Gt(){return _().$$.context}function Jt(t){return _().$$.context.has(t)}const m=[],H=[];let p=[];const M=[],U=Promise.resolve();let C=!1;function z(){C||(C=!0,U.then(F))}function Kt(){return z(),U}function S(t){p.push(t)}const A=new Set;let h=0;function F(){if(h!==0)return;const t=g;do{try{for(;h<m.length;){const n=m[h];h++,y(n),st(n.$$)}}catch(n){throw m.length=0,h=0,n}for(y(null),m.length=0,h=0;H.length;)H.pop()();for(let n=0;n<p.length;n+=1){const e=p[n];A.has(e)||(A.add(e),e())}p.length=0}while(m.length);for(;M.length;)M.pop()();C=!1,A.clear(),y(t)}function st(t){if(t.fragment!==null){t.update(),$(t.before_update);const n=t.dirty;t.dirty=[-1],t.fragment&&t.fragment.p(t.ctx,n),t.after_update.forEach(S)}}function ot(t){const n=[],e=[];p.forEach(r=>t.indexOf(r)===-1?n.push(r):e.push(r)),e.forEach(r=>r()),p=n}const v=new Set;let d;function Qt(){d={r:0,c:[],p:d}}function Vt(){d.r||$(d.c),d=d.p}function lt(t,n){t&&t.i&&(v.delete(t),t.i(n))}function Xt(t,n,e,r){if(t&&t.o){if(v.has(t))return;v.add(t),d.c.push(()=>{v.delete(t),r&&(e&&t.d(1),r())}),t.o(n)}else r&&r()}function Yt(t){t&&t.c()}function Zt(t,n){t&&t.l(n)}function at(t,n,e){const{fragment:r,after_update:i}=t.$$;r&&r.m(n,e),S(()=>{const o=t.$$.on_mount.map(O).filter(P);t.$$.on_destroy?t.$$.on_destroy.push(...o):$(o),t.$$.on_mount=[]}),i.forEach(S)}function ft(t,n){const e=t.$$;e.fragment!==null&&(ot(e.after_update),$(e.on_destroy),e.fragment&&e.fragment.d(n),e.on_destroy=e.fragment=null,e.ctx=[])}function _t(t,n){t.$$.dirty[0]===-1&&(m.push(t),z(),t.$$.dirty.fill(0)),t.$$.dirty[n/31|0]|=1<<n%31}function tn(t,n,e,r,i,o,c=null,l=[-1]){const u=g;y(t);const s=t.$$={fragment:null,ctx:[],props:o,update:w,not_equal:i,bound:T(),on_mount:[],on_destroy:[],on_disconnect:[],before_update:[],after_update:[],context:new Map(n.context||(u?u.$$.context:[])),callbacks:T(),dirty:l,skip_bound:!1,root:n.target||u.$$.root};c&&c(s.root);let f=!1;if(s.ctx=e?e(t,n.props||{},(a,x,...k)=>{const D=k.length?k[0]:x;return s.ctx&&i(s.ctx[a],s.ctx[a]=D)&&(!s.skip_bound&&s.bound[a]&&s.bound[a](D),f&&_t(t,a)),x}):[],s.update(),f=!0,$(s.before_update),s.fragment=r?r(s.ctx):!1,n.target){if(n.hydrate){K();const a=rt(n.target);s.fragment&&s.fragment.l(a),a.forEach(Z)}else s.fragment&&s.fragment.c();n.intro&&lt(t.$$.fragment),at(t,n.target,n.anchor),Q(),F()}y(u)}class nn{constructor(){N(this,"$$");N(this,"$$set")}$destroy(){ft(this,1),this.$destroy=w}$on(n,e){if(!P(e))return w;const r=this.$$.callbacks[n]||(this.$$.callbacks[n]=[]);return r.push(e),()=>{const i=r.indexOf(e);i!==-1&&r.splice(i,1)}}$set(n){this.$$set&&!G(n)&&(this.$$.skip_bound=!0,this.$$set(n),this.$$.skip_bound=!1)}}export{Wt as $,xt as A,gt as B,Qt as C,Vt as D,At as E,zt as F,Kt as G,Bt as H,ft as I,Yt as J,at as K,Zt as L,Pt as M,H as N,W as O,Et as P,St as Q,Tt as R,nn as S,nt as T,vt as U,bt as V,Ot as W,kt as X,Lt as Y,It as Z,Gt as _,Mt as a,Jt as a0,Ft as a1,Rt as a2,wt as b,Y as c,Z as d,Dt as e,rt as f,ct as g,Ht as h,tn as i,tt as j,Nt as k,pt as l,mt as m,w as n,et as o,qt as p,jt as q,Ut as r,ht as s,j as t,Ct as u,yt as v,$ as w,Xt as x,lt as y,$t as z};
hfstudio/static/_app/immutable/chunks/BHHrQo_1.js ADDED
@@ -0,0 +1 @@
 
 
1
+ import{s as e}from"./Dh5qNFGZ.js";const r=()=>{const s=e;return{page:{subscribe:s.page.subscribe},navigating:{subscribe:s.navigating.subscribe},updated:s.updated}},b={subscribe(s){return r().page.subscribe(s)}};export{b as p};
hfstudio/static/_app/immutable/chunks/Dh5qNFGZ.js ADDED
@@ -0,0 +1,3 @@
 
 
 
 
1
+ var kt=Object.defineProperty;var Et=(e,t,n)=>t in e?kt(e,t,{enumerable:!0,configurable:!0,writable:!0,value:n}):e[t]=n;var R=(e,t,n)=>Et(e,typeof t!="symbol"?t+"":t,n);import{S as At,F as Rt,Y as Tt,Z as Ut,_ as It,$ as Lt,a0 as $t,a1 as xt,r as ve,a2 as Ct,G as be,n as ge,s as Pt}from"./9DiovRey.js";class Qe extends At{constructor(n){if(!n||!n.target&&!n.$$inline)throw new Error("'target' is a required option");super();R(this,"$$prop_def");R(this,"$$events_def");R(this,"$$slot_def")}$destroy(){super.$destroy(),this.$destroy=()=>{console.warn("Component was already destroyed")}}$capture_state(){}$inject_state(){}}class Ot extends Qe{}const Nt=Object.freeze(Object.defineProperty({__proto__:null,SvelteComponent:Qe,SvelteComponentTyped:Ot,afterUpdate:Rt,beforeUpdate:Tt,createEventDispatcher:Ut,getAllContexts:It,getContext:Lt,hasContext:$t,onDestroy:xt,onMount:ve,setContext:Ct,tick:be},Symbol.toStringTag,{value:"Module"}));class ce{constructor(t,n){this.status=t,typeof n=="string"?this.body={message:n}:n?this.body=n:this.body={message:`Error: ${t}`}}toString(){return JSON.stringify(this.body)}}class Re{constructor(t,n){this.status=t,this.location=n}}class Te extends Error{constructor(t,n,r){super(r),this.status=t,this.text=n}}new URL("sveltekit-internal://");function jt(e,t){return e==="/"||t==="ignore"?e:t==="never"?e.endsWith("/")?e.slice(0,-1):e:t==="always"&&!e.endsWith("/")?e+"/":e}function Dt(e){return e.split("%25").map(decodeURI).join("%25")}function qt(e){for(const t in e)e[t]=decodeURIComponent(e[t]);return e}function me({href:e}){return e.split("#")[0]}function Ft(e,t,n,r=!1){const a=new URL(e);Object.defineProperty(a,"searchParams",{value:new Proxy(a.searchParams,{get(i,o){if(o==="get"||o==="getAll"||o==="has")return l=>(n(l),i[o](l));t();const c=Reflect.get(i,o);return typeof c=="function"?c.bind(i):c}}),enumerable:!0,configurable:!0});const s=["href","pathname","search","toString","toJSON"];r&&s.push("hash");for(const i of s)Object.defineProperty(a,i,{get(){return t(),e[i]},enumerable:!0,configurable:!0});return a}function Bt(...e){let t=5381;for(const n of e)if(typeof n=="string"){let r=n.length;for(;r;)t=t*33^n.charCodeAt(--r)}else if(ArrayBuffer.isView(n)){const r=new Uint8Array(n.buffer,n.byteOffset,n.byteLength);let a=r.length;for(;a;)t=t*33^r[--a]}else throw new TypeError("value must be a string or TypedArray");return(t>>>0).toString(36)}new TextEncoder;const Mt=new TextDecoder;function Vt(e){const t=atob(e),n=new Uint8Array(t.length);for(let r=0;r<t.length;r++)n[r]=t.charCodeAt(r);return n}const Gt=window.fetch;window.fetch=(e,t)=>((e instanceof Request?e.method:(t==null?void 0:t.method)||"GET")!=="GET"&&Y.delete(Ue(e)),Gt(e,t));const Y=new Map;function Yt(e,t){const n=Ue(e,t),r=document.querySelector(n);if(r!=null&&r.textContent){r.remove();let{body:a,...s}=JSON.parse(r.textContent);const i=r.getAttribute("data-ttl");return i&&Y.set(n,{body:a,init:s,ttl:1e3*Number(i)}),r.getAttribute("data-b64")!==null&&(a=Vt(a)),Promise.resolve(new Response(a,s))}return window.fetch(e,t)}function Ht(e,t,n){if(Y.size>0){const r=Ue(e,n),a=Y.get(r);if(a){if(performance.now()<a.ttl&&["default","force-cache","only-if-cached",void 0].includes(n==null?void 0:n.cache))return new Response(a.body,a.init);Y.delete(r)}}return window.fetch(t,n)}function Ue(e,t){let r=`script[data-sveltekit-fetched][data-url=${JSON.stringify(e instanceof Request?e.url:e)}]`;if(t!=null&&t.headers||t!=null&&t.body){const a=[];t.headers&&a.push([...new Headers(t.headers)].join(",")),t.body&&(typeof t.body=="string"||ArrayBuffer.isView(t.body))&&a.push(t.body),r+=`[data-hash="${Bt(...a)}"]`}return r}const Kt=/^(\[)?(\.\.\.)?(\w+)(?:=(\w+))?(\])?$/;function zt(e){const t=[];return{pattern:e==="/"?/^\/$/:new RegExp(`^${Jt(e).map(r=>{const a=/^\[\.\.\.(\w+)(?:=(\w+))?\]$/.exec(r);if(a)return t.push({name:a[1],matcher:a[2],optional:!1,rest:!0,chained:!0}),"(?:/([^]*))?";const s=/^\[\[(\w+)(?:=(\w+))?\]\]$/.exec(r);if(s)return t.push({name:s[1],matcher:s[2],optional:!0,rest:!1,chained:!0}),"(?:/([^/]+))?";if(!r)return;const i=r.split(/\[(.+?)\](?!\])/);return"/"+i.map((c,l)=>{if(l%2){if(c.startsWith("x+"))return _e(String.fromCharCode(parseInt(c.slice(2),16)));if(c.startsWith("u+"))return _e(String.fromCharCode(...c.slice(2).split("-").map(u=>parseInt(u,16))));const d=Kt.exec(c),[,h,y,f,p]=d;return t.push({name:f,matcher:p,optional:!!h,rest:!!y,chained:y?l===1&&i[0]==="":!1}),y?"([^]*?)":h?"([^/]*)?":"([^/]+?)"}return _e(c)}).join("")}).join("")}/?$`),params:t}}function Wt(e){return e!==""&&!/^\([^)]+\)$/.test(e)}function Jt(e){return e.slice(1).split("/").filter(Wt)}function Xt(e,t,n){const r={},a=e.slice(1),s=a.filter(o=>o!==void 0);let i=0;for(let o=0;o<t.length;o+=1){const c=t[o];let l=a[o-i];if(c.chained&&c.rest&&i&&(l=a.slice(o-i,o+1).filter(d=>d).join("/"),i=0),l===void 0){c.rest&&(r[c.name]="");continue}if(!c.matcher||n[c.matcher](l)){r[c.name]=l;const d=t[o+1],h=a[o+1];d&&!d.rest&&d.optional&&h&&c.chained&&(i=0),!d&&!h&&Object.keys(r).length===s.length&&(i=0);continue}if(c.optional&&c.chained){i++;continue}return}if(!i)return r}function _e(e){return e.normalize().replace(/[[\]]/g,"\\$&").replace(/%/g,"%25").replace(/\//g,"%2[Ff]").replace(/\?/g,"%3[Ff]").replace(/#/g,"%23").replace(/[.*+?^${}()|\\]/g,"\\$&")}function Zt({nodes:e,server_loads:t,dictionary:n,matchers:r}){const a=new Set(t);return Object.entries(n).map(([o,[c,l,d]])=>{const{pattern:h,params:y}=zt(o),f={id:o,exec:p=>{const u=h.exec(p);if(u)return Xt(u,y,r)},errors:[1,...d||[]].map(p=>e[p]),layouts:[0,...l||[]].map(i),leaf:s(c)};return f.errors.length=f.layouts.length=Math.max(f.errors.length,f.layouts.length),f});function s(o){const c=o<0;return c&&(o=~o),[c,e[o]]}function i(o){return o===void 0?o:[a.has(o),e[o]]}}function et(e,t=JSON.parse){try{return t(sessionStorage[e])}catch{}}function Be(e,t,n=JSON.stringify){const r=n(t);try{sessionStorage[e]=r}catch{}}const D=[];function Ie(e,t=ge){let n;const r=new Set;function a(o){if(Pt(e,o)&&(e=o,n)){const c=!D.length;for(const l of r)l[1](),D.push(l,e);if(c){for(let l=0;l<D.length;l+=2)D[l][0](D[l+1]);D.length=0}}}function s(o){a(o(e))}function i(o,c=ge){const l=[o,c];return r.add(l),r.size===1&&(n=t(a,s)||ge),o(e),()=>{r.delete(l),r.size===0&&n&&(n(),n=null)}}return{set:a,update:s,subscribe:i}}var Xe;const $=((Xe=globalThis.__sveltekit_pr8qbd)==null?void 0:Xe.base)??"";var Ze;const Qt=((Ze=globalThis.__sveltekit_pr8qbd)==null?void 0:Ze.assets)??$??"",en="1760660574318",tt="sveltekit:snapshot",nt="sveltekit:scroll",at="sveltekit:states",tn="sveltekit:pageurl",F="sveltekit:history",z="sveltekit:navigation",O={tap:1,hover:2,viewport:3,eager:4,off:-1,false:-1},Z=location.origin;function Le(e){if(e instanceof URL)return e;let t=document.baseURI;if(!t){const n=document.getElementsByTagName("base");t=n.length?n[0].href:document.URL}return new URL(e,t)}function le(){return{x:pageXOffset,y:pageYOffset}}function q(e,t){return e.getAttribute(`data-sveltekit-${t}`)}const Me={...O,"":O.hover};function rt(e){let t=e.assignedSlot??e.parentNode;return(t==null?void 0:t.nodeType)===11&&(t=t.host),t}function ot(e,t){for(;e&&e!==t;){if(e.nodeName.toUpperCase()==="A"&&e.hasAttribute("href"))return e;e=rt(e)}}function Se(e,t,n){let r;try{if(r=new URL(e instanceof SVGAElement?e.href.baseVal:e.href,document.baseURI),n&&r.hash.match(/^#[^/]/)){const o=location.hash.split("#")[1]||"/";r.hash=`#${o}${r.hash}`}}catch{}const a=e instanceof SVGAElement?e.target.baseVal:e.target,s=!r||!!a||fe(r,t,n)||(e.getAttribute("rel")||"").split(/\s+/).includes("external"),i=(r==null?void 0:r.origin)===Z&&e.hasAttribute("download");return{url:r,external:s,target:a,download:i}}function ee(e){let t=null,n=null,r=null,a=null,s=null,i=null,o=e;for(;o&&o!==document.documentElement;)r===null&&(r=q(o,"preload-code")),a===null&&(a=q(o,"preload-data")),t===null&&(t=q(o,"keepfocus")),n===null&&(n=q(o,"noscroll")),s===null&&(s=q(o,"reload")),i===null&&(i=q(o,"replacestate")),o=rt(o);function c(l){switch(l){case"":case"true":return!0;case"off":case"false":return!1;default:return}}return{preload_code:Me[r??"off"],preload_data:Me[a??"off"],keepfocus:c(t),noscroll:c(n),reload:c(s),replace_state:c(i)}}function Ve(e){const t=Ie(e);let n=!0;function r(){n=!0,t.update(i=>i)}function a(i){n=!1,t.set(i)}function s(i){let o;return t.subscribe(c=>{(o===void 0||n&&c!==o)&&i(o=c)})}return{notify:r,set:a,subscribe:s}}const st={v:()=>{}};function nn(){const{set:e,subscribe:t}=Ie(!1);let n;async function r(){clearTimeout(n);try{const a=await fetch(`${Qt}/_app/version.json`,{headers:{pragma:"no-cache","cache-control":"no-cache"}});if(!a.ok)return!1;const i=(await a.json()).version!==en;return i&&(e(!0),st.v(),clearTimeout(n)),i}catch{return!1}}return{subscribe:t,check:r}}function fe(e,t,n){return e.origin!==Z||!e.pathname.startsWith(t)?!0:n?!(e.pathname===t+"/"||e.pathname===t+"/index.html"||e.protocol==="file:"&&e.pathname.replace(/\/[^/]+\.html?$/,"")===t):!1}function Vn(e){}function an(e){const t=on(e),n=new ArrayBuffer(t.length),r=new DataView(n);for(let a=0;a<n.byteLength;a++)r.setUint8(a,t.charCodeAt(a));return n}const rn="ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";function on(e){e.length%4===0&&(e=e.replace(/==?$/,""));let t="",n=0,r=0;for(let a=0;a<e.length;a++)n<<=6,n|=rn.indexOf(e[a]),r+=6,r===24&&(t+=String.fromCharCode((n&16711680)>>16),t+=String.fromCharCode((n&65280)>>8),t+=String.fromCharCode(n&255),n=r=0);return r===12?(n>>=4,t+=String.fromCharCode(n)):r===18&&(n>>=2,t+=String.fromCharCode((n&65280)>>8),t+=String.fromCharCode(n&255)),t}const sn=-1,cn=-2,ln=-3,fn=-4,un=-5,dn=-6;function hn(e,t){if(typeof e=="number")return a(e,!0);if(!Array.isArray(e)||e.length===0)throw new Error("Invalid input");const n=e,r=Array(n.length);function a(s,i=!1){if(s===sn)return;if(s===ln)return NaN;if(s===fn)return 1/0;if(s===un)return-1/0;if(s===dn)return-0;if(i||typeof s!="number")throw new Error("Invalid input");if(s in r)return r[s];const o=n[s];if(!o||typeof o!="object")r[s]=o;else if(Array.isArray(o))if(typeof o[0]=="string"){const c=o[0],l=t==null?void 0:t[c];if(l)return r[s]=l(a(o[1]));switch(c){case"Date":r[s]=new Date(o[1]);break;case"Set":const d=new Set;r[s]=d;for(let f=1;f<o.length;f+=1)d.add(a(o[f]));break;case"Map":const h=new Map;r[s]=h;for(let f=1;f<o.length;f+=2)h.set(a(o[f]),a(o[f+1]));break;case"RegExp":r[s]=new RegExp(o[1],o[2]);break;case"Object":r[s]=Object(o[1]);break;case"BigInt":r[s]=BigInt(o[1]);break;case"null":const y=Object.create(null);r[s]=y;for(let f=1;f<o.length;f+=2)y[o[f]]=a(o[f+1]);break;case"Int8Array":case"Uint8Array":case"Uint8ClampedArray":case"Int16Array":case"Uint16Array":case"Int32Array":case"Uint32Array":case"Float32Array":case"Float64Array":case"BigInt64Array":case"BigUint64Array":{const f=globalThis[c],p=new f(a(o[1]));r[s]=o[2]!==void 0?p.subarray(o[2],o[3]):p;break}case"ArrayBuffer":{const f=o[1],p=an(f);r[s]=p;break}case"Temporal.Duration":case"Temporal.Instant":case"Temporal.PlainDate":case"Temporal.PlainTime":case"Temporal.PlainDateTime":case"Temporal.PlainMonthDay":case"Temporal.PlainYearMonth":case"Temporal.ZonedDateTime":{const f=c.slice(9);r[s]=Temporal[f].from(o[1]);break}case"URL":{const f=new URL(o[1]);r[s]=f;break}case"URLSearchParams":{const f=new URLSearchParams(o[1]);r[s]=f;break}default:throw new Error(`Unknown type ${c}`)}}else{const c=new Array(o.length);r[s]=c;for(let l=0;l<o.length;l+=1){const d=o[l];d!==cn&&(c[l]=a(d))}}else{const c={};r[s]=c;for(const l in o){if(l==="__proto__")throw new Error("Cannot parse an object with a `__proto__` property");const d=o[l];c[l]=a(d)}}return r[s]}return a(0)}const it=new Set(["load","prerender","csr","ssr","trailingSlash","config"]);[...it];const pn=new Set([...it]);[...pn];function gn(e){return e.filter(t=>t!=null)}const mn="x-sveltekit-invalidated",_n="x-sveltekit-trailing-slash";function te(e){return e instanceof ce||e instanceof Te?e.status:500}function wn(e){return e instanceof Te?e.text:"Internal Error"}let T,W,we;const yn=ve.toString().includes("$$")||/function \w+\(\) \{\}/.test(ve.toString());yn?(T={data:{},form:null,error:null,params:{},route:{id:null},state:{},status:-1,url:new URL("https://example.com")},W={current:null},we={current:!1}):(T=new class{constructor(){R(this,"data",$state.raw({}));R(this,"form",$state.raw(null));R(this,"error",$state.raw(null));R(this,"params",$state.raw({}));R(this,"route",$state.raw({id:null}));R(this,"state",$state.raw({}));R(this,"status",$state.raw(-1));R(this,"url",$state.raw(new URL("https://example.com")))}},W=new class{constructor(){R(this,"current",$state.raw(null))}},we=new class{constructor(){R(this,"current",$state.raw(!1))}},st.v=()=>we.current=!0);function vn(e){Object.assign(T,e)}const bn="/__data.json",Sn=".html__data.json";function kn(e){return e.endsWith(".html")?e.replace(/\.html$/,Sn):e.replace(/\/$/,"")+bn}const Ge={spanContext(){return En},setAttribute(){return this},setAttributes(){return this},addEvent(){return this},setStatus(){return this},updateName(){return this},end(){return this},isRecording(){return!1},recordException(){return this},addLink(){return this},addLinks(){return this}},En={traceId:"",spanId:"",traceFlags:0},{tick:An}=Nt,Rn=new Set(["icon","shortcut icon","apple-touch-icon"]),j=et(nt)??{},J=et(tt)??{},C={url:Ve({}),page:Ve({}),navigating:Ie(null),updated:nn()};function $e(e){j[e]=le()}function Tn(e,t){let n=e+1;for(;j[n];)delete j[n],n+=1;for(n=t+1;J[n];)delete J[n],n+=1}function V(e,t=!1){return t?location.replace(e.href):location.href=e.href,new Promise(()=>{})}async function ct(){if("serviceWorker"in navigator){const e=await navigator.serviceWorker.getRegistration($||"/");e&&await e.update()}}function Ye(){}let xe,ke,ne,x,Ee,k;const ae=[],re=[];let I=null;const Q=new Map,lt=new Set,Un=new Set,H=new Set;let b={branch:[],error:null,url:null},Ce=!1,oe=!1,He=!0,X=!1,G=!1,ft=!1,Pe=!1,ut,A,L,N;const K=new Set,Ke=new Map;async function Kn(e,t,n){var s,i,o,c,l;(s=globalThis.__sveltekit_pr8qbd)!=null&&s.data&&globalThis.__sveltekit_pr8qbd.data,document.URL!==location.href&&(location.href=location.href),k=e,await((o=(i=e.hooks).init)==null?void 0:o.call(i)),xe=Zt(e),x=document.documentElement,Ee=t,ke=e.nodes[0],ne=e.nodes[1],ke(),ne(),A=(c=history.state)==null?void 0:c[F],L=(l=history.state)==null?void 0:l[z],A||(A=L=Date.now(),history.replaceState({...history.state,[F]:A,[z]:L},""));const r=j[A];function a(){r&&(history.scrollRestoration="manual",scrollTo(r.x,r.y))}n?(a(),await Dn(Ee,n)):(await B({type:"enter",url:Le(k.hash?Fn(new URL(location.href)):location.href),replace_state:!0}),a()),jn()}function In(){ae.length=0,Pe=!1}function dt(e){re.some(t=>t==null?void 0:t.snapshot)&&(J[e]=re.map(t=>{var n;return(n=t==null?void 0:t.snapshot)==null?void 0:n.capture()}))}function ht(e){var t;(t=J[e])==null||t.forEach((n,r)=>{var a,s;(s=(a=re[r])==null?void 0:a.snapshot)==null||s.restore(n)})}function ze(){$e(A),Be(nt,j),dt(L),Be(tt,J)}async function pt(e,t,n,r){let a;t.invalidateAll&&(I=null),await B({type:"goto",url:Le(e),keepfocus:t.keepFocus,noscroll:t.noScroll,replace_state:t.replaceState,state:t.state,redirect_count:n,nav_token:r,accept:()=>{t.invalidateAll&&(Pe=!0,a=[...Ke.keys()]),t.invalidate&&t.invalidate.forEach(Nn)}}),t.invalidateAll&&be().then(be).then(()=>{Ke.forEach(({resource:s},i)=>{var o;a!=null&&a.includes(i)&&((o=s.refresh)==null||o.call(s))})})}async function Ln(e){if(e.id!==(I==null?void 0:I.id)){const t={};K.add(t),I={id:e.id,token:t,promise:_t({...e,preload:t}).then(n=>(K.delete(t),n.type==="loaded"&&n.state.error&&(I=null),n))}}return I.promise}async function ye(e){var n;const t=(n=await de(e,!1))==null?void 0:n.route;t&&await Promise.all([...t.layouts,t.leaf].map(r=>r==null?void 0:r[1]()))}function gt(e,t,n){var a;b=e.state;const r=document.querySelector("style[data-sveltekit]");if(r&&r.remove(),Object.assign(T,e.props.page),ut=new k.root({target:t,props:{...e.props,stores:C,components:re},hydrate:n,sync:!1}),ht(L),n){const s={from:null,to:{params:b.params,route:{id:((a=b.route)==null?void 0:a.id)??null},url:new URL(location.href)},willUnload:!1,type:"enter",complete:Promise.resolve()};H.forEach(i=>i(s))}oe=!0}function se({url:e,params:t,branch:n,status:r,error:a,route:s,form:i}){let o="never";if($&&(e.pathname===$||e.pathname===$+"/"))o="always";else for(const f of n)(f==null?void 0:f.slash)!==void 0&&(o=f.slash);e.pathname=jt(e.pathname,o),e.search=e.search;const c={type:"loaded",state:{url:e,params:t,branch:n,error:a,route:s},props:{constructors:gn(n).map(f=>f.node.component),page:De(T)}};i!==void 0&&(c.props.form=i);let l={},d=!T,h=0;for(let f=0;f<Math.max(n.length,b.branch.length);f+=1){const p=n[f],u=b.branch[f];(p==null?void 0:p.data)!==(u==null?void 0:u.data)&&(d=!0),p&&(l={...l,...p.data},d&&(c.props[`data_${h}`]=l),h+=1)}return(!b.url||e.href!==b.url.href||b.error!==a||i!==void 0&&i!==T.form||d)&&(c.props.page={error:a,params:t,route:{id:(s==null?void 0:s.id)??null},state:{},status:r,url:new URL(e),form:i??null,data:d?l:T.data}),c}async function Oe({loader:e,parent:t,url:n,params:r,route:a,server_data_node:s}){var d,h,y;let i=null,o=!0;const c={dependencies:new Set,params:new Set,parent:!1,route:!1,url:!1,search_params:new Set},l=await e();if((d=l.universal)!=null&&d.load){let f=function(...u){for(const g of u){const{href:_}=new URL(g,n);c.dependencies.add(_)}};const p={tracing:{enabled:!1,root:Ge,current:Ge},route:new Proxy(a,{get:(u,g)=>(o&&(c.route=!0),u[g])}),params:new Proxy(r,{get:(u,g)=>(o&&c.params.add(g),u[g])}),data:(s==null?void 0:s.data)??null,url:Ft(n,()=>{o&&(c.url=!0)},u=>{o&&c.search_params.add(u)},k.hash),async fetch(u,g){u instanceof Request&&(g={body:u.method==="GET"||u.method==="HEAD"?void 0:await u.blob(),cache:u.cache,credentials:u.credentials,headers:[...u.headers].length>0?u==null?void 0:u.headers:void 0,integrity:u.integrity,keepalive:u.keepalive,method:u.method,mode:u.mode,redirect:u.redirect,referrer:u.referrer,referrerPolicy:u.referrerPolicy,signal:u.signal,...g});const{resolved:_,promise:U}=mt(u,g,n);return o&&f(_.href),U},setHeaders:()=>{},depends:f,parent(){return o&&(c.parent=!0),t()},untrack(u){o=!1;try{return u()}finally{o=!0}}};i=await l.universal.load.call(null,p)??null}return{node:l,loader:e,server:s,universal:(h=l.universal)!=null&&h.load?{type:"data",data:i,uses:c}:null,data:i??(s==null?void 0:s.data)??null,slash:((y=l.universal)==null?void 0:y.trailingSlash)??(s==null?void 0:s.slash)}}function mt(e,t,n){let r=e instanceof Request?e.url:e;const a=new URL(r,n);a.origin===n.origin&&(r=a.href.slice(n.origin.length));const s=oe?Ht(r,a.href,t):Yt(r,t);return{resolved:a,promise:s}}function We(e,t,n,r,a,s){if(Pe)return!0;if(!a)return!1;if(a.parent&&e||a.route&&t||a.url&&n)return!0;for(const i of a.search_params)if(r.has(i))return!0;for(const i of a.params)if(s[i]!==b.params[i])return!0;for(const i of a.dependencies)if(ae.some(o=>o(new URL(i))))return!0;return!1}function Ne(e,t){return(e==null?void 0:e.type)==="data"?e:(e==null?void 0:e.type)==="skip"?t??null:null}function $n(e,t){if(!e)return new Set(t.searchParams.keys());const n=new Set([...e.searchParams.keys(),...t.searchParams.keys()]);for(const r of n){const a=e.searchParams.getAll(r),s=t.searchParams.getAll(r);a.every(i=>s.includes(i))&&s.every(i=>a.includes(i))&&n.delete(r)}return n}function Je({error:e,url:t,route:n,params:r}){return{type:"loaded",state:{error:e,url:t,route:n,params:r,branch:[]},props:{page:De(T),constructors:[]}}}async function _t({id:e,invalidating:t,url:n,params:r,route:a,preload:s}){if((I==null?void 0:I.id)===e)return K.delete(I.token),I.promise;const{errors:i,layouts:o,leaf:c}=a,l=[...o,c];i.forEach(w=>w==null?void 0:w().catch(()=>{})),l.forEach(w=>w==null?void 0:w[1]().catch(()=>{}));let d=null;const h=b.url?e!==ie(b.url):!1,y=b.route?a.id!==b.route.id:!1,f=$n(b.url,n);let p=!1;const u=l.map((w,m)=>{var P;const v=b.branch[m],S=!!(w!=null&&w[0])&&((v==null?void 0:v.loader)!==w[1]||We(p,y,h,f,(P=v.server)==null?void 0:P.uses,r));return S&&(p=!0),S});if(u.some(Boolean)){try{d=await vt(n,u)}catch(w){const m=await M(w,{url:n,params:r,route:{id:e}});return K.has(s)?Je({error:m,url:n,params:r,route:a}):ue({status:te(w),error:m,url:n,route:a})}if(d.type==="redirect")return d}const g=d==null?void 0:d.nodes;let _=!1;const U=l.map(async(w,m)=>{var he;if(!w)return;const v=b.branch[m],S=g==null?void 0:g[m];if((!S||S.type==="skip")&&w[1]===(v==null?void 0:v.loader)&&!We(_,y,h,f,(he=v.universal)==null?void 0:he.uses,r))return v;if(_=!0,(S==null?void 0:S.type)==="error")throw S;return Oe({loader:w[1],url:n,params:r,route:a,parent:async()=>{var Fe;const qe={};for(let pe=0;pe<m;pe+=1)Object.assign(qe,(Fe=await U[pe])==null?void 0:Fe.data);return qe},server_data_node:Ne(S===void 0&&w[0]?{type:"skip"}:S??null,w[0]?v==null?void 0:v.server:void 0)})});for(const w of U)w.catch(()=>{});const E=[];for(let w=0;w<l.length;w+=1)if(l[w])try{E.push(await U[w])}catch(m){if(m instanceof Re)return{type:"redirect",location:m.location};if(K.has(s))return Je({error:await M(m,{params:r,url:n,route:{id:a.id}}),url:n,params:r,route:a});let v=te(m),S;if(g!=null&&g.includes(m))v=m.status??v,S=m.error;else if(m instanceof ce)S=m.body;else{if(await C.updated.check())return await ct(),await V(n);S=await M(m,{params:r,url:n,route:{id:a.id}})}const P=await xn(w,E,i);return P?se({url:n,params:r,branch:E.slice(0,P.idx).concat(P.node),status:v,error:S,route:a}):await yt(n,{id:a.id},S,v)}else E.push(void 0);return se({url:n,params:r,branch:E,status:200,error:null,route:a,form:t?void 0:null})}async function xn(e,t,n){for(;e--;)if(n[e]){let r=e;for(;!t[r];)r-=1;try{return{idx:r+1,node:{node:await n[e](),loader:n[e],data:{},server:null,universal:null}}}catch{continue}}}async function ue({status:e,error:t,url:n,route:r}){const a={};let s=null;if(k.server_loads[0]===0)try{const o=await vt(n,[!0]);if(o.type!=="data"||o.nodes[0]&&o.nodes[0].type!=="data")throw 0;s=o.nodes[0]??null}catch{(n.origin!==Z||n.pathname!==location.pathname||Ce)&&await V(n)}try{const o=await Oe({loader:ke,url:n,params:a,route:r,parent:()=>Promise.resolve({}),server_data_node:Ne(s)}),c={node:await ne(),loader:ne,universal:null,server:null,data:null};return se({url:n,params:a,branch:[o,c],status:e,error:t,route:null})}catch(o){if(o instanceof Re)return pt(new URL(o.location,location.href),{},0);throw o}}async function Cn(e){const t=e.href;if(Q.has(t))return Q.get(t);let n;try{const r=(async()=>{let a=await k.hooks.reroute({url:new URL(e),fetch:async(s,i)=>mt(s,i,e).promise})??e;if(typeof a=="string"){const s=new URL(e);k.hash?s.hash=a:s.pathname=a,a=s}return a})();Q.set(t,r),n=await r}catch{Q.delete(t);return}return n}async function de(e,t){if(e&&!fe(e,$,k.hash)){const n=await Cn(e);if(!n)return;const r=Pn(n);for(const a of xe){const s=a.exec(r);if(s)return{id:ie(e),invalidating:t,route:a,params:qt(s),url:e}}}}function Pn(e){return Dt(k.hash?e.hash.replace(/^#/,"").replace(/[?#].+/,""):e.pathname.slice($.length))||"/"}function ie(e){return(k.hash?e.hash.replace(/^#/,""):e.pathname)+e.search}function wt({url:e,type:t,intent:n,delta:r,event:a}){let s=!1;const i=je(b,n,e,t);r!==void 0&&(i.navigation.delta=r),a!==void 0&&(i.navigation.event=a);const o={...i.navigation,cancel:()=>{s=!0,i.reject(new Error("navigation cancelled"))}};return X||lt.forEach(c=>c(o)),s?null:i}async function B({type:e,url:t,popped:n,keepfocus:r,noscroll:a,replace_state:s,state:i={},redirect_count:o=0,nav_token:c={},accept:l=Ye,block:d=Ye,event:h}){const y=N;N=c;const f=await de(t,!1),p=e==="enter"?je(b,f,t,e):wt({url:t,type:e,delta:n==null?void 0:n.delta,intent:f,event:h});if(!p){d(),N===c&&(N=y);return}const u=A,g=L;l(),X=!0,oe&&p.navigation.type!=="enter"&&C.navigating.set(W.current=p.navigation);let _=f&&await _t(f);if(!_){if(fe(t,$,k.hash))return await V(t,s);_=await yt(t,{id:null},await M(new Te(404,"Not Found",`Not found: ${t.pathname}`),{url:t,params:{},route:{id:null}}),404,s)}if(t=(f==null?void 0:f.url)||t,N!==c)return p.reject(new Error("navigation aborted")),!1;if(_.type==="redirect"){if(o<20){await B({type:e,url:new URL(_.location,t),popped:n,keepfocus:r,noscroll:a,replace_state:s,state:i,redirect_count:o+1,nav_token:c}),p.fulfil(void 0);return}_=await ue({status:500,error:await M(new Error("Redirect loop"),{url:t,params:{},route:{id:null}}),url:t,route:{id:null}})}else _.props.page.status>=400&&await C.updated.check()&&(await ct(),await V(t,s));if(In(),$e(u),dt(g),_.props.page.url.pathname!==t.pathname&&(t.pathname=_.props.page.url.pathname),i=n?n.state:i,!n){const m=s?0:1,v={[F]:A+=m,[z]:L+=m,[at]:i};(s?history.replaceState:history.pushState).call(history,v,"",t),s||Tn(A,L)}if(I=null,_.props.page.state=i,oe){const m=(await Promise.all(Array.from(Un,v=>v(p.navigation)))).filter(v=>typeof v=="function");if(m.length>0){let v=function(){m.forEach(S=>{H.delete(S)})};m.push(v),m.forEach(S=>{H.add(S)})}b=_.state,_.props.page&&(_.props.page.url=t),ut.$set(_.props),vn(_.props.page),ft=!0}else gt(_,Ee,!1);const{activeElement:U}=document;await An();let E=n?n.scroll:a?le():null;if(He){const m=t.hash&&document.getElementById(St(t));if(E)scrollTo(E.x,E.y);else if(m){m.scrollIntoView();const{top:v,left:S}=m.getBoundingClientRect();E={x:pageXOffset+S,y:pageYOffset+v}}else scrollTo(0,0)}const w=document.activeElement!==U&&document.activeElement!==document.body;!r&&!w&&qn(t,E),He=!0,_.props.page&&Object.assign(T,_.props.page),X=!1,e==="popstate"&&ht(L),p.fulfil(void 0),H.forEach(m=>m(p.navigation)),C.navigating.set(W.current=null)}async function yt(e,t,n,r,a){return e.origin===Z&&e.pathname===location.pathname&&!Ce?await ue({status:r,error:n,url:e,route:t}):await V(e,a)}function On(){let e,t,n;x.addEventListener("mousemove",o=>{const c=o.target;clearTimeout(e),e=setTimeout(()=>{s(c,O.hover)},20)});function r(o){o.defaultPrevented||s(o.composedPath()[0],O.tap)}x.addEventListener("mousedown",r),x.addEventListener("touchstart",r,{passive:!0});const a=new IntersectionObserver(o=>{for(const c of o)c.isIntersecting&&(ye(new URL(c.target.href)),a.unobserve(c.target))},{threshold:0});async function s(o,c){const l=ot(o,x),d=l===t&&c>=n;if(!l||d)return;const{url:h,external:y,download:f}=Se(l,$,k.hash);if(y||f)return;const p=ee(l),u=h&&ie(b.url)===ie(h);if(!(p.reload||u))if(c<=p.preload_data){t=l,n=O.tap;const g=await de(h,!1);if(!g)return;Ln(g)}else c<=p.preload_code&&(t=l,n=c,ye(h))}function i(){a.disconnect();for(const o of x.querySelectorAll("a")){const{url:c,external:l,download:d}=Se(o,$,k.hash);if(l||d)continue;const h=ee(o);h.reload||(h.preload_code===O.viewport&&a.observe(o),h.preload_code===O.eager&&ye(c))}}H.add(i),i()}function M(e,t){if(e instanceof ce)return e.body;const n=te(e),r=wn(e);return k.hooks.handleError({error:e,event:t,status:n,message:r})??{message:r}}function zn(e,t={}){return e=new URL(Le(e)),e.origin!==Z?Promise.reject(new Error("goto: invalid URL")):pt(e,t,0)}function Nn(e){if(typeof e=="function")ae.push(e);else{const{href:t}=new URL(e,location.href);ae.push(n=>n.href===t)}}function jn(){var t;history.scrollRestoration="manual",addEventListener("beforeunload",n=>{let r=!1;if(ze(),!X){const a=je(b,void 0,null,"leave"),s={...a.navigation,cancel:()=>{r=!0,a.reject(new Error("navigation cancelled"))}};lt.forEach(i=>i(s))}r?(n.preventDefault(),n.returnValue=""):history.scrollRestoration="auto"}),addEventListener("visibilitychange",()=>{document.visibilityState==="hidden"&&ze()}),(t=navigator.connection)!=null&&t.saveData||On(),x.addEventListener("click",async n=>{if(n.button||n.which!==1||n.metaKey||n.ctrlKey||n.shiftKey||n.altKey||n.defaultPrevented)return;const r=ot(n.composedPath()[0],x);if(!r)return;const{url:a,external:s,target:i,download:o}=Se(r,$,k.hash);if(!a)return;if(i==="_parent"||i==="_top"){if(window.parent!==window)return}else if(i&&i!=="_self")return;const c=ee(r);if(!(r instanceof SVGAElement)&&a.protocol!==location.protocol&&!(a.protocol==="https:"||a.protocol==="http:")||o)return;const[d,h]=(k.hash?a.hash.replace(/^#/,""):a.href).split("#"),y=d===me(location);if(s||c.reload&&(!y||!h)){wt({url:a,type:"link",event:n})?X=!0:n.preventDefault();return}if(h!==void 0&&y){const[,f]=b.url.href.split("#");if(f===h){if(n.preventDefault(),h===""||h==="top"&&r.ownerDocument.getElementById("top")===null)scrollTo({top:0});else{const p=r.ownerDocument.getElementById(decodeURIComponent(h));p&&(p.scrollIntoView(),p.focus())}return}if(G=!0,$e(A),e(a),!c.replace_state)return;G=!1}n.preventDefault(),await new Promise(f=>{requestAnimationFrame(()=>{setTimeout(f,0)}),setTimeout(f,100)}),await B({type:"link",url:a,keepfocus:c.keepfocus,noscroll:c.noscroll,replace_state:c.replace_state??a.href===location.href,event:n})}),x.addEventListener("submit",n=>{if(n.defaultPrevented)return;const r=HTMLFormElement.prototype.cloneNode.call(n.target),a=n.submitter;if(((a==null?void 0:a.formTarget)||r.target)==="_blank"||((a==null?void 0:a.formMethod)||r.method)!=="get")return;const o=new URL((a==null?void 0:a.hasAttribute("formaction"))&&(a==null?void 0:a.formAction)||r.action);if(fe(o,$,!1))return;const c=n.target,l=ee(c);if(l.reload)return;n.preventDefault(),n.stopPropagation();const d=new FormData(c,a);o.search=new URLSearchParams(d).toString(),B({type:"form",url:o,keepfocus:l.keepfocus,noscroll:l.noscroll,replace_state:l.replace_state??o.href===location.href,event:n})}),addEventListener("popstate",async n=>{var r;if(!Ae){if((r=n.state)!=null&&r[F]){const a=n.state[F];if(N={},a===A)return;const s=j[a],i=n.state[at]??{},o=new URL(n.state[tn]??location.href),c=n.state[z],l=b.url?me(location)===me(b.url):!1;if(c===L&&(ft||l)){i!==T.state&&(T.state=i),e(o),j[A]=le(),s&&scrollTo(s.x,s.y),A=a;return}const h=a-A;await B({type:"popstate",url:o,popped:{state:i,scroll:s,delta:h},accept:()=>{A=a,L=c},block:()=>{history.go(-h)},nav_token:N,event:n})}else if(!G){const a=new URL(location.href);e(a),k.hash&&location.reload()}}}),addEventListener("hashchange",()=>{G&&(G=!1,history.replaceState({...history.state,[F]:++A,[z]:L},"",location.href))});for(const n of document.querySelectorAll("link"))Rn.has(n.rel)&&(n.href=n.href);addEventListener("pageshow",n=>{n.persisted&&C.navigating.set(W.current=null)});function e(n){b.url=T.url=n,C.page.set(De(T)),C.page.notify()}}async function Dn(e,{status:t=200,error:n,node_ids:r,params:a,route:s,server_route:i,data:o,form:c}){Ce=!0;const l=new URL(location.href);let d;({params:a={},route:s={id:null}}=await de(l,!1)||{}),d=xe.find(({id:f})=>f===s.id);let h,y=!0;try{const f=r.map(async(u,g)=>{const _=o[g];return _!=null&&_.uses&&(_.uses=bt(_.uses)),Oe({loader:k.nodes[u],url:l,params:a,route:s,parent:async()=>{const U={};for(let E=0;E<g;E+=1)Object.assign(U,(await f[E]).data);return U},server_data_node:Ne(_)})}),p=await Promise.all(f);if(d){const u=d.layouts;for(let g=0;g<u.length;g++)u[g]||p.splice(g,0,void 0)}h=se({url:l,params:a,branch:p,status:t,error:n,form:c,route:d??null})}catch(f){if(f instanceof Re){await V(new URL(f.location,location.href));return}h=await ue({status:te(f),error:await M(f,{url:l,params:a,route:s}),url:l,route:s}),e.textContent="",y=!1}h.props.page&&(h.props.page.state={}),gt(h,e,y)}async function vt(e,t){var s;const n=new URL(e);n.pathname=kn(e.pathname),e.pathname.endsWith("/")&&n.searchParams.append(_n,"1"),n.searchParams.append(mn,t.map(i=>i?"1":"0").join(""));const r=window.fetch,a=await r(n.href,{});if(!a.ok){let i;throw(s=a.headers.get("content-type"))!=null&&s.includes("application/json")?i=await a.json():a.status===404?i="Not Found":a.status===500&&(i="Internal Error"),new ce(a.status,i)}return new Promise(async i=>{var h;const o=new Map,c=a.body.getReader();function l(y){return hn(y,{...k.decoders,Promise:f=>new Promise((p,u)=>{o.set(f,{fulfil:p,reject:u})})})}let d="";for(;;){const{done:y,value:f}=await c.read();if(y&&!d)break;for(d+=!f&&d?`
2
+ `:Mt.decode(f,{stream:!0});;){const p=d.indexOf(`
3
+ `);if(p===-1)break;const u=JSON.parse(d.slice(0,p));if(d=d.slice(p+1),u.type==="redirect")return i(u);if(u.type==="data")(h=u.nodes)==null||h.forEach(g=>{(g==null?void 0:g.type)==="data"&&(g.uses=bt(g.uses),g.data=l(g.data))}),i(u);else if(u.type==="chunk"){const{id:g,data:_,error:U}=u,E=o.get(g);o.delete(g),U?E.reject(l(U)):E.fulfil(l(_))}}}})}function bt(e){return{dependencies:new Set((e==null?void 0:e.dependencies)??[]),params:new Set((e==null?void 0:e.params)??[]),parent:!!(e!=null&&e.parent),route:!!(e!=null&&e.route),url:!!(e!=null&&e.url),search_params:new Set((e==null?void 0:e.search_params)??[])}}let Ae=!1;function qn(e,t=null){const n=document.querySelector("[autofocus]");if(n)n.focus();else{const r=St(e);if(r&&document.getElementById(r)){const{x:s,y:i}=t??le();setTimeout(()=>{const o=history.state;Ae=!0,location.replace(`#${r}`),k.hash&&location.replace(e.hash),history.replaceState(o,"",e.hash),scrollTo(s,i),Ae=!1})}else{const s=document.body,i=s.getAttribute("tabindex");s.tabIndex=-1,s.focus({preventScroll:!0,focusVisible:!1}),i!==null?s.setAttribute("tabindex",i):s.removeAttribute("tabindex")}const a=getSelection();if(a&&a.type!=="None"){const s=[];for(let i=0;i<a.rangeCount;i+=1)s.push(a.getRangeAt(i));setTimeout(()=>{if(a.rangeCount===s.length){for(let i=0;i<a.rangeCount;i+=1){const o=s[i],c=a.getRangeAt(i);if(o.commonAncestorContainer!==c.commonAncestorContainer||o.startContainer!==c.startContainer||o.endContainer!==c.endContainer||o.startOffset!==c.startOffset||o.endOffset!==c.endOffset)return}a.removeAllRanges()}})}}}function je(e,t,n,r){var c,l;let a,s;const i=new Promise((d,h)=>{a=d,s=h});return i.catch(()=>{}),{navigation:{from:{params:e.params,route:{id:((c=e.route)==null?void 0:c.id)??null},url:e.url},to:n&&{params:(t==null?void 0:t.params)??null,route:{id:((l=t==null?void 0:t.route)==null?void 0:l.id)??null},url:n},willUnload:!t,type:r,complete:i},fulfil:a,reject:s}}function De(e){return{data:e.data,error:e.error,form:e.form,params:e.params,route:e.route,state:e.state,status:e.status,url:e.url}}function Fn(e){const t=new URL(e);return t.hash=decodeURIComponent(e.hash),t}function St(e){let t;if(k.hash){const[,,n]=e.hash.split("#",3);t=n??""}else t=e.hash.slice(1);return decodeURIComponent(t)}export{Kn as a,zn as g,Vn as l,C as s};
hfstudio/static/_app/immutable/chunks/IHki7fMi.js ADDED
@@ -0,0 +1 @@
 
 
1
+ const e="4";typeof window<"u"&&(window.__svelte||(window.__svelte={v:new Set})).v.add(e);
hfstudio/static/_app/immutable/entry/app.DrVe4Aen.js ADDED
@@ -0,0 +1,2 @@
 
 
 
1
+ const __vite__mapDeps=(i,m=__vite__mapDeps,d=(m.f||(m.f=["../nodes/0.BWfnr5bB.js","../chunks/9DiovRey.js","../chunks/IHki7fMi.js","../assets/0.DkRYx-5s.css","../nodes/1.DRlzjau5.js","../chunks/BHHrQo_1.js","../chunks/Dh5qNFGZ.js","../nodes/2.BSR-L-2e.js","../nodes/3.VqKPhUiT.js"])))=>i.map(i=>d[i]);
2
+ import{S as j,i as q,s as B,d,x as h,y as g,C as O,D as A,b as E,h as U,E as w,k as F,F as G,r as H,G as J,H as y,I as P,J as R,K as L,L as C,o as D,M as p,e as K,f as W,j as z,N as I,a as Q,g as X,t as Y}from"../chunks/9DiovRey.js";import"../chunks/IHki7fMi.js";const Z="modulepreload",M=function(o,e){return new URL(o,e).href},N={},S=function(e,n,i){let r=Promise.resolve();if(n&&n.length>0){const t=document.getElementsByTagName("link"),s=document.querySelector("meta[property=csp-nonce]"),a=(s==null?void 0:s.nonce)||(s==null?void 0:s.getAttribute("nonce"));r=Promise.allSettled(n.map(f=>{if(f=M(f,i),f in N)return;N[f]=!0;const l=f.endsWith(".css"),_=l?'[rel="stylesheet"]':"";if(!!i)for(let k=t.length-1;k>=0;k--){const v=t[k];if(v.href===f&&(!l||v.rel==="stylesheet"))return}else if(document.querySelector(`link[href="${f}"]${_}`))return;const m=document.createElement("link");if(m.rel=l?"stylesheet":Z,l||(m.as="script"),m.crossOrigin="",m.href=f,a&&m.setAttribute("nonce",a),document.head.appendChild(m),l)return new Promise((k,v)=>{m.addEventListener("load",k),m.addEventListener("error",()=>v(new Error(`Unable to preload CSS for ${f}`)))})}))}function u(t){const s=new Event("vite:preloadError",{cancelable:!0});if(s.payload=t,window.dispatchEvent(s),!s.defaultPrevented)throw t}return r.then(t=>{for(const s of t||[])s.status==="rejected"&&u(s.reason);return e().catch(u)})},ae={};function $(o){let e,n,i;var r=o[2][0];function u(t,s){return{props:{data:t[4],form:t[3],params:t[1].params}}}return r&&(e=y(r,u(o)),o[12](e)),{c(){e&&R(e.$$.fragment),n=w()},l(t){e&&C(e.$$.fragment,t),n=w()},m(t,s){e&&L(e,t,s),E(t,n,s),i=!0},p(t,s){if(s&4&&r!==(r=t[2][0])){if(e){O();const a=e;h(a.$$.fragment,1,0,()=>{P(a,1)}),A()}r?(e=y(r,u(t)),t[12](e),R(e.$$.fragment),g(e.$$.fragment,1),L(e,n.parentNode,n)):e=null}else if(r){const a={};s&16&&(a.data=t[4]),s&8&&(a.form=t[3]),s&2&&(a.params=t[1].params),e.$set(a)}},i(t){i||(e&&g(e.$$.fragment,t),i=!0)},o(t){e&&h(e.$$.fragment,t),i=!1},d(t){t&&d(n),o[12](null),e&&P(e,t)}}}function x(o){let e,n,i;var r=o[2][0];function u(t,s){return{props:{data:t[4],params:t[1].params,$$slots:{default:[ee]},$$scope:{ctx:t}}}}return r&&(e=y(r,u(o)),o[11](e)),{c(){e&&R(e.$$.fragment),n=w()},l(t){e&&C(e.$$.fragment,t),n=w()},m(t,s){e&&L(e,t,s),E(t,n,s),i=!0},p(t,s){if(s&4&&r!==(r=t[2][0])){if(e){O();const a=e;h(a.$$.fragment,1,0,()=>{P(a,1)}),A()}r?(e=y(r,u(t)),t[11](e),R(e.$$.fragment),g(e.$$.fragment,1),L(e,n.parentNode,n)):e=null}else if(r){const a={};s&16&&(a.data=t[4]),s&2&&(a.params=t[1].params),s&8239&&(a.$$scope={dirty:s,ctx:t}),e.$set(a)}},i(t){i||(e&&g(e.$$.fragment,t),i=!0)},o(t){e&&h(e.$$.fragment,t),i=!1},d(t){t&&d(n),o[11](null),e&&P(e,t)}}}function ee(o){let e,n,i;var r=o[2][1];function u(t,s){return{props:{data:t[5],form:t[3],params:t[1].params}}}return r&&(e=y(r,u(o)),o[10](e)),{c(){e&&R(e.$$.fragment),n=w()},l(t){e&&C(e.$$.fragment,t),n=w()},m(t,s){e&&L(e,t,s),E(t,n,s),i=!0},p(t,s){if(s&4&&r!==(r=t[2][1])){if(e){O();const a=e;h(a.$$.fragment,1,0,()=>{P(a,1)}),A()}r?(e=y(r,u(t)),t[10](e),R(e.$$.fragment),g(e.$$.fragment,1),L(e,n.parentNode,n)):e=null}else if(r){const a={};s&32&&(a.data=t[5]),s&8&&(a.form=t[3]),s&2&&(a.params=t[1].params),e.$set(a)}},i(t){i||(e&&g(e.$$.fragment,t),i=!0)},o(t){e&&h(e.$$.fragment,t),i=!1},d(t){t&&d(n),o[10](null),e&&P(e,t)}}}function T(o){let e,n=o[7]&&V(o);return{c(){e=z("div"),n&&n.c(),this.h()},l(i){e=K(i,"DIV",{id:!0,"aria-live":!0,"aria-atomic":!0,style:!0});var r=W(e);n&&n.l(r),r.forEach(d),this.h()},h(){D(e,"id","svelte-announcer"),D(e,"aria-live","assertive"),D(e,"aria-atomic","true"),p(e,"position","absolute"),p(e,"left","0"),p(e,"top","0"),p(e,"clip","rect(0 0 0 0)"),p(e,"clip-path","inset(50%)"),p(e,"overflow","hidden"),p(e,"white-space","nowrap"),p(e,"width","1px"),p(e,"height","1px")},m(i,r){E(i,e,r),n&&n.m(e,null)},p(i,r){i[7]?n?n.p(i,r):(n=V(i),n.c(),n.m(e,null)):n&&(n.d(1),n=null)},d(i){i&&d(e),n&&n.d()}}}function V(o){let e;return{c(){e=Y(o[8])},l(n){e=X(n,o[8])},m(n,i){E(n,e,i)},p(n,i){i&256&&Q(e,n[8])},d(n){n&&d(e)}}}function te(o){let e,n,i,r,u;const t=[x,$],s=[];function a(l,_){return l[2][1]?0:1}e=a(o),n=s[e]=t[e](o);let f=o[6]&&T(o);return{c(){n.c(),i=F(),f&&f.c(),r=w()},l(l){n.l(l),i=U(l),f&&f.l(l),r=w()},m(l,_){s[e].m(l,_),E(l,i,_),f&&f.m(l,_),E(l,r,_),u=!0},p(l,[_]){let b=e;e=a(l),e===b?s[e].p(l,_):(O(),h(s[b],1,1,()=>{s[b]=null}),A(),n=s[e],n?n.p(l,_):(n=s[e]=t[e](l),n.c()),g(n,1),n.m(i.parentNode,i)),l[6]?f?f.p(l,_):(f=T(l),f.c(),f.m(r.parentNode,r)):f&&(f.d(1),f=null)},i(l){u||(g(n),u=!0)},o(l){h(n),u=!1},d(l){l&&(d(i),d(r)),s[e].d(l),f&&f.d(l)}}}function ne(o,e,n){let{stores:i}=e,{page:r}=e,{constructors:u}=e,{components:t=[]}=e,{form:s}=e,{data_0:a=null}=e,{data_1:f=null}=e;G(i.page.notify);let l=!1,_=!1,b=null;H(()=>{const c=i.page.subscribe(()=>{l&&(n(7,_=!0),J().then(()=>{n(8,b=document.title||"untitled page")}))});return n(6,l=!0),c});function m(c){I[c?"unshift":"push"](()=>{t[1]=c,n(0,t)})}function k(c){I[c?"unshift":"push"](()=>{t[0]=c,n(0,t)})}function v(c){I[c?"unshift":"push"](()=>{t[0]=c,n(0,t)})}return o.$$set=c=>{"stores"in c&&n(9,i=c.stores),"page"in c&&n(1,r=c.page),"constructors"in c&&n(2,u=c.constructors),"components"in c&&n(0,t=c.components),"form"in c&&n(3,s=c.form),"data_0"in c&&n(4,a=c.data_0),"data_1"in c&&n(5,f=c.data_1)},o.$$.update=()=>{o.$$.dirty&514&&i.page.set(r)},[t,r,u,s,a,f,l,_,b,i,m,k,v]}class le extends j{constructor(e){super(),q(this,e,ne,te,B,{stores:9,page:1,constructors:2,components:0,form:3,data_0:4,data_1:5})}}const fe=[()=>S(()=>import("../nodes/0.BWfnr5bB.js"),__vite__mapDeps([0,1,2,3]),import.meta.url),()=>S(()=>import("../nodes/1.DRlzjau5.js"),__vite__mapDeps([4,1,2,5,6]),import.meta.url),()=>S(()=>import("../nodes/2.BSR-L-2e.js"),__vite__mapDeps([7,1,2]),import.meta.url),()=>S(()=>import("../nodes/3.VqKPhUiT.js"),__vite__mapDeps([8,1,2,6,5]),import.meta.url)],ce=[],ue={"/":[2],"/auth/callback":[3]},se={handleError:({error:o})=>{console.error(o)},reroute:()=>{},transport:{}},ie=Object.fromEntries(Object.entries(se.transport).map(([o,e])=>[o,e.decode])),_e=!1,me=(o,e)=>ie[o](e);export{me as decode,ie as decoders,ue as dictionary,_e as hash,se as hooks,ae as matchers,fe as nodes,le as root,ce as server_loads};
hfstudio/static/_app/immutable/entry/start.CYVq8xer.js ADDED
@@ -0,0 +1 @@
 
 
1
+ import{l as o,a as r}from"../chunks/Dh5qNFGZ.js";export{o as load_css,r as start};
hfstudio/static/_app/immutable/nodes/0.BWfnr5bB.js ADDED
@@ -0,0 +1 @@
 
 
1
+ import{S as mt,i as gt,s as _t,v as xt,d as y,w as bt,x as vt,y as yt,o as c,z as wt,A as Tt,B as kt,b as et,c as s,u as dt,m as St,e as o,f as U,q as k,h as b,j as r,k as v,r as Ct,a as It,g as pt,t as ht,n as Lt}from"../chunks/9DiovRey.js";import"../chunks/IHki7fMi.js";function Mt(i){let e,t="Sign In";return{c(){e=r("span"),e.textContent=t},l(l){e=o(l,"SPAN",{"data-svelte-h":!0}),k(e)!=="svelte-6n3gky"&&(e.textContent=t)},m(l,u){et(l,e,u)},p:Lt,d(l){l&&y(e)}}}function At(i){let e,t,l;return{c(){e=r("span"),t=ht("Sign Out, "),l=ht(i[2])},l(u){e=o(u,"SPAN",{});var d=U(e);t=pt(d,"Sign Out, "),l=pt(d,i[2]),d.forEach(y)},m(u,d){et(u,e,d),s(e,t),s(e,l)},p(u,d){d&4&&It(l,u[2])},d(u){u&&y(e)}}}function Et(i){let e,t,l,u='<div class="flex items-center gap-3"><img src="/assets/hf-studio-logo.png" alt="HF Logo" class="w-8 h-8"/> <h1 class="text-xl font-semibold">HFStudio<sup class="text-xs text-gray-500 ml-1">BETA</sup></h1></div>',d,n,p,C="Tasks",q,g,I,f="🎙️",O,w,L="Text to Speech",S,z,M,st="<span>🎵</span> <span>Voice Cloning</span>",W,A,nt="<span>🎧</span> <span>Speech to Text</span>",J,E,at="<span>🎼</span> <span>Sound Effects</span>",K,H,lt="<span>🎸</span> <span>Music Generation</span>",Q,N,ot="<span>🔊</span> <span>Audio Enhancement</span>",X,D,T,B,rt,Y,Z,V,j,$,ct;function it(a,_){return a[1]?At:Mt}let F=it(i),x=F(i);const tt=i[5].default,m=xt(tt,i,i[4],null);return{c(){e=r("div"),t=r("aside"),l=r("div"),l.innerHTML=u,d=v(),n=r("nav"),p=r("div"),p.textContent=C,q=v(),g=r("button"),I=r("span"),I.textContent=f,O=v(),w=r("span"),w.textContent=L,z=v(),M=r("button"),M.innerHTML=st,W=v(),A=r("button"),A.innerHTML=nt,J=v(),E=r("button"),E.innerHTML=at,K=v(),H=r("button"),H.innerHTML=lt,Q=v(),N=r("button"),N.innerHTML=ot,X=v(),D=r("div"),T=r("button"),B=r("img"),Y=v(),x.c(),Z=v(),V=r("main"),m&&m.c(),this.h()},l(a){e=o(a,"DIV",{class:!0});var _=U(e);t=o(_,"ASIDE",{class:!0});var P=U(t);l=o(P,"DIV",{class:!0,"data-svelte-h":!0}),k(l)!=="svelte-1vahj38"&&(l.innerHTML=u),d=b(P),n=o(P,"NAV",{class:!0});var h=U(n);p=o(h,"DIV",{class:!0,"data-svelte-h":!0}),k(p)!=="svelte-1x5465q"&&(p.textContent=C),q=b(h),g=o(h,"BUTTON",{class:!0});var G=U(g);I=o(G,"SPAN",{"data-svelte-h":!0}),k(I)!=="svelte-1yx42xi"&&(I.textContent=f),O=b(G),w=o(G,"SPAN",{"data-svelte-h":!0}),k(w)!=="svelte-2j89jk"&&(w.textContent=L),G.forEach(y),z=b(h),M=o(h,"BUTTON",{class:!0,"data-svelte-h":!0}),k(M)!=="svelte-10dl8nf"&&(M.innerHTML=st),W=b(h),A=o(h,"BUTTON",{class:!0,"data-svelte-h":!0}),k(A)!=="svelte-wf0x5d"&&(A.innerHTML=nt),J=b(h),E=o(h,"BUTTON",{class:!0,"data-svelte-h":!0}),k(E)!=="svelte-x7bha3"&&(E.innerHTML=at),K=b(h),H=o(h,"BUTTON",{class:!0,"data-svelte-h":!0}),k(H)!=="svelte-1tyblmt"&&(H.innerHTML=lt),Q=b(h),N=o(h,"BUTTON",{class:!0,"data-svelte-h":!0}),k(N)!=="svelte-1emrjb3"&&(N.innerHTML=ot),h.forEach(y),X=b(P),D=o(P,"DIV",{class:!0});var ut=U(D);T=o(ut,"BUTTON",{class:!0});var R=U(T);B=o(R,"IMG",{src:!0,alt:!0,class:!0}),Y=b(R),x.l(R),R.forEach(y),ut.forEach(y),P.forEach(y),Z=b(_),V=o(_,"MAIN",{class:!0});var ft=U(V);m&&m.l(ft),ft.forEach(y),_.forEach(y),this.h()},h(){c(l,"class","p-4 border-b border-gray-200"),c(p,"class","mt-2 mb-1 px-2 text-xs font-medium text-gray-500 uppercase"),c(g,"class",S="w-full flex items-center gap-2 px-2 py-1.5 rounded-md hover:bg-gray-100 transition-colors text-left "+(i[0]==="tts"?"bg-gray-100":"")),c(M,"class","w-full flex items-center gap-2 px-2 py-1.5 rounded-md text-left opacity-40 cursor-not-allowed"),M.disabled=!0,c(A,"class","w-full flex items-center gap-2 px-2 py-1.5 rounded-md text-left opacity-40 cursor-not-allowed"),A.disabled=!0,c(E,"class","w-full flex items-center gap-2 px-2 py-1.5 rounded-md text-left opacity-40 cursor-not-allowed"),E.disabled=!0,c(H,"class","w-full flex items-center gap-2 px-2 py-1.5 rounded-md text-left opacity-40 cursor-not-allowed"),H.disabled=!0,c(N,"class","w-full flex items-center gap-2 px-2 py-1.5 rounded-md text-left opacity-40 cursor-not-allowed"),N.disabled=!0,c(n,"class","p-2 text-sm"),St(B.src,rt="/assets/hf-logo.png")||c(B,"src",rt),c(B,"alt","HF Logo"),c(B,"class","w-5 h-5"),c(T,"class","w-full px-6 py-3 bg-black text-white rounded-lg font-medium hover:bg-gray-800 transition-colors shadow-sm flex items-center justify-center gap-2 text-sm"),c(D,"class","absolute bottom-4 left-2 right-2 w-52"),c(t,"class","w-56 border-r border-gray-200 bg-white flex-shrink-0 "),c(V,"class","flex-1 overflow-auto"),c(e,"class","flex h-screen bg-white")},m(a,_){et(a,e,_),s(e,t),s(t,l),s(t,d),s(t,n),s(n,p),s(n,q),s(n,g),s(g,I),s(g,O),s(g,w),s(n,z),s(n,M),s(n,W),s(n,A),s(n,J),s(n,E),s(n,K),s(n,H),s(n,Q),s(n,N),s(t,X),s(t,D),s(D,T),s(T,B),s(T,Y),x.m(T,null),s(e,Z),s(e,V),m&&m.m(V,null),j=!0,$||(ct=[dt(g,"click",i[6]),dt(T,"click",i[3])],$=!0)},p(a,[_]){(!j||_&1&&S!==(S="w-full flex items-center gap-2 px-2 py-1.5 rounded-md hover:bg-gray-100 transition-colors text-left "+(a[0]==="tts"?"bg-gray-100":"")))&&c(g,"class",S),F===(F=it(a))&&x?x.p(a,_):(x.d(1),x=F(a),x&&(x.c(),x.m(T,null))),m&&m.p&&(!j||_&16)&&wt(m,tt,a,a[4],j?kt(tt,a[4],_,null):Tt(a[4]),null)},i(a){j||(yt(m,a),j=!0)},o(a){vt(m,a),j=!1},d(a){a&&y(e),x.d(),m&&m.d(a),$=!1,bt(ct)}}}function Ht(i,e,t){let{$$slots:l={},$$scope:u}=e,d="tts",n=!1,p="";Ct(()=>{C(),document.addEventListener("visibilitychange",()=>{document.hidden||C()}),window.addEventListener("storage",C);const f=setInterval(C,1e3);return()=>{window.removeEventListener("storage",C),clearInterval(f)}});function C(){const f=localStorage.getItem("hf_access_token");f?q(f):(t(1,n=!1),t(2,p=""))}async function q(f){try{const w=f.startsWith("hf_oauth_")?"https://huggingface.co/oauth/userinfo":"https://huggingface.co/api/whoami",L=await fetch(w,{headers:{Authorization:`Bearer ${f}`}});if(L.ok){const S=await L.json();t(1,n=!0);const z=S.name||S.login||"User";t(2,p=z.split(" ")[0])}else localStorage.removeItem("hf_access_token"),t(1,n=!1),t(2,p="")}catch{localStorage.removeItem("hf_access_token"),t(1,n=!1),t(2,p="")}}function g(){if(n)localStorage.removeItem("hf_access_token"),sessionStorage.removeItem("oauth_state"),t(1,n=!1),t(2,p="");else{const f="cdf32a17-e40f-4a84-b683-f66aa1105793",O="http://localhost:11111/auth/callback",w="read-repos",L=Math.random().toString(36).substring(2,15),S=`https://huggingface.co/oauth/authorize?client_id=${f}&redirect_uri=${encodeURIComponent(O)}&scope=${w}&response_type=code&state=${L}`;sessionStorage.setItem("oauth_state",L),window.location.href=S}}const I=()=>t(0,d="tts");return i.$$set=f=>{"$$scope"in f&&t(4,u=f.$$scope)},[d,n,p,g,u,l,I]}class Ot extends mt{constructor(e){super(),gt(this,e,Ht,Et,_t,{})}}export{Ot as component};
hfstudio/static/_app/immutable/nodes/1.DRlzjau5.js ADDED
@@ -0,0 +1 @@
 
 
1
+ import{S as x,i as S,s as j,n as u,d as c,a as h,b as _,c as d,e as v,f as g,g as b,h as k,j as E,t as $,k as q,l as y}from"../chunks/9DiovRey.js";import"../chunks/IHki7fMi.js";import{p as C}from"../chunks/BHHrQo_1.js";function H(p){var f;let a,s=p[0].status+"",r,n,o,i=((f=p[0].error)==null?void 0:f.message)+"",m;return{c(){a=E("h1"),r=$(s),n=q(),o=E("p"),m=$(i)},l(e){a=v(e,"H1",{});var t=g(a);r=b(t,s),t.forEach(c),n=k(e),o=v(e,"P",{});var l=g(o);m=b(l,i),l.forEach(c)},m(e,t){_(e,a,t),d(a,r),_(e,n,t),_(e,o,t),d(o,m)},p(e,[t]){var l;t&1&&s!==(s=e[0].status+"")&&h(r,s),t&1&&i!==(i=((l=e[0].error)==null?void 0:l.message)+"")&&h(m,i)},i:u,o:u,d(e){e&&(c(a),c(n),c(o))}}}function P(p,a,s){let r;return y(p,C,n=>s(0,r=n)),[r]}class B extends x{constructor(a){super(),S(this,a,P,H,j,{})}}export{B as component};
hfstudio/static/_app/immutable/nodes/2.BSR-L-2e.js ADDED
@@ -0,0 +1,16 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import{S as Ye,i as Ze,s as Me,v as ft,O as V,d as f,P as Vl,x as w,y as k,z as ct,A as dt,B as mt,Q as Al,b as G,c as o,R as vn,f as m,E as Ut,T as bn,U as Yl,V as R,I as B,K as U,L as O,J as x,w as xl,o as i,D as dl,W as yt,a as ut,u as P,e as c,g as I,h as p,q as Qe,j as d,t as D,k as v,n as Kt,C as ml,M as cl,N as kn,X as Dl,m as Zl}from"../chunks/9DiovRey.js";import"../chunks/IHki7fMi.js";function Bt(a){return(a==null?void 0:a.length)!==void 0?a:Array.from(a)}function et(a,e){const s={},t={},l={$$scope:1};let n=a.length;for(;n--;){const r=a[n],u=e[n];if(u){for(const g in r)g in u||(t[g]=1);for(const g in u)l[g]||(s[g]=u[g],l[g]=1);a[n]=u}else for(const g in r)l[g]=1}for(const r in t)r in s||(s[r]=void 0);return s}function wt(a){return typeof a=="object"&&a!==null?a:{}}/**
2
+ * @license lucide-svelte v0.303.0 - ISC
3
+
4
+ This source code is licensed under the ISC license.
5
+ See the LICENSE file in the root directory of this source tree.
6
+ */const en={xmlns:"http://www.w3.org/2000/svg",width:24,height:24,viewBox:"0 0 24 24",fill:"none",stroke:"currentColor","stroke-width":2,"stroke-linecap":"round","stroke-linejoin":"round"};function tn(a,e,s){const t=a.slice();return t[10]=e[s][0],t[11]=e[s][1],t}function Ul(a){let e,s=[a[11]],t={};for(let l=0;l<s.length;l+=1)t=V(t,s[l]);return{c(){e=bn(a[10]),this.h()},l(l){e=vn(l,a[10],{}),m(e).forEach(f),this.h()},h(){Al(e,t)},m(l,n){G(l,e,n)},p(l,n){Al(e,t=et(s,[n&32&&l[11]]))},d(l){l&&f(e)}}}function ln(a){let e=a[10],s,t=a[10]&&Ul(a);return{c(){t&&t.c(),s=Ut()},l(l){t&&t.l(l),s=Ut()},m(l,n){t&&t.m(l,n),G(l,s,n)},p(l,n){l[10]?e?Me(e,l[10])?(t.d(1),t=Ul(l),e=l[10],t.c(),t.m(s.parentNode,s)):t.p(l,n):(t=Ul(l),e=l[10],t.c(),t.m(s.parentNode,s)):e&&(t.d(1),t=null,e=l[10])},d(l){l&&f(s),t&&t.d(l)}}}function yn(a){let e,s,t,l,n,r=Bt(a[5]),u=[];for(let _=0;_<r.length;_+=1)u[_]=ln(tn(a,r,_));const g=a[9].default,E=ft(g,a,a[8],null);let N=[en,a[6],{width:a[2]},{height:a[2]},{stroke:a[1]},{"stroke-width":t=a[4]?Number(a[3])*24/Number(a[2]):a[3]},{class:l=`lucide-icon lucide lucide-${a[0]} ${a[7].class??""}`}],T={};for(let _=0;_<N.length;_+=1)T=V(T,N[_]);return{c(){e=bn("svg");for(let _=0;_<u.length;_+=1)u[_].c();s=Ut(),E&&E.c(),this.h()},l(_){e=vn(_,"svg",{width:!0,height:!0,stroke:!0,"stroke-width":!0,class:!0});var b=m(e);for(let $=0;$<u.length;$+=1)u[$].l(b);s=Ut(),E&&E.l(b),b.forEach(f),this.h()},h(){Al(e,T)},m(_,b){G(_,e,b);for(let $=0;$<u.length;$+=1)u[$]&&u[$].m(e,null);o(e,s),E&&E.m(e,null),n=!0},p(_,[b]){if(b&32){r=Bt(_[5]);let $;for($=0;$<r.length;$+=1){const S=tn(_,r,$);u[$]?u[$].p(S,b):(u[$]=ln(S),u[$].c(),u[$].m(e,s))}for(;$<u.length;$+=1)u[$].d(1);u.length=r.length}E&&E.p&&(!n||b&256)&&ct(E,g,_,_[8],n?mt(g,_[8],b,null):dt(_[8]),null),Al(e,T=et(N,[en,b&64&&_[6],(!n||b&4)&&{width:_[2]},(!n||b&4)&&{height:_[2]},(!n||b&2)&&{stroke:_[1]},(!n||b&28&&t!==(t=_[4]?Number(_[3])*24/Number(_[2]):_[3]))&&{"stroke-width":t},(!n||b&129&&l!==(l=`lucide-icon lucide lucide-${_[0]} ${_[7].class??""}`))&&{class:l}]))},i(_){n||(k(E,_),n=!0)},o(_){w(E,_),n=!1},d(_){_&&f(e),Vl(u,_),E&&E.d(_)}}}function wn(a,e,s){const t=["name","color","size","strokeWidth","absoluteStrokeWidth","iconNode"];let l=Yl(e,t),{$$slots:n={},$$scope:r}=e,{name:u}=e,{color:g="currentColor"}=e,{size:E=24}=e,{strokeWidth:N=2}=e,{absoluteStrokeWidth:T=!1}=e,{iconNode:_}=e;return a.$$set=b=>{s(7,e=V(V({},e),R(b))),s(6,l=Yl(e,t)),"name"in b&&s(0,u=b.name),"color"in b&&s(1,g=b.color),"size"in b&&s(2,E=b.size),"strokeWidth"in b&&s(3,N=b.strokeWidth),"absoluteStrokeWidth"in b&&s(4,T=b.absoluteStrokeWidth),"iconNode"in b&&s(5,_=b.iconNode),"$$scope"in b&&s(8,r=b.$$scope)},e=R(e),[u,g,E,N,T,_,l,e,r,n]}class Et extends Ye{constructor(e){super(),Ze(this,e,wn,yn,Me,{name:0,color:1,size:2,strokeWidth:3,absoluteStrokeWidth:4,iconNode:5})}}function En(a){let e;const s=a[2].default,t=ft(s,a,a[3],null);return{c(){t&&t.c()},l(l){t&&t.l(l)},m(l,n){t&&t.m(l,n),e=!0},p(l,n){t&&t.p&&(!e||n&8)&&ct(t,s,l,l[3],e?mt(s,l[3],n,null):dt(l[3]),null)},i(l){e||(k(t,l),e=!0)},o(l){w(t,l),e=!1},d(l){t&&t.d(l)}}}function Nn(a){let e,s;const t=[{name:"alert-circle"},a[1],{iconNode:a[0]}];let l={$$slots:{default:[En]},$$scope:{ctx:a}};for(let n=0;n<t.length;n+=1)l=V(l,t[n]);return e=new Et({props:l}),{c(){x(e.$$.fragment)},l(n){O(e.$$.fragment,n)},m(n,r){U(e,n,r),s=!0},p(n,[r]){const u=r&3?et(t,[t[0],r&2&&wt(n[1]),r&1&&{iconNode:n[0]}]):{};r&8&&(u.$$scope={dirty:r,ctx:n}),e.$set(u)},i(n){s||(k(e.$$.fragment,n),s=!0)},o(n){w(e.$$.fragment,n),s=!1},d(n){B(e,n)}}}function Tn(a,e,s){let{$$slots:t={},$$scope:l}=e;const n=[["circle",{cx:"12",cy:"12",r:"10"}],["line",{x1:"12",x2:"12",y1:"8",y2:"12"}],["line",{x1:"12",x2:"12.01",y1:"16",y2:"16"}]];return a.$$set=r=>{s(1,e=V(V({},e),R(r))),"$$scope"in r&&s(3,l=r.$$scope)},e=R(e),[n,e,t,l]}class In extends Ye{constructor(e){super(),Ze(this,e,Tn,Nn,Me,{})}}function Dn(a){let e;const s=a[2].default,t=ft(s,a,a[3],null);return{c(){t&&t.c()},l(l){t&&t.l(l)},m(l,n){t&&t.m(l,n),e=!0},p(l,n){t&&t.p&&(!e||n&8)&&ct(t,s,l,l[3],e?mt(s,l[3],n,null):dt(l[3]),null)},i(l){e||(k(t,l),e=!0)},o(l){w(t,l),e=!1},d(l){t&&t.d(l)}}}function Vn(a){let e,s;const t=[{name:"chevron-down"},a[1],{iconNode:a[0]}];let l={$$slots:{default:[Dn]},$$scope:{ctx:a}};for(let n=0;n<t.length;n+=1)l=V(l,t[n]);return e=new Et({props:l}),{c(){x(e.$$.fragment)},l(n){O(e.$$.fragment,n)},m(n,r){U(e,n,r),s=!0},p(n,[r]){const u=r&3?et(t,[t[0],r&2&&wt(n[1]),r&1&&{iconNode:n[0]}]):{};r&8&&(u.$$scope={dirty:r,ctx:n}),e.$set(u)},i(n){s||(k(e.$$.fragment,n),s=!0)},o(n){w(e.$$.fragment,n),s=!1},d(n){B(e,n)}}}function An(a,e,s){let{$$slots:t={},$$scope:l}=e;const n=[["path",{d:"m6 9 6 6 6-6"}]];return a.$$set=r=>{s(1,e=V(V({},e),R(r))),"$$scope"in r&&s(3,l=r.$$scope)},e=R(e),[n,e,t,l]}class Cn extends Ye{constructor(e){super(),Ze(this,e,An,Vn,Me,{})}}function Sn(a){let e;const s=a[2].default,t=ft(s,a,a[3],null);return{c(){t&&t.c()},l(l){t&&t.l(l)},m(l,n){t&&t.m(l,n),e=!0},p(l,n){t&&t.p&&(!e||n&8)&&ct(t,s,l,l[3],e?mt(s,l[3],n,null):dt(l[3]),null)},i(l){e||(k(t,l),e=!0)},o(l){w(t,l),e=!1},d(l){t&&t.d(l)}}}function Pn(a){let e,s;const t=[{name:"download"},a[1],{iconNode:a[0]}];let l={$$slots:{default:[Sn]},$$scope:{ctx:a}};for(let n=0;n<t.length;n+=1)l=V(l,t[n]);return e=new Et({props:l}),{c(){x(e.$$.fragment)},l(n){O(e.$$.fragment,n)},m(n,r){U(e,n,r),s=!0},p(n,[r]){const u=r&3?et(t,[t[0],r&2&&wt(n[1]),r&1&&{iconNode:n[0]}]):{};r&8&&(u.$$scope={dirty:r,ctx:n}),e.$set(u)},i(n){s||(k(e.$$.fragment,n),s=!0)},o(n){w(e.$$.fragment,n),s=!1},d(n){B(e,n)}}}function zn(a,e,s){let{$$slots:t={},$$scope:l}=e;const n=[["path",{d:"M21 15v4a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2v-4"}],["polyline",{points:"7 10 12 15 17 10"}],["line",{x1:"12",x2:"12",y1:"15",y2:"3"}]];return a.$$set=r=>{s(1,e=V(V({},e),R(r))),"$$scope"in r&&s(3,l=r.$$scope)},e=R(e),[n,e,t,l]}class nn extends Ye{constructor(e){super(),Ze(this,e,zn,Pn,Me,{})}}function Bn(a){let e;const s=a[2].default,t=ft(s,a,a[3],null);return{c(){t&&t.c()},l(l){t&&t.l(l)},m(l,n){t&&t.m(l,n),e=!0},p(l,n){t&&t.p&&(!e||n&8)&&ct(t,s,l,l[3],e?mt(s,l[3],n,null):dt(l[3]),null)},i(l){e||(k(t,l),e=!0)},o(l){w(t,l),e=!1},d(l){t&&t.d(l)}}}function Un(a){let e,s;const t=[{name:"loader-2"},a[1],{iconNode:a[0]}];let l={$$slots:{default:[Bn]},$$scope:{ctx:a}};for(let n=0;n<t.length;n+=1)l=V(l,t[n]);return e=new Et({props:l}),{c(){x(e.$$.fragment)},l(n){O(e.$$.fragment,n)},m(n,r){U(e,n,r),s=!0},p(n,[r]){const u=r&3?et(t,[t[0],r&2&&wt(n[1]),r&1&&{iconNode:n[0]}]):{};r&8&&(u.$$scope={dirty:r,ctx:n}),e.$set(u)},i(n){s||(k(e.$$.fragment,n),s=!0)},o(n){w(e.$$.fragment,n),s=!1},d(n){B(e,n)}}}function On(a,e,s){let{$$slots:t={},$$scope:l}=e;const n=[["path",{d:"M21 12a9 9 0 1 1-6.219-8.56"}]];return a.$$set=r=>{s(1,e=V(V({},e),R(r))),"$$scope"in r&&s(3,l=r.$$scope)},e=R(e),[n,e,t,l]}class xn extends Ye{constructor(e){super(),Ze(this,e,On,Un,Me,{})}}function jn(a){let e;const s=a[2].default,t=ft(s,a,a[3],null);return{c(){t&&t.c()},l(l){t&&t.l(l)},m(l,n){t&&t.m(l,n),e=!0},p(l,n){t&&t.p&&(!e||n&8)&&ct(t,s,l,l[3],e?mt(s,l[3],n,null):dt(l[3]),null)},i(l){e||(k(t,l),e=!0)},o(l){w(t,l),e=!1},d(l){t&&t.d(l)}}}function Mn(a){let e,s;const t=[{name:"more-horizontal"},a[1],{iconNode:a[0]}];let l={$$slots:{default:[jn]},$$scope:{ctx:a}};for(let n=0;n<t.length;n+=1)l=V(l,t[n]);return e=new Et({props:l}),{c(){x(e.$$.fragment)},l(n){O(e.$$.fragment,n)},m(n,r){U(e,n,r),s=!0},p(n,[r]){const u=r&3?et(t,[t[0],r&2&&wt(n[1]),r&1&&{iconNode:n[0]}]):{};r&8&&(u.$$scope={dirty:r,ctx:n}),e.$set(u)},i(n){s||(k(e.$$.fragment,n),s=!0)},o(n){w(e.$$.fragment,n),s=!1},d(n){B(e,n)}}}function Ln(a,e,s){let{$$slots:t={},$$scope:l}=e;const n=[["circle",{cx:"12",cy:"12",r:"1"}],["circle",{cx:"19",cy:"12",r:"1"}],["circle",{cx:"5",cy:"12",r:"1"}]];return a.$$set=r=>{s(1,e=V(V({},e),R(r))),"$$scope"in r&&s(3,l=r.$$scope)},e=R(e),[n,e,t,l]}class $n extends Ye{constructor(e){super(),Ze(this,e,Ln,Mn,Me,{})}}function Hn(a){let e;const s=a[2].default,t=ft(s,a,a[3],null);return{c(){t&&t.c()},l(l){t&&t.l(l)},m(l,n){t&&t.m(l,n),e=!0},p(l,n){t&&t.p&&(!e||n&8)&&ct(t,s,l,l[3],e?mt(s,l[3],n,null):dt(l[3]),null)},i(l){e||(k(t,l),e=!0)},o(l){w(t,l),e=!1},d(l){t&&t.d(l)}}}function Wn(a){let e,s;const t=[{name:"play"},a[1],{iconNode:a[0]}];let l={$$slots:{default:[Hn]},$$scope:{ctx:a}};for(let n=0;n<t.length;n+=1)l=V(l,t[n]);return e=new Et({props:l}),{c(){x(e.$$.fragment)},l(n){O(e.$$.fragment,n)},m(n,r){U(e,n,r),s=!0},p(n,[r]){const u=r&3?et(t,[t[0],r&2&&wt(n[1]),r&1&&{iconNode:n[0]}]):{};r&8&&(u.$$scope={dirty:r,ctx:n}),e.$set(u)},i(n){s||(k(e.$$.fragment,n),s=!0)},o(n){w(e.$$.fragment,n),s=!1},d(n){B(e,n)}}}function qn(a,e,s){let{$$slots:t={},$$scope:l}=e;const n=[["polygon",{points:"5 3 19 12 5 21 5 3"}]];return a.$$set=r=>{s(1,e=V(V({},e),R(r))),"$$scope"in r&&s(3,l=r.$$scope)},e=R(e),[n,e,t,l]}class jl extends Ye{constructor(e){super(),Ze(this,e,qn,Wn,Me,{})}}function Fn(a){let e;const s=a[2].default,t=ft(s,a,a[3],null);return{c(){t&&t.c()},l(l){t&&t.l(l)},m(l,n){t&&t.m(l,n),e=!0},p(l,n){t&&t.p&&(!e||n&8)&&ct(t,s,l,l[3],e?mt(s,l[3],n,null):dt(l[3]),null)},i(l){e||(k(t,l),e=!0)},o(l){w(t,l),e=!1},d(l){t&&t.d(l)}}}function Gn(a){let e,s;const t=[{name:"settings"},a[1],{iconNode:a[0]}];let l={$$slots:{default:[Fn]},$$scope:{ctx:a}};for(let n=0;n<t.length;n+=1)l=V(l,t[n]);return e=new Et({props:l}),{c(){x(e.$$.fragment)},l(n){O(e.$$.fragment,n)},m(n,r){U(e,n,r),s=!0},p(n,[r]){const u=r&3?et(t,[t[0],r&2&&wt(n[1]),r&1&&{iconNode:n[0]}]):{};r&8&&(u.$$scope={dirty:r,ctx:n}),e.$set(u)},i(n){s||(k(e.$$.fragment,n),s=!0)},o(n){w(e.$$.fragment,n),s=!1},d(n){B(e,n)}}}function Rn(a,e,s){let{$$slots:t={},$$scope:l}=e;const n=[["path",{d:"M12.22 2h-.44a2 2 0 0 0-2 2v.18a2 2 0 0 1-1 1.73l-.43.25a2 2 0 0 1-2 0l-.15-.08a2 2 0 0 0-2.73.73l-.22.38a2 2 0 0 0 .73 2.73l.15.1a2 2 0 0 1 1 1.72v.51a2 2 0 0 1-1 1.74l-.15.09a2 2 0 0 0-.73 2.73l.22.38a2 2 0 0 0 2.73.73l.15-.08a2 2 0 0 1 2 0l.43.25a2 2 0 0 1 1 1.73V20a2 2 0 0 0 2 2h.44a2 2 0 0 0 2-2v-.18a2 2 0 0 1 1-1.73l.43-.25a2 2 0 0 1 2 0l.15.08a2 2 0 0 0 2.73-.73l.22-.39a2 2 0 0 0-.73-2.73l-.15-.08a2 2 0 0 1-1-1.74v-.5a2 2 0 0 1 1-1.74l.15-.09a2 2 0 0 0 .73-2.73l-.22-.38a2 2 0 0 0-2.73-.73l-.15.08a2 2 0 0 1-2 0l-.43-.25a2 2 0 0 1-1-1.73V4a2 2 0 0 0-2-2z"}],["circle",{cx:"12",cy:"12",r:"3"}]];return a.$$set=r=>{s(1,e=V(V({},e),R(r))),"$$scope"in r&&s(3,l=r.$$scope)},e=R(e),[n,e,t,l]}class Kn extends Ye{constructor(e){super(),Ze(this,e,Rn,Gn,Me,{})}}function Xn(a){let e;const s=a[2].default,t=ft(s,a,a[3],null);return{c(){t&&t.c()},l(l){t&&t.l(l)},m(l,n){t&&t.m(l,n),e=!0},p(l,n){t&&t.p&&(!e||n&8)&&ct(t,s,l,l[3],e?mt(s,l[3],n,null):dt(l[3]),null)},i(l){e||(k(t,l),e=!0)},o(l){w(t,l),e=!1},d(l){t&&t.d(l)}}}function Jn(a){let e,s;const t=[{name:"share"},a[1],{iconNode:a[0]}];let l={$$slots:{default:[Xn]},$$scope:{ctx:a}};for(let n=0;n<t.length;n+=1)l=V(l,t[n]);return e=new Et({props:l}),{c(){x(e.$$.fragment)},l(n){O(e.$$.fragment,n)},m(n,r){U(e,n,r),s=!0},p(n,[r]){const u=r&3?et(t,[t[0],r&2&&wt(n[1]),r&1&&{iconNode:n[0]}]):{};r&8&&(u.$$scope={dirty:r,ctx:n}),e.$set(u)},i(n){s||(k(e.$$.fragment,n),s=!0)},o(n){w(e.$$.fragment,n),s=!1},d(n){B(e,n)}}}function Qn(a,e,s){let{$$slots:t={},$$scope:l}=e;const n=[["path",{d:"M4 12v8a2 2 0 0 0 2 2h12a2 2 0 0 0 2-2v-8"}],["polyline",{points:"16 6 12 2 8 6"}],["line",{x1:"12",x2:"12",y1:"2",y2:"15"}]];return a.$$set=r=>{s(1,e=V(V({},e),R(r))),"$$scope"in r&&s(3,l=r.$$scope)},e=R(e),[n,e,t,l]}class Ol extends Ye{constructor(e){super(),Ze(this,e,Qn,Jn,Me,{})}}function Yn(a){let e;const s=a[2].default,t=ft(s,a,a[3],null);return{c(){t&&t.c()},l(l){t&&t.l(l)},m(l,n){t&&t.m(l,n),e=!0},p(l,n){t&&t.p&&(!e||n&8)&&ct(t,s,l,l[3],e?mt(s,l[3],n,null):dt(l[3]),null)},i(l){e||(k(t,l),e=!0)},o(l){w(t,l),e=!1},d(l){t&&t.d(l)}}}function Zn(a){let e,s;const t=[{name:"skip-back"},a[1],{iconNode:a[0]}];let l={$$slots:{default:[Yn]},$$scope:{ctx:a}};for(let n=0;n<t.length;n+=1)l=V(l,t[n]);return e=new Et({props:l}),{c(){x(e.$$.fragment)},l(n){O(e.$$.fragment,n)},m(n,r){U(e,n,r),s=!0},p(n,[r]){const u=r&3?et(t,[t[0],r&2&&wt(n[1]),r&1&&{iconNode:n[0]}]):{};r&8&&(u.$$scope={dirty:r,ctx:n}),e.$set(u)},i(n){s||(k(e.$$.fragment,n),s=!0)},o(n){w(e.$$.fragment,n),s=!1},d(n){B(e,n)}}}function es(a,e,s){let{$$slots:t={},$$scope:l}=e;const n=[["polygon",{points:"19 20 9 12 19 4 19 20"}],["line",{x1:"5",x2:"5",y1:"19",y2:"5"}]];return a.$$set=r=>{s(1,e=V(V({},e),R(r))),"$$scope"in r&&s(3,l=r.$$scope)},e=R(e),[n,e,t,l]}class ts extends Ye{constructor(e){super(),Ze(this,e,es,Zn,Me,{})}}function ls(a){let e;const s=a[2].default,t=ft(s,a,a[3],null);return{c(){t&&t.c()},l(l){t&&t.l(l)},m(l,n){t&&t.m(l,n),e=!0},p(l,n){t&&t.p&&(!e||n&8)&&ct(t,s,l,l[3],e?mt(s,l[3],n,null):dt(l[3]),null)},i(l){e||(k(t,l),e=!0)},o(l){w(t,l),e=!1},d(l){t&&t.d(l)}}}function ns(a){let e,s;const t=[{name:"skip-forward"},a[1],{iconNode:a[0]}];let l={$$slots:{default:[ls]},$$scope:{ctx:a}};for(let n=0;n<t.length;n+=1)l=V(l,t[n]);return e=new Et({props:l}),{c(){x(e.$$.fragment)},l(n){O(e.$$.fragment,n)},m(n,r){U(e,n,r),s=!0},p(n,[r]){const u=r&3?et(t,[t[0],r&2&&wt(n[1]),r&1&&{iconNode:n[0]}]):{};r&8&&(u.$$scope={dirty:r,ctx:n}),e.$set(u)},i(n){s||(k(e.$$.fragment,n),s=!0)},o(n){w(e.$$.fragment,n),s=!1},d(n){B(e,n)}}}function ss(a,e,s){let{$$slots:t={},$$scope:l}=e;const n=[["polygon",{points:"5 4 15 12 5 20 5 4"}],["line",{x1:"19",x2:"19",y1:"5",y2:"19"}]];return a.$$set=r=>{s(1,e=V(V({},e),R(r))),"$$scope"in r&&s(3,l=r.$$scope)},e=R(e),[n,e,t,l]}class as extends Ye{constructor(e){super(),Ze(this,e,ss,ns,Me,{})}}function sn(a,e,s){const t=a.slice();return t[39]=e[s],t}function an(a,e,s){const t=a.slice();return t[42]=e[s],t}function rn(a,e,s){const t=a.slice();return t[42]=e[s],t}function on(a){let e,s,t,l,n='<p class="font-medium text-blue-900">To run locally:</p> <code class="text-xs bg-blue-100 px-1.5 py-0.5 rounded">pip install hfstudio</code> <span class="text-blue-700">and run</span> <code class="text-xs bg-blue-100 px-1.5 py-0.5 rounded">hfstudio</code> <span class="text-blue-700">from your terminal</span>',r;return s=new In({props:{size:18,class:"text-blue-600 mt-0.5 flex-shrink-0"}}),{c(){e=d("div"),x(s.$$.fragment),t=v(),l=d("div"),l.innerHTML=n,this.h()},l(u){e=c(u,"DIV",{class:!0});var g=m(e);O(s.$$.fragment,g),t=p(g),l=c(g,"DIV",{class:!0,"data-svelte-h":!0}),Qe(l)!=="svelte-p3cqs1"&&(l.innerHTML=n),g.forEach(f),this.h()},h(){i(l,"class","text-sm"),i(e,"class","mb-4 p-3 bg-blue-50 border border-blue-200 rounded-lg flex items-start gap-2")},m(u,g){G(u,e,g),U(s,e,null),o(e,t),o(e,l),r=!0},i(u){r||(k(s.$$.fragment,u),r=!0)},o(u){w(s.$$.fragment,u),r=!1},d(u){u&&f(e),B(s)}}}function un(a){let e,s="Clear",t,l;return{c(){e=d("button"),e.textContent=s,this.h()},l(n){e=c(n,"BUTTON",{class:!0,"data-svelte-h":!0}),Qe(e)!=="svelte-18e8snq"&&(e.textContent=s),this.h()},h(){i(e,"class","absolute top-4 right-6 text-sm text-gray-400 hover:text-gray-600")},m(n,r){G(n,e,r),t||(l=P(e,"click",a[26]),t=!0)},p:Kt,d(n){n&&f(e),t=!1,l()}}}function rs(a){let e,s,t;return e=new jl({props:{size:20}}),{c(){x(e.$$.fragment),s=D(`
7
+ Generate speech`)},l(l){O(e.$$.fragment,l),s=I(l,`
8
+ Generate speech`)},m(l,n){U(e,l,n),G(l,s,n),t=!0},i(l){t||(k(e.$$.fragment,l),t=!0)},o(l){w(e.$$.fragment,l),t=!1},d(l){l&&f(s),B(e,l)}}}function os(a){let e,s,t;return e=new xn({props:{size:20,class:"animate-spin"}}),{c(){x(e.$$.fragment),s=D(`
9
+ Generating...`)},l(l){O(e.$$.fragment,l),s=I(l,`
10
+ Generating...`)},m(l,n){U(e,l,n),G(l,s,n),t=!0},i(l){t||(k(e.$$.fragment,l),t=!0)},o(l){w(e.$$.fragment,l),t=!1},d(l){l&&f(s),B(e,l)}}}function fn(a){let e,s,t,l,n,r,u,g,E,N,T,_,b,$,S,ue,de,M="Share",K,j,W,Ee="Download",Le,X,Z,Ne,ee,L,me,Nt,J,Te,Ie=zt(a[12])+"",He,ht,We,Ue,pe,te,ae=zt(a[13])+"",q,Ot,fe,ce,re,tt,lt,De,Q,gt,nt,Ve,xt,Se,Ae,Oe=zt(a[12])+"",jt,Mt,ve,qe,Fe,Tt,It=zt(a[13])+"",he,xe,oe,be,_t,Lt,st,Pe,Ge,Ht,at,le,Wt,ne,Xt,Jt;S=new Ol({props:{size:14,class:"text-gray-600"}}),X=new nn({props:{size:14,class:"text-gray-600"}});const pt=[us,is],$e=[];function vt(y,z){return y[11]?0:1}L=vt(a),me=$e[L]=pt[L](a),re=new ts({props:{size:20,class:"text-gray-600"}});const ul=[cs,fs],rt=[];function bt(y,z){return y[11]?0:1}De=bt(a),Q=rt[De]=ul[De](a),Ve=new as({props:{size:20,class:"text-gray-600"}}),_t=new Ol({props:{size:14}}),Ge=new nn({props:{size:16,class:"text-gray-600"}}),le=new $n({props:{size:16,class:"text-gray-600"}});let F=a[6]&&cn(a);return{c(){e=d("div"),s=d("div"),t=d("div"),l=v(),n=d("div"),r=d("h3"),u=D(a[14]),g=v(),E=d("p"),N=D(a[1]),T=D(" • Created 1 second ago"),_=v(),b=d("div"),$=d("button"),x(S.$$.fragment),ue=v(),de=d("span"),de.textContent=M,K=v(),j=d("button"),W=d("span"),W.textContent=Ee,Le=v(),x(X.$$.fragment),Z=v(),Ne=d("div"),ee=d("button"),me.c(),Nt=v(),J=d("div"),Te=d("span"),He=D(Ie),ht=v(),We=d("div"),Ue=d("div"),pe=v(),te=d("span"),q=D(ae),Ot=v(),fe=d("div"),ce=d("button"),x(re.$$.fragment),tt=v(),lt=d("button"),Q.c(),gt=v(),nt=d("button"),x(Ve.$$.fragment),xt=v(),Se=d("div"),Ae=d("span"),jt=D(Oe),Mt=v(),ve=d("div"),qe=d("div"),Fe=v(),Tt=d("span"),he=D(It),xe=v(),oe=d("div"),be=d("button"),x(_t.$$.fragment),Lt=D(`
11
+ Share`),st=v(),Pe=d("button"),x(Ge.$$.fragment),Ht=v(),at=d("button"),x(le.$$.fragment),Wt=v(),F&&F.c(),this.h()},l(y){e=c(y,"DIV",{class:!0});var z=m(e);s=c(z,"DIV",{class:!0});var ze=m(s);t=c(ze,"DIV",{class:!0}),m(t).forEach(f),l=p(ze),n=c(ze,"DIV",{class:!0});var Y=m(n);r=c(Y,"H3",{class:!0});var Qt=m(r);u=I(Qt,a[14]),Qt.forEach(f),g=p(Y),E=c(Y,"P",{class:!0});var ot=m(E);N=I(ot,a[1]),T=I(ot," • Created 1 second ago"),ot.forEach(f),Y.forEach(f),_=p(ze),b=c(ze,"DIV",{class:!0});var je=m(b);$=c(je,"BUTTON",{class:!0});var Re=m($);O(S.$$.fragment,Re),ue=p(Re),de=c(Re,"SPAN",{class:!0,"data-svelte-h":!0}),Qe(de)!=="svelte-hbn8gl"&&(de.textContent=M),Re.forEach(f),K=p(je),j=c(je,"BUTTON",{class:!0});var qt=m(j);W=c(qt,"SPAN",{class:!0,"data-svelte-h":!0}),Qe(W)!=="svelte-h01aeg"&&(W.textContent=Ee),Le=p(qt),O(X.$$.fragment,qt),qt.forEach(f),je.forEach(f),ze.forEach(f),Z=p(z),Ne=c(z,"DIV",{class:!0});var Vt=m(Ne);ee=c(Vt,"BUTTON",{class:!0});var $t=m(ee);me.l($t),$t.forEach(f),Nt=p(Vt),J=c(Vt,"DIV",{class:!0});var Ke=m(J);Te=c(Ke,"SPAN",{class:!0});var Ft=m(Te);He=I(Ft,Ie),Ft.forEach(f),ht=p(Ke),We=c(Ke,"DIV",{class:!0});var Yt=m(We);Ue=c(Yt,"DIV",{class:!0,style:!0}),m(Ue).forEach(f),Yt.forEach(f),pe=p(Ke),te=c(Ke,"SPAN",{class:!0});var Zt=m(te);q=I(Zt,ae),Zt.forEach(f),Ke.forEach(f),Vt.forEach(f),Ot=p(z),fe=c(z,"DIV",{class:!0});var H=m(fe);ce=c(H,"BUTTON",{class:!0,title:!0});var el=m(ce);O(re.$$.fragment,el),el.forEach(f),tt=p(H),lt=c(H,"BUTTON",{class:!0});var kt=m(lt);Q.l(kt),kt.forEach(f),gt=p(H),nt=c(H,"BUTTON",{class:!0,title:!0});var it=m(nt);O(Ve.$$.fragment,it),it.forEach(f),xt=p(H),Se=c(H,"DIV",{class:!0});var Be=m(Se);Ae=c(Be,"SPAN",{class:!0});var fl=m(Ae);jt=I(fl,Oe),fl.forEach(f),Mt=p(Be),ve=c(Be,"DIV",{class:!0});var tl=m(ve);qe=c(tl,"DIV",{class:!0,style:!0}),m(qe).forEach(f),tl.forEach(f),Fe=p(Be),Tt=c(Be,"SPAN",{class:!0});var Dt=m(Tt);he=I(Dt,It),Dt.forEach(f),Be.forEach(f),xe=p(H),oe=c(H,"DIV",{class:!0});var Xe=m(oe);be=c(Xe,"BUTTON",{class:!0});var At=m(be);O(_t.$$.fragment,At),Lt=I(At,`
12
+ Share`),At.forEach(f),st=p(Xe),Pe=c(Xe,"BUTTON",{class:!0,title:!0});var ll=m(Pe);O(Ge.$$.fragment,ll),ll.forEach(f),Ht=p(Xe),at=c(Xe,"BUTTON",{class:!0,title:!0});var Ce=m(at);O(le.$$.fragment,Ce),Ce.forEach(f),Xe.forEach(f),H.forEach(f),Wt=p(z),F&&F.l(z),z.forEach(f),this.h()},h(){i(t,"class","w-2 h-2 bg-green-500 rounded-full"),i(r,"class","font-medium text-gray-900 text-sm"),i(E,"class","text-xs text-gray-500"),i(n,"class","flex-1"),i(de,"class","text-gray-700"),i($,"class","flex items-center gap-1.5 px-3 py-1.5 text-sm border border-gray-200 rounded-md hover:bg-gray-50 transition-colors"),i(W,"class","text-gray-700"),i(j,"class","flex items-center gap-1.5 px-3 py-1.5 text-sm border border-gray-200 rounded-md hover:bg-gray-50 transition-colors"),i(b,"class","flex items-center gap-2"),i(s,"class","flex items-center gap-3 mb-4"),i(ee,"class","w-8 h-8 bg-black rounded-full flex items-center justify-center hover:bg-gray-800 transition-colors"),i(Te,"class","text-xs text-gray-500 font-mono"),i(Ue,"class","h-full bg-gradient-to-r from-amber-400 to-orange-500 rounded-full transition-all"),cl(Ue,"width",a[12]/a[13]*100+"%"),i(We,"class","flex-1 h-1 bg-gray-200 rounded-full cursor-pointer"),i(te,"class","text-xs text-gray-500 font-mono"),i(J,"class","flex-1 flex items-center gap-2"),i(Ne,"class","flex items-center gap-3 mb-4"),i(ce,"class","p-2 hover:bg-gray-100 rounded-full"),i(ce,"title","Skip back"),i(lt,"class","w-12 h-12 bg-black rounded-full flex items-center justify-center hover:bg-gray-800 transition-colors"),i(nt,"class","p-2 hover:bg-gray-100 rounded-full"),i(nt,"title","Skip forward"),i(Ae,"class","text-xs text-gray-500 font-mono"),i(qe,"class","h-full bg-gradient-to-r from-amber-400 to-orange-500 rounded-full transition-all"),cl(qe,"width",a[12]/a[13]*100+"%"),i(ve,"class","flex-1 h-1 bg-gray-200 rounded-full"),i(Tt,"class","text-xs text-gray-500 font-mono"),i(Se,"class","flex-1 flex items-center gap-3"),i(be,"class","flex items-center gap-2 px-3 py-1.5 text-sm border border-gray-200 rounded-md hover:bg-gray-50"),i(Pe,"class","p-2 hover:bg-gray-100 rounded-md"),i(Pe,"title","Download"),i(at,"class","p-2 hover:bg-gray-100 rounded-md"),i(at,"title","More options"),i(oe,"class","flex items-center gap-2"),i(fe,"class","flex items-center gap-4 mb-4"),i(e,"class","p-4 border border-gray-200 rounded-lg bg-white")},m(y,z){G(y,e,z),o(e,s),o(s,t),o(s,l),o(s,n),o(n,r),o(r,u),o(n,g),o(n,E),o(E,N),o(E,T),o(s,_),o(s,b),o(b,$),U(S,$,null),o($,ue),o($,de),o(b,K),o(b,j),o(j,W),o(j,Le),U(X,j,null),o(e,Z),o(e,Ne),o(Ne,ee),$e[L].m(ee,null),o(Ne,Nt),o(Ne,J),o(J,Te),o(Te,He),o(J,ht),o(J,We),o(We,Ue),o(J,pe),o(J,te),o(te,q),o(e,Ot),o(e,fe),o(fe,ce),U(re,ce,null),o(fe,tt),o(fe,lt),rt[De].m(lt,null),o(fe,gt),o(fe,nt),U(Ve,nt,null),o(fe,xt),o(fe,Se),o(Se,Ae),o(Ae,jt),o(Se,Mt),o(Se,ve),o(ve,qe),o(Se,Fe),o(Se,Tt),o(Tt,he),o(fe,xe),o(fe,oe),o(oe,be),U(_t,be,null),o(be,Lt),o(oe,st),o(oe,Pe),U(Ge,Pe,null),o(oe,Ht),o(oe,at),U(le,at,null),o(e,Wt),F&&F.m(e,null),ne=!0,Xt||(Jt=[P($,"click",pn),P(j,"click",a[24]),P(ee,"click",a[19]),P(lt,"click",a[19]),P(be,"click",pn),P(Pe,"click",a[24])],Xt=!0)},p(y,z){(!ne||z[0]&16384)&&ut(u,y[14]),(!ne||z[0]&2)&&ut(N,y[1]);let ze=L;L=vt(y),L!==ze&&(ml(),w($e[ze],1,1,()=>{$e[ze]=null}),dl(),me=$e[L],me||(me=$e[L]=pt[L](y),me.c()),k(me,1),me.m(ee,null)),(!ne||z[0]&4096)&&Ie!==(Ie=zt(y[12])+"")&&ut(He,Ie),(!ne||z[0]&12288)&&cl(Ue,"width",y[12]/y[13]*100+"%"),(!ne||z[0]&8192)&&ae!==(ae=zt(y[13])+"")&&ut(q,ae);let Y=De;De=bt(y),De!==Y&&(ml(),w(rt[Y],1,1,()=>{rt[Y]=null}),dl(),Q=rt[De],Q||(Q=rt[De]=ul[De](y),Q.c()),k(Q,1),Q.m(lt,null)),(!ne||z[0]&4096)&&Oe!==(Oe=zt(y[12])+"")&&ut(jt,Oe),(!ne||z[0]&12288)&&cl(qe,"width",y[12]/y[13]*100+"%"),(!ne||z[0]&8192)&&It!==(It=zt(y[13])+"")&&ut(he,It),y[6]?F?F.p(y,z):(F=cn(y),F.c(),F.m(e,null)):F&&(F.d(1),F=null)},i(y){ne||(k(S.$$.fragment,y),k(X.$$.fragment,y),k(me),k(re.$$.fragment,y),k(Q),k(Ve.$$.fragment,y),k(_t.$$.fragment,y),k(Ge.$$.fragment,y),k(le.$$.fragment,y),ne=!0)},o(y){w(S.$$.fragment,y),w(X.$$.fragment,y),w(me),w(re.$$.fragment,y),w(Q),w(Ve.$$.fragment,y),w(_t.$$.fragment,y),w(Ge.$$.fragment,y),w(le.$$.fragment,y),ne=!1},d(y){y&&f(e),B(S),B(X),$e[L].d(),B(re),rt[De].d(),B(Ve),B(_t),B(Ge),B(le),F&&F.d(),Xt=!1,xl(Jt)}}}function is(a){let e,s;return e=new jl({props:{size:14,class:"text-white ml-0.5"}}),{c(){x(e.$$.fragment)},l(t){O(e.$$.fragment,t)},m(t,l){U(e,t,l),s=!0},i(t){s||(k(e.$$.fragment,t),s=!0)},o(t){w(e.$$.fragment,t),s=!1},d(t){B(e,t)}}}function us(a){let e;return{c(){e=d("div"),this.h()},l(s){e=c(s,"DIV",{class:!0}),m(e).forEach(f),this.h()},h(){i(e,"class","pause-filled text-white")},m(s,t){G(s,e,t)},i:Kt,o:Kt,d(s){s&&f(e)}}}function fs(a){let e,s;return e=new jl({props:{size:20,class:"text-white ml-0.5"}}),{c(){x(e.$$.fragment)},l(t){O(e.$$.fragment,t)},m(t,l){U(e,t,l),s=!0},i(t){s||(k(e.$$.fragment,t),s=!0)},o(t){w(e.$$.fragment,t),s=!1},d(t){B(e,t)}}}function cs(a){let e;return{c(){e=d("div"),this.h()},l(s){e=c(s,"DIV",{class:!0}),m(e).forEach(f),this.h()},h(){i(e,"class","pause-filled text-white scale-150")},m(s,t){G(s,e,t)},i:Kt,o:Kt,d(s){s&&f(e)}}}function cn(a){let e,s,t,l;return{c(){e=d("audio"),this.h()},l(n){e=c(n,"AUDIO",{src:!0,style:!0}),m(e).forEach(f),this.h()},h(){Zl(e.src,s=a[6])||i(e,"src",s),cl(e,"display","none")},m(n,r){G(n,e,r),a[30](e),t||(l=[P(e,"loadedmetadata",a[20]),P(e,"timeupdate",a[21]),P(e,"play",a[22]),P(e,"pause",a[23])],t=!0)},p(n,r){r[0]&64&&!Zl(e.src,s=n[6])&&i(e,"src",s)},d(n){n&&f(e),a[30](null),t=!1,xl(l)}}}function dn(a){let e=a[42].name+"",s,t,l=a[42].badge&&ds(a);return{c(){s=D(e),l&&l.c(),t=Ut()},l(n){s=I(n,e),l&&l.l(n),t=Ut()},m(n,r){G(n,s,r),l&&l.m(n,r),G(n,t,r)},p(n,r){n[42].badge&&l.p(n,r)},d(n){n&&(f(s),f(t)),l&&l.d(n)}}}function ds(a){let e,s,t,l=a[42].badge+"",n,r;return{c(){e=D(" "),s=d("span"),t=D("("),n=D(l),r=D(")"),this.h()},l(u){e=I(u," "),s=c(u,"SPAN",{class:!0});var g=m(s);t=I(g,"("),n=I(g,l),r=I(g,")"),g.forEach(f),this.h()},h(){i(s,"class","text-xs text-gray-500")},m(u,g){G(u,e,g),G(u,s,g),o(s,t),o(s,n),o(s,r)},p:Kt,d(u){u&&(f(e),f(s))}}}function mn(a){let e,s=a[42].name===a[2]&&dn(a);return{c(){s&&s.c(),e=Ut()},l(t){s&&s.l(t),e=Ut()},m(t,l){s&&s.m(t,l),G(t,e,l)},p(t,l){t[42].name===t[2]?s?s.p(t,l):(s=dn(t),s.c(),s.m(e.parentNode,e)):s&&(s.d(1),s=null)},d(t){t&&f(e),s&&s.d(t)}}}function hn(a){let e,s=Bt(a[16]),t=[];for(let l=0;l<s.length;l+=1)t[l]=gn(an(a,s,l));return{c(){e=d("div");for(let l=0;l<t.length;l+=1)t[l].c();this.h()},l(l){e=c(l,"DIV",{class:!0});var n=m(e);for(let r=0;r<t.length;r+=1)t[r].l(n);n.forEach(f),this.h()},h(){i(e,"class","absolute top-full left-0 right-0 mt-1 bg-white border border-gray-200 rounded-lg shadow-lg z-10")},m(l,n){G(l,e,n);for(let r=0;r<t.length;r+=1)t[r]&&t[r].m(e,null)},p(l,n){if(n[0]&65556){s=Bt(l[16]);let r;for(r=0;r<s.length;r+=1){const u=an(l,s,r);t[r]?t[r].p(u,n):(t[r]=gn(u),t[r].c(),t[r].m(e,null))}for(;r<t.length;r+=1)t[r].d(1);t.length=s.length}},d(l){l&&f(e),Vl(t,l)}}}function ms(a){let e,s,t,l=a[42].badge+"",n,r;return{c(){e=D(" "),s=d("span"),t=D("("),n=D(l),r=D(")"),this.h()},l(u){e=I(u," "),s=c(u,"SPAN",{class:!0});var g=m(s);t=I(g,"("),n=I(g,l),r=I(g,")"),g.forEach(f),this.h()},h(){i(s,"class","text-xs text-gray-500")},m(u,g){G(u,e,g),G(u,s,g),o(s,t),o(s,n),o(s,r)},p:Kt,d(u){u&&(f(e),f(s))}}}function gn(a){let e,s=a[42].name+"",t,l,n,r,u,g=a[42].badge&&ms(a);function E(){return a[32](a[42])}return{c(){e=d("button"),t=D(s),g&&g.c(),l=v(),this.h()},l(N){e=c(N,"BUTTON",{class:!0});var T=m(e);t=I(T,s),g&&g.l(T),l=p(T),T.forEach(f),this.h()},h(){i(e,"class",n="w-full px-3 py-2 text-left hover:bg-gray-50 transition-colors text-sm "+(a[42].name===a[2]?"bg-gray-100":""))},m(N,T){G(N,e,T),o(e,t),g&&g.m(e,null),o(e,l),r||(u=P(e,"click",E),r=!0)},p(N,T){a=N,a[42].badge&&g.p(a,T),T[0]&4&&n!==(n="w-full px-3 py-2 text-left hover:bg-gray-50 transition-colors text-sm "+(a[42].name===a[2]?"bg-gray-100":""))&&i(e,"class",n)},d(N){N&&f(e),g&&g.d(),r=!1,u()}}}function _n(a){let e,s,t,l=a[39].name[0]+"",n,r,u,g=a[39].name+"",E,N,T,_=a[39].description+"",b,$,S,ue,de;function M(){return a[33](a[39])}return{c(){e=d("button"),s=d("div"),t=d("div"),n=D(l),r=v(),u=d("span"),E=D(g),N=v(),T=d("div"),b=D(_),$=v(),this.h()},l(K){e=c(K,"BUTTON",{class:!0});var j=m(e);s=c(j,"DIV",{class:!0});var W=m(s);t=c(W,"DIV",{class:!0});var Ee=m(t);n=I(Ee,l),Ee.forEach(f),r=p(W),u=c(W,"SPAN",{class:!0});var Le=m(u);E=I(Le,g),Le.forEach(f),W.forEach(f),N=p(j),T=c(j,"DIV",{class:!0});var X=m(T);b=I(X,_),X.forEach(f),$=p(j),j.forEach(f),this.h()},h(){i(t,"class","w-8 h-8 bg-gradient-to-br from-amber-400 to-orange-500 rounded-full flex items-center justify-center text-white text-xs font-medium"),i(u,"class","text-sm font-medium"),i(s,"class","flex items-center gap-2"),i(T,"class","text-xs text-gray-500"),i(e,"class",S="w-full flex items-center justify-between p-2 rounded-md hover:bg-gray-50 transition-colors text-left "+(a[39].name===a[1]?"bg-gray-100":""))},m(K,j){G(K,e,j),o(e,s),o(s,t),o(t,n),o(s,r),o(s,u),o(u,E),o(e,N),o(e,T),o(T,b),o(e,$),ue||(de=P(e,"click",M),ue=!0)},p(K,j){a=K,j[0]&2&&S!==(S="w-full flex items-center justify-between p-2 rounded-md hover:bg-gray-50 transition-colors text-left "+(a[39].name===a[1]?"bg-gray-100":""))&&i(e,"class",S)},d(K){K&&f(e),ue=!1,de()}}}function hs(a){let e,s,t,l,n,r,u,g,E,N,T,_,b,$,S,ue,de,M,K,j,W,Ee,Le,X,Z,Ne,ee,L,me,Nt,J,Te,Ie,He=a[0].length+"",ht,We,Ue,pe,te,ae,q,Ot,fe,ce,re,tt,lt="Model",De,Q,gt,nt,Ve,xt,Se,Ae,Oe,jt='<h3 class="font-medium text-gray-900">Voice</h3>',Mt,ve,qe,Fe,Tt='<div class="flex items-center gap-2"><div class="w-8 h-8 bg-gray-400 rounded-full flex items-center justify-center text-white text-xs font-medium">+</div> <span class="text-sm font-medium text-gray-600">Clone your voice</span></div> <div class="text-xs text-gray-400">(coming soon)</div>',It,he,xe,oe,be,_t="Speed",Lt,st,Pe=a[7].toFixed(1)+"",Ge,Ht,at,le,Wt,ne,Xt="<span>0.5x</span> <span>2.0x</span>",Jt,pt,$e,vt,ul="Stability",rt,bt,F=(a[8]*100).toFixed(0)+"",y,z,ze,Y,Qt,ot,je,Re,qt="Similarity",Vt,$t,Ke=(a[9]*100).toFixed(0)+"",Ft,Yt,Zt,H,el,kt,it,Be,fl="Style",tl,Dt,Xe=a[10]===0?"None":"Exaggerated",At,ll,Ce,Je,Cl,Ml;ue=new Kn({props:{size:18,class:"text-gray-600"}}),K=new Ol({props:{size:18,class:"text-gray-600"}}),Ee=new $n({props:{size:18,class:"text-gray-600"}});let ie=a[3]==="local"&&on(),ke=a[0]&&un(a);const Ll=[os,rs],Gt=[];function Hl(h,A){return h[5]?0:1}te=Hl(a),ae=Gt[te]=Ll[te](a);let se=a[6]&&fn(a),nl=Bt(a[16]),ge=[];for(let h=0;h<nl.length;h+=1)ge[h]=mn(rn(a,nl,h));Ve=new Cn({props:{size:16,class:"text-gray-500"}});let ye=a[4]&&hn(a),sl=Bt(a[17]),_e=[];for(let h=0;h<sl.length;h+=1)_e[h]=_n(sn(a,sl,h));return{c(){e=d("div"),s=d("header"),t=d("div"),l=d("div"),n=d("div"),r=d("button"),u=D("API"),E=v(),N=d("button"),T=D("Local"),b=v(),$=d("div"),S=d("button"),x(ue.$$.fragment),de=v(),M=d("button"),x(K.$$.fragment),j=v(),W=d("button"),x(Ee.$$.fragment),Le=v(),X=d("div"),Z=d("div"),ie&&ie.c(),Ne=v(),ee=d("div"),L=d("textarea"),me=v(),ke&&ke.c(),Nt=v(),J=d("div"),Te=d("div"),Ie=d("span"),ht=D(He),We=D(" / 5,000 characters"),Ue=v(),pe=d("button"),ae.c(),Ot=v(),se&&se.c(),fe=v(),ce=d("div"),re=d("div"),tt=d("h3"),tt.textContent=lt,De=v(),Q=d("button"),gt=d("span");for(let h=0;h<ge.length;h+=1)ge[h].c();nt=v(),x(Ve.$$.fragment),xt=v(),ye&&ye.c(),Se=v(),Ae=d("div"),Oe=d("div"),Oe.innerHTML=jt,Mt=v(),ve=d("div");for(let h=0;h<_e.length;h+=1)_e[h].c();qe=v(),Fe=d("button"),Fe.innerHTML=Tt,It=v(),he=d("div"),xe=d("div"),oe=d("div"),be=d("label"),be.textContent=_t,Lt=v(),st=d("span"),Ge=D(Pe),Ht=D("x"),at=v(),le=d("input"),Wt=v(),ne=d("div"),ne.innerHTML=Xt,Jt=v(),pt=d("div"),$e=d("div"),vt=d("label"),vt.textContent=ul,rt=v(),bt=d("span"),y=D(F),z=D("%"),ze=v(),Y=d("input"),Qt=v(),ot=d("div"),je=d("div"),Re=d("label"),Re.textContent=qt,Vt=v(),$t=d("span"),Ft=D(Ke),Yt=D("%"),Zt=v(),H=d("input"),el=v(),kt=d("div"),it=d("div"),Be=d("label"),Be.textContent=fl,tl=v(),Dt=d("span"),At=D(Xe),ll=v(),Ce=d("input"),this.h()},l(h){e=c(h,"DIV",{class:!0});var A=m(e);s=c(A,"HEADER",{class:!0});var we=m(s);t=c(we,"DIV",{class:!0});var C=m(t);l=c(C,"DIV",{class:!0});var Ct=m(l);n=c(Ct,"DIV",{class:!0});var hl=m(n);r=c(hl,"BUTTON",{class:!0});var Wl=m(r);u=I(Wl,"API"),Wl.forEach(f),E=p(hl),N=c(hl,"BUTTON",{class:!0});var ql=m(N);T=I(ql,"Local"),ql.forEach(f),hl.forEach(f),Ct.forEach(f),b=p(C),$=c(C,"DIV",{class:!0});var al=m($);S=c(al,"BUTTON",{class:!0,title:!0});var Fl=m(S);O(ue.$$.fragment,Fl),Fl.forEach(f),de=p(al),M=c(al,"BUTTON",{class:!0,title:!0});var Gl=m(M);O(K.$$.fragment,Gl),Gl.forEach(f),j=p(al),W=c(al,"BUTTON",{class:!0,title:!0});var Rl=m(W);O(Ee.$$.fragment,Rl),Rl.forEach(f),al.forEach(f),C.forEach(f),we.forEach(f),Le=p(A),X=c(A,"DIV",{class:!0});var gl=m(X);Z=c(gl,"DIV",{class:!0});var St=m(Z);ie&&ie.l(St),Ne=p(St),ee=c(St,"DIV",{class:!0});var _l=m(ee);L=c(_l,"TEXTAREA",{class:!0,placeholder:!0}),m(L).forEach(f),me=p(_l),ke&&ke.l(_l),_l.forEach(f),Nt=p(St),J=c(St,"DIV",{class:!0});var pl=m(J);Te=c(pl,"DIV",{class:!0});var Kl=m(Te);Ie=c(Kl,"SPAN",{class:!0});var Sl=m(Ie);ht=I(Sl,He),We=I(Sl," / 5,000 characters"),Sl.forEach(f),Kl.forEach(f),Ue=p(pl),pe=c(pl,"BUTTON",{class:!0});var Xl=m(pe);ae.l(Xl),Xl.forEach(f),pl.forEach(f),Ot=p(St),se&&se.l(St),St.forEach(f),fe=p(gl),ce=c(gl,"DIV",{class:!0});var rl=m(ce);re=c(rl,"DIV",{class:!0});var ol=m(re);tt=c(ol,"H3",{class:!0,"data-svelte-h":!0}),Qe(tt)!=="svelte-b3hs3r"&&(tt.textContent=lt),De=p(ol),Q=c(ol,"BUTTON",{class:!0});var vl=m(Q);gt=c(vl,"SPAN",{});var Jl=m(gt);for(let Rt=0;Rt<ge.length;Rt+=1)ge[Rt].l(Jl);Jl.forEach(f),nt=p(vl),O(Ve.$$.fragment,vl),vl.forEach(f),xt=p(ol),ye&&ye.l(ol),ol.forEach(f),Se=p(rl),Ae=c(rl,"DIV",{class:!0});var bl=m(Ae);Oe=c(bl,"DIV",{class:!0,"data-svelte-h":!0}),Qe(Oe)!=="svelte-182x1ki"&&(Oe.innerHTML=jt),Mt=p(bl),ve=c(bl,"DIV",{class:!0});var $l=m(ve);for(let Rt=0;Rt<_e.length;Rt+=1)_e[Rt].l($l);qe=p($l),Fe=c($l,"BUTTON",{class:!0,"data-svelte-h":!0}),Qe(Fe)!=="svelte-20x663"&&(Fe.innerHTML=Tt),$l.forEach(f),bl.forEach(f),It=p(rl),he=c(rl,"DIV",{class:!0});var Pt=m(he);xe=c(Pt,"DIV",{});var il=m(xe);oe=c(il,"DIV",{class:!0});var kl=m(oe);be=c(kl,"LABEL",{class:!0,"data-svelte-h":!0}),Qe(be)!=="svelte-9vcpiu"&&(be.textContent=_t),Lt=p(kl),st=c(kl,"SPAN",{class:!0});var Pl=m(st);Ge=I(Pl,Pe),Ht=I(Pl,"x"),Pl.forEach(f),kl.forEach(f),at=p(il),le=c(il,"INPUT",{type:!0,min:!0,max:!0,step:!0,class:!0}),Wt=p(il),ne=c(il,"DIV",{class:!0,"data-svelte-h":!0}),Qe(ne)!=="svelte-4ydm1m"&&(ne.innerHTML=Xt),il.forEach(f),Jt=p(Pt),pt=c(Pt,"DIV",{});var yl=m(pt);$e=c(yl,"DIV",{class:!0});var wl=m($e);vt=c(wl,"LABEL",{class:!0,"data-svelte-h":!0}),Qe(vt)!=="svelte-1lgjete"&&(vt.textContent=ul),rt=p(wl),bt=c(wl,"SPAN",{class:!0});var zl=m(bt);y=I(zl,F),z=I(zl,"%"),zl.forEach(f),wl.forEach(f),ze=p(yl),Y=c(yl,"INPUT",{type:!0,min:!0,max:!0,step:!0,class:!0}),yl.forEach(f),Qt=p(Pt),ot=c(Pt,"DIV",{});var El=m(ot);je=c(El,"DIV",{class:!0});var Nl=m(je);Re=c(Nl,"LABEL",{class:!0,"data-svelte-h":!0}),Qe(Re)!=="svelte-1ha0vec"&&(Re.textContent=qt),Vt=p(Nl),$t=c(Nl,"SPAN",{class:!0});var Bl=m($t);Ft=I(Bl,Ke),Yt=I(Bl,"%"),Bl.forEach(f),Nl.forEach(f),Zt=p(El),H=c(El,"INPUT",{type:!0,min:!0,max:!0,step:!0,class:!0}),El.forEach(f),el=p(Pt),kt=c(Pt,"DIV",{});var Tl=m(kt);it=c(Tl,"DIV",{class:!0});var Il=m(it);Be=c(Il,"LABEL",{class:!0,"data-svelte-h":!0}),Qe(Be)!=="svelte-1ata0tk"&&(Be.textContent=fl),tl=p(Il),Dt=c(Il,"SPAN",{class:!0});var Ql=m(Dt);At=I(Ql,Xe),Ql.forEach(f),Il.forEach(f),ll=p(Tl),Ce=c(Tl,"INPUT",{type:!0,min:!0,max:!0,step:!0,class:!0}),Tl.forEach(f),Pt.forEach(f),rl.forEach(f),gl.forEach(f),A.forEach(f),this.h()},h(){i(r,"class",g="px-3 py-1 text-sm font-medium rounded transition-colors "+(a[3]==="api"?"bg-white shadow-sm":"text-gray-600")),i(N,"class",_="px-3 py-1 text-sm font-medium rounded transition-colors "+(a[3]==="local"?"bg-white shadow-sm":"text-gray-600")),i(n,"class","flex items-center bg-gray-100 rounded-md p-0.5"),i(l,"class","flex items-center gap-3"),i(S,"class","p-2 hover:bg-gray-50 rounded-md"),i(S,"title","Settings"),i(M,"class","p-2 hover:bg-gray-50 rounded-md"),i(M,"title","Share"),i(W,"class","p-2 hover:bg-gray-50 rounded-md"),i(W,"title","More"),i($,"class","flex items-center gap-2"),i(t,"class","flex items-center justify-between px-4 py-2"),i(s,"class","border-b border-gray-200 bg-white"),i(L,"class","w-full h-full p-6 bg-white resize-none border-0 focus:outline-none text-gray-900 text-base leading-relaxed"),i(L,"placeholder","Enter text to convert to speech..."),i(ee,"class","flex-1 pb-24"),i(Ie,"class","text-sm text-gray-500"),i(Te,"class","flex items-center justify-between mb-3"),pe.disabled=q=a[5]||!a[0].trim(),i(pe,"class","w-full px-6 py-3 bg-gradient-to-r from-amber-400 to-orange-500 text-white rounded-lg font-medium hover:from-amber-500 hover:to-orange-600 disabled:opacity-50 disabled:cursor-not-allowed flex items-center justify-center gap-2 shadow-sm"),i(J,"class","fixed bottom-0 left-56 right-80 p-4 bg-white border-t border-gray-200"),i(Z,"class","flex-1 flex flex-col p-6"),i(tt,"class","font-medium text-gray-900 mb-3"),i(Q,"class","w-full p-3 border border-gray-200 rounded-lg bg-white text-sm focus:outline-none focus:ring-2 focus:ring-amber-400 focus:border-transparent appearance-none bg-no-repeat bg-right pr-10 shadow-sm text-left flex items-center justify-between"),i(re,"class","mb-6 relative model-dropdown"),i(Oe,"class","mb-3"),i(Fe,"class","w-full flex items-center justify-between p-2 rounded-md opacity-50 cursor-not-allowed text-left"),Fe.disabled=!0,i(ve,"class","space-y-1"),i(Ae,"class","mb-6"),i(be,"class","text-sm font-medium text-gray-700"),i(st,"class","text-sm text-gray-500"),i(oe,"class","flex justify-between mb-1"),i(le,"type","range"),i(le,"min","0.5"),i(le,"max","2"),i(le,"step","0.1"),i(le,"class","w-full h-1.5 bg-gray-200 rounded-lg appearance-none cursor-pointer slider-hf"),i(ne,"class","flex justify-between text-xs text-gray-400 mt-1"),i(vt,"class","text-sm font-medium text-gray-700"),i(bt,"class","text-sm text-gray-500"),i($e,"class","flex justify-between mb-1"),i(Y,"type","range"),i(Y,"min","0"),i(Y,"max","1"),i(Y,"step","0.01"),i(Y,"class","w-full h-1.5 bg-gray-200 rounded-lg appearance-none cursor-pointer slider-hf"),i(Re,"class","text-sm font-medium text-gray-700"),i($t,"class","text-sm text-gray-500"),i(je,"class","flex justify-between mb-1"),i(H,"type","range"),i(H,"min","0"),i(H,"max","1"),i(H,"step","0.01"),i(H,"class","w-full h-1.5 bg-gray-200 rounded-lg appearance-none cursor-pointer slider-hf"),i(Be,"class","text-sm font-medium text-gray-700"),i(Dt,"class","text-sm text-gray-500"),i(it,"class","flex justify-between mb-1"),i(Ce,"type","range"),i(Ce,"min","0"),i(Ce,"max","1"),i(Ce,"step","1"),i(Ce,"class","w-full h-1.5 bg-gray-200 rounded-lg appearance-none cursor-pointer slider-hf"),i(he,"class","space-y-4 pt-4 border-t border-gray-200"),i(ce,"class","w-80 border-l border-gray-200 bg-white p-4 overflow-y-auto"),i(X,"class","flex-1 flex"),i(e,"class","flex flex-col h-full")},m(h,A){G(h,e,A),o(e,s),o(s,t),o(t,l),o(l,n),o(n,r),o(r,u),o(n,E),o(n,N),o(N,T),o(t,b),o(t,$),o($,S),U(ue,S,null),o($,de),o($,M),U(K,M,null),o($,j),o($,W),U(Ee,W,null),o(e,Le),o(e,X),o(X,Z),ie&&ie.m(Z,null),o(Z,Ne),o(Z,ee),o(ee,L),yt(L,a[0]),o(ee,me),ke&&ke.m(ee,null),o(Z,Nt),o(Z,J),o(J,Te),o(Te,Ie),o(Ie,ht),o(Ie,We),o(J,Ue),o(J,pe),Gt[te].m(pe,null),o(Z,Ot),se&&se.m(Z,null),o(X,fe),o(X,ce),o(ce,re),o(re,tt),o(re,De),o(re,Q),o(Q,gt);for(let we=0;we<ge.length;we+=1)ge[we]&&ge[we].m(gt,null);o(Q,nt),U(Ve,Q,null),o(re,xt),ye&&ye.m(re,null),o(ce,Se),o(ce,Ae),o(Ae,Oe),o(Ae,Mt),o(Ae,ve);for(let we=0;we<_e.length;we+=1)_e[we]&&_e[we].m(ve,null);o(ve,qe),o(ve,Fe),o(ce,It),o(ce,he),o(he,xe),o(xe,oe),o(oe,be),o(oe,Lt),o(oe,st),o(st,Ge),o(st,Ht),o(xe,at),o(xe,le),yt(le,a[7]),o(xe,Wt),o(xe,ne),o(he,Jt),o(he,pt),o(pt,$e),o($e,vt),o($e,rt),o($e,bt),o(bt,y),o(bt,z),o(pt,ze),o(pt,Y),yt(Y,a[8]),o(he,Qt),o(he,ot),o(ot,je),o(je,Re),o(je,Vt),o(je,$t),o($t,Ft),o($t,Yt),o(ot,Zt),o(ot,H),yt(H,a[9]),o(he,el),o(he,kt),o(kt,it),o(it,Be),o(it,tl),o(it,Dt),o(Dt,At),o(kt,ll),o(kt,Ce),yt(Ce,a[10]),Je=!0,Cl||(Ml=[P(r,"click",a[27]),P(N,"click",a[28]),P(L,"input",a[29]),P(pe,"click",a[18]),P(Q,"click",a[31]),P(le,"change",a[34]),P(le,"input",a[34]),P(Y,"change",a[35]),P(Y,"input",a[35]),P(H,"change",a[36]),P(H,"input",a[36]),P(Ce,"change",a[37]),P(Ce,"input",a[37]),P(e,"click",a[25])],Cl=!0)},p(h,A){(!Je||A[0]&8&&g!==(g="px-3 py-1 text-sm font-medium rounded transition-colors "+(h[3]==="api"?"bg-white shadow-sm":"text-gray-600")))&&i(r,"class",g),(!Je||A[0]&8&&_!==(_="px-3 py-1 text-sm font-medium rounded transition-colors "+(h[3]==="local"?"bg-white shadow-sm":"text-gray-600")))&&i(N,"class",_),h[3]==="local"?ie?A[0]&8&&k(ie,1):(ie=on(),ie.c(),k(ie,1),ie.m(Z,Ne)):ie&&(ml(),w(ie,1,1,()=>{ie=null}),dl()),A[0]&1&&yt(L,h[0]),h[0]?ke?ke.p(h,A):(ke=un(h),ke.c(),ke.m(ee,null)):ke&&(ke.d(1),ke=null),(!Je||A[0]&1)&&He!==(He=h[0].length+"")&&ut(ht,He);let we=te;if(te=Hl(h),te!==we&&(ml(),w(Gt[we],1,1,()=>{Gt[we]=null}),dl(),ae=Gt[te],ae||(ae=Gt[te]=Ll[te](h),ae.c()),k(ae,1),ae.m(pe,null)),(!Je||A[0]&33&&q!==(q=h[5]||!h[0].trim()))&&(pe.disabled=q),h[6]?se?(se.p(h,A),A[0]&64&&k(se,1)):(se=fn(h),se.c(),k(se,1),se.m(Z,null)):se&&(ml(),w(se,1,1,()=>{se=null}),dl()),A[0]&65540){nl=Bt(h[16]);let C;for(C=0;C<nl.length;C+=1){const Ct=rn(h,nl,C);ge[C]?ge[C].p(Ct,A):(ge[C]=mn(Ct),ge[C].c(),ge[C].m(gt,null))}for(;C<ge.length;C+=1)ge[C].d(1);ge.length=nl.length}if(h[4]?ye?ye.p(h,A):(ye=hn(h),ye.c(),ye.m(re,null)):ye&&(ye.d(1),ye=null),A[0]&131074){sl=Bt(h[17]);let C;for(C=0;C<sl.length;C+=1){const Ct=sn(h,sl,C);_e[C]?_e[C].p(Ct,A):(_e[C]=_n(Ct),_e[C].c(),_e[C].m(ve,qe))}for(;C<_e.length;C+=1)_e[C].d(1);_e.length=sl.length}(!Je||A[0]&128)&&Pe!==(Pe=h[7].toFixed(1)+"")&&ut(Ge,Pe),A[0]&128&&yt(le,h[7]),(!Je||A[0]&256)&&F!==(F=(h[8]*100).toFixed(0)+"")&&ut(y,F),A[0]&256&&yt(Y,h[8]),(!Je||A[0]&512)&&Ke!==(Ke=(h[9]*100).toFixed(0)+"")&&ut(Ft,Ke),A[0]&512&&yt(H,h[9]),(!Je||A[0]&1024)&&Xe!==(Xe=h[10]===0?"None":"Exaggerated")&&ut(At,Xe),A[0]&1024&&yt(Ce,h[10])},i(h){Je||(k(ue.$$.fragment,h),k(K.$$.fragment,h),k(Ee.$$.fragment,h),k(ie),k(ae),k(se),k(Ve.$$.fragment,h),Je=!0)},o(h){w(ue.$$.fragment,h),w(K.$$.fragment,h),w(Ee.$$.fragment,h),w(ie),w(ae),w(se),w(Ve.$$.fragment,h),Je=!1},d(h){h&&f(e),B(ue),B(K),B(Ee),ie&&ie.d(),ke&&ke.d(),Gt[te].d(),se&&se.d(),Vl(ge,h),B(Ve),ye&&ye.d(),Vl(_e,h),Cl=!1,xl(Ml)}}}function zt(a){const e=Math.floor(a/60),s=Math.floor(a%60);return`${e}:${s.toString().padStart(2,"0")}`}function pn(){console.log("Share audio")}function gs(a,e,s){let t=`Adam was playing outside when he heard a tiny meow! He looked around. Meow! There it was again! He tiptoed toward the bushes. Pushing the leaves aside, he gasped. A fluffy, orange kitten with big, curious eyes stared up at him. "Oh no! Where is your home?" Adam asked. The kitten just blinked and let out a tiny mew!
13
+
14
+ "Mama! I found a lost kitten!" Adam called as he carried the little furball inside. The kitten sniffed around, then jumped up—boing!—right onto the couch. "Oh!" Mama laughed. "Let's give it some milk while we find its owner." The kitten licked the milk happily and purred, prrrr! Adam giggled. "I think he likes it here!"
15
+
16
+ That evening, there was a knock at the door. A little girl stood there, eyes wide. "Have you seen my kitten, Biscuit?" she asked. Adam smiled and pointed. The kitten ran to her, mew mew mew! The girl hugged Biscuit tightly. "Thank you!" she said. As she left, Adam waved. "Goodbye, Biscuit!" he whispered. And in the quiet, he could still hear a happy prrrr!`,l="Novia",n="Chatterbox",r="api",u=!1,g=!1,E=null,N=1,T=.5,_=.75,b=0,$=!1,S=0,ue=0,de="",M=null;const K=[{id:"chatterbox",name:"Chatterbox",badge:"recommended"},{id:"kokoro",name:"Kokoro",badge:"faster but lower quality"}],j=[{id:"novia",name:"Novia",description:"Warm, conversational voice"},{id:"sarah",name:"Sarah",description:"Clear, professional tone"},{id:"alex",name:"Alex",description:"Friendly, approachable voice"},{id:"emma",name:"Emma",description:"Calm, soothing delivery"}];async function W(){t.trim()&&(s(5,g=!0),s(6,E=null),s(12,S=0),s(11,$=!1),s(14,de=t.length>30?t.substring(0,30)+"...":t),setTimeout(()=>{s(6,E="/samples/harvard.wav"),s(5,g=!1)},2e3))}function Ee(){M&&($?M.pause():M.play())}function Le(){M&&(s(13,ue=M.duration),M.play())}function X(){M&&s(12,S=M.currentTime)}function Z(){s(11,$=!0)}function Ne(){s(11,$=!1)}function ee(){if(E){const q=document.createElement("a");q.href=E,q.download="speech.wav",q.click()}}function L(q){q.target.closest(".model-dropdown")||s(4,u=!1)}function me(){s(0,t=""),s(6,E=null)}const Nt=()=>s(3,r="api"),J=()=>s(3,r="local");function Te(){t=this.value,s(0,t)}function Ie(q){kn[q?"unshift":"push"](()=>{M=q,s(15,M)})}const He=()=>s(4,u=!u),ht=q=>{s(2,n=q.name),s(4,u=!1)},We=q=>s(1,l=q.name);function Ue(){N=Dl(this.value),s(7,N)}function pe(){T=Dl(this.value),s(8,T)}function te(){_=Dl(this.value),s(9,_)}function ae(){b=Dl(this.value),s(10,b)}return[t,l,n,r,u,g,E,N,T,_,b,$,S,ue,de,M,K,j,W,Ee,Le,X,Z,Ne,ee,L,me,Nt,J,Te,Ie,He,ht,We,Ue,pe,te,ae]}class vs extends Ye{constructor(e){super(),Ze(this,e,gs,hs,Me,{},null,[-1,-1])}}export{vs as component};
hfstudio/static/_app/immutable/nodes/3.VqKPhUiT.js ADDED
@@ -0,0 +1 @@
 
 
1
+ import{S as V,i as j,s as q,n as A,d,b as y,c as h,m as N,o as f,p as O,h as E,e as p,f as b,q as H,k as P,j as _,l as z,r as M,a as S,u as R,g as I,t as C}from"../chunks/9DiovRey.js";import"../chunks/IHki7fMi.js";import{g as F}from"../chunks/Dh5qNFGZ.js";import{p as B}from"../chunks/BHHrQo_1.js";function G(m){let s,t,l,e,r;return{c(){s=_("div"),t=_("div"),l=P(),e=_("p"),r=C(m[0]),this.h()},l(u){s=p(u,"DIV",{class:!0});var o=b(s);t=p(o,"DIV",{class:!0}),b(t).forEach(d),l=E(o),e=p(o,"P",{});var n=b(e);r=I(n,m[0]),n.forEach(d),o.forEach(d),this.h()},h(){f(t,"class","animate-spin w-8 h-8 border-2 border-amber-400 border-t-transparent rounded-full mx-auto mb-2"),f(s,"class","text-gray-600 mb-4")},m(u,o){y(u,s,o),h(s,t),h(s,l),h(s,e),h(e,r)},p(u,o){o&1&&S(r,u[0])},d(u){u&&d(s)}}}function J(m){let s,t,l,e,r,u,o,n,k="Return to HFStudio",g,x;return{c(){s=_("div"),t=_("p"),l=C(m[0]),e=P(),r=_("p"),u=C(m[1]),o=P(),n=_("button"),n.textContent=k,this.h()},l(c){s=p(c,"DIV",{class:!0});var a=b(s);t=p(a,"P",{class:!0});var i=b(t);l=I(i,m[0]),i.forEach(d),e=E(a),r=p(a,"P",{class:!0});var v=b(r);u=I(v,m[1]),v.forEach(d),a.forEach(d),o=E(c),n=p(c,"BUTTON",{class:!0,"data-svelte-h":!0}),H(n)!=="svelte-lo2i5l"&&(n.textContent=k),this.h()},h(){f(t,"class","font-medium"),f(r,"class","text-sm mt-1"),f(s,"class","text-red-600 mb-4"),f(n,"class","px-4 py-2 bg-gradient-to-r from-amber-400 to-orange-500 text-white rounded-lg hover:from-amber-500 hover:to-orange-600 transition-colors")},m(c,a){y(c,s,a),h(s,t),h(t,l),h(s,e),h(s,r),h(r,u),y(c,o,a),y(c,n,a),g||(x=R(n,"click",m[2]),g=!0)},p(c,a){a&1&&S(l,c[0]),a&2&&S(u,c[1])},d(c){c&&(d(s),d(o),d(n)),g=!1,x()}}}function L(m){let s,t,l,e,r,u,o,n,k="HFStudio Authentication",g;function x(i,v){return i[1]?J:G}let c=x(m),a=c(m);return{c(){s=P(),t=_("div"),l=_("div"),e=_("div"),r=_("img"),o=P(),n=_("h1"),n.textContent=k,g=P(),a.c(),this.h()},l(i){O("svelte-17lku3q",document.head).forEach(d),s=E(i),t=p(i,"DIV",{class:!0});var D=b(t);l=p(D,"DIV",{class:!0});var T=b(l);e=p(T,"DIV",{class:!0});var w=b(e);r=p(w,"IMG",{src:!0,alt:!0,class:!0}),o=E(w),n=p(w,"H1",{class:!0,"data-svelte-h":!0}),H(n)!=="svelte-l7zisw"&&(n.textContent=k),g=E(w),a.l(w),w.forEach(d),T.forEach(d),D.forEach(d),this.h()},h(){document.title="Authenticating with Hugging Face - HFStudio",N(r.src,u="/assets/hf-logo.png")||f(r,"src",u),f(r,"alt","HF Logo"),f(r,"class","w-12 h-12 mx-auto mb-4"),f(n,"class","text-xl font-semibold mb-2"),f(e,"class","text-center"),f(l,"class","max-w-md w-full bg-white rounded-lg shadow-md p-6"),f(t,"class","min-h-screen flex items-center justify-center bg-gray-50")},m(i,v){y(i,s,v),y(i,t,v),h(t,l),h(l,e),h(e,r),h(e,o),h(e,n),h(e,g),a.m(e,null)},p(i,[v]){c===(c=x(i))&&a?a.p(i,v):(a.d(1),a=c(i),a&&(a.c(),a.m(e,null)))},i:A,o:A,d(i){i&&(d(s),d(t)),a.d()}}}function U(m,s,t){let l;z(m,B,o=>t(3,l=o));let e="Processing...",r=null;return M(async()=>{try{const o=l.url.searchParams.get("code"),n=l.url.searchParams.get("state"),k=l.url.searchParams.get("error"),g=l.url.searchParams.get("error_description");if(k){t(1,r=g||k),t(0,e="Authentication failed");return}if(!o){t(1,r="No authorization code received"),t(0,e="Authentication failed");return}const x=sessionStorage.getItem("oauth_state");if(x&&n!==x){t(1,r="Invalid state parameter"),t(0,e="Authentication failed");return}const c=await fetch("/api/auth/token",{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify({code:o})});if(!c.ok){const i=await c.text();throw console.error("Token exchange failed:",i),new Error(`Failed to exchange code for token: ${i}`)}const a=await c.json();localStorage.setItem("hf_access_token",a.access_token),t(0,e="Successfully authenticated!"),setTimeout(()=>{F("/")},2e3)}catch(o){t(1,r=o.message),t(0,e="Authentication failed")}}),[e,r,()=>F("/")]}class Y extends V{constructor(s){super(),j(this,s,U,L,q,{})}}export{Y as component};
hfstudio/static/_app/version.json ADDED
@@ -0,0 +1 @@
 
 
1
+ {"version":"1760660574318"}
hfstudio/static/assets/hf-logo.png ADDED

Git LFS Details

  • SHA256: 9cf16f4f32604eaf76dabbdf47701eea5a768ebcc7296acc1d1758181f71db73
  • Pointer size: 131 Bytes
  • Size of remote file: 185 kB
hfstudio/static/assets/hf-studio-logo.png ADDED

Git LFS Details

  • SHA256: 7a33aae62a750e8ee190c7e993e17d9ddc0a54b213ea0823d14fcf1b366dc269
  • Pointer size: 130 Bytes
  • Size of remote file: 66.8 kB
hfstudio/static/index.html ADDED
@@ -0,0 +1,35 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <!doctype html>
2
+ <html lang="en">
3
+ <head>
4
+ <meta charset="utf-8" />
5
+ <link rel="icon" href="/assets/hf-logo.png" />
6
+ <meta name="viewport" content="width=device-width, initial-scale=1" />
7
+ <title>HFStudio - Text to Speech</title>
8
+
9
+ <link rel="modulepreload" href="/_app/immutable/entry/start.CYVq8xer.js">
10
+ <link rel="modulepreload" href="/_app/immutable/chunks/Dh5qNFGZ.js">
11
+ <link rel="modulepreload" href="/_app/immutable/chunks/9DiovRey.js">
12
+ <link rel="modulepreload" href="/_app/immutable/entry/app.DrVe4Aen.js">
13
+ <link rel="modulepreload" href="/_app/immutable/chunks/IHki7fMi.js">
14
+ </head>
15
+ <body data-sveltekit-preload-data="hover">
16
+ <div style="display: contents">
17
+ <script>
18
+ {
19
+ __sveltekit_pr8qbd = {
20
+ base: ""
21
+ };
22
+
23
+ const element = document.currentScript.parentElement;
24
+
25
+ Promise.all([
26
+ import("/_app/immutable/entry/start.CYVq8xer.js"),
27
+ import("/_app/immutable/entry/app.DrVe4Aen.js")
28
+ ]).then(([kit, app]) => {
29
+ kit.start(app, element);
30
+ });
31
+ }
32
+ </script>
33
+ </div>
34
+ </body>
35
+ </html>
hfstudio/static/samples/harvard.wav ADDED
@@ -0,0 +1,3 @@
 
 
 
 
1
+ version https://git-lfs.github.com/spec/v1
2
+ oid sha256:971b4163670445c415c6b0fb6813c38093409ecac2f6b4d429ae3574d24ad470
3
+ size 3249924
package-lock.json ADDED
@@ -0,0 +1,6 @@
 
 
 
 
 
 
 
1
+ {
2
+ "name": "hfstudio",
3
+ "lockfileVersion": 3,
4
+ "requires": true,
5
+ "packages": {}
6
+ }
pyproject.toml ADDED
@@ -0,0 +1,63 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ [build-system]
2
+ requires = ["setuptools>=61.0", "wheel"]
3
+ build-backend = "setuptools.build_meta"
4
+
5
+ [project]
6
+ name = "hfstudio"
7
+ dynamic = ["version"]
8
+ description = "Local and API-based Text-to-Speech Studio"
9
+ readme = "README.md"
10
+ requires-python = ">=3.8"
11
+ license = {text = "MIT"}
12
+ authors = [
13
+ {name = "HFStudio Team"}
14
+ ]
15
+ classifiers = [
16
+ "Development Status :: 3 - Alpha",
17
+ "Intended Audience :: Developers",
18
+ "Topic :: Multimedia :: Sound/Audio :: Speech",
19
+ "License :: OSI Approved :: MIT License",
20
+ "Programming Language :: Python :: 3",
21
+ "Programming Language :: Python :: 3.8",
22
+ "Programming Language :: Python :: 3.9",
23
+ "Programming Language :: Python :: 3.10",
24
+ "Programming Language :: Python :: 3.11",
25
+ ]
26
+ dependencies = [
27
+ "fastapi>=0.100.0",
28
+ "uvicorn[standard]>=0.20.0",
29
+ "typer[all]>=0.9.0",
30
+ "pydantic>=2.0.0",
31
+ ]
32
+
33
+ [project.optional-dependencies]
34
+ dev = [
35
+ "pytest>=7.0.0",
36
+ "pytest-asyncio>=0.21.0",
37
+ "black>=23.0.0",
38
+ "ruff>=0.1.0",
39
+ ]
40
+
41
+ [project.scripts]
42
+ hfstudio = "hfstudio.cli:main"
43
+
44
+ [project.urls]
45
+ Homepage = "https://github.com/yourusername/hfstudio"
46
+ Repository = "https://github.com/yourusername/hfstudio"
47
+
48
+ [tool.setuptools]
49
+ packages = ["hfstudio"]
50
+
51
+ [tool.setuptools.package-data]
52
+ hfstudio = ["frontend/package.json", "static/**/*"]
53
+
54
+ [tool.setuptools.dynamic]
55
+ version = {attr = "hfstudio.__version__"}
56
+
57
+ [tool.ruff]
58
+ line-length = 88
59
+ target-version = "py38"
60
+
61
+ [tool.black]
62
+ line-length = 88
63
+ target-version = ['py38']
requirements.txt ADDED
@@ -0,0 +1,8 @@
 
 
 
 
 
 
 
 
 
1
+ fastapi>=0.104.0
2
+ uvicorn[standard]>=0.24.0
3
+ pydantic>=2.0.0
4
+ httpx>=0.25.0
5
+ numpy>=1.24.0
6
+ soundfile>=0.12.0
7
+ typer>=0.9.0
8
+ rich>=13.0.0
requirements_space.txt ADDED
@@ -0,0 +1,8 @@
 
 
 
 
 
 
 
 
 
1
+ fastapi>=0.104.0
2
+ uvicorn[standard]>=0.24.0
3
+ pydantic>=2.0.0
4
+ httpx>=0.25.0
5
+ numpy>=1.24.0
6
+ soundfile>=0.12.0
7
+ typer>=0.9.0
8
+ rich>=13.0.0