Spaces:
Sleeping
Sleeping
Upload folder using huggingface_hub
Browse filesThis view is limited to 50 files because it contains too many changes.
See raw diff
- .gitattributes +22 -0
- .gitignore +81 -0
- DEPLOYMENT_GUIDE.md +251 -0
- Inference.ipynb +62 -0
- LICENSE +21 -0
- README.md +105 -12
- README_DEPLOYMENT.md +88 -0
- REFACTORING_README.md +172 -0
- app-webui.bat +9 -0
- app.py +7 -0
- ckpts/README.md +10 -0
- data/Emilia_ZH_EN_pinyin/vocab.txt +2586 -0
- data/librispeech_pc_test_clean_cross_sentence.lst +0 -0
- deployment/.gitignore +81 -0
- deployment/README.md +89 -0
- deployment/app.py +45 -0
- deployment/app_minimal.py +31 -0
- deployment/requirements.txt +15 -0
- deployment/requirements_minimal.txt +1 -0
- deployment/src/f5_tts/api.py +174 -0
- deployment/src/f5_tts/cleantext/number_tha.py +145 -0
- deployment/src/f5_tts/cleantext/th_repeat.py +41 -0
- deployment/src/f5_tts/config.py +98 -0
- deployment/src/f5_tts/configs/E2TTS_Base_train.yaml +45 -0
- deployment/src/f5_tts/configs/E2TTS_Small_train.yaml +45 -0
- deployment/src/f5_tts/configs/F5TTS_Base_train.yaml +48 -0
- deployment/src/f5_tts/configs/F5TTS_Small_train.yaml +48 -0
- deployment/src/f5_tts/eval/README.md +52 -0
- deployment/src/f5_tts/eval/ecapa_tdnn.py +330 -0
- deployment/src/f5_tts/eval/eval_infer_batch.py +207 -0
- deployment/src/f5_tts/eval/eval_infer_batch.sh +13 -0
- deployment/src/f5_tts/eval/eval_librispeech_test_clean.py +96 -0
- deployment/src/f5_tts/eval/eval_seedtts_testset.py +95 -0
- deployment/src/f5_tts/eval/eval_utmos.py +44 -0
- deployment/src/f5_tts/eval/utils_eval.py +413 -0
- deployment/src/f5_tts/f5_tts_webui.py +295 -0
- deployment/src/f5_tts/infer/README.md +219 -0
- deployment/src/f5_tts/infer/SHARED.md +164 -0
- deployment/src/f5_tts/infer/examples/basic/basic.toml +11 -0
- deployment/src/f5_tts/infer/examples/basic/basic_ref_en.wav +3 -0
- deployment/src/f5_tts/infer/examples/basic/basic_ref_zh.wav +3 -0
- deployment/src/f5_tts/infer/examples/multi/country.flac +3 -0
- deployment/src/f5_tts/infer/examples/multi/main.flac +3 -0
- deployment/src/f5_tts/infer/examples/multi/story.toml +20 -0
- deployment/src/f5_tts/infer/examples/multi/story.txt +1 -0
- deployment/src/f5_tts/infer/examples/multi/town.flac +3 -0
- deployment/src/f5_tts/infer/examples/thai_examples/ref_gen_1.wav +3 -0
- deployment/src/f5_tts/infer/examples/thai_examples/ref_gen_2.wav +3 -0
- deployment/src/f5_tts/infer/examples/thai_examples/ref_gen_3.wav +3 -0
- deployment/src/f5_tts/infer/examples/thai_examples/ref_gen_4.wav +3 -0
.gitattributes
CHANGED
|
@@ -33,3 +33,25 @@ 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 |
+
deployment/src/f5_tts/infer/examples/basic/basic_ref_en.wav filter=lfs diff=lfs merge=lfs -text
|
| 37 |
+
deployment/src/f5_tts/infer/examples/basic/basic_ref_zh.wav filter=lfs diff=lfs merge=lfs -text
|
| 38 |
+
deployment/src/f5_tts/infer/examples/multi/country.flac filter=lfs diff=lfs merge=lfs -text
|
| 39 |
+
deployment/src/f5_tts/infer/examples/multi/main.flac filter=lfs diff=lfs merge=lfs -text
|
| 40 |
+
deployment/src/f5_tts/infer/examples/multi/town.flac filter=lfs diff=lfs merge=lfs -text
|
| 41 |
+
deployment/src/f5_tts/infer/examples/thai_examples/ref_gen_1.wav filter=lfs diff=lfs merge=lfs -text
|
| 42 |
+
deployment/src/f5_tts/infer/examples/thai_examples/ref_gen_2.wav filter=lfs diff=lfs merge=lfs -text
|
| 43 |
+
deployment/src/f5_tts/infer/examples/thai_examples/ref_gen_3.wav filter=lfs diff=lfs merge=lfs -text
|
| 44 |
+
deployment/src/f5_tts/infer/examples/thai_examples/ref_gen_4.wav filter=lfs diff=lfs merge=lfs -text
|
| 45 |
+
deployment/src/f5_tts/infer/examples/thai_examples/tts_gen_1.wav filter=lfs diff=lfs merge=lfs -text
|
| 46 |
+
deployment/src/f5_tts/infer/examples/thai_examples/tts_gen_2.wav filter=lfs diff=lfs merge=lfs -text
|
| 47 |
+
src/f5_tts/infer/examples/basic/basic_ref_en.wav filter=lfs diff=lfs merge=lfs -text
|
| 48 |
+
src/f5_tts/infer/examples/basic/basic_ref_zh.wav filter=lfs diff=lfs merge=lfs -text
|
| 49 |
+
src/f5_tts/infer/examples/multi/country.flac filter=lfs diff=lfs merge=lfs -text
|
| 50 |
+
src/f5_tts/infer/examples/multi/main.flac filter=lfs diff=lfs merge=lfs -text
|
| 51 |
+
src/f5_tts/infer/examples/multi/town.flac filter=lfs diff=lfs merge=lfs -text
|
| 52 |
+
src/f5_tts/infer/examples/thai_examples/ref_gen_1.wav filter=lfs diff=lfs merge=lfs -text
|
| 53 |
+
src/f5_tts/infer/examples/thai_examples/ref_gen_2.wav filter=lfs diff=lfs merge=lfs -text
|
| 54 |
+
src/f5_tts/infer/examples/thai_examples/ref_gen_3.wav filter=lfs diff=lfs merge=lfs -text
|
| 55 |
+
src/f5_tts/infer/examples/thai_examples/ref_gen_4.wav filter=lfs diff=lfs merge=lfs -text
|
| 56 |
+
src/f5_tts/infer/examples/thai_examples/tts_gen_1.wav filter=lfs diff=lfs merge=lfs -text
|
| 57 |
+
src/f5_tts/infer/examples/thai_examples/tts_gen_2.wav filter=lfs diff=lfs merge=lfs -text
|
.gitignore
ADDED
|
@@ -0,0 +1,81 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
# Python
|
| 2 |
+
__pycache__/
|
| 3 |
+
*.py[cod]
|
| 4 |
+
*$py.class
|
| 5 |
+
*.so
|
| 6 |
+
.Python
|
| 7 |
+
build/
|
| 8 |
+
develop-eggs/
|
| 9 |
+
dist/
|
| 10 |
+
downloads/
|
| 11 |
+
eggs/
|
| 12 |
+
.eggs/
|
| 13 |
+
lib/
|
| 14 |
+
lib64/
|
| 15 |
+
parts/
|
| 16 |
+
sdist/
|
| 17 |
+
var/
|
| 18 |
+
wheels/
|
| 19 |
+
*.egg-info/
|
| 20 |
+
.installed.cfg
|
| 21 |
+
*.egg
|
| 22 |
+
MANIFEST
|
| 23 |
+
|
| 24 |
+
# PyTorch
|
| 25 |
+
*.pth
|
| 26 |
+
*.pt
|
| 27 |
+
|
| 28 |
+
# Gradio
|
| 29 |
+
.gradio/
|
| 30 |
+
flagged/
|
| 31 |
+
|
| 32 |
+
# Environment
|
| 33 |
+
.env
|
| 34 |
+
.venv
|
| 35 |
+
env/
|
| 36 |
+
venv/
|
| 37 |
+
ENV/
|
| 38 |
+
env.bak/
|
| 39 |
+
venv.bak/
|
| 40 |
+
|
| 41 |
+
# IDE
|
| 42 |
+
.vscode/
|
| 43 |
+
.idea/
|
| 44 |
+
*.swp
|
| 45 |
+
*.swo
|
| 46 |
+
*~
|
| 47 |
+
|
| 48 |
+
# OS
|
| 49 |
+
.DS_Store
|
| 50 |
+
.DS_Store?
|
| 51 |
+
._*
|
| 52 |
+
.Spotlight-V100
|
| 53 |
+
.Trashes
|
| 54 |
+
ehthumbs.db
|
| 55 |
+
Thumbs.db
|
| 56 |
+
|
| 57 |
+
# Logs
|
| 58 |
+
*.log
|
| 59 |
+
logs/
|
| 60 |
+
|
| 61 |
+
# Temporary files
|
| 62 |
+
*.tmp
|
| 63 |
+
*.temp
|
| 64 |
+
tmp/
|
| 65 |
+
temp/
|
| 66 |
+
|
| 67 |
+
# Cache
|
| 68 |
+
.cache/
|
| 69 |
+
*.cache
|
| 70 |
+
|
| 71 |
+
# Model downloads (if large)
|
| 72 |
+
# ckpts/
|
| 73 |
+
# models/
|
| 74 |
+
|
| 75 |
+
# Audio files (if large)
|
| 76 |
+
# *.wav
|
| 77 |
+
# *.mp3
|
| 78 |
+
# *.flac
|
| 79 |
+
|
| 80 |
+
# Jupyter
|
| 81 |
+
.ipynb_checkpoints
|
DEPLOYMENT_GUIDE.md
ADDED
|
@@ -0,0 +1,251 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
# 🚀 คู่มือการ Deploy F5-TTS Thai WebUI
|
| 2 |
+
|
| 3 |
+
## วิธีการ Deploy ไป Hugging Face Spaces
|
| 4 |
+
|
| 5 |
+
### ขั้นตอนที่ 1: เตรียม Account และ Repository
|
| 6 |
+
|
| 7 |
+
1. **สร้าง Hugging Face Account** (ถ้ายังไม่มี)
|
| 8 |
+
- ไปที่ https://huggingface.co/join
|
| 9 |
+
- สร้าง account ฟรี
|
| 10 |
+
|
| 11 |
+
2. **สร้าง Space ใหม่**
|
| 12 |
+
- ไปที่ https://huggingface.co/new-space
|
| 13 |
+
- ตั้งชื่อ Space (เช่น `f5-tts-thai`)
|
| 14 |
+
- เลือก SDK: **Gradio**
|
| 15 |
+
- เลือก Hardware: **CPU basic** (ฟรี) หรือ **GPU** (ต้องเสียเงิน)
|
| 16 |
+
|
| 17 |
+
### ขั้นตอนที่ 2: Upload โค้ด
|
| 18 |
+
|
| 19 |
+
**วิธีที่ 1: ใช้ Git (แนะนำ)**
|
| 20 |
+
|
| 21 |
+
```bash
|
| 22 |
+
# Clone repository ที่สร้างจาก HF Spaces
|
| 23 |
+
git clone https://huggingface.co/spaces/YOUR_USERNAME/f5-tts-thai
|
| 24 |
+
cd f5-tts-thai
|
| 25 |
+
|
| 26 |
+
# คัดลอกไฟล์จากโปรเจ็กต์ของคุณ
|
| 27 |
+
cp -r /path/to/F5-TTS-THAI/src .
|
| 28 |
+
cp /path/to/F5-TTS-THAI/app.py .
|
| 29 |
+
cp /path/to/F5-TTS-THAI/requirements.txt .
|
| 30 |
+
|
| 31 |
+
# สร้าง README.md จาก README_DEPLOYMENT.md
|
| 32 |
+
cp /path/to/F5-TTS-THAI/README_DEPLOYMENT.md README.md
|
| 33 |
+
|
| 34 |
+
# Commit และ push
|
| 35 |
+
git add .
|
| 36 |
+
git commit -m "Initial deployment"
|
| 37 |
+
git push
|
| 38 |
+
```
|
| 39 |
+
|
| 40 |
+
**วิธีที่ 2: อัปโหลดผ่าน Web Interface**
|
| 41 |
+
|
| 42 |
+
1. ไปที่ Space ที่คุณสร้าง
|
| 43 |
+
2. คลิก "Files and versions"
|
| 44 |
+
3. อัปโหลดไฟล์ทีละไฟล์:
|
| 45 |
+
- `app.py`
|
| 46 |
+
- `requirements.txt`
|
| 47 |
+
- `README.md` (จาก README_DEPLOYMENT.md)
|
| 48 |
+
- โฟลเดอร์ `src/` ทั้งหมด
|
| 49 |
+
|
| 50 |
+
### ขั้นตอนที่ 3: ตรวจสอบการ Deploy
|
| 51 |
+
|
| 52 |
+
1. **รอการ Build**
|
| 53 |
+
- Hugging Face จะ build app อัตโนมัติ
|
| 54 |
+
- ดู logs ได้ที่ "Logs" tab
|
| 55 |
+
|
| 56 |
+
2. **ทดสอบ App**
|
| 57 |
+
- เมื่อ build สำเร็จ จะแสดง URL ของ app
|
| 58 |
+
- ทดสอบ functionality ต่างๆ
|
| 59 |
+
|
| 60 |
+
### ขั้นตอนที่ 4: Configuration ขั้นสูง
|
| 61 |
+
|
| 62 |
+
**เปิดใช้งาน GPU (ต้องเสียเงิน)**
|
| 63 |
+
|
| 64 |
+
```yaml
|
| 65 |
+
# ใน README.md header
|
| 66 |
+
---
|
| 67 |
+
title: F5-TTS Thai
|
| 68 |
+
emoji: 🎤
|
| 69 |
+
colorFrom: blue
|
| 70 |
+
colorTo: purple
|
| 71 |
+
sdk: gradio
|
| 72 |
+
sdk_version: 4.44.0
|
| 73 |
+
app_file: app.py
|
| 74 |
+
pinned: false
|
| 75 |
+
license: mit
|
| 76 |
+
python_version: 3.10
|
| 77 |
+
hardware: gpu-t4-small # เปลี่ยนจาก cpu-basic
|
| 78 |
+
---
|
| 79 |
+
```
|
| 80 |
+
|
| 81 |
+
**ปรับแต่ง Environment Variables**
|
| 82 |
+
|
| 83 |
+
ใน Space settings เพิ่ม variables:
|
| 84 |
+
- `CUDA_VISIBLE_DEVICES=0` (สำหรับ GPU)
|
| 85 |
+
- `TRANSFORMERS_CACHE=/tmp` (เพื่อประหยัด storage)
|
| 86 |
+
|
| 87 |
+
## วิธีการ Deploy ไป Gradio.app
|
| 88 |
+
|
| 89 |
+
### ขั้นตอนที่ 1: สร้าง Account
|
| 90 |
+
|
| 91 |
+
1. ไปที่ https://gradio.app
|
| 92 |
+
2. สร้าง account และ login
|
| 93 |
+
|
| 94 |
+
### ขั้นตอนที่ 2: Deploy
|
| 95 |
+
|
| 96 |
+
```bash
|
| 97 |
+
# ติดตั้ง gradio
|
| 98 |
+
pip install gradio
|
| 99 |
+
|
| 100 |
+
# Upload app
|
| 101 |
+
python app.py --share
|
| 102 |
+
```
|
| 103 |
+
|
| 104 |
+
## การ Optimize สำหรับ Production
|
| 105 |
+
|
| 106 |
+
### 1. ลดขนาด Model
|
| 107 |
+
|
| 108 |
+
```python
|
| 109 |
+
# ใน config.py เปลี่ยนเป็น
|
| 110 |
+
DEFAULT_MODEL_BASE = "hf://VIZINTZOR/F5-TTS-THAI/model_650000_FP16.pt" # ใช้ FP16
|
| 111 |
+
```
|
| 112 |
+
|
| 113 |
+
### 2. เพิ่ม Caching
|
| 114 |
+
|
| 115 |
+
```python
|
| 116 |
+
# ใน model_manager.py
|
| 117 |
+
@lru_cache(maxsize=1)
|
| 118 |
+
def get_cached_model():
|
| 119 |
+
return load_model(...)
|
| 120 |
+
```
|
| 121 |
+
|
| 122 |
+
### 3. ปรับแต่ง Memory Usage
|
| 123 |
+
|
| 124 |
+
```python
|
| 125 |
+
# ใน app.py
|
| 126 |
+
import torch
|
| 127 |
+
torch.set_num_threads(2) # ลด CPU threads
|
| 128 |
+
```
|
| 129 |
+
|
| 130 |
+
### 4. เพิ่ม Error Handling
|
| 131 |
+
|
| 132 |
+
```python
|
| 133 |
+
# ใน app.py
|
| 134 |
+
import gc
|
| 135 |
+
import torch
|
| 136 |
+
|
| 137 |
+
def cleanup_memory():
|
| 138 |
+
gc.collect()
|
| 139 |
+
if torch.cuda.is_available():
|
| 140 |
+
torch.cuda.empty_cache()
|
| 141 |
+
```
|
| 142 |
+
|
| 143 |
+
## Troubleshooting
|
| 144 |
+
|
| 145 |
+
### ปัญหา: Out of Memory
|
| 146 |
+
|
| 147 |
+
**แก้ไข:**
|
| 148 |
+
```python
|
| 149 |
+
# ใช้โมเดล FP16
|
| 150 |
+
# ลด NFE steps
|
| 151 |
+
# เพิ่ม memory cleanup
|
| 152 |
+
```
|
| 153 |
+
|
| 154 |
+
### ปัญหา: Slow Loading
|
| 155 |
+
|
| 156 |
+
**แก้ไข:**
|
| 157 |
+
```python
|
| 158 |
+
# Pre-load models
|
| 159 |
+
# ใช้ model caching
|
| 160 |
+
# ปรับ CPU/GPU settings
|
| 161 |
+
```
|
| 162 |
+
|
| 163 |
+
### ปัญหา: Import Errors
|
| 164 |
+
|
| 165 |
+
**แก้ไข:**
|
| 166 |
+
```python
|
| 167 |
+
# ตรวจสอบ requirements.txt
|
| 168 |
+
# เพิ่ม try-except สำหรับ imports
|
| 169 |
+
# ใช้ fallback interface
|
| 170 |
+
```
|
| 171 |
+
|
| 172 |
+
## การ Monitor และ Maintain
|
| 173 |
+
|
| 174 |
+
### 1. ดู Logs
|
| 175 |
+
|
| 176 |
+
```bash
|
| 177 |
+
# ดู logs ของ HF Spaces
|
| 178 |
+
# Monitor memory usage
|
| 179 |
+
# ตรวจสอบ error rates
|
| 180 |
+
```
|
| 181 |
+
|
| 182 |
+
### 2. Update App
|
| 183 |
+
|
| 184 |
+
```bash
|
| 185 |
+
# git pull latest changes
|
| 186 |
+
# test locally first
|
| 187 |
+
# deploy gradually
|
| 188 |
+
```
|
| 189 |
+
|
| 190 |
+
### 3. Scale Up/Down
|
| 191 |
+
|
| 192 |
+
```bash
|
| 193 |
+
# เปลี่ยน hardware specs
|
| 194 |
+
# ปรับ concurrent users
|
| 195 |
+
# optimize model loading
|
| 196 |
+
```
|
| 197 |
+
|
| 198 |
+
## Security Considerations
|
| 199 |
+
|
| 200 |
+
### 1. Input Validation
|
| 201 |
+
|
| 202 |
+
```python
|
| 203 |
+
def validate_audio_input(audio_file):
|
| 204 |
+
# ตรวจสอบ��นาดไฟล์
|
| 205 |
+
# ตรวจสอบรูปแบบไฟล์
|
| 206 |
+
# จำกัดความยาวเสียง
|
| 207 |
+
```
|
| 208 |
+
|
| 209 |
+
### 2. Rate Limiting
|
| 210 |
+
|
| 211 |
+
```python
|
| 212 |
+
import time
|
| 213 |
+
from functools import wraps
|
| 214 |
+
|
| 215 |
+
def rate_limit(calls_per_minute=10):
|
| 216 |
+
# implement rate limiting
|
| 217 |
+
```
|
| 218 |
+
|
| 219 |
+
### 3. Content Filtering
|
| 220 |
+
|
| 221 |
+
```python
|
| 222 |
+
def filter_inappropriate_content(text):
|
| 223 |
+
# กรองเนื้อหาที่ไม่เหมาะสม
|
| 224 |
+
# ตรวจสอบ spam
|
| 225 |
+
```
|
| 226 |
+
|
| 227 |
+
## Cost Optimization
|
| 228 |
+
|
| 229 |
+
### Free Tier (CPU)
|
| 230 |
+
- **ข้อจำกัด**: ช้า, memory จำกัด
|
| 231 |
+
- **เหมาะสำหรับ**: demo, testing
|
| 232 |
+
|
| 233 |
+
### GPU Tier (T4/A10G)
|
| 234 |
+
- **ราคา**: ~$0.60-3.00/ชั่วโมง
|
| 235 |
+
- **เหมาะสำหรับ**: production, fast inference
|
| 236 |
+
|
| 237 |
+
### Tips ประหยัดค่าใช้จ่าย
|
| 238 |
+
1. ใช้ CPU สำหรับ development
|
| 239 |
+
2. เปิด GPU เฉพาะเวลาที่ต้องการ
|
| 240 |
+
3. ใช้ auto-shutdown
|
| 241 |
+
4. Monitor usage regularly
|
| 242 |
+
|
| 243 |
+
## สรุป
|
| 244 |
+
|
| 245 |
+
การ deploy F5-TTS Thai WebUI ไป cloud platforms ทำได้ง่ายและมีหลายทางเลือก:
|
| 246 |
+
|
| 247 |
+
✅ **Hugging Face Spaces**: ง่าย, มี free tier
|
| 248 |
+
✅ **Gradio.app**: รวดเร็ว, เหมาะสำหรับ quick demos
|
| 249 |
+
✅ **Cloud Platforms**: AWS, GCP, Azure สำหรับ enterprise
|
| 250 |
+
|
| 251 |
+
เลือกตามความต้องการและงบประมาณของคุณ! 🚀
|
Inference.ipynb
ADDED
|
@@ -0,0 +1,62 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
{
|
| 2 |
+
"nbformat": 4,
|
| 3 |
+
"nbformat_minor": 0,
|
| 4 |
+
"metadata": {
|
| 5 |
+
"colab": {
|
| 6 |
+
"provenance": [],
|
| 7 |
+
"gpuType": "T4"
|
| 8 |
+
},
|
| 9 |
+
"kernelspec": {
|
| 10 |
+
"name": "python3",
|
| 11 |
+
"display_name": "Python 3"
|
| 12 |
+
},
|
| 13 |
+
"language_info": {
|
| 14 |
+
"name": "python"
|
| 15 |
+
},
|
| 16 |
+
"accelerator": "GPU"
|
| 17 |
+
},
|
| 18 |
+
"cells": [
|
| 19 |
+
{
|
| 20 |
+
"cell_type": "markdown",
|
| 21 |
+
"source": [
|
| 22 |
+
"# ติดตั้ง"
|
| 23 |
+
],
|
| 24 |
+
"metadata": {
|
| 25 |
+
"id": "fXnq08ZVNMAh"
|
| 26 |
+
}
|
| 27 |
+
},
|
| 28 |
+
{
|
| 29 |
+
"cell_type": "code",
|
| 30 |
+
"execution_count": null,
|
| 31 |
+
"metadata": {
|
| 32 |
+
"id": "tTdQJcckmuZ4"
|
| 33 |
+
},
|
| 34 |
+
"outputs": [],
|
| 35 |
+
"source": [
|
| 36 |
+
"!git clone https://github.com/VYNCX/F5-TTS-THAI.git\n",
|
| 37 |
+
"%cd F5-TTS-THAI\n",
|
| 38 |
+
"!pip install git+https://github.com/VYNCX/F5-TTS-THAI.git"
|
| 39 |
+
]
|
| 40 |
+
},
|
| 41 |
+
{
|
| 42 |
+
"cell_type": "markdown",
|
| 43 |
+
"source": [
|
| 44 |
+
"# ใช้งาน"
|
| 45 |
+
],
|
| 46 |
+
"metadata": {
|
| 47 |
+
"id": "wJNZvZB7PXSI"
|
| 48 |
+
}
|
| 49 |
+
},
|
| 50 |
+
{
|
| 51 |
+
"cell_type": "code",
|
| 52 |
+
"source": [
|
| 53 |
+
"!python src/f5_tts/f5_tts_webui.py --share"
|
| 54 |
+
],
|
| 55 |
+
"metadata": {
|
| 56 |
+
"id": "UoKmwDmfm6qP"
|
| 57 |
+
},
|
| 58 |
+
"execution_count": null,
|
| 59 |
+
"outputs": []
|
| 60 |
+
}
|
| 61 |
+
]
|
| 62 |
+
}
|
LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
MIT License
|
| 2 |
+
|
| 3 |
+
Copyright (c) 2024 Yushen CHEN
|
| 4 |
+
|
| 5 |
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
| 6 |
+
of this software and associated documentation files (the "Software"), to deal
|
| 7 |
+
in the Software without restriction, including without limitation the rights
|
| 8 |
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
| 9 |
+
copies of the Software, and to permit persons to whom the Software is
|
| 10 |
+
furnished to do so, subject to the following conditions:
|
| 11 |
+
|
| 12 |
+
The above copyright notice and this permission notice shall be included in all
|
| 13 |
+
copies or substantial portions of the Software.
|
| 14 |
+
|
| 15 |
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
| 16 |
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
| 17 |
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
| 18 |
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
| 19 |
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
| 20 |
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
| 21 |
+
SOFTWARE.
|
README.md
CHANGED
|
@@ -1,12 +1,105 @@
|
|
| 1 |
-
---
|
| 2 |
-
title: F5
|
| 3 |
-
|
| 4 |
-
|
| 5 |
-
|
| 6 |
-
|
| 7 |
-
|
| 8 |
-
|
| 9 |
-
|
| 10 |
-
|
| 11 |
-
|
| 12 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
---
|
| 2 |
+
title: F5-TTS-THAI
|
| 3 |
+
app_file: .
|
| 4 |
+
sdk: gradio
|
| 5 |
+
sdk_version: 5.38.0
|
| 6 |
+
---
|
| 7 |
+
# F5-TTS: A Fairytaler that Fakes Fluent and Faithful Speech with Flow Matching. Support For Thai language.
|
| 8 |
+
|
| 9 |
+
[](https://github.com/SWivid/F5-TTS)
|
| 10 |
+
[](https://arxiv.org/abs/2410.06885)
|
| 11 |
+
[](https://x-lance.sjtu.edu.cn/)
|
| 12 |
+
[](https://www.pcl.ac.cn)
|
| 13 |
+
<!-- <img src="https://github.com/user-attachments/assets/12d7749c-071a-427c-81bf-b87b91def670" alt="Watermark" style="width: 40px; height: auto"> -->
|
| 14 |
+
|
| 15 |
+
Text-to-Speech (TTS) ภาษาไทย — เครื่องมือสร้างเสียงพูดจากข้อความด้วยเทคนิค Flow Matching ด้วยโมเดล F5-TTS
|
| 16 |
+
|
| 17 |
+
โมเดล Finetune : [VIZINTZOR/F5-TTS-THAI](https://huggingface.co/VIZINTZOR/F5-TTS-THAI)
|
| 18 |
+
|
| 19 |
+
- โมเดล last steps : 1,000,000
|
| 20 |
+
- การอ่านข้อความยาวๆ หรือบางคำ ยังไม่ถูกต้อง
|
| 21 |
+
|
| 22 |
+
# การติดตั้ง
|
| 23 |
+
ก่อนเริ่มใช้งาน ต้องติดตั้ง:
|
| 24 |
+
- Python (แนะนำเวอร์ชัน 3.10 ขึ้นไป)
|
| 25 |
+
- [CUDA](https://developer.nvidia.com/cuda-downloads) แนะนำ CUDA version 11.8
|
| 26 |
+
```sh
|
| 27 |
+
git clone https://github.com/VYNCX/F5-TTS-THAI.git
|
| 28 |
+
cd F5-TTS-THAI
|
| 29 |
+
python -m venv venv
|
| 30 |
+
call venv/scripts/activate
|
| 31 |
+
pip install git+https://github.com/VYNCX/F5-TTS-THAI.git
|
| 32 |
+
|
| 33 |
+
#จำเป็นต้องติดตั้งเพื่อใช้งานได้มีประสิทธิภาพกับ GPU
|
| 34 |
+
pip install torch==2.3.0+cu118 torchaudio==2.3.0+cu118 --extra-index-url https://download.pytorch.org/whl/cu118
|
| 35 |
+
```
|
| 36 |
+
หรือ รันไฟล์ `install.bat` เพื่อติดตั้ง
|
| 37 |
+
|
| 38 |
+
# การใช้งาน
|
| 39 |
+
สามารถรันไฟล์ `app-webui.bat` เพื่อใช้งานได้
|
| 40 |
+
```sh
|
| 41 |
+
python src/f5_tts/f5_tts_webui.py
|
| 42 |
+
```
|
| 43 |
+
หรือ
|
| 44 |
+
|
| 45 |
+
```sh
|
| 46 |
+
f5-tts_webui
|
| 47 |
+
```
|
| 48 |
+
ใช้งานบน [Google Colab](https://colab.research.google.com/drive/10yb4-mGbSoyyfMyDX1xVF6uLqfeoCNxV?usp=sharing)
|
| 49 |
+
|
| 50 |
+
คำแนะนำ :
|
| 51 |
+
- สามารถตั้งค่า "ตัวอักษรสูงสุดต่อส่วน" หรือ max_chars เพื่อลดความผิดพลาดการอ่าน แต่ความเร็วในการสร้างจะช้าลง สามารถปรับลด NFE Step เพื่อเพิ่มความเร็วได้.
|
| 52 |
+
- อย่าลืมเว้นวรรคประโยคเพื่อให้สามารถแบ่งส่วนในการสร้างได้.
|
| 53 |
+
- สำหรับ ref_text หรือ ข้อความตันฉบับ แนะนำให้ใช้เป็นภาษาไทยหรือคำอ่านภาษาไทยสำหรับเสียงภาษาอื่น เพื่อให้การอ่านภาษาไทยดีขึ้น เช่น Good Morning > กู้ดมอร์นิ่ง.
|
| 54 |
+
- สำหรับเสียงต้นแบบ ควรใช้ความยาวไม่เกิน 10 วินาที ถ้าเป็นไปได้ห้ามมีเสียงรบกวน.
|
| 55 |
+
- สามารถปรับลดความเร็ว เพื่อให้การอ่านคำดีขึ้นได้ เช่น ความเร็ว 0.8-0.9 เพื่อลดการอ่านผิดหรือคำขาดหาย แต่ลดมากไปอาจมีเสียงต้นฉบับแทรกเข้ามา.
|
| 56 |
+
|
| 57 |
+
<details><summary>ตัวอย่าง WebUI</summary>
|
| 58 |
+
|
| 59 |
+
- Text To Speech
|
| 60 |
+

|
| 61 |
+
|
| 62 |
+
- Multi Speech
|
| 63 |
+

|
| 64 |
+
|
| 65 |
+
|
| 66 |
+
# ฝึกอบรม และ Finetune
|
| 67 |
+
ใช้งานบน Google Colab [Finetune](https://colab.research.google.com/drive/1jwzw4Jn1qF8-F0o3TND68hLHdIqqgYEe?usp=sharing) หรือ
|
| 68 |
+
|
| 69 |
+
ติดตั้ง
|
| 70 |
+
|
| 71 |
+
```sh
|
| 72 |
+
cd F5-TTS-THAI
|
| 73 |
+
pip install -e .
|
| 74 |
+
```
|
| 75 |
+
|
| 76 |
+
เปิด Gradio
|
| 77 |
+
```sh
|
| 78 |
+
f5-tts_finetune-gradio
|
| 79 |
+
```
|
| 80 |
+
|
| 81 |
+
# ตัวอย่าง��สียง
|
| 82 |
+
|
| 83 |
+
- เสียงต้นฉบับ
|
| 84 |
+
- ข้อความ : ได้รับข่าวคราวของเราที่จะหาที่มันเป็นไปที่จะจัดขึ้น.
|
| 85 |
+
|
| 86 |
+
https://github.com/user-attachments/assets/003c8a54-6f75-4456-907d-d28897e4c393
|
| 87 |
+
|
| 88 |
+
- เสียงที่สร้าง 1(ข้อความเดียวกัน)
|
| 89 |
+
- ข้อความ : ได้รับข่าวคราวของเราที่จะหาที่มันเป็นไปที่จะจัดขึ้น.
|
| 90 |
+
|
| 91 |
+
https://github.com/user-attachments/assets/926829f2-8d56-4f0f-8e2e-d73cfcecc511
|
| 92 |
+
|
| 93 |
+
- เสียงที่สร้าง 2(ข้อความใหม่)
|
| 94 |
+
- ข้อความ : ฉันชอบฟังเพลงขณะขับรถ เพราะช่วยให้รู้สึกผ่อนคลาย
|
| 95 |
+
|
| 96 |
+
https://github.com/user-attachments/assets/06d6e94b-5f83-4d69-99d1-ad19caa9792b
|
| 97 |
+
|
| 98 |
+
# อ้างอิง
|
| 99 |
+
|
| 100 |
+
- [F5-TTS](https://github.com/SWivid/F5-TTS)
|
| 101 |
+
|
| 102 |
+
|
| 103 |
+
|
| 104 |
+
|
| 105 |
+
|
README_DEPLOYMENT.md
ADDED
|
@@ -0,0 +1,88 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
---
|
| 2 |
+
title: F5-TTS Thai
|
| 3 |
+
emoji: 🎤
|
| 4 |
+
colorFrom: blue
|
| 5 |
+
colorTo: purple
|
| 6 |
+
sdk: gradio
|
| 7 |
+
sdk_version: 4.44.0
|
| 8 |
+
app_file: app.py
|
| 9 |
+
pinned: false
|
| 10 |
+
license: mit
|
| 11 |
+
python_version: 3.10
|
| 12 |
+
hardware: cpu-basic
|
| 13 |
+
---
|
| 14 |
+
|
| 15 |
+
# F5-TTS ภาษาไทย 🎤
|
| 16 |
+
|
| 17 |
+
Zero-shot Text-to-Speech สำหรับภาษาไทย ด้วยโมเดล F5-TTS
|
| 18 |
+
|
| 19 |
+
## ✨ Features
|
| 20 |
+
|
| 21 |
+
- **Multi-Speech Generation**: สร้างเสียงพูดหลายสไตล์ในไฟล์เดียว
|
| 22 |
+
- **Voice Cloning**: โคลนเสียงจากไฟล์ตัวอย่างสั้นๆ
|
| 23 |
+
- **Thai Language Support**: รองรับภาษาไทยอย่างเต็มรูปแบบ
|
| 24 |
+
- **Real-time Processing**: ประมวลผลแบบ real-time
|
| 25 |
+
- **Segment Editing**: แก้ไขและปรับแต่งเสียงแต่ละส่วนได้
|
| 26 |
+
|
| 27 |
+
## 🚀 วิธีใช้งาน
|
| 28 |
+
|
| 29 |
+
### Multi-Speech Generation
|
| 30 |
+
|
| 31 |
+
1. **เพิ่มประเภทคำพูด**: คลิก "เพิ่มประเภทคำพูด" เพื่อเพิ่มสไตล์เสียงใหม่
|
| 32 |
+
2. **อัปโหลดเสียงตัวอย่าง**: อัปโหลดไฟล์เสียงสำหรับแต่ละสไตล์
|
| 33 |
+
3. **ใส่ข้อความต้นฉบับ**: พิมพ์ข้อความที่สอดคล้องกับเสียงตัวอย่าง
|
| 34 |
+
4. **เขียนสคริปต์**: ใช้รูปแบบ `{ชื่อสไตล์} ข้อความที่จะพูด`
|
| 35 |
+
|
| 36 |
+
### ตัวอย่างการใช้งาน
|
| 37 |
+
|
| 38 |
+
```
|
| 39 |
+
{ปกติ} สวัสดีครับ มีอะไรให้ผมช่วยไหมครับ
|
| 40 |
+
{เศร้า} ผมเครียดจริงๆ นะตอนนี้...
|
| 41 |
+
{โกรธ} รู้ไหม! เธอไม่ควรอยู่ที่นี่!
|
| 42 |
+
{กระซิบ} ฉันมีอะไรจะบอกคุณ แต่มันเป็นความลับนะ
|
| 43 |
+
```
|
| 44 |
+
|
| 45 |
+
## ⚙️ Technical Details
|
| 46 |
+
|
| 47 |
+
### Models Used
|
| 48 |
+
- **F5-TTS**: Zero-shot text-to-speech model
|
| 49 |
+
- **Vocoder**: Neural vocoder for high-quality audio synthesis
|
| 50 |
+
- **Text Processing**: Thai text normalization and processing
|
| 51 |
+
|
| 52 |
+
### System Requirements
|
| 53 |
+
- **RAM**: อย่างน้อย 4GB (แนะนำ 8GB+)
|
| 54 |
+
- **GPU**: ไม่จำเป็น แต่จะช่วยเพิ่มความเร็ว
|
| 55 |
+
- **Storage**: ~2GB สำหรับโมเดลและ dependencies
|
| 56 |
+
|
| 57 |
+
## 🔧 Configuration
|
| 58 |
+
|
| 59 |
+
### Model Settings
|
| 60 |
+
- **NFE Steps**: ควบคุมคุณภาพเสียง (16-64)
|
| 61 |
+
- **Cross Fade Duration**: ปรับการต่อเสียงระหว่างส่วน
|
| 62 |
+
- **Speed**: ปรับความเร็วการพูด
|
| 63 |
+
- **CFG Strength**: ปรับความแข็งแกร่งของ guidance
|
| 64 |
+
|
| 65 |
+
### Tips สำหรับผลลัพธ์ที่ดี
|
| 66 |
+
1. **เสียงตัวอย่าง**: ใช้เสียงที่ชัดเจน ไม่มีเสียงรบกวน ความยาว 5-10 วินาที
|
| 67 |
+
2. **ข้อความต้นฉบับ**: ให้ตรงกับเสียงตัวอย่างที่สุด
|
| 68 |
+
3. **ข้อความที่จะสร้าง**: เว้นวรรคและใส่เครื่องหมายวรรคตอนให้ชัดเจน
|
| 69 |
+
4. **การตั้งค่า**: เริ่มด้วยค่า default แล้วค่อยปรับแต่ง
|
| 70 |
+
|
| 71 |
+
## 🚨 Limitations
|
| 72 |
+
|
| 73 |
+
- รองรับเฉพาะภาษาไทยเป็นหลัก
|
| 74 |
+
- คุณภาพเสียงขึ้นอยู่กับเสียงตัวอย่าง
|
| 75 |
+
- ใช้เวลาในการประมวลผลตามความยาวข้อความ
|
| 76 |
+
- ต้องใช้ internet เพื่อดาวน์โหลดโมเดล
|
| 77 |
+
|
| 78 |
+
## 📝 License
|
| 79 |
+
|
| 80 |
+
MIT License - ใช้งานได้อย่างอิสระ
|
| 81 |
+
|
| 82 |
+
## 🤝 Contributing
|
| 83 |
+
|
| 84 |
+
สามารถมีส่วนร่วมพัฒนาได้ที่ [GitHub Repository](https://github.com/yourusername/F5-TTS-THAI)
|
| 85 |
+
|
| 86 |
+
## 🐛 Bug Reports
|
| 87 |
+
|
| 88 |
+
หากพบปัญหาการใช้งาน กรุณาแจ้งได้ที่ Issues ของ GitHub Repository
|
REFACTORING_README.md
ADDED
|
@@ -0,0 +1,172 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
# F5-TTS Thai WebUI - Refactoring Documentation
|
| 2 |
+
|
| 3 |
+
## สรุปการ Refactoring
|
| 4 |
+
|
| 5 |
+
ไฟล์ `src/f5_tts/f5_tts_webui.py` ได้รับการปรับปรุงโครงสร้างใหม่ (refactored) เพื่อให้โค้ดมีความเป็นระเบียบ ง่ายต่อการดูแลรักษา และขยายได้ในอนาคต
|
| 6 |
+
|
| 7 |
+
## ปัญหาของโค้ดเดิม
|
| 8 |
+
|
| 9 |
+
- **ไฟล์ใหญ่เกินไป**: มีโค้ดกว่า 680 บรรทัดในไฟล์เดียว
|
| 10 |
+
- **ฟังก์ชันยาวเกินไป**: มีฟังก์ชันที่มีโค้ดหลายร้อยบรรทัด
|
| 11 |
+
- **ตัวแปร Global**: ใช้ตัวแปร global หลายตัวทำให้ยากต่อการติดตาม
|
| 12 |
+
- **การแยกหน้าที่ไม่ชัดเจน**: โค้ดสำหรับ UI, business logic, และ model management ปนกัน
|
| 13 |
+
- **การ duplicate code**: มีโค้ดที่ทำงานคล้ายกันแต่เขียนซ้ำ
|
| 14 |
+
- **ยากต่อการทดสอบ**: โค้ดเดิมยากต่อการเขียน unit tests
|
| 15 |
+
|
| 16 |
+
## โครงสร้างใหม่หลังการ Refactoring
|
| 17 |
+
|
| 18 |
+
### 1. แยกไฟล์ตามหน้าที่ (Separation of Concerns)
|
| 19 |
+
|
| 20 |
+
```
|
| 21 |
+
src/f5_tts/
|
| 22 |
+
├── config.py # Configuration และ constants
|
| 23 |
+
├── model_manager.py # จัดการโมเดล F5-TTS
|
| 24 |
+
├── tts_processor.py # ประมวลผล Text-to-Speech และ Speech-to-Text
|
| 25 |
+
├── multi_speech_processor.py # ประมวลผล Multi-Speech และ Segment Editing
|
| 26 |
+
├── ui_components.py # Gradio UI Components
|
| 27 |
+
└── f5_tts_webui.py # Main application class
|
| 28 |
+
```
|
| 29 |
+
|
| 30 |
+
### 2. Classes และ Responsibilities
|
| 31 |
+
|
| 32 |
+
#### `config.py`
|
| 33 |
+
- เก็บ constants และ configuration ทั้งหมด
|
| 34 |
+
- Model paths, default settings, UI configurations
|
| 35 |
+
- ข้อความสำหรับ UI (ตัวอย่าง, คำแนะนำ)
|
| 36 |
+
|
| 37 |
+
#### `ModelManager` class
|
| 38 |
+
- จัดการการโหลดและเปลี่ยนโมเดล F5-TTS
|
| 39 |
+
- รองรับ Default, FP16, และ Custom models
|
| 40 |
+
- จัดการ vocoder loading
|
| 41 |
+
- Error handling สำหรับการโหลดโมเดล
|
| 42 |
+
|
| 43 |
+
#### `TTSProcessor` class
|
| 44 |
+
- ประมวลผล Text-to-Speech
|
| 45 |
+
- จัดการ seed generation และ validation
|
| 46 |
+
- Audio preprocessing และ postprocessing
|
| 47 |
+
- Spectrogram generation
|
| 48 |
+
|
| 49 |
+
#### `SpeechToTextProcessor` class
|
| 50 |
+
- ประมวลผล Speech-to-Text ด้วย Whisper
|
| 51 |
+
- รองรับการแปลภาษา
|
| 52 |
+
- จัดการ model configurations
|
| 53 |
+
|
| 54 |
+
#### `MultiSpeechProcessor` class
|
| 55 |
+
- ประมวลผล Multi-Speech generation
|
| 56 |
+
- จัดการ speech types และ segments
|
| 57 |
+
- Segment editing และ regeneration
|
| 58 |
+
- Silence management
|
| 59 |
+
|
| 60 |
+
#### `UIComponents` class
|
| 61 |
+
- สร้าง Gradio components
|
| 62 |
+
- จัดการ speech type management
|
| 63 |
+
- แยก UI logic ออกจาก business logic
|
| 64 |
+
|
| 65 |
+
#### `F5TTSWebUI` class
|
| 66 |
+
- Main application class
|
| 67 |
+
- ประสานงานระหว่าง components
|
| 68 |
+
- Event handling และ binding
|
| 69 |
+
|
| 70 |
+
## ประโยชน์ของการ Refactoring
|
| 71 |
+
|
| 72 |
+
### 1. **Maintainability (ความง่ายในการดูแลรักษา)**
|
| 73 |
+
- โค้ดแต่ละส่วนมีหน้าที่ชัดเจน
|
| 74 |
+
- แก้ไขส่วนใดส่วนหนึ่งไม่กระทบส่วนอื่น
|
| 75 |
+
- ง่ายต่อการค้นหาและแก้ไข bugs
|
| 76 |
+
|
| 77 |
+
### 2. **Reusability (การใช้ซ้ำได้)**
|
| 78 |
+
- Classes สามารถนำไปใช้ในโปรเจ็กต์อื่นได้
|
| 79 |
+
- Components สามารถใช้งานแยกจากกันได้
|
| 80 |
+
|
| 81 |
+
### 3. **Testability (การทดสอบได้)**
|
| 82 |
+
- สามารถเขียน unit tests สำหรับแต่ละ class ได้
|
| 83 |
+
- Mock dependencies ได้ง่าย
|
| 84 |
+
- Isolated testing สำหรับแต่ละ functionality
|
| 85 |
+
|
| 86 |
+
### 4. **Scalability (การขยายได้)**
|
| 87 |
+
- เพิ่ม features ใหม่ได้ง่าย
|
| 88 |
+
- เปลี่ยนแปลง implementation ได้โดยไม่กระทบส่วนอื่น
|
| 89 |
+
- รองรับการเพิ่ม model types ใหม่
|
| 90 |
+
|
| 91 |
+
### 5. **Readability (ความอ่านง่าย)**
|
| 92 |
+
- โค้ดสั้นลงในแต่ละไฟล์
|
| 93 |
+
- ชื่อ class และ method สื่อความหมายชัดเจน
|
| 94 |
+
- Documentation ครบ���้วน
|
| 95 |
+
|
| 96 |
+
## วิธีการใช้งานหลังการ Refactoring
|
| 97 |
+
|
| 98 |
+
### การรันแอพพลิเคชั่น
|
| 99 |
+
```python
|
| 100 |
+
from f5_tts.f5_tts_webui import main
|
| 101 |
+
|
| 102 |
+
# หรือ
|
| 103 |
+
python -m f5_tts.f5_tts_webui --share
|
| 104 |
+
```
|
| 105 |
+
|
| 106 |
+
### การใช้งาน Components แยกต่างหาก
|
| 107 |
+
```python
|
| 108 |
+
from f5_tts.model_manager import ModelManager
|
| 109 |
+
from f5_tts.tts_processor import TTSProcessor
|
| 110 |
+
|
| 111 |
+
# สร้าง model manager
|
| 112 |
+
model_manager = ModelManager()
|
| 113 |
+
|
| 114 |
+
# สร้าง TTS processor
|
| 115 |
+
tts_processor = TTSProcessor(model_manager)
|
| 116 |
+
|
| 117 |
+
# ใช้งาน TTS
|
| 118 |
+
result = tts_processor.infer_tts(
|
| 119 |
+
ref_audio="path/to/audio.wav",
|
| 120 |
+
ref_text="เสียงต้นฉบับ",
|
| 121 |
+
gen_text="ข้อความที่จะสร้าง"
|
| 122 |
+
)
|
| 123 |
+
```
|
| 124 |
+
|
| 125 |
+
## การเปลี่ยนแปลงที่สำคัญ
|
| 126 |
+
|
| 127 |
+
### 1. **ไม่มีตัวแปร Global แล้ว**
|
| 128 |
+
- `f5tts_model` และ `vocoder` ถูกย้ายไปอยู่ใน `ModelManager`
|
| 129 |
+
- ใช้ dependency injection แทน global state
|
| 130 |
+
|
| 131 |
+
### 2. **Error Handling ที่ดีขึ้น**
|
| 132 |
+
- ตรวจสอบ errors ใน model loading
|
| 133 |
+
- Graceful handling สำหรับ invalid inputs
|
| 134 |
+
|
| 135 |
+
### 3. **Configuration Management**
|
| 136 |
+
- Constants ทั้งหมดอยู่ในที่เดียว
|
| 137 |
+
- ง่ายต่อการเปลี่ยนแปลง configuration
|
| 138 |
+
|
| 139 |
+
### 4. **Type Safety**
|
| 140 |
+
- ใช้ type hints ในฟังก์ชันสำคัญ
|
| 141 |
+
- ลดความเสี่ยงของ runtime errors
|
| 142 |
+
|
| 143 |
+
## การทดสอบ
|
| 144 |
+
|
| 145 |
+
หลังจากการ refactoring สามารถเขียนและรัน tests ได้:
|
| 146 |
+
|
| 147 |
+
```python
|
| 148 |
+
# ตัวอย่าง unit test
|
| 149 |
+
def test_model_manager():
|
| 150 |
+
manager = ModelManager()
|
| 151 |
+
assert manager.get_model() is not None
|
| 152 |
+
assert manager.get_vocoder() is not None
|
| 153 |
+
|
| 154 |
+
def test_tts_processor():
|
| 155 |
+
model_manager = ModelManager()
|
| 156 |
+
processor = TTSProcessor(model_manager)
|
| 157 |
+
# Test TTS functionality
|
| 158 |
+
```
|
| 159 |
+
|
| 160 |
+
## อนาคต
|
| 161 |
+
|
| 162 |
+
การ refactoring นี้เป็นฐานสำหรับการพัฒนาต่อไปในอนาคต:
|
| 163 |
+
|
| 164 |
+
1. **เพิ่ม Model Types ใหม่**: ง่ายต่อการเพิ่ม support สำหรับโมเดลใหม่
|
| 165 |
+
2. **API Endpoints**: สามารถสร้าง REST API ได้ง่าย
|
| 166 |
+
3. **Batch Processing**: เพิ่ม functionality สำหรับประมวลผลหลายไฟล์
|
| 167 |
+
4. **Advanced Features**: เพิ่ม features เช่น voice cloning, style transfer
|
| 168 |
+
5. **Performance Optimization**: ปรับปรุงประสิทธิภาพได้ง่าย
|
| 169 |
+
|
| 170 |
+
## สรุป
|
| 171 |
+
|
| 172 |
+
การ refactoring นี้ทำให้โค้ดมีคุณภาพดีขึ้นอย่างมาก พร้อมสำหรับการพัฒนาและขยายในอนาคต ในขณะที่ยังคงความสามารถเดิมทุกอย่างไว้
|
app-webui.bat
ADDED
|
@@ -0,0 +1,9 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
@echo off
|
| 2 |
+
|
| 3 |
+
set "current_dir=%CD%"
|
| 4 |
+
|
| 5 |
+
call venv/scripts/activate
|
| 6 |
+
|
| 7 |
+
python src/f5_tts/f5_tts_webui.py
|
| 8 |
+
|
| 9 |
+
pause
|
app.py
ADDED
|
@@ -0,0 +1,7 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
import gradio as gr
|
| 2 |
+
|
| 3 |
+
def greet(name):
|
| 4 |
+
return "Hello " + name + "!!"
|
| 5 |
+
|
| 6 |
+
demo = gr.Interface(fn=greet, inputs="text", outputs="text")
|
| 7 |
+
demo.launch()
|
ckpts/README.md
ADDED
|
@@ -0,0 +1,10 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
|
| 2 |
+
Pretrained model ckpts. https://huggingface.co/SWivid/F5-TTS
|
| 3 |
+
|
| 4 |
+
```
|
| 5 |
+
ckpts/
|
| 6 |
+
E2TTS_Base/
|
| 7 |
+
model_1200000.pt
|
| 8 |
+
F5TTS_Base/
|
| 9 |
+
model_1200000.pt
|
| 10 |
+
```
|
data/Emilia_ZH_EN_pinyin/vocab.txt
ADDED
|
@@ -0,0 +1,2586 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
|
| 2 |
+
!
|
| 3 |
+
"
|
| 4 |
+
#
|
| 5 |
+
$
|
| 6 |
+
%
|
| 7 |
+
&
|
| 8 |
+
'
|
| 9 |
+
(
|
| 10 |
+
)
|
| 11 |
+
*
|
| 12 |
+
+
|
| 13 |
+
,
|
| 14 |
+
-
|
| 15 |
+
.
|
| 16 |
+
/
|
| 17 |
+
0
|
| 18 |
+
1
|
| 19 |
+
2
|
| 20 |
+
3
|
| 21 |
+
4
|
| 22 |
+
5
|
| 23 |
+
6
|
| 24 |
+
7
|
| 25 |
+
8
|
| 26 |
+
9
|
| 27 |
+
:
|
| 28 |
+
;
|
| 29 |
+
=
|
| 30 |
+
>
|
| 31 |
+
?
|
| 32 |
+
@
|
| 33 |
+
A
|
| 34 |
+
B
|
| 35 |
+
C
|
| 36 |
+
D
|
| 37 |
+
E
|
| 38 |
+
F
|
| 39 |
+
G
|
| 40 |
+
H
|
| 41 |
+
I
|
| 42 |
+
J
|
| 43 |
+
K
|
| 44 |
+
L
|
| 45 |
+
M
|
| 46 |
+
N
|
| 47 |
+
O
|
| 48 |
+
P
|
| 49 |
+
Q
|
| 50 |
+
R
|
| 51 |
+
S
|
| 52 |
+
T
|
| 53 |
+
U
|
| 54 |
+
V
|
| 55 |
+
W
|
| 56 |
+
X
|
| 57 |
+
Y
|
| 58 |
+
Z
|
| 59 |
+
[
|
| 60 |
+
\
|
| 61 |
+
]
|
| 62 |
+
_
|
| 63 |
+
a
|
| 64 |
+
a1
|
| 65 |
+
ai1
|
| 66 |
+
ai2
|
| 67 |
+
ai3
|
| 68 |
+
ai4
|
| 69 |
+
an1
|
| 70 |
+
an3
|
| 71 |
+
an4
|
| 72 |
+
ang1
|
| 73 |
+
ang2
|
| 74 |
+
ang4
|
| 75 |
+
ao1
|
| 76 |
+
ao2
|
| 77 |
+
ao3
|
| 78 |
+
ao4
|
| 79 |
+
b
|
| 80 |
+
ba
|
| 81 |
+
ba1
|
| 82 |
+
ba2
|
| 83 |
+
ba3
|
| 84 |
+
ba4
|
| 85 |
+
bai1
|
| 86 |
+
bai2
|
| 87 |
+
bai3
|
| 88 |
+
bai4
|
| 89 |
+
ban1
|
| 90 |
+
ban2
|
| 91 |
+
ban3
|
| 92 |
+
ban4
|
| 93 |
+
bang1
|
| 94 |
+
bang2
|
| 95 |
+
bang3
|
| 96 |
+
bang4
|
| 97 |
+
bao1
|
| 98 |
+
bao2
|
| 99 |
+
bao3
|
| 100 |
+
bao4
|
| 101 |
+
bei
|
| 102 |
+
bei1
|
| 103 |
+
bei2
|
| 104 |
+
bei3
|
| 105 |
+
bei4
|
| 106 |
+
ben1
|
| 107 |
+
ben2
|
| 108 |
+
ben3
|
| 109 |
+
ben4
|
| 110 |
+
beng
|
| 111 |
+
beng1
|
| 112 |
+
beng2
|
| 113 |
+
beng3
|
| 114 |
+
beng4
|
| 115 |
+
bi1
|
| 116 |
+
bi2
|
| 117 |
+
bi3
|
| 118 |
+
bi4
|
| 119 |
+
bian1
|
| 120 |
+
bian2
|
| 121 |
+
bian3
|
| 122 |
+
bian4
|
| 123 |
+
biao1
|
| 124 |
+
biao2
|
| 125 |
+
biao3
|
| 126 |
+
bie1
|
| 127 |
+
bie2
|
| 128 |
+
bie3
|
| 129 |
+
bie4
|
| 130 |
+
bin1
|
| 131 |
+
bin4
|
| 132 |
+
bing1
|
| 133 |
+
bing2
|
| 134 |
+
bing3
|
| 135 |
+
bing4
|
| 136 |
+
bo
|
| 137 |
+
bo1
|
| 138 |
+
bo2
|
| 139 |
+
bo3
|
| 140 |
+
bo4
|
| 141 |
+
bu2
|
| 142 |
+
bu3
|
| 143 |
+
bu4
|
| 144 |
+
c
|
| 145 |
+
ca1
|
| 146 |
+
cai1
|
| 147 |
+
cai2
|
| 148 |
+
cai3
|
| 149 |
+
cai4
|
| 150 |
+
can1
|
| 151 |
+
can2
|
| 152 |
+
can3
|
| 153 |
+
can4
|
| 154 |
+
cang1
|
| 155 |
+
cang2
|
| 156 |
+
cao1
|
| 157 |
+
cao2
|
| 158 |
+
cao3
|
| 159 |
+
ce4
|
| 160 |
+
cen1
|
| 161 |
+
cen2
|
| 162 |
+
ceng1
|
| 163 |
+
ceng2
|
| 164 |
+
ceng4
|
| 165 |
+
cha1
|
| 166 |
+
cha2
|
| 167 |
+
cha3
|
| 168 |
+
cha4
|
| 169 |
+
chai1
|
| 170 |
+
chai2
|
| 171 |
+
chan1
|
| 172 |
+
chan2
|
| 173 |
+
chan3
|
| 174 |
+
chan4
|
| 175 |
+
chang1
|
| 176 |
+
chang2
|
| 177 |
+
chang3
|
| 178 |
+
chang4
|
| 179 |
+
chao1
|
| 180 |
+
chao2
|
| 181 |
+
chao3
|
| 182 |
+
che1
|
| 183 |
+
che2
|
| 184 |
+
che3
|
| 185 |
+
che4
|
| 186 |
+
chen1
|
| 187 |
+
chen2
|
| 188 |
+
chen3
|
| 189 |
+
chen4
|
| 190 |
+
cheng1
|
| 191 |
+
cheng2
|
| 192 |
+
cheng3
|
| 193 |
+
cheng4
|
| 194 |
+
chi1
|
| 195 |
+
chi2
|
| 196 |
+
chi3
|
| 197 |
+
chi4
|
| 198 |
+
chong1
|
| 199 |
+
chong2
|
| 200 |
+
chong3
|
| 201 |
+
chong4
|
| 202 |
+
chou1
|
| 203 |
+
chou2
|
| 204 |
+
chou3
|
| 205 |
+
chou4
|
| 206 |
+
chu1
|
| 207 |
+
chu2
|
| 208 |
+
chu3
|
| 209 |
+
chu4
|
| 210 |
+
chua1
|
| 211 |
+
chuai1
|
| 212 |
+
chuai2
|
| 213 |
+
chuai3
|
| 214 |
+
chuai4
|
| 215 |
+
chuan1
|
| 216 |
+
chuan2
|
| 217 |
+
chuan3
|
| 218 |
+
chuan4
|
| 219 |
+
chuang1
|
| 220 |
+
chuang2
|
| 221 |
+
chuang3
|
| 222 |
+
chuang4
|
| 223 |
+
chui1
|
| 224 |
+
chui2
|
| 225 |
+
chun1
|
| 226 |
+
chun2
|
| 227 |
+
chun3
|
| 228 |
+
chuo1
|
| 229 |
+
chuo4
|
| 230 |
+
ci1
|
| 231 |
+
ci2
|
| 232 |
+
ci3
|
| 233 |
+
ci4
|
| 234 |
+
cong1
|
| 235 |
+
cong2
|
| 236 |
+
cou4
|
| 237 |
+
cu1
|
| 238 |
+
cu4
|
| 239 |
+
cuan1
|
| 240 |
+
cuan2
|
| 241 |
+
cuan4
|
| 242 |
+
cui1
|
| 243 |
+
cui3
|
| 244 |
+
cui4
|
| 245 |
+
cun1
|
| 246 |
+
cun2
|
| 247 |
+
cun4
|
| 248 |
+
cuo1
|
| 249 |
+
cuo2
|
| 250 |
+
cuo4
|
| 251 |
+
d
|
| 252 |
+
da
|
| 253 |
+
da1
|
| 254 |
+
da2
|
| 255 |
+
da3
|
| 256 |
+
da4
|
| 257 |
+
dai1
|
| 258 |
+
dai2
|
| 259 |
+
dai3
|
| 260 |
+
dai4
|
| 261 |
+
dan1
|
| 262 |
+
dan2
|
| 263 |
+
dan3
|
| 264 |
+
dan4
|
| 265 |
+
dang1
|
| 266 |
+
dang2
|
| 267 |
+
dang3
|
| 268 |
+
dang4
|
| 269 |
+
dao1
|
| 270 |
+
dao2
|
| 271 |
+
dao3
|
| 272 |
+
dao4
|
| 273 |
+
de
|
| 274 |
+
de1
|
| 275 |
+
de2
|
| 276 |
+
dei3
|
| 277 |
+
den4
|
| 278 |
+
deng1
|
| 279 |
+
deng2
|
| 280 |
+
deng3
|
| 281 |
+
deng4
|
| 282 |
+
di1
|
| 283 |
+
di2
|
| 284 |
+
di3
|
| 285 |
+
di4
|
| 286 |
+
dia3
|
| 287 |
+
dian1
|
| 288 |
+
dian2
|
| 289 |
+
dian3
|
| 290 |
+
dian4
|
| 291 |
+
diao1
|
| 292 |
+
diao3
|
| 293 |
+
diao4
|
| 294 |
+
die1
|
| 295 |
+
die2
|
| 296 |
+
die4
|
| 297 |
+
ding1
|
| 298 |
+
ding2
|
| 299 |
+
ding3
|
| 300 |
+
ding4
|
| 301 |
+
diu1
|
| 302 |
+
dong1
|
| 303 |
+
dong3
|
| 304 |
+
dong4
|
| 305 |
+
dou1
|
| 306 |
+
dou2
|
| 307 |
+
dou3
|
| 308 |
+
dou4
|
| 309 |
+
du1
|
| 310 |
+
du2
|
| 311 |
+
du3
|
| 312 |
+
du4
|
| 313 |
+
duan1
|
| 314 |
+
duan2
|
| 315 |
+
duan3
|
| 316 |
+
duan4
|
| 317 |
+
dui1
|
| 318 |
+
dui4
|
| 319 |
+
dun1
|
| 320 |
+
dun3
|
| 321 |
+
dun4
|
| 322 |
+
duo1
|
| 323 |
+
duo2
|
| 324 |
+
duo3
|
| 325 |
+
duo4
|
| 326 |
+
e
|
| 327 |
+
e1
|
| 328 |
+
e2
|
| 329 |
+
e3
|
| 330 |
+
e4
|
| 331 |
+
ei2
|
| 332 |
+
en1
|
| 333 |
+
en4
|
| 334 |
+
er
|
| 335 |
+
er2
|
| 336 |
+
er3
|
| 337 |
+
er4
|
| 338 |
+
f
|
| 339 |
+
fa1
|
| 340 |
+
fa2
|
| 341 |
+
fa3
|
| 342 |
+
fa4
|
| 343 |
+
fan1
|
| 344 |
+
fan2
|
| 345 |
+
fan3
|
| 346 |
+
fan4
|
| 347 |
+
fang1
|
| 348 |
+
fang2
|
| 349 |
+
fang3
|
| 350 |
+
fang4
|
| 351 |
+
fei1
|
| 352 |
+
fei2
|
| 353 |
+
fei3
|
| 354 |
+
fei4
|
| 355 |
+
fen1
|
| 356 |
+
fen2
|
| 357 |
+
fen3
|
| 358 |
+
fen4
|
| 359 |
+
feng1
|
| 360 |
+
feng2
|
| 361 |
+
feng3
|
| 362 |
+
feng4
|
| 363 |
+
fo2
|
| 364 |
+
fou2
|
| 365 |
+
fou3
|
| 366 |
+
fu1
|
| 367 |
+
fu2
|
| 368 |
+
fu3
|
| 369 |
+
fu4
|
| 370 |
+
g
|
| 371 |
+
ga1
|
| 372 |
+
ga2
|
| 373 |
+
ga3
|
| 374 |
+
ga4
|
| 375 |
+
gai1
|
| 376 |
+
gai2
|
| 377 |
+
gai3
|
| 378 |
+
gai4
|
| 379 |
+
gan1
|
| 380 |
+
gan2
|
| 381 |
+
gan3
|
| 382 |
+
gan4
|
| 383 |
+
gang1
|
| 384 |
+
gang2
|
| 385 |
+
gang3
|
| 386 |
+
gang4
|
| 387 |
+
gao1
|
| 388 |
+
gao2
|
| 389 |
+
gao3
|
| 390 |
+
gao4
|
| 391 |
+
ge1
|
| 392 |
+
ge2
|
| 393 |
+
ge3
|
| 394 |
+
ge4
|
| 395 |
+
gei2
|
| 396 |
+
gei3
|
| 397 |
+
gen1
|
| 398 |
+
gen2
|
| 399 |
+
gen3
|
| 400 |
+
gen4
|
| 401 |
+
geng1
|
| 402 |
+
geng3
|
| 403 |
+
geng4
|
| 404 |
+
gong1
|
| 405 |
+
gong3
|
| 406 |
+
gong4
|
| 407 |
+
gou1
|
| 408 |
+
gou2
|
| 409 |
+
gou3
|
| 410 |
+
gou4
|
| 411 |
+
gu
|
| 412 |
+
gu1
|
| 413 |
+
gu2
|
| 414 |
+
gu3
|
| 415 |
+
gu4
|
| 416 |
+
gua1
|
| 417 |
+
gua2
|
| 418 |
+
gua3
|
| 419 |
+
gua4
|
| 420 |
+
guai1
|
| 421 |
+
guai2
|
| 422 |
+
guai3
|
| 423 |
+
guai4
|
| 424 |
+
guan1
|
| 425 |
+
guan2
|
| 426 |
+
guan3
|
| 427 |
+
guan4
|
| 428 |
+
guang1
|
| 429 |
+
guang2
|
| 430 |
+
guang3
|
| 431 |
+
guang4
|
| 432 |
+
gui1
|
| 433 |
+
gui2
|
| 434 |
+
gui3
|
| 435 |
+
gui4
|
| 436 |
+
gun3
|
| 437 |
+
gun4
|
| 438 |
+
guo1
|
| 439 |
+
guo2
|
| 440 |
+
guo3
|
| 441 |
+
guo4
|
| 442 |
+
h
|
| 443 |
+
ha1
|
| 444 |
+
ha2
|
| 445 |
+
ha3
|
| 446 |
+
hai1
|
| 447 |
+
hai2
|
| 448 |
+
hai3
|
| 449 |
+
hai4
|
| 450 |
+
han1
|
| 451 |
+
han2
|
| 452 |
+
han3
|
| 453 |
+
han4
|
| 454 |
+
hang1
|
| 455 |
+
hang2
|
| 456 |
+
hang4
|
| 457 |
+
hao1
|
| 458 |
+
hao2
|
| 459 |
+
hao3
|
| 460 |
+
hao4
|
| 461 |
+
he1
|
| 462 |
+
he2
|
| 463 |
+
he4
|
| 464 |
+
hei1
|
| 465 |
+
hen2
|
| 466 |
+
hen3
|
| 467 |
+
hen4
|
| 468 |
+
heng1
|
| 469 |
+
heng2
|
| 470 |
+
heng4
|
| 471 |
+
hong1
|
| 472 |
+
hong2
|
| 473 |
+
hong3
|
| 474 |
+
hong4
|
| 475 |
+
hou1
|
| 476 |
+
hou2
|
| 477 |
+
hou3
|
| 478 |
+
hou4
|
| 479 |
+
hu1
|
| 480 |
+
hu2
|
| 481 |
+
hu3
|
| 482 |
+
hu4
|
| 483 |
+
hua1
|
| 484 |
+
hua2
|
| 485 |
+
hua4
|
| 486 |
+
huai2
|
| 487 |
+
huai4
|
| 488 |
+
huan1
|
| 489 |
+
huan2
|
| 490 |
+
huan3
|
| 491 |
+
huan4
|
| 492 |
+
huang1
|
| 493 |
+
huang2
|
| 494 |
+
huang3
|
| 495 |
+
huang4
|
| 496 |
+
hui1
|
| 497 |
+
hui2
|
| 498 |
+
hui3
|
| 499 |
+
hui4
|
| 500 |
+
hun1
|
| 501 |
+
hun2
|
| 502 |
+
hun4
|
| 503 |
+
huo
|
| 504 |
+
huo1
|
| 505 |
+
huo2
|
| 506 |
+
huo3
|
| 507 |
+
huo4
|
| 508 |
+
i
|
| 509 |
+
j
|
| 510 |
+
ji1
|
| 511 |
+
ji2
|
| 512 |
+
ji3
|
| 513 |
+
ji4
|
| 514 |
+
jia
|
| 515 |
+
jia1
|
| 516 |
+
jia2
|
| 517 |
+
jia3
|
| 518 |
+
jia4
|
| 519 |
+
jian1
|
| 520 |
+
jian2
|
| 521 |
+
jian3
|
| 522 |
+
jian4
|
| 523 |
+
jiang1
|
| 524 |
+
jiang2
|
| 525 |
+
jiang3
|
| 526 |
+
jiang4
|
| 527 |
+
jiao1
|
| 528 |
+
jiao2
|
| 529 |
+
jiao3
|
| 530 |
+
jiao4
|
| 531 |
+
jie1
|
| 532 |
+
jie2
|
| 533 |
+
jie3
|
| 534 |
+
jie4
|
| 535 |
+
jin1
|
| 536 |
+
jin2
|
| 537 |
+
jin3
|
| 538 |
+
jin4
|
| 539 |
+
jing1
|
| 540 |
+
jing2
|
| 541 |
+
jing3
|
| 542 |
+
jing4
|
| 543 |
+
jiong3
|
| 544 |
+
jiu1
|
| 545 |
+
jiu2
|
| 546 |
+
jiu3
|
| 547 |
+
jiu4
|
| 548 |
+
ju1
|
| 549 |
+
ju2
|
| 550 |
+
ju3
|
| 551 |
+
ju4
|
| 552 |
+
juan1
|
| 553 |
+
juan2
|
| 554 |
+
juan3
|
| 555 |
+
juan4
|
| 556 |
+
jue1
|
| 557 |
+
jue2
|
| 558 |
+
jue4
|
| 559 |
+
jun1
|
| 560 |
+
jun4
|
| 561 |
+
k
|
| 562 |
+
ka1
|
| 563 |
+
ka2
|
| 564 |
+
ka3
|
| 565 |
+
kai1
|
| 566 |
+
kai2
|
| 567 |
+
kai3
|
| 568 |
+
kai4
|
| 569 |
+
kan1
|
| 570 |
+
kan2
|
| 571 |
+
kan3
|
| 572 |
+
kan4
|
| 573 |
+
kang1
|
| 574 |
+
kang2
|
| 575 |
+
kang4
|
| 576 |
+
kao1
|
| 577 |
+
kao2
|
| 578 |
+
kao3
|
| 579 |
+
kao4
|
| 580 |
+
ke1
|
| 581 |
+
ke2
|
| 582 |
+
ke3
|
| 583 |
+
ke4
|
| 584 |
+
ken3
|
| 585 |
+
keng1
|
| 586 |
+
kong1
|
| 587 |
+
kong3
|
| 588 |
+
kong4
|
| 589 |
+
kou1
|
| 590 |
+
kou2
|
| 591 |
+
kou3
|
| 592 |
+
kou4
|
| 593 |
+
ku1
|
| 594 |
+
ku2
|
| 595 |
+
ku3
|
| 596 |
+
ku4
|
| 597 |
+
kua1
|
| 598 |
+
kua3
|
| 599 |
+
kua4
|
| 600 |
+
kuai3
|
| 601 |
+
kuai4
|
| 602 |
+
kuan1
|
| 603 |
+
kuan2
|
| 604 |
+
kuan3
|
| 605 |
+
kuang1
|
| 606 |
+
kuang2
|
| 607 |
+
kuang4
|
| 608 |
+
kui1
|
| 609 |
+
kui2
|
| 610 |
+
kui3
|
| 611 |
+
kui4
|
| 612 |
+
kun1
|
| 613 |
+
kun3
|
| 614 |
+
kun4
|
| 615 |
+
kuo4
|
| 616 |
+
l
|
| 617 |
+
la
|
| 618 |
+
la1
|
| 619 |
+
la2
|
| 620 |
+
la3
|
| 621 |
+
la4
|
| 622 |
+
lai2
|
| 623 |
+
lai4
|
| 624 |
+
lan2
|
| 625 |
+
lan3
|
| 626 |
+
lan4
|
| 627 |
+
lang1
|
| 628 |
+
lang2
|
| 629 |
+
lang3
|
| 630 |
+
lang4
|
| 631 |
+
lao1
|
| 632 |
+
lao2
|
| 633 |
+
lao3
|
| 634 |
+
lao4
|
| 635 |
+
le
|
| 636 |
+
le1
|
| 637 |
+
le4
|
| 638 |
+
lei
|
| 639 |
+
lei1
|
| 640 |
+
lei2
|
| 641 |
+
lei3
|
| 642 |
+
lei4
|
| 643 |
+
leng1
|
| 644 |
+
leng2
|
| 645 |
+
leng3
|
| 646 |
+
leng4
|
| 647 |
+
li
|
| 648 |
+
li1
|
| 649 |
+
li2
|
| 650 |
+
li3
|
| 651 |
+
li4
|
| 652 |
+
lia3
|
| 653 |
+
lian2
|
| 654 |
+
lian3
|
| 655 |
+
lian4
|
| 656 |
+
liang2
|
| 657 |
+
liang3
|
| 658 |
+
liang4
|
| 659 |
+
liao1
|
| 660 |
+
liao2
|
| 661 |
+
liao3
|
| 662 |
+
liao4
|
| 663 |
+
lie1
|
| 664 |
+
lie2
|
| 665 |
+
lie3
|
| 666 |
+
lie4
|
| 667 |
+
lin1
|
| 668 |
+
lin2
|
| 669 |
+
lin3
|
| 670 |
+
lin4
|
| 671 |
+
ling2
|
| 672 |
+
ling3
|
| 673 |
+
ling4
|
| 674 |
+
liu1
|
| 675 |
+
liu2
|
| 676 |
+
liu3
|
| 677 |
+
liu4
|
| 678 |
+
long1
|
| 679 |
+
long2
|
| 680 |
+
long3
|
| 681 |
+
long4
|
| 682 |
+
lou1
|
| 683 |
+
lou2
|
| 684 |
+
lou3
|
| 685 |
+
lou4
|
| 686 |
+
lu1
|
| 687 |
+
lu2
|
| 688 |
+
lu3
|
| 689 |
+
lu4
|
| 690 |
+
luan2
|
| 691 |
+
luan3
|
| 692 |
+
luan4
|
| 693 |
+
lun1
|
| 694 |
+
lun2
|
| 695 |
+
lun4
|
| 696 |
+
luo1
|
| 697 |
+
luo2
|
| 698 |
+
luo3
|
| 699 |
+
luo4
|
| 700 |
+
lv2
|
| 701 |
+
lv3
|
| 702 |
+
lv4
|
| 703 |
+
lve3
|
| 704 |
+
lve4
|
| 705 |
+
m
|
| 706 |
+
ma
|
| 707 |
+
ma1
|
| 708 |
+
ma2
|
| 709 |
+
ma3
|
| 710 |
+
ma4
|
| 711 |
+
mai2
|
| 712 |
+
mai3
|
| 713 |
+
mai4
|
| 714 |
+
man1
|
| 715 |
+
man2
|
| 716 |
+
man3
|
| 717 |
+
man4
|
| 718 |
+
mang2
|
| 719 |
+
mang3
|
| 720 |
+
mao1
|
| 721 |
+
mao2
|
| 722 |
+
mao3
|
| 723 |
+
mao4
|
| 724 |
+
me
|
| 725 |
+
mei2
|
| 726 |
+
mei3
|
| 727 |
+
mei4
|
| 728 |
+
men
|
| 729 |
+
men1
|
| 730 |
+
men2
|
| 731 |
+
men4
|
| 732 |
+
meng
|
| 733 |
+
meng1
|
| 734 |
+
meng2
|
| 735 |
+
meng3
|
| 736 |
+
meng4
|
| 737 |
+
mi1
|
| 738 |
+
mi2
|
| 739 |
+
mi3
|
| 740 |
+
mi4
|
| 741 |
+
mian2
|
| 742 |
+
mian3
|
| 743 |
+
mian4
|
| 744 |
+
miao1
|
| 745 |
+
miao2
|
| 746 |
+
miao3
|
| 747 |
+
miao4
|
| 748 |
+
mie1
|
| 749 |
+
mie4
|
| 750 |
+
min2
|
| 751 |
+
min3
|
| 752 |
+
ming2
|
| 753 |
+
ming3
|
| 754 |
+
ming4
|
| 755 |
+
miu4
|
| 756 |
+
mo1
|
| 757 |
+
mo2
|
| 758 |
+
mo3
|
| 759 |
+
mo4
|
| 760 |
+
mou1
|
| 761 |
+
mou2
|
| 762 |
+
mou3
|
| 763 |
+
mu2
|
| 764 |
+
mu3
|
| 765 |
+
mu4
|
| 766 |
+
n
|
| 767 |
+
n2
|
| 768 |
+
na1
|
| 769 |
+
na2
|
| 770 |
+
na3
|
| 771 |
+
na4
|
| 772 |
+
nai2
|
| 773 |
+
nai3
|
| 774 |
+
nai4
|
| 775 |
+
nan1
|
| 776 |
+
nan2
|
| 777 |
+
nan3
|
| 778 |
+
nan4
|
| 779 |
+
nang1
|
| 780 |
+
nang2
|
| 781 |
+
nang3
|
| 782 |
+
nao1
|
| 783 |
+
nao2
|
| 784 |
+
nao3
|
| 785 |
+
nao4
|
| 786 |
+
ne
|
| 787 |
+
ne2
|
| 788 |
+
ne4
|
| 789 |
+
nei3
|
| 790 |
+
nei4
|
| 791 |
+
nen4
|
| 792 |
+
neng2
|
| 793 |
+
ni1
|
| 794 |
+
ni2
|
| 795 |
+
ni3
|
| 796 |
+
ni4
|
| 797 |
+
nian1
|
| 798 |
+
nian2
|
| 799 |
+
nian3
|
| 800 |
+
nian4
|
| 801 |
+
niang2
|
| 802 |
+
niang4
|
| 803 |
+
niao2
|
| 804 |
+
niao3
|
| 805 |
+
niao4
|
| 806 |
+
nie1
|
| 807 |
+
nie4
|
| 808 |
+
nin2
|
| 809 |
+
ning2
|
| 810 |
+
ning3
|
| 811 |
+
ning4
|
| 812 |
+
niu1
|
| 813 |
+
niu2
|
| 814 |
+
niu3
|
| 815 |
+
niu4
|
| 816 |
+
nong2
|
| 817 |
+
nong4
|
| 818 |
+
nou4
|
| 819 |
+
nu2
|
| 820 |
+
nu3
|
| 821 |
+
nu4
|
| 822 |
+
nuan3
|
| 823 |
+
nuo2
|
| 824 |
+
nuo4
|
| 825 |
+
nv2
|
| 826 |
+
nv3
|
| 827 |
+
nve4
|
| 828 |
+
o
|
| 829 |
+
o1
|
| 830 |
+
o2
|
| 831 |
+
ou1
|
| 832 |
+
ou2
|
| 833 |
+
ou3
|
| 834 |
+
ou4
|
| 835 |
+
p
|
| 836 |
+
pa1
|
| 837 |
+
pa2
|
| 838 |
+
pa4
|
| 839 |
+
pai1
|
| 840 |
+
pai2
|
| 841 |
+
pai3
|
| 842 |
+
pai4
|
| 843 |
+
pan1
|
| 844 |
+
pan2
|
| 845 |
+
pan4
|
| 846 |
+
pang1
|
| 847 |
+
pang2
|
| 848 |
+
pang4
|
| 849 |
+
pao1
|
| 850 |
+
pao2
|
| 851 |
+
pao3
|
| 852 |
+
pao4
|
| 853 |
+
pei1
|
| 854 |
+
pei2
|
| 855 |
+
pei4
|
| 856 |
+
pen1
|
| 857 |
+
pen2
|
| 858 |
+
pen4
|
| 859 |
+
peng1
|
| 860 |
+
peng2
|
| 861 |
+
peng3
|
| 862 |
+
peng4
|
| 863 |
+
pi1
|
| 864 |
+
pi2
|
| 865 |
+
pi3
|
| 866 |
+
pi4
|
| 867 |
+
pian1
|
| 868 |
+
pian2
|
| 869 |
+
pian4
|
| 870 |
+
piao1
|
| 871 |
+
piao2
|
| 872 |
+
piao3
|
| 873 |
+
piao4
|
| 874 |
+
pie1
|
| 875 |
+
pie2
|
| 876 |
+
pie3
|
| 877 |
+
pin1
|
| 878 |
+
pin2
|
| 879 |
+
pin3
|
| 880 |
+
pin4
|
| 881 |
+
ping1
|
| 882 |
+
ping2
|
| 883 |
+
po1
|
| 884 |
+
po2
|
| 885 |
+
po3
|
| 886 |
+
po4
|
| 887 |
+
pou1
|
| 888 |
+
pu1
|
| 889 |
+
pu2
|
| 890 |
+
pu3
|
| 891 |
+
pu4
|
| 892 |
+
q
|
| 893 |
+
qi1
|
| 894 |
+
qi2
|
| 895 |
+
qi3
|
| 896 |
+
qi4
|
| 897 |
+
qia1
|
| 898 |
+
qia3
|
| 899 |
+
qia4
|
| 900 |
+
qian1
|
| 901 |
+
qian2
|
| 902 |
+
qian3
|
| 903 |
+
qian4
|
| 904 |
+
qiang1
|
| 905 |
+
qiang2
|
| 906 |
+
qiang3
|
| 907 |
+
qiang4
|
| 908 |
+
qiao1
|
| 909 |
+
qiao2
|
| 910 |
+
qiao3
|
| 911 |
+
qiao4
|
| 912 |
+
qie1
|
| 913 |
+
qie2
|
| 914 |
+
qie3
|
| 915 |
+
qie4
|
| 916 |
+
qin1
|
| 917 |
+
qin2
|
| 918 |
+
qin3
|
| 919 |
+
qin4
|
| 920 |
+
qing1
|
| 921 |
+
qing2
|
| 922 |
+
qing3
|
| 923 |
+
qing4
|
| 924 |
+
qiong1
|
| 925 |
+
qiong2
|
| 926 |
+
qiu1
|
| 927 |
+
qiu2
|
| 928 |
+
qiu3
|
| 929 |
+
qu1
|
| 930 |
+
qu2
|
| 931 |
+
qu3
|
| 932 |
+
qu4
|
| 933 |
+
quan1
|
| 934 |
+
quan2
|
| 935 |
+
quan3
|
| 936 |
+
quan4
|
| 937 |
+
que1
|
| 938 |
+
que2
|
| 939 |
+
que4
|
| 940 |
+
qun2
|
| 941 |
+
r
|
| 942 |
+
ran2
|
| 943 |
+
ran3
|
| 944 |
+
rang1
|
| 945 |
+
rang2
|
| 946 |
+
rang3
|
| 947 |
+
rang4
|
| 948 |
+
rao2
|
| 949 |
+
rao3
|
| 950 |
+
rao4
|
| 951 |
+
re2
|
| 952 |
+
re3
|
| 953 |
+
re4
|
| 954 |
+
ren2
|
| 955 |
+
ren3
|
| 956 |
+
ren4
|
| 957 |
+
reng1
|
| 958 |
+
reng2
|
| 959 |
+
ri4
|
| 960 |
+
rong1
|
| 961 |
+
rong2
|
| 962 |
+
rong3
|
| 963 |
+
rou2
|
| 964 |
+
rou4
|
| 965 |
+
ru2
|
| 966 |
+
ru3
|
| 967 |
+
ru4
|
| 968 |
+
ruan2
|
| 969 |
+
ruan3
|
| 970 |
+
rui3
|
| 971 |
+
rui4
|
| 972 |
+
run4
|
| 973 |
+
ruo4
|
| 974 |
+
s
|
| 975 |
+
sa1
|
| 976 |
+
sa2
|
| 977 |
+
sa3
|
| 978 |
+
sa4
|
| 979 |
+
sai1
|
| 980 |
+
sai4
|
| 981 |
+
san1
|
| 982 |
+
san2
|
| 983 |
+
san3
|
| 984 |
+
san4
|
| 985 |
+
sang1
|
| 986 |
+
sang3
|
| 987 |
+
sang4
|
| 988 |
+
sao1
|
| 989 |
+
sao2
|
| 990 |
+
sao3
|
| 991 |
+
sao4
|
| 992 |
+
se4
|
| 993 |
+
sen1
|
| 994 |
+
seng1
|
| 995 |
+
sha1
|
| 996 |
+
sha2
|
| 997 |
+
sha3
|
| 998 |
+
sha4
|
| 999 |
+
shai1
|
| 1000 |
+
shai2
|
| 1001 |
+
shai3
|
| 1002 |
+
shai4
|
| 1003 |
+
shan1
|
| 1004 |
+
shan3
|
| 1005 |
+
shan4
|
| 1006 |
+
shang
|
| 1007 |
+
shang1
|
| 1008 |
+
shang3
|
| 1009 |
+
shang4
|
| 1010 |
+
shao1
|
| 1011 |
+
shao2
|
| 1012 |
+
shao3
|
| 1013 |
+
shao4
|
| 1014 |
+
she1
|
| 1015 |
+
she2
|
| 1016 |
+
she3
|
| 1017 |
+
she4
|
| 1018 |
+
shei2
|
| 1019 |
+
shen1
|
| 1020 |
+
shen2
|
| 1021 |
+
shen3
|
| 1022 |
+
shen4
|
| 1023 |
+
sheng1
|
| 1024 |
+
sheng2
|
| 1025 |
+
sheng3
|
| 1026 |
+
sheng4
|
| 1027 |
+
shi
|
| 1028 |
+
shi1
|
| 1029 |
+
shi2
|
| 1030 |
+
shi3
|
| 1031 |
+
shi4
|
| 1032 |
+
shou1
|
| 1033 |
+
shou2
|
| 1034 |
+
shou3
|
| 1035 |
+
shou4
|
| 1036 |
+
shu1
|
| 1037 |
+
shu2
|
| 1038 |
+
shu3
|
| 1039 |
+
shu4
|
| 1040 |
+
shua1
|
| 1041 |
+
shua2
|
| 1042 |
+
shua3
|
| 1043 |
+
shua4
|
| 1044 |
+
shuai1
|
| 1045 |
+
shuai3
|
| 1046 |
+
shuai4
|
| 1047 |
+
shuan1
|
| 1048 |
+
shuan4
|
| 1049 |
+
shuang1
|
| 1050 |
+
shuang3
|
| 1051 |
+
shui2
|
| 1052 |
+
shui3
|
| 1053 |
+
shui4
|
| 1054 |
+
shun3
|
| 1055 |
+
shun4
|
| 1056 |
+
shuo1
|
| 1057 |
+
shuo4
|
| 1058 |
+
si1
|
| 1059 |
+
si2
|
| 1060 |
+
si3
|
| 1061 |
+
si4
|
| 1062 |
+
song1
|
| 1063 |
+
song3
|
| 1064 |
+
song4
|
| 1065 |
+
sou1
|
| 1066 |
+
sou3
|
| 1067 |
+
sou4
|
| 1068 |
+
su1
|
| 1069 |
+
su2
|
| 1070 |
+
su4
|
| 1071 |
+
suan1
|
| 1072 |
+
suan4
|
| 1073 |
+
sui1
|
| 1074 |
+
sui2
|
| 1075 |
+
sui3
|
| 1076 |
+
sui4
|
| 1077 |
+
sun1
|
| 1078 |
+
sun3
|
| 1079 |
+
suo
|
| 1080 |
+
suo1
|
| 1081 |
+
suo2
|
| 1082 |
+
suo3
|
| 1083 |
+
t
|
| 1084 |
+
ta1
|
| 1085 |
+
ta2
|
| 1086 |
+
ta3
|
| 1087 |
+
ta4
|
| 1088 |
+
tai1
|
| 1089 |
+
tai2
|
| 1090 |
+
tai4
|
| 1091 |
+
tan1
|
| 1092 |
+
tan2
|
| 1093 |
+
tan3
|
| 1094 |
+
tan4
|
| 1095 |
+
tang1
|
| 1096 |
+
tang2
|
| 1097 |
+
tang3
|
| 1098 |
+
tang4
|
| 1099 |
+
tao1
|
| 1100 |
+
tao2
|
| 1101 |
+
tao3
|
| 1102 |
+
tao4
|
| 1103 |
+
te4
|
| 1104 |
+
teng2
|
| 1105 |
+
ti1
|
| 1106 |
+
ti2
|
| 1107 |
+
ti3
|
| 1108 |
+
ti4
|
| 1109 |
+
tian1
|
| 1110 |
+
tian2
|
| 1111 |
+
tian3
|
| 1112 |
+
tiao1
|
| 1113 |
+
tiao2
|
| 1114 |
+
tiao3
|
| 1115 |
+
tiao4
|
| 1116 |
+
tie1
|
| 1117 |
+
tie2
|
| 1118 |
+
tie3
|
| 1119 |
+
tie4
|
| 1120 |
+
ting1
|
| 1121 |
+
ting2
|
| 1122 |
+
ting3
|
| 1123 |
+
tong1
|
| 1124 |
+
tong2
|
| 1125 |
+
tong3
|
| 1126 |
+
tong4
|
| 1127 |
+
tou
|
| 1128 |
+
tou1
|
| 1129 |
+
tou2
|
| 1130 |
+
tou4
|
| 1131 |
+
tu1
|
| 1132 |
+
tu2
|
| 1133 |
+
tu3
|
| 1134 |
+
tu4
|
| 1135 |
+
tuan1
|
| 1136 |
+
tuan2
|
| 1137 |
+
tui1
|
| 1138 |
+
tui2
|
| 1139 |
+
tui3
|
| 1140 |
+
tui4
|
| 1141 |
+
tun1
|
| 1142 |
+
tun2
|
| 1143 |
+
tun4
|
| 1144 |
+
tuo1
|
| 1145 |
+
tuo2
|
| 1146 |
+
tuo3
|
| 1147 |
+
tuo4
|
| 1148 |
+
u
|
| 1149 |
+
v
|
| 1150 |
+
w
|
| 1151 |
+
wa
|
| 1152 |
+
wa1
|
| 1153 |
+
wa2
|
| 1154 |
+
wa3
|
| 1155 |
+
wa4
|
| 1156 |
+
wai1
|
| 1157 |
+
wai3
|
| 1158 |
+
wai4
|
| 1159 |
+
wan1
|
| 1160 |
+
wan2
|
| 1161 |
+
wan3
|
| 1162 |
+
wan4
|
| 1163 |
+
wang1
|
| 1164 |
+
wang2
|
| 1165 |
+
wang3
|
| 1166 |
+
wang4
|
| 1167 |
+
wei1
|
| 1168 |
+
wei2
|
| 1169 |
+
wei3
|
| 1170 |
+
wei4
|
| 1171 |
+
wen1
|
| 1172 |
+
wen2
|
| 1173 |
+
wen3
|
| 1174 |
+
wen4
|
| 1175 |
+
weng1
|
| 1176 |
+
weng4
|
| 1177 |
+
wo1
|
| 1178 |
+
wo2
|
| 1179 |
+
wo3
|
| 1180 |
+
wo4
|
| 1181 |
+
wu1
|
| 1182 |
+
wu2
|
| 1183 |
+
wu3
|
| 1184 |
+
wu4
|
| 1185 |
+
x
|
| 1186 |
+
xi1
|
| 1187 |
+
xi2
|
| 1188 |
+
xi3
|
| 1189 |
+
xi4
|
| 1190 |
+
xia1
|
| 1191 |
+
xia2
|
| 1192 |
+
xia4
|
| 1193 |
+
xian1
|
| 1194 |
+
xian2
|
| 1195 |
+
xian3
|
| 1196 |
+
xian4
|
| 1197 |
+
xiang1
|
| 1198 |
+
xiang2
|
| 1199 |
+
xiang3
|
| 1200 |
+
xiang4
|
| 1201 |
+
xiao1
|
| 1202 |
+
xiao2
|
| 1203 |
+
xiao3
|
| 1204 |
+
xiao4
|
| 1205 |
+
xie1
|
| 1206 |
+
xie2
|
| 1207 |
+
xie3
|
| 1208 |
+
xie4
|
| 1209 |
+
xin1
|
| 1210 |
+
xin2
|
| 1211 |
+
xin4
|
| 1212 |
+
xing1
|
| 1213 |
+
xing2
|
| 1214 |
+
xing3
|
| 1215 |
+
xing4
|
| 1216 |
+
xiong1
|
| 1217 |
+
xiong2
|
| 1218 |
+
xiu1
|
| 1219 |
+
xiu3
|
| 1220 |
+
xiu4
|
| 1221 |
+
xu
|
| 1222 |
+
xu1
|
| 1223 |
+
xu2
|
| 1224 |
+
xu3
|
| 1225 |
+
xu4
|
| 1226 |
+
xuan1
|
| 1227 |
+
xuan2
|
| 1228 |
+
xuan3
|
| 1229 |
+
xuan4
|
| 1230 |
+
xue1
|
| 1231 |
+
xue2
|
| 1232 |
+
xue3
|
| 1233 |
+
xue4
|
| 1234 |
+
xun1
|
| 1235 |
+
xun2
|
| 1236 |
+
xun4
|
| 1237 |
+
y
|
| 1238 |
+
ya
|
| 1239 |
+
ya1
|
| 1240 |
+
ya2
|
| 1241 |
+
ya3
|
| 1242 |
+
ya4
|
| 1243 |
+
yan1
|
| 1244 |
+
yan2
|
| 1245 |
+
yan3
|
| 1246 |
+
yan4
|
| 1247 |
+
yang1
|
| 1248 |
+
yang2
|
| 1249 |
+
yang3
|
| 1250 |
+
yang4
|
| 1251 |
+
yao1
|
| 1252 |
+
yao2
|
| 1253 |
+
yao3
|
| 1254 |
+
yao4
|
| 1255 |
+
ye1
|
| 1256 |
+
ye2
|
| 1257 |
+
ye3
|
| 1258 |
+
ye4
|
| 1259 |
+
yi
|
| 1260 |
+
yi1
|
| 1261 |
+
yi2
|
| 1262 |
+
yi3
|
| 1263 |
+
yi4
|
| 1264 |
+
yin1
|
| 1265 |
+
yin2
|
| 1266 |
+
yin3
|
| 1267 |
+
yin4
|
| 1268 |
+
ying1
|
| 1269 |
+
ying2
|
| 1270 |
+
ying3
|
| 1271 |
+
ying4
|
| 1272 |
+
yo1
|
| 1273 |
+
yong1
|
| 1274 |
+
yong2
|
| 1275 |
+
yong3
|
| 1276 |
+
yong4
|
| 1277 |
+
you1
|
| 1278 |
+
you2
|
| 1279 |
+
you3
|
| 1280 |
+
you4
|
| 1281 |
+
yu1
|
| 1282 |
+
yu2
|
| 1283 |
+
yu3
|
| 1284 |
+
yu4
|
| 1285 |
+
yuan1
|
| 1286 |
+
yuan2
|
| 1287 |
+
yuan3
|
| 1288 |
+
yuan4
|
| 1289 |
+
yue1
|
| 1290 |
+
yue4
|
| 1291 |
+
yun1
|
| 1292 |
+
yun2
|
| 1293 |
+
yun3
|
| 1294 |
+
yun4
|
| 1295 |
+
z
|
| 1296 |
+
za1
|
| 1297 |
+
za2
|
| 1298 |
+
za3
|
| 1299 |
+
zai1
|
| 1300 |
+
zai3
|
| 1301 |
+
zai4
|
| 1302 |
+
zan1
|
| 1303 |
+
zan2
|
| 1304 |
+
zan3
|
| 1305 |
+
zan4
|
| 1306 |
+
zang1
|
| 1307 |
+
zang4
|
| 1308 |
+
zao1
|
| 1309 |
+
zao2
|
| 1310 |
+
zao3
|
| 1311 |
+
zao4
|
| 1312 |
+
ze2
|
| 1313 |
+
ze4
|
| 1314 |
+
zei2
|
| 1315 |
+
zen3
|
| 1316 |
+
zeng1
|
| 1317 |
+
zeng4
|
| 1318 |
+
zha1
|
| 1319 |
+
zha2
|
| 1320 |
+
zha3
|
| 1321 |
+
zha4
|
| 1322 |
+
zhai1
|
| 1323 |
+
zhai2
|
| 1324 |
+
zhai3
|
| 1325 |
+
zhai4
|
| 1326 |
+
zhan1
|
| 1327 |
+
zhan2
|
| 1328 |
+
zhan3
|
| 1329 |
+
zhan4
|
| 1330 |
+
zhang1
|
| 1331 |
+
zhang2
|
| 1332 |
+
zhang3
|
| 1333 |
+
zhang4
|
| 1334 |
+
zhao1
|
| 1335 |
+
zhao2
|
| 1336 |
+
zhao3
|
| 1337 |
+
zhao4
|
| 1338 |
+
zhe
|
| 1339 |
+
zhe1
|
| 1340 |
+
zhe2
|
| 1341 |
+
zhe3
|
| 1342 |
+
zhe4
|
| 1343 |
+
zhen1
|
| 1344 |
+
zhen2
|
| 1345 |
+
zhen3
|
| 1346 |
+
zhen4
|
| 1347 |
+
zheng1
|
| 1348 |
+
zheng2
|
| 1349 |
+
zheng3
|
| 1350 |
+
zheng4
|
| 1351 |
+
zhi1
|
| 1352 |
+
zhi2
|
| 1353 |
+
zhi3
|
| 1354 |
+
zhi4
|
| 1355 |
+
zhong1
|
| 1356 |
+
zhong2
|
| 1357 |
+
zhong3
|
| 1358 |
+
zhong4
|
| 1359 |
+
zhou1
|
| 1360 |
+
zhou2
|
| 1361 |
+
zhou3
|
| 1362 |
+
zhou4
|
| 1363 |
+
zhu1
|
| 1364 |
+
zhu2
|
| 1365 |
+
zhu3
|
| 1366 |
+
zhu4
|
| 1367 |
+
zhua1
|
| 1368 |
+
zhua2
|
| 1369 |
+
zhua3
|
| 1370 |
+
zhuai1
|
| 1371 |
+
zhuai3
|
| 1372 |
+
zhuai4
|
| 1373 |
+
zhuan1
|
| 1374 |
+
zhuan2
|
| 1375 |
+
zhuan3
|
| 1376 |
+
zhuan4
|
| 1377 |
+
zhuang1
|
| 1378 |
+
zhuang4
|
| 1379 |
+
zhui1
|
| 1380 |
+
zhui4
|
| 1381 |
+
zhun1
|
| 1382 |
+
zhun2
|
| 1383 |
+
zhun3
|
| 1384 |
+
zhuo1
|
| 1385 |
+
zhuo2
|
| 1386 |
+
zi
|
| 1387 |
+
zi1
|
| 1388 |
+
zi2
|
| 1389 |
+
zi3
|
| 1390 |
+
zi4
|
| 1391 |
+
zong1
|
| 1392 |
+
zong2
|
| 1393 |
+
zong3
|
| 1394 |
+
zong4
|
| 1395 |
+
zou1
|
| 1396 |
+
zou2
|
| 1397 |
+
zou3
|
| 1398 |
+
zou4
|
| 1399 |
+
zu1
|
| 1400 |
+
zu2
|
| 1401 |
+
zu3
|
| 1402 |
+
zuan1
|
| 1403 |
+
zuan3
|
| 1404 |
+
zuan4
|
| 1405 |
+
zui2
|
| 1406 |
+
zui3
|
| 1407 |
+
zui4
|
| 1408 |
+
zun1
|
| 1409 |
+
zuo
|
| 1410 |
+
zuo1
|
| 1411 |
+
zuo2
|
| 1412 |
+
zuo3
|
| 1413 |
+
zuo4
|
| 1414 |
+
{
|
| 1415 |
+
~
|
| 1416 |
+
¡
|
| 1417 |
+
¢
|
| 1418 |
+
£
|
| 1419 |
+
¥
|
| 1420 |
+
§
|
| 1421 |
+
¨
|
| 1422 |
+
©
|
| 1423 |
+
«
|
| 1424 |
+
®
|
| 1425 |
+
¯
|
| 1426 |
+
°
|
| 1427 |
+
±
|
| 1428 |
+
²
|
| 1429 |
+
³
|
| 1430 |
+
´
|
| 1431 |
+
µ
|
| 1432 |
+
·
|
| 1433 |
+
¹
|
| 1434 |
+
º
|
| 1435 |
+
»
|
| 1436 |
+
¼
|
| 1437 |
+
½
|
| 1438 |
+
¾
|
| 1439 |
+
¿
|
| 1440 |
+
À
|
| 1441 |
+
Á
|
| 1442 |
+
Â
|
| 1443 |
+
Ã
|
| 1444 |
+
Ä
|
| 1445 |
+
Å
|
| 1446 |
+
Æ
|
| 1447 |
+
Ç
|
| 1448 |
+
È
|
| 1449 |
+
É
|
| 1450 |
+
Ê
|
| 1451 |
+
Í
|
| 1452 |
+
Î
|
| 1453 |
+
Ñ
|
| 1454 |
+
Ó
|
| 1455 |
+
Ö
|
| 1456 |
+
×
|
| 1457 |
+
Ø
|
| 1458 |
+
Ú
|
| 1459 |
+
Ü
|
| 1460 |
+
Ý
|
| 1461 |
+
Þ
|
| 1462 |
+
ß
|
| 1463 |
+
à
|
| 1464 |
+
á
|
| 1465 |
+
â
|
| 1466 |
+
ã
|
| 1467 |
+
ä
|
| 1468 |
+
å
|
| 1469 |
+
æ
|
| 1470 |
+
ç
|
| 1471 |
+
è
|
| 1472 |
+
é
|
| 1473 |
+
ê
|
| 1474 |
+
ë
|
| 1475 |
+
ì
|
| 1476 |
+
í
|
| 1477 |
+
î
|
| 1478 |
+
ï
|
| 1479 |
+
ð
|
| 1480 |
+
ñ
|
| 1481 |
+
ò
|
| 1482 |
+
ó
|
| 1483 |
+
ô
|
| 1484 |
+
õ
|
| 1485 |
+
ö
|
| 1486 |
+
ø
|
| 1487 |
+
ù
|
| 1488 |
+
ú
|
| 1489 |
+
û
|
| 1490 |
+
ü
|
| 1491 |
+
ý
|
| 1492 |
+
Ā
|
| 1493 |
+
ā
|
| 1494 |
+
ă
|
| 1495 |
+
ą
|
| 1496 |
+
ć
|
| 1497 |
+
Č
|
| 1498 |
+
č
|
| 1499 |
+
Đ
|
| 1500 |
+
đ
|
| 1501 |
+
ē
|
| 1502 |
+
ė
|
| 1503 |
+
ę
|
| 1504 |
+
ě
|
| 1505 |
+
ĝ
|
| 1506 |
+
ğ
|
| 1507 |
+
ħ
|
| 1508 |
+
ī
|
| 1509 |
+
į
|
| 1510 |
+
İ
|
| 1511 |
+
ı
|
| 1512 |
+
Ł
|
| 1513 |
+
ł
|
| 1514 |
+
ń
|
| 1515 |
+
ņ
|
| 1516 |
+
ň
|
| 1517 |
+
ŋ
|
| 1518 |
+
Ō
|
| 1519 |
+
ō
|
| 1520 |
+
ő
|
| 1521 |
+
œ
|
| 1522 |
+
ř
|
| 1523 |
+
Ś
|
| 1524 |
+
ś
|
| 1525 |
+
Ş
|
| 1526 |
+
ş
|
| 1527 |
+
Š
|
| 1528 |
+
š
|
| 1529 |
+
Ť
|
| 1530 |
+
ť
|
| 1531 |
+
ũ
|
| 1532 |
+
ū
|
| 1533 |
+
ź
|
| 1534 |
+
Ż
|
| 1535 |
+
ż
|
| 1536 |
+
Ž
|
| 1537 |
+
ž
|
| 1538 |
+
ơ
|
| 1539 |
+
ư
|
| 1540 |
+
ǎ
|
| 1541 |
+
ǐ
|
| 1542 |
+
ǒ
|
| 1543 |
+
ǔ
|
| 1544 |
+
ǚ
|
| 1545 |
+
ș
|
| 1546 |
+
ț
|
| 1547 |
+
ɑ
|
| 1548 |
+
ɔ
|
| 1549 |
+
ɕ
|
| 1550 |
+
ə
|
| 1551 |
+
ɛ
|
| 1552 |
+
ɜ
|
| 1553 |
+
ɡ
|
| 1554 |
+
ɣ
|
| 1555 |
+
ɪ
|
| 1556 |
+
ɫ
|
| 1557 |
+
ɴ
|
| 1558 |
+
ɹ
|
| 1559 |
+
ɾ
|
| 1560 |
+
ʃ
|
| 1561 |
+
ʊ
|
| 1562 |
+
ʌ
|
| 1563 |
+
ʒ
|
| 1564 |
+
ʔ
|
| 1565 |
+
ʰ
|
| 1566 |
+
ʷ
|
| 1567 |
+
ʻ
|
| 1568 |
+
ʾ
|
| 1569 |
+
ʿ
|
| 1570 |
+
ˈ
|
| 1571 |
+
ː
|
| 1572 |
+
˙
|
| 1573 |
+
˜
|
| 1574 |
+
ˢ
|
| 1575 |
+
́
|
| 1576 |
+
̅
|
| 1577 |
+
Α
|
| 1578 |
+
Β
|
| 1579 |
+
Δ
|
| 1580 |
+
Ε
|
| 1581 |
+
Θ
|
| 1582 |
+
Κ
|
| 1583 |
+
Λ
|
| 1584 |
+
Μ
|
| 1585 |
+
Ξ
|
| 1586 |
+
Π
|
| 1587 |
+
Σ
|
| 1588 |
+
Τ
|
| 1589 |
+
Φ
|
| 1590 |
+
Χ
|
| 1591 |
+
Ψ
|
| 1592 |
+
Ω
|
| 1593 |
+
ά
|
| 1594 |
+
έ
|
| 1595 |
+
ή
|
| 1596 |
+
ί
|
| 1597 |
+
α
|
| 1598 |
+
β
|
| 1599 |
+
γ
|
| 1600 |
+
δ
|
| 1601 |
+
ε
|
| 1602 |
+
ζ
|
| 1603 |
+
η
|
| 1604 |
+
θ
|
| 1605 |
+
ι
|
| 1606 |
+
κ
|
| 1607 |
+
λ
|
| 1608 |
+
μ
|
| 1609 |
+
ν
|
| 1610 |
+
ξ
|
| 1611 |
+
ο
|
| 1612 |
+
π
|
| 1613 |
+
ρ
|
| 1614 |
+
ς
|
| 1615 |
+
σ
|
| 1616 |
+
τ
|
| 1617 |
+
υ
|
| 1618 |
+
φ
|
| 1619 |
+
χ
|
| 1620 |
+
ψ
|
| 1621 |
+
ω
|
| 1622 |
+
ϊ
|
| 1623 |
+
ό
|
| 1624 |
+
ύ
|
| 1625 |
+
ώ
|
| 1626 |
+
ϕ
|
| 1627 |
+
ϵ
|
| 1628 |
+
Ё
|
| 1629 |
+
А
|
| 1630 |
+
Б
|
| 1631 |
+
В
|
| 1632 |
+
Г
|
| 1633 |
+
Д
|
| 1634 |
+
Е
|
| 1635 |
+
Ж
|
| 1636 |
+
З
|
| 1637 |
+
И
|
| 1638 |
+
Й
|
| 1639 |
+
К
|
| 1640 |
+
Л
|
| 1641 |
+
М
|
| 1642 |
+
Н
|
| 1643 |
+
О
|
| 1644 |
+
П
|
| 1645 |
+
Р
|
| 1646 |
+
С
|
| 1647 |
+
Т
|
| 1648 |
+
У
|
| 1649 |
+
Ф
|
| 1650 |
+
Х
|
| 1651 |
+
Ц
|
| 1652 |
+
Ч
|
| 1653 |
+
Ш
|
| 1654 |
+
Щ
|
| 1655 |
+
Ы
|
| 1656 |
+
Ь
|
| 1657 |
+
Э
|
| 1658 |
+
Ю
|
| 1659 |
+
Я
|
| 1660 |
+
а
|
| 1661 |
+
б
|
| 1662 |
+
в
|
| 1663 |
+
г
|
| 1664 |
+
д
|
| 1665 |
+
е
|
| 1666 |
+
ж
|
| 1667 |
+
з
|
| 1668 |
+
и
|
| 1669 |
+
й
|
| 1670 |
+
к
|
| 1671 |
+
л
|
| 1672 |
+
м
|
| 1673 |
+
н
|
| 1674 |
+
о
|
| 1675 |
+
п
|
| 1676 |
+
р
|
| 1677 |
+
с
|
| 1678 |
+
т
|
| 1679 |
+
у
|
| 1680 |
+
ф
|
| 1681 |
+
х
|
| 1682 |
+
ц
|
| 1683 |
+
ч
|
| 1684 |
+
ш
|
| 1685 |
+
щ
|
| 1686 |
+
ъ
|
| 1687 |
+
ы
|
| 1688 |
+
ь
|
| 1689 |
+
э
|
| 1690 |
+
ю
|
| 1691 |
+
я
|
| 1692 |
+
ё
|
| 1693 |
+
і
|
| 1694 |
+
ְ
|
| 1695 |
+
ִ
|
| 1696 |
+
ֵ
|
| 1697 |
+
ֶ
|
| 1698 |
+
ַ
|
| 1699 |
+
ָ
|
| 1700 |
+
ֹ
|
| 1701 |
+
ּ
|
| 1702 |
+
־
|
| 1703 |
+
ׁ
|
| 1704 |
+
א
|
| 1705 |
+
ב
|
| 1706 |
+
ג
|
| 1707 |
+
ד
|
| 1708 |
+
ה
|
| 1709 |
+
ו
|
| 1710 |
+
ז
|
| 1711 |
+
ח
|
| 1712 |
+
ט
|
| 1713 |
+
י
|
| 1714 |
+
כ
|
| 1715 |
+
ל
|
| 1716 |
+
ם
|
| 1717 |
+
מ
|
| 1718 |
+
ן
|
| 1719 |
+
נ
|
| 1720 |
+
ס
|
| 1721 |
+
ע
|
| 1722 |
+
פ
|
| 1723 |
+
ק
|
| 1724 |
+
ר
|
| 1725 |
+
ש
|
| 1726 |
+
ת
|
| 1727 |
+
أ
|
| 1728 |
+
ب
|
| 1729 |
+
ة
|
| 1730 |
+
ت
|
| 1731 |
+
ج
|
| 1732 |
+
ح
|
| 1733 |
+
د
|
| 1734 |
+
ر
|
| 1735 |
+
ز
|
| 1736 |
+
س
|
| 1737 |
+
ص
|
| 1738 |
+
ط
|
| 1739 |
+
ع
|
| 1740 |
+
ق
|
| 1741 |
+
ك
|
| 1742 |
+
ل
|
| 1743 |
+
م
|
| 1744 |
+
ن
|
| 1745 |
+
ه
|
| 1746 |
+
و
|
| 1747 |
+
ي
|
| 1748 |
+
َ
|
| 1749 |
+
ُ
|
| 1750 |
+
ِ
|
| 1751 |
+
ْ
|
| 1752 |
+
ก
|
| 1753 |
+
ข
|
| 1754 |
+
ง
|
| 1755 |
+
จ
|
| 1756 |
+
ต
|
| 1757 |
+
ท
|
| 1758 |
+
น
|
| 1759 |
+
ป
|
| 1760 |
+
ย
|
| 1761 |
+
ร
|
| 1762 |
+
ว
|
| 1763 |
+
ส
|
| 1764 |
+
ห
|
| 1765 |
+
อ
|
| 1766 |
+
ฮ
|
| 1767 |
+
ั
|
| 1768 |
+
า
|
| 1769 |
+
ี
|
| 1770 |
+
ึ
|
| 1771 |
+
โ
|
| 1772 |
+
ใ
|
| 1773 |
+
ไ
|
| 1774 |
+
่
|
| 1775 |
+
้
|
| 1776 |
+
์
|
| 1777 |
+
ḍ
|
| 1778 |
+
Ḥ
|
| 1779 |
+
ḥ
|
| 1780 |
+
ṁ
|
| 1781 |
+
ṃ
|
| 1782 |
+
ṅ
|
| 1783 |
+
ṇ
|
| 1784 |
+
Ṛ
|
| 1785 |
+
ṛ
|
| 1786 |
+
Ṣ
|
| 1787 |
+
ṣ
|
| 1788 |
+
Ṭ
|
| 1789 |
+
ṭ
|
| 1790 |
+
ạ
|
| 1791 |
+
ả
|
| 1792 |
+
Ấ
|
| 1793 |
+
ấ
|
| 1794 |
+
ầ
|
| 1795 |
+
ậ
|
| 1796 |
+
ắ
|
| 1797 |
+
ằ
|
| 1798 |
+
ẻ
|
| 1799 |
+
ẽ
|
| 1800 |
+
ế
|
| 1801 |
+
ề
|
| 1802 |
+
ể
|
| 1803 |
+
ễ
|
| 1804 |
+
ệ
|
| 1805 |
+
ị
|
| 1806 |
+
ọ
|
| 1807 |
+
ỏ
|
| 1808 |
+
ố
|
| 1809 |
+
ồ
|
| 1810 |
+
ộ
|
| 1811 |
+
ớ
|
| 1812 |
+
ờ
|
| 1813 |
+
ở
|
| 1814 |
+
ụ
|
| 1815 |
+
ủ
|
| 1816 |
+
ứ
|
| 1817 |
+
ữ
|
| 1818 |
+
ἀ
|
| 1819 |
+
ἁ
|
| 1820 |
+
Ἀ
|
| 1821 |
+
ἐ
|
| 1822 |
+
ἔ
|
| 1823 |
+
ἰ
|
| 1824 |
+
ἱ
|
| 1825 |
+
ὀ
|
| 1826 |
+
ὁ
|
| 1827 |
+
ὐ
|
| 1828 |
+
ὲ
|
| 1829 |
+
ὸ
|
| 1830 |
+
���
|
| 1831 |
+
᾽
|
| 1832 |
+
ῆ
|
| 1833 |
+
ῇ
|
| 1834 |
+
ῶ
|
| 1835 |
+
|
| 1836 |
+
‑
|
| 1837 |
+
‒
|
| 1838 |
+
–
|
| 1839 |
+
—
|
| 1840 |
+
―
|
| 1841 |
+
‖
|
| 1842 |
+
†
|
| 1843 |
+
‡
|
| 1844 |
+
•
|
| 1845 |
+
…
|
| 1846 |
+
‧
|
| 1847 |
+
|
| 1848 |
+
′
|
| 1849 |
+
″
|
| 1850 |
+
⁄
|
| 1851 |
+
|
| 1852 |
+
⁰
|
| 1853 |
+
⁴
|
| 1854 |
+
⁵
|
| 1855 |
+
⁶
|
| 1856 |
+
⁷
|
| 1857 |
+
⁸
|
| 1858 |
+
⁹
|
| 1859 |
+
₁
|
| 1860 |
+
₂
|
| 1861 |
+
₃
|
| 1862 |
+
€
|
| 1863 |
+
₱
|
| 1864 |
+
₹
|
| 1865 |
+
₽
|
| 1866 |
+
℃
|
| 1867 |
+
ℏ
|
| 1868 |
+
ℓ
|
| 1869 |
+
№
|
| 1870 |
+
ℝ
|
| 1871 |
+
™
|
| 1872 |
+
⅓
|
| 1873 |
+
⅔
|
| 1874 |
+
⅛
|
| 1875 |
+
→
|
| 1876 |
+
∂
|
| 1877 |
+
∈
|
| 1878 |
+
∑
|
| 1879 |
+
−
|
| 1880 |
+
∗
|
| 1881 |
+
√
|
| 1882 |
+
∞
|
| 1883 |
+
∫
|
| 1884 |
+
≈
|
| 1885 |
+
≠
|
| 1886 |
+
≡
|
| 1887 |
+
≤
|
| 1888 |
+
≥
|
| 1889 |
+
⋅
|
| 1890 |
+
⋯
|
| 1891 |
+
█
|
| 1892 |
+
♪
|
| 1893 |
+
⟨
|
| 1894 |
+
⟩
|
| 1895 |
+
、
|
| 1896 |
+
。
|
| 1897 |
+
《
|
| 1898 |
+
》
|
| 1899 |
+
「
|
| 1900 |
+
」
|
| 1901 |
+
【
|
| 1902 |
+
】
|
| 1903 |
+
あ
|
| 1904 |
+
う
|
| 1905 |
+
え
|
| 1906 |
+
お
|
| 1907 |
+
か
|
| 1908 |
+
が
|
| 1909 |
+
き
|
| 1910 |
+
ぎ
|
| 1911 |
+
く
|
| 1912 |
+
ぐ
|
| 1913 |
+
け
|
| 1914 |
+
げ
|
| 1915 |
+
こ
|
| 1916 |
+
ご
|
| 1917 |
+
さ
|
| 1918 |
+
し
|
| 1919 |
+
じ
|
| 1920 |
+
す
|
| 1921 |
+
ず
|
| 1922 |
+
せ
|
| 1923 |
+
ぜ
|
| 1924 |
+
そ
|
| 1925 |
+
ぞ
|
| 1926 |
+
た
|
| 1927 |
+
だ
|
| 1928 |
+
ち
|
| 1929 |
+
っ
|
| 1930 |
+
つ
|
| 1931 |
+
で
|
| 1932 |
+
と
|
| 1933 |
+
ど
|
| 1934 |
+
な
|
| 1935 |
+
に
|
| 1936 |
+
ね
|
| 1937 |
+
の
|
| 1938 |
+
は
|
| 1939 |
+
ば
|
| 1940 |
+
ひ
|
| 1941 |
+
ぶ
|
| 1942 |
+
へ
|
| 1943 |
+
べ
|
| 1944 |
+
ま
|
| 1945 |
+
み
|
| 1946 |
+
む
|
| 1947 |
+
め
|
| 1948 |
+
も
|
| 1949 |
+
ゃ
|
| 1950 |
+
や
|
| 1951 |
+
ゆ
|
| 1952 |
+
ょ
|
| 1953 |
+
よ
|
| 1954 |
+
ら
|
| 1955 |
+
り
|
| 1956 |
+
る
|
| 1957 |
+
れ
|
| 1958 |
+
ろ
|
| 1959 |
+
わ
|
| 1960 |
+
を
|
| 1961 |
+
ん
|
| 1962 |
+
ァ
|
| 1963 |
+
ア
|
| 1964 |
+
ィ
|
| 1965 |
+
イ
|
| 1966 |
+
ウ
|
| 1967 |
+
ェ
|
| 1968 |
+
エ
|
| 1969 |
+
オ
|
| 1970 |
+
カ
|
| 1971 |
+
ガ
|
| 1972 |
+
キ
|
| 1973 |
+
ク
|
| 1974 |
+
ケ
|
| 1975 |
+
ゲ
|
| 1976 |
+
コ
|
| 1977 |
+
ゴ
|
| 1978 |
+
サ
|
| 1979 |
+
ザ
|
| 1980 |
+
シ
|
| 1981 |
+
ジ
|
| 1982 |
+
ス
|
| 1983 |
+
ズ
|
| 1984 |
+
セ
|
| 1985 |
+
ゾ
|
| 1986 |
+
タ
|
| 1987 |
+
ダ
|
| 1988 |
+
チ
|
| 1989 |
+
ッ
|
| 1990 |
+
ツ
|
| 1991 |
+
テ
|
| 1992 |
+
デ
|
| 1993 |
+
ト
|
| 1994 |
+
ド
|
| 1995 |
+
ナ
|
| 1996 |
+
ニ
|
| 1997 |
+
ネ
|
| 1998 |
+
ノ
|
| 1999 |
+
バ
|
| 2000 |
+
パ
|
| 2001 |
+
ビ
|
| 2002 |
+
ピ
|
| 2003 |
+
フ
|
| 2004 |
+
プ
|
| 2005 |
+
ヘ
|
| 2006 |
+
ベ
|
| 2007 |
+
ペ
|
| 2008 |
+
ホ
|
| 2009 |
+
ボ
|
| 2010 |
+
ポ
|
| 2011 |
+
マ
|
| 2012 |
+
ミ
|
| 2013 |
+
ム
|
| 2014 |
+
メ
|
| 2015 |
+
モ
|
| 2016 |
+
ャ
|
| 2017 |
+
ヤ
|
| 2018 |
+
ュ
|
| 2019 |
+
ユ
|
| 2020 |
+
ョ
|
| 2021 |
+
ヨ
|
| 2022 |
+
ラ
|
| 2023 |
+
リ
|
| 2024 |
+
ル
|
| 2025 |
+
レ
|
| 2026 |
+
ロ
|
| 2027 |
+
ワ
|
| 2028 |
+
ン
|
| 2029 |
+
・
|
| 2030 |
+
ー
|
| 2031 |
+
ㄋ
|
| 2032 |
+
ㄍ
|
| 2033 |
+
ㄎ
|
| 2034 |
+
ㄏ
|
| 2035 |
+
ㄓ
|
| 2036 |
+
ㄕ
|
| 2037 |
+
ㄚ
|
| 2038 |
+
ㄜ
|
| 2039 |
+
ㄟ
|
| 2040 |
+
ㄤ
|
| 2041 |
+
ㄥ
|
| 2042 |
+
ㄧ
|
| 2043 |
+
ㄱ
|
| 2044 |
+
ㄴ
|
| 2045 |
+
ㄷ
|
| 2046 |
+
ㄹ
|
| 2047 |
+
ㅁ
|
| 2048 |
+
ㅂ
|
| 2049 |
+
ㅅ
|
| 2050 |
+
ㅈ
|
| 2051 |
+
ㅍ
|
| 2052 |
+
ㅎ
|
| 2053 |
+
ㅏ
|
| 2054 |
+
ㅓ
|
| 2055 |
+
ㅗ
|
| 2056 |
+
ㅜ
|
| 2057 |
+
ㅡ
|
| 2058 |
+
ㅣ
|
| 2059 |
+
㗎
|
| 2060 |
+
가
|
| 2061 |
+
각
|
| 2062 |
+
간
|
| 2063 |
+
갈
|
| 2064 |
+
감
|
| 2065 |
+
갑
|
| 2066 |
+
갓
|
| 2067 |
+
갔
|
| 2068 |
+
강
|
| 2069 |
+
같
|
| 2070 |
+
개
|
| 2071 |
+
거
|
| 2072 |
+
건
|
| 2073 |
+
걸
|
| 2074 |
+
겁
|
| 2075 |
+
것
|
| 2076 |
+
겉
|
| 2077 |
+
게
|
| 2078 |
+
겠
|
| 2079 |
+
겨
|
| 2080 |
+
결
|
| 2081 |
+
겼
|
| 2082 |
+
경
|
| 2083 |
+
계
|
| 2084 |
+
고
|
| 2085 |
+
곤
|
| 2086 |
+
골
|
| 2087 |
+
곱
|
| 2088 |
+
공
|
| 2089 |
+
과
|
| 2090 |
+
관
|
| 2091 |
+
광
|
| 2092 |
+
교
|
| 2093 |
+
구
|
| 2094 |
+
국
|
| 2095 |
+
굴
|
| 2096 |
+
귀
|
| 2097 |
+
귄
|
| 2098 |
+
그
|
| 2099 |
+
근
|
| 2100 |
+
글
|
| 2101 |
+
금
|
| 2102 |
+
기
|
| 2103 |
+
긴
|
| 2104 |
+
길
|
| 2105 |
+
까
|
| 2106 |
+
깍
|
| 2107 |
+
깔
|
| 2108 |
+
깜
|
| 2109 |
+
깨
|
| 2110 |
+
께
|
| 2111 |
+
꼬
|
| 2112 |
+
꼭
|
| 2113 |
+
꽃
|
| 2114 |
+
꾸
|
| 2115 |
+
꿔
|
| 2116 |
+
끔
|
| 2117 |
+
끗
|
| 2118 |
+
끝
|
| 2119 |
+
끼
|
| 2120 |
+
나
|
| 2121 |
+
난
|
| 2122 |
+
날
|
| 2123 |
+
남
|
| 2124 |
+
납
|
| 2125 |
+
내
|
| 2126 |
+
냐
|
| 2127 |
+
냥
|
| 2128 |
+
너
|
| 2129 |
+
넘
|
| 2130 |
+
넣
|
| 2131 |
+
네
|
| 2132 |
+
녁
|
| 2133 |
+
년
|
| 2134 |
+
녕
|
| 2135 |
+
노
|
| 2136 |
+
녹
|
| 2137 |
+
놀
|
| 2138 |
+
누
|
| 2139 |
+
눈
|
| 2140 |
+
느
|
| 2141 |
+
는
|
| 2142 |
+
늘
|
| 2143 |
+
니
|
| 2144 |
+
님
|
| 2145 |
+
닙
|
| 2146 |
+
다
|
| 2147 |
+
닥
|
| 2148 |
+
단
|
| 2149 |
+
달
|
| 2150 |
+
닭
|
| 2151 |
+
당
|
| 2152 |
+
대
|
| 2153 |
+
더
|
| 2154 |
+
덕
|
| 2155 |
+
던
|
| 2156 |
+
덥
|
| 2157 |
+
데
|
| 2158 |
+
도
|
| 2159 |
+
독
|
| 2160 |
+
동
|
| 2161 |
+
돼
|
| 2162 |
+
됐
|
| 2163 |
+
되
|
| 2164 |
+
된
|
| 2165 |
+
될
|
| 2166 |
+
두
|
| 2167 |
+
둑
|
| 2168 |
+
둥
|
| 2169 |
+
드
|
| 2170 |
+
들
|
| 2171 |
+
등
|
| 2172 |
+
디
|
| 2173 |
+
따
|
| 2174 |
+
딱
|
| 2175 |
+
딸
|
| 2176 |
+
땅
|
| 2177 |
+
때
|
| 2178 |
+
떤
|
| 2179 |
+
떨
|
| 2180 |
+
떻
|
| 2181 |
+
또
|
| 2182 |
+
똑
|
| 2183 |
+
뚱
|
| 2184 |
+
뛰
|
| 2185 |
+
뜻
|
| 2186 |
+
띠
|
| 2187 |
+
라
|
| 2188 |
+
락
|
| 2189 |
+
란
|
| 2190 |
+
람
|
| 2191 |
+
랍
|
| 2192 |
+
랑
|
| 2193 |
+
래
|
| 2194 |
+
랜
|
| 2195 |
+
러
|
| 2196 |
+
런
|
| 2197 |
+
럼
|
| 2198 |
+
렇
|
| 2199 |
+
레
|
| 2200 |
+
려
|
| 2201 |
+
력
|
| 2202 |
+
렵
|
| 2203 |
+
렸
|
| 2204 |
+
로
|
| 2205 |
+
록
|
| 2206 |
+
롬
|
| 2207 |
+
루
|
| 2208 |
+
르
|
| 2209 |
+
른
|
| 2210 |
+
를
|
| 2211 |
+
름
|
| 2212 |
+
릉
|
| 2213 |
+
리
|
| 2214 |
+
릴
|
| 2215 |
+
림
|
| 2216 |
+
마
|
| 2217 |
+
막
|
| 2218 |
+
만
|
| 2219 |
+
많
|
| 2220 |
+
말
|
| 2221 |
+
맑
|
| 2222 |
+
맙
|
| 2223 |
+
맛
|
| 2224 |
+
매
|
| 2225 |
+
머
|
| 2226 |
+
먹
|
| 2227 |
+
멍
|
| 2228 |
+
메
|
| 2229 |
+
면
|
| 2230 |
+
명
|
| 2231 |
+
몇
|
| 2232 |
+
모
|
| 2233 |
+
목
|
| 2234 |
+
몸
|
| 2235 |
+
못
|
| 2236 |
+
무
|
| 2237 |
+
문
|
| 2238 |
+
물
|
| 2239 |
+
뭐
|
| 2240 |
+
뭘
|
| 2241 |
+
미
|
| 2242 |
+
민
|
| 2243 |
+
밌
|
| 2244 |
+
밑
|
| 2245 |
+
바
|
| 2246 |
+
박
|
| 2247 |
+
밖
|
| 2248 |
+
반
|
| 2249 |
+
받
|
| 2250 |
+
발
|
| 2251 |
+
밤
|
| 2252 |
+
밥
|
| 2253 |
+
방
|
| 2254 |
+
배
|
| 2255 |
+
백
|
| 2256 |
+
밸
|
| 2257 |
+
뱀
|
| 2258 |
+
버
|
| 2259 |
+
번
|
| 2260 |
+
벌
|
| 2261 |
+
벚
|
| 2262 |
+
베
|
| 2263 |
+
벼
|
| 2264 |
+
벽
|
| 2265 |
+
별
|
| 2266 |
+
병
|
| 2267 |
+
보
|
| 2268 |
+
복
|
| 2269 |
+
본
|
| 2270 |
+
볼
|
| 2271 |
+
봐
|
| 2272 |
+
봤
|
| 2273 |
+
부
|
| 2274 |
+
분
|
| 2275 |
+
불
|
| 2276 |
+
비
|
| 2277 |
+
빔
|
| 2278 |
+
빛
|
| 2279 |
+
빠
|
| 2280 |
+
빨
|
| 2281 |
+
뼈
|
| 2282 |
+
뽀
|
| 2283 |
+
뿅
|
| 2284 |
+
쁘
|
| 2285 |
+
사
|
| 2286 |
+
산
|
| 2287 |
+
살
|
| 2288 |
+
삼
|
| 2289 |
+
샀
|
| 2290 |
+
상
|
| 2291 |
+
새
|
| 2292 |
+
색
|
| 2293 |
+
생
|
| 2294 |
+
서
|
| 2295 |
+
선
|
| 2296 |
+
설
|
| 2297 |
+
섭
|
| 2298 |
+
섰
|
| 2299 |
+
성
|
| 2300 |
+
세
|
| 2301 |
+
셔
|
| 2302 |
+
션
|
| 2303 |
+
셨
|
| 2304 |
+
소
|
| 2305 |
+
속
|
| 2306 |
+
손
|
| 2307 |
+
송
|
| 2308 |
+
수
|
| 2309 |
+
숙
|
| 2310 |
+
순
|
| 2311 |
+
술
|
| 2312 |
+
숫
|
| 2313 |
+
숭
|
| 2314 |
+
숲
|
| 2315 |
+
쉬
|
| 2316 |
+
쉽
|
| 2317 |
+
스
|
| 2318 |
+
슨
|
| 2319 |
+
습
|
| 2320 |
+
슷
|
| 2321 |
+
시
|
| 2322 |
+
식
|
| 2323 |
+
신
|
| 2324 |
+
실
|
| 2325 |
+
싫
|
| 2326 |
+
심
|
| 2327 |
+
십
|
| 2328 |
+
싶
|
| 2329 |
+
싸
|
| 2330 |
+
써
|
| 2331 |
+
쓰
|
| 2332 |
+
쓴
|
| 2333 |
+
씌
|
| 2334 |
+
씨
|
| 2335 |
+
씩
|
| 2336 |
+
씬
|
| 2337 |
+
아
|
| 2338 |
+
악
|
| 2339 |
+
안
|
| 2340 |
+
않
|
| 2341 |
+
알
|
| 2342 |
+
야
|
| 2343 |
+
약
|
| 2344 |
+
얀
|
| 2345 |
+
양
|
| 2346 |
+
얘
|
| 2347 |
+
어
|
| 2348 |
+
언
|
| 2349 |
+
얼
|
| 2350 |
+
엄
|
| 2351 |
+
업
|
| 2352 |
+
없
|
| 2353 |
+
었
|
| 2354 |
+
엉
|
| 2355 |
+
에
|
| 2356 |
+
여
|
| 2357 |
+
역
|
| 2358 |
+
연
|
| 2359 |
+
염
|
| 2360 |
+
엽
|
| 2361 |
+
영
|
| 2362 |
+
옆
|
| 2363 |
+
예
|
| 2364 |
+
옛
|
| 2365 |
+
오
|
| 2366 |
+
온
|
| 2367 |
+
올
|
| 2368 |
+
옷
|
| 2369 |
+
옹
|
| 2370 |
+
와
|
| 2371 |
+
왔
|
| 2372 |
+
왜
|
| 2373 |
+
요
|
| 2374 |
+
욕
|
| 2375 |
+
용
|
| 2376 |
+
우
|
| 2377 |
+
운
|
| 2378 |
+
울
|
| 2379 |
+
웃
|
| 2380 |
+
워
|
| 2381 |
+
원
|
| 2382 |
+
월
|
| 2383 |
+
웠
|
| 2384 |
+
위
|
| 2385 |
+
윙
|
| 2386 |
+
유
|
| 2387 |
+
육
|
| 2388 |
+
윤
|
| 2389 |
+
으
|
| 2390 |
+
은
|
| 2391 |
+
을
|
| 2392 |
+
음
|
| 2393 |
+
응
|
| 2394 |
+
의
|
| 2395 |
+
이
|
| 2396 |
+
익
|
| 2397 |
+
인
|
| 2398 |
+
일
|
| 2399 |
+
읽
|
| 2400 |
+
임
|
| 2401 |
+
입
|
| 2402 |
+
있
|
| 2403 |
+
자
|
| 2404 |
+
작
|
| 2405 |
+
잔
|
| 2406 |
+
잖
|
| 2407 |
+
잘
|
| 2408 |
+
잡
|
| 2409 |
+
잤
|
| 2410 |
+
장
|
| 2411 |
+
재
|
| 2412 |
+
저
|
| 2413 |
+
전
|
| 2414 |
+
점
|
| 2415 |
+
정
|
| 2416 |
+
제
|
| 2417 |
+
져
|
| 2418 |
+
졌
|
| 2419 |
+
조
|
| 2420 |
+
족
|
| 2421 |
+
좀
|
| 2422 |
+
종
|
| 2423 |
+
좋
|
| 2424 |
+
죠
|
| 2425 |
+
주
|
| 2426 |
+
준
|
| 2427 |
+
줄
|
| 2428 |
+
중
|
| 2429 |
+
줘
|
| 2430 |
+
즈
|
| 2431 |
+
즐
|
| 2432 |
+
즘
|
| 2433 |
+
지
|
| 2434 |
+
진
|
| 2435 |
+
집
|
| 2436 |
+
짜
|
| 2437 |
+
짝
|
| 2438 |
+
쩌
|
| 2439 |
+
쪼
|
| 2440 |
+
쪽
|
| 2441 |
+
쫌
|
| 2442 |
+
쭈
|
| 2443 |
+
쯔
|
| 2444 |
+
찌
|
| 2445 |
+
찍
|
| 2446 |
+
차
|
| 2447 |
+
착
|
| 2448 |
+
찾
|
| 2449 |
+
책
|
| 2450 |
+
처
|
| 2451 |
+
천
|
| 2452 |
+
철
|
| 2453 |
+
체
|
| 2454 |
+
쳐
|
| 2455 |
+
쳤
|
| 2456 |
+
초
|
| 2457 |
+
촌
|
| 2458 |
+
추
|
| 2459 |
+
출
|
| 2460 |
+
춤
|
| 2461 |
+
춥
|
| 2462 |
+
춰
|
| 2463 |
+
치
|
| 2464 |
+
친
|
| 2465 |
+
칠
|
| 2466 |
+
침
|
| 2467 |
+
칩
|
| 2468 |
+
칼
|
| 2469 |
+
커
|
| 2470 |
+
켓
|
| 2471 |
+
코
|
| 2472 |
+
콩
|
| 2473 |
+
쿠
|
| 2474 |
+
퀴
|
| 2475 |
+
크
|
| 2476 |
+
큰
|
| 2477 |
+
큽
|
| 2478 |
+
키
|
| 2479 |
+
킨
|
| 2480 |
+
타
|
| 2481 |
+
태
|
| 2482 |
+
터
|
| 2483 |
+
턴
|
| 2484 |
+
털
|
| 2485 |
+
테
|
| 2486 |
+
토
|
| 2487 |
+
통
|
| 2488 |
+
투
|
| 2489 |
+
트
|
| 2490 |
+
특
|
| 2491 |
+
튼
|
| 2492 |
+
틀
|
| 2493 |
+
티
|
| 2494 |
+
팀
|
| 2495 |
+
파
|
| 2496 |
+
팔
|
| 2497 |
+
패
|
| 2498 |
+
페
|
| 2499 |
+
펜
|
| 2500 |
+
펭
|
| 2501 |
+
평
|
| 2502 |
+
포
|
| 2503 |
+
폭
|
| 2504 |
+
표
|
| 2505 |
+
품
|
| 2506 |
+
풍
|
| 2507 |
+
프
|
| 2508 |
+
플
|
| 2509 |
+
피
|
| 2510 |
+
필
|
| 2511 |
+
하
|
| 2512 |
+
학
|
| 2513 |
+
한
|
| 2514 |
+
할
|
| 2515 |
+
함
|
| 2516 |
+
합
|
| 2517 |
+
항
|
| 2518 |
+
해
|
| 2519 |
+
햇
|
| 2520 |
+
했
|
| 2521 |
+
행
|
| 2522 |
+
허
|
| 2523 |
+
험
|
| 2524 |
+
형
|
| 2525 |
+
혜
|
| 2526 |
+
호
|
| 2527 |
+
혼
|
| 2528 |
+
홀
|
| 2529 |
+
화
|
| 2530 |
+
회
|
| 2531 |
+
획
|
| 2532 |
+
후
|
| 2533 |
+
휴
|
| 2534 |
+
흐
|
| 2535 |
+
흔
|
| 2536 |
+
희
|
| 2537 |
+
히
|
| 2538 |
+
힘
|
| 2539 |
+
ﷺ
|
| 2540 |
+
ﷻ
|
| 2541 |
+
!
|
| 2542 |
+
,
|
| 2543 |
+
?
|
| 2544 |
+
�
|
| 2545 |
+
𠮶
|
| 2546 |
+
ค
|
| 2547 |
+
เ
|
| 2548 |
+
็
|
| 2549 |
+
ผ
|
| 2550 |
+
ู
|
| 2551 |
+
บ
|
| 2552 |
+
พ
|
| 2553 |
+
ำ
|
| 2554 |
+
แ
|
| 2555 |
+
ม
|
| 2556 |
+
ะ
|
| 2557 |
+
ิ
|
| 2558 |
+
ด
|
| 2559 |
+
ฝ
|
| 2560 |
+
ุ
|
| 2561 |
+
ล
|
| 2562 |
+
ื
|
| 2563 |
+
ถ
|
| 2564 |
+
ฬ
|
| 2565 |
+
ฟ
|
| 2566 |
+
ณ
|
| 2567 |
+
ซ
|
| 2568 |
+
ธ
|
| 2569 |
+
ช
|
| 2570 |
+
ฉ
|
| 2571 |
+
ศ
|
| 2572 |
+
ญ
|
| 2573 |
+
ภ
|
| 2574 |
+
ฆ
|
| 2575 |
+
ษ
|
| 2576 |
+
ฐ
|
| 2577 |
+
๊
|
| 2578 |
+
ฒ
|
| 2579 |
+
ฎ
|
| 2580 |
+
๋
|
| 2581 |
+
ฏ
|
| 2582 |
+
ฤ
|
| 2583 |
+
ๅ
|
| 2584 |
+
ฑ
|
| 2585 |
+
ฌ
|
| 2586 |
+
ฃ
|
data/librispeech_pc_test_clean_cross_sentence.lst
ADDED
|
The diff for this file is too large to render.
See raw diff
|
|
|
deployment/.gitignore
ADDED
|
@@ -0,0 +1,81 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
# Python
|
| 2 |
+
__pycache__/
|
| 3 |
+
*.py[cod]
|
| 4 |
+
*$py.class
|
| 5 |
+
*.so
|
| 6 |
+
.Python
|
| 7 |
+
build/
|
| 8 |
+
develop-eggs/
|
| 9 |
+
dist/
|
| 10 |
+
downloads/
|
| 11 |
+
eggs/
|
| 12 |
+
.eggs/
|
| 13 |
+
lib/
|
| 14 |
+
lib64/
|
| 15 |
+
parts/
|
| 16 |
+
sdist/
|
| 17 |
+
var/
|
| 18 |
+
wheels/
|
| 19 |
+
*.egg-info/
|
| 20 |
+
.installed.cfg
|
| 21 |
+
*.egg
|
| 22 |
+
MANIFEST
|
| 23 |
+
|
| 24 |
+
# PyTorch
|
| 25 |
+
*.pth
|
| 26 |
+
*.pt
|
| 27 |
+
|
| 28 |
+
# Gradio
|
| 29 |
+
.gradio/
|
| 30 |
+
flagged/
|
| 31 |
+
|
| 32 |
+
# Environment
|
| 33 |
+
.env
|
| 34 |
+
.venv
|
| 35 |
+
env/
|
| 36 |
+
venv/
|
| 37 |
+
ENV/
|
| 38 |
+
env.bak/
|
| 39 |
+
venv.bak/
|
| 40 |
+
|
| 41 |
+
# IDE
|
| 42 |
+
.vscode/
|
| 43 |
+
.idea/
|
| 44 |
+
*.swp
|
| 45 |
+
*.swo
|
| 46 |
+
*~
|
| 47 |
+
|
| 48 |
+
# OS
|
| 49 |
+
.DS_Store
|
| 50 |
+
.DS_Store?
|
| 51 |
+
._*
|
| 52 |
+
.Spotlight-V100
|
| 53 |
+
.Trashes
|
| 54 |
+
ehthumbs.db
|
| 55 |
+
Thumbs.db
|
| 56 |
+
|
| 57 |
+
# Logs
|
| 58 |
+
*.log
|
| 59 |
+
logs/
|
| 60 |
+
|
| 61 |
+
# Temporary files
|
| 62 |
+
*.tmp
|
| 63 |
+
*.temp
|
| 64 |
+
tmp/
|
| 65 |
+
temp/
|
| 66 |
+
|
| 67 |
+
# Cache
|
| 68 |
+
.cache/
|
| 69 |
+
*.cache
|
| 70 |
+
|
| 71 |
+
# Model downloads (if large)
|
| 72 |
+
# ckpts/
|
| 73 |
+
# models/
|
| 74 |
+
|
| 75 |
+
# Audio files (if large)
|
| 76 |
+
# *.wav
|
| 77 |
+
# *.mp3
|
| 78 |
+
# *.flac
|
| 79 |
+
|
| 80 |
+
# Jupyter
|
| 81 |
+
.ipynb_checkpoints
|
deployment/README.md
ADDED
|
@@ -0,0 +1,89 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
---
|
| 2 |
+
title: F5-TTS Thai
|
| 3 |
+
emoji: 🎤
|
| 4 |
+
colorFrom: blue
|
| 5 |
+
colorTo: purple
|
| 6 |
+
sdk: gradio
|
| 7 |
+
sdk_version: 4.44.0
|
| 8 |
+
app_file: app.py
|
| 9 |
+
pinned: false
|
| 10 |
+
license: mit
|
| 11 |
+
python_version: 3.10
|
| 12 |
+
hardware: cpu-basic
|
| 13 |
+
short_description: Zero-shot Text-to-Speech for Thai language
|
| 14 |
+
---
|
| 15 |
+
|
| 16 |
+
# F5-TTS ภาษาไทย 🎤
|
| 17 |
+
|
| 18 |
+
Zero-shot Text-to-Speech สำหรับภาษาไทย ด้วยโมเดล F5-TTS
|
| 19 |
+
|
| 20 |
+
## ✨ Features
|
| 21 |
+
|
| 22 |
+
- **Multi-Speech Generation**: สร้างเสียงพูดหลายสไตล์ในไฟล์เดียว
|
| 23 |
+
- **Voice Cloning**: โคลนเสียงจากไฟล์ตัวอย่างสั้นๆ
|
| 24 |
+
- **Thai Language Support**: รองรับภาษาไทยอย่างเต็มรูปแบบ
|
| 25 |
+
- **Real-time Processing**: ประมวลผลแบบ real-time
|
| 26 |
+
- **Segment Editing**: แก้ไขและปรับแต่งเสียงแต่ละส่วนได้
|
| 27 |
+
|
| 28 |
+
## 🚀 วิธีใช้งาน
|
| 29 |
+
|
| 30 |
+
### Multi-Speech Generation
|
| 31 |
+
|
| 32 |
+
1. **เพิ่มประเภทคำพูด**: คลิก "เพิ่มประเภทคำพูด" เพื่อเพิ่มสไตล์เสียงใหม่
|
| 33 |
+
2. **อัปโหลดเสียงตัวอย่าง**: อัปโหลดไฟล์เสียงสำหรับแต่ละสไตล์
|
| 34 |
+
3. **ใส่ข้อความต้นฉบับ**: พิมพ์ข้อความที่สอดคล้องกับเสียงตัวอย่าง
|
| 35 |
+
4. **เขียนสคริปต์**: ใช้รูปแบบ `{ชื่อสไตล์} ข้อความที่จะพูด`
|
| 36 |
+
|
| 37 |
+
### ตัวอย่างการใช้งาน
|
| 38 |
+
|
| 39 |
+
```
|
| 40 |
+
{ปกติ} สวัสดีครับ มีอะไรให้ผมช่วยไหมครับ
|
| 41 |
+
{เศร้า} ผมเครียดจริงๆ นะตอนนี้...
|
| 42 |
+
{โกรธ} รู้ไหม! เธอไม่ควรอยู่ที่นี่!
|
| 43 |
+
{กระซิบ} ฉันมีอะไรจะบอกคุณ แต่มันเป็นความลับนะ
|
| 44 |
+
```
|
| 45 |
+
|
| 46 |
+
## ⚙️ Technical Details
|
| 47 |
+
|
| 48 |
+
### Models Used
|
| 49 |
+
- **F5-TTS**: Zero-shot text-to-speech model
|
| 50 |
+
- **Vocoder**: Neural vocoder for high-quality audio synthesis
|
| 51 |
+
- **Text Processing**: Thai text normalization and processing
|
| 52 |
+
|
| 53 |
+
### System Requirements
|
| 54 |
+
- **RAM**: อย่างน้อย 4GB (แนะนำ 8GB+)
|
| 55 |
+
- **GPU**: ไม่จำเป็น แต่จะช่วยเพิ่มความเร็ว
|
| 56 |
+
- **Storage**: ~2GB สำหรับโมเดลและ dependencies
|
| 57 |
+
|
| 58 |
+
## 🔧 Configuration
|
| 59 |
+
|
| 60 |
+
### Model Settings
|
| 61 |
+
- **NFE Steps**: ควบคุมคุณภาพเสียง (16-64)
|
| 62 |
+
- **Cross Fade Duration**: ปรับการต่อเสียงระหว่างส่วน
|
| 63 |
+
- **Speed**: ปรับความเร็วการพูด
|
| 64 |
+
- **CFG Strength**: ปรับความแข็งแกร่งของ guidance
|
| 65 |
+
|
| 66 |
+
### Tips สำหรับผลลัพธ์ที่ดี
|
| 67 |
+
1. **เสียงตัวอย่าง**: ใช้เสียงที่ชัดเจน ไม่มีเสียงรบกวน ความยาว 5-10 วินาที
|
| 68 |
+
2. **ข้อความต้นฉบับ**: ให้ตรงกับเสียงตัวอย่างที่สุด
|
| 69 |
+
3. **ข้อความที่จะสร้าง**: เว้นวรรคและใส่เครื่องหมายวรรคตอนให้ชัดเจน
|
| 70 |
+
4. **การตั้งค่า**: เริ่มด้วยค่า default แล้วค่อยปรับแต่ง
|
| 71 |
+
|
| 72 |
+
## 🚨 Limitations
|
| 73 |
+
|
| 74 |
+
- รองรับเฉพาะภาษาไทยเป็นหลัก
|
| 75 |
+
- คุณภาพเสียงขึ้นอยู่กับเสียงตัวอย่าง
|
| 76 |
+
- ใช้เวลาในการประมวลผลตามความยาวข้อความ
|
| 77 |
+
- ต้องใช้ internet เพื่อดาวน์โหลดโมเดล
|
| 78 |
+
|
| 79 |
+
## 📝 License
|
| 80 |
+
|
| 81 |
+
MIT License - ใช้งานได้อย่างอิสระ
|
| 82 |
+
|
| 83 |
+
## 🤝 Contributing
|
| 84 |
+
|
| 85 |
+
สามารถมีส่วนร่วมพัฒนาได้ที่ [GitHub Repository](https://github.com/yourusername/F5-TTS-THAI)
|
| 86 |
+
|
| 87 |
+
## 🐛 Bug Reports
|
| 88 |
+
|
| 89 |
+
หากพบปัญหาการใช้งาน กรุณาแจ้งได้ที่ Issues ของ GitHub Repository
|
deployment/app.py
ADDED
|
@@ -0,0 +1,45 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
#!/usr/bin/env python3
|
| 2 |
+
import os
|
| 3 |
+
import sys
|
| 4 |
+
import gradio as gr
|
| 5 |
+
|
| 6 |
+
# Add src to path
|
| 7 |
+
current_dir = os.path.dirname(os.path.abspath(__file__))
|
| 8 |
+
src_dir = os.path.join(current_dir, "src")
|
| 9 |
+
if src_dir not in sys.path:
|
| 10 |
+
sys.path.insert(0, src_dir)
|
| 11 |
+
|
| 12 |
+
def create_demo():
|
| 13 |
+
"""Create the main demo interface"""
|
| 14 |
+
try:
|
| 15 |
+
from f5_tts.f5_tts_webui import F5TTSWebUI
|
| 16 |
+
app = F5TTSWebUI()
|
| 17 |
+
return app.create_gradio_interface()
|
| 18 |
+
except Exception as e:
|
| 19 |
+
# Fallback interface if imports fail
|
| 20 |
+
with gr.Blocks(title="F5-TTS Thai") as demo:
|
| 21 |
+
gr.Markdown("# F5-TTS ภาษาไทย 🎤")
|
| 22 |
+
gr.Markdown("## ⚠️ กำลังโหลดระบบ...")
|
| 23 |
+
gr.Markdown(f"**Status:** กำลังดาวน์โหลดและเตรียมโมเดล")
|
| 24 |
+
gr.Markdown("""
|
| 25 |
+
### กรุณารอสักครู่...
|
| 26 |
+
- ระบบกำลังดาวน์โหลด dependencies
|
| 27 |
+
- กำลังโหลดโมเดล F5-TTS
|
| 28 |
+
- โปรเซสนี้อาจใช้เวลา 2-5 นาที
|
| 29 |
+
|
| 30 |
+
**หากยังไม่ทำงาน กรุณารีเฟรชหน้าใหม่**
|
| 31 |
+
""")
|
| 32 |
+
|
| 33 |
+
with gr.Row():
|
| 34 |
+
status_text = gr.Textbox(label="สถานะ", value="กำลังเตรียมระบบ...", interactive=False)
|
| 35 |
+
refresh_btn = gr.Button("🔄 รีเฟรช", variant="primary")
|
| 36 |
+
refresh_btn.click(fn=lambda: "รีเฟรชแล้ว", outputs=status_text)
|
| 37 |
+
|
| 38 |
+
return demo
|
| 39 |
+
|
| 40 |
+
# Create the demo - THIS IS IMPORTANT FOR HF SPACES
|
| 41 |
+
demo = create_demo()
|
| 42 |
+
|
| 43 |
+
# Launch settings
|
| 44 |
+
if __name__ == "__main__":
|
| 45 |
+
demo.launch()
|
deployment/app_minimal.py
ADDED
|
@@ -0,0 +1,31 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
import gradio as gr
|
| 2 |
+
|
| 3 |
+
def test_function(text):
|
| 4 |
+
return f"ทดสอบสำเร็จ! คุณพิมพ์: {text}"
|
| 5 |
+
|
| 6 |
+
# Simple demo for testing
|
| 7 |
+
with gr.Blocks(title="F5-TTS Thai Test") as demo:
|
| 8 |
+
gr.Markdown("# 🧪 F5-TTS Thai - Test App")
|
| 9 |
+
gr.Markdown("แอปทดสอบเพื่อตรวจสอบว่า Hugging Face Spaces ทำงานได้")
|
| 10 |
+
|
| 11 |
+
with gr.Row():
|
| 12 |
+
input_text = gr.Textbox(label="ทดสอบการพิมพ์", placeholder="พิมพ์อะไรก็ได้...")
|
| 13 |
+
output_text = gr.Textbox(label="ผลลัพธ์")
|
| 14 |
+
|
| 15 |
+
test_btn = gr.Button("ทดสอบ", variant="primary")
|
| 16 |
+
test_btn.click(fn=test_function, inputs=input_text, outputs=output_text)
|
| 17 |
+
|
| 18 |
+
gr.Markdown("""
|
| 19 |
+
### ✅ หากแอปนี้ทำงานได้ แสดงว่า:
|
| 20 |
+
- Gradio ทำงานได้ปกติ
|
| 21 |
+
- โครงสร้างไฟล์ถูกต้อง
|
| 22 |
+
- สามารถอัปโหลดแอปหลักได้
|
| 23 |
+
|
| 24 |
+
### 📝 ขั้นตอนต่อไป:
|
| 25 |
+
1. แทนที่ `app_minimal.py` ด้วย `app.py`
|
| 26 |
+
2. อัปโหลดโฟลเดอร์ `src/`
|
| 27 |
+
3. อัปเดต `requirements.txt`
|
| 28 |
+
""")
|
| 29 |
+
|
| 30 |
+
if __name__ == "__main__":
|
| 31 |
+
demo.launch()
|
deployment/requirements.txt
ADDED
|
@@ -0,0 +1,15 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
gradio>=4.0.0
|
| 2 |
+
torch>=2.0.0
|
| 3 |
+
torchaudio>=2.0.0
|
| 4 |
+
numpy>=1.21.0
|
| 5 |
+
soundfile>=0.12.1
|
| 6 |
+
cached-path>=1.5.0
|
| 7 |
+
faster-whisper>=0.9.0
|
| 8 |
+
transformers>=4.30.0
|
| 9 |
+
accelerate>=0.20.0
|
| 10 |
+
datasets>=2.10.0
|
| 11 |
+
librosa>=0.10.0
|
| 12 |
+
scipy>=1.9.0
|
| 13 |
+
matplotlib>=3.5.0
|
| 14 |
+
Pillow>=9.0.0
|
| 15 |
+
requests>=2.25.0
|
deployment/requirements_minimal.txt
ADDED
|
@@ -0,0 +1 @@
|
|
|
|
|
|
|
| 1 |
+
gradio>=4.0.0
|
deployment/src/f5_tts/api.py
ADDED
|
@@ -0,0 +1,174 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
import random
|
| 2 |
+
import sys
|
| 3 |
+
from importlib.resources import files
|
| 4 |
+
|
| 5 |
+
import soundfile as sf
|
| 6 |
+
import tqdm
|
| 7 |
+
from cached_path import cached_path
|
| 8 |
+
|
| 9 |
+
from f5_tts.infer.utils_infer import (
|
| 10 |
+
hop_length,
|
| 11 |
+
infer_process,
|
| 12 |
+
load_model,
|
| 13 |
+
load_vocoder,
|
| 14 |
+
preprocess_ref_audio_text,
|
| 15 |
+
remove_silence_for_generated_wav,
|
| 16 |
+
save_spectrogram,
|
| 17 |
+
transcribe,
|
| 18 |
+
target_sample_rate,
|
| 19 |
+
)
|
| 20 |
+
from f5_tts.model import DiT, UNetT
|
| 21 |
+
from f5_tts.model.utils import seed_everything
|
| 22 |
+
|
| 23 |
+
|
| 24 |
+
class F5TTS:
|
| 25 |
+
def __init__(
|
| 26 |
+
self,
|
| 27 |
+
model_type="F5-TTS",
|
| 28 |
+
ckpt_file="",
|
| 29 |
+
vocab_file="",
|
| 30 |
+
ode_method="euler",
|
| 31 |
+
use_ema=True,
|
| 32 |
+
vocoder_name="vocos",
|
| 33 |
+
local_path=None,
|
| 34 |
+
device=None,
|
| 35 |
+
hf_cache_dir=None,
|
| 36 |
+
):
|
| 37 |
+
# Initialize parameters
|
| 38 |
+
self.final_wave = None
|
| 39 |
+
self.target_sample_rate = target_sample_rate
|
| 40 |
+
self.hop_length = hop_length
|
| 41 |
+
self.seed = -1
|
| 42 |
+
self.mel_spec_type = vocoder_name
|
| 43 |
+
|
| 44 |
+
# Set device
|
| 45 |
+
if device is not None:
|
| 46 |
+
self.device = device
|
| 47 |
+
else:
|
| 48 |
+
import torch
|
| 49 |
+
|
| 50 |
+
self.device = (
|
| 51 |
+
"cuda"
|
| 52 |
+
if torch.cuda.is_available()
|
| 53 |
+
else "xpu"
|
| 54 |
+
if torch.xpu.is_available()
|
| 55 |
+
else "mps"
|
| 56 |
+
if torch.backends.mps.is_available()
|
| 57 |
+
else "cpu"
|
| 58 |
+
)
|
| 59 |
+
|
| 60 |
+
# Load models
|
| 61 |
+
self.load_vocoder_model(vocoder_name, local_path=local_path, hf_cache_dir=hf_cache_dir)
|
| 62 |
+
self.load_ema_model(
|
| 63 |
+
model_type, ckpt_file, vocoder_name, vocab_file, ode_method, use_ema, hf_cache_dir=hf_cache_dir
|
| 64 |
+
)
|
| 65 |
+
|
| 66 |
+
def load_vocoder_model(self, vocoder_name, local_path=None, hf_cache_dir=None):
|
| 67 |
+
self.vocoder = load_vocoder(vocoder_name, local_path is not None, local_path, self.device, hf_cache_dir)
|
| 68 |
+
|
| 69 |
+
def load_ema_model(self, model_type, ckpt_file, mel_spec_type, vocab_file, ode_method, use_ema, hf_cache_dir=None):
|
| 70 |
+
if model_type == "F5-TTS":
|
| 71 |
+
if not ckpt_file:
|
| 72 |
+
if mel_spec_type == "vocos":
|
| 73 |
+
ckpt_file = str(
|
| 74 |
+
cached_path("hf://SWivid/F5-TTS/F5TTS_Base/model_1200000.safetensors", cache_dir=hf_cache_dir)
|
| 75 |
+
)
|
| 76 |
+
elif mel_spec_type == "bigvgan":
|
| 77 |
+
ckpt_file = str(
|
| 78 |
+
cached_path("hf://SWivid/F5-TTS/F5TTS_Base_bigvgan/model_1250000.pt", cache_dir=hf_cache_dir)
|
| 79 |
+
)
|
| 80 |
+
model_cfg = dict(dim=1024, depth=22, heads=16, ff_mult=2, text_dim=512, conv_layers=4)
|
| 81 |
+
model_cls = DiT
|
| 82 |
+
elif model_type == "E2-TTS":
|
| 83 |
+
if not ckpt_file:
|
| 84 |
+
ckpt_file = str(
|
| 85 |
+
cached_path("hf://SWivid/E2-TTS/E2TTS_Base/model_1200000.safetensors", cache_dir=hf_cache_dir)
|
| 86 |
+
)
|
| 87 |
+
model_cfg = dict(dim=1024, depth=24, heads=16, ff_mult=4)
|
| 88 |
+
model_cls = UNetT
|
| 89 |
+
else:
|
| 90 |
+
raise ValueError(f"Unknown model type: {model_type}")
|
| 91 |
+
|
| 92 |
+
self.ema_model = load_model(
|
| 93 |
+
model_cls, model_cfg, ckpt_file, mel_spec_type, vocab_file, ode_method, use_ema, self.device
|
| 94 |
+
)
|
| 95 |
+
|
| 96 |
+
def transcribe(self, ref_audio, language=None):
|
| 97 |
+
return transcribe(ref_audio, language)
|
| 98 |
+
|
| 99 |
+
def export_wav(self, wav, file_wave, remove_silence=False):
|
| 100 |
+
sf.write(file_wave, wav, self.target_sample_rate)
|
| 101 |
+
|
| 102 |
+
if remove_silence:
|
| 103 |
+
remove_silence_for_generated_wav(file_wave)
|
| 104 |
+
|
| 105 |
+
def export_spectrogram(self, spect, file_spect):
|
| 106 |
+
save_spectrogram(spect, file_spect)
|
| 107 |
+
|
| 108 |
+
def infer(
|
| 109 |
+
self,
|
| 110 |
+
ref_file,
|
| 111 |
+
ref_text,
|
| 112 |
+
gen_text,
|
| 113 |
+
show_info=print,
|
| 114 |
+
progress=tqdm,
|
| 115 |
+
target_rms=0.1,
|
| 116 |
+
cross_fade_duration=0.15,
|
| 117 |
+
sway_sampling_coef=-1,
|
| 118 |
+
cfg_strength=2,
|
| 119 |
+
nfe_step=32,
|
| 120 |
+
speed=1.0,
|
| 121 |
+
fix_duration=None,
|
| 122 |
+
remove_silence=False,
|
| 123 |
+
file_wave=None,
|
| 124 |
+
file_spect=None,
|
| 125 |
+
seed=-1,
|
| 126 |
+
):
|
| 127 |
+
if seed == -1:
|
| 128 |
+
seed = random.randint(0, sys.maxsize)
|
| 129 |
+
seed_everything(seed)
|
| 130 |
+
self.seed = seed
|
| 131 |
+
|
| 132 |
+
ref_file, ref_text = preprocess_ref_audio_text(ref_file, ref_text, device=self.device)
|
| 133 |
+
|
| 134 |
+
wav, sr, spect = infer_process(
|
| 135 |
+
ref_file,
|
| 136 |
+
ref_text,
|
| 137 |
+
gen_text,
|
| 138 |
+
self.ema_model,
|
| 139 |
+
self.vocoder,
|
| 140 |
+
self.mel_spec_type,
|
| 141 |
+
show_info=show_info,
|
| 142 |
+
progress=progress,
|
| 143 |
+
target_rms=target_rms,
|
| 144 |
+
cross_fade_duration=cross_fade_duration,
|
| 145 |
+
nfe_step=nfe_step,
|
| 146 |
+
cfg_strength=cfg_strength,
|
| 147 |
+
sway_sampling_coef=sway_sampling_coef,
|
| 148 |
+
speed=speed,
|
| 149 |
+
fix_duration=fix_duration,
|
| 150 |
+
device=self.device,
|
| 151 |
+
)
|
| 152 |
+
|
| 153 |
+
if file_wave is not None:
|
| 154 |
+
self.export_wav(wav, file_wave, remove_silence)
|
| 155 |
+
|
| 156 |
+
if file_spect is not None:
|
| 157 |
+
self.export_spectrogram(spect, file_spect)
|
| 158 |
+
|
| 159 |
+
return wav, sr, spect
|
| 160 |
+
|
| 161 |
+
|
| 162 |
+
if __name__ == "__main__":
|
| 163 |
+
f5tts = F5TTS()
|
| 164 |
+
|
| 165 |
+
wav, sr, spect = f5tts.infer(
|
| 166 |
+
ref_file=str(files("f5_tts").joinpath("infer/examples/basic/basic_ref_en.wav")),
|
| 167 |
+
ref_text="some call me nature, others call me mother nature.",
|
| 168 |
+
gen_text="""I don't really care what you call me. I've been a silent spectator, watching species evolve, empires rise and fall. But always remember, I am mighty and enduring. Respect me and I'll nurture you; ignore me and you shall face the consequences.""",
|
| 169 |
+
file_wave=str(files("f5_tts").joinpath("../../tests/api_out.wav")),
|
| 170 |
+
file_spect=str(files("f5_tts").joinpath("../../tests/api_out.png")),
|
| 171 |
+
seed=-1, # random seed = -1
|
| 172 |
+
)
|
| 173 |
+
|
| 174 |
+
print("seed :", f5tts.seed)
|
deployment/src/f5_tts/cleantext/number_tha.py
ADDED
|
@@ -0,0 +1,145 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
def number_to_thai_text(num, digit_by_digit=False):
|
| 2 |
+
# Thai numerals and place values
|
| 3 |
+
thai_digits = {
|
| 4 |
+
0: "ศูนย์", 1: "หนึ่ง", 2: "สอง", 3: "สาม", 4: "สี่",
|
| 5 |
+
5: "ห้า", 6: "หก", 7: "เจ็ด", 8: "แปด", 9: "เก้า"
|
| 6 |
+
}
|
| 7 |
+
thai_places = ["", "สิบ", "ร้อย", "พัน", "หมื่น", "แสน", "ล้าน"]
|
| 8 |
+
|
| 9 |
+
# Handle zero case
|
| 10 |
+
if num == 0:
|
| 11 |
+
return thai_digits[0]
|
| 12 |
+
|
| 13 |
+
# If digit_by_digit is True, read each digit separately
|
| 14 |
+
if digit_by_digit:
|
| 15 |
+
return " ".join(thai_digits[int(d)] for d in str(num))
|
| 16 |
+
|
| 17 |
+
# For very large numbers, we'll process in chunks of millions
|
| 18 |
+
if num >= 1000000:
|
| 19 |
+
millions = num // 1000000
|
| 20 |
+
remainder = num % 1000000
|
| 21 |
+
result = number_to_thai_text(millions) + "ล้าน"
|
| 22 |
+
if remainder > 0:
|
| 23 |
+
result += number_to_thai_text(remainder)
|
| 24 |
+
return result
|
| 25 |
+
|
| 26 |
+
# Convert number to string and reverse it for easier place value processing
|
| 27 |
+
num_str = str(num)
|
| 28 |
+
digits = [int(d) for d in num_str]
|
| 29 |
+
digits.reverse() # Reverse to process from units to highest place
|
| 30 |
+
|
| 31 |
+
result = []
|
| 32 |
+
for i, digit in enumerate(digits):
|
| 33 |
+
if digit == 0:
|
| 34 |
+
continue # Skip zeros
|
| 35 |
+
|
| 36 |
+
# Special case for tens place
|
| 37 |
+
if i == 1:
|
| 38 |
+
if digit == 1:
|
| 39 |
+
result.append(thai_places[i]) # "สิบ" for 10-19
|
| 40 |
+
elif digit == 2:
|
| 41 |
+
result.append("ยี่" + thai_places[i]) # "ยี่สิบ" for 20-29
|
| 42 |
+
else:
|
| 43 |
+
result.append(thai_digits[digit] + thai_places[i])
|
| 44 |
+
# Special case for units place
|
| 45 |
+
elif i == 0 and digit == 1:
|
| 46 |
+
if len(digits) > 1 and digits[1] in [1, 2]:
|
| 47 |
+
result.append("เอ็ด") # "เอ็ด" for 11, 21
|
| 48 |
+
else:
|
| 49 |
+
result.append(thai_digits[digit])
|
| 50 |
+
else:
|
| 51 |
+
result.append(thai_digits[digit] + thai_places[i])
|
| 52 |
+
|
| 53 |
+
# Reverse back and join
|
| 54 |
+
result.reverse()
|
| 55 |
+
return "".join(result)
|
| 56 |
+
|
| 57 |
+
def replace_numbers_with_thai(text):
|
| 58 |
+
import re
|
| 59 |
+
|
| 60 |
+
# Function to convert matched number to Thai text
|
| 61 |
+
def convert_match(match):
|
| 62 |
+
num_str = match.group(0).replace(',', '')
|
| 63 |
+
|
| 64 |
+
# Skip if the string is empty or invalid after removing commas
|
| 65 |
+
if not num_str or num_str == '.':
|
| 66 |
+
return match.group(0)
|
| 67 |
+
|
| 68 |
+
# Handle decimal numbers
|
| 69 |
+
if '.' in num_str:
|
| 70 |
+
parts = num_str.split('.')
|
| 71 |
+
integer_part = parts[0]
|
| 72 |
+
decimal_part = parts[1] if len(parts) > 1 else ''
|
| 73 |
+
|
| 74 |
+
# If integer part is empty, treat as 0
|
| 75 |
+
integer_value = int(integer_part) if integer_part else 0
|
| 76 |
+
|
| 77 |
+
# If integer part is too long (>7 digits), read digit by digit
|
| 78 |
+
if len(integer_part) > 7:
|
| 79 |
+
result = number_to_thai_text(integer_value, digit_by_digit=True)
|
| 80 |
+
else:
|
| 81 |
+
result = number_to_thai_text(integer_value)
|
| 82 |
+
|
| 83 |
+
# Add decimal part if it exists
|
| 84 |
+
if decimal_part:
|
| 85 |
+
result += "จุด " + " ".join(number_to_thai_text(int(d)) for d in decimal_part)
|
| 86 |
+
return result
|
| 87 |
+
|
| 88 |
+
# Handle integer numbers
|
| 89 |
+
num = int(num_str)
|
| 90 |
+
if len(num_str) > 7: # If number exceeds 7 digits
|
| 91 |
+
return number_to_thai_text(num, digit_by_digit=True)
|
| 92 |
+
return number_to_thai_text(num)
|
| 93 |
+
|
| 94 |
+
# Replace all numbers (with or without commas and decimals) in the text
|
| 95 |
+
def process_text(text):
|
| 96 |
+
# Split by spaces to process each word
|
| 97 |
+
words = text.split()
|
| 98 |
+
result = []
|
| 99 |
+
|
| 100 |
+
for word in words:
|
| 101 |
+
# Match only valid numeric strings (allowing commas and one decimal point)
|
| 102 |
+
if re.match(r'^[\d,]+(\.\d+)?$', word): # Valid number with optional decimal
|
| 103 |
+
result.append(convert_match(re.match(r'[\d,\.]+', word)))
|
| 104 |
+
else:
|
| 105 |
+
# If word contains non-numeric characters, read numbers digit-by-digit
|
| 106 |
+
if any(c.isdigit() for c in word):
|
| 107 |
+
processed = ""
|
| 108 |
+
num_chunk = ""
|
| 109 |
+
for char in word:
|
| 110 |
+
if char.isdigit():
|
| 111 |
+
num_chunk += char
|
| 112 |
+
else:
|
| 113 |
+
if num_chunk:
|
| 114 |
+
processed += " ".join(number_to_thai_text(int(d)) for d in num_chunk) + " "
|
| 115 |
+
num_chunk = ""
|
| 116 |
+
processed += char + " "
|
| 117 |
+
if num_chunk: # Handle any remaining numbers
|
| 118 |
+
processed += " ".join(number_to_thai_text(int(d)) for d in num_chunk)
|
| 119 |
+
result.append(processed.strip())
|
| 120 |
+
else:
|
| 121 |
+
result.append(word)
|
| 122 |
+
|
| 123 |
+
return " ".join(result)
|
| 124 |
+
|
| 125 |
+
return process_text(text)
|
| 126 |
+
|
| 127 |
+
# Test the functions
|
| 128 |
+
if __name__ == "__main__":
|
| 129 |
+
# Test number_to_thai_text
|
| 130 |
+
test_numbers = [1, 12, 500, 6450, 100000, 12345678]
|
| 131 |
+
for num in test_numbers:
|
| 132 |
+
print(f"{num:,} -> {number_to_thai_text(num)}")
|
| 133 |
+
|
| 134 |
+
# Test with decimals and mixed text
|
| 135 |
+
test_texts = [
|
| 136 |
+
"ฉันมีเงิน 500 บาท",
|
| 137 |
+
"ราคา 123.45 บาท",
|
| 138 |
+
"บ้านเลขที่ 12 34",
|
| 139 |
+
"วันที่ 15 08 2023",
|
| 140 |
+
]
|
| 141 |
+
|
| 142 |
+
for text in test_texts:
|
| 143 |
+
result = replace_numbers_with_thai(text)
|
| 144 |
+
print(f"\nOriginal: {text}")
|
| 145 |
+
print(f"Converted: {result}")
|
deployment/src/f5_tts/cleantext/th_repeat.py
ADDED
|
@@ -0,0 +1,41 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
from pythainlp.tokenize import syllable_tokenize
|
| 2 |
+
|
| 3 |
+
def remove_symbol(text):
|
| 4 |
+
symbols = "{}[]()-_?/\\|!*%$&@#^<>+-\";:~\`=“”"
|
| 5 |
+
for symbol in symbols:
|
| 6 |
+
text = text.replace(symbol, '')
|
| 7 |
+
text = text.replace(" ๆ","ๆ")
|
| 8 |
+
return text
|
| 9 |
+
|
| 10 |
+
def process_thai_repeat(text):
|
| 11 |
+
|
| 12 |
+
cleaned_symbols = remove_symbol(text)
|
| 13 |
+
|
| 14 |
+
words = syllable_tokenize(cleaned_symbols)
|
| 15 |
+
|
| 16 |
+
result = []
|
| 17 |
+
i = 0
|
| 18 |
+
while i < len(words):
|
| 19 |
+
if i + 1 < len(words) and words[i + 1] == "ๆ":
|
| 20 |
+
result.append(words[i])
|
| 21 |
+
result.append(words[i])
|
| 22 |
+
i += 2
|
| 23 |
+
else:
|
| 24 |
+
result.append(words[i])
|
| 25 |
+
i += 1
|
| 26 |
+
|
| 27 |
+
return "".join(result)
|
| 28 |
+
|
| 29 |
+
if __name__ == "__main__":
|
| 30 |
+
# Example
|
| 31 |
+
test_cases = [
|
| 32 |
+
"วันที่ ฉันสนุกมากๆ",
|
| 33 |
+
"ดีมากๆ",
|
| 34 |
+
"บ้านสวยๆ",
|
| 35 |
+
"เขียนเร็วๆ",
|
| 36 |
+
"วันที่ ฉันสนุกมากๆ และกินอร่อยๆ"
|
| 37 |
+
]
|
| 38 |
+
|
| 39 |
+
for text in test_cases:
|
| 40 |
+
result = process_thai_repeat(text)
|
| 41 |
+
print(f"Original: {text} -> Converted: {result}")
|
deployment/src/f5_tts/config.py
ADDED
|
@@ -0,0 +1,98 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
"""
|
| 2 |
+
Configuration settings for F5-TTS Thai WebUI
|
| 3 |
+
"""
|
| 4 |
+
|
| 5 |
+
# Model configurations
|
| 6 |
+
DEFAULT_MODEL_BASE = "hf://VIZINTZOR/F5-TTS-THAI/model_1000000.pt"
|
| 7 |
+
FP16_MODEL_BASE = "hf://VIZINTZOR/F5-TTS-THAI/model_650000_FP16.pt"
|
| 8 |
+
VOCAB_BASE = "./vocab/vocab.txt"
|
| 9 |
+
VOCAB_HF = "hf://VIZINTZOR/F5-TTS-THAI/vocab.txt"
|
| 10 |
+
|
| 11 |
+
MODEL_CHOICES = ["Default", "FP16", "Custom"]
|
| 12 |
+
|
| 13 |
+
# F5TTS model configuration
|
| 14 |
+
F5TTS_MODEL_CFG = {
|
| 15 |
+
"dim": 1024,
|
| 16 |
+
"depth": 22,
|
| 17 |
+
"heads": 16,
|
| 18 |
+
"ff_mult": 2,
|
| 19 |
+
"text_dim": 512,
|
| 20 |
+
"conv_layers": 4
|
| 21 |
+
}
|
| 22 |
+
|
| 23 |
+
# Audio settings
|
| 24 |
+
TARGET_SAMPLE_RATE = 24000
|
| 25 |
+
HOP_LENGTH = 256
|
| 26 |
+
|
| 27 |
+
# UI settings
|
| 28 |
+
MAX_SPEECH_TYPES = 100
|
| 29 |
+
MAX_SEGMENTS = 20
|
| 30 |
+
|
| 31 |
+
# Default TTS settings
|
| 32 |
+
DEFAULT_TTS_SETTINGS = {
|
| 33 |
+
"remove_silence": True,
|
| 34 |
+
"cross_fade_duration": 0.15,
|
| 35 |
+
"nfe_step": 32,
|
| 36 |
+
"speed": 1.0,
|
| 37 |
+
"cfg_strength": 2.0,
|
| 38 |
+
"max_chars": 250,
|
| 39 |
+
"seed": -1,
|
| 40 |
+
"no_ref_audio": False
|
| 41 |
+
}
|
| 42 |
+
|
| 43 |
+
# Whisper model settings
|
| 44 |
+
WHISPER_MODELS = ['base', 'small', 'medium', 'large-v2', 'large-v3', 'large-v3-turbo']
|
| 45 |
+
WHISPER_COMPUTE_TYPES = ["float32", "float16", "int8_float16", "int8"]
|
| 46 |
+
WHISPER_LANGUAGES = {
|
| 47 |
+
"source": ["Auto", 'th', "en"],
|
| 48 |
+
"target": ['th', "en"]
|
| 49 |
+
}
|
| 50 |
+
|
| 51 |
+
# Example configurations
|
| 52 |
+
EXAMPLES = [
|
| 53 |
+
[
|
| 54 |
+
"./src/f5_tts/infer/examples/thai_examples/ref_gen_1.wav",
|
| 55 |
+
"ได้รับข่าวคราวของเราที่จะหาที่มันเป็นไปที่จะจัดขึ้น.",
|
| 56 |
+
"พรุ่งนี้มีประชุมสำคัญ อย่าลืมเตรียมเอกสารให้เรียบร้อย"
|
| 57 |
+
],
|
| 58 |
+
[
|
| 59 |
+
"./src/f5_tts/infer/examples/thai_examples/ref_gen_2.wav",
|
| 60 |
+
"ฉันเดินทางไปเที่ยวที่จังหวัดเชียงใหม่ในช่วงฤดูหนาวเพื่อสัมผัสอากาศเย็นสบาย.",
|
| 61 |
+
"ฉันชอบฟังเพลงขณะขับรถ เพราะช่วยให้รู้สึกผ่อนคลาย"
|
| 62 |
+
],
|
| 63 |
+
[
|
| 64 |
+
"./src/f5_tts/infer/examples/thai_examples/ref_gen_3.wav",
|
| 65 |
+
"กู้ดอาฟเต้อนูนไนท์ทูมีทยู.",
|
| 66 |
+
"วันนี้อากาศดีมาก เหมาะกับการไปเดินเล่นที่สวนสาธารณะ"
|
| 67 |
+
],
|
| 68 |
+
[
|
| 69 |
+
"./src/f5_tts/infer/examples/thai_examples/ref_gen_4.wav",
|
| 70 |
+
"เราอยากจะตื่นขึ้นมามั้ยคะ.",
|
| 71 |
+
"เมื่อวานฉันไปเดินเล่นที่ชายหาด เสียงคลื่นซัดฝั่งเป็นจังหวะที่ชวนให้ใจสงบ."
|
| 72 |
+
]
|
| 73 |
+
]
|
| 74 |
+
|
| 75 |
+
TIPS_TEXT = """
|
| 76 |
+
- สามารถตั้งค่า "ตัวอักษรสูงสุดต่อส่วน" หรือ max_chars เพื่อลดความผิดพลาดการอ่าน แต่ความเร็วในการสร้างจะช้าลง สามารถปรับลด NFE Step เพื่อเพิ่มความเร็วได้
|
| 77 |
+
ปรับ NFE Step เหลือ 7 สามารถเพิ่มความเร็วการในการสร้างได้มาก แต่เสียงที่ได้พอฟังได้.
|
| 78 |
+
- อย่าลืมเว้นวรรคประโยคเพื่อให้สามารถแบ่งส่วนในการสร้างได้.
|
| 79 |
+
- สำหรับ ref_text หรือ ข้อความตันฉบับ แนะนำให้ใช้เป็นภาษาไทยหรือคำอ่านภาษาไทยสำหรับเสียงภาษาอื่น เพื่อให้การอ่านภาษาไทยดีขึ้น เช่น Good Morning > กู้ดมอร์นิ่ง.
|
| 80 |
+
- สำหรับเสียงต้นแบบ ควรใช้ความยาวไม่เกิน 10 วินาที ถ้าเป็นไปได้ห้ามมีเสียงรบกวน.
|
| 81 |
+
- สามารถปรับลดความเร็วให้ช้าลง ถ้าเสียงต้นฉบับมีความยาวไม่มาก เช่น 2-5 วินาที
|
| 82 |
+
- การอ่านข้อความยาวๆ หรือบางคำ ยังไม่ถูกต้อง สามารถปรับลดความเร็วเพื่อให้การอ่านถูกต้องได้ เช่น ถ้าเสียงต้นฉบับมีความยาว 1-3 วินาที อาจจะต้องประความเร็วเหลือ 0.8-0.9.
|
| 83 |
+
- โมเดลตอนนี้ยังเน้นการอ่านภาษาไทยเป็นหลัก ���ารอ่านภาษาไทยผสมกับภาษาอังกฤษยังต้องปรับปรุง.
|
| 84 |
+
"""
|
| 85 |
+
|
| 86 |
+
MULTISPEECH_EXAMPLE_TEXT = """
|
| 87 |
+
**ตัวอย่าง:**
|
| 88 |
+
{ปกติ} สวัสดีครับ มีอะไรให้ผมช่วยไหมครับ
|
| 89 |
+
{เศร้า} ผมเครียดจริงๆ นะตอนนี้...
|
| 90 |
+
{โกรธ} รู้ไหม! เธอไม่ควรอยู่ที่นี่!
|
| 91 |
+
{กระซิบ} ฉันมีอะไรจะบอกคุณ แต่มันเป็นความลับนะ.
|
| 92 |
+
"""
|
| 93 |
+
|
| 94 |
+
MULTISPEECH_PLACEHOLDER = """ป้อนสคริปต์โดยใส่ชื่อผู้พูด (หรือลักษณะอารมณ์) ไว้ที่ต้นแต่ละบล็อก ตัวอย่างเช่น:
|
| 95 |
+
{ปกติ} สวัสดีครับ มีอะไรให้ผมช่วยไหมครับ
|
| 96 |
+
{เศร้า} ผมเครียดจริงๆ นะตอนนี้...
|
| 97 |
+
{โกรธ} รู้ไหม! เธอไม่ควรอยู่ที่นี่!
|
| 98 |
+
{กระซิบ} ฉันมีอะไรจะบอกคุณ แต่มันเป็นความลับนะ."""
|
deployment/src/f5_tts/configs/E2TTS_Base_train.yaml
ADDED
|
@@ -0,0 +1,45 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
hydra:
|
| 2 |
+
run:
|
| 3 |
+
dir: ckpts/${model.name}_${model.mel_spec.mel_spec_type}_${model.tokenizer}_${datasets.name}/${now:%Y-%m-%d}/${now:%H-%M-%S}
|
| 4 |
+
|
| 5 |
+
datasets:
|
| 6 |
+
name: Emilia_ZH_EN # dataset name
|
| 7 |
+
batch_size_per_gpu: 38400 # 8 GPUs, 8 * 38400 = 307200
|
| 8 |
+
batch_size_type: frame # "frame" or "sample"
|
| 9 |
+
max_samples: 64 # max sequences per batch if use frame-wise batch_size. we set 32 for small models, 64 for base models
|
| 10 |
+
num_workers: 16
|
| 11 |
+
|
| 12 |
+
optim:
|
| 13 |
+
epochs: 15
|
| 14 |
+
learning_rate: 7.5e-5
|
| 15 |
+
num_warmup_updates: 20000 # warmup updates
|
| 16 |
+
grad_accumulation_steps: 1 # note: updates = steps / grad_accumulation_steps
|
| 17 |
+
max_grad_norm: 1.0 # gradient clipping
|
| 18 |
+
bnb_optimizer: False # use bnb 8bit AdamW optimizer or not
|
| 19 |
+
|
| 20 |
+
model:
|
| 21 |
+
name: E2TTS_Base
|
| 22 |
+
tokenizer: pinyin
|
| 23 |
+
tokenizer_path: None # if tokenizer = 'custom', define the path to the tokenizer you want to use (should be vocab.txt)
|
| 24 |
+
arch:
|
| 25 |
+
dim: 1024
|
| 26 |
+
depth: 24
|
| 27 |
+
heads: 16
|
| 28 |
+
ff_mult: 4
|
| 29 |
+
mel_spec:
|
| 30 |
+
target_sample_rate: 24000
|
| 31 |
+
n_mel_channels: 100
|
| 32 |
+
hop_length: 256
|
| 33 |
+
win_length: 1024
|
| 34 |
+
n_fft: 1024
|
| 35 |
+
mel_spec_type: vocos # 'vocos' or 'bigvgan'
|
| 36 |
+
vocoder:
|
| 37 |
+
is_local: False # use local offline ckpt or not
|
| 38 |
+
local_path: None # local vocoder path
|
| 39 |
+
|
| 40 |
+
ckpts:
|
| 41 |
+
logger: wandb # wandb | tensorboard | None
|
| 42 |
+
save_per_updates: 50000 # save checkpoint per updates
|
| 43 |
+
keep_last_n_checkpoints: -1 # -1 to keep all, 0 to not save intermediate, > 0 to keep last N checkpoints
|
| 44 |
+
last_per_updates: 5000 # save last checkpoint per updates
|
| 45 |
+
save_dir: ckpts/${model.name}_${model.mel_spec.mel_spec_type}_${model.tokenizer}_${datasets.name}
|
deployment/src/f5_tts/configs/E2TTS_Small_train.yaml
ADDED
|
@@ -0,0 +1,45 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
hydra:
|
| 2 |
+
run:
|
| 3 |
+
dir: ckpts/${model.name}_${model.mel_spec.mel_spec_type}_${model.tokenizer}_${datasets.name}/${now:%Y-%m-%d}/${now:%H-%M-%S}
|
| 4 |
+
|
| 5 |
+
datasets:
|
| 6 |
+
name: Emilia_ZH_EN
|
| 7 |
+
batch_size_per_gpu: 38400 # 8 GPUs, 8 * 38400 = 307200
|
| 8 |
+
batch_size_type: frame # "frame" or "sample"
|
| 9 |
+
max_samples: 64 # max sequences per batch if use frame-wise batch_size. we set 32 for small models, 64 for base models
|
| 10 |
+
num_workers: 16
|
| 11 |
+
|
| 12 |
+
optim:
|
| 13 |
+
epochs: 15
|
| 14 |
+
learning_rate: 7.5e-5
|
| 15 |
+
num_warmup_updates: 20000 # warmup updates
|
| 16 |
+
grad_accumulation_steps: 1 # note: updates = steps / grad_accumulation_steps
|
| 17 |
+
max_grad_norm: 1.0
|
| 18 |
+
bnb_optimizer: False
|
| 19 |
+
|
| 20 |
+
model:
|
| 21 |
+
name: E2TTS_Small
|
| 22 |
+
tokenizer: pinyin
|
| 23 |
+
tokenizer_path: None # if tokenizer = 'custom', define the path to the tokenizer you want to use (should be vocab.txt)
|
| 24 |
+
arch:
|
| 25 |
+
dim: 768
|
| 26 |
+
depth: 20
|
| 27 |
+
heads: 12
|
| 28 |
+
ff_mult: 4
|
| 29 |
+
mel_spec:
|
| 30 |
+
target_sample_rate: 24000
|
| 31 |
+
n_mel_channels: 100
|
| 32 |
+
hop_length: 256
|
| 33 |
+
win_length: 1024
|
| 34 |
+
n_fft: 1024
|
| 35 |
+
mel_spec_type: vocos # 'vocos' or 'bigvgan'
|
| 36 |
+
vocoder:
|
| 37 |
+
is_local: False # use local offline ckpt or not
|
| 38 |
+
local_path: None # local vocoder path
|
| 39 |
+
|
| 40 |
+
ckpts:
|
| 41 |
+
logger: wandb # wandb | tensorboard | None
|
| 42 |
+
save_per_updates: 50000 # save checkpoint per updates
|
| 43 |
+
keep_last_n_checkpoints: -1 # -1 to keep all, 0 to not save intermediate, > 0 to keep last N checkpoints
|
| 44 |
+
last_per_updates: 5000 # save last checkpoint per updates
|
| 45 |
+
save_dir: ckpts/${model.name}_${model.mel_spec.mel_spec_type}_${model.tokenizer}_${datasets.name}
|
deployment/src/f5_tts/configs/F5TTS_Base_train.yaml
ADDED
|
@@ -0,0 +1,48 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
hydra:
|
| 2 |
+
run:
|
| 3 |
+
dir: ckpts/${model.name}_${model.mel_spec.mel_spec_type}_${model.tokenizer}_${datasets.name}/${now:%Y-%m-%d}/${now:%H-%M-%S}
|
| 4 |
+
|
| 5 |
+
datasets:
|
| 6 |
+
name: Emilia_ZH_EN # dataset name
|
| 7 |
+
batch_size_per_gpu: 38400 # 8 GPUs, 8 * 38400 = 307200
|
| 8 |
+
batch_size_type: frame # "frame" or "sample"
|
| 9 |
+
max_samples: 64 # max sequences per batch if use frame-wise batch_size. we set 32 for small models, 64 for base models
|
| 10 |
+
num_workers: 16
|
| 11 |
+
|
| 12 |
+
optim:
|
| 13 |
+
epochs: 15
|
| 14 |
+
learning_rate: 7.5e-5
|
| 15 |
+
num_warmup_updates: 20000 # warmup updates
|
| 16 |
+
grad_accumulation_steps: 1 # note: updates = steps / grad_accumulation_steps
|
| 17 |
+
max_grad_norm: 1.0 # gradient clipping
|
| 18 |
+
bnb_optimizer: False # use bnb 8bit AdamW optimizer or not
|
| 19 |
+
|
| 20 |
+
model:
|
| 21 |
+
name: F5TTS_Base # model name
|
| 22 |
+
tokenizer: pinyin # tokenizer type
|
| 23 |
+
tokenizer_path: None # if tokenizer = 'custom', define the path to the tokenizer you want to use (should be vocab.txt)
|
| 24 |
+
arch:
|
| 25 |
+
dim: 1024
|
| 26 |
+
depth: 22
|
| 27 |
+
heads: 16
|
| 28 |
+
ff_mult: 2
|
| 29 |
+
text_dim: 512
|
| 30 |
+
conv_layers: 4
|
| 31 |
+
checkpoint_activations: False # recompute activations and save memory for extra compute
|
| 32 |
+
mel_spec:
|
| 33 |
+
target_sample_rate: 24000
|
| 34 |
+
n_mel_channels: 100
|
| 35 |
+
hop_length: 256
|
| 36 |
+
win_length: 1024
|
| 37 |
+
n_fft: 1024
|
| 38 |
+
mel_spec_type: vocos # 'vocos' or 'bigvgan'
|
| 39 |
+
vocoder:
|
| 40 |
+
is_local: False # use local offline ckpt or not
|
| 41 |
+
local_path: None # local vocoder path
|
| 42 |
+
|
| 43 |
+
ckpts:
|
| 44 |
+
logger: wandb # wandb | tensorboard | None
|
| 45 |
+
save_per_updates: 50000 # save checkpoint per updates
|
| 46 |
+
keep_last_n_checkpoints: -1 # -1 to keep all, 0 to not save intermediate, > 0 to keep last N checkpoints
|
| 47 |
+
last_per_updates: 5000 # save last checkpoint per updates
|
| 48 |
+
save_dir: ckpts/${model.name}_${model.mel_spec.mel_spec_type}_${model.tokenizer}_${datasets.name}
|
deployment/src/f5_tts/configs/F5TTS_Small_train.yaml
ADDED
|
@@ -0,0 +1,48 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
hydra:
|
| 2 |
+
run:
|
| 3 |
+
dir: ckpts/${model.name}_${model.mel_spec.mel_spec_type}_${model.tokenizer}_${datasets.name}/${now:%Y-%m-%d}/${now:%H-%M-%S}
|
| 4 |
+
|
| 5 |
+
datasets:
|
| 6 |
+
name: Emilia_ZH_EN
|
| 7 |
+
batch_size_per_gpu: 38400 # 8 GPUs, 8 * 38400 = 307200
|
| 8 |
+
batch_size_type: frame # "frame" or "sample"
|
| 9 |
+
max_samples: 64 # max sequences per batch if use frame-wise batch_size. we set 32 for small models, 64 for base models
|
| 10 |
+
num_workers: 16
|
| 11 |
+
|
| 12 |
+
optim:
|
| 13 |
+
epochs: 15
|
| 14 |
+
learning_rate: 7.5e-5
|
| 15 |
+
num_warmup_updates: 20000 # warmup updates
|
| 16 |
+
grad_accumulation_steps: 1 # note: updates = steps / grad_accumulation_steps
|
| 17 |
+
max_grad_norm: 1.0 # gradient clipping
|
| 18 |
+
bnb_optimizer: False # use bnb 8bit AdamW optimizer or not
|
| 19 |
+
|
| 20 |
+
model:
|
| 21 |
+
name: F5TTS_Small
|
| 22 |
+
tokenizer: pinyin
|
| 23 |
+
tokenizer_path: None # if tokenizer = 'custom', define the path to the tokenizer you want to use (should be vocab.txt)
|
| 24 |
+
arch:
|
| 25 |
+
dim: 768
|
| 26 |
+
depth: 18
|
| 27 |
+
heads: 12
|
| 28 |
+
ff_mult: 2
|
| 29 |
+
text_dim: 512
|
| 30 |
+
conv_layers: 4
|
| 31 |
+
checkpoint_activations: False # recompute activations and save memory for extra compute
|
| 32 |
+
mel_spec:
|
| 33 |
+
target_sample_rate: 24000
|
| 34 |
+
n_mel_channels: 100
|
| 35 |
+
hop_length: 256
|
| 36 |
+
win_length: 1024
|
| 37 |
+
n_fft: 1024
|
| 38 |
+
mel_spec_type: vocos # 'vocos' or 'bigvgan'
|
| 39 |
+
vocoder:
|
| 40 |
+
is_local: False # use local offline ckpt or not
|
| 41 |
+
local_path: None # local vocoder path
|
| 42 |
+
|
| 43 |
+
ckpts:
|
| 44 |
+
logger: wandb # wandb | tensorboard | None
|
| 45 |
+
save_per_updates: 50000 # save checkpoint per updates
|
| 46 |
+
keep_last_n_checkpoints: -1 # -1 to keep all, 0 to not save intermediate, > 0 to keep last N checkpoints
|
| 47 |
+
last_per_updates: 5000 # save last checkpoint per updates
|
| 48 |
+
save_dir: ckpts/${model.name}_${model.mel_spec.mel_spec_type}_${model.tokenizer}_${datasets.name}
|
deployment/src/f5_tts/eval/README.md
ADDED
|
@@ -0,0 +1,52 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
|
| 2 |
+
# Evaluation
|
| 3 |
+
|
| 4 |
+
Install packages for evaluation:
|
| 5 |
+
|
| 6 |
+
```bash
|
| 7 |
+
pip install -e .[eval]
|
| 8 |
+
```
|
| 9 |
+
|
| 10 |
+
## Generating Samples for Evaluation
|
| 11 |
+
|
| 12 |
+
### Prepare Test Datasets
|
| 13 |
+
|
| 14 |
+
1. *Seed-TTS testset*: Download from [seed-tts-eval](https://github.com/BytedanceSpeech/seed-tts-eval).
|
| 15 |
+
2. *LibriSpeech test-clean*: Download from [OpenSLR](http://www.openslr.org/12/).
|
| 16 |
+
3. Unzip the downloaded datasets and place them in the `data/` directory.
|
| 17 |
+
4. Update the path for *LibriSpeech test-clean* data in `src/f5_tts/eval/eval_infer_batch.py`
|
| 18 |
+
5. Our filtered LibriSpeech-PC 4-10s subset: `data/librispeech_pc_test_clean_cross_sentence.lst`
|
| 19 |
+
|
| 20 |
+
### Batch Inference for Test Set
|
| 21 |
+
|
| 22 |
+
To run batch inference for evaluations, execute the following commands:
|
| 23 |
+
|
| 24 |
+
```bash
|
| 25 |
+
# batch inference for evaluations
|
| 26 |
+
accelerate config # if not set before
|
| 27 |
+
bash src/f5_tts/eval/eval_infer_batch.sh
|
| 28 |
+
```
|
| 29 |
+
|
| 30 |
+
## Objective Evaluation on Generated Results
|
| 31 |
+
|
| 32 |
+
### Download Evaluation Model Checkpoints
|
| 33 |
+
|
| 34 |
+
1. Chinese ASR Model: [Paraformer-zh](https://huggingface.co/funasr/paraformer-zh)
|
| 35 |
+
2. English ASR Model: [Faster-Whisper](https://huggingface.co/Systran/faster-whisper-large-v3)
|
| 36 |
+
3. WavLM Model: Download from [Google Drive](https://drive.google.com/file/d/1-aE1NfzpRCLxA4GUxX9ITI3F9LlbtEGP/view).
|
| 37 |
+
|
| 38 |
+
Then update in the following scripts with the paths you put evaluation model ckpts to.
|
| 39 |
+
|
| 40 |
+
### Objective Evaluation
|
| 41 |
+
|
| 42 |
+
Update the path with your batch-inferenced results, and carry out WER / SIM / UTMOS evaluations:
|
| 43 |
+
```bash
|
| 44 |
+
# Evaluation [WER] for Seed-TTS test [ZH] set
|
| 45 |
+
python src/f5_tts/eval/eval_seedtts_testset.py --eval_task wer --lang zh --gen_wav_dir <GEN_WAV_DIR> --gpu_nums 8
|
| 46 |
+
|
| 47 |
+
# Evaluation [SIM] for LibriSpeech-PC test-clean (cross-sentence)
|
| 48 |
+
python src/f5_tts/eval/eval_librispeech_test_clean.py --eval_task sim --gen_wav_dir <GEN_WAV_DIR> --librispeech_test_clean_path <TEST_CLEAN_PATH>
|
| 49 |
+
|
| 50 |
+
# Evaluation [UTMOS]. --ext: Audio extension
|
| 51 |
+
python src/f5_tts/eval/eval_utmos.py --audio_dir <WAV_DIR> --ext wav
|
| 52 |
+
```
|
deployment/src/f5_tts/eval/ecapa_tdnn.py
ADDED
|
@@ -0,0 +1,330 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
# just for speaker similarity evaluation, third-party code
|
| 2 |
+
|
| 3 |
+
# From https://github.com/microsoft/UniSpeech/blob/main/downstreams/speaker_verification/models/
|
| 4 |
+
# part of the code is borrowed from https://github.com/lawlict/ECAPA-TDNN
|
| 5 |
+
|
| 6 |
+
import os
|
| 7 |
+
import torch
|
| 8 |
+
import torch.nn as nn
|
| 9 |
+
import torch.nn.functional as F
|
| 10 |
+
|
| 11 |
+
|
| 12 |
+
""" Res2Conv1d + BatchNorm1d + ReLU
|
| 13 |
+
"""
|
| 14 |
+
|
| 15 |
+
|
| 16 |
+
class Res2Conv1dReluBn(nn.Module):
|
| 17 |
+
"""
|
| 18 |
+
in_channels == out_channels == channels
|
| 19 |
+
"""
|
| 20 |
+
|
| 21 |
+
def __init__(self, channels, kernel_size=1, stride=1, padding=0, dilation=1, bias=True, scale=4):
|
| 22 |
+
super().__init__()
|
| 23 |
+
assert channels % scale == 0, "{} % {} != 0".format(channels, scale)
|
| 24 |
+
self.scale = scale
|
| 25 |
+
self.width = channels // scale
|
| 26 |
+
self.nums = scale if scale == 1 else scale - 1
|
| 27 |
+
|
| 28 |
+
self.convs = []
|
| 29 |
+
self.bns = []
|
| 30 |
+
for i in range(self.nums):
|
| 31 |
+
self.convs.append(nn.Conv1d(self.width, self.width, kernel_size, stride, padding, dilation, bias=bias))
|
| 32 |
+
self.bns.append(nn.BatchNorm1d(self.width))
|
| 33 |
+
self.convs = nn.ModuleList(self.convs)
|
| 34 |
+
self.bns = nn.ModuleList(self.bns)
|
| 35 |
+
|
| 36 |
+
def forward(self, x):
|
| 37 |
+
out = []
|
| 38 |
+
spx = torch.split(x, self.width, 1)
|
| 39 |
+
for i in range(self.nums):
|
| 40 |
+
if i == 0:
|
| 41 |
+
sp = spx[i]
|
| 42 |
+
else:
|
| 43 |
+
sp = sp + spx[i]
|
| 44 |
+
# Order: conv -> relu -> bn
|
| 45 |
+
sp = self.convs[i](sp)
|
| 46 |
+
sp = self.bns[i](F.relu(sp))
|
| 47 |
+
out.append(sp)
|
| 48 |
+
if self.scale != 1:
|
| 49 |
+
out.append(spx[self.nums])
|
| 50 |
+
out = torch.cat(out, dim=1)
|
| 51 |
+
|
| 52 |
+
return out
|
| 53 |
+
|
| 54 |
+
|
| 55 |
+
""" Conv1d + BatchNorm1d + ReLU
|
| 56 |
+
"""
|
| 57 |
+
|
| 58 |
+
|
| 59 |
+
class Conv1dReluBn(nn.Module):
|
| 60 |
+
def __init__(self, in_channels, out_channels, kernel_size=1, stride=1, padding=0, dilation=1, bias=True):
|
| 61 |
+
super().__init__()
|
| 62 |
+
self.conv = nn.Conv1d(in_channels, out_channels, kernel_size, stride, padding, dilation, bias=bias)
|
| 63 |
+
self.bn = nn.BatchNorm1d(out_channels)
|
| 64 |
+
|
| 65 |
+
def forward(self, x):
|
| 66 |
+
return self.bn(F.relu(self.conv(x)))
|
| 67 |
+
|
| 68 |
+
|
| 69 |
+
""" The SE connection of 1D case.
|
| 70 |
+
"""
|
| 71 |
+
|
| 72 |
+
|
| 73 |
+
class SE_Connect(nn.Module):
|
| 74 |
+
def __init__(self, channels, se_bottleneck_dim=128):
|
| 75 |
+
super().__init__()
|
| 76 |
+
self.linear1 = nn.Linear(channels, se_bottleneck_dim)
|
| 77 |
+
self.linear2 = nn.Linear(se_bottleneck_dim, channels)
|
| 78 |
+
|
| 79 |
+
def forward(self, x):
|
| 80 |
+
out = x.mean(dim=2)
|
| 81 |
+
out = F.relu(self.linear1(out))
|
| 82 |
+
out = torch.sigmoid(self.linear2(out))
|
| 83 |
+
out = x * out.unsqueeze(2)
|
| 84 |
+
|
| 85 |
+
return out
|
| 86 |
+
|
| 87 |
+
|
| 88 |
+
""" SE-Res2Block of the ECAPA-TDNN architecture.
|
| 89 |
+
"""
|
| 90 |
+
|
| 91 |
+
# def SE_Res2Block(channels, kernel_size, stride, padding, dilation, scale):
|
| 92 |
+
# return nn.Sequential(
|
| 93 |
+
# Conv1dReluBn(channels, 512, kernel_size=1, stride=1, padding=0),
|
| 94 |
+
# Res2Conv1dReluBn(512, kernel_size, stride, padding, dilation, scale=scale),
|
| 95 |
+
# Conv1dReluBn(512, channels, kernel_size=1, stride=1, padding=0),
|
| 96 |
+
# SE_Connect(channels)
|
| 97 |
+
# )
|
| 98 |
+
|
| 99 |
+
|
| 100 |
+
class SE_Res2Block(nn.Module):
|
| 101 |
+
def __init__(self, in_channels, out_channels, kernel_size, stride, padding, dilation, scale, se_bottleneck_dim):
|
| 102 |
+
super().__init__()
|
| 103 |
+
self.Conv1dReluBn1 = Conv1dReluBn(in_channels, out_channels, kernel_size=1, stride=1, padding=0)
|
| 104 |
+
self.Res2Conv1dReluBn = Res2Conv1dReluBn(out_channels, kernel_size, stride, padding, dilation, scale=scale)
|
| 105 |
+
self.Conv1dReluBn2 = Conv1dReluBn(out_channels, out_channels, kernel_size=1, stride=1, padding=0)
|
| 106 |
+
self.SE_Connect = SE_Connect(out_channels, se_bottleneck_dim)
|
| 107 |
+
|
| 108 |
+
self.shortcut = None
|
| 109 |
+
if in_channels != out_channels:
|
| 110 |
+
self.shortcut = nn.Conv1d(
|
| 111 |
+
in_channels=in_channels,
|
| 112 |
+
out_channels=out_channels,
|
| 113 |
+
kernel_size=1,
|
| 114 |
+
)
|
| 115 |
+
|
| 116 |
+
def forward(self, x):
|
| 117 |
+
residual = x
|
| 118 |
+
if self.shortcut:
|
| 119 |
+
residual = self.shortcut(x)
|
| 120 |
+
|
| 121 |
+
x = self.Conv1dReluBn1(x)
|
| 122 |
+
x = self.Res2Conv1dReluBn(x)
|
| 123 |
+
x = self.Conv1dReluBn2(x)
|
| 124 |
+
x = self.SE_Connect(x)
|
| 125 |
+
|
| 126 |
+
return x + residual
|
| 127 |
+
|
| 128 |
+
|
| 129 |
+
""" Attentive weighted mean and standard deviation pooling.
|
| 130 |
+
"""
|
| 131 |
+
|
| 132 |
+
|
| 133 |
+
class AttentiveStatsPool(nn.Module):
|
| 134 |
+
def __init__(self, in_dim, attention_channels=128, global_context_att=False):
|
| 135 |
+
super().__init__()
|
| 136 |
+
self.global_context_att = global_context_att
|
| 137 |
+
|
| 138 |
+
# Use Conv1d with stride == 1 rather than Linear, then we don't need to transpose inputs.
|
| 139 |
+
if global_context_att:
|
| 140 |
+
self.linear1 = nn.Conv1d(in_dim * 3, attention_channels, kernel_size=1) # equals W and b in the paper
|
| 141 |
+
else:
|
| 142 |
+
self.linear1 = nn.Conv1d(in_dim, attention_channels, kernel_size=1) # equals W and b in the paper
|
| 143 |
+
self.linear2 = nn.Conv1d(attention_channels, in_dim, kernel_size=1) # equals V and k in the paper
|
| 144 |
+
|
| 145 |
+
def forward(self, x):
|
| 146 |
+
if self.global_context_att:
|
| 147 |
+
context_mean = torch.mean(x, dim=-1, keepdim=True).expand_as(x)
|
| 148 |
+
context_std = torch.sqrt(torch.var(x, dim=-1, keepdim=True) + 1e-10).expand_as(x)
|
| 149 |
+
x_in = torch.cat((x, context_mean, context_std), dim=1)
|
| 150 |
+
else:
|
| 151 |
+
x_in = x
|
| 152 |
+
|
| 153 |
+
# DON'T use ReLU here! In experiments, I find ReLU hard to converge.
|
| 154 |
+
alpha = torch.tanh(self.linear1(x_in))
|
| 155 |
+
# alpha = F.relu(self.linear1(x_in))
|
| 156 |
+
alpha = torch.softmax(self.linear2(alpha), dim=2)
|
| 157 |
+
mean = torch.sum(alpha * x, dim=2)
|
| 158 |
+
residuals = torch.sum(alpha * (x**2), dim=2) - mean**2
|
| 159 |
+
std = torch.sqrt(residuals.clamp(min=1e-9))
|
| 160 |
+
return torch.cat([mean, std], dim=1)
|
| 161 |
+
|
| 162 |
+
|
| 163 |
+
class ECAPA_TDNN(nn.Module):
|
| 164 |
+
def __init__(
|
| 165 |
+
self,
|
| 166 |
+
feat_dim=80,
|
| 167 |
+
channels=512,
|
| 168 |
+
emb_dim=192,
|
| 169 |
+
global_context_att=False,
|
| 170 |
+
feat_type="wavlm_large",
|
| 171 |
+
sr=16000,
|
| 172 |
+
feature_selection="hidden_states",
|
| 173 |
+
update_extract=False,
|
| 174 |
+
config_path=None,
|
| 175 |
+
):
|
| 176 |
+
super().__init__()
|
| 177 |
+
|
| 178 |
+
self.feat_type = feat_type
|
| 179 |
+
self.feature_selection = feature_selection
|
| 180 |
+
self.update_extract = update_extract
|
| 181 |
+
self.sr = sr
|
| 182 |
+
|
| 183 |
+
torch.hub._validate_not_a_forked_repo = lambda a, b, c: True
|
| 184 |
+
try:
|
| 185 |
+
local_s3prl_path = os.path.expanduser("~/.cache/torch/hub/s3prl_s3prl_main")
|
| 186 |
+
self.feature_extract = torch.hub.load(local_s3prl_path, feat_type, source="local", config_path=config_path)
|
| 187 |
+
except: # noqa: E722
|
| 188 |
+
self.feature_extract = torch.hub.load("s3prl/s3prl", feat_type)
|
| 189 |
+
|
| 190 |
+
if len(self.feature_extract.model.encoder.layers) == 24 and hasattr(
|
| 191 |
+
self.feature_extract.model.encoder.layers[23].self_attn, "fp32_attention"
|
| 192 |
+
):
|
| 193 |
+
self.feature_extract.model.encoder.layers[23].self_attn.fp32_attention = False
|
| 194 |
+
if len(self.feature_extract.model.encoder.layers) == 24 and hasattr(
|
| 195 |
+
self.feature_extract.model.encoder.layers[11].self_attn, "fp32_attention"
|
| 196 |
+
):
|
| 197 |
+
self.feature_extract.model.encoder.layers[11].self_attn.fp32_attention = False
|
| 198 |
+
|
| 199 |
+
self.feat_num = self.get_feat_num()
|
| 200 |
+
self.feature_weight = nn.Parameter(torch.zeros(self.feat_num))
|
| 201 |
+
|
| 202 |
+
if feat_type != "fbank" and feat_type != "mfcc":
|
| 203 |
+
freeze_list = ["final_proj", "label_embs_concat", "mask_emb", "project_q", "quantizer"]
|
| 204 |
+
for name, param in self.feature_extract.named_parameters():
|
| 205 |
+
for freeze_val in freeze_list:
|
| 206 |
+
if freeze_val in name:
|
| 207 |
+
param.requires_grad = False
|
| 208 |
+
break
|
| 209 |
+
|
| 210 |
+
if not self.update_extract:
|
| 211 |
+
for param in self.feature_extract.parameters():
|
| 212 |
+
param.requires_grad = False
|
| 213 |
+
|
| 214 |
+
self.instance_norm = nn.InstanceNorm1d(feat_dim)
|
| 215 |
+
# self.channels = [channels] * 4 + [channels * 3]
|
| 216 |
+
self.channels = [channels] * 4 + [1536]
|
| 217 |
+
|
| 218 |
+
self.layer1 = Conv1dReluBn(feat_dim, self.channels[0], kernel_size=5, padding=2)
|
| 219 |
+
self.layer2 = SE_Res2Block(
|
| 220 |
+
self.channels[0],
|
| 221 |
+
self.channels[1],
|
| 222 |
+
kernel_size=3,
|
| 223 |
+
stride=1,
|
| 224 |
+
padding=2,
|
| 225 |
+
dilation=2,
|
| 226 |
+
scale=8,
|
| 227 |
+
se_bottleneck_dim=128,
|
| 228 |
+
)
|
| 229 |
+
self.layer3 = SE_Res2Block(
|
| 230 |
+
self.channels[1],
|
| 231 |
+
self.channels[2],
|
| 232 |
+
kernel_size=3,
|
| 233 |
+
stride=1,
|
| 234 |
+
padding=3,
|
| 235 |
+
dilation=3,
|
| 236 |
+
scale=8,
|
| 237 |
+
se_bottleneck_dim=128,
|
| 238 |
+
)
|
| 239 |
+
self.layer4 = SE_Res2Block(
|
| 240 |
+
self.channels[2],
|
| 241 |
+
self.channels[3],
|
| 242 |
+
kernel_size=3,
|
| 243 |
+
stride=1,
|
| 244 |
+
padding=4,
|
| 245 |
+
dilation=4,
|
| 246 |
+
scale=8,
|
| 247 |
+
se_bottleneck_dim=128,
|
| 248 |
+
)
|
| 249 |
+
|
| 250 |
+
# self.conv = nn.Conv1d(self.channels[-1], self.channels[-1], kernel_size=1)
|
| 251 |
+
cat_channels = channels * 3
|
| 252 |
+
self.conv = nn.Conv1d(cat_channels, self.channels[-1], kernel_size=1)
|
| 253 |
+
self.pooling = AttentiveStatsPool(
|
| 254 |
+
self.channels[-1], attention_channels=128, global_context_att=global_context_att
|
| 255 |
+
)
|
| 256 |
+
self.bn = nn.BatchNorm1d(self.channels[-1] * 2)
|
| 257 |
+
self.linear = nn.Linear(self.channels[-1] * 2, emb_dim)
|
| 258 |
+
|
| 259 |
+
def get_feat_num(self):
|
| 260 |
+
self.feature_extract.eval()
|
| 261 |
+
wav = [torch.randn(self.sr).to(next(self.feature_extract.parameters()).device)]
|
| 262 |
+
with torch.no_grad():
|
| 263 |
+
features = self.feature_extract(wav)
|
| 264 |
+
select_feature = features[self.feature_selection]
|
| 265 |
+
if isinstance(select_feature, (list, tuple)):
|
| 266 |
+
return len(select_feature)
|
| 267 |
+
else:
|
| 268 |
+
return 1
|
| 269 |
+
|
| 270 |
+
def get_feat(self, x):
|
| 271 |
+
if self.update_extract:
|
| 272 |
+
x = self.feature_extract([sample for sample in x])
|
| 273 |
+
else:
|
| 274 |
+
with torch.no_grad():
|
| 275 |
+
if self.feat_type == "fbank" or self.feat_type == "mfcc":
|
| 276 |
+
x = self.feature_extract(x) + 1e-6 # B x feat_dim x time_len
|
| 277 |
+
else:
|
| 278 |
+
x = self.feature_extract([sample for sample in x])
|
| 279 |
+
|
| 280 |
+
if self.feat_type == "fbank":
|
| 281 |
+
x = x.log()
|
| 282 |
+
|
| 283 |
+
if self.feat_type != "fbank" and self.feat_type != "mfcc":
|
| 284 |
+
x = x[self.feature_selection]
|
| 285 |
+
if isinstance(x, (list, tuple)):
|
| 286 |
+
x = torch.stack(x, dim=0)
|
| 287 |
+
else:
|
| 288 |
+
x = x.unsqueeze(0)
|
| 289 |
+
norm_weights = F.softmax(self.feature_weight, dim=-1).unsqueeze(-1).unsqueeze(-1).unsqueeze(-1)
|
| 290 |
+
x = (norm_weights * x).sum(dim=0)
|
| 291 |
+
x = torch.transpose(x, 1, 2) + 1e-6
|
| 292 |
+
|
| 293 |
+
x = self.instance_norm(x)
|
| 294 |
+
return x
|
| 295 |
+
|
| 296 |
+
def forward(self, x):
|
| 297 |
+
x = self.get_feat(x)
|
| 298 |
+
|
| 299 |
+
out1 = self.layer1(x)
|
| 300 |
+
out2 = self.layer2(out1)
|
| 301 |
+
out3 = self.layer3(out2)
|
| 302 |
+
out4 = self.layer4(out3)
|
| 303 |
+
|
| 304 |
+
out = torch.cat([out2, out3, out4], dim=1)
|
| 305 |
+
out = F.relu(self.conv(out))
|
| 306 |
+
out = self.bn(self.pooling(out))
|
| 307 |
+
out = self.linear(out)
|
| 308 |
+
|
| 309 |
+
return out
|
| 310 |
+
|
| 311 |
+
|
| 312 |
+
def ECAPA_TDNN_SMALL(
|
| 313 |
+
feat_dim,
|
| 314 |
+
emb_dim=256,
|
| 315 |
+
feat_type="wavlm_large",
|
| 316 |
+
sr=16000,
|
| 317 |
+
feature_selection="hidden_states",
|
| 318 |
+
update_extract=False,
|
| 319 |
+
config_path=None,
|
| 320 |
+
):
|
| 321 |
+
return ECAPA_TDNN(
|
| 322 |
+
feat_dim=feat_dim,
|
| 323 |
+
channels=512,
|
| 324 |
+
emb_dim=emb_dim,
|
| 325 |
+
feat_type=feat_type,
|
| 326 |
+
sr=sr,
|
| 327 |
+
feature_selection=feature_selection,
|
| 328 |
+
update_extract=update_extract,
|
| 329 |
+
config_path=config_path,
|
| 330 |
+
)
|
deployment/src/f5_tts/eval/eval_infer_batch.py
ADDED
|
@@ -0,0 +1,207 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
import os
|
| 2 |
+
import sys
|
| 3 |
+
|
| 4 |
+
sys.path.append(os.getcwd())
|
| 5 |
+
|
| 6 |
+
import argparse
|
| 7 |
+
import time
|
| 8 |
+
from importlib.resources import files
|
| 9 |
+
|
| 10 |
+
import torch
|
| 11 |
+
import torchaudio
|
| 12 |
+
from accelerate import Accelerator
|
| 13 |
+
from tqdm import tqdm
|
| 14 |
+
|
| 15 |
+
from f5_tts.eval.utils_eval import (
|
| 16 |
+
get_inference_prompt,
|
| 17 |
+
get_librispeech_test_clean_metainfo,
|
| 18 |
+
get_seedtts_testset_metainfo,
|
| 19 |
+
)
|
| 20 |
+
from f5_tts.infer.utils_infer import load_checkpoint, load_vocoder
|
| 21 |
+
from f5_tts.model import CFM, DiT, UNetT
|
| 22 |
+
from f5_tts.model.utils import get_tokenizer
|
| 23 |
+
|
| 24 |
+
accelerator = Accelerator()
|
| 25 |
+
device = f"cuda:{accelerator.process_index}"
|
| 26 |
+
|
| 27 |
+
|
| 28 |
+
# --------------------- Dataset Settings -------------------- #
|
| 29 |
+
|
| 30 |
+
target_sample_rate = 24000
|
| 31 |
+
n_mel_channels = 100
|
| 32 |
+
hop_length = 256
|
| 33 |
+
win_length = 1024
|
| 34 |
+
n_fft = 1024
|
| 35 |
+
target_rms = 0.1
|
| 36 |
+
|
| 37 |
+
rel_path = str(files("f5_tts").joinpath("../../"))
|
| 38 |
+
|
| 39 |
+
|
| 40 |
+
def main():
|
| 41 |
+
# ---------------------- infer setting ---------------------- #
|
| 42 |
+
|
| 43 |
+
parser = argparse.ArgumentParser(description="batch inference")
|
| 44 |
+
|
| 45 |
+
parser.add_argument("-s", "--seed", default=None, type=int)
|
| 46 |
+
parser.add_argument("-d", "--dataset", default="Emilia_ZH_EN")
|
| 47 |
+
parser.add_argument("-n", "--expname", required=True)
|
| 48 |
+
parser.add_argument("-c", "--ckptstep", default=1200000, type=int)
|
| 49 |
+
parser.add_argument("-m", "--mel_spec_type", default="vocos", type=str, choices=["bigvgan", "vocos"])
|
| 50 |
+
parser.add_argument("-to", "--tokenizer", default="pinyin", type=str, choices=["pinyin", "char"])
|
| 51 |
+
|
| 52 |
+
parser.add_argument("-nfe", "--nfestep", default=32, type=int)
|
| 53 |
+
parser.add_argument("-o", "--odemethod", default="euler")
|
| 54 |
+
parser.add_argument("-ss", "--swaysampling", default=-1, type=float)
|
| 55 |
+
|
| 56 |
+
parser.add_argument("-t", "--testset", required=True)
|
| 57 |
+
|
| 58 |
+
args = parser.parse_args()
|
| 59 |
+
|
| 60 |
+
seed = args.seed
|
| 61 |
+
dataset_name = args.dataset
|
| 62 |
+
exp_name = args.expname
|
| 63 |
+
ckpt_step = args.ckptstep
|
| 64 |
+
ckpt_path = rel_path + f"/ckpts/{exp_name}/model_{ckpt_step}.pt"
|
| 65 |
+
mel_spec_type = args.mel_spec_type
|
| 66 |
+
tokenizer = args.tokenizer
|
| 67 |
+
|
| 68 |
+
nfe_step = args.nfestep
|
| 69 |
+
ode_method = args.odemethod
|
| 70 |
+
sway_sampling_coef = args.swaysampling
|
| 71 |
+
|
| 72 |
+
testset = args.testset
|
| 73 |
+
|
| 74 |
+
infer_batch_size = 1 # max frames. 1 for ddp single inference (recommended)
|
| 75 |
+
cfg_strength = 2.0
|
| 76 |
+
speed = 1.0
|
| 77 |
+
use_truth_duration = False
|
| 78 |
+
no_ref_audio = False
|
| 79 |
+
|
| 80 |
+
if exp_name == "F5TTS_Base":
|
| 81 |
+
model_cls = DiT
|
| 82 |
+
model_cfg = dict(dim=1024, depth=22, heads=16, ff_mult=2, text_dim=512, conv_layers=4)
|
| 83 |
+
|
| 84 |
+
elif exp_name == "E2TTS_Base":
|
| 85 |
+
model_cls = UNetT
|
| 86 |
+
model_cfg = dict(dim=1024, depth=24, heads=16, ff_mult=4)
|
| 87 |
+
|
| 88 |
+
if testset == "ls_pc_test_clean":
|
| 89 |
+
metalst = rel_path + "/data/librispeech_pc_test_clean_cross_sentence.lst"
|
| 90 |
+
librispeech_test_clean_path = "<SOME_PATH>/LibriSpeech/test-clean" # test-clean path
|
| 91 |
+
metainfo = get_librispeech_test_clean_metainfo(metalst, librispeech_test_clean_path)
|
| 92 |
+
|
| 93 |
+
elif testset == "seedtts_test_zh":
|
| 94 |
+
metalst = rel_path + "/data/seedtts_testset/zh/meta.lst"
|
| 95 |
+
metainfo = get_seedtts_testset_metainfo(metalst)
|
| 96 |
+
|
| 97 |
+
elif testset == "seedtts_test_en":
|
| 98 |
+
metalst = rel_path + "/data/seedtts_testset/en/meta.lst"
|
| 99 |
+
metainfo = get_seedtts_testset_metainfo(metalst)
|
| 100 |
+
|
| 101 |
+
# path to save genereted wavs
|
| 102 |
+
output_dir = (
|
| 103 |
+
f"{rel_path}/"
|
| 104 |
+
f"results/{exp_name}_{ckpt_step}/{testset}/"
|
| 105 |
+
f"seed{seed}_{ode_method}_nfe{nfe_step}_{mel_spec_type}"
|
| 106 |
+
f"{f'_ss{sway_sampling_coef}' if sway_sampling_coef else ''}"
|
| 107 |
+
f"_cfg{cfg_strength}_speed{speed}"
|
| 108 |
+
f"{'_gt-dur' if use_truth_duration else ''}"
|
| 109 |
+
f"{'_no-ref-audio' if no_ref_audio else ''}"
|
| 110 |
+
)
|
| 111 |
+
|
| 112 |
+
# -------------------------------------------------#
|
| 113 |
+
|
| 114 |
+
use_ema = True
|
| 115 |
+
|
| 116 |
+
prompts_all = get_inference_prompt(
|
| 117 |
+
metainfo,
|
| 118 |
+
speed=speed,
|
| 119 |
+
tokenizer=tokenizer,
|
| 120 |
+
target_sample_rate=target_sample_rate,
|
| 121 |
+
n_mel_channels=n_mel_channels,
|
| 122 |
+
hop_length=hop_length,
|
| 123 |
+
mel_spec_type=mel_spec_type,
|
| 124 |
+
target_rms=target_rms,
|
| 125 |
+
use_truth_duration=use_truth_duration,
|
| 126 |
+
infer_batch_size=infer_batch_size,
|
| 127 |
+
)
|
| 128 |
+
|
| 129 |
+
# Vocoder model
|
| 130 |
+
local = False
|
| 131 |
+
if mel_spec_type == "vocos":
|
| 132 |
+
vocoder_local_path = "../checkpoints/charactr/vocos-mel-24khz"
|
| 133 |
+
elif mel_spec_type == "bigvgan":
|
| 134 |
+
vocoder_local_path = "../checkpoints/bigvgan_v2_24khz_100band_256x"
|
| 135 |
+
vocoder = load_vocoder(vocoder_name=mel_spec_type, is_local=local, local_path=vocoder_local_path)
|
| 136 |
+
|
| 137 |
+
# Tokenizer
|
| 138 |
+
vocab_char_map, vocab_size = get_tokenizer(dataset_name, tokenizer)
|
| 139 |
+
|
| 140 |
+
# Model
|
| 141 |
+
model = CFM(
|
| 142 |
+
transformer=model_cls(**model_cfg, text_num_embeds=vocab_size, mel_dim=n_mel_channels),
|
| 143 |
+
mel_spec_kwargs=dict(
|
| 144 |
+
n_fft=n_fft,
|
| 145 |
+
hop_length=hop_length,
|
| 146 |
+
win_length=win_length,
|
| 147 |
+
n_mel_channels=n_mel_channels,
|
| 148 |
+
target_sample_rate=target_sample_rate,
|
| 149 |
+
mel_spec_type=mel_spec_type,
|
| 150 |
+
),
|
| 151 |
+
odeint_kwargs=dict(
|
| 152 |
+
method=ode_method,
|
| 153 |
+
),
|
| 154 |
+
vocab_char_map=vocab_char_map,
|
| 155 |
+
).to(device)
|
| 156 |
+
|
| 157 |
+
dtype = torch.float32 if mel_spec_type == "bigvgan" else None
|
| 158 |
+
model = load_checkpoint(model, ckpt_path, device, dtype=dtype, use_ema=use_ema)
|
| 159 |
+
|
| 160 |
+
if not os.path.exists(output_dir) and accelerator.is_main_process:
|
| 161 |
+
os.makedirs(output_dir)
|
| 162 |
+
|
| 163 |
+
# start batch inference
|
| 164 |
+
accelerator.wait_for_everyone()
|
| 165 |
+
start = time.time()
|
| 166 |
+
|
| 167 |
+
with accelerator.split_between_processes(prompts_all) as prompts:
|
| 168 |
+
for prompt in tqdm(prompts, disable=not accelerator.is_local_main_process):
|
| 169 |
+
utts, ref_rms_list, ref_mels, ref_mel_lens, total_mel_lens, final_text_list = prompt
|
| 170 |
+
ref_mels = ref_mels.to(device)
|
| 171 |
+
ref_mel_lens = torch.tensor(ref_mel_lens, dtype=torch.long).to(device)
|
| 172 |
+
total_mel_lens = torch.tensor(total_mel_lens, dtype=torch.long).to(device)
|
| 173 |
+
|
| 174 |
+
# Inference
|
| 175 |
+
with torch.inference_mode():
|
| 176 |
+
generated, _ = model.sample(
|
| 177 |
+
cond=ref_mels,
|
| 178 |
+
text=final_text_list,
|
| 179 |
+
duration=total_mel_lens,
|
| 180 |
+
lens=ref_mel_lens,
|
| 181 |
+
steps=nfe_step,
|
| 182 |
+
cfg_strength=cfg_strength,
|
| 183 |
+
sway_sampling_coef=sway_sampling_coef,
|
| 184 |
+
no_ref_audio=no_ref_audio,
|
| 185 |
+
seed=seed,
|
| 186 |
+
)
|
| 187 |
+
# Final result
|
| 188 |
+
for i, gen in enumerate(generated):
|
| 189 |
+
gen = gen[ref_mel_lens[i] : total_mel_lens[i], :].unsqueeze(0)
|
| 190 |
+
gen_mel_spec = gen.permute(0, 2, 1).to(torch.float32)
|
| 191 |
+
if mel_spec_type == "vocos":
|
| 192 |
+
generated_wave = vocoder.decode(gen_mel_spec).cpu()
|
| 193 |
+
elif mel_spec_type == "bigvgan":
|
| 194 |
+
generated_wave = vocoder(gen_mel_spec).squeeze(0).cpu()
|
| 195 |
+
|
| 196 |
+
if ref_rms_list[i] < target_rms:
|
| 197 |
+
generated_wave = generated_wave * ref_rms_list[i] / target_rms
|
| 198 |
+
torchaudio.save(f"{output_dir}/{utts[i]}.wav", generated_wave, target_sample_rate)
|
| 199 |
+
|
| 200 |
+
accelerator.wait_for_everyone()
|
| 201 |
+
if accelerator.is_main_process:
|
| 202 |
+
timediff = time.time() - start
|
| 203 |
+
print(f"Done batch inference in {timediff / 60 :.2f} minutes.")
|
| 204 |
+
|
| 205 |
+
|
| 206 |
+
if __name__ == "__main__":
|
| 207 |
+
main()
|
deployment/src/f5_tts/eval/eval_infer_batch.sh
ADDED
|
@@ -0,0 +1,13 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
#!/bin/bash
|
| 2 |
+
|
| 3 |
+
# e.g. F5-TTS, 16 NFE
|
| 4 |
+
accelerate launch src/f5_tts/eval/eval_infer_batch.py -s 0 -n "F5TTS_Base" -t "seedtts_test_zh" -nfe 16
|
| 5 |
+
accelerate launch src/f5_tts/eval/eval_infer_batch.py -s 0 -n "F5TTS_Base" -t "seedtts_test_en" -nfe 16
|
| 6 |
+
accelerate launch src/f5_tts/eval/eval_infer_batch.py -s 0 -n "F5TTS_Base" -t "ls_pc_test_clean" -nfe 16
|
| 7 |
+
|
| 8 |
+
# e.g. Vanilla E2 TTS, 32 NFE
|
| 9 |
+
accelerate launch src/f5_tts/eval/eval_infer_batch.py -s 0 -n "E2TTS_Base" -t "seedtts_test_zh" -o "midpoint" -ss 0
|
| 10 |
+
accelerate launch src/f5_tts/eval/eval_infer_batch.py -s 0 -n "E2TTS_Base" -t "seedtts_test_en" -o "midpoint" -ss 0
|
| 11 |
+
accelerate launch src/f5_tts/eval/eval_infer_batch.py -s 0 -n "E2TTS_Base" -t "ls_pc_test_clean" -o "midpoint" -ss 0
|
| 12 |
+
|
| 13 |
+
# etc.
|
deployment/src/f5_tts/eval/eval_librispeech_test_clean.py
ADDED
|
@@ -0,0 +1,96 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
# Evaluate with Librispeech test-clean, ~3s prompt to generate 4-10s audio (the way of valle/voicebox evaluation)
|
| 2 |
+
|
| 3 |
+
import argparse
|
| 4 |
+
import json
|
| 5 |
+
import os
|
| 6 |
+
import sys
|
| 7 |
+
|
| 8 |
+
sys.path.append(os.getcwd())
|
| 9 |
+
|
| 10 |
+
import multiprocessing as mp
|
| 11 |
+
from importlib.resources import files
|
| 12 |
+
|
| 13 |
+
import numpy as np
|
| 14 |
+
from f5_tts.eval.utils_eval import (
|
| 15 |
+
get_librispeech_test,
|
| 16 |
+
run_asr_wer,
|
| 17 |
+
run_sim,
|
| 18 |
+
)
|
| 19 |
+
|
| 20 |
+
rel_path = str(files("f5_tts").joinpath("../../"))
|
| 21 |
+
|
| 22 |
+
|
| 23 |
+
def get_args():
|
| 24 |
+
parser = argparse.ArgumentParser()
|
| 25 |
+
parser.add_argument("-e", "--eval_task", type=str, default="wer", choices=["sim", "wer"])
|
| 26 |
+
parser.add_argument("-l", "--lang", type=str, default="en")
|
| 27 |
+
parser.add_argument("-g", "--gen_wav_dir", type=str, required=True)
|
| 28 |
+
parser.add_argument("-p", "--librispeech_test_clean_path", type=str, required=True)
|
| 29 |
+
parser.add_argument("-n", "--gpu_nums", type=int, default=8, help="Number of GPUs to use")
|
| 30 |
+
parser.add_argument("--local", action="store_true", help="Use local custom checkpoint directory")
|
| 31 |
+
return parser.parse_args()
|
| 32 |
+
|
| 33 |
+
|
| 34 |
+
def main():
|
| 35 |
+
args = get_args()
|
| 36 |
+
eval_task = args.eval_task
|
| 37 |
+
lang = args.lang
|
| 38 |
+
librispeech_test_clean_path = args.librispeech_test_clean_path # test-clean path
|
| 39 |
+
gen_wav_dir = args.gen_wav_dir
|
| 40 |
+
metalst = rel_path + "/data/librispeech_pc_test_clean_cross_sentence.lst"
|
| 41 |
+
|
| 42 |
+
gpus = list(range(args.gpu_nums))
|
| 43 |
+
test_set = get_librispeech_test(metalst, gen_wav_dir, gpus, librispeech_test_clean_path)
|
| 44 |
+
|
| 45 |
+
## In LibriSpeech, some speakers utilized varying voice characteristics for different characters in the book,
|
| 46 |
+
## leading to a low similarity for the ground truth in some cases.
|
| 47 |
+
# test_set = get_librispeech_test(metalst, gen_wav_dir, gpus, librispeech_test_clean_path, eval_ground_truth = True) # eval ground truth
|
| 48 |
+
|
| 49 |
+
local = args.local
|
| 50 |
+
if local: # use local custom checkpoint dir
|
| 51 |
+
asr_ckpt_dir = "../checkpoints/Systran/faster-whisper-large-v3"
|
| 52 |
+
else:
|
| 53 |
+
asr_ckpt_dir = "" # auto download to cache dir
|
| 54 |
+
wavlm_ckpt_dir = "../checkpoints/UniSpeech/wavlm_large_finetune.pth"
|
| 55 |
+
|
| 56 |
+
# --------------------------- WER ---------------------------
|
| 57 |
+
|
| 58 |
+
if eval_task == "wer":
|
| 59 |
+
wer_results = []
|
| 60 |
+
wers = []
|
| 61 |
+
|
| 62 |
+
with mp.Pool(processes=len(gpus)) as pool:
|
| 63 |
+
args = [(rank, lang, sub_test_set, asr_ckpt_dir) for (rank, sub_test_set) in test_set]
|
| 64 |
+
results = pool.map(run_asr_wer, args)
|
| 65 |
+
for r in results:
|
| 66 |
+
wer_results.extend(r)
|
| 67 |
+
|
| 68 |
+
wer_result_path = f"{gen_wav_dir}/{lang}_wer_results.jsonl"
|
| 69 |
+
with open(wer_result_path, "w") as f:
|
| 70 |
+
for line in wer_results:
|
| 71 |
+
wers.append(line["wer"])
|
| 72 |
+
json_line = json.dumps(line, ensure_ascii=False)
|
| 73 |
+
f.write(json_line + "\n")
|
| 74 |
+
|
| 75 |
+
wer = round(np.mean(wers) * 100, 3)
|
| 76 |
+
print(f"\nTotal {len(wers)} samples")
|
| 77 |
+
print(f"WER : {wer}%")
|
| 78 |
+
print(f"Results have been saved to {wer_result_path}")
|
| 79 |
+
|
| 80 |
+
# --------------------------- SIM ---------------------------
|
| 81 |
+
|
| 82 |
+
if eval_task == "sim":
|
| 83 |
+
sims = []
|
| 84 |
+
with mp.Pool(processes=len(gpus)) as pool:
|
| 85 |
+
args = [(rank, sub_test_set, wavlm_ckpt_dir) for (rank, sub_test_set) in test_set]
|
| 86 |
+
results = pool.map(run_sim, args)
|
| 87 |
+
for r in results:
|
| 88 |
+
sims.extend(r)
|
| 89 |
+
|
| 90 |
+
sim = round(sum(sims) / len(sims), 3)
|
| 91 |
+
print(f"\nTotal {len(sims)} samples")
|
| 92 |
+
print(f"SIM : {sim}")
|
| 93 |
+
|
| 94 |
+
|
| 95 |
+
if __name__ == "__main__":
|
| 96 |
+
main()
|
deployment/src/f5_tts/eval/eval_seedtts_testset.py
ADDED
|
@@ -0,0 +1,95 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
# Evaluate with Seed-TTS testset
|
| 2 |
+
|
| 3 |
+
import argparse
|
| 4 |
+
import json
|
| 5 |
+
import os
|
| 6 |
+
import sys
|
| 7 |
+
|
| 8 |
+
sys.path.append(os.getcwd())
|
| 9 |
+
|
| 10 |
+
import multiprocessing as mp
|
| 11 |
+
from importlib.resources import files
|
| 12 |
+
|
| 13 |
+
import numpy as np
|
| 14 |
+
from f5_tts.eval.utils_eval import (
|
| 15 |
+
get_seed_tts_test,
|
| 16 |
+
run_asr_wer,
|
| 17 |
+
run_sim,
|
| 18 |
+
)
|
| 19 |
+
|
| 20 |
+
rel_path = str(files("f5_tts").joinpath("../../"))
|
| 21 |
+
|
| 22 |
+
|
| 23 |
+
def get_args():
|
| 24 |
+
parser = argparse.ArgumentParser()
|
| 25 |
+
parser.add_argument("-e", "--eval_task", type=str, default="wer", choices=["sim", "wer"])
|
| 26 |
+
parser.add_argument("-l", "--lang", type=str, default="en", choices=["zh", "en"])
|
| 27 |
+
parser.add_argument("-g", "--gen_wav_dir", type=str, required=True)
|
| 28 |
+
parser.add_argument("-n", "--gpu_nums", type=int, default=8, help="Number of GPUs to use")
|
| 29 |
+
parser.add_argument("--local", action="store_true", help="Use local custom checkpoint directory")
|
| 30 |
+
return parser.parse_args()
|
| 31 |
+
|
| 32 |
+
|
| 33 |
+
def main():
|
| 34 |
+
args = get_args()
|
| 35 |
+
eval_task = args.eval_task
|
| 36 |
+
lang = args.lang
|
| 37 |
+
gen_wav_dir = args.gen_wav_dir
|
| 38 |
+
metalst = rel_path + f"/data/seedtts_testset/{lang}/meta.lst" # seed-tts testset
|
| 39 |
+
|
| 40 |
+
# NOTE. paraformer-zh result will be slightly different according to the number of gpus, cuz batchsize is different
|
| 41 |
+
# zh 1.254 seems a result of 4 workers wer_seed_tts
|
| 42 |
+
gpus = list(range(args.gpu_nums))
|
| 43 |
+
test_set = get_seed_tts_test(metalst, gen_wav_dir, gpus)
|
| 44 |
+
|
| 45 |
+
local = args.local
|
| 46 |
+
if local: # use local custom checkpoint dir
|
| 47 |
+
if lang == "zh":
|
| 48 |
+
asr_ckpt_dir = "../checkpoints/funasr" # paraformer-zh dir under funasr
|
| 49 |
+
elif lang == "en":
|
| 50 |
+
asr_ckpt_dir = "../checkpoints/Systran/faster-whisper-large-v3"
|
| 51 |
+
else:
|
| 52 |
+
asr_ckpt_dir = "" # auto download to cache dir
|
| 53 |
+
wavlm_ckpt_dir = "../checkpoints/UniSpeech/wavlm_large_finetune.pth"
|
| 54 |
+
|
| 55 |
+
# --------------------------- WER ---------------------------
|
| 56 |
+
|
| 57 |
+
if eval_task == "wer":
|
| 58 |
+
wer_results = []
|
| 59 |
+
wers = []
|
| 60 |
+
|
| 61 |
+
with mp.Pool(processes=len(gpus)) as pool:
|
| 62 |
+
args = [(rank, lang, sub_test_set, asr_ckpt_dir) for (rank, sub_test_set) in test_set]
|
| 63 |
+
results = pool.map(run_asr_wer, args)
|
| 64 |
+
for r in results:
|
| 65 |
+
wer_results.extend(r)
|
| 66 |
+
|
| 67 |
+
wer_result_path = f"{gen_wav_dir}/{lang}_wer_results.jsonl"
|
| 68 |
+
with open(wer_result_path, "w") as f:
|
| 69 |
+
for line in wer_results:
|
| 70 |
+
wers.append(line["wer"])
|
| 71 |
+
json_line = json.dumps(line, ensure_ascii=False)
|
| 72 |
+
f.write(json_line + "\n")
|
| 73 |
+
|
| 74 |
+
wer = round(np.mean(wers) * 100, 3)
|
| 75 |
+
print(f"\nTotal {len(wers)} samples")
|
| 76 |
+
print(f"WER : {wer}%")
|
| 77 |
+
print(f"Results have been saved to {wer_result_path}")
|
| 78 |
+
|
| 79 |
+
# --------------------------- SIM ---------------------------
|
| 80 |
+
|
| 81 |
+
if eval_task == "sim":
|
| 82 |
+
sims = []
|
| 83 |
+
with mp.Pool(processes=len(gpus)) as pool:
|
| 84 |
+
args = [(rank, sub_test_set, wavlm_ckpt_dir) for (rank, sub_test_set) in test_set]
|
| 85 |
+
results = pool.map(run_sim, args)
|
| 86 |
+
for r in results:
|
| 87 |
+
sims.extend(r)
|
| 88 |
+
|
| 89 |
+
sim = round(sum(sims) / len(sims), 3)
|
| 90 |
+
print(f"\nTotal {len(sims)} samples")
|
| 91 |
+
print(f"SIM : {sim}")
|
| 92 |
+
|
| 93 |
+
|
| 94 |
+
if __name__ == "__main__":
|
| 95 |
+
main()
|
deployment/src/f5_tts/eval/eval_utmos.py
ADDED
|
@@ -0,0 +1,44 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
import argparse
|
| 2 |
+
import json
|
| 3 |
+
from pathlib import Path
|
| 4 |
+
|
| 5 |
+
import librosa
|
| 6 |
+
import torch
|
| 7 |
+
from tqdm import tqdm
|
| 8 |
+
|
| 9 |
+
|
| 10 |
+
def main():
|
| 11 |
+
parser = argparse.ArgumentParser(description="UTMOS Evaluation")
|
| 12 |
+
parser.add_argument("--audio_dir", type=str, required=True, help="Audio file path.")
|
| 13 |
+
parser.add_argument("--ext", type=str, default="wav", help="Audio extension.")
|
| 14 |
+
args = parser.parse_args()
|
| 15 |
+
|
| 16 |
+
device = "cuda" if torch.cuda.is_available() else "xpu" if torch.xpu.is_available() else "cpu"
|
| 17 |
+
|
| 18 |
+
predictor = torch.hub.load("tarepan/SpeechMOS:v1.2.0", "utmos22_strong", trust_repo=True)
|
| 19 |
+
predictor = predictor.to(device)
|
| 20 |
+
|
| 21 |
+
audio_paths = list(Path(args.audio_dir).rglob(f"*.{args.ext}"))
|
| 22 |
+
utmos_results = {}
|
| 23 |
+
utmos_score = 0
|
| 24 |
+
|
| 25 |
+
for audio_path in tqdm(audio_paths, desc="Processing"):
|
| 26 |
+
wav_name = audio_path.stem
|
| 27 |
+
wav, sr = librosa.load(audio_path, sr=None, mono=True)
|
| 28 |
+
wav_tensor = torch.from_numpy(wav).to(device).unsqueeze(0)
|
| 29 |
+
score = predictor(wav_tensor, sr)
|
| 30 |
+
utmos_results[str(wav_name)] = score.item()
|
| 31 |
+
utmos_score += score.item()
|
| 32 |
+
|
| 33 |
+
avg_score = utmos_score / len(audio_paths) if len(audio_paths) > 0 else 0
|
| 34 |
+
print(f"UTMOS: {avg_score}")
|
| 35 |
+
|
| 36 |
+
utmos_result_path = Path(args.audio_dir) / "utmos_results.json"
|
| 37 |
+
with open(utmos_result_path, "w", encoding="utf-8") as f:
|
| 38 |
+
json.dump(utmos_results, f, ensure_ascii=False, indent=4)
|
| 39 |
+
|
| 40 |
+
print(f"Results have been saved to {utmos_result_path}")
|
| 41 |
+
|
| 42 |
+
|
| 43 |
+
if __name__ == "__main__":
|
| 44 |
+
main()
|
deployment/src/f5_tts/eval/utils_eval.py
ADDED
|
@@ -0,0 +1,413 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
import math
|
| 2 |
+
import os
|
| 3 |
+
import random
|
| 4 |
+
import string
|
| 5 |
+
from pathlib import Path
|
| 6 |
+
|
| 7 |
+
import torch
|
| 8 |
+
import torch.nn.functional as F
|
| 9 |
+
import torchaudio
|
| 10 |
+
from tqdm import tqdm
|
| 11 |
+
|
| 12 |
+
from f5_tts.eval.ecapa_tdnn import ECAPA_TDNN_SMALL
|
| 13 |
+
from f5_tts.model.modules import MelSpec
|
| 14 |
+
from f5_tts.model.utils import convert_char_to_pinyin
|
| 15 |
+
|
| 16 |
+
|
| 17 |
+
# seedtts testset metainfo: utt, prompt_text, prompt_wav, gt_text, gt_wav
|
| 18 |
+
def get_seedtts_testset_metainfo(metalst):
|
| 19 |
+
f = open(metalst)
|
| 20 |
+
lines = f.readlines()
|
| 21 |
+
f.close()
|
| 22 |
+
metainfo = []
|
| 23 |
+
for line in lines:
|
| 24 |
+
if len(line.strip().split("|")) == 5:
|
| 25 |
+
utt, prompt_text, prompt_wav, gt_text, gt_wav = line.strip().split("|")
|
| 26 |
+
elif len(line.strip().split("|")) == 4:
|
| 27 |
+
utt, prompt_text, prompt_wav, gt_text = line.strip().split("|")
|
| 28 |
+
gt_wav = os.path.join(os.path.dirname(metalst), "wavs", utt + ".wav")
|
| 29 |
+
if not os.path.isabs(prompt_wav):
|
| 30 |
+
prompt_wav = os.path.join(os.path.dirname(metalst), prompt_wav)
|
| 31 |
+
metainfo.append((utt, prompt_text, prompt_wav, gt_text, gt_wav))
|
| 32 |
+
return metainfo
|
| 33 |
+
|
| 34 |
+
|
| 35 |
+
# librispeech test-clean metainfo: gen_utt, ref_txt, ref_wav, gen_txt, gen_wav
|
| 36 |
+
def get_librispeech_test_clean_metainfo(metalst, librispeech_test_clean_path):
|
| 37 |
+
f = open(metalst)
|
| 38 |
+
lines = f.readlines()
|
| 39 |
+
f.close()
|
| 40 |
+
metainfo = []
|
| 41 |
+
for line in lines:
|
| 42 |
+
ref_utt, ref_dur, ref_txt, gen_utt, gen_dur, gen_txt = line.strip().split("\t")
|
| 43 |
+
|
| 44 |
+
# ref_txt = ref_txt[0] + ref_txt[1:].lower() + '.' # if use librispeech test-clean (no-pc)
|
| 45 |
+
ref_spk_id, ref_chaptr_id, _ = ref_utt.split("-")
|
| 46 |
+
ref_wav = os.path.join(librispeech_test_clean_path, ref_spk_id, ref_chaptr_id, ref_utt + ".flac")
|
| 47 |
+
|
| 48 |
+
# gen_txt = gen_txt[0] + gen_txt[1:].lower() + '.' # if use librispeech test-clean (no-pc)
|
| 49 |
+
gen_spk_id, gen_chaptr_id, _ = gen_utt.split("-")
|
| 50 |
+
gen_wav = os.path.join(librispeech_test_clean_path, gen_spk_id, gen_chaptr_id, gen_utt + ".flac")
|
| 51 |
+
|
| 52 |
+
metainfo.append((gen_utt, ref_txt, ref_wav, " " + gen_txt, gen_wav))
|
| 53 |
+
|
| 54 |
+
return metainfo
|
| 55 |
+
|
| 56 |
+
|
| 57 |
+
# padded to max length mel batch
|
| 58 |
+
def padded_mel_batch(ref_mels):
|
| 59 |
+
max_mel_length = torch.LongTensor([mel.shape[-1] for mel in ref_mels]).amax()
|
| 60 |
+
padded_ref_mels = []
|
| 61 |
+
for mel in ref_mels:
|
| 62 |
+
padded_ref_mel = F.pad(mel, (0, max_mel_length - mel.shape[-1]), value=0)
|
| 63 |
+
padded_ref_mels.append(padded_ref_mel)
|
| 64 |
+
padded_ref_mels = torch.stack(padded_ref_mels)
|
| 65 |
+
padded_ref_mels = padded_ref_mels.permute(0, 2, 1)
|
| 66 |
+
return padded_ref_mels
|
| 67 |
+
|
| 68 |
+
|
| 69 |
+
# get prompts from metainfo containing: utt, prompt_text, prompt_wav, gt_text, gt_wav
|
| 70 |
+
|
| 71 |
+
|
| 72 |
+
def get_inference_prompt(
|
| 73 |
+
metainfo,
|
| 74 |
+
speed=1.0,
|
| 75 |
+
tokenizer="pinyin",
|
| 76 |
+
polyphone=True,
|
| 77 |
+
target_sample_rate=24000,
|
| 78 |
+
n_fft=1024,
|
| 79 |
+
win_length=1024,
|
| 80 |
+
n_mel_channels=100,
|
| 81 |
+
hop_length=256,
|
| 82 |
+
mel_spec_type="vocos",
|
| 83 |
+
target_rms=0.1,
|
| 84 |
+
use_truth_duration=False,
|
| 85 |
+
infer_batch_size=1,
|
| 86 |
+
num_buckets=200,
|
| 87 |
+
min_secs=3,
|
| 88 |
+
max_secs=40,
|
| 89 |
+
):
|
| 90 |
+
prompts_all = []
|
| 91 |
+
|
| 92 |
+
min_tokens = min_secs * target_sample_rate // hop_length
|
| 93 |
+
max_tokens = max_secs * target_sample_rate // hop_length
|
| 94 |
+
|
| 95 |
+
batch_accum = [0] * num_buckets
|
| 96 |
+
utts, ref_rms_list, ref_mels, ref_mel_lens, total_mel_lens, final_text_list = (
|
| 97 |
+
[[] for _ in range(num_buckets)] for _ in range(6)
|
| 98 |
+
)
|
| 99 |
+
|
| 100 |
+
mel_spectrogram = MelSpec(
|
| 101 |
+
n_fft=n_fft,
|
| 102 |
+
hop_length=hop_length,
|
| 103 |
+
win_length=win_length,
|
| 104 |
+
n_mel_channels=n_mel_channels,
|
| 105 |
+
target_sample_rate=target_sample_rate,
|
| 106 |
+
mel_spec_type=mel_spec_type,
|
| 107 |
+
)
|
| 108 |
+
|
| 109 |
+
for utt, prompt_text, prompt_wav, gt_text, gt_wav in tqdm(metainfo, desc="Processing prompts..."):
|
| 110 |
+
# Audio
|
| 111 |
+
ref_audio, ref_sr = torchaudio.load(prompt_wav)
|
| 112 |
+
ref_rms = torch.sqrt(torch.mean(torch.square(ref_audio)))
|
| 113 |
+
if ref_rms < target_rms:
|
| 114 |
+
ref_audio = ref_audio * target_rms / ref_rms
|
| 115 |
+
assert ref_audio.shape[-1] > 5000, f"Empty prompt wav: {prompt_wav}, or torchaudio backend issue."
|
| 116 |
+
if ref_sr != target_sample_rate:
|
| 117 |
+
resampler = torchaudio.transforms.Resample(ref_sr, target_sample_rate)
|
| 118 |
+
ref_audio = resampler(ref_audio)
|
| 119 |
+
|
| 120 |
+
# Text
|
| 121 |
+
if len(prompt_text[-1].encode("utf-8")) == 1:
|
| 122 |
+
prompt_text = prompt_text + " "
|
| 123 |
+
text = [prompt_text + gt_text]
|
| 124 |
+
if tokenizer == "pinyin":
|
| 125 |
+
text_list = convert_char_to_pinyin(text, polyphone=polyphone)
|
| 126 |
+
else:
|
| 127 |
+
text_list = text
|
| 128 |
+
|
| 129 |
+
# Duration, mel frame length
|
| 130 |
+
ref_mel_len = ref_audio.shape[-1] // hop_length
|
| 131 |
+
if use_truth_duration:
|
| 132 |
+
gt_audio, gt_sr = torchaudio.load(gt_wav)
|
| 133 |
+
if gt_sr != target_sample_rate:
|
| 134 |
+
resampler = torchaudio.transforms.Resample(gt_sr, target_sample_rate)
|
| 135 |
+
gt_audio = resampler(gt_audio)
|
| 136 |
+
total_mel_len = ref_mel_len + int(gt_audio.shape[-1] / hop_length / speed)
|
| 137 |
+
|
| 138 |
+
# # test vocoder resynthesis
|
| 139 |
+
# ref_audio = gt_audio
|
| 140 |
+
else:
|
| 141 |
+
ref_text_len = len(prompt_text.encode("utf-8"))
|
| 142 |
+
gen_text_len = len(gt_text.encode("utf-8"))
|
| 143 |
+
total_mel_len = ref_mel_len + int(ref_mel_len / ref_text_len * gen_text_len / speed)
|
| 144 |
+
|
| 145 |
+
# to mel spectrogram
|
| 146 |
+
ref_mel = mel_spectrogram(ref_audio)
|
| 147 |
+
ref_mel = ref_mel.squeeze(0)
|
| 148 |
+
|
| 149 |
+
# deal with batch
|
| 150 |
+
assert infer_batch_size > 0, "infer_batch_size should be greater than 0."
|
| 151 |
+
assert (
|
| 152 |
+
min_tokens <= total_mel_len <= max_tokens
|
| 153 |
+
), f"Audio {utt} has duration {total_mel_len*hop_length//target_sample_rate}s out of range [{min_secs}, {max_secs}]."
|
| 154 |
+
bucket_i = math.floor((total_mel_len - min_tokens) / (max_tokens - min_tokens + 1) * num_buckets)
|
| 155 |
+
|
| 156 |
+
utts[bucket_i].append(utt)
|
| 157 |
+
ref_rms_list[bucket_i].append(ref_rms)
|
| 158 |
+
ref_mels[bucket_i].append(ref_mel)
|
| 159 |
+
ref_mel_lens[bucket_i].append(ref_mel_len)
|
| 160 |
+
total_mel_lens[bucket_i].append(total_mel_len)
|
| 161 |
+
final_text_list[bucket_i].extend(text_list)
|
| 162 |
+
|
| 163 |
+
batch_accum[bucket_i] += total_mel_len
|
| 164 |
+
|
| 165 |
+
if batch_accum[bucket_i] >= infer_batch_size:
|
| 166 |
+
# print(f"\n{len(ref_mels[bucket_i][0][0])}\n{ref_mel_lens[bucket_i]}\n{total_mel_lens[bucket_i]}")
|
| 167 |
+
prompts_all.append(
|
| 168 |
+
(
|
| 169 |
+
utts[bucket_i],
|
| 170 |
+
ref_rms_list[bucket_i],
|
| 171 |
+
padded_mel_batch(ref_mels[bucket_i]),
|
| 172 |
+
ref_mel_lens[bucket_i],
|
| 173 |
+
total_mel_lens[bucket_i],
|
| 174 |
+
final_text_list[bucket_i],
|
| 175 |
+
)
|
| 176 |
+
)
|
| 177 |
+
batch_accum[bucket_i] = 0
|
| 178 |
+
(
|
| 179 |
+
utts[bucket_i],
|
| 180 |
+
ref_rms_list[bucket_i],
|
| 181 |
+
ref_mels[bucket_i],
|
| 182 |
+
ref_mel_lens[bucket_i],
|
| 183 |
+
total_mel_lens[bucket_i],
|
| 184 |
+
final_text_list[bucket_i],
|
| 185 |
+
) = [], [], [], [], [], []
|
| 186 |
+
|
| 187 |
+
# add residual
|
| 188 |
+
for bucket_i, bucket_frames in enumerate(batch_accum):
|
| 189 |
+
if bucket_frames > 0:
|
| 190 |
+
prompts_all.append(
|
| 191 |
+
(
|
| 192 |
+
utts[bucket_i],
|
| 193 |
+
ref_rms_list[bucket_i],
|
| 194 |
+
padded_mel_batch(ref_mels[bucket_i]),
|
| 195 |
+
ref_mel_lens[bucket_i],
|
| 196 |
+
total_mel_lens[bucket_i],
|
| 197 |
+
final_text_list[bucket_i],
|
| 198 |
+
)
|
| 199 |
+
)
|
| 200 |
+
# not only leave easy work for last workers
|
| 201 |
+
random.seed(666)
|
| 202 |
+
random.shuffle(prompts_all)
|
| 203 |
+
|
| 204 |
+
return prompts_all
|
| 205 |
+
|
| 206 |
+
|
| 207 |
+
# get wav_res_ref_text of seed-tts test metalst
|
| 208 |
+
# https://github.com/BytedanceSpeech/seed-tts-eval
|
| 209 |
+
|
| 210 |
+
|
| 211 |
+
def get_seed_tts_test(metalst, gen_wav_dir, gpus):
|
| 212 |
+
f = open(metalst)
|
| 213 |
+
lines = f.readlines()
|
| 214 |
+
f.close()
|
| 215 |
+
|
| 216 |
+
test_set_ = []
|
| 217 |
+
for line in tqdm(lines):
|
| 218 |
+
if len(line.strip().split("|")) == 5:
|
| 219 |
+
utt, prompt_text, prompt_wav, gt_text, gt_wav = line.strip().split("|")
|
| 220 |
+
elif len(line.strip().split("|")) == 4:
|
| 221 |
+
utt, prompt_text, prompt_wav, gt_text = line.strip().split("|")
|
| 222 |
+
|
| 223 |
+
if not os.path.exists(os.path.join(gen_wav_dir, utt + ".wav")):
|
| 224 |
+
continue
|
| 225 |
+
gen_wav = os.path.join(gen_wav_dir, utt + ".wav")
|
| 226 |
+
if not os.path.isabs(prompt_wav):
|
| 227 |
+
prompt_wav = os.path.join(os.path.dirname(metalst), prompt_wav)
|
| 228 |
+
|
| 229 |
+
test_set_.append((gen_wav, prompt_wav, gt_text))
|
| 230 |
+
|
| 231 |
+
num_jobs = len(gpus)
|
| 232 |
+
if num_jobs == 1:
|
| 233 |
+
return [(gpus[0], test_set_)]
|
| 234 |
+
|
| 235 |
+
wav_per_job = len(test_set_) // num_jobs + 1
|
| 236 |
+
test_set = []
|
| 237 |
+
for i in range(num_jobs):
|
| 238 |
+
test_set.append((gpus[i], test_set_[i * wav_per_job : (i + 1) * wav_per_job]))
|
| 239 |
+
|
| 240 |
+
return test_set
|
| 241 |
+
|
| 242 |
+
|
| 243 |
+
# get librispeech test-clean cross sentence test
|
| 244 |
+
|
| 245 |
+
|
| 246 |
+
def get_librispeech_test(metalst, gen_wav_dir, gpus, librispeech_test_clean_path, eval_ground_truth=False):
|
| 247 |
+
f = open(metalst)
|
| 248 |
+
lines = f.readlines()
|
| 249 |
+
f.close()
|
| 250 |
+
|
| 251 |
+
test_set_ = []
|
| 252 |
+
for line in tqdm(lines):
|
| 253 |
+
ref_utt, ref_dur, ref_txt, gen_utt, gen_dur, gen_txt = line.strip().split("\t")
|
| 254 |
+
|
| 255 |
+
if eval_ground_truth:
|
| 256 |
+
gen_spk_id, gen_chaptr_id, _ = gen_utt.split("-")
|
| 257 |
+
gen_wav = os.path.join(librispeech_test_clean_path, gen_spk_id, gen_chaptr_id, gen_utt + ".flac")
|
| 258 |
+
else:
|
| 259 |
+
if not os.path.exists(os.path.join(gen_wav_dir, gen_utt + ".wav")):
|
| 260 |
+
raise FileNotFoundError(f"Generated wav not found: {gen_utt}")
|
| 261 |
+
gen_wav = os.path.join(gen_wav_dir, gen_utt + ".wav")
|
| 262 |
+
|
| 263 |
+
ref_spk_id, ref_chaptr_id, _ = ref_utt.split("-")
|
| 264 |
+
ref_wav = os.path.join(librispeech_test_clean_path, ref_spk_id, ref_chaptr_id, ref_utt + ".flac")
|
| 265 |
+
|
| 266 |
+
test_set_.append((gen_wav, ref_wav, gen_txt))
|
| 267 |
+
|
| 268 |
+
num_jobs = len(gpus)
|
| 269 |
+
if num_jobs == 1:
|
| 270 |
+
return [(gpus[0], test_set_)]
|
| 271 |
+
|
| 272 |
+
wav_per_job = len(test_set_) // num_jobs + 1
|
| 273 |
+
test_set = []
|
| 274 |
+
for i in range(num_jobs):
|
| 275 |
+
test_set.append((gpus[i], test_set_[i * wav_per_job : (i + 1) * wav_per_job]))
|
| 276 |
+
|
| 277 |
+
return test_set
|
| 278 |
+
|
| 279 |
+
|
| 280 |
+
# load asr model
|
| 281 |
+
|
| 282 |
+
|
| 283 |
+
def load_asr_model(lang, ckpt_dir=""):
|
| 284 |
+
if lang == "zh":
|
| 285 |
+
from funasr import AutoModel
|
| 286 |
+
|
| 287 |
+
model = AutoModel(
|
| 288 |
+
model=os.path.join(ckpt_dir, "paraformer-zh"),
|
| 289 |
+
# vad_model = os.path.join(ckpt_dir, "fsmn-vad"),
|
| 290 |
+
# punc_model = os.path.join(ckpt_dir, "ct-punc"),
|
| 291 |
+
# spk_model = os.path.join(ckpt_dir, "cam++"),
|
| 292 |
+
disable_update=True,
|
| 293 |
+
) # following seed-tts setting
|
| 294 |
+
elif lang == "en":
|
| 295 |
+
from faster_whisper import WhisperModel
|
| 296 |
+
|
| 297 |
+
model_size = "large-v3" if ckpt_dir == "" else ckpt_dir
|
| 298 |
+
model = WhisperModel(model_size, device="cuda", compute_type="float16")
|
| 299 |
+
return model
|
| 300 |
+
|
| 301 |
+
|
| 302 |
+
# WER Evaluation, the way Seed-TTS does
|
| 303 |
+
|
| 304 |
+
|
| 305 |
+
def run_asr_wer(args):
|
| 306 |
+
rank, lang, test_set, ckpt_dir = args
|
| 307 |
+
|
| 308 |
+
if lang == "zh":
|
| 309 |
+
import zhconv
|
| 310 |
+
|
| 311 |
+
torch.cuda.set_device(rank)
|
| 312 |
+
elif lang == "en":
|
| 313 |
+
os.environ["CUDA_VISIBLE_DEVICES"] = str(rank)
|
| 314 |
+
else:
|
| 315 |
+
raise NotImplementedError(
|
| 316 |
+
"lang support only 'zh' (funasr paraformer-zh), 'en' (faster-whisper-large-v3), for now."
|
| 317 |
+
)
|
| 318 |
+
|
| 319 |
+
asr_model = load_asr_model(lang, ckpt_dir=ckpt_dir)
|
| 320 |
+
|
| 321 |
+
from zhon.hanzi import punctuation
|
| 322 |
+
|
| 323 |
+
punctuation_all = punctuation + string.punctuation
|
| 324 |
+
wer_results = []
|
| 325 |
+
|
| 326 |
+
from jiwer import compute_measures
|
| 327 |
+
|
| 328 |
+
for gen_wav, prompt_wav, truth in tqdm(test_set):
|
| 329 |
+
if lang == "zh":
|
| 330 |
+
res = asr_model.generate(input=gen_wav, batch_size_s=300, disable_pbar=True)
|
| 331 |
+
hypo = res[0]["text"]
|
| 332 |
+
hypo = zhconv.convert(hypo, "zh-cn")
|
| 333 |
+
elif lang == "en":
|
| 334 |
+
segments, _ = asr_model.transcribe(gen_wav, beam_size=5, language="en")
|
| 335 |
+
hypo = ""
|
| 336 |
+
for segment in segments:
|
| 337 |
+
hypo = hypo + " " + segment.text
|
| 338 |
+
|
| 339 |
+
raw_truth = truth
|
| 340 |
+
raw_hypo = hypo
|
| 341 |
+
|
| 342 |
+
for x in punctuation_all:
|
| 343 |
+
truth = truth.replace(x, "")
|
| 344 |
+
hypo = hypo.replace(x, "")
|
| 345 |
+
|
| 346 |
+
truth = truth.replace(" ", " ")
|
| 347 |
+
hypo = hypo.replace(" ", " ")
|
| 348 |
+
|
| 349 |
+
if lang == "zh":
|
| 350 |
+
truth = " ".join([x for x in truth])
|
| 351 |
+
hypo = " ".join([x for x in hypo])
|
| 352 |
+
elif lang == "en":
|
| 353 |
+
truth = truth.lower()
|
| 354 |
+
hypo = hypo.lower()
|
| 355 |
+
|
| 356 |
+
measures = compute_measures(truth, hypo)
|
| 357 |
+
wer = measures["wer"]
|
| 358 |
+
|
| 359 |
+
# ref_list = truth.split(" ")
|
| 360 |
+
# subs = measures["substitutions"] / len(ref_list)
|
| 361 |
+
# dele = measures["deletions"] / len(ref_list)
|
| 362 |
+
# inse = measures["insertions"] / len(ref_list)
|
| 363 |
+
|
| 364 |
+
wer_results.append(
|
| 365 |
+
{
|
| 366 |
+
"wav": Path(gen_wav).stem,
|
| 367 |
+
"truth": raw_truth,
|
| 368 |
+
"hypo": raw_hypo,
|
| 369 |
+
"wer": wer,
|
| 370 |
+
}
|
| 371 |
+
)
|
| 372 |
+
|
| 373 |
+
return wer_results
|
| 374 |
+
|
| 375 |
+
|
| 376 |
+
# SIM Evaluation
|
| 377 |
+
|
| 378 |
+
|
| 379 |
+
def run_sim(args):
|
| 380 |
+
rank, test_set, ckpt_dir = args
|
| 381 |
+
device = f"cuda:{rank}"
|
| 382 |
+
|
| 383 |
+
model = ECAPA_TDNN_SMALL(feat_dim=1024, feat_type="wavlm_large", config_path=None)
|
| 384 |
+
state_dict = torch.load(ckpt_dir, weights_only=True, map_location=lambda storage, loc: storage)
|
| 385 |
+
model.load_state_dict(state_dict["model"], strict=False)
|
| 386 |
+
|
| 387 |
+
use_gpu = True if torch.cuda.is_available() else False
|
| 388 |
+
if use_gpu:
|
| 389 |
+
model = model.cuda(device)
|
| 390 |
+
model.eval()
|
| 391 |
+
|
| 392 |
+
sims = []
|
| 393 |
+
for wav1, wav2, truth in tqdm(test_set):
|
| 394 |
+
wav1, sr1 = torchaudio.load(wav1)
|
| 395 |
+
wav2, sr2 = torchaudio.load(wav2)
|
| 396 |
+
|
| 397 |
+
resample1 = torchaudio.transforms.Resample(orig_freq=sr1, new_freq=16000)
|
| 398 |
+
resample2 = torchaudio.transforms.Resample(orig_freq=sr2, new_freq=16000)
|
| 399 |
+
wav1 = resample1(wav1)
|
| 400 |
+
wav2 = resample2(wav2)
|
| 401 |
+
|
| 402 |
+
if use_gpu:
|
| 403 |
+
wav1 = wav1.cuda(device)
|
| 404 |
+
wav2 = wav2.cuda(device)
|
| 405 |
+
with torch.no_grad():
|
| 406 |
+
emb1 = model(wav1)
|
| 407 |
+
emb2 = model(wav2)
|
| 408 |
+
|
| 409 |
+
sim = F.cosine_similarity(emb1, emb2)[0].item()
|
| 410 |
+
# print(f"VSim score between two audios: {sim:.4f} (-1.0, 1.0).")
|
| 411 |
+
sims.append(sim)
|
| 412 |
+
|
| 413 |
+
return sims
|
deployment/src/f5_tts/f5_tts_webui.py
ADDED
|
@@ -0,0 +1,295 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
"""
|
| 2 |
+
F5-TTS Thai WebUI - Refactored Version
|
| 3 |
+
เวอร์ชันที่ปรับปรุงโครงสร้างใหม่ให้มีระเบียบและง่ายต่อการดูแลรักษา
|
| 4 |
+
"""
|
| 5 |
+
|
| 6 |
+
import argparse
|
| 7 |
+
import sys
|
| 8 |
+
import os
|
| 9 |
+
import gradio as gr
|
| 10 |
+
|
| 11 |
+
# Add the src directory to Python path for imports
|
| 12 |
+
current_dir = os.path.dirname(os.path.abspath(__file__))
|
| 13 |
+
src_dir = os.path.dirname(current_dir)
|
| 14 |
+
if src_dir not in sys.path:
|
| 15 |
+
sys.path.insert(0, src_dir)
|
| 16 |
+
|
| 17 |
+
from f5_tts.model_manager import ModelManager
|
| 18 |
+
from f5_tts.tts_processor import TTSProcessor, SpeechToTextProcessor
|
| 19 |
+
from f5_tts.multi_speech_processor import MultiSpeechProcessor
|
| 20 |
+
from f5_tts.ui_components import UIComponents
|
| 21 |
+
from f5_tts.config import MAX_SPEECH_TYPES
|
| 22 |
+
|
| 23 |
+
|
| 24 |
+
class F5TTSWebUI:
|
| 25 |
+
"""หลัก Web UI Application สำหรับ F5-TTS Thai"""
|
| 26 |
+
|
| 27 |
+
def __init__(self):
|
| 28 |
+
self.model_manager = ModelManager()
|
| 29 |
+
self.tts_processor = TTSProcessor(self.model_manager)
|
| 30 |
+
self.stt_processor = SpeechToTextProcessor()
|
| 31 |
+
self.multi_speech_processor = MultiSpeechProcessor(self.model_manager)
|
| 32 |
+
self.ui_components = UIComponents()
|
| 33 |
+
|
| 34 |
+
def create_gradio_interface(self):
|
| 35 |
+
"""สร้าง Gradio interface"""
|
| 36 |
+
with gr.Blocks(title="F5-TTS ไทย", theme=gr.themes.Ocean()) as demo:
|
| 37 |
+
gr.Markdown("# F5-TTS ภาษาไทย")
|
| 38 |
+
gr.Markdown("สร้างคำพูดจากข้อความ ด้วย Zero-shot TTS หรือ เสียงต้นฉบับ ภาษาไทย.")
|
| 39 |
+
|
| 40 |
+
# Model selection section
|
| 41 |
+
model_select, model_custom, model_status, load_custom_btn = self.ui_components.create_model_selection_section()
|
| 42 |
+
|
| 43 |
+
# Setup model selection events
|
| 44 |
+
self._setup_model_selection_events(
|
| 45 |
+
model_select, model_custom, model_status, load_custom_btn
|
| 46 |
+
)
|
| 47 |
+
|
| 48 |
+
# Create tabs
|
| 49 |
+
#with gr.Tab(label="Text To Speech"):
|
| 50 |
+
# self._create_tts_tab()
|
| 51 |
+
|
| 52 |
+
with gr.Tab(label="Multi Speech"):
|
| 53 |
+
self._create_multispeech_tab()
|
| 54 |
+
|
| 55 |
+
#with gr.Tab(label="Speech to Text"):
|
| 56 |
+
# self._create_stt_tab()
|
| 57 |
+
|
| 58 |
+
return demo
|
| 59 |
+
|
| 60 |
+
def _setup_model_selection_events(self, model_select, model_custom, model_status, load_custom_btn):
|
| 61 |
+
"""ตั้งค่า events สำหรับการเลือกโมเดล"""
|
| 62 |
+
|
| 63 |
+
# Model selection change event
|
| 64 |
+
model_select.change(
|
| 65 |
+
fn=self.model_manager.update_custom_model_visibility,
|
| 66 |
+
inputs=model_select,
|
| 67 |
+
outputs=model_custom
|
| 68 |
+
)
|
| 69 |
+
|
| 70 |
+
# Load custom model button
|
| 71 |
+
load_custom_btn.click(
|
| 72 |
+
fn=self.model_manager.load_model_by_choice,
|
| 73 |
+
inputs=[model_select, model_custom],
|
| 74 |
+
outputs=model_status
|
| 75 |
+
)
|
| 76 |
+
|
| 77 |
+
def _create_tts_tab(self):
|
| 78 |
+
"""สร้าง Text To Speech tab"""
|
| 79 |
+
tts_components = self.ui_components.create_tts_tab(self.tts_processor.infer_tts)
|
| 80 |
+
|
| 81 |
+
# Setup TTS generation
|
| 82 |
+
tts_components['controls']['generate_btn'].click(
|
| 83 |
+
fn=self.tts_processor.infer_tts,
|
| 84 |
+
inputs=[
|
| 85 |
+
tts_components['inputs']['ref_audio'],
|
| 86 |
+
tts_components['inputs']['ref_text'],
|
| 87 |
+
tts_components['inputs']['gen_text'],
|
| 88 |
+
tts_components['inputs']['remove_silence'],
|
| 89 |
+
tts_components['inputs']['cross_fade_duration'],
|
| 90 |
+
tts_components['inputs']['nfe_step'],
|
| 91 |
+
tts_components['inputs']['speed'],
|
| 92 |
+
tts_components['inputs']['cfg_strength'],
|
| 93 |
+
tts_components['inputs']['max_chars'],
|
| 94 |
+
tts_components['inputs']['seed'],
|
| 95 |
+
tts_components['inputs']['no_ref_audio']
|
| 96 |
+
],
|
| 97 |
+
outputs=[
|
| 98 |
+
tts_components['outputs']['output_audio'],
|
| 99 |
+
tts_components['outputs']['spectrogram'],
|
| 100 |
+
tts_components['inputs']['ref_text'],
|
| 101 |
+
tts_components['outputs']['seed_output']
|
| 102 |
+
]
|
| 103 |
+
)
|
| 104 |
+
|
| 105 |
+
def _create_multispeech_tab(self):
|
| 106 |
+
"""สร้าง Multi Speech tab"""
|
| 107 |
+
ms_components = self.ui_components.create_multispeech_tab()
|
| 108 |
+
|
| 109 |
+
# Setup speech type management
|
| 110 |
+
self._setup_speech_type_events(ms_components)
|
| 111 |
+
|
| 112 |
+
# Setup multispeech generation
|
| 113 |
+
self._setup_multispeech_generation(ms_components)
|
| 114 |
+
|
| 115 |
+
# Setup segment editing
|
| 116 |
+
self._setup_segment_editing(ms_components)
|
| 117 |
+
|
| 118 |
+
def _setup_speech_type_events(self, ms_components):
|
| 119 |
+
"""ตั้งค่า events สำหรับ speech type management"""
|
| 120 |
+
|
| 121 |
+
# Add speech type button
|
| 122 |
+
ms_components['controls']['add_speech_type_btn'].click(
|
| 123 |
+
fn=self.ui_components.add_speech_type_fn,
|
| 124 |
+
outputs=ms_components['controls']['speech_type_rows']
|
| 125 |
+
)
|
| 126 |
+
|
| 127 |
+
# Delete speech type buttons
|
| 128 |
+
for i in range(1, len(self.ui_components.speech_type_delete_btns)):
|
| 129 |
+
if self.ui_components.speech_type_delete_btns[i] is not None:
|
| 130 |
+
self.ui_components.speech_type_delete_btns[i].click(
|
| 131 |
+
fn=self.ui_components.delete_speech_type_fn,
|
| 132 |
+
outputs=[
|
| 133 |
+
self.ui_components.speech_type_rows[i],
|
| 134 |
+
self.ui_components.speech_type_names[i],
|
| 135 |
+
self.ui_components.speech_type_audios[i],
|
| 136 |
+
self.ui_components.speech_type_ref_texts[i]
|
| 137 |
+
]
|
| 138 |
+
)
|
| 139 |
+
|
| 140 |
+
# Insert speech type buttons
|
| 141 |
+
for i, insert_btn in enumerate(self.ui_components.speech_type_insert_btns):
|
| 142 |
+
insert_fn = self.ui_components.make_insert_speech_type_fn(i)
|
| 143 |
+
insert_btn.click(
|
| 144 |
+
fn=insert_fn,
|
| 145 |
+
inputs=[ms_components['inputs']['gen_text'], self.ui_components.speech_type_names[i]],
|
| 146 |
+
outputs=ms_components['inputs']['gen_text']
|
| 147 |
+
)
|
| 148 |
+
|
| 149 |
+
# Validation for generate button
|
| 150 |
+
ms_components['inputs']['gen_text'].change(
|
| 151 |
+
fn=self.multi_speech_processor.validate_speech_types,
|
| 152 |
+
inputs=[ms_components['inputs']['gen_text']] + ms_components['inputs']['speech_type_names'],
|
| 153 |
+
outputs=ms_components['controls']['generate_btn']
|
| 154 |
+
)
|
| 155 |
+
|
| 156 |
+
def _setup_multispeech_generation(self, ms_components):
|
| 157 |
+
"""ตั้งค่า multispeech generation"""
|
| 158 |
+
|
| 159 |
+
# Prepare inputs for generation
|
| 160 |
+
generation_inputs = [
|
| 161 |
+
ms_components['inputs']['gen_text'],
|
| 162 |
+
ms_components['inputs']['cross_fade_duration'],
|
| 163 |
+
ms_components['inputs']['nfe_step']
|
| 164 |
+
] + (
|
| 165 |
+
ms_components['inputs']['speech_type_names'] +
|
| 166 |
+
ms_components['inputs']['speech_type_audios'] +
|
| 167 |
+
ms_components['inputs']['speech_type_ref_texts'] +
|
| 168 |
+
[ms_components['inputs']['remove_silence']] +
|
| 169 |
+
ms_components['inputs']['segment_silence_inputs']
|
| 170 |
+
)
|
| 171 |
+
|
| 172 |
+
# Prepare outputs for generation
|
| 173 |
+
generation_outputs = [
|
| 174 |
+
ms_components['outputs']['audio_output'],
|
| 175 |
+
ms_components['outputs']['download_btn']
|
| 176 |
+
] + (
|
| 177 |
+
ms_components['outputs']['segment_players'] +
|
| 178 |
+
ms_components['outputs']['segment_text_inputs'] +
|
| 179 |
+
ms_components['outputs']['segment_silence_inputs'] +
|
| 180 |
+
ms_components['outputs']['segment_regen_btns'] +
|
| 181 |
+
[ms_components['state']['segments_state'], ms_components['state']['sr_state']]
|
| 182 |
+
)
|
| 183 |
+
|
| 184 |
+
# Generate button click
|
| 185 |
+
ms_components['controls']['generate_btn'].click(
|
| 186 |
+
fn=self._wrap_multispeech_generation,
|
| 187 |
+
inputs=generation_inputs,
|
| 188 |
+
outputs=generation_outputs
|
| 189 |
+
)
|
| 190 |
+
|
| 191 |
+
def _wrap_multispeech_generation(self, gen_text, cross_fade_duration, nfe_step, *args):
|
| 192 |
+
"""Wrapper สำหรับ multispeech generation"""
|
| 193 |
+
speech_types_data = args[:MAX_SPEECH_TYPES * 3]
|
| 194 |
+
remove_silence = args[MAX_SPEECH_TYPES * 3]
|
| 195 |
+
silence_inputs = args[MAX_SPEECH_TYPES * 3 + 1:]
|
| 196 |
+
|
| 197 |
+
return self.multi_speech_processor.generate_multistyle_speech(
|
| 198 |
+
gen_text,
|
| 199 |
+
cross_fade_duration,
|
| 200 |
+
nfe_step,
|
| 201 |
+
speech_types_data,
|
| 202 |
+
remove_silence,
|
| 203 |
+
silence_inputs
|
| 204 |
+
)
|
| 205 |
+
|
| 206 |
+
def _setup_segment_editing(self, ms_components):
|
| 207 |
+
"""ตั้งค่า segment editing"""
|
| 208 |
+
|
| 209 |
+
# Update silence button
|
| 210 |
+
ms_components['controls']['update_silence_btn'].click(
|
| 211 |
+
fn=self.multi_speech_processor.update_silence_all,
|
| 212 |
+
inputs=ms_components['inputs']['segment_silence_inputs'] + [
|
| 213 |
+
ms_components['state']['segments_state'],
|
| 214 |
+
ms_components['state']['sr_state']
|
| 215 |
+
],
|
| 216 |
+
outputs=ms_components['outputs']['segment_players'] +
|
| 217 |
+
ms_components['outputs']['segment_text_inputs'] +
|
| 218 |
+
ms_components['outputs']['segment_silence_inputs'] +
|
| 219 |
+
ms_components['outputs']['segment_regen_btns'] + [
|
| 220 |
+
ms_components['outputs']['audio_output'],
|
| 221 |
+
ms_components['outputs']['download_btn'],
|
| 222 |
+
ms_components['state']['segments_state'],
|
| 223 |
+
ms_components['state']['sr_state']
|
| 224 |
+
]
|
| 225 |
+
)
|
| 226 |
+
|
| 227 |
+
# Regenerate segment buttons
|
| 228 |
+
for i, btn in enumerate(ms_components['outputs']['segment_regen_btns']):
|
| 229 |
+
btn.click(
|
| 230 |
+
fn=self._wrap_regenerate_segment,
|
| 231 |
+
inputs=[
|
| 232 |
+
gr.State(i),
|
| 233 |
+
ms_components['outputs']['segment_text_inputs'][i],
|
| 234 |
+
ms_components['outputs']['segment_silence_inputs'][i],
|
| 235 |
+
ms_components['state']['segments_state'],
|
| 236 |
+
ms_components['inputs']['cross_fade_duration'],
|
| 237 |
+
ms_components['inputs']['nfe_step']
|
| 238 |
+
],
|
| 239 |
+
outputs=ms_components['outputs']['segment_players'] +
|
| 240 |
+
ms_components['outputs']['segment_text_inputs'] +
|
| 241 |
+
ms_components['outputs']['segment_silence_inputs'] +
|
| 242 |
+
ms_components['outputs']['segment_regen_btns'] + [
|
| 243 |
+
ms_components['outputs']['audio_output'],
|
| 244 |
+
ms_components['outputs']['download_btn'],
|
| 245 |
+
ms_components['state']['segments_state'],
|
| 246 |
+
ms_components['state']['sr_state']
|
| 247 |
+
]
|
| 248 |
+
)
|
| 249 |
+
|
| 250 |
+
def _wrap_regenerate_segment(self, idx, new_text, silence_ms, segments, cross_fade_duration, nfe_step):
|
| 251 |
+
"""Wrapper สำหรับ regenerate segment"""
|
| 252 |
+
return self.multi_speech_processor.regenerate_segment(
|
| 253 |
+
idx, new_text, silence_ms, segments, cross_fade_duration, nfe_step
|
| 254 |
+
)
|
| 255 |
+
|
| 256 |
+
def _create_stt_tab(self):
|
| 257 |
+
"""สร้าง Speech to Text tab"""
|
| 258 |
+
stt_components = self.ui_components.create_stt_tab()
|
| 259 |
+
|
| 260 |
+
# Setup STT generation
|
| 261 |
+
stt_components['controls']['generate_btn_stt'].click(
|
| 262 |
+
fn=self.stt_processor.transcribe_text,
|
| 263 |
+
inputs=[
|
| 264 |
+
stt_components['inputs']['ref_audio_input'],
|
| 265 |
+
stt_components['inputs']['is_translate'],
|
| 266 |
+
stt_components['inputs']['model_wp'],
|
| 267 |
+
stt_components['inputs']['compute_type'],
|
| 268 |
+
stt_components['inputs']['target_lg'],
|
| 269 |
+
stt_components['inputs']['source_lg']
|
| 270 |
+
],
|
| 271 |
+
outputs=stt_components['outputs']['output_ref_text']
|
| 272 |
+
)
|
| 273 |
+
|
| 274 |
+
|
| 275 |
+
def main():
|
| 276 |
+
"""Main function สำหรับรัน application"""
|
| 277 |
+
try:
|
| 278 |
+
parser = argparse.ArgumentParser(description="F5-TTS Thai WebUI - Refactored")
|
| 279 |
+
parser.add_argument("--share", action="store_true", help="Share the app")
|
| 280 |
+
args = parser.parse_args()
|
| 281 |
+
|
| 282 |
+
print("กำลังเริ่มต้น F5-TTS Thai WebUI...")
|
| 283 |
+
app = F5TTSWebUI()
|
| 284 |
+
demo = app.create_gradio_interface()
|
| 285 |
+
print("WebUI พร้อมใช้งาน!")
|
| 286 |
+
demo.launch(inbrowser=True, share=args.share)
|
| 287 |
+
except Exception as e:
|
| 288 |
+
print(f"เกิดข้อผิดพลาด: {e}")
|
| 289 |
+
import traceback
|
| 290 |
+
traceback.print_exc()
|
| 291 |
+
|
| 292 |
+
|
| 293 |
+
if __name__ == "__main__":
|
| 294 |
+
main()
|
| 295 |
+
|
deployment/src/f5_tts/infer/README.md
ADDED
|
@@ -0,0 +1,219 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
# Inference
|
| 2 |
+
|
| 3 |
+
The pretrained model checkpoints can be reached at [🤗 Hugging Face](https://huggingface.co/SWivid/F5-TTS) and [🤖 Model Scope](https://www.modelscope.cn/models/SWivid/F5-TTS_Emilia-ZH-EN), or will be automatically downloaded when running inference scripts.
|
| 4 |
+
|
| 5 |
+
**More checkpoints with whole community efforts can be found in [SHARED.md](SHARED.md), supporting more languages.**
|
| 6 |
+
|
| 7 |
+
Currently support **30s for a single** generation, which is the **total length** including both prompt and output audio. However, you can provide `infer_cli` and `infer_gradio` with longer text, will automatically do chunk generation. Long reference audio will be **clip short to ~15s**.
|
| 8 |
+
|
| 9 |
+
To avoid possible inference failures, make sure you have seen through the following instructions.
|
| 10 |
+
|
| 11 |
+
- Use reference audio <15s and leave some silence (e.g. 1s) at the end. Otherwise there is a risk of truncating in the middle of word, leading to suboptimal generation.
|
| 12 |
+
- Uppercased letters will be uttered letter by letter, so use lowercased letters for normal words.
|
| 13 |
+
- Add some spaces (blank: " ") or punctuations (e.g. "," ".") to explicitly introduce some pauses.
|
| 14 |
+
- Preprocess numbers to Chinese letters if you want to have them read in Chinese, otherwise in English.
|
| 15 |
+
- If the generation output is blank (pure silence), check for ffmpeg installation (various tutorials online, blogs, videos, etc.).
|
| 16 |
+
- Try turn off use_ema if using an early-stage finetuned checkpoint (which goes just few updates).
|
| 17 |
+
|
| 18 |
+
|
| 19 |
+
## Gradio App
|
| 20 |
+
|
| 21 |
+
Currently supported features:
|
| 22 |
+
|
| 23 |
+
- Basic TTS with Chunk Inference
|
| 24 |
+
- Multi-Style / Multi-Speaker Generation
|
| 25 |
+
- Voice Chat powered by Qwen2.5-3B-Instruct
|
| 26 |
+
- [Custom inference with more language support](src/f5_tts/infer/SHARED.md)
|
| 27 |
+
|
| 28 |
+
The cli command `f5-tts_infer-gradio` equals to `python src/f5_tts/infer/infer_gradio.py`, which launches a Gradio APP (web interface) for inference.
|
| 29 |
+
|
| 30 |
+
The script will load model checkpoints from Huggingface. You can also manually download files and update the path to `load_model()` in `infer_gradio.py`. Currently only load TTS models first, will load ASR model to do transcription if `ref_text` not provided, will load LLM model if use Voice Chat.
|
| 31 |
+
|
| 32 |
+
More flags options:
|
| 33 |
+
|
| 34 |
+
```bash
|
| 35 |
+
# Automatically launch the interface in the default web browser
|
| 36 |
+
f5-tts_infer-gradio --inbrowser
|
| 37 |
+
|
| 38 |
+
# Set the root path of the application, if it's not served from the root ("/") of the domain
|
| 39 |
+
# For example, if the application is served at "https://example.com/myapp"
|
| 40 |
+
f5-tts_infer-gradio --root_path "/myapp"
|
| 41 |
+
```
|
| 42 |
+
|
| 43 |
+
Could also be used as a component for larger application:
|
| 44 |
+
```python
|
| 45 |
+
import gradio as gr
|
| 46 |
+
from f5_tts.infer.infer_gradio import app
|
| 47 |
+
|
| 48 |
+
with gr.Blocks() as main_app:
|
| 49 |
+
gr.Markdown("# This is an example of using F5-TTS within a bigger Gradio app")
|
| 50 |
+
|
| 51 |
+
# ... other Gradio components
|
| 52 |
+
|
| 53 |
+
app.render()
|
| 54 |
+
|
| 55 |
+
main_app.launch()
|
| 56 |
+
```
|
| 57 |
+
|
| 58 |
+
|
| 59 |
+
## CLI Inference
|
| 60 |
+
|
| 61 |
+
The cli command `f5-tts_infer-cli` equals to `python src/f5_tts/infer/infer_cli.py`, which is a command line tool for inference.
|
| 62 |
+
|
| 63 |
+
The script will load model checkpoints from Huggingface. You can also manually download files and use `--ckpt_file` to specify the model you want to load, or directly update in `infer_cli.py`.
|
| 64 |
+
|
| 65 |
+
For change vocab.txt use `--vocab_file` to provide your `vocab.txt` file.
|
| 66 |
+
|
| 67 |
+
Basically you can inference with flags:
|
| 68 |
+
```bash
|
| 69 |
+
# Leave --ref_text "" will have ASR model transcribe (extra GPU memory usage)
|
| 70 |
+
f5-tts_infer-cli \
|
| 71 |
+
--model "F5-TTS" \
|
| 72 |
+
--ref_audio "ref_audio.wav" \
|
| 73 |
+
--ref_text "The content, subtitle or transcription of reference audio." \
|
| 74 |
+
--gen_text "Some text you want TTS model generate for you."
|
| 75 |
+
|
| 76 |
+
# Choose Vocoder
|
| 77 |
+
f5-tts_infer-cli --vocoder_name bigvgan --load_vocoder_from_local --ckpt_file <YOUR_CKPT_PATH, eg:ckpts/F5TTS_Base_bigvgan/model_1250000.pt>
|
| 78 |
+
f5-tts_infer-cli --vocoder_name vocos --load_vocoder_from_local --ckpt_file <YOUR_CKPT_PATH, eg:ckpts/F5TTS_Base/model_1200000.safetensors>
|
| 79 |
+
|
| 80 |
+
# More instructions
|
| 81 |
+
f5-tts_infer-cli --help
|
| 82 |
+
```
|
| 83 |
+
|
| 84 |
+
And a `.toml` file would help with more flexible usage.
|
| 85 |
+
|
| 86 |
+
```bash
|
| 87 |
+
f5-tts_infer-cli -c custom.toml
|
| 88 |
+
```
|
| 89 |
+
|
| 90 |
+
For example, you can use `.toml` to pass in variables, refer to `src/f5_tts/infer/examples/basic/basic.toml`:
|
| 91 |
+
|
| 92 |
+
```toml
|
| 93 |
+
# F5-TTS | E2-TTS
|
| 94 |
+
model = "F5-TTS"
|
| 95 |
+
ref_audio = "infer/examples/basic/basic_ref_en.wav"
|
| 96 |
+
# If an empty "", transcribes the reference audio automatically.
|
| 97 |
+
ref_text = "Some call me nature, others call me mother nature."
|
| 98 |
+
gen_text = "I don't really care what you call me. I've been a silent spectator, watching species evolve, empires rise and fall. But always remember, I am mighty and enduring."
|
| 99 |
+
# File with text to generate. Ignores the text above.
|
| 100 |
+
gen_file = ""
|
| 101 |
+
remove_silence = false
|
| 102 |
+
output_dir = "tests"
|
| 103 |
+
```
|
| 104 |
+
|
| 105 |
+
You can also leverage `.toml` file to do multi-style generation, refer to `src/f5_tts/infer/examples/multi/story.toml`.
|
| 106 |
+
|
| 107 |
+
```toml
|
| 108 |
+
# F5-TTS | E2-TTS
|
| 109 |
+
model = "F5-TTS"
|
| 110 |
+
ref_audio = "infer/examples/multi/main.flac"
|
| 111 |
+
# If an empty "", transcribes the reference audio automatically.
|
| 112 |
+
ref_text = ""
|
| 113 |
+
gen_text = ""
|
| 114 |
+
# File with text to generate. Ignores the text above.
|
| 115 |
+
gen_file = "infer/examples/multi/story.txt"
|
| 116 |
+
remove_silence = true
|
| 117 |
+
output_dir = "tests"
|
| 118 |
+
|
| 119 |
+
[voices.town]
|
| 120 |
+
ref_audio = "infer/examples/multi/town.flac"
|
| 121 |
+
ref_text = ""
|
| 122 |
+
|
| 123 |
+
[voices.country]
|
| 124 |
+
ref_audio = "infer/examples/multi/country.flac"
|
| 125 |
+
ref_text = ""
|
| 126 |
+
```
|
| 127 |
+
You should mark the voice with `[main]` `[town]` `[country]` whenever you want to change voice, refer to `src/f5_tts/infer/examples/multi/story.txt`.
|
| 128 |
+
|
| 129 |
+
## Speech Editing
|
| 130 |
+
|
| 131 |
+
To test speech editing capabilities, use the following command:
|
| 132 |
+
|
| 133 |
+
```bash
|
| 134 |
+
python src/f5_tts/infer/speech_edit.py
|
| 135 |
+
```
|
| 136 |
+
|
| 137 |
+
## Socket Realtime Client
|
| 138 |
+
|
| 139 |
+
To communicate with socket server you need to run
|
| 140 |
+
```bash
|
| 141 |
+
python src/f5_tts/socket_server.py
|
| 142 |
+
```
|
| 143 |
+
|
| 144 |
+
<details>
|
| 145 |
+
<summary>Then create client to communicate</summary>
|
| 146 |
+
|
| 147 |
+
```bash
|
| 148 |
+
# If PyAudio not installed
|
| 149 |
+
sudo apt-get install portaudio19-dev
|
| 150 |
+
pip install pyaudio
|
| 151 |
+
```
|
| 152 |
+
|
| 153 |
+
``` python
|
| 154 |
+
# Create the socket_client.py
|
| 155 |
+
import socket
|
| 156 |
+
import asyncio
|
| 157 |
+
import pyaudio
|
| 158 |
+
import numpy as np
|
| 159 |
+
import logging
|
| 160 |
+
import time
|
| 161 |
+
|
| 162 |
+
logging.basicConfig(level=logging.INFO)
|
| 163 |
+
logger = logging.getLogger(__name__)
|
| 164 |
+
|
| 165 |
+
|
| 166 |
+
async def listen_to_F5TTS(text, server_ip="localhost", server_port=9998):
|
| 167 |
+
client_socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
|
| 168 |
+
await asyncio.get_event_loop().run_in_executor(None, client_socket.connect, (server_ip, int(server_port)))
|
| 169 |
+
|
| 170 |
+
start_time = time.time()
|
| 171 |
+
first_chunk_time = None
|
| 172 |
+
|
| 173 |
+
async def play_audio_stream():
|
| 174 |
+
nonlocal first_chunk_time
|
| 175 |
+
p = pyaudio.PyAudio()
|
| 176 |
+
stream = p.open(format=pyaudio.paFloat32, channels=1, rate=24000, output=True, frames_per_buffer=2048)
|
| 177 |
+
|
| 178 |
+
try:
|
| 179 |
+
while True:
|
| 180 |
+
data = await asyncio.get_event_loop().run_in_executor(None, client_socket.recv, 8192)
|
| 181 |
+
if not data:
|
| 182 |
+
break
|
| 183 |
+
if data == b"END":
|
| 184 |
+
logger.info("End of audio received.")
|
| 185 |
+
break
|
| 186 |
+
|
| 187 |
+
audio_array = np.frombuffer(data, dtype=np.float32)
|
| 188 |
+
stream.write(audio_array.tobytes())
|
| 189 |
+
|
| 190 |
+
if first_chunk_time is None:
|
| 191 |
+
first_chunk_time = time.time()
|
| 192 |
+
|
| 193 |
+
finally:
|
| 194 |
+
stream.stop_stream()
|
| 195 |
+
stream.close()
|
| 196 |
+
p.terminate()
|
| 197 |
+
|
| 198 |
+
logger.info(f"Total time taken: {time.time() - start_time:.4f} seconds")
|
| 199 |
+
|
| 200 |
+
try:
|
| 201 |
+
data_to_send = f"{text}".encode("utf-8")
|
| 202 |
+
await asyncio.get_event_loop().run_in_executor(None, client_socket.sendall, data_to_send)
|
| 203 |
+
await play_audio_stream()
|
| 204 |
+
|
| 205 |
+
except Exception as e:
|
| 206 |
+
logger.error(f"Error in listen_to_F5TTS: {e}")
|
| 207 |
+
|
| 208 |
+
finally:
|
| 209 |
+
client_socket.close()
|
| 210 |
+
|
| 211 |
+
|
| 212 |
+
if __name__ == "__main__":
|
| 213 |
+
text_to_send = "As a Reader assistant, I'm familiar with new technology. which are key to its improved performance in terms of both training speed and inference efficiency. Let's break down the components"
|
| 214 |
+
|
| 215 |
+
asyncio.run(listen_to_F5TTS(text_to_send))
|
| 216 |
+
```
|
| 217 |
+
|
| 218 |
+
</details>
|
| 219 |
+
|
deployment/src/f5_tts/infer/SHARED.md
ADDED
|
@@ -0,0 +1,164 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
<!-- omit in toc -->
|
| 2 |
+
# Shared Model Cards
|
| 3 |
+
|
| 4 |
+
<!-- omit in toc -->
|
| 5 |
+
### **Prerequisites of using**
|
| 6 |
+
- This document is serving as a quick lookup table for the community training/finetuning result, with various language support.
|
| 7 |
+
- The models in this repository are open source and are based on voluntary contributions from contributors.
|
| 8 |
+
- The use of models must be conditioned on respect for the respective creators. The convenience brought comes from their efforts.
|
| 9 |
+
|
| 10 |
+
<!-- omit in toc -->
|
| 11 |
+
### **Welcome to share here**
|
| 12 |
+
- Have a pretrained/finetuned result: model checkpoint (pruned best to facilitate inference, i.e. leave only `ema_model_state_dict`) and corresponding vocab file (for tokenization).
|
| 13 |
+
- Host a public [huggingface model repository](https://huggingface.co/new) and upload the model related files.
|
| 14 |
+
- Make a pull request adding a model card to the current page, i.e. `src\f5_tts\infer\SHARED.md`.
|
| 15 |
+
|
| 16 |
+
<!-- omit in toc -->
|
| 17 |
+
### Supported Languages
|
| 18 |
+
- [Multilingual](#multilingual)
|
| 19 |
+
- [F5-TTS Base @ zh \& en @ F5-TTS](#f5-tts-base--zh--en--f5-tts)
|
| 20 |
+
- [English](#english)
|
| 21 |
+
- [Finnish](#finnish)
|
| 22 |
+
- [F5-TTS Base @ fi @ AsmoKoskinen](#f5-tts-base--fi--asmokoskinen)
|
| 23 |
+
- [French](#french)
|
| 24 |
+
- [F5-TTS Base @ fr @ RASPIAUDIO](#f5-tts-base--fr--raspiaudio)
|
| 25 |
+
- [Hindi](#hindi)
|
| 26 |
+
- [F5-TTS Small @ hi @ SPRINGLab](#f5-tts-small--hi--springlab)
|
| 27 |
+
- [Italian](#italian)
|
| 28 |
+
- [F5-TTS Base @ it @ alien79](#f5-tts-base--it--alien79)
|
| 29 |
+
- [Japanese](#japanese)
|
| 30 |
+
- [F5-TTS Base @ ja @ Jmica](#f5-tts-base--ja--jmica)
|
| 31 |
+
- [Mandarin](#mandarin)
|
| 32 |
+
- [Russian](#russian)
|
| 33 |
+
- [F5-TTS Base @ ru @ HotDro4illa](#f5-tts-base--ru--hotdro4illa)
|
| 34 |
+
- [Spanish](#spanish)
|
| 35 |
+
- [F5-TTS Base @ es @ jpgallegoar](#f5-tts-base--es--jpgallegoar)
|
| 36 |
+
|
| 37 |
+
|
| 38 |
+
## Multilingual
|
| 39 |
+
|
| 40 |
+
#### F5-TTS Base @ zh & en @ F5-TTS
|
| 41 |
+
|Model|🤗Hugging Face|Data (Hours)|Model License|
|
| 42 |
+
|:---:|:------------:|:-----------:|:-------------:|
|
| 43 |
+
|F5-TTS Base|[ckpt & vocab](https://huggingface.co/SWivid/F5-TTS/tree/main/F5TTS_Base)|[Emilia 95K zh&en](https://huggingface.co/datasets/amphion/Emilia-Dataset/tree/fc71e07)|cc-by-nc-4.0|
|
| 44 |
+
|
| 45 |
+
```bash
|
| 46 |
+
Model: hf://SWivid/F5-TTS/F5TTS_Base/model_1200000.safetensors
|
| 47 |
+
Vocab: hf://SWivid/F5-TTS/F5TTS_Base/vocab.txt
|
| 48 |
+
Config: {"dim": 1024, "depth": 22, "heads": 16, "ff_mult": 2, "text_dim": 512, "conv_layers": 4}
|
| 49 |
+
```
|
| 50 |
+
|
| 51 |
+
*Other infos, e.g. Author info, Github repo, Link to some sampled results, Usage instruction, Tutorial (Blog, Video, etc.) ...*
|
| 52 |
+
|
| 53 |
+
|
| 54 |
+
## English
|
| 55 |
+
|
| 56 |
+
|
| 57 |
+
## Finnish
|
| 58 |
+
|
| 59 |
+
#### F5-TTS Base @ fi @ AsmoKoskinen
|
| 60 |
+
|Model|🤗Hugging Face|Data|Model License|
|
| 61 |
+
|:---:|:------------:|:-----------:|:-------------:|
|
| 62 |
+
|F5-TTS Base|[ckpt & vocab](https://huggingface.co/AsmoKoskinen/F5-TTS_Finnish_Model)|[Common Voice](https://huggingface.co/datasets/mozilla-foundation/common_voice_17_0), [Vox Populi](https://huggingface.co/datasets/facebook/voxpopuli)|cc-by-nc-4.0|
|
| 63 |
+
|
| 64 |
+
```bash
|
| 65 |
+
Model: hf://AsmoKoskinen/F5-TTS_Finnish_Model/model_common_voice_fi_vox_populi_fi_20241206.safetensors
|
| 66 |
+
Vocab: hf://AsmoKoskinen/F5-TTS_Finnish_Model/vocab.txt
|
| 67 |
+
Config: {"dim": 1024, "depth": 22, "heads": 16, "ff_mult": 2, "text_dim": 512, "conv_layers": 4}
|
| 68 |
+
```
|
| 69 |
+
|
| 70 |
+
|
| 71 |
+
## French
|
| 72 |
+
|
| 73 |
+
#### F5-TTS Base @ fr @ RASPIAUDIO
|
| 74 |
+
|Model|🤗Hugging Face|Data (Hours)|Model License|
|
| 75 |
+
|:---:|:------------:|:-----------:|:-------------:|
|
| 76 |
+
|F5-TTS Base|[ckpt & vocab](https://huggingface.co/RASPIAUDIO/F5-French-MixedSpeakers-reduced)|[LibriVox](https://librivox.org/)|cc-by-nc-4.0|
|
| 77 |
+
|
| 78 |
+
```bash
|
| 79 |
+
Model: hf://RASPIAUDIO/F5-French-MixedSpeakers-reduced/model_last_reduced.pt
|
| 80 |
+
Vocab: hf://RASPIAUDIO/F5-French-MixedSpeakers-reduced/vocab.txt
|
| 81 |
+
Config: {"dim": 1024, "depth": 22, "heads": 16, "ff_mult": 2, "text_dim": 512, "conv_layers": 4}
|
| 82 |
+
```
|
| 83 |
+
|
| 84 |
+
- [Online Inference with Hugging Face Space](https://huggingface.co/spaces/RASPIAUDIO/f5-tts_french).
|
| 85 |
+
- [Tutorial video to train a new language model](https://www.youtube.com/watch?v=UO4usaOojys).
|
| 86 |
+
- [Discussion about this training can be found here](https://github.com/SWivid/F5-TTS/issues/434).
|
| 87 |
+
|
| 88 |
+
|
| 89 |
+
## Hindi
|
| 90 |
+
|
| 91 |
+
#### F5-TTS Small @ hi @ SPRINGLab
|
| 92 |
+
|Model|🤗Hugging Face|Data (Hours)|Model License|
|
| 93 |
+
|:---:|:------------:|:-----------:|:-------------:|
|
| 94 |
+
|F5-TTS Small|[ckpt & vocab](https://huggingface.co/SPRINGLab/F5-Hindi-24KHz)|[IndicTTS Hi](https://huggingface.co/datasets/SPRINGLab/IndicTTS-Hindi) & [IndicVoices-R Hi](https://huggingface.co/datasets/SPRINGLab/IndicVoices-R_Hindi) |cc-by-4.0|
|
| 95 |
+
|
| 96 |
+
```bash
|
| 97 |
+
Model: hf://SPRINGLab/F5-Hindi-24KHz/model_2500000.safetensors
|
| 98 |
+
Vocab: hf://SPRINGLab/F5-Hindi-24KHz/vocab.txt
|
| 99 |
+
Config: {"dim": 768, "depth": 18, "heads": 12, "ff_mult": 2, "text_dim": 512, "conv_layers": 4}
|
| 100 |
+
```
|
| 101 |
+
|
| 102 |
+
- Authors: SPRING Lab, Indian Institute of Technology, Madras
|
| 103 |
+
- Website: https://asr.iitm.ac.in/
|
| 104 |
+
|
| 105 |
+
|
| 106 |
+
## Italian
|
| 107 |
+
|
| 108 |
+
#### F5-TTS Base @ it @ alien79
|
| 109 |
+
|Model|🤗Hugging Face|Data|Model License|
|
| 110 |
+
|:---:|:------------:|:-----------:|:-------------:|
|
| 111 |
+
|F5-TTS Base|[ckpt & vocab](https://huggingface.co/alien79/F5-TTS-italian)|[ylacombe/cml-tts](https://huggingface.co/datasets/ylacombe/cml-tts) |cc-by-nc-4.0|
|
| 112 |
+
|
| 113 |
+
```bash
|
| 114 |
+
Model: hf://alien79/F5-TTS-italian/model_159600.safetensors
|
| 115 |
+
Vocab: hf://alien79/F5-TTS-italian/vocab.txt
|
| 116 |
+
Config: {"dim": 1024, "depth": 22, "heads": 16, "ff_mult": 2, "text_dim": 512, "conv_layers": 4}
|
| 117 |
+
```
|
| 118 |
+
|
| 119 |
+
- Trained by [Mithril Man](https://github.com/MithrilMan)
|
| 120 |
+
- Model details on [hf project home](https://huggingface.co/alien79/F5-TTS-italian)
|
| 121 |
+
- Open to collaborations to further improve the model
|
| 122 |
+
|
| 123 |
+
|
| 124 |
+
## Japanese
|
| 125 |
+
|
| 126 |
+
#### F5-TTS Base @ ja @ Jmica
|
| 127 |
+
|Model|🤗Hugging Face|Data (Hours)|Model License|
|
| 128 |
+
|:---:|:------------:|:-----------:|:-------------:|
|
| 129 |
+
|F5-TTS Base|[ckpt & vocab](https://huggingface.co/Jmica/F5TTS/tree/main/JA_25498980)|[Emilia 1.7k JA](https://huggingface.co/datasets/amphion/Emilia-Dataset/tree/fc71e07) & [Galgame Dataset 5.4k](https://huggingface.co/datasets/OOPPEENN/Galgame_Dataset)|cc-by-nc-4.0|
|
| 130 |
+
|
| 131 |
+
```bash
|
| 132 |
+
Model: hf://Jmica/F5TTS/JA_25498980/model_25498980.pt
|
| 133 |
+
Vocab: hf://Jmica/F5TTS/JA_25498980/vocab_updated.txt
|
| 134 |
+
Config: {"dim": 1024, "depth": 22, "heads": 16, "ff_mult": 2, "text_dim": 512, "conv_layers": 4}
|
| 135 |
+
```
|
| 136 |
+
|
| 137 |
+
|
| 138 |
+
## Mandarin
|
| 139 |
+
|
| 140 |
+
|
| 141 |
+
## Russian
|
| 142 |
+
|
| 143 |
+
#### F5-TTS Base @ ru @ HotDro4illa
|
| 144 |
+
|Model|🤗Hugging Face|Data (Hours)|Model License|
|
| 145 |
+
|:---:|:------------:|:-----------:|:-------------:|
|
| 146 |
+
|F5-TTS Base|[ckpt & vocab](https://huggingface.co/hotstone228/F5-TTS-Russian)|[Common voice](https://huggingface.co/datasets/mozilla-foundation/common_voice_17_0)|cc-by-nc-4.0|
|
| 147 |
+
|
| 148 |
+
```bash
|
| 149 |
+
Model: hf://hotstone228/F5-TTS-Russian/model_last.safetensors
|
| 150 |
+
Vocab: hf://hotstone228/F5-TTS-Russian/vocab.txt
|
| 151 |
+
Config: {"dim": 1024, "depth": 22, "heads": 16, "ff_mult": 2, "text_dim": 512, "conv_layers": 4}
|
| 152 |
+
```
|
| 153 |
+
- Finetuned by [HotDro4illa](https://github.com/HotDro4illa)
|
| 154 |
+
- Any improvements are welcome
|
| 155 |
+
|
| 156 |
+
|
| 157 |
+
## Spanish
|
| 158 |
+
|
| 159 |
+
#### F5-TTS Base @ es @ jpgallegoar
|
| 160 |
+
|Model|🤗Hugging Face|Data (Hours)|Model License|
|
| 161 |
+
|:---:|:------------:|:-----------:|:-------------:|
|
| 162 |
+
|F5-TTS Base|[ckpt & vocab](https://huggingface.co/jpgallegoar/F5-Spanish)|[Voxpopuli](https://huggingface.co/datasets/facebook/voxpopuli) & Crowdsourced & TEDx, 218 hours|cc0-1.0|
|
| 163 |
+
|
| 164 |
+
- @jpgallegoar [GitHub repo](https://github.com/jpgallegoar/Spanish-F5), Jupyter Notebook and Gradio usage for Spanish model.
|
deployment/src/f5_tts/infer/examples/basic/basic.toml
ADDED
|
@@ -0,0 +1,11 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
# F5-TTS | E2-TTS
|
| 2 |
+
model = "F5-TTS"
|
| 3 |
+
ref_audio = "infer/examples/basic/basic_ref_en.wav"
|
| 4 |
+
# If an empty "", transcribes the reference audio automatically.
|
| 5 |
+
ref_text = "Some call me nature, others call me mother nature."
|
| 6 |
+
gen_text = "I don't really care what you call me. I've been a silent spectator, watching species evolve, empires rise and fall. But always remember, I am mighty and enduring."
|
| 7 |
+
# File with text to generate. Ignores the text above.
|
| 8 |
+
gen_file = ""
|
| 9 |
+
remove_silence = false
|
| 10 |
+
output_dir = "tests"
|
| 11 |
+
output_file = "infer_cli_basic.wav"
|
deployment/src/f5_tts/infer/examples/basic/basic_ref_en.wav
ADDED
|
@@ -0,0 +1,3 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
version https://git-lfs.github.com/spec/v1
|
| 2 |
+
oid sha256:b0e22048e72414fcc1e6b6342e47a774d748a195ed34e4a5b3fcf416707f2b71
|
| 3 |
+
size 256018
|
deployment/src/f5_tts/infer/examples/basic/basic_ref_zh.wav
ADDED
|
@@ -0,0 +1,3 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
version https://git-lfs.github.com/spec/v1
|
| 2 |
+
oid sha256:96724a113240d1f82c6ded1334122f0176b96c9226ccd3c919e625bcfd2a3ede
|
| 3 |
+
size 324558
|
deployment/src/f5_tts/infer/examples/multi/country.flac
ADDED
|
@@ -0,0 +1,3 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
version https://git-lfs.github.com/spec/v1
|
| 2 |
+
oid sha256:bb15708b4b3875e37beec46591a5d89e1a9a63fdad3b8fe4a5c8738f4f554400
|
| 3 |
+
size 180321
|
deployment/src/f5_tts/infer/examples/multi/main.flac
ADDED
|
@@ -0,0 +1,3 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
version https://git-lfs.github.com/spec/v1
|
| 2 |
+
oid sha256:4abb1107771ce7e14926fde879b959dde6db6e572476b98684f04e45e978ab19
|
| 3 |
+
size 279219
|
deployment/src/f5_tts/infer/examples/multi/story.toml
ADDED
|
@@ -0,0 +1,20 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
# F5-TTS | E2-TTS
|
| 2 |
+
model = "F5-TTS"
|
| 3 |
+
ref_audio = "infer/examples/multi/main.flac"
|
| 4 |
+
# If an empty "", transcribes the reference audio automatically.
|
| 5 |
+
ref_text = ""
|
| 6 |
+
gen_text = ""
|
| 7 |
+
# File with text to generate. Ignores the text above.
|
| 8 |
+
gen_file = "infer/examples/multi/story.txt"
|
| 9 |
+
remove_silence = true
|
| 10 |
+
output_dir = "tests"
|
| 11 |
+
output_file = "infer_cli_story.wav"
|
| 12 |
+
|
| 13 |
+
[voices.town]
|
| 14 |
+
ref_audio = "infer/examples/multi/town.flac"
|
| 15 |
+
ref_text = ""
|
| 16 |
+
|
| 17 |
+
[voices.country]
|
| 18 |
+
ref_audio = "infer/examples/multi/country.flac"
|
| 19 |
+
ref_text = ""
|
| 20 |
+
|
deployment/src/f5_tts/infer/examples/multi/story.txt
ADDED
|
@@ -0,0 +1 @@
|
|
|
|
|
|
|
| 1 |
+
A Town Mouse and a Country Mouse were acquaintances, and the Country Mouse one day invited his friend to come and see him at his home in the fields. The Town Mouse came, and they sat down to a dinner of barleycorns and roots, the latter of which had a distinctly earthy flavour. The fare was not much to the taste of the guest, and presently he broke out with [town] “My poor dear friend, you live here no better than the ants. Now, you should just see how I fare! My larder is a regular horn of plenty. You must come and stay with me, and I promise you you shall live on the fat of the land.” [main] So when he returned to town he took the Country Mouse with him, and showed him into a larder containing flour and oatmeal and figs and honey and dates. The Country Mouse had never seen anything like it, and sat down to enjoy the luxuries his friend provided: but before they had well begun, the door of the larder opened and someone came in. The two Mice scampered off and hid themselves in a narrow and exceedingly uncomfortable hole. Presently, when all was quiet, they ventured out again; but someone else came in, and off they scuttled again. This was too much for the visitor. [country] “Goodbye,” [main] said he, [country] “I’m off. You live in the lap of luxury, I can see, but you are surrounded by dangers; whereas at home I can enjoy my simple dinner of roots and corn in peace.”
|
deployment/src/f5_tts/infer/examples/multi/town.flac
ADDED
|
@@ -0,0 +1,3 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
version https://git-lfs.github.com/spec/v1
|
| 2 |
+
oid sha256:e7d069b8ebd5180c3b30fde5d378f0a1ddac96722d62cf43537efc3c3f3a3ce8
|
| 3 |
+
size 229383
|
deployment/src/f5_tts/infer/examples/thai_examples/ref_gen_1.wav
ADDED
|
@@ -0,0 +1,3 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
version https://git-lfs.github.com/spec/v1
|
| 2 |
+
oid sha256:0012dc98101ec049fb2ff8e644984a1cc92c43b31327324354ed0089e31f6847
|
| 3 |
+
size 376844
|
deployment/src/f5_tts/infer/examples/thai_examples/ref_gen_2.wav
ADDED
|
@@ -0,0 +1,3 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
version https://git-lfs.github.com/spec/v1
|
| 2 |
+
oid sha256:f2786aa1c286b572a046a8cc69e6fc5657e0367c69c2c02912b54803fa369f08
|
| 3 |
+
size 386802
|
deployment/src/f5_tts/infer/examples/thai_examples/ref_gen_3.wav
ADDED
|
@@ -0,0 +1,3 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
version https://git-lfs.github.com/spec/v1
|
| 2 |
+
oid sha256:2d4c32a6fe2db670030bfa0280f307e1fa370ac33e10ded60cc44c72da452930
|
| 3 |
+
size 494282
|
deployment/src/f5_tts/infer/examples/thai_examples/ref_gen_4.wav
ADDED
|
@@ -0,0 +1,3 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
version https://git-lfs.github.com/spec/v1
|
| 2 |
+
oid sha256:da5c6c828b02e966d22c5014d523e2af0879bf5baa41ae1361361741eea5ad20
|
| 3 |
+
size 195884
|