cmdbox 0.6.4__py3-none-any.whl → 0.6.4.2__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 +6 -0
- cmdbox/app/common.py +7 -4
- cmdbox/app/commons/loghandler.py +101 -20
- cmdbox/app/edge.py +1 -3
- cmdbox/app/features/cli/{cmdbox_mcp_client.py → cmdbox_agent_mcp_client.py} +4 -3
- cmdbox/app/features/cli/{cmdbox_mcp_proxy.py → cmdbox_agent_mcp_proxy.py} +4 -4
- cmdbox/app/features/cli/cmdbox_cmd_list.py +1 -1
- cmdbox/app/features/cli/cmdbox_server_list.py +1 -1
- cmdbox/app/features/cli/cmdbox_server_start.py +2 -2
- cmdbox/app/features/cli/cmdbox_server_stop.py +2 -2
- cmdbox/app/features/cli/cmdbox_tts_install.py +11 -1
- cmdbox/app/features/cli/cmdbox_tts_start.py +1 -1
- cmdbox/app/features/cli/cmdbox_vision_install.py +213 -0
- cmdbox/app/features/cli/cmdbox_vision_predict.py +192 -0
- cmdbox/app/features/cli/cmdbox_vision_start.py +230 -0
- cmdbox/app/features/cli/cmdbox_web_apikey_add.py +1 -1
- cmdbox/app/features/cli/cmdbox_web_apikey_del.py +1 -1
- cmdbox/app/features/cli/cmdbox_web_gencert.py +1 -1
- cmdbox/app/features/cli/cmdbox_web_genpass.py +1 -1
- cmdbox/app/features/cli/cmdbox_web_group_add.py +1 -1
- cmdbox/app/features/cli/cmdbox_web_group_del.py +1 -1
- cmdbox/app/features/cli/cmdbox_web_group_edit.py +1 -1
- cmdbox/app/features/cli/cmdbox_web_group_list.py +2 -2
- cmdbox/app/features/cli/cmdbox_web_start.py +1 -0
- cmdbox/app/features/cli/cmdbox_web_stop.py +1 -1
- cmdbox/app/features/cli/cmdbox_web_user_add.py +1 -1
- cmdbox/app/features/cli/cmdbox_web_user_del.py +1 -1
- cmdbox/app/features/cli/cmdbox_web_user_edit.py +1 -1
- cmdbox/app/features/cli/cmdbox_web_user_list.py +2 -2
- 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/mcp.py +4 -1
- cmdbox/app/options.py +6 -4
- cmdbox/app/web.py +39 -17
- cmdbox/extensions/features.yml +4 -1
- cmdbox/licenses/LICENSE_APScheduler_3_11_0_MIT_License.txt +19 -0
- cmdbox/licenses/LICENSE_backoff_2_2_1_MIT_License.txt +21 -0
- cmdbox/licenses/LICENSE_fastapi-sso_0_18_0_MIT_License.txt +21 -0
- cmdbox/licenses/LICENSE_litellm-enterprise_0_1_19_UNKNOWN.txt +37 -0
- cmdbox/licenses/LICENSE_oauthlib_3_3_1_BSD-3-Clause.txt +27 -0
- cmdbox/licenses/LICENSE_orjson_3_11_1_Apache_Software_License-MIT_License.txt +201 -0
- cmdbox/licenses/files.txt +28 -23
- cmdbox/logconf_cmdbox.yml +32 -0
- cmdbox/version.py +2 -2
- cmdbox/web/agent.html +8 -0
- cmdbox/web/assets/cmdbox/agent.js +45 -1
- cmdbox/web/assets/cmdbox/common.js +4 -22
- cmdbox/web/voicevox_license_list.txt +41 -0
- {cmdbox-0.6.4.dist-info → cmdbox-0.6.4.2.dist-info}/METADATA +2 -1
- {cmdbox-0.6.4.dist-info → cmdbox-0.6.4.2.dist-info}/RECORD +78 -69
- cmdbox/licenses/LICENSE_voicevox_core_0_16_0_MIT.txt +0 -20
- /cmdbox/licenses/{LICENSE_SQLAlchemy_2_0_42_MIT.txt → LICENSE_SQLAlchemy_2_0_43_MIT.txt} +0 -0
- /cmdbox/licenses/{LICENSE_anyio_4_9_0_MIT_License.txt → LICENSE_anyio_4_10_0_UNKNOWN.txt} +0 -0
- /cmdbox/licenses/{LICENSE_certifi_2025_7_14_Mozilla_Public_License_2_0-MPL_2_0.txt → LICENSE_certifi_2025_8_3_Mozilla_Public_License_2_0-MPL_2_0.txt} +0 -0
- /cmdbox/licenses/{LICENSE_charset-normalizer_3_4_2_MIT_License.txt → LICENSE_charset-normalizer_3_4_3_MIT.txt} +0 -0
- /cmdbox/licenses/{LICENSE_cryptography_45_0_5_Apache-2_0_OR_BSD-3-Clause.txt → LICENSE_cryptography_45_0_6_Apache-2_0_OR_BSD-3-Clause.txt} +0 -0
- /cmdbox/licenses/{LICENSE_fastmcp_2_11_0_Apache_Software_License.txt → LICENSE_fastmcp_2_11_3_Apache_Software_License.txt} +0 -0
- /cmdbox/licenses/{LICENSE_google-adk_1_9_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_177_0_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_106_0_Apache_2_0.txt → LICENSE_google-cloud-aiplatform_1_108_0_Apache_2_0.txt} +0 -0
- /cmdbox/licenses/{LICENSE_google-genai_1_28_0_Apache_Software_License.txt → LICENSE_google-genai_1_29_0_Apache_Software_License.txt} +0 -0
- /cmdbox/licenses/{LICENSE_greenlet_3_2_3_MIT_AND_Python-2_0.txt → LICENSE_greenlet_3_2_4_MIT_AND_Python-2_0.txt} +0 -0
- /cmdbox/licenses/{LICENSE_huggingface-hub_0_34_3_Apache_Software_License.txt → LICENSE_huggingface-hub_0_34_4_Apache_Software_License.txt} +0 -0
- /cmdbox/licenses/{LICENSE_litellm_1_74_12_MIT_License.txt → LICENSE_litellm_1_75_5_post1_MIT_License.txt} +0 -0
- /cmdbox/licenses/{LICENSE_markdown-it-py_3_0_0_MIT_License.txt → LICENSE_markdown-it-py_4_0_0_MIT_License.txt} +0 -0
- /cmdbox/licenses/{LICENSE_mcp_1_12_3_MIT_License.txt → LICENSE_mcp_1_12_4_MIT_License.txt} +0 -0
- /cmdbox/licenses/{LICENSE_multidict_6_6_3_Apache_License_2_0.txt → LICENSE_multidict_6_6_4_Apache_License_2_0.txt} +0 -0
- /cmdbox/licenses/{LICENSE_openai_1_98_0_Apache_Software_License.txt → LICENSE_openai_1_99_9_Apache_Software_License.txt} +0 -0
- /cmdbox/licenses/{LICENSE_redis_6_2_0_MIT_License.txt → LICENSE_redis_6_4_0_MIT_License.txt} +0 -0
- /cmdbox/licenses/{LICENSE_rpds-py_0_26_0_MIT.txt → LICENSE_rpds-py_0_27_0_UNKNOWN.txt} +0 -0
- /cmdbox/licenses/{LICENSE_sphinx-intl_2_3_1_BSD_License.txt → LICENSE_sphinx-intl_2_3_2_UNKNOWN.txt} +0 -0
- /cmdbox/licenses/{LICENSE_tenacity_8_5_0_Apache_Software_License.txt → LICENSE_tenacity_9_1_2_Apache_Software_License.txt} +0 -0
- /cmdbox/licenses/{LICENSE_tiktoken_0_9_0_MIT_License-Copyright-c-2022_OpenAI-Shantanu_Jain-Permission_is_hereby_granted-free_of_charge-to_any_pers.txt → LICENSE_tiktoken_0_11_0_MIT_License-Copyright-c-2022_OpenAI-Shantanu_Jain-Permission_is_hereby_granted-free_of_charge-to_any_per.txt} +0 -0
- {cmdbox-0.6.4.dist-info → cmdbox-0.6.4.2.dist-info}/WHEEL +0 -0
- {cmdbox-0.6.4.dist-info → cmdbox-0.6.4.2.dist-info}/entry_points.txt +0 -0
- {cmdbox-0.6.4.dist-info → cmdbox-0.6.4.2.dist-info}/licenses/LICENSE +0 -0
- {cmdbox-0.6.4.dist-info → cmdbox-0.6.4.2.dist-info}/top_level.txt +0 -0
|
@@ -0,0 +1,192 @@
|
|
|
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.features.cli import cmdbox_vision_start
|
|
5
|
+
from cmdbox.app.options import Options
|
|
6
|
+
from pathlib import Path
|
|
7
|
+
from typing import Dict, Any, Tuple, List, Union
|
|
8
|
+
import argparse
|
|
9
|
+
import logging
|
|
10
|
+
import json
|
|
11
|
+
|
|
12
|
+
|
|
13
|
+
class VisionPredict(cmdbox_vision_start.VisionStart):
|
|
14
|
+
|
|
15
|
+
def get_mode(self) -> Union[str, List[str]]:
|
|
16
|
+
"""
|
|
17
|
+
この機能のモードを返します
|
|
18
|
+
|
|
19
|
+
Returns:
|
|
20
|
+
Union[str, List[str]]: モード
|
|
21
|
+
"""
|
|
22
|
+
return 'vision'
|
|
23
|
+
|
|
24
|
+
def get_cmd(self):
|
|
25
|
+
"""
|
|
26
|
+
この機能のコマンドを返します
|
|
27
|
+
|
|
28
|
+
Returns:
|
|
29
|
+
str: コマンド
|
|
30
|
+
"""
|
|
31
|
+
return 'predict'
|
|
32
|
+
|
|
33
|
+
def get_option(self):
|
|
34
|
+
"""
|
|
35
|
+
この機能のオプションを返します
|
|
36
|
+
|
|
37
|
+
Returns:
|
|
38
|
+
Dict[str, Any]: オプション
|
|
39
|
+
"""
|
|
40
|
+
return dict(
|
|
41
|
+
use_redis=self.USE_REDIS_MEIGHT, nouse_webmode=False, use_agent=True,
|
|
42
|
+
description_ja="画像/動画の推論を実行します。",
|
|
43
|
+
description_en="Executes inference on images/videos.",
|
|
44
|
+
choice=[
|
|
45
|
+
dict(opt="host", type=Options.T_STR, default=self.default_host, required=True, multi=False, hide=True, choice=None, web="mask",
|
|
46
|
+
description_ja="Redisサーバーのサービスホストを指定します。",
|
|
47
|
+
description_en="Specify the service host of the Redis server."),
|
|
48
|
+
dict(opt="port", type=Options.T_INT, default=self.default_port, required=True, multi=False, hide=True, choice=None, web="mask",
|
|
49
|
+
description_ja="Redisサーバーのサービスポートを指定します。",
|
|
50
|
+
description_en="Specify the service port of the Redis server."),
|
|
51
|
+
dict(opt="password", type=Options.T_STR, default=self.default_pass, required=True, multi=False, hide=True, choice=None, web="mask",
|
|
52
|
+
description_ja=f"Redisサーバーのアクセスパスワード(任意)を指定します。省略時は `{self.default_pass}` を使用します。",
|
|
53
|
+
description_en=f"Specify the access password of the Redis server (optional). If omitted, `{self.default_pass}` is used."),
|
|
54
|
+
dict(opt="svname", type=Options.T_STR, default=self.default_svname, required=True, multi=False, hide=True, choice=None, web="readonly",
|
|
55
|
+
description_ja="サーバーのサービス名を指定します。省略時は `server` を使用します。",
|
|
56
|
+
description_en="Specify the service name of the inference server. If omitted, `server` is used."),
|
|
57
|
+
dict(opt="retry_count", type=Options.T_INT, default=3, required=False, multi=False, hide=True, choice=None,
|
|
58
|
+
description_ja="Redisサーバーへの再接続回数を指定します。0以下を指定すると永遠に再接続を行います。",
|
|
59
|
+
description_en="Specifies the number of reconnections to the Redis server.If less than 0 is specified, reconnection is forever."),
|
|
60
|
+
dict(opt="retry_interval", type=Options.T_INT, default=5, required=False, multi=False, hide=True, choice=None,
|
|
61
|
+
description_ja="Redisサーバーに再接続までの秒数を指定します。",
|
|
62
|
+
description_en="Specifies the number of seconds before reconnecting to the Redis server."),
|
|
63
|
+
dict(opt="timeout", type=Options.T_INT, default="60", required=False, multi=False, hide=True, choice=None,
|
|
64
|
+
description_ja="サーバーの応答が返ってくるまでの最大待ち時間を指定。",
|
|
65
|
+
description_en="Specify the maximum waiting time until the server responds."),
|
|
66
|
+
dict(opt="vision_engine", type=Options.T_STR, default="sam2", required=True, multi=False, hide=False,
|
|
67
|
+
choice=["sam2"],
|
|
68
|
+
choice_show=dict(sam2=["sam2_model", "sam2_point"]),
|
|
69
|
+
description_ja="使用するVisionエンジンを指定します。",
|
|
70
|
+
description_en="Specify the Vision engine to use."),
|
|
71
|
+
dict(opt="sam2_model", type=Options.T_STR, default="092824/sam2.1_hiera_tiny.pt", required=True, multi=False, hide=False,
|
|
72
|
+
choice=[k for k in self.VISION_MODEL.keys() if self.VISION_MODEL[k]['type'] == 'sam2'],
|
|
73
|
+
choice_edit=True,
|
|
74
|
+
description_ja="使用するSAM2モデルを指定します。",
|
|
75
|
+
description_en="Specify the SAM2 model to use."),
|
|
76
|
+
dict(opt="sam2_point", type=Options.T_STR, default=None, required=True, multi=True, hide=False, choice=None,
|
|
77
|
+
description_ja="使用するSAM2モデルのポイントを指定します。 `x,y` の形式で指定してください。",
|
|
78
|
+
description_en="Specify the SAM2 model points to use. Please specify in the format `x,y`."),
|
|
79
|
+
]
|
|
80
|
+
)
|
|
81
|
+
|
|
82
|
+
def get_svcmd(self):
|
|
83
|
+
"""
|
|
84
|
+
この機能のサーバー側のコマンドを返します
|
|
85
|
+
|
|
86
|
+
Returns:
|
|
87
|
+
str: サーバー側のコマンド
|
|
88
|
+
"""
|
|
89
|
+
return 'vision_predict'
|
|
90
|
+
|
|
91
|
+
def apprun(self, logger:logging.Logger, args:argparse.Namespace, tm:float, pf:List[Dict[str, float]]=[]) -> Tuple[int, Dict[str, Any], Any]:
|
|
92
|
+
"""
|
|
93
|
+
この機能の実行を行います
|
|
94
|
+
|
|
95
|
+
Args:
|
|
96
|
+
logger (logging.Logger): ロガー
|
|
97
|
+
args (argparse.Namespace): 引数
|
|
98
|
+
tm (float): 実行開始時間
|
|
99
|
+
pf (List[Dict[str, float]]): 呼出元のパフォーマンス情報
|
|
100
|
+
|
|
101
|
+
Returns:
|
|
102
|
+
Tuple[int, Dict[str, Any], Any]: 終了コード, 結果, オブジェクト
|
|
103
|
+
"""
|
|
104
|
+
if args.vision_engine is None:
|
|
105
|
+
msg = dict(warn=f"Please specify the --vision_engine option.")
|
|
106
|
+
common.print_format(msg, False, tm, args.output_json, args.output_json_append, pf=pf)
|
|
107
|
+
return self.RESP_WARN, msg, None
|
|
108
|
+
if args.vision_engine == 'sam2':
|
|
109
|
+
if args.sam2_model is None:
|
|
110
|
+
msg = dict(warn=f"Please specify the --sam2_model option.")
|
|
111
|
+
common.print_format(msg, False, tm, args.output_json, args.output_json_append, pf=pf)
|
|
112
|
+
return self.RESP_WARN, msg, None
|
|
113
|
+
|
|
114
|
+
vision_engine_b64 = convert.str2b64str(args.vision_engine)
|
|
115
|
+
sam2_model_b64 = convert.str2b64str(args.sam2_model)
|
|
116
|
+
sam2_point_b64 = convert.str2b64str(common.to_str(args.sam2_point))
|
|
117
|
+
|
|
118
|
+
cl = client.Client(logger, redis_host=args.host, redis_port=args.port, redis_password=args.password, svname=args.svname)
|
|
119
|
+
ret = cl.redis_cli.send_cmd(self.get_svcmd(),
|
|
120
|
+
[vision_engine_b64, sam2_model_b64, sam2_point_b64],
|
|
121
|
+
retry_count=args.retry_count, retry_interval=args.retry_interval, timeout=args.timeout, nowait=False)
|
|
122
|
+
common.print_format(ret, False, tm, None, False, pf=pf)
|
|
123
|
+
if 'success' not in ret:
|
|
124
|
+
return self.RESP_WARN, ret, cl
|
|
125
|
+
return self.RESP_SUCCESS, ret, cl
|
|
126
|
+
|
|
127
|
+
msg = dict(warn=f"Unsupported vision engine: {args.vision_engine}")
|
|
128
|
+
common.print_format(msg, False, tm, args.output_json, args.output_json_append, pf=pf)
|
|
129
|
+
return self.RESP_WARN, msg, None
|
|
130
|
+
|
|
131
|
+
def is_cluster_redirect(self):
|
|
132
|
+
"""
|
|
133
|
+
クラスター宛のメッセージの場合、メッセージを転送するかどうかを返します
|
|
134
|
+
|
|
135
|
+
Returns:
|
|
136
|
+
bool: メッセージを転送する場合はTrue
|
|
137
|
+
"""
|
|
138
|
+
return False
|
|
139
|
+
|
|
140
|
+
def svrun(self, data_dir:Path, logger:logging.Logger, redis_cli:redis_client.RedisClient, msg:List[str],
|
|
141
|
+
sessions:Dict[str, Dict[str, Any]]) -> int:
|
|
142
|
+
"""
|
|
143
|
+
この機能のサーバー側の実行を行います
|
|
144
|
+
|
|
145
|
+
Args:
|
|
146
|
+
data_dir (Path): データディレクトリ
|
|
147
|
+
logger (logging.Logger): ロガー
|
|
148
|
+
redis_cli (redis_client.RedisClient): Redisクライアント
|
|
149
|
+
msg (List[str]): 受信メッセージ
|
|
150
|
+
sessions (Dict[str, Dict[str, Any]]): セッション情報
|
|
151
|
+
|
|
152
|
+
Returns:
|
|
153
|
+
int: 終了コード
|
|
154
|
+
"""
|
|
155
|
+
if logger.level == logging.DEBUG:
|
|
156
|
+
logger.debug(f"audit write svrun msg: {msg}")
|
|
157
|
+
vision_engine = convert.b64str2str(msg[2])
|
|
158
|
+
sam2_model = convert.b64str2str(msg[3])
|
|
159
|
+
sam2_point = json.loads(convert.b64str2str(msg[4]))
|
|
160
|
+
st = self.predict(msg[1], vision_engine, sam2_model, sam2_point, data_dir, logger, redis_cli, sessions)
|
|
161
|
+
return st
|
|
162
|
+
|
|
163
|
+
def predict(self, reskey:str, vision_engine:str, sam2_model:str, sam2_point:List[List[int]], data_dir:Path, logger:logging.Logger,
|
|
164
|
+
redis_cli:redis_client.RedisClient, sessions:Dict[str, Dict[str, Any]]) -> int:
|
|
165
|
+
"""
|
|
166
|
+
SAM2のモデルを使用して指定したポイントのマスクを取得します
|
|
167
|
+
|
|
168
|
+
Args:
|
|
169
|
+
reskey (str): レスポンスキー
|
|
170
|
+
vision_engine (str): Visionエンジン
|
|
171
|
+
sam2_model (str): SAM2モデル
|
|
172
|
+
sam2_point (List[List[int,int]]): SAM2モデルのポイント
|
|
173
|
+
data_dir (Path): データディレクトリ
|
|
174
|
+
logger (logging.Logger): ロガー
|
|
175
|
+
redis_cli (redis_client.RedisClient): Redisクライアント
|
|
176
|
+
sessions (Dict[str, Dict[str, Any]]): セッション情報
|
|
177
|
+
|
|
178
|
+
Returns:
|
|
179
|
+
int: レスポンスコード
|
|
180
|
+
"""
|
|
181
|
+
try:
|
|
182
|
+
if vision_engine == 'sam2':
|
|
183
|
+
raise NotImplementedError("SAM2 model is not implemented yet.")
|
|
184
|
+
else:
|
|
185
|
+
logger.warning(f"Unsupported vision engine: {vision_engine}")
|
|
186
|
+
redis_cli.rpush(reskey, dict(warn=f"Unsupported vision engine: {vision_engine}"))
|
|
187
|
+
return self.RESP_WARN
|
|
188
|
+
|
|
189
|
+
except Exception as e:
|
|
190
|
+
logger.warning(f"Failed to start: {e}", exc_info=True)
|
|
191
|
+
redis_cli.rpush(reskey, dict(warn=f"Failed to start: {e}"))
|
|
192
|
+
return self.RESP_WARN
|
|
@@ -0,0 +1,230 @@
|
|
|
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 VisionStart(feature.UnsupportEdgeFeature):
|
|
12
|
+
VISION_MODEL = dict()
|
|
13
|
+
VISION_MODEL['092824/sam2.1_hiera_tiny'] = dict(type='sam2',
|
|
14
|
+
path='092824/sam2.1_hiera_tiny.pt',
|
|
15
|
+
conf='configs/sam2.1/sam2.1_hiera_t.yaml',
|
|
16
|
+
url='https://dl.fbaipublicfiles.com/segment_anything_2/092824/sam2.1_hiera_tiny.pt')
|
|
17
|
+
VISION_MODEL['092824/sam2.1_hiera_small'] = dict(type='sam2',
|
|
18
|
+
path='092824/sam2.1_hiera_small.pt',
|
|
19
|
+
conf='configs/sam2.1/sam2.1_hiera_s.yaml',
|
|
20
|
+
url='https://dl.fbaipublicfiles.com/segment_anything_2/092824/sam2.1_hiera_small.pt')
|
|
21
|
+
VISION_MODEL['092824/sam2.1_hiera_base_plus'] = dict(type='sam2',
|
|
22
|
+
path='092824/sam2.1_hiera_base_plus.pt',
|
|
23
|
+
conf='configs/sam2.1/sam2.1_hiera_b+.yaml',
|
|
24
|
+
url='https://dl.fbaipublicfiles.com/segment_anything_2/092824/sam2.1_hiera_base_plus.pt')
|
|
25
|
+
VISION_MODEL['092824/sam2.1_hiera_large'] = dict(type='sam2',
|
|
26
|
+
path='092824/sam2.1_hiera_large.pt',
|
|
27
|
+
conf='configs/sam2.1/sam2.1_hiera_l.yaml',
|
|
28
|
+
url='https://dl.fbaipublicfiles.com/segment_anything_2/092824/sam2.1_hiera_large.pt')
|
|
29
|
+
|
|
30
|
+
def get_mode(self) -> Union[str, List[str]]:
|
|
31
|
+
"""
|
|
32
|
+
この機能のモードを返します
|
|
33
|
+
|
|
34
|
+
Returns:
|
|
35
|
+
Union[str, List[str]]: モード
|
|
36
|
+
"""
|
|
37
|
+
return 'vision'
|
|
38
|
+
|
|
39
|
+
def get_cmd(self):
|
|
40
|
+
"""
|
|
41
|
+
この機能のコマンドを返します
|
|
42
|
+
|
|
43
|
+
Returns:
|
|
44
|
+
str: コマンド
|
|
45
|
+
"""
|
|
46
|
+
return 'start'
|
|
47
|
+
|
|
48
|
+
def get_option(self):
|
|
49
|
+
"""
|
|
50
|
+
この機能のオプションを返します
|
|
51
|
+
|
|
52
|
+
Returns:
|
|
53
|
+
Dict[str, Any]: オプション
|
|
54
|
+
"""
|
|
55
|
+
return dict(
|
|
56
|
+
use_redis=self.USE_REDIS_MEIGHT, nouse_webmode=False, use_agent=True,
|
|
57
|
+
description_ja="画像/動画の推論を開始します。",
|
|
58
|
+
description_en="Starts inference on images/videos.",
|
|
59
|
+
choice=[
|
|
60
|
+
dict(opt="host", type=Options.T_STR, default=self.default_host, required=True, multi=False, hide=True, choice=None, web="mask",
|
|
61
|
+
description_ja="Redisサーバーのサービスホストを指定します。",
|
|
62
|
+
description_en="Specify the service host of the Redis server."),
|
|
63
|
+
dict(opt="port", type=Options.T_INT, default=self.default_port, required=True, multi=False, hide=True, choice=None, web="mask",
|
|
64
|
+
description_ja="Redisサーバーのサービスポートを指定します。",
|
|
65
|
+
description_en="Specify the service port of the Redis server."),
|
|
66
|
+
dict(opt="password", type=Options.T_STR, default=self.default_pass, required=True, multi=False, hide=True, choice=None, web="mask",
|
|
67
|
+
description_ja=f"Redisサーバーのアクセスパスワード(任意)を指定します。省略時は `{self.default_pass}` を使用します。",
|
|
68
|
+
description_en=f"Specify the access password of the Redis server (optional). If omitted, `{self.default_pass}` is used."),
|
|
69
|
+
dict(opt="svname", type=Options.T_STR, default=self.default_svname, required=True, multi=False, hide=True, choice=None, web="readonly",
|
|
70
|
+
description_ja="サーバーのサービス名を指定します。省略時は `server` を使用します。",
|
|
71
|
+
description_en="Specify the service name of the inference server. If omitted, `server` is used."),
|
|
72
|
+
dict(opt="retry_count", type=Options.T_INT, default=3, required=False, multi=False, hide=True, choice=None,
|
|
73
|
+
description_ja="Redisサーバーへの再接続回数を指定します。0以下を指定すると永遠に再接続を行います。",
|
|
74
|
+
description_en="Specifies the number of reconnections to the Redis server.If less than 0 is specified, reconnection is forever."),
|
|
75
|
+
dict(opt="retry_interval", type=Options.T_INT, default=5, required=False, multi=False, hide=True, choice=None,
|
|
76
|
+
description_ja="Redisサーバーに再接続までの秒数を指定します。",
|
|
77
|
+
description_en="Specifies the number of seconds before reconnecting to the Redis server."),
|
|
78
|
+
dict(opt="timeout", type=Options.T_INT, default="60", required=False, multi=False, hide=True, choice=None,
|
|
79
|
+
description_ja="サーバーの応答が返ってくるまでの最大待ち時間を指定。",
|
|
80
|
+
description_en="Specify the maximum waiting time until the server responds."),
|
|
81
|
+
dict(opt="vision_engine", type=Options.T_STR, default="sam2", required=True, multi=False, hide=False,
|
|
82
|
+
choice=["sam2"],
|
|
83
|
+
choice_show=dict(sam2=["sam2_model"]),
|
|
84
|
+
description_ja="使用するVisionエンジンを指定します。",
|
|
85
|
+
description_en="Specify the Vision engine to use."),
|
|
86
|
+
dict(opt="sam2_model", type=Options.T_STR, default="092824/sam2.1_hiera_tiny.pt", required=True, multi=False, hide=False,
|
|
87
|
+
choice=[k for k in self.VISION_MODEL.keys() if self.VISION_MODEL[k]['type'] == 'sam2'],
|
|
88
|
+
choice_edit=True,
|
|
89
|
+
description_ja="使用するSAM2モデルを指定します。",
|
|
90
|
+
description_en="Specify the SAM2 model to use."),
|
|
91
|
+
]
|
|
92
|
+
)
|
|
93
|
+
|
|
94
|
+
def get_svcmd(self):
|
|
95
|
+
"""
|
|
96
|
+
この機能のサーバー側のコマンドを返します
|
|
97
|
+
|
|
98
|
+
Returns:
|
|
99
|
+
str: サーバー側のコマンド
|
|
100
|
+
"""
|
|
101
|
+
return 'vision_start'
|
|
102
|
+
|
|
103
|
+
def apprun(self, logger:logging.Logger, args:argparse.Namespace, tm:float, pf:List[Dict[str, float]]=[]) -> Tuple[int, Dict[str, Any], Any]:
|
|
104
|
+
"""
|
|
105
|
+
この機能の実行を行います
|
|
106
|
+
|
|
107
|
+
Args:
|
|
108
|
+
logger (logging.Logger): ロガー
|
|
109
|
+
args (argparse.Namespace): 引数
|
|
110
|
+
tm (float): 実行開始時間
|
|
111
|
+
pf (List[Dict[str, float]]): 呼出元のパフォーマンス情報
|
|
112
|
+
|
|
113
|
+
Returns:
|
|
114
|
+
Tuple[int, Dict[str, Any], Any]: 終了コード, 結果, オブジェクト
|
|
115
|
+
"""
|
|
116
|
+
if args.vision_engine is None:
|
|
117
|
+
msg = dict(warn=f"Please specify the --vision_engine option.")
|
|
118
|
+
common.print_format(msg, False, tm, args.output_json, args.output_json_append, pf=pf)
|
|
119
|
+
return self.RESP_WARN, msg, None
|
|
120
|
+
if args.vision_engine == 'sam2':
|
|
121
|
+
if args.sam2_model is None:
|
|
122
|
+
msg = dict(warn=f"Please specify the --sam2_model option.")
|
|
123
|
+
common.print_format(msg, False, tm, args.output_json, args.output_json_append, pf=pf)
|
|
124
|
+
return self.RESP_WARN, msg, None
|
|
125
|
+
|
|
126
|
+
vision_engine_b64 = convert.str2b64str(args.vision_engine)
|
|
127
|
+
sam2_model_b64 = convert.str2b64str(args.sam2_model)
|
|
128
|
+
cl = client.Client(logger, redis_host=args.host, redis_port=args.port, redis_password=args.password, svname=args.svname)
|
|
129
|
+
ret = cl.redis_cli.send_cmd(self.get_svcmd(),
|
|
130
|
+
[vision_engine_b64, sam2_model_b64],
|
|
131
|
+
retry_count=args.retry_count, retry_interval=args.retry_interval, timeout=args.timeout, nowait=False)
|
|
132
|
+
common.print_format(ret, False, tm, None, False, pf=pf)
|
|
133
|
+
if 'success' not in ret:
|
|
134
|
+
return self.RESP_WARN, ret, cl
|
|
135
|
+
return self.RESP_SUCCESS, ret, cl
|
|
136
|
+
|
|
137
|
+
msg = dict(warn=f"Unsupported vision engine: {args.vision_engine}")
|
|
138
|
+
common.print_format(msg, False, tm, args.output_json, args.output_json_append, pf=pf)
|
|
139
|
+
return self.RESP_WARN, msg, None
|
|
140
|
+
|
|
141
|
+
def is_cluster_redirect(self):
|
|
142
|
+
"""
|
|
143
|
+
クラスター宛のメッセージの場合、メッセージを転送するかどうかを返します
|
|
144
|
+
|
|
145
|
+
Returns:
|
|
146
|
+
bool: メッセージを転送する場合はTrue
|
|
147
|
+
"""
|
|
148
|
+
return True
|
|
149
|
+
|
|
150
|
+
def svrun(self, data_dir:Path, logger:logging.Logger, redis_cli:redis_client.RedisClient, msg:List[str],
|
|
151
|
+
sessions:Dict[str, Dict[str, Any]]) -> int:
|
|
152
|
+
"""
|
|
153
|
+
この機能のサーバー側の実行を行います
|
|
154
|
+
|
|
155
|
+
Args:
|
|
156
|
+
data_dir (Path): データディレクトリ
|
|
157
|
+
logger (logging.Logger): ロガー
|
|
158
|
+
redis_cli (redis_client.RedisClient): Redisクライアント
|
|
159
|
+
msg (List[str]): 受信メッセージ
|
|
160
|
+
sessions (Dict[str, Dict[str, Any]]): セッション情報
|
|
161
|
+
|
|
162
|
+
Returns:
|
|
163
|
+
int: 終了コード
|
|
164
|
+
"""
|
|
165
|
+
if logger.level == logging.DEBUG:
|
|
166
|
+
logger.debug(f"audit write svrun msg: {msg}")
|
|
167
|
+
vision_engine = convert.b64str2str(msg[2])
|
|
168
|
+
sam2_model = convert.b64str2str(msg[3])
|
|
169
|
+
st = self.start(msg[1], vision_engine, sam2_model, data_dir, logger, redis_cli, sessions)
|
|
170
|
+
return st
|
|
171
|
+
|
|
172
|
+
def start(self, reskey:str, vision_engine:str, sam2_model:str, data_dir:Path, logger:logging.Logger,
|
|
173
|
+
redis_cli:redis_client.RedisClient, sessions:Dict[str, Dict[str, Any]]) -> int:
|
|
174
|
+
"""
|
|
175
|
+
SAM2のモデルを開始します
|
|
176
|
+
|
|
177
|
+
Args:
|
|
178
|
+
reskey (str): レスポンスキー
|
|
179
|
+
vision_engine (str): Visionエンジン
|
|
180
|
+
sam2_model (str): SAM2モデル
|
|
181
|
+
data_dir (Path): データディレクトリ
|
|
182
|
+
logger (logging.Logger): ロガー
|
|
183
|
+
redis_cli (redis_client.RedisClient): Redisクライアント
|
|
184
|
+
sessions (Dict[str, Dict[str, Any]]): セッション情報
|
|
185
|
+
|
|
186
|
+
Returns:
|
|
187
|
+
int: レスポンスコード
|
|
188
|
+
"""
|
|
189
|
+
try:
|
|
190
|
+
if vision_engine == 'sam2':
|
|
191
|
+
#===============================================================
|
|
192
|
+
# SAM2モデルの初期化
|
|
193
|
+
from sam2.build_sam import build_sam2
|
|
194
|
+
from sam2.sam2_image_predictor import SAM2ImagePredictor
|
|
195
|
+
#from sam2.sam2_video_predictor import SAM2VideoPredictor
|
|
196
|
+
import torch
|
|
197
|
+
|
|
198
|
+
sam2_dir = Path(version.__file__).parent / '.sam2' / 'model'
|
|
199
|
+
if not sam2_dir.exists():
|
|
200
|
+
logger.error(f"Failed to start SAM2 model: sam2 directory does not exist: {sam2_dir}")
|
|
201
|
+
redis_cli.rpush(reskey, dict(warn=f"Failed to start SAM2 model: sam2 directory does not exist: {sam2_dir}"))
|
|
202
|
+
return self.RESP_WARN
|
|
203
|
+
|
|
204
|
+
model_file = sam2_dir / self.VISION_MODEL[sam2_model]['path']
|
|
205
|
+
config_file = self.VISION_MODEL[sam2_model]['conf']
|
|
206
|
+
if not model_file.exists():
|
|
207
|
+
logger.error(f"Failed to start SAM2 model: model file does not exist: {model_file}")
|
|
208
|
+
redis_cli.rpush(reskey, dict(warn=f"Failed to start SAM2 model: model file does not exist: {model_file}"))
|
|
209
|
+
return self.RESP_WARN
|
|
210
|
+
|
|
211
|
+
device = 'cuda' if torch.cuda.is_available() else 'cpu'
|
|
212
|
+
# vvmファイルの読込み
|
|
213
|
+
predictor = SAM2ImagePredictor(build_sam2(config_file, model_file, device=device))
|
|
214
|
+
sessions[sam2_model] = dict(
|
|
215
|
+
info=self.VISION_MODEL[sam2_model].copy(),
|
|
216
|
+
predictor=predictor,
|
|
217
|
+
)
|
|
218
|
+
#===============================================================
|
|
219
|
+
# 成功時の処理
|
|
220
|
+
rescode, msg = (self.RESP_SUCCESS, dict(success=f'Success to start SAM2. Model: {sam2_model}'))
|
|
221
|
+
redis_cli.rpush(reskey, msg)
|
|
222
|
+
return rescode
|
|
223
|
+
else:
|
|
224
|
+
logger.warning(f"Unsupported vision engine: {vision_engine}")
|
|
225
|
+
redis_cli.rpush(reskey, dict(warn=f"Unsupported vision engine: {vision_engine}"))
|
|
226
|
+
return self.RESP_WARN
|
|
227
|
+
except Exception as e:
|
|
228
|
+
logger.warning(f"Failed to start: {e}", exc_info=True)
|
|
229
|
+
redis_cli.rpush(reskey, dict(warn=f"Failed to start: {e}"))
|
|
230
|
+
return self.RESP_WARN
|
|
@@ -33,7 +33,7 @@ class WebApikeyAdd(feature.UnsupportEdgeFeature):
|
|
|
33
33
|
Dict[str, Any]: オプション
|
|
34
34
|
"""
|
|
35
35
|
return dict(
|
|
36
|
-
use_redis=self.USE_REDIS_MEIGHT, nouse_webmode=False,
|
|
36
|
+
use_redis=self.USE_REDIS_MEIGHT, nouse_webmode=False, use_agent=False,
|
|
37
37
|
description_ja="WebモードのユーザーのApiKeyを追加します。",
|
|
38
38
|
description_en="Add an ApiKey for a user in Web mode.",
|
|
39
39
|
choice=[
|
|
@@ -33,7 +33,7 @@ class WebApikeyDel(feature.UnsupportEdgeFeature):
|
|
|
33
33
|
Dict[str, Any]: オプション
|
|
34
34
|
"""
|
|
35
35
|
return dict(
|
|
36
|
-
use_redis=self.USE_REDIS_MEIGHT, nouse_webmode=False,
|
|
36
|
+
use_redis=self.USE_REDIS_MEIGHT, nouse_webmode=False, use_agent=False,
|
|
37
37
|
description_ja="WebモードのユーザーのApiKeyを削除します。",
|
|
38
38
|
description_en="Del an ApiKey for a user in Web mode.",
|
|
39
39
|
choice=[
|
|
@@ -38,7 +38,7 @@ class WebGencert(feature.UnsupportEdgeFeature):
|
|
|
38
38
|
Dict[str, Any]: オプション
|
|
39
39
|
"""
|
|
40
40
|
return dict(
|
|
41
|
-
use_redis=self.USE_REDIS_FALSE, nouse_webmode=False,
|
|
41
|
+
use_redis=self.USE_REDIS_FALSE, nouse_webmode=False, use_agent=False,
|
|
42
42
|
description_ja="webモードでSSLを簡易的に実装するために自己署名証明書を生成します。",
|
|
43
43
|
description_en="Generate a self-signed certificate for simple implementation of SSL in web mode.",
|
|
44
44
|
choice=[
|
|
@@ -40,7 +40,7 @@ class WebGenpass(feature.OneshotResultEdgeFeature):
|
|
|
40
40
|
Dict[str, Any]: オプション
|
|
41
41
|
"""
|
|
42
42
|
return dict(
|
|
43
|
-
use_redis=self.USE_REDIS_FALSE, nouse_webmode=False,
|
|
43
|
+
use_redis=self.USE_REDIS_FALSE, nouse_webmode=False, use_agent=True,
|
|
44
44
|
description_ja="webモードで使用できるパスワード文字列を生成します。",
|
|
45
45
|
description_en="Generates a password string that can be used in web mode.",
|
|
46
46
|
choice=[
|
|
@@ -33,7 +33,7 @@ class WebGroupAdd(feature.UnsupportEdgeFeature):
|
|
|
33
33
|
Dict[str, Any]: オプション
|
|
34
34
|
"""
|
|
35
35
|
return dict(
|
|
36
|
-
use_redis=self.USE_REDIS_MEIGHT, nouse_webmode=False,
|
|
36
|
+
use_redis=self.USE_REDIS_MEIGHT, nouse_webmode=False, use_agent=False,
|
|
37
37
|
description_ja="Webモードのグループを追加します。",
|
|
38
38
|
description_en="Add a group in Web mode.",
|
|
39
39
|
choice=[
|
|
@@ -33,7 +33,7 @@ class WebGroupDel(feature.UnsupportEdgeFeature):
|
|
|
33
33
|
Dict[str, Any]: オプション
|
|
34
34
|
"""
|
|
35
35
|
return dict(
|
|
36
|
-
use_redis=self.USE_REDIS_MEIGHT, nouse_webmode=False,
|
|
36
|
+
use_redis=self.USE_REDIS_MEIGHT, nouse_webmode=False, use_agent=False,
|
|
37
37
|
description_ja="Webモードのグループを削除します。",
|
|
38
38
|
description_en="Del a group in Web mode.",
|
|
39
39
|
choice=[
|
|
@@ -33,7 +33,7 @@ class WebGroupEdit(feature.UnsupportEdgeFeature):
|
|
|
33
33
|
Dict[str, Any]: オプション
|
|
34
34
|
"""
|
|
35
35
|
return dict(
|
|
36
|
-
use_redis=self.USE_REDIS_MEIGHT, nouse_webmode=False,
|
|
36
|
+
use_redis=self.USE_REDIS_MEIGHT, nouse_webmode=False, use_agent=False,
|
|
37
37
|
description_ja="Webモードのグループを編集します。",
|
|
38
38
|
description_en="Edit a group in Web mode.",
|
|
39
39
|
choice=[
|
|
@@ -6,7 +6,7 @@ import argparse
|
|
|
6
6
|
import logging
|
|
7
7
|
|
|
8
8
|
|
|
9
|
-
class WebGroupList(feature.
|
|
9
|
+
class WebGroupList(feature.UnsupportEdgeFeature):
|
|
10
10
|
def get_mode(self) -> Union[str, List[str]]:
|
|
11
11
|
"""
|
|
12
12
|
この機能のモードを返します
|
|
@@ -33,7 +33,7 @@ class WebGroupList(feature.OneshotResultEdgeFeature):
|
|
|
33
33
|
Dict[str, Any]: オプション
|
|
34
34
|
"""
|
|
35
35
|
return dict(
|
|
36
|
-
use_redis=self.USE_REDIS_MEIGHT, nouse_webmode=False,
|
|
36
|
+
use_redis=self.USE_REDIS_MEIGHT, nouse_webmode=False, use_agent=False,
|
|
37
37
|
description_ja="Webモードのグループー一覧を取得します。",
|
|
38
38
|
description_en="Get a list of users in Web mode.",
|
|
39
39
|
choice=[
|
|
@@ -38,6 +38,7 @@ class WebStart(feature.UnsupportEdgeFeature, agent_base.AgentBase):
|
|
|
38
38
|
opt = super().get_option()
|
|
39
39
|
opt['use_redis'] = self.USE_REDIS_MEIGHT
|
|
40
40
|
opt['nouse_webmode'] = True
|
|
41
|
+
opt['use_agent'] = False
|
|
41
42
|
opt['description_ja'] = "Webモードを起動します。"
|
|
42
43
|
opt['description_en'] = "Start Web mode."
|
|
43
44
|
opt['choice'] += [
|
|
@@ -33,7 +33,7 @@ class WebStop(feature.UnsupportEdgeFeature):
|
|
|
33
33
|
Dict[str, Any]: オプション
|
|
34
34
|
"""
|
|
35
35
|
return dict(
|
|
36
|
-
use_redis=self.USE_REDIS_MEIGHT, nouse_webmode=True,
|
|
36
|
+
use_redis=self.USE_REDIS_MEIGHT, nouse_webmode=True, use_agent=False,
|
|
37
37
|
description_ja="Webモードを停止します。",
|
|
38
38
|
description_en="Stop Web mode.",
|
|
39
39
|
choice=[
|
|
@@ -33,7 +33,7 @@ class WebUserAdd(feature.UnsupportEdgeFeature):
|
|
|
33
33
|
Dict[str, Any]: オプション
|
|
34
34
|
"""
|
|
35
35
|
return dict(
|
|
36
|
-
use_redis=self.USE_REDIS_MEIGHT, nouse_webmode=False,
|
|
36
|
+
use_redis=self.USE_REDIS_MEIGHT, nouse_webmode=False, use_agent=False,
|
|
37
37
|
description_ja="Webモードのユーザーを追加します。",
|
|
38
38
|
description_en="Add a user in Web mode.",
|
|
39
39
|
choice=[
|
|
@@ -33,7 +33,7 @@ class WebUserDel(feature.UnsupportEdgeFeature):
|
|
|
33
33
|
Dict[str, Any]: オプション
|
|
34
34
|
"""
|
|
35
35
|
return dict(
|
|
36
|
-
use_redis=self.USE_REDIS_MEIGHT, nouse_webmode=False,
|
|
36
|
+
use_redis=self.USE_REDIS_MEIGHT, nouse_webmode=False, use_agent=False,
|
|
37
37
|
description_ja="Webモードのユーザーを削除します。",
|
|
38
38
|
description_en="Delete a user in Web mode.",
|
|
39
39
|
choice=[
|
|
@@ -33,7 +33,7 @@ class WebUserEdit(feature.UnsupportEdgeFeature):
|
|
|
33
33
|
Dict[str, Any]: オプション
|
|
34
34
|
"""
|
|
35
35
|
return dict(
|
|
36
|
-
use_redis=self.USE_REDIS_MEIGHT, nouse_webmode=False,
|
|
36
|
+
use_redis=self.USE_REDIS_MEIGHT, nouse_webmode=False, use_agent=False,
|
|
37
37
|
description_ja="Webモードのユーザーを編集します。",
|
|
38
38
|
description_en="Edit users in Web mode.",
|
|
39
39
|
choice=[
|
|
@@ -6,7 +6,7 @@ import argparse
|
|
|
6
6
|
import logging
|
|
7
7
|
|
|
8
8
|
|
|
9
|
-
class WebUserList(feature.
|
|
9
|
+
class WebUserList(feature.UnsupportEdgeFeature):
|
|
10
10
|
def get_mode(self) -> Union[str, List[str]]:
|
|
11
11
|
"""
|
|
12
12
|
この機能のモードを返します
|
|
@@ -33,7 +33,7 @@ class WebUserList(feature.OneshotResultEdgeFeature):
|
|
|
33
33
|
Dict[str, Any]: オプション
|
|
34
34
|
"""
|
|
35
35
|
return dict(
|
|
36
|
-
use_redis=self.USE_REDIS_MEIGHT, nouse_webmode=False,
|
|
36
|
+
use_redis=self.USE_REDIS_MEIGHT, nouse_webmode=False, use_agent=False,
|
|
37
37
|
description_ja="Webモードのユーザー一覧を取得します。",
|
|
38
38
|
description_en="Get a list of users in Web mode.",
|
|
39
39
|
choice=[
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
from cmdbox.app import common, feature
|
|
2
2
|
from cmdbox.app.auth import signin
|
|
3
|
+
from cmdbox.app.features.cli import agent_base
|
|
3
4
|
from cmdbox.app.web import Web
|
|
4
5
|
from fastapi import FastAPI, Depends, HTTPException, Request, Response, WebSocket
|
|
5
6
|
from fastapi.responses import HTMLResponse, StreamingResponse
|
|
@@ -38,6 +39,16 @@ class Agent(feature.WebFeature):
|
|
|
38
39
|
web.options.audit_exec(req, res, web)
|
|
39
40
|
return web.agent_html_data
|
|
40
41
|
|
|
42
|
+
@app.get('/agent/llmsetting')
|
|
43
|
+
async def agent(req:Request, res:Response):
|
|
44
|
+
signin = web.signin.check_signin(req, res)
|
|
45
|
+
if signin is not None:
|
|
46
|
+
return signin
|
|
47
|
+
res.headers['Access-Control-Allow-Origin'] = '*'
|
|
48
|
+
web.options.audit_exec(req, res, web)
|
|
49
|
+
cmd = agent_base.AgentBase(web.appcls, web.ver)
|
|
50
|
+
return cmd.get_option().get('choice')
|
|
51
|
+
|
|
41
52
|
@app.post('/agent/session/list')
|
|
42
53
|
async def agent_session_list(req:Request, res:Response):
|
|
43
54
|
signin = web.signin.check_signin(req, res)
|
|
@@ -150,12 +161,9 @@ class Agent(feature.WebFeature):
|
|
|
150
161
|
if 'signin' in session:
|
|
151
162
|
user_id = session['signin']['name']
|
|
152
163
|
groups = session['signin']['groups']
|
|
153
|
-
# 言語認識
|
|
154
|
-
language, _ = locale.getlocale()
|
|
155
|
-
is_japan = language.find('Japan') >= 0 or language.find('ja_JP') >= 0
|
|
156
164
|
# セッションを作成する
|
|
157
165
|
agent_session = await web.create_agent_session(web.agent_runner.session_service, user_id, session_id=session_id)
|
|
158
|
-
startmsg = "こんにちは!何かお手伝いできることはありますか?" if is_japan else "Hello! Is there anything I can help you with?"
|
|
166
|
+
startmsg = "こんにちは!何かお手伝いできることはありますか?" if common.is_japan() else "Hello! Is there anything I can help you with?"
|
|
159
167
|
yield json.dumps(dict(message=startmsg), default=common.default_json_enc)
|
|
160
168
|
def _replace_match(match_obj):
|
|
161
169
|
json_str = match_obj.group(0)
|
|
@@ -229,6 +237,10 @@ class Agent(feature.WebFeature):
|
|
|
229
237
|
break
|
|
230
238
|
except self.SSEDisconnect as e:
|
|
231
239
|
break
|
|
240
|
+
except NotImplementedError as e:
|
|
241
|
+
web.logger.warning(f'The session table needs to be reloaded.{e}', exc_info=True)
|
|
242
|
+
yield json.dumps(dict(message=f'The session table needs to be reloaded. Please reload your browser.'), default=common.default_json_enc)
|
|
243
|
+
break
|
|
232
244
|
except Exception as e:
|
|
233
245
|
web.logger.warning(f'chat error.', exc_info=True)
|
|
234
246
|
yield json.dumps(dict(message=f'<pre>{traceback.format_exc()}</pre>'), default=common.default_json_enc)
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
from cmdbox.app import feature
|
|
1
|
+
from cmdbox.app import common, feature
|
|
2
2
|
from cmdbox.app.web import Web
|
|
3
3
|
from fastapi import FastAPI, Request, Response, HTTPException
|
|
4
4
|
|
|
@@ -20,5 +20,13 @@ class GetCmdChoices(feature.WebFeature):
|
|
|
20
20
|
form = await req.form()
|
|
21
21
|
mode = form.get('mode')
|
|
22
22
|
cmd = form.get('cmd')
|
|
23
|
-
ret = web.options.get_cmd_choices(mode, cmd, True)
|
|
23
|
+
ret = web.options.get_cmd_choices(mode, cmd, True).copy()
|
|
24
|
+
fobj = web.options.get_cmd_attr(mode, cmd, 'feature')
|
|
25
|
+
desc = web.options.get_cmd_attr(mode, cmd, 'description_en' if not common.is_japan() else 'description_ja')
|
|
26
|
+
desc_nouse_webmode = '\U00002B55 Web' if not web.options.get_cmd_attr(mode, cmd, 'nouse_webmode') else '\U0000274C Web'
|
|
27
|
+
desc_use_agent = '\U00002B55 Agent' if web.options.get_cmd_attr(mode, cmd, 'use_agent') else '\U0000274C Agent'
|
|
28
|
+
desc_edge = '\U00002B55 Edge' if not isinstance(fobj, feature.UnsupportEdgeFeature) else '\U0000274C Edge'
|
|
29
|
+
help = dict(opt="help", type=web.options.T_TEXT, default=f"\U00002B55 CLI, {desc_nouse_webmode}, {desc_use_agent}, {desc_edge}, {desc}",
|
|
30
|
+
required=False, multi=False, hide=False, choice=None, description_ja="-", description_en="-")
|
|
31
|
+
ret.insert(0, help)
|
|
24
32
|
return ret
|