diff --git a/openapi.json b/openapi.json index 84d321c315..f8b0cbbfad 100644 --- a/openapi.json +++ b/openapi.json @@ -1 +1 @@ -{"openapi":"3.0.2","info":{"title":"VOICEVOX Engine","description":"VOICEVOXの音声合成エンジンです。","version":"0.14.0-preview.12"},"paths":{"/audio_query":{"post":{"tags":["クエリ作成"],"summary":"音声合成用のクエリを作成する","description":"クエリの初期値を得ます。ここで得られたクエリはそのまま音声合成に利用できます。各値の意味は`Schemas`を参照してください。","operationId":"audio_query_audio_query_post","parameters":[{"required":true,"schema":{"title":"Text","type":"string"},"name":"text","in":"query"},{"required":true,"schema":{"title":"Speaker","type":"integer"},"name":"speaker","in":"query"},{"required":false,"schema":{"title":"Core Version","type":"string"},"name":"core_version","in":"query"}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/AudioQuery"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/audio_query_from_preset":{"post":{"tags":["クエリ作成"],"summary":"音声合成用のクエリをプリセットを用いて作成する","description":"クエリの初期値を得ます。ここで得られたクエリはそのまま音声合成に利用できます。各値の意味は`Schemas`を参照してください。","operationId":"audio_query_from_preset_audio_query_from_preset_post","parameters":[{"required":true,"schema":{"title":"Text","type":"string"},"name":"text","in":"query"},{"required":true,"schema":{"title":"Preset Id","type":"integer"},"name":"preset_id","in":"query"},{"required":false,"schema":{"title":"Core Version","type":"string"},"name":"core_version","in":"query"}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/AudioQuery"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/accent_phrases":{"post":{"tags":["クエリ編集"],"summary":"テキストからアクセント句を得る","description":"テキストからアクセント句を得ます。\nis_kanaが`true`のとき、テキストは次のようなAquesTalkライクな記法に従う読み仮名として処理されます。デフォルトは`false`です。\n* 全てのカナはカタカナで記述される\n* アクセント句は`/`または`、`で区切る。`、`で区切った場合に限り無音区間が挿入される。\n* カナの手前に`_`を入れるとそのカナは無声化される\n* アクセント位置を`'`で指定する。全てのアクセント句にはアクセント位置を1つ指定する必要がある。\n* アクセント句末に`?`(全角)を入れることにより疑問文の発音ができる。","operationId":"accent_phrases_accent_phrases_post","parameters":[{"required":true,"schema":{"title":"Text","type":"string"},"name":"text","in":"query"},{"required":true,"schema":{"title":"Speaker","type":"integer"},"name":"speaker","in":"query"},{"required":false,"schema":{"title":"Is Kana","type":"boolean","default":false},"name":"is_kana","in":"query"},{"required":false,"schema":{"title":"Core Version","type":"string"},"name":"core_version","in":"query"}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"title":"Response Accent Phrases Accent Phrases Post","type":"array","items":{"$ref":"#/components/schemas/AccentPhrase"}}}}},"400":{"description":"読み仮名のパースに失敗","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ParseKanaBadRequest"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/mora_data":{"post":{"tags":["クエリ編集"],"summary":"アクセント句から音高・音素長を得る","operationId":"mora_data_mora_data_post","parameters":[{"required":true,"schema":{"title":"Speaker","type":"integer"},"name":"speaker","in":"query"},{"required":false,"schema":{"title":"Core Version","type":"string"},"name":"core_version","in":"query"}],"requestBody":{"content":{"application/json":{"schema":{"title":"Accent Phrases","type":"array","items":{"$ref":"#/components/schemas/AccentPhrase"}}}},"required":true},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"title":"Response Mora Data Mora Data Post","type":"array","items":{"$ref":"#/components/schemas/AccentPhrase"}}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/mora_length":{"post":{"tags":["クエリ編集"],"summary":"アクセント句から音素長を得る","operationId":"mora_length_mora_length_post","parameters":[{"required":true,"schema":{"title":"Speaker","type":"integer"},"name":"speaker","in":"query"},{"required":false,"schema":{"title":"Core Version","type":"string"},"name":"core_version","in":"query"}],"requestBody":{"content":{"application/json":{"schema":{"title":"Accent Phrases","type":"array","items":{"$ref":"#/components/schemas/AccentPhrase"}}}},"required":true},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"title":"Response Mora Length Mora Length Post","type":"array","items":{"$ref":"#/components/schemas/AccentPhrase"}}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/mora_pitch":{"post":{"tags":["クエリ編集"],"summary":"アクセント句から音高を得る","operationId":"mora_pitch_mora_pitch_post","parameters":[{"required":true,"schema":{"title":"Speaker","type":"integer"},"name":"speaker","in":"query"},{"required":false,"schema":{"title":"Core Version","type":"string"},"name":"core_version","in":"query"}],"requestBody":{"content":{"application/json":{"schema":{"title":"Accent Phrases","type":"array","items":{"$ref":"#/components/schemas/AccentPhrase"}}}},"required":true},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"title":"Response Mora Pitch Mora Pitch Post","type":"array","items":{"$ref":"#/components/schemas/AccentPhrase"}}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/synthesis":{"post":{"tags":["音声合成"],"summary":"音声合成する","operationId":"synthesis_synthesis_post","parameters":[{"required":true,"schema":{"title":"Speaker","type":"integer"},"name":"speaker","in":"query"},{"description":"疑問系のテキストが与えられたら語尾を自動調整する","required":false,"schema":{"title":"Enable Interrogative Upspeak","type":"boolean","description":"疑問系のテキストが与えられたら語尾を自動調整する","default":true},"name":"enable_interrogative_upspeak","in":"query"},{"required":false,"schema":{"title":"Core Version","type":"string"},"name":"core_version","in":"query"}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/AudioQuery"}}},"required":true},"responses":{"200":{"description":"Successful Response","content":{"audio/wav":{"schema":{"type":"string","format":"binary"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/cancellable_synthesis":{"post":{"tags":["音声合成"],"summary":"音声合成する(キャンセル可能)","operationId":"cancellable_synthesis_cancellable_synthesis_post","parameters":[{"required":true,"schema":{"title":"Speaker","type":"integer"},"name":"speaker","in":"query"},{"required":false,"schema":{"title":"Core Version","type":"string"},"name":"core_version","in":"query"}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/AudioQuery"}}},"required":true},"responses":{"200":{"description":"Successful Response","content":{"audio/wav":{"schema":{"type":"string","format":"binary"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/multi_synthesis":{"post":{"tags":["音声合成"],"summary":"複数まとめて音声合成する","operationId":"multi_synthesis_multi_synthesis_post","parameters":[{"required":true,"schema":{"title":"Speaker","type":"integer"},"name":"speaker","in":"query"},{"required":false,"schema":{"title":"Core Version","type":"string"},"name":"core_version","in":"query"}],"requestBody":{"content":{"application/json":{"schema":{"title":"Queries","type":"array","items":{"$ref":"#/components/schemas/AudioQuery"}}}},"required":true},"responses":{"200":{"description":"Successful Response","content":{"application/zip":{"schema":{"type":"string","format":"binary"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/morphable_targets":{"post":{"tags":["音声合成"],"summary":"指定した話者に対してエンジン内の話者がモーフィングが可能か判定する","description":"指定されたベース話者に対してエンジン内の各話者がモーフィング機能を利用可能か返します。\nモーフィングの許可/禁止は`/speakers`の`speaker.supported_features.synthesis_morphing`に記載されています。\nプロパティが存在しない場合は、モーフィングが許可されているとみなします。\n返り値の話者はstring型なので注意。","operationId":"morphable_targets_morphable_targets_post","parameters":[{"required":false,"schema":{"title":"Core Version","type":"string"},"name":"core_version","in":"query"}],"requestBody":{"content":{"application/json":{"schema":{"title":"Base Speakers","type":"array","items":{"type":"integer"}}}},"required":true},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"title":"Response Morphable Targets Morphable Targets Post","type":"array","items":{"type":"object","additionalProperties":{"$ref":"#/components/schemas/MorphableTargetInfo"}}}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/synthesis_morphing":{"post":{"tags":["音声合成"],"summary":"2人の話者でモーフィングした音声を合成する","description":"指定された2人の話者で音声を合成、指定した割合でモーフィングした音声を得ます。\nモーフィングの割合は`morph_rate`で指定でき、0.0でベースの話者、1.0でターゲットの話者に近づきます。","operationId":"_synthesis_morphing_synthesis_morphing_post","parameters":[{"required":true,"schema":{"title":"Base Speaker","type":"integer"},"name":"base_speaker","in":"query"},{"required":true,"schema":{"title":"Target Speaker","type":"integer"},"name":"target_speaker","in":"query"},{"required":true,"schema":{"title":"Morph Rate","maximum":1.0,"minimum":0.0,"type":"number"},"name":"morph_rate","in":"query"},{"required":false,"schema":{"title":"Core Version","type":"string"},"name":"core_version","in":"query"}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/AudioQuery"}}},"required":true},"responses":{"200":{"description":"Successful Response","content":{"audio/wav":{"schema":{"type":"string","format":"binary"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/connect_waves":{"post":{"tags":["その他"],"summary":"base64エンコードされた複数のwavデータを一つに結合する","description":"base64エンコードされたwavデータを一纏めにし、wavファイルで返します。","operationId":"connect_waves_connect_waves_post","requestBody":{"content":{"application/json":{"schema":{"title":"Waves","type":"array","items":{"type":"string"}}}},"required":true},"responses":{"200":{"description":"Successful Response","content":{"audio/wav":{"schema":{"type":"string","format":"binary"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/presets":{"get":{"tags":["その他"],"summary":"Get Presets","description":"エンジンが保持しているプリセットの設定を返します\n\nReturns\n-------\npresets: List[Preset]\n プリセットのリスト","operationId":"get_presets_presets_get","responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"title":"Response Get Presets Presets Get","type":"array","items":{"$ref":"#/components/schemas/Preset"}}}}}}}},"/add_preset":{"post":{"tags":["その他"],"summary":"Add Preset","description":"新しいプリセットを追加します\n\nParameters\n-------\npreset: Preset\n 新しいプリセット。\n プリセットIDが既存のものと重複している場合は、新規のプリセットIDが採番されます。\n\nReturns\n-------\nid: int\n 追加したプリセットのプリセットID","operationId":"add_preset_add_preset_post","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Preset"}}},"required":true},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"title":"Response Add Preset Add Preset Post","type":"integer"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/update_preset":{"post":{"tags":["その他"],"summary":"Update Preset","description":"既存のプリセットを更新します\n\nParameters\n-------\npreset: Preset\n 更新するプリセット。\n プリセットIDが更新対象と一致している必要があります。\n\nReturns\n-------\nid: int\n 更新したプリセットのプリセットID","operationId":"update_preset_update_preset_post","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Preset"}}},"required":true},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"title":"Response Update Preset Update Preset Post","type":"integer"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/delete_preset":{"post":{"tags":["その他"],"summary":"Delete Preset","description":"既存のプリセットを削除します\n\nParameters\n-------\nid: int\n 削除するプリセットのプリセットID","operationId":"delete_preset_delete_preset_post","parameters":[{"required":true,"schema":{"title":"Id","type":"integer"},"name":"id","in":"query"}],"responses":{"204":{"description":"Successful Response"},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/version":{"get":{"tags":["その他"],"summary":"Version","operationId":"version_version_get","responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}}}}},"/core_versions":{"get":{"tags":["その他"],"summary":"Core Versions","operationId":"core_versions_core_versions_get","responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"title":"Response Core Versions Core Versions Get","type":"array","items":{"type":"string"}}}}}}}},"/speakers":{"get":{"tags":["その他"],"summary":"Speakers","operationId":"speakers_speakers_get","parameters":[{"required":false,"schema":{"title":"Core Version","type":"string"},"name":"core_version","in":"query"}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"title":"Response Speakers Speakers Get","type":"array","items":{"$ref":"#/components/schemas/Speaker"}}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/speaker_info":{"get":{"tags":["その他"],"summary":"Speaker Info","description":"指定されたspeaker_uuidに関する情報をjson形式で返します。\n画像や音声はbase64エンコードされたものが返されます。\n\nReturns\n-------\nret_data: SpeakerInfo","operationId":"speaker_info_speaker_info_get","parameters":[{"required":true,"schema":{"title":"Speaker Uuid","type":"string"},"name":"speaker_uuid","in":"query"},{"required":false,"schema":{"title":"Core Version","type":"string"},"name":"core_version","in":"query"}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/SpeakerInfo"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/downloadable_libraries":{"get":{"tags":["その他"],"summary":"Downloadable Libraries","description":"ダウンロード可能なモデル情報を返します。\n\nReturns\n-------\nret_data: List[DownloadableLibrary]","operationId":"downloadable_libraries_downloadable_libraries_get","responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"title":"Response Downloadable Libraries Downloadable Libraries Get","type":"array","items":{"$ref":"#/components/schemas/DownloadableLibrary"}}}}}}}},"/initialize_speaker":{"post":{"tags":["その他"],"summary":"Initialize Speaker","description":"指定されたspeaker_idの話者を初期化します。\n実行しなくても他のAPIは使用できますが、初回実行時に時間がかかることがあります。","operationId":"initialize_speaker_initialize_speaker_post","parameters":[{"required":true,"schema":{"title":"Speaker","type":"integer"},"name":"speaker","in":"query"},{"description":"既に初期化済みの話者の再初期化をスキップするかどうか","required":false,"schema":{"title":"Skip Reinit","type":"boolean","description":"既に初期化済みの話者の再初期化をスキップするかどうか","default":false},"name":"skip_reinit","in":"query"},{"required":false,"schema":{"title":"Core Version","type":"string"},"name":"core_version","in":"query"}],"responses":{"204":{"description":"Successful Response"},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/is_initialized_speaker":{"get":{"tags":["その他"],"summary":"Is Initialized Speaker","description":"指定されたspeaker_idの話者が初期化されているかどうかを返します。","operationId":"is_initialized_speaker_is_initialized_speaker_get","parameters":[{"required":true,"schema":{"title":"Speaker","type":"integer"},"name":"speaker","in":"query"},{"required":false,"schema":{"title":"Core Version","type":"string"},"name":"core_version","in":"query"}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"title":"Response Is Initialized Speaker Is Initialized Speaker Get","type":"boolean"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/user_dict":{"get":{"tags":["ユーザー辞書"],"summary":"Get User Dict Words","description":"ユーザー辞書に登録されている単語の一覧を返します。\n単語の表層形(surface)は正規化済みの物を返します。\n\nReturns\n-------\nDict[str, UserDictWord]\n 単語のUUIDとその詳細","operationId":"get_user_dict_words_user_dict_get","responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"title":"Response Get User Dict Words User Dict Get","type":"object","additionalProperties":{"$ref":"#/components/schemas/UserDictWord"}}}}}}}},"/user_dict_word":{"post":{"tags":["ユーザー辞書"],"summary":"Add User Dict Word","description":"ユーザー辞書に言葉を追加します。\n\nParameters\n----------\nsurface : str\n 言葉の表層形\npronunciation: str\n 言葉の発音(カタカナ)\naccent_type: int\n アクセント型(音が下がる場所を指す)\nword_type: WordTypes, optional\n PROPER_NOUN(固有名詞)、COMMON_NOUN(普通名詞)、VERB(動詞)、ADJECTIVE(形容詞)、SUFFIX(語尾)のいずれか\npriority: int, optional\n 単語の優先度(0から10までの整数)\n 数字が大きいほど優先度が高くなる\n 1から9までの値を指定することを推奨","operationId":"add_user_dict_word_user_dict_word_post","parameters":[{"required":true,"schema":{"title":"Surface","type":"string"},"name":"surface","in":"query"},{"required":true,"schema":{"title":"Pronunciation","type":"string"},"name":"pronunciation","in":"query"},{"required":true,"schema":{"title":"Accent Type","type":"integer"},"name":"accent_type","in":"query"},{"required":false,"schema":{"$ref":"#/components/schemas/WordTypes"},"name":"word_type","in":"query"},{"required":false,"schema":{"title":"Priority","maximum":10.0,"minimum":0.0,"type":"integer"},"name":"priority","in":"query"}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"title":"Response Add User Dict Word User Dict Word Post","type":"string"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/user_dict_word/{word_uuid}":{"put":{"tags":["ユーザー辞書"],"summary":"Rewrite User Dict Word","description":"ユーザー辞書に登録されている言葉を更新します。\n\nParameters\n----------\nsurface : str\n 言葉の表層形\npronunciation: str\n 言葉の発音(カタカナ)\naccent_type: int\n アクセント型(音が下がる場所を指す)\nword_uuid: str\n 更新する言葉のUUID\nword_type: WordTypes, optional\n PROPER_NOUN(固有名詞)、COMMON_NOUN(普通名詞)、VERB(動詞)、ADJECTIVE(形容詞)、SUFFIX(語尾)のいずれか\npriority: int, optional\n 単語の優先度(0から10までの整数)\n 数字が大きいほど優先度が高くなる\n 1から9までの値を指定することを推奨","operationId":"rewrite_user_dict_word_user_dict_word__word_uuid__put","parameters":[{"required":true,"schema":{"title":"Word Uuid","type":"string"},"name":"word_uuid","in":"path"},{"required":true,"schema":{"title":"Surface","type":"string"},"name":"surface","in":"query"},{"required":true,"schema":{"title":"Pronunciation","type":"string"},"name":"pronunciation","in":"query"},{"required":true,"schema":{"title":"Accent Type","type":"integer"},"name":"accent_type","in":"query"},{"required":false,"schema":{"$ref":"#/components/schemas/WordTypes"},"name":"word_type","in":"query"},{"required":false,"schema":{"title":"Priority","maximum":10.0,"minimum":0.0,"type":"integer"},"name":"priority","in":"query"}],"responses":{"204":{"description":"Successful Response"},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}},"delete":{"tags":["ユーザー辞書"],"summary":"Delete User Dict Word","description":"ユーザー辞書に登録されている言葉を削除します。\n\nParameters\n----------\nword_uuid: str\n 削除する言葉のUUID","operationId":"delete_user_dict_word_user_dict_word__word_uuid__delete","parameters":[{"required":true,"schema":{"title":"Word Uuid","type":"string"},"name":"word_uuid","in":"path"}],"responses":{"204":{"description":"Successful Response"},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/import_user_dict":{"post":{"tags":["ユーザー辞書"],"summary":"Import User Dict Words","description":"他のユーザー辞書をインポートします。\n\nParameters\n----------\nimport_dict_data: Dict[str, UserDictWord]\n インポートするユーザー辞書のデータ\noverride: bool\n 重複したエントリがあった場合、上書きするかどうか","operationId":"import_user_dict_words_import_user_dict_post","parameters":[{"required":true,"schema":{"title":"Override","type":"boolean"},"name":"override","in":"query"}],"requestBody":{"content":{"application/json":{"schema":{"title":"Import Dict Data","type":"object","additionalProperties":{"$ref":"#/components/schemas/UserDictWord"}}}},"required":true},"responses":{"204":{"description":"Successful Response"},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/supported_devices":{"get":{"tags":["その他"],"summary":"Supported Devices","operationId":"supported_devices_supported_devices_get","parameters":[{"required":false,"schema":{"title":"Core Version","type":"string"},"name":"core_version","in":"query"}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/SupportedDevicesInfo"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/engine_manifest":{"get":{"tags":["その他"],"summary":"Engine Manifest","operationId":"engine_manifest_engine_manifest_get","responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/EngineManifest"}}}}}}},"/setting":{"get":{"tags":["設定"],"summary":"Setting Get","operationId":"setting_get_setting_get","responses":{"200":{"description":"Successful Response","content":{"text/html":{"schema":{"type":"string"}}}}}},"post":{"tags":["設定"],"summary":"Setting Post","operationId":"setting_post_setting_post","requestBody":{"content":{"application/x-www-form-urlencoded":{"schema":{"$ref":"#/components/schemas/Body_setting_post_setting_post"}}}},"responses":{"200":{"description":"Successful Response","content":{"text/html":{"schema":{"type":"string"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}}},"components":{"schemas":{"AccentPhrase":{"title":"AccentPhrase","required":["moras","accent"],"type":"object","properties":{"moras":{"title":"モーラのリスト","type":"array","items":{"$ref":"#/components/schemas/Mora"}},"accent":{"title":"アクセント箇所","type":"integer"},"pause_mora":{"title":"後ろに無音を付けるかどうか","allOf":[{"$ref":"#/components/schemas/Mora"}]},"is_interrogative":{"title":"疑問系かどうか","type":"boolean","default":false}},"description":"アクセント句ごとの情報"},"AudioQuery":{"title":"AudioQuery","required":["accent_phrases","speedScale","pitchScale","intonationScale","volumeScale","prePhonemeLength","postPhonemeLength","outputSamplingRate","outputStereo"],"type":"object","properties":{"accent_phrases":{"title":"アクセント句のリスト","type":"array","items":{"$ref":"#/components/schemas/AccentPhrase"}},"speedScale":{"title":"全体の話速","type":"number"},"pitchScale":{"title":"全体の音高","type":"number"},"intonationScale":{"title":"全体の抑揚","type":"number"},"volumeScale":{"title":"全体の音量","type":"number"},"prePhonemeLength":{"title":"音声の前の無音時間","type":"number"},"postPhonemeLength":{"title":"音声の後の無音時間","type":"number"},"outputSamplingRate":{"title":"音声データの出力サンプリングレート","type":"integer"},"outputStereo":{"title":"音声データをステレオ出力するか否か","type":"boolean"},"kana":{"title":"[読み取り専用]AquesTalkライクな読み仮名。音声合成クエリとしては無視される","type":"string"}},"description":"音声合成用のクエリ"},"Body_setting_post_setting_post":{"title":"Body_setting_post_setting_post","type":"object","properties":{"cors_policy_mode":{"title":"Cors Policy Mode","type":"string"},"allow_origin":{"title":"Allow Origin","type":"string"}}},"DownloadableLibrary":{"title":"DownloadableLibrary","required":["download_url","bytes","speaker","speaker_info"],"type":"object","properties":{"download_url":{"title":"音声ライブラリのダウンロードURL","type":"string"},"bytes":{"title":"音声ライブラリのバイト数","type":"integer"},"speaker":{"title":"話者情報","allOf":[{"$ref":"#/components/schemas/Speaker"}]},"speaker_info":{"title":"話者の追加情報","allOf":[{"$ref":"#/components/schemas/SpeakerInfo"}]}},"description":"ダウンロード可能な音声ライブラリの情報(最新情報をwebで取得することを考慮して、ローカルの情報はない)"},"EngineManifest":{"title":"EngineManifest","required":["manifest_version","name","brand_name","uuid","url","icon","default_sampling_rate","terms_of_service","update_infos","dependency_licenses","supported_features"],"type":"object","properties":{"manifest_version":{"title":"マニフェストのバージョン","type":"string"},"name":{"title":"エンジン名","type":"string"},"brand_name":{"title":"ブランド名","type":"string"},"uuid":{"title":"エンジンのUUID","type":"string"},"url":{"title":"エンジンのURL","type":"string"},"icon":{"title":"エンジンのアイコンをBASE64エンコードしたもの","type":"string"},"default_sampling_rate":{"title":"デフォルトのサンプリング周波数","type":"integer"},"terms_of_service":{"title":"エンジンの利用規約","type":"string"},"update_infos":{"title":"エンジンのアップデート情報","type":"array","items":{"$ref":"#/components/schemas/UpdateInfo"}},"dependency_licenses":{"title":"依存関係のライセンス情報","type":"array","items":{"$ref":"#/components/schemas/LicenseInfo"}},"downloadable_libraries_path":{"title":"ダウンロード可能な音声ライブラリ情報を取得するためのローカルjsonパス","type":"string"},"downloadable_libraries_url":{"title":"ダウンロード可能な音声ライブラリ情報を取得するためのAPIのURL","type":"string"},"supported_features":{"title":"エンジンが持つ機能","allOf":[{"$ref":"#/components/schemas/SupportedFeatures"}]}},"description":"エンジン自体に関する情報"},"HTTPValidationError":{"title":"HTTPValidationError","type":"object","properties":{"detail":{"title":"Detail","type":"array","items":{"$ref":"#/components/schemas/ValidationError"}}}},"LicenseInfo":{"title":"LicenseInfo","required":["name","text"],"type":"object","properties":{"name":{"title":"依存ライブラリ名","type":"string"},"version":{"title":"依存ライブラリのバージョン","type":"string"},"license":{"title":"依存ライブラリのライセンス名","type":"string"},"text":{"title":"依存ライブラリのライセンス本文","type":"string"}},"description":"依存ライブラリのライセンス情報"},"Mora":{"title":"Mora","required":["text","vowel","vowel_length","pitch"],"type":"object","properties":{"text":{"title":"文字","type":"string"},"consonant":{"title":"子音の音素","type":"string"},"consonant_length":{"title":"子音の音長","type":"number"},"vowel":{"title":"母音の音素","type":"string"},"vowel_length":{"title":"母音の音長","type":"number"},"pitch":{"title":"音高","type":"number"}},"description":"モーラ(子音+母音)ごとの情報"},"MorphableTargetInfo":{"title":"MorphableTargetInfo","required":["is_morphable"],"type":"object","properties":{"is_morphable":{"title":"指定した話者に対してモーフィングの可否","type":"boolean"}}},"ParseKanaBadRequest":{"title":"ParseKanaBadRequest","required":["text","error_name","error_args"],"type":"object","properties":{"text":{"title":"エラーメッセージ","type":"string"},"error_name":{"title":"エラー名","type":"string","description":"|name|description|\n|---|---|\n| UNKNOWN_TEXT | 判別できない読み仮名があります: {text} |\n| ACCENT_TOP | 句頭にアクセントは置けません: {text} |\n| ACCENT_TWICE | 1つのアクセント句に二つ以上のアクセントは置けません: {text} |\n| ACCENT_NOTFOUND | アクセントを指定していないアクセント句があります: {text} |\n| EMPTY_PHRASE | {position}番目のアクセント句が空白です |\n| INTERROGATION_MARK_NOT_AT_END | アクセント句末以外に「?」は置けません: {text} |\n| INFINITE_LOOP | 処理時に無限ループになってしまいました...バグ報告をお願いします。 |"},"error_args":{"title":"エラーを起こした箇所","type":"object","additionalProperties":{"type":"string"}}}},"Preset":{"title":"Preset","required":["id","name","speaker_uuid","style_id","speedScale","pitchScale","intonationScale","volumeScale","prePhonemeLength","postPhonemeLength"],"type":"object","properties":{"id":{"title":"プリセットID","type":"integer"},"name":{"title":"プリセット名","type":"string"},"speaker_uuid":{"title":"スピーカーのUUID","type":"string"},"style_id":{"title":"スタイルID","type":"integer"},"speedScale":{"title":"全体の話速","type":"number"},"pitchScale":{"title":"全体の音高","type":"number"},"intonationScale":{"title":"全体の抑揚","type":"number"},"volumeScale":{"title":"全体の音量","type":"number"},"prePhonemeLength":{"title":"音声の前の無音時間","type":"number"},"postPhonemeLength":{"title":"音声の後の無音時間","type":"number"}},"description":"プリセット情報"},"Speaker":{"title":"Speaker","required":["name","speaker_uuid","styles"],"type":"object","properties":{"supported_features":{"title":"スピーカーの対応機能","allOf":[{"$ref":"#/components/schemas/SpeakerSupportedFeatures"}]},"name":{"title":"名前","type":"string"},"speaker_uuid":{"title":"スピーカーのUUID","type":"string"},"styles":{"title":"スピーカースタイルの一覧","type":"array","items":{"$ref":"#/components/schemas/SpeakerStyle"}},"version":{"title":"Version","type":"string","default":"スピーカーのバージョン"}},"description":"スピーカー情報"},"SpeakerInfo":{"title":"SpeakerInfo","required":["policy","portrait","style_infos"],"type":"object","properties":{"policy":{"title":"policy.md","type":"string"},"portrait":{"title":"portrait.pngをbase64エンコードしたもの","type":"string"},"style_infos":{"title":"スタイルの追加情報","type":"array","items":{"$ref":"#/components/schemas/StyleInfo"}}},"description":"話者の追加情報"},"SpeakerStyle":{"title":"SpeakerStyle","required":["name","id"],"type":"object","properties":{"name":{"title":"スタイル名","type":"string"},"id":{"title":"スタイルID","type":"integer"}},"description":"スピーカーのスタイル情報"},"SpeakerSupportPermittedSynthesisMorphing":{"title":"SpeakerSupportPermittedSynthesisMorphing","enum":["ALL","SELF_ONLY","NOTHING"],"type":"string","description":"An enumeration."},"SpeakerSupportedFeatures":{"title":"SpeakerSupportedFeatures","type":"object","properties":{"permitted_synthesis_morphing":{"title":"モーフィング機能への対応","allOf":[{"$ref":"#/components/schemas/SpeakerSupportPermittedSynthesisMorphing"}],"default":"ALL"}},"description":"話者の対応機能の情報"},"StyleInfo":{"title":"StyleInfo","required":["id","icon","voice_samples"],"type":"object","properties":{"id":{"title":"スタイルID","type":"integer"},"icon":{"title":"当該スタイルのアイコンをbase64エンコードしたもの","type":"string"},"portrait":{"title":"当該スタイルのportrait.pngをbase64エンコードしたもの","type":"string"},"voice_samples":{"title":"voice_sampleのwavファイルをbase64エンコードしたもの","type":"array","items":{"type":"string"}}},"description":"スタイルの追加情報"},"SupportedDevicesInfo":{"title":"SupportedDevicesInfo","required":["cpu","cuda","dml"],"type":"object","properties":{"cpu":{"title":"CPUに対応しているか","type":"boolean"},"cuda":{"title":"CUDA(Nvidia GPU)に対応しているか","type":"boolean"},"dml":{"title":"DirectML(Nvidia GPU/Radeon GPU等)に対応しているか","type":"boolean"}},"description":"対応しているデバイスの情報"},"SupportedFeatures":{"title":"SupportedFeatures","required":["adjust_mora_pitch","adjust_phoneme_length","adjust_speed_scale","adjust_pitch_scale","adjust_intonation_scale","adjust_volume_scale","interrogative_upspeak","synthesis_morphing"],"type":"object","properties":{"adjust_mora_pitch":{"title":"モーラごとの音高の調整","type":"boolean"},"adjust_phoneme_length":{"title":"音素ごとの長さの調整","type":"boolean"},"adjust_speed_scale":{"title":"全体の話速の調整","type":"boolean"},"adjust_pitch_scale":{"title":"全体の音高の調整","type":"boolean"},"adjust_intonation_scale":{"title":"全体の抑揚の調整","type":"boolean"},"adjust_volume_scale":{"title":"全体の音量の調整","type":"boolean"},"interrogative_upspeak":{"title":"疑問文の自動調整","type":"boolean"},"synthesis_morphing":{"title":"2人の話者でモーフィングした音声を合成","type":"boolean"}},"description":"エンジンが持つ機能の一覧"},"UpdateInfo":{"title":"UpdateInfo","required":["version","descriptions"],"type":"object","properties":{"version":{"title":"エンジンのバージョン名","type":"string"},"descriptions":{"title":"アップデートの詳細についての説明","type":"array","items":{"type":"string"}},"contributors":{"title":"貢献者名","type":"array","items":{"type":"string"}}},"description":"エンジンのアップデート情報"},"UserDictWord":{"title":"UserDictWord","required":["surface","priority","part_of_speech","part_of_speech_detail_1","part_of_speech_detail_2","part_of_speech_detail_3","inflectional_type","inflectional_form","stem","yomi","pronunciation","accent_type","accent_associative_rule"],"type":"object","properties":{"surface":{"title":"表層形","type":"string"},"priority":{"title":"優先度","maximum":10.0,"minimum":0.0,"type":"integer"},"context_id":{"title":"文脈ID","type":"integer","default":1348},"part_of_speech":{"title":"品詞","type":"string"},"part_of_speech_detail_1":{"title":"品詞細分類1","type":"string"},"part_of_speech_detail_2":{"title":"品詞細分類2","type":"string"},"part_of_speech_detail_3":{"title":"品詞細分類3","type":"string"},"inflectional_type":{"title":"活用型","type":"string"},"inflectional_form":{"title":"活用形","type":"string"},"stem":{"title":"原形","type":"string"},"yomi":{"title":"読み","type":"string"},"pronunciation":{"title":"発音","type":"string"},"accent_type":{"title":"アクセント型","type":"integer"},"mora_count":{"title":"モーラ数","type":"integer"},"accent_associative_rule":{"title":"アクセント結合規則","type":"string"}},"description":"辞書のコンパイルに使われる情報"},"ValidationError":{"title":"ValidationError","required":["loc","msg","type"],"type":"object","properties":{"loc":{"title":"Location","type":"array","items":{"type":"string"}},"msg":{"title":"Message","type":"string"},"type":{"title":"Error Type","type":"string"}}},"WordTypes":{"title":"WordTypes","enum":["PROPER_NOUN","COMMON_NOUN","VERB","ADJECTIVE","SUFFIX"],"type":"string","description":"\n fastapiでword_type引数を検証する時に使用するクラス\n "}}}} \ No newline at end of file +{"openapi":"3.0.2","info":{"title":"VOICEVOX Engine","description":"VOICEVOXの音声合成エンジンです。","version":"latest"},"paths":{"/audio_query":{"post":{"tags":["クエリ作成"],"summary":"音声合成用のクエリを作成する","description":"クエリの初期値を得ます。ここで得られたクエリはそのまま音声合成に利用できます。各値の意味は`Schemas`を参照してください。","operationId":"audio_query_audio_query_post","parameters":[{"required":true,"schema":{"title":"Text","type":"string"},"name":"text","in":"query"},{"required":true,"schema":{"title":"Speaker","type":"integer"},"name":"speaker","in":"query"},{"required":false,"schema":{"title":"Core Version","type":"string"},"name":"core_version","in":"query"}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/AudioQuery"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/audio_query_from_preset":{"post":{"tags":["クエリ作成"],"summary":"音声合成用のクエリをプリセットを用いて作成する","description":"クエリの初期値を得ます。ここで得られたクエリはそのまま音声合成に利用できます。各値の意味は`Schemas`を参照してください。","operationId":"audio_query_from_preset_audio_query_from_preset_post","parameters":[{"required":true,"schema":{"title":"Text","type":"string"},"name":"text","in":"query"},{"required":true,"schema":{"title":"Preset Id","type":"integer"},"name":"preset_id","in":"query"},{"required":false,"schema":{"title":"Core Version","type":"string"},"name":"core_version","in":"query"}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/AudioQuery"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/accent_phrases":{"post":{"tags":["クエリ編集"],"summary":"テキストからアクセント句を得る","description":"テキストからアクセント句を得ます。\nis_kanaが`true`のとき、テキストは次のようなAquesTalkライクな記法に従う読み仮名として処理されます。デフォルトは`false`です。\n* 全てのカナはカタカナで記述される\n* アクセント句は`/`または`、`で区切る。`、`で区切った場合に限り無音区間が挿入される。\n* カナの手前に`_`を入れるとそのカナは無声化される\n* アクセント位置を`'`で指定する。全てのアクセント句にはアクセント位置を1つ指定する必要がある。\n* アクセント句末に`?`(全角)を入れることにより疑問文の発音ができる。","operationId":"accent_phrases_accent_phrases_post","parameters":[{"required":true,"schema":{"title":"Text","type":"string"},"name":"text","in":"query"},{"required":true,"schema":{"title":"Speaker","type":"integer"},"name":"speaker","in":"query"},{"required":false,"schema":{"title":"Is Kana","type":"boolean","default":false},"name":"is_kana","in":"query"},{"required":false,"schema":{"title":"Core Version","type":"string"},"name":"core_version","in":"query"}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"title":"Response Accent Phrases Accent Phrases Post","type":"array","items":{"$ref":"#/components/schemas/AccentPhrase"}}}}},"400":{"description":"読み仮名のパースに失敗","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ParseKanaBadRequest"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/mora_data":{"post":{"tags":["クエリ編集"],"summary":"アクセント句から音高・音素長を得る","operationId":"mora_data_mora_data_post","parameters":[{"required":true,"schema":{"title":"Speaker","type":"integer"},"name":"speaker","in":"query"},{"required":false,"schema":{"title":"Core Version","type":"string"},"name":"core_version","in":"query"}],"requestBody":{"content":{"application/json":{"schema":{"title":"Accent Phrases","type":"array","items":{"$ref":"#/components/schemas/AccentPhrase"}}}},"required":true},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"title":"Response Mora Data Mora Data Post","type":"array","items":{"$ref":"#/components/schemas/AccentPhrase"}}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/mora_length":{"post":{"tags":["クエリ編集"],"summary":"アクセント句から音素長を得る","operationId":"mora_length_mora_length_post","parameters":[{"required":true,"schema":{"title":"Speaker","type":"integer"},"name":"speaker","in":"query"},{"required":false,"schema":{"title":"Core Version","type":"string"},"name":"core_version","in":"query"}],"requestBody":{"content":{"application/json":{"schema":{"title":"Accent Phrases","type":"array","items":{"$ref":"#/components/schemas/AccentPhrase"}}}},"required":true},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"title":"Response Mora Length Mora Length Post","type":"array","items":{"$ref":"#/components/schemas/AccentPhrase"}}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/mora_pitch":{"post":{"tags":["クエリ編集"],"summary":"アクセント句から音高を得る","operationId":"mora_pitch_mora_pitch_post","parameters":[{"required":true,"schema":{"title":"Speaker","type":"integer"},"name":"speaker","in":"query"},{"required":false,"schema":{"title":"Core Version","type":"string"},"name":"core_version","in":"query"}],"requestBody":{"content":{"application/json":{"schema":{"title":"Accent Phrases","type":"array","items":{"$ref":"#/components/schemas/AccentPhrase"}}}},"required":true},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"title":"Response Mora Pitch Mora Pitch Post","type":"array","items":{"$ref":"#/components/schemas/AccentPhrase"}}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/synthesis":{"post":{"tags":["音声合成"],"summary":"音声合成する","operationId":"synthesis_synthesis_post","parameters":[{"required":true,"schema":{"title":"Speaker","type":"integer"},"name":"speaker","in":"query"},{"description":"疑問系のテキストが与えられたら語尾を自動調整する","required":false,"schema":{"title":"Enable Interrogative Upspeak","type":"boolean","description":"疑問系のテキストが与えられたら語尾を自動調整する","default":true},"name":"enable_interrogative_upspeak","in":"query"},{"required":false,"schema":{"title":"Core Version","type":"string"},"name":"core_version","in":"query"}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/AudioQuery"}}},"required":true},"responses":{"200":{"description":"Successful Response","content":{"audio/wav":{"schema":{"type":"string","format":"binary"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/cancellable_synthesis":{"post":{"tags":["音声合成"],"summary":"音声合成する(キャンセル可能)","operationId":"cancellable_synthesis_cancellable_synthesis_post","parameters":[{"required":true,"schema":{"title":"Speaker","type":"integer"},"name":"speaker","in":"query"},{"required":false,"schema":{"title":"Core Version","type":"string"},"name":"core_version","in":"query"}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/AudioQuery"}}},"required":true},"responses":{"200":{"description":"Successful Response","content":{"audio/wav":{"schema":{"type":"string","format":"binary"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/multi_synthesis":{"post":{"tags":["音声合成"],"summary":"複数まとめて音声合成する","operationId":"multi_synthesis_multi_synthesis_post","parameters":[{"required":true,"schema":{"title":"Speaker","type":"integer"},"name":"speaker","in":"query"},{"required":false,"schema":{"title":"Core Version","type":"string"},"name":"core_version","in":"query"}],"requestBody":{"content":{"application/json":{"schema":{"title":"Queries","type":"array","items":{"$ref":"#/components/schemas/AudioQuery"}}}},"required":true},"responses":{"200":{"description":"Successful Response","content":{"application/zip":{"schema":{"type":"string","format":"binary"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/morphable_targets":{"post":{"tags":["音声合成"],"summary":"指定した話者に対してエンジン内の話者がモーフィングが可能か判定する","description":"指定されたベース話者に対してエンジン内の各話者がモーフィング機能を利用可能か返します。\nモーフィングの許可/禁止は`/speakers`の`speaker.supported_features.synthesis_morphing`に記載されています。\nプロパティが存在しない場合は、モーフィングが許可されているとみなします。\n返り値の話者はstring型なので注意。","operationId":"morphable_targets_morphable_targets_post","parameters":[{"required":false,"schema":{"title":"Core Version","type":"string"},"name":"core_version","in":"query"}],"requestBody":{"content":{"application/json":{"schema":{"title":"Base Speakers","type":"array","items":{"type":"integer"}}}},"required":true},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"title":"Response Morphable Targets Morphable Targets Post","type":"array","items":{"type":"object","additionalProperties":{"$ref":"#/components/schemas/MorphableTargetInfo"}}}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/synthesis_morphing":{"post":{"tags":["音声合成"],"summary":"2人の話者でモーフィングした音声を合成する","description":"指定された2人の話者で音声を合成、指定した割合でモーフィングした音声を得ます。\nモーフィングの割合は`morph_rate`で指定でき、0.0でベースの話者、1.0でターゲットの話者に近づきます。","operationId":"_synthesis_morphing_synthesis_morphing_post","parameters":[{"required":true,"schema":{"title":"Base Speaker","type":"integer"},"name":"base_speaker","in":"query"},{"required":true,"schema":{"title":"Target Speaker","type":"integer"},"name":"target_speaker","in":"query"},{"required":true,"schema":{"title":"Morph Rate","maximum":1.0,"minimum":0.0,"type":"number"},"name":"morph_rate","in":"query"},{"required":false,"schema":{"title":"Core Version","type":"string"},"name":"core_version","in":"query"}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/AudioQuery"}}},"required":true},"responses":{"200":{"description":"Successful Response","content":{"audio/wav":{"schema":{"type":"string","format":"binary"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/connect_waves":{"post":{"tags":["その他"],"summary":"base64エンコードされた複数のwavデータを一つに結合する","description":"base64エンコードされたwavデータを一纏めにし、wavファイルで返します。","operationId":"connect_waves_connect_waves_post","requestBody":{"content":{"application/json":{"schema":{"title":"Waves","type":"array","items":{"type":"string"}}}},"required":true},"responses":{"200":{"description":"Successful Response","content":{"audio/wav":{"schema":{"type":"string","format":"binary"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/presets":{"get":{"tags":["その他"],"summary":"Get Presets","description":"エンジンが保持しているプリセットの設定を返します\n\nReturns\n-------\npresets: List[Preset]\n プリセットのリスト","operationId":"get_presets_presets_get","responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"title":"Response Get Presets Presets Get","type":"array","items":{"$ref":"#/components/schemas/Preset"}}}}}}}},"/add_preset":{"post":{"tags":["その他"],"summary":"Add Preset","description":"新しいプリセットを追加します\n\nParameters\n-------\npreset: Preset\n 新しいプリセット。\n プリセットIDが既存のものと重複している場合は、新規のプリセットIDが採番されます。\n\nReturns\n-------\nid: int\n 追加したプリセットのプリセットID","operationId":"add_preset_add_preset_post","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Preset"}}},"required":true},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"title":"Response Add Preset Add Preset Post","type":"integer"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/update_preset":{"post":{"tags":["その他"],"summary":"Update Preset","description":"既存のプリセットを更新します\n\nParameters\n-------\npreset: Preset\n 更新するプリセット。\n プリセットIDが更新対象と一致している必要があります。\n\nReturns\n-------\nid: int\n 更新したプリセットのプリセットID","operationId":"update_preset_update_preset_post","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Preset"}}},"required":true},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"title":"Response Update Preset Update Preset Post","type":"integer"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/delete_preset":{"post":{"tags":["その他"],"summary":"Delete Preset","description":"既存のプリセットを削除します\n\nParameters\n-------\nid: int\n 削除するプリセットのプリセットID","operationId":"delete_preset_delete_preset_post","parameters":[{"required":true,"schema":{"title":"Id","type":"integer"},"name":"id","in":"query"}],"responses":{"204":{"description":"Successful Response"},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/version":{"get":{"tags":["その他"],"summary":"Version","operationId":"version_version_get","responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"title":"Response Version Version Get","type":"string"}}}}}}},"/core_versions":{"get":{"tags":["その他"],"summary":"Core Versions","operationId":"core_versions_core_versions_get","responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"title":"Response Core Versions Core Versions Get","type":"array","items":{"type":"string"}}}}}}}},"/speakers":{"get":{"tags":["その他"],"summary":"Speakers","operationId":"speakers_speakers_get","parameters":[{"required":false,"schema":{"title":"Core Version","type":"string"},"name":"core_version","in":"query"}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"title":"Response Speakers Speakers Get","type":"array","items":{"$ref":"#/components/schemas/Speaker"}}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/speaker_info":{"get":{"tags":["その他"],"summary":"Speaker Info","description":"指定されたspeaker_uuidに関する情報をjson形式で返します。\n画像や音声はbase64エンコードされたものが返されます。\n\nReturns\n-------\nret_data: SpeakerInfo","operationId":"speaker_info_speaker_info_get","parameters":[{"required":true,"schema":{"title":"Speaker Uuid","type":"string"},"name":"speaker_uuid","in":"query"},{"required":false,"schema":{"title":"Core Version","type":"string"},"name":"core_version","in":"query"}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/SpeakerInfo"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/downloadable_libraries":{"get":{"tags":["音声ライブラリ管理"],"summary":"Downloadable Libraries","description":"ダウンロード可能な音声ライブラリの情報を返します。\n\nReturns\n-------\nret_data: List[DownloadableLibrary]","operationId":"downloadable_libraries_downloadable_libraries_get","responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"title":"Response Downloadable Libraries Downloadable Libraries Get","type":"array","items":{"$ref":"#/components/schemas/DownloadableLibrary"}}}}}}}},"/installed_libraries":{"get":{"tags":["音声ライブラリ管理"],"summary":"Installed Libraries","description":"インストールした音声ライブラリの情報を返します。\n\nReturns\n-------\nret_data: List[DownloadableLibrary]","operationId":"installed_libraries_installed_libraries_get","responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"title":"Response Installed Libraries Installed Libraries Get","type":"array","items":{"$ref":"#/components/schemas/DownloadableLibrary"}}}}}}}},"/install_library/{library_uuid}":{"post":{"tags":["音声ライブラリ管理"],"summary":"Install Library","description":"音声ライブラリをインストールします。\n音声ライブラリのZIPファイルをリクエストボディとして送信してください。\n\nParameters\n----------\nlibrary_uuid: str\n 音声ライブラリのID","operationId":"install_library_install_library__library_uuid__post","parameters":[{"required":true,"schema":{"title":"Library Uuid","type":"string"},"name":"library_uuid","in":"path"}],"responses":{"204":{"description":"Successful Response"},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/initialize_speaker":{"post":{"tags":["その他"],"summary":"Initialize Speaker","description":"指定されたspeaker_idの話者を初期化します。\n実行しなくても他のAPIは使用できますが、初回実行時に時間がかかることがあります。","operationId":"initialize_speaker_initialize_speaker_post","parameters":[{"required":true,"schema":{"title":"Speaker","type":"integer"},"name":"speaker","in":"query"},{"description":"既に初期化済みの話者の再初期化をスキップするかどうか","required":false,"schema":{"title":"Skip Reinit","type":"boolean","description":"既に初期化済みの話者の再初期化をスキップするかどうか","default":false},"name":"skip_reinit","in":"query"},{"required":false,"schema":{"title":"Core Version","type":"string"},"name":"core_version","in":"query"}],"responses":{"204":{"description":"Successful Response"},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/is_initialized_speaker":{"get":{"tags":["その他"],"summary":"Is Initialized Speaker","description":"指定されたspeaker_idの話者が初期化されているかどうかを返します。","operationId":"is_initialized_speaker_is_initialized_speaker_get","parameters":[{"required":true,"schema":{"title":"Speaker","type":"integer"},"name":"speaker","in":"query"},{"required":false,"schema":{"title":"Core Version","type":"string"},"name":"core_version","in":"query"}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"title":"Response Is Initialized Speaker Is Initialized Speaker Get","type":"boolean"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/user_dict":{"get":{"tags":["ユーザー辞書"],"summary":"Get User Dict Words","description":"ユーザー辞書に登録されている単語の一覧を返します。\n単語の表層形(surface)は正規化済みの物を返します。\n\nReturns\n-------\nDict[str, UserDictWord]\n 単語のUUIDとその詳細","operationId":"get_user_dict_words_user_dict_get","responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"title":"Response Get User Dict Words User Dict Get","type":"object","additionalProperties":{"$ref":"#/components/schemas/UserDictWord"}}}}}}}},"/user_dict_word":{"post":{"tags":["ユーザー辞書"],"summary":"Add User Dict Word","description":"ユーザー辞書に言葉を追加します。\n\nParameters\n----------\nsurface : str\n 言葉の表層形\npronunciation: str\n 言葉の発音(カタカナ)\naccent_type: int\n アクセント型(音が下がる場所を指す)\nword_type: WordTypes, optional\n PROPER_NOUN(固有名詞)、COMMON_NOUN(普通名詞)、VERB(動詞)、ADJECTIVE(形容詞)、SUFFIX(語尾)のいずれか\npriority: int, optional\n 単語の優先度(0から10までの整数)\n 数字が大きいほど優先度が高くなる\n 1から9までの値を指定することを推奨","operationId":"add_user_dict_word_user_dict_word_post","parameters":[{"required":true,"schema":{"title":"Surface","type":"string"},"name":"surface","in":"query"},{"required":true,"schema":{"title":"Pronunciation","type":"string"},"name":"pronunciation","in":"query"},{"required":true,"schema":{"title":"Accent Type","type":"integer"},"name":"accent_type","in":"query"},{"required":false,"schema":{"$ref":"#/components/schemas/WordTypes"},"name":"word_type","in":"query"},{"required":false,"schema":{"title":"Priority","maximum":10.0,"minimum":0.0,"type":"integer"},"name":"priority","in":"query"}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"title":"Response Add User Dict Word User Dict Word Post","type":"string"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/user_dict_word/{word_uuid}":{"put":{"tags":["ユーザー辞書"],"summary":"Rewrite User Dict Word","description":"ユーザー辞書に登録されている言葉を更新します。\n\nParameters\n----------\nsurface : str\n 言葉の表層形\npronunciation: str\n 言葉の発音(カタカナ)\naccent_type: int\n アクセント型(音が下がる場所を指す)\nword_uuid: str\n 更新する言葉のUUID\nword_type: WordTypes, optional\n PROPER_NOUN(固有名詞)、COMMON_NOUN(普通名詞)、VERB(動詞)、ADJECTIVE(形容詞)、SUFFIX(語尾)のいずれか\npriority: int, optional\n 単語の優先度(0から10までの整数)\n 数字が大きいほど優先度が高くなる\n 1から9までの値を指定することを推奨","operationId":"rewrite_user_dict_word_user_dict_word__word_uuid__put","parameters":[{"required":true,"schema":{"title":"Word Uuid","type":"string"},"name":"word_uuid","in":"path"},{"required":true,"schema":{"title":"Surface","type":"string"},"name":"surface","in":"query"},{"required":true,"schema":{"title":"Pronunciation","type":"string"},"name":"pronunciation","in":"query"},{"required":true,"schema":{"title":"Accent Type","type":"integer"},"name":"accent_type","in":"query"},{"required":false,"schema":{"$ref":"#/components/schemas/WordTypes"},"name":"word_type","in":"query"},{"required":false,"schema":{"title":"Priority","maximum":10.0,"minimum":0.0,"type":"integer"},"name":"priority","in":"query"}],"responses":{"204":{"description":"Successful Response"},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}},"delete":{"tags":["ユーザー辞書"],"summary":"Delete User Dict Word","description":"ユーザー辞書に登録されている言葉を削除します。\n\nParameters\n----------\nword_uuid: str\n 削除する言葉のUUID","operationId":"delete_user_dict_word_user_dict_word__word_uuid__delete","parameters":[{"required":true,"schema":{"title":"Word Uuid","type":"string"},"name":"word_uuid","in":"path"}],"responses":{"204":{"description":"Successful Response"},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/import_user_dict":{"post":{"tags":["ユーザー辞書"],"summary":"Import User Dict Words","description":"他のユーザー辞書をインポートします。\n\nParameters\n----------\nimport_dict_data: Dict[str, UserDictWord]\n インポートするユーザー辞書のデータ\noverride: bool\n 重複したエントリがあった場合、上書きするかどうか","operationId":"import_user_dict_words_import_user_dict_post","parameters":[{"required":true,"schema":{"title":"Override","type":"boolean"},"name":"override","in":"query"}],"requestBody":{"content":{"application/json":{"schema":{"title":"Import Dict Data","type":"object","additionalProperties":{"$ref":"#/components/schemas/UserDictWord"}}}},"required":true},"responses":{"204":{"description":"Successful Response"},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/supported_devices":{"get":{"tags":["その他"],"summary":"Supported Devices","operationId":"supported_devices_supported_devices_get","parameters":[{"required":false,"schema":{"title":"Core Version","type":"string"},"name":"core_version","in":"query"}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/SupportedDevicesInfo"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/engine_manifest":{"get":{"tags":["その他"],"summary":"Engine Manifest","operationId":"engine_manifest_engine_manifest_get","responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/EngineManifest"}}}}}}},"/setting":{"get":{"tags":["設定"],"summary":"Setting Get","operationId":"setting_get_setting_get","responses":{"200":{"description":"Successful Response","content":{"text/html":{"schema":{"type":"string"}}}}}},"post":{"tags":["設定"],"summary":"Setting Post","operationId":"setting_post_setting_post","requestBody":{"content":{"application/x-www-form-urlencoded":{"schema":{"$ref":"#/components/schemas/Body_setting_post_setting_post"}}}},"responses":{"200":{"description":"Successful Response","content":{"text/html":{"schema":{"type":"string"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}}},"components":{"schemas":{"AccentPhrase":{"title":"AccentPhrase","required":["moras","accent"],"type":"object","properties":{"moras":{"title":"モーラのリスト","type":"array","items":{"$ref":"#/components/schemas/Mora"}},"accent":{"title":"アクセント箇所","type":"integer"},"pause_mora":{"title":"後ろに無音を付けるかどうか","allOf":[{"$ref":"#/components/schemas/Mora"}]},"is_interrogative":{"title":"疑問系かどうか","type":"boolean","default":false}},"description":"アクセント句ごとの情報"},"AudioQuery":{"title":"AudioQuery","required":["accent_phrases","speedScale","pitchScale","intonationScale","volumeScale","prePhonemeLength","postPhonemeLength","outputSamplingRate","outputStereo"],"type":"object","properties":{"accent_phrases":{"title":"アクセント句のリスト","type":"array","items":{"$ref":"#/components/schemas/AccentPhrase"}},"speedScale":{"title":"全体の話速","type":"number"},"pitchScale":{"title":"全体の音高","type":"number"},"intonationScale":{"title":"全体の抑揚","type":"number"},"volumeScale":{"title":"全体の音量","type":"number"},"prePhonemeLength":{"title":"音声の前の無音時間","type":"number"},"postPhonemeLength":{"title":"音声の後の無音時間","type":"number"},"outputSamplingRate":{"title":"音声データの出力サンプリングレート","type":"integer"},"outputStereo":{"title":"音声データをステレオ出力するか否か","type":"boolean"},"kana":{"title":"[読み取り専用]AquesTalkライクな読み仮名。音声合成クエリとしては無視される","type":"string"}},"description":"音声合成用のクエリ"},"Body_setting_post_setting_post":{"title":"Body_setting_post_setting_post","type":"object","properties":{"cors_policy_mode":{"title":"Cors Policy Mode","type":"string"},"allow_origin":{"title":"Allow Origin","type":"string"}}},"DownloadableLibrary":{"title":"DownloadableLibrary","required":["name","uuid","version","download_url","bytes","speakers"],"type":"object","properties":{"name":{"title":"音声ライブラリの名前","type":"string"},"uuid":{"title":"音声ライブラリのUUID","type":"string"},"version":{"title":"音声ライブラリのバージョン","type":"string"},"download_url":{"title":"音声ライブラリのダウンロードURL","type":"string"},"bytes":{"title":"音声ライブラリのバイト数","type":"integer"},"speakers":{"title":"音声ライブラリに含まれる話者のリスト","type":"array","items":{"$ref":"#/components/schemas/LibrarySpeaker"}}},"description":"ダウンロード可能な音声ライブラリの情報"},"EngineManifest":{"title":"EngineManifest","required":["manifest_version","name","brand_name","uuid","url","icon","default_sampling_rate","terms_of_service","update_infos","dependency_licenses","supported_features"],"type":"object","properties":{"manifest_version":{"title":"マニフェストのバージョン","type":"string"},"name":{"title":"エンジン名","type":"string"},"brand_name":{"title":"ブランド名","type":"string"},"uuid":{"title":"エンジンのUUID","type":"string"},"url":{"title":"エンジンのURL","type":"string"},"icon":{"title":"エンジンのアイコンをBASE64エンコードしたもの","type":"string"},"default_sampling_rate":{"title":"デフォルトのサンプリング周波数","type":"integer"},"terms_of_service":{"title":"エンジンの利用規約","type":"string"},"update_infos":{"title":"エンジンのアップデート情報","type":"array","items":{"$ref":"#/components/schemas/UpdateInfo"}},"dependency_licenses":{"title":"依存関係のライセンス情報","type":"array","items":{"$ref":"#/components/schemas/LicenseInfo"}},"supported_features":{"title":"エンジンが持つ機能","allOf":[{"$ref":"#/components/schemas/SupportedFeatures"}]}},"description":"エンジン自体に関する情報"},"HTTPValidationError":{"title":"HTTPValidationError","type":"object","properties":{"detail":{"title":"Detail","type":"array","items":{"$ref":"#/components/schemas/ValidationError"}}}},"LibrarySpeaker":{"title":"LibrarySpeaker","required":["speaker","speaker_info"],"type":"object","properties":{"speaker":{"title":"話者情報","allOf":[{"$ref":"#/components/schemas/Speaker"}]},"speaker_info":{"title":"話者の追加情報","allOf":[{"$ref":"#/components/schemas/SpeakerInfo"}]}},"description":"音声ライブラリに含まれる話者の情報"},"LicenseInfo":{"title":"LicenseInfo","required":["name","text"],"type":"object","properties":{"name":{"title":"依存ライブラリ名","type":"string"},"version":{"title":"依存ライブラリのバージョン","type":"string"},"license":{"title":"依存ライブラリのライセンス名","type":"string"},"text":{"title":"依存ライブラリのライセンス本文","type":"string"}},"description":"依存ライブラリのライセンス情報"},"Mora":{"title":"Mora","required":["text","vowel","vowel_length","pitch"],"type":"object","properties":{"text":{"title":"文字","type":"string"},"consonant":{"title":"子音の音素","type":"string"},"consonant_length":{"title":"子音の音長","type":"number"},"vowel":{"title":"母音の音素","type":"string"},"vowel_length":{"title":"母音の音長","type":"number"},"pitch":{"title":"音高","type":"number"}},"description":"モーラ(子音+母音)ごとの情報"},"MorphableTargetInfo":{"title":"MorphableTargetInfo","required":["is_morphable"],"type":"object","properties":{"is_morphable":{"title":"指定した話者に対してモーフィングの可否","type":"boolean"}}},"ParseKanaBadRequest":{"title":"ParseKanaBadRequest","required":["text","error_name","error_args"],"type":"object","properties":{"text":{"title":"エラーメッセージ","type":"string"},"error_name":{"title":"エラー名","type":"string","description":"|name|description|\n|---|---|\n| UNKNOWN_TEXT | 判別できない読み仮名があります: {text} |\n| ACCENT_TOP | 句頭にアクセントは置けません: {text} |\n| ACCENT_TWICE | 1つのアクセント句に二つ以上のアクセントは置けません: {text} |\n| ACCENT_NOTFOUND | アクセントを指定していないアクセント句があります: {text} |\n| EMPTY_PHRASE | {position}番目のアクセント句が空白です |\n| INTERROGATION_MARK_NOT_AT_END | アクセント句末以外に「?」は置けません: {text} |\n| INFINITE_LOOP | 処理時に無限ループになってしまいました...バグ報告をお願いします。 |"},"error_args":{"title":"エラーを起こした箇所","type":"object","additionalProperties":{"type":"string"}}}},"Preset":{"title":"Preset","required":["id","name","speaker_uuid","style_id","speedScale","pitchScale","intonationScale","volumeScale","prePhonemeLength","postPhonemeLength"],"type":"object","properties":{"id":{"title":"プリセットID","type":"integer"},"name":{"title":"プリセット名","type":"string"},"speaker_uuid":{"title":"スピーカーのUUID","type":"string"},"style_id":{"title":"スタイルID","type":"integer"},"speedScale":{"title":"全体の話速","type":"number"},"pitchScale":{"title":"全体の音高","type":"number"},"intonationScale":{"title":"全体の抑揚","type":"number"},"volumeScale":{"title":"全体の音量","type":"number"},"prePhonemeLength":{"title":"音声の前の無音時間","type":"number"},"postPhonemeLength":{"title":"音声の後の無音時間","type":"number"}},"description":"プリセット情報"},"Speaker":{"title":"Speaker","required":["name","speaker_uuid","styles"],"type":"object","properties":{"supported_features":{"title":"スピーカーの対応機能","allOf":[{"$ref":"#/components/schemas/SpeakerSupportedFeatures"}]},"name":{"title":"名前","type":"string"},"speaker_uuid":{"title":"スピーカーのUUID","type":"string"},"styles":{"title":"スピーカースタイルの一覧","type":"array","items":{"$ref":"#/components/schemas/SpeakerStyle"}},"version":{"title":"Version","type":"string","default":"スピーカーのバージョン"}},"description":"スピーカー情報"},"SpeakerInfo":{"title":"SpeakerInfo","required":["policy","portrait","style_infos"],"type":"object","properties":{"policy":{"title":"policy.md","type":"string"},"portrait":{"title":"portrait.pngをbase64エンコードしたもの","type":"string"},"style_infos":{"title":"スタイルの追加情報","type":"array","items":{"$ref":"#/components/schemas/StyleInfo"}}},"description":"話者の追加情報"},"SpeakerStyle":{"title":"SpeakerStyle","required":["name","id"],"type":"object","properties":{"name":{"title":"スタイル名","type":"string"},"id":{"title":"スタイルID","type":"integer"}},"description":"スピーカーのスタイル情報"},"SpeakerSupportPermittedSynthesisMorphing":{"title":"SpeakerSupportPermittedSynthesisMorphing","enum":["ALL","SELF_ONLY","NOTHING"],"type":"string","description":"An enumeration."},"SpeakerSupportedFeatures":{"title":"SpeakerSupportedFeatures","type":"object","properties":{"permitted_synthesis_morphing":{"title":"モーフィング機能への対応","allOf":[{"$ref":"#/components/schemas/SpeakerSupportPermittedSynthesisMorphing"}],"default":"ALL"}},"description":"話者の対応機能の情報"},"StyleInfo":{"title":"StyleInfo","required":["id","icon","voice_samples"],"type":"object","properties":{"id":{"title":"スタイルID","type":"integer"},"icon":{"title":"当該スタイルのアイコンをbase64エンコードしたもの","type":"string"},"portrait":{"title":"当該スタイルのportrait.pngをbase64エンコードしたもの","type":"string"},"voice_samples":{"title":"voice_sampleのwavファイルをbase64エンコードしたもの","type":"array","items":{"type":"string"}}},"description":"スタイルの追加情報"},"SupportedDevicesInfo":{"title":"SupportedDevicesInfo","required":["cpu","cuda","dml"],"type":"object","properties":{"cpu":{"title":"CPUに対応しているか","type":"boolean"},"cuda":{"title":"CUDA(Nvidia GPU)に対応しているか","type":"boolean"},"dml":{"title":"DirectML(Nvidia GPU/Radeon GPU等)に対応しているか","type":"boolean"}},"description":"対応しているデバイスの情報"},"SupportedFeatures":{"title":"SupportedFeatures","required":["adjust_mora_pitch","adjust_phoneme_length","adjust_speed_scale","adjust_pitch_scale","adjust_intonation_scale","adjust_volume_scale","interrogative_upspeak","synthesis_morphing","manage_library"],"type":"object","properties":{"adjust_mora_pitch":{"title":"モーラごとの音高の調整","type":"boolean"},"adjust_phoneme_length":{"title":"音素ごとの長さの調整","type":"boolean"},"adjust_speed_scale":{"title":"全体の話速の調整","type":"boolean"},"adjust_pitch_scale":{"title":"全体の音高の調整","type":"boolean"},"adjust_intonation_scale":{"title":"全体の抑揚の調整","type":"boolean"},"adjust_volume_scale":{"title":"全体の音量の調整","type":"boolean"},"interrogative_upspeak":{"title":"疑問文の自動調整","type":"boolean"},"synthesis_morphing":{"title":"2人の話者でモーフィングした音声を合成","type":"boolean"},"manage_library":{"title":"音声ライブラリのインストール・アンインストール","type":"boolean"}},"description":"エンジンが持つ機能の一覧"},"UpdateInfo":{"title":"UpdateInfo","required":["version","descriptions"],"type":"object","properties":{"version":{"title":"エンジンのバージョン名","type":"string"},"descriptions":{"title":"アップデートの詳細についての説明","type":"array","items":{"type":"string"}},"contributors":{"title":"貢献者名","type":"array","items":{"type":"string"}}},"description":"エンジンのアップデート情報"},"UserDictWord":{"title":"UserDictWord","required":["surface","priority","part_of_speech","part_of_speech_detail_1","part_of_speech_detail_2","part_of_speech_detail_3","inflectional_type","inflectional_form","stem","yomi","pronunciation","accent_type","accent_associative_rule"],"type":"object","properties":{"surface":{"title":"表層形","type":"string"},"priority":{"title":"優先度","maximum":10.0,"minimum":0.0,"type":"integer"},"context_id":{"title":"文脈ID","type":"integer","default":1348},"part_of_speech":{"title":"品詞","type":"string"},"part_of_speech_detail_1":{"title":"品詞細分類1","type":"string"},"part_of_speech_detail_2":{"title":"品詞細分類2","type":"string"},"part_of_speech_detail_3":{"title":"品詞細分類3","type":"string"},"inflectional_type":{"title":"活用型","type":"string"},"inflectional_form":{"title":"活用形","type":"string"},"stem":{"title":"原形","type":"string"},"yomi":{"title":"読み","type":"string"},"pronunciation":{"title":"発音","type":"string"},"accent_type":{"title":"アクセント型","type":"integer"},"mora_count":{"title":"モーラ数","type":"integer"},"accent_associative_rule":{"title":"アクセント結合規則","type":"string"}},"description":"辞書のコンパイルに使われる情報"},"ValidationError":{"title":"ValidationError","required":["loc","msg","type"],"type":"object","properties":{"loc":{"title":"Location","type":"array","items":{"anyOf":[{"type":"string"},{"type":"integer"}]}},"msg":{"title":"Message","type":"string"},"type":{"title":"Error Type","type":"string"}}},"WordTypes":{"title":"WordTypes","enum":["PROPER_NOUN","COMMON_NOUN","VERB","ADJECTIVE","SUFFIX"],"type":"string","description":"fastapiでword_type引数を検証する時に使用するクラス"}}}} \ No newline at end of file diff --git a/openapitools.json b/openapitools.json index 3b40e47a45..601ac1d61f 100644 --- a/openapitools.json +++ b/openapitools.json @@ -2,6 +2,6 @@ "$schema": "node_modules/@openapitools/openapi-generator-cli/config.schema.json", "spaces": 2, "generator-cli": { - "version": "5.3.0" + "version": "5.2.1" } } diff --git a/package-lock.json b/package-lock.json index 2cc2fd1c2c..d28fb2c714 100644 --- a/package-lock.json +++ b/package-lock.json @@ -11,6 +11,7 @@ "dependencies": { "@gtm-support/vue-gtm": "1.2.3", "@quasar/extras": "1.10.10", + "async-lock": "1.4.0", "buffer": "6.0.3", "clone-deep": "4.0.1", "core-js": "3.12.1", @@ -25,6 +26,7 @@ "markdown-it": "12.0.4", "move-file": "3.0.0", "multistream": "4.1.0", + "node-fetch": "3.3.1", "quasar": "2.11.6", "semver": "7.3.5", "shlex": "2.1.2", @@ -43,6 +45,7 @@ "@openapitools/openapi-generator-cli": "2.3.3", "@playwright/test": "1.32.1", "@quasar/vite-plugin": "1.3.0", + "@types/async-lock": "1.4.0", "@types/clone-deep": "4.0.1", "@types/electron-devtools-installer": "2.2.2", "@types/encoding-japanese": "1.0.18", @@ -50,6 +53,7 @@ "@types/markdown-it": "12.2.0", "@types/mousetrap": "1.6.8", "@types/multistream": "4.1.0", + "@types/node": "16.18.23", "@types/semver": "7.3.9", "@types/unzipper": "0.10.5", "@types/uuid": "8.3.4", @@ -713,22 +717,6 @@ "node": ">= 10.0.0" } }, - "node_modules/@esbuild/win32-x64": { - "version": "0.16.17", - "resolved": "https://registry.npmjs.org/@esbuild/win32-x64/-/win32-x64-0.16.17.tgz", - "integrity": "sha512-y+EHuSchhL7FjHgvQL/0fnnFmO4T1bhvWANX6gcnqTjtnKWbTvUMCpGnv2+t+31d7RzyEAYAd4u2fnIhHL6N/Q==", - "cpu": [ - "x64" - ], - "dev": true, - "optional": true, - "os": [ - "win32" - ], - "engines": { - "node": ">=12" - } - }, "node_modules/@eslint/eslintrc": { "version": "1.3.2", "resolved": "https://registry.npmjs.org/@eslint/eslintrc/-/eslintrc-1.3.2.tgz", @@ -1742,6 +1730,12 @@ "integrity": "sha512-yOlFc+7UtL/89t2ZhjPvvB/DeAr3r+Dq58IgzsFkOAvVC6NMJXmCGjbptdXdR9qsX7pKcTL+s87FtYREi2dEEQ==", "dev": true }, + "node_modules/@types/async-lock": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/@types/async-lock/-/async-lock-1.4.0.tgz", + "integrity": "sha512-2+rYSaWrpdbQG3SA0LmMT6YxWLrI81AqpMlSkw3QtFc2HGDufkweQSn30Eiev7x9LL0oyFrBqk1PXOnB9IEgKg==", + "dev": true + }, "node_modules/@types/cacheable-request": { "version": "6.0.3", "resolved": "https://registry.npmjs.org/@types/cacheable-request/-/cacheable-request-6.0.3.tgz", @@ -1899,9 +1893,9 @@ } }, "node_modules/@types/node": { - "version": "15.3.0", - "resolved": "https://registry.npmjs.org/@types/node/-/node-15.3.0.tgz", - "integrity": "sha512-8/bnjSZD86ZfpBsDlCIkNXIvm+h6wi9g7IqL+kmFkQ+Wvu3JrasgLElfiPgoo8V8vVfnEi0QVS12gbl94h9YsQ==", + "version": "16.18.23", + "resolved": "https://registry.npmjs.org/@types/node/-/node-16.18.23.tgz", + "integrity": "sha512-XAMpaw1s1+6zM+jn2tmw8MyaRDIJfXxqmIQIS0HfoGYPuf7dUWeiUKopwq13KFX9lEp1+THGtlaaYx39Nxr58g==", "devOptional": true }, "node_modules/@types/normalize-package-data": { @@ -3579,6 +3573,11 @@ "node": ">=0.12.0" } }, + "node_modules/async-lock": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/async-lock/-/async-lock-1.4.0.tgz", + "integrity": "sha512-coglx5yIWuetakm3/1dsX9hxCNox22h7+V80RQOu2XUUMidtArxKoZoOtHUPuR84SycKTXzgGzAUR5hJxujyJQ==" + }, "node_modules/asynckit": { "version": "0.4.0", "resolved": "https://registry.npmjs.org/asynckit/-/asynckit-0.4.0.tgz", @@ -6284,21 +6283,6 @@ "node": ">= 8" } }, - "node_modules/cross-spawn/node_modules/which": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/which/-/which-2.0.2.tgz", - "integrity": "sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA==", - "dev": true, - "dependencies": { - "isexe": "^2.0.0" - }, - "bin": { - "node-which": "bin/node-which" - }, - "engines": { - "node": ">= 8" - } - }, "node_modules/cross-var": { "version": "1.1.0", "resolved": "https://registry.npmjs.org/cross-var/-/cross-var-1.1.0.tgz", @@ -7268,12 +7252,6 @@ "node": ">=8.0.0" } }, - "node_modules/electron/node_modules/@types/node": { - "version": "16.11.41", - "resolved": "https://registry.npmjs.org/@types/node/-/node-16.11.41.tgz", - "integrity": "sha512-mqoYK2TnVjdkGk8qXAVGc/x9nSaTpSrFaGFm43BUH3IdoBV0nta6hYaGmdOvIMlbHJbUEVen3gvwpwovAZKNdQ==", - "dev": true - }, "node_modules/elliptic": { "version": "6.5.4", "resolved": "https://registry.npmjs.org/elliptic/-/elliptic-6.5.4.tgz", @@ -11818,9 +11796,9 @@ } }, "node_modules/multistream/node_modules/readable-stream": { - "version": "3.6.2", - "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-3.6.2.tgz", - "integrity": "sha512-9u/sniCrY3D5WdsERHzHE4G2YCXqoG5FTHUiCC4SIbr6XcLZBY05ya9EKjYek9O5xOAwjGq+1JdGBAS7Q9ScoA==", + "version": "3.6.0", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-3.6.0.tgz", + "integrity": "sha512-BViHy7LKeTz4oNnkcLJ+lVSL6vpiFeX6/d3oSH8zCW7UxP2onchk+vTGB143xuFjHS3deTgkKoXXymXqymiIdA==", "dependencies": { "inherits": "^2.0.3", "string_decoder": "^1.1.1", @@ -12060,21 +12038,6 @@ "url": "https://github.com/sponsors/isaacs" } }, - "node_modules/node-gyp/node_modules/which": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/which/-/which-2.0.2.tgz", - "integrity": "sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA==", - "dev": true, - "dependencies": { - "isexe": "^2.0.0" - }, - "bin": { - "node-which": "bin/node-which" - }, - "engines": { - "node": ">= 8" - } - }, "node_modules/node-libs-browser": { "version": "2.2.1", "resolved": "https://registry.npmjs.org/node-libs-browser/-/node-libs-browser-2.2.1.tgz", @@ -16875,6 +16838,21 @@ "integrity": "sha512-2JAn3z8AR6rjK8Sm8orRC0h/bcl/DqL7tRPdGZ4I1CjdF+EaMLmYxBHyXuKL849eucPFhvBoxMsflfOb8kxaeQ==", "dev": true }, + "node_modules/which": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/which/-/which-2.0.2.tgz", + "integrity": "sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA==", + "dev": true, + "dependencies": { + "isexe": "^2.0.0" + }, + "bin": { + "node-which": "bin/node-which" + }, + "engines": { + "node": ">= 8" + } + }, "node_modules/which-boxed-primitive": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/which-boxed-primitive/-/which-boxed-primitive-1.0.2.tgz", @@ -17610,13 +17588,6 @@ } } }, - "@esbuild/win32-x64": { - "version": "0.16.17", - "resolved": "https://registry.npmjs.org/@esbuild/win32-x64/-/win32-x64-0.16.17.tgz", - "integrity": "sha512-y+EHuSchhL7FjHgvQL/0fnnFmO4T1bhvWANX6gcnqTjtnKWbTvUMCpGnv2+t+31d7RzyEAYAd4u2fnIhHL6N/Q==", - "dev": true, - "optional": true - }, "@eslint/eslintrc": { "version": "1.3.2", "resolved": "https://registry.npmjs.org/@eslint/eslintrc/-/eslintrc-1.3.2.tgz", @@ -18327,6 +18298,12 @@ "integrity": "sha512-yOlFc+7UtL/89t2ZhjPvvB/DeAr3r+Dq58IgzsFkOAvVC6NMJXmCGjbptdXdR9qsX7pKcTL+s87FtYREi2dEEQ==", "dev": true }, + "@types/async-lock": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/@types/async-lock/-/async-lock-1.4.0.tgz", + "integrity": "sha512-2+rYSaWrpdbQG3SA0LmMT6YxWLrI81AqpMlSkw3QtFc2HGDufkweQSn30Eiev7x9LL0oyFrBqk1PXOnB9IEgKg==", + "dev": true + }, "@types/cacheable-request": { "version": "6.0.3", "resolved": "https://registry.npmjs.org/@types/cacheable-request/-/cacheable-request-6.0.3.tgz", @@ -18484,9 +18461,9 @@ } }, "@types/node": { - "version": "15.3.0", - "resolved": "https://registry.npmjs.org/@types/node/-/node-15.3.0.tgz", - "integrity": "sha512-8/bnjSZD86ZfpBsDlCIkNXIvm+h6wi9g7IqL+kmFkQ+Wvu3JrasgLElfiPgoo8V8vVfnEi0QVS12gbl94h9YsQ==", + "version": "16.18.23", + "resolved": "https://registry.npmjs.org/@types/node/-/node-16.18.23.tgz", + "integrity": "sha512-XAMpaw1s1+6zM+jn2tmw8MyaRDIJfXxqmIQIS0HfoGYPuf7dUWeiUKopwq13KFX9lEp1+THGtlaaYx39Nxr58g==", "devOptional": true }, "@types/normalize-package-data": { @@ -19839,6 +19816,11 @@ "integrity": "sha512-NW2cX8m1Q7KPA7a5M2ULQeZ2wR5qI5PAbw5L0UOMxdioVk9PMZ0h1TmyZEkPYrCvYjDlFICusOu1dlEKAAeXBw==", "dev": true }, + "async-lock": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/async-lock/-/async-lock-1.4.0.tgz", + "integrity": "sha512-coglx5yIWuetakm3/1dsX9hxCNox22h7+V80RQOu2XUUMidtArxKoZoOtHUPuR84SycKTXzgGzAUR5hJxujyJQ==" + }, "asynckit": { "version": "0.4.0", "resolved": "https://registry.npmjs.org/asynckit/-/asynckit-0.4.0.tgz", @@ -22141,17 +22123,6 @@ "path-key": "^3.1.0", "shebang-command": "^2.0.0", "which": "^2.0.1" - }, - "dependencies": { - "which": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/which/-/which-2.0.2.tgz", - "integrity": "sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA==", - "dev": true, - "requires": { - "isexe": "^2.0.0" - } - } } }, "cross-var": { @@ -22657,14 +22628,6 @@ "@electron/get": "^1.14.1", "@types/node": "^16.11.26", "extract-zip": "^2.0.1" - }, - "dependencies": { - "@types/node": { - "version": "16.11.41", - "resolved": "https://registry.npmjs.org/@types/node/-/node-16.11.41.tgz", - "integrity": "sha512-mqoYK2TnVjdkGk8qXAVGc/x9nSaTpSrFaGFm43BUH3IdoBV0nta6hYaGmdOvIMlbHJbUEVen3gvwpwovAZKNdQ==", - "dev": true - } } }, "electron-builder": { @@ -26448,9 +26411,9 @@ }, "dependencies": { "readable-stream": { - "version": "3.6.2", - "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-3.6.2.tgz", - "integrity": "sha512-9u/sniCrY3D5WdsERHzHE4G2YCXqoG5FTHUiCC4SIbr6XcLZBY05ya9EKjYek9O5xOAwjGq+1JdGBAS7Q9ScoA==", + "version": "3.6.0", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-3.6.0.tgz", + "integrity": "sha512-BViHy7LKeTz4oNnkcLJ+lVSL6vpiFeX6/d3oSH8zCW7UxP2onchk+vTGB143xuFjHS3deTgkKoXXymXqymiIdA==", "requires": { "inherits": "^2.0.3", "string_decoder": "^1.1.1", @@ -26615,15 +26578,6 @@ "requires": { "glob": "^7.1.3" } - }, - "which": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/which/-/which-2.0.2.tgz", - "integrity": "sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA==", - "dev": true, - "requires": { - "isexe": "^2.0.0" - } } } }, @@ -30345,6 +30299,15 @@ } } }, + "which": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/which/-/which-2.0.2.tgz", + "integrity": "sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA==", + "dev": true, + "requires": { + "isexe": "^2.0.0" + } + }, "which-boxed-primitive": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/which-boxed-primitive/-/which-boxed-primitive-1.0.2.tgz", diff --git a/package.json b/package.json index 04e6b16be5..49c619fbd7 100644 --- a/package.json +++ b/package.json @@ -33,6 +33,7 @@ "dependencies": { "@gtm-support/vue-gtm": "1.2.3", "@quasar/extras": "1.10.10", + "async-lock": "1.4.0", "buffer": "6.0.3", "clone-deep": "4.0.1", "core-js": "3.12.1", @@ -47,6 +48,7 @@ "markdown-it": "12.0.4", "move-file": "3.0.0", "multistream": "4.1.0", + "node-fetch": "3.3.1", "quasar": "2.11.6", "semver": "7.3.5", "shlex": "2.1.2", @@ -68,6 +70,7 @@ "@openapitools/openapi-generator-cli": "2.3.3", "@playwright/test": "1.32.1", "@quasar/vite-plugin": "1.3.0", + "@types/async-lock": "1.4.0", "@types/clone-deep": "4.0.1", "@types/electron-devtools-installer": "2.2.2", "@types/encoding-japanese": "1.0.18", @@ -75,6 +78,7 @@ "@types/markdown-it": "12.2.0", "@types/mousetrap": "1.6.8", "@types/multistream": "4.1.0", + "@types/node": "16.18.23", "@types/semver": "7.3.9", "@types/unzipper": "0.10.5", "@types/uuid": "8.3.4", diff --git a/src/background.ts b/src/background.ts index 97d1133e15..8d1ea51802 100644 --- a/src/background.ts +++ b/src/background.ts @@ -3,6 +3,7 @@ import path from "path"; import fs from "fs"; +import { randomUUID } from "crypto"; import { app, protocol, @@ -35,11 +36,14 @@ import { defaultToolbarButtonSetting, engineSettingSchema, EngineId, + LibraryInstallId, + LibraryInstallStatus, } from "./type/preload"; import EngineManager from "./background/engineManager"; import VvppManager, { isVvppFile } from "./background/vvppManager"; import configMigration014 from "./background/configMigration014"; +import LibraryManager from "./background/libraryManager"; import { ipcMainHandle, ipcMainSend } from "@/electron/ipc"; type SingleInstanceLockData = { @@ -203,6 +207,10 @@ const engineManager = new EngineManager({ vvppEngineDir, }); const vvppManager = new VvppManager({ vvppEngineDir }); +const libraryManager = new LibraryManager({ + engineManager, + tempDir: app.getPath("temp"), +}); // エンジンのフォルダを開く function openEngineDirectory(engineId: EngineId) { @@ -879,6 +887,37 @@ ipcMainHandle("READ_FILE", (_, { filePath }) => { return fs.promises.readFile(filePath); }); +ipcMainHandle("START_LIBRARY_INSTALL", (_, { engineId, library }) => { + const libraryInstallId = LibraryInstallId(randomUUID()); + setTimeout(() => { + libraryManager.installLibrary( + engineId, + library, + libraryInstallId, + (status: LibraryInstallStatus) => { + if (status.status === "downloading" && status.contentLength) { + win.setProgressBar(status.downloaded / status.contentLength); + } else if (status.status === "installing") { + win.setProgressBar(2); + } else if (status.status === "error") { + win.setProgressBar(-1); + dialog.showErrorBox( + "ライブラリのインストールに失敗しました", + status.message + ); + } else { + win.setProgressBar(-1); + } + ipcMainSend(win, "UPDATE_LIBRARY_INSTALL_STATUS", { + libraryInstallId, + status, + }); + } + ); + }, 0); + return libraryInstallId; +}); + // app callback app.on("web-contents-created", (e, contents) => { // リンククリック時はブラウザを開く diff --git a/src/background/engineManager.ts b/src/background/engineManager.ts index 88c799ec13..025c70c999 100644 --- a/src/background/engineManager.ts +++ b/src/background/engineManager.ts @@ -419,6 +419,7 @@ export class EngineManager { log.info( `ENGINE ${engineId}: Killing current process (PID=${engineProcess.pid})...` ); + if (!engineProcess.pid) throw Error("engineProcess.pid is undefined"); treeKill(engineProcess.pid, (error) => { // error変数の値がundefined以外であればkillコマンドが失敗したことを意味します。 if (error != null) { diff --git a/src/background/libraryManager.ts b/src/background/libraryManager.ts new file mode 100644 index 0000000000..52097834ec --- /dev/null +++ b/src/background/libraryManager.ts @@ -0,0 +1,161 @@ +import fs from "fs"; +import path from "path"; +import AsyncLock from "async-lock"; +import fetch from "node-fetch"; +import log from "electron-log"; +import EngineManager from "./engineManager"; +import { + EngineId, + LibraryInstallId, + LibraryInstallStatus, +} from "@/type/preload"; +import { DownloadableLibrary } from "@/openapi"; + +export class LibraryManager { + engineManager: EngineManager; + tempDir: string; + lock: AsyncLock; + + constructor({ + engineManager, + tempDir, + }: { + engineManager: EngineManager; + tempDir: string; + }) { + this.engineManager = engineManager; + this.tempDir = tempDir; + this.lock = new AsyncLock(); + } + + async installLibrary( + engineId: EngineId, + library: DownloadableLibrary, + libraryInstallId: LibraryInstallId, + onUpdate: (status: LibraryInstallStatus) => void + ): Promise { + const engine = this.engineManager.fetchEngineInfo(engineId); + const prefix = `LIBRARY INSTALL ${libraryInstallId}: `; + log.log( + prefix + + `Started ${library.name}, Engine: ${engine.name}, URL: ${library.downloadUrl}` + ); + const downloadRes = await fetch(library.downloadUrl); + if (!downloadRes.ok) { + log.error( + prefix + + `Failed to download library: Server returned ${downloadRes.status}` + ); + onUpdate({ + status: "error", + message: `ダウンロード先のサーバーが${downloadRes.status}エラーを返しました`, + }); + return; + } else if (downloadRes.body === null) { + log.error(prefix + `Failed to download library: No body`); + onUpdate({ + status: "error", + message: `ダウンロード先のサーバーがライブラリを返しませんでした`, + }); + return; + } + const tempFilePath = path.join(this.tempDir, `vv-temp-${libraryInstallId}`); + log.log(prefix + `Writing to ${tempFilePath}`); + + const total = Number(downloadRes.headers.get("content-length")); + let downloaded = 0; + onUpdate({ + status: "downloading", + contentLength: total, + downloaded, + }); + const tempFile = fs.createWriteStream(tempFilePath); + try { + const progressInterval = 1024 * 1024; + let lastProgress = 0; + downloadRes.body.on("data", (chunk) => { + downloaded += chunk.length; + tempFile.write(chunk); + if ( + Math.floor(downloaded) - Math.floor(lastProgress) >= + progressInterval + ) { + onUpdate({ + status: "downloading", + contentLength: total, + downloaded, + }); + if (total) { + log.log( + prefix + + `Downloaded ${downloaded}/${total} bytes (${( + (downloaded / total) * + 100 + ).toFixed(1)}%)` + ); + } else { + log.log( + prefix + + `Downloaded ${downloaded} bytes (content-length header is not set)` + ); + } + lastProgress = downloaded; + } + }); + await new Promise((resolve) => { + if (!downloadRes.body) throw new Error("res.body is null"); + downloadRes.body.on("end", resolve); + }); + tempFile.close(); + log.log(prefix + "Download complete"); + + // OpenAPIのクライアントでは、ファイルをアップロードするためのAPIがないので、 + // node-fetchを使って直接アップロードする + const url = + engine.host.replace(/\/$/, "") + `/install_library/${library.uuid}`; + const bodyStream = fs.createReadStream(tempFilePath); + + onUpdate({ + status: "installing", + }); + + log.log(prefix + "Waiting for lock"); + await this.lock.acquire(`${engineId}`, async () => { + log.log(prefix + "Installing library"); + const installRes = await fetch(url, { + method: "POST", + + body: bodyStream, + }); + if (!installRes.ok) { + log.error( + prefix + + `Failed to install library: Server returned ${installRes.status}` + ); + onUpdate({ + status: "error", + message: `ライブラリのインストールに失敗しました。エラーコード:${installRes.status}`, + }); + return; + } + log.log(prefix + "Library installed"); + }); + onUpdate({ + status: "done", + }); + } catch (e) { + log.error(prefix + "Failed to install library"); + log.error(e); + onUpdate({ + status: "error", + message: `ライブラリのインストールに失敗しました。エラー内容:${e}`, + }); + } finally { + tempFile.close(); + log.log(prefix + "Removing temp file"); + await fs.promises.rm(tempFilePath); + } + } +} + +export default LibraryManager; diff --git a/src/components/EngineManageDialog.vue b/src/components/EngineManageDialog.vue index d9a7d41a16..092de40cd8 100644 --- a/src/components/EngineManageDialog.vue +++ b/src/components/EngineManageDialog.vue @@ -457,6 +457,7 @@ const getFeatureName = (name: keyof SupportedFeatures) => { adjustVolumeScale: "全体の音量の調整", interrogativeUpspeak: "疑問文の自動調整", synthesisMorphing: "2人の話者でモーフィングした音声を合成", + manageLibrary: "音声ライブラリの管理", }; return featureNameMap[name]; }; diff --git a/src/components/LDDEngineSection.vue b/src/components/LDDEngineSection.vue new file mode 100644 index 0000000000..0fe3947507 --- /dev/null +++ b/src/components/LDDEngineSection.vue @@ -0,0 +1,732 @@ + + + + + diff --git a/src/components/LibraryDownloadDialog.vue b/src/components/LibraryDownloadDialog.vue new file mode 100644 index 0000000000..04e2267e2a --- /dev/null +++ b/src/components/LibraryDownloadDialog.vue @@ -0,0 +1,351 @@ + + + + + diff --git a/src/components/MenuBar.vue b/src/components/MenuBar.vue index f556269744..c93b279679 100644 --- a/src/components/MenuBar.vue +++ b/src/components/MenuBar.vue @@ -509,6 +509,22 @@ async function updateEngines() { disableWhenUiLocked: false, }); } + if ( + Object.values(engineManifests.value).some( + (e) => e.supportedFeatures?.manageLibrary + ) + ) { + engineMenu.subMenu.push({ + type: "button", + label: "音声ライブラリのダウンロード", + onClick: () => { + store.dispatch("SET_DIALOG_OPEN", { + isLibraryDownloadDialogOpen: true, + }); + }, + disableWhenUiLocked: true, + }); + } } // engineInfos、engineManifests、enableMultiEngineを見て動的に更新できるようにする // FIXME: computedにする diff --git a/src/electron/preload.ts b/src/electron/preload.ts index 4fb0640f7b..8a1bd5950a 100644 --- a/src/electron/preload.ts +++ b/src/electron/preload.ts @@ -289,6 +289,10 @@ const api: Sandbox = { restartApp: ({ isMultiEngineOffMode }: { isMultiEngineOffMode: boolean }) => { ipcRendererInvoke("RESTART_APP", { isMultiEngineOffMode }); }, + + startLibraryInstall: async ({ engineId, library }) => { + return ipcRendererInvoke("START_LIBRARY_INSTALL", { engineId, library }); + }, }; contextBridge.exposeInMainWorld(SandboxKey, api); diff --git a/src/helpers/imageHelper.ts b/src/helpers/imageHelper.ts index 122d9ecc7e..4e5113a06c 100644 --- a/src/helpers/imageHelper.ts +++ b/src/helpers/imageHelper.ts @@ -16,9 +16,10 @@ function detectImageTypeFromBase64(data: string): string { export function base64ImageToUri(image: string): string { const mimeType = detectImageTypeFromBase64(image); const buffer = Buffer.from(image, "base64"); - return URL.createObjectURL( + const url = URL.createObjectURL( new Blob([buffer.buffer], { type: mimeType, }) ); + return url; } diff --git a/src/helpers/sizeHelper.ts b/src/helpers/sizeHelper.ts new file mode 100644 index 0000000000..6986e35dfd --- /dev/null +++ b/src/helpers/sizeHelper.ts @@ -0,0 +1,6 @@ +export function bytesToSize(bytes: number): string { + const sizes = ["B", "KB", "MB", "GB", "TB"]; + if (bytes === 0) return "0 B"; + const i = parseInt(String(Math.floor(Math.log(bytes) / Math.log(1024)))); + return (bytes / Math.pow(1024, i)).toFixed(2) + " " + sizes[i]; +} diff --git a/src/openapi/.openapi-generator/FILES b/src/openapi/.openapi-generator/FILES index a953c62938..f3ea9dd6aa 100644 --- a/src/openapi/.openapi-generator/FILES +++ b/src/openapi/.openapi-generator/FILES @@ -1,27 +1,28 @@ -apis/DefaultApi.ts -apis/index.ts -index.ts -models/AccentPhrase.ts -models/AudioQuery.ts -models/DownloadableLibrary.ts -models/EngineManifest.ts -models/HTTPValidationError.ts -models/LicenseInfo.ts -models/Mora.ts -models/MorphableTargetInfo.ts -models/ParseKanaBadRequest.ts -models/Preset.ts -models/Speaker.ts -models/SpeakerInfo.ts -models/SpeakerStyle.ts -models/SpeakerSupportPermittedSynthesisMorphing.ts -models/SpeakerSupportedFeatures.ts -models/StyleInfo.ts -models/SupportedDevicesInfo.ts -models/SupportedFeatures.ts -models/UpdateInfo.ts -models/UserDictWord.ts -models/ValidationError.ts -models/WordTypes.ts -models/index.ts -runtime.ts +apis/DefaultApi.ts +apis/index.ts +index.ts +models/AccentPhrase.ts +models/AudioQuery.ts +models/DownloadableLibrary.ts +models/EngineManifest.ts +models/HTTPValidationError.ts +models/LibrarySpeaker.ts +models/LicenseInfo.ts +models/Mora.ts +models/MorphableTargetInfo.ts +models/ParseKanaBadRequest.ts +models/Preset.ts +models/Speaker.ts +models/SpeakerInfo.ts +models/SpeakerStyle.ts +models/SpeakerSupportPermittedSynthesisMorphing.ts +models/SpeakerSupportedFeatures.ts +models/StyleInfo.ts +models/SupportedDevicesInfo.ts +models/SupportedFeatures.ts +models/UpdateInfo.ts +models/UserDictWord.ts +models/ValidationError.ts +models/WordTypes.ts +models/index.ts +runtime.ts diff --git a/src/openapi/.openapi-generator/VERSION b/src/openapi/.openapi-generator/VERSION index e230c8396d..804440660c 100644 --- a/src/openapi/.openapi-generator/VERSION +++ b/src/openapi/.openapi-generator/VERSION @@ -1 +1 @@ -5.3.0 \ No newline at end of file +5.2.1 \ No newline at end of file diff --git a/src/openapi/apis/DefaultApi.ts b/src/openapi/apis/DefaultApi.ts index 359f5506f6..0ce10a34b7 100644 --- a/src/openapi/apis/DefaultApi.ts +++ b/src/openapi/apis/DefaultApi.ts @@ -4,7 +4,7 @@ * VOICEVOX Engine * VOICEVOXの音声合成エンジンです。 * - * The version of the OpenAPI document: 0.14.0-preview.12 + * The version of the OpenAPI document: latest * * * NOTE: This class is auto generated by OpenAPI Generator (https://openapi-generator.tech). @@ -116,6 +116,10 @@ export interface InitializeSpeakerInitializeSpeakerPostRequest { coreVersion?: string; } +export interface InstallLibraryInstallLibraryLibraryUuidPostRequest { + libraryUuid: string; +} + export interface IsInitializedSpeakerIsInitializedSpeakerGetRequest { speaker: number; coreVersion?: string; @@ -374,7 +378,7 @@ export interface DefaultApiInterface { deleteUserDictWordUserDictWordWordUuidDelete(requestParameters: DeleteUserDictWordUserDictWordWordUuidDeleteRequest, initOverrides?: RequestInit): Promise; /** - * ダウンロード可能なモデル情報を返します。 Returns ------- ret_data: List[DownloadableLibrary] + * ダウンロード可能な音声ライブラリの情報を返します。 Returns ------- ret_data: List[DownloadableLibrary] * @summary Downloadable Libraries * @param {*} [options] Override http request option. * @throws {RequiredError} @@ -383,7 +387,7 @@ export interface DefaultApiInterface { downloadableLibrariesDownloadableLibrariesGetRaw(initOverrides?: RequestInit): Promise>>; /** - * ダウンロード可能なモデル情報を返します。 Returns ------- ret_data: List[DownloadableLibrary] + * ダウンロード可能な音声ライブラリの情報を返します。 Returns ------- ret_data: List[DownloadableLibrary] * Downloadable Libraries */ downloadableLibrariesDownloadableLibrariesGet(initOverrides?: RequestInit): Promise>; @@ -467,6 +471,37 @@ export interface DefaultApiInterface { */ initializeSpeakerInitializeSpeakerPost(requestParameters: InitializeSpeakerInitializeSpeakerPostRequest, initOverrides?: RequestInit): Promise; + /** + * 音声ライブラリをインストールします。 音声ライブラリのZIPファイルをリクエストボディとして送信してください。 Parameters ---------- library_uuid: str 音声ライブラリのID + * @summary Install Library + * @param {string} libraryUuid + * @param {*} [options] Override http request option. + * @throws {RequiredError} + * @memberof DefaultApiInterface + */ + installLibraryInstallLibraryLibraryUuidPostRaw(requestParameters: InstallLibraryInstallLibraryLibraryUuidPostRequest, initOverrides?: RequestInit): Promise>; + + /** + * 音声ライブラリをインストールします。 音声ライブラリのZIPファイルをリクエストボディとして送信してください。 Parameters ---------- library_uuid: str 音声ライブラリのID + * Install Library + */ + installLibraryInstallLibraryLibraryUuidPost(requestParameters: InstallLibraryInstallLibraryLibraryUuidPostRequest, initOverrides?: RequestInit): Promise; + + /** + * インストールした音声ライブラリの情報を返します。 Returns ------- ret_data: List[DownloadableLibrary] + * @summary Installed Libraries + * @param {*} [options] Override http request option. + * @throws {RequiredError} + * @memberof DefaultApiInterface + */ + installedLibrariesInstalledLibrariesGetRaw(initOverrides?: RequestInit): Promise>>; + + /** + * インストールした音声ライブラリの情報を返します。 Returns ------- ret_data: List[DownloadableLibrary] + * Installed Libraries + */ + installedLibrariesInstalledLibrariesGet(initOverrides?: RequestInit): Promise>; + /** * 指定されたspeaker_idの話者が初期化されているかどうかを返します。 * @summary Is Initialized Speaker @@ -728,12 +763,12 @@ export interface DefaultApiInterface { * @throws {RequiredError} * @memberof DefaultApiInterface */ - versionVersionGetRaw(initOverrides?: RequestInit): Promise>; + versionVersionGetRaw(initOverrides?: RequestInit): Promise>; /** * Version */ - versionVersionGet(initOverrides?: RequestInit): Promise; + versionVersionGet(initOverrides?: RequestInit): Promise; } @@ -1158,7 +1193,7 @@ export class DefaultApi extends runtime.BaseAPI implements DefaultApiInterface { } /** - * ダウンロード可能なモデル情報を返します。 Returns ------- ret_data: List[DownloadableLibrary] + * ダウンロード可能な音声ライブラリの情報を返します。 Returns ------- ret_data: List[DownloadableLibrary] * Downloadable Libraries */ async downloadableLibrariesDownloadableLibrariesGetRaw(initOverrides?: RequestInit): Promise>> { @@ -1177,7 +1212,7 @@ export class DefaultApi extends runtime.BaseAPI implements DefaultApiInterface { } /** - * ダウンロード可能なモデル情報を返します。 Returns ------- ret_data: List[DownloadableLibrary] + * ダウンロード可能な音声ライブラリの情報を返します。 Returns ------- ret_data: List[DownloadableLibrary] * Downloadable Libraries */ async downloadableLibrariesDownloadableLibrariesGet(initOverrides?: RequestInit): Promise> { @@ -1352,6 +1387,65 @@ export class DefaultApi extends runtime.BaseAPI implements DefaultApiInterface { await this.initializeSpeakerInitializeSpeakerPostRaw(requestParameters, initOverrides); } + /** + * 音声ライブラリをインストールします。 音声ライブラリのZIPファイルをリクエストボディとして送信してください。 Parameters ---------- library_uuid: str 音声ライブラリのID + * Install Library + */ + async installLibraryInstallLibraryLibraryUuidPostRaw(requestParameters: InstallLibraryInstallLibraryLibraryUuidPostRequest, initOverrides?: RequestInit): Promise> { + if (requestParameters.libraryUuid === null || requestParameters.libraryUuid === undefined) { + throw new runtime.RequiredError('libraryUuid','Required parameter requestParameters.libraryUuid was null or undefined when calling installLibraryInstallLibraryLibraryUuidPost.'); + } + + const queryParameters: any = {}; + + const headerParameters: runtime.HTTPHeaders = {}; + + const response = await this.request({ + path: `/install_library/{library_uuid}`.replace(`{${"library_uuid"}}`, encodeURIComponent(String(requestParameters.libraryUuid))), + method: 'POST', + headers: headerParameters, + query: queryParameters, + }, initOverrides); + + return new runtime.VoidApiResponse(response); + } + + /** + * 音声ライブラリをインストールします。 音声ライブラリのZIPファイルをリクエストボディとして送信してください。 Parameters ---------- library_uuid: str 音声ライブラリのID + * Install Library + */ + async installLibraryInstallLibraryLibraryUuidPost(requestParameters: InstallLibraryInstallLibraryLibraryUuidPostRequest, initOverrides?: RequestInit): Promise { + await this.installLibraryInstallLibraryLibraryUuidPostRaw(requestParameters, initOverrides); + } + + /** + * インストールした音声ライブラリの情報を返します。 Returns ------- ret_data: List[DownloadableLibrary] + * Installed Libraries + */ + async installedLibrariesInstalledLibrariesGetRaw(initOverrides?: RequestInit): Promise>> { + const queryParameters: any = {}; + + const headerParameters: runtime.HTTPHeaders = {}; + + const response = await this.request({ + path: `/installed_libraries`, + method: 'GET', + headers: headerParameters, + query: queryParameters, + }, initOverrides); + + return new runtime.JSONApiResponse(response, (jsonValue) => jsonValue.map(DownloadableLibraryFromJSON)); + } + + /** + * インストールした音声ライブラリの情報を返します。 Returns ------- ret_data: List[DownloadableLibrary] + * Installed Libraries + */ + async installedLibrariesInstalledLibrariesGet(initOverrides?: RequestInit): Promise> { + const response = await this.installedLibrariesInstalledLibrariesGetRaw(initOverrides); + return await response.value(); + } + /** * 指定されたspeaker_idの話者が初期化されているかどうかを返します。 * Is Initialized Speaker @@ -1999,7 +2093,7 @@ export class DefaultApi extends runtime.BaseAPI implements DefaultApiInterface { /** * Version */ - async versionVersionGetRaw(initOverrides?: RequestInit): Promise> { + async versionVersionGetRaw(initOverrides?: RequestInit): Promise> { const queryParameters: any = {}; const headerParameters: runtime.HTTPHeaders = {}; @@ -2017,7 +2111,7 @@ export class DefaultApi extends runtime.BaseAPI implements DefaultApiInterface { /** * Version */ - async versionVersionGet(initOverrides?: RequestInit): Promise { + async versionVersionGet(initOverrides?: RequestInit): Promise { const response = await this.versionVersionGetRaw(initOverrides); return await response.value(); } diff --git a/src/openapi/models/AccentPhrase.ts b/src/openapi/models/AccentPhrase.ts index bb8746a88a..115f6d4900 100644 --- a/src/openapi/models/AccentPhrase.ts +++ b/src/openapi/models/AccentPhrase.ts @@ -4,7 +4,7 @@ * VOICEVOX Engine * VOICEVOXの音声合成エンジンです。 * - * The version of the OpenAPI document: 0.14.0-preview.12 + * The version of the OpenAPI document: latest * * * NOTE: This class is auto generated by OpenAPI Generator (https://openapi-generator.tech). @@ -43,7 +43,7 @@ export interface AccentPhrase { * @type {Mora} * @memberof AccentPhrase */ - pauseMora?: Mora | null; + pauseMora?: Mora; /** * * @type {boolean} @@ -85,3 +85,4 @@ export function AccentPhraseToJSON(value?: AccentPhrase | null): any { }; } + diff --git a/src/openapi/models/AudioQuery.ts b/src/openapi/models/AudioQuery.ts index 6045cdd41b..32bc9030a3 100644 --- a/src/openapi/models/AudioQuery.ts +++ b/src/openapi/models/AudioQuery.ts @@ -4,7 +4,7 @@ * VOICEVOX Engine * VOICEVOXの音声合成エンジンです。 * - * The version of the OpenAPI document: 0.14.0-preview.12 + * The version of the OpenAPI document: latest * * * NOTE: This class is auto generated by OpenAPI Generator (https://openapi-generator.tech). @@ -133,3 +133,4 @@ export function AudioQueryToJSON(value?: AudioQuery | null): any { }; } + diff --git a/src/openapi/models/DownloadableLibrary.ts b/src/openapi/models/DownloadableLibrary.ts index 5d1ec26aff..a672263d91 100644 --- a/src/openapi/models/DownloadableLibrary.ts +++ b/src/openapi/models/DownloadableLibrary.ts @@ -4,7 +4,7 @@ * VOICEVOX Engine * VOICEVOXの音声合成エンジンです。 * - * The version of the OpenAPI document: 0.14.0-preview.12 + * The version of the OpenAPI document: latest * * * NOTE: This class is auto generated by OpenAPI Generator (https://openapi-generator.tech). @@ -14,18 +14,14 @@ import { exists, mapValues } from '../runtime'; import { - Speaker, - SpeakerFromJSON, - SpeakerFromJSONTyped, - SpeakerToJSON, - SpeakerInfo, - SpeakerInfoFromJSON, - SpeakerInfoFromJSONTyped, - SpeakerInfoToJSON, + LibrarySpeaker, + LibrarySpeakerFromJSON, + LibrarySpeakerFromJSONTyped, + LibrarySpeakerToJSON, } from './'; /** - * ダウンロード可能な音声ライブラリの情報(最新情報をwebで取得することを考慮して、ローカルの情報はない) + * ダウンロード可能な音声ライブラリの情報 * @export * @interface DownloadableLibrary */ @@ -35,25 +31,37 @@ export interface DownloadableLibrary { * @type {string} * @memberof DownloadableLibrary */ - downloadUrl: string; + name: string; /** * - * @type {number} + * @type {string} * @memberof DownloadableLibrary */ - bytes: number; + uuid: string; + /** + * + * @type {string} + * @memberof DownloadableLibrary + */ + version: string; /** * - * @type {Speaker} + * @type {string} * @memberof DownloadableLibrary */ - speaker: Speaker | null; + downloadUrl: string; /** * - * @type {SpeakerInfo} + * @type {number} * @memberof DownloadableLibrary */ - speakerInfo: SpeakerInfo | null; + bytes: number; + /** + * + * @type {Array} + * @memberof DownloadableLibrary + */ + speakers: Array; } export function DownloadableLibraryFromJSON(json: any): DownloadableLibrary { @@ -66,10 +74,12 @@ export function DownloadableLibraryFromJSONTyped(json: any, ignoreDiscriminator: } return { + 'name': json['name'], + 'uuid': json['uuid'], + 'version': json['version'], 'downloadUrl': json['download_url'], 'bytes': json['bytes'], - 'speaker': SpeakerFromJSON(json['speaker']), - 'speakerInfo': SpeakerInfoFromJSON(json['speaker_info']), + 'speakers': ((json['speakers'] as Array).map(LibrarySpeakerFromJSON)), }; } @@ -82,10 +92,13 @@ export function DownloadableLibraryToJSON(value?: DownloadableLibrary | null): a } return { + 'name': value.name, + 'uuid': value.uuid, + 'version': value.version, 'download_url': value.downloadUrl, 'bytes': value.bytes, - 'speaker': SpeakerToJSON(value.speaker), - 'speaker_info': SpeakerInfoToJSON(value.speakerInfo), + 'speakers': ((value.speakers as Array).map(LibrarySpeakerToJSON)), }; } + diff --git a/src/openapi/models/EngineManifest.ts b/src/openapi/models/EngineManifest.ts index 0a38340e1b..358069da58 100644 --- a/src/openapi/models/EngineManifest.ts +++ b/src/openapi/models/EngineManifest.ts @@ -4,7 +4,7 @@ * VOICEVOX Engine * VOICEVOXの音声合成エンジンです。 * - * The version of the OpenAPI document: 0.14.0-preview.12 + * The version of the OpenAPI document: latest * * * NOTE: This class is auto generated by OpenAPI Generator (https://openapi-generator.tech). @@ -94,24 +94,12 @@ export interface EngineManifest { * @memberof EngineManifest */ dependencyLicenses: Array; - /** - * - * @type {string} - * @memberof EngineManifest - */ - downloadableLibrariesPath?: string; - /** - * - * @type {string} - * @memberof EngineManifest - */ - downloadableLibrariesUrl?: string; /** * * @type {SupportedFeatures} * @memberof EngineManifest */ - supportedFeatures: SupportedFeatures | null; + supportedFeatures: SupportedFeatures; } export function EngineManifestFromJSON(json: any): EngineManifest { @@ -134,8 +122,6 @@ export function EngineManifestFromJSONTyped(json: any, ignoreDiscriminator: bool 'termsOfService': json['terms_of_service'], 'updateInfos': ((json['update_infos'] as Array).map(UpdateInfoFromJSON)), 'dependencyLicenses': ((json['dependency_licenses'] as Array).map(LicenseInfoFromJSON)), - 'downloadableLibrariesPath': !exists(json, 'downloadable_libraries_path') ? undefined : json['downloadable_libraries_path'], - 'downloadableLibrariesUrl': !exists(json, 'downloadable_libraries_url') ? undefined : json['downloadable_libraries_url'], 'supportedFeatures': SupportedFeaturesFromJSON(json['supported_features']), }; } @@ -159,9 +145,8 @@ export function EngineManifestToJSON(value?: EngineManifest | null): any { 'terms_of_service': value.termsOfService, 'update_infos': ((value.updateInfos as Array).map(UpdateInfoToJSON)), 'dependency_licenses': ((value.dependencyLicenses as Array).map(LicenseInfoToJSON)), - 'downloadable_libraries_path': value.downloadableLibrariesPath, - 'downloadable_libraries_url': value.downloadableLibrariesUrl, 'supported_features': SupportedFeaturesToJSON(value.supportedFeatures), }; } + diff --git a/src/openapi/models/HTTPValidationError.ts b/src/openapi/models/HTTPValidationError.ts index 9380b54ffe..1507f3bade 100644 --- a/src/openapi/models/HTTPValidationError.ts +++ b/src/openapi/models/HTTPValidationError.ts @@ -4,7 +4,7 @@ * VOICEVOX Engine * VOICEVOXの音声合成エンジンです。 * - * The version of the OpenAPI document: 0.14.0-preview.12 + * The version of the OpenAPI document: latest * * * NOTE: This class is auto generated by OpenAPI Generator (https://openapi-generator.tech). @@ -61,3 +61,4 @@ export function HTTPValidationErrorToJSON(value?: HTTPValidationError | null): a }; } + diff --git a/src/openapi/models/LibrarySpeaker.ts b/src/openapi/models/LibrarySpeaker.ts new file mode 100644 index 0000000000..d42d6a36aa --- /dev/null +++ b/src/openapi/models/LibrarySpeaker.ts @@ -0,0 +1,76 @@ +/* tslint:disable */ +/* eslint-disable */ +/** + * VOICEVOX Engine + * VOICEVOXの音声合成エンジンです。 + * + * The version of the OpenAPI document: latest + * + * + * NOTE: This class is auto generated by OpenAPI Generator (https://openapi-generator.tech). + * https://openapi-generator.tech + * Do not edit the class manually. + */ + +import { exists, mapValues } from '../runtime'; +import { + Speaker, + SpeakerFromJSON, + SpeakerFromJSONTyped, + SpeakerToJSON, + SpeakerInfo, + SpeakerInfoFromJSON, + SpeakerInfoFromJSONTyped, + SpeakerInfoToJSON, +} from './'; + +/** + * 音声ライブラリに含まれる話者の情報 + * @export + * @interface LibrarySpeaker + */ +export interface LibrarySpeaker { + /** + * + * @type {Speaker} + * @memberof LibrarySpeaker + */ + speaker: Speaker; + /** + * + * @type {SpeakerInfo} + * @memberof LibrarySpeaker + */ + speakerInfo: SpeakerInfo; +} + +export function LibrarySpeakerFromJSON(json: any): LibrarySpeaker { + return LibrarySpeakerFromJSONTyped(json, false); +} + +export function LibrarySpeakerFromJSONTyped(json: any, ignoreDiscriminator: boolean): LibrarySpeaker { + if ((json === undefined) || (json === null)) { + return json; + } + return { + + 'speaker': SpeakerFromJSON(json['speaker']), + 'speakerInfo': SpeakerInfoFromJSON(json['speaker_info']), + }; +} + +export function LibrarySpeakerToJSON(value?: LibrarySpeaker | null): any { + if (value === undefined) { + return undefined; + } + if (value === null) { + return null; + } + return { + + 'speaker': SpeakerToJSON(value.speaker), + 'speaker_info': SpeakerInfoToJSON(value.speakerInfo), + }; +} + + diff --git a/src/openapi/models/LicenseInfo.ts b/src/openapi/models/LicenseInfo.ts index 22fbb92f97..78e732af21 100644 --- a/src/openapi/models/LicenseInfo.ts +++ b/src/openapi/models/LicenseInfo.ts @@ -4,7 +4,7 @@ * VOICEVOX Engine * VOICEVOXの音声合成エンジンです。 * - * The version of the OpenAPI document: 0.14.0-preview.12 + * The version of the OpenAPI document: latest * * * NOTE: This class is auto generated by OpenAPI Generator (https://openapi-generator.tech). @@ -78,3 +78,4 @@ export function LicenseInfoToJSON(value?: LicenseInfo | null): any { }; } + diff --git a/src/openapi/models/Mora.ts b/src/openapi/models/Mora.ts index e12dbdd6ab..3e3821a836 100644 --- a/src/openapi/models/Mora.ts +++ b/src/openapi/models/Mora.ts @@ -4,7 +4,7 @@ * VOICEVOX Engine * VOICEVOXの音声合成エンジンです。 * - * The version of the OpenAPI document: 0.14.0-preview.12 + * The version of the OpenAPI document: latest * * * NOTE: This class is auto generated by OpenAPI Generator (https://openapi-generator.tech). @@ -94,3 +94,4 @@ export function MoraToJSON(value?: Mora | null): any { }; } + diff --git a/src/openapi/models/MorphableTargetInfo.ts b/src/openapi/models/MorphableTargetInfo.ts index 3783a267df..e70a573fda 100644 --- a/src/openapi/models/MorphableTargetInfo.ts +++ b/src/openapi/models/MorphableTargetInfo.ts @@ -4,7 +4,7 @@ * VOICEVOX Engine * VOICEVOXの音声合成エンジンです。 * - * The version of the OpenAPI document: 0.14.0-preview.12 + * The version of the OpenAPI document: latest * * * NOTE: This class is auto generated by OpenAPI Generator (https://openapi-generator.tech). @@ -54,3 +54,4 @@ export function MorphableTargetInfoToJSON(value?: MorphableTargetInfo | null): a }; } + diff --git a/src/openapi/models/ParseKanaBadRequest.ts b/src/openapi/models/ParseKanaBadRequest.ts index 0a5d68beed..c115cd14ba 100644 --- a/src/openapi/models/ParseKanaBadRequest.ts +++ b/src/openapi/models/ParseKanaBadRequest.ts @@ -4,7 +4,7 @@ * VOICEVOX Engine * VOICEVOXの音声合成エンジンです。 * - * The version of the OpenAPI document: 0.14.0-preview.12 + * The version of the OpenAPI document: latest * * * NOTE: This class is auto generated by OpenAPI Generator (https://openapi-generator.tech). @@ -27,14 +27,14 @@ export interface ParseKanaBadRequest { text: string; /** * |name|description| -|---|---| -| UNKNOWN_TEXT | 判別できない読み仮名があります: {text} | -| ACCENT_TOP | 句頭にアクセントは置けません: {text} | -| ACCENT_TWICE | 1つのアクセント句に二つ以上のアクセントは置けません: {text} | -| ACCENT_NOTFOUND | アクセントを指定していないアクセント句があります: {text} | -| EMPTY_PHRASE | {position}番目のアクセント句が空白です | -| INTERROGATION_MARK_NOT_AT_END | アクセント句末以外に「?」は置けません: {text} | -| INFINITE_LOOP | 処理時に無限ループになってしまいました...バグ報告をお願いします。 | + * |---|---| + * | UNKNOWN_TEXT | 判別できない読み仮名があります: {text} | + * | ACCENT_TOP | 句頭にアクセントは置けません: {text} | + * | ACCENT_TWICE | 1つのアクセント句に二つ以上のアクセントは置けません: {text} | + * | ACCENT_NOTFOUND | アクセントを指定していないアクセント句があります: {text} | + * | EMPTY_PHRASE | {position}番目のアクセント句が空白です | + * | INTERROGATION_MARK_NOT_AT_END | アクセント句末以外に「?」は置けません: {text} | + * | INFINITE_LOOP | 処理時に無限ループになってしまいました...バグ報告をお願いします。 | * @type {string} * @memberof ParseKanaBadRequest */ @@ -78,3 +78,4 @@ export function ParseKanaBadRequestToJSON(value?: ParseKanaBadRequest | null): a }; } + diff --git a/src/openapi/models/Preset.ts b/src/openapi/models/Preset.ts index 55691e2520..55ee86a7bb 100644 --- a/src/openapi/models/Preset.ts +++ b/src/openapi/models/Preset.ts @@ -4,7 +4,7 @@ * VOICEVOX Engine * VOICEVOXの音声合成エンジンです。 * - * The version of the OpenAPI document: 0.14.0-preview.12 + * The version of the OpenAPI document: latest * * * NOTE: This class is auto generated by OpenAPI Generator (https://openapi-generator.tech). @@ -126,3 +126,4 @@ export function PresetToJSON(value?: Preset | null): any { }; } + diff --git a/src/openapi/models/Speaker.ts b/src/openapi/models/Speaker.ts index 2a3d37b096..83cdefc077 100644 --- a/src/openapi/models/Speaker.ts +++ b/src/openapi/models/Speaker.ts @@ -4,7 +4,7 @@ * VOICEVOX Engine * VOICEVOXの音声合成エンジンです。 * - * The version of the OpenAPI document: 0.14.0-preview.12 + * The version of the OpenAPI document: latest * * * NOTE: This class is auto generated by OpenAPI Generator (https://openapi-generator.tech). @@ -35,7 +35,7 @@ export interface Speaker { * @type {SpeakerSupportedFeatures} * @memberof Speaker */ - supportedFeatures?: SpeakerSupportedFeatures | null; + supportedFeatures?: SpeakerSupportedFeatures; /** * * @type {string} @@ -97,3 +97,4 @@ export function SpeakerToJSON(value?: Speaker | null): any { }; } + diff --git a/src/openapi/models/SpeakerInfo.ts b/src/openapi/models/SpeakerInfo.ts index a89d24312d..ce9a558b72 100644 --- a/src/openapi/models/SpeakerInfo.ts +++ b/src/openapi/models/SpeakerInfo.ts @@ -4,7 +4,7 @@ * VOICEVOX Engine * VOICEVOXの音声合成エンジンです。 * - * The version of the OpenAPI document: 0.14.0-preview.12 + * The version of the OpenAPI document: latest * * * NOTE: This class is auto generated by OpenAPI Generator (https://openapi-generator.tech). @@ -77,3 +77,4 @@ export function SpeakerInfoToJSON(value?: SpeakerInfo | null): any { }; } + diff --git a/src/openapi/models/SpeakerStyle.ts b/src/openapi/models/SpeakerStyle.ts index 5cae0e3589..ce995c50e7 100644 --- a/src/openapi/models/SpeakerStyle.ts +++ b/src/openapi/models/SpeakerStyle.ts @@ -4,7 +4,7 @@ * VOICEVOX Engine * VOICEVOXの音声合成エンジンです。 * - * The version of the OpenAPI document: 0.14.0-preview.12 + * The version of the OpenAPI document: latest * * * NOTE: This class is auto generated by OpenAPI Generator (https://openapi-generator.tech). @@ -62,3 +62,4 @@ export function SpeakerStyleToJSON(value?: SpeakerStyle | null): any { }; } + diff --git a/src/openapi/models/SpeakerSupportPermittedSynthesisMorphing.ts b/src/openapi/models/SpeakerSupportPermittedSynthesisMorphing.ts index ce3db35511..b1e4e41104 100644 --- a/src/openapi/models/SpeakerSupportPermittedSynthesisMorphing.ts +++ b/src/openapi/models/SpeakerSupportPermittedSynthesisMorphing.ts @@ -4,7 +4,7 @@ * VOICEVOX Engine * VOICEVOXの音声合成エンジンです。 * - * The version of the OpenAPI document: 0.14.0-preview.12 + * The version of the OpenAPI document: latest * * * NOTE: This class is auto generated by OpenAPI Generator (https://openapi-generator.tech). diff --git a/src/openapi/models/SpeakerSupportedFeatures.ts b/src/openapi/models/SpeakerSupportedFeatures.ts index 215e56fcf7..ecb14107b5 100644 --- a/src/openapi/models/SpeakerSupportedFeatures.ts +++ b/src/openapi/models/SpeakerSupportedFeatures.ts @@ -4,7 +4,7 @@ * VOICEVOX Engine * VOICEVOXの音声合成エンジンです。 * - * The version of the OpenAPI document: 0.14.0-preview.12 + * The version of the OpenAPI document: latest * * * NOTE: This class is auto generated by OpenAPI Generator (https://openapi-generator.tech). @@ -31,7 +31,7 @@ export interface SpeakerSupportedFeatures { * @type {SpeakerSupportPermittedSynthesisMorphing} * @memberof SpeakerSupportedFeatures */ - permittedSynthesisMorphing?: SpeakerSupportPermittedSynthesisMorphing | null; + permittedSynthesisMorphing?: SpeakerSupportPermittedSynthesisMorphing; } export function SpeakerSupportedFeaturesFromJSON(json: any): SpeakerSupportedFeatures { @@ -61,3 +61,4 @@ export function SpeakerSupportedFeaturesToJSON(value?: SpeakerSupportedFeatures }; } + diff --git a/src/openapi/models/StyleInfo.ts b/src/openapi/models/StyleInfo.ts index 35bdd859d3..df6f6795c7 100644 --- a/src/openapi/models/StyleInfo.ts +++ b/src/openapi/models/StyleInfo.ts @@ -4,7 +4,7 @@ * VOICEVOX Engine * VOICEVOXの音声合成エンジンです。 * - * The version of the OpenAPI document: 0.14.0-preview.12 + * The version of the OpenAPI document: latest * * * NOTE: This class is auto generated by OpenAPI Generator (https://openapi-generator.tech). @@ -78,3 +78,4 @@ export function StyleInfoToJSON(value?: StyleInfo | null): any { }; } + diff --git a/src/openapi/models/SupportedDevicesInfo.ts b/src/openapi/models/SupportedDevicesInfo.ts index 437841e0f5..5fdaf0d4a7 100644 --- a/src/openapi/models/SupportedDevicesInfo.ts +++ b/src/openapi/models/SupportedDevicesInfo.ts @@ -4,7 +4,7 @@ * VOICEVOX Engine * VOICEVOXの音声合成エンジンです。 * - * The version of the OpenAPI document: 0.14.0-preview.12 + * The version of the OpenAPI document: latest * * * NOTE: This class is auto generated by OpenAPI Generator (https://openapi-generator.tech). @@ -70,3 +70,4 @@ export function SupportedDevicesInfoToJSON(value?: SupportedDevicesInfo | null): }; } + diff --git a/src/openapi/models/SupportedFeatures.ts b/src/openapi/models/SupportedFeatures.ts index bed0ca38bf..56e2a76217 100644 --- a/src/openapi/models/SupportedFeatures.ts +++ b/src/openapi/models/SupportedFeatures.ts @@ -4,7 +4,7 @@ * VOICEVOX Engine * VOICEVOXの音声合成エンジンです。 * - * The version of the OpenAPI document: 0.14.0-preview.12 + * The version of the OpenAPI document: latest * * * NOTE: This class is auto generated by OpenAPI Generator (https://openapi-generator.tech). @@ -67,6 +67,12 @@ export interface SupportedFeatures { * @memberof SupportedFeatures */ synthesisMorphing: boolean; + /** + * + * @type {boolean} + * @memberof SupportedFeatures + */ + manageLibrary: boolean; } export function SupportedFeaturesFromJSON(json: any): SupportedFeatures { @@ -87,6 +93,7 @@ export function SupportedFeaturesFromJSONTyped(json: any, ignoreDiscriminator: b 'adjustVolumeScale': json['adjust_volume_scale'], 'interrogativeUpspeak': json['interrogative_upspeak'], 'synthesisMorphing': json['synthesis_morphing'], + 'manageLibrary': json['manage_library'], }; } @@ -107,6 +114,8 @@ export function SupportedFeaturesToJSON(value?: SupportedFeatures | null): any { 'adjust_volume_scale': value.adjustVolumeScale, 'interrogative_upspeak': value.interrogativeUpspeak, 'synthesis_morphing': value.synthesisMorphing, + 'manage_library': value.manageLibrary, }; } + diff --git a/src/openapi/models/UpdateInfo.ts b/src/openapi/models/UpdateInfo.ts index c48f44d6be..615c2c6975 100644 --- a/src/openapi/models/UpdateInfo.ts +++ b/src/openapi/models/UpdateInfo.ts @@ -4,7 +4,7 @@ * VOICEVOX Engine * VOICEVOXの音声合成エンジンです。 * - * The version of the OpenAPI document: 0.14.0-preview.12 + * The version of the OpenAPI document: latest * * * NOTE: This class is auto generated by OpenAPI Generator (https://openapi-generator.tech). @@ -70,3 +70,4 @@ export function UpdateInfoToJSON(value?: UpdateInfo | null): any { }; } + diff --git a/src/openapi/models/UserDictWord.ts b/src/openapi/models/UserDictWord.ts index 392993b073..fa0c943d57 100644 --- a/src/openapi/models/UserDictWord.ts +++ b/src/openapi/models/UserDictWord.ts @@ -4,7 +4,7 @@ * VOICEVOX Engine * VOICEVOXの音声合成エンジンです。 * - * The version of the OpenAPI document: 0.14.0-preview.12 + * The version of the OpenAPI document: latest * * * NOTE: This class is auto generated by OpenAPI Generator (https://openapi-generator.tech). @@ -166,3 +166,4 @@ export function UserDictWordToJSON(value?: UserDictWord | null): any { }; } + diff --git a/src/openapi/models/ValidationError.ts b/src/openapi/models/ValidationError.ts index ffce319392..39c7534eee 100644 --- a/src/openapi/models/ValidationError.ts +++ b/src/openapi/models/ValidationError.ts @@ -4,7 +4,7 @@ * VOICEVOX Engine * VOICEVOXの音声合成エンジンです。 * - * The version of the OpenAPI document: 0.14.0-preview.12 + * The version of the OpenAPI document: latest * * * NOTE: This class is auto generated by OpenAPI Generator (https://openapi-generator.tech). @@ -21,10 +21,10 @@ import { exists, mapValues } from '../runtime'; export interface ValidationError { /** * - * @type {Array} + * @type {Array} * @memberof ValidationError */ - loc: Array; + loc: Array; /** * * @type {string} @@ -49,7 +49,7 @@ export function ValidationErrorFromJSONTyped(json: any, ignoreDiscriminator: boo } return { - 'loc': json['loc'], + 'loc': ((json['loc'] as Array).map(string | numberFromJSON)), 'msg': json['msg'], 'type': json['type'], }; @@ -64,9 +64,10 @@ export function ValidationErrorToJSON(value?: ValidationError | null): any { } return { - 'loc': value.loc, + 'loc': ((value.loc as Array).map(string | numberToJSON)), 'msg': value.msg, 'type': value.type, }; } + diff --git a/src/openapi/models/WordTypes.ts b/src/openapi/models/WordTypes.ts index 58b6486993..f9cb1bd4e9 100644 --- a/src/openapi/models/WordTypes.ts +++ b/src/openapi/models/WordTypes.ts @@ -4,7 +4,7 @@ * VOICEVOX Engine * VOICEVOXの音声合成エンジンです。 * - * The version of the OpenAPI document: 0.14.0-preview.12 + * The version of the OpenAPI document: latest * * * NOTE: This class is auto generated by OpenAPI Generator (https://openapi-generator.tech). @@ -13,9 +13,7 @@ */ /** - * - fastapiでword_type引数を検証する時に使用するクラス - + * fastapiでword_type引数を検証する時に使用するクラス * @export * @enum {string} */ diff --git a/src/openapi/models/index.ts b/src/openapi/models/index.ts index 752ae47a1f..6c8de13996 100644 --- a/src/openapi/models/index.ts +++ b/src/openapi/models/index.ts @@ -5,6 +5,7 @@ export * from './AudioQuery'; export * from './DownloadableLibrary'; export * from './EngineManifest'; export * from './HTTPValidationError'; +export * from './LibrarySpeaker'; export * from './LicenseInfo'; export * from './Mora'; export * from './MorphableTargetInfo'; diff --git a/src/openapi/runtime.ts b/src/openapi/runtime.ts index f933fc4338..0399890194 100644 --- a/src/openapi/runtime.ts +++ b/src/openapi/runtime.ts @@ -4,7 +4,7 @@ * VOICEVOX Engine * VOICEVOXの音声合成エンジンです。 * - * The version of the OpenAPI document: 0.14.0-preview.12 + * The version of the OpenAPI document: latest * * * NOTE: This class is auto generated by OpenAPI Generator (https://openapi-generator.tech). @@ -148,7 +148,7 @@ export class Configuration { return this.configuration.basePath != null ? this.configuration.basePath : BASE_PATH; } - get fetchApi(): FetchAPI | undefined { + get fetchApi(): FetchAPI { return this.configuration.fetchApi; } diff --git a/src/plugins/ipcMessageReceiverPlugin.ts b/src/plugins/ipcMessageReceiverPlugin.ts index c21788d017..4af1e8996b 100644 --- a/src/plugins/ipcMessageReceiverPlugin.ts +++ b/src/plugins/ipcMessageReceiverPlugin.ts @@ -56,5 +56,15 @@ export const ipcMessageReceiver: Plugin = { 300 ) ); + + window.electron.onReceivedIPCMsg( + "UPDATE_LIBRARY_INSTALL_STATUS", + (_, { libraryInstallId, status }) => { + options.store.dispatch("UPDATE_LIBRARY_INSTALL_STATUS", { + libraryInstallId, + status, + }); + } + ); }, }; diff --git a/src/store/engine.ts b/src/store/engine.ts index 357a7375bd..937e71dbd3 100644 --- a/src/store/engine.ts +++ b/src/store/engine.ts @@ -1,3 +1,4 @@ +import { toRaw } from "vue"; import { EngineState, EngineStoreState, EngineStoreTypes } from "./type"; import { createUILockAction } from "./ui"; import { createPartialStore } from "./vuex"; @@ -7,6 +8,7 @@ import type { EngineId, EngineInfo } from "@/type/preload"; export const engineStoreState: EngineStoreState = { engineStates: {}, engineSupportedDevices: {}, + libraryInstallStatuses: {}, }; export const engineStore = createPartialStore({ @@ -405,4 +407,27 @@ export const engineStore = createPartialStore({ return supportedDevices?.cuda || supportedDevices?.dml; }, }, + + START_LIBRARY_INSTALL: { + action: async (_, { engineId, library }) => { + return await window.electron.startLibraryInstall({ + engineId, + library: toRaw(library), + }); + }, + }, + + UPDATE_LIBRARY_INSTALL_STATUS: { + action: async ({ commit }, { libraryInstallId, status }) => { + commit("SET_LIBRARY_INSTALL_STATUS", { libraryInstallId, status }); + }, + }, + SET_LIBRARY_INSTALL_STATUS: { + mutation: async (state, { libraryInstallId, status }) => { + state.libraryInstallStatuses = { + ...state.libraryInstallStatuses, + [libraryInstallId]: status, + }; + }, + }, }); diff --git a/src/store/type.ts b/src/store/type.ts index 51df5d9538..b2b044b037 100644 --- a/src/store/type.ts +++ b/src/store/type.ts @@ -16,6 +16,7 @@ import { SupportedDevicesInfo, UserDictWord, MorphableTargetInfo, + DownloadableLibrary, } from "@/openapi"; import { CharacterInfo, @@ -50,6 +51,8 @@ import { StyleId, AudioKey, PresetKey, + LibraryInstallStatus, + LibraryInstallId, } from "@/type/preload"; import { IEngineConnectorFactory } from "@/infrastructures/EngineConnector"; @@ -726,6 +729,7 @@ export type CommandStoreTypes = { export type EngineStoreState = { engineStates: Record; engineSupportedDevices: Record; + libraryInstallStatuses: Record; }; export type EngineStoreTypes = { @@ -834,6 +838,26 @@ export type EngineStoreTypes = { ENGINE_CAN_USE_GPU: { getter: (engineId: EngineId) => boolean; }; + + START_LIBRARY_INSTALL: { + action(payload: { + engineId: EngineId; + library: DownloadableLibrary; + }): Promise; + }; + + UPDATE_LIBRARY_INSTALL_STATUS: { + action(payload: { + libraryInstallId: LibraryInstallId; + status: LibraryInstallStatus; + }): void; + }; + SET_LIBRARY_INSTALL_STATUS: { + mutation: { + libraryInstallId: LibraryInstallId; + status: LibraryInstallStatus; + }; + }; }; /* @@ -1109,6 +1133,7 @@ export type UiStoreState = { isAcceptTermsDialogOpen: boolean; isDictionaryManageDialogOpen: boolean; isEngineManageDialogOpen: boolean; + isLibraryDownloadDialogOpen: boolean; isMaximized: boolean; isPinned: boolean; isFullscreen: boolean; @@ -1168,6 +1193,7 @@ export type UiStoreTypes = { isToolbarSettingDialogOpen?: boolean; isCharacterOrderDialogOpen?: boolean; isEngineManageDialogOpen?: boolean; + isLibraryDownloadDialogOpen?: boolean; }; action(payload: { isDefaultStyleSelectDialogOpen?: boolean; @@ -1180,6 +1206,7 @@ export type UiStoreTypes = { isToolbarSettingDialogOpen?: boolean; isCharacterOrderDialogOpen?: boolean; isEngineManageDialogOpen?: boolean; + isLibraryDownloadDialogOpen?: boolean; }): void; }; diff --git a/src/store/ui.ts b/src/store/ui.ts index 38908d18b9..38ede47bfc 100644 --- a/src/store/ui.ts +++ b/src/store/ui.ts @@ -48,6 +48,7 @@ export const uiStoreState: UiStoreState = { isAcceptTermsDialogOpen: false, isDictionaryManageDialogOpen: false, isEngineManageDialogOpen: false, + isLibraryDownloadDialogOpen: false, isMaximized: false, isPinned: false, isFullscreen: false, @@ -144,6 +145,7 @@ export const uiStore = createPartialStore({ isToolbarSettingDialogOpen?: boolean; isCharacterOrderDialogOpen?: boolean; isEngineManageDialogOpen?: boolean; + isLibraryDownloadDialogOpen?: boolean; } ) { for (const [key, value] of Object.entries(dialogState)) { diff --git a/src/type/ipc.ts b/src/type/ipc.ts index df7b78b8ce..2c11a7059e 100644 --- a/src/type/ipc.ts +++ b/src/type/ipc.ts @@ -1,3 +1,4 @@ +import { DownloadableLibrary } from "@/openapi"; import { AppInfos, ElectronStoreType, @@ -12,6 +13,8 @@ import { EngineSetting, EngineId, MessageBoxReturnValue, + LibraryInstallStatus, + LibraryInstallId, } from "@/type/preload"; /** @@ -305,6 +308,11 @@ export type IpcIHData = { args: [obj: { filePath: string }]; return: ArrayBuffer; }; + + START_LIBRARY_INSTALL: { + args: [obj: { library: DownloadableLibrary; engineId: EngineId }]; + return: LibraryInstallId; + }; }; /** @@ -360,4 +368,11 @@ export type IpcSOData = { args: [obj: { width: number; height: number }]; return: void; }; + + UPDATE_LIBRARY_INSTALL_STATUS: { + args: [ + obj: { status: LibraryInstallStatus; libraryInstallId: LibraryInstallId } + ]; + return: void; + }; }; diff --git a/src/type/preload.ts b/src/type/preload.ts index 71e51e7b14..99adc80db4 100644 --- a/src/type/preload.ts +++ b/src/type/preload.ts @@ -1,16 +1,17 @@ import { z } from "zod"; import { IpcSOData } from "./ipc"; +import { DownloadableLibrary } from "@/openapi"; export const isMac = typeof process === "undefined" ? navigator.userAgent.includes("Mac") : process.platform === "darwin"; -export const engineIdSchema = z.string().uuid().brand<"EngineId">(); +export const engineIdSchema = z.string().brand<"EngineId">(); export type EngineId = z.infer; export const EngineId = (id: string): EngineId => engineIdSchema.parse(id); -export const speakerIdSchema = z.string().uuid().brand<"SpeakerId">(); +export const speakerIdSchema = z.string().brand<"SpeakerId">(); export type SpeakerId = z.infer; export const SpeakerId = (id: string): SpeakerId => speakerIdSchema.parse(id); @@ -18,11 +19,23 @@ export const styleIdSchema = z.number().brand<"StyleId">(); export type StyleId = z.infer; export const StyleId = (id: number): StyleId => styleIdSchema.parse(id); -export const audioKeySchema = z.string().uuid().brand<"AudioKey">(); +export const audioKeySchema = z.string().brand<"AudioKey">(); export type AudioKey = z.infer; export const AudioKey = (id: string): AudioKey => audioKeySchema.parse(id); -export const presetKeySchema = z.string().uuid().brand<"PresetKey">(); +export const libraryIdSchema = z.string().brand<"LibraryId">(); +export type LibraryId = z.infer; +export const LibraryId = (id: string): LibraryId => libraryIdSchema.parse(id); + +export const libraryInstallIdSchema = z + .string() + .uuid() + .brand<"LibraryInstallId">(); +export type LibraryInstallId = z.infer; +export const LibraryInstallId = (id: string): LibraryInstallId => + libraryInstallIdSchema.parse(id); + +export const presetKeySchema = z.string().brand<"PresetKey">(); export type PresetKey = z.infer; export const PresetKey = (id: string): PresetKey => presetKeySchema.parse(id); @@ -220,6 +233,10 @@ export interface Sandbox { uninstallVvppEngine(engineId: EngineId): Promise; validateEngineDir(engineDir: string): Promise; restartApp(obj: { isMultiEngineOffMode: boolean }): void; + startLibraryInstall(obj: { + engineId: EngineId; + library: DownloadableLibrary; + }): Promise; } export type AppInfos = { @@ -630,3 +647,22 @@ export interface MessageBoxReturnValue { } export const SandboxKey = "electron" as const; +export type LibraryInstallStatus = + | { + status: "pending"; + } + | { + status: "downloading"; + contentLength: number; + downloaded: number; + } + | { + status: "installing"; + } + | { + status: "done"; + } + | { + status: "error"; + message: string; + }; diff --git a/src/views/EditorHome.vue b/src/views/EditorHome.vue index 233a8e6138..84f3e7f6be 100644 --- a/src/views/EditorHome.vue +++ b/src/views/EditorHome.vue @@ -158,6 +158,7 @@ /> + @@ -188,6 +189,8 @@ import AcceptTermsDialog from "@/components/AcceptTermsDialog.vue"; import DictionaryManageDialog from "@/components/DictionaryManageDialog.vue"; import EngineManageDialog from "@/components/EngineManageDialog.vue"; import ProgressDialog from "@/components/ProgressDialog.vue"; +import LibraryDownloadDialog from "@/components/LibraryDownloadDialog.vue"; + import { AudioItem, EngineState } from "@/store/type"; import { AudioKey, @@ -677,6 +680,15 @@ const isDictionaryManageDialogOpenComputed = computed({ }), }); +// 音声ライブラリのダウンロード +const isLibraryDownloadDialogOpenComputed = computed({ + get: () => store.state.isLibraryDownloadDialogOpen, + set: (val) => + store.dispatch("SET_DIALOG_OPEN", { + isLibraryDownloadDialogOpen: val, + }), +}); + const isAcceptRetrieveTelemetryDialogOpenComputed = computed({ get: () => !store.state.isAcceptTermsDialogOpen && diff --git a/tests/unit/store/Vuex.spec.ts b/tests/unit/store/Vuex.spec.ts index bbd54c9333..4ce545b6bf 100644 --- a/tests/unit/store/Vuex.spec.ts +++ b/tests/unit/store/Vuex.spec.ts @@ -50,9 +50,11 @@ describe("store/vuex.js test", () => { isEngineManageDialogOpen: false, isAcceptRetrieveTelemetryDialogOpen: false, isAcceptTermsDialogOpen: false, + isLibraryDownloadDialogOpen: false, isMaximized: false, isMultiEngineOffMode: false, savedLastCommandUnixMillisec: null, + libraryInstallStatuses: {}, savingSetting: { fileEncoding: "UTF-8", fileNamePattern: "", @@ -117,6 +119,7 @@ describe("store/vuex.js test", () => { adjustVolumeScale: true, interrogativeUpspeak: true, synthesisMorphing: true, + manageLibrary: true, }, }, },