Plana-Archive commited on
Commit
08c1bd7
·
verified ·
1 Parent(s): 8da57f0

Upload folder using huggingface_hub

Browse files
This view is limited to 50 files because it contains too many changes.   See raw diff
Files changed (50) hide show
  1. .gitattributes +74 -0
  2. BanG-Dream-VITS/.gitattributes +110 -0
  3. BanG-Dream-VITS/.pre-commit-config.yaml +25 -0
  4. BanG-Dream-VITS/BANNER.PNG +3 -0
  5. BanG-Dream-VITS/LICENSE +661 -0
  6. BanG-Dream-VITS/README.md +15 -0
  7. BanG-Dream-VITS/app.py +329 -0
  8. BanG-Dream-VITS/app.py (Cadangan utama) +260 -0
  9. BanG-Dream-VITS/attentions.py +464 -0
  10. BanG-Dream-VITS/attentions_onnx.py +378 -0
  11. BanG-Dream-VITS/ave-mujica-avemuji.gif +3 -0
  12. BanG-Dream-VITS/bert_gen.py +81 -0
  13. BanG-Dream-VITS/clap_gen.py +64 -0
  14. BanG-Dream-VITS/clap_wrapper.py +49 -0
  15. BanG-Dream-VITS/classify.py +180 -0
  16. BanG-Dream-VITS/cleaner.py +31 -0
  17. BanG-Dream-VITS/commons.py +158 -0
  18. BanG-Dream-VITS/compress_model.py +89 -0
  19. BanG-Dream-VITS/config.py +248 -0
  20. BanG-Dream-VITS/config.yml +177 -0
  21. BanG-Dream-VITS/configs/config.json +957 -0
  22. BanG-Dream-VITS/css/custom.css +18 -0
  23. BanG-Dream-VITS/data_utils.py +404 -0
  24. BanG-Dream-VITS/default_config.yml +177 -0
  25. BanG-Dream-VITS/emo_gen.py +174 -0
  26. BanG-Dream-VITS/empty_emo.npy +3 -0
  27. BanG-Dream-VITS/export_onnx.py +14 -0
  28. BanG-Dream-VITS/filelists/Mygo.list +0 -0
  29. BanG-Dream-VITS/filelists/Mygo.list.cleaned +0 -0
  30. BanG-Dream-VITS/filelists/esd.list +3 -0
  31. BanG-Dream-VITS/filelists/sample.list +3 -0
  32. BanG-Dream-VITS/filelists/train.list +0 -0
  33. BanG-Dream-VITS/filelists/val.list +8 -0
  34. BanG-Dream-VITS/hiyoriUI.py +725 -0
  35. BanG-Dream-VITS/image/あこ.png +3 -0
  36. BanG-Dream-VITS/image/こころ.png +3 -0
  37. BanG-Dream-VITS/image/そよ.png +3 -0
  38. BanG-Dream-VITS/image/たえ.png +3 -0
  39. BanG-Dream-VITS/image/つくし.png +3 -0
  40. BanG-Dream-VITS/image/つぐみ.png +3 -0
  41. BanG-Dream-VITS/image/にゃむ.png +3 -0
  42. BanG-Dream-VITS/image/はぐみ.png +3 -0
  43. BanG-Dream-VITS/image/ひまり.png +3 -0
  44. BanG-Dream-VITS/image/ましろ.png +3 -0
  45. BanG-Dream-VITS/image//343/201/276/343/201/231/343/201/215.png +0 -0
  46. BanG-Dream-VITS/image/りみ.png +3 -0
  47. BanG-Dream-VITS/image/イヴ.png +3 -0
  48. BanG-Dream-VITS/image/チュチュ.png +3 -0
  49. BanG-Dream-VITS/image/パレオ.png +3 -0
  50. BanG-Dream-VITS/image//343/203/236/343/202/271/343/202/255/343/203/263/343/202/260.png +0 -0
.gitattributes CHANGED
@@ -60,3 +60,77 @@ lyric-generator-ja/frontend/public/font/materialdesignicons-webfont.ttf filter=l
60
  lyric-generator-ja/frontend/public/font/materialdesignicons-webfont.woff filter=lfs diff=lfs merge=lfs -text
61
  lyric-generator-ja/frontend/public/font/materialdesignicons-webfont.woff2 filter=lfs diff=lfs merge=lfs -text
62
  lyric-generator-ja/frontend/public/font/materialdesignicons-webfont_ie.eot filter=lfs diff=lfs merge=lfs -text
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
60
  lyric-generator-ja/frontend/public/font/materialdesignicons-webfont.woff filter=lfs diff=lfs merge=lfs -text
61
  lyric-generator-ja/frontend/public/font/materialdesignicons-webfont.woff2 filter=lfs diff=lfs merge=lfs -text
62
  lyric-generator-ja/frontend/public/font/materialdesignicons-webfont_ie.eot filter=lfs diff=lfs merge=lfs -text
63
+ BanG-Dream-VITS/BANNER.PNG filter=lfs diff=lfs merge=lfs -text
64
+ BanG-Dream-VITS/ave-mujica-avemuji.gif filter=lfs diff=lfs merge=lfs -text
65
+ BanG-Dream-VITS/image/あこ.png filter=lfs diff=lfs merge=lfs -text
66
+ BanG-Dream-VITS/image/こころ.png filter=lfs diff=lfs merge=lfs -text
67
+ BanG-Dream-VITS/image/そよ.png filter=lfs diff=lfs merge=lfs -text
68
+ BanG-Dream-VITS/image/たえ.png filter=lfs diff=lfs merge=lfs -text
69
+ BanG-Dream-VITS/image/つくし.png filter=lfs diff=lfs merge=lfs -text
70
+ BanG-Dream-VITS/image/つぐみ.png filter=lfs diff=lfs merge=lfs -text
71
+ BanG-Dream-VITS/image/にゃむ.png filter=lfs diff=lfs merge=lfs -text
72
+ BanG-Dream-VITS/image/はぐみ.png filter=lfs diff=lfs merge=lfs -text
73
+ BanG-Dream-VITS/image/ひまり.png filter=lfs diff=lfs merge=lfs -text
74
+ BanG-Dream-VITS/image/ましろ.png filter=lfs diff=lfs merge=lfs -text
75
+ BanG-Dream-VITS/image/りみ.png filter=lfs diff=lfs merge=lfs -text
76
+ BanG-Dream-VITS/image/イヴ.png filter=lfs diff=lfs merge=lfs -text
77
+ BanG-Dream-VITS/image/チュチュ.png filter=lfs diff=lfs merge=lfs -text
78
+ BanG-Dream-VITS/image/パレオ.png filter=lfs diff=lfs merge=lfs -text
79
+ BanG-Dream-VITS/image/モカ.png filter=lfs diff=lfs merge=lfs -text
80
+ BanG-Dream-VITS/image/リサ.png filter=lfs diff=lfs merge=lfs -text
81
+ BanG-Dream-VITS/image/レイヤ.png filter=lfs diff=lfs merge=lfs -text
82
+ BanG-Dream-VITS/image/ロック.png filter=lfs diff=lfs merge=lfs -text
83
+ BanG-Dream-VITS/image/一愛.png filter=lfs diff=lfs merge=lfs -text
84
+ BanG-Dream-VITS/image/七深.png filter=lfs diff=lfs merge=lfs -text
85
+ BanG-Dream-VITS/image/光.png filter=lfs diff=lfs merge=lfs -text
86
+ BanG-Dream-VITS/image/克洛迪娜.png filter=lfs diff=lfs merge=lfs -text
87
+ BanG-Dream-VITS/image/初華.png filter=lfs diff=lfs merge=lfs -text
88
+ BanG-Dream-VITS/image/千聖.png filter=lfs diff=lfs merge=lfs -text
89
+ BanG-Dream-VITS/image/友希那.png filter=lfs diff=lfs merge=lfs -text
90
+ BanG-Dream-VITS/image/司.png filter=lfs diff=lfs merge=lfs -text
91
+ BanG-Dream-VITS/image/壘.png filter=lfs diff=lfs merge=lfs -text
92
+ BanG-Dream-VITS/image/奈奈.png filter=lfs diff=lfs merge=lfs -text
93
+ BanG-Dream-VITS/image/彩.png filter=lfs diff=lfs merge=lfs -text
94
+ BanG-Dream-VITS/image/愛音.png filter=lfs diff=lfs merge=lfs -text
95
+ BanG-Dream-VITS/image/文.png filter=lfs diff=lfs merge=lfs -text
96
+ BanG-Dream-VITS/image/日菜.png filter=lfs diff=lfs merge=lfs -text
97
+ BanG-Dream-VITS/image/晶.png filter=lfs diff=lfs merge=lfs -text
98
+ BanG-Dream-VITS/image/有咲.png filter=lfs diff=lfs merge=lfs -text
99
+ BanG-Dream-VITS/image/未知留.png filter=lfs diff=lfs merge=lfs -text
100
+ BanG-Dream-VITS/image/栞.png filter=lfs diff=lfs merge=lfs -text
101
+ BanG-Dream-VITS/image/楽奈.png filter=lfs diff=lfs merge=lfs -text
102
+ BanG-Dream-VITS/image/沙綾.png filter=lfs diff=lfs merge=lfs -text
103
+ BanG-Dream-VITS/image/海鈴.png filter=lfs diff=lfs merge=lfs -text
104
+ BanG-Dream-VITS/image/燈.png filter=lfs diff=lfs merge=lfs -text
105
+ BanG-Dream-VITS/image/燐子.png filter=lfs diff=lfs merge=lfs -text
106
+ BanG-Dream-VITS/image/珠緒.png filter=lfs diff=lfs merge=lfs -text
107
+ BanG-Dream-VITS/image/真晝.png filter=lfs diff=lfs merge=lfs -text
108
+ BanG-Dream-VITS/image/真矢.png filter=lfs diff=lfs merge=lfs -text
109
+ BanG-Dream-VITS/image/睦.png filter=lfs diff=lfs merge=lfs -text
110
+ BanG-Dream-VITS/image/祥子.png filter=lfs diff=lfs merge=lfs -text
111
+ BanG-Dream-VITS/image/立希.png filter=lfs diff=lfs merge=lfs -text
112
+ BanG-Dream-VITS/image/純那.png filter=lfs diff=lfs merge=lfs -text
113
+ BanG-Dream-VITS/image/紗夜.png filter=lfs diff=lfs merge=lfs -text
114
+ BanG-Dream-VITS/image/美咲.png filter=lfs diff=lfs merge=lfs -text
115
+ BanG-Dream-VITS/image/美帆.png filter=lfs diff=lfs merge=lfs -text
116
+ BanG-Dream-VITS/image/美空.png filter=lfs diff=lfs merge=lfs -text
117
+ BanG-Dream-VITS/image/艾露.png filter=lfs diff=lfs merge=lfs -text
118
+ BanG-Dream-VITS/image/艾露露.png filter=lfs diff=lfs merge=lfs -text
119
+ BanG-Dream-VITS/image/花音.png filter=lfs diff=lfs merge=lfs -text
120
+ BanG-Dream-VITS/image/菈樂菲.png filter=lfs diff=lfs merge=lfs -text
121
+ BanG-Dream-VITS/image/華戀.png filter=lfs diff=lfs merge=lfs -text
122
+ BanG-Dream-VITS/image/薫.png filter=lfs diff=lfs merge=lfs -text
123
+ BanG-Dream-VITS/image/蘭.png filter=lfs diff=lfs merge=lfs -text
124
+ BanG-Dream-VITS/image/透子.png filter=lfs diff=lfs merge=lfs -text
125
+ BanG-Dream-VITS/image/雙葉.png filter=lfs diff=lfs merge=lfs -text
126
+ BanG-Dream-VITS/image/靜羽.png filter=lfs diff=lfs merge=lfs -text
127
+ BanG-Dream-VITS/image/香子.png filter=lfs diff=lfs merge=lfs -text
128
+ BanG-Dream-VITS/image/香澄.png filter=lfs diff=lfs merge=lfs -text
129
+ BanG-Dream-VITS/image/麻弥.png filter=lfs diff=lfs merge=lfs -text
130
+ BanG-Dream-VITS/img/yuyu.png filter=lfs diff=lfs merge=lfs -text
131
+ BanG-Dream-VITS/img/参数说明.png filter=lfs diff=lfs merge=lfs -text
132
+ BanG-Dream-VITS/img/宵宫.png filter=lfs diff=lfs merge=lfs -text
133
+ BanG-Dream-VITS/img/微信图片_20231010105112.png filter=lfs diff=lfs merge=lfs -text
134
+ BanG-Dream-VITS/img/神里绫华.png filter=lfs diff=lfs merge=lfs -text
135
+ BanG-Dream-VITS/img/纳西妲.png filter=lfs diff=lfs merge=lfs -text
136
+ BanG-Dream-VITS/temp.wav filter=lfs diff=lfs merge=lfs -text
BanG-Dream-VITS/.gitattributes ADDED
@@ -0,0 +1,110 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ *.7z filter=lfs diff=lfs merge=lfs -text
2
+ *.arrow filter=lfs diff=lfs merge=lfs -text
3
+ *.bin filter=lfs diff=lfs merge=lfs -text
4
+ *.bz2 filter=lfs diff=lfs merge=lfs -text
5
+ *.ckpt filter=lfs diff=lfs merge=lfs -text
6
+ *.ftz filter=lfs diff=lfs merge=lfs -text
7
+ *.gz filter=lfs diff=lfs merge=lfs -text
8
+ *.h5 filter=lfs diff=lfs merge=lfs -text
9
+ *.joblib filter=lfs diff=lfs merge=lfs -text
10
+ *.lfs.* filter=lfs diff=lfs merge=lfs -text
11
+ *.mlmodel filter=lfs diff=lfs merge=lfs -text
12
+ *.model filter=lfs diff=lfs merge=lfs -text
13
+ *.msgpack filter=lfs diff=lfs merge=lfs -text
14
+ *.npy filter=lfs diff=lfs merge=lfs -text
15
+ *.npz filter=lfs diff=lfs merge=lfs -text
16
+ *.onnx filter=lfs diff=lfs merge=lfs -text
17
+ *.ot filter=lfs diff=lfs merge=lfs -text
18
+ *.parquet filter=lfs diff=lfs merge=lfs -text
19
+ *.pb filter=lfs diff=lfs merge=lfs -text
20
+ *.pickle filter=lfs diff=lfs merge=lfs -text
21
+ *.pkl filter=lfs diff=lfs merge=lfs -text
22
+ *.pt filter=lfs diff=lfs merge=lfs -text
23
+ *.pth filter=lfs diff=lfs merge=lfs -text
24
+ *.rar filter=lfs diff=lfs merge=lfs -text
25
+ *.safetensors filter=lfs diff=lfs merge=lfs -text
26
+ saved_model/**/* filter=lfs diff=lfs merge=lfs -text
27
+ *.tar.* filter=lfs diff=lfs merge=lfs -text
28
+ *.tar filter=lfs diff=lfs merge=lfs -text
29
+ *.tflite filter=lfs diff=lfs merge=lfs -text
30
+ *.tgz filter=lfs diff=lfs merge=lfs -text
31
+ *.wasm filter=lfs diff=lfs merge=lfs -text
32
+ *.xz filter=lfs diff=lfs merge=lfs -text
33
+ *.zip filter=lfs diff=lfs merge=lfs -text
34
+ *.zst filter=lfs diff=lfs merge=lfs -text
35
+ *tfevents* filter=lfs diff=lfs merge=lfs -text
36
+ image/あこ.png filter=lfs diff=lfs merge=lfs -text
37
+ image/こころ.png filter=lfs diff=lfs merge=lfs -text
38
+ image/そよ.png filter=lfs diff=lfs merge=lfs -text
39
+ image/たえ.png filter=lfs diff=lfs merge=lfs -text
40
+ image/つくし.png filter=lfs diff=lfs merge=lfs -text
41
+ image/つぐみ.png filter=lfs diff=lfs merge=lfs -text
42
+ image/にゃむ.png filter=lfs diff=lfs merge=lfs -text
43
+ image/はぐみ.png filter=lfs diff=lfs merge=lfs -text
44
+ image/ひまり.png filter=lfs diff=lfs merge=lfs -text
45
+ image/ましろ.png filter=lfs diff=lfs merge=lfs -text
46
+ image/りみ.png filter=lfs diff=lfs merge=lfs -text
47
+ image/イヴ.png filter=lfs diff=lfs merge=lfs -text
48
+ image/チュチュ.png filter=lfs diff=lfs merge=lfs -text
49
+ image/パレオ.png filter=lfs diff=lfs merge=lfs -text
50
+ image/モカ.png filter=lfs diff=lfs merge=lfs -text
51
+ image/リサ.png filter=lfs diff=lfs merge=lfs -text
52
+ image/レイヤ.png filter=lfs diff=lfs merge=lfs -text
53
+ image/ロック.png filter=lfs diff=lfs merge=lfs -text
54
+ image/一愛.png filter=lfs diff=lfs merge=lfs -text
55
+ image/七深.png filter=lfs diff=lfs merge=lfs -text
56
+ image/光.png filter=lfs diff=lfs merge=lfs -text
57
+ image/克洛迪娜.png filter=lfs diff=lfs merge=lfs -text
58
+ image/初華.png filter=lfs diff=lfs merge=lfs -text
59
+ image/千聖.png filter=lfs diff=lfs merge=lfs -text
60
+ image/友希那.png filter=lfs diff=lfs merge=lfs -text
61
+ image/司.png filter=lfs diff=lfs merge=lfs -text
62
+ image/壘.png filter=lfs diff=lfs merge=lfs -text
63
+ image/奈奈.png filter=lfs diff=lfs merge=lfs -text
64
+ image/彩.png filter=lfs diff=lfs merge=lfs -text
65
+ image/愛音.png filter=lfs diff=lfs merge=lfs -text
66
+ image/文.png filter=lfs diff=lfs merge=lfs -text
67
+ image/日菜.png filter=lfs diff=lfs merge=lfs -text
68
+ image/晶.png filter=lfs diff=lfs merge=lfs -text
69
+ image/有咲.png filter=lfs diff=lfs merge=lfs -text
70
+ image/未知留.png filter=lfs diff=lfs merge=lfs -text
71
+ image/栞.png filter=lfs diff=lfs merge=lfs -text
72
+ image/楽奈.png filter=lfs diff=lfs merge=lfs -text
73
+ image/沙綾.png filter=lfs diff=lfs merge=lfs -text
74
+ image/海鈴.png filter=lfs diff=lfs merge=lfs -text
75
+ image/燈.png filter=lfs diff=lfs merge=lfs -text
76
+ image/燐子.png filter=lfs diff=lfs merge=lfs -text
77
+ image/珠緒.png filter=lfs diff=lfs merge=lfs -text
78
+ image/真晝.png filter=lfs diff=lfs merge=lfs -text
79
+ image/真矢.png filter=lfs diff=lfs merge=lfs -text
80
+ image/睦.png filter=lfs diff=lfs merge=lfs -text
81
+ image/祥子.png filter=lfs diff=lfs merge=lfs -text
82
+ image/立希.png filter=lfs diff=lfs merge=lfs -text
83
+ image/純那.png filter=lfs diff=lfs merge=lfs -text
84
+ image/紗夜.png filter=lfs diff=lfs merge=lfs -text
85
+ image/美咲.png filter=lfs diff=lfs merge=lfs -text
86
+ image/美帆.png filter=lfs diff=lfs merge=lfs -text
87
+ image/美空.png filter=lfs diff=lfs merge=lfs -text
88
+ image/艾露.png filter=lfs diff=lfs merge=lfs -text
89
+ image/艾露露.png filter=lfs diff=lfs merge=lfs -text
90
+ image/花音.png filter=lfs diff=lfs merge=lfs -text
91
+ image/菈樂菲.png filter=lfs diff=lfs merge=lfs -text
92
+ image/華戀.png filter=lfs diff=lfs merge=lfs -text
93
+ image/薫.png filter=lfs diff=lfs merge=lfs -text
94
+ image/蘭.png filter=lfs diff=lfs merge=lfs -text
95
+ image/透子.png filter=lfs diff=lfs merge=lfs -text
96
+ image/雙葉.png filter=lfs diff=lfs merge=lfs -text
97
+ image/靜羽.png filter=lfs diff=lfs merge=lfs -text
98
+ image/香子.png filter=lfs diff=lfs merge=lfs -text
99
+ image/香澄.png filter=lfs diff=lfs merge=lfs -text
100
+ image/麻弥.png filter=lfs diff=lfs merge=lfs -text
101
+ img/yuyu.png filter=lfs diff=lfs merge=lfs -text
102
+ img/参数说明.png filter=lfs diff=lfs merge=lfs -text
103
+ img/宵宫.png filter=lfs diff=lfs merge=lfs -text
104
+ img/微信图片_20231010105112.png filter=lfs diff=lfs merge=lfs -text
105
+ img/神里绫华.png filter=lfs diff=lfs merge=lfs -text
106
+ img/纳西妲.png filter=lfs diff=lfs merge=lfs -text
107
+ temp.wav filter=lfs diff=lfs merge=lfs -text
108
+ ave-mujica-avemuji.gif filter=lfs diff=lfs merge=lfs -text
109
+ d16ca6d1c911d68e1c6a998d893356f4.jpg filter=lfs diff=lfs merge=lfs -text
110
+ BANNER.PNG filter=lfs diff=lfs merge=lfs -text
BanG-Dream-VITS/.pre-commit-config.yaml ADDED
@@ -0,0 +1,25 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ repos:
2
+ - repo: https://github.com/pre-commit/pre-commit-hooks
3
+ rev: v4.5.0
4
+ hooks:
5
+ - id: check-yaml
6
+ - id: end-of-file-fixer
7
+ - id: trailing-whitespace
8
+
9
+ - repo: https://github.com/astral-sh/ruff-pre-commit
10
+ rev: v0.1.7
11
+ hooks:
12
+ - id: ruff
13
+ args: [ --fix ]
14
+
15
+ - repo: https://github.com/psf/black
16
+ rev: 23.11.0
17
+ hooks:
18
+ - id: black
19
+
20
+ - repo: https://github.com/codespell-project/codespell
21
+ rev: v2.2.6
22
+ hooks:
23
+ - id: codespell
24
+ files: ^.*\.(py|md|rst|yml)$
25
+ args: [-L=fro]
BanG-Dream-VITS/BANNER.PNG ADDED

Git LFS Details

  • SHA256: ad776993cc1ac4b4e6ada9f873ac1b20b42bd36757d5ac521d7151b0ab902a18
  • Pointer size: 131 Bytes
  • Size of remote file: 178 kB
