Fraser commited on
Commit
62fead0
·
1 Parent(s): 7165ef5

add UI options

Browse files
CLAUDE.md ADDED
@@ -0,0 +1,50 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ # CLAUDE.md
2
+
3
+ This file provides guidance to Claude Code (claude.ai/code) when working with code in this repository.
4
+
5
+ ## Project Overview
6
+
7
+ This is a Svelte 5 + TypeScript + Vite single-page application. It uses the latest Svelte 5 with runes syntax (`$state()`, `$derived()`, etc.).
8
+
9
+ ## Essential Commands
10
+
11
+ ```bash
12
+ # Install dependencies
13
+ npm install
14
+
15
+ # Development server with HMR
16
+ npm run dev
17
+
18
+ # Type checking
19
+ npm run check
20
+
21
+ # Production build (outputs to dist/)
22
+ npm run build
23
+
24
+ # Preview production build
25
+ npm run preview
26
+ ```
27
+
28
+ ## Architecture
29
+
30
+ ### Component Structure
31
+ - Components use `.svelte` files with TypeScript support via `lang="ts"` in script tags
32
+ - Main entry: `src/main.ts` → mounts `src/App.svelte`
33
+ - Reusable components go in `src/lib/`
34
+ - Uses Svelte 5 runes syntax (not Svelte 4 syntax)
35
+
36
+ ### Key Patterns
37
+ 1. **State Management**: Use `$state()` rune for reactive state
38
+ 2. **TypeScript**: All components should use `<script lang="ts">`
39
+ 3. **Imports**: Use ES module imports, components are default exports
40
+ 4. **Styling**: Component styles are scoped by default, global styles in `src/app.css`
41
+
42
+ ### Build Configuration
43
+ - Vite handles bundling with `vite.config.ts`
44
+ - TypeScript config uses project references (tsconfig.json + tsconfig.app.json)
45
+ - Production builds go to `dist/` directory
46
+
47
+ ## Important Notes
48
+ - This is NOT SvelteKit - no routing, SSR, or API routes
49
+ - HMR preserves component state (can be toggled in vite.config.ts)
50
+ - All paths in imports should be relative or use `$lib` alias for src/lib
index.html CHANGED
@@ -4,7 +4,7 @@
4
  <meta charset="UTF-8" />
5
  <link rel="icon" type="image/svg+xml" href="/vite.svg" />
6
  <meta name="viewport" content="width=device-width, initial-scale=1.0" />
7
- <title>Vite + Svelte + TS</title>
8
  </head>
9
  <body>
10
  <div id="app"></div>
 
4
  <meta charset="UTF-8" />
5
  <link rel="icon" type="image/svg+xml" href="/vite.svg" />
6
  <meta name="viewport" content="width=device-width, initial-scale=1.0" />
7
+ <title>HF Multi-Space Demo | FLUX + Joy Caption + RWKV</title>
8
  </head>
9
  <body>
10
  <div id="app"></div>
