main
dart 254 lines 7.57 KB
Raw
1 import 'package:flutter/material.dart';
2
3 /// Available KittenTTS model variants downloadable from HuggingFace.
4 ///
5 /// Each variant has a different parameter count and quality trade-off.
6 enum KittenTtsModelVariant {
7 /// 15M parameters, ~56 MB total, high quality.
8 nano,
9
10 /// 15M parameters, ~25 MB total, int8 quantized. Best for most devices.
11 nanoInt8,
12
13 /// 40M parameters, ~41 MB total, higher quality.
14 micro,
15
16 /// 80M parameters, ~80 MB total, best quality.
17 mini;
18
19 String get displayName {
20 switch (this) {
21 case KittenTtsModelVariant.nano:
22 return 'Kitten TTS Nano';
23 case KittenTtsModelVariant.nanoInt8:
24 return 'Kitten TTS Nano (Int8)';
25 case KittenTtsModelVariant.micro:
26 return 'Kitten TTS Micro';
27 case KittenTtsModelVariant.mini:
28 return 'Kitten TTS Mini';
29 }
30 }
31
32 /// Short label shown in badges (e.g. "15M", "80M").
33 String get parameterLabel {
34 switch (this) {
35 case KittenTtsModelVariant.nano:
36 return '15M';
37 case KittenTtsModelVariant.nanoInt8:
38 return '15M';
39 case KittenTtsModelVariant.micro:
40 return '40M';
41 case KittenTtsModelVariant.mini:
42 return '80M';
43 }
44 }
45
46 /// Approximate total size in bytes for all 3 files combined.
47 int get totalSizeBytes {
48 switch (this) {
49 case KittenTtsModelVariant.nano:
50 return 56 * 1024 * 1024;
51 case KittenTtsModelVariant.nanoInt8:
52 return 25 * 1024 * 1024;
53 case KittenTtsModelVariant.micro:
54 return 41 * 1024 * 1024;
55 case KittenTtsModelVariant.mini:
56 return 80 * 1024 * 1024;
57 }
58 }
59
60 String get description {
61 switch (this) {
62 case KittenTtsModelVariant.nano:
63 return 'Balanced quality and size. Good for most devices.';
64 case KittenTtsModelVariant.nanoInt8:
65 return 'Smallest model with excellent quality. Recommended for most devices.';
66 case KittenTtsModelVariant.micro:
67 return 'Higher quality with more parameters. Requires more RAM.';
68 case KittenTtsModelVariant.mini:
69 return 'Highest quality, largest size. Best for high-end devices.';
70 }
71 }
72
73 /// Whether this variant is recommended as the default.
74 bool get isRecommended => this == KittenTtsModelVariant.nanoInt8;
75
76 /// HuggingFace repository ID for this variant.
77 String get huggingFaceRepoId {
78 switch (this) {
79 case KittenTtsModelVariant.nano:
80 return 'palshub/kitten-tts-nano-0.8-fp32';
81 case KittenTtsModelVariant.nanoInt8:
82 return 'palshub/kitten-tts-nano-0.8-int8';
83 case KittenTtsModelVariant.micro:
84 return 'palshub/kitten-tts-micro-0.8';
85 case KittenTtsModelVariant.mini:
86 return 'palshub/kitten-tts-mini-0.8';
87 }
88 }
89
90 /// The ONNX model file name inside the HF repo.
91 String get sourceModelFileName {
92 switch (this) {
93 case KittenTtsModelVariant.nano:
94 return 'kitten_tts_nano_v0_8.onnx';
95 case KittenTtsModelVariant.nanoInt8:
96 return 'kitten_tts_nano_v0_8.onnx';
97 case KittenTtsModelVariant.micro:
98 return 'kitten_tts_micro_v0_8.onnx';
99 case KittenTtsModelVariant.mini:
100 return 'kitten_tts_mini_v0_8.onnx';
101 }
102 }
103
104 /// sherpa-onnx bundle directory for this variant.
105 String get bundleDirName {
106 switch (this) {
107 case KittenTtsModelVariant.nano:
108 return 'kitten-nano-en-v0_1-fp16';
109 case KittenTtsModelVariant.nanoInt8:
110 return 'kitten-nano-en-v0_1-fp16';
111 case KittenTtsModelVariant.micro:
112 return 'kitten-nano-en-v0_2-fp16';
113 case KittenTtsModelVariant.mini:
114 return 'kitten-mini-en-v0_1-fp16';
115 }
116 }
117
118 String get tarballUrl {
119 switch (this) {
120 case KittenTtsModelVariant.nano:
121 case KittenTtsModelVariant.nanoInt8:
122 return 'https://github.com/k2-fsa/sherpa-onnx/releases/download/tts-models/kitten-nano-en-v0_1-fp16.tar.bz2';
123 case KittenTtsModelVariant.micro:
124 return 'https://github.com/k2-fsa/sherpa-onnx/releases/download/tts-models/kitten-nano-en-v0_2-fp16.tar.bz2';
125 case KittenTtsModelVariant.mini:
126 return 'https://github.com/k2-fsa/sherpa-onnx/releases/download/tts-models/kitten-mini-en-v0_1-fp16.tar.bz2';
127 }
128 }
129
130 String get modelFileName => 'model.fp16.onnx';
131 String get voicesFileName => 'voices.bin';
132 String get tokensFileName => 'tokens.txt';
133 String get dataDirName => 'espeak-ng-data';
134
135 /// The 3 files required for this variant.
136 List<KittenTtsModelFile> get files {
137 return [
138 KittenTtsModelFile(
139 fileName: 'config.json',
140 downloadUrl:
141 'https://huggingface.co/$huggingFaceRepoId/resolve/main/config.json',
142 sizeBytes: 2 * 1024,
143 ),
144 KittenTtsModelFile(
145 fileName: sourceModelFileName,
146 downloadUrl:
147 'https://huggingface.co/$huggingFaceRepoId/resolve/main/$sourceModelFileName',
148 sizeBytes: _modelFileSizeBytes,
149 ),
150 KittenTtsModelFile(
151 fileName: 'voices.npz',
152 downloadUrl:
153 'https://huggingface.co/$huggingFaceRepoId/resolve/main/voices.npz',
154 sizeBytes: 3 * 1024 * 1024,
155 ),
156 ];
157 }
158
159 int get _modelFileSizeBytes {
160 switch (this) {
161 case KittenTtsModelVariant.nano:
162 return 52 * 1024 * 1024;
163 case KittenTtsModelVariant.nanoInt8:
164 return 21 * 1024 * 1024;
165 case KittenTtsModelVariant.micro:
166 return 37 * 1024 * 1024;
167 case KittenTtsModelVariant.mini:
168 return 76 * 1024 * 1024;
169 }
170 }
171
172 /// Storage directory name for this variant.
173 String get dirName => name;
174 }
175
176 /// Metadata for a single file within a KittenTTS model variant.
177 @immutable
178 class KittenTtsModelFile {
179 final String fileName;
180 final String downloadUrl;
181 final int sizeBytes;
182
183 const KittenTtsModelFile({
184 required this.fileName,
185 required this.downloadUrl,
186 required this.sizeBytes,
187 });
188 }
189
190 /// A fully-specified KittenTTS model with its variant and files.
191 @immutable
192 class KittenTtsModel {
193 final KittenTtsModelVariant variant;
194 final List<KittenTtsModelFile> files;
195 final int totalSizeBytes;
196
197 const KittenTtsModel({
198 required this.variant,
199 required this.files,
200 required this.totalSizeBytes,
201 });
202
203 static final List<KittenTtsModel> allModels = [
204 KittenTtsModel(
205 variant: KittenTtsModelVariant.nano,
206 files: KittenTtsModelVariant.nano.files,
207 totalSizeBytes: KittenTtsModelVariant.nano.totalSizeBytes,
208 ),
209 KittenTtsModel(
210 variant: KittenTtsModelVariant.nanoInt8,
211 files: KittenTtsModelVariant.nanoInt8.files,
212 totalSizeBytes: KittenTtsModelVariant.nanoInt8.totalSizeBytes,
213 ),
214 KittenTtsModel(
215 variant: KittenTtsModelVariant.micro,
216 files: KittenTtsModelVariant.micro.files,
217 totalSizeBytes: KittenTtsModelVariant.micro.totalSizeBytes,
218 ),
219 KittenTtsModel(
220 variant: KittenTtsModelVariant.mini,
221 files: KittenTtsModelVariant.mini.files,
222 totalSizeBytes: KittenTtsModelVariant.mini.totalSizeBytes,
223 ),
224 ];
225
226 String get displayName => variant.displayName;
227
228 String get parameterLabel => variant.parameterLabel;
229
230 String get description => variant.description;
231
232 bool get isRecommended => variant.isRecommended;
233 }
234
235 /// Progress for downloading a single file of a model variant.
236 @immutable
237 class KittenTtsFileProgress {
238 final String fileName;
239 final KittenTtsModelVariant variant;
240 final int receivedBytes;
241 final int totalBytes;
242 final bool isComplete;
243
244 const KittenTtsFileProgress({
245 required this.fileName,
246 required this.variant,
247 this.receivedBytes = 0,
248 this.totalBytes = 0,
249 this.isComplete = false,
250 });
251
252 double get fraction =>
253 totalBytes > 0 ? (receivedBytes / totalBytes).clamp(0.0, 1.0) : 0.0;
254 }