Skip to content

Commit 6f5c384

Browse files
authored
整理: ユーザー辞書のdocstring・変数名・型・コメント (#836)
1 parent e90a2f7 commit 6f5c384

File tree

2 files changed

+181
-30
lines changed

2 files changed

+181
-30
lines changed

test/test_user_dict.py

+3-3
Original file line numberDiff line numberDiff line change
@@ -11,8 +11,8 @@
1111
from voicevox_engine.model import UserDictWord, WordTypes
1212
from voicevox_engine.part_of_speech_data import MAX_PRIORITY, part_of_speech_data
1313
from voicevox_engine.user_dict import (
14+
_create_word,
1415
apply_word,
15-
create_word,
1616
delete_word,
1717
import_user_dict,
1818
read_dict,
@@ -90,7 +90,7 @@ def test_read_not_exist_json(self):
9090
def test_create_word(self):
9191
# 将来的に品詞などが追加された時にテストを増やす
9292
self.assertEqual(
93-
create_word(surface="test", pronunciation="テスト", accent_type=1),
93+
_create_word(surface="test", pronunciation="テスト", accent_type=1),
9494
UserDictWord(
9595
surface="test",
9696
priority=5,
@@ -219,7 +219,7 @@ def test_priority(self):
219219
for pos in part_of_speech_data:
220220
for i in range(MAX_PRIORITY + 1):
221221
self.assertEqual(
222-
create_word(
222+
_create_word(
223223
surface="test",
224224
pronunciation="テスト",
225225
accent_type=1,

voicevox_engine/user_dict.py

+178-27
Original file line numberDiff line numberDiff line change
@@ -21,27 +21,39 @@
2121
if not save_dir.is_dir():
2222
save_dir.mkdir(parents=True)
2323

24-
default_dict_path = root_dir / "default.csv"
25-
user_dict_path = save_dir / "user_dict.json"
26-
compiled_dict_path = save_dir / "user.dic"
24+
default_dict_path = root_dir / "default.csv" # VOICEVOXデフォルト辞書ファイルのパス
25+
user_dict_path = save_dir / "user_dict.json" # ユーザー辞書ファイルのパス
26+
compiled_dict_path = save_dir / "user.dic" # コンパイル済み辞書ファイルのパス
2727

2828

29+
# 同時書き込みの制御
2930
mutex_user_dict = threading.Lock()
3031
mutex_openjtalk_dict = threading.Lock()
3132

3233

3334
@mutex_wrapper(mutex_user_dict)
34-
def write_to_json(user_dict: Dict[str, UserDictWord], user_dict_path: Path):
35+
def _write_to_json(user_dict: Dict[str, UserDictWord], user_dict_path: Path) -> None:
36+
"""
37+
ユーザー辞書ファイルへのユーザー辞書データ書き込み
38+
Parameters
39+
----------
40+
user_dict : Dict[str, UserDictWord]
41+
ユーザー辞書データ
42+
user_dict_path : Path
43+
ユーザー辞書ファイルのパス
44+
"""
3545
converted_user_dict = {}
3646
for word_uuid, word in user_dict.items():
3747
word_dict = word.dict()
38-
word_dict["cost"] = priority2cost(
48+
word_dict["cost"] = _priority2cost(
3949
word_dict["context_id"], word_dict["priority"]
4050
)
4151
del word_dict["priority"]
4252
converted_user_dict[word_uuid] = word_dict
4353
# 予めjsonに変換できることを確かめる
4454
user_dict_json = json.dumps(converted_user_dict, ensure_ascii=False)
55+
56+
# ユーザー辞書ファイルへの書き込み
4557
user_dict_path.write_text(user_dict_json, encoding="utf-8")
4658

4759

@@ -50,21 +62,38 @@ def update_dict(
5062
default_dict_path: Path = default_dict_path,
5163
user_dict_path: Path = user_dict_path,
5264
compiled_dict_path: Path = compiled_dict_path,
53-
):
65+
) -> None:
66+
"""
67+
辞書の更新
68+
Parameters
69+
----------
70+
default_dict_path : Path
71+
デフォルト辞書ファイルのパス
72+
user_dict_path : Path
73+
ユーザー辞書ファイルのパス
74+
compiled_dict_path : Path
75+
コンパイル済み辞書ファイルのパス
76+
"""
5477
random_string = uuid4()
55-
tmp_csv_path = save_dir / f".tmp.dict_csv-{random_string}"
56-
tmp_compiled_path = save_dir / f".tmp.dict_compiled-{random_string}"
78+
tmp_csv_path = save_dir / f".tmp.dict_csv-{random_string}" # csv形式辞書データの一時保存ファイル
79+
tmp_compiled_path = (
80+
save_dir / f".tmp.dict_compiled-{random_string}"
81+
) # コンパイル済み辞書データの一時保存ファイル
5782

5883
try:
5984
# 辞書.csvを作成
6085
csv_text = ""
86+
87+
# デフォルト辞書データの追加
6188
if not default_dict_path.is_file():
6289
print("Warning: Cannot find default dictionary.", file=sys.stderr)
6390
return
6491
default_dict = default_dict_path.read_text(encoding="utf-8")
6592
if default_dict == default_dict.rstrip():
6693
default_dict += "\n"
6794
csv_text += default_dict
95+
96+
# ユーザー辞書データの追加
6897
user_dict = read_dict(user_dict_path=user_dict_path)
6998
for word_uuid in user_dict:
7099
word = user_dict[word_uuid]
@@ -77,7 +106,7 @@ def update_dict(
77106
).format(
78107
surface=word.surface,
79108
context_id=word.context_id,
80-
cost=priority2cost(word.context_id, word.priority),
109+
cost=_priority2cost(word.context_id, word.priority),
81110
part_of_speech=word.part_of_speech,
82111
part_of_speech_detail_1=word.part_of_speech_detail_1,
83112
part_of_speech_detail_2=word.part_of_speech_detail_2,
@@ -91,6 +120,7 @@ def update_dict(
91120
mora_count=word.mora_count,
92121
accent_associative_rule=word.accent_associative_rule,
93122
)
123+
# 辞書データを辞書.csv へ一時保存
94124
tmp_csv_path.write_text(csv_text, encoding="utf-8")
95125

96126
# 辞書.csvをOpenJTalk用にコンパイル
@@ -119,10 +149,23 @@ def update_dict(
119149

120150
@mutex_wrapper(mutex_user_dict)
121151
def read_dict(user_dict_path: Path = user_dict_path) -> Dict[str, UserDictWord]:
152+
"""
153+
ユーザー辞書の読み出し
154+
Parameters
155+
----------
156+
user_dict_path : Path
157+
ユーザー辞書ファイルのパス
158+
Returns
159+
-------
160+
result : Dict[str, UserDictWord]
161+
ユーザー辞書
162+
"""
163+
# 指定ユーザー辞書が存在しない場合、空辞書を返す
122164
if not user_dict_path.is_file():
123165
return {}
166+
124167
with user_dict_path.open(encoding="utf-8") as f:
125-
result = {}
168+
result: Dict[str, UserDictWord] = {}
126169
for word_uuid, word in json.load(f).items():
127170
# cost2priorityで変換を行う際にcontext_idが必要となるが、
128171
# 0.12以前の辞書は、context_idがハードコーディングされていたためにユーザー辞書内に保管されていない
@@ -131,20 +174,39 @@ def read_dict(user_dict_path: Path = user_dict_path) -> Dict[str, UserDictWord]:
131174
word["context_id"] = part_of_speech_data[
132175
WordTypes.PROPER_NOUN
133176
].context_id
134-
word["priority"] = cost2priority(word["context_id"], word["cost"])
177+
word["priority"] = _cost2priority(word["context_id"], word["cost"])
135178
del word["cost"]
136179
result[str(UUID(word_uuid))] = UserDictWord(**word)
137180

138181
return result
139182

140183

141-
def create_word(
184+
def _create_word(
142185
surface: str,
143186
pronunciation: str,
144187
accent_type: int,
145188
word_type: Optional[WordTypes] = None,
146189
priority: Optional[int] = None,
147190
) -> UserDictWord:
191+
"""
192+
単語オブジェクトの生成
193+
Parameters
194+
----------
195+
surface : str
196+
単語情報
197+
pronunciation : str
198+
単語情報
199+
accent_type : int
200+
単語情報
201+
word_type : Optional[WordTypes]
202+
品詞
203+
priority : Optional[int]
204+
優先度
205+
Returns
206+
-------
207+
: UserDictWord
208+
単語オブジェクト
209+
"""
148210
if word_type is None:
149211
word_type = WordTypes.PROPER_NOUN
150212
if word_type not in part_of_speech_data.keys():
@@ -181,7 +243,31 @@ def apply_word(
181243
user_dict_path: Path = user_dict_path,
182244
compiled_dict_path: Path = compiled_dict_path,
183245
) -> str:
184-
word = create_word(
246+
"""
247+
新規単語の追加
248+
Parameters
249+
----------
250+
surface : str
251+
単語情報
252+
pronunciation : str
253+
単語情報
254+
accent_type : int
255+
単語情報
256+
word_type : Optional[WordTypes]
257+
品詞
258+
priority : Optional[int]
259+
優先度
260+
user_dict_path : Path
261+
ユーザー辞書ファイルのパス
262+
compiled_dict_path : Path
263+
コンパイル済み辞書ファイルのパス
264+
Returns
265+
-------
266+
word_uuid : UserDictWord
267+
追加された単語に発行されたUUID
268+
"""
269+
# 新規単語の追加による辞書データの更新
270+
word = _create_word(
185271
surface=surface,
186272
pronunciation=pronunciation,
187273
accent_type=accent_type,
@@ -191,8 +277,11 @@ def apply_word(
191277
user_dict = read_dict(user_dict_path=user_dict_path)
192278
word_uuid = str(uuid4())
193279
user_dict[word_uuid] = word
194-
write_to_json(user_dict, user_dict_path)
280+
281+
# 更新された辞書データの保存と適用
282+
_write_to_json(user_dict, user_dict_path)
195283
update_dict(user_dict_path=user_dict_path, compiled_dict_path=compiled_dict_path)
284+
196285
return word_uuid
197286

198287

@@ -205,32 +294,71 @@ def rewrite_word(
205294
priority: Optional[int] = None,
206295
user_dict_path: Path = user_dict_path,
207296
compiled_dict_path: Path = compiled_dict_path,
208-
):
209-
word = create_word(
297+
) -> None:
298+
"""
299+
既存単語の上書き更新
300+
Parameters
301+
----------
302+
word_uuid : str
303+
単語UUID
304+
surface : str
305+
単語情報
306+
pronunciation : str
307+
単語情報
308+
accent_type : int
309+
単語情報
310+
word_type : Optional[WordTypes]
311+
品詞
312+
priority : Optional[int]
313+
優先度
314+
user_dict_path : Path
315+
ユーザー辞書ファイルのパス
316+
compiled_dict_path : Path
317+
コンパイル済み辞書ファイルのパス
318+
"""
319+
word = _create_word(
210320
surface=surface,
211321
pronunciation=pronunciation,
212322
accent_type=accent_type,
213323
word_type=word_type,
214324
priority=priority,
215325
)
326+
327+
# 既存単語の上書きによる辞書データの更新
216328
user_dict = read_dict(user_dict_path=user_dict_path)
217329
if word_uuid not in user_dict:
218330
raise HTTPException(status_code=422, detail="UUIDに該当するワードが見つかりませんでした")
219331
user_dict[word_uuid] = word
220-
write_to_json(user_dict, user_dict_path)
332+
333+
# 更新された辞書データの保存と適用
334+
_write_to_json(user_dict, user_dict_path)
221335
update_dict(user_dict_path=user_dict_path, compiled_dict_path=compiled_dict_path)
222336

223337

224338
def delete_word(
225339
word_uuid: str,
226340
user_dict_path: Path = user_dict_path,
227341
compiled_dict_path: Path = compiled_dict_path,
228-
):
342+
) -> None:
343+
"""
344+
単語の削除
345+
Parameters
346+
----------
347+
word_uuid : str
348+
単語UUID
349+
user_dict_path : Path
350+
ユーザー辞書ファイルのパス
351+
compiled_dict_path : Path
352+
コンパイル済み辞書ファイルのパス
353+
"""
354+
# 既存単語の削除による辞書データの更新
229355
user_dict = read_dict(user_dict_path=user_dict_path)
230356
if word_uuid not in user_dict:
231357
raise HTTPException(status_code=422, detail="IDに該当するワードが見つかりませんでした")
232358
del user_dict[word_uuid]
233-
write_to_json(user_dict, user_dict_path)
359+
360+
# 更新された辞書データの保存と適用
361+
_write_to_json(user_dict, user_dict_path)
234362
update_dict(user_dict_path=user_dict_path, compiled_dict_path=compiled_dict_path)
235363

236364

@@ -240,8 +368,23 @@ def import_user_dict(
240368
user_dict_path: Path = user_dict_path,
241369
default_dict_path: Path = default_dict_path,
242370
compiled_dict_path: Path = compiled_dict_path,
243-
):
244-
# 念のため型チェックを行う
371+
) -> None:
372+
"""
373+
ユーザー辞書のインポート
374+
Parameters
375+
----------
376+
dict_data : Dict[str, UserDictWord]
377+
インポートするユーザー辞書のデータ
378+
override : bool
379+
重複したエントリがあった場合、上書きするかどうか
380+
user_dict_path : Path
381+
ユーザー辞書ファイルのパス
382+
default_dict_path : Path
383+
デフォルト辞書ファイルのパス
384+
compiled_dict_path : Path
385+
コンパイル済み辞書ファイルのパス
386+
"""
387+
# インポートする辞書データのバリデーション
245388
for word_uuid, word in dict_data.items():
246389
UUID(word_uuid)
247390
assert isinstance(word, UserDictWord)
@@ -263,36 +406,44 @@ def import_user_dict(
263406
break
264407
else:
265408
raise ValueError("対応していない品詞です")
409+
410+
# 既存辞書の読み出し
266411
old_dict = read_dict(user_dict_path=user_dict_path)
412+
413+
# 辞書データの更新
414+
# 重複エントリの上書き
267415
if override:
268416
new_dict = {**old_dict, **dict_data}
417+
# 重複エントリの保持
269418
else:
270419
new_dict = {**dict_data, **old_dict}
271-
write_to_json(user_dict=new_dict, user_dict_path=user_dict_path)
420+
421+
# 更新された辞書データの保存と適用
422+
_write_to_json(user_dict=new_dict, user_dict_path=user_dict_path)
272423
update_dict(
273424
default_dict_path=default_dict_path,
274425
user_dict_path=user_dict_path,
275426
compiled_dict_path=compiled_dict_path,
276427
)
277428

278429

279-
def search_cost_candidates(context_id: int) -> List[int]:
430+
def _search_cost_candidates(context_id: int) -> List[int]:
280431
for value in part_of_speech_data.values():
281432
if value.context_id == context_id:
282433
return value.cost_candidates
283434
raise HTTPException(status_code=422, detail="品詞IDが不正です")
284435

285436

286-
def cost2priority(context_id: int, cost: conint(ge=-32768, le=32767)) -> int:
287-
cost_candidates = search_cost_candidates(context_id)
437+
def _cost2priority(context_id: int, cost: conint(ge=-32768, le=32767)) -> int:
438+
cost_candidates = _search_cost_candidates(context_id)
288439
# cost_candidatesの中にある値で最も近い値を元にpriorityを返す
289440
# 参考: https://qiita.com/Krypf/items/2eada91c37161d17621d
290441
# この関数とpriority2cost関数によって、辞書ファイルのcostを操作しても最も近いpriorityのcostに上書きされる
291442
return MAX_PRIORITY - np.argmin(np.abs(np.array(cost_candidates) - cost))
292443

293444

294-
def priority2cost(
445+
def _priority2cost(
295446
context_id: int, priority: conint(ge=MIN_PRIORITY, le=MAX_PRIORITY)
296447
) -> int:
297-
cost_candidates = search_cost_candidates(context_id)
448+
cost_candidates = _search_cost_candidates(context_id)
298449
return cost_candidates[MAX_PRIORITY - priority]

0 commit comments

Comments
 (0)