package-lock.json ADDED
@@ -0,0 +1,1435 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ {
2
+ "name": "svelte",
3
+ "version": "0.0.0",
4
+ "lockfileVersion": 3,
5
+ "requires": true,
6
+ "packages": {
7
+ "": {
8
+ "name": "svelte",
9
+ "version": "0.0.0",
10
+ "devDependencies": {
11
+ "@sveltejs/vite-plugin-svelte": "^5.0.3",
12
+ "@tsconfig/svelte": "^5.0.4",
13
+ "@types/node": "^24.0.14",
14
+ "svelte": "^5.28.1",
15
+ "svelte-check": "^4.1.6",
16
+ "typescript": "~5.8.3",
17
+ "vite": "^6.3.5"
18
+ }
19
+ },
20
+ "node_modules/@ampproject/remapping": {
21
+ "version": "2.3.0",
22
+ "resolved": "https://registry.npmjs.org/@ampproject/remapping/-/remapping-2.3.0.tgz",
23
+ "integrity": "sha512-30iZtAPgz+LTIYoeivqYo853f02jBYSd5uGnGpkFV0M3xOt9aN73erkgYAmZU43x4VfqcnLxW9Kpg3R5LC4YYw==",
24
+ "dev": true,
25
+ "license": "Apache-2.0",
26
+ "dependencies": {
27
+ "@jridgewell/gen-mapping": "^0.3.5",
28
+ "@jridgewell/trace-mapping": "^0.3.24"
29
+ },
30
+ "engines": {
31
+ "node": ">=6.0.0"
32
+ }
33
+ },
34
+ "node_modules/@esbuild/aix-ppc64": {
35
+ "version": "0.25.6",
36
+ "resolved": "https://registry.npmjs.org/@esbuild/aix-ppc64/-/aix-ppc64-0.25.6.tgz",
37
+ "integrity": "sha512-ShbM/3XxwuxjFiuVBHA+d3j5dyac0aEVVq1oluIDf71hUw0aRF59dV/efUsIwFnR6m8JNM2FjZOzmaZ8yG61kw==",
38
+ "cpu": [
39
+ "ppc64"
40
+ ],
41
+ "dev": true,
42
+ "license": "MIT",
43
+ "optional": true,
44
+ "os": [
45
+ "aix"
46
+ ],
47
+ "engines": {
48
+ "node": ">=18"
49
+ }
50
+ },
51
+ "node_modules/@esbuild/android-arm": {
52
+ "version": "0.25.6",
53
+ "resolved": "https://registry.npmjs.org/@esbuild/android-arm/-/android-arm-0.25.6.tgz",
54
+ "integrity": "sha512-S8ToEOVfg++AU/bHwdksHNnyLyVM+eMVAOf6yRKFitnwnbwwPNqKr3srzFRe7nzV69RQKb5DgchIX5pt3L53xg==",
55
+ "cpu": [
56
+ "arm"
57
+ ],
58
+ "dev": true,
59
+ "license": "MIT",
60
+ "optional": true,
61
+ "os": [
62
+ "android"
63
+ ],
64
+ "engines": {
65
+ "node": ">=18"
66
+ }
67
+ },
68
+ "node_modules/@esbuild/android-arm64": {
69
+ "version": "0.25.6",
70
+ "resolved": "https://registry.npmjs.org/@esbuild/android-arm64/-/android-arm64-0.25.6.tgz",
71
+ "integrity": "sha512-hd5zdUarsK6strW+3Wxi5qWws+rJhCCbMiC9QZyzoxfk5uHRIE8T287giQxzVpEvCwuJ9Qjg6bEjcRJcgfLqoA==",
72
+ "cpu": [
73
+ "arm64"
74
+ ],
75
+ "dev": true,
76
+ "license": "MIT",
77
+ "optional": true,
78
+ "os": [
79
+ "android"
80
+ ],
81
+ "engines": {
82
+ "node": ">=18"
83
+ }
84
+ },
85
+ "node_modules/@esbuild/android-x64": {
86
+ "version": "0.25.6",
87
+ "resolved": "https://registry.npmjs.org/@esbuild/android-x64/-/android-x64-0.25.6.tgz",
88
+ "integrity": "sha512-0Z7KpHSr3VBIO9A/1wcT3NTy7EB4oNC4upJ5ye3R7taCc2GUdeynSLArnon5G8scPwaU866d3H4BCrE5xLW25A==",
89
+ "cpu": [
90
+ "x64"
91
+ ],
92
+ "dev": true,
93
+ "license": "MIT",
94
+ "optional": true,
95
+ "os": [
96
+ "android"
97
+ ],
98
+ "engines": {
99
+ "node": ">=18"
100
+ }
101
+ },
102
+ "node_modules/@esbuild/darwin-arm64": {
103
+ "version": "0.25.6",
104
+ "resolved": "https://registry.npmjs.org/@esbuild/darwin-arm64/-/darwin-arm64-0.25.6.tgz",
105
+ "integrity": "sha512-FFCssz3XBavjxcFxKsGy2DYK5VSvJqa6y5HXljKzhRZ87LvEi13brPrf/wdyl/BbpbMKJNOr1Sd0jtW4Ge1pAA==",
106
+ "cpu": [
107
+ "arm64"
108
+ ],
109
+ "dev": true,
110
+ "license": "MIT",
111
+ "optional": true,
112
+ "os": [
113
+ "darwin"
114
+ ],
115
+ "engines": {
116
+ "node": ">=18"
117
+ }
118
+ },
119
+ "node_modules/@esbuild/darwin-x64": {
120
+ "version": "0.25.6",
121
+ "resolved": "https://registry.npmjs.org/@esbuild/darwin-x64/-/darwin-x64-0.25.6.tgz",
122
+ "integrity": "sha512-GfXs5kry/TkGM2vKqK2oyiLFygJRqKVhawu3+DOCk7OxLy/6jYkWXhlHwOoTb0WqGnWGAS7sooxbZowy+pK9Yg==",
123
+ "cpu": [
124
+ "x64"
125
+ ],
126
+ "dev": true,
127
+ "license": "MIT",
128
+ "optional": true,
129
+ "os": [
130
+ "darwin"
131
+ ],
132
+ "engines": {
133
+ "node": ">=18"
134
+ }
135
+ },
136
+ "node_modules/@esbuild/freebsd-arm64": {
137
+ "version": "0.25.6",
138
+ "resolved": "https://registry.npmjs.org/@esbuild/freebsd-arm64/-/freebsd-arm64-0.25.6.tgz",
139
+ "integrity": "sha512-aoLF2c3OvDn2XDTRvn8hN6DRzVVpDlj2B/F66clWd/FHLiHaG3aVZjxQX2DYphA5y/evbdGvC6Us13tvyt4pWg==",
140
+ "cpu": [
141
+ "arm64"
142
+ ],
143
+ "dev": true,
144
+ "license": "MIT",
145
+ "optional": true,
146
+ "os": [
147
+ "freebsd"
148
+ ],
149
+ "engines": {
150
+ "node": ">=18"
151
+ }
152
+ },
153
+ "node_modules/@esbuild/freebsd-x64": {
154
+ "version": "0.25.6",
155
+ "resolved": "https://registry.npmjs.org/@esbuild/freebsd-x64/-/freebsd-x64-0.25.6.tgz",
156
+ "integrity": "sha512-2SkqTjTSo2dYi/jzFbU9Plt1vk0+nNg8YC8rOXXea+iA3hfNJWebKYPs3xnOUf9+ZWhKAaxnQNUf2X9LOpeiMQ==",
157
+ "cpu": [
158
+ "x64"
159
+ ],
160
+ "dev": true,
161
+ "license": "MIT",
162
+ "optional": true,
163
+ "os": [
164
+ "freebsd"
165
+ ],
166
+ "engines": {
167
+ "node": ">=18"
168
+ }
169
+ },
170
+ "node_modules/@esbuild/linux-arm": {
171
+ "version": "0.25.6",
172
+ "resolved": "https://registry.npmjs.org/@esbuild/linux-arm/-/linux-arm-0.25.6.tgz",
173
+ "integrity": "sha512-SZHQlzvqv4Du5PrKE2faN0qlbsaW/3QQfUUc6yO2EjFcA83xnwm91UbEEVx4ApZ9Z5oG8Bxz4qPE+HFwtVcfyw==",
174
+ "cpu": [
175
+ "arm"
176
+ ],
177
+ "dev": true,
178
+ "license": "MIT",
179
+ "optional": true,
180
+ "os": [
181
+ "linux"
182
+ ],
183
+ "engines": {
184
+ "node": ">=18"
185
+ }
186
+ },
187
+ "node_modules/@esbuild/linux-arm64": {
188
+ "version": "0.25.6",
189
+ "resolved": "https://registry.npmjs.org/@esbuild/linux-arm64/-/linux-arm64-0.25.6.tgz",
190
+ "integrity": "sha512-b967hU0gqKd9Drsh/UuAm21Khpoh6mPBSgz8mKRq4P5mVK8bpA+hQzmm/ZwGVULSNBzKdZPQBRT3+WuVavcWsQ==",
191
+ "cpu": [
192
+ "arm64"
193
+ ],
194
+ "dev": true,
195
+ "license": "MIT",
196
+ "optional": true,
197
+ "os": [
198
+ "linux"
199
+ ],
200
+ "engines": {
201
+ "node": ">=18"
202
+ }
203
+ },
204
+ "node_modules/@esbuild/linux-ia32": {
205
+ "version": "0.25.6",
206
+ "resolved": "https://registry.npmjs.org/@esbuild/linux-ia32/-/linux-ia32-0.25.6.tgz",
207
+ "integrity": "sha512-aHWdQ2AAltRkLPOsKdi3xv0mZ8fUGPdlKEjIEhxCPm5yKEThcUjHpWB1idN74lfXGnZ5SULQSgtr5Qos5B0bPw==",
208
+ "cpu": [
209
+ "ia32"
210
+ ],
211
+ "dev": true,
212
+ "license": "MIT",
213
+ "optional": true,
214
+ "os": [
215
+ "linux"
216
+ ],
217
+ "engines": {
218
+ "node": ">=18"
219
+ }
220
+ },
221
+ "node_modules/@esbuild/linux-loong64": {
222
+ "version": "0.25.6",
223
+ "resolved": "https://registry.npmjs.org/@esbuild/linux-loong64/-/linux-loong64-0.25.6.tgz",
224
+ "integrity": "sha512-VgKCsHdXRSQ7E1+QXGdRPlQ/e08bN6WMQb27/TMfV+vPjjTImuT9PmLXupRlC90S1JeNNW5lzkAEO/McKeJ2yg==",
225
+ "cpu": [
226
+ "loong64"
227
+ ],
228
+ "dev": true,
229
+ "license": "MIT",
230
+ "optional": true,
231
+ "os": [
232
+ "linux"
233
+ ],
234
+ "engines": {
235
+ "node": ">=18"
236
+ }
237
+ },
238
+ "node_modules/@esbuild/linux-mips64el": {
239
+ "version": "0.25.6",
240
+ "resolved": "https://registry.npmjs.org/@esbuild/linux-mips64el/-/linux-mips64el-0.25.6.tgz",
241
+ "integrity": "sha512-WViNlpivRKT9/py3kCmkHnn44GkGXVdXfdc4drNmRl15zVQ2+D2uFwdlGh6IuK5AAnGTo2qPB1Djppj+t78rzw==",
242
+ "cpu": [
243
+ "mips64el"
244
+ ],
245
+ "dev": true,
246
+ "license": "MIT",
247
+ "optional": true,
248
+ "os": [
249
+ "linux"
250
+ ],
251
+ "engines": {
252
+ "node": ">=18"
253
+ }
254
+ },
255
+ "node_modules/@esbuild/linux-ppc64": {
256
+ "version": "0.25.6",
257
+ "resolved": "https://registry.npmjs.org/@esbuild/linux-ppc64/-/linux-ppc64-0.25.6.tgz",
258
+ "integrity": "sha512-wyYKZ9NTdmAMb5730I38lBqVu6cKl4ZfYXIs31Baf8aoOtB4xSGi3THmDYt4BTFHk7/EcVixkOV2uZfwU3Q2Jw==",
259
+ "cpu": [
260
+ "ppc64"
261
+ ],
262
+ "dev": true,
263
+ "license": "MIT",
264
+ "optional": true,
265
+ "os": [
266
+ "linux"
267
+ ],
268
+ "engines": {
269
+ "node": ">=18"
270
+ }
271
+ },
272
+ "node_modules/@esbuild/linux-riscv64": {
273
+ "version": "0.25.6",
274
+ "resolved": "https://registry.npmjs.org/@esbuild/linux-riscv64/-/linux-riscv64-0.25.6.tgz",
275
+ "integrity": "sha512-KZh7bAGGcrinEj4qzilJ4hqTY3Dg2U82c8bv+e1xqNqZCrCyc+TL9AUEn5WGKDzm3CfC5RODE/qc96OcbIe33w==",
276
+ "cpu": [
277
+ "riscv64"
278
+ ],
279
+ "dev": true,
280
+ "license": "MIT",
281
+ "optional": true,
282
+ "os": [
283
+ "linux"
284
+ ],
285
+ "engines": {
286
+ "node": ">=18"
287
+ }
288
+ },
289
+ "node_modules/@esbuild/linux-s390x": {
290
+ "version": "0.25.6",
291
+ "resolved": "https://registry.npmjs.org/@esbuild/linux-s390x/-/linux-s390x-0.25.6.tgz",
292
+ "integrity": "sha512-9N1LsTwAuE9oj6lHMyyAM+ucxGiVnEqUdp4v7IaMmrwb06ZTEVCIs3oPPplVsnjPfyjmxwHxHMF8b6vzUVAUGw==",
293
+ "cpu": [
294
+ "s390x"
295
+ ],
296
+ "dev": true,
297
+ "license": "MIT",
298
+ "optional": true,
299
+ "os": [
300
+ "linux"
301
+ ],
302
+ "engines": {
303
+ "node": ">=18"
304
+ }
305
+ },
306
+ "node_modules/@esbuild/linux-x64": {
307
+ "version": "0.25.6",
308
+ "resolved": "https://registry.npmjs.org/@esbuild/linux-x64/-/linux-x64-0.25.6.tgz",
309
+ "integrity": "sha512-A6bJB41b4lKFWRKNrWoP2LHsjVzNiaurf7wyj/XtFNTsnPuxwEBWHLty+ZE0dWBKuSK1fvKgrKaNjBS7qbFKig==",
310
+ "cpu": [
311
+ "x64"
312
+ ],
313
+ "dev": true,
314
+ "license": "MIT",
315
+ "optional": true,
316
+ "os": [
317
+ "linux"
318
+ ],
319
+ "engines": {
320
+ "node": ">=18"
321
+ }
322
+ },
323
+ "node_modules/@esbuild/netbsd-arm64": {
324
+ "version": "0.25.6",
325
+ "resolved": "https://registry.npmjs.org/@esbuild/netbsd-arm64/-/netbsd-arm64-0.25.6.tgz",
326
+ "integrity": "sha512-IjA+DcwoVpjEvyxZddDqBY+uJ2Snc6duLpjmkXm/v4xuS3H+3FkLZlDm9ZsAbF9rsfP3zeA0/ArNDORZgrxR/Q==",
327
+ "cpu": [
328
+ "arm64"
329
+ ],
330
+ "dev": true,
331
+ "license": "MIT",
332
+ "optional": true,
333
+ "os": [
334
+ "netbsd"
335
+ ],
336
+ "engines": {
337
+ "node": ">=18"
338
+ }
339
+ },
340
+ "node_modules/@esbuild/netbsd-x64": {
341
+ "version": "0.25.6",
342
+ "resolved": "https://registry.npmjs.org/@esbuild/netbsd-x64/-/netbsd-x64-0.25.6.tgz",
343
+ "integrity": "sha512-dUXuZr5WenIDlMHdMkvDc1FAu4xdWixTCRgP7RQLBOkkGgwuuzaGSYcOpW4jFxzpzL1ejb8yF620UxAqnBrR9g==",
344
+ "cpu": [
345
+ "x64"
346
+ ],
347
+ "dev": true,
348
+ "license": "MIT",
349
+ "optional": true,
350
+ "os": [
351
+ "netbsd"
352
+ ],
353
+ "engines": {
354
+ "node": ">=18"
355
+ }
356
+ },
357
+ "node_modules/@esbuild/openbsd-arm64": {
358
+ "version": "0.25.6",
359
+ "resolved": "https://registry.npmjs.org/@esbuild/openbsd-arm64/-/openbsd-arm64-0.25.6.tgz",
360
+ "integrity": "sha512-l8ZCvXP0tbTJ3iaqdNf3pjaOSd5ex/e6/omLIQCVBLmHTlfXW3zAxQ4fnDmPLOB1x9xrcSi/xtCWFwCZRIaEwg==",
361
+ "cpu": [
362
+ "arm64"
363
+ ],
364
+ "dev": true,
365
+ "license": "MIT",
366
+ "optional": true,
367
+ "os": [
368
+ "openbsd"
369
+ ],
370
+ "engines": {
371
+ "node": ">=18"
372
+ }
373
+ },
374
+ "node_modules/@esbuild/openbsd-x64": {
375
+ "version": "0.25.6",
376
+ "resolved": "https://registry.npmjs.org/@esbuild/openbsd-x64/-/openbsd-x64-0.25.6.tgz",
377
+ "integrity": "sha512-hKrmDa0aOFOr71KQ/19JC7az1P0GWtCN1t2ahYAf4O007DHZt/dW8ym5+CUdJhQ/qkZmI1HAF8KkJbEFtCL7gw==",
378
+ "cpu": [
379
+ "x64"
380
+ ],
381
+ "dev": true,
382
+ "license": "MIT",
383
+ "optional": true,
384
+ "os": [
385
+ "openbsd"
386
+ ],
387
+ "engines": {
388
+ "node": ">=18"
389
+ }
390
+ },
391
+ "node_modules/@esbuild/openharmony-arm64": {
392
+ "version": "0.25.6",
393
+ "resolved": "https://registry.npmjs.org/@esbuild/openharmony-arm64/-/openharmony-arm64-0.25.6.tgz",
394
+ "integrity": "sha512-+SqBcAWoB1fYKmpWoQP4pGtx+pUUC//RNYhFdbcSA16617cchuryuhOCRpPsjCblKukAckWsV+aQ3UKT/RMPcA==",
395
+ "cpu": [
396
+ "arm64"
397
+ ],
398
+ "dev": true,
399
+ "license": "MIT",
400
+ "optional": true,
401
+ "os": [
402
+ "openharmony"
403
+ ],
404
+ "engines": {
405
+ "node": ">=18"
406
+ }
407
+ },
408
+ "node_modules/@esbuild/sunos-x64": {
409
+ "version": "0.25.6",
410
+ "resolved": "https://registry.npmjs.org/@esbuild/sunos-x64/-/sunos-x64-0.25.6.tgz",
411
+ "integrity": "sha512-dyCGxv1/Br7MiSC42qinGL8KkG4kX0pEsdb0+TKhmJZgCUDBGmyo1/ArCjNGiOLiIAgdbWgmWgib4HoCi5t7kA==",
412
+ "cpu": [
413
+ "x64"
414
+ ],
415
+ "dev": true,
416
+ "license": "MIT",
417
+ "optional": true,
418
+ "os": [
419
+ "sunos"
420
+ ],
421
+ "engines": {
422
+ "node": ">=18"
423
+ }
424
+ },
425
+ "node_modules/@esbuild/win32-arm64": {
426
+ "version": "0.25.6",
427
+ "resolved": "https://registry.npmjs.org/@esbuild/win32-arm64/-/win32-arm64-0.25.6.tgz",
428
+ "integrity": "sha512-42QOgcZeZOvXfsCBJF5Afw73t4veOId//XD3i+/9gSkhSV6Gk3VPlWncctI+JcOyERv85FUo7RxuxGy+z8A43Q==",
429
+ "cpu": [
430
+ "arm64"
431
+ ],
432
+ "dev": true,
433
+ "license": "MIT",
434
+ "optional": true,
435
+ "os": [
436
+ "win32"
437
+ ],
438
+ "engines": {
439
+ "node": ">=18"
440
+ }
441
+ },
442
+ "node_modules/@esbuild/win32-ia32": {
443
+ "version": "0.25.6",
444
+ "resolved": "https://registry.npmjs.org/@esbuild/win32-ia32/-/win32-ia32-0.25.6.tgz",
445
+ "integrity": "sha512-4AWhgXmDuYN7rJI6ORB+uU9DHLq/erBbuMoAuB4VWJTu5KtCgcKYPynF0YI1VkBNuEfjNlLrFr9KZPJzrtLkrQ==",
446
+ "cpu": [
447
+ "ia32"
448
+ ],
449
+ "dev": true,
450
+ "license": "MIT",
451
+ "optional": true,
452
+ "os": [
453
+ "win32"
454
+ ],
455
+ "engines": {
456
+ "node": ">=18"
457
+ }
458
+ },
459
+ "node_modules/@esbuild/win32-x64": {
460
+ "version": "0.25.6",
461
+ "resolved": "https://registry.npmjs.org/@esbuild/win32-x64/-/win32-x64-0.25.6.tgz",
462
+ "integrity": "sha512-NgJPHHbEpLQgDH2MjQu90pzW/5vvXIZ7KOnPyNBm92A6WgZ/7b6fJyUBjoumLqeOQQGqY2QjQxRo97ah4Sj0cA==",
463
+ "cpu": [
464
+ "x64"
465
+ ],
466
+ "dev": true,
467
+ "license": "MIT",
468
+ "optional": true,
469
+ "os": [
470
+ "win32"
471
+ ],
472
+ "engines": {
473
+ "node": ">=18"
474
+ }
475
+ },
476
+ "node_modules/@jridgewell/gen-mapping": {
477
+ "version": "0.3.12",
478
+ "resolved": "https://registry.npmjs.org/@jridgewell/gen-mapping/-/gen-mapping-0.3.12.tgz",
479
+ "integrity": "sha512-OuLGC46TjB5BbN1dH8JULVVZY4WTdkF7tV9Ys6wLL1rubZnCMstOhNHueU5bLCrnRuDhKPDM4g6sw4Bel5Gzqg==",
480
+ "dev": true,
481
+ "license": "MIT",
482
+ "dependencies": {
483
+ "@jridgewell/sourcemap-codec": "^1.5.0",
484
+ "@jridgewell/trace-mapping": "^0.3.24"
485
+ }
486
+ },
487
+ "node_modules/@jridgewell/resolve-uri": {
488
+ "version": "3.1.2",
489
+ "resolved": "https://registry.npmjs.org/@jridgewell/resolve-uri/-/resolve-uri-3.1.2.tgz",
490
+ "integrity": "sha512-bRISgCIjP20/tbWSPWMEi54QVPRZExkuD9lJL+UIxUKtwVJA8wW1Trb1jMs1RFXo1CBTNZ/5hpC9QvmKWdopKw==",
491
+ "dev": true,
492
+ "license": "MIT",
493
+ "engines": {
494
+ "node": ">=6.0.0"
495
+ }
496
+ },
497
+ "node_modules/@jridgewell/sourcemap-codec": {
498
+ "version": "1.5.4",
499
+ "resolved": "https://registry.npmjs.org/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.5.4.tgz",
500
+ "integrity": "sha512-VT2+G1VQs/9oz078bLrYbecdZKs912zQlkelYpuf+SXF+QvZDYJlbx/LSx+meSAwdDFnF8FVXW92AVjjkVmgFw==",
501
+ "dev": true,
502
+ "license": "MIT"
503
+ },
504
+ "node_modules/@jridgewell/trace-mapping": {
505
+ "version": "0.3.29",
506
+ "resolved": "https://registry.npmjs.org/@jridgewell/trace-mapping/-/trace-mapping-0.3.29.tgz",
507
+ "integrity": "sha512-uw6guiW/gcAGPDhLmd77/6lW8QLeiV5RUTsAX46Db6oLhGaVj4lhnPwb184s1bkc8kdVg/+h988dro8GRDpmYQ==",
508
+ "dev": true,
509
+ "license": "MIT",
510
+ "dependencies": {
511
+ "@jridgewell/resolve-uri": "^3.1.0",
512
+ "@jridgewell/sourcemap-codec": "^1.4.14"
513
+ }
514
+ },
515
+ "node_modules/@rollup/rollup-android-arm-eabi": {
516
+ "version": "4.45.1",
517
+ "resolved": "https://registry.npmjs.org/@rollup/rollup-android-arm-eabi/-/rollup-android-arm-eabi-4.45.1.tgz",
518
+ "integrity": "sha512-NEySIFvMY0ZQO+utJkgoMiCAjMrGvnbDLHvcmlA33UXJpYBCvlBEbMMtV837uCkS+plG2umfhn0T5mMAxGrlRA==",
519
+ "cpu": [
520
+ "arm"
521
+ ],
522
+ "dev": true,
523
+ "license": "MIT",
524
+ "optional": true,
525
+ "os": [
526
+ "android"
527
+ ]
528
+ },
529
+ "node_modules/@rollup/rollup-android-arm64": {
530
+ "version": "4.45.1",
531
+ "resolved": "https://registry.npmjs.org/@rollup/rollup-android-arm64/-/rollup-android-arm64-4.45.1.tgz",
532
+ "integrity": "sha512-ujQ+sMXJkg4LRJaYreaVx7Z/VMgBBd89wGS4qMrdtfUFZ+TSY5Rs9asgjitLwzeIbhwdEhyj29zhst3L1lKsRQ==",
533
+ "cpu": [
534
+ "arm64"
535
+ ],
536
+ "dev": true,
537
+ "license": "MIT",
538
+ "optional": true,
539
+ "os": [
540
+ "android"
541
+ ]
542
+ },
543
+ "node_modules/@rollup/rollup-darwin-arm64": {
544
+ "version": "4.45.1",
545
+ "resolved": "https://registry.npmjs.org/@rollup/rollup-darwin-arm64/-/rollup-darwin-arm64-4.45.1.tgz",
546
+ "integrity": "sha512-FSncqHvqTm3lC6Y13xncsdOYfxGSLnP+73k815EfNmpewPs+EyM49haPS105Rh4aF5mJKywk9X0ogzLXZzN9lA==",
547
+ "cpu": [
548
+ "arm64"
549
+ ],
550
+ "dev": true,
551
+ "license": "MIT",
552
+ "optional": true,
553
+ "os": [
554
+ "darwin"
555
+ ]
556
+ },
557
+ "node_modules/@rollup/rollup-darwin-x64": {
558
+ "version": "4.45.1",
559
+ "resolved": "https://registry.npmjs.org/@rollup/rollup-darwin-x64/-/rollup-darwin-x64-4.45.1.tgz",
560
+ "integrity": "sha512-2/vVn/husP5XI7Fsf/RlhDaQJ7x9zjvC81anIVbr4b/f0xtSmXQTFcGIQ/B1cXIYM6h2nAhJkdMHTnD7OtQ9Og==",
561
+ "cpu": [
562
+ "x64"
563
+ ],
564
+ "dev": true,
565
+ "license": "MIT",
566
+ "optional": true,
567
+ "os": [
568
+ "darwin"
569
+ ]
570
+ },
571
+ "node_modules/@rollup/rollup-freebsd-arm64": {
572
+ "version": "4.45.1",
573
+ "resolved": "https://registry.npmjs.org/@rollup/rollup-freebsd-arm64/-/rollup-freebsd-arm64-4.45.1.tgz",
574
+ "integrity": "sha512-4g1kaDxQItZsrkVTdYQ0bxu4ZIQ32cotoQbmsAnW1jAE4XCMbcBPDirX5fyUzdhVCKgPcrwWuucI8yrVRBw2+g==",
575
+ "cpu": [
576
+ "arm64"
577
+ ],
578
+ "dev": true,
579
+ "license": "MIT",
580
+ "optional": true,
581
+ "os": [
582
+ "freebsd"
583
+ ]
584
+ },
585
+ "node_modules/@rollup/rollup-freebsd-x64": {
586
+ "version": "4.45.1",
587
+ "resolved": "https://registry.npmjs.org/@rollup/rollup-freebsd-x64/-/rollup-freebsd-x64-4.45.1.tgz",
588
+ "integrity": "sha512-L/6JsfiL74i3uK1Ti2ZFSNsp5NMiM4/kbbGEcOCps99aZx3g8SJMO1/9Y0n/qKlWZfn6sScf98lEOUe2mBvW9A==",
589
+ "cpu": [
590
+ "x64"
591
+ ],
592
+ "dev": true,
593
+ "license": "MIT",
594
+ "optional": true,
595
+ "os": [
596
+ "freebsd"
597
+ ]
598
+ },
599
+ "node_modules/@rollup/rollup-linux-arm-gnueabihf": {
600
+ "version": "4.45.1",
601
+ "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm-gnueabihf/-/rollup-linux-arm-gnueabihf-4.45.1.tgz",
602
+ "integrity": "sha512-RkdOTu2jK7brlu+ZwjMIZfdV2sSYHK2qR08FUWcIoqJC2eywHbXr0L8T/pONFwkGukQqERDheaGTeedG+rra6Q==",
603
+ "cpu": [
604
+ "arm"
605
+ ],
606
+ "dev": true,
607
+ "license": "MIT",
608
+ "optional": true,
609
+ "os": [
610
+ "linux"
611
+ ]
612
+ },
613
+ "node_modules/@rollup/rollup-linux-arm-musleabihf": {
614
+ "version": "4.45.1",
615
+ "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm-musleabihf/-/rollup-linux-arm-musleabihf-4.45.1.tgz",
616
+ "integrity": "sha512-3kJ8pgfBt6CIIr1o+HQA7OZ9mp/zDk3ctekGl9qn/pRBgrRgfwiffaUmqioUGN9hv0OHv2gxmvdKOkARCtRb8Q==",
617
+ "cpu": [
618
+ "arm"
619
+ ],
620
+ "dev": true,
621
+ "license": "MIT",
622
+ "optional": true,
623
+ "os": [
624
+ "linux"
625
+ ]
626
+ },
627
+ "node_modules/@rollup/rollup-linux-arm64-gnu": {
628
+ "version": "4.45.1",
629
+ "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm64-gnu/-/rollup-linux-arm64-gnu-4.45.1.tgz",
630
+ "integrity": "sha512-k3dOKCfIVixWjG7OXTCOmDfJj3vbdhN0QYEqB+OuGArOChek22hn7Uy5A/gTDNAcCy5v2YcXRJ/Qcnm4/ma1xw==",
631
+ "cpu": [
632
+ "arm64"
633
+ ],
634
+ "dev": true,
635
+ "license": "MIT",
636
+ "optional": true,
637
+ "os": [
638
+ "linux"
639
+ ]
640
+ },
641
+ "node_modules/@rollup/rollup-linux-arm64-musl": {
642
+ "version": "4.45.1",
643
+ "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm64-musl/-/rollup-linux-arm64-musl-4.45.1.tgz",
644
+ "integrity": "sha512-PmI1vxQetnM58ZmDFl9/Uk2lpBBby6B6rF4muJc65uZbxCs0EA7hhKCk2PKlmZKuyVSHAyIw3+/SiuMLxKxWog==",
645
+ "cpu": [
646
+ "arm64"
647
+ ],
648
+ "dev": true,
649
+ "license": "MIT",
650
+ "optional": true,
651
+ "os": [
652
+ "linux"
653
+ ]
654
+ },
655
+ "node_modules/@rollup/rollup-linux-loongarch64-gnu": {
656
+ "version": "4.45.1",
657
+ "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-loongarch64-gnu/-/rollup-linux-loongarch64-gnu-4.45.1.tgz",
658
+ "integrity": "sha512-9UmI0VzGmNJ28ibHW2GpE2nF0PBQqsyiS4kcJ5vK+wuwGnV5RlqdczVocDSUfGX/Na7/XINRVoUgJyFIgipoRg==",
659
+ "cpu": [
660
+ "loong64"
661
+ ],
662
+ "dev": true,
663
+ "license": "MIT",
664
+ "optional": true,
665
+ "os": [
666
+ "linux"
667
+ ]
668
+ },
669
+ "node_modules/@rollup/rollup-linux-powerpc64le-gnu": {
670
+ "version": "4.45.1",
671
+ "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-powerpc64le-gnu/-/rollup-linux-powerpc64le-gnu-4.45.1.tgz",
672
+ "integrity": "sha512-7nR2KY8oEOUTD3pBAxIBBbZr0U7U+R9HDTPNy+5nVVHDXI4ikYniH1oxQz9VoB5PbBU1CZuDGHkLJkd3zLMWsg==",
673
+ "cpu": [
674
+ "ppc64"
675
+ ],
676
+ "dev": true,
677
+ "license": "MIT",
678
+ "optional": true,
679
+ "os": [
680
+ "linux"
681
+ ]
682
+ },
683
+ "node_modules/@rollup/rollup-linux-riscv64-gnu": {
684
+ "version": "4.45.1",
685
+ "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-riscv64-gnu/-/rollup-linux-riscv64-gnu-4.45.1.tgz",
686
+ "integrity": "sha512-nlcl3jgUultKROfZijKjRQLUu9Ma0PeNv/VFHkZiKbXTBQXhpytS8CIj5/NfBeECZtY2FJQubm6ltIxm/ftxpw==",
687
+ "cpu": [
688
+ "riscv64"
689
+ ],
690
+ "dev": true,
691
+ "license": "MIT",
692
+ "optional": true,
693
+ "os": [
694
+ "linux"
695
+ ]
696
+ },
697
+ "node_modules/@rollup/rollup-linux-riscv64-musl": {
698
+ "version": "4.45.1",
699
+ "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-riscv64-musl/-/rollup-linux-riscv64-musl-4.45.1.tgz",
700
+ "integrity": "sha512-HJV65KLS51rW0VY6rvZkiieiBnurSzpzore1bMKAhunQiECPuxsROvyeaot/tcK3A3aGnI+qTHqisrpSgQrpgA==",
701
+ "cpu": [
702
+ "riscv64"
703
+ ],
704
+ "dev": true,
705
+ "license": "MIT",
706
+ "optional": true,
707
+ "os": [
708
+ "linux"
709
+ ]
710
+ },
711
+ "node_modules/@rollup/rollup-linux-s390x-gnu": {
712
+ "version": "4.45.1",
713
+ "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-s390x-gnu/-/rollup-linux-s390x-gnu-4.45.1.tgz",
714
+ "integrity": "sha512-NITBOCv3Qqc6hhwFt7jLV78VEO/il4YcBzoMGGNxznLgRQf43VQDae0aAzKiBeEPIxnDrACiMgbqjuihx08OOw==",
715
+ "cpu": [
716
+ "s390x"
717
+ ],
718
+ "dev": true,
719
+ "license": "MIT",
720
+ "optional": true,
721
+ "os": [
722
+ "linux"
723
+ ]
724
+ },
725
+ "node_modules/@rollup/rollup-linux-x64-gnu": {
726
+ "version": "4.45.1",
727
+ "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-x64-gnu/-/rollup-linux-x64-gnu-4.45.1.tgz",
728
+ "integrity": "sha512-+E/lYl6qu1zqgPEnTrs4WysQtvc/Sh4fC2nByfFExqgYrqkKWp1tWIbe+ELhixnenSpBbLXNi6vbEEJ8M7fiHw==",
729
+ "cpu": [
730
+ "x64"
731
+ ],
732
+ "dev": true,
733
+ "license": "MIT",
734
+ "optional": true,
735
+ "os": [
736
+ "linux"
737
+ ]
738
+ },
739
+ "node_modules/@rollup/rollup-linux-x64-musl": {
740
+ "version": "4.45.1",
741
+ "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-x64-musl/-/rollup-linux-x64-musl-4.45.1.tgz",
742
+ "integrity": "sha512-a6WIAp89p3kpNoYStITT9RbTbTnqarU7D8N8F2CV+4Cl9fwCOZraLVuVFvlpsW0SbIiYtEnhCZBPLoNdRkjQFw==",
743
+ "cpu": [
744
+ "x64"
745
+ ],
746
+ "dev": true,
747
+ "license": "MIT",
748
+ "optional": true,
749
+ "os": [
750
+ "linux"
751
+ ]
752
+ },
753
+ "node_modules/@rollup/rollup-win32-arm64-msvc": {
754
+ "version": "4.45.1",
755
+ "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-arm64-msvc/-/rollup-win32-arm64-msvc-4.45.1.tgz",
756
+ "integrity": "sha512-T5Bi/NS3fQiJeYdGvRpTAP5P02kqSOpqiopwhj0uaXB6nzs5JVi2XMJb18JUSKhCOX8+UE1UKQufyD6Or48dJg==",
757
+ "cpu": [
758
+ "arm64"
759
+ ],
760
+ "dev": true,
761
+ "license": "MIT",
762
+ "optional": true,
763
+ "os": [
764
+ "win32"
765
+ ]
766
+ },
767
+ "node_modules/@rollup/rollup-win32-ia32-msvc": {
768
+ "version": "4.45.1",
769
+ "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-ia32-msvc/-/rollup-win32-ia32-msvc-4.45.1.tgz",
770
+ "integrity": "sha512-lxV2Pako3ujjuUe9jiU3/s7KSrDfH6IgTSQOnDWr9aJ92YsFd7EurmClK0ly/t8dzMkDtd04g60WX6yl0sGfdw==",
771
+ "cpu": [
772
+ "ia32"
773
+ ],
774
+ "dev": true,
775
+ "license": "MIT",
776
+ "optional": true,
777
+ "os": [
778
+ "win32"
779
+ ]
780
+ },
781
+ "node_modules/@rollup/rollup-win32-x64-msvc": {
782
+ "version": "4.45.1",
783
+ "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-x64-msvc/-/rollup-win32-x64-msvc-4.45.1.tgz",
784
+ "integrity": "sha512-M/fKi4sasCdM8i0aWJjCSFm2qEnYRR8AMLG2kxp6wD13+tMGA4Z1tVAuHkNRjud5SW2EM3naLuK35w9twvf6aA==",
785
+ "cpu": [
786
+ "x64"
787
+ ],
788
+ "dev": true,
789
+ "license": "MIT",
790
+ "optional": true,
791
+ "os": [
792
+ "win32"
793
+ ]
794
+ },
795
+ "node_modules/@sveltejs/acorn-typescript": {
796
+ "version": "1.0.5",
797
+ "resolved": "https://registry.npmjs.org/@sveltejs/acorn-typescript/-/acorn-typescript-1.0.5.tgz",
798
+ "integrity": "sha512-IwQk4yfwLdibDlrXVE04jTZYlLnwsTT2PIOQQGNLWfjavGifnk1JD1LcZjZaBTRcxZu2FfPfNLOE04DSu9lqtQ==",
799
+ "dev": true,
800
+ "license": "MIT",
801
+ "peerDependencies": {
802
+ "acorn": "^8.9.0"
803
+ }
804
+ },
805
+ "node_modules/@sveltejs/vite-plugin-svelte": {
806
+ "version": "5.1.1",
807
+ "resolved": "https://registry.npmjs.org/@sveltejs/vite-plugin-svelte/-/vite-plugin-svelte-5.1.1.tgz",
808
+ "integrity": "sha512-Y1Cs7hhTc+a5E9Va/xwKlAJoariQyHY+5zBgCZg4PFWNYQ1nMN9sjK1zhw1gK69DuqVP++sht/1GZg1aRwmAXQ==",
809
+ "dev": true,
810
+ "license": "MIT",
811
+ "dependencies": {
812
+ "@sveltejs/vite-plugin-svelte-inspector": "^4.0.1",
813
+ "debug": "^4.4.1",
814
+ "deepmerge": "^4.3.1",
815
+ "kleur": "^4.1.5",
816
+ "magic-string": "^0.30.17",
817
+ "vitefu": "^1.0.6"
818
+ },
819
+ "engines": {
820
+ "node": "^18.0.0 || ^20.0.0 || >=22"
821
+ },
822
+ "peerDependencies": {
823
+ "svelte": "^5.0.0",
824
+ "vite": "^6.0.0"
825
+ }
826
+ },
827
+ "node_modules/@sveltejs/vite-plugin-svelte-inspector": {
828
+ "version": "4.0.1",
829
+ "resolved": "https://registry.npmjs.org/@sveltejs/vite-plugin-svelte-inspector/-/vite-plugin-svelte-inspector-4.0.1.tgz",
830
+ "integrity": "sha512-J/Nmb2Q2y7mck2hyCX4ckVHcR5tu2J+MtBEQqpDrrgELZ2uvraQcK/ioCV61AqkdXFgriksOKIceDcQmqnGhVw==",
831
+ "dev": true,
832
+ "license": "MIT",
833
+ "dependencies": {
834
+ "debug": "^4.3.7"
835
+ },
836
+ "engines": {
837
+ "node": "^18.0.0 || ^20.0.0 || >=22"
838
+ },
839
+ "peerDependencies": {
840
+ "@sveltejs/vite-plugin-svelte": "^5.0.0",
841
+ "svelte": "^5.0.0",
842
+ "vite": "^6.0.0"
843
+ }
844
+ },
845
+ "node_modules/@tsconfig/svelte": {
846
+ "version": "5.0.4",
847
+ "resolved": "https://registry.npmjs.org/@tsconfig/svelte/-/svelte-5.0.4.tgz",
848
+ "integrity": "sha512-BV9NplVgLmSi4mwKzD8BD/NQ8erOY/nUE/GpgWe2ckx+wIQF5RyRirn/QsSSCPeulVpc3RA/iJt6DpfTIZps0Q==",
849
+ "dev": true,
850
+ "license": "MIT"
851
+ },
852
+ "node_modules/@types/estree": {
853
+ "version": "1.0.8",
854
+ "resolved": "https://registry.npmjs.org/@types/estree/-/estree-1.0.8.tgz",
855
+ "integrity": "sha512-dWHzHa2WqEXI/O1E9OjrocMTKJl2mSrEolh1Iomrv6U+JuNwaHXsXx9bLu5gG7BUWFIN0skIQJQ/L1rIex4X6w==",
856
+ "dev": true,
857
+ "license": "MIT"
858
+ },
859
+ "node_modules/@types/node": {
860
+ "version": "24.0.14",
861
+ "resolved": "https://registry.npmjs.org/@types/node/-/node-24.0.14.tgz",
862
+ "integrity": "sha512-4zXMWD91vBLGRtHK3YbIoFMia+1nqEz72coM42C5ETjnNCa/heoj7NT1G67iAfOqMmcfhuCZ4uNpyz8EjlAejw==",
863
+ "dev": true,
864
+ "license": "MIT",
865
+ "dependencies": {
866
+ "undici-types": "~7.8.0"
867
+ }
868
+ },
869
+ "node_modules/acorn": {
870
+ "version": "8.15.0",
871
+ "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.15.0.tgz",
872
+ "integrity": "sha512-NZyJarBfL7nWwIq+FDL6Zp/yHEhePMNnnJ0y3qfieCrmNvYct8uvtiV41UvlSe6apAfk0fY1FbWx+NwfmpvtTg==",
873
+ "dev": true,
874
+ "license": "MIT",
875
+ "bin": {
876
+ "acorn": "bin/acorn"
877
+ },
878
+ "engines": {
879
+ "node": ">=0.4.0"
880
+ }
881
+ },
882
+ "node_modules/aria-query": {
883
+ "version": "5.3.2",
884
+ "resolved": "https://registry.npmjs.org/aria-query/-/aria-query-5.3.2.tgz",
885
+ "integrity": "sha512-COROpnaoap1E2F000S62r6A60uHZnmlvomhfyT2DlTcrY1OrBKn2UhH7qn5wTC9zMvD0AY7csdPSNwKP+7WiQw==",
886
+ "dev": true,
887
+ "license": "Apache-2.0",
888
+ "engines": {
889
+ "node": ">= 0.4"
890
+ }
891
+ },
892
+ "node_modules/axobject-query": {
893
+ "version": "4.1.0",
894
+ "resolved": "https://registry.npmjs.org/axobject-query/-/axobject-query-4.1.0.tgz",
895
+ "integrity": "sha512-qIj0G9wZbMGNLjLmg1PT6v2mE9AH2zlnADJD/2tC6E00hgmhUOfEB6greHPAfLRSufHqROIUTkw6E+M3lH0PTQ==",
896
+ "dev": true,
897
+ "license": "Apache-2.0",
898
+ "engines": {
899
+ "node": ">= 0.4"
900
+ }
901
+ },
902
+ "node_modules/chokidar": {
903
+ "version": "4.0.3",
904
+ "resolved": "https://registry.npmjs.org/chokidar/-/chokidar-4.0.3.tgz",
905
+ "integrity": "sha512-Qgzu8kfBvo+cA4962jnP1KkS6Dop5NS6g7R5LFYJr4b8Ub94PPQXUksCw9PvXoeXPRRddRNC5C1JQUR2SMGtnA==",
906
+ "dev": true,
907
+ "license": "MIT",
908
+ "dependencies": {
909
+ "readdirp": "^4.0.1"
910
+ },
911
+ "engines": {
912
+ "node": ">= 14.16.0"
913
+ },
914
+ "funding": {
915
+ "url": "https://paulmillr.com/funding/"
916
+ }
917
+ },
918
+ "node_modules/clsx": {
919
+ "version": "2.1.1",
920
+ "resolved": "https://registry.npmjs.org/clsx/-/clsx-2.1.1.tgz",
921
+ "integrity": "sha512-eYm0QWBtUrBWZWG0d386OGAw16Z995PiOVo2B7bjWSbHedGl5e0ZWaq65kOGgUSNesEIDkB9ISbTg/JK9dhCZA==",
922
+ "dev": true,
923
+ "license": "MIT",
924
+ "engines": {
925
+ "node": ">=6"
926
+ }
927
+ },
928
+ "node_modules/debug": {
929
+ "version": "4.4.1",
930
+ "resolved": "https://registry.npmjs.org/debug/-/debug-4.4.1.tgz",
931
+ "integrity": "sha512-KcKCqiftBJcZr++7ykoDIEwSa3XWowTfNPo92BYxjXiyYEVrUQh2aLyhxBCwww+heortUFxEJYcRzosstTEBYQ==",
932
+ "dev": true,
933
+ "license": "MIT",
934
+ "dependencies": {
935
+ "ms": "^2.1.3"
936
+ },
937
+ "engines": {
938
+ "node": ">=6.0"
939
+ },
940
+ "peerDependenciesMeta": {
941
+ "supports-color": {
942
+ "optional": true
943
+ }
944
+ }
945
+ },
946
+ "node_modules/deepmerge": {
947
+ "version": "4.3.1",
948
+ "resolved": "https://registry.npmjs.org/deepmerge/-/deepmerge-4.3.1.tgz",
949
+ "integrity": "sha512-3sUqbMEc77XqpdNO7FRyRog+eW3ph+GYCbj+rK+uYyRMuwsVy0rMiVtPn+QJlKFvWP/1PYpapqYn0Me2knFn+A==",
950
+ "dev": true,
951
+ "license": "MIT",
952
+ "engines": {
953
+ "node": ">=0.10.0"
954
+ }
955
+ },
956
+ "node_modules/esbuild": {
957
+ "version": "0.25.6",
958
+ "resolved": "https://registry.npmjs.org/esbuild/-/esbuild-0.25.6.tgz",
959
+ "integrity": "sha512-GVuzuUwtdsghE3ocJ9Bs8PNoF13HNQ5TXbEi2AhvVb8xU1Iwt9Fos9FEamfoee+u/TOsn7GUWc04lz46n2bbTg==",
960
+ "dev": true,
961
+ "hasInstallScript": true,
962
+ "license": "MIT",
963
+ "bin": {
964
+ "esbuild": "bin/esbuild"
965
+ },
966
+ "engines": {
967
+ "node": ">=18"
968
+ },
969
+ "optionalDependencies": {
970
+ "@esbuild/aix-ppc64": "0.25.6",
971
+ "@esbuild/android-arm": "0.25.6",
972
+ "@esbuild/android-arm64": "0.25.6",
973
+ "@esbuild/android-x64": "0.25.6",
974
+ "@esbuild/darwin-arm64": "0.25.6",
975
+ "@esbuild/darwin-x64": "0.25.6",
976
+ "@esbuild/freebsd-arm64": "0.25.6",
977
+ "@esbuild/freebsd-x64": "0.25.6",
978
+ "@esbuild/linux-arm": "0.25.6",
979
+ "@esbuild/linux-arm64": "0.25.6",
980
+ "@esbuild/linux-ia32": "0.25.6",
981
+ "@esbuild/linux-loong64": "0.25.6",
982
+ "@esbuild/linux-mips64el": "0.25.6",
983
+ "@esbuild/linux-ppc64": "0.25.6",
984
+ "@esbuild/linux-riscv64": "0.25.6",
985
+ "@esbuild/linux-s390x": "0.25.6",
986
+ "@esbuild/linux-x64": "0.25.6",
987
+ "@esbuild/netbsd-arm64": "0.25.6",
988
+ "@esbuild/netbsd-x64": "0.25.6",
989
+ "@esbuild/openbsd-arm64": "0.25.6",
990
+ "@esbuild/openbsd-x64": "0.25.6",
991
+ "@esbuild/openharmony-arm64": "0.25.6",
992
+ "@esbuild/sunos-x64": "0.25.6",
993
+ "@esbuild/win32-arm64": "0.25.6",
994
+ "@esbuild/win32-ia32": "0.25.6",
995
+ "@esbuild/win32-x64": "0.25.6"
996
+ }
997
+ },
998
+ "node_modules/esm-env": {
999
+ "version": "1.2.2",
1000
+ "resolved": "https://registry.npmjs.org/esm-env/-/esm-env-1.2.2.tgz",
1001
+ "integrity": "sha512-Epxrv+Nr/CaL4ZcFGPJIYLWFom+YeV1DqMLHJoEd9SYRxNbaFruBwfEX/kkHUJf55j2+TUbmDcmuilbP1TmXHA==",
1002
+ "dev": true,
1003
+ "license": "MIT"
1004
+ },
1005
+ "node_modules/esrap": {
1006
+ "version": "2.1.0",
1007
+ "resolved": "https://registry.npmjs.org/esrap/-/esrap-2.1.0.tgz",
1008
+ "integrity": "sha512-yzmPNpl7TBbMRC5Lj2JlJZNPml0tzqoqP5B1JXycNUwtqma9AKCO0M2wHrdgsHcy1WRW7S9rJknAMtByg3usgA==",
1009
+ "dev": true,
1010
+ "license": "MIT",
1011
+ "dependencies": {
1012
+ "@jridgewell/sourcemap-codec": "^1.4.15"
1013
+ }
1014
+ },
1015
+ "node_modules/fdir": {
1016
+ "version": "6.4.6",
1017
+ "resolved": "https://registry.npmjs.org/fdir/-/fdir-6.4.6.tgz",
1018
+ "integrity": "sha512-hiFoqpyZcfNm1yc4u8oWCf9A2c4D3QjCrks3zmoVKVxpQRzmPNar1hUJcBG2RQHvEVGDN+Jm81ZheVLAQMK6+w==",
1019
+ "dev": true,
1020
+ "license": "MIT",
1021
+ "peerDependencies": {
1022
+ "picomatch": "^3 || ^4"
1023
+ },
1024
+ "peerDependenciesMeta": {
1025
+ "picomatch": {
1026
+ "optional": true
1027
+ }
1028
+ }
1029
+ },
1030
+ "node_modules/fsevents": {
1031
+ "version": "2.3.3",
1032
+ "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.3.tgz",
1033
+ "integrity": "sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw==",
1034
+ "dev": true,
1035
+ "hasInstallScript": true,
1036
+ "license": "MIT",
1037
+ "optional": true,
1038
+ "os": [
1039
+ "darwin"
1040
+ ],
1041
+ "engines": {
1042
+ "node": "^8.16.0 || ^10.6.0 || >=11.0.0"
1043
+ }
1044
+ },
1045
+ "node_modules/is-reference": {
1046
+ "version": "3.0.3",
1047
+ "resolved": "https://registry.npmjs.org/is-reference/-/is-reference-3.0.3.tgz",
1048
+ "integrity": "sha512-ixkJoqQvAP88E6wLydLGGqCJsrFUnqoH6HnaczB8XmDH1oaWU+xxdptvikTgaEhtZ53Ky6YXiBuUI2WXLMCwjw==",
1049
+ "dev": true,
1050
+ "license": "MIT",
1051
+ "dependencies": {
1052
+ "@types/estree": "^1.0.6"
1053
+ }
1054
+ },
1055
+ "node_modules/kleur": {
1056
+ "version": "4.1.5",
1057
+ "resolved": "https://registry.npmjs.org/kleur/-/kleur-4.1.5.tgz",
1058
+ "integrity": "sha512-o+NO+8WrRiQEE4/7nwRJhN1HWpVmJm511pBHUxPLtp0BUISzlBplORYSmTclCnJvQq2tKu/sgl3xVpkc7ZWuQQ==",
1059
+ "dev": true,
1060
+ "license": "MIT",
1061
+ "engines": {
1062
+ "node": ">=6"
1063
+ }
1064
+ },
1065
+ "node_modules/locate-character": {
1066
+ "version": "3.0.0",
1067
+ "resolved": "https://registry.npmjs.org/locate-character/-/locate-character-3.0.0.tgz",
1068
+ "integrity": "sha512-SW13ws7BjaeJ6p7Q6CO2nchbYEc3X3J6WrmTTDto7yMPqVSZTUyY5Tjbid+Ab8gLnATtygYtiDIJGQRRn2ZOiA==",
1069
+ "dev": true,
1070
+ "license": "MIT"
1071
+ },
1072
+ "node_modules/magic-string": {
1073
+ "version": "0.30.17",
1074
+ "resolved": "https://registry.npmjs.org/magic-string/-/magic-string-0.30.17.tgz",
1075
+ "integrity": "sha512-sNPKHvyjVf7gyjwS4xGTaW/mCnF8wnjtifKBEhxfZ7E/S8tQ0rssrwGNn6q8JH/ohItJfSQp9mBtQYuTlH5QnA==",
1076
+ "dev": true,
1077
+ "license": "MIT",
1078
+ "dependencies": {
1079
+ "@jridgewell/sourcemap-codec": "^1.5.0"
1080
+ }
1081
+ },
1082
+ "node_modules/mri": {
1083
+ "version": "1.2.0",
1084
+ "resolved": "https://registry.npmjs.org/mri/-/mri-1.2.0.tgz",
1085
+ "integrity": "sha512-tzzskb3bG8LvYGFF/mDTpq3jpI6Q9wc3LEmBaghu+DdCssd1FakN7Bc0hVNmEyGq1bq3RgfkCb3cmQLpNPOroA==",
1086
+ "dev": true,
1087
+ "license": "MIT",
1088
+ "engines": {
1089
+ "node": ">=4"
1090
+ }
1091
+ },
1092
+ "node_modules/ms": {
1093
+ "version": "2.1.3",
1094
+ "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz",
1095
+ "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==",
1096
+ "dev": true,
1097
+ "license": "MIT"
1098
+ },
1099
+ "node_modules/nanoid": {
1100
+ "version": "3.3.11",
1101
+ "resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.3.11.tgz",
1102
+ "integrity": "sha512-N8SpfPUnUp1bK+PMYW8qSWdl9U+wwNWI4QKxOYDy9JAro3WMX7p2OeVRF9v+347pnakNevPmiHhNmZ2HbFA76w==",
1103
+ "dev": true,
1104
+ "funding": [
1105
+ {
1106
+ "type": "github",
1107
+ "url": "https://github.com/sponsors/ai"
1108
+ }
1109
+ ],
1110
+ "license": "MIT",
1111
+ "bin": {
1112
+ "nanoid": "bin/nanoid.cjs"
1113
+ },
1114
+ "engines": {
1115
+ "node": "^10 || ^12 || ^13.7 || ^14 || >=15.0.1"
1116
+ }
1117
+ },
1118
+ "node_modules/picocolors": {
1119
+ "version": "1.1.1",
1120
+ "resolved": "https://registry.npmjs.org/picocolors/-/picocolors-1.1.1.tgz",
1121
+ "integrity": "sha512-xceH2snhtb5M9liqDsmEw56le376mTZkEX/jEb/RxNFyegNul7eNslCXP9FDj/Lcu0X8KEyMceP2ntpaHrDEVA==",
1122
+ "dev": true,
1123
+ "license": "ISC"
1124
+ },
1125
+ "node_modules/picomatch": {
1126
+ "version": "4.0.2",
1127
+ "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-4.0.2.tgz",
1128
+ "integrity": "sha512-M7BAV6Rlcy5u+m6oPhAPFgJTzAioX/6B0DxyvDlo9l8+T3nLKbrczg2WLUyzd45L8RqfUMyGPzekbMvX2Ldkwg==",
1129
+ "dev": true,
1130
+ "license": "MIT",
1131
+ "engines": {
1132
+ "node": ">=12"
1133
+ },
1134
+ "funding": {
1135
+ "url": "https://github.com/sponsors/jonschlinkert"
1136
+ }
1137
+ },
1138
+ "node_modules/postcss": {
1139
+ "version": "8.5.6",
1140
+ "resolved": "https://registry.npmjs.org/postcss/-/postcss-8.5.6.tgz",
1141
+ "integrity": "sha512-3Ybi1tAuwAP9s0r1UQ2J4n5Y0G05bJkpUIO0/bI9MhwmD70S5aTWbXGBwxHrelT+XM1k6dM0pk+SwNkpTRN7Pg==",
1142
+ "dev": true,
1143
+ "funding": [
1144
+ {
1145
+ "type": "opencollective",
1146
+ "url": "https://opencollective.com/postcss/"
1147
+ },
1148
+ {
1149
+ "type": "tidelift",
1150
+ "url": "https://tidelift.com/funding/github/npm/postcss"
1151
+ },
1152
+ {
1153
+ "type": "github",
1154
+ "url": "https://github.com/sponsors/ai"
1155
+ }
1156
+ ],
1157
+ "license": "MIT",
1158
+ "dependencies": {
1159
+ "nanoid": "^3.3.11",
1160
+ "picocolors": "^1.1.1",
1161
+ "source-map-js": "^1.2.1"
1162
+ },
1163
+ "engines": {
1164
+ "node": "^10 || ^12 || >=14"
1165
+ }
1166
+ },
1167
+ "node_modules/readdirp": {
1168
+ "version": "4.1.2",
1169
+ "resolved": "https://registry.npmjs.org/readdirp/-/readdirp-4.1.2.tgz",
1170
+ "integrity": "sha512-GDhwkLfywWL2s6vEjyhri+eXmfH6j1L7JE27WhqLeYzoh/A3DBaYGEj2H/HFZCn/kMfim73FXxEJTw06WtxQwg==",
1171
+ "dev": true,
1172
+ "license": "MIT",
1173
+ "engines": {
1174
+ "node": ">= 14.18.0"
1175
+ },
1176
+ "funding": {
1177
+ "type": "individual",
1178
+ "url": "https://paulmillr.com/funding/"
1179
+ }
1180
+ },
1181
+ "node_modules/rollup": {
1182
+ "version": "4.45.1",
1183
+ "resolved": "https://registry.npmjs.org/rollup/-/rollup-4.45.1.tgz",
1184
+ "integrity": "sha512-4iya7Jb76fVpQyLoiVpzUrsjQ12r3dM7fIVz+4NwoYvZOShknRmiv+iu9CClZml5ZLGb0XMcYLutK6w9tgxHDw==",
1185
+ "dev": true,
1186
+ "license": "MIT",
1187
+ "dependencies": {
1188
+ "@types/estree": "1.0.8"
1189
+ },
1190
+ "bin": {
1191
+ "rollup": "dist/bin/rollup"
1192
+ },
1193
+ "engines": {
1194
+ "node": ">=18.0.0",
1195
+ "npm": ">=8.0.0"
1196
+ },
1197
+ "optionalDependencies": {
1198
+ "@rollup/rollup-android-arm-eabi": "4.45.1",
1199
+ "@rollup/rollup-android-arm64": "4.45.1",
1200
+ "@rollup/rollup-darwin-arm64": "4.45.1",
1201
+ "@rollup/rollup-darwin-x64": "4.45.1",
1202
+ "@rollup/rollup-freebsd-arm64": "4.45.1",
1203
+ "@rollup/rollup-freebsd-x64": "4.45.1",
1204
+ "@rollup/rollup-linux-arm-gnueabihf": "4.45.1",
1205
+ "@rollup/rollup-linux-arm-musleabihf": "4.45.1",
1206
+ "@rollup/rollup-linux-arm64-gnu": "4.45.1",
1207
+ "@rollup/rollup-linux-arm64-musl": "4.45.1",
1208
+ "@rollup/rollup-linux-loongarch64-gnu": "4.45.1",
1209
+ "@rollup/rollup-linux-powerpc64le-gnu": "4.45.1",
1210
+ "@rollup/rollup-linux-riscv64-gnu": "4.45.1",
1211
+ "@rollup/rollup-linux-riscv64-musl": "4.45.1",
1212
+ "@rollup/rollup-linux-s390x-gnu": "4.45.1",
1213
+ "@rollup/rollup-linux-x64-gnu": "4.45.1",
1214
+ "@rollup/rollup-linux-x64-musl": "4.45.1",
1215
+ "@rollup/rollup-win32-arm64-msvc": "4.45.1",
1216
+ "@rollup/rollup-win32-ia32-msvc": "4.45.1",
1217
+ "@rollup/rollup-win32-x64-msvc": "4.45.1",
1218
+ "fsevents": "~2.3.2"
1219
+ }
1220
+ },
1221
+ "node_modules/sade": {
1222
+ "version": "1.8.1",
1223
+ "resolved": "https://registry.npmjs.org/sade/-/sade-1.8.1.tgz",
1224
+ "integrity": "sha512-xal3CZX1Xlo/k4ApwCFrHVACi9fBqJ7V+mwhBsuf/1IOKbBy098Fex+Wa/5QMubw09pSZ/u8EY8PWgevJsXp1A==",
1225
+ "dev": true,
1226
+ "license": "MIT",
1227
+ "dependencies": {
1228
+ "mri": "^1.1.0"
1229
+ },
1230
+ "engines": {
1231
+ "node": ">=6"
1232
+ }
1233
+ },
1234
+ "node_modules/source-map-js": {
1235
+ "version": "1.2.1",
1236
+ "resolved": "https://registry.npmjs.org/source-map-js/-/source-map-js-1.2.1.tgz",
1237
+ "integrity": "sha512-UXWMKhLOwVKb728IUtQPXxfYU+usdybtUrK/8uGE8CQMvrhOpwvzDBwj0QhSL7MQc7vIsISBG8VQ8+IDQxpfQA==",
1238
+ "dev": true,
1239
+ "license": "BSD-3-Clause",
1240
+ "engines": {
1241
+ "node": ">=0.10.0"
1242
+ }
1243
+ },
1244
+ "node_modules/svelte": {
1245
+ "version": "5.36.1",
1246
+ "resolved": "https://registry.npmjs.org/svelte/-/svelte-5.36.1.tgz",
1247
+ "integrity": "sha512-h8GmkFVKHP9zcr0/tFZH7kx/3gRkuslFKy5rKd4H66zM+Q/ywmUzeiebC14LjpHkM4feMsTClQvlWROZgEftRw==",
1248
+ "dev": true,
1249
+ "license": "MIT",
1250
+ "dependencies": {
1251
+ "@ampproject/remapping": "^2.3.0",
1252
+ "@jridgewell/sourcemap-codec": "^1.5.0",
1253
+ "@sveltejs/acorn-typescript": "^1.0.5",
1254
+ "@types/estree": "^1.0.5",
1255
+ "acorn": "^8.12.1",
1256
+ "aria-query": "^5.3.1",
1257
+ "axobject-query": "^4.1.0",
1258
+ "clsx": "^2.1.1",
1259
+ "esm-env": "^1.2.1",
1260
+ "esrap": "^2.1.0",
1261
+ "is-reference": "^3.0.3",
1262
+ "locate-character": "^3.0.0",
1263
+ "magic-string": "^0.30.11",
1264
+ "zimmerframe": "^1.1.2"
1265
+ },
1266
+ "engines": {
1267
+ "node": ">=18"
1268
+ }
1269
+ },
1270
+ "node_modules/svelte-check": {
1271
+ "version": "4.2.2",
1272
+ "resolved": "https://registry.npmjs.org/svelte-check/-/svelte-check-4.2.2.tgz",
1273
+ "integrity": "sha512-1+31EOYZ7NKN0YDMKusav2hhEoA51GD9Ws6o//0SphMT0ve9mBTsTUEX7OmDMadUP3KjNHsSKtJrqdSaD8CrGQ==",
1274
+ "dev": true,
1275
+ "license": "MIT",
1276
+ "dependencies": {
1277
+ "@jridgewell/trace-mapping": "^0.3.25",
1278
+ "chokidar": "^4.0.1",
1279
+ "fdir": "^6.2.0",
1280
+ "picocolors": "^1.0.0",
1281
+ "sade": "^1.7.4"
1282
+ },
1283
+ "bin": {
1284
+ "svelte-check": "bin/svelte-check"
1285
+ },
1286
+ "engines": {
1287
+ "node": ">= 18.0.0"
1288
+ },
1289
+ "peerDependencies": {
1290
+ "svelte": "^4.0.0 || ^5.0.0-next.0",
1291
+ "typescript": ">=5.0.0"
1292
+ }
1293
+ },
1294
+ "node_modules/tinyglobby": {
1295
+ "version": "0.2.14",
1296
+ "resolved": "https://registry.npmjs.org/tinyglobby/-/tinyglobby-0.2.14.tgz",
1297
+ "integrity": "sha512-tX5e7OM1HnYr2+a2C/4V0htOcSQcoSTH9KgJnVvNm5zm/cyEWKJ7j7YutsH9CxMdtOkkLFy2AHrMci9IM8IPZQ==",
1298
+ "dev": true,
1299
+ "license": "MIT",
1300
+ "dependencies": {
1301
+ "fdir": "^6.4.4",
1302
+ "picomatch": "^4.0.2"
1303
+ },
1304
+ "engines": {
1305
+ "node": ">=12.0.0"
1306
+ },
1307
+ "funding": {
1308
+ "url": "https://github.com/sponsors/SuperchupuDev"
1309
+ }
1310
+ },
1311
+ "node_modules/typescript": {
1312
+ "version": "5.8.3",
1313
+ "resolved": "https://registry.npmjs.org/typescript/-/typescript-5.8.3.tgz",
1314
+ "integrity": "sha512-p1diW6TqL9L07nNxvRMM7hMMw4c5XOo/1ibL4aAIGmSAt9slTE1Xgw5KWuof2uTOvCg9BY7ZRi+GaF+7sfgPeQ==",
1315
+ "dev": true,
1316
+ "license": "Apache-2.0",
1317
+ "bin": {
1318
+ "tsc": "bin/tsc",
1319
+ "tsserver": "bin/tsserver"
1320
+ },
1321
+ "engines": {
1322
+ "node": ">=14.17"
1323
+ }
1324
+ },
1325
+ "node_modules/undici-types": {
1326
+ "version": "7.8.0",
1327
+ "resolved": "https://registry.npmjs.org/undici-types/-/undici-types-7.8.0.tgz",
1328
+ "integrity": "sha512-9UJ2xGDvQ43tYyVMpuHlsgApydB8ZKfVYTsLDhXkFL/6gfkp+U8xTGdh8pMJv1SpZna0zxG1DwsKZsreLbXBxw==",
1329
+ "dev": true,
1330
+ "license": "MIT"
1331
+ },
1332
+ "node_modules/vite": {
1333
+ "version": "6.3.5",
1334
+ "resolved": "https://registry.npmjs.org/vite/-/vite-6.3.5.tgz",
1335
+ "integrity": "sha512-cZn6NDFE7wdTpINgs++ZJ4N49W2vRp8LCKrn3Ob1kYNtOo21vfDoaV5GzBfLU4MovSAB8uNRm4jgzVQZ+mBzPQ==",
1336
+ "dev": true,
1337
+ "license": "MIT",
1338
+ "dependencies": {
1339
+ "esbuild": "^0.25.0",
1340
+ "fdir": "^6.4.4",
1341
+ "picomatch": "^4.0.2",
1342
+ "postcss": "^8.5.3",
1343
+ "rollup": "^4.34.9",
1344
+ "tinyglobby": "^0.2.13"
1345
+ },
1346
+ "bin": {
1347
+ "vite": "bin/vite.js"
1348
+ },
1349
+ "engines": {
1350
+ "node": "^18.0.0 || ^20.0.0 || >=22.0.0"
1351
+ },
1352
+ "funding": {
1353
+ "url": "https://github.com/vitejs/vite?sponsor=1"
1354
+ },
1355
+ "optionalDependencies": {
1356
+ "fsevents": "~2.3.3"
1357
+ },
1358
+ "peerDependencies": {
1359
+ "@types/node": "^18.0.0 || ^20.0.0 || >=22.0.0",
1360
+ "jiti": ">=1.21.0",
1361
+ "less": "*",
1362
+ "lightningcss": "^1.21.0",
1363
+ "sass": "*",
1364
+ "sass-embedded": "*",
1365
+ "stylus": "*",
1366
+ "sugarss": "*",
1367
+ "terser": "^5.16.0",
1368
+ "tsx": "^4.8.1",
1369
+ "yaml": "^2.4.2"
1370
+ },
1371
+ "peerDependenciesMeta": {
1372
+ "@types/node": {
1373
+ "optional": true
1374
+ },
1375
+ "jiti": {
1376
+ "optional": true
1377
+ },
1378
+ "less": {
1379
+ "optional": true
1380
+ },
1381
+ "lightningcss": {
1382
+ "optional": true
1383
+ },
1384
+ "sass": {
1385
+ "optional": true
1386
+ },
1387
+ "sass-embedded": {
1388
+ "optional": true
1389
+ },
1390
+ "stylus": {
1391
+ "optional": true
1392
+ },
1393
+ "sugarss": {
1394
+ "optional": true
1395
+ },
1396
+ "terser": {
1397
+ "optional": true
1398
+ },
1399
+ "tsx": {
1400
+ "optional": true
1401
+ },
1402
+ "yaml": {
1403
+ "optional": true
1404
+ }
1405
+ }
1406
+ },
1407
+ "node_modules/vitefu": {
1408
+ "version": "1.1.1",
1409
+ "resolved": "https://registry.npmjs.org/vitefu/-/vitefu-1.1.1.tgz",
1410
+ "integrity": "sha512-B/Fegf3i8zh0yFbpzZ21amWzHmuNlLlmJT6n7bu5e+pCHUKQIfXSYokrqOBGEMMe9UG2sostKQF9mml/vYaWJQ==",
1411
+ "dev": true,
1412
+ "license": "MIT",
1413
+ "workspaces": [
1414
+ "tests/deps/*",
1415
+ "tests/projects/*",
1416
+ "tests/projects/workspace/packages/*"
1417
+ ],
1418
+ "peerDependencies": {
1419
+ "vite": "^3.0.0 || ^4.0.0 || ^5.0.0 || ^6.0.0 || ^7.0.0-beta.0"
1420
+ },
1421
+ "peerDependenciesMeta": {
1422
+ "vite": {
1423
+ "optional": true
1424
+ }
1425
+ }
1426
+ },
1427
+ "node_modules/zimmerframe": {
1428
+ "version": "1.1.2",
1429
+ "resolved": "https://registry.npmjs.org/zimmerframe/-/zimmerframe-1.1.2.tgz",
1430
+ "integrity": "sha512-rAbqEGa8ovJy4pyBxZM70hg4pE6gDgaQ0Sl9M3enG3I0d6H4XSAM3GeNGLKnsBpuijUow064sf7ww1nutC5/3w==",
1431
+ "dev": true,
1432
+ "license": "MIT"
1433
+ }
1434
+ }
1435
+ }
package.json CHANGED
@@ -12,6 +12,7 @@
12
  "devDependencies": {
13
  "@sveltejs/vite-plugin-svelte": "^5.0.3",
14
  "@tsconfig/svelte": "^5.0.4",
 
15
  "svelte": "^5.28.1",
16
  "svelte-check": "^4.1.6",
17
  "typescript": "~5.8.3",
 
12
  "devDependencies": {
13
  "@sveltejs/vite-plugin-svelte": "^5.0.3",
14
  "@tsconfig/svelte": "^5.0.4",
15
+ "@types/node": "^24.0.14",
16
  "svelte": "^5.28.1",
17
  "svelte-check": "^4.1.6",
18
  "typescript": "~5.8.3",
prototype_index.html ADDED
@@ -0,0 +1,458 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <!doctype html>
2
+ <html lang="en">
3
+ <head>
4
+ <meta charset="utf-8" />
5
+ <meta name="viewport" content="width=device-width, initial-scale=1" />
6
+ <title>FLUX-1 Schnell Demo (HF OAuth)</title>
7
+ <style>
8
+ :root {
9
+ font-family: system-ui, -apple-system, Segoe UI, Roboto, Helvetica, Arial, sans-serif;
10
+ }
11
+ body {
12
+ margin: 0;
13
+ padding: 2rem;
14
+ background: #f5f5f5;
15
+ }
16
+ .card {
17
+ max-width: 900px;
18
+ margin: 0 auto;
19
+ background: #ffffff;
20
+ padding: 2rem;
21
+ border-radius: 10px;
22
+ box-shadow: 0 2px 8px rgba(0, 0, 0, 0.08);
23
+ }
24
+ h1 {
25
+ margin-top: 0;
26
+ }
27
+ #signin {
28
+ background: #ff7b7b;
29
+ color: #fff;
30
+ border: none;
31
+ padding: 0.6rem 1.2rem;
32
+ border-radius: 6px;
33
+ cursor: pointer;
34
+ font-size: 1rem;
35
+ display: none; /* shown once JS decides it's needed */
36
+ }
37
+ #banner {
38
+ display: none;
39
+ margin-top: 1rem;
40
+ padding: 0.8rem 1rem;
41
+ border-radius: 6px;
42
+ background: #fff3cd;
43
+ color: #856404;
44
+ border: 1px solid #ffeeba;
45
+ }
46
+ /* Generator UI */
47
+ form {
48
+ margin-top: 2rem;
49
+ }
50
+ label {
51
+ font-weight: 600;
52
+ margin-bottom: 0.25rem;
53
+ display: block;
54
+ }
55
+ input[type="text"], input[type="number"] {
56
+ width: 100%;
57
+ padding: 0.5rem 0.75rem;
58
+ border: 1px solid #ccc;
59
+ border-radius: 4px;
60
+ box-sizing: border-box;
61
+ margin-bottom: 1rem;
62
+ }
63
+ button.generate {
64
+ background: #007bff;
65
+ color: #fff;
66
+ border: none;
67
+ padding: 0.6rem 1.4rem;
68
+ border-radius: 6px;
69
+ cursor: pointer;
70
+ font-size: 1rem;
71
+ }
72
+ button.generate:disabled {
73
+ background: #9ac7ff;
74
+ cursor: not-allowed;
75
+ }
76
+ img {
77
+ max-width: 100%;
78
+ border-radius: 8px;
79
+ margin-top: 1rem;
80
+ }
81
+ </style>
82
+ </head>
83
+ <body>
84
+ <div class="card">
85
+ <h1>FLUX-1 Schnell + Joy Caption + RWKV Space</h1>
86
+ <p>
87
+ This static Space demonstrates how to call a remote Gradio Space while
88
+ letting <strong>each visitor&rsquo;s own Hugging Face subscription</strong> cover
89
+ the compute costs. Generate images with FLUX-1, caption them with Joy Caption, and generate text with RWKV.
90
+ </p>
91
+
92
+ <!-- 1️⃣ Sign-in button (shown only when needed) -->
93
+ <button id="signin">Sign in with Hugging Face</button>
94
+ <div id="banner"></div>
95
+
96
+ <!-- 2️⃣ Image-generation form (hidden until the app is ready) -->
97
+ <form id="generateForm" style="display:none;">
98
+ <label for="prompt">Prompt</label>
99
+ <input type="text" id="prompt" placeholder="Enter your prompt" required />
100
+
101
+ <label for="seed">Seed</label>
102
+ <input type="number" id="seed" value="0" min="0" max="2147483647" />
103
+
104
+ <label>
105
+ <input type="checkbox" id="randomize_seed" checked /> Randomize seed
106
+ </label>
107
+
108
+ <div style="display:flex; gap:1rem;">
109
+ <div style="flex:1;">
110
+ <label for="width">Width</label>
111
+ <input type="number" id="width" value="1024" min="256" max="2048" step="32" />
112
+ </div>
113
+ <div style="flex:1;">
114
+ <label for="height">Height</label>
115
+ <input type="number" id="height" value="1024" min="256" max="2048" step="32" />
116
+ </div>
117
+ </div>
118
+
119
+ <label for="steps">Number of inference steps</label>
120
+ <input type="number" id="steps" value="4" min="1" max="50" />
121
+
122
+ <button type="submit" class="generate">Generate Image</button>
123
+ </form>
124
+
125
+ <!-- 3️⃣ Caption form -->
126
+ <form id="captionForm" style="display:none; margin-top:2rem; border-top:1px solid #eee; padding-top:2rem;">
127
+ <h3>Caption Image</h3>
128
+ <label for="imageInput">Upload Image or Generate Above</label>
129
+ <input type="file" id="imageInput" accept="image/*" />
130
+
131
+ <label for="captionType">Caption Type</label>
132
+ <select id="captionType">
133
+ <option value="Descriptive">Descriptive</option>
134
+ <option value="Descriptive (Informal)">Descriptive (Informal)</option>
135
+ <option value="Training Prompt">Training Prompt</option>
136
+ <option value="MidJourney">MidJourney</option>
137
+ <option value="Booru tag list">Booru tag list</option>
138
+ <option value="Booru-like tag list">Booru-like tag list</option>
139
+ <option value="Art Critic">Art Critic</option>
140
+ <option value="Product Listing">Product Listing</option>
141
+ <option value="Social Media Post">Social Media Post</option>
142
+ </select>
143
+
144
+ <label for="captionLength">Caption Length</label>
145
+ <select id="captionLength">
146
+ <option value="any">Any</option>
147
+ <option value="very short">Very Short</option>
148
+ <option value="short">Short</option>
149
+ <option value="medium-length">Medium</option>
150
+ <option value="long" selected>Long</option>
151
+ <option value="very long">Very Long</option>
152
+ </select>
153
+
154
+ <button type="submit" class="generate">Generate Caption</button>
155
+ </form>
156
+
157
+ <!-- 4️⃣ Result container -->
158
+ <div id="result"></div>
159
+
160
+ <!-- 5️⃣ Caption result -->
161
+ <div id="captionResult" style="margin-top:1rem;"></div>
162
+
163
+ <!-- 6️⃣ Text generation form -->
164
+ <form id="textForm" style="display:none; margin-top:2rem; border-top:1px solid #eee; padding-top:2rem;">
165
+ <h3>Generate Text</h3>
166
+ <label for="textPrompt">Prompt</label>
167
+ <textarea id="textPrompt" rows="4" placeholder="Enter your prompt here..." style="width:100%; padding:0.5rem; border:1px solid #ccc; border-radius:4px; box-sizing:border-box; margin-bottom:1rem;"></textarea>
168
+
169
+ <div style="display:flex; gap:1rem;">
170
+ <div style="flex:1;">
171
+ <label for="maxTokens">Max Tokens</label>
172
+ <input type="number" id="maxTokens" value="200" min="10" max="1000" step="10" />
173
+ </div>
174
+ <div style="flex:1;">
175
+ <label for="temperature">Temperature</label>
176
+ <input type="number" id="temperature" value="1.0" min="0.2" max="2.0" step="0.1" />
177
+ </div>
178
+ </div>
179
+
180
+ <div style="display:flex; gap:1rem;">
181
+ <div style="flex:1;">
182
+ <label for="topP">Top P</label>
183
+ <input type="number" id="topP" value="0.7" min="0.0" max="1.0" step="0.05" />
184
+ </div>
185
+ <div style="flex:1;">
186
+ <label for="presencePenalty">Presence Penalty</label>
187
+ <input type="number" id="presencePenalty" value="0.1" min="0.0" max="1.0" step="0.1" />
188
+ </div>
189
+ </div>
190
+
191
+ <label for="countPenalty">Count Penalty</label>
192
+ <input type="number" id="countPenalty" value="0.1" min="0.0" max="1.0" step="0.1" />
193
+
194
+ <button type="submit" class="generate">Generate Text</button>
195
+ </form>
196
+
197
+ <!-- 7️⃣ Text generation result -->
198
+ <div id="textResult" style="margin-top:1rem;"></div>
199
+
200
+ <hr />
201
+ <p>
202
+ Source &amp; docs:
203
+ <a href="https://huggingface.co/docs/hub/spaces-oauth" target="_blank">Spaces OAuth</a>,
204
+ <a href="https://github.com/huggingface/huggingface.js" target="_blank">huggingface.js</a>,
205
+ <a href="https://js.gradio.app" target="_blank">@gradio/client</a>
206
+ </p>
207
+ </div>
208
+
209
+ <!-- 4️⃣ App logic -->
210
+ <script type="module">
211
+ import {
212
+ oauthLoginUrl,
213
+ oauthHandleRedirectIfPresent
214
+ } from "https://cdn.jsdelivr.net/npm/@huggingface/[email protected]/+esm";
215
+ import { Client } from "https://cdn.jsdelivr.net/npm/@gradio/client/dist/index.min.js";
216
+
217
+ // DOM helpers
218
+ const signinBtn = document.getElementById("signin");
219
+ const banner = document.getElementById("banner");
220
+ const form = document.getElementById("generateForm");
221
+ const resultDiv = document.getElementById("result");
222
+ const captionForm = document.getElementById("captionForm");
223
+ const captionResultDiv = document.getElementById("captionResult");
224
+ const textForm = document.getElementById("textForm");
225
+ const textResultDiv = document.getElementById("textResult");
226
+
227
+ const BANNER_ANON =
228
+ "⚠️ You are not logged in – anonymous users get only ~60 seconds of zero-GPU time per day. Sign in for higher limits.";
229
+
230
+ // Try to finish OAuth redirect (if we just came back from HF SSO)
231
+ let session = await oauthHandleRedirectIfPresent();
232
+
233
+ if (!session) {
234
+ // Not signed in: show banner & sign-in button
235
+ banner.textContent = BANNER_ANON;
236
+ banner.style.display = "block";
237
+ signinBtn.style.display = "inline-block";
238
+ signinBtn.onclick = async () => {
239
+ const url = await oauthLoginUrl({ scopes: ["inference-api"] });
240
+ window.location.href = url; // full-page redirect
241
+ };
242
+
243
+ // Proceed anonymously (limited quota)
244
+ startApp(null);
245
+ } else {
246
+ banner.style.display = "none";
247
+ startApp(session.accessToken, session.userInfo);
248
+ }
249
+
250
+ /**
251
+ * Main app logic: connect to remote Space & wire up the form.
252
+ * @param {string|null} hfToken
253
+ * @param {object} [userInfo]
254
+ */
255
+ async function startApp(hfToken, userInfo = null) {
256
+ try {
257
+ banner.textContent = "Connecting to FLUX.1-schnell, Joy Caption, and RWKV…";
258
+ banner.style.display = "block";
259
+
260
+ const opts = hfToken ? { hf_token: hfToken } : {};
261
+ const flux = await Client.connect(
262
+ "black-forest-labs/FLUX.1-schnell",
263
+ opts
264
+ );
265
+
266
+ const joyCaption = await Client.connect(
267
+ "fancyfeast/joy-caption-alpha-two",
268
+ opts
269
+ );
270
+
271
+ const rwkv = await Client.connect(
272
+ "BlinkDL/RWKV-Gradio-2",
273
+ opts
274
+ );
275
+
276
+ banner.style.display = "none";
277
+ form.style.display = "block";
278
+ captionForm.style.display = "block";
279
+ textForm.style.display = "block";
280
+
281
+ if (userInfo) {
282
+ const greeting = document.createElement("p");
283
+ greeting.textContent = `Hello, ${userInfo.name || userInfo.preferred_username}!`;
284
+ form.parentNode.insertBefore(greeting, form);
285
+ }
286
+
287
+ form.addEventListener("submit", async (e) => {
288
+ e.preventDefault();
289
+ const prompt = document.getElementById("prompt").value;
290
+ const seed = parseInt(document.getElementById("seed").value, 10);
291
+ const randomize = document.getElementById("randomize_seed").checked;
292
+ const width = parseInt(document.getElementById("width").value, 10);
293
+ const height = parseInt(document.getElementById("height").value, 10);
294
+ const steps = parseInt(document.getElementById("steps").value, 10);
295
+
296
+ const btn = form.querySelector("button.generate");
297
+ btn.disabled = true;
298
+ btn.textContent = "Generating…";
299
+ resultDiv.innerHTML = "Generating image…";
300
+
301
+ try {
302
+ const output = await flux.predict("/infer", [
303
+ prompt,
304
+ seed,
305
+ randomize,
306
+ width,
307
+ height,
308
+ steps
309
+ ]);
310
+
311
+ const [image, usedSeed] = output.data;
312
+ let url;
313
+ if (typeof image === "string") url = image;
314
+ else if (image && image.url) url = image.url;
315
+ else if (image && image.path) url = image.path;
316
+
317
+ if (url) {
318
+ resultDiv.innerHTML = `
319
+ <img src="${url}" alt="Generated" />
320
+ <p><strong>Seed</strong>: ${usedSeed}</p>
321
+ <p><strong>Prompt</strong>: ${prompt}</p>
322
+ `;
323
+
324
+ // Store image for captioning (fetch the image as blob)
325
+ try {
326
+ const response = await fetch(url);
327
+ currentImage = await response.blob();
328
+ } catch (imgErr) {
329
+ console.warn("Could not fetch generated image for captioning:", imgErr);
330
+ }
331
+ } else {
332
+ resultDiv.textContent = "Unexpected image format – open console.";
333
+ }
334
+ } catch (err) {
335
+ console.error(err);
336
+ resultDiv.textContent = `Generation failed: ${err}`;
337
+ } finally {
338
+ btn.disabled = false;
339
+ btn.textContent = "Generate Image";
340
+ }
341
+ });
342
+
343
+ // Caption form event listener
344
+ let currentImage = null;
345
+
346
+ captionForm.addEventListener("submit", async (e) => {
347
+ e.preventDefault();
348
+
349
+ const imageInput = document.getElementById("imageInput");
350
+ const captionType = document.getElementById("captionType").value;
351
+ const captionLength = document.getElementById("captionLength").value;
352
+
353
+ let imageToCaption = currentImage;
354
+
355
+ // If user uploaded an image, use that
356
+ if (imageInput.files && imageInput.files[0]) {
357
+ imageToCaption = imageInput.files[0];
358
+ }
359
+
360
+ if (!imageToCaption) {
361
+ captionResultDiv.innerHTML = "Please upload an image or generate one above.";
362
+ return;
363
+ }
364
+
365
+ const btn = captionForm.querySelector("button");
366
+ btn.disabled = true;
367
+ btn.textContent = "Generating Caption…";
368
+ captionResultDiv.innerHTML = "Generating caption…";
369
+
370
+ try {
371
+ const output = await joyCaption.predict("/stream_chat", [
372
+ imageToCaption,
373
+ captionType,
374
+ captionLength,
375
+ [], // extra_options
376
+ "", // name_input
377
+ "" // custom_prompt
378
+ ]);
379
+
380
+ const [prompt, caption] = output.data;
381
+ captionResultDiv.innerHTML = `
382
+ <div style="background:#f8f9fa; padding:1rem; border-radius:6px; margin-top:1rem;">
383
+ <h4>Generated Caption</h4>
384
+ <p><strong>Type:</strong> ${captionType}</p>
385
+ <p><strong>Length:</strong> ${captionLength}</p>
386
+ <p><strong>Caption:</strong></p>
387
+ <p style="font-style:italic;">${caption}</p>
388
+ </div>
389
+ `;
390
+ } catch (err) {
391
+ console.error(err);
392
+ captionResultDiv.innerHTML = `<p style="color:red;">Caption generation failed: ${err}</p>`;
393
+ } finally {
394
+ btn.disabled = false;
395
+ btn.textContent = "Generate Caption";
396
+ }
397
+ });
398
+
399
+ // Text generation form event listener
400
+ textForm.addEventListener("submit", async (e) => {
401
+ e.preventDefault();
402
+
403
+ const prompt = document.getElementById("textPrompt").value.trim();
404
+ const maxTokens = parseInt(document.getElementById("maxTokens").value, 10);
405
+ const temperature = parseFloat(document.getElementById("temperature").value);
406
+ const topP = parseFloat(document.getElementById("topP").value);
407
+ const presencePenalty = parseFloat(document.getElementById("presencePenalty").value);
408
+ const countPenalty = parseFloat(document.getElementById("countPenalty").value);
409
+
410
+ if (!prompt) {
411
+ textResultDiv.innerHTML = "<p style='color:red;'>Please enter a prompt.</p>";
412
+ return;
413
+ }
414
+
415
+ const btn = textForm.querySelector("button");
416
+ btn.disabled = true;
417
+ btn.textContent = "Generating Text…";
418
+ textResultDiv.innerHTML = "Generating text…";
419
+
420
+ try {
421
+ const output = await rwkv.predict(0, [
422
+ prompt,
423
+ maxTokens,
424
+ temperature,
425
+ topP,
426
+ presencePenalty,
427
+ countPenalty
428
+ ]);
429
+
430
+ const generatedText = output.data[0];
431
+ textResultDiv.innerHTML = `
432
+ <div style="background:#f8f9fa; padding:1rem; border-radius:6px; margin-top:1rem;">
433
+ <h4>Generated Text</h4>
434
+ <p><strong>Prompt:</strong> ${prompt.substring(0, 100)}${prompt.length > 100 ? '...' : ''}</p>
435
+ <p><strong>Generated:</strong></p>
436
+ <div style="white-space:pre-wrap; font-family:monospace; background:#fff; padding:1rem; border-radius:4px; border:1px solid #ddd;">${generatedText}</div>
437
+ </div>
438
+ `;
439
+ } catch (err) {
440
+ console.error(err);
441
+ textResultDiv.innerHTML = `<p style="color:red;">Text generation failed: ${err}</p>`;
442
+ } finally {
443
+ btn.disabled = false;
444
+ btn.textContent = "Generate Text";
445
+ }
446
+ });
447
+
448
+
449
+ } catch (err) {
450
+ console.error(err);
451
+ banner.textContent = `❌ Failed to connect: ${err}`;
452
+ banner.style.display = "block";
453
+ signinBtn.style.display = "none";
454
+ }
455
+ }
456
+ </script>
457
+ </body>
458
+ </html>
src/App.svelte CHANGED
@@ -1,47 +1,194 @@
1
  <script lang="ts">
