cmdbox 0.6.3.2__py3-none-any.whl → 0.6.4__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.

Files changed (133) hide show
  1. cmdbox/app/app.py +16 -7
  2. cmdbox/app/common.py +2 -2
  3. cmdbox/app/commons/redis_client.py +1 -1
  4. cmdbox/app/edge.py +1 -1
  5. cmdbox/app/feature.py +1 -1
  6. cmdbox/app/features/cli/cmdbox_audit_createdb.py +224 -224
  7. cmdbox/app/features/cli/cmdbox_audit_delete.py +4 -4
  8. cmdbox/app/features/cli/cmdbox_audit_search.py +4 -4
  9. cmdbox/app/features/cli/cmdbox_audit_write.py +6 -8
  10. cmdbox/app/features/cli/cmdbox_client_file_copy.py +3 -3
  11. cmdbox/app/features/cli/cmdbox_client_file_download.py +3 -3
  12. cmdbox/app/features/cli/cmdbox_client_file_list.py +3 -3
  13. cmdbox/app/features/cli/cmdbox_client_file_mkdir.py +3 -3
  14. cmdbox/app/features/cli/cmdbox_client_file_move.py +3 -3
  15. cmdbox/app/features/cli/cmdbox_client_file_remove.py +3 -3
  16. cmdbox/app/features/cli/cmdbox_client_file_rmdir.py +3 -3
  17. cmdbox/app/features/cli/cmdbox_client_file_upload.py +3 -3
  18. cmdbox/app/features/cli/cmdbox_client_http.py +7 -6
  19. cmdbox/app/features/cli/cmdbox_client_server_info.py +4 -4
  20. cmdbox/app/features/cli/cmdbox_cmd_list.py +3 -3
  21. cmdbox/app/features/cli/cmdbox_cmd_load.py +5 -5
  22. cmdbox/app/features/cli/cmdbox_edge_config.py +1 -1
  23. cmdbox/app/features/cli/cmdbox_edge_start.py +3 -3
  24. cmdbox/app/features/cli/cmdbox_mcp_client.py +174 -174
  25. cmdbox/app/features/cli/cmdbox_mcp_proxy.py +96 -96
  26. cmdbox/app/features/cli/cmdbox_server_list.py +2 -2
  27. cmdbox/app/features/cli/cmdbox_server_start.py +103 -103
  28. cmdbox/app/features/cli/cmdbox_server_stop.py +4 -4
  29. cmdbox/app/features/cli/cmdbox_tts_install.py +307 -0
  30. cmdbox/app/features/cli/cmdbox_tts_say.py +179 -0
  31. cmdbox/app/features/cli/cmdbox_tts_start.py +329 -0
  32. cmdbox/app/features/cli/cmdbox_tts_stop.py +108 -0
  33. cmdbox/app/features/cli/cmdbox_web_apikey_add.py +91 -91
  34. cmdbox/app/features/cli/cmdbox_web_apikey_del.py +91 -91
  35. cmdbox/app/features/cli/cmdbox_web_gencert.py +6 -6
  36. cmdbox/app/features/cli/cmdbox_web_genpass.py +168 -168
  37. cmdbox/app/features/cli/cmdbox_web_group_add.py +94 -94
  38. cmdbox/app/features/cli/cmdbox_web_group_del.py +87 -87
  39. cmdbox/app/features/cli/cmdbox_web_group_edit.py +94 -94
  40. cmdbox/app/features/cli/cmdbox_web_group_list.py +87 -87
  41. cmdbox/app/features/cli/cmdbox_web_start.py +235 -235
  42. cmdbox/app/features/cli/cmdbox_web_stop.py +72 -72
  43. cmdbox/app/features/cli/cmdbox_web_user_add.py +104 -104
  44. cmdbox/app/features/cli/cmdbox_web_user_del.py +87 -87
  45. cmdbox/app/features/cli/cmdbox_web_user_edit.py +104 -104
  46. cmdbox/app/features/cli/cmdbox_web_user_list.py +87 -87
  47. cmdbox/app/filer.py +9 -9
  48. cmdbox/app/mcp.py +15 -7
  49. cmdbox/app/options.py +46 -43
  50. cmdbox/app/server.py +224 -224
  51. cmdbox/extensions/features.yml +3 -0
  52. cmdbox/extensions/sample_project/sample/app/features/cli/sample_client_time.py +2 -2
  53. cmdbox/extensions/sample_project/sample/app/features/cli/sample_server_time.py +3 -3
  54. cmdbox/licenses/LICENSE_Werkzeug_3_1_1_BSD_License.txt +28 -0
  55. cmdbox/licenses/LICENSE_absolufy-imports_0_3_1_MIT_License.txt +21 -0
  56. cmdbox/licenses/LICENSE_cyclopts_3_22_5_Apache_Software_License.txt +201 -0
  57. cmdbox/licenses/LICENSE_isodate_0_7_2_BSD_License.txt +26 -0
  58. cmdbox/licenses/LICENSE_lazy-object-proxy_1_11_0_BSD_License.txt +20 -0
  59. cmdbox/licenses/LICENSE_openapi-core_0_19_5_BSD_License.txt +29 -0
  60. cmdbox/licenses/LICENSE_openapi-schema-validator_0_6_3_BSD_License.txt +29 -0
  61. cmdbox/licenses/LICENSE_openapi-spec-validator_0_7_2_Apache_Software_License.txt +201 -0
  62. cmdbox/licenses/LICENSE_opentelemetry-semantic-conventions_0_57b0_UNKNOWN.txt +201 -0
  63. cmdbox/licenses/LICENSE_parse_1_20_2_MIT_License.txt +19 -0
  64. cmdbox/licenses/LICENSE_pathable_0_4_4_Apache_Software_License.txt +201 -0
  65. cmdbox/licenses/{LICENSE_pillow_11_2_1_UNKNOWN.txt → LICENSE_pillow_11_3_0_UNKNOWN.txt} +393 -3
  66. cmdbox/licenses/LICENSE_pyperclip_1_9_0_BSD_License.txt +27 -0
  67. cmdbox/licenses/LICENSE_rfc3339-validator_0_1_4_MIT_License.txt +22 -0
  68. cmdbox/licenses/LICENSE_rich-rst_1_3_1_MIT_License.txt +7 -0
  69. cmdbox/licenses/{LICENSE_setuptools_65_5_0_MIT_License.txt → LICENSE_setuptools_80_9_0_UNKNOWN.txt} +0 -2
  70. cmdbox/licenses/LICENSE_tokenizers_0_21_4_Apache_Software_License.txt +1 -0
  71. cmdbox/licenses/LICENSE_voicevox_core_0_16_0_MIT.txt +20 -0
  72. cmdbox/licenses/LICENSE_watchdog_6_0_0_Apache_Software_License.txt +16 -0
  73. cmdbox/licenses/{LICENSE_typer_0_16_0_MIT_License.txt → LICENSE_wsproto_1_2_0_MIT_License.txt} +2 -2
  74. cmdbox/licenses/files.txt +56 -42
  75. cmdbox/logconf_cmdbox.yml +104 -0
  76. cmdbox/version.py +2 -2
  77. cmdbox/web/agent.html +8 -2
  78. cmdbox/web/assets/cmdbox/agent.js +182 -1
  79. cmdbox/web/assets/cmdbox/common.js +16 -3
  80. cmdbox/web/assets/cmdbox/svgicon.js +18 -0
  81. {cmdbox-0.6.3.2.dist-info → cmdbox-0.6.4.dist-info}/METADATA +28 -20
  82. {cmdbox-0.6.3.2.dist-info → cmdbox-0.6.4.dist-info}/RECORD +122 -112
  83. {cmdbox-0.6.3.2.dist-info → cmdbox-0.6.4.dist-info}/WHEEL +1 -1
  84. cmdbox/config.yml +0 -3
  85. cmdbox/licenses/LICENSE_httptools_0_6_4_MIT_License.txt +0 -21
  86. cmdbox/licenses/LICENSE_shellingham_1_5_4_ISC_License-ISCL.txt +0 -13
  87. cmdbox/licenses/LICENSE_watchfiles_1_1_0_MIT_License.txt +0 -21
  88. cmdbox/logconf_audit.yml +0 -43
  89. cmdbox/logconf_client.yml +0 -43
  90. cmdbox/logconf_edge.yml +0 -43
  91. cmdbox/logconf_gui.yml +0 -43
  92. cmdbox/logconf_mcp.yml +0 -43
  93. cmdbox/logconf_server.yml +0 -43
  94. cmdbox/logconf_web.yml +0 -43
  95. /cmdbox/licenses/{LICENSE_Authlib_1_6_0_BSD_License.txt → LICENSE_Authlib_1_6_1_BSD_License.txt} +0 -0
  96. /cmdbox/licenses/{LICENSE_SQLAlchemy_2_0_41_MIT.txt → LICENSE_SQLAlchemy_2_0_42_MIT.txt} +0 -0
  97. /cmdbox/licenses/{LICENSE_aiohttp_3_12_13_Apache-2_0.txt → LICENSE_aiohttp_3_12_15_Apache-2_0_AND_MIT.txt} +0 -0
  98. /cmdbox/licenses/{LICENSE_aiosignal_1_3_2_Apache_Software_License.txt → LICENSE_aiosignal_1_4_0_Apache_Software_License.txt} +0 -0
  99. /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
  100. /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
  101. /cmdbox/licenses/{LICENSE_docstring_parser_0_16_MIT_License.txt → LICENSE_docstring_parser_0_17_0_MIT_License.txt} +0 -0
  102. /cmdbox/licenses/{LICENSE_fastapi_0_115_14_MIT_License.txt → LICENSE_fastapi_0_116_1_MIT_License.txt} +0 -0
  103. /cmdbox/licenses/{LICENSE_fastmcp_2_10_1_Apache_Software_License.txt → LICENSE_fastmcp_2_11_0_Apache_Software_License.txt} +0 -0
  104. /cmdbox/licenses/{LICENSE_fsspec_2025_5_1_BSD_License.txt → LICENSE_fsspec_2025_7_0_BSD_License.txt} +0 -0
  105. /cmdbox/licenses/{LICENSE_google-adk_1_5_0_Apache_Software_License.txt → LICENSE_google-adk_1_9_0_Apache_Software_License.txt} +0 -0
  106. /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
  107. /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
  108. /cmdbox/licenses/{LICENSE_google-cloud-bigquery_3_34_0_Apache_Software_License.txt → LICENSE_google-cloud-bigquery_3_35_1_Apache_Software_License.txt} +0 -0
  109. /cmdbox/licenses/{LICENSE_google-genai_1_23_0_Apache_Software_License.txt → LICENSE_google-genai_1_28_0_Apache_Software_License.txt} +0 -0
  110. /cmdbox/licenses/{LICENSE_grpcio-status_1_73_1_Apache_Software_License.txt → LICENSE_grpcio-status_1_74_0_Apache_Software_License.txt} +0 -0
  111. /cmdbox/licenses/{LICENSE_grpcio_1_73_1_Apache_Software_License.txt → LICENSE_grpcio_1_74_0_Apache_Software_License.txt} +0 -0
  112. /cmdbox/licenses/{LICENSE_huggingface-hub_0_33_1_Apache_Software_License.txt → LICENSE_huggingface-hub_0_34_3_Apache_Software_License.txt} +0 -0
  113. /cmdbox/licenses/{LICENSE_opentelemetry-api_1_34_1_Apache_Software_License.txt → LICENSE_jsonschema-path_0_3_4_Apache_Software_License.txt} +0 -0
  114. /cmdbox/licenses/{LICENSE_jsonschema_4_24_0_UNKNOWN.txt → LICENSE_jsonschema_4_25_0_UNKNOWN.txt} +0 -0
  115. /cmdbox/licenses/{LICENSE_litellm_1_73_6_MIT_License.txt → LICENSE_litellm_1_74_12_MIT_License.txt} +0 -0
  116. /cmdbox/licenses/{LICENSE_mcp_1_10_1_MIT_License.txt → LICENSE_mcp_1_12_3_MIT_License.txt} +0 -0
  117. /cmdbox/licenses/{LICENSE_multidict_6_6_2_Apache_License_2_0.txt → LICENSE_multidict_6_6_3_Apache_License_2_0.txt} +0 -0
  118. /cmdbox/licenses/{LICENSE_nh3_0_2_21_MIT.txt → LICENSE_nh3_0_3_0_MIT.txt} +0 -0
  119. /cmdbox/licenses/{LICENSE_numpy_2_3_1_BSD_License.txt → LICENSE_numpy_2_3_2_BSD_License.txt} +0 -0
  120. /cmdbox/licenses/{LICENSE_openai_1_93_0_Apache_Software_License.txt → LICENSE_openai_1_98_0_Apache_Software_License.txt} +0 -0
  121. /cmdbox/licenses/{LICENSE_opentelemetry-sdk_1_34_1_Apache_Software_License.txt → LICENSE_opentelemetry-api_1_36_0_UNKNOWN.txt} +0 -0
  122. /cmdbox/licenses/{LICENSE_opentelemetry-semantic-conventions_0_55b1_Apache_Software_License.txt → LICENSE_opentelemetry-sdk_1_36_0_UNKNOWN.txt} +0 -0
  123. /cmdbox/licenses/{LICENSE_tokenizers_0_21_2_Apache_Software_License.txt → LICENSE_pywin32_311_Python_Software_Foundation_License.txt} +0 -0
  124. /cmdbox/licenses/{LICENSE_regex_2024_11_6_Apache_Software_License.txt → LICENSE_regex_2025_7_34_UNKNOWN.txt} +0 -0
  125. /cmdbox/licenses/{LICENSE_rich_14_0_0_MIT_License.txt → LICENSE_rich_14_1_0_MIT_License.txt} +0 -0
  126. /cmdbox/licenses/{LICENSE_rpds-py_0_25_1_MIT.txt → LICENSE_rpds-py_0_26_0_MIT.txt} +0 -0
  127. /cmdbox/licenses/{LICENSE_sse-starlette_2_3_6_BSD_License.txt → LICENSE_sse-starlette_3_0_2_UNKNOWN.txt} +0 -0
  128. /cmdbox/licenses/{LICENSE_starlette_0_46_2_BSD_License.txt → LICENSE_starlette_0_47_2_BSD_License.txt} +0 -0
  129. /cmdbox/licenses/{LICENSE_typing_extensions_4_14_0_UNKNOWN.txt → LICENSE_typing_extensions_4_14_1_UNKNOWN.txt} +0 -0
  130. /cmdbox/licenses/{LICENSE_zope_event_5_1_Zope_Public_License.txt → LICENSE_zope_event_5_1_1_Zope_Public_License.txt} +0 -0
  131. {cmdbox-0.6.3.2.dist-info → cmdbox-0.6.4.dist-info}/entry_points.txt +0 -0
  132. {cmdbox-0.6.3.2.dist-info → cmdbox-0.6.4.dist-info/licenses}/LICENSE +0 -0
  133. {cmdbox-0.6.3.2.dist-info → cmdbox-0.6.4.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.OneshotNotifyEdgeFeature):
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