KGSS commited on
Commit
79175ca
·
verified ·
1 Parent(s): 5a6bdfd

Sad-tts-v1: Vocence OmniVoice miner + weights

Browse files
.gitattributes CHANGED
@@ -33,3 +33,4 @@ saved_model/**/* filter=lfs diff=lfs merge=lfs -text
33
  *.zip filter=lfs diff=lfs merge=lfs -text
34
  *.zst filter=lfs diff=lfs merge=lfs -text
35
  *tfevents* filter=lfs diff=lfs merge=lfs -text
 
 
33
  *.zip filter=lfs diff=lfs merge=lfs -text
34
  *.zst filter=lfs diff=lfs merge=lfs -text
35
  *tfevents* filter=lfs diff=lfs merge=lfs -text
36
+ tokenizer.json filter=lfs diff=lfs merge=lfs -text
.gitignore ADDED
@@ -0,0 +1,9 @@
 
 
 
 
 
 
 
 
 
 
1
+ .cache/
2
+ __pycache__/
3
+ *.pyc
4
+ *.bak
5
+ *.bak-*
6
+
7
+ # Large checkpoints — add from https://huggingface.co/k2-fsa/OmniVoice (or your fork) before Hub push
8
+ /model.safetensors
9
+ /audio_tokenizer/model.safetensors
README.md ADDED
@@ -0,0 +1,58 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ ---
2
+ license: apache-2.0
3
+ pipeline_tag: text-to-speech
4
+ language:
5
+ - en
6
+ - zh
7
+ - multilingual
8
+ tags:
9
+ - vocence
10
+ - bittensor
11
+ - prompt-tts
12
+ - omnivoice
13
+ - sad-tts-v1
14
+ ---
15
+
16
+ # Sad-tts-v1 (Vocence PromptTTS)
17
+
18
+ **Sad-tts-v1** is a **[Vocence SN78](https://github.com/Vocence-bt/vocence)** miner bundle (OmniVoice backbone). Hub: **`KGSS/Sad-tts-v1`** — natural-language **instruction** plus **text** in, **mono WAV** out via [`miner.py`](./miner.py).
19
+
20
+ Base weights align with **[k2-fsa/OmniVoice](https://huggingface.co/k2-fsa/OmniVoice)** · Apache-2.0 · [`omnivoice`](https://pypi.org/project/omnivoice/) runtime. Pin commits in `miner_deploy_sad_tts_v1.py` and [VOCENCE_HF.md](./VOCENCE_HF.md).
21
+
22
+ ## Vocence contract
23
+
24
+ | Method | Role |
25
+ |--------|------|
26
+ | `Miner(path_hf_repo)` | Load checkpoint from a directory (or HF snapshot) containing `config.json`, `model.safetensors`, tokenizers, and `audio_tokenizer/`. |
27
+ | `warmup()` | One short synthesis to prime the stack. |
28
+ | `generate_wav(instruction, text)` | Returns `(float32 mono ndarray, sample_rate)`; typically **24 kHz**. |
29
+
30
+ Validators send **free-form** `instruction`. OmniVoice **voice-design** only accepts [whitelisted attribute tags](https://huggingface.co/k2-fsa/OmniVoice); **`miner.py` maps** keywords (gender, age, pitch, whisper, accent, Chinese dialects) to those tags. Unmatched instructions fall back to `runtime.default_instruct` in [`vocence_config.yaml`](./vocence_config.yaml).
31
+
32
+ ## Repo layout
33
+
34
+ | File | Role |
35
+ |------|------|
36
+ | `miner.py` | Engine + NL → `instruct` mapping |
37
+ | `chute_config.yml` | Chutes image (PyTorch cu128 + `omnivoice`) |
38
+ | `vocence_config.yaml` | Limits, default voice tags, `num_step` / `guidance_scale` |
39
+ | Weight files | Shipped in this Hub repo (`model.safetensors`, `audio_tokenizer/`); see [VOCENCE_HF.md](./VOCENCE_HF.md) |
40
+
41
+ ## Local quick check (GPU)
42
+
43
+ ```bash
44
+ pip install omnivoice torch torchaudio # match CUDA index from chute_config.yml
45
+ # Copy snapshot: huggingface-cli download k2-fsa/OmniVoice --local-dir ./OmniVoice_weights
46
+ python -c "
47
+ from pathlib import Path
48
+ from miner import Miner
49
+ m = Miner(Path('./OmniVoice_weights'))
50
+ m.warmup()
51
+ w, sr = m.generate_wav('Calm female voice, British accent.', 'Hello from OmniVoice on Vocence.')
52
+ print(w.shape, sr)
53
+ "
54
+ ```
55
+
56
+ ## License
57
+
58
+ **Apache-2.0** for this packaging layout and miner glue; **OmniVoice** weights and upstream code remain under their stated licenses on the [model card](https://huggingface.co/k2-fsa/OmniVoice).
VOCENCE_HF.md ADDED
@@ -0,0 +1,21 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ # Publishing **Sad-tts-v1** (`KGSS/Sad-tts-v1`)
2
+
3
+ 1. **Weights** — Full OmniVoice-style snapshot (main `model.safetensors` + `audio_tokenizer/`). Upstream reference: **[k2-fsa/OmniVoice](https://huggingface.co/k2-fsa/OmniVoice)**.
4
+
5
+ - `model.safetensors`
6
+ - `config.json`, `tokenizer.json`, `tokenizer_config.json`, `chat_template.jinja`, etc.
7
+ - `audio_tokenizer/` (directory with its `model.safetensors` and configs)
8
+
9
+ You can sync without Git LFS clutter locally:
10
+
11
+ ```bash
12
+ huggingface-cli download k2-fsa/OmniVoice --local-dir ./mysnap
13
+ cp -r miner.py chute_config.yml vocence_config.yaml README.md ./mysnap/
14
+ # then push ./mysnap to your Hub repo
15
+ ```
16
+
17
+ 2. **Revision** — Pin the commit SHA in your deploy script as `VOCENCE_REVISION` and use the same value in `vocence miner commit --model-revision`.
18
+
19
+ 3. **`chute_config.yml` on SN78** — Subnet Chutes integrations require TEE + supported GPU class (see your working `rhy-TTS-v1` deploy); this folder’s `chute_config.yml` matches that pattern.
20
+
21
+ 4. **Safetensors metadata** — OmniVoice checkpoints from the official Hub use standard PyTorch safetensors metadata; no `pt-sn78v`-style patching should be needed (unlike some custom Qwen repacks).
audio_tokenizer/.gitattributes ADDED
@@ -0,0 +1,35 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ *.7z filter=lfs diff=lfs merge=lfs -text
2
+ *.arrow filter=lfs diff=lfs merge=lfs -text
3
+ *.bin filter=lfs diff=lfs merge=lfs -text
4
+ *.bz2 filter=lfs diff=lfs merge=lfs -text
5
+ *.ckpt filter=lfs diff=lfs merge=lfs -text
6
+ *.ftz filter=lfs diff=lfs merge=lfs -text
7
+ *.gz filter=lfs diff=lfs merge=lfs -text
8
+ *.h5 filter=lfs diff=lfs merge=lfs -text
9
+ *.joblib filter=lfs diff=lfs merge=lfs -text
10
+ *.lfs.* filter=lfs diff=lfs merge=lfs -text
11
+ *.mlmodel filter=lfs diff=lfs merge=lfs -text
12
+ *.model filter=lfs diff=lfs merge=lfs -text
13
+ *.msgpack filter=lfs diff=lfs merge=lfs -text
14
+ *.npy filter=lfs diff=lfs merge=lfs -text
15
+ *.npz filter=lfs diff=lfs merge=lfs -text
16
+ *.onnx filter=lfs diff=lfs merge=lfs -text
17
+ *.ot filter=lfs diff=lfs merge=lfs -text
18
+ *.parquet filter=lfs diff=lfs merge=lfs -text
19
+ *.pb filter=lfs diff=lfs merge=lfs -text
20
+ *.pickle filter=lfs diff=lfs merge=lfs -text
21
+ *.pkl filter=lfs diff=lfs merge=lfs -text
22
+ *.pt filter=lfs diff=lfs merge=lfs -text
23
+ *.pth filter=lfs diff=lfs merge=lfs -text
24
+ *.rar filter=lfs diff=lfs merge=lfs -text
25
+ *.safetensors filter=lfs diff=lfs merge=lfs -text
26
+ saved_model/**/* filter=lfs diff=lfs merge=lfs -text
27
+ *.tar.* filter=lfs diff=lfs merge=lfs -text
28
+ *.tar filter=lfs diff=lfs merge=lfs -text
29
+ *.tflite filter=lfs diff=lfs merge=lfs -text
30
+ *.tgz filter=lfs diff=lfs merge=lfs -text
31
+ *.wasm filter=lfs diff=lfs merge=lfs -text
32
+ *.xz filter=lfs diff=lfs merge=lfs -text
33
+ *.zip filter=lfs diff=lfs merge=lfs -text
34
+ *.zst filter=lfs diff=lfs merge=lfs -text
35
+ *tfevents* filter=lfs diff=lfs merge=lfs -text
audio_tokenizer/LICENSE ADDED
@@ -0,0 +1,43 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ BOSON HIGGS AUDIO 2 COMMUNITY LICENSE AGREEMENT
2
+
3
+ Boson Higgs Audio 2 Version Release Date: June 20, 2025
4
+
5
+ This License Agreement (the “Agreement”) is entered into by and between Licensee (as defined below) and Boson AI USA, Inc. (“Boson”) and is based upon the Meta Llama 3 Community License Agreement as of April 18, 2024 (the “Meta License Agreement”), which can be found at https://llama.meta.com/llama3/license/. The terms and conditions of the Meta License Agreement are hereby incorporated herein by reference and Unless stated otherwise below, its terms apply. The Higgs Audio 2 model developed by Boson AI USA, Inc. (“Higgs Materials”) is an audio model derived from Meta Llama 3 software and algorithms.
6
+
7
+ “Agreement” means the terms and conditions for use, reproduction, distribution and modification of the Higgs Materials set forth herein and the Meta License Agreement.
8
+
9
+ “Licensee” or “you” means you, or your employer or any other person or entity (if you are entering into this Agreement on such person or entity’s behalf), of the age required under applicable laws, rules or regulations to provide legal consent and that has legal authority to bind your employer or such other person or entity if you are entering into this Agreement on their behalf.
10
+
11
+ “Higgs Audio 2” means the foundational large audio language models and software and algorithms, including machine-learning model code, trained model weights, inference-enabling code, training-enabling code, fine-tuning enabling code and other elements of the foregoing developed by Boson AI distributed at https://github.com/boson-ai/boson-multimodal or otherwise.
12
+ “Higgs Materials” means, collectively, Boson’s proprietary modification of Meta Llama 3 and Documentation (and any portion thereof) made available under this Agreement.
13
+
14
+ “Boson” or “we” means Boson AI USA, Inc.
15
+
16
+ By clicking “I Accept” below or by using or distributing any portion or element of the Higgs Materials, you agree to be bound by this Agreement.
17
+
18
+ 1. License Rights and Redistribution.
19
+ a. Grant of Rights. You are granted a non-exclusive, worldwide, non-transferable and royalty-free limited license under Boson’s intellectual property or other rights owned by Boson embodied in the Higgs Materials to use, reproduce, distribute, copy, create derivative works of, and make modifications to the Higgs Materials.
20
+ b. Redistribution and Use.
21
+ i. If you distribute or make available the Higgs Materials (or any derivative works thereof), or a product or service that uses any of them, including another AI model, you shall (A) provide a copy of this Agreement and the of Meta License ’s Llama 3 agreement with any such Higgs Materials; and (B) prominently display “Built with Higgs Materials licensed from Boson AI USA, Inc., Copyright Boson AI USA, Inc., All Rights Reserved and Meta Llama 3 licensed under the Meta Llama 3 Community License, Copyright Meta Platforms, Inc., All Right Reserved". based on Meta Llama 3” on a related website, user interface, blogpost, about page, or product documentation. If you use the Higgs Materials to create, modify, enhance, train, fine tune, or otherwise improve an AI model or similar software, which is distributed or made available, you shall also include “Higgs Audio 2” at the beginning of any such AI model or software name.
22
+ ii. Even if you receive Higgs Materials, or any modifications, enhancements or derivative works thereof, from a Licensee as part of an integrated end user product, then Section 2 of this Agreement will apply to you.
23
+ iii. You must retain in all copies of the Llama Materials that you distribute and as set forth above, include the following attribution notice within a “Notice” text file distributed as a part of such copies:
24
+ “Meta Llama 3 is licensed under the Meta Llama 3 Community License, Copyright © Meta Platforms, Inc. All Rights Reserved.”
25
+ “Boson Higgs Audio 2 is licensed under the Boson Community License, Copyright © Boson AI USA, Inc. All Rights Reserved.”
26
+ iv. Your use of the Higgs Materials must comply with applicable laws and regulations (including trade compliance laws and regulations) and adhere to the Acceptable Use Policy for the Llama Materials (available at https://llama.meta.com/llama3/use-policy), which is hereby incorporated by reference into this Agreement.
27
+ v. You will not use the Higgs Materials or any output or results of the Higgs Materials to improve any other large language model (excluding Boson Higgs Audio 2 or derivative works thereof).
28
+ vi. You hereby acknowledge that Boson is the owner of the Higgs Materials and under no circumstance shall you bring any legal action, claim, charge, demand challenging such ownership rights of Boson.
29
+
30
+ 2. Additional Commercial Terms. If the annual active users of the products or services made available by or for Licensee, or Licensee’s affiliates, is greater than 100,000 annual active users in the preceding calendar year, you must request an expanded license from Boson AI, which Boson AI may grant to you in its sole discretion, and you are not authorized to exercise any of the rights under this Agreement unless or until Boson AI otherwise expressly grants you such rights.
31
+
32
+ 3. Disclaimer of Warranty. UNLESS REQUIRED BY APPLICABLE LAW, THE Higgs Materials AND ANY OUTPUT AND RESULTS THEREFROM ARE PROVIDED ON AN “AS IS” BASIS, WITH ALL FAULTS, WITHOUT WARRANTIES OF ANY KIND EXPRESS, IMPLIED, BASED UPON CUSTOM AND USAGE OR COURSE OF DEALING, AND BOSON AI DISCLAIMS ALL WARRANTIES OF ANY KIND, BOTH EXPRESS AND IMPLIED, INCLUDING, WITHOUT LIMITATION, ANY WARRANTIES OF TITLE, NON-INFRINGEMENT, MERCHANTABILITY, OR FITNESS FOR A PARTICULAR PURPOSE. YOU ARE SOLELY RESPONSIBLE FOR DETERMINING THE APPROPRIATENESS OF USING OR REDISTRIBUTING THE HIGGS MATERIALS AND ASSUME ANY AND ALL RISKS ASSOCIATED WITH YOUR USE OF THE HIGGS MATERIALS AND ANY OUTPUT AND RESULTS.
33
+
34
+ 4. Limitation of Liability. IN NO EVENT WILL BOSON AI OR ITS AFFILIATES BE LIABLE UNDER ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, TORT, NEGLIGENCE, PRODUCTS LIABILITY, OR OTHERWISE, ARISING OUT OF THIS AGREEMENT, FOR ANY LOST PROFITS OR ANY INDIRECT, SPECIAL, CONSEQUENTIAL, INCIDENTAL, EXEMPLARY OR PUNITIVE DAMAGES, EVEN IF BOSON, META OR ITS AFFILIATES HAVE BEEN ADVISED OF THE POSSIBILITY OF ANY OF THE FOREGOING.
35
+
36
+ 5. Intellectual Property.
37
+ a. No trademark licenses are granted under this Agreement, or in connection with the Higgs Materials., nNeither Boson nor Licensee may use any name or mark owned by, or associated with, the other party hereto or any of its affiliates, except as required for reasonable and customary use in describing and redistributing the Higgs Materials or as set forth in this Section 5(a). Boson hereby grants you a license to use “Higgs Audio 2” (the “Mark”) solely as required to comply with the last sentence of Section 1.b.i. All goodwill arising out of your use of the Mark will inure to the benefit of Meta and Boson AI.
38
+ b. Subject to Boson’s ownership of the Higgs Materials and derivatives made by or for Boson AI, with respect to any derivative works and modifications of the Higgs Materials that are made by you, as between you and Boson AI, you are and will be the owner of such derivative works and modifications.
39
+ c. If you institute litigation or other proceedings against Boson AI, Meta or any entity (including a cross-claim or counterclaim in a lawsuit) alleging that the Higgs Materials or Boson Higgs Audio 2 outputs or results, or any portion thereof any of the foregoing, constitutes infringement of the intellectual property or other rights owned or licensable by you, then any licenses granted to you hereunder this Agreement shall immediately terminate as of the date such litigation or claim is filed or instituted. You will indemnify and hold harmless Boson AI from and against any claim, charge, demand, cause of action by any third party arising out of or related to your use or distribution of the Higgs Materials.
40
+
41
+ 6. Term and Termination. The term of this Agreement will commence upon your acceptance of this Agreement or access to the Higgs Materials and will continue in full force and effect until terminated in accordance with the terms and conditions herein. Boson AI may terminate this Agreement if you are in breach of any term or condition of this Agreement by providing you with written notice. Upon your receipt of written notice of termination of this Agreement, you shall delete the Higgs Materials from any computer, server or IT device and cease use of the Higgs Materials in all respects. Sections 1(b)(vi), 3, 4 and 7 shall survive the termination of this Agreement.
42
+
43
+ 7. Governing Law and Jurisdiction. This Agreement will be governed and construed under the laws of the State of California without regard to choice of law principles, and the UN Convention on Contracts for the International Sale of Goods does not apply to this Agreement. The federal courts in the Northern District of California and the state courts in Santa Clara County, California shall have exclusive jurisdiction of any dispute arising out of this Agreement.
audio_tokenizer/README.md ADDED
@@ -0,0 +1,199 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ ---
2
+ library_name: transformers
3
+ tags: []
4
+ ---
5
+
6
+ # Model Card for Model ID
7
+
8
+ <!-- Provide a quick summary of what the model is/does. -->
9
+
10
+
11
+
12
+ ## Model Details
13
+
14
+ ### Model Description
15
+
16
+ <!-- Provide a longer summary of what this model is. -->
17
+
18
+ This is the model card of a 🤗 transformers model that has been pushed on the Hub. This model card has been automatically generated.
19
+
20
+ - **Developed by:** [More Information Needed]
21
+ - **Funded by [optional]:** [More Information Needed]
22
+ - **Shared by [optional]:** [More Information Needed]
23
+ - **Model type:** [More Information Needed]
24
+ - **Language(s) (NLP):** [More Information Needed]
25
+ - **License:** [More Information Needed]
26
+ - **Finetuned from model [optional]:** [More Information Needed]
27
+
28
+ ### Model Sources [optional]
29
+
30
+ <!-- Provide the basic links for the model. -->
31
+
32
+ - **Repository:** [More Information Needed]
33
+ - **Paper [optional]:** [More Information Needed]
34
+ - **Demo [optional]:** [More Information Needed]
35
+
36
+ ## Uses
37
+
38
+ <!-- Address questions around how the model is intended to be used, including the foreseeable users of the model and those affected by the model. -->
39
+
40
+ ### Direct Use
41
+
42
+ <!-- This section is for the model use without fine-tuning or plugging into a larger ecosystem/app. -->
43
+
44
+ [More Information Needed]
45
+
46
+ ### Downstream Use [optional]
47
+
48
+ <!-- This section is for the model use when fine-tuned for a task, or when plugged into a larger ecosystem/app -->
49
+
50
+ [More Information Needed]
51
+
52
+ ### Out-of-Scope Use
53
+
54
+ <!-- This section addresses misuse, malicious use, and uses that the model will not work well for. -->
55
+
56
+ [More Information Needed]
57
+
58
+ ## Bias, Risks, and Limitations
59
+
60
+ <!-- This section is meant to convey both technical and sociotechnical limitations. -->
61
+
62
+ [More Information Needed]
63
+
64
+ ### Recommendations
65
+
66
+ <!-- This section is meant to convey recommendations with respect to the bias, risk, and technical limitations. -->
67
+
68
+ Users (both direct and downstream) should be made aware of the risks, biases and limitations of the model. More information needed for further recommendations.
69
+
70
+ ## How to Get Started with the Model
71
+
72
+ Use the code below to get started with the model.
73
+
74
+ [More Information Needed]
75
+
76
+ ## Training Details
77
+
78
+ ### Training Data
79
+
80
+ <!-- This should link to a Dataset Card, perhaps with a short stub of information on what the training data is all about as well as documentation related to data pre-processing or additional filtering. -->
81
+
82
+ [More Information Needed]
83
+
84
+ ### Training Procedure
85
+
86
+ <!-- This relates heavily to the Technical Specifications. Content here should link to that section when it is relevant to the training procedure. -->
87
+
88
+ #### Preprocessing [optional]
89
+
90
+ [More Information Needed]
91
+
92
+
93
+ #### Training Hyperparameters
94
+
95
+ - **Training regime:** [More Information Needed] <!--fp32, fp16 mixed precision, bf16 mixed precision, bf16 non-mixed precision, fp16 non-mixed precision, fp8 mixed precision -->
96
+
97
+ #### Speeds, Sizes, Times [optional]
98
+
99
+ <!-- This section provides information about throughput, start/end time, checkpoint size if relevant, etc. -->
100
+
101
+ [More Information Needed]
102
+
103
+ ## Evaluation
104
+
105
+ <!-- This section describes the evaluation protocols and provides the results. -->
106
+
107
+ ### Testing Data, Factors & Metrics
108
+
109
+ #### Testing Data
110
+
111
+ <!-- This should link to a Dataset Card if possible. -->
112
+
113
+ [More Information Needed]
114
+
115
+ #### Factors
116
+
117
+ <!-- These are the things the evaluation is disaggregating by, e.g., subpopulations or domains. -->
118
+
119
+ [More Information Needed]
120
+
121
+ #### Metrics
122
+
123
+ <!-- These are the evaluation metrics being used, ideally with a description of why. -->
124
+
125
+ [More Information Needed]
126
+
127
+ ### Results
128
+
129
+ [More Information Needed]
130
+
131
+ #### Summary
132
+
133
+
134
+
135
+ ## Model Examination [optional]
136
+
137
+ <!-- Relevant interpretability work for the model goes here -->
138
+
139
+ [More Information Needed]
140
+
141
+ ## Environmental Impact
142
+
143
+ <!-- Total emissions (in grams of CO2eq) and additional considerations, such as electricity usage, go here. Edit the suggested text below accordingly -->
144
+
145
+ Carbon emissions can be estimated using the [Machine Learning Impact calculator](https://mlco2.github.io/impact#compute) presented in [Lacoste et al. (2019)](https://arxiv.org/abs/1910.09700).
146
+
147
+ - **Hardware Type:** [More Information Needed]
148
+ - **Hours used:** [More Information Needed]
149
+ - **Cloud Provider:** [More Information Needed]
150
+ - **Compute Region:** [More Information Needed]
151
+ - **Carbon Emitted:** [More Information Needed]
152
+
153
+ ## Technical Specifications [optional]
154
+
155
+ ### Model Architecture and Objective
156
+
157
+ [More Information Needed]
158
+
159
+ ### Compute Infrastructure
160
+
161
+ [More Information Needed]
162
+
163
+ #### Hardware
164
+
165
+ [More Information Needed]
166
+
167
+ #### Software
168
+
169
+ [More Information Needed]
170
+
171
+ ## Citation [optional]
172
+
173
+ <!-- If there is a paper or blog post introducing the model, the APA and Bibtex information for that should go in this section. -->
174
+
175
+ **BibTeX:**
176
+
177
+ [More Information Needed]
178
+
179
+ **APA:**
180
+
181
+ [More Information Needed]
182
+
183
+ ## Glossary [optional]
184
+
185
+ <!-- If relevant, include terms and calculations in this section that can help readers understand the model or model card. -->
186
+
187
+ [More Information Needed]
188
+
189
+ ## More Information [optional]
190
+
191
+ [More Information Needed]
192
+
193
+ ## Model Card Authors [optional]
194
+
195
+ [More Information Needed]
196
+
197
+ ## Model Card Contact
198
+
199
+ [More Information Needed]
audio_tokenizer/config.json ADDED
@@ -0,0 +1,129 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ {
2
+ "acoustic_model_config": {
3
+ "codebook_dim": 8,
4
+ "codebook_loss_weight": 1.0,
5
+ "codebook_size": 1024,
6
+ "commitment_loss_weight": 0.25,
7
+ "decoder_hidden_size": 1024,
8
+ "downsampling_ratios": [
9
+ 8,
10
+ 5,
11
+ 4,
12
+ 2,
13
+ 3
14
+ ],
15
+ "encoder_hidden_size": 64,
16
+ "hidden_size": 256,
17
+ "hop_length": 960,
18
+ "model_type": "dac",
19
+ "n_codebooks": 9,
20
+ "quantizer_dropout": 0,
21
+ "sampling_rate": 16000,
22
+ "upsampling_ratios": [
23
+ 8,
24
+ 5,
25
+ 4,
26
+ 2,
27
+ 3
28
+ ]
29
+ },
30
+ "architectures": [
31
+ "HiggsAudioV2TokenizerModel"
32
+ ],
33
+ "block_dilations": [
34
+ 1,
35
+ 1
36
+ ],
37
+ "channel_ratios": [
38
+ 1,
39
+ 1
40
+ ],
41
+ "codebook_dim": 64,
42
+ "codebook_size": 1024,
43
+ "downsample_factor": 320,
44
+ "dtype": "float32",
45
+ "initializer_range": 0.02,
46
+ "kernel_size": 3,
47
+ "model_type": "higgs_audio_v2_tokenizer",
48
+ "sample_rate": 24000,
49
+ "semantic_model_config": {
50
+ "activation_dropout": 0.1,
51
+ "apply_spec_augment": true,
52
+ "attention_dropout": 0.1,
53
+ "bos_token_id": 1,
54
+ "classifier_proj_size": 256,
55
+ "conv_bias": false,
56
+ "conv_dim": [
57
+ 512,
58
+ 512,
59
+ 512,
60
+ 512,
61
+ 512,
62
+ 512,
63
+ 512
64
+ ],
65
+ "conv_kernel": [
66
+ 10,
67
+ 3,
68
+ 3,
69
+ 3,
70
+ 3,
71
+ 2,
72
+ 2
73
+ ],
74
+ "conv_pos_batch_norm": false,
75
+ "conv_stride": [
76
+ 5,
77
+ 2,
78
+ 2,
79
+ 2,
80
+ 2,
81
+ 2,
82
+ 2
83
+ ],
84
+ "ctc_loss_reduction": "sum",
85
+ "ctc_zero_infinity": false,
86
+ "do_stable_layer_norm": false,
87
+ "eos_token_id": 2,
88
+ "feat_extract_activation": "gelu",
89
+ "feat_extract_norm": "group",
90
+ "feat_proj_dropout": 0.0,
91
+ "feat_proj_layer_norm": true,
92
+ "final_dropout": 0.1,
93
+ "hidden_act": "gelu",
94
+ "hidden_dropout": 0.1,
95
+ "hidden_size": 768,
96
+ "initializer_range": 0.02,
97
+ "intermediate_size": 3072,
98
+ "layer_norm_eps": 1e-05,
99
+ "layerdrop": 0.1,
100
+ "mask_feature_length": 10,
101
+ "mask_feature_min_masks": 0,
102
+ "mask_feature_prob": 0.0,
103
+ "mask_time_length": 10,
104
+ "mask_time_min_masks": 2,
105
+ "mask_time_prob": 0.0,
106
+ "model_type": "hubert",
107
+ "num_attention_heads": 12,
108
+ "num_conv_pos_embedding_groups": 16,
109
+ "num_conv_pos_embeddings": 128,
110
+ "num_feat_extract_layers": 7,
111
+ "num_hidden_layers": 12,
112
+ "pad_token_id": 0,
113
+ "use_weighted_layer_sum": false,
114
+ "vocab_size": 32
115
+ },
116
+ "semantic_sample_rate": 16000,
117
+ "strides": [
118
+ 1,
119
+ 1
120
+ ],
121
+ "target_bandwidths": [
122
+ 0.5,
123
+ 1,
124
+ 1.5,
125
+ 2
126
+ ],
127
+ "transformers_version": "5.3.0.dev0",
128
+ "unit_kernel_size": 3
129
+ }
audio_tokenizer/preprocessor_config.json ADDED
@@ -0,0 +1,9 @@
 
 
 
 
 
 
 
 
 
 
1
+ {
2
+ "feature_extractor_type": "DacFeatureExtractor",
3
+ "feature_size": 1,
4
+ "hop_length": 960,
5
+ "padding_side": "right",
6
+ "padding_value": 0.0,
7
+ "return_attention_mask": true,
8
+ "sampling_rate": 24000
9
+ }
chat_template.jinja ADDED
@@ -0,0 +1,89 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ {%- if tools %}
2
+ {{- '<|im_start|>system\n' }}
3
+ {%- if messages[0].role == 'system' %}
4
+ {{- messages[0].content + '\n\n' }}
5
+ {%- endif %}
6
+ {{- "# Tools\n\nYou may call one or more functions to assist with the user query.\n\nYou are provided with function signatures within <tools></tools> XML tags:\n<tools>" }}
7
+ {%- for tool in tools %}
8
+ {{- "\n" }}
9
+ {{- tool | tojson }}
10
+ {%- endfor %}
11
+ {{- "\n</tools>\n\nFor each function call, return a json object with function name and arguments within <tool_call></tool_call> XML tags:\n<tool_call>\n{\"name\": <function-name>, \"arguments\": <args-json-object>}\n</tool_call><|im_end|>\n" }}
12
+ {%- else %}
13
+ {%- if messages[0].role == 'system' %}
14
+ {{- '<|im_start|>system\n' + messages[0].content + '<|im_end|>\n' }}
15
+ {%- endif %}
16
+ {%- endif %}
17
+ {%- set ns = namespace(multi_step_tool=true, last_query_index=messages|length - 1) %}
18
+ {%- for message in messages[::-1] %}
19
+ {%- set index = (messages|length - 1) - loop.index0 %}
20
+ {%- if ns.multi_step_tool and message.role == "user" and message.content is string and not(message.content.startswith('<tool_response>') and message.content.endswith('</tool_response>')) %}
21
+ {%- set ns.multi_step_tool = false %}
22
+ {%- set ns.last_query_index = index %}
23
+ {%- endif %}
24
+ {%- endfor %}
25
+ {%- for message in messages %}
26
+ {%- if message.content is string %}
27
+ {%- set content = message.content %}
28
+ {%- else %}
29
+ {%- set content = '' %}
30
+ {%- endif %}
31
+ {%- if (message.role == "user") or (message.role == "system" and not loop.first) %}
32
+ {{- '<|im_start|>' + message.role + '\n' + content + '<|im_end|>' + '\n' }}
33
+ {%- elif message.role == "assistant" %}
34
+ {%- set reasoning_content = '' %}
35
+ {%- if message.reasoning_content is string %}
36
+ {%- set reasoning_content = message.reasoning_content %}
37
+ {%- else %}
38
+ {%- if '</think>' in content %}
39
+ {%- set reasoning_content = content.split('</think>')[0].rstrip('\n').split('<think>')[-1].lstrip('\n') %}
40
+ {%- set content = content.split('</think>')[-1].lstrip('\n') %}
41
+ {%- endif %}
42
+ {%- endif %}
43
+ {%- if loop.index0 > ns.last_query_index %}
44
+ {%- if loop.last or (not loop.last and reasoning_content) %}
45
+ {{- '<|im_start|>' + message.role + '\n<think>\n' + reasoning_content.strip('\n') + '\n</think>\n\n' + content.lstrip('\n') }}
46
+ {%- else %}
47
+ {{- '<|im_start|>' + message.role + '\n' + content }}
48
+ {%- endif %}
49
+ {%- else %}
50
+ {{- '<|im_start|>' + message.role + '\n' + content }}
51
+ {%- endif %}
52
+ {%- if message.tool_calls %}
53
+ {%- for tool_call in message.tool_calls %}
54
+ {%- if (loop.first and content) or (not loop.first) %}
55
+ {{- '\n' }}
56
+ {%- endif %}
57
+ {%- if tool_call.function %}
58
+ {%- set tool_call = tool_call.function %}
59
+ {%- endif %}
60
+ {{- '<tool_call>\n{"name": "' }}
61
+ {{- tool_call.name }}
62
+ {{- '", "arguments": ' }}
63
+ {%- if tool_call.arguments is string %}
64
+ {{- tool_call.arguments }}
65
+ {%- else %}
66
+ {{- tool_call.arguments | tojson }}
67
+ {%- endif %}
68
+ {{- '}\n</tool_call>' }}
69
+ {%- endfor %}
70
+ {%- endif %}
71
+ {{- '<|im_end|>\n' }}
72
+ {%- elif message.role == "tool" %}
73
+ {%- if loop.first or (messages[loop.index0 - 1].role != "tool") %}
74
+ {{- '<|im_start|>user' }}
75
+ {%- endif %}
76
+ {{- '\n<tool_response>\n' }}
77
+ {{- content }}
78
+ {{- '\n</tool_response>' }}
79
+ {%- if loop.last or (messages[loop.index0 + 1].role != "tool") %}
80
+ {{- '<|im_end|>\n' }}
81
+ {%- endif %}
82
+ {%- endif %}
83
+ {%- endfor %}
84
+ {%- if add_generation_prompt %}
85
+ {{- '<|im_start|>assistant\n' }}
86
+ {%- if enable_thinking is defined and enable_thinking is false %}
87
+ {{- '<think>\n\n</think>\n\n' }}
88
+ {%- endif %}
89
+ {%- endif %}
chute_config.yml ADDED
@@ -0,0 +1,26 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ # Vocence PromptTTS — k2-fsa/OmniVoice (diffusion LM TTS, voice design via `instruct`).
2
+ # Weights + tokenizer ship in the HF repo; miner maps free-form `instruction` → OmniVoice tags.
3
+
4
+ Image:
5
+ from_base: parachutes/base-python:3.12.9
6
+ run_command:
7
+ - pip install --no-cache-dir torch==2.10.0 torchaudio==2.10.0 --extra-index-url https://download.pytorch.org/whl/cu128
8
+ - pip install --no-cache-dir transformers accelerate safetensors soundfile scipy einops
9
+ - pip install --no-cache-dir omnivoice
10
+ - pip install --no-cache-dir numpy pyyaml huggingface_hub
11
+
12
+ NodeSelector:
13
+ gpu_count: 1
14
+ min_vram_gb_per_gpu: 48
15
+ include: ["pro_6000"]
16
+ exclude: []
17
+
18
+ Chute:
19
+ tagline: Sad-tts-v1 OmniVoice TTS (PromptTTS voice design, Vocence)
20
+ readme: NL instruction + text to WAV; Vocence SN78 Sad-tts-v1 miner.
21
+ boost: 1.32
22
+ shutdown_after_seconds: 86400
23
+ concurrency: 1
24
+ max_instances: 1
25
+ scaling_threshold: 0.5
26
+ tee: true
config.json ADDED
@@ -0,0 +1,101 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ {
2
+ "architectures": [
3
+ "OmniVoice"
4
+ ],
5
+ "audio_codebook_weights": [
6
+ 8,
7
+ 8,
8
+ 6,
9
+ 6,
10
+ 4,
11
+ 4,
12
+ 2,
13
+ 2
14
+ ],
15
+ "audio_mask_id": 1024,
16
+ "audio_vocab_size": 1025,
17
+ "bos_token_id": null,
18
+ "dtype": "float32",
19
+ "eos_token_id": 151645,
20
+ "llm_config": {
21
+ "_name_or_path": "",
22
+ "architectures": [
23
+ "Qwen3ForCausalLM"
24
+ ],
25
+ "attention_bias": false,
26
+ "attention_dropout": 0.0,
27
+ "bos_token_id": 151643,
28
+ "chunk_size_feed_forward": 0,
29
+ "dtype": "float32",
30
+ "eos_token_id": 151645,
31
+ "head_dim": 128,
32
+ "hidden_act": "silu",
33
+ "hidden_size": 1024,
34
+ "id2label": {
35
+ "0": "LABEL_0",
36
+ "1": "LABEL_1"
37
+ },
38
+ "initializer_range": 0.02,
39
+ "intermediate_size": 3072,
40
+ "is_encoder_decoder": false,
41
+ "label2id": {
42
+ "LABEL_0": 0,
43
+ "LABEL_1": 1
44
+ },
45
+ "layer_types": [
46
+ "full_attention",
47
+ "full_attention",
48
+ "full_attention",
49
+ "full_attention",
50
+ "full_attention",
51
+ "full_attention",
52
+ "full_attention",
53
+ "full_attention",
54
+ "full_attention",
55
+ "full_attention",
56
+ "full_attention",
57
+ "full_attention",
58
+ "full_attention",
59
+ "full_attention",
60
+ "full_attention",
61
+ "full_attention",
62
+ "full_attention",
63
+ "full_attention",
64
+ "full_attention",
65
+ "full_attention",
66
+ "full_attention",
67
+ "full_attention",
68
+ "full_attention",
69
+ "full_attention",
70
+ "full_attention",
71
+ "full_attention",
72
+ "full_attention",
73
+ "full_attention"
74
+ ],
75
+ "max_position_embeddings": 40960,
76
+ "max_window_layers": 28,
77
+ "model_type": "qwen3",
78
+ "num_attention_heads": 16,
79
+ "num_hidden_layers": 28,
80
+ "num_key_value_heads": 8,
81
+ "output_attentions": false,
82
+ "output_hidden_states": false,
83
+ "pad_token_id": null,
84
+ "problem_type": null,
85
+ "return_dict": true,
86
+ "rms_norm_eps": 1e-06,
87
+ "rope_parameters": {
88
+ "rope_theta": 1000000,
89
+ "rope_type": "default"
90
+ },
91
+ "sliding_window": null,
92
+ "tie_word_embeddings": true,
93
+ "use_cache": true,
94
+ "use_sliding_window": false,
95
+ "vocab_size": 151676
96
+ },
97
+ "model_type": "omnivoice",
98
+ "num_audio_codebook": 8,
99
+ "pad_token_id": 151643,
100
+ "transformers_version": "5.3.0"
101
+ }
miner.py ADDED
@@ -0,0 +1,391 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ """
2
+ Vocence SN78 PromptTTS engine for OmniVoice (k2-fsa/OmniVoice).
3
+
4
+ OmniVoice voice-design mode only accepts whitelisted comma-separated attributes
5
+ in ``instruct``; free-form validator ``instruction`` is mapped to those tags.
6
+ """
7
+
8
+ from __future__ import annotations
9
+
10
+ import re
11
+ from pathlib import Path
12
+ from typing import Any, Mapping
13
+
14
+ import numpy as np
15
+
16
+ _VOCENCE_YAML = "vocence_config.yaml"
17
+ _ZH_RE = re.compile(r"[\u4e00-\u9fff]")
18
+ _WORD_RE = re.compile(r"\w+", re.UNICODE)
19
+
20
+
21
+ def _read_vocence_yaml(repo: Path) -> dict[str, Any]:
22
+ path = repo / _VOCENCE_YAML
23
+ if not path.is_file():
24
+ return {}
25
+ from yaml import safe_load
26
+
27
+ with path.open("r", encoding="utf-8") as fh:
28
+ data = safe_load(fh)
29
+ return data if isinstance(data, Mapping) else {}
30
+
31
+
32
+ def _has_cjk(s: str) -> bool:
33
+ return bool(re.search(r"[\u3040-\u30ff\u3100-\u312f\u3400-\u9fff\uac00-\ud7af]", s))
34
+
35
+
36
+ def _pick_language(text: str, instruction_lower: str, default_lang: str = "English") -> str | None:
37
+ t, ins = text or "", instruction_lower or ""
38
+ if "japanese" in ins or "日本" in t or re.search(r"[\u3040-\u30ff]", t):
39
+ return "Japanese"
40
+ if "korean" in ins or "한글" in t or re.search(r"[\uac00-\ud7af]", t):
41
+ return "Korean"
42
+ if _has_cjk(t) or "chinese" in ins or "mandarin" in ins or "cantonese" in ins:
43
+ return "Chinese"
44
+ if any(
45
+ w in ins
46
+ for w in (
47
+ "french",
48
+ "german",
49
+ "spanish",
50
+ "italian",
51
+ "portuguese",
52
+ "russian",
53
+ "arabic",
54
+ "hindi",
55
+ )
56
+ ):
57
+ for name in (
58
+ "French",
59
+ "German",
60
+ "Spanish",
61
+ "Italian",
62
+ "Portuguese",
63
+ "Russian",
64
+ "Arabic",
65
+ "Hindi",
66
+ ):
67
+ if name.lower() in ins:
68
+ return name
69
+ return default_lang if default_lang else None
70
+
71
+
72
+ def _inject_natural_punctuation(text: str) -> str:
73
+ """Light pacing hints for long unpunctuated Latin text (OmniVoice benefits from boundaries)."""
74
+ if not text or not text.strip():
75
+ return text
76
+ if _has_cjk(text):
77
+ return text
78
+ words = _WORD_RE.findall(text)
79
+ if len(words) < 22:
80
+ return text
81
+ if len(re.findall(r"[,.;:!?]", text)) >= max(2, len(words) // 14):
82
+ return text
83
+ parts: list[str] = []
84
+ breaks = ("and", "but", "or", "yet", "so", "while", "however", "therefore")
85
+ wix = 0
86
+ i = 0
87
+ n = len(text)
88
+ last_break_at = -10
89
+ while i < n:
90
+ ch = text[i]
91
+ if ch.isalnum():
92
+ j = i
93
+ while j < n and (text[j].isalnum() or text[j] == "'"):
94
+ j += 1
95
+ token = text[i:j]
96
+ low = token.lower()
97
+ if (
98
+ low in breaks
99
+ and wix > 0
100
+ and (wix - last_break_at) >= 8
101
+ ):
102
+ while parts and parts[-1] == " ":
103
+ parts.pop()
104
+ parts.append(", ")
105
+ last_break_at = wix
106
+ parts.append(token)
107
+ wix += 1
108
+ i = j
109
+ else:
110
+ parts.append(ch)
111
+ i += 1
112
+ return "".join(parts)
113
+
114
+
115
+ def _nl_to_omnivoice_instruct(
116
+ instruction: str,
117
+ text: str,
118
+ *,
119
+ default_instruct: str,
120
+ ) -> str:
121
+ """Map free-form NL to OmniVoice voice-design tags (English or Chinese dialect tokens)."""
122
+ raw = (instruction or "").strip()
123
+ t = text or ""
124
+
125
+ gender: str | None = None
126
+ age: str | None = None
127
+ pitch: str | None = None
128
+ style: str | None = None
129
+ accent: str | None = None
130
+ dialect_zh: str | None = None
131
+
132
+ s = raw.lower()
133
+ # Gender
134
+ female = any(
135
+ k in s
136
+ for k in (
137
+ "female",
138
+ "woman",
139
+ "girl",
140
+ "lady",
141
+ "mother",
142
+ "soprano",
143
+ "feminine",
144
+ "herself",
145
+ )
146
+ ) or bool(re.search(r"\b(she|her)\b", s))
147
+ male = any(
148
+ k in s
149
+ for k in (
150
+ "male",
151
+ "man",
152
+ "boy",
153
+ "gentleman",
154
+ "father",
155
+ "baritone",
156
+ "masculine",
157
+ "himself",
158
+ )
159
+ ) or bool(re.search(r"\b(he|his|him)\b", s))
160
+ if female and not male:
161
+ gender = "female"
162
+ elif male and not female:
163
+ gender = "male"
164
+
165
+ # Age
166
+ if any(k in s for k in ("child", "kid", "toddler")):
167
+ age = "child"
168
+ elif "teen" in s or "teenager" in s:
169
+ age = "teenager"
170
+ elif any(k in s for k in ("elderly", "old man", "old woman", "senior", "grandfather", "grandmother")):
171
+ age = "elderly"
172
+ elif any(k in s for k in ("middle-aged", "middle aged", "mature")):
173
+ age = "middle-aged"
174
+ elif any(k in s for k in ("young adult", "young woman", "young man", "adult")):
175
+ age = "young adult"
176
+ elif "young" in s and "young adult" not in s:
177
+ age = "young adult"
178
+
179
+ # Pitch
180
+ if any(k in s for k in ("very low", "very deep", "bass", "gravely low")):
181
+ pitch = "very low pitch"
182
+ elif any(k in s for k in ("low pitch", "deep voice", "low voice", "baritone")) or "deep" in s:
183
+ pitch = "low pitch"
184
+ elif any(k in s for k in ("very high", "shrill", "squeaky")):
185
+ pitch = "very high pitch"
186
+ elif any(k in s for k in ("high pitch", "high voice")) or "high-pitched" in s:
187
+ pitch = "high pitch"
188
+ elif any(k in s for k in ("moderate", "neutral", "mid", "mid-range", "normal pitch")):
189
+ pitch = "moderate pitch"
190
+
191
+ if "whisper" in s or "whispering" in s:
192
+ style = "whisper"
193
+
194
+ # English accents (mutually exclusive — first match wins)
195
+ accent_rules = (
196
+ ("british", "british accent"),
197
+ ("uk accent", "british accent"),
198
+ ("scottish", "british accent"),
199
+ ("american", "american accent"),
200
+ ("us accent", "american accent"),
201
+ ("australian", "australian accent"),
202
+ ("indian accent", "indian accent"),
203
+ ("indian english", "indian accent"),
204
+ ("canadian", "canadian accent"),
205
+ ("russian accent", "russian accent"),
206
+ ("japanese accent", "japanese accent"),
207
+ ("korean accent", "korean accent"),
208
+ ("portuguese accent", "portuguese accent"),
209
+ ("chinese accent", "chinese accent"),
210
+ )
211
+ for key, tag in accent_rules:
212
+ if key in s:
213
+ accent = tag
214
+ break
215
+
216
+ # Chinese dialects (Chinese chars / keywords)
217
+ zh_dialect = (
218
+ ("四川", "四川话"),
219
+ ("sichuan", "四川话"),
220
+ ("东北", "东北话"),
221
+ ("陕西", "陕西话"),
222
+ ("河南", "河南话"),
223
+ ("云南", "云南话"),
224
+ ("贵州", "贵州话"),
225
+ ("山东", "济南话"),
226
+ ("青岛", "青岛话"),
227
+ ("石家庄", "石家庄话"),
228
+ ("甘肃", "甘肃话"),
229
+ ("宁夏", "宁夏话"),
230
+ ("桂林", "桂林话"),
231
+ ("济南", "济南话"),
232
+ )
233
+ ins_or_t = raw + t
234
+ for key, tag in zh_dialect:
235
+ if key in ins_or_t:
236
+ dialect_zh = tag
237
+ break
238
+
239
+ parts: list[str] = []
240
+ if dialect_zh:
241
+ zh_bits: list[str] = []
242
+ if gender == "female":
243
+ zh_bits.append("女")
244
+ elif gender == "male":
245
+ zh_bits.append("男")
246
+ if age == "child":
247
+ zh_bits.append("儿童")
248
+ elif age == "teenager":
249
+ zh_bits.append("少年")
250
+ elif age in ("young adult", "middle-aged"):
251
+ zh_bits.append("青年" if age == "young adult" else "中年")
252
+ elif age == "elderly":
253
+ zh_bits.append("老年")
254
+ if pitch == "very low pitch":
255
+ zh_bits.append("极低音调")
256
+ elif pitch == "low pitch":
257
+ zh_bits.append("低音调")
258
+ elif pitch == "moderate pitch":
259
+ zh_bits.append("中音调")
260
+ elif pitch == "high pitch":
261
+ zh_bits.append("高音调")
262
+ elif pitch == "very high pitch":
263
+ zh_bits.append("极高音调")
264
+ if style == "whisper":
265
+ zh_bits.append("耳语")
266
+ zh_bits.append(dialect_zh)
267
+ return ",".join(zh_bits)
268
+
269
+ # English path
270
+ for x in (gender, age, pitch, style, accent):
271
+ if x:
272
+ parts.append(x)
273
+ if not parts:
274
+ return default_instruct.strip() or "young adult, moderate pitch, american accent"
275
+
276
+ # Omnivoice rejects mixing accent with Chinese dialect — we handled dialect above.
277
+ return ", ".join(parts)
278
+
279
+
280
+ def _speed_from_instruction(s: str) -> float | None:
281
+ s = (s or "").lower()
282
+ if any(w in s for w in ("very slow", "slowly", "unhurried")):
283
+ return 0.85
284
+ if "slow" in s:
285
+ return 0.93
286
+ if any(w in s for w in ("very fast", "rapid", "quickly", "hurried")):
287
+ return 1.12
288
+ if "fast" in s:
289
+ return 1.06
290
+ return None
291
+
292
+
293
+ def _to_mono_f32(segment: np.ndarray) -> np.ndarray:
294
+ arr = np.asarray(segment, dtype=np.float32)
295
+ if arr.ndim > 1:
296
+ arr = arr.mean(axis=-1)
297
+ return np.ascontiguousarray(arr, dtype=np.float32)
298
+
299
+
300
+ def _peak_normalize(wav: np.ndarray, ceiling: float = 0.38) -> np.ndarray:
301
+ if wav.size == 0:
302
+ return wav
303
+ p = float(np.max(np.abs(wav)))
304
+ if p <= 0 or p <= ceiling:
305
+ return wav
306
+ return (wav * (ceiling / p)).astype(np.float32, copy=False)
307
+
308
+
309
+ class Miner:
310
+ """OmniVoice engine: NL ``instruction`` → voice-design ``instruct``; ``text`` → speech."""
311
+
312
+ def __init__(self, path_hf_repo: Path) -> None:
313
+ import torch
314
+ from omnivoice import OmniVoice
315
+
316
+ self._root = Path(path_hf_repo).resolve()
317
+ if not (self._root / "config.json").is_file():
318
+ raise FileNotFoundError(f"Missing config.json under {self._root}")
319
+
320
+ cfg = _read_vocence_yaml(self._root)
321
+ runtime = cfg.get("runtime") or {}
322
+ limits = cfg.get("limits") or {}
323
+ gen = cfg.get("generation") or {}
324
+
325
+ self._cap_instruction = int(limits.get("max_instruction_chars", 600))
326
+ self._cap_text = int(limits.get("max_text_chars", 2000))
327
+ self._max_seconds = float(gen.get("max_seconds", 30))
328
+ self._default_language = str(limits.get("default_language") or runtime.get("default_language", "English"))
329
+ self._default_instruct = str(
330
+ runtime.get("default_instruct") or "young adult, moderate pitch, american accent"
331
+ )
332
+ self._num_step = int(runtime.get("num_step", 24))
333
+ self._guidance_scale = float(runtime.get("guidance_scale", 2.0))
334
+
335
+ prefer_cuda = torch.cuda.is_available()
336
+ ckpt = str(self._root)
337
+ dtype = torch.float16 if prefer_cuda else torch.float32
338
+ map_kw: dict[str, Any] = {"dtype": dtype}
339
+ if prefer_cuda:
340
+ map_kw["device_map"] = "cuda:0"
341
+ else:
342
+ map_kw["device_map"] = "cpu"
343
+
344
+ self._torch = torch
345
+ self._model = OmniVoice.from_pretrained(ckpt, **map_kw)
346
+
347
+ def warmup(self) -> None:
348
+ _ = self.generate_wav(
349
+ "Speak clearly in a neutral American accent.",
350
+ "Warm-up.",
351
+ )
352
+
353
+ def generate_wav(self, instruction: str, text: str) -> tuple[np.ndarray, int]:
354
+ if not text or not str(text).strip():
355
+ raise ValueError("text must be non-empty")
356
+
357
+ inst_full = (instruction or "").strip()[: self._cap_instruction]
358
+ tts_text = _inject_natural_punctuation(str(text).strip()[: self._cap_text])
359
+ lang = _pick_language(tts_text, inst_full.lower(), self._default_language)
360
+
361
+ instruct = _nl_to_omnivoice_instruct(
362
+ inst_full, tts_text, default_instruct=self._default_instruct
363
+ )
364
+ speed = _speed_from_instruction(inst_full)
365
+
366
+ gen_kwargs: dict[str, Any] = dict(
367
+ num_step=self._num_step,
368
+ guidance_scale=self._guidance_scale,
369
+ )
370
+
371
+ audios = self._model.generate(
372
+ text=tts_text,
373
+ language=lang,
374
+ instruct=instruct,
375
+ speed=speed,
376
+ **gen_kwargs,
377
+ )
378
+ if not audios:
379
+ raise ValueError("OmniVoice returned no audio")
380
+ first = audios[0]
381
+ if first is None or first.size == 0:
382
+ raise ValueError("OmniVoice returned empty audio")
383
+
384
+ sr = int(getattr(self._model, "sampling_rate", None) or 24000)
385
+ wav = _peak_normalize(_to_mono_f32(first))
386
+ dur = float(wav.shape[0]) / float(sr)
387
+ if dur > self._max_seconds + 1e-3:
388
+ max_samples = int(self._max_seconds * sr)
389
+ wav = wav[:max_samples]
390
+
391
+ return wav, sr
tokenizer.json ADDED
@@ -0,0 +1,3 @@
 
 
 
 
1
+ version https://git-lfs.github.com/spec/v1
2
+ oid sha256:408f669b7e2b045fdf54201d815bd364e6667dbd845115da81239c40bc6dcfd1
3
+ size 11423986
tokenizer_config.json ADDED
@@ -0,0 +1,23 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ {
2
+ "add_prefix_space": false,
3
+ "backend": "tokenizers",
4
+ "bos_token": null,
5
+ "clean_up_tokenization_spaces": false,
6
+ "eos_token": "<|im_end|>",
7
+ "errors": "replace",
8
+ "extra_special_tokens": [
9
+ "<|denoise|>",
10
+ "<|lang_start|>",
11
+ "<|lang_end|>",
12
+ "<|instruct_start|>",
13
+ "<|instruct_end|>",
14
+ "<|text_start|>",
15
+ "<|text_end|>"
16
+ ],
17
+ "is_local": true,
18
+ "model_max_length": 131072,
19
+ "pad_token": "<|endoftext|>",
20
+ "split_special_tokens": false,
21
+ "tokenizer_class": "Qwen2Tokenizer",
22
+ "unk_token": null
23
+ }
vocence_config.yaml ADDED
@@ -0,0 +1,21 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ # Vocence PromptTTS — OmniVoice (voice design). See miner.py for NL → instruct mapping.
2
+
3
+ runtime:
4
+ adapter: "omnivoice_voice_design"
5
+ device_preference: "cuda"
6
+ dtype: "float16"
7
+ default_language: "English"
8
+ # When the NL instruction does not map to any OmniVoice attribute, use this valid instruct:
9
+ default_instruct: "young adult, moderate pitch, american accent"
10
+ # Optional generation overrides (passed to OmniVoice.generate)
11
+ num_step: 24
12
+ guidance_scale: 2.0
13
+
14
+ generation:
15
+ sample_rate: 24000
16
+ max_seconds: 30
17
+
18
+ limits:
19
+ max_text_chars: 2000
20
+ max_instruction_chars: 600
21
+ default_language: "English"