cmdbox 0.6.3.2__py3-none-any.whl → 0.6.4.1__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Potentially problematic release.
This version of cmdbox might be problematic. Click here for more details.
- cmdbox/app/app.py +22 -7
- cmdbox/app/common.py +9 -6
- cmdbox/app/commons/loghandler.py +101 -20
- cmdbox/app/commons/redis_client.py +1 -1
- cmdbox/app/edge.py +2 -4
- cmdbox/app/feature.py +1 -1
- cmdbox/app/features/cli/cmdbox_agent_mcp_client.py +175 -0
- cmdbox/app/features/cli/cmdbox_agent_mcp_proxy.py +96 -0
- cmdbox/app/features/cli/cmdbox_audit_createdb.py +224 -224
- cmdbox/app/features/cli/cmdbox_audit_delete.py +4 -4
- cmdbox/app/features/cli/cmdbox_audit_search.py +4 -4
- cmdbox/app/features/cli/cmdbox_audit_write.py +6 -8
- cmdbox/app/features/cli/cmdbox_client_file_copy.py +3 -3
- cmdbox/app/features/cli/cmdbox_client_file_download.py +3 -3
- cmdbox/app/features/cli/cmdbox_client_file_list.py +3 -3
- cmdbox/app/features/cli/cmdbox_client_file_mkdir.py +3 -3
- cmdbox/app/features/cli/cmdbox_client_file_move.py +3 -3
- cmdbox/app/features/cli/cmdbox_client_file_remove.py +3 -3
- cmdbox/app/features/cli/cmdbox_client_file_rmdir.py +3 -3
- cmdbox/app/features/cli/cmdbox_client_file_upload.py +3 -3
- cmdbox/app/features/cli/cmdbox_client_http.py +7 -6
- cmdbox/app/features/cli/cmdbox_client_server_info.py +4 -4
- cmdbox/app/features/cli/cmdbox_cmd_list.py +4 -4
- cmdbox/app/features/cli/cmdbox_cmd_load.py +5 -5
- cmdbox/app/features/cli/cmdbox_edge_config.py +1 -1
- cmdbox/app/features/cli/cmdbox_edge_start.py +3 -3
- cmdbox/app/features/cli/cmdbox_mcp_client.py +174 -174
- cmdbox/app/features/cli/cmdbox_mcp_proxy.py +96 -96
- cmdbox/app/features/cli/cmdbox_server_list.py +3 -3
- cmdbox/app/features/cli/cmdbox_server_start.py +103 -103
- cmdbox/app/features/cli/cmdbox_server_stop.py +6 -6
- cmdbox/app/features/cli/cmdbox_tts_install.py +317 -0
- cmdbox/app/features/cli/cmdbox_tts_say.py +179 -0
- cmdbox/app/features/cli/cmdbox_tts_start.py +329 -0
- cmdbox/app/features/cli/cmdbox_tts_stop.py +108 -0
- cmdbox/app/features/cli/cmdbox_web_apikey_add.py +91 -91
- cmdbox/app/features/cli/cmdbox_web_apikey_del.py +91 -91
- cmdbox/app/features/cli/cmdbox_web_gencert.py +7 -7
- cmdbox/app/features/cli/cmdbox_web_genpass.py +168 -168
- cmdbox/app/features/cli/cmdbox_web_group_add.py +94 -94
- cmdbox/app/features/cli/cmdbox_web_group_del.py +87 -87
- cmdbox/app/features/cli/cmdbox_web_group_edit.py +94 -94
- cmdbox/app/features/cli/cmdbox_web_group_list.py +87 -87
- cmdbox/app/features/cli/cmdbox_web_start.py +236 -235
- cmdbox/app/features/cli/cmdbox_web_stop.py +72 -72
- cmdbox/app/features/cli/cmdbox_web_user_add.py +104 -104
- cmdbox/app/features/cli/cmdbox_web_user_del.py +87 -87
- cmdbox/app/features/cli/cmdbox_web_user_edit.py +104 -104
- cmdbox/app/features/cli/cmdbox_web_user_list.py +87 -87
- cmdbox/app/features/web/cmdbox_web_agent.py +16 -4
- cmdbox/app/features/web/cmdbox_web_get_cmd_choices.py +10 -2
- cmdbox/app/features/web/cmdbox_web_save_cmd.py +1 -0
- cmdbox/app/features/web/cmdbox_web_versions_used.py +4 -0
- cmdbox/app/filer.py +9 -9
- cmdbox/app/mcp.py +19 -8
- cmdbox/app/options.py +52 -47
- cmdbox/app/server.py +224 -224
- cmdbox/app/web.py +39 -17
- cmdbox/extensions/features.yml +7 -1
- cmdbox/extensions/sample_project/sample/app/features/cli/sample_client_time.py +2 -2
- cmdbox/extensions/sample_project/sample/app/features/cli/sample_server_time.py +3 -3
- cmdbox/licenses/LICENSE_APScheduler_3_11_0_MIT_License.txt +19 -0
- cmdbox/licenses/LICENSE_SQLAlchemy_2_0_43_MIT.txt +19 -0
- cmdbox/licenses/LICENSE_Werkzeug_3_1_1_BSD_License.txt +28 -0
- cmdbox/licenses/LICENSE_absolufy-imports_0_3_1_MIT_License.txt +21 -0
- cmdbox/licenses/LICENSE_anyio_4_10_0_UNKNOWN.txt +20 -0
- cmdbox/licenses/{LICENSE_typer_0_16_0_MIT_License.txt → LICENSE_backoff_2_2_1_MIT_License.txt} +1 -1
- cmdbox/licenses/LICENSE_certifi_2025_8_3_Mozilla_Public_License_2_0-MPL_2_0.txt +20 -0
- cmdbox/licenses/LICENSE_charset-normalizer_3_4_3_MIT.txt +21 -0
- cmdbox/licenses/LICENSE_cryptography_45_0_6_Apache-2_0_OR_BSD-3-Clause.txt +3 -0
- cmdbox/licenses/LICENSE_cyclopts_3_22_5_Apache_Software_License.txt +201 -0
- cmdbox/licenses/LICENSE_fastapi-sso_0_18_0_MIT_License.txt +21 -0
- cmdbox/licenses/LICENSE_fastmcp_2_11_3_Apache_Software_License.txt +201 -0
- cmdbox/licenses/LICENSE_google-adk_1_9_0_Apache_Software_License.txt +202 -0
- cmdbox/licenses/LICENSE_google-genai_1_28_0_Apache_Software_License.txt +202 -0
- cmdbox/licenses/LICENSE_google-genai_1_29_0_Apache_Software_License.txt +202 -0
- cmdbox/licenses/LICENSE_greenlet_3_2_4_MIT_AND_Python-2_0.txt +30 -0
- cmdbox/licenses/LICENSE_isodate_0_7_2_BSD_License.txt +26 -0
- cmdbox/licenses/LICENSE_lazy-object-proxy_1_11_0_BSD_License.txt +20 -0
- cmdbox/licenses/LICENSE_litellm-enterprise_0_1_19_UNKNOWN.txt +37 -0
- cmdbox/licenses/LICENSE_litellm_1_75_5_post1_MIT_License.txt +26 -0
- cmdbox/licenses/LICENSE_markdown-it-py_4_0_0_MIT_License.txt +21 -0
- cmdbox/licenses/LICENSE_mcp_1_12_4_MIT_License.txt +21 -0
- cmdbox/licenses/LICENSE_multidict_6_6_4_Apache_License_2_0.txt +13 -0
- cmdbox/licenses/LICENSE_oauthlib_3_3_1_BSD-3-Clause.txt +27 -0
- cmdbox/licenses/LICENSE_openai_1_99_9_Apache_Software_License.txt +201 -0
- cmdbox/licenses/LICENSE_openapi-core_0_19_5_BSD_License.txt +29 -0
- cmdbox/licenses/LICENSE_openapi-schema-validator_0_6_3_BSD_License.txt +29 -0
- cmdbox/licenses/LICENSE_openapi-spec-validator_0_7_2_Apache_Software_License.txt +201 -0
- cmdbox/licenses/LICENSE_opentelemetry-api_1_36_0_UNKNOWN.txt +201 -0
- cmdbox/licenses/LICENSE_opentelemetry-sdk_1_36_0_UNKNOWN.txt +201 -0
- cmdbox/licenses/LICENSE_opentelemetry-semantic-conventions_0_57b0_UNKNOWN.txt +201 -0
- cmdbox/licenses/LICENSE_orjson_3_11_1_Apache_Software_License-MIT_License.txt +201 -0
- cmdbox/licenses/LICENSE_parse_1_20_2_MIT_License.txt +19 -0
- cmdbox/licenses/LICENSE_pathable_0_4_4_Apache_Software_License.txt +201 -0
- cmdbox/licenses/{LICENSE_pillow_11_2_1_UNKNOWN.txt → LICENSE_pillow_11_3_0_UNKNOWN.txt} +393 -3
- cmdbox/licenses/LICENSE_pyperclip_1_9_0_BSD_License.txt +27 -0
- cmdbox/licenses/LICENSE_redis_6_4_0_MIT_License.txt +21 -0
- cmdbox/licenses/LICENSE_rfc3339-validator_0_1_4_MIT_License.txt +22 -0
- cmdbox/licenses/LICENSE_rich-rst_1_3_1_MIT_License.txt +7 -0
- cmdbox/licenses/LICENSE_rpds-py_0_27_0_UNKNOWN.txt +19 -0
- cmdbox/licenses/{LICENSE_setuptools_65_5_0_MIT_License.txt → LICENSE_setuptools_80_9_0_UNKNOWN.txt} +0 -2
- cmdbox/licenses/LICENSE_sphinx-intl_2_3_2_UNKNOWN.txt +25 -0
- cmdbox/licenses/LICENSE_tenacity_9_1_2_Apache_Software_License.txt +202 -0
- cmdbox/licenses/LICENSE_tiktoken_0_11_0_MIT_License-Copyright-c-2022_OpenAI-Shantanu_Jain-Permission_is_hereby_granted-free_of_charge-to_any_per.txt +21 -0
- cmdbox/licenses/LICENSE_tokenizers_0_21_4_Apache_Software_License.txt +1 -0
- cmdbox/licenses/LICENSE_voicevox_core_0_16_0_MIT.txt +20 -0
- cmdbox/licenses/LICENSE_watchdog_6_0_0_Apache_Software_License.txt +16 -0
- cmdbox/licenses/{LICENSE_httptools_0_6_4_MIT_License.txt → LICENSE_wsproto_1_2_0_MIT_License.txt} +3 -3
- cmdbox/licenses/files.txt +69 -50
- cmdbox/logconf_cmdbox.yml +136 -0
- cmdbox/version.py +2 -2
- cmdbox/web/agent.html +16 -2
- cmdbox/web/assets/cmdbox/agent.js +226 -1
- cmdbox/web/assets/cmdbox/common.js +20 -25
- cmdbox/web/assets/cmdbox/svgicon.js +18 -0
- {cmdbox-0.6.3.2.dist-info → cmdbox-0.6.4.1.dist-info}/METADATA +29 -20
- {cmdbox-0.6.3.2.dist-info → cmdbox-0.6.4.1.dist-info}/RECORD +158 -118
- {cmdbox-0.6.3.2.dist-info → cmdbox-0.6.4.1.dist-info}/WHEEL +1 -1
- cmdbox/config.yml +0 -3
- cmdbox/licenses/LICENSE_shellingham_1_5_4_ISC_License-ISCL.txt +0 -13
- cmdbox/licenses/LICENSE_watchfiles_1_1_0_MIT_License.txt +0 -21
- cmdbox/logconf_audit.yml +0 -43
- cmdbox/logconf_client.yml +0 -43
- cmdbox/logconf_edge.yml +0 -43
- cmdbox/logconf_gui.yml +0 -43
- cmdbox/logconf_mcp.yml +0 -43
- cmdbox/logconf_server.yml +0 -43
- cmdbox/logconf_web.yml +0 -43
- /cmdbox/licenses/{LICENSE_Authlib_1_6_0_BSD_License.txt → LICENSE_Authlib_1_6_1_BSD_License.txt} +0 -0
- /cmdbox/licenses/{LICENSE_SQLAlchemy_2_0_41_MIT.txt → LICENSE_SQLAlchemy_2_0_42_MIT.txt} +0 -0
- /cmdbox/licenses/{LICENSE_aiohttp_3_12_13_Apache-2_0.txt → LICENSE_aiohttp_3_12_15_Apache-2_0_AND_MIT.txt} +0 -0
- /cmdbox/licenses/{LICENSE_aiosignal_1_3_2_Apache_Software_License.txt → LICENSE_aiosignal_1_4_0_Apache_Software_License.txt} +0 -0
- /cmdbox/licenses/{LICENSE_certifi_2025_6_15_Mozilla_Public_License_2_0-MPL_2_0.txt → LICENSE_certifi_2025_7_14_Mozilla_Public_License_2_0-MPL_2_0.txt} +0 -0
- /cmdbox/licenses/{LICENSE_cryptography_45_0_4_Apache-2_0_OR_BSD-3-Clause.txt → LICENSE_cryptography_45_0_5_Apache-2_0_OR_BSD-3-Clause.txt} +0 -0
- /cmdbox/licenses/{LICENSE_docstring_parser_0_16_MIT_License.txt → LICENSE_docstring_parser_0_17_0_MIT_License.txt} +0 -0
- /cmdbox/licenses/{LICENSE_fastapi_0_115_14_MIT_License.txt → LICENSE_fastapi_0_116_1_MIT_License.txt} +0 -0
- /cmdbox/licenses/{LICENSE_fastmcp_2_10_1_Apache_Software_License.txt → LICENSE_fastmcp_2_11_0_Apache_Software_License.txt} +0 -0
- /cmdbox/licenses/{LICENSE_fsspec_2025_5_1_BSD_License.txt → LICENSE_fsspec_2025_7_0_BSD_License.txt} +0 -0
- /cmdbox/licenses/{LICENSE_google-adk_1_5_0_Apache_Software_License.txt → LICENSE_google-adk_1_10_0_Apache_Software_License.txt} +0 -0
- /cmdbox/licenses/{LICENSE_google-api-python-client_2_174_0_Apache_Software_License.txt → LICENSE_google-api-python-client_2_177_0_Apache_Software_License.txt} +0 -0
- /cmdbox/licenses/{LICENSE_huggingface-hub_0_33_1_Apache_Software_License.txt → LICENSE_google-api-python-client_2_178_0_Apache_Software_License.txt} +0 -0
- /cmdbox/licenses/{LICENSE_google-cloud-aiplatform_1_100_0_Apache_2_0.txt → LICENSE_google-cloud-aiplatform_1_106_0_Apache_2_0.txt} +0 -0
- /cmdbox/licenses/{LICENSE_google-cloud-bigquery_3_34_0_Apache_Software_License.txt → LICENSE_google-cloud-aiplatform_1_108_0_Apache_2_0.txt} +0 -0
- /cmdbox/licenses/{LICENSE_google-genai_1_23_0_Apache_Software_License.txt → LICENSE_google-cloud-bigquery_3_35_1_Apache_Software_License.txt} +0 -0
- /cmdbox/licenses/{LICENSE_grpcio-status_1_73_1_Apache_Software_License.txt → LICENSE_grpcio-status_1_74_0_Apache_Software_License.txt} +0 -0
- /cmdbox/licenses/{LICENSE_grpcio_1_73_1_Apache_Software_License.txt → LICENSE_grpcio_1_74_0_Apache_Software_License.txt} +0 -0
- /cmdbox/licenses/{LICENSE_opentelemetry-api_1_34_1_Apache_Software_License.txt → LICENSE_huggingface-hub_0_34_3_Apache_Software_License.txt} +0 -0
- /cmdbox/licenses/{LICENSE_opentelemetry-sdk_1_34_1_Apache_Software_License.txt → LICENSE_huggingface-hub_0_34_4_Apache_Software_License.txt} +0 -0
- /cmdbox/licenses/{LICENSE_opentelemetry-semantic-conventions_0_55b1_Apache_Software_License.txt → LICENSE_jsonschema-path_0_3_4_Apache_Software_License.txt} +0 -0
- /cmdbox/licenses/{LICENSE_jsonschema_4_24_0_UNKNOWN.txt → LICENSE_jsonschema_4_25_0_UNKNOWN.txt} +0 -0
- /cmdbox/licenses/{LICENSE_litellm_1_73_6_MIT_License.txt → LICENSE_litellm_1_74_12_MIT_License.txt} +0 -0
- /cmdbox/licenses/{LICENSE_mcp_1_10_1_MIT_License.txt → LICENSE_mcp_1_12_3_MIT_License.txt} +0 -0
- /cmdbox/licenses/{LICENSE_multidict_6_6_2_Apache_License_2_0.txt → LICENSE_multidict_6_6_3_Apache_License_2_0.txt} +0 -0
- /cmdbox/licenses/{LICENSE_nh3_0_2_21_MIT.txt → LICENSE_nh3_0_3_0_MIT.txt} +0 -0
- /cmdbox/licenses/{LICENSE_numpy_2_3_1_BSD_License.txt → LICENSE_numpy_2_3_2_BSD_License.txt} +0 -0
- /cmdbox/licenses/{LICENSE_openai_1_93_0_Apache_Software_License.txt → LICENSE_openai_1_98_0_Apache_Software_License.txt} +0 -0
- /cmdbox/licenses/{LICENSE_tokenizers_0_21_2_Apache_Software_License.txt → LICENSE_pywin32_311_Python_Software_Foundation_License.txt} +0 -0
- /cmdbox/licenses/{LICENSE_regex_2024_11_6_Apache_Software_License.txt → LICENSE_regex_2025_7_34_UNKNOWN.txt} +0 -0
- /cmdbox/licenses/{LICENSE_rich_14_0_0_MIT_License.txt → LICENSE_rich_14_1_0_MIT_License.txt} +0 -0
- /cmdbox/licenses/{LICENSE_rpds-py_0_25_1_MIT.txt → LICENSE_rpds-py_0_26_0_MIT.txt} +0 -0
- /cmdbox/licenses/{LICENSE_sse-starlette_2_3_6_BSD_License.txt → LICENSE_sse-starlette_3_0_2_UNKNOWN.txt} +0 -0
- /cmdbox/licenses/{LICENSE_starlette_0_46_2_BSD_License.txt → LICENSE_starlette_0_47_2_BSD_License.txt} +0 -0
- /cmdbox/licenses/{LICENSE_typing_extensions_4_14_0_UNKNOWN.txt → LICENSE_typing_extensions_4_14_1_UNKNOWN.txt} +0 -0
- /cmdbox/licenses/{LICENSE_zope_event_5_1_Zope_Public_License.txt → LICENSE_zope_event_5_1_1_Zope_Public_License.txt} +0 -0
- {cmdbox-0.6.3.2.dist-info → cmdbox-0.6.4.1.dist-info}/entry_points.txt +0 -0
- {cmdbox-0.6.3.2.dist-info → cmdbox-0.6.4.1.dist-info/licenses}/LICENSE +0 -0
- {cmdbox-0.6.3.2.dist-info → cmdbox-0.6.4.1.dist-info}/top_level.txt +0 -0
|
@@ -0,0 +1,179 @@
|
|
|
1
|
+
from cmdbox.app import common, client, feature
|
|
2
|
+
from cmdbox.app.commons import convert, redis_client
|
|
3
|
+
from cmdbox.app.features.cli import cmdbox_tts_start
|
|
4
|
+
from cmdbox.app.options import Options
|
|
5
|
+
from pathlib import Path
|
|
6
|
+
from typing import Dict, Any, Tuple, List, Union
|
|
7
|
+
import argparse
|
|
8
|
+
import logging
|
|
9
|
+
import requests
|
|
10
|
+
import subprocess
|
|
11
|
+
import sys
|
|
12
|
+
|
|
13
|
+
|
|
14
|
+
class TtsSay(cmdbox_tts_start.TtsStart):
|
|
15
|
+
|
|
16
|
+
def get_cmd(self):
|
|
17
|
+
"""
|
|
18
|
+
この機能のコマンドを返します
|
|
19
|
+
|
|
20
|
+
Returns:
|
|
21
|
+
str: コマンド
|
|
22
|
+
"""
|
|
23
|
+
return 'say'
|
|
24
|
+
|
|
25
|
+
def get_option(self):
|
|
26
|
+
"""
|
|
27
|
+
この機能のオプションを返します
|
|
28
|
+
|
|
29
|
+
Returns:
|
|
30
|
+
Dict[str, Any]: オプション
|
|
31
|
+
"""
|
|
32
|
+
opt = super().get_option()
|
|
33
|
+
opt['description_ja'] = "Text-to-Speech(TTS)エンジンを使ってテキストを音声に変換します。"
|
|
34
|
+
opt['description_en'] = "Converts text to speech using the Text-to-Speech (TTS) engine."
|
|
35
|
+
opt['choice'] += [
|
|
36
|
+
dict(opt="tts_text", type=Options.T_TEXT, default=None, required=True, multi=False, hide=False, choice=None,
|
|
37
|
+
description_ja="変換するテキストを指定します。",
|
|
38
|
+
description_en="Specifies the text to convert."),
|
|
39
|
+
dict(opt="tts_output", type=Options.T_FILE, default=None, required=False, multi=False, hide=False, choice=None, fileio="out",
|
|
40
|
+
description_ja="変換後の音声ファイルの出力先を指定します。",
|
|
41
|
+
description_en="Specifies the output file for the converted audio."),
|
|
42
|
+
]
|
|
43
|
+
return opt
|
|
44
|
+
|
|
45
|
+
def apprun(self, logger:logging.Logger, args:argparse.Namespace, tm:float, pf:List[Dict[str, float]]=[]) -> Tuple[int, Dict[str, Any], Any]:
|
|
46
|
+
"""
|
|
47
|
+
この機能の実行を行います
|
|
48
|
+
|
|
49
|
+
Args:
|
|
50
|
+
logger (logging.Logger): ロガー
|
|
51
|
+
args (argparse.Namespace): 引数
|
|
52
|
+
tm (float): 実行開始時間
|
|
53
|
+
pf (List[Dict[str, float]]): 呼出元のパフォーマンス情報
|
|
54
|
+
|
|
55
|
+
Returns:
|
|
56
|
+
Tuple[int, Dict[str, Any], Any]: 終了コード, 結果, オブジェクト
|
|
57
|
+
"""
|
|
58
|
+
if args.tts_engine is None:
|
|
59
|
+
msg = dict(warn=f"Please specify the --tts_engine option.")
|
|
60
|
+
common.print_format(msg, False, tm, args.output_json, args.output_json_append, pf=pf)
|
|
61
|
+
return self.RESP_WARN, msg, None
|
|
62
|
+
if args.tts_engine == 'voicevox':
|
|
63
|
+
if args.voicevox_model is None:
|
|
64
|
+
msg = dict(warn=f"Please specify the --voicevox_model option.")
|
|
65
|
+
common.print_format(msg, False, tm, args.output_json, args.output_json_append, pf=pf)
|
|
66
|
+
return self.RESP_WARN, msg, None
|
|
67
|
+
if args.tts_text is None:
|
|
68
|
+
msg = dict(warn=f"Please specify the --tts_text option.")
|
|
69
|
+
common.print_format(msg, False, tm, args.output_json, args.output_json_append, pf=pf)
|
|
70
|
+
return self.RESP_WARN, msg, None
|
|
71
|
+
|
|
72
|
+
tts_engine_b64 = convert.str2b64str(args.tts_engine)
|
|
73
|
+
voicevox_model_b64 = convert.str2b64str(args.voicevox_model) if args.voicevox_model is not None else '-'
|
|
74
|
+
tts_text_b64 = convert.str2b64str(args.tts_text)
|
|
75
|
+
|
|
76
|
+
cl = client.Client(logger, redis_host=args.host, redis_port=args.port, redis_password=args.password, svname=args.svname)
|
|
77
|
+
ret = cl.redis_cli.send_cmd(self.get_svcmd(),
|
|
78
|
+
[tts_engine_b64, voicevox_model_b64, tts_text_b64],
|
|
79
|
+
retry_count=args.retry_count, retry_interval=args.retry_interval, timeout=args.timeout, nowait=False)
|
|
80
|
+
if args.tts_output:
|
|
81
|
+
if 'success' in ret and 'data' in ret['success']:
|
|
82
|
+
wav_b64 = ret['success']['data']
|
|
83
|
+
wav_data = convert.b64str2bytes(wav_b64)
|
|
84
|
+
with open(args.tts_output, 'wb') as f:
|
|
85
|
+
f.write(wav_data)
|
|
86
|
+
del ret['success']['data'] # 音声データは削除
|
|
87
|
+
common.print_format(ret, False, tm, None, False, pf=pf)
|
|
88
|
+
if 'success' not in ret:
|
|
89
|
+
return self.RESP_WARN, ret, cl
|
|
90
|
+
return self.RESP_SUCCESS, ret, cl
|
|
91
|
+
|
|
92
|
+
def get_svcmd(self):
|
|
93
|
+
"""
|
|
94
|
+
この機能のサーバー側のコマンドを返します
|
|
95
|
+
|
|
96
|
+
Returns:
|
|
97
|
+
str: サーバー側のコマンド
|
|
98
|
+
"""
|
|
99
|
+
return 'tts_say'
|
|
100
|
+
|
|
101
|
+
def is_cluster_redirect(self):
|
|
102
|
+
"""
|
|
103
|
+
クラスター宛のメッセージの場合、メッセージを転送するかどうかを返します
|
|
104
|
+
|
|
105
|
+
Returns:
|
|
106
|
+
bool: メッセージを転送する場合はTrue
|
|
107
|
+
"""
|
|
108
|
+
return False
|
|
109
|
+
|
|
110
|
+
def svrun(self, data_dir:Path, logger:logging.Logger, redis_cli:redis_client.RedisClient, msg:List[str],
|
|
111
|
+
sessions:Dict[str, Dict[str, Any]]) -> int:
|
|
112
|
+
"""
|
|
113
|
+
この機能のサーバー側の実行を行います
|
|
114
|
+
|
|
115
|
+
Args:
|
|
116
|
+
data_dir (Path): データディレクトリ
|
|
117
|
+
logger (logging.Logger): ロガー
|
|
118
|
+
redis_cli (redis_client.RedisClient): Redisクライアント
|
|
119
|
+
msg (List[str]): 受信メッセージ
|
|
120
|
+
sessions (Dict[str, Dict[str, Any]]): セッション情報
|
|
121
|
+
|
|
122
|
+
Returns:
|
|
123
|
+
int: 終了コード
|
|
124
|
+
"""
|
|
125
|
+
if logger.level == logging.DEBUG:
|
|
126
|
+
logger.debug(f"audit write svrun msg: {msg}")
|
|
127
|
+
tts_engine = convert.b64str2str(msg[2])
|
|
128
|
+
voicevox_model = convert.b64str2str(msg[3])
|
|
129
|
+
tts_text = convert.b64str2str(msg[4])
|
|
130
|
+
st = self.say(msg[1], tts_engine, voicevox_model, tts_text, data_dir, logger, redis_cli, sessions)
|
|
131
|
+
return st
|
|
132
|
+
|
|
133
|
+
def say(self, reskey:str, tts_engine:str, voicevox_model:str, tts_text:str, data_dir:Path, logger:logging.Logger,
|
|
134
|
+
redis_cli:redis_client.RedisClient, sessions:Dict[str, Dict[str, Any]]) -> int:
|
|
135
|
+
"""
|
|
136
|
+
TTSエンジンを使ってテキストを音声に変換します
|
|
137
|
+
|
|
138
|
+
Args:
|
|
139
|
+
reskey (str): レスポンスキー
|
|
140
|
+
tts_engine (str): TTSエンジン
|
|
141
|
+
voicevox_model (str): VoiceVoxモデル
|
|
142
|
+
tts_text (str): TTSテキスト
|
|
143
|
+
data_dir (Path): データディレクトリ
|
|
144
|
+
logger (logging.Logger): ロガー
|
|
145
|
+
redis_cli (redis_client.RedisClient): Redisクライアント
|
|
146
|
+
sessions (Dict[str, Dict[str, Any]]): セッション情報
|
|
147
|
+
|
|
148
|
+
Returns:
|
|
149
|
+
int: レスポンスコード
|
|
150
|
+
"""
|
|
151
|
+
try:
|
|
152
|
+
if tts_engine == 'voicevox':
|
|
153
|
+
#===============================================================
|
|
154
|
+
# voicevoxモデルを使ってテキストを音声に変換
|
|
155
|
+
style_key = [k for k,v in cmdbox_tts_start.TtsStart.VOICEVOX_STYLE.items() if v['select'] == voicevox_model]
|
|
156
|
+
if not style_key:
|
|
157
|
+
logger.error(f"Invalid voicevox_model specified: {voicevox_model}")
|
|
158
|
+
redis_cli.rpush(reskey, dict(warn=f"Invalid voicevox_model specified: {voicevox_model}"))
|
|
159
|
+
return self.RESP_WARN
|
|
160
|
+
style = cmdbox_tts_start.TtsStart.VOICEVOX_STYLE[style_key[0]]
|
|
161
|
+
model_key = style['model_key']
|
|
162
|
+
if model_key not in sessions:
|
|
163
|
+
logger.warning(f"VoiceVox model is not running: {voicevox_model}")
|
|
164
|
+
redis_cli.rpush(reskey, dict(warn=f"VoiceVox model is not running: {voicevox_model}"))
|
|
165
|
+
return self.RESP_WARN
|
|
166
|
+
# セッションの削除
|
|
167
|
+
from voicevox_core.blocking import Synthesizer
|
|
168
|
+
session = sessions[model_key]
|
|
169
|
+
synthesizer:Synthesizer = session['synthesizer']
|
|
170
|
+
wav_b64 = convert.bytes2b64str(synthesizer.tts(text=tts_text, style_id=session['style_id']))
|
|
171
|
+
#===============================================================
|
|
172
|
+
# 成功時の処理
|
|
173
|
+
rescode, msg = (self.RESP_SUCCESS, dict(success=dict(data=wav_b64, format='wav', model=voicevox_model)))
|
|
174
|
+
redis_cli.rpush(reskey, msg)
|
|
175
|
+
return rescode
|
|
176
|
+
except Exception as e:
|
|
177
|
+
logger.warning(f"Failed to say: {e}", exc_info=True)
|
|
178
|
+
redis_cli.rpush(reskey, dict(warn=f"Failed to say: {e}"))
|
|
179
|
+
return self.RESP_WARN
|
|
@@ -0,0 +1,329 @@
|
|
|
1
|
+
from cmdbox import version
|
|
2
|
+
from cmdbox.app import common, client, feature
|
|
3
|
+
from cmdbox.app.commons import convert, redis_client
|
|
4
|
+
from cmdbox.app.options import Options
|
|
5
|
+
from pathlib import Path
|
|
6
|
+
from typing import Dict, Any, Tuple, List, Union
|
|
7
|
+
import argparse
|
|
8
|
+
import logging
|
|
9
|
+
|
|
10
|
+
|
|
11
|
+
class TtsStart(feature.UnsupportEdgeFeature):
|
|
12
|
+
VOICEVOX_STYLE = dict()
|
|
13
|
+
VOICEVOX_STYLE['0.vvm_2'] = dict(fn='0.vvm',ch='四国めたん',md='ノーマル',st=2)
|
|
14
|
+
VOICEVOX_STYLE['0.vvm_0'] = dict(fn='0.vvm',ch='四国めたん',md='あまあま',st=0)
|
|
15
|
+
VOICEVOX_STYLE['0.vvm_6'] = dict(fn='0.vvm',ch='四国めたん',md='ツンツン',st=6)
|
|
16
|
+
VOICEVOX_STYLE['0.vvm_4'] = dict(fn='0.vvm',ch='四国めたん',md='セクシー',st=4)
|
|
17
|
+
VOICEVOX_STYLE['0.vvm_3'] = dict(fn='0.vvm',ch='ずんだもん',md='ノーマル',st=3)
|
|
18
|
+
VOICEVOX_STYLE['0.vvm_1'] = dict(fn='0.vvm',ch='ずんだもん',md='あまあま',st=1)
|
|
19
|
+
VOICEVOX_STYLE['0.vvm_7'] = dict(fn='0.vvm',ch='ずんだもん',md='ツンツン',st=7)
|
|
20
|
+
VOICEVOX_STYLE['0.vvm_5'] = dict(fn='0.vvm',ch='ずんだもん',md='セクシー',st=5)
|
|
21
|
+
VOICEVOX_STYLE['0.vvm_8'] = dict(fn='0.vvm',ch='春日部つむぎ',md='ノーマル',st=8)
|
|
22
|
+
VOICEVOX_STYLE['0.vvm_10'] = dict(fn='0.vvm',ch='雨晴はう',md='ノーマル',st=10)
|
|
23
|
+
VOICEVOX_STYLE['1.vvm_14'] = dict(fn='1.vvm',ch='冥鳴ひまり',md='ノーマル',st=14)
|
|
24
|
+
VOICEVOX_STYLE['2.vvm_16'] = dict(fn='2.vvm',ch='九州そら',md='ノーマル',st=16)
|
|
25
|
+
VOICEVOX_STYLE['2.vvm_15'] = dict(fn='2.vvm',ch='九州そら',md='あまあま',st=15)
|
|
26
|
+
VOICEVOX_STYLE['2.vvm_18'] = dict(fn='2.vvm',ch='九州そら',md='ツンツン',st=18)
|
|
27
|
+
VOICEVOX_STYLE['2.vvm_17'] = dict(fn='2.vvm',ch='九州そら',md='セクシー',st=17)
|
|
28
|
+
VOICEVOX_STYLE['3.vvm_9'] = dict(fn='3.vvm',ch='波音リツ',md='ノーマル',st=9)
|
|
29
|
+
VOICEVOX_STYLE['3.vvm_65'] = dict(fn='3.vvm',ch='波音リツ',md='クイーン',st=65)
|
|
30
|
+
VOICEVOX_STYLE['3.vvm_61'] = dict(fn='3.vvm',ch='中国うさぎ',md='ノーマル',st=61)
|
|
31
|
+
VOICEVOX_STYLE['3.vvm_62'] = dict(fn='3.vvm',ch='中国うさぎ',md='おどろき',st=62)
|
|
32
|
+
VOICEVOX_STYLE['3.vvm_63'] = dict(fn='3.vvm',ch='中国うさぎ',md='こわがり',st=63)
|
|
33
|
+
VOICEVOX_STYLE['3.vvm_64'] = dict(fn='3.vvm',ch='中国うさぎ',md='へろへろ',st=64)
|
|
34
|
+
VOICEVOX_STYLE['4.vvm_11'] = dict(fn='4.vvm',ch='玄野武宏',md='ノーマル',st=11)
|
|
35
|
+
VOICEVOX_STYLE['4.vvm_21'] = dict(fn='4.vvm',ch='剣崎雌雄',md='ノーマル',st=21)
|
|
36
|
+
VOICEVOX_STYLE['5.vvm_36'] = dict(fn='5.vvm',ch='四国めたん',md='ささやき',st=36)
|
|
37
|
+
VOICEVOX_STYLE['5.vvm_37'] = dict(fn='5.vvm',ch='四国めたん',md='ヒソヒソ',st=37)
|
|
38
|
+
VOICEVOX_STYLE['5.vvm_22'] = dict(fn='5.vvm',ch='ずんだもん',md='ささやき',st=22)
|
|
39
|
+
VOICEVOX_STYLE['5.vvm_38'] = dict(fn='5.vvm',ch='ずんだもん',md='ヒソヒソ',st=38)
|
|
40
|
+
VOICEVOX_STYLE['5.vvm_19'] = dict(fn='5.vvm',ch='九州そら',md='ささやき',st=19)
|
|
41
|
+
VOICEVOX_STYLE['6.vvm_29'] = dict(fn='6.vvm',ch='No.7',md='ノーマル',st=29)
|
|
42
|
+
VOICEVOX_STYLE['6.vvm_30'] = dict(fn='6.vvm',ch='No.7',md='アナウンス',st=30)
|
|
43
|
+
VOICEVOX_STYLE['6.vvm_31'] = dict(fn='6.vvm',ch='No.7',md='読み聞かせ',st=31)
|
|
44
|
+
VOICEVOX_STYLE['7.vvm_27'] = dict(fn='7.vvm',ch='後鬼',md='人間ver.',st=27)
|
|
45
|
+
VOICEVOX_STYLE['7.vvm_28'] = dict(fn='7.vvm',ch='後鬼',md='ぬいぐるみver.',st=28)
|
|
46
|
+
VOICEVOX_STYLE['8.vvm_23'] = dict(fn='8.vvm',ch='WhiteCUL',md='ノーマル',st=23)
|
|
47
|
+
VOICEVOX_STYLE['8.vvm_24'] = dict(fn='8.vvm',ch='WhiteCUL',md='たのしい',st=24)
|
|
48
|
+
VOICEVOX_STYLE['8.vvm_25'] = dict(fn='8.vvm',ch='WhiteCUL',md='かなしい',st=25)
|
|
49
|
+
VOICEVOX_STYLE['8.vvm_26'] = dict(fn='8.vvm',ch='WhiteCUL',md='びえーん',st=26)
|
|
50
|
+
VOICEVOX_STYLE['9.vvm_12'] = dict(fn='9.vvm',ch='白上虎太郎',md='ふつう',st=12)
|
|
51
|
+
VOICEVOX_STYLE['9.vvm_32'] = dict(fn='9.vvm',ch='白上虎太郎',md='わーい',st=32)
|
|
52
|
+
VOICEVOX_STYLE['9.vvm_33'] = dict(fn='9.vvm',ch='白上虎太郎',md='びくびく',st=33)
|
|
53
|
+
VOICEVOX_STYLE['9.vvm_34'] = dict(fn='9.vvm',ch='白上虎太郎',md='おこ',st=34)
|
|
54
|
+
VOICEVOX_STYLE['9.vvm_35'] = dict(fn='9.vvm',ch='白上虎太郎',md='びえーん',st=35)
|
|
55
|
+
VOICEVOX_STYLE['10.vvm_39'] = dict(fn='10.vvm',ch='玄野武宏',md='喜び',st=39)
|
|
56
|
+
VOICEVOX_STYLE['10.vvm_40'] = dict(fn='10.vvm',ch='玄野武宏',md='ツンギレ',st=40)
|
|
57
|
+
VOICEVOX_STYLE['10.vvm_41'] = dict(fn='10.vvm',ch='玄野武宏',md='悲しみ',st=41)
|
|
58
|
+
VOICEVOX_STYLE['10.vvm_42'] = dict(fn='10.vvm',ch='ちび式じい',md='ノーマル',st=42)
|
|
59
|
+
VOICEVOX_STYLE['11.vvm_43'] = dict(fn='11.vvm',ch='櫻歌ミコ',md='ノーマル',st=43)
|
|
60
|
+
VOICEVOX_STYLE['11.vvm_44'] = dict(fn='11.vvm',ch='櫻歌ミコ',md='第二形態',st=44)
|
|
61
|
+
VOICEVOX_STYLE['11.vvm_45'] = dict(fn='11.vvm',ch='櫻歌ミコ',md='ロリ',st=45)
|
|
62
|
+
VOICEVOX_STYLE['11.vvm_47'] = dict(fn='11.vvm',ch='ナースロボ_タイプT',md='ノーマル',st=47)
|
|
63
|
+
VOICEVOX_STYLE['11.vvm_48'] = dict(fn='11.vvm',ch='ナースロボ_タイプT',md='楽々',st=48)
|
|
64
|
+
VOICEVOX_STYLE['11.vvm_49'] = dict(fn='11.vvm',ch='ナースロボ_タイプT',md='恐怖',st=49)
|
|
65
|
+
VOICEVOX_STYLE['11.vvm_50'] = dict(fn='11.vvm',ch='ナースロボ_タイプT',md='内緒話',st=50)
|
|
66
|
+
VOICEVOX_STYLE['12.vvm_51'] = dict(fn='12.vvm',ch='†聖騎士 紅桜†',md='ノーマル',st=51)
|
|
67
|
+
VOICEVOX_STYLE['12.vvm_52'] = dict(fn='12.vvm',ch='雀松朱司',md='ノーマル',st=52)
|
|
68
|
+
VOICEVOX_STYLE['12.vvm_53'] = dict(fn='12.vvm',ch='麒ヶ島宗麟',md='ノーマル',st=53)
|
|
69
|
+
VOICEVOX_STYLE['13.vvm_54'] = dict(fn='13.vvm',ch='春歌ナナ',md='ノーマル',st=54)
|
|
70
|
+
VOICEVOX_STYLE['13.vvm_55'] = dict(fn='13.vvm',ch='猫使アル',md='ノーマル',st=55)
|
|
71
|
+
VOICEVOX_STYLE['13.vvm_56'] = dict(fn='13.vvm',ch='猫使アル',md='おちつき',st=56)
|
|
72
|
+
VOICEVOX_STYLE['13.vvm_57'] = dict(fn='13.vvm',ch='猫使アル',md='うきうき',st=57)
|
|
73
|
+
VOICEVOX_STYLE['13.vvm_58'] = dict(fn='13.vvm',ch='猫使ビィ',md='ノーマル',st=58)
|
|
74
|
+
VOICEVOX_STYLE['13.vvm_59'] = dict(fn='13.vvm',ch='猫使ビィ',md='おちつき',st=59)
|
|
75
|
+
VOICEVOX_STYLE['13.vvm_60'] = dict(fn='13.vvm',ch='猫使ビィ',md='人見知り',st=60)
|
|
76
|
+
VOICEVOX_STYLE['14.vvm_67'] = dict(fn='14.vvm',ch='栗田まろん',md='ノーマル',st=67)
|
|
77
|
+
VOICEVOX_STYLE['14.vvm_68'] = dict(fn='14.vvm',ch='あいえるたん',md='ノーマル',st=68)
|
|
78
|
+
VOICEVOX_STYLE['14.vvm_69'] = dict(fn='14.vvm',ch='満別花丸',md='ノーマル',st=69)
|
|
79
|
+
VOICEVOX_STYLE['14.vvm_70'] = dict(fn='14.vvm',ch='満別花丸',md='元気',st=70)
|
|
80
|
+
VOICEVOX_STYLE['14.vvm_71'] = dict(fn='14.vvm',ch='満別花丸',md='ささやき',st=71)
|
|
81
|
+
VOICEVOX_STYLE['14.vvm_72'] = dict(fn='14.vvm',ch='満別花丸',md='ぶりっ子',st=72)
|
|
82
|
+
VOICEVOX_STYLE['14.vvm_73'] = dict(fn='14.vvm',ch='満別花丸',md='ボーイ',st=73)
|
|
83
|
+
VOICEVOX_STYLE['14.vvm_74'] = dict(fn='14.vvm',ch='琴詠ニア',md='ノーマル',st=74)
|
|
84
|
+
VOICEVOX_STYLE['15.vvm_75'] = dict(fn='15.vvm',ch='ずんだもん',md='ヘロヘロ',st=75)
|
|
85
|
+
VOICEVOX_STYLE['15.vvm_76'] = dict(fn='15.vvm',ch='ずんだもん',md='なみだめ',st=76)
|
|
86
|
+
VOICEVOX_STYLE['15.vvm_13'] = dict(fn='15.vvm',ch='青山龍星',md='ノーマル',st=13)
|
|
87
|
+
VOICEVOX_STYLE['15.vvm_81'] = dict(fn='15.vvm',ch='青山龍星',md='熱血',st=81)
|
|
88
|
+
VOICEVOX_STYLE['15.vvm_82'] = dict(fn='15.vvm',ch='青山龍星',md='不機嫌',st=82)
|
|
89
|
+
VOICEVOX_STYLE['15.vvm_83'] = dict(fn='15.vvm',ch='青山龍星',md='喜び',st=83)
|
|
90
|
+
VOICEVOX_STYLE['15.vvm_84'] = dict(fn='15.vvm',ch='青山龍星',md='しっとり',st=84)
|
|
91
|
+
VOICEVOX_STYLE['15.vvm_85'] = dict(fn='15.vvm',ch='青山龍星',md='かなしみ',st=85)
|
|
92
|
+
VOICEVOX_STYLE['15.vvm_86'] = dict(fn='15.vvm',ch='青山龍星',md='囁き',st=86)
|
|
93
|
+
VOICEVOX_STYLE['15.vvm_20'] = dict(fn='15.vvm',ch='もち子さん',md='ノーマル',st=20)
|
|
94
|
+
VOICEVOX_STYLE['15.vvm_66'] = dict(fn='15.vvm',ch='もち子さん',md='セクシー/あん子',st=66)
|
|
95
|
+
VOICEVOX_STYLE['15.vvm_77'] = dict(fn='15.vvm',ch='もち子さん',md='泣き',st=77)
|
|
96
|
+
VOICEVOX_STYLE['15.vvm_78'] = dict(fn='15.vvm',ch='もち子さん',md='怒り',st=78)
|
|
97
|
+
VOICEVOX_STYLE['15.vvm_79'] = dict(fn='15.vvm',ch='もち子さん',md='喜び',st=79)
|
|
98
|
+
VOICEVOX_STYLE['15.vvm_80'] = dict(fn='15.vvm',ch='もち子さん',md='のんびり',st=80)
|
|
99
|
+
VOICEVOX_STYLE['15.vvm_46'] = dict(fn='15.vvm',ch='小夜/SAYO',md='ノーマル',st=46)
|
|
100
|
+
VOICEVOX_STYLE['16.vvm_87'] = dict(fn='16.vvm',ch='後鬼',md='人間(怒り)ver.',st=87)
|
|
101
|
+
VOICEVOX_STYLE['16.vvm_88'] = dict(fn='16.vvm',ch='後鬼',md='鬼ver.',st=88)
|
|
102
|
+
VOICEVOX_STYLE['17.vvm_89'] = dict(fn='17.vvm',ch='Voidoll',md='ノーマル',st=89)
|
|
103
|
+
VOICEVOX_STYLE['18.vvm_90'] = dict(fn='18.vvm',ch='ぞん子',md='ノーマル',st=90)
|
|
104
|
+
VOICEVOX_STYLE['18.vvm_91'] = dict(fn='18.vvm',ch='ぞん子',md='低血圧',st=91)
|
|
105
|
+
VOICEVOX_STYLE['18.vvm_92'] = dict(fn='18.vvm',ch='ぞん子',md='覚醒',st=92)
|
|
106
|
+
VOICEVOX_STYLE['18.vvm_93'] = dict(fn='18.vvm',ch='ぞん子',md='実況風',st=93)
|
|
107
|
+
VOICEVOX_STYLE['18.vvm_94'] = dict(fn='18.vvm',ch='中部つるぎ',md='ノーマル',st=94)
|
|
108
|
+
VOICEVOX_STYLE['18.vvm_95'] = dict(fn='18.vvm',ch='中部つるぎ',md='怒り',st=95)
|
|
109
|
+
VOICEVOX_STYLE['18.vvm_96'] = dict(fn='18.vvm',ch='中部つるぎ',md='ヒソヒソ',st=96)
|
|
110
|
+
VOICEVOX_STYLE['18.vvm_97'] = dict(fn='18.vvm',ch='中部つるぎ',md='おどおど',st=97)
|
|
111
|
+
VOICEVOX_STYLE['18.vvm_98'] = dict(fn='18.vvm',ch='中部つるぎ',md='絶望と敗北',st=98)
|
|
112
|
+
VOICEVOX_STYLE['19.vvm_99'] = dict(fn='19.vvm',ch='離途',md='ノーマル',st=99)
|
|
113
|
+
VOICEVOX_STYLE['19.vvm_101'] = dict(fn='19.vvm',ch='離途',md='シリアス',st=101)
|
|
114
|
+
VOICEVOX_STYLE['19.vvm_100'] = dict(fn='19.vvm',ch='黒沢冴白',md='ノーマル',st=100)
|
|
115
|
+
VOICEVOX_STYLE['20.vvm_102'] = dict(fn='20.vvm',ch='ユーレイちゃん',md='ノーマル',st=102)
|
|
116
|
+
VOICEVOX_STYLE['20.vvm_103'] = dict(fn='20.vvm',ch='ユーレイちゃん',md='甘々',st=103)
|
|
117
|
+
VOICEVOX_STYLE['20.vvm_104'] = dict(fn='20.vvm',ch='ユーレイちゃん',md='哀しみ',st=104)
|
|
118
|
+
VOICEVOX_STYLE['20.vvm_105'] = dict(fn='20.vvm',ch='ユーレイちゃん',md='ささやき',st=105)
|
|
119
|
+
VOICEVOX_STYLE['20.vvm_106'] = dict(fn='20.vvm',ch='ユーレイちゃん',md='ツクモちゃん',st=106)
|
|
120
|
+
VOICEVOX_STYLE['21.vvm_110'] = dict(fn='21.vvm',ch='猫使アル',md='つよつよ',st=110)
|
|
121
|
+
VOICEVOX_STYLE['21.vvm_111'] = dict(fn='21.vvm',ch='猫使アル',md='へろへろ',st=111)
|
|
122
|
+
VOICEVOX_STYLE['21.vvm_112'] = dict(fn='21.vvm',ch='猫使ビィ',md='つよつよ',st=112)
|
|
123
|
+
VOICEVOX_STYLE['21.vvm_107'] = dict(fn='21.vvm',ch='東北ずん子',md='ノーマル',st=107)
|
|
124
|
+
VOICEVOX_STYLE['21.vvm_108'] = dict(fn='21.vvm',ch='東北きりたん',md='ノーマル',st=108)
|
|
125
|
+
VOICEVOX_STYLE['21.vvm_109'] = dict(fn='21.vvm',ch='東北イタコ',md='ノーマル',st=109)
|
|
126
|
+
for k, v in VOICEVOX_STYLE.items():
|
|
127
|
+
v['model_key'] = f'voicevox_{v["fn"]}_{v["st"]}'
|
|
128
|
+
v['select'] = f'{v["ch"]}{v["md"]}'
|
|
129
|
+
|
|
130
|
+
def get_mode(self) -> Union[str, List[str]]:
|
|
131
|
+
"""
|
|
132
|
+
この機能のモードを返します
|
|
133
|
+
|
|
134
|
+
Returns:
|
|
135
|
+
Union[str, List[str]]: モード
|
|
136
|
+
"""
|
|
137
|
+
return 'tts'
|
|
138
|
+
|
|
139
|
+
def get_cmd(self):
|
|
140
|
+
"""
|
|
141
|
+
この機能のコマンドを返します
|
|
142
|
+
|
|
143
|
+
Returns:
|
|
144
|
+
str: コマンド
|
|
145
|
+
"""
|
|
146
|
+
return 'start'
|
|
147
|
+
|
|
148
|
+
def get_option(self):
|
|
149
|
+
"""
|
|
150
|
+
この機能のオプションを返します
|
|
151
|
+
|
|
152
|
+
Returns:
|
|
153
|
+
Dict[str, Any]: オプション
|
|
154
|
+
"""
|
|
155
|
+
return dict(
|
|
156
|
+
use_redis=self.USE_REDIS_MEIGHT, nouse_webmode=False, use_agent=True,
|
|
157
|
+
description_ja="Text-to-Speech(TTS)エンジンを開始します。",
|
|
158
|
+
description_en="Starts the Text-to-Speech (TTS) engine.",
|
|
159
|
+
choice=[
|
|
160
|
+
dict(opt="host", type=Options.T_STR, default=self.default_host, required=True, multi=False, hide=True, choice=None, web="mask",
|
|
161
|
+
description_ja="Redisサーバーのサービスホストを指定します。",
|
|
162
|
+
description_en="Specify the service host of the Redis server."),
|
|
163
|
+
dict(opt="port", type=Options.T_INT, default=self.default_port, required=True, multi=False, hide=True, choice=None, web="mask",
|
|
164
|
+
description_ja="Redisサーバーのサービスポートを指定します。",
|
|
165
|
+
description_en="Specify the service port of the Redis server."),
|
|
166
|
+
dict(opt="password", type=Options.T_STR, default=self.default_pass, required=True, multi=False, hide=True, choice=None, web="mask",
|
|
167
|
+
description_ja=f"Redisサーバーのアクセスパスワード(任意)を指定します。省略時は `{self.default_pass}` を使用します。",
|
|
168
|
+
description_en=f"Specify the access password of the Redis server (optional). If omitted, `{self.default_pass}` is used."),
|
|
169
|
+
dict(opt="svname", type=Options.T_STR, default=self.default_svname, required=True, multi=False, hide=True, choice=None, web="readonly",
|
|
170
|
+
description_ja="サーバーのサービス名を指定します。省略時は `server` を使用します。",
|
|
171
|
+
description_en="Specify the service name of the inference server. If omitted, `server` is used."),
|
|
172
|
+
dict(opt="retry_count", type=Options.T_INT, default=3, required=False, multi=False, hide=True, choice=None,
|
|
173
|
+
description_ja="Redisサーバーへの再接続回数を指定します。0以下を指定すると永遠に再接続を行います。",
|
|
174
|
+
description_en="Specifies the number of reconnections to the Redis server.If less than 0 is specified, reconnection is forever."),
|
|
175
|
+
dict(opt="retry_interval", type=Options.T_INT, default=5, required=False, multi=False, hide=True, choice=None,
|
|
176
|
+
description_ja="Redisサーバーに再接続までの秒数を指定します。",
|
|
177
|
+
description_en="Specifies the number of seconds before reconnecting to the Redis server."),
|
|
178
|
+
dict(opt="timeout", type=Options.T_INT, default="60", required=False, multi=False, hide=True, choice=None,
|
|
179
|
+
description_ja="サーバーの応答が返ってくるまでの最大待ち時間を指定。",
|
|
180
|
+
description_en="Specify the maximum waiting time until the server responds."),
|
|
181
|
+
dict(opt="tts_engine", type=Options.T_STR, default="voicevox", required=True, multi=False, hide=False,
|
|
182
|
+
choice=["voicevox"],
|
|
183
|
+
choice_show=dict(voicevox=["voicevox_model"]),
|
|
184
|
+
description_ja="使用するTTSエンジンを指定します。",
|
|
185
|
+
description_en="Specify the TTS engine to use."),
|
|
186
|
+
dict(opt="voicevox_model", type=Options.T_STR, default=None, required=False, multi=False, hide=False,
|
|
187
|
+
choice=[v['select'] for v in TtsStart.VOICEVOX_STYLE.values()],
|
|
188
|
+
choice_edit=True,
|
|
189
|
+
description_ja="使用するTTSエンジンのモデルを指定します。",
|
|
190
|
+
description_en="Specify the model of the TTS engine to use."),
|
|
191
|
+
]
|
|
192
|
+
)
|
|
193
|
+
|
|
194
|
+
def get_svcmd(self):
|
|
195
|
+
"""
|
|
196
|
+
この機能のサーバー側のコマンドを返します
|
|
197
|
+
|
|
198
|
+
Returns:
|
|
199
|
+
str: サーバー側のコマンド
|
|
200
|
+
"""
|
|
201
|
+
return 'tts_start'
|
|
202
|
+
|
|
203
|
+
def apprun(self, logger:logging.Logger, args:argparse.Namespace, tm:float, pf:List[Dict[str, float]]=[]) -> Tuple[int, Dict[str, Any], Any]:
|
|
204
|
+
"""
|
|
205
|
+
この機能の実行を行います
|
|
206
|
+
|
|
207
|
+
Args:
|
|
208
|
+
logger (logging.Logger): ロガー
|
|
209
|
+
args (argparse.Namespace): 引数
|
|
210
|
+
tm (float): 実行開始時間
|
|
211
|
+
pf (List[Dict[str, float]]): 呼出元のパフォーマンス情報
|
|
212
|
+
|
|
213
|
+
Returns:
|
|
214
|
+
Tuple[int, Dict[str, Any], Any]: 終了コード, 結果, オブジェクト
|
|
215
|
+
"""
|
|
216
|
+
if args.tts_engine is None:
|
|
217
|
+
msg = dict(warn=f"Please specify the --tts_engine option.")
|
|
218
|
+
common.print_format(msg, False, tm, args.output_json, args.output_json_append, pf=pf)
|
|
219
|
+
return self.RESP_WARN, msg, None
|
|
220
|
+
if args.tts_engine == 'voicevox':
|
|
221
|
+
if args.voicevox_model is None:
|
|
222
|
+
msg = dict(warn=f"Please specify the --voicevox_model option.")
|
|
223
|
+
common.print_format(msg, False, tm, args.output_json, args.output_json_append, pf=pf)
|
|
224
|
+
return self.RESP_WARN, msg, None
|
|
225
|
+
|
|
226
|
+
tts_engine_b64 = convert.str2b64str(args.tts_engine)
|
|
227
|
+
voicevox_model_b64 = convert.str2b64str(args.voicevox_model) if args.voicevox_model is not None else '-'
|
|
228
|
+
|
|
229
|
+
cl = client.Client(logger, redis_host=args.host, redis_port=args.port, redis_password=args.password, svname=args.svname)
|
|
230
|
+
ret = cl.redis_cli.send_cmd(self.get_svcmd(),
|
|
231
|
+
[tts_engine_b64, voicevox_model_b64],
|
|
232
|
+
retry_count=args.retry_count, retry_interval=args.retry_interval, timeout=args.timeout, nowait=False)
|
|
233
|
+
common.print_format(ret, False, tm, None, False, pf=pf)
|
|
234
|
+
if 'success' not in ret:
|
|
235
|
+
return self.RESP_WARN, ret, cl
|
|
236
|
+
return self.RESP_SUCCESS, ret, cl
|
|
237
|
+
|
|
238
|
+
def is_cluster_redirect(self):
|
|
239
|
+
"""
|
|
240
|
+
クラスター宛のメッセージの場合、メッセージを転送するかどうかを返します
|
|
241
|
+
|
|
242
|
+
Returns:
|
|
243
|
+
bool: メッセージを転送する場合はTrue
|
|
244
|
+
"""
|
|
245
|
+
return True
|
|
246
|
+
|
|
247
|
+
def svrun(self, data_dir:Path, logger:logging.Logger, redis_cli:redis_client.RedisClient, msg:List[str],
|
|
248
|
+
sessions:Dict[str, Dict[str, Any]]) -> int:
|
|
249
|
+
"""
|
|
250
|
+
この機能のサーバー側の実行を行います
|
|
251
|
+
|
|
252
|
+
Args:
|
|
253
|
+
data_dir (Path): データディレクトリ
|
|
254
|
+
logger (logging.Logger): ロガー
|
|
255
|
+
redis_cli (redis_client.RedisClient): Redisクライアント
|
|
256
|
+
msg (List[str]): 受信メッセージ
|
|
257
|
+
sessions (Dict[str, Dict[str, Any]]): セッション情報
|
|
258
|
+
|
|
259
|
+
Returns:
|
|
260
|
+
int: 終了コード
|
|
261
|
+
"""
|
|
262
|
+
if logger.level == logging.DEBUG:
|
|
263
|
+
logger.debug(f"audit write svrun msg: {msg}")
|
|
264
|
+
tts_engine = convert.b64str2str(msg[2])
|
|
265
|
+
voicevox_model = convert.b64str2str(msg[3])
|
|
266
|
+
st = self.start(msg[1], tts_engine, voicevox_model, data_dir, logger, redis_cli, sessions)
|
|
267
|
+
return st
|
|
268
|
+
|
|
269
|
+
def start(self, reskey:str, tts_engine:str, voicevox_model:str, data_dir:Path, logger:logging.Logger,
|
|
270
|
+
redis_cli:redis_client.RedisClient, sessions:Dict[str, Dict[str, Any]]) -> int:
|
|
271
|
+
"""
|
|
272
|
+
TTSエンジンのモデルを開始します
|
|
273
|
+
|
|
274
|
+
Args:
|
|
275
|
+
reskey (str): レスポンスキー
|
|
276
|
+
tts_engine (str): TTSエンジン
|
|
277
|
+
voicevox_model (str): VoiceVoxモデル
|
|
278
|
+
data_dir (Path): データディレクトリ
|
|
279
|
+
logger (logging.Logger): ロガー
|
|
280
|
+
redis_cli (redis_client.RedisClient): Redisクライアント
|
|
281
|
+
sessions (Dict[str, Dict[str, Any]]): セッション情報
|
|
282
|
+
|
|
283
|
+
Returns:
|
|
284
|
+
int: レスポンスコード
|
|
285
|
+
"""
|
|
286
|
+
try:
|
|
287
|
+
if tts_engine == 'voicevox':
|
|
288
|
+
#===============================================================
|
|
289
|
+
# voicevoxの初期化
|
|
290
|
+
from voicevox_core.blocking import Onnxruntime, OpenJtalk, Synthesizer, VoiceModelFile
|
|
291
|
+
voicevox_dir = Path(version.__file__).parent / '.voicevox' / 'voicevox_core'
|
|
292
|
+
if not voicevox_dir.exists():
|
|
293
|
+
logger.error(f"Failed to start VoiceVox core: voicevox directory does not exist: {voicevox_dir}")
|
|
294
|
+
redis_cli.rpush(reskey, dict(warn=f"Failed to start VoiceVox core: voicevox directory does not exist: {voicevox_dir}"))
|
|
295
|
+
return self.RESP_WARN
|
|
296
|
+
voicevox_onnxruntime_path = voicevox_dir / 'onnxruntime' / 'lib' / Onnxruntime.LIB_VERSIONED_FILENAME
|
|
297
|
+
open_jtalk_dict_dir = voicevox_dir / 'dict' / 'open_jtalk_dic_utf_8-1.11'
|
|
298
|
+
# voicevox_modelのチェック
|
|
299
|
+
style_key = [k for k,v in TtsStart.VOICEVOX_STYLE.items() if v['select'] == voicevox_model]
|
|
300
|
+
if not style_key:
|
|
301
|
+
logger.error(f"Invalid voicevox_model specified: {voicevox_model}")
|
|
302
|
+
redis_cli.rpush(reskey, dict(warn=f"Invalid voicevox_model specified: {voicevox_model}"))
|
|
303
|
+
return self.RESP_WARN
|
|
304
|
+
style = TtsStart.VOICEVOX_STYLE[style_key[0]]
|
|
305
|
+
model_key = style['model_key']
|
|
306
|
+
if model_key in sessions:
|
|
307
|
+
logger.warning(f"VoiceVox model is already running: {voicevox_model}")
|
|
308
|
+
redis_cli.rpush(reskey, dict(warn=f"VoiceVox model is already running: {voicevox_model} ({model_key})"))
|
|
309
|
+
return self.RESP_WARN
|
|
310
|
+
# vvmファイルの読込み
|
|
311
|
+
synthesizer = Synthesizer(Onnxruntime.load_once(filename=str(voicevox_onnxruntime_path)), OpenJtalk(open_jtalk_dict_dir))
|
|
312
|
+
with VoiceModelFile.open(voicevox_dir / 'models' / 'vvms' / style['fn']) as model:
|
|
313
|
+
synthesizer.load_voice_model(model)
|
|
314
|
+
# セッションに登録
|
|
315
|
+
sessions[model_key] = dict(
|
|
316
|
+
model_id=model.id,
|
|
317
|
+
model_key=model_key,
|
|
318
|
+
synthesizer=synthesizer,
|
|
319
|
+
style_id=style['st'],
|
|
320
|
+
)
|
|
321
|
+
#===============================================================
|
|
322
|
+
# 成功時の処理
|
|
323
|
+
rescode, msg = (self.RESP_SUCCESS, dict(success=f'Success to start VoiceVox. Model: {voicevox_model}'))
|
|
324
|
+
redis_cli.rpush(reskey, msg)
|
|
325
|
+
return rescode
|
|
326
|
+
except Exception as e:
|
|
327
|
+
logger.warning(f"Failed to start: {e}", exc_info=True)
|
|
328
|
+
redis_cli.rpush(reskey, dict(warn=f"Failed to start: {e}"))
|
|
329
|
+
return self.RESP_WARN
|
|
@@ -0,0 +1,108 @@
|
|
|
1
|
+
from cmdbox.app.commons import convert, redis_client
|
|
2
|
+
from cmdbox.app.features.cli import cmdbox_tts_start
|
|
3
|
+
from pathlib import Path
|
|
4
|
+
from typing import Dict, Any, Tuple, List, Union
|
|
5
|
+
import logging
|
|
6
|
+
|
|
7
|
+
|
|
8
|
+
class TtsStop(cmdbox_tts_start.TtsStart):
|
|
9
|
+
|
|
10
|
+
def get_cmd(self):
|
|
11
|
+
"""
|
|
12
|
+
この機能のコマンドを返します
|
|
13
|
+
|
|
14
|
+
Returns:
|
|
15
|
+
str: コマンド
|
|
16
|
+
"""
|
|
17
|
+
return 'stop'
|
|
18
|
+
|
|
19
|
+
def get_option(self):
|
|
20
|
+
"""
|
|
21
|
+
この機能のオプションを返します
|
|
22
|
+
|
|
23
|
+
Returns:
|
|
24
|
+
Dict[str, Any]: オプション
|
|
25
|
+
"""
|
|
26
|
+
opt = super().get_option()
|
|
27
|
+
opt['description_ja'] = "Text-to-Speech(TTS)エンジンを停止します。"
|
|
28
|
+
opt['description_en'] = "Stops the Text-to-Speech (TTS) engine."
|
|
29
|
+
return opt
|
|
30
|
+
|
|
31
|
+
def get_svcmd(self):
|
|
32
|
+
"""
|
|
33
|
+
この機能のサーバー側のコマンドを返します
|
|
34
|
+
|
|
35
|
+
Returns:
|
|
36
|
+
str: サーバー側のコマンド
|
|
37
|
+
"""
|
|
38
|
+
return 'tts_stop'
|
|
39
|
+
|
|
40
|
+
def svrun(self, data_dir:Path, logger:logging.Logger, redis_cli:redis_client.RedisClient, msg:List[str],
|
|
41
|
+
sessions:Dict[str, Dict[str, Any]]) -> int:
|
|
42
|
+
"""
|
|
43
|
+
この機能のサーバー側の実行を行います
|
|
44
|
+
|
|
45
|
+
Args:
|
|
46
|
+
data_dir (Path): データディレクトリ
|
|
47
|
+
logger (logging.Logger): ロガー
|
|
48
|
+
redis_cli (redis_client.RedisClient): Redisクライアント
|
|
49
|
+
msg (List[str]): 受信メッセージ
|
|
50
|
+
sessions (Dict[str, Dict[str, Any]]): セッション情報
|
|
51
|
+
|
|
52
|
+
Returns:
|
|
53
|
+
int: 終了コード
|
|
54
|
+
"""
|
|
55
|
+
if logger.level == logging.DEBUG:
|
|
56
|
+
logger.debug(f"audit write svrun msg: {msg}")
|
|
57
|
+
tts_engine = convert.b64str2str(msg[2])
|
|
58
|
+
voicevox_model = convert.b64str2str(msg[3])
|
|
59
|
+
st = self.stop(msg[1], tts_engine, voicevox_model, data_dir, logger, redis_cli, sessions)
|
|
60
|
+
return st
|
|
61
|
+
|
|
62
|
+
def stop(self, reskey:str, tts_engine:str, voicevox_model:str, data_dir:Path, logger:logging.Logger,
|
|
63
|
+
redis_cli:redis_client.RedisClient, sessions:Dict[str, Dict[str, Any]]) -> int:
|
|
64
|
+
"""
|
|
65
|
+
TTSエンジンのモデルを停止します
|
|
66
|
+
|
|
67
|
+
Args:
|
|
68
|
+
reskey (str): レスポンスキー
|
|
69
|
+
tts_engine (str): TTSエンジン
|
|
70
|
+
voicevox_model (str): VoiceVoxモデル
|
|
71
|
+
data_dir (Path): データディレクトリ
|
|
72
|
+
logger (logging.Logger): ロガー
|
|
73
|
+
redis_cli (redis_client.RedisClient): Redisクライアント
|
|
74
|
+
sessions (Dict[str, Dict[str, Any]]): セッション情報
|
|
75
|
+
|
|
76
|
+
Returns:
|
|
77
|
+
int: レスポンスコード
|
|
78
|
+
"""
|
|
79
|
+
try:
|
|
80
|
+
if tts_engine == 'voicevox':
|
|
81
|
+
#===============================================================
|
|
82
|
+
# voicevoxモデルの停止
|
|
83
|
+
style_key = [k for k,v in cmdbox_tts_start.TtsStart.VOICEVOX_STYLE.items() if v['select'] == voicevox_model]
|
|
84
|
+
if not style_key:
|
|
85
|
+
logger.error(f"Invalid voicevox_model specified: {voicevox_model}")
|
|
86
|
+
redis_cli.rpush(reskey, dict(warn=f"Invalid voicevox_model specified: {voicevox_model}"))
|
|
87
|
+
return self.RESP_WARN
|
|
88
|
+
style = cmdbox_tts_start.TtsStart.VOICEVOX_STYLE[style_key[0]]
|
|
89
|
+
model_key = style['model_key']
|
|
90
|
+
if model_key not in sessions:
|
|
91
|
+
logger.warning(f"VoiceVox model is not running: {voicevox_model}")
|
|
92
|
+
redis_cli.rpush(reskey, dict(warn=f"VoiceVox model is not running: {voicevox_model}"))
|
|
93
|
+
return self.RESP_WARN
|
|
94
|
+
# セッションの削除
|
|
95
|
+
from voicevox_core.blocking import Synthesizer
|
|
96
|
+
session = sessions[model_key]
|
|
97
|
+
synthesizer:Synthesizer = session['synthesizer']
|
|
98
|
+
synthesizer.unload_voice_model(session['model_id'])
|
|
99
|
+
del sessions[model_key]
|
|
100
|
+
#===============================================================
|
|
101
|
+
# 成功時の処理
|
|
102
|
+
rescode, msg = (self.RESP_SUCCESS, dict(success=f'Success to stop VoiceVox. Model: {voicevox_model}'))
|
|
103
|
+
redis_cli.rpush(reskey, msg)
|
|
104
|
+
return rescode
|
|
105
|
+
except Exception as e:
|
|
106
|
+
logger.warning(f"Failed to stop: {e}", exc_info=True)
|
|
107
|
+
redis_cli.rpush(reskey, dict(warn=f"Failed to stop: {e}"))
|
|
108
|
+
return self.RESP_WARN
|