2
- import svelteLogo from './assets/svelte.svg'
3
- import viteLogo from '/vite.svg'
4
- import Counter from './lib/Counter.svelte'
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
5
  </script>
6
 
7
- <main>
8
- <div>
9
- <a href="https://vite.dev" target="_blank" rel="noreferrer">
10
- <img src={viteLogo} class="logo" alt="Vite Logo" />
11
- </a>
12
- <a href="https://svelte.dev" target="_blank" rel="noreferrer">
13
- <img src={svelteLogo} class="logo svelte" alt="Svelte Logo" />
14
- </a>
15
- </div>
16
- <h1>Vite + Svelte</h1>
17
-
18
  <div class="card">
19
- <Counter />
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
20
  </div>
21
-
22
- <p>
23
- Check out <a href="https://github.com/sveltejs/kit#readme" target="_blank" rel="noreferrer">SvelteKit</a>, the official Svelte app framework powered by Vite!
24
- </p>
25
-
26
- <p class="read-the-docs">
27
- Click on the Vite and Svelte logos to learn more
28
- </p>
29
- </main>
30
 
31
  <style>
32
- .logo {
33
- height: 6em;
34
- padding: 1.5em;
35
- will-change: filter;
36
- transition: filter 300ms;
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
37
  }
38
- .logo:hover {
39
- filter: drop-shadow(0 0 2em #646cffaa);
 
 
40
  }
41
- .logo.svelte:hover {
42
- filter: drop-shadow(0 0 2em #ff3e00aa);
 
 
43
  }
44
- .read-the-docs {
45
- color: #888;
 
46
  }
47
- </style>
 
1
  <script lang="ts">
2
+ import { onMount } from 'svelte';
3
+ import { authStore } from './lib/stores/auth';
4
+ import SignInButton from './lib/components/Auth/SignInButton.svelte';
5
+ import AuthBanner from './lib/components/Auth/AuthBanner.svelte';
6
+ import FluxGenerator from './lib/components/ImageGeneration/FluxGenerator.svelte';
7
+ import JoyCaption from './lib/components/ImageCaption/JoyCaption.svelte';
8
+ import RWKVGenerator from './lib/components/TextGeneration/RWKVGenerator.svelte';
9
+ import type { HuggingFaceLibs, GradioLibs, GradioClient, FluxGenerationResult } from './lib/types';
10
+
11
+ // These will be loaded from window after HF libs are loaded
12
+ let hfAuth: HuggingFaceLibs | null = $state(null);
13
+ let gradioClient: GradioLibs | null = $state(null);
14
+
15
+ // Gradio client instances
16
+ let fluxClient: GradioClient | null = $state(null);
17
+ let joyCaptionClient: GradioClient | null = $state(null);
18
+ let rwkvClient: GradioClient | null = $state(null);
19
+
20
+ // Current generated image for passing to caption component
21
+ let currentImageBlob: Blob | null = $state(null);
22
+
23
+ // Auth state from store
24
+ const auth = $derived(authStore);
25
+
26
+ onMount(async () => {
27
+ // Load HF libraries
28
+ const script1 = document.createElement('script');
29
+ script1.type = 'module';
30
+ script1.textContent = `
31
+ import {
32
+ oauthLoginUrl,
33
+ oauthHandleRedirectIfPresent
34
+ } from "https://cdn.jsdelivr.net/npm/@huggingface/[email protected]/+esm";
35
+ import { Client } from "https://cdn.jsdelivr.net/npm/@gradio/client/dist/index.min.js";
36
+
37
+ window.hfAuth = { oauthLoginUrl, oauthHandleRedirectIfPresent };
38
+ window.gradioClient = { Client };
39
+ `;
40
+ document.head.appendChild(script1);
41
+
42
+ // Wait for libraries to load
43
+ await new Promise(resolve => {
44
+ const checkLibs = setInterval(() => {
45
+ if (window.hfAuth && window.gradioClient) {
46
+ clearInterval(checkLibs);
47
+ resolve(undefined);
48
+ }
49
+ }, 100);
50
+ });
51
+
52
+ hfAuth = window.hfAuth as HuggingFaceLibs;
53
+ gradioClient = window.gradioClient as GradioLibs;
54
+
55
+ // Handle OAuth redirect
56
+ try {
57
+ const session = await hfAuth.oauthHandleRedirectIfPresent();
58
+ authStore.setSession(session);
59
+
60
+ // Start the app
61
+ await initializeClients(session?.accessToken || null);
62
+ } catch (err) {
63
+ console.error("OAuth handling error:", err);
64
+ authStore.setSession(null);
65
+ await initializeClients(null);
66
+ }
67
+ });
68
+
69
+ async function initializeClients(hfToken: string | null) {
70
+ if (!gradioClient) return;
71
+
72
+ authStore.setBannerMessage("Connecting to FLUX.1-schnell, Joy Caption, and RWKV…");
73
+
74
+ try {
75
+ const opts = hfToken ? { hf_token: hfToken } : {};
76
+
77
+ // Connect to all three spaces
78
+ fluxClient = await gradioClient.Client.connect(
79
+ "black-forest-labs/FLUX.1-schnell",
80
+ opts
81
+ );
82
+
83
+ joyCaptionClient = await gradioClient.Client.connect(
84
+ "fancyfeast/joy-caption-alpha-two",
85
+ opts
86
+ );
87
+
88
+ rwkvClient = await gradioClient.Client.connect(
89
+ "BlinkDL/RWKV-Gradio-2",
90
+ opts
91
+ );
92
+
93
+ authStore.setBannerMessage("");
94
+ } catch (err) {
95
+ console.error(err);
96
+ authStore.setBannerMessage(`❌ Failed to connect: ${err}`);
97
+ }
98
+ }
99
+
100
+ function handleImageGenerated(result: FluxGenerationResult, imageBlob: Blob) {
101
+ currentImageBlob = imageBlob;
102
+ }
103
  </script>
104
 
105
+ <div class="app">
 
 
 
 
 
 
 
 
 
 
106
  <div class="card">
107
+ <h1>FLUX-1 Schnell + Joy Caption + RWKV Space</h1>
108
+ <p>
109
+ This Svelte-powered Space demonstrates how to call remote Gradio Spaces while
110
+ letting <strong>each visitor's own Hugging Face subscription</strong> cover
111
+ the compute costs. Generate images with FLUX-1, caption them with Joy Caption, and generate text with RWKV.
112
+ </p>
113
+
114
+ {#if $auth.showSignIn}
115
+ <SignInButton {hfAuth} />
116
+ {/if}
117
+
118
+ <AuthBanner
119
+ message={$auth.bannerMessage}
120
+ visible={!!$auth.bannerMessage}
121
+ />
122
+
123
+ {#if $auth.userInfo}
124
+ <p>Hello, {$auth.userInfo.name || $auth.userInfo.preferred_username}!</p>
125
+ {/if}
126
+
127
+ {#if fluxClient}
128
+ <FluxGenerator
129
+ client={fluxClient}
130
+ onImageGenerated={handleImageGenerated}
131
+ />
132
+ {/if}
133
+
134
+ {#if joyCaptionClient}
135
+ <JoyCaption
136
+ client={joyCaptionClient}
137
+ currentImage={currentImageBlob}
138
+ />
139
+ {/if}
140
+
141
+ {#if rwkvClient}
142
+ <RWKVGenerator client={rwkvClient} />
143
+ {/if}
144
+
145
+ <hr />
146
+ <p class="footer">
147
+ Source & docs:
148
+ <a href="https://huggingface.co/docs/hub/spaces-oauth" target="_blank">Spaces OAuth</a>,
149
+ <a href="https://github.com/huggingface/huggingface.js" target="_blank">huggingface.js</a>,
150
+ <a href="https://js.gradio.app" target="_blank">@gradio/client</a>
151
+ </p>
152
  </div>
153
+ </div>
 
 
 
 
 
 
 
 
154
 
155
  <style>
156
+ .app {
157
+ min-height: 100vh;
158
+ background: #f5f5f5;
159
+ padding: 2rem;
160
+ }
161
+
162
+ .card {
163
+ max-width: 900px;
164
+ margin: 0 auto;
165
+ background: #ffffff;
166
+ padding: 2rem;
167
+ border-radius: 10px;
168
+ box-shadow: 0 2px 8px rgba(0, 0, 0, 0.08);
169
+ }
170
+
171
+ h1 {
172
+ margin-top: 0;
173
+ }
174
+
175
+ hr {
176
+ margin: 3rem 0 2rem;
177
+ border: none;
178
+ border-top: 1px solid #eee;
179
  }
180
+
181
+ .footer {
182
+ color: #666;
183
+ font-size: 0.9rem;
184
  }
185
+
186
+ .footer a {
187
+ color: #007bff;
188
+ text-decoration: none;
189
  }
190
+
191
+ .footer a:hover {
192
+ text-decoration: underline;
193
  }
194
+ </style>
src/app.css CHANGED
@@ -1,11 +1,11 @@
1
  :root {
2
- font-family: system-ui, Avenir, Helvetica, Arial, sans-serif;
3
  line-height: 1.5;
4
  font-weight: 400;
5
 
6
- color-scheme: light dark;
7
- color: rgba(255, 255, 255, 0.87);
8
- background-color: #242424;
9
 
10
  font-synthesis: none;
11
  text-rendering: optimizeLegibility;
@@ -13,67 +13,70 @@
13
  -moz-osx-font-smoothing: grayscale;
14
  }
15
 
16
- a {
17
- font-weight: 500;
18
- color: #646cff;
19
- text-decoration: inherit;
20
- }
21
- a:hover {
22
- color: #535bf2;
23
  }
24
 
25
  body {
26
  margin: 0;
27
  display: flex;
28
- place-items: center;
29
  min-width: 320px;
30
  min-height: 100vh;
31
  }
32
 
33
- h1 {
34
- font-size: 3.2em;
35
- line-height: 1.1;
36
  }
37
 
38
- .card {
39
- padding: 2em;
 
 
40
  }
41
 
42
- #app {
43
- max-width: 1280px;
44
- margin: 0 auto;
45
- padding: 2rem;
46
- text-align: center;
47
  }
48
 
49
  button {
50
- border-radius: 8px;
51
- border: 1px solid transparent;
52
- padding: 0.6em 1.2em;
53
- font-size: 1em;
54
- font-weight: 500;
55
  font-family: inherit;
56
- background-color: #1a1a1a;
57
- cursor: pointer;
58
- transition: border-color 0.25s;
 
 
 
 
 
 
 
 
59
  }
60
- button:hover {
61
- border-color: #646cff;
 
 
 
 
 
 
 
 
 
 
 
 
62
  }
63
- button:focus,
64
- button:focus-visible {
65
- outline: 4px auto -webkit-focus-ring-color;
 
 
 
 
 
66
  }
67
 
68
- @media (prefers-color-scheme: light) {
69
- :root {
70
- color: #213547;
71
- background-color: #ffffff;
72
- }
73
- a:hover {
74
- color: #747bff;
75
- }
76
- button {
77
- background-color: #f9f9f9;
78
- }
79
  }
 
1
  :root {
2
+ font-family: system-ui, -apple-system, Segoe UI, Roboto, Helvetica, Arial, sans-serif;
3
  line-height: 1.5;
4
  font-weight: 400;
5
 
6
+ color-scheme: light;
7
+ color: #213547;
8
+ background-color: #f5f5f5;
9
 
10
  font-synthesis: none;
11
  text-rendering: optimizeLegibility;
 
13
  -moz-osx-font-smoothing: grayscale;
14
  }
15
 
16
+ * {
17
+ box-sizing: border-box;
 
 
 
 
 
18
  }
19
 
20
  body {
21
  margin: 0;
22
  display: flex;
 
23
  min-width: 320px;
24
  min-height: 100vh;
25
  }
26
 
27
+ #app {
28
+ width: 100%;
 
29
  }
30
 
31
+ a {
32
+ font-weight: 500;
33
+ color: #007bff;
34
+ text-decoration: inherit;
35
  }
36
 
37
+ a:hover {
38
+ text-decoration: underline;
 
 
 
39
  }
40
 
41
  button {
 
 
 
 
 
42
  font-family: inherit;
43
+ font-size: inherit;
44
+ }
45
+
46
+ h1, h2, h3, h4, h5, h6 {
47
+ font-weight: 600;
48
+ line-height: 1.2;
49
+ }
50
+
51
+ /* Utility classes */
52
+ .text-center {
53
+ text-align: center;
54
  }
55
+
56
+ .mt-1 { margin-top: 0.5rem; }
57
+ .mt-2 { margin-top: 1rem; }
58
+ .mt-3 { margin-top: 1.5rem; }
59
+ .mt-4 { margin-top: 2rem; }
60
+
61
+ .mb-1 { margin-bottom: 0.5rem; }
62
+ .mb-2 { margin-bottom: 1rem; }
63
+ .mb-3 { margin-bottom: 1.5rem; }
64
+ .mb-4 { margin-bottom: 2rem; }
65
+
66
+ /* Hide scrollbar for Chrome, Safari and Opera */
67
+ ::-webkit-scrollbar {
68
+ width: 8px;
69
  }
70
+
71
+ ::-webkit-scrollbar-track {
72
+ background: #f1f1f1;
73
+ }
74
+
75
+ ::-webkit-scrollbar-thumb {
76
+ background: #888;
77
+ border-radius: 4px;
78
  }
79
 
80
+ ::-webkit-scrollbar-thumb:hover {
81
+ background: #555;
 
 
 
 
 
 
 
 
 
82
  }
src/lib/components/Auth/AuthBanner.svelte ADDED
@@ -0,0 +1,25 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <script lang="ts">
2
+ interface Props {
3
+ message?: string;
4
+ visible?: boolean;
5
+ }
6
+
7
+ let { message = "", visible = false }: Props = $props();
8
+ </script>
9
+
10
+ {#if visible && message}
11
+ <div class="banner">
12
+ {message}
13
+ </div>
14
+ {/if}
15
+
16
+ <style>
17
+ .banner {
18
+ margin-top: 1rem;
19
+ padding: 0.8rem 1rem;
20
+ border-radius: 6px;
21
+ background: #fff3cd;
22
+ color: #856404;
23
+ border: 1px solid #ffeeba;
24
+ }
25
+ </style>
src/lib/components/Auth/SignInButton.svelte ADDED
@@ -0,0 +1,46 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <script lang="ts">
2
+ import type { HuggingFaceLibs } from '$lib/types';
3
+
4
+ interface Props {
5
+ hfAuth: HuggingFaceLibs | null;
6
+ }
7
+
8
+ let { hfAuth = null }: Props = $props();
9
+
10
+ async function handleSignIn() {
11
+ if (!hfAuth) return;
12
+
13
+ const url = await hfAuth.oauthLoginUrl({ scopes: ["inference-api"] });
14
+ window.location.href = url;
15
+ }
16
+ </script>
17
+
18
+ <button
19
+ class="signin-button"
20
+ onclick={handleSignIn}
21
+ disabled={!hfAuth}
22
+ >
23
+ Sign in with Hugging Face
24
+ </button>
25
+
26
+ <style>
27
+ .signin-button {
28
+ background: #ff7b7b;
29
+ color: #fff;
30
+ border: none;
31
+ padding: 0.6rem 1.2rem;
32
+ border-radius: 6px;
33
+ cursor: pointer;
34
+ font-size: 1rem;
35
+ transition: background-color 0.2s;
36
+ }
37
+
38
+ .signin-button:hover:not(:disabled) {
39
+ background: #ff6565;
40
+ }
41
+
42
+ .signin-button:disabled {
43
+ opacity: 0.6;
44
+ cursor: not-allowed;
45
+ }
46
+ </style>
src/lib/components/ImageCaption/JoyCaption.svelte ADDED
@@ -0,0 +1,219 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <script lang="ts">
2
+ import type { GradioClient, CaptionParams, CaptionResult, CaptionType, CaptionLength } from '$lib/types';
3
+
4
+ interface Props {
5
+ client: GradioClient | null;
6
+ currentImage?: Blob | null;
7
+ }
8
+
9
+ let { client = null, currentImage = null }: Props = $props();
10
+
11
+ let imageInput: HTMLInputElement;
12
+ let uploadedImage: File | null = $state(null);
13
+ let captionType: CaptionType = $state("Descriptive");
14
+ let captionLength: CaptionLength = $state("long");
15
+ let isGenerating = $state(false);
16
+ let result: CaptionResult | null = $state(null);
17
+ let error: string | null = $state(null);
18
+
19
+ const captionTypes: CaptionType[] = [
20
+ "Descriptive",
21
+ "Descriptive (Informal)",
22
+ "Training Prompt",
23
+ "MidJourney",
24
+ "Booru tag list",
25
+ "Booru-like tag list",
26
+ "Art Critic",
27
+ "Product Listing",
28
+ "Social Media Post"
29
+ ];
30
+
31
+ const captionLengths: CaptionLength[] = [
32
+ "any",
33
+ "very short",
34
+ "short",
35
+ "medium-length",
36
+ "long",
37
+ "very long"
38
+ ];
39
+
40
+ function handleFileChange(e: Event) {
41
+ const target = e.target as HTMLInputElement;
42
+ if (target.files && target.files[0]) {
43
+ uploadedImage = target.files[0];
44
+ }
45
+ }
46
+
47
+ async function handleSubmit(e: Event) {
48
+ e.preventDefault();
49
+
50
+ const imageToCaption = uploadedImage || currentImage;
51
+
52
+ if (!client || !imageToCaption) {
53
+ error = "Please upload an image or generate one above.";
54
+ return;
55
+ }
56
+
57
+ isGenerating = true;
58
+ error = null;
59
+ result = null;
60
+
61
+ try {
62
+ const output = await client.predict("/stream_chat", [
63
+ imageToCaption,
64
+ captionType,
65
+ captionLength,
66
+ [], // extra_options
67
+ "", // name_input
68
+ "" // custom_prompt
69
+ ]);
70
+
71
+ const [prompt, caption] = output.data;
72
+
73
+ result = {
74
+ caption,
75
+ type: captionType,
76
+ length: captionLength
77
+ };
78
+ } catch (err) {
79
+ console.error(err);
80
+ error = `Caption generation failed: ${err}`;
81
+ } finally {
82
+ isGenerating = false;
83
+ }
84
+ }
85
+ </script>
86
+
87
+ <form class="caption-form" onsubmit={handleSubmit}>
88
+ <h3>Caption Image</h3>
89
+
90
+ <label for="imageInput">
91
+ Upload Image {currentImage ? 'or use generated image' : ''}
92
+ </label>
93
+ <input
94
+ type="file"
95
+ id="imageInput"
96
+ accept="image/*"
97
+ onchange={handleFileChange}
98
+ bind:this={imageInput}
99
+ disabled={isGenerating}
100
+ />
101
+
102
+ <label for="captionType">Caption Type</label>
103
+ <select
104
+ id="captionType"
105
+ bind:value={captionType}
106
+ disabled={isGenerating}
107
+ >
108
+ {#each captionTypes as type}
109
+ <option value={type}>{type}</option>
110
+ {/each}
111
+ </select>
112
+
113
+ <label for="captionLength">Caption Length</label>
114
+ <select
115
+ id="captionLength"
116
+ bind:value={captionLength}
117
+ disabled={isGenerating}
118
+ >
119
+ {#each captionLengths as length}
120
+ <option value={length}>
121
+ {length.charAt(0).toUpperCase() + length.slice(1).replace('-', ' ')}
122
+ </option>
123
+ {/each}
124
+ </select>
125
+
126
+ <button
127
+ type="submit"
128
+ class="generate-button"
129
+ disabled={isGenerating || !client}
130
+ >
131
+ {isGenerating ? 'Generating Caption…' : 'Generate Caption'}
132
+ </button>
133
+ </form>
134
+
135
+ {#if error}
136
+ <div class="error-message">{error}</div>
137
+ {/if}
138
+
139
+ {#if result}
140
+ <div class="caption-result">
141
+ <h4>Generated Caption</h4>
142
+ <p><strong>Type:</strong> {result.type}</p>
143
+ <p><strong>Length:</strong> {result.length}</p>
144
+ <p><strong>Caption:</strong></p>
145
+ <p class="caption-text">{result.caption}</p>
146
+ </div>
147
+ {/if}
148
+
149
+ <style>
150
+ .caption-form {
151
+ margin-top: 2rem;
152
+ padding-top: 2rem;
153
+ border-top: 1px solid #eee;
154
+ }
155
+
156
+ h3 {
157
+ margin-top: 0;
158
+ margin-bottom: 1.5rem;
159
+ }
160
+
161
+ label {
162
+ font-weight: 600;
163
+ margin-bottom: 0.25rem;
164
+ display: block;
165
+ }
166
+
167
+ input[type="file"],
168
+ select {
169
+ width: 100%;
170
+ padding: 0.5rem 0.75rem;
171
+ border: 1px solid #ccc;
172
+ border-radius: 4px;
173
+ box-sizing: border-box;
174
+ margin-bottom: 1rem;
175
+ }
176
+
177
+ .generate-button {
178
+ background: #007bff;
179
+ color: #fff;
180
+ border: none;
181
+ padding: 0.6rem 1.4rem;
182
+ border-radius: 6px;
183
+ cursor: pointer;
184
+ font-size: 1rem;
185
+ transition: background-color 0.2s;
186
+ }
187
+
188
+ .generate-button:hover:not(:disabled) {
189
+ background: #0056b3;
190
+ }
191
+
192
+ .generate-button:disabled {
193
+ background: #9ac7ff;
194
+ cursor: not-allowed;
195
+ }
196
+
197
+ .caption-result {
198
+ background: #f8f9fa;
199
+ padding: 1rem;
200
+ border-radius: 6px;
201
+ margin-top: 1rem;
202
+ }
203
+
204
+ .caption-result h4 {
205
+ margin-top: 0;
206
+ }
207
+
208
+ .caption-text {
209
+ font-style: italic;
210
+ }
211
+
212
+ .error-message {
213
+ color: #dc3545;
214
+ margin-top: 1rem;
215
+ padding: 0.5rem;
216
+ background: #f8d7da;
217
+ border-radius: 4px;
218
+ }
219
+ </style>
src/lib/components/ImageGeneration/FluxGenerator.svelte ADDED
@@ -0,0 +1,257 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <script lang="ts">
2
+ import type { GradioClient, FluxGenerationParams, FluxGenerationResult } from '$lib/types';
3
+
4
+ interface Props {
5
+ client: GradioClient | null;
6
+ onImageGenerated?: ((result: FluxGenerationResult, imageBlob: Blob) => void) | null;
7
+ }
8
+
9
+ let { client = null, onImageGenerated = null }: Props = $props();
10
+
11
+ let params: FluxGenerationParams = $state({
12
+ prompt: "",
13
+ seed: 0,
14
+ randomizeSeed: true,
15
+ width: 1024,
16
+ height: 1024,
17
+ steps: 4
18
+ });
19
+
20
+ let isGenerating = $state(false);
21
+ let result: FluxGenerationResult | null = $state(null);
22
+ let error: string | null = $state(null);
23
+
24
+ async function handleSubmit(e: Event) {
25
+ e.preventDefault();
26
+ if (!client || !params.prompt.trim()) return;
27
+
28
+ isGenerating = true;
29
+ error = null;
30
+
31
+ try {
32
+ const output = await client.predict("/infer", [
33
+ params.prompt,
34
+ params.seed,
35
+ params.randomizeSeed,
36
+ params.width,
37
+ params.height,
38
+ params.steps
39
+ ]);
40
+
41
+ const [image, usedSeed] = output.data;
42
+ let url: string | undefined;
43
+
44
+ if (typeof image === "string") url = image;
45
+ else if (image && image.url) url = image.url;
46
+ else if (image && image.path) url = image.path;
47
+
48
+ if (url) {
49
+ result = {
50
+ imageUrl: url,
51
+ seed: usedSeed,
52
+ prompt: params.prompt
53
+ };
54
+
55
+ // Fetch image as blob for captioning
56
+ if (onImageGenerated) {
57
+ try {
58
+ const response = await fetch(url);
59
+ const blob = await response.blob();
60
+ onImageGenerated(result, blob);
61
+ } catch (err) {
62
+ console.warn("Could not fetch generated image for captioning:", err);
63
+ }
64
+ }
65
+ } else {
66
+ error = "Unexpected image format returned from API";
67
+ }
68
+ } catch (err) {
69
+ console.error(err);
70
+ error = `Generation failed: ${err}`;
71
+ } finally {
72
+ isGenerating = false;
73
+ }
74
+ }
75
+ </script>
76
+
77
+ <form class="generator-form" onsubmit={handleSubmit}>
78
+ <h3>Generate Image with FLUX-1 Schnell</h3>
79
+
80
+ <label for="prompt">Prompt</label>
81
+ <input
82
+ type="text"
83
+ id="prompt"
84
+ bind:value={params.prompt}
85
+ placeholder="Enter your prompt"
86
+ required
87
+ disabled={isGenerating}
88
+ />
89
+
90
+ <label for="seed">Seed</label>
91
+ <input
92
+ type="number"
93
+ id="seed"
94
+ bind:value={params.seed}
95
+ min="0"
96
+ max="2147483647"
97
+ disabled={isGenerating}
98
+ />
99
+
100
+ <label>
101
+ <input
102
+ type="checkbox"
103
+ bind:checked={params.randomizeSeed}
104
+ disabled={isGenerating}
105
+ />
106
+ Randomize seed
107
+ </label>
108
+
109
+ <div class="input-row">
110
+ <div class="input-group">
111
+ <label for="width">Width</label>
112
+ <input
113
+ type="number"
114
+ id="width"
115
+ bind:value={params.width}
116
+ min="256"
117
+ max="2048"
118
+ step="32"
119
+ disabled={isGenerating}
120
+ />
121
+ </div>
122
+ <div class="input-group">
123
+ <label for="height">Height</label>
124
+ <input
125
+ type="number"
126
+ id="height"
127
+ bind:value={params.height}
128
+ min="256"
129
+ max="2048"
130
+ step="32"
131
+ disabled={isGenerating}
132
+ />
133
+ </div>
134
+ </div>
135
+
136
+ <label for="steps">Number of inference steps</label>
137
+ <input
138
+ type="number"
139
+ id="steps"
140
+ bind:value={params.steps}
141
+ min="1"
142
+ max="50"
143
+ disabled={isGenerating}
144
+ />
145
+
146
+ <button
147
+ type="submit"
148
+ class="generate-button"
149
+ disabled={isGenerating || !client}
150
+ >
151
+ {isGenerating ? 'Generating…' : 'Generate Image'}
152
+ </button>
153
+ </form>
154
+
155
+ {#if error}
156
+ <div class="error-message">{error}</div>
157
+ {/if}
158
+
159
+ {#if isGenerating}
160
+ <div class="status-message">Generating image…</div>
161
+ {/if}
162
+
163
+ {#if result}
164
+ <div class="result">
165
+ <img src={result.imageUrl} alt="Generated" />
166
+ <p><strong>Seed</strong>: {result.seed}</p>
167
+ <p><strong>Prompt</strong>: {result.prompt}</p>
168
+ </div>
169
+ {/if}
170
+
171
+ <style>
172
+ .generator-form {
173
+ margin-top: 2rem;
174
+ padding-top: 2rem;
175
+ border-top: 1px solid #eee;
176
+ }
177
+
178
+ h3 {
179
+ margin-top: 0;
180
+ margin-bottom: 1.5rem;
181
+ }
182
+
183
+ label {
184
+ font-weight: 600;
185
+ margin-bottom: 0.25rem;
186
+ display: block;
187
+ }
188
+
189
+ input[type="text"],
190
+ input[type="number"] {
191
+ width: 100%;
192
+ padding: 0.5rem 0.75rem;
193
+ border: 1px solid #ccc;
194
+ border-radius: 4px;
195
+ box-sizing: border-box;
196
+ margin-bottom: 1rem;
197
+ }
198
+
199
+ input[type="checkbox"] {
200
+ margin-right: 0.5rem;
201
+ }
202
+
203
+ .input-row {
204
+ display: flex;
205
+ gap: 1rem;
206
+ }
207
+
208
+ .input-group {
209
+ flex: 1;
210
+ }
211
+
212
+ .generate-button {
213
+ background: #007bff;
214
+ color: #fff;
215
+ border: none;
216
+ padding: 0.6rem 1.4rem;
217
+ border-radius: 6px;
218
+ cursor: pointer;
219
+ font-size: 1rem;
220
+ transition: background-color 0.2s;
221
+ }
222
+
223
+ .generate-button:hover:not(:disabled) {
224
+ background: #0056b3;
225
+ }
226
+
227
+ .generate-button:disabled {
228
+ background: #9ac7ff;
229
+ cursor: not-allowed;
230
+ }
231
+
232
+ .result {
233
+ margin-top: 1rem;
234
+ }
235
+
236
+ .result img {
237
+ max-width: 100%;
238
+ border-radius: 8px;
239
+ margin-bottom: 1rem;
240
+ }
241
+
242
+ .error-message {
243
+ color: #dc3545;
244
+ margin-top: 1rem;
245
+ padding: 0.5rem;
246
+ background: #f8d7da;
247
+ border-radius: 4px;
248
+ }
249
+
250
+ .status-message {
251
+ color: #0c5460;
252
+ margin-top: 1rem;
253
+ padding: 0.5rem;
254
+ background: #d1ecf1;
255
+ border-radius: 4px;
256
+ }
257
+ </style>
src/lib/components/TextGeneration/RWKVGenerator.svelte ADDED
@@ -0,0 +1,253 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <script lang="ts">
2
+ import type { GradioClient, TextGenerationParams, TextGenerationResult } from '$lib/types';
3
+
4
+ interface Props {
5
+ client: GradioClient | null;
6
+ }
7
+
8
+ let { client = null }: Props = $props();
9
+
10
+ let params: TextGenerationParams = $state({
11
+ prompt: "",
12
+ maxTokens: 200,
13
+ temperature: 1.0,
14
+ topP: 0.7,
15
+ presencePenalty: 0.1,
16
+ countPenalty: 0.1
17
+ });
18
+
19
+ let isGenerating = $state(false);
20
+ let result: TextGenerationResult | null = $state(null);
21
+ let error: string | null = $state(null);
22
+
23
+ async function handleSubmit(e: Event) {
24
+ e.preventDefault();
25
+
26
+ if (!client || !params.prompt.trim()) {
27
+ error = "Please enter a prompt.";
28
+ return;
29
+ }
30
+
31
+ isGenerating = true;
32
+ error = null;
33
+ result = null;
34
+
35
+ try {
36
+ const output = await client.predict(0, [
37
+ params.prompt,
38
+ params.maxTokens,
39
+ params.temperature,
40
+ params.topP,
41
+ params.presencePenalty,
42
+ params.countPenalty
43
+ ]);
44
+
45
+ const generatedText = output.data[0];
46
+
47
+ result = {
48
+ text: generatedText,
49
+ prompt: params.prompt
50
+ };
51
+ } catch (err) {
52
+ console.error(err);
53
+ error = `Text generation failed: ${err}`;
54
+ } finally {
55
+ isGenerating = false;
56
+ }
57
+ }
58
+ </script>
59
+
60
+ <form class="text-form" onsubmit={handleSubmit}>
61
+ <h3>Generate Text with RWKV</h3>
62
+
63
+ <label for="textPrompt">Prompt</label>
64
+ <textarea
65
+ id="textPrompt"
66
+ bind:value={params.prompt}
67
+ rows="4"
68
+ placeholder="Enter your prompt here..."
69
+ disabled={isGenerating}
70
+ ></textarea>
71
+
72
+ <div class="input-row">
73
+ <div class="input-group">
74
+ <label for="maxTokens">Max Tokens</label>
75
+ <input
76
+ type="number"
77
+ id="maxTokens"
78
+ bind:value={params.maxTokens}
79
+ min="10"
80
+ max="1000"
81
+ step="10"
82
+ disabled={isGenerating}
83
+ />
84
+ </div>
85
+ <div class="input-group">
86
+ <label for="temperature">Temperature</label>
87
+ <input
88
+ type="number"
89
+ id="temperature"
90
+ bind:value={params.temperature}
91
+ min="0.2"
92
+ max="2.0"
93
+ step="0.1"
94
+ disabled={isGenerating}
95
+ />
96
+ </div>
97
+ </div>
98
+
99
+ <div class="input-row">
100
+ <div class="input-group">
101
+ <label for="topP">Top P</label>
102
+ <input
103
+ type="number"
104
+ id="topP"
105
+ bind:value={params.topP}
106
+ min="0.0"
107
+ max="1.0"
108
+ step="0.05"
109
+ disabled={isGenerating}
110
+ />
111
+ </div>
112
+ <div class="input-group">
113
+ <label for="presencePenalty">Presence Penalty</label>
114
+ <input
115
+ type="number"
116
+ id="presencePenalty"
117
+ bind:value={params.presencePenalty}
118
+ min="0.0"
119
+ max="1.0"
120
+ step="0.1"
121
+ disabled={isGenerating}
122
+ />
123
+ </div>
124
+ </div>
125
+
126
+ <label for="countPenalty">Count Penalty</label>
127
+ <input
128
+ type="number"
129
+ id="countPenalty"
130
+ bind:value={params.countPenalty}
131
+ min="0.0"
132
+ max="1.0"
133
+ step="0.1"
134
+ disabled={isGenerating}
135
+ />
136
+
137
+ <button
138
+ type="submit"
139
+ class="generate-button"
140
+ disabled={isGenerating || !client}
141
+ >
142
+ {isGenerating ? 'Generating Text…' : 'Generate Text'}
143
+ </button>
144
+ </form>
145
+
146
+ {#if error}
147
+ <div class="error-message">{error}</div>
148
+ {/if}
149
+
150
+ {#if result}
151
+ <div class="text-result">
152
+ <h4>Generated Text</h4>
153
+ <p><strong>Prompt:</strong> {result.prompt.substring(0, 100)}{result.prompt.length > 100 ? '...' : ''}</p>
154
+ <p><strong>Generated:</strong></p>
155
+ <div class="generated-text">{result.text}</div>
156
+ </div>
157
+ {/if}
158
+
159
+ <style>
160
+ .text-form {
161
+ margin-top: 2rem;
162
+ padding-top: 2rem;
163
+ border-top: 1px solid #eee;
164
+ }
165
+
166
+ h3 {
167
+ margin-top: 0;
168
+ margin-bottom: 1.5rem;
169
+ }
170
+
171
+ label {
172
+ font-weight: 600;
173
+ margin-bottom: 0.25rem;
174
+ display: block;
175
+ }
176
+
177
+ textarea {
178
+ width: 100%;
179
+ padding: 0.5rem;
180
+ border: 1px solid #ccc;
181
+ border-radius: 4px;
182
+ box-sizing: border-box;
183
+ margin-bottom: 1rem;
184
+ font-family: inherit;
185
+ resize: vertical;
186
+ }
187
+
188
+ input[type="number"] {
189
+ width: 100%;
190
+ padding: 0.5rem 0.75rem;
191
+ border: 1px solid #ccc;
192
+ border-radius: 4px;
193
+ box-sizing: border-box;
194
+ margin-bottom: 1rem;
195
+ }
196
+
197
+ .input-row {
198
+ display: flex;
199
+ gap: 1rem;
200
+ }
201
+
202
+ .input-group {
203
+ flex: 1;
204
+ }
205
+
206
+ .generate-button {
207
+ background: #007bff;
208
+ color: #fff;
209
+ border: none;
210
+ padding: 0.6rem 1.4rem;
211
+ border-radius: 6px;
212
+ cursor: pointer;
213
+ font-size: 1rem;
214
+ transition: background-color 0.2s;
215
+ }
216
+
217
+ .generate-button:hover:not(:disabled) {
218
+ background: #0056b3;
219
+ }
220
+
221
+ .generate-button:disabled {
222
+ background: #9ac7ff;
223
+ cursor: not-allowed;
224
+ }
225
+
226
+ .text-result {
227
+ background: #f8f9fa;
228
+ padding: 1rem;
229
+ border-radius: 6px;
230
+ margin-top: 1rem;
231
+ }
232
+
233
+ .text-result h4 {
234
+ margin-top: 0;
235
+ }
236
+
237
+ .generated-text {
238
+ white-space: pre-wrap;
239
+ font-family: monospace;
240
+ background: #fff;
241
+ padding: 1rem;
242
+ border-radius: 4px;
243
+ border: 1px solid #ddd;
244
+ }
245
+
246
+ .error-message {
247
+ color: #dc3545;
248
+ margin-top: 1rem;
249
+ padding: 0.5rem;
250
+ background: #f8d7da;
251
+ border-radius: 4px;
252
+ }
253
+ </style>
src/lib/stores/auth.ts ADDED
@@ -0,0 +1,67 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import { writable } from 'svelte/store';
2
+
3
+ export interface UserInfo {
4
+ name?: string;
5
+ preferred_username?: string;
6
+ email?: string;
7
+ }
8
+
9
+ export interface AuthSession {
10
+ accessToken: string;
11
+ userInfo: UserInfo;
12
+ }
13
+
14
+ export interface AuthState {
15
+ isAuthenticated: boolean;
16
+ session: AuthSession | null;
17
+ isLoading: boolean;
18
+ showSignIn: boolean;
19
+ bannerMessage: string;
20
+ userInfo: UserInfo | null;
21
+ }
22
+
23
+ const BANNER_ANON = "⚠️ You are not logged in – anonymous users get only ~60 seconds of zero-GPU time per day. Sign in for higher limits.";
24
+
25
+ function createAuthStore() {
26
+ const { subscribe, set, update } = writable<AuthState>({
27
+ isAuthenticated: false,
28
+ session: null,
29
+ isLoading: true,
30
+ showSignIn: false,
31
+ bannerMessage: "",
32
+ userInfo: null
33
+ });
34
+
35
+ return {
36
+ subscribe,
37
+ setSession: (session: AuthSession | null) => {
38
+ update(state => ({
39
+ ...state,
40
+ isAuthenticated: !!session,
41
+ session,
42
+ isLoading: false,
43
+ showSignIn: !session,
44
+ bannerMessage: session ? "" : BANNER_ANON,
45
+ userInfo: session?.userInfo || null
46
+ }));
47
+ },
48
+ setLoading: (isLoading: boolean) => {
49
+ update(state => ({ ...state, isLoading }));
50
+ },
51
+ setBannerMessage: (message: string) => {
52
+ update(state => ({ ...state, bannerMessage: message }));
53
+ },
54
+ reset: () => {
55
+ set({
56
+ isAuthenticated: false,
57
+ session: null,
58
+ isLoading: false,
59
+ showSignIn: true,
60
+ bannerMessage: BANNER_ANON,
61
+ userInfo: null
62
+ });
63
+ }
64
+ };
65
+ }
66
+
67
+ export const authStore = createAuthStore();
src/lib/types/index.ts ADDED
@@ -0,0 +1,74 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ export interface FluxGenerationParams {
2
+ prompt: string;
3
+ seed: number;
4
+ randomizeSeed: boolean;
5
+ width: number;
6
+ height: number;
7
+ steps: number;
8
+ }
9
+
10
+ export interface FluxGenerationResult {
11
+ imageUrl: string;
12
+ seed: number;
13
+ prompt: string;
14
+ }
15
+
16
+ export interface CaptionParams {
17
+ image: Blob | File;
18
+ captionType: CaptionType;
19
+ captionLength: CaptionLength;
20
+ }
21
+
22
+ export type CaptionType =
23
+ | "Descriptive"
24
+ | "Descriptive (Informal)"
25
+ | "Training Prompt"
26
+ | "MidJourney"
27
+ | "Booru tag list"
28
+ | "Booru-like tag list"
29
+ | "Art Critic"
30
+ | "Product Listing"
31
+ | "Social Media Post";
32
+
33
+ export type CaptionLength =
34
+ | "any"
35
+ | "very short"
36
+ | "short"
37
+ | "medium-length"
38
+ | "long"
39
+ | "very long";
40
+
41
+ export interface CaptionResult {
42
+ caption: string;
43
+ type: CaptionType;
44
+ length: CaptionLength;
45
+ }
46
+
47
+ export interface TextGenerationParams {
48
+ prompt: string;
49
+ maxTokens: number;
50
+ temperature: number;
51
+ topP: number;
52
+ presencePenalty: number;
53
+ countPenalty: number;
54
+ }
55
+
56
+ export interface TextGenerationResult {
57
+ text: string;
58
+ prompt: string;
59
+ }
60
+
61
+ export interface GradioClient {
62
+ predict: (endpoint: string | number, params: any[]) => Promise<{ data: any[] }>;
63
+ }
64
+
65
+ export interface HuggingFaceLibs {
66
+ oauthLoginUrl: (options: { scopes: string[] }) => Promise<string>;
67
+ oauthHandleRedirectIfPresent: () => Promise<any>;
68
+ }
69
+
70
+ export interface GradioLibs {
71
+ Client: {
72
+ connect: (space: string, options?: { hf_token?: string }) => Promise<GradioClient>;
73
+ };
74
+ }
src/vite-env.d.ts CHANGED
@@ -1,2 +1,11 @@
1
  /// <reference types="svelte" />
2
  /// <reference types="vite/client" />
 
 
 
 
 
 
 
 
 
 
1
  /// <reference types="svelte" />
2
  /// <reference types="vite/client" />
3
+
4
+ import type { HuggingFaceLibs, GradioLibs } from './lib/types';
5
+
6
+ declare global {
7
+ interface Window {
8
+ hfAuth: HuggingFaceLibs;
9
+ gradioClient: GradioLibs;
10
+ }
11
+ }
tsconfig.app.json CHANGED
@@ -14,7 +14,12 @@
14
  "allowJs": true,
15
  "checkJs": true,
16
  "isolatedModules": true,
17
- "moduleDetection": "force"
 
 
 
 
 
18
  },
19
  "include": ["src/**/*.ts", "src/**/*.js", "src/**/*.svelte"]
20
  }
 
14
  "allowJs": true,
15
  "checkJs": true,
16
  "isolatedModules": true,
17
+ "moduleDetection": "force",
18
+ "baseUrl": ".",
19
+ "paths": {
20
+ "$lib": ["./src/lib"],
21
+ "$lib/*": ["./src/lib/*"]
22
+ }
23
  },
24
  "include": ["src/**/*.ts", "src/**/*.js", "src/**/*.svelte"]
25
  }
vite.config.ts CHANGED
@@ -1,7 +1,13 @@
1
  import { defineConfig } from 'vite'
2
  import { svelte } from '@sveltejs/vite-plugin-svelte'
 
3
 
4
  // https://vite.dev/config/
5
  export default defineConfig({
6
  plugins: [svelte()],
 
 
 
 
 
7
  })
 
1
  import { defineConfig } from 'vite'
2
  import { svelte } from '@sveltejs/vite-plugin-svelte'
3
+ import { fileURLToPath, URL } from 'url'
4
 
5
  // https://vite.dev/config/
6
  export default defineConfig({
7
  plugins: [svelte()],
8
+ resolve: {
9
+ alias: {
10
+ '$lib': fileURLToPath(new URL('./src/lib', import.meta.url))
11
+ }
12
+ }
13
  })