BanG-Dream-VITS/LICENSE ADDED
@@ -0,0 +1,661 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ GNU AFFERO GENERAL PUBLIC LICENSE
2
+ Version 3, 19 November 2007
3
+
4
+ Copyright (C) 2007 Free Software Foundation, Inc. <https://fsf.org/>
5
+ Everyone is permitted to copy and distribute verbatim copies
6
+ of this license document, but changing it is not allowed.
7
+
8
+ Preamble
9
+
10
+ The GNU Affero General Public License is a free, copyleft license for
11
+ software and other kinds of works, specifically designed to ensure
12
+ cooperation with the community in the case of network server software.
13
+
14
+ The licenses for most software and other practical works are designed
15
+ to take away your freedom to share and change the works. By contrast,
16
+ our General Public Licenses are intended to guarantee your freedom to
17
+ share and change all versions of a program--to make sure it remains free
18
+ software for all its users.
19
+
20
+ When we speak of free software, we are referring to freedom, not
21
+ price. Our General Public Licenses are designed to make sure that you
22
+ have the freedom to distribute copies of free software (and charge for
23
+ them if you wish), that you receive source code or can get it if you
24
+ want it, that you can change the software or use pieces of it in new
25
+ free programs, and that you know you can do these things.
26
+
27
+ Developers that use our General Public Licenses protect your rights
28
+ with two steps: (1) assert copyright on the software, and (2) offer
29
+ you this License which gives you legal permission to copy, distribute
30
+ and/or modify the software.
31
+
32
+ A secondary benefit of defending all users' freedom is that
33
+ improvements made in alternate versions of the program, if they
34
+ receive widespread use, become available for other developers to
35
+ incorporate. Many developers of free software are heartened and
36
+ encouraged by the resulting cooperation. However, in the case of
37
+ software used on network servers, this result may fail to come about.
38
+ The GNU General Public License permits making a modified version and
39
+ letting the public access it on a server without ever releasing its
40
+ source code to the public.
41
+
42
+ The GNU Affero General Public License is designed specifically to
43
+ ensure that, in such cases, the modified source code becomes available
44
+ to the community. It requires the operator of a network server to
45
+ provide the source code of the modified version running there to the
46
+ users of that server. Therefore, public use of a modified version, on
47
+ a publicly accessible server, gives the public access to the source
48
+ code of the modified version.
49
+
50
+ An older license, called the Affero General Public License and
51
+ published by Affero, was designed to accomplish similar goals. This is
52
+ a different license, not a version of the Affero GPL, but Affero has
53
+ released a new version of the Affero GPL which permits relicensing under
54
+ this license.
55
+
56
+ The precise terms and conditions for copying, distribution and
57
+ modification follow.
58
+
59
+ TERMS AND CONDITIONS
60
+
61
+ 0. Definitions.
62
+
63
+ "This License" refers to version 3 of the GNU Affero General Public License.
64
+
65
+ "Copyright" also means copyright-like laws that apply to other kinds of
66
+ works, such as semiconductor masks.
67
+
68
+ "The Program" refers to any copyrightable work licensed under this
69
+ License. Each licensee is addressed as "you". "Licensees" and
70
+ "recipients" may be individuals or organizations.
71
+
72
+ To "modify" a work means to copy from or adapt all or part of the work
73
+ in a fashion requiring copyright permission, other than the making of an
74
+ exact copy. The resulting work is called a "modified version" of the
75
+ earlier work or a work "based on" the earlier work.
76
+
77
+ A "covered work" means either the unmodified Program or a work based
78
+ on the Program.
79
+
80
+ To "propagate" a work means to do anything with it that, without
81
+ permission, would make you directly or secondarily liable for
82
+ infringement under applicable copyright law, except executing it on a
83
+ computer or modifying a private copy. Propagation includes copying,
84
+ distribution (with or without modification), making available to the
85
+ public, and in some countries other activities as well.
86
+
87
+ To "convey" a work means any kind of propagation that enables other
88
+ parties to make or receive copies. Mere interaction with a user through
89
+ a computer network, with no transfer of a copy, is not conveying.
90
+
91
+ An interactive user interface displays "Appropriate Legal Notices"
92
+ to the extent that it includes a convenient and prominently visible
93
+ feature that (1) displays an appropriate copyright notice, and (2)
94
+ tells the user that there is no warranty for the work (except to the
95
+ extent that warranties are provided), that licensees may convey the
96
+ work under this License, and how to view a copy of this License. If
97
+ the interface presents a list of user commands or options, such as a
98
+ menu, a prominent item in the list meets this criterion.
99
+
100
+ 1. Source Code.
101
+
102
+ The "source code" for a work means the preferred form of the work
103
+ for making modifications to it. "Object code" means any non-source
104
+ form of a work.
105
+
106
+ A "Standard Interface" means an interface that either is an official
107
+ standard defined by a recognized standards body, or, in the case of
108
+ interfaces specified for a particular programming language, one that
109
+ is widely used among developers working in that language.
110
+
111
+ The "System Libraries" of an executable work include anything, other
112
+ than the work as a whole, that (a) is included in the normal form of
113
+ packaging a Major Component, but which is not part of that Major
114
+ Component, and (b) serves only to enable use of the work with that
115
+ Major Component, or to implement a Standard Interface for which an
116
+ implementation is available to the public in source code form. A
117
+ "Major Component", in this context, means a major essential component
118
+ (kernel, window system, and so on) of the specific operating system
119
+ (if any) on which the executable work runs, or a compiler used to
120
+ produce the work, or an object code interpreter used to run it.
121
+
122
+ The "Corresponding Source" for a work in object code form means all
123
+ the source code needed to generate, install, and (for an executable
124
+ work) run the object code and to modify the work, including scripts to
125
+ control those activities. However, it does not include the work's
126
+ System Libraries, or general-purpose tools or generally available free
127
+ programs which are used unmodified in performing those activities but
128
+ which are not part of the work. For example, Corresponding Source
129
+ includes interface definition files associated with source files for
130
+ the work, and the source code for shared libraries and dynamically
131
+ linked subprograms that the work is specifically designed to require,
132
+ such as by intimate data communication or control flow between those
133
+ subprograms and other parts of the work.
134
+
135
+ The Corresponding Source need not include anything that users
136
+ can regenerate automatically from other parts of the Corresponding
137
+ Source.
138
+
139
+ The Corresponding Source for a work in source code form is that
140
+ same work.
141
+
142
+ 2. Basic Permissions.
143
+
144
+ All rights granted under this License are granted for the term of
145
+ copyright on the Program, and are irrevocable provided the stated
146
+ conditions are met. This License explicitly affirms your unlimited
147
+ permission to run the unmodified Program. The output from running a
148
+ covered work is covered by this License only if the output, given its
149
+ content, constitutes a covered work. This License acknowledges your
150
+ rights of fair use or other equivalent, as provided by copyright law.
151
+
152
+ You may make, run and propagate covered works that you do not
153
+ convey, without conditions so long as your license otherwise remains
154
+ in force. You may convey covered works to others for the sole purpose
155
+ of having them make modifications exclusively for you, or provide you
156
+ with facilities for running those works, provided that you comply with
157
+ the terms of this License in conveying all material for which you do
158
+ not control copyright. Those thus making or running the covered works
159
+ for you must do so exclusively on your behalf, under your direction
160
+ and control, on terms that prohibit them from making any copies of
161
+ your copyrighted material outside their relationship with you.
162
+
163
+ Conveying under any other circumstances is permitted solely under
164
+ the conditions stated below. Sublicensing is not allowed; section 10
165
+ makes it unnecessary.
166
+
167
+ 3. Protecting Users' Legal Rights From Anti-Circumvention Law.
168
+
169
+ No covered work shall be deemed part of an effective technological
170
+ measure under any applicable law fulfilling obligations under article
171
+ 11 of the WIPO copyright treaty adopted on 20 December 1996, or
172
+ similar laws prohibiting or restricting circumvention of such
173
+ measures.
174
+
175
+ When you convey a covered work, you waive any legal power to forbid
176
+ circumvention of technological measures to the extent such circumvention
177
+ is effected by exercising rights under this License with respect to
178
+ the covered work, and you disclaim any intention to limit operation or
179
+ modification of the work as a means of enforcing, against the work's
180
+ users, your or third parties' legal rights to forbid circumvention of
181
+ technological measures.
182
+
183
+ 4. Conveying Verbatim Copies.
184
+
185
+ You may convey verbatim copies of the Program's source code as you
186
+ receive it, in any medium, provided that you conspicuously and
187
+ appropriately publish on each copy an appropriate copyright notice;
188
+ keep intact all notices stating that this License and any
189
+ non-permissive terms added in accord with section 7 apply to the code;
190
+ keep intact all notices of the absence of any warranty; and give all
191
+ recipients a copy of this License along with the Program.
192
+
193
+ You may charge any price or no price for each copy that you convey,
194
+ and you may offer support or warranty protection for a fee.
195
+
196
+ 5. Conveying Modified Source Versions.
197
+
198
+ You may convey a work based on the Program, or the modifications to
199
+ produce it from the Program, in the form of source code under the
200
+ terms of section 4, provided that you also meet all of these conditions:
201
+
202
+ a) The work must carry prominent notices stating that you modified
203
+ it, and giving a relevant date.
204
+
205
+ b) The work must carry prominent notices stating that it is
206
+ released under this License and any conditions added under section
207
+ 7. This requirement modifies the requirement in section 4 to
208
+ "keep intact all notices".
209
+
210
+ c) You must license the entire work, as a whole, under this
211
+ License to anyone who comes into possession of a copy. This
212
+ License will therefore apply, along with any applicable section 7
213
+ additional terms, to the whole of the work, and all its parts,
214
+ regardless of how they are packaged. This License gives no
215
+ permission to license the work in any other way, but it does not
216
+ invalidate such permission if you have separately received it.
217
+
218
+ d) If the work has interactive user interfaces, each must display
219
+ Appropriate Legal Notices; however, if the Program has interactive
220
+ interfaces that do not display Appropriate Legal Notices, your
221
+ work need not make them do so.
222
+
223
+ A compilation of a covered work with other separate and independent
224
+ works, which are not by their nature extensions of the covered work,
225
+ and which are not combined with it such as to form a larger program,
226
+ in or on a volume of a storage or distribution medium, is called an
227
+ "aggregate" if the compilation and its resulting copyright are not
228
+ used to limit the access or legal rights of the compilation's users
229
+ beyond what the individual works permit. Inclusion of a covered work
230
+ in an aggregate does not cause this License to apply to the other
231
+ parts of the aggregate.
232
+
233
+ 6. Conveying Non-Source Forms.
234
+
235
+ You may convey a covered work in object code form under the terms
236
+ of sections 4 and 5, provided that you also convey the
237
+ machine-readable Corresponding Source under the terms of this License,
238
+ in one of these ways:
239
+
240
+ a) Convey the object code in, or embodied in, a physical product
241
+ (including a physical distribution medium), accompanied by the
242
+ Corresponding Source fixed on a durable physical medium
243
+ customarily used for software interchange.
244
+
245
+ b) Convey the object code in, or embodied in, a physical product
246
+ (including a physical distribution medium), accompanied by a
247
+ written offer, valid for at least three years and valid for as
248
+ long as you offer spare parts or customer support for that product
249
+ model, to give anyone who possesses the object code either (1) a
250
+ copy of the Corresponding Source for all the software in the
251
+ product that is covered by this License, on a durable physical
252
+ medium customarily used for software interchange, for a price no
253
+ more than your reasonable cost of physically performing this
254
+ conveying of source, or (2) access to copy the
255
+ Corresponding Source from a network server at no charge.
256
+
257
+ c) Convey individual copies of the object code with a copy of the
258
+ written offer to provide the Corresponding Source. This
259
+ alternative is allowed only occasionally and noncommercially, and
260
+ only if you received the object code with such an offer, in accord
261
+ with subsection 6b.
262
+
263
+ d) Convey the object code by offering access from a designated
264
+ place (gratis or for a charge), and offer equivalent access to the
265
+ Corresponding Source in the same way through the same place at no
266
+ further charge. You need not require recipients to copy the
267
+ Corresponding Source along with the object code. If the place to
268
+ copy the object code is a network server, the Corresponding Source
269
+ may be on a different server (operated by you or a third party)
270
+ that supports equivalent copying facilities, provided you maintain
271
+ clear directions next to the object code saying where to find the
272
+ Corresponding Source. Regardless of what server hosts the
273
+ Corresponding Source, you remain obligated to ensure that it is
274
+ available for as long as needed to satisfy these requirements.
275
+
276
+ e) Convey the object code using peer-to-peer transmission, provided
277
+ you inform other peers where the object code and Corresponding
278
+ Source of the work are being offered to the general public at no
279
+ charge under subsection 6d.
280
+
281
+ A separable portion of the object code, whose source code is excluded
282
+ from the Corresponding Source as a System Library, need not be
283
+ included in conveying the object code work.
284
+
285
+ A "User Product" is either (1) a "consumer product", which means any
286
+ tangible personal property which is normally used for personal, family,
287
+ or household purposes, or (2) anything designed or sold for incorporation
288
+ into a dwelling. In determining whether a product is a consumer product,
289
+ doubtful cases shall be resolved in favor of coverage. For a particular
290
+ product received by a particular user, "normally used" refers to a
291
+ typical or common use of that class of product, regardless of the status
292
+ of the particular user or of the way in which the particular user
293
+ actually uses, or expects or is expected to use, the product. A product
294
+ is a consumer product regardless of whether the product has substantial
295
+ commercial, industrial or non-consumer uses, unless such uses represent
296
+ the only significant mode of use of the product.
297
+
298
+ "Installation Information" for a User Product means any methods,
299
+ procedures, authorization keys, or other information required to install
300
+ and execute modified versions of a covered work in that User Product from
301
+ a modified version of its Corresponding Source. The information must
302
+ suffice to ensure that the continued functioning of the modified object
303
+ code is in no case prevented or interfered with solely because
304
+ modification has been made.
305
+
306
+ If you convey an object code work under this section in, or with, or
307
+ specifically for use in, a User Product, and the conveying occurs as
308
+ part of a transaction in which the right of possession and use of the
309
+ User Product is transferred to the recipient in perpetuity or for a
310
+ fixed term (regardless of how the transaction is characterized), the
311
+ Corresponding Source conveyed under this section must be accompanied
312
+ by the Installation Information. But this requirement does not apply
313
+ if neither you nor any third party retains the ability to install
314
+ modified object code on the User Product (for example, the work has
315
+ been installed in ROM).
316
+
317
+ The requirement to provide Installation Information does not include a
318
+ requirement to continue to provide support service, warranty, or updates
319
+ for a work that has been modified or installed by the recipient, or for
320
+ the User Product in which it has been modified or installed. Access to a
321
+ network may be denied when the modification itself materially and
322
+ adversely affects the operation of the network or violates the rules and
323
+ protocols for communication across the network.
324
+
325
+ Corresponding Source conveyed, and Installation Information provided,
326
+ in accord with this section must be in a format that is publicly
327
+ documented (and with an implementation available to the public in
328
+ source code form), and must require no special password or key for
329
+ unpacking, reading or copying.
330
+
331
+ 7. Additional Terms.
332
+
333
+ "Additional permissions" are terms that supplement the terms of this
334
+ License by making exceptions from one or more of its conditions.
335
+ Additional permissions that are applicable to the entire Program shall
336
+ be treated as though they were included in this License, to the extent
337
+ that they are valid under applicable law. If additional permissions
338
+ apply only to part of the Program, that part may be used separately
339
+ under those permissions, but the entire Program remains governed by
340
+ this License without regard to the additional permissions.
341
+
342
+ When you convey a copy of a covered work, you may at your option
343
+ remove any additional permissions from that copy, or from any part of
344
+ it. (Additional permissions may be written to require their own
345
+ removal in certain cases when you modify the work.) You may place
346
+ additional permissions on material, added by you to a covered work,
347
+ for which you have or can give appropriate copyright permission.
348
+
349
+ Notwithstanding any other provision of this License, for material you
350
+ add to a covered work, you may (if authorized by the copyright holders of
351
+ that material) supplement the terms of this License with terms:
352
+
353
+ a) Disclaiming warranty or limiting liability differently from the
354
+ terms of sections 15 and 16 of this License; or
355
+
356
+ b) Requiring preservation of specified reasonable legal notices or
357
+ author attributions in that material or in the Appropriate Legal
358
+ Notices displayed by works containing it; or
359
+
360
+ c) Prohibiting misrepresentation of the origin of that material, or
361
+ requiring that modified versions of such material be marked in
362
+ reasonable ways as different from the original version; or
363
+
364
+ d) Limiting the use for publicity purposes of names of licensors or
365
+ authors of the material; or
366
+
367
+ e) Declining to grant rights under trademark law for use of some
368
+ trade names, trademarks, or service marks; or
369
+
370
+ f) Requiring indemnification of licensors and authors of that
371
+ material by anyone who conveys the material (or modified versions of
372
+ it) with contractual assumptions of liability to the recipient, for
373
+ any liability that these contractual assumptions directly impose on
374
+ those licensors and authors.
375
+
376
+ All other non-permissive additional terms are considered "further
377
+ restrictions" within the meaning of section 10. If the Program as you
378
+ received it, or any part of it, contains a notice stating that it is
379
+ governed by this License along with a term that is a further
380
+ restriction, you may remove that term. If a license document contains
381
+ a further restriction but permits relicensing or conveying under this
382
+ License, you may add to a covered work material governed by the terms
383
+ of that license document, provided that the further restriction does
384
+ not survive such relicensing or conveying.
385
+
386
+ If you add terms to a covered work in accord with this section, you
387
+ must place, in the relevant source files, a statement of the
388
+ additional terms that apply to those files, or a notice indicating
389
+ where to find the applicable terms.
390
+
391
+ Additional terms, permissive or non-permissive, may be stated in the
392
+ form of a separately written license, or stated as exceptions;
393
+ the above requirements apply either way.
394
+
395
+ 8. Termination.
396
+
397
+ You may not propagate or modify a covered work except as expressly
398
+ provided under this License. Any attempt otherwise to propagate or
399
+ modify it is void, and will automatically terminate your rights under
400
+ this License (including any patent licenses granted under the third
401
+ paragraph of section 11).
402
+
403
+ However, if you cease all violation of this License, then your
404
+ license from a particular copyright holder is reinstated (a)
405
+ provisionally, unless and until the copyright holder explicitly and
406
+ finally terminates your license, and (b) permanently, if the copyright
407
+ holder fails to notify you of the violation by some reasonable means
408
+ prior to 60 days after the cessation.
409
+
410
+ Moreover, your license from a particular copyright holder is
411
+ reinstated permanently if the copyright holder notifies you of the
412
+ violation by some reasonable means, this is the first time you have
413
+ received notice of violation of this License (for any work) from that
414
+ copyright holder, and you cure the violation prior to 30 days after
415
+ your receipt of the notice.
416
+
417
+ Termination of your rights under this section does not terminate the
418
+ licenses of parties who have received copies or rights from you under
419
+ this License. If your rights have been terminated and not permanently
420
+ reinstated, you do not qualify to receive new licenses for the same
421
+ material under section 10.
422
+
423
+ 9. Acceptance Not Required for Having Copies.
424
+
425
+ You are not required to accept this License in order to receive or
426
+ run a copy of the Program. Ancillary propagation of a covered work
427
+ occurring solely as a consequence of using peer-to-peer transmission
428
+ to receive a copy likewise does not require acceptance. However,
429
+ nothing other than this License grants you permission to propagate or
430
+ modify any covered work. These actions infringe copyright if you do
431
+ not accept this License. Therefore, by modifying or propagating a
432
+ covered work, you indicate your acceptance of this License to do so.
433
+
434
+ 10. Automatic Licensing of Downstream Recipients.
435
+
436
+ Each time you convey a covered work, the recipient automatically
437
+ receives a license from the original licensors, to run, modify and
438
+ propagate that work, subject to this License. You are not responsible
439
+ for enforcing compliance by third parties with this License.
440
+
441
+ An "entity transaction" is a transaction transferring control of an
442
+ organization, or substantially all assets of one, or subdividing an
443
+ organization, or merging organizations. If propagation of a covered
444
+ work results from an entity transaction, each party to that
445
+ transaction who receives a copy of the work also receives whatever
446
+ licenses to the work the party's predecessor in interest had or could
447
+ give under the previous paragraph, plus a right to possession of the
448
+ Corresponding Source of the work from the predecessor in interest, if
449
+ the predecessor has it or can get it with reasonable efforts.
450
+
451
+ You may not impose any further restrictions on the exercise of the
452
+ rights granted or affirmed under this License. For example, you may
453
+ not impose a license fee, royalty, or other charge for exercise of
454
+ rights granted under this License, and you may not initiate litigation
455
+ (including a cross-claim or counterclaim in a lawsuit) alleging that
456
+ any patent claim is infringed by making, using, selling, offering for
457
+ sale, or importing the Program or any portion of it.
458
+
459
+ 11. Patents.
460
+
461
+ A "contributor" is a copyright holder who authorizes use under this
462
+ License of the Program or a work on which the Program is based. The
463
+ work thus licensed is called the contributor's "contributor version".
464
+
465
+ A contributor's "essential patent claims" are all patent claims
466
+ owned or controlled by the contributor, whether already acquired or
467
+ hereafter acquired, that would be infringed by some manner, permitted
468
+ by this License, of making, using, or selling its contributor version,
469
+ but do not include claims that would be infringed only as a
470
+ consequence of further modification of the contributor version. For
471
+ purposes of this definition, "control" includes the right to grant
472
+ patent sublicenses in a manner consistent with the requirements of
473
+ this License.
474
+
475
+ Each contributor grants you a non-exclusive, worldwide, royalty-free
476
+ patent license under the contributor's essential patent claims, to
477
+ make, use, sell, offer for sale, import and otherwise run, modify and
478
+ propagate the contents of its contributor version.
479
+
480
+ In the following three paragraphs, a "patent license" is any express
481
+ agreement or commitment, however denominated, not to enforce a patent
482
+ (such as an express permission to practice a patent or covenant not to
483
+ sue for patent infringement). To "grant" such a patent license to a
484
+ party means to make such an agreement or commitment not to enforce a
485
+ patent against the party.
486
+
487
+ If you convey a covered work, knowingly relying on a patent license,
488
+ and the Corresponding Source of the work is not available for anyone
489
+ to copy, free of charge and under the terms of this License, through a
490
+ publicly available network server or other readily accessible means,
491
+ then you must either (1) cause the Corresponding Source to be so
492
+ available, or (2) arrange to deprive yourself of the benefit of the
493
+ patent license for this particular work, or (3) arrange, in a manner
494
+ consistent with the requirements of this License, to extend the patent
495
+ license to downstream recipients. "Knowingly relying" means you have
496
+ actual knowledge that, but for the patent license, your conveying the
497
+ covered work in a country, or your recipient's use of the covered work
498
+ in a country, would infringe one or more identifiable patents in that
499
+ country that you have reason to believe are valid.
500
+
501
+ If, pursuant to or in connection with a single transaction or
502
+ arrangement, you convey, or propagate by procuring conveyance of, a
503
+ covered work, and grant a patent license to some of the parties
504
+ receiving the covered work authorizing them to use, propagate, modify
505
+ or convey a specific copy of the covered work, then the patent license
506
+ you grant is automatically extended to all recipients of the covered
507
+ work and works based on it.
508
+
509
+ A patent license is "discriminatory" if it does not include within
510
+ the scope of its coverage, prohibits the exercise of, or is
511
+ conditioned on the non-exercise of one or more of the rights that are
512
+ specifically granted under this License. You may not convey a covered
513
+ work if you are a party to an arrangement with a third party that is
514
+ in the business of distributing software, under which you make payment
515
+ to the third party based on the extent of your activity of conveying
516
+ the work, and under which the third party grants, to any of the
517
+ parties who would receive the covered work from you, a discriminatory
518
+ patent license (a) in connection with copies of the covered work
519
+ conveyed by you (or copies made from those copies), or (b) primarily
520
+ for and in connection with specific products or compilations that
521
+ contain the covered work, unless you entered into that arrangement,
522
+ or that patent license was granted, prior to 28 March 2007.
523
+
524
+ Nothing in this License shall be construed as excluding or limiting
525
+ any implied license or other defenses to infringement that may
526
+ otherwise be available to you under applicable patent law.
527
+
528
+ 12. No Surrender of Others' Freedom.
529
+
530
+ If conditions are imposed on you (whether by court order, agreement or
531
+ otherwise) that contradict the conditions of this License, they do not
532
+ excuse you from the conditions of this License. If you cannot convey a
533
+ covered work so as to satisfy simultaneously your obligations under this
534
+ License and any other pertinent obligations, then as a consequence you may
535
+ not convey it at all. For example, if you agree to terms that obligate you
536
+ to collect a royalty for further conveying from those to whom you convey
537
+ the Program, the only way you could satisfy both those terms and this
538
+ License would be to refrain entirely from conveying the Program.
539
+
540
+ 13. Remote Network Interaction; Use with the GNU General Public License.
541
+
542
+ Notwithstanding any other provision of this License, if you modify the
543
+ Program, your modified version must prominently offer all users
544
+ interacting with it remotely through a computer network (if your version
545
+ supports such interaction) an opportunity to receive the Corresponding
546
+ Source of your version by providing access to the Corresponding Source
547
+ from a network server at no charge, through some standard or customary
548
+ means of facilitating copying of software. This Corresponding Source
549
+ shall include the Corresponding Source for any work covered by version 3
550
+ of the GNU General Public License that is incorporated pursuant to the
551
+ following paragraph.
552
+
553
+ Notwithstanding any other provision of this License, you have
554
+ permission to link or combine any covered work with a work licensed
555
+ under version 3 of the GNU General Public License into a single
556
+ combined work, and to convey the resulting work. The terms of this
557
+ License will continue to apply to the part which is the covered work,
558
+ but the work with which it is combined will remain governed by version
559
+ 3 of the GNU General Public License.
560
+
561
+ 14. Revised Versions of this License.
562
+
563
+ The Free Software Foundation may publish revised and/or new versions of
564
+ the GNU Affero General Public License from time to time. Such new versions
565
+ will be similar in spirit to the present version, but may differ in detail to
566
+ address new problems or concerns.
567
+
568
+ Each version is given a distinguishing version number. If the
569
+ Program specifies that a certain numbered version of the GNU Affero General
570
+ Public License "or any later version" applies to it, you have the
571
+ option of following the terms and conditions either of that numbered
572
+ version or of any later version published by the Free Software
573
+ Foundation. If the Program does not specify a version number of the
574
+ GNU Affero General Public License, you may choose any version ever published
575
+ by the Free Software Foundation.
576
+
577
+ If the Program specifies that a proxy can decide which future
578
+ versions of the GNU Affero General Public License can be used, that proxy's
579
+ public statement of acceptance of a version permanently authorizes you
580
+ to choose that version for the Program.
581
+
582
+ Later license versions may give you additional or different
583
+ permissions. However, no additional obligations are imposed on any
584
+ author or copyright holder as a result of your choosing to follow a
585
+ later version.
586
+
587
+ 15. Disclaimer of Warranty.
588
+
589
+ THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY
590
+ APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT
591
+ HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY
592
+ OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO,
593
+ THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
594
+ PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM
595
+ IS WITH YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF
596
+ ALL NECESSARY SERVICING, REPAIR OR CORRECTION.
597
+
598
+ 16. Limitation of Liability.
599
+
600
+ IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
601
+ WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MODIFIES AND/OR CONVEYS
602
+ THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY
603
+ GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE
604
+ USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF
605
+ DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD
606
+ PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS),
607
+ EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF
608
+ SUCH DAMAGES.
609
+
610
+ 17. Interpretation of Sections 15 and 16.
611
+
612
+ If the disclaimer of warranty and limitation of liability provided
613
+ above cannot be given local legal effect according to their terms,
614
+ reviewing courts shall apply local law that most closely approximates
615
+ an absolute waiver of all civil liability in connection with the
616
+ Program, unless a warranty or assumption of liability accompanies a
617
+ copy of the Program in return for a fee.
618
+
619
+ END OF TERMS AND CONDITIONS
620
+
621
+ How to Apply These Terms to Your New Programs
622
+
623
+ If you develop a new program, and you want it to be of the greatest
624
+ possible use to the public, the best way to achieve this is to make it
625
+ free software which everyone can redistribute and change under these terms.
626
+
627
+ To do so, attach the following notices to the program. It is safest
628
+ to attach them to the start of each source file to most effectively
629
+ state the exclusion of warranty; and each file should have at least
630
+ the "copyright" line and a pointer to where the full notice is found.
631
+
632
+ <one line to give the program's name and a brief idea of what it does.>
633
+ Copyright (C) <year> <name of author>
634
+
635
+ This program is free software: you can redistribute it and/or modify
636
+ it under the terms of the GNU Affero General Public License as published
637
+ by the Free Software Foundation, either version 3 of the License, or
638
+ (at your option) any later version.
639
+
640
+ This program is distributed in the hope that it will be useful,
641
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
642
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
643
+ GNU Affero General Public License for more details.
644
+
645
+ You should have received a copy of the GNU Affero General Public License
646
+ along with this program. If not, see <https://www.gnu.org/licenses/>.
647
+
648
+ Also add information on how to contact you by electronic and paper mail.
649
+
650
+ If your software can interact with users remotely through a computer
651
+ network, you should also make sure that it provides a way for users to
652
+ get its source. For example, if your program is a web application, its
653
+ interface could display a "Source" link that leads users to an archive
654
+ of the code. There are many ways you could offer source, and different
655
+ solutions will be better for different programs; see section 13 for the
656
+ specific requirements.
657
+
658
+ You should also get your employer (if you work as a programmer) or school,
659
+ if any, to sign a "copyright disclaimer" for the program, if necessary.
660
+ For more information on this, and how to apply and follow the GNU AGPL, see
661
+ <https://www.gnu.org/licenses/>.
BanG-Dream-VITS/README.md ADDED
@@ -0,0 +1,15 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ ---
2
+ title: BanG Dream! It's MyGO!!!!!
3
+ emoji: 🎸
4
+ colorFrom: green
5
+ colorTo: gray
6
+ sdk: gradio
7
+ sdk_version: 4.12.0
8
+ app_file: app.py
9
+ pinned: true
10
+ python_version: '3.10'
11
+ short_description: Generate Voice BanG Dream! VITS
12
+ ---
13
+
14
+ # BanGDream MyGO VITS
15
+ Aplikasi ini dijalankan dengan Python 3.10 untuk stabilitas library audio.
BanG-Dream-VITS/app.py ADDED
@@ -0,0 +1,329 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import os
2
+ os.system("pip uninstall -y gradio gradio-client")
3
+ os.system("pip install gradio==3.50.2 huggingface-hub==0.25.2 transformers==4.44.2")
4
+ import gradio as gr
5
+ import logging
6
+ import torch
7
+ import numpy as np
8
+ import random
9
+ import shutil
10
+ import gc
11
+ import psutil
12
+ import re
13
+ from huggingface_hub import snapshot_download
14
+
15
+ # --- 0. AUTO CLEANER FUNCTION ---
16
+ def cleanup_memory():
17
+ gc.collect()
18
+ if torch.cuda.is_available():
19
+ torch.cuda.empty_cache()
20
+ temp_dir = "temp"
21
+ if os.path.exists(temp_dir):
22
+ try:
23
+ shutil.rmtree(temp_dir)
24
+ os.makedirs(temp_dir)
25
+ except: pass
26
+
27
+ cleanup_memory()
28
+
29
+ # --- 1. SETUP ASSETS ---
30
+ def setup_shittim_box():
31
+ repo_id = "Plana-Archive/Anime-Models"
32
+ # Menyesuaikan dengan path subfolder yang benar di Hugging Face
33
+ remote_sub_folder = "Anime-VITS/MyGO-AveMujica-VITS"
34
+
35
+ if not os.path.exists("Data"):
36
+ try:
37
+ # Mendownload konten secara spesifik berdasarkan pola subfolder repositori
38
+ snapshot_download(
39
+ repo_id=repo_id,
40
+ allow_patterns=[f"{remote_sub_folder}/**/*"],
41
+ local_dir="."
42
+ )
43
+
44
+ # Memindahkan folder utama yang dibutuhkan aplikasi ke root direktori
45
+ folders = ["Data", "bert", "emotional", "logs", "image"]
46
+ for f in folders:
47
+ src = os.path.join(remote_sub_folder, f)
48
+ if os.path.exists(src):
49
+ if os.path.exists(f):
50
+ shutil.rmtree(f)
51
+ shutil.move(src, f)
52
+
53
+ # Membersihkan sisa folder Anime-VITS hasil download setelah dipindahkan
54
+ if os.path.exists("Anime-VITS"):
55
+ shutil.rmtree("Anime-VITS")
56
+ except Exception:
57
+ pass
58
+
59
+ setup_shittim_box()
60
+
61
+ # --- 2. IMPORT MODUL ---
62
+ import utils
63
+ import commons
64
+ from models import SynthesizerTrn
65
+ from text.symbols import symbols
66
+ from text import cleaned_text_to_sequence, get_bert
67
+ from text.cleaner import clean_text
68
+
69
+ logging.basicConfig(level=logging.INFO)
70
+ device = torch.device("cuda" if torch.cuda.is_available() else "cpu")
71
+
72
+ # --- 3. CONFIG & CHARACTER LIST ---
73
+ config_path = "Data/BangDream/config.json"
74
+ hps = utils.get_hparams_from_file(config_path)
75
+ model_dir = "Data/BangDream/models/"
76
+ model_file = [os.path.join(model_dir, f) for f in os.listdir(model_dir) if f.endswith('.pth')][-1]
77
+
78
+ net_g = SynthesizerTrn(
79
+ len(symbols), hps.data.filter_length // 2 + 1,
80
+ hps.train.segment_size // hps.data.hop_length,
81
+ n_speakers=hps.data.n_speakers, **hps.model
82
+ ).to(device)
83
+ _ = net_g.eval()
84
+ _ = utils.load_checkpoint(model_file, net_g, None, skip_optimizer=True)
85
+
86
+ NAME_MAP = {
87
+ "燈": "Tomori", "そよ": "Soyo",
88
+ "睦": "Mutsumi", "祥子": "Sakiko",
89
+ "愛音": "Anon", "立希": "Taki",
90
+ "楽奈": "Rana", "海鈴": "Umiri",
91
+ "初華": "Uika", "にゃむ": "Nyaamu"
92
+ }
93
+
94
+ additional_characters = [
95
+ "あこ", "こころ", "たえ", "つくし", "つぐみ", "はぐみ", "ひまり", "ましろ", "ますき", "りみ",
96
+ "イヴ", "チュチュ", "パレオ", "モカ", "リサ", "レイヤ", "ロック", "一愛", "七深", "光",
97
+ "克洛迪娜", "八千代", "千聖", "友希那", "司", "壘", "奈奈", "巴", "彩", "悠悠子", "文",
98
+ "日菜", "晶", "有咲", "未知留", "栞", "沙綾", "珠緒", "瑠唯", "真晝", "真矢", "純那",
99
+ "美咲", "美帆", "美空", "艾露", "艾露露", "花音", "菈樂菲", "華戀", "薫", "蘭", "透子",
100
+ "雙葉", "靜羽", "香子", "香澄", "麻弥"
101
+ ]
102
+
103
+ additional_romaji = {
104
+ "あこ": "Ako", "こころ": "Kokoro", "たえ": "Tae", "つくし": "Tsukushi", "つぐみ": "Tsugumi",
105
+ "はぐみ": "Hagumi", "ひまり": "Himari", "ましろ": "Mashiro", "ますき": "Masuki", "りみ": "Rimi",
106
+ "イヴ": "Eve", "チュチュ": "Chuchu", "パレオ": "Pareo", "モカ": "Moka", "リサ": "Lisa",
107
+ "レイヤ": "Layer", "ロック": "Rock", "一愛": "Kazusa", "七深": "Nanami", "光": "Hikaru",
108
+ "克洛迪娜": "Claudine", "八千代": "Yachiyo", "千聖": "Chisato", "友希那": "Yukina", "司": "Tsukasa",
109
+ "壘": "Rui", "奈奈": "Nana", "巴": "Tomoe", "彩": "Aya", "悠悠子": "Yuyuko", "文": "Fumi",
110
+ "日菜": "Hina", "晶": "Akira", "有咲": "Arisa", "未知留": "Michiru", "栞": "Shiori",
111
+ "沙綾": "Saaya", "珠緒": "Tamao", "瑠唯": "Rui", "真晝": "Mahiru", "真矢": "Maya",
112
+ "純那": "Junna", "美咲": "Misaki", "美帆": "Miho", "美空": "Misora", "艾露": "Airu",
113
+ "艾露露": "Airuru", "花音": "Kanon", "菈樂菲": "Rarafe", "華戀": "Karen", "薫": "Kaoru",
114
+ "蘭": "Ran", "透子": "Touko", "雙葉": "Futaba", "靜羽": "Shizuha", "香子": "Kyouko",
115
+ "香澄": "Kasumi", "麻弥": "Maya"
116
+ }
117
+
118
+ for char, rom in additional_romaji.items():
119
+ if char not in NAME_MAP:
120
+ NAME_MAP[char] = rom
121
+
122
+ original_spk = ["燈", "そよ", "睦", "祥子", "愛音", "立希", "���奈", "海鈴", "初華", "にゃむ"]
123
+ new_spk = []
124
+ for char in additional_characters:
125
+ if char not in original_spk:
126
+ new_spk.append(char)
127
+ SORTED_SPK = original_spk + new_spk
128
+
129
+ # --- 4. INFERENCE ENGINE ---
130
+ def infer(text, sdp_ratio, noise_scale, noise_scale_w, length_scale, sid_name):
131
+ if not text.strip(): return "Teks kosong!", None
132
+ try:
133
+ if psutil.virtual_memory().percent > 85:
134
+ cleanup_memory()
135
+
136
+ norm_text, phone, tone, word2ph = clean_text(text, "JP")
137
+ phone, tone, lang_seq = cleaned_text_to_sequence(phone, tone, "JP")
138
+ if hps.data.add_blank:
139
+ phone = commons.intersperse(phone, 0)
140
+ tone = commons.intersperse(tone, 0)
141
+ lang_seq = commons.intersperse(lang_seq, 0)
142
+ for i in range(len(word2ph)): word2ph[i] = word2ph[i] * 2
143
+ word2ph[0] += 1
144
+ bert_ori = get_bert(norm_text, word2ph, "JP", device, "", 0.7)
145
+ with torch.no_grad():
146
+ x = torch.LongTensor(phone).to(device).unsqueeze(0)
147
+ t = torch.LongTensor(tone).to(device).unsqueeze(0)
148
+ l = torch.LongTensor(lang_seq).to(device).unsqueeze(0)
149
+ bert = torch.zeros(1024, len(phone)).to(device).unsqueeze(0).float()
150
+ ja_bert = bert_ori.to(device).unsqueeze(0).float()
151
+ en_bert = torch.zeros(1024, len(phone)).to(device).unsqueeze(0).float()
152
+ sid_id = torch.LongTensor([hps.data.spk2id[sid_name]]).to(device)
153
+ audio = net_g.infer(x, torch.LongTensor([len(phone)]).to(device), sid_id, t, l, bert, ja_bert, en_bert,
154
+ sdp_ratio=sdp_ratio, noise_scale=noise_scale, noise_scale_w=noise_scale_w,
155
+ length_scale=length_scale)[0][0,0].data.cpu().float().numpy()
156
+ cleanup_memory()
157
+ return "Berhasil Membuat ✅!", (hps.data.sampling_rate, (audio * 32767).astype(np.int16))
158
+ except Exception as e:
159
+ cleanup_memory()
160
+ return f"Error: {str(e)}", None
161
+
162
+ def get_char_info_html():
163
+ html = f'''<div class="info-content-area" id="info-content-main" style="display: grid; grid-template-columns: 1fr 1fr; gap: 10px; padding: 15px; background: white; border: 1px solid #e1f0e5; border-top: none; border-radius: 0 0 10px 10px; max-height: 300px; overflow-y: auto;">'''
164
+ for name in SORTED_SPK:
165
+ romaji = NAME_MAP.get(name, "Character")
166
+ html += f'''
167
+ <div style="border: 1px solid #e1f0e5; border-radius: 12px; padding: 10px; border-left: 5px solid #a8e6cf; background: #fff;">
168
+ <div style="font-weight: 800; color: #2d3748; font-size: 14px; margin-bottom: 2px;">{name}</div>
169
+ <div style="color: #a0aec0; font-size: 11px;">{romaji}</div>
170
+ </div>
171
+ '''
172
+ html += "</div>"
173
+ return html
174
+
175
+ # --- 5. UI STYLE (BABY GREEN THEME) ---
176
+ css = """
177
+ :root {
178
+ --primary-600: #a8e6cf !important;
179
+ --accent-600: #a8e6cf !important;
180
+ }
181
+ .gradio-container, .gradio-container * {
182
+ --loader-color: #dcedc1 !important;
183
+ }
184
+ .ba-header-container {
185
+ border: 1.5px solid #e1f0e5;
186
+ border-radius: 12px;
187
+ margin-bottom: 12px;
188
+ background: white;
189
+ overflow: hidden;
190
+ line-height: 0;
191
+ }
192
+ .ba-header-container img {
193
+ width: 100%;
194
+ height: auto;
195
+ }
196
+ .status-container {
197
+ border: 1.5px solid #e1f0e5;
198
+ border-radius: 12px;
199
+ padding: 15px 22px;
200
+ margin-bottom: 20px;
201
+ background: white;
202
+ }
203
+ .status-title {
204
+ color: #88d498 !important;
205
+ font-weight: 800;
206
+ font-size: 16px;
207
+ margin-bottom: 8px;
208
+ }
209
+ .dot {
210
+ height: 8px;
211
+ width: 8px;
212
+ background-color: #88d498;
213
+ border-radius: 50%;
214
+ display: inline-block;
215
+ margin-right: 6px;
216
+ box-shadow: 0 0 0 0 rgba(136, 212, 152, 1);
217
+ animation: pulse-green 2s infinite;
218
+ }
219
+ @keyframes pulse-green {
220
+ 0% { transform: scale(0.95); box-shadow: 0 0 0 0 rgba(136, 212, 152, 0.7); }
221
+ 70% { transform: scale(1); box-shadow: 0 0 0 10px rgba(136, 212, 152, 0); }
222
+ 100% { transform: scale(0.95); box-shadow: 0 0 0 0 rgba(136, 212, 152, 0); }
223
+ }
224
+
225
+ .text-green-bold { color: #88d498 !important; font-weight: 900 !important; }
226
+ .text-blue-status { color: #88d498 !important; }
227
+ .slim-card { max-width: 480px; margin: 0 auto; background: transparent; padding: 10px; }
228
+ .char-img { border-radius: 15px; border: 1px solid #e1f0e5; margin-bottom: 15px; width: 100%; }
229
+ .scroll-box { height: 220px; overflow-y: auto; border: 1px solid #f0f4f8; border-radius: 12px; padding: 10px; background: #fafbfc; margin-bottom: 10px; }
230
+ .char-btn { background: white !important; border: 1px solid #e2e8f0 !important; border-left: 5px solid #a8e6cf !important; text-align: left !important; padding: 8px !important; font-size: 12px !important; margin-bottom: 4px !important; width: 100%; color: #4a5568 !important; }
231
+ .warning-card { background: #fffcf0; border: 2px dashed #ffd3b6; border-radius: 10px; padding: 12px; margin-bottom: 15px; text-align: center; }
232
+
233
+ .jp-btn {
234
+ background: #a8e6cf !important;
235
+ border: 1px solid #a8e6cf !important;
236
+ color: #ffffff !important;
237
+ font-weight: 700 !important;
238
+ border-radius: 10px !important;
239
+ margin-bottom: 10px;
240
+ font-size: 12px !important;
241
+ width: 100%;
242
+ cursor: pointer;
243
+ }
244
+
245
+ .gen-btn { background: #a8e6cf !important; color: #ffffff !important; font-weight: 700 !important; border-radius: 12px !important; height: 45px !important; width: 100%; border: none !important; cursor: pointer; }
246
+ .info-header-custom { background: #dcedc1 !important; color: #4a5568 !important; border: none !important; border-radius: 8px 8px 0 0 !important; padding: 12px 15px !important; width: 100% !important; cursor: pointer; font-weight: 800 !important; margin-top: 5px; }
247
+ .credit-footer { margin-top: 25px; padding: 15px; background: white; border-radius: 12px; text-align: center; border-bottom: 4px solid #a8e6cf; color: #94a3b8; font-weight: 700; font-size: 12px; letter-spacing: 2px; }
248
+
249
+ .gif-container { display: flex; justify-content: center; margin-top: 15px; margin-bottom: 10px; width: 100%; }
250
+ .gif-container img { border-radius: 12px; max-width: 100%; height: auto; border: 1.5px solid #e1f0e5; object-fit: contain; }
251
+
252
+ label[for="input_text"] {
253
+ background: #a8e6cf !important;
254
+ color: #4a5568 !important;
255
+ padding: 6px 12px !important;
256
+ border-radius: 12px !important;
257
+ font-weight: 600 !important;
258
+ display: inline-block !important;
259
+ width: auto !important;
260
+ margin-bottom: 6px !important;
261
+ }
262
+ """
263
+
264
+ with gr.Blocks(css=css) as app:
265
+ with gr.Column(elem_classes="slim-card"):
266
+ gr.HTML("""
267
+ <div class="ba-header-container">
268
+ <img src="https://huggingface.co/spaces/Plana-Archive/BanG-Dream-VITS/resolve/main/BANNER.PNG" alt="BanG Dream Banner">
269
+ </div>
270
+ <div class="status-container">
271
+ <div class="status-title">System Status</div>
272
+ <div class="status-item"><span style="color:#4a5568">Model :</span> <span class="text-green-bold">&nbsp;LOADED ✅</span></div>
273
+ <div class="status-item"><span style="color:#88d498; font-weight:700;"><span class="dot"></span> Online</span></div>
274
+ </div>
275
+ """)
276
+
277
+ char_img = gr.Image(value=f"image/{SORTED_SPK[0]}.png", show_label=False, interactive=False, height=300, elem_classes="char-img")
278
+ active_spk = gr.State(SORTED_SPK[0])
279
+ char_display = gr.Markdown(f"📍 Selected: **{SORTED_SPK[0]}**")
280
+
281
+ with gr.Column(elem_classes="scroll-box"):
282
+ for name in SORTED_SPK:
283
+ romaji = NAME_MAP.get(name, "Character")
284
+ btn = gr.Button(f"👤 {name} | {romaji}", elem_classes="char-btn")
285
+ btn.click(lambda n=name: (n, f"📍 Selected: **{n}**", f"image/{n}.png"),
286
+ outputs=[active_spk, char_display, char_img])
287
+
288
+ gr.HTML("""
289
+ <div class="warning-card">
290
+ <div style="color:#f5a623;font-weight:800;font-size:13px;">🔖 PERINGATAN MINNA 🔖</div>
291
+ <div style="color:#855d1a;font-size:11px;font-weight:600;">
292
+ Pilih Karakter, masukkan teks Jepang, lalu klik Generate Voice! ✨
293
+ </div>
294
+ </div>
295
+ """)
296
+
297
+ input_text = gr.TextArea(label="Input Text (Japanese)", value="こんにちは、お会いできて光栄です。", lines=3, elem_id="input_text")
298
+
299
+ def get_random_jp_text():
300
+ texts = ["こんにちは!", "私の音楽 を聴いてください。", "一生、離さないから。", "私たちは、まだ終わっていない。", "Ave Mujicaの世界へようこそ。"]
301
+ return random.choice(texts)
302
+
303
+ gr.Button("🍏 INPUTS RANDOM TEXT 🍏", elem_classes="jp-btn").click(get_random_jp_text, outputs=[input_text])
304
+
305
+ with gr.Row():
306
+ speed_sl = gr.Slider(label="Speed", minimum=0.5, maximum=2.0, value=1.0, step=0.1)
307
+ sdp_sl = gr.Slider(label="SDP", minimum=0, maximum=1.0, value=0.2, step=0.1)
308
+
309
+ btn_gen = gr.Button("🥒 GENERATE VOICE 🥒", elem_classes="gen-btn")
310
+ audio_out = gr.Audio(label="Voice Output", type="numpy")
311
+ status_msg = gr.Textbox(visible=False)
312
+
313
+ gr.HTML(f"""
314
+ <div class="gif-container">
315
+ <img src="https://huggingface.co/spaces/Plana-Archive/BanG-Dream-VITS/resolve/main/ave-mujica-avemuji.gif" alt="BanG Dream GIF">
316
+ </div>
317
+ <button onclick="document.getElementById('info-content-main').style.display = (document.getElementById('info-content-main').style.display === 'none') ? 'grid' : 'none';" class="info-header-custom">
318
+ 📑 Character Information 📑
319
+ </button>
320
+ """)
321
+ gr.HTML(get_char_info_html())
322
+
323
+ gr.HTML("""<div class="credit-footer">🍏 CREATED BY MUTSUMI 🍏</div>""")
324
+
325
+ btn_gen.click(infer, inputs=[input_text, sdp_sl, gr.State(0.6), gr.State(0.8), speed_sl, active_spk],
326
+ outputs=[status_msg, audio_out])
327
+
328
+ if __name__ == "__main__":
329
+ app.queue().launch(server_name="0.0.0.0", server_port=7860, quiet=True)
BanG-Dream-VITS/app.py (Cadangan utama) ADDED
@@ -0,0 +1,260 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import os
2
+ os.system("pip uninstall -y gradio gradio-client")
3
+ os.system("pip install gradio==3.50.2 huggingface-hub==0.25.2 transformers==4.44.2")
4
+ import gradio as gr
5
+ import logging
6
+ import torch
7
+ import numpy as np
8
+ import random
9
+ import shutil
10
+ import gc
11
+ import psutil
12
+ from huggingface_hub import snapshot_download
13
+
14
+ # --- 0. AUTO CLEANER FUNCTION ---
15
+ def cleanup_memory():
16
+ gc.collect()
17
+ if torch.cuda.is_available():
18
+ torch.cuda.empty_cache()
19
+ temp_dir = "temp"
20
+ if os.path.exists(temp_dir):
21
+ try:
22
+ shutil.rmtree(temp_dir)
23
+ os.makedirs(temp_dir)
24
+ except: pass
25
+
26
+ cleanup_memory()
27
+
28
+ # --- 1. SETUP ASSETS ---
29
+ def setup_shittim_box():
30
+ repo_id = "Plana-Archive/Plana-TTS"
31
+ sub_folder = "MyGO-AveMujica-VITS"
32
+ if not os.path.exists("Data"):
33
+ try:
34
+ snapshot_download(repo_id=repo_id, allow_patterns=[f"{sub_folder}/**/*"], local_dir=".")
35
+ folders = ["Data", "bert", "emotional", "logs", "image"]
36
+ for f in folders:
37
+ src = os.path.join(sub_folder, f)
38
+ if os.path.exists(src):
39
+ if os.path.exists(f): shutil.rmtree(f)
40
+ shutil.move(src, f)
41
+ if os.path.exists(sub_folder): shutil.rmtree(sub_folder)
42
+ except Exception: pass
43
+
44
+ setup_shittim_box()
45
+
46
+ # --- 2. IMPORT MODUL ---
47
+ import utils
48
+ import commons
49
+ from models import SynthesizerTrn
50
+ from text.symbols import symbols
51
+ from text import cleaned_text_to_sequence, get_bert
52
+ from text.cleaner import clean_text
53
+
54
+ logging.basicConfig(level=logging.INFO)
55
+ device = torch.device("cuda" if torch.cuda.is_available() else "cpu")
56
+
57
+ # --- 3. CONFIG & CHARACTER LIST ---
58
+ config_path = "Data/BangDream/config.json"
59
+ hps = utils.get_hparams_from_file(config_path)
60
+ model_dir = "Data/BangDream/models/"
61
+ model_file = [os.path.join(model_dir, f) for f in os.listdir(model_dir) if f.endswith('.pth')][-1]
62
+
63
+ net_g = SynthesizerTrn(
64
+ len(symbols), hps.data.filter_length // 2 + 1,
65
+ hps.train.segment_size // hps.data.hop_length,
66
+ n_speakers=hps.data.n_speakers, **hps.model
67
+ ).to(device)
68
+ _ = net_g.eval()
69
+ _ = utils.load_checkpoint(model_file, net_g, None, skip_optimizer=True)
70
+
71
+ NAME_MAP = {
72
+ "燈": "Tomori", "そよ": "Soyo",
73
+ "睦": "Mutsumi", "祥子": "Sakiko",
74
+ "愛音": "Anon", "立希": "Taki",
75
+ "楽奈": "Rana", "海鈴": "Umiri",
76
+ "初華": "Uika", "にゃむ": "Nyaamu"
77
+ }
78
+ SORTED_SPK = ["燈", "そよ", "睦", "祥子", "愛音", "立希", "楽奈", "海鈴", "初華", "にゃむ"]
79
+
80
+ # --- 4. INFERENCE ENGINE ---
81
+ def infer(text, sdp_ratio, noise_scale, noise_scale_w, length_scale, sid_name):
82
+ if not text.strip(): return "Teks kosong!", None
83
+ try:
84
+ if psutil.virtual_memory().percent > 85:
85
+ cleanup_memory()
86
+
87
+ norm_text, phone, tone, word2ph = clean_text(text, "JP")
88
+ phone, tone, lang_seq = cleaned_text_to_sequence(phone, tone, "JP")
89
+ if hps.data.add_blank:
90
+ phone = commons.intersperse(phone, 0)
91
+ tone = commons.intersperse(tone, 0)
92
+ lang_seq = commons.intersperse(lang_seq, 0)
93
+ for i in range(len(word2ph)): word2ph[i] = word2ph[i] * 2
94
+ word2ph[0] += 1
95
+ bert_ori = get_bert(norm_text, word2ph, "JP", device, "", 0.7)
96
+ with torch.no_grad():
97
+ x = torch.LongTensor(phone).to(device).unsqueeze(0)
98
+ t = torch.LongTensor(tone).to(device).unsqueeze(0)
99
+ l = torch.LongTensor(lang_seq).to(device).unsqueeze(0)
100
+ bert = torch.zeros(1024, len(phone)).to(device).unsqueeze(0).float()
101
+ ja_bert = bert_ori.to(device).unsqueeze(0).float()
102
+ en_bert = torch.zeros(1024, len(phone)).to(device).unsqueeze(0).float()
103
+ sid_id = torch.LongTensor([hps.data.spk2id[sid_name]]).to(device)
104
+ audio = net_g.infer(x, torch.LongTensor([len(phone)]).to(device), sid_id, t, l, bert, ja_bert, en_bert,
105
+ sdp_ratio=sdp_ratio, noise_scale=noise_scale, noise_scale_w=noise_scale_w,
106
+ length_scale=length_scale)[0][0,0].data.cpu().float().numpy()
107
+ cleanup_memory()
108
+ return "Berhasil Membuat ✅!", (hps.data.sampling_rate, (audio * 32767).astype(np.int16))
109
+ except Exception as e:
110
+ cleanup_memory()
111
+ return f"Error: {str(e)}", None
112
+
113
+ # --- 5. UI DESIGN (Gradio 3.50.2) ---
114
+ css = """
115
+ @import url('https://fonts.googleapis.com/css2?family=Inter:wght@400;700;800&display=swap');
116
+ body, .gradio-container { background-color: #f7f9fc !important; font-family: 'Inter', sans-serif !important; }
117
+ .slim-card { max-width: 480px; margin: 0 auto !important; background: white; border-radius: 20px; padding: 25px; box-shadow: 0 4px 25px rgba(0,0,0,0.03); }
118
+
119
+ :root { --loader-color: #1299ff !important; }
120
+ .progress-bar, .primary-500, .accent-500 { background-color: #1299ff !important; }
121
+ div[role="progressbar"] > div { background-color: #1299ff !important; }
122
+ svg[class*="loading"] { fill: #1299ff !important; stroke: #1299ff !important; }
123
+
124
+ .ba-header { text-align: center; margin-bottom: 20px; }
125
+ .ba-header h1 { color: #1299ff !important; font-weight: 800; margin: 0; font-size: 1.6rem; }
126
+ .ba-header p { color: #8a99af; font-size: 10px; letter-spacing: 2px; margin: 0; }
127
+
128
+ .status-online { background: #f0f7ff; border: 1px solid #d0e4ff; border-radius: 12px; padding: 12px; margin-bottom: 20px; }
129
+ .dot { height: 8px; width: 8px; background-color: #2ecc71; border-radius: 50%; display: inline-block; margin-right: 6px; animation: blink 1.5s infinite; }
130
+ @keyframes blink { 0% { opacity: 1; } 50% { opacity: 0.4; } 100% { opacity: 1; } }
131
+
132
+ .char-img { border-radius: 15px; border: 1px solid #f1f5f9; margin-bottom: 15px; }
133
+ .warning-minna { background: #fff9f0; border: 1px dashed #ff9800; border-radius: 10px; padding: 12px; text-align: center; margin-bottom: 15px; }
134
+ .scroll-box { height: 260px; overflow-y: auto; border: 1px solid #f0f4f8; border-radius: 12px; padding: 8px; margin-bottom: 15px; }
135
+ .char-btn {
136
+ background: white !important; border: 1px solid #e2e8f0 !important; border-left: 5px solid #1299ff !important;
137
+ text-align: left !important; padding: 8px !important; font-size: 12px !important; transition: 0.1s !important;
138
+ }
139
+ .char-btn:hover { background: #f0f7ff !important; border-color: #1299ff !important; }
140
+ .jp-btn { background: #f8fafc !important; border: 1px solid #cbd5e1 !important; color: #475569 !important; font-weight: 700 !important; border-radius: 10px !important; }
141
+ .gen-btn { background: #1299ff !important; color: white !important; font-weight: 400 !important; border-radius: 12px !important; border: none !important; font-size: 14px !important; }
142
+ .credit-footer { margin-top: 25px; padding: 15px; background: white; border-radius: 12px; text-align: center; border: 1px solid #eef2f6; border-bottom: 4px solid #1299ff; color: #94a3b8; font-weight: 700; font-size: 12px; letter-spacing: 2px; }
143
+
144
+ /* Label Input Text background biru, teks putih */
145
+ label[for="input_text"] {
146
+ background: #1299ff !important;
147
+ color: white !important;
148
+ padding: 6px 12px !important;
149
+ border-radius: 12px !important;
150
+ font-weight: 600 !important;
151
+ display: inline-block !important;
152
+ width: auto !important;
153
+ margin-bottom: 6px !important;
154
+ }
155
+
156
+ /* Audio player di tengah */
157
+ .gr-audio {
158
+ display: flex !important;
159
+ justify-content: center !important;
160
+ background: transparent !important;
161
+ border: none !important;
162
+ padding: 0 !important;
163
+ margin: 10px 0 !important;
164
+ }
165
+ .gr-audio > div {
166
+ width: auto !important;
167
+ display: flex;
168
+ justify-content: center;
169
+ }
170
+ audio {
171
+ margin: 0 auto !important;
172
+ display: block !important;
173
+ width: 100% !important;
174
+ max-width: 360px;
175
+ border-radius: 30px;
176
+ }
177
+ label[for="audio_out"] {
178
+ display: none !important;
179
+ }
180
+ .audio-wrap {
181
+ background: transparent !important;
182
+ border: none !important;
183
+ box-shadow: none !important;
184
+ }
185
+ """
186
+
187
+ with gr.Blocks(css=css) as app:
188
+ with gr.Column(elem_classes="slim-card"):
189
+ gr.HTML("""
190
+ <div class="ba-header">
191
+ <h1>BanG Dream VITS</h1>
192
+ <p>🎸 Ave Mujica & MyGO 🎸</p>
193
+ </div>
194
+ <div class="status-online">
195
+ <div style="font-weight:800; color:#1299ff; font-size:11px; margin-bottom:4px;"><span class="dot"></span> SYSTEM STATUS</div>
196
+ <div style="font-size: 11px; color: #4a5568; line-height: 1.6;">
197
+ Model: ✅ LOADED<br>
198
+ Status: ONLINE
199
+ </div>
200
+ </div>
201
+ """)
202
+
203
+ char_img = gr.Image(value=f"image/{SORTED_SPK[0]}.png", show_label=False, interactive=False, height=300, elem_classes="char-img")
204
+ active_spk = gr.Textbox(value=SORTED_SPK[0], visible=False)
205
+
206
+ gr.HTML("<p style='font-weight:800; font-size:11px; color:#8a99af; margin-bottom:8px;'>SELECT CHARACTER</p>")
207
+
208
+ gr.HTML("""
209
+ <div class="warning-minna">
210
+ <div style="color:#ff9800; font-weight:800; font-size:12px; margin-bottom:4px;">🔖 PERINGATAN MINNA 🔖</div>
211
+ <p style="color:#666; font-size:11px; margin:0; line-height:1.4;">Setelah di pilih characternya akan Loading otomatis dan ke input, baru bisa di gunakan.</p>
212
+ </div>
213
+ """)
214
+
215
+ with gr.Column(elem_classes="scroll-box"):
216
+ for i in range(0, len(SORTED_SPK), 2):
217
+ with gr.Row():
218
+ for j in range(2):
219
+ if i + j < len(SORTED_SPK):
220
+ name = SORTED_SPK[i+j]
221
+ romaji = NAME_MAP.get(name, "Character")
222
+ btn = gr.Button(f"{name} | {romaji}", elem_classes="char-btn")
223
+ btn.click(lambda n=name: n, outputs=[active_spk])
224
+
225
+ input_text = gr.TextArea(label="Input Text (Japanese)", placeholder="Masukkan teks...", lines=3)
226
+ btn_random_input = gr.Button("🎲 Klik Acak Inputs", elem_classes="jp-btn")
227
+
228
+ with gr.Row():
229
+ speed_sl = gr.Slider(label="Speed", minimum=0.5, maximum=2.0, value=1.0, step=0.1)
230
+ sdp_sl = gr.Slider(label="SDP", minimum=0, maximum=1.0, value=0.2, step=0.1)
231
+
232
+ btn_gen = gr.Button("🎐GENERATE VOICE🎐", variant="primary", elem_classes="gen-btn")
233
+ audio_out = gr.Audio(label="Voice Output", type="numpy")
234
+ status_msg = gr.Textbox(label="Status Log", interactive=False)
235
+
236
+ gr.HTML("""<div class="credit-footer">🍃 CREATED BY MUTSUMI 🍃</div>""")
237
+
238
+ def update_image(name):
239
+ return f"image/{name}.png"
240
+
241
+ def get_random_jp_text():
242
+ texts = [
243
+ "こんにちは、お会いできて光栄です。",
244
+ "私の音楽を聴いてください。",
245
+ "一生、離さないから。",
246
+ "私たちは、まだ終わっていない。",
247
+ "Ave Mujicaの世界へようこそ。",
248
+ "あなたは私の運命の人ですか?",
249
+ "心の叫びを歌に乗せて。",
250
+ "静かな夜に、私の声が響く。"
251
+ ]
252
+ return random.choice(texts)
253
+
254
+ active_spk.change(update_image, inputs=[active_spk], outputs=[char_img])
255
+ btn_random_input.click(get_random_jp_text, outputs=[input_text])
256
+ btn_gen.click(infer, inputs=[input_text, sdp_sl, gr.State(0.6), gr.State(0.8), speed_sl, active_spk],
257
+ outputs=[status_msg, audio_out])
258
+
259
+ # Launch untuk Hugging Face Spaces
260
+ app.launch(server_name="0.0.0.0", share=False, debug=False, quiet=True)
BanG-Dream-VITS/attentions.py ADDED
@@ -0,0 +1,464 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import math
2
+ import torch
3
+ from torch import nn
4
+ from torch.nn import functional as F
5
+
6
+ import commons
7
+ import logging
8
+
9
+ logger = logging.getLogger(__name__)
10
+
11
+
12
+ class LayerNorm(nn.Module):
13
+ def __init__(self, channels, eps=1e-5):
14
+ super().__init__()
15
+ self.channels = channels
16
+ self.eps = eps
17
+
18
+ self.gamma = nn.Parameter(torch.ones(channels))
19
+ self.beta = nn.Parameter(torch.zeros(channels))
20
+
21
+ def forward(self, x):
22
+ x = x.transpose(1, -1)
23
+ x = F.layer_norm(x, (self.channels,), self.gamma, self.beta, self.eps)
24
+ return x.transpose(1, -1)
25
+
26
+
27
+ @torch.jit.script
28
+ def fused_add_tanh_sigmoid_multiply(input_a, input_b, n_channels):
29
+ n_channels_int = n_channels[0]
30
+ in_act = input_a + input_b
31
+ t_act = torch.tanh(in_act[:, :n_channels_int, :])
32
+ s_act = torch.sigmoid(in_act[:, n_channels_int:, :])
33
+ acts = t_act * s_act
34
+ return acts
35
+
36
+
37
+ class Encoder(nn.Module):
38
+ def __init__(
39
+ self,
40
+ hidden_channels,
41
+ filter_channels,
42
+ n_heads,
43
+ n_layers,
44
+ kernel_size=1,
45
+ p_dropout=0.0,
46
+ window_size=4,
47
+ isflow=True,
48
+ **kwargs
49
+ ):
50
+ super().__init__()
51
+ self.hidden_channels = hidden_channels
52
+ self.filter_channels = filter_channels
53
+ self.n_heads = n_heads
54
+ self.n_layers = n_layers
55
+ self.kernel_size = kernel_size
56
+ self.p_dropout = p_dropout
57
+ self.window_size = window_size
58
+ # if isflow:
59
+ # cond_layer = torch.nn.Conv1d(256, 2*hidden_channels*n_layers, 1)
60
+ # self.cond_pre = torch.nn.Conv1d(hidden_channels, 2*hidden_channels, 1)
61
+ # self.cond_layer = weight_norm(cond_layer, name='weight')
62
+ # self.gin_channels = 256
63
+ self.cond_layer_idx = self.n_layers
64
+ if "gin_channels" in kwargs:
65
+ self.gin_channels = kwargs["gin_channels"]
66
+ if self.gin_channels != 0:
67
+ self.spk_emb_linear = nn.Linear(self.gin_channels, self.hidden_channels)
68
+ # vits2 says 3rd block, so idx is 2 by default
69
+ self.cond_layer_idx = (
70
+ kwargs["cond_layer_idx"] if "cond_layer_idx" in kwargs else 2
71
+ )
72
+ logging.debug(self.gin_channels, self.cond_layer_idx)
73
+ assert (
74
+ self.cond_layer_idx < self.n_layers
75
+ ), "cond_layer_idx should be less than n_layers"
76
+ self.drop = nn.Dropout(p_dropout)
77
+ self.attn_layers = nn.ModuleList()
78
+ self.norm_layers_1 = nn.ModuleList()
79
+ self.ffn_layers = nn.ModuleList()
80
+ self.norm_layers_2 = nn.ModuleList()
81
+ for i in range(self.n_layers):
82
+ self.attn_layers.append(
83
+ MultiHeadAttention(
84
+ hidden_channels,
85
+ hidden_channels,
86
+ n_heads,
87
+ p_dropout=p_dropout,
88
+ window_size=window_size,
89
+ )
90
+ )
91
+ self.norm_layers_1.append(LayerNorm(hidden_channels))
92
+ self.ffn_layers.append(
93
+ FFN(
94
+ hidden_channels,
95
+ hidden_channels,
96
+ filter_channels,
97
+ kernel_size,
98
+ p_dropout=p_dropout,
99
+ )
100
+ )
101
+ self.norm_layers_2.append(LayerNorm(hidden_channels))
102
+
103
+ def forward(self, x, x_mask, g=None):
104
+ attn_mask = x_mask.unsqueeze(2) * x_mask.unsqueeze(-1)
105
+ x = x * x_mask
106
+ for i in range(self.n_layers):
107
+ if i == self.cond_layer_idx and g is not None:
108
+ g = self.spk_emb_linear(g.transpose(1, 2))
109
+ g = g.transpose(1, 2)
110
+ x = x + g
111
+ x = x * x_mask
112
+ y = self.attn_layers[i](x, x, attn_mask)
113
+ y = self.drop(y)
114
+ x = self.norm_layers_1[i](x + y)
115
+
116
+ y = self.ffn_layers[i](x, x_mask)
117
+ y = self.drop(y)
118
+ x = self.norm_layers_2[i](x + y)
119
+ x = x * x_mask
120
+ return x
121
+
122
+
123
+ class Decoder(nn.Module):
124
+ def __init__(
125
+ self,
126
+ hidden_channels,
127
+ filter_channels,
128
+ n_heads,
129
+ n_layers,
130
+ kernel_size=1,
131
+ p_dropout=0.0,
132
+ proximal_bias=False,
133
+ proximal_init=True,
134
+ **kwargs
135
+ ):
136
+ super().__init__()
137
+ self.hidden_channels = hidden_channels
138
+ self.filter_channels = filter_channels
139
+ self.n_heads = n_heads
140
+ self.n_layers = n_layers
141
+ self.kernel_size = kernel_size
142
+ self.p_dropout = p_dropout
143
+ self.proximal_bias = proximal_bias
144
+ self.proximal_init = proximal_init
145
+
146
+ self.drop = nn.Dropout(p_dropout)
147
+ self.self_attn_layers = nn.ModuleList()
148
+ self.norm_layers_0 = nn.ModuleList()
149
+ self.encdec_attn_layers = nn.ModuleList()
150
+ self.norm_layers_1 = nn.ModuleList()
151
+ self.ffn_layers = nn.ModuleList()
152
+ self.norm_layers_2 = nn.ModuleList()
153
+ for i in range(self.n_layers):
154
+ self.self_attn_layers.append(
155
+ MultiHeadAttention(
156
+ hidden_channels,
157
+ hidden_channels,
158
+ n_heads,
159
+ p_dropout=p_dropout,
160
+ proximal_bias=proximal_bias,
161
+ proximal_init=proximal_init,
162
+ )
163
+ )
164
+ self.norm_layers_0.append(LayerNorm(hidden_channels))
165
+ self.encdec_attn_layers.append(
166
+ MultiHeadAttention(
167
+ hidden_channels, hidden_channels, n_heads, p_dropout=p_dropout
168
+ )
169
+ )
170
+ self.norm_layers_1.append(LayerNorm(hidden_channels))
171
+ self.ffn_layers.append(
172
+ FFN(
173
+ hidden_channels,
174
+ hidden_channels,
175
+ filter_channels,
176
+ kernel_size,
177
+ p_dropout=p_dropout,
178
+ causal=True,
179
+ )
180
+ )
181
+ self.norm_layers_2.append(LayerNorm(hidden_channels))
182
+
183
+ def forward(self, x, x_mask, h, h_mask):
184
+ """
185
+ x: decoder input
186
+ h: encoder output
187
+ """
188
+ self_attn_mask = commons.subsequent_mask(x_mask.size(2)).to(
189
+ device=x.device, dtype=x.dtype
190
+ )
191
+ encdec_attn_mask = h_mask.unsqueeze(2) * x_mask.unsqueeze(-1)
192
+ x = x * x_mask
193
+ for i in range(self.n_layers):
194
+ y = self.self_attn_layers[i](x, x, self_attn_mask)
195
+ y = self.drop(y)
196
+ x = self.norm_layers_0[i](x + y)
197
+
198
+ y = self.encdec_attn_layers[i](x, h, encdec_attn_mask)
199
+ y = self.drop(y)
200
+ x = self.norm_layers_1[i](x + y)
201
+
202
+ y = self.ffn_layers[i](x, x_mask)
203
+ y = self.drop(y)
204
+ x = self.norm_layers_2[i](x + y)
205
+ x = x * x_mask
206
+ return x
207
+
208
+
209
+ class MultiHeadAttention(nn.Module):
210
+ def __init__(
211
+ self,
212
+ channels,
213
+ out_channels,
214
+ n_heads,
215
+ p_dropout=0.0,
216
+ window_size=None,
217
+ heads_share=True,
218
+ block_length=None,
219
+ proximal_bias=False,
220
+ proximal_init=False,
221
+ ):
222
+ super().__init__()
223
+ assert channels % n_heads == 0
224
+
225
+ self.channels = channels
226
+ self.out_channels = out_channels
227
+ self.n_heads = n_heads
228
+ self.p_dropout = p_dropout
229
+ self.window_size = window_size
230
+ self.heads_share = heads_share
231
+ self.block_length = block_length
232
+ self.proximal_bias = proximal_bias
233
+ self.proximal_init = proximal_init
234
+ self.attn = None
235
+
236
+ self.k_channels = channels // n_heads
237
+ self.conv_q = nn.Conv1d(channels, channels, 1)
238
+ self.conv_k = nn.Conv1d(channels, channels, 1)
239
+ self.conv_v = nn.Conv1d(channels, channels, 1)
240
+ self.conv_o = nn.Conv1d(channels, out_channels, 1)
241
+ self.drop = nn.Dropout(p_dropout)
242
+
243
+ if window_size is not None:
244
+ n_heads_rel = 1 if heads_share else n_heads
245
+ rel_stddev = self.k_channels**-0.5
246
+ self.emb_rel_k = nn.Parameter(
247
+ torch.randn(n_heads_rel, window_size * 2 + 1, self.k_channels)
248
+ * rel_stddev
249
+ )
250
+ self.emb_rel_v = nn.Parameter(
251
+ torch.randn(n_heads_rel, window_size * 2 + 1, self.k_channels)
252
+ * rel_stddev
253
+ )
254
+
255
+ nn.init.xavier_uniform_(self.conv_q.weight)
256
+ nn.init.xavier_uniform_(self.conv_k.weight)
257
+ nn.init.xavier_uniform_(self.conv_v.weight)
258
+ if proximal_init:
259
+ with torch.no_grad():
260
+ self.conv_k.weight.copy_(self.conv_q.weight)
261
+ self.conv_k.bias.copy_(self.conv_q.bias)
262
+
263
+ def forward(self, x, c, attn_mask=None):
264
+ q = self.conv_q(x)
265
+ k = self.conv_k(c)
266
+ v = self.conv_v(c)
267
+
268
+ x, self.attn = self.attention(q, k, v, mask=attn_mask)
269
+
270
+ x = self.conv_o(x)
271
+ return x
272
+
273
+ def attention(self, query, key, value, mask=None):
274
+ # reshape [b, d, t] -> [b, n_h, t, d_k]
275
+ b, d, t_s, t_t = (*key.size(), query.size(2))
276
+ query = query.view(b, self.n_heads, self.k_channels, t_t).transpose(2, 3)
277
+ key = key.view(b, self.n_heads, self.k_channels, t_s).transpose(2, 3)
278
+ value = value.view(b, self.n_heads, self.k_channels, t_s).transpose(2, 3)
279
+
280
+ scores = torch.matmul(query / math.sqrt(self.k_channels), key.transpose(-2, -1))
281
+ if self.window_size is not None:
282
+ assert (
283
+ t_s == t_t
284
+ ), "Relative attention is only available for self-attention."
285
+ key_relative_embeddings = self._get_relative_embeddings(self.emb_rel_k, t_s)
286
+ rel_logits = self._matmul_with_relative_keys(
287
+ query / math.sqrt(self.k_channels), key_relative_embeddings
288
+ )
289
+ scores_local = self._relative_position_to_absolute_position(rel_logits)
290
+ scores = scores + scores_local
291
+ if self.proximal_bias:
292
+ assert t_s == t_t, "Proximal bias is only available for self-attention."
293
+ scores = scores + self._attention_bias_proximal(t_s).to(
294
+ device=scores.device, dtype=scores.dtype
295
+ )
296
+ if mask is not None:
297
+ scores = scores.masked_fill(mask == 0, -1e4)
298
+ if self.block_length is not None:
299
+ assert (
300
+ t_s == t_t
301
+ ), "Local attention is only available for self-attention."
302
+ block_mask = (
303
+ torch.ones_like(scores)
304
+ .triu(-self.block_length)
305
+ .tril(self.block_length)
306
+ )
307
+ scores = scores.masked_fill(block_mask == 0, -1e4)
308
+ p_attn = F.softmax(scores, dim=-1) # [b, n_h, t_t, t_s]
309
+ p_attn = self.drop(p_attn)
310
+ output = torch.matmul(p_attn, value)
311
+ if self.window_size is not None:
312
+ relative_weights = self._absolute_position_to_relative_position(p_attn)
313
+ value_relative_embeddings = self._get_relative_embeddings(
314
+ self.emb_rel_v, t_s
315
+ )
316
+ output = output + self._matmul_with_relative_values(
317
+ relative_weights, value_relative_embeddings
318
+ )
319
+ output = (
320
+ output.transpose(2, 3).contiguous().view(b, d, t_t)
321
+ ) # [b, n_h, t_t, d_k] -> [b, d, t_t]
322
+ return output, p_attn
323
+
324
+ def _matmul_with_relative_values(self, x, y):
325
+ """
326
+ x: [b, h, l, m]
327
+ y: [h or 1, m, d]
328
+ ret: [b, h, l, d]
329
+ """
330
+ ret = torch.matmul(x, y.unsqueeze(0))
331
+ return ret
332
+
333
+ def _matmul_with_relative_keys(self, x, y):
334
+ """
335
+ x: [b, h, l, d]
336
+ y: [h or 1, m, d]
337
+ ret: [b, h, l, m]
338
+ """
339
+ ret = torch.matmul(x, y.unsqueeze(0).transpose(-2, -1))
340
+ return ret
341
+
342
+ def _get_relative_embeddings(self, relative_embeddings, length):
343
+ 2 * self.window_size + 1
344
+ # Pad first before slice to avoid using cond ops.
345
+ pad_length = max(length - (self.window_size + 1), 0)
346
+ slice_start_position = max((self.window_size + 1) - length, 0)
347
+ slice_end_position = slice_start_position + 2 * length - 1
348
+ if pad_length > 0:
349
+ padded_relative_embeddings = F.pad(
350
+ relative_embeddings,
351
+ commons.convert_pad_shape([[0, 0], [pad_length, pad_length], [0, 0]]),
352
+ )
353
+ else:
354
+ padded_relative_embeddings = relative_embeddings
355
+ used_relative_embeddings = padded_relative_embeddings[
356
+ :, slice_start_position:slice_end_position
357
+ ]
358
+ return used_relative_embeddings
359
+
360
+ def _relative_position_to_absolute_position(self, x):
361
+ """
362
+ x: [b, h, l, 2*l-1]
363
+ ret: [b, h, l, l]
364
+ """
365
+ batch, heads, length, _ = x.size()
366
+ # Concat columns of pad to shift from relative to absolute indexing.
367
+ x = F.pad(x, commons.convert_pad_shape([[0, 0], [0, 0], [0, 0], [0, 1]]))
368
+
369
+ # Concat extra elements so to add up to shape (len+1, 2*len-1).
370
+ x_flat = x.view([batch, heads, length * 2 * length])
371
+ x_flat = F.pad(
372
+ x_flat, commons.convert_pad_shape([[0, 0], [0, 0], [0, length - 1]])
373
+ )
374
+
375
+ # Reshape and slice out the padded elements.
376
+ x_final = x_flat.view([batch, heads, length + 1, 2 * length - 1])[
377
+ :, :, :length, length - 1 :
378
+ ]
379
+ return x_final
380
+
381
+ def _absolute_position_to_relative_position(self, x):
382
+ """
383
+ x: [b, h, l, l]
384
+ ret: [b, h, l, 2*l-1]
385
+ """
386
+ batch, heads, length, _ = x.size()
387
+ # pad along column
388
+ x = F.pad(
389
+ x, commons.convert_pad_shape([[0, 0], [0, 0], [0, 0], [0, length - 1]])
390
+ )
391
+ x_flat = x.view([batch, heads, length**2 + length * (length - 1)])
392
+ # add 0's in the beginning that will skew the elements after reshape
393
+ x_flat = F.pad(x_flat, commons.convert_pad_shape([[0, 0], [0, 0], [length, 0]]))
394
+ x_final = x_flat.view([batch, heads, length, 2 * length])[:, :, :, 1:]
395
+ return x_final
396
+
397
+ def _attention_bias_proximal(self, length):
398
+ """Bias for self-attention to encourage attention to close positions.
399
+ Args:
400
+ length: an integer scalar.
401
+ Returns:
402
+ a Tensor with shape [1, 1, length, length]
403
+ """
404
+ r = torch.arange(length, dtype=torch.float32)
405
+ diff = torch.unsqueeze(r, 0) - torch.unsqueeze(r, 1)
406
+ return torch.unsqueeze(torch.unsqueeze(-torch.log1p(torch.abs(diff)), 0), 0)
407
+
408
+
409
+ class FFN(nn.Module):
410
+ def __init__(
411
+ self,
412
+ in_channels,
413
+ out_channels,
414
+ filter_channels,
415
+ kernel_size,
416
+ p_dropout=0.0,
417
+ activation=None,
418
+ causal=False,
419
+ ):
420
+ super().__init__()
421
+ self.in_channels = in_channels
422
+ self.out_channels = out_channels
423
+ self.filter_channels = filter_channels
424
+ self.kernel_size = kernel_size
425
+ self.p_dropout = p_dropout
426
+ self.activation = activation
427
+ self.causal = causal
428
+
429
+ if causal:
430
+ self.padding = self._causal_padding
431
+ else:
432
+ self.padding = self._same_padding
433
+
434
+ self.conv_1 = nn.Conv1d(in_channels, filter_channels, kernel_size)
435
+ self.conv_2 = nn.Conv1d(filter_channels, out_channels, kernel_size)
436
+ self.drop = nn.Dropout(p_dropout)
437
+
438
+ def forward(self, x, x_mask):
439
+ x = self.conv_1(self.padding(x * x_mask))
440
+ if self.activation == "gelu":
441
+ x = x * torch.sigmoid(1.702 * x)
442
+ else:
443
+ x = torch.relu(x)
444
+ x = self.drop(x)
445
+ x = self.conv_2(self.padding(x * x_mask))
446
+ return x * x_mask
447
+
448
+ def _causal_padding(self, x):
449
+ if self.kernel_size == 1:
450
+ return x
451
+ pad_l = self.kernel_size - 1
452
+ pad_r = 0
453
+ padding = [[0, 0], [0, 0], [pad_l, pad_r]]
454
+ x = F.pad(x, commons.convert_pad_shape(padding))
455
+ return x
456
+
457
+ def _same_padding(self, x):
458
+ if self.kernel_size == 1:
459
+ return x
460
+ pad_l = (self.kernel_size - 1) // 2
461
+ pad_r = self.kernel_size // 2
462
+ padding = [[0, 0], [0, 0], [pad_l, pad_r]]
463
+ x = F.pad(x, commons.convert_pad_shape(padding))
464
+ return x
BanG-Dream-VITS/attentions_onnx.py ADDED
@@ -0,0 +1,378 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import math
2
+ import torch
3
+ from torch import nn
4
+ from torch.nn import functional as F
5
+
6
+ import commons
7
+ import logging
8
+
9
+ logger = logging.getLogger(__name__)
10
+
11
+
12
+ class LayerNorm(nn.Module):
13
+ def __init__(self, channels, eps=1e-5):
14
+ super().__init__()
15
+ self.channels = channels
16
+ self.eps = eps
17
+
18
+ self.gamma = nn.Parameter(torch.ones(channels))
19
+ self.beta = nn.Parameter(torch.zeros(channels))
20
+
21
+ def forward(self, x):
22
+ x = x.transpose(1, -1)
23
+ x = F.layer_norm(x, (self.channels,), self.gamma, self.beta, self.eps)
24
+ return x.transpose(1, -1)
25
+
26
+
27
+ @torch.jit.script
28
+ def fused_add_tanh_sigmoid_multiply(input_a, input_b, n_channels):
29
+ n_channels_int = n_channels[0]
30
+ in_act = input_a + input_b
31
+ t_act = torch.tanh(in_act[:, :n_channels_int, :])
32
+ s_act = torch.sigmoid(in_act[:, n_channels_int:, :])
33
+ acts = t_act * s_act
34
+ return acts
35
+
36
+
37
+ class Encoder(nn.Module):
38
+ def __init__(
39
+ self,
40
+ hidden_channels,
41
+ filter_channels,
42
+ n_heads,
43
+ n_layers,
44
+ kernel_size=1,
45
+ p_dropout=0.0,
46
+ window_size=4,
47
+ isflow=True,
48
+ **kwargs
49
+ ):
50
+ super().__init__()
51
+ self.hidden_channels = hidden_channels
52
+ self.filter_channels = filter_channels
53
+ self.n_heads = n_heads
54
+ self.n_layers = n_layers
55
+ self.kernel_size = kernel_size
56
+ self.p_dropout = p_dropout
57
+ self.window_size = window_size
58
+ # if isflow:
59
+ # cond_layer = torch.nn.Conv1d(256, 2*hidden_channels*n_layers, 1)
60
+ # self.cond_pre = torch.nn.Conv1d(hidden_channels, 2*hidden_channels, 1)
61
+ # self.cond_layer = weight_norm(cond_layer, name='weight')
62
+ # self.gin_channels = 256
63
+ self.cond_layer_idx = self.n_layers
64
+ if "gin_channels" in kwargs:
65
+ self.gin_channels = kwargs["gin_channels"]
66
+ if self.gin_channels != 0:
67
+ self.spk_emb_linear = nn.Linear(self.gin_channels, self.hidden_channels)
68
+ # vits2 says 3rd block, so idx is 2 by default
69
+ self.cond_layer_idx = (
70
+ kwargs["cond_layer_idx"] if "cond_layer_idx" in kwargs else 2
71
+ )
72
+ logging.debug(self.gin_channels, self.cond_layer_idx)
73
+ assert (
74
+ self.cond_layer_idx < self.n_layers
75
+ ), "cond_layer_idx should be less than n_layers"
76
+ self.drop = nn.Dropout(p_dropout)
77
+ self.attn_layers = nn.ModuleList()
78
+ self.norm_layers_1 = nn.ModuleList()
79
+ self.ffn_layers = nn.ModuleList()
80
+ self.norm_layers_2 = nn.ModuleList()
81
+ for i in range(self.n_layers):
82
+ self.attn_layers.append(
83
+ MultiHeadAttention(
84
+ hidden_channels,
85
+ hidden_channels,
86
+ n_heads,
87
+ p_dropout=p_dropout,
88
+ window_size=window_size,
89
+ )
90
+ )
91
+ self.norm_layers_1.append(LayerNorm(hidden_channels))
92
+ self.ffn_layers.append(
93
+ FFN(
94
+ hidden_channels,
95
+ hidden_channels,
96
+ filter_channels,
97
+ kernel_size,
98
+ p_dropout=p_dropout,
99
+ )
100
+ )
101
+ self.norm_layers_2.append(LayerNorm(hidden_channels))
102
+
103
+ def forward(self, x, x_mask, g=None):
104
+ attn_mask = x_mask.unsqueeze(2) * x_mask.unsqueeze(-1)
105
+ x = x * x_mask
106
+ for i in range(self.n_layers):
107
+ if i == self.cond_layer_idx and g is not None:
108
+ g = self.spk_emb_linear(g.transpose(1, 2))
109
+ g = g.transpose(1, 2)
110
+ x = x + g
111
+ x = x * x_mask
112
+ y = self.attn_layers[i](x, x, attn_mask)
113
+ y = self.drop(y)
114
+ x = self.norm_layers_1[i](x + y)
115
+
116
+ y = self.ffn_layers[i](x, x_mask)
117
+ y = self.drop(y)
118
+ x = self.norm_layers_2[i](x + y)
119
+ x = x * x_mask
120
+ return x
121
+
122
+
123
+ class MultiHeadAttention(nn.Module):
124
+ def __init__(
125
+ self,
126
+ channels,
127
+ out_channels,
128
+ n_heads,
129
+ p_dropout=0.0,
130
+ window_size=None,
131
+ heads_share=True,
132
+ block_length=None,
133
+ proximal_bias=False,
134
+ proximal_init=False,
135
+ ):
136
+ super().__init__()
137
+ assert channels % n_heads == 0
138
+
139
+ self.channels = channels
140
+ self.out_channels = out_channels
141
+ self.n_heads = n_heads
142
+ self.p_dropout = p_dropout
143
+ self.window_size = window_size
144
+ self.heads_share = heads_share
145
+ self.block_length = block_length
146
+ self.proximal_bias = proximal_bias
147
+ self.proximal_init = proximal_init
148
+ self.attn = None
149
+
150
+ self.k_channels = channels // n_heads
151
+ self.conv_q = nn.Conv1d(channels, channels, 1)
152
+ self.conv_k = nn.Conv1d(channels, channels, 1)
153
+ self.conv_v = nn.Conv1d(channels, channels, 1)
154
+ self.conv_o = nn.Conv1d(channels, out_channels, 1)
155
+ self.drop = nn.Dropout(p_dropout)
156
+
157
+ if window_size is not None:
158
+ n_heads_rel = 1 if heads_share else n_heads
159
+ rel_stddev = self.k_channels**-0.5
160
+ self.emb_rel_k = nn.Parameter(
161
+ torch.randn(n_heads_rel, window_size * 2 + 1, self.k_channels)
162
+ * rel_stddev
163
+ )
164
+ self.emb_rel_v = nn.Parameter(
165
+ torch.randn(n_heads_rel, window_size * 2 + 1, self.k_channels)
166
+ * rel_stddev
167
+ )
168
+
169
+ nn.init.xavier_uniform_(self.conv_q.weight)
170
+ nn.init.xavier_uniform_(self.conv_k.weight)
171
+ nn.init.xavier_uniform_(self.conv_v.weight)
172
+ if proximal_init:
173
+ with torch.no_grad():
174
+ self.conv_k.weight.copy_(self.conv_q.weight)
175
+ self.conv_k.bias.copy_(self.conv_q.bias)
176
+
177
+ def forward(self, x, c, attn_mask=None):
178
+ q = self.conv_q(x)
179
+ k = self.conv_k(c)
180
+ v = self.conv_v(c)
181
+
182
+ x, self.attn = self.attention(q, k, v, mask=attn_mask)
183
+
184
+ x = self.conv_o(x)
185
+ return x
186
+
187
+ def attention(self, query, key, value, mask=None):
188
+ # reshape [b, d, t] -> [b, n_h, t, d_k]
189
+ b, d, t_s, t_t = (*key.size(), query.size(2))
190
+ query = query.view(b, self.n_heads, self.k_channels, t_t).transpose(2, 3)
191
+ key = key.view(b, self.n_heads, self.k_channels, t_s).transpose(2, 3)
192
+ value = value.view(b, self.n_heads, self.k_channels, t_s).transpose(2, 3)
193
+
194
+ scores = torch.matmul(query / math.sqrt(self.k_channels), key.transpose(-2, -1))
195
+ if self.window_size is not None:
196
+ assert (
197
+ t_s == t_t
198
+ ), "Relative attention is only available for self-attention."
199
+ key_relative_embeddings = self._get_relative_embeddings(self.emb_rel_k, t_s)
200
+ rel_logits = self._matmul_with_relative_keys(
201
+ query / math.sqrt(self.k_channels), key_relative_embeddings
202
+ )
203
+ scores_local = self._relative_position_to_absolute_position(rel_logits)
204
+ scores = scores + scores_local
205
+ if self.proximal_bias:
206
+ assert t_s == t_t, "Proximal bias is only available for self-attention."
207
+ scores = scores + self._attention_bias_proximal(t_s).to(
208
+ device=scores.device, dtype=scores.dtype
209
+ )
210
+ if mask is not None:
211
+ scores = scores.masked_fill(mask == 0, -1e4)
212
+ if self.block_length is not None:
213
+ assert (
214
+ t_s == t_t
215
+ ), "Local attention is only available for self-attention."
216
+ block_mask = (
217
+ torch.ones_like(scores)
218
+ .triu(-self.block_length)
219
+ .tril(self.block_length)
220
+ )
221
+ scores = scores.masked_fill(block_mask == 0, -1e4)
222
+ p_attn = F.softmax(scores, dim=-1) # [b, n_h, t_t, t_s]
223
+ p_attn = self.drop(p_attn)
224
+ output = torch.matmul(p_attn, value)
225
+ if self.window_size is not None:
226
+ relative_weights = self._absolute_position_to_relative_position(p_attn)
227
+ value_relative_embeddings = self._get_relative_embeddings(
228
+ self.emb_rel_v, t_s
229
+ )
230
+ output = output + self._matmul_with_relative_values(
231
+ relative_weights, value_relative_embeddings
232
+ )
233
+ output = (
234
+ output.transpose(2, 3).contiguous().view(b, d, t_t)
235
+ ) # [b, n_h, t_t, d_k] -> [b, d, t_t]
236
+ return output, p_attn
237
+
238
+ def _matmul_with_relative_values(self, x, y):
239
+ """
240
+ x: [b, h, l, m]
241
+ y: [h or 1, m, d]
242
+ ret: [b, h, l, d]
243
+ """
244
+ ret = torch.matmul(x, y.unsqueeze(0))
245
+ return ret
246
+
247
+ def _matmul_with_relative_keys(self, x, y):
248
+ """
249
+ x: [b, h, l, d]
250
+ y: [h or 1, m, d]
251
+ ret: [b, h, l, m]
252
+ """
253
+ ret = torch.matmul(x, y.unsqueeze(0).transpose(-2, -1))
254
+ return ret
255
+
256
+ def _get_relative_embeddings(self, relative_embeddings, length):
257
+ max_relative_position = 2 * self.window_size + 1
258
+ # Pad first before slice to avoid using cond ops.
259
+ pad_length = max(length - (self.window_size + 1), 0)
260
+ slice_start_position = max((self.window_size + 1) - length, 0)
261
+ slice_end_position = slice_start_position + 2 * length - 1
262
+ if pad_length > 0:
263
+ padded_relative_embeddings = F.pad(
264
+ relative_embeddings,
265
+ commons.convert_pad_shape([[0, 0], [pad_length, pad_length], [0, 0]]),
266
+ )
267
+ else:
268
+ padded_relative_embeddings = relative_embeddings
269
+ used_relative_embeddings = padded_relative_embeddings[
270
+ :, slice_start_position:slice_end_position
271
+ ]
272
+ return used_relative_embeddings
273
+
274
+ def _relative_position_to_absolute_position(self, x):
275
+ """
276
+ x: [b, h, l, 2*l-1]
277
+ ret: [b, h, l, l]
278
+ """
279
+ batch, heads, length, _ = x.size()
280
+ # Concat columns of pad to shift from relative to absolute indexing.
281
+ x = F.pad(x, commons.convert_pad_shape([[0, 0], [0, 0], [0, 0], [0, 1]]))
282
+
283
+ # Concat extra elements so to add up to shape (len+1, 2*len-1).
284
+ x_flat = x.view([batch, heads, length * 2 * length])
285
+ x_flat = F.pad(
286
+ x_flat, commons.convert_pad_shape([[0, 0], [0, 0], [0, length - 1]])
287
+ )
288
+
289
+ # Reshape and slice out the padded elements.
290
+ x_final = x_flat.view([batch, heads, length + 1, 2 * length - 1])[
291
+ :, :, :length, length - 1 :
292
+ ]
293
+ return x_final
294
+
295
+ def _absolute_position_to_relative_position(self, x):
296
+ """
297
+ x: [b, h, l, l]
298
+ ret: [b, h, l, 2*l-1]
299
+ """
300
+ batch, heads, length, _ = x.size()
301
+ # padd along column
302
+ x = F.pad(
303
+ x, commons.convert_pad_shape([[0, 0], [0, 0], [0, 0], [0, length - 1]])
304
+ )
305
+ x_flat = x.view([batch, heads, length**2 + length * (length - 1)])
306
+ # add 0's in the beginning that will skew the elements after reshape
307
+ x_flat = F.pad(x_flat, commons.convert_pad_shape([[0, 0], [0, 0], [length, 0]]))
308
+ x_final = x_flat.view([batch, heads, length, 2 * length])[:, :, :, 1:]
309
+ return x_final
310
+
311
+ def _attention_bias_proximal(self, length):
312
+ """Bias for self-attention to encourage attention to close positions.
313
+ Args:
314
+ length: an integer scalar.
315
+ Returns:
316
+ a Tensor with shape [1, 1, length, length]
317
+ """
318
+ r = torch.arange(length, dtype=torch.float32)
319
+ diff = torch.unsqueeze(r, 0) - torch.unsqueeze(r, 1)
320
+ return torch.unsqueeze(torch.unsqueeze(-torch.log1p(torch.abs(diff)), 0), 0)
321
+
322
+
323
+ class FFN(nn.Module):
324
+ def __init__(
325
+ self,
326
+ in_channels,
327
+ out_channels,
328
+ filter_channels,
329
+ kernel_size,
330
+ p_dropout=0.0,
331
+ activation=None,
332
+ causal=False,
333
+ ):
334
+ super().__init__()
335
+ self.in_channels = in_channels
336
+ self.out_channels = out_channels
337
+ self.filter_channels = filter_channels
338
+ self.kernel_size = kernel_size
339
+ self.p_dropout = p_dropout
340
+ self.activation = activation
341
+ self.causal = causal
342
+
343
+ if causal:
344
+ self.padding = self._causal_padding
345
+ else:
346
+ self.padding = self._same_padding
347
+
348
+ self.conv_1 = nn.Conv1d(in_channels, filter_channels, kernel_size)
349
+ self.conv_2 = nn.Conv1d(filter_channels, out_channels, kernel_size)
350
+ self.drop = nn.Dropout(p_dropout)
351
+
352
+ def forward(self, x, x_mask):
353
+ x = self.conv_1(self.padding(x * x_mask))
354
+ if self.activation == "gelu":
355
+ x = x * torch.sigmoid(1.702 * x)
356
+ else:
357
+ x = torch.relu(x)
358
+ x = self.drop(x)
359
+ x = self.conv_2(self.padding(x * x_mask))
360
+ return x * x_mask
361
+
362
+ def _causal_padding(self, x):
363
+ if self.kernel_size == 1:
364
+ return x
365
+ pad_l = self.kernel_size - 1
366
+ pad_r = 0
367
+ padding = [[0, 0], [0, 0], [pad_l, pad_r]]
368
+ x = F.pad(x, commons.convert_pad_shape(padding))
369
+ return x
370
+
371
+ def _same_padding(self, x):
372
+ if self.kernel_size == 1:
373
+ return x
374
+ pad_l = (self.kernel_size - 1) // 2
375
+ pad_r = self.kernel_size // 2
376
+ padding = [[0, 0], [0, 0], [pad_l, pad_r]]
377
+ x = F.pad(x, commons.convert_pad_shape(padding))
378
+ return x
BanG-Dream-VITS/ave-mujica-avemuji.gif ADDED

Git LFS Details

  • SHA256: d0de9f3a10b6f55cd7ef9bca89cb89b90486f9edf3c2d715e71740c465030005
  • Pointer size: 132 Bytes
  • Size of remote file: 2.15 MB
BanG-Dream-VITS/bert_gen.py ADDED
@@ -0,0 +1,81 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import torch
2
+ from multiprocessing import Pool
3
+ import commons
4
+ import utils
5
+ from tqdm import tqdm
6
+ from text import check_bert_models, cleaned_text_to_sequence, get_bert
7
+ import argparse
8
+ import torch.multiprocessing as mp
9
+ from config import config
10
+
11
+
12
+ def process_line(x):
13
+ line, add_blank = x
14
+ device = config.bert_gen_config.device
15
+ if config.bert_gen_config.use_multi_device:
16
+ rank = mp.current_process()._identity
17
+ rank = rank[0] if len(rank) > 0 else 0
18
+ if torch.cuda.is_available():
19
+ gpu_id = rank % torch.cuda.device_count()
20
+ device = torch.device(f"cuda:{gpu_id}")
21
+ else:
22
+ device = torch.device("cpu")
23
+ wav_path, _, language_str, text, phones, tone, word2ph = line.strip().split("|")
24
+ phone = phones.split(" ")
25
+ tone = [int(i) for i in tone.split(" ")]
26
+ word2ph = [int(i) for i in word2ph.split(" ")]
27
+ word2ph = [i for i in word2ph]
28
+ phone, tone, language = cleaned_text_to_sequence(phone, tone, language_str)
29
+
30
+ if add_blank:
31
+ phone = commons.intersperse(phone, 0)
32
+ tone = commons.intersperse(tone, 0)
33
+ language = commons.intersperse(language, 0)
34
+ for i in range(len(word2ph)):
35
+ word2ph[i] = word2ph[i] * 2
36
+ word2ph[0] += 1
37
+
38
+ bert_path = wav_path.replace(".WAV", ".wav").replace(".wav", ".bert.pt")
39
+
40
+ try:
41
+ bert = torch.load(bert_path)
42
+ assert bert.shape[0] == 2048
43
+ except Exception:
44
+ bert = get_bert(text, word2ph, language_str, device)
45
+ assert bert.shape[-1] == len(phone)
46
+ torch.save(bert, bert_path)
47
+
48
+
49
+ preprocess_text_config = config.preprocess_text_config
50
+
51
+ if __name__ == "__main__":
52
+ parser = argparse.ArgumentParser()
53
+ parser.add_argument(
54
+ "-c", "--config", type=str, default=config.bert_gen_config.config_path
55
+ )
56
+ parser.add_argument(
57
+ "--num_processes", type=int, default=config.bert_gen_config.num_processes
58
+ )
59
+ args, _ = parser.parse_known_args()
60
+ config_path = args.config
61
+ hps = utils.get_hparams_from_file(config_path)
62
+ check_bert_models()
63
+ lines = []
64
+ with open(hps.data.training_files, encoding="utf-8") as f:
65
+ lines.extend(f.readlines())
66
+
67
+ with open(hps.data.validation_files, encoding="utf-8") as f:
68
+ lines.extend(f.readlines())
69
+ add_blank = [hps.data.add_blank] * len(lines)
70
+
71
+ if len(lines) != 0:
72
+ num_processes = args.num_processes
73
+ with Pool(processes=num_processes) as pool:
74
+ for _ in tqdm(
75
+ pool.imap_unordered(process_line, zip(lines, add_blank)),
76
+ total=len(lines),
77
+ ):
78
+ # 这里是缩进的代码块,表示循环体
79
+ pass # 使用pass语句作为占位符
80
+
81
+ print(f"bert生成完毕!, 共有{len(lines)}个bert.pt生成!")
BanG-Dream-VITS/clap_gen.py ADDED
@@ -0,0 +1,64 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import argparse
2
+ from multiprocessing import Pool, cpu_count
3
+
4
+ import torch
5
+ import torch.multiprocessing as mp
6
+ from tqdm import tqdm
7
+
8
+ import utils
9
+ from config import config
10
+ from clap_wrapper import get_clap_audio_feature
11
+ import librosa
12
+ import os
13
+
14
+ os.environ["OMP_NUM_THREADS"] = "1"
15
+ os.environ["MKL_NUM_THREADS"] = "1"
16
+
17
+
18
+ def process_line(line):
19
+ device = config.emo_gen_config.device
20
+ if config.emo_gen_config.use_multi_device:
21
+ rank = mp.current_process()._identity
22
+ rank = rank[0] if len(rank) > 0 else 0
23
+ if torch.cuda.is_available():
24
+ gpu_id = rank % torch.cuda.device_count()
25
+ device = torch.device(f"cuda:{gpu_id}")
26
+ else:
27
+ device = torch.device("cpu")
28
+ wav_path, _, language_str, text, phones, tone, word2ph = line.strip().split("|")
29
+
30
+ clap_path = wav_path.replace(".WAV", ".wav").replace(".wav", ".emo.npy")
31
+ if os.path.isfile(clap_path):
32
+ return
33
+
34
+ audio = librosa.load(wav_path, 48000)[0]
35
+ # audio = librosa.resample(audio, 44100, 48000)
36
+
37
+ clap = get_clap_audio_feature(audio, device)
38
+ torch.save(clap, clap_path)
39
+
40
+
41
+ if __name__ == "__main__":
42
+ parser = argparse.ArgumentParser()
43
+ parser.add_argument(
44
+ "-c", "--config", type=str, default=config.emo_gen_config.config_path
45
+ )
46
+ parser.add_argument(
47
+ "--num_processes", type=int, default=config.emo_gen_config.num_processes
48
+ )
49
+ args, _ = parser.parse_known_args()
50
+ config_path = args.config
51
+ hps = utils.get_hparams_from_file(config_path)
52
+ lines = []
53
+ with open(hps.data.training_files, encoding="utf-8") as f:
54
+ lines.extend(f.readlines())
55
+
56
+ with open(hps.data.validation_files, encoding="utf-8") as f:
57
+ lines.extend(f.readlines())
58
+ if len(lines) != 0:
59
+ num_processes = min(args.num_processes, cpu_count())
60
+ with Pool(processes=num_processes) as pool:
61
+ for _ in tqdm(pool.imap_unordered(process_line, lines), total=len(lines)):
62
+ pass
63
+
64
+ print(f"clap生成完毕!, 共有{len(lines)}个emo.pt生成!")
BanG-Dream-VITS/clap_wrapper.py ADDED
@@ -0,0 +1,49 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import sys
2
+
3
+ import torch
4
+ from transformers import ClapModel, ClapProcessor
5
+
6
+ from config import config
7
+
8
+ models = dict()
9
+ processor = ClapProcessor.from_pretrained("./emotional/clap-htsat-fused")
10
+
11
+
12
+ def get_clap_audio_feature(audio_data, device=config.bert_gen_config.device):
13
+ if (
14
+ sys.platform == "darwin"
15
+ and torch.backends.mps.is_available()
16
+ and device == "cpu"
17
+ ):
18
+ device = "mps"
19
+ if not device:
20
+ device = "cuda"
21
+ if device not in models.keys():
22
+ models[device] = ClapModel.from_pretrained("./emotional/clap-htsat-fused").to(
23
+ device
24
+ )
25
+ with torch.no_grad():
26
+ inputs = processor(
27
+ audios=audio_data, return_tensors="pt", sampling_rate=48000
28
+ ).to(device)
29
+ emb = models[device].get_audio_features(**inputs)
30
+ return emb.T
31
+
32
+
33
+ def get_clap_text_feature(text, device=config.bert_gen_config.device):
34
+ if (
35
+ sys.platform == "darwin"
36
+ and torch.backends.mps.is_available()
37
+ and device == "cpu"
38
+ ):
39
+ device = "mps"
40
+ if not device:
41
+ device = "cuda"
42
+ if device not in models.keys():
43
+ models[device] = ClapModel.from_pretrained("./emotional/clap-htsat-fused").to(
44
+ device
45
+ )
46
+ with torch.no_grad():
47
+ inputs = processor(text=text, return_tensors="pt").to(device)
48
+ emb = models[device].get_text_features(**inputs)
49
+ return emb.T
BanG-Dream-VITS/classify.py ADDED
@@ -0,0 +1,180 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ from sklearn.cluster import *
2
+ import os
3
+ import numpy as np
4
+ from config import config
5
+ import yaml
6
+ import argparse
7
+ import shutil
8
+
9
+ def ensure_dir(directory):
10
+ if not os.path.exists(directory):
11
+ os.makedirs(directory)
12
+
13
+ if __name__ == "__main__":
14
+ parser = argparse.ArgumentParser()
15
+ parser.add_argument("-a", "--algorithm", default="k", help="choose algorithm", type=str)
16
+ parser.add_argument("-n", "--num_clusters", default=4, help="number of clusters", type=int)
17
+ parser.add_argument("-r", "--range", default=4, help="number of files in a class", type=int)
18
+ args = parser.parse_args()
19
+
20
+ filelist_dict = {}
21
+ yml_result = {}
22
+ base_dir = "D:/Vits2/Bert-VITS2/Data/BanGDream/filelists"
23
+ output_dir = "D:/Vits2/classifedSample"
24
+
25
+ with open(os.path.join(base_dir, "Mygo.list"), mode="r", encoding="utf-8") as f:
26
+ embs = []
27
+ wavnames = []
28
+ for line in f:
29
+ parts = line.strip().split("|")
30
+ speaker = parts[1] # 假设 speaker 是第二个部分
31
+ filepath = parts[0] # 假设 filepath 是第一个部分
32
+ # ... 其余部分可以根据需要使用
33
+
34
+ if speaker not in filelist_dict:
35
+ filelist_dict[speaker] = []
36
+ yml_result[speaker] = {}
37
+ filelist_dict[speaker].append(filepath)
38
+
39
+ for speaker in filelist_dict:
40
+ print("\nspeaker: " + speaker)
41
+
42
+ embs = []
43
+ wavnames = []
44
+
45
+ for file in filelist_dict[speaker]:
46
+ try:
47
+ embs.append(np.expand_dims(np.load(f"{os.path.splitext(file)[0]}.emo.npy"), axis=0))
48
+ wavnames.append(file)
49
+ except Exception as e:
50
+ print(e)
51
+
52
+ if embs:
53
+ n_clusters = args.num_clusters
54
+ x = np.concatenate(embs, axis=0)
55
+ x = np.squeeze(x)
56
+
57
+ if args.algorithm == "b":
58
+ model = Birch(n_clusters=n_clusters, threshold=0.2)
59
+ elif args.algorithm == "s":
60
+ model = SpectralClustering(n_clusters=n_clusters)
61
+ elif args.algorithm == "a":
62
+ model = AgglomerativeClustering(n_clusters=n_clusters)
63
+ else:
64
+ model = KMeans(n_clusters=n_clusters, random_state=10)
65
+
66
+ y_predict = model.fit_predict(x)
67
+ classes = [[] for i in range(y_predict.max() + 1)]
68
+
69
+ for idx, wavname in enumerate(wavnames):
70
+ classes[y_predict[idx]].append(wavname)
71
+
72
+ for i in range(y_predict.max() + 1):
73
+ print("类别:", i, "本类中样本数量:", len(classes[i]))
74
+ yml_result[speaker][f"class{i}"] = []
75
+ class_dir = os.path.join(output_dir, speaker, f"class{i}")
76
+
77
+ num_samples_in_class = len(classes[i])
78
+ for j in range(min(args.range, num_samples_in_class)):
79
+ wav_file = classes[i][j]
80
+ print(wav_file)
81
+
82
+ # 复制文件到新目录
83
+ ensure_dir(class_dir)
84
+ shutil.copy(os.path.join(base_dir, wav_file), os.path.join(class_dir, os.path.basename(wav_file)))
85
+
86
+ yml_result[speaker][f"class{i}"].append(wav_file)
87
+
88
+ with open(os.path.join(base_dir, "emo_clustering.yml"), "w", encoding="utf-8") as f:
89
+ yaml.dump(yml_result, f)
90
+
91
+ '''
92
+ from sklearn.cluster import *
93
+ import os
94
+ import numpy as np
95
+ from config import config
96
+ import yaml
97
+ import argparse
98
+
99
+
100
+ if __name__ == "__main__":
101
+ parser = argparse.ArgumentParser()
102
+ parser.add_argument(
103
+ "-a", "--algorithm", default="s", help="choose algorithm", type=str
104
+ )
105
+ parser.add_argument(
106
+ "-n", "--num_clusters", default=3, help="number of clusters", type=int
107
+ )
108
+ parser.add_argument(
109
+ "-r", "--range", default=4, help="number of files in a class", type=int
110
+ )
111
+ args = parser.parse_args()
112
+ filelist_dict = {}
113
+ yml_result = {}
114
+ with open(
115
+ "D:/Vits2/Bert-VITS2/Data/BanGDream/filelists/Mygo.list", mode="r", encoding="utf-8"
116
+ ) as f:
117
+ embs = []
118
+ wavnames = []
119
+ for line in f:
120
+ speaker = line.split("|")[1]
121
+ if speaker not in filelist_dict:
122
+ filelist_dict[speaker] = []
123
+ yml_result[speaker] = {}
124
+ filelist_dict[speaker].append(line.split("|")[0])
125
+ #print(filelist_dict)
126
+
127
+ for speaker in filelist_dict:
128
+ print("\nspeaker: " + speaker)
129
+
130
+ # 清空 embs 和 wavnames 列表
131
+ embs = []
132
+ wavnames = []
133
+
134
+ for file in filelist_dict[speaker]:
135
+ try:
136
+ embs.append(
137
+ np.expand_dims(
138
+ np.load(f"{os.path.splitext(file)[0]}.emo.npy"), axis=0
139
+ )
140
+ )
141
+ wavnames.append(os.path.basename(file))
142
+ except Exception as e:
143
+ print(e)
144
+
145
+ if embs:
146
+ # 聚类算法类的数量
147
+ n_clusters = args.num_clusters
148
+ x = np.concatenate(embs, axis=0)
149
+ x = np.squeeze(x)
150
+ # 聚类算法类的数量
151
+ n_clusters = args.num_clusters
152
+ if args.algorithm == "b":
153
+ model = Birch(n_clusters=n_clusters, threshold=0.2)
154
+ elif args.algorithm == "s":
155
+ model = SpectralClustering(n_clusters=n_clusters)
156
+ elif args.algorithm == "a":
157
+ model = AgglomerativeClustering(n_clusters=n_clusters)
158
+ else:
159
+ model = KMeans(n_clusters=n_clusters, random_state=10)
160
+ # 可以自行尝试各种不同的聚类算法
161
+ y_predict = model.fit_predict(x)
162
+ classes = [[] for i in range(y_predict.max() + 1)]
163
+
164
+ for idx, wavname in enumerate(wavnames):
165
+ classes[y_predict[idx]].append(wavname)
166
+
167
+ for i in range(y_predict.max() + 1):
168
+ print("类别:", i, "本类中样本数量:", len(classes[i]))
169
+ yml_result[speaker][f"class{i}"] = []
170
+
171
+ # 修正:确保不会尝试访问超出范围的元素
172
+ num_samples_in_class = len(classes[i])
173
+ for j in range(min(args.range, num_samples_in_class)):
174
+ print(classes[i][j])
175
+ yml_result[speaker][f"class{i}"].append(classes[i][j])
176
+ with open(
177
+ os.path.join('D:/Vits2/Bert-VITS2/Data/BanGDream', "emo_clustering.yml"), "w", encoding="utf-8"
178
+ ) as f:
179
+ yaml.dump(yml_result, f)
180
+ '''
BanG-Dream-VITS/cleaner.py ADDED
@@ -0,0 +1,31 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import os
2
+ import shutil
3
+ import psutil
4
+ import gc
5
+ import time
6
+
7
+ def cleanup_cache(temp_dir="temp"):
8
+ """Membersihkan folder temp dan paksa garbage collection RAM"""
9
+ # 1. Bersihkan folder sementara jika ada
10
+ if os.path.exists(temp_dir):
11
+ try:
12
+ shutil.rmtree(temp_dir)
13
+ os.makedirs(temp_dir)
14
+ print(f"--- Folder {temp_dir} telah dibersihkan ---")
15
+ except Exception as e:
16
+ print(f"Gagal hapus folder temp: {e}")
17
+
18
+ # 2. Paksa Python lepas memori yang tidak terpakai
19
+ gc.collect()
20
+
21
+ # 3. Cek penggunaan RAM saat ini
22
+ ram_usage = psutil.virtual_memory().percent
23
+ print(f"--- Penggunaan RAM saat ini: {ram_usage}% ---")
24
+
25
+ return ram_usage
26
+
27
+ def auto_clean_threshold(threshold=85):
28
+ """Bersihkan jika RAM di atas 85%"""
29
+ if psutil.virtual_memory().percent > threshold:
30
+ print("RAM Hampir Penuh! Memulai pembersihan darurat...")
31
+ gc.collect()
BanG-Dream-VITS/commons.py ADDED
@@ -0,0 +1,158 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import math
2
+ import torch
3
+ from torch.nn import functional as F
4
+
5
+
6
+ def init_weights(m, mean=0.0, std=0.01):
7
+ classname = m.__class__.__name__
8
+ if classname.find("Conv") != -1:
9
+ m.weight.data.normal_(mean, std)
10
+
11
+
12
+ def get_padding(kernel_size, dilation=1):
13
+ return int((kernel_size * dilation - dilation) / 2)
14
+
15
+
16
+ def convert_pad_shape(pad_shape):
17
+ layer = pad_shape[::-1]
18
+ pad_shape = [item for sublist in layer for item in sublist]
19
+ return pad_shape
20
+
21
+
22
+ def intersperse(lst, item):
23
+ result = [item] * (len(lst) * 2 + 1)
24
+ result[1::2] = lst
25
+ return result
26
+
27
+
28
+ def kl_divergence(m_p, logs_p, m_q, logs_q):
29
+ """KL(P||Q)"""
30
+ kl = (logs_q - logs_p) - 0.5
31
+ kl += (
32
+ 0.5 * (torch.exp(2.0 * logs_p) + ((m_p - m_q) ** 2)) * torch.exp(-2.0 * logs_q)
33
+ )
34
+ return kl
35
+
36
+
37
+ def rand_gumbel(shape):
38
+ """Sample from the Gumbel distribution, protect from overflows."""
39
+ uniform_samples = torch.rand(shape) * 0.99998 + 0.00001
40
+ return -torch.log(-torch.log(uniform_samples))
41
+
42
+
43
+ def rand_gumbel_like(x):
44
+ g = rand_gumbel(x.size()).to(dtype=x.dtype, device=x.device)
45
+ return g
46
+
47
+
48
+ def slice_segments(x, ids_str, segment_size=4):
49
+ gather_indices = ids_str.view(x.size(0), 1, 1).repeat(
50
+ 1, x.size(1), 1
51
+ ) + torch.arange(segment_size, device=x.device)
52
+ return torch.gather(x, 2, gather_indices)
53
+
54
+
55
+ def rand_slice_segments(x, x_lengths=None, segment_size=4):
56
+ b, d, t = x.size()
57
+ if x_lengths is None:
58
+ x_lengths = t
59
+ ids_str_max = torch.clamp(x_lengths - segment_size + 1, min=0)
60
+ ids_str = (torch.rand([b], device=x.device) * ids_str_max).to(dtype=torch.long)
61
+ ret = slice_segments(x, ids_str, segment_size)
62
+ return ret, ids_str
63
+
64
+
65
+ def get_timing_signal_1d(length, channels, min_timescale=1.0, max_timescale=1.0e4):
66
+ position = torch.arange(length, dtype=torch.float)
67
+ num_timescales = channels // 2
68
+ log_timescale_increment = math.log(float(max_timescale) / float(min_timescale)) / (
69
+ num_timescales - 1
70
+ )
71
+ inv_timescales = min_timescale * torch.exp(
72
+ torch.arange(num_timescales, dtype=torch.float) * -log_timescale_increment
73
+ )
74
+ scaled_time = position.unsqueeze(0) * inv_timescales.unsqueeze(1)
75
+ signal = torch.cat([torch.sin(scaled_time), torch.cos(scaled_time)], 0)
76
+ signal = F.pad(signal, [0, 0, 0, channels % 2])
77
+ signal = signal.view(1, channels, length)
78
+ return signal
79
+
80
+
81
+ def add_timing_signal_1d(x, min_timescale=1.0, max_timescale=1.0e4):
82
+ b, channels, length = x.size()
83
+ signal = get_timing_signal_1d(length, channels, min_timescale, max_timescale)
84
+ return x + signal.to(dtype=x.dtype, device=x.device)
85
+
86
+
87
+ def cat_timing_signal_1d(x, min_timescale=1.0, max_timescale=1.0e4, axis=1):
88
+ b, channels, length = x.size()
89
+ signal = get_timing_signal_1d(length, channels, min_timescale, max_timescale)
90
+ return torch.cat([x, signal.to(dtype=x.dtype, device=x.device)], axis)
91
+
92
+
93
+ def subsequent_mask(length):
94
+ mask = torch.tril(torch.ones(length, length)).unsqueeze(0).unsqueeze(0)
95
+ return mask
96
+
97
+
98
+ @torch.jit.script
99
+ def fused_add_tanh_sigmoid_multiply(input_a, input_b, n_channels):
100
+ n_channels_int = n_channels[0]
101
+ in_act = input_a + input_b
102
+ t_act = torch.tanh(in_act[:, :n_channels_int, :])
103
+ s_act = torch.sigmoid(in_act[:, n_channels_int:, :])
104
+ acts = t_act * s_act
105
+ return acts
106
+
107
+
108
+ def convert_pad_shape(pad_shape):
109
+ layer = pad_shape[::-1]
110
+ pad_shape = [item for sublist in layer for item in sublist]
111
+ return pad_shape
112
+
113
+
114
+ def shift_1d(x):
115
+ x = F.pad(x, convert_pad_shape([[0, 0], [0, 0], [1, 0]]))[:, :, :-1]
116
+ return x
117
+
118
+
119
+ def sequence_mask(length, max_length=None):
120
+ if max_length is None:
121
+ max_length = length.max()
122
+ x = torch.arange(max_length, dtype=length.dtype, device=length.device)
123
+ return x.unsqueeze(0) < length.unsqueeze(1)
124
+
125
+
126
+ def generate_path(duration, mask):
127
+ """
128
+ duration: [b, 1, t_x]
129
+ mask: [b, 1, t_y, t_x]
130
+ """
131
+
132
+ b, _, t_y, t_x = mask.shape
133
+ cum_duration = torch.cumsum(duration, -1)
134
+
135
+ cum_duration_flat = cum_duration.view(b * t_x)
136
+ path = sequence_mask(cum_duration_flat, t_y).to(mask.dtype)
137
+ path = path.view(b, t_x, t_y)
138
+ path = path - F.pad(path, convert_pad_shape([[0, 0], [1, 0], [0, 0]]))[:, :-1]
139
+ path = path.unsqueeze(1).transpose(2, 3) * mask
140
+ return path
141
+
142
+
143
+ def clip_grad_value_(parameters, clip_value, norm_type=2):
144
+ if isinstance(parameters, torch.Tensor):
145
+ parameters = [parameters]
146
+ parameters = list(filter(lambda p: p.grad is not None, parameters))
147
+ norm_type = float(norm_type)
148
+ if clip_value is not None:
149
+ clip_value = float(clip_value)
150
+
151
+ total_norm = 0
152
+ for p in parameters:
153
+ param_norm = p.grad.data.norm(norm_type)
154
+ total_norm += param_norm.item() ** norm_type
155
+ if clip_value is not None:
156
+ p.grad.data.clamp_(min=-clip_value, max=clip_value)
157
+ total_norm = total_norm ** (1.0 / norm_type)
158
+ return total_norm
BanG-Dream-VITS/compress_model.py ADDED
@@ -0,0 +1,89 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ from collections import OrderedDict
2
+ from text.symbols import symbols
3
+ import torch
4
+
5
+ from tools.log import logger
6
+ import utils
7
+ from models import SynthesizerTrn
8
+ import os
9
+
10
+
11
+ def copyStateDict(state_dict):
12
+ if list(state_dict.keys())[0].startswith("module"):
13
+ start_idx = 1
14
+ else:
15
+ start_idx = 0
16
+ new_state_dict = OrderedDict()
17
+ for k, v in state_dict.items():
18
+ name = ",".join(k.split(".")[start_idx:])
19
+ new_state_dict[name] = v
20
+ return new_state_dict
21
+
22
+
23
+ def removeOptimizer(config: str, input_model: str, ishalf: bool, output_model: str):
24
+ hps = utils.get_hparams_from_file(config)
25
+
26
+ net_g = SynthesizerTrn(
27
+ len(symbols),
28
+ hps.data.filter_length // 2 + 1,
29
+ hps.train.segment_size // hps.data.hop_length,
30
+ n_speakers=hps.data.n_speakers,
31
+ **hps.model,
32
+ )
33
+
34
+ optim_g = torch.optim.AdamW(
35
+ net_g.parameters(),
36
+ hps.train.learning_rate,
37
+ betas=hps.train.betas,
38
+ eps=hps.train.eps,
39
+ )
40
+
41
+ state_dict_g = torch.load(input_model, map_location="cpu")
42
+ new_dict_g = copyStateDict(state_dict_g)
43
+ keys = []
44
+ for k, v in new_dict_g["model"].items():
45
+ if "enc_q" in k:
46
+ continue # noqa: E701
47
+ keys.append(k)
48
+
49
+ new_dict_g = (
50
+ {k: new_dict_g["model"][k].half() for k in keys}
51
+ if ishalf
52
+ else {k: new_dict_g["model"][k] for k in keys}
53
+ )
54
+
55
+ torch.save(
56
+ {
57
+ "model": new_dict_g,
58
+ "iteration": 0,
59
+ "optimizer": optim_g.state_dict(),
60
+ "learning_rate": 0.0001,
61
+ },
62
+ output_model,
63
+ )
64
+
65
+
66
+ if __name__ == "__main__":
67
+ import argparse
68
+
69
+ parser = argparse.ArgumentParser()
70
+ parser.add_argument("-c", "--config", type=str, default="configs/config.json")
71
+ parser.add_argument("-i", "--input", type=str)
72
+ parser.add_argument("-o", "--output", type=str, default=None)
73
+ parser.add_argument(
74
+ "-hf", "--half", action="store_true", default=False, help="Save as FP16"
75
+ )
76
+
77
+ args = parser.parse_args()
78
+
79
+ output = args.output
80
+
81
+ if output is None:
82
+ import os.path
83
+
84
+ filename, ext = os.path.splitext(args.input)
85
+ half = "_half" if args.half else ""
86
+ output = filename + "_release" + half + ext
87
+
88
+ removeOptimizer(args.config, args.input, args.half, output)
89
+ logger.info(f"压缩模型成功, 输出模型: {os.path.abspath(output)}")
BanG-Dream-VITS/config.py ADDED
@@ -0,0 +1,248 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ """
2
+ @Desc: 全局配置文件读取
3
+ """
4
+ import argparse
5
+ import yaml
6
+ from typing import Dict, List
7
+ import os
8
+ import shutil
9
+ import sys
10
+
11
+
12
+ class Resample_config:
13
+ """重采样配置"""
14
+
15
+ def __init__(self, in_dir: str, out_dir: str, sampling_rate: int = 44100):
16
+ self.sampling_rate: int = sampling_rate # 目标采样率
17
+ self.in_dir: str = in_dir # 待处理音频目录路径
18
+ self.out_dir: str = out_dir # 重采样输出路径
19
+
20
+ @classmethod
21
+ def from_dict(cls, dataset_path: str, data: Dict[str, any]):
22
+ """从字典中生成实例"""
23
+
24
+ # 不检查路径是否有效,此逻辑在resample.py中处理
25
+ data["in_dir"] = os.path.join(dataset_path, data["in_dir"])
26
+ data["out_dir"] = os.path.join(dataset_path, data["out_dir"])
27
+
28
+ return cls(**data)
29
+
30
+
31
+ class Preprocess_text_config:
32
+ """数据预处理配置"""
33
+
34
+ def __init__(
35
+ self,
36
+ transcription_path: str,
37
+ cleaned_path: str,
38
+ train_path: str,
39
+ val_path: str,
40
+ config_path: str,
41
+ val_per_lang: int = 5,
42
+ max_val_total: int = 10000,
43
+ clean: bool = True,
44
+ ):
45
+ self.transcription_path: str = transcription_path # 原始文本文件路径,文本格式应为{wav_path}|{speaker_name}|{language}|{text}。
46
+ self.cleaned_path: str = cleaned_path # 数据清洗后文本路径,可以不填。不填则将在原始文本目录生成
47
+ self.train_path: str = train_path # 训练集路径,可以不填。不填则将在原始文本目录生成
48
+ self.val_path: str = val_path # 验证集路径,可以不填。不填则将在原始文本目录生成
49
+ self.config_path: str = config_path # 配置文件路径
50
+ self.val_per_lang: int = val_per_lang # 每个speaker的验证集条数
51
+ self.max_val_total: int = max_val_total # 验证集最大条数,多于的会被截断并放到训练集中
52
+ self.clean: bool = clean # 是否进行数据清洗
53
+
54
+ @classmethod
55
+ def from_dict(cls, dataset_path: str, data: Dict[str, any]):
56
+ """从字典中生成实例"""
57
+
58
+ data["transcription_path"] = os.path.join(
59
+ dataset_path, data["transcription_path"]
60
+ )
61
+ if data["cleaned_path"] == "" or data["cleaned_path"] is None:
62
+ data["cleaned_path"] = None
63
+ else:
64
+ data["cleaned_path"] = os.path.join(dataset_path, data["cleaned_path"])
65
+ data["train_path"] = os.path.join(dataset_path, data["train_path"])
66
+ data["val_path"] = os.path.join(dataset_path, data["val_path"])
67
+ data["config_path"] = os.path.join(dataset_path, data["config_path"])
68
+
69
+ return cls(**data)
70
+
71
+
72
+ class Bert_gen_config:
73
+ """bert_gen 配置"""
74
+
75
+ def __init__(
76
+ self,
77
+ config_path: str,
78
+ num_processes: int = 2,
79
+ device: str = "cuda",
80
+ use_multi_device: bool = False,
81
+ ):
82
+ self.config_path = config_path
83
+ self.num_processes = num_processes
84
+ self.device = device
85
+ self.use_multi_device = use_multi_device
86
+
87
+ @classmethod
88
+ def from_dict(cls, dataset_path: str, data: Dict[str, any]):
89
+ data["config_path"] = os.path.join(dataset_path, data["config_path"])
90
+
91
+ return cls(**data)
92
+
93
+
94
+ class Emo_gen_config:
95
+ """emo_gen 配置"""
96
+
97
+ def __init__(
98
+ self,
99
+ config_path: str,
100
+ num_processes: int = 2,
101
+ device: str = "cuda",
102
+ use_multi_device: bool = False,
103
+ ):
104
+ self.config_path = config_path
105
+ self.num_processes = num_processes
106
+ self.device = device
107
+ self.use_multi_device = use_multi_device
108
+
109
+ @classmethod
110
+ def from_dict(cls, dataset_path: str, data: Dict[str, any]):
111
+ data["config_path"] = os.path.join(dataset_path, data["config_path"])
112
+
113
+ return cls(**data)
114
+
115
+
116
+ class Train_ms_config:
117
+ """训练配置"""
118
+
119
+ def __init__(
120
+ self,
121
+ config_path: str,
122
+ env: Dict[str, any],
123
+ base: Dict[str, any],
124
+ model: str,
125
+ num_workers: int,
126
+ spec_cache: bool,
127
+ keep_ckpts: int,
128
+ ):
129
+ self.env = env # 需要加载的环境变量
130
+ self.base = base # 底模配置
131
+ self.model = model # 训练模型存储目录,该路径为相对于dataset_path的路径,而非项目根目录
132
+ self.config_path = config_path # 配置文件路径
133
+ self.num_workers = num_workers # worker数量
134
+ self.spec_cache = spec_cache # 是否启用spec缓存
135
+ self.keep_ckpts = keep_ckpts # ckpt数量
136
+
137
+ @classmethod
138
+ def from_dict(cls, dataset_path: str, data: Dict[str, any]):
139
+ # data["model"] = os.path.join(dataset_path, data["model"])
140
+ data["config_path"] = os.path.join(dataset_path, data["config_path"])
141
+
142
+ return cls(**data)
143
+
144
+
145
+ class Webui_config:
146
+ """webui 配置"""
147
+
148
+ def __init__(
149
+ self,
150
+ device: str,
151
+ model: str,
152
+ config_path: str,
153
+ language_identification_library: str,
154
+ port: int = 7860,
155
+ share: bool = False,
156
+ debug: bool = False,
157
+ ):
158
+ self.device: str = device
159
+ self.model: str = model # 端口号
160
+ self.config_path: str = config_path # 是否公开部署,对外网开放
161
+ self.port: int = port # 是否开启debug模式
162
+ self.share: bool = share # 模型路径
163
+ self.debug: bool = debug # 配置文件路径
164
+ self.language_identification_library: str = (
165
+ language_identification_library # 语种识别库
166
+ )
167
+
168
+ @classmethod
169
+ def from_dict(cls, dataset_path: str, data: Dict[str, any]):
170
+ data["config_path"] = os.path.join(dataset_path, data["config_path"])
171
+ data["model"] = os.path.join(dataset_path, data["model"])
172
+ return cls(**data)
173
+
174
+
175
+ class Server_config:
176
+ def __init__(
177
+ self, models: List[Dict[str, any]], port: int = 5000, device: str = "cuda"
178
+ ):
179
+ self.models: List[Dict[str, any]] = models # 需要加载的所有模型的配置
180
+ self.port: int = port # 端口号
181
+ self.device: str = device # 模型默认使用设备
182
+
183
+ @classmethod
184
+ def from_dict(cls, data: Dict[str, any]):
185
+ return cls(**data)
186
+
187
+
188
+ class Translate_config:
189
+ """翻译api配置"""
190
+
191
+ def __init__(self, app_key: str, secret_key: str):
192
+ self.app_key = app_key
193
+ self.secret_key = secret_key
194
+
195
+ @classmethod
196
+ def from_dict(cls, data: Dict[str, any]):
197
+ return cls(**data)
198
+
199
+
200
+ class Config:
201
+ def __init__(self, config_path: str):
202
+ if not os.path.isfile(config_path) and os.path.isfile("default_config.yml"):
203
+ shutil.copy(src="default_config.yml", dst=config_path)
204
+ print(
205
+ f"已根据默认配置文件default_config.yml生成配置文件{config_path}。请按该配置文件的说明进行配置后重新运行。"
206
+ )
207
+ print("如无特殊需求,请勿修改default_config.yml或备份该文件。")
208
+ sys.exit(0)
209
+ with open(file=config_path, mode="r", encoding="utf-8") as file:
210
+ yaml_config: Dict[str, any] = yaml.safe_load(file.read())
211
+ dataset_path: str = yaml_config["dataset_path"]
212
+ openi_token: str = yaml_config["openi_token"]
213
+ self.dataset_path: str = dataset_path
214
+ self.mirror: str = yaml_config["mirror"]
215
+ self.openi_token: str = openi_token
216
+ self.resample_config: Resample_config = Resample_config.from_dict(
217
+ dataset_path, yaml_config["resample"]
218
+ )
219
+ self.preprocess_text_config: Preprocess_text_config = (
220
+ Preprocess_text_config.from_dict(
221
+ dataset_path, yaml_config["preprocess_text"]
222
+ )
223
+ )
224
+ self.bert_gen_config: Bert_gen_config = Bert_gen_config.from_dict(
225
+ dataset_path, yaml_config["bert_gen"]
226
+ )
227
+ self.emo_gen_config: Emo_gen_config = Emo_gen_config.from_dict(
228
+ dataset_path, yaml_config["emo_gen"]
229
+ )
230
+ self.train_ms_config: Train_ms_config = Train_ms_config.from_dict(
231
+ dataset_path, yaml_config["train_ms"]
232
+ )
233
+ self.webui_config: Webui_config = Webui_config.from_dict(
234
+ dataset_path, yaml_config["webui"]
235
+ )
236
+ self.server_config: Server_config = Server_config.from_dict(
237
+ yaml_config["server"]
238
+ )
239
+ self.translate_config: Translate_config = Translate_config.from_dict(
240
+ yaml_config["translate"]
241
+ )
242
+
243
+
244
+ parser = argparse.ArgumentParser()
245
+ # 为避免与以前的config.json起冲突,将其更名如下
246
+ parser.add_argument("-y", "--yml_config", type=str, default="config.yml")
247
+ args, _ = parser.parse_known_args()
248
+ config = Config(args.yml_config)
BanG-Dream-VITS/config.yml ADDED
@@ -0,0 +1,177 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ # 全局配置
2
+ # 对于希望在同一时间使用多个配置文件的情况,例如两个GPU同时跑两个训练集:通过环境变量指定配置文件,不指定则默认为./config.yml
3
+
4
+ # 拟提供通用路径配置,统一存放数据,避免数据放得很乱
5
+ # 每个数据集与其对应的模型存放至统一路径下,后续所有的路径配置均为相对于datasetPath的路径
6
+ # 不填或者填空则路径为相对于项目根目录的路径
7
+ dataset_path: "Data/"
8
+
9
+ # 模型镜像源,默认huggingface,使用openi镜像源需指定openi_token
10
+ mirror: ""
11
+ openi_token: "" # openi token
12
+
13
+ # resample 音频重采样配置
14
+ # 注意, “:” 后需要加空格
15
+ resample:
16
+ # 目标重采样率
17
+ sampling_rate: 44100
18
+ # 音频文件输入路径,重采样会将该路径下所有.wav音频文件重采样
19
+ # 请填入相对于datasetPath的相对路径
20
+ in_dir: "audios/raw" # 相对于根目录的路径为 /datasetPath/in_dir
21
+ # 音频文件重采样后输出路径
22
+ out_dir: "audios/wavs"
23
+
24
+
25
+ # preprocess_text 数据集预处理相关配置
26
+ # 注意, “:” 后需要加空格
27
+ preprocess_text:
28
+ # 原始文本文件路径,文本格式应为{wav_path}|{speaker_name}|{language}|{text}。
29
+ transcription_path: "filelists/你的数据集文本.list"
30
+ # 数据清洗后文本路径,可以不填。不填则将在原始文本目录生成
31
+ cleaned_path: ""
32
+ # 训练集路径
33
+ train_path: "filelists/train.list"
34
+ # 验证集路径
35
+ val_path: "filelists/val.list"
36
+ # 配置文件路径
37
+ config_path: "config.json"
38
+ # 每个语言的验证集条数
39
+ val_per_lang: 4
40
+ # 验证集最大条数,多于的会被截断并放到训练集中
41
+ max_val_total: 12
42
+ # 是否进行数据清洗
43
+ clean: true
44
+
45
+
46
+ # bert_gen 相关配置
47
+ # 注意, “:” 后需要加空格
48
+ bert_gen:
49
+ # 训练数据集配置文件路径
50
+ config_path: "config.json"
51
+ # 并行数
52
+ num_processes: 4
53
+ # 使用设备:可选项 "cuda" 显卡推理,"cpu" cpu推理
54
+ # 该选项同时决定了get_bert_feature的默认设备
55
+ device: "cuda"
56
+ # 使用多卡推理
57
+ use_multi_device: false
58
+
59
+ # emo_gen 相关配置
60
+ # 注意, “:” 后需要加空格
61
+ emo_gen:
62
+ # 训练数据集配置文件路径
63
+ config_path: "config.json"
64
+ # 并行数
65
+ num_processes: 4
66
+ # 使用设备:可选项 "cuda" 显卡推理,"cpu" cpu推理
67
+ device: "cuda"
68
+ # 使用多卡推理
69
+ use_multi_device: false
70
+
71
+ # train 训练配置
72
+ # 注意, “:” 后需要加空格
73
+ train_ms:
74
+ env:
75
+ MASTER_ADDR: "localhost"
76
+ MASTER_PORT: 10086
77
+ WORLD_SIZE: 1
78
+ LOCAL_RANK: 0
79
+ RANK: 0
80
+ # 可以填写任意名的环境变量
81
+ # THE_ENV_VAR_YOU_NEED_TO_USE: "1234567"
82
+ # 底模设置
83
+ base:
84
+ use_base_model: false
85
+ repo_id: "Stardust_minus/Bert-VITS2"
86
+ model_image: "Bert-VITS2_2.3底模" # openi网页的模型名
87
+ # 训练模型存储目录:与旧版本的区别,原先数据集是存放在logs/model_name下的,现在改为统一存放在Data/你的数据集/models下
88
+ model: "models"
89
+ # 配置文件路径
90
+ config_path: "config.json"
91
+ # 训练使用的worker,不建议超过CPU核心数
92
+ num_workers: 16
93
+ # 关闭此项可以节约接近50%的磁盘空间,但是可能导致实际训练速度变慢和更高的CPU使用率。
94
+ spec_cache: True
95
+ # 保存的检查点数量,多于此数目的权重会被删除来节省空间。
96
+ keep_ckpts: 8
97
+
98
+
99
+ # webui webui配置
100
+ # 注意, “:” 后需要加空格
101
+ webui:
102
+ # 推理设备
103
+ device: "cuda"
104
+ # 模型路径
105
+ model: "models/G_8000.pth"
106
+ # 配置文件路径
107
+ config_path: "config.json"
108
+ # 端口号
109
+ port: 7860
110
+ # 是否公开部署,对外网开放
111
+ share: false
112
+ # 是否开启debug模式
113
+ debug: false
114
+ # 语种识别库,可选langid, fastlid
115
+ language_identification_library: "langid"
116
+
117
+
118
+ # server-fastapi配置
119
+ # 注意, “:” 后需要加空格
120
+ # 注意,本配置下的所有配置均为相对于根目录的路径
121
+ server:
122
+ # 端口号
123
+ port: 5000
124
+ # 模型默认使用设备:但是当前并没有实现这个配置。
125
+ device: "cuda"
126
+ # 需要加载的所有模型的配置,可以填多个模型,也可以不填模型,等网页成功后手动加载模型
127
+ # 不加载模型的配置格式:删除默认给的两个模型配置,给models赋值 [ ],也就是空列表。参考模型2的speakers 即 models: [ ]
128
+ # 注意,所有模型都必须正确配置model与config的路径,空路径会导致加载错误。
129
+ # 也可以不填模型,等网页加载成功后手动填写models。
130
+ models:
131
+ - # 模型的路径
132
+ model: ""
133
+ # 模型config.json的路径
134
+ config: ""
135
+ # 模型使用设备,若填写则会覆盖默认配置
136
+ device: "cuda"
137
+ # 模型默认使用的语言
138
+ language: "ZH"
139
+ # 模型人物默认参数
140
+ # 不必填写所有人物,不填的使用默认值
141
+ # 暂时不用填写,当前尚未实现按人区分配置
142
+ speakers:
143
+ - speaker: "科比"
144
+ sdp_ratio: 0.2
145
+ noise_scale: 0.6
146
+ noise_scale_w: 0.8
147
+ length_scale: 1
148
+ - speaker: "五条悟"
149
+ sdp_ratio: 0.3
150
+ noise_scale: 0.7
151
+ noise_scale_w: 0.8
152
+ length_scale: 0.5
153
+ - speaker: "安倍晋三"
154
+ sdp_ratio: 0.2
155
+ noise_scale: 0.6
156
+ noise_scale_w: 0.8
157
+ length_scale: 1.2
158
+ - # 模型的路径
159
+ model: ""
160
+ # 模型config.json的路径
161
+ config: ""
162
+ # 模型使用设备,若填写则会覆盖默认配置
163
+ device: "cpu"
164
+ # 模型默认使用的语言
165
+ language: "JP"
166
+ # 模型人物默认参数
167
+ # 不必填写所有人物,不填的使用默认值
168
+ speakers: [ ] # 也可以不填
169
+
170
+ # 百度翻译开放平台 api配置
171
+ # api接入文档 https://api.fanyi.baidu.com/doc/21
172
+ # 请不要在github等网站公开分享你的app id 与 key
173
+ translate:
174
+ # 你的APPID
175
+ "app_key": "20231117001883321"
176
+ # 你的密钥
177
+ "secret_key": "lMQbvZHeJveDceLof2wf"
BanG-Dream-VITS/configs/config.json ADDED
@@ -0,0 +1,957 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ {
2
+ "train": {
3
+ "log_interval": 200,
4
+ "eval_interval": 1000,
5
+ "seed": 42,
6
+ "epochs": 1000,
7
+ "learning_rate": 0.0002,
8
+ "betas": [
9
+ 0.8,
10
+ 0.99
11
+ ],
12
+ "eps": 1e-09,
13
+ "batch_size": 16,
14
+ "bf16_run": false,
15
+ "lr_decay": 0.99995,
16
+ "segment_size": 16384,
17
+ "init_lr_ratio": 1,
18
+ "warmup_epochs": 0,
19
+ "c_mel": 45,
20
+ "c_kl": 1.0,
21
+ "c_commit": 100,
22
+ "skip_optimizer": true,
23
+ "freeze_ZH_bert": false,
24
+ "freeze_JP_bert": false,
25
+ "freeze_EN_bert": false,
26
+ "freeze_emo": false
27
+ },
28
+ "data": {
29
+ "training_files": "filelists/train.list",
30
+ "validation_files": "filelists/val.list",
31
+ "max_wav_value": 32768.0,
32
+ "sampling_rate": 44100,
33
+ "filter_length": 2048,
34
+ "hop_length": 512,
35
+ "win_length": 2048,
36
+ "n_mel_channels": 128,
37
+ "mel_fmin": 0.0,
38
+ "mel_fmax": null,
39
+ "add_blank": true,
40
+ "n_speakers": 850,
41
+ "cleaned_text": true,
42
+ "spk2id": {
43
+ "派蒙_ZH": 0,
44
+ "纳西妲_ZH": 1,
45
+ "凯亚_ZH": 2,
46
+ "阿贝多_ZH": 3,
47
+ "温迪_ZH": 4,
48
+ "枫原万叶_ZH": 5,
49
+ "钟离_ZH": 6,
50
+ "荒泷一斗_ZH": 7,
51
+ "八重神子_ZH": 8,
52
+ "艾尔海森_ZH": 9,
53
+ "提纳里_ZH": 10,
54
+ "迪希雅_ZH": 11,
55
+ "卡维_ZH": 12,
56
+ "宵宫_ZH": 13,
57
+ "那维莱特_ZH": 14,
58
+ "莱依拉_ZH": 15,
59
+ "赛诺_ZH": 16,
60
+ "莫娜_ZH": 17,
61
+ "诺艾尔_ZH": 18,
62
+ "托马_ZH": 19,
63
+ "凝光_ZH": 20,
64
+ "林尼_ZH": 21,
65
+ "北斗_ZH": 22,
66
+ "柯莱_ZH": 23,
67
+ "神里绫华_ZH": 24,
68
+ "可莉_ZH": 25,
69
+ "芭芭拉_ZH": 26,
70
+ "雷电将军_ZH": 27,
71
+ "娜维娅_ZH": 28,
72
+ "芙宁娜_ZH": 29,
73
+ "珊瑚宫心海_ZH": 30,
74
+ "鹿野院平藏_ZH": 31,
75
+ "迪奥娜_ZH": 32,
76
+ "琴_ZH": 33,
77
+ "五郎_ZH": 34,
78
+ "班尼特_ZH": 35,
79
+ "达达利亚_ZH": 36,
80
+ "安柏_ZH": 37,
81
+ "莱欧斯利_ZH": 38,
82
+ "夜兰_ZH": 39,
83
+ "妮露_ZH": 40,
84
+ "辛焱_ZH": 41,
85
+ "丽莎_ZH": 42,
86
+ "珐露珊_ZH": 43,
87
+ "魈_ZH": 44,
88
+ "香菱_ZH": 45,
89
+ "迪卢克_ZH": 46,
90
+ "砂糖_ZH": 47,
91
+ "烟绯_ZH": 48,
92
+ "早柚_ZH": 49,
93
+ "云堇_ZH": 50,
94
+ "刻晴_ZH": 51,
95
+ "重云_ZH": 52,
96
+ "优菈_ZH": 53,
97
+ "胡桃_ZH": 54,
98
+ "流浪者_ZH": 55,
99
+ "久岐忍_ZH": 56,
100
+ "神里绫人_ZH": 57,
101
+ "甘雨_ZH": 58,
102
+ "戴因斯雷布_ZH": 59,
103
+ "菲谢尔_ZH": 60,
104
+ "白术_ZH": 61,
105
+ "行秋_ZH": 62,
106
+ "九条裟罗_ZH": 63,
107
+ "夏洛蒂_ZH": 64,
108
+ "雷泽_ZH": 65,
109
+ "申鹤_ZH": 66,
110
+ "荧_ZH": 67,
111
+ "空_ZH": 68,
112
+ "迪娜泽黛_ZH": 69,
113
+ "凯瑟琳_ZH": 70,
114
+ "多莉_ZH": 71,
115
+ "坎蒂丝_ZH": 72,
116
+ "琳妮特_ZH": 73,
117
+ "萍姥姥_ZH": 74,
118
+ "罗莎莉亚_ZH": 75,
119
+ "埃德_ZH": 76,
120
+ "爱贝尔_ZH": 77,
121
+ "伊迪娅_ZH": 78,
122
+ "留云借风真君_ZH": 79,
123
+ "绮良良_ZH": 80,
124
+ "陌生人_ZH": 81,
125
+ "七七_ZH": 82,
126
+ "式大将_ZH": 83,
127
+ "瑶瑶_ZH": 84,
128
+ "奥兹_ZH": 85,
129
+ "菲米尼_ZH": 86,
130
+ "米卡_ZH": 87,
131
+ "哲平_ZH": 88,
132
+ "浮游水蕈兽·元素生命_ZH": 89,
133
+ "大肉丸_ZH": 90,
134
+ "托克_ZH": 91,
135
+ "蒂玛乌斯_ZH": 92,
136
+ "昆钧_ZH": 93,
137
+ "欧菲妮_ZH": 94,
138
+ "塞琉斯_ZH": 95,
139
+ "仆人_ZH": 96,
140
+ "迈勒斯_ZH": 97,
141
+ "希格雯_ZH": 98,
142
+ "阿守_ZH": 99,
143
+ "拉赫曼_ZH": 100,
144
+ "杜拉夫_ZH": 101,
145
+ "伊利亚斯_ZH": 102,
146
+ "阿晃_ZH": 103,
147
+ "旁白_ZH": 104,
148
+ "爱德琳_ZH": 105,
149
+ "埃洛伊_ZH": 106,
150
+ "德沃沙克_ZH": 107,
151
+ "玛乔丽_ZH": 108,
152
+ "塞塔蕾_ZH": 109,
153
+ "柊千里_ZH": 110,
154
+ "海芭夏_ZH": 111,
155
+ "九条镰治_ZH": 112,
156
+ "阿娜耶_ZH": 113,
157
+ "笼钓瓶一心_ZH": 114,
158
+ "回声海螺_ZH": 115,
159
+ "劳维克_ZH": 116,
160
+ "元太_ZH": 117,
161
+ "阿扎尔_ZH": 118,
162
+ "查尔斯_ZH": 119,
163
+ "阿洛瓦_ZH": 120,
164
+ "埃勒曼_ZH": 121,
165
+ "纳比尔_ZH": 122,
166
+ "莎拉_ZH": 123,
167
+ "康纳_ZH": 124,
168
+ "博来_ZH": 125,
169
+ "玛塞勒_ZH": 126,
170
+ "阿祇_ZH": 127,
171
+ "博士_ZH": 128,
172
+ "玛格丽特_ZH": 129,
173
+ "迪尔菲_ZH": 130,
174
+ "宛烟_ZH": 131,
175
+ "羽生田千鹤_ZH": 132,
176
+ "海妮耶_ZH": 133,
177
+ "旅行者_ZH": 134,
178
+ "霍夫曼_ZH": 135,
179
+ "佐西摩斯_ZH": 136,
180
+ "鹿野奈奈_ZH": 137,
181
+ "舒伯特_ZH": 138,
182
+ "天叔_ZH": 139,
183
+ "艾莉丝_ZH": 140,
184
+ "龙二_ZH": 141,
185
+ "莺儿_ZH": 142,
186
+ "嘉良_ZH": 143,
187
+ "一心传名刀_ZH": 144,
188
+ "珊瑚_ZH": 145,
189
+ "言笑_ZH": 146,
190
+ "久利须_ZH": 147,
191
+ "嘉玛_ZH": 148,
192
+ "艾文_ZH": 149,
193
+ "克洛琳德_ZH": 150,
194
+ "丹吉尔_ZH": 151,
195
+ "女士_ZH": 152,
196
+ "白老先生_ZH": 153,
197
+ "天目十五_ZH": 154,
198
+ "老孟_ZH": 155,
199
+ "巴达维_ZH": 156,
200
+ "长生_ZH": 157,
201
+ "吴船长_ZH": 158,
202
+ "拉齐_ZH": 159,
203
+ "艾伯特_ZH": 160,
204
+ "松浦_ZH": 161,
205
+ "埃泽_ZH": 162,
206
+ "阿圆_ZH": 163,
207
+ "莫塞伊思_ZH": 164,
208
+ "阿拉夫_ZH": 165,
209
+ "杜吉耶_ZH": 166,
210
+ "石头_ZH": 167,
211
+ "百闻_ZH": 168,
212
+ "波洛_ZH": 169,
213
+ "斯坦利_ZH": 170,
214
+ "博易_ZH": 171,
215
+ "迈蒙_ZH": 172,
216
+ "掇星攫辰天君_ZH": 173,
217
+ "毗伽尔_ZH": 174,
218
+ "芙卡洛斯_ZH": 175,
219
+ "恶龙_ZH": 176,
220
+ "恕筠_ZH": 177,
221
+ "知易_ZH": 178,
222
+ "克列门特_ZH": 179,
223
+ "大慈树王_ZH": 180,
224
+ "西拉杰_ZH": 181,
225
+ "上杉_ZH": 182,
226
+ "阿尔卡米_ZH": 183,
227
+ "纯水精灵_ZH": 184,
228
+ "常九爷_ZH": 185,
229
+ "沙扎曼_ZH": 186,
230
+ "田铁嘴_ZH": 187,
231
+ "克罗索_ZH": 188,
232
+ "阿巴图伊_ZH": 189,
233
+ "阿佩普_ZH": 190,
234
+ "埃尔欣根_ZH": 191,
235
+ "萨赫哈蒂_ZH": 192,
236
+ "塔杰·拉德卡尼_ZH": 193,
237
+ "安西_ZH": 194,
238
+ "陆行岩本真蕈·元素生命_ZH": 195,
239
+ "派蒙_JP": 196,
240
+ "纳西妲_JP": 197,
241
+ "凯亚_JP": 198,
242
+ "阿贝多_JP": 199,
243
+ "温迪_JP": 200,
244
+ "枫原万叶_JP": 201,
245
+ "钟离_JP": 202,
246
+ "荒泷一斗_JP": 203,
247
+ "八重神子_JP": 204,
248
+ "艾尔海森_JP": 205,
249
+ "提纳里_JP": 206,
250
+ "迪希雅_JP": 207,
251
+ "卡维_JP": 208,
252
+ "宵宫_JP": 209,
253
+ "那维莱特_JP": 210,
254
+ "莱依拉_JP": 211,
255
+ "赛诺_JP": 212,
256
+ "莫娜_JP": 213,
257
+ "诺艾尔_JP": 214,
258
+ "托马_JP": 215,
259
+ "凝光_JP": 216,
260
+ "林尼_JP": 217,
261
+ "北斗_JP": 218,
262
+ "柯莱_JP": 219,
263
+ "神里绫华_JP": 220,
264
+ "可莉_JP": 221,
265
+ "芭芭拉_JP": 222,
266
+ "雷电将军_JP": 223,
267
+ "娜维娅_JP": 224,
268
+ "芙宁娜_JP": 225,
269
+ "珊瑚宫心海_JP": 226,
270
+ "鹿野院平藏_JP": 227,
271
+ "迪奥娜_JP": 228,
272
+ "琴_JP": 229,
273
+ "五郎_JP": 230,
274
+ "班尼特_JP": 231,
275
+ "达达利亚_JP": 232,
276
+ "安柏_JP": 233,
277
+ "莱欧斯利_JP": 234,
278
+ "夜兰_JP": 235,
279
+ "妮露_JP": 236,
280
+ "辛焱_JP": 237,
281
+ "丽莎_JP": 238,
282
+ "珐露珊_JP": 239,
283
+ "魈_JP": 240,
284
+ "香菱_JP": 241,
285
+ "迪卢克_JP": 242,
286
+ "砂糖_JP": 243,
287
+ "烟绯_JP": 244,
288
+ "早柚_JP": 245,
289
+ "云堇_JP": 246,
290
+ "刻晴_JP": 247,
291
+ "重云_JP": 248,
292
+ "优菈_JP": 249,
293
+ "胡桃_JP": 250,
294
+ "流浪者_JP": 251,
295
+ "久岐忍_JP": 252,
296
+ "神里绫人_JP": 253,
297
+ "甘雨_JP": 254,
298
+ "戴因斯雷布_JP": 255,
299
+ "菲谢尔_JP": 256,
300
+ "白术_JP": 257,
301
+ "行秋_JP": 258,
302
+ "九条裟罗_JP": 259,
303
+ "夏洛蒂_JP": 260,
304
+ "雷泽_JP": 261,
305
+ "申鹤_JP": 262,
306
+ "空_JP": 263,
307
+ "荧_JP": 264,
308
+ "迪娜泽黛_JP": 265,
309
+ "凯瑟琳_JP": 266,
310
+ "多莉_JP": 267,
311
+ "坎蒂丝_JP": 268,
312
+ "琳妮特_JP": 269,
313
+ "萍姥姥_JP": 270,
314
+ "罗莎莉亚_JP": 271,
315
+ "埃德_JP": 272,
316
+ "爱贝尔_JP": 273,
317
+ "伊迪娅_JP": 274,
318
+ "留云借风真君_JP": 275,
319
+ "绮良良_JP": 276,
320
+ "陌生人_JP": 277,
321
+ "七七_JP": 278,
322
+ "式大将_JP": 279,
323
+ "瑶瑶_JP": 280,
324
+ "奥兹_JP": 281,
325
+ "菲米尼_JP": 282,
326
+ "米卡_JP": 283,
327
+ "哲平_JP": 284,
328
+ "浮游水蕈兽·元素生命_JP": 285,
329
+ "大肉丸_JP": 286,
330
+ "托克_JP": 287,
331
+ "蒂玛乌斯_JP": 288,
332
+ "昆钧_JP": 289,
333
+ "欧菲妮_JP": 290,
334
+ "塞琉斯_JP": 291,
335
+ "仆人_JP": 292,
336
+ "迈勒斯_JP": 293,
337
+ "希格雯_JP": 294,
338
+ "阿守_JP": 295,
339
+ "拉赫曼_JP": 296,
340
+ "杜拉夫_JP": 297,
341
+ "伊利亚斯_JP": 298,
342
+ "阿晃_JP": 299,
343
+ "旁白_JP": 300,
344
+ "爱德琳_JP": 301,
345
+ "埃洛伊_JP": 302,
346
+ "德沃沙克_JP": 303,
347
+ "玛乔丽_JP": 304,
348
+ "塞塔蕾_JP": 305,
349
+ "柊千里_JP": 306,
350
+ "海芭夏_JP": 307,
351
+ "九条镰治_JP": 308,
352
+ "阿娜耶_JP": 309,
353
+ "笼钓瓶一心_JP": 310,
354
+ "回声海螺_JP": 311,
355
+ "劳维克_JP": 312,
356
+ "元太_JP": 313,
357
+ "阿扎尔_JP": 314,
358
+ "查尔斯_JP": 315,
359
+ "阿洛瓦_JP": 316,
360
+ "埃勒曼_JP": 317,
361
+ "纳比尔_JP": 318,
362
+ "莎拉_JP": 319,
363
+ "康纳_JP": 320,
364
+ "博来_JP": 321,
365
+ "玛塞勒_JP": 322,
366
+ "阿祇_JP": 323,
367
+ "博士_JP": 324,
368
+ "迪尔菲_JP": 325,
369
+ "玛格丽特_JP": 326,
370
+ "宛烟_JP": 327,
371
+ "羽生田千鹤_JP": 328,
372
+ "海妮耶_JP": 329,
373
+ "霍夫曼_JP": 330,
374
+ "旅行者_JP": 331,
375
+ "佐西摩斯_JP": 332,
376
+ "舒伯特_JP": 333,
377
+ "鹿野奈奈_JP": 334,
378
+ "天叔_JP": 335,
379
+ "龙二_JP": 336,
380
+ "艾莉丝_JP": 337,
381
+ "莺儿_JP": 338,
382
+ "嘉良_JP": 339,
383
+ "珊瑚_JP": 340,
384
+ "言笑_JP": 341,
385
+ "一心传名刀_JP": 342,
386
+ "费迪南德_JP": 343,
387
+ "久利须_JP": 344,
388
+ "嘉玛_JP": 345,
389
+ "艾文_JP": 346,
390
+ "克洛琳德_JP": 347,
391
+ "丹吉尔_JP": 348,
392
+ "天目十五_JP": 349,
393
+ "女士_JP": 350,
394
+ "老孟_JP": 351,
395
+ "白老先生_JP": 352,
396
+ "舍利夫_JP": 353,
397
+ "巴达维_JP": 354,
398
+ "拉齐_JP": 355,
399
+ "长生_JP": 356,
400
+ "吴船长_JP": 357,
401
+ "艾伯特_JP": 358,
402
+ "松浦_JP": 359,
403
+ "埃泽_JP": 360,
404
+ "阿圆_JP": 361,
405
+ "阿拉夫_JP": 362,
406
+ "莫塞伊思_JP": 363,
407
+ "石头_JP": 364,
408
+ "百闻_JP": 365,
409
+ "杜吉耶_JP": 366,
410
+ "波洛_JP": 367,
411
+ "掇星攫辰天君_JP": 368,
412
+ "迈蒙_JP": 369,
413
+ "博易_JP": 370,
414
+ "诗筠_JP": 371,
415
+ "斯坦利_JP": 372,
416
+ "毗伽尔_JP": 373,
417
+ "芙卡洛斯_JP": 374,
418
+ "恶龙_JP": 375,
419
+ "小仓澪_JP": 376,
420
+ "恕筠_JP": 377,
421
+ "知易_JP": 378,
422
+ "克列门特_JP": 379,
423
+ "大慈树王_JP": 380,
424
+ "望雅_JP": 381,
425
+ "黑田_JP": 382,
426
+ "卡莉娜_JP": 383,
427
+ "马姆杜_JP": 384,
428
+ "科林斯_JP": 385,
429
+ "上杉_JP": 386,
430
+ "西拉杰_JP": 387,
431
+ "菲尔戈黛特_JP": 388,
432
+ "一平_JP": 389,
433
+ "纯水精灵_JP": 390,
434
+ "阿尔卡米_JP": 391,
435
+ "老戴_JP": 392,
436
+ "谢赫祖拜尔_JP": 393,
437
+ "沙扎曼_JP": 394,
438
+ "田铁嘴_JP": 395,
439
+ "小野寺_JP": 396,
440
+ "百识_JP": 397,
441
+ "克罗索_JP": 398,
442
+ "莱斯格_JP": 399,
443
+ "芷巧_JP": 400,
444
+ "加藤洋平_JP": 401,
445
+ "阿巴图伊_JP": 402,
446
+ "埃尔欣根_JP": 403,
447
+ "斯嘉莉_JP": 404,
448
+ "阿佩普_JP": 405,
449
+ "巫女_JP": 406,
450
+ "卡布斯_JP": 407,
451
+ "洛伦佐_JP": 408,
452
+ "萨赫哈蒂_JP": 409,
453
+ "娜德瓦_JP": 410,
454
+ "塞德娜_JP": 411,
455
+ "塔杰·拉德卡尼_JP": 412,
456
+ "绘星_JP": 413,
457
+ "泽田_JP": 414,
458
+ "安西_JP": 415,
459
+ "拉伊德_JP": 416,
460
+ "亚卡巴_JP": 417,
461
+ "有乐斋_JP": 418,
462
+ "莱昂_JP": 419,
463
+ "尤苏波夫_JP": 420,
464
+ "夏妮_JP": 421,
465
+ "埃舍尔_JP": 422,
466
+ "萨齐因_JP": 423,
467
+ "古山_JP": 424,
468
+ "自称渊上之物_JP": 425,
469
+ "丹羽_JP": 426,
470
+ "塞萨尔的日记_JP": 427,
471
+ "派蒙_EN": 428,
472
+ "纳西妲_EN": 429,
473
+ "凯亚_EN": 430,
474
+ "阿贝多_EN": 431,
475
+ "温迪_EN": 432,
476
+ "枫原万叶_EN": 433,
477
+ "钟离_EN": 434,
478
+ "荒泷一斗_EN": 435,
479
+ "八重神子_EN": 436,
480
+ "艾尔海森_EN": 437,
481
+ "提纳里_EN": 438,
482
+ "迪希雅_EN": 439,
483
+ "卡维_EN": 440,
484
+ "宵宫_EN": 441,
485
+ "莱依拉_EN": 442,
486
+ "那维莱特_EN": 443,
487
+ "赛诺_EN": 444,
488
+ "莫娜_EN": 445,
489
+ "诺艾尔_EN": 446,
490
+ "托马_EN": 447,
491
+ "凝光_EN": 448,
492
+ "林尼_EN": 449,
493
+ "北斗_EN": 450,
494
+ "柯莱_EN": 451,
495
+ "神里绫华_EN": 452,
496
+ "可莉_EN": 453,
497
+ "芭芭拉_EN": 454,
498
+ "雷电将军_EN": 455,
499
+ "娜维娅_EN": 456,
500
+ "芙宁娜_EN": 457,
501
+ "珊瑚宫心海_EN": 458,
502
+ "鹿野院平藏_EN": 459,
503
+ "迪奥娜_EN": 460,
504
+ "五郎_EN": 461,
505
+ "琴_EN": 462,
506
+ "班尼特_EN": 463,
507
+ "达达利亚_EN": 464,
508
+ "安柏_EN": 465,
509
+ "莱欧斯利_EN": 466,
510
+ "夜兰_EN": 467,
511
+ "妮露_EN": 468,
512
+ "辛焱_EN": 469,
513
+ "珐露珊_EN": 470,
514
+ "丽莎_EN": 471,
515
+ "魈_EN": 472,
516
+ "香菱_EN": 473,
517
+ "迪卢克_EN": 474,
518
+ "砂糖_EN": 475,
519
+ "烟绯_EN": 476,
520
+ "早柚_EN": 477,
521
+ "云堇_EN": 478,
522
+ "刻晴_EN": 479,
523
+ "重云_EN": 480,
524
+ "优菈_EN": 481,
525
+ "胡桃_EN": 482,
526
+ "流浪者_EN": 483,
527
+ "久岐忍_EN": 484,
528
+ "神里绫人_EN": 485,
529
+ "甘雨_EN": 486,
530
+ "戴因斯雷布_EN": 487,
531
+ "菲谢尔_EN": 488,
532
+ "白术_EN": 489,
533
+ "行秋_EN": 490,
534
+ "九条裟罗_EN": 491,
535
+ "夏洛蒂_EN": 492,
536
+ "雷泽_EN": 493,
537
+ "申鹤_EN": 494,
538
+ "荧_EN": 495,
539
+ "空_EN": 496,
540
+ "迪娜泽黛_EN": 497,
541
+ "凯瑟琳_EN": 498,
542
+ "多莉_EN": 499,
543
+ "坎蒂丝_EN": 500,
544
+ "琳妮特_EN": 501,
545
+ "萍姥姥_EN": 502,
546
+ "罗莎莉亚_EN": 503,
547
+ "埃德_EN": 504,
548
+ "爱贝尔_EN": 505,
549
+ "伊迪娅_EN": 506,
550
+ "留云借风真君_EN": 507,
551
+ "绮良良_EN": 508,
552
+ "陌生人_EN": 509,
553
+ "七七_EN": 510,
554
+ "式大将_EN": 511,
555
+ "瑶瑶_EN": 512,
556
+ "奥兹_EN": 513,
557
+ "菲米尼_EN": 514,
558
+ "米卡_EN": 515,
559
+ "哲平_EN": 516,
560
+ "浮游水蕈兽·元素生命_EN": 517,
561
+ "大肉丸_EN": 518,
562
+ "托克_EN": 519,
563
+ "蒂玛乌斯_EN": 520,
564
+ "昆钧_EN": 521,
565
+ "欧菲妮_EN": 522,
566
+ "塞琉斯_EN": 523,
567
+ "仆人_EN": 524,
568
+ "迈勒斯_EN": 525,
569
+ "希格雯_EN": 526,
570
+ "阿守_EN": 527,
571
+ "拉赫曼_EN": 528,
572
+ "杜拉夫_EN": 529,
573
+ "伊利亚斯_EN": 530,
574
+ "阿晃_EN": 531,
575
+ "旁白_EN": 532,
576
+ "爱德琳_EN": 533,
577
+ "埃洛伊_EN": 534,
578
+ "德沃沙克_EN": 535,
579
+ "玛乔丽_EN": 536,
580
+ "塞塔蕾_EN": 537,
581
+ "柊千里_EN": 538,
582
+ "海芭夏_EN": 539,
583
+ "九条镰治_EN": 540,
584
+ "阿娜耶_EN": 541,
585
+ "笼钓瓶一心_EN": 542,
586
+ "回声海螺_EN": 543,
587
+ "劳维克_EN": 544,
588
+ "元太_EN": 545,
589
+ "阿扎尔_EN": 546,
590
+ "查尔斯_EN": 547,
591
+ "阿洛瓦_EN": 548,
592
+ "埃勒曼_EN": 549,
593
+ "纳比尔_EN": 550,
594
+ "莎拉_EN": 551,
595
+ "康纳_EN": 552,
596
+ "博来_EN": 553,
597
+ "玛塞勒_EN": 554,
598
+ "阿祇_EN": 555,
599
+ "博士_EN": 556,
600
+ "迪尔菲_EN": 557,
601
+ "宛烟_EN": 558,
602
+ "玛格丽特_EN": 559,
603
+ "羽生田千鹤_EN": 560,
604
+ "海妮耶_EN": 561,
605
+ "霍夫曼_EN": 562,
606
+ "旅行者_EN": 563,
607
+ "佐西摩斯_EN": 564,
608
+ "鹿野奈奈_EN": 565,
609
+ "舒伯特_EN": 566,
610
+ "天叔_EN": 567,
611
+ "艾莉丝_EN": 568,
612
+ "龙二_EN": 569,
613
+ "莺儿_EN": 570,
614
+ "嘉良_EN": 571,
615
+ "珊瑚_EN": 572,
616
+ "费迪南德_EN": 573,
617
+ "言笑_EN": 574,
618
+ "一心传名刀_EN": 575,
619
+ "久利须_EN": 576,
620
+ "嘉玛_EN": 577,
621
+ "艾文_EN": 578,
622
+ "克洛琳德_EN": 579,
623
+ "丹吉尔_EN": 580,
624
+ "女士_EN": 581,
625
+ "天目十五_EN": 582,
626
+ "老孟_EN": 583,
627
+ "白老先生_EN": 584,
628
+ "舍利夫_EN": 585,
629
+ "巴达维_EN": 586,
630
+ "拉齐_EN": 587,
631
+ "长生_EN": 588,
632
+ "吴船长_EN": 589,
633
+ "艾伯特_EN": 590,
634
+ "松浦_EN": 591,
635
+ "埃泽_EN": 592,
636
+ "阿圆_EN": 593,
637
+ "阿拉夫_EN": 594,
638
+ "莫塞伊思_EN": 595,
639
+ "石头_EN": 596,
640
+ "百闻_EN": 597,
641
+ "杜吉耶_EN": 598,
642
+ "波洛_EN": 599,
643
+ "斯坦利_EN": 600,
644
+ "掇星攫辰天君_EN": 601,
645
+ "迈蒙_EN": 602,
646
+ "博易_EN": 603,
647
+ "诗筠_EN": 604,
648
+ "毗伽尔_EN": 605,
649
+ "慧心_EN": 606,
650
+ "芙卡洛斯_EN": 607,
651
+ "恶龙_EN": 608,
652
+ "小仓澪_EN": 609,
653
+ "恕筠_EN": 610,
654
+ "知易_EN": 611,
655
+ "克列门特_EN": 612,
656
+ "大慈树王_EN": 613,
657
+ "维多利亚_EN": 614,
658
+ "黑田_EN": 615,
659
+ "马姆杜_EN": 616,
660
+ "科林斯_EN": 617,
661
+ "上杉_EN": 618,
662
+ "西拉杰_EN": 619,
663
+ "宁禄_EN": 620,
664
+ "纯水精灵_EN": 621,
665
+ "常九爷_EN": 622,
666
+ "阿尔卡米_EN": 623,
667
+ "沙扎曼_EN": 624,
668
+ "田铁嘴_EN": 625,
669
+ "加萨尼_EN": 626,
670
+ "克罗索_EN": 627,
671
+ "星稀_EN": 628,
672
+ "莱斯格_EN": 629,
673
+ "阿巴图伊_EN": 630,
674
+ "埃尔欣根_EN": 631,
675
+ "阿佩普_EN": 632,
676
+ "萨赫哈蒂_EN": 633,
677
+ "洛伦佐_EN": 634,
678
+ "塔杰·拉德卡尼_EN": 635,
679
+ "泽田_EN": 636,
680
+ "安西_EN": 637,
681
+ "埃舍尔_EN": 638,
682
+ "三月七_ZH": 639,
683
+ "丹恒_ZH": 640,
684
+ "希儿_ZH": 641,
685
+ "娜塔莎_ZH": 642,
686
+ "希露瓦_ZH": 643,
687
+ "瓦尔特_ZH": 644,
688
+ "佩拉_ZH": 645,
689
+ "布洛妮娅_ZH": 646,
690
+ "虎克_ZH": 647,
691
+ "素裳_ZH": 648,
692
+ "克拉拉_ZH": 649,
693
+ "符玄_ZH": 650,
694
+ "白露_ZH": 651,
695
+ "杰帕德_ZH": 652,
696
+ "景元_ZH": 653,
697
+ "藿藿_ZH": 654,
698
+ "姬子_ZH": 655,
699
+ "穹_ZH": 656,
700
+ "星_ZH": 657,
701
+ "卡芙卡_ZH": 658,
702
+ "桂乃芬_ZH": 659,
703
+ "艾丝妲_ZH": 660,
704
+ "玲可_ZH": 661,
705
+ "彦卿_ZH": 662,
706
+ "托帕_ZH": 663,
707
+ "驭空_ZH": 664,
708
+ "浮烟_ZH": 665,
709
+ "停云_ZH": 666,
710
+ "镜流_ZH": 667,
711
+ "罗刹_ZH": 668,
712
+ "卢卡_ZH": 669,
713
+ "史瓦罗_ZH": 670,
714
+ "黑塔_ZH": 671,
715
+ "桑博_ZH": 672,
716
+ "伦纳德_ZH": 673,
717
+ "明曦_ZH": 674,
718
+ "银狼_ZH": 675,
719
+ "帕姆_ZH": 676,
720
+ "青雀_ZH": 677,
721
+ "乔瓦尼_ZH": 678,
722
+ "公输师傅_ZH": 679,
723
+ "晴霓_ZH": 680,
724
+ "螺丝咕姆_ZH": 681,
725
+ "阿兰_ZH": 682,
726
+ "奥列格_ZH": 683,
727
+ "丹枢_ZH": 684,
728
+ "尾巴_ZH": 685,
729
+ "寒鸦_ZH": 686,
730
+ "雪衣_ZH": 687,
731
+ "可可利亚_ZH": 688,
732
+ "青镞_ZH": 689,
733
+ "半夏_ZH": 690,
734
+ "银枝_ZH": 691,
735
+ "大毫_ZH": 692,
736
+ "霄翰_ZH": 693,
737
+ "信使_ZH": 694,
738
+ "费斯曼_ZH": 695,
739
+ "绿芙蓉_ZH": 696,
740
+ "金人会长_ZH": 697,
741
+ "维利特_ZH": 698,
742
+ "维尔德_ZH": 699,
743
+ "斯科特_ZH": 700,
744
+ "卡波特_ZH": 701,
745
+ "刃_ZH": 702,
746
+ "岩明_ZH": 703,
747
+ "浣溪_ZH": 704,
748
+ "三月七_JP": 705,
749
+ "丹恒_JP": 706,
750
+ "希儿_JP": 707,
751
+ "娜塔莎_JP": 708,
752
+ "希露瓦_JP": 709,
753
+ "瓦尔特_JP": 710,
754
+ "佩拉_JP": 711,
755
+ "布洛妮娅_JP": 712,
756
+ "虎克_JP": 713,
757
+ "素裳_JP": 714,
758
+ "克拉拉_JP": 715,
759
+ "符玄_JP": 716,
760
+ "白露_JP": 717,
761
+ "杰帕德_JP": 718,
762
+ "景元_JP": 719,
763
+ "藿藿_JP": 720,
764
+ "姬子_JP": 721,
765
+ "卡芙卡_JP": 722,
766
+ "穹_JP": 723,
767
+ "星_JP": 724,
768
+ "桂乃芬_JP": 725,
769
+ "艾丝妲_JP": 726,
770
+ "彦卿_JP": 727,
771
+ "玲可_JP": 728,
772
+ "托帕_JP": 729,
773
+ "驭空_JP": 730,
774
+ "浮烟_JP": 731,
775
+ "停云_JP": 732,
776
+ "镜流_JP": 733,
777
+ "罗刹_JP": 734,
778
+ "卢卡_JP": 735,
779
+ "史瓦罗_JP": 736,
780
+ "黑塔_JP": 737,
781
+ "桑博_JP": 738,
782
+ "伦纳德_JP": 739,
783
+ "明曦_JP": 740,
784
+ "银狼_JP": 741,
785
+ "帕姆_JP": 742,
786
+ "青雀_JP": 743,
787
+ "乔瓦尼_JP": 744,
788
+ "公输师傅_JP": 745,
789
+ "晴霓_JP": 746,
790
+ "螺丝咕姆_JP": 747,
791
+ "阿兰_JP": 748,
792
+ "奥列格_JP": 749,
793
+ "丹枢_JP": 750,
794
+ "尾巴_JP": 751,
795
+ "寒鸦_JP": 752,
796
+ "雪衣_JP": 753,
797
+ "可可利亚_JP": 754,
798
+ "青镞_JP": 755,
799
+ "半夏_JP": 756,
800
+ "银枝_JP": 757,
801
+ "大毫_JP": 758,
802
+ "霄翰_JP": 759,
803
+ "信使_JP": 760,
804
+ "费斯曼_JP": 761,
805
+ "绿芙蓉_JP": 762,
806
+ "金人会长_JP": 763,
807
+ "维利特_JP": 764,
808
+ "维尔德_JP": 765,
809
+ "斯科特_JP": 766,
810
+ "刃_JP": 767,
811
+ "卡波特_JP": 768,
812
+ "岩明_JP": 769,
813
+ "浣溪_JP": 770,
814
+ "净砚_JP": 771,
815
+ "紫月季_JP": 772,
816
+ "歌蒂_JP": 773,
817
+ "奇怪的云骑_JP": 774,
818
+ "幻胧_JP": 775,
819
+ "斯薇塔_JP": 776,
820
+ "隐书_JP": 777,
821
+ "三月七_EN": 778,
822
+ "丹恒_EN": 779,
823
+ "希儿_EN": 780,
824
+ "娜塔莎_EN": 781,
825
+ "希露瓦_EN": 782,
826
+ "瓦尔特_EN": 783,
827
+ "佩拉_EN": 784,
828
+ "布洛妮娅_EN": 785,
829
+ "虎克_EN": 786,
830
+ "素裳_EN": 787,
831
+ "克拉拉_EN": 788,
832
+ "符玄_EN": 789,
833
+ "白露_EN": 790,
834
+ "杰帕德_EN": 791,
835
+ "景元_EN": 792,
836
+ "藿藿_EN": 793,
837
+ "姬子_EN": 794,
838
+ "卡芙卡_EN": 795,
839
+ "穹_EN": 796,
840
+ "星_EN": 797,
841
+ "桂乃芬_EN": 798,
842
+ "艾丝妲_EN": 799,
843
+ "彦卿_EN": 800,
844
+ "玲可_EN": 801,
845
+ "托帕_EN": 802,
846
+ "驭空_EN": 803,
847
+ "浮烟_EN": 804,
848
+ "停云_EN": 805,
849
+ "镜流_EN": 806,
850
+ "罗刹_EN": 807,
851
+ "卢卡_EN": 808,
852
+ "史瓦罗_EN": 809,
853
+ "黑塔_EN": 810,
854
+ "桑博_EN": 811,
855
+ "伦纳德_EN": 812,
856
+ "明曦_EN": 813,
857
+ "银狼_EN": 814,
858
+ "帕姆_EN": 815,
859
+ "青雀_EN": 816,
860
+ "乔瓦尼_EN": 817,
861
+ "公输师傅_EN": 818,
862
+ "晴霓_EN": 819,
863
+ "螺丝咕姆_EN": 820,
864
+ "阿兰_EN": 821,
865
+ "奥列格_EN": 822,
866
+ "丹枢_EN": 823,
867
+ "尾巴_EN": 824,
868
+ "寒鸦_EN": 825,
869
+ "雪衣_EN": 826,
870
+ "可可利亚_EN": 827,
871
+ "青镞_EN": 828,
872
+ "半夏_EN": 829,
873
+ "银枝_EN": 830,
874
+ "大毫_EN": 831,
875
+ "霄翰_EN": 832,
876
+ "信使_EN": 833,
877
+ "费斯曼_EN": 834,
878
+ "绿芙蓉_EN": 835,
879
+ "金人会长_EN": 836,
880
+ "维利特_EN": 837,
881
+ "维尔德_EN": 838,
882
+ "刃_EN": 839,
883
+ "卡波特_EN": 840,
884
+ "岩明_EN": 841,
885
+ "浣溪_EN": 842,
886
+ "紫月季_EN": 843,
887
+ "幻胧_EN": 844,
888
+ "女声_EN": 845,
889
+ "陆景和": 846,
890
+ "莫弈": 847,
891
+ "左然": 848,
892
+ "夏彦": 849
893
+ }
894
+ },
895
+ "model": {
896
+ "use_spk_conditioned_encoder": true,
897
+ "use_noise_scaled_mas": true,
898
+ "use_mel_posterior_encoder": false,
899
+ "use_duration_discriminator": true,
900
+ "inter_channels": 192,
901
+ "hidden_channels": 192,
902
+ "filter_channels": 768,
903
+ "n_heads": 2,
904
+ "n_layers": 6,
905
+ "kernel_size": 3,
906
+ "p_dropout": 0.1,
907
+ "resblock": "1",
908
+ "resblock_kernel_sizes": [
909
+ 3,
910
+ 7,
911
+ 11
912
+ ],
913
+ "resblock_dilation_sizes": [
914
+ [
915
+ 1,
916
+ 3,
917
+ 5
918
+ ],
919
+ [
920
+ 1,
921
+ 3,
922
+ 5
923
+ ],
924
+ [
925
+ 1,
926
+ 3,
927
+ 5
928
+ ]
929
+ ],
930
+ "upsample_rates": [
931
+ 8,
932
+ 8,
933
+ 2,
934
+ 2,
935
+ 2
936
+ ],
937
+ "upsample_initial_channel": 512,
938
+ "upsample_kernel_sizes": [
939
+ 16,
940
+ 16,
941
+ 8,
942
+ 2,
943
+ 2
944
+ ],
945
+ "n_layers_q": 3,
946
+ "use_spectral_norm": false,
947
+ "gin_channels": 512,
948
+ "slm": {
949
+ "model": "./slm/wavlm-base-plus",
950
+ "sr": 16000,
951
+ "hidden": 768,
952
+ "nlayers": 13,
953
+ "initial_channel": 64
954
+ }
955
+ },
956
+ "version": "2.3"
957
+ }
BanG-Dream-VITS/css/custom.css ADDED
@@ -0,0 +1,18 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+
2
+ #yml_code {
3
+ height: 600px;
4
+ flex-grow: inherit;
5
+ overflow-y: auto;
6
+ }
7
+
8
+ #json_code {
9
+ height: 600px;
10
+ flex-grow: inherit;
11
+ overflow-y: auto;
12
+ }
13
+
14
+ #gpu_code {
15
+ height: 300px;
16
+ flex-grow: inherit;
17
+ overflow-y: auto;
18
+ }
BanG-Dream-VITS/data_utils.py ADDED
@@ -0,0 +1,404 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import os
2
+ import random
3
+ import torch
4
+ import torch.utils.data
5
+ from tqdm import tqdm
6
+ from tools.log import logger
7
+ import commons
8
+ from mel_processing import spectrogram_torch, mel_spectrogram_torch
9
+ from utils import load_wav_to_torch, load_filepaths_and_text
10
+ from text import cleaned_text_to_sequence
11
+ from config import config
12
+
13
+ """Multi speaker version"""
14
+
15
+
16
+ class TextAudioSpeakerLoader(torch.utils.data.Dataset):
17
+ """
18
+ 1) loads audio, speaker_id, text pairs
19
+ 2) normalizes text and converts them to sequences of integers
20
+ 3) computes spectrograms from audio files.
21
+ """
22
+
23
+ def __init__(self, audiopaths_sid_text, hparams):
24
+ self.audiopaths_sid_text = load_filepaths_and_text(audiopaths_sid_text)
25
+ self.max_wav_value = hparams.max_wav_value
26
+ self.sampling_rate = hparams.sampling_rate
27
+ self.filter_length = hparams.filter_length
28
+ self.hop_length = hparams.hop_length
29
+ self.win_length = hparams.win_length
30
+ self.sampling_rate = hparams.sampling_rate
31
+ self.spk_map = hparams.spk2id
32
+ self.hparams = hparams
33
+
34
+ self.use_mel_spec_posterior = getattr(
35
+ hparams, "use_mel_posterior_encoder", False
36
+ )
37
+ if self.use_mel_spec_posterior:
38
+ self.n_mel_channels = getattr(hparams, "n_mel_channels", 80)
39
+
40
+ self.cleaned_text = getattr(hparams, "cleaned_text", False)
41
+
42
+ self.add_blank = hparams.add_blank
43
+ self.min_text_len = getattr(hparams, "min_text_len", 1)
44
+ self.max_text_len = getattr(hparams, "max_text_len", 384)
45
+
46
+ random.seed(1234)
47
+ random.shuffle(self.audiopaths_sid_text)
48
+ self._filter()
49
+
50
+ def _filter(self):
51
+ """
52
+ Filter text & store spec lengths
53
+ """
54
+ # Store spectrogram lengths for Bucketing
55
+ # wav_length ~= file_size / (wav_channels * Bytes per dim) = file_size / (1 * 2)
56
+ # spec_length = wav_length // hop_length
57
+
58
+ audiopaths_sid_text_new = []
59
+ lengths = []
60
+ skipped = 0
61
+ logger.info("Init dataset...")
62
+ for _id, spk, language, text, phones, tone, word2ph in tqdm(
63
+ self.audiopaths_sid_text
64
+ ):
65
+ audiopath = f"{_id}"
66
+ if self.min_text_len <= len(phones) and len(phones) <= self.max_text_len:
67
+ phones = phones.split(" ")
68
+ tone = [int(i) for i in tone.split(" ")]
69
+ word2ph = [int(i) for i in word2ph.split(" ")]
70
+ audiopaths_sid_text_new.append(
71
+ [audiopath, spk, language, text, phones, tone, word2ph]
72
+ )
73
+ lengths.append(os.path.getsize(audiopath) // (2 * self.hop_length))
74
+ else:
75
+ skipped += 1
76
+ logger.info(
77
+ "skipped: "
78
+ + str(skipped)
79
+ + ", total: "
80
+ + str(len(self.audiopaths_sid_text))
81
+ )
82
+ self.audiopaths_sid_text = audiopaths_sid_text_new
83
+ self.lengths = lengths
84
+
85
+ def get_audio_text_speaker_pair(self, audiopath_sid_text):
86
+ # separate filename, speaker_id and text
87
+ audiopath, sid, language, text, phones, tone, word2ph = audiopath_sid_text
88
+
89
+ bert, ja_bert, en_bert, phones, tone, language = self.get_text(
90
+ text, word2ph, phones, tone, language, audiopath
91
+ )
92
+
93
+ spec, wav = self.get_audio(audiopath)
94
+ sid = torch.LongTensor([int(self.spk_map[sid])])
95
+
96
+ return (phones, spec, wav, sid, tone, language, bert, ja_bert, en_bert)
97
+
98
+ def get_audio(self, filename):
99
+ audio, sampling_rate = load_wav_to_torch(filename)
100
+ if sampling_rate != self.sampling_rate:
101
+ raise ValueError(
102
+ "{} {} SR doesn't match target {} SR".format(
103
+ filename, sampling_rate, self.sampling_rate
104
+ )
105
+ )
106
+ audio_norm = audio / self.max_wav_value
107
+ audio_norm = audio_norm.unsqueeze(0)
108
+ spec_filename = filename.replace(".wav", ".spec.pt")
109
+ if self.use_mel_spec_posterior:
110
+ spec_filename = spec_filename.replace(".spec.pt", ".mel.pt")
111
+ try:
112
+ spec = torch.load(spec_filename)
113
+ except:
114
+ if self.use_mel_spec_posterior:
115
+ spec = mel_spectrogram_torch(
116
+ audio_norm,
117
+ self.filter_length,
118
+ self.n_mel_channels,
119
+ self.sampling_rate,
120
+ self.hop_length,
121
+ self.win_length,
122
+ self.hparams.mel_fmin,
123
+ self.hparams.mel_fmax,
124
+ center=False,
125
+ )
126
+ else:
127
+ spec = spectrogram_torch(
128
+ audio_norm,
129
+ self.filter_length,
130
+ self.sampling_rate,
131
+ self.hop_length,
132
+ self.win_length,
133
+ center=False,
134
+ )
135
+ spec = torch.squeeze(spec, 0)
136
+ if config.train_ms_config.spec_cache:
137
+ torch.save(spec, spec_filename)
138
+ return spec, audio_norm
139
+
140
+ def get_text(self, text, word2ph, phone, tone, language_str, wav_path):
141
+ phone, tone, language = cleaned_text_to_sequence(phone, tone, language_str)
142
+ if self.add_blank:
143
+ phone = commons.intersperse(phone, 0)
144
+ tone = commons.intersperse(tone, 0)
145
+ language = commons.intersperse(language, 0)
146
+ for i in range(len(word2ph)):
147
+ word2ph[i] = word2ph[i] * 2
148
+ word2ph[0] += 1
149
+ bert_path = wav_path.replace(".wav", ".bert.pt")
150
+ try:
151
+ bert_ori = torch.load(bert_path)
152
+ assert bert_ori.shape[-1] == len(phone)
153
+ except Exception as e:
154
+ logger.warning("Bert load Failed")
155
+ logger.warning(e)
156
+
157
+ if language_str == "ZH":
158
+ bert = bert_ori
159
+ ja_bert = torch.randn(1024, len(phone))
160
+ en_bert = torch.randn(1024, len(phone))
161
+ elif language_str == "JP":
162
+ bert = torch.randn(1024, len(phone))
163
+ ja_bert = bert_ori
164
+ en_bert = torch.randn(1024, len(phone))
165
+ elif language_str == "EN":
166
+ bert = torch.randn(1024, len(phone))
167
+ ja_bert = torch.randn(1024, len(phone))
168
+ en_bert = bert_ori
169
+ phone = torch.LongTensor(phone)
170
+ tone = torch.LongTensor(tone)
171
+ language = torch.LongTensor(language)
172
+ return bert, ja_bert, en_bert, phone, tone, language
173
+
174
+ def get_sid(self, sid):
175
+ sid = torch.LongTensor([int(sid)])
176
+ return sid
177
+
178
+ def __getitem__(self, index):
179
+ return self.get_audio_text_speaker_pair(self.audiopaths_sid_text[index])
180
+
181
+ def __len__(self):
182
+ return len(self.audiopaths_sid_text)
183
+
184
+
185
+ class TextAudioSpeakerCollate:
186
+ """Zero-pads model inputs and targets"""
187
+
188
+ def __init__(self, return_ids=False):
189
+ self.return_ids = return_ids
190
+
191
+ def __call__(self, batch):
192
+ """Collate's training batch from normalized text, audio and speaker identities
193
+ PARAMS
194
+ ------
195
+ batch: [text_normalized, spec_normalized, wav_normalized, sid]
196
+ """
197
+ # Right zero-pad all one-hot text sequences to max input length
198
+ _, ids_sorted_decreasing = torch.sort(
199
+ torch.LongTensor([x[1].size(1) for x in batch]), dim=0, descending=True
200
+ )
201
+
202
+ max_text_len = max([len(x[0]) for x in batch])
203
+ max_spec_len = max([x[1].size(1) for x in batch])
204
+ max_wav_len = max([x[2].size(1) for x in batch])
205
+
206
+ text_lengths = torch.LongTensor(len(batch))
207
+ spec_lengths = torch.LongTensor(len(batch))
208
+ wav_lengths = torch.LongTensor(len(batch))
209
+ sid = torch.LongTensor(len(batch))
210
+
211
+ text_padded = torch.LongTensor(len(batch), max_text_len)
212
+ tone_padded = torch.LongTensor(len(batch), max_text_len)
213
+ language_padded = torch.LongTensor(len(batch), max_text_len)
214
+ bert_padded = torch.FloatTensor(len(batch), 1024, max_text_len)
215
+ ja_bert_padded = torch.FloatTensor(len(batch), 1024, max_text_len)
216
+ en_bert_padded = torch.FloatTensor(len(batch), 1024, max_text_len)
217
+
218
+ spec_padded = torch.FloatTensor(len(batch), batch[0][1].size(0), max_spec_len)
219
+ wav_padded = torch.FloatTensor(len(batch), 1, max_wav_len)
220
+ text_padded.zero_()
221
+ tone_padded.zero_()
222
+ language_padded.zero_()
223
+ spec_padded.zero_()
224
+ wav_padded.zero_()
225
+ bert_padded.zero_()
226
+ ja_bert_padded.zero_()
227
+ en_bert_padded.zero_()
228
+
229
+ for i in range(len(ids_sorted_decreasing)):
230
+ row = batch[ids_sorted_decreasing[i]]
231
+
232
+ text = row[0]
233
+ text_padded[i, : text.size(0)] = text
234
+ text_lengths[i] = text.size(0)
235
+
236
+ spec = row[1]
237
+ spec_padded[i, :, : spec.size(1)] = spec
238
+ spec_lengths[i] = spec.size(1)
239
+
240
+ wav = row[2]
241
+ wav_padded[i, :, : wav.size(1)] = wav
242
+ wav_lengths[i] = wav.size(1)
243
+
244
+ sid[i] = row[3]
245
+
246
+ tone = row[4]
247
+ tone_padded[i, : tone.size(0)] = tone
248
+
249
+ language = row[5]
250
+ language_padded[i, : language.size(0)] = language
251
+
252
+ bert = row[6]
253
+ bert_padded[i, :, : bert.size(1)] = bert
254
+
255
+ ja_bert = row[7]
256
+ ja_bert_padded[i, :, : ja_bert.size(1)] = ja_bert
257
+
258
+ en_bert = row[8]
259
+ en_bert_padded[i, :, : en_bert.size(1)] = en_bert
260
+
261
+ return (
262
+ text_padded,
263
+ text_lengths,
264
+ spec_padded,
265
+ spec_lengths,
266
+ wav_padded,
267
+ wav_lengths,
268
+ sid,
269
+ tone_padded,
270
+ language_padded,
271
+ bert_padded,
272
+ ja_bert_padded,
273
+ en_bert_padded,
274
+ )
275
+
276
+
277
+ class DistributedBucketSampler(torch.utils.data.distributed.DistributedSampler):
278
+ """
279
+ Maintain similar input lengths in a batch.
280
+ Length groups are specified by boundaries.
281
+ Ex) boundaries = [b1, b2, b3] -> any batch is included either {x | b1 < length(x) <=b2} or {x | b2 < length(x) <= b3}.
282
+
283
+ It removes samples which are not included in the boundaries.
284
+ Ex) boundaries = [b1, b2, b3] -> any x s.t. length(x) <= b1 or length(x) > b3 are discarded.
285
+ """
286
+
287
+ def __init__(
288
+ self,
289
+ dataset,
290
+ batch_size,
291
+ boundaries,
292
+ num_replicas=None,
293
+ rank=None,
294
+ shuffle=True,
295
+ ):
296
+ super().__init__(dataset, num_replicas=num_replicas, rank=rank, shuffle=shuffle)
297
+ self.lengths = dataset.lengths
298
+ self.batch_size = batch_size
299
+ self.boundaries = boundaries
300
+
301
+ self.buckets, self.num_samples_per_bucket = self._create_buckets()
302
+ self.total_size = sum(self.num_samples_per_bucket)
303
+ self.num_samples = self.total_size // self.num_replicas
304
+
305
+ def _create_buckets(self):
306
+ buckets = [[] for _ in range(len(self.boundaries) - 1)]
307
+ for i in range(len(self.lengths)):
308
+ length = self.lengths[i]
309
+ idx_bucket = self._bisect(length)
310
+ if idx_bucket != -1:
311
+ buckets[idx_bucket].append(i)
312
+
313
+ try:
314
+ for i in range(len(buckets) - 1, 0, -1):
315
+ if len(buckets[i]) == 0:
316
+ buckets.pop(i)
317
+ self.boundaries.pop(i + 1)
318
+ assert all(len(bucket) > 0 for bucket in buckets)
319
+ # When one bucket is not traversed
320
+ except Exception as e:
321
+ print("Bucket warning ", e)
322
+ for i in range(len(buckets) - 1, -1, -1):
323
+ if len(buckets[i]) == 0:
324
+ buckets.pop(i)
325
+ self.boundaries.pop(i + 1)
326
+
327
+ num_samples_per_bucket = []
328
+ for i in range(len(buckets)):
329
+ len_bucket = len(buckets[i])
330
+ total_batch_size = self.num_replicas * self.batch_size
331
+ rem = (
332
+ total_batch_size - (len_bucket % total_batch_size)
333
+ ) % total_batch_size
334
+ num_samples_per_bucket.append(len_bucket + rem)
335
+ return buckets, num_samples_per_bucket
336
+
337
+ def __iter__(self):
338
+ # deterministically shuffle based on epoch
339
+ g = torch.Generator()
340
+ g.manual_seed(self.epoch)
341
+
342
+ indices = []
343
+ if self.shuffle:
344
+ for bucket in self.buckets:
345
+ indices.append(torch.randperm(len(bucket), generator=g).tolist())
346
+ else:
347
+ for bucket in self.buckets:
348
+ indices.append(list(range(len(bucket))))
349
+
350
+ batches = []
351
+ for i in range(len(self.buckets)):
352
+ bucket = self.buckets[i]
353
+ len_bucket = len(bucket)
354
+ if len_bucket == 0:
355
+ continue
356
+ ids_bucket = indices[i]
357
+ num_samples_bucket = self.num_samples_per_bucket[i]
358
+
359
+ # add extra samples to make it evenly divisible
360
+ rem = num_samples_bucket - len_bucket
361
+ ids_bucket = (
362
+ ids_bucket
363
+ + ids_bucket * (rem // len_bucket)
364
+ + ids_bucket[: (rem % len_bucket)]
365
+ )
366
+
367
+ # subsample
368
+ ids_bucket = ids_bucket[self.rank :: self.num_replicas]
369
+
370
+ # batching
371
+ for j in range(len(ids_bucket) // self.batch_size):
372
+ batch = [
373
+ bucket[idx]
374
+ for idx in ids_bucket[
375
+ j * self.batch_size : (j + 1) * self.batch_size
376
+ ]
377
+ ]
378
+ batches.append(batch)
379
+
380
+ if self.shuffle:
381
+ batch_ids = torch.randperm(len(batches), generator=g).tolist()
382
+ batches = [batches[i] for i in batch_ids]
383
+ self.batches = batches
384
+
385
+ assert len(self.batches) * self.batch_size == self.num_samples
386
+ return iter(self.batches)
387
+
388
+ def _bisect(self, x, lo=0, hi=None):
389
+ if hi is None:
390
+ hi = len(self.boundaries) - 1
391
+
392
+ if hi > lo:
393
+ mid = (hi + lo) // 2
394
+ if self.boundaries[mid] < x and x <= self.boundaries[mid + 1]:
395
+ return mid
396
+ elif x <= self.boundaries[mid]:
397
+ return self._bisect(x, lo, mid)
398
+ else:
399
+ return self._bisect(x, mid + 1, hi)
400
+ else:
401
+ return -1
402
+
403
+ def __len__(self):
404
+ return self.num_samples // self.batch_size
BanG-Dream-VITS/default_config.yml ADDED
@@ -0,0 +1,177 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ # 全局配置
2
+ # 对于希望在同一时间使用多个配置文件的情况,例如两个GPU同时跑两个训练集:通过环境变量指定配置文件,不指定则默认为./config.yml
3
+
4
+ # 拟提供通用路径配置,统一存放数据,避免数据放得很乱
5
+ # 每个数据集与其对应的模型存放至统一路径下,后续所有的路径配置均为相对于datasetPath的路径
6
+ # 不填或者填空则路径为相对于项目根目录的路径
7
+ dataset_path: "Data/"
8
+
9
+ # 模型镜像源,默认huggingface,使用openi镜像源需指定openi_token
10
+ mirror: ""
11
+ openi_token: "" # openi token
12
+
13
+ # resample 音频重采样配置
14
+ # 注意, “:” 后需要加空格
15
+ resample:
16
+ # 目标重采样率
17
+ sampling_rate: 44100
18
+ # 音频文件输入路径,重采样会将该路径下所有.wav音频文件重采样
19
+ # 请填入相对于datasetPath的相对路径
20
+ in_dir: "audios/raw" # 相对于根目录的路径为 /datasetPath/in_dir
21
+ # 音频文件重采样后输出路径
22
+ out_dir: "audios/wavs"
23
+
24
+
25
+ # preprocess_text 数据集预处理相关配置
26
+ # 注意, “:” 后需要加空格
27
+ preprocess_text:
28
+ # 原始文本文件路径,文本格式应为{wav_path}|{speaker_name}|{language}|{text}。
29
+ transcription_path: "filelists/你的数据集文本.list"
30
+ # 数据清洗后文本路径,可以不填。不填则将在原始文本目录生成
31
+ cleaned_path: ""
32
+ # 训练集路径
33
+ train_path: "filelists/train.list"
34
+ # 验证集路径
35
+ val_path: "filelists/val.list"
36
+ # 配置文件路径
37
+ config_path: "config.json"
38
+ # 每个语言的验证集条数
39
+ val_per_lang: 4
40
+ # 验证集最大条数,多于的会被截断并放到训练集中
41
+ max_val_total: 12
42
+ # 是否进行数据清洗
43
+ clean: true
44
+
45
+
46
+ # bert_gen 相关配置
47
+ # 注意, “:” 后需要加空格
48
+ bert_gen:
49
+ # 训练数据集配置文件路径
50
+ config_path: "config.json"
51
+ # 并行数
52
+ num_processes: 4
53
+ # 使用设备:可选项 "cuda" 显卡推理,"cpu" cpu推理
54
+ # 该选项同时决定了get_bert_feature的默认设备
55
+ device: "cuda"
56
+ # 使用多卡推理
57
+ use_multi_device: false
58
+
59
+ # emo_gen 相关配置
60
+ # 注意, “:” 后需要加空格
61
+ emo_gen:
62
+ # 训练数据集配置文件路径
63
+ config_path: "config.json"
64
+ # 并行数
65
+ num_processes: 4
66
+ # 使用设备:可选项 "cuda" 显卡推理,"cpu" cpu推理
67
+ device: "cuda"
68
+ # 使用多卡推理
69
+ use_multi_device: false
70
+
71
+ # train 训练配置
72
+ # 注意, “:” 后需要加空格
73
+ train_ms:
74
+ env:
75
+ MASTER_ADDR: "localhost"
76
+ MASTER_PORT: 10086
77
+ WORLD_SIZE: 1
78
+ LOCAL_RANK: 0
79
+ RANK: 0
80
+ # 可以填写任意名的环境变量
81
+ # THE_ENV_VAR_YOU_NEED_TO_USE: "1234567"
82
+ # 底模设置
83
+ base:
84
+ use_base_model: false
85
+ repo_id: "Stardust_minus/Bert-VITS2"
86
+ model_image: "Bert-VITS2_2.2-Clap底模" # openi网页的模型名
87
+ # 训练模型存储目录:与旧版本的区别,原先数据集是存放在logs/model_name下的,现在改为统一存放在Data/你的数据集/models下
88
+ model: "models"
89
+ # 配置文件路径
90
+ config_path: "config.json"
91
+ # 训练使用的worker,不建议超过CPU核心数
92
+ num_workers: 16
93
+ # 关闭此项可以节约接近50%的磁盘空间,但是可能导致实际训练速度变慢和更高的CPU使用率。
94
+ spec_cache: True
95
+ # 保存的检查点数量,多于此数目的权重会被删除来节省空间。
96
+ keep_ckpts: 8
97
+
98
+
99
+ # webui webui配置
100
+ # 注意, “:” 后需要加空格
101
+ webui:
102
+ # 推理设备
103
+ device: "cuda"
104
+ # 模型路径
105
+ model: "models/G_8000.pth"
106
+ # 配置文件路径
107
+ config_path: "config.json"
108
+ # 端口号
109
+ port: 7860
110
+ # 是否公开部署,对外网开放
111
+ share: false
112
+ # 是否开启debug模式
113
+ debug: false
114
+ # 语种识别库,可选langid, fastlid
115
+ language_identification_library: "langid"
116
+
117
+
118
+ # server-fastapi配置
119
+ # 注意, “:” 后需要加空格
120
+ # 注意,本配置下的所有配置均为相对于根目录的路径
121
+ server:
122
+ # 端口号
123
+ port: 5000
124
+ # 模型默认使用设备:但是当前并没有实现这个配置。
125
+ device: "cuda"
126
+ # 需要加载的所有模型的配置,可以填多个模型,也可以不填模型,等网页成功后手动加载模型
127
+ # 不加载模型的配置格式:删除默认给的两个模型配置,给models赋值 [ ],也就是空列表。参考模型2的speakers 即 models: [ ]
128
+ # 注意,所有模型都必须正确配置model与config的路径,空路径会导致加载错误。
129
+ # 也可以不填模型,等网页加载成功后手动填写models。
130
+ models:
131
+ - # 模型的路径
132
+ model: ""
133
+ # 模型config.json的路径
134
+ config: ""
135
+ # 模型使用设备,若填写则会覆盖默认配置
136
+ device: "cuda"
137
+ # 模型默认使用的语言
138
+ language: "ZH"
139
+ # 模型人物默认参数
140
+ # 不必填写所有人物,不填的使用默认值
141
+ # 暂时不用填写,当前尚未实现按人区分配置
142
+ speakers:
143
+ - speaker: "科比"
144
+ sdp_ratio: 0.2
145
+ noise_scale: 0.6
146
+ noise_scale_w: 0.8
147
+ length_scale: 1
148
+ - speaker: "五条悟"
149
+ sdp_ratio: 0.3
150
+ noise_scale: 0.7
151
+ noise_scale_w: 0.8
152
+ length_scale: 0.5
153
+ - speaker: "安倍晋三"
154
+ sdp_ratio: 0.2
155
+ noise_scale: 0.6
156
+ noise_scale_w: 0.8
157
+ length_scale: 1.2
158
+ - # 模型的路径
159
+ model: ""
160
+ # 模型config.json的路径
161
+ config: ""
162
+ # 模型使用设备,若填写则会覆盖默认配置
163
+ device: "cpu"
164
+ # 模型默认使用的语言
165
+ language: "JP"
166
+ # 模型人物默认参数
167
+ # 不必填写所有人物,不填的使用默认值
168
+ speakers: [ ] # 也可以不填
169
+
170
+ # 百度翻译开放平台 api配置
171
+ # api接入文档 https://api.fanyi.baidu.com/doc/21
172
+ # 请不要在github等网站公开分享你的app id 与 key
173
+ translate:
174
+ # 你的APPID
175
+ "app_key": ""
176
+ # 你的密钥
177
+ "secret_key": ""
BanG-Dream-VITS/emo_gen.py ADDED
@@ -0,0 +1,174 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import argparse
2
+ import os
3
+ from pathlib import Path
4
+
5
+ import librosa
6
+ import numpy as np
7
+ import torch
8
+ import torch.nn as nn
9
+ from torch.utils.data import Dataset
10
+ from torch.utils.data import DataLoader, Dataset
11
+ from tqdm import tqdm
12
+ from transformers import Wav2Vec2Processor
13
+ from transformers.models.wav2vec2.modeling_wav2vec2 import (
14
+ Wav2Vec2Model,
15
+ Wav2Vec2PreTrainedModel,
16
+ )
17
+ import sys
18
+ import utils
19
+ from config import config
20
+
21
+
22
+ class RegressionHead(nn.Module):
23
+ r"""Classification head."""
24
+
25
+ def __init__(self, config):
26
+ super().__init__()
27
+
28
+ self.dense = nn.Linear(config.hidden_size, config.hidden_size)
29
+ self.dropout = nn.Dropout(config.final_dropout)
30
+ self.out_proj = nn.Linear(config.hidden_size, config.num_labels)
31
+
32
+ def forward(self, features, **kwargs):
33
+ x = features
34
+ x = self.dropout(x)
35
+ x = self.dense(x)
36
+ x = torch.tanh(x)
37
+ x = self.dropout(x)
38
+ x = self.out_proj(x)
39
+
40
+ return x
41
+
42
+
43
+ class EmotionModel(Wav2Vec2PreTrainedModel):
44
+ r"""Speech emotion classifier."""
45
+
46
+ def __init__(self, config):
47
+ super().__init__(config)
48
+
49
+ self.config = config
50
+ self.wav2vec2 = Wav2Vec2Model(config)
51
+ self.classifier = RegressionHead(config)
52
+ self.init_weights()
53
+
54
+ def forward(
55
+ self,
56
+ input_values,
57
+ ):
58
+ outputs = self.wav2vec2(input_values)
59
+ hidden_states = outputs[0]
60
+ hidden_states = torch.mean(hidden_states, dim=1)
61
+ logits = self.classifier(hidden_states)
62
+
63
+ return hidden_states, logits
64
+
65
+
66
+ class AudioDataset(Dataset):
67
+ def __init__(self, list_of_wav_files, sr, processor):
68
+ self.list_of_wav_files = list_of_wav_files
69
+ self.processor = processor
70
+ self.sr = sr
71
+
72
+ def __len__(self):
73
+ return len(self.list_of_wav_files)
74
+
75
+ def __getitem__(self, idx):
76
+ wav_file = self.list_of_wav_files[idx]
77
+ audio_data, _ = librosa.load(wav_file, sr=self.sr)
78
+ processed_data = self.processor(audio_data, sampling_rate=self.sr)[
79
+ "input_values"
80
+ ][0]
81
+ return torch.from_numpy(processed_data)
82
+
83
+
84
+ def process_func(
85
+ x: np.ndarray,
86
+ sampling_rate: int,
87
+ model: EmotionModel,
88
+ processor: Wav2Vec2Processor,
89
+ device: str,
90
+ embeddings: bool = False,
91
+ ) -> np.ndarray:
92
+ device = (
93
+ "cuda:0"
94
+ if torch.cuda.is_available()
95
+ else (
96
+ "mps"
97
+ if sys.platform == "darwin" and torch.backends.mps.is_available()
98
+ else "cpu"
99
+ )
100
+ )
101
+ r"""Predict emotions or extract embeddings from raw audio signal."""
102
+ model = model.to(device)
103
+ y = processor(x, sampling_rate=sampling_rate)
104
+ y = y["input_values"][0]
105
+ y = torch.from_numpy(y).unsqueeze(0).to(device)
106
+
107
+ # run through model
108
+ with torch.no_grad():
109
+ y = model(y)[0 if embeddings else 1]
110
+
111
+ # convert to numpy
112
+ y = y.detach().cpu().numpy()
113
+
114
+ return y
115
+
116
+
117
+
118
+ def get_emo(path):
119
+ wav, sr = librosa.load(path, 16000)
120
+ device = config.bert_gen_config.device
121
+ print("successfully generate the emo vec")
122
+ return process_func(
123
+ np.expand_dims(wav, 0).astype(np.float),
124
+ sr,
125
+ model,
126
+ processor,
127
+ device,
128
+ embeddings=True,
129
+ ).squeeze(0)
130
+
131
+
132
+ if __name__ == "__main__":
133
+ parser = argparse.ArgumentParser()
134
+ parser.add_argument(
135
+ "-c", "--config", type=str, default=config.bert_gen_config.config_path
136
+ )
137
+ parser.add_argument(
138
+ "--num_processes", type=int, default=config.bert_gen_config.num_processes
139
+ )
140
+ args, _ = parser.parse_known_args()
141
+ config_path = args.config
142
+ hps = utils.get_hparams_from_file(config_path)
143
+
144
+ device = config.bert_gen_config.device
145
+
146
+ model_name = "./emotional/wav2vec2-large-robust-12-ft-emotion-msp-dim"
147
+ REPO_ID = "audeering/wav2vec2-large-robust-12-ft-emotion-msp-dim"
148
+ if not Path(model_name).joinpath("pytorch_model.bin").exists():
149
+ utils.download_emo_models(config.mirror, REPO_ID, model_name)
150
+
151
+ processor = Wav2Vec2Processor.from_pretrained(model_name)
152
+ model = EmotionModel.from_pretrained(model_name).to(device)
153
+
154
+ lines = []
155
+ with open(hps.data.training_files, encoding="utf-8") as f:
156
+ lines.extend(f.readlines())
157
+
158
+ with open(hps.data.validation_files, encoding="utf-8") as f:
159
+ lines.extend(f.readlines())
160
+
161
+ wavnames = [line.split("|")[0] for line in lines]
162
+ dataset = AudioDataset(wavnames, 16000, processor)
163
+ data_loader = DataLoader(dataset, batch_size=1, shuffle=False, num_workers=16)
164
+
165
+ with torch.no_grad():
166
+ for i, data in tqdm(enumerate(data_loader), total=len(data_loader)):
167
+ wavname = wavnames[i]
168
+ emo_path = wavname.replace(".wav", ".emo.npy")
169
+ if os.path.exists(emo_path):
170
+ continue
171
+ emb = model(data.to(device))[0].detach().cpu().numpy()
172
+ np.save(emo_path, emb)
173
+
174
+ print("Emo vec 生成完毕!")
BanG-Dream-VITS/empty_emo.npy ADDED
@@ -0,0 +1,3 @@
 
 
 
 
1
+ version https://git-lfs.github.com/spec/v1
2
+ oid sha256:07063411ab7d6e7aacfc73c582616c3fbc8fdf518b20d42d8be77bc9caf6fab9
3
+ size 3238
BanG-Dream-VITS/export_onnx.py ADDED
@@ -0,0 +1,14 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ from onnx_modules import export_onnx
2
+ import os
3
+
4
+ if __name__ == "__main__":
5
+ export_path = "BertVits2.2PT"
6
+ model_path = "model\\G_0.pth"
7
+ config_path = "model\\config.json"
8
+ novq = False
9
+ dev = False
10
+ if not os.path.exists("onnx"):
11
+ os.makedirs("onnx")
12
+ if not os.path.exists(f"onnx/{export_path}"):
13
+ os.makedirs(f"onnx/{export_path}")
14
+ export_onnx(export_path, model_path, config_path, novq, dev)
BanG-Dream-VITS/filelists/Mygo.list ADDED
The diff for this file is too large to render. See raw diff
 
BanG-Dream-VITS/filelists/Mygo.list.cleaned ADDED
The diff for this file is too large to render. See raw diff
 
BanG-Dream-VITS/filelists/esd.list ADDED
@@ -0,0 +1,3 @@
 
 
 
 
1
+ Example:
2
+ {wav_path}|{speaker_name}|{language}|{text}
3
+ 派蒙_1.wav|派蒙|ZH|前面的区域,以后再来探索吧!
BanG-Dream-VITS/filelists/sample.list ADDED
@@ -0,0 +1,3 @@
 
 
 
 
1
+ Example:
2
+ {wav_path}|{speaker_name}|{language}|{text}
3
+ 派蒙_1.wav|派蒙|ZH|前面的区域,以后再来探索吧!
BanG-Dream-VITS/filelists/train.list ADDED
The diff for this file is too large to render. See raw diff
 
BanG-Dream-VITS/filelists/val.list ADDED
@@ -0,0 +1,8 @@
 
 
 
 
 
 
 
 
 
1
+ /content/drive/MyDrive/Mygo/event235-15-063.wav|燈|JP|うん……愛音ちゃん……ありがとう|_ u N . . . . . . a i o t o ch a N . . . . . . a r i g a t o _|0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0|1 2 1 1 1 1 1 1 2 3 3 1 1 1 1 1 1 7 1
2
+ /content/drive/MyDrive/Mygo/event235-29-022.wav|燈|JP|私……祥ちゃんも……みんな,傷つけて……|_ w a t a k u sh i . . . . . . s a ch i ch a N m o . . . . . . m i N n a , k i z u ts u k e t e . . . . . . _|0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0|1 8 1 1 1 1 1 1 4 3 2 1 1 1 1 1 1 5 1 8 2 1 1 1 1 1 1 1
3
+ /content/drive/MyDrive/Mygo/event235-30-058.wav|燈|JP|無理じゃない!|_ m u r i j a n a i ! _|0 0 0 0 0 0 0 0 0 0 0 0|1 4 2 3 1 1
4
+ /content/drive/MyDrive/Mygo/event235-32-011.wav|燈|JP|僕が手を離してしまった|_ b o k u g a t e o h a n a sh i t e sh i m a q t a _|0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0|1 4 2 2 1 3 3 2 5 2 1
5
+ /content/drive/MyDrive/Mygo/event235-05-001.wav|そよ|JP|ごきげんよう,睦ちゃん.今日も菜園のお世話してるの?|_ g o k i g e N y o , b o k u ch a N . ky o m o s a i e N n o o s e w a sh i t e r u n o ? _|0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0|1 2 3 2 2 1 4 3 1 2 2 3 2 2 1 4 2 4 2 1 1
6
+ /content/drive/MyDrive/Mygo/event235-28-016.wav|そよ|JP|心のどこかで,ここは自分がいる場所じゃないような気がして|_ k o k o r o n o d o k o k a d e , k o k o w a j i b u N g a i r u b a sh o j a n a i y o n a k i g a sh i t e _|0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0|1 6 2 4 2 2 1 4 2 5 2 3 4 2 3 2 2 2 2 2 2 1
7
+ /content/drive/MyDrive/Mygo/event235-39-005.wav|そよ|JP|やりたいって言ったの誰だっけ.ライブ,明日だけど|_ y a r i t a i q t e i q t a n o d a r e d a q k e . r a i b u , a s u d a k e d o _|0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0|1 4 3 3 2 2 2 4 2 2 1 1 5 1 3 2 4 1
8
+ /content/drive/MyDrive/Mygo/event235-27-053.wav|そよ|JP|……でも,私,本気で|_ . . . . . . d e m o , w a t a k u sh i , h o N k i d e _|0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0|1 1 1 1 1 1 1 2 2 1 8 1 5 2 1
BanG-Dream-VITS/hiyoriUI.py ADDED
@@ -0,0 +1,725 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ """
2
+ api服务,网页后端 多版本多模型 fastapi实现
3
+ 原 server_fastapi
4
+ """
5
+ import logging
6
+ import gc
7
+ import random
8
+ import librosa
9
+ import gradio
10
+ import numpy as np
11
+ import utils
12
+ from fastapi import FastAPI, Query, Request, File, UploadFile, Form
13
+ from fastapi.responses import Response, FileResponse
14
+ from fastapi.staticfiles import StaticFiles
15
+ from io import BytesIO
16
+ from scipy.io import wavfile
17
+ import uvicorn
18
+ import torch
19
+ import webbrowser
20
+ import psutil
21
+ import GPUtil
22
+ from typing import Dict, Optional, List, Set, Union, Tuple
23
+ import os
24
+ from tools.log import logger
25
+ from urllib.parse import unquote
26
+
27
+ from infer import infer, get_net_g, latest_version
28
+ import tools.translate as trans
29
+ from tools.sentence import split_by_language
30
+ from re_matching import cut_sent
31
+
32
+
33
+ from config import config
34
+
35
+ os.environ["TOKENIZERS_PARALLELISM"] = "false"
36
+
37
+
38
+ class Model:
39
+ """模型封装类"""
40
+
41
+ def __init__(self, config_path: str, model_path: str, device: str, language: str):
42
+ self.config_path: str = os.path.normpath(config_path)
43
+ self.model_path: str = os.path.normpath(model_path)
44
+ self.device: str = device
45
+ self.language: str = language
46
+ self.hps = utils.get_hparams_from_file(config_path)
47
+ self.spk2id: Dict[str, int] = self.hps.data.spk2id # spk - id 映射字典
48
+ self.id2spk: Dict[int, str] = dict() # id - spk 映射字典
49
+ for speaker, speaker_id in self.hps.data.spk2id.items():
50
+ self.id2spk[speaker_id] = speaker
51
+ self.version: str = (
52
+ self.hps.version if hasattr(self.hps, "version") else latest_version
53
+ )
54
+ self.net_g = get_net_g(
55
+ model_path=model_path,
56
+ version=self.version,
57
+ device=device,
58
+ hps=self.hps,
59
+ )
60
+
61
+ def to_dict(self) -> Dict[str, any]:
62
+ return {
63
+ "config_path": self.config_path,
64
+ "model_path": self.model_path,
65
+ "device": self.device,
66
+ "language": self.language,
67
+ "spk2id": self.spk2id,
68
+ "id2spk": self.id2spk,
69
+ "version": self.version,
70
+ }
71
+
72
+
73
+ class Models:
74
+ def __init__(self):
75
+ self.models: Dict[int, Model] = dict()
76
+ self.num = 0
77
+ # spkInfo[角色名][模型id] = 角色id
78
+ self.spk_info: Dict[str, Dict[int, int]] = dict()
79
+ self.path2ids: Dict[str, Set[int]] = dict() # 路径指向的model的id
80
+
81
+ def init_model(
82
+ self, config_path: str, model_path: str, device: str, language: str
83
+ ) -> int:
84
+ """
85
+ 初始化并添加一个模型
86
+
87
+ :param config_path: 模型config.json路径
88
+ :param model_path: 模型路径
89
+ :param device: 模型推理使用设备
90
+ :param language: 模型推理默认语言
91
+ """
92
+ # 若文件不存在则不进行加载
93
+ if not os.path.isfile(model_path):
94
+ if model_path != "":
95
+ logger.warning(f"模型文件{model_path} 不存在,不进行初始化")
96
+ return self.num
97
+ if not os.path.isfile(config_path):
98
+ if config_path != "":
99
+ logger.warning(f"配置文件{config_path} 不存在,不进行初始化")
100
+ return self.num
101
+
102
+ # 若路径中的模型已存在,则不添加模型,若不存在,则进行初始化。
103
+ model_path = os.path.realpath(model_path)
104
+ if model_path not in self.path2ids.keys():
105
+ self.path2ids[model_path] = {self.num}
106
+ self.models[self.num] = Model(
107
+ config_path=config_path,
108
+ model_path=model_path,
109
+ device=device,
110
+ language=language,
111
+ )
112
+ logger.success(f"添加模型{model_path},使用配置文件{os.path.realpath(config_path)}")
113
+ else:
114
+ # 获取一个指向id
115
+ m_id = next(iter(self.path2ids[model_path]))
116
+ self.models[self.num] = self.models[m_id]
117
+ self.path2ids[model_path].add(self.num)
118
+ logger.success("模型已存在,添加模型引用。")
119
+ # 添加角色信息
120
+ for speaker, speaker_id in self.models[self.num].spk2id.items():
121
+ if speaker not in self.spk_info.keys():
122
+ self.spk_info[speaker] = {self.num: speaker_id}
123
+ else:
124
+ self.spk_info[speaker][self.num] = speaker_id
125
+ # 修改计数
126
+ self.num += 1
127
+ return self.num - 1
128
+
129
+ def del_model(self, index: int) -> Optional[int]:
130
+ """删除对应序号的模型,若不存在则返回None"""
131
+ if index not in self.models.keys():
132
+ return None
133
+ # 删除角色信息
134
+ for speaker, speaker_id in self.models[index].spk2id.items():
135
+ self.spk_info[speaker].pop(index)
136
+ if len(self.spk_info[speaker]) == 0:
137
+ # 若对应角色的所有模型都被删除,则清除该角色信息
138
+ self.spk_info.pop(speaker)
139
+ # 删除路径信息
140
+ model_path = os.path.realpath(self.models[index].model_path)
141
+ self.path2ids[model_path].remove(index)
142
+ if len(self.path2ids[model_path]) == 0:
143
+ self.path2ids.pop(model_path)
144
+ logger.success(f"删除模型{model_path}, id = {index}")
145
+ else:
146
+ logger.success(f"删除模型引用{model_path}, id = {index}")
147
+ # 删除模型
148
+ self.models.pop(index)
149
+ gc.collect()
150
+ if torch.cuda.is_available():
151
+ torch.cuda.empty_cache()
152
+ return index
153
+
154
+ def get_models(self):
155
+ """获取所有模型"""
156
+ return self.models
157
+
158
+
159
+ if __name__ == "__main__":
160
+ app = FastAPI()
161
+ app.logger = logger
162
+ # 挂载静态文件
163
+ logger.info("开始挂载网页页面")
164
+ StaticDir: str = "./Web"
165
+ if not os.path.isdir(StaticDir):
166
+ logger.warning(
167
+ "缺少网页资源,无法开启网页页面,如有需要请在 https://github.com/jiangyuxiaoxiao/Bert-VITS2-UI 或者Bert-VITS对应版本的release页面下载"
168
+ )
169
+ else:
170
+ dirs = [fir.name for fir in os.scandir(StaticDir) if fir.is_dir()]
171
+ files = [fir.name for fir in os.scandir(StaticDir) if fir.is_dir()]
172
+ for dirName in dirs:
173
+ app.mount(
174
+ f"/{dirName}",
175
+ StaticFiles(directory=f"./{StaticDir}/{dirName}"),
176
+ name=dirName,
177
+ )
178
+ loaded_models = Models()
179
+ # 加载模型
180
+ logger.info("开始加载模型")
181
+ models_info = config.server_config.models
182
+ for model_info in models_info:
183
+ loaded_models.init_model(
184
+ config_path=model_info["config"],
185
+ model_path=model_info["model"],
186
+ device=model_info["device"],
187
+ language=model_info["language"],
188
+ )
189
+
190
+ @app.get("/")
191
+ async def index():
192
+ return FileResponse("./Web/index.html")
193
+
194
+ async def _voice(
195
+ text: str,
196
+ model_id: int,
197
+ speaker_name: str,
198
+ speaker_id: int,
199
+ sdp_ratio: float,
200
+ noise: float,
201
+ noisew: float,
202
+ length: float,
203
+ language: str,
204
+ auto_translate: bool,
205
+ auto_split: bool,
206
+ emotion: Optional[Union[int, str]] = None,
207
+ reference_audio=None,
208
+ style_text: Optional[str] = None,
209
+ style_weight: float = 0.7,
210
+ ) -> Union[Response, Dict[str, any]]:
211
+ """TTS实现函数"""
212
+
213
+ # 检查
214
+ # 检查模型是否存在
215
+ if model_id not in loaded_models.models.keys():
216
+ logger.error(f"/voice 请求错误:模型model_id={model_id}未加载")
217
+ return {"status": 10, "detail": f"模型model_id={model_id}未加载"}
218
+ # 检查是否提供speaker
219
+ if speaker_name is None and speaker_id is None:
220
+ logger.error("/voice 请求错误:推理请求未提供speaker_name或speaker_id")
221
+ return {"status": 11, "detail": "请提供speaker_name或speaker_id"}
222
+ elif speaker_name is None:
223
+ # 检查speaker_id是否存在
224
+ if speaker_id not in loaded_models.models[model_id].id2spk.keys():
225
+ logger.error(f"/voice 请求错误:角色speaker_id={speaker_id}不存在")
226
+ return {"status": 12, "detail": f"角色speaker_id={speaker_id}不存在"}
227
+ speaker_name = loaded_models.models[model_id].id2spk[speaker_id]
228
+ # 检查speaker_name是否存在
229
+ if speaker_name not in loaded_models.models[model_id].spk2id.keys():
230
+ logger.error(f"/voice 请求错误:角色speaker_name={speaker_name}不存在")
231
+ return {"status": 13, "detail": f"角色speaker_name={speaker_name}不存在"}
232
+ # 未传入则使用默认语言
233
+ if language is None:
234
+ language = loaded_models.models[model_id].language
235
+ # 翻译会破坏mix结构,auto也会变得无意义。不要在这两个模式下使用
236
+ if auto_translate:
237
+ if language == "auto" or language == "mix":
238
+ logger.error(
239
+ f"/voice 请求错误:请勿同时使用language = {language}与auto_translate模式"
240
+ )
241
+ return {
242
+ "status": 20,
243
+ "detail": f"请勿同时使用language = {language}与auto_translate模式",
244
+ }
245
+ text = trans.translate(Sentence=text, to_Language=language.lower())
246
+ if reference_audio is not None:
247
+ ref_audio = BytesIO(await reference_audio.read())
248
+ # 2.2 适配
249
+ if loaded_models.models[model_id].version == "2.2":
250
+ ref_audio, _ = librosa.load(ref_audio, 48000)
251
+ else:
252
+ ref_audio = reference_audio
253
+
254
+ # 改动:增加使用 || 对文本进行主动切分
255
+ # 切分优先级: || → auto/mix → auto_split
256
+ text2 = text.replace("\n", "").lstrip()
257
+ texts: List[str] = text2.split("||")
258
+
259
+ # 对于mix和auto的说明:出于版本兼容性���考虑,暂时无法使用multilang的方式进行推理
260
+ if language == "MIX":
261
+ text_language_speakers: List[Tuple[str, str, str]] = []
262
+ for _text in texts:
263
+ speaker_pieces = _text.split("[") # 按说话人分割多块
264
+ for speaker_piece in speaker_pieces:
265
+ if speaker_piece == "":
266
+ continue
267
+ speaker_piece2 = speaker_piece.split("]")
268
+ if len(speaker_piece2) != 2:
269
+ return {
270
+ "status": 21,
271
+ "detail": "MIX语法错误",
272
+ }
273
+ speaker = speaker_piece2[0].strip()
274
+ lang_pieces = speaker_piece2[1].split("<")
275
+ for lang_piece in lang_pieces:
276
+ if lang_piece == "":
277
+ continue
278
+ lang_piece2 = lang_piece.split(">")
279
+ if len(lang_piece2) != 2:
280
+ return {
281
+ "status": 21,
282
+ "detail": "MIX语法错误",
283
+ }
284
+ lang = lang_piece2[0].strip()
285
+ if lang.upper() not in ["ZH", "EN", "JP"]:
286
+ return {
287
+ "status": 21,
288
+ "detail": "MIX语法错误",
289
+ }
290
+ t = lang_piece2[1]
291
+ text_language_speakers.append((t, lang.upper(), speaker))
292
+
293
+ elif language == "AUTO":
294
+ text_language_speakers: List[Tuple[str, str, str]] = [
295
+ (final_text, language.upper().replace("JA", "JP"), speaker_name)
296
+ for sub_list in [
297
+ split_by_language(_text, target_languages=["zh", "ja", "en"])
298
+ for _text in texts
299
+ if _text != ""
300
+ ]
301
+ for final_text, language in sub_list
302
+ if final_text != ""
303
+ ]
304
+ else:
305
+ text_language_speakers: List[Tuple[str, str, str]] = [
306
+ (_text, language, speaker_name) for _text in texts if _text != ""
307
+ ]
308
+
309
+ if auto_split:
310
+ text_language_speakers: List[Tuple[str, str, str]] = [
311
+ (final_text, lang, speaker)
312
+ for _text, lang, speaker in text_language_speakers
313
+ for final_text in cut_sent(_text)
314
+ ]
315
+
316
+ audios = []
317
+ with torch.no_grad():
318
+ for _text, lang, speaker in text_language_speakers:
319
+ audios.append(
320
+ infer(
321
+ text=_text,
322
+ sdp_ratio=sdp_ratio,
323
+ noise_scale=noise,
324
+ noise_scale_w=noisew,
325
+ length_scale=length,
326
+ sid=speaker,
327
+ language=lang,
328
+ hps=loaded_models.models[model_id].hps,
329
+ net_g=loaded_models.models[model_id].net_g,
330
+ device=loaded_models.models[model_id].device,
331
+ emotion=emotion,
332
+ reference_audio=ref_audio,
333
+ style_text=style_text,
334
+ style_weight=style_weight,
335
+ )
336
+ )
337
+ # audios.append(np.zeros(int(44100 * 0.2)))
338
+ # audios.pop()
339
+ audio = np.concatenate(audios)
340
+ audio = gradio.processing_utils.convert_to_16_bit_wav(audio)
341
+ with BytesIO() as wavContent:
342
+ wavfile.write(
343
+ wavContent, loaded_models.models[model_id].hps.data.sampling_rate, audio
344
+ )
345
+ response = Response(content=wavContent.getvalue(), media_type="audio/wav")
346
+ return response
347
+
348
+ @app.post("/voice")
349
+ async def voice(
350
+ request: Request, # fastapi自动注入
351
+ text: str = Form(...),
352
+ model_id: int = Query(..., description="模型ID"), # 模型序号
353
+ speaker_name: str = Query(
354
+ None, description="说话人名"
355
+ ), # speaker_name与 speaker_id二者选其一
356
+ speaker_id: int = Query(None, description="说话人id,与speaker_name二选一"),
357
+ sdp_ratio: float = Query(0.2, description="SDP/DP混合比"),
358
+ noise: float = Query(0.2, description="感情"),
359
+ noisew: float = Query(0.9, description="音素长度"),
360
+ length: float = Query(1, description="语速"),
361
+ language: str = Query(None, description="语言"), # 若不指定使用语言则使用默认值
362
+ auto_translate: bool = Query(False, description="自动翻译"),
363
+ auto_split: bool = Query(False, description="自动切分"),
364
+ emotion: Optional[Union[int, str]] = Query(None, description="emo"),
365
+ reference_audio: UploadFile = File(None),
366
+ style_text: Optional[str] = Form(None, description="风格文本"),
367
+ style_weight: float = Query(0.7, description="风格权重"),
368
+ ):
369
+ """语音接口,若需要上传参考音频请仅使用post请求"""
370
+ logger.info(
371
+ f"{request.client.host}:{request.client.port}/voice { unquote(str(request.query_params) )} text={text}"
372
+ )
373
+ return await _voice(
374
+ text=text,
375
+ model_id=model_id,
376
+ speaker_name=speaker_name,
377
+ speaker_id=speaker_id,
378
+ sdp_ratio=sdp_ratio,
379
+ noise=noise,
380
+ noisew=noisew,
381
+ length=length,
382
+ language=language,
383
+ auto_translate=auto_translate,
384
+ auto_split=auto_split,
385
+ emotion=emotion,
386
+ reference_audio=reference_audio,
387
+ style_text=style_text,
388
+ style_weight=style_weight,
389
+ )
390
+
391
+ @app.get("/voice")
392
+ async def voice(
393
+ request: Request, # fastapi自动注入
394
+ text: str = Query(..., description="输入文字"),
395
+ model_id: int = Query(..., description="模型ID"), # 模型序号
396
+ speaker_name: str = Query(
397
+ None, description="说话人名"
398
+ ), # speaker_name与 speaker_id二者选其一
399
+ speaker_id: int = Query(None, description="说话人id,与speaker_name二选一"),
400
+ sdp_ratio: float = Query(0.2, description="SDP/DP混合比"),
401
+ noise: float = Query(0.2, description="感情"),
402
+ noisew: float = Query(0.9, description="音素长度"),
403
+ length: float = Query(1, description="语速"),
404
+ language: str = Query(None, description="语言"), # 若不指定使用语言则使用默认值
405
+ auto_translate: bool = Query(False, description="自动翻译"),
406
+ auto_split: bool = Query(False, description="自动切分"),
407
+ emotion: Optional[Union[int, str]] = Query(None, description="emo"),
408
+ style_text: Optional[str] = Query(None, description="风格文本"),
409
+ style_weight: float = Query(0.7, description="风格权重"),
410
+ ):
411
+ """语音接口,不建议使用"""
412
+ logger.info(
413
+ f"{request.client.host}:{request.client.port}/voice { unquote(str(request.query_params) )}"
414
+ )
415
+ return await _voice(
416
+ text=text,
417
+ model_id=model_id,
418
+ speaker_name=speaker_name,
419
+ speaker_id=speaker_id,
420
+ sdp_ratio=sdp_ratio,
421
+ noise=noise,
422
+ noisew=noisew,
423
+ length=length,
424
+ language=language,
425
+ auto_translate=auto_translate,
426
+ auto_split=auto_split,
427
+ emotion=emotion,
428
+ style_text=style_text,
429
+ style_weight=style_weight,
430
+ )
431
+
432
+ @app.get("/models/info")
433
+ def get_loaded_models_info(request: Request):
434
+ """获取已加载模型信息"""
435
+
436
+ result: Dict[str, Dict] = dict()
437
+ for key, model in loaded_models.models.items():
438
+ result[str(key)] = model.to_dict()
439
+ return result
440
+
441
+ @app.get("/models/delete")
442
+ def delete_model(
443
+ request: Request, model_id: int = Query(..., description="删除模型id")
444
+ ):
445
+ """删除指定模型"""
446
+ logger.info(
447
+ f"{request.client.host}:{request.client.port}/models/delete { unquote(str(request.query_params) )}"
448
+ )
449
+ result = loaded_models.del_model(model_id)
450
+ if result is None:
451
+ logger.error(f"/models/delete 模型删除错误:模型{model_id}不存在,删除失败")
452
+ return {"status": 14, "detail": f"模型{model_id}不存在,删除失败"}
453
+
454
+ return {"status": 0, "detail": "删除成功"}
455
+
456
+ @app.get("/models/add")
457
+ def add_model(
458
+ request: Request,
459
+ model_path: str = Query(..., description="添加模型路径"),
460
+ config_path: str = Query(
461
+ None, description="添加模型配置文件路径,不填则使用./config.json或../config.json"
462
+ ),
463
+ device: str = Query("cuda", description="推理使用设备"),
464
+ language: str = Query("ZH", description="模型默认语言"),
465
+ ):
466
+ """添加指定模型:允许重复添加相同路径模型,且不重复占用内存"""
467
+ logger.info(
468
+ f"{request.client.host}:{request.client.port}/models/add { unquote(str(request.query_params) )}"
469
+ )
470
+ if config_path is None:
471
+ model_dir = os.path.dirname(model_path)
472
+ if os.path.isfile(os.path.join(model_dir, "config.json")):
473
+ config_path = os.path.join(model_dir, "config.json")
474
+ elif os.path.isfile(os.path.join(model_dir, "../config.json")):
475
+ config_path = os.path.join(model_dir, "../config.json")
476
+ else:
477
+ logger.error("/models/add 模型添加失败:未在模型所在目录以及上级目录找到config.json文件")
478
+ return {
479
+ "status": 15,
480
+ "detail": "查询未传���配置文件路径,同时默认路径./与../中不存在配置文件config.json。",
481
+ }
482
+ try:
483
+ model_id = loaded_models.init_model(
484
+ config_path=config_path,
485
+ model_path=model_path,
486
+ device=device,
487
+ language=language,
488
+ )
489
+ except Exception:
490
+ logging.exception("模型加载出错")
491
+ return {
492
+ "status": 16,
493
+ "detail": "模型加载出错,详细查看日志",
494
+ }
495
+ return {
496
+ "status": 0,
497
+ "detail": "模型添加成功",
498
+ "Data": {
499
+ "model_id": model_id,
500
+ "model_info": loaded_models.models[model_id].to_dict(),
501
+ },
502
+ }
503
+
504
+ def _get_all_models(root_dir: str = "Data", only_unloaded: bool = False):
505
+ """从root_dir搜索获取所有可用模型"""
506
+ result: Dict[str, List[str]] = dict()
507
+ files = os.listdir(root_dir) + ["."]
508
+ for file in files:
509
+ if os.path.isdir(os.path.join(root_dir, file)):
510
+ sub_dir = os.path.join(root_dir, file)
511
+ # 搜索 "sub_dir" 、 "sub_dir/models" 两个路径
512
+ result[file] = list()
513
+ sub_files = os.listdir(sub_dir)
514
+ model_files = []
515
+ for sub_file in sub_files:
516
+ relpath = os.path.realpath(os.path.join(sub_dir, sub_file))
517
+ if only_unloaded and relpath in loaded_models.path2ids.keys():
518
+ continue
519
+ if sub_file.endswith(".pth") and sub_file.startswith("G_"):
520
+ if os.path.isfile(relpath):
521
+ model_files.append(sub_file)
522
+ # 对模型文件按步数排序
523
+ model_files = sorted(
524
+ model_files,
525
+ key=lambda pth: int(pth.lstrip("G_").rstrip(".pth"))
526
+ if pth.lstrip("G_").rstrip(".pth").isdigit()
527
+ else 10**10,
528
+ )
529
+ result[file] = model_files
530
+ models_dir = os.path.join(sub_dir, "models")
531
+ model_files = []
532
+ if os.path.isdir(models_dir):
533
+ sub_files = os.listdir(models_dir)
534
+ for sub_file in sub_files:
535
+ relpath = os.path.realpath(os.path.join(models_dir, sub_file))
536
+ if only_unloaded and relpath in loaded_models.path2ids.keys():
537
+ continue
538
+ if sub_file.endswith(".pth") and sub_file.startswith("G_"):
539
+ if os.path.isfile(os.path.join(models_dir, sub_file)):
540
+ model_files.append(f"models/{sub_file}")
541
+ # 对模型文件按步数排序
542
+ model_files = sorted(
543
+ model_files,
544
+ key=lambda pth: int(pth.lstrip("models/G_").rstrip(".pth"))
545
+ if pth.lstrip("models/G_").rstrip(".pth").isdigit()
546
+ else 10**10,
547
+ )
548
+ result[file] += model_files
549
+ if len(result[file]) == 0:
550
+ result.pop(file)
551
+
552
+ return result
553
+
554
+ @app.get("/models/get_unloaded")
555
+ def get_unloaded_models_info(
556
+ request: Request, root_dir: str = Query("Data", description="搜索根目录")
557
+ ):
558
+ """获取未加载模型"""
559
+ logger.info(
560
+ f"{request.client.host}:{request.client.port}/models/get_unloaded { unquote(str(request.query_params) )}"
561
+ )
562
+ return _get_all_models(root_dir, only_unloaded=True)
563
+
564
+ @app.get("/models/get_local")
565
+ def get_local_models_info(
566
+ request: Request, root_dir: str = Query("Data", description="搜索根目录")
567
+ ):
568
+ """获取全部本地模型"""
569
+ logger.info(
570
+ f"{request.client.host}:{request.client.port}/models/get_local { unquote(str(request.query_params) )}"
571
+ )
572
+ return _get_all_models(root_dir, only_unloaded=False)
573
+
574
+ @app.get("/status")
575
+ def get_status():
576
+ """获取电脑运行状态"""
577
+ cpu_percent = psutil.cpu_percent(interval=1)
578
+ memory_info = psutil.virtual_memory()
579
+ memory_total = memory_info.total
580
+ memory_available = memory_info.available
581
+ memory_used = memory_info.used
582
+ memory_percent = memory_info.percent
583
+ gpuInfo = []
584
+ devices = ["cpu"]
585
+ for i in range(torch.cuda.device_count()):
586
+ devices.append(f"cuda:{i}")
587
+ gpus = GPUtil.getGPUs()
588
+ for gpu in gpus:
589
+ gpuInfo.append(
590
+ {
591
+ "gpu_id": gpu.id,
592
+ "gpu_load": gpu.load,
593
+ "gpu_memory": {
594
+ "total": gpu.memoryTotal,
595
+ "used": gpu.memoryUsed,
596
+ "free": gpu.memoryFree,
597
+ },
598
+ }
599
+ )
600
+ return {
601
+ "devices": devices,
602
+ "cpu_percent": cpu_percent,
603
+ "memory_total": memory_total,
604
+ "memory_available": memory_available,
605
+ "memory_used": memory_used,
606
+ "memory_percent": memory_percent,
607
+ "gpu": gpuInfo,
608
+ }
609
+
610
+ @app.get("/tools/translate")
611
+ def translate(
612
+ request: Request,
613
+ texts: str = Query(..., description="待翻译文本"),
614
+ to_language: str = Query(..., description="翻译目标语言"),
615
+ ):
616
+ """翻译"""
617
+ logger.info(
618
+ f"{request.client.host}:{request.client.port}/tools/translate { unquote(str(request.query_params) )}"
619
+ )
620
+ return {"texts": trans.translate(Sentence=texts, to_Language=to_language)}
621
+
622
+ all_examples: Dict[str, Dict[str, List]] = dict() # 存放示例
623
+
624
+ @app.get("/tools/random_example")
625
+ def random_example(
626
+ request: Request,
627
+ language: str = Query(None, description="指定语言,未指定则随机返回"),
628
+ root_dir: str = Query("Data", description="搜索根目录"),
629
+ ):
630
+ """
631
+ 获取一个随机音频+文本,用于对比,音频会从本地目录随机选择。
632
+ """
633
+ logger.info(
634
+ f"{request.client.host}:{request.client.port}/tools/random_example { unquote(str(request.query_params) )}"
635
+ )
636
+ global all_examples
637
+ # 数据初始化
638
+ if root_dir not in all_examples.keys():
639
+ all_examples[root_dir] = {"ZH": [], "JP": [], "EN": []}
640
+
641
+ examples = all_examples[root_dir]
642
+
643
+ # 从项目Data目录中搜索train/val.list
644
+ for root, directories, _files in os.walk(root_dir):
645
+ for file in _files:
646
+ if file in ["train.list", "val.list"]:
647
+ with open(
648
+ os.path.join(root, file), mode="r", encoding="utf-8"
649
+ ) as f:
650
+ lines = f.readlines()
651
+ for line in lines:
652
+ data = line.split("|")
653
+ if len(data) != 7:
654
+ continue
655
+ # 音频存在 且语言为ZH/EN/JP
656
+ if os.path.isfile(data[0]) and data[2] in [
657
+ "ZH",
658
+ "JP",
659
+ "EN",
660
+ ]:
661
+ examples[data[2]].append(
662
+ {
663
+ "text": data[3],
664
+ "audio": data[0],
665
+ "speaker": data[1],
666
+ }
667
+ )
668
+
669
+ examples = all_examples[root_dir]
670
+ if language is None:
671
+ if len(examples["ZH"]) + len(examples["JP"]) + len(examples["EN"]) == 0:
672
+ return {"status": 17, "detail": "没有加载任何示例数据"}
673
+ else:
674
+ # 随机选一个
675
+ rand_num = random.randint(
676
+ 0,
677
+ len(examples["ZH"]) + len(examples["JP"]) + len(examples["EN"]) - 1,
678
+ )
679
+ # ZH
680
+ if rand_num < len(examples["ZH"]):
681
+ return {"status": 0, "Data": examples["ZH"][rand_num]}
682
+ # JP
683
+ if rand_num < len(examples["ZH"]) + len(examples["JP"]):
684
+ return {
685
+ "status": 0,
686
+ "Data": examples["JP"][rand_num - len(examples["ZH"])],
687
+ }
688
+ # EN
689
+ return {
690
+ "status": 0,
691
+ "Data": examples["EN"][
692
+ rand_num - len(examples["ZH"]) - len(examples["JP"])
693
+ ],
694
+ }
695
+
696
+ else:
697
+ if len(examples[language]) == 0:
698
+ return {"status": 17, "detail": f"没有加载任何{language}数据"}
699
+ return {
700
+ "status": 0,
701
+ "Data": examples[language][
702
+ random.randint(0, len(examples[language]) - 1)
703
+ ],
704
+ }
705
+
706
+ @app.get("/tools/get_audio")
707
+ def get_audio(request: Request, path: str = Query(..., description="本地音频路径")):
708
+ logger.info(
709
+ f"{request.client.host}:{request.client.port}/tools/get_audio { unquote(str(request.query_params) )}"
710
+ )
711
+ if not os.path.isfile(path):
712
+ logger.error(f"/tools/get_audio 获取音频错误:指定音频{path}不存在")
713
+ return {"status": 18, "detail": "指定音频不存在"}
714
+ if not path.lower().endswith(".wav"):
715
+ logger.error(f"/tools/get_audio 获取音频错误:音频{path}非wav文件")
716
+ return {"status": 19, "detail": "非wav格式文件"}
717
+ return FileResponse(path=path)
718
+
719
+ logger.warning("本地服务,请勿将服务端口暴露于外网")
720
+ logger.info(f"api文档地址 http://127.0.0.1:{config.server_config.port}/docs")
721
+ if os.path.isdir(StaticDir):
722
+ webbrowser.open(f"http://127.0.0.1:{config.server_config.port}")
723
+ uvicorn.run(
724
+ app, port=config.server_config.port, host="0.0.0.0", log_level="warning"
725
+ )
BanG-Dream-VITS/image/あこ.png ADDED

Git LFS Details

  • SHA256: d1a19308810248f080038d0031dc690ca4476688b7f85040f1e411ade90a37e1
  • Pointer size: 131 Bytes
  • Size of remote file: 163 kB
BanG-Dream-VITS/image/こころ.png ADDED

Git LFS Details

  • SHA256: f2c86f6ca1cdc615f78a60e8c8e91b83a47ed1ffe4590cfb314de509c8ffa924
  • Pointer size: 131 Bytes
  • Size of remote file: 134 kB
BanG-Dream-VITS/image/そよ.png ADDED

Git LFS Details

  • SHA256: 73a4cbf1127059e2fead8d8e85db88e987000fe2420f1316ab7a4a945fb44508
  • Pointer size: 131 Bytes
  • Size of remote file: 454 kB
BanG-Dream-VITS/image/たえ.png ADDED

Git LFS Details

  • SHA256: 40cc370912940d6d18770a1e66bbe903c10fae05a4327e776b43d3e38bcfe4d9
  • Pointer size: 131 Bytes
  • Size of remote file: 118 kB
BanG-Dream-VITS/image/つくし.png ADDED

Git LFS Details

  • SHA256: cf0241009ddd705dccf2e0fc52444c6c2794a6f8cf53a752de7cad71f3051bce
  • Pointer size: 131 Bytes
  • Size of remote file: 111 kB
BanG-Dream-VITS/image/つぐみ.png ADDED

Git LFS Details

  • SHA256: f0b43bb4c13cb17f386a1758454c4d0718775f1a7fe89d8a7caef590765c37ac
  • Pointer size: 131 Bytes
  • Size of remote file: 125 kB
BanG-Dream-VITS/image/にゃむ.png ADDED

Git LFS Details

  • SHA256: 6810095337e08e512803377879fea65892f570ef46080de500cf58dc36536184
  • Pointer size: 131 Bytes
  • Size of remote file: 243 kB
BanG-Dream-VITS/image/はぐみ.png ADDED

Git LFS Details

  • SHA256: a28f9ab9c09cc0e13617483b208c6965a0f180b2eda872fb1ec0d852ee682a6f
  • Pointer size: 131 Bytes
  • Size of remote file: 112 kB
BanG-Dream-VITS/image/ひまり.png ADDED

Git LFS Details

  • SHA256: b1a6c85f7af718984c38540766e908fb3ae035b8baee8808af3598d2cbfd1d04
  • Pointer size: 131 Bytes
  • Size of remote file: 113 kB
BanG-Dream-VITS/image/ましろ.png ADDED

Git LFS Details

  • SHA256: 2beb0d2613de9f2bf26eced01ac1a44345af685090842ade4aef58394bcdee41
  • Pointer size: 131 Bytes
  • Size of remote file: 107 kB
BanG-Dream-VITS/image//343/201/276/343/201/231/343/201/215.png ADDED
BanG-Dream-VITS/image/りみ.png ADDED

Git LFS Details

  • SHA256: e22b2eab156ba42274317bada7cdbfdb3d9170265ef8bd69089af4e7fb70a0c9
  • Pointer size: 131 Bytes
  • Size of remote file: 115 kB
BanG-Dream-VITS/image/イヴ.png ADDED

Git LFS Details

  • SHA256: 5f6729d3876a0470a4ff2ef79ad656cafe8d93a51206a36e5c80eef00a37b97d
  • Pointer size: 131 Bytes
  • Size of remote file: 133 kB
BanG-Dream-VITS/image/チュチュ.png ADDED

Git LFS Details

  • SHA256: e6e8fff79b839d1f9e0a3edd4aba192c8d8f29df1bd6a4c1e33a72524eb983f7
  • Pointer size: 131 Bytes
  • Size of remote file: 120 kB
BanG-Dream-VITS/image/パレオ.png ADDED

Git LFS Details

  • SHA256: 891c0b3f7faafc360a197525b9d70136578cba0e298e3cebefab06e6edee1911
  • Pointer size: 131 Bytes
  • Size of remote file: 131 kB
BanG-Dream-VITS/image//343/203/236/343/202/271/343/202/255/343/203/263/343/202/260.png ADDED