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
cmdbox/app/app.py
CHANGED
|
@@ -6,6 +6,7 @@ import argparse
|
|
|
6
6
|
import argcomplete
|
|
7
7
|
import logging
|
|
8
8
|
import time
|
|
9
|
+
import threading
|
|
9
10
|
import sys
|
|
10
11
|
|
|
11
12
|
|
|
@@ -180,4 +181,9 @@ class CmdBoxApp:
|
|
|
180
181
|
アプリケーションの設定を読み込みます。
|
|
181
182
|
"""
|
|
182
183
|
logger, _ = common.load_config(args.mode, debug=args.debug, data=args.data, webcall=webcall if args.cmd != 'webcap' else True, ver=self.ver)
|
|
184
|
+
if not hasattr(common, 'logsv') and hasattr(args, 'logsv') and args.logsv:
|
|
185
|
+
from cmdbox.app.commons import loghandler
|
|
186
|
+
common.logsv = loghandler.LogRecordTCPServer("logsv", host="localhost", port=9020, debug=args.debug)
|
|
187
|
+
threading.Thread(daemon=True, target=common.logsv.serve_until_stopped, name="logsv").start()
|
|
188
|
+
|
|
183
189
|
return logger
|
cmdbox/app/common.py
CHANGED
|
@@ -4,7 +4,6 @@ from cmdbox.app.commons import convert, module, loghandler
|
|
|
4
4
|
from cryptography.fernet import Fernet
|
|
5
5
|
from pathlib import Path
|
|
6
6
|
from rich.console import Console
|
|
7
|
-
from rich.logging import RichHandler
|
|
8
7
|
from tabulate import tabulate
|
|
9
8
|
from typing import List, Tuple, Dict, Any
|
|
10
9
|
import argparse
|
|
@@ -195,7 +194,7 @@ def console_log(console:Console, message:Any, highlight:bool=True, **kwargs) ->
|
|
|
195
194
|
**kwargs: その他のキーワード引数
|
|
196
195
|
"""
|
|
197
196
|
dtstr = datetime.datetime.now().strftime('[%Y-%m-%d %H:%M:%S]')
|
|
198
|
-
console.print(f"{dtstr} {message}", highlight=highlight, **kwargs)
|
|
197
|
+
console.print(f"{dtstr} {message}", highlight=highlight, crop=False, soft_wrap=True, **kwargs)
|
|
199
198
|
|
|
200
199
|
def default_logger(debug:bool=False, ver=version, webcall:bool=False) -> logging.Logger:
|
|
201
200
|
"""
|
|
@@ -268,8 +267,12 @@ def load_config(mode:str, debug:bool=False, data=HOME_DIR, webcall:bool=False, v
|
|
|
268
267
|
for k, l in log_config['loggers'].items():
|
|
269
268
|
if 'handlers' in l and std_key in l['handlers']:
|
|
270
269
|
l['handlers'].remove(std_key)
|
|
271
|
-
if 'loggers' not in log_config
|
|
272
|
-
raise BaseException(f"Loggers not found
|
|
270
|
+
if 'loggers' not in log_config:
|
|
271
|
+
raise BaseException(f"Loggers not found at log_conf_path={log_conf_path}")
|
|
272
|
+
if log_name not in log_config['loggers']:
|
|
273
|
+
if ver.__appid__ not in log_config['loggers']:
|
|
274
|
+
raise BaseException(f"Loggers not found.({ver.__appid__}) at log_conf_path={log_conf_path}")
|
|
275
|
+
log_name = ver.__appid__
|
|
273
276
|
log_config['disable_existing_loggers'] = False # これを入れないとdictConfigで既存のロガーが無効になる
|
|
274
277
|
logging.config.dictConfig(log_config)
|
|
275
278
|
logger = logging.getLogger(log_name)
|
cmdbox/app/commons/loghandler.py
CHANGED
|
@@ -4,6 +4,11 @@ from rich.theme import Theme
|
|
|
4
4
|
import re
|
|
5
5
|
import logging
|
|
6
6
|
import logging.handlers
|
|
7
|
+
import pickle
|
|
8
|
+
import socketserver
|
|
9
|
+
import struct
|
|
10
|
+
import socket
|
|
11
|
+
|
|
7
12
|
|
|
8
13
|
class Colors:
|
|
9
14
|
S = "\033["
|
|
@@ -103,6 +108,9 @@ theme=Theme({
|
|
|
103
108
|
"repr.log_success": "green",})
|
|
104
109
|
|
|
105
110
|
class LogLevelHighlighter(highlighter.ReprHighlighter):
|
|
111
|
+
"""
|
|
112
|
+
ログメッセージのログレベルをハイライトします。
|
|
113
|
+
"""
|
|
106
114
|
def __init__(self):
|
|
107
115
|
#self.highlights = []
|
|
108
116
|
self.highlights.append(r"(?P<log_debug>DEBUG|EXEC)")
|
|
@@ -112,29 +120,12 @@ class LogLevelHighlighter(highlighter.ReprHighlighter):
|
|
|
112
120
|
self.highlights.append(r"(?P<log_fatal>FATAL|CRITICAL)")
|
|
113
121
|
self.highlights.append(r"(?P<log_product>CMDBOX|IINFER|USOUND|GAIAN|GAIC|WITSHAPE)")
|
|
114
122
|
self.highlights.append(r"(?P<log_success>SUCCESS|OK|PASSED|DONE|COMPLETE|START|FINISH|OPEN|CONNECTED|ALLOW)")
|
|
115
|
-
"""
|
|
116
|
-
self.highlights.append(r"(?P<tag_start><)(?P<tag_name>[-\w.:|]*)(?P<tag_contents>[\w\W]*)(?P<tag_end>>)")
|
|
117
|
-
self.highlights.append(r'(?P<attrib_name>[\w_]{1,50})=(?P<attrib_value>"?[\w_]+"?)?')
|
|
118
|
-
self.highlights.append(r"(?P<brace>[][{}()])")
|
|
119
|
-
self.highlights.append(highlighter._combine_regex(
|
|
120
|
-
r"(?P<ipv4>[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3})",
|
|
121
|
-
r"(?P<ipv6>([A-Fa-f0-9]{1,4}::?){1,7}[A-Fa-f0-9]{1,4})",
|
|
122
|
-
r"(?P<eui64>(?:[0-9A-Fa-f]{1,2}-){7}[0-9A-Fa-f]{1,2}|(?:[0-9A-Fa-f]{1,2}:){7}[0-9A-Fa-f]{1,2}|(?:[0-9A-Fa-f]{4}\.){3}[0-9A-Fa-f]{4})",
|
|
123
|
-
r"(?P<eui48>(?:[0-9A-Fa-f]{1,2}-){5}[0-9A-Fa-f]{1,2}|(?:[0-9A-Fa-f]{1,2}:){5}[0-9A-Fa-f]{1,2}|(?:[0-9A-Fa-f]{4}\.){2}[0-9A-Fa-f]{4})",
|
|
124
|
-
r"(?P<uuid>[a-fA-F0-9]{8}-[a-fA-F0-9]{4}-[a-fA-F0-9]{4}-[a-fA-F0-9]{4}-[a-fA-F0-9]{12})",
|
|
125
|
-
r"(?P<call>[\w.]*?)\(",
|
|
126
|
-
r"\b(?P<bool_true>True)\b|\b(?P<bool_false>False)\b|\b(?P<none>None)\b",
|
|
127
|
-
r"(?P<ellipsis>\.\.\.)",
|
|
128
|
-
r"(?P<number_complex>(?<!\w)(?:\-?[0-9]+\.?[0-9]*(?:e[-+]?\d+?)?)(?:[-+](?:[0-9]+\.?[0-9]*(?:e[-+]?\d+)?))?j)",
|
|
129
|
-
r"(?P<number>(?<!\w)\-?[0-9]+\.?[0-9]*(e[-+]?\d+?)?\b|0x[0-9a-fA-F]*)",
|
|
130
|
-
r"(?P<path>\B(/[-\w._+]+)*\/)(?P<filename>[-\w._+]*)?",
|
|
131
|
-
r"(?<![\\\w])(?P<str>b?'''.*?(?<!\\)'''|b?'.*?(?<!\\)'|b?\"\"\".*?(?<!\\)\"\"\"|b?\".*?(?<!\\)\")",
|
|
132
|
-
r"(?P<url>(file|https|http|ws|wss)://[-0-9a-zA-Z$_+!`(),.?/;:&=%#~@]*)",
|
|
133
|
-
))
|
|
134
|
-
"""
|
|
135
123
|
self.highlights = [re.compile(h, re.IGNORECASE) for h in self.highlights]
|
|
136
124
|
|
|
137
125
|
class ColorfulStreamHandler(logging.StreamHandler):
|
|
126
|
+
"""
|
|
127
|
+
コンソールにカラフルなログメッセージを出力します。
|
|
128
|
+
"""
|
|
138
129
|
console = Console(soft_wrap=True, height=True, highlighter=LogLevelHighlighter(), theme=theme)
|
|
139
130
|
|
|
140
131
|
def emit(self, record: logging.LogRecord) -> None:
|
|
@@ -154,3 +145,93 @@ class TimedRotatingFileHandler(logging.handlers.TimedRotatingFileHandler):
|
|
|
154
145
|
record.levelname = level_mapping_nc[record.levelno]
|
|
155
146
|
super().emit(record)
|
|
156
147
|
|
|
148
|
+
class SocketHandler(logging.handlers.SocketHandler):
|
|
149
|
+
def emit(self, record: logging.LogRecord) -> None:
|
|
150
|
+
record.levelname = level_mapping_nc[record.levelno]
|
|
151
|
+
super().emit(record)
|
|
152
|
+
|
|
153
|
+
class LogRecordRequestHandler(socketserver.StreamRequestHandler):
|
|
154
|
+
"""
|
|
155
|
+
ログリクエストを処理するためのハンドラ
|
|
156
|
+
"""
|
|
157
|
+
def setup(self):
|
|
158
|
+
super().setup()
|
|
159
|
+
from cmdbox.app import common
|
|
160
|
+
common.set_debug(self._getLogger(), LogRecordTCPServer.debug)
|
|
161
|
+
|
|
162
|
+
def _getLogger(self):
|
|
163
|
+
if self.server.logname is not None:
|
|
164
|
+
name = self.server.logname
|
|
165
|
+
else:
|
|
166
|
+
name = self.logname
|
|
167
|
+
return logging.getLogger(name)
|
|
168
|
+
|
|
169
|
+
def handle(self):
|
|
170
|
+
"""
|
|
171
|
+
ログリクエストを処理します。
|
|
172
|
+
"""
|
|
173
|
+
while True:
|
|
174
|
+
chunk = self.connection.recv(4)
|
|
175
|
+
if len(chunk) < 4:
|
|
176
|
+
break
|
|
177
|
+
slen = struct.unpack('>L', chunk)[0]
|
|
178
|
+
chunk = self.connection.recv(slen)
|
|
179
|
+
while len(chunk) < slen:
|
|
180
|
+
chunk = chunk + self.connection.recv(slen - len(chunk))
|
|
181
|
+
obj = self.unPickle(chunk)
|
|
182
|
+
record = logging.makeLogRecord(obj)
|
|
183
|
+
self.handleLogRecord(record)
|
|
184
|
+
|
|
185
|
+
def unPickle(self, data):
|
|
186
|
+
return pickle.loads(data)
|
|
187
|
+
|
|
188
|
+
def handleLogRecord(self, record):
|
|
189
|
+
logger = self._getLogger()
|
|
190
|
+
logger.handle(record)
|
|
191
|
+
|
|
192
|
+
class LogRecordTCPServer(socketserver.ThreadingTCPServer):
|
|
193
|
+
"""
|
|
194
|
+
ログレコードを受信するためのTCPサーバー。
|
|
195
|
+
"""
|
|
196
|
+
# 停止後すぐにサーバーを再起動できるようにする
|
|
197
|
+
allow_reuse_address = True
|
|
198
|
+
|
|
199
|
+
def __init__(self, logname, host='localhost', port=logging.handlers.DEFAULT_TCP_LOGGING_PORT,
|
|
200
|
+
handler=LogRecordRequestHandler, debug=False):
|
|
201
|
+
"""
|
|
202
|
+
コンストラクタ
|
|
203
|
+
|
|
204
|
+
Args:
|
|
205
|
+
logname (str): ログ名
|
|
206
|
+
host (str): ホスト名
|
|
207
|
+
port (int): ポート番号
|
|
208
|
+
handler (socketserver.RequestHandler): リクエストハンドラ
|
|
209
|
+
debug (bool): デバッグモード
|
|
210
|
+
"""
|
|
211
|
+
socketserver.ThreadingTCPServer.__init__(self, (host, port), handler, bind_and_activate=False)
|
|
212
|
+
self.allow_reuse_address = False
|
|
213
|
+
self.allow_reuse_port = False
|
|
214
|
+
self.request_queue_size = 15
|
|
215
|
+
self.abort = 0
|
|
216
|
+
self.timeout = 1
|
|
217
|
+
self.logname = logname
|
|
218
|
+
self.handler = handler
|
|
219
|
+
LogRecordTCPServer.debug = debug
|
|
220
|
+
|
|
221
|
+
def serve_until_stopped(self):
|
|
222
|
+
import select
|
|
223
|
+
abort = 0
|
|
224
|
+
try:
|
|
225
|
+
self.server_bind()
|
|
226
|
+
self.server_activate()
|
|
227
|
+
except:
|
|
228
|
+
# すでにlogsvが起動中の場合は待機しない
|
|
229
|
+
self.server_close()
|
|
230
|
+
abort = 1
|
|
231
|
+
while not abort:
|
|
232
|
+
rd, wr, ex = select.select([self.socket.fileno()],
|
|
233
|
+
[], [],
|
|
234
|
+
self.timeout)
|
|
235
|
+
if rd:
|
|
236
|
+
self.handle_request()
|
|
237
|
+
abort = self.abort
|
cmdbox/app/edge.py
CHANGED
|
@@ -9,7 +9,6 @@ from uvicorn.config import Config
|
|
|
9
9
|
import argparse
|
|
10
10
|
import json
|
|
11
11
|
import logging
|
|
12
|
-
import locale
|
|
13
12
|
import queue
|
|
14
13
|
import requests
|
|
15
14
|
import time
|
|
@@ -54,7 +53,6 @@ class Edge(object):
|
|
|
54
53
|
|
|
55
54
|
import questionary
|
|
56
55
|
ref_opts = self.options.get_cmd_choices(edge_mode, edge_cmd)
|
|
57
|
-
language, _ = locale.getlocale()
|
|
58
56
|
edge_dir = Path(self.data) / '.edge'
|
|
59
57
|
common.mkdirs(edge_dir)
|
|
60
58
|
conf_file = edge_dir / 'edge.conf'
|
|
@@ -96,7 +94,7 @@ class Edge(object):
|
|
|
96
94
|
default = str(default) if isinstance(default, int) or isinstance(default, float) else default
|
|
97
95
|
description_ja = r['description_ja'] if 'description_ja' in r else None
|
|
98
96
|
description_en = r['description_en'] if 'description_en' in r else None
|
|
99
|
-
help = description_en if
|
|
97
|
+
help = description_en if not common.is_japan() else description_ja
|
|
100
98
|
choice = r['choice'] if 'choice' in r else None
|
|
101
99
|
choice = [str(c) for c in choice] if choice is not None else None
|
|
102
100
|
required = r['required'] if 'required' in r else False
|
|
@@ -6,7 +6,7 @@ import argparse
|
|
|
6
6
|
import logging
|
|
7
7
|
|
|
8
8
|
|
|
9
|
-
class
|
|
9
|
+
class AgentMcpClient(feature.UnsupportEdgeFeature):
|
|
10
10
|
def get_mode(self) -> Union[str, List[str]]:
|
|
11
11
|
"""
|
|
12
12
|
この機能のモードを返します
|
|
@@ -14,7 +14,7 @@ class McpClient(feature.UnsupportEdgeFeature):
|
|
|
14
14
|
Returns:
|
|
15
15
|
Union[str, List[str]]: モード
|
|
16
16
|
"""
|
|
17
|
-
return '
|
|
17
|
+
return 'agent'
|
|
18
18
|
|
|
19
19
|
def get_cmd(self) -> str:
|
|
20
20
|
"""
|
|
@@ -23,7 +23,7 @@ class McpClient(feature.UnsupportEdgeFeature):
|
|
|
23
23
|
Returns:
|
|
24
24
|
str: コマンド
|
|
25
25
|
"""
|
|
26
|
-
return '
|
|
26
|
+
return 'mcp_client'
|
|
27
27
|
|
|
28
28
|
def get_option(self):
|
|
29
29
|
"""
|
|
@@ -33,6 +33,7 @@ class McpClient(feature.UnsupportEdgeFeature):
|
|
|
33
33
|
Dict[str, Any]: オプション
|
|
34
34
|
"""
|
|
35
35
|
return dict(
|
|
36
|
+
# webからclientを実行するとmcp処理とデッドロックが発生するため、webmodeを無効にします。
|
|
36
37
|
use_redis=self.USE_REDIS_FALSE, nouse_webmode=True, use_agent=False,
|
|
37
38
|
description_ja="リモートMCPサーバーにリクエストを行うMCPクライアントを起動します。",
|
|
38
39
|
description_en="Starts an MCP client that makes requests to a remote MCP server.",
|
|
@@ -6,7 +6,7 @@ import argparse
|
|
|
6
6
|
import logging
|
|
7
7
|
|
|
8
8
|
|
|
9
|
-
class
|
|
9
|
+
class AgentMcpProxy(feature.UnsupportEdgeFeature):
|
|
10
10
|
def get_mode(self) -> Union[str, List[str]]:
|
|
11
11
|
"""
|
|
12
12
|
この機能のモードを返します
|
|
@@ -14,7 +14,7 @@ class McpProxy(feature.UnsupportEdgeFeature):
|
|
|
14
14
|
Returns:
|
|
15
15
|
Union[str, List[str]]: モード
|
|
16
16
|
"""
|
|
17
|
-
return '
|
|
17
|
+
return 'agent'
|
|
18
18
|
|
|
19
19
|
def get_cmd(self) -> str:
|
|
20
20
|
"""
|
|
@@ -23,7 +23,7 @@ class McpProxy(feature.UnsupportEdgeFeature):
|
|
|
23
23
|
Returns:
|
|
24
24
|
str: コマンド
|
|
25
25
|
"""
|
|
26
|
-
return '
|
|
26
|
+
return 'mcp_proxy'
|
|
27
27
|
|
|
28
28
|
def get_option(self):
|
|
29
29
|
"""
|
|
@@ -33,7 +33,7 @@ class McpProxy(feature.UnsupportEdgeFeature):
|
|
|
33
33
|
Dict[str, Any]: オプション
|
|
34
34
|
"""
|
|
35
35
|
return dict(
|
|
36
|
-
use_redis=self.USE_REDIS_FALSE, nouse_webmode=
|
|
36
|
+
use_redis=self.USE_REDIS_FALSE, nouse_webmode=True, use_agent=False,
|
|
37
37
|
description_ja="標準入力を受け付け、リモートMCPサーバーにリクエストを行うProxyサーバーを起動します。",
|
|
38
38
|
description_en="Starts a Proxy server that accepts standard input and makes requests to a remote MCP server.",
|
|
39
39
|
choice=[
|
|
@@ -99,7 +99,7 @@ class CmdList(feature.OneshotResultEdgeFeature):
|
|
|
99
99
|
cmd_list = [dict(title=r.get('title',''), mode=r['mode'], cmd=r['cmd'],
|
|
100
100
|
description=r.get('description','') + options.get_cmd_attr(r['mode'], r['cmd'], 'description_ja' if is_japan else 'description_en'),
|
|
101
101
|
tag=r.get('tag','')) for r in cmd_list \
|
|
102
|
-
|
|
102
|
+
if signin.Signin._check_cmd(self.signin_file_data, args.groups, r['mode'], r['cmd'], logger)]
|
|
103
103
|
ret = dict(success=cmd_list)
|
|
104
104
|
|
|
105
105
|
common.print_format(ret, args.format, tm, args.output_json, args.output_json_append, pf=pf)
|
|
@@ -33,7 +33,7 @@ class ServerList(feature.OneshotResultEdgeFeature):
|
|
|
33
33
|
Dict[str, Any]: オプション
|
|
34
34
|
"""
|
|
35
35
|
return dict(
|
|
36
|
-
use_redis=self.USE_REDIS_TRUE, nouse_webmode=False,
|
|
36
|
+
use_redis=self.USE_REDIS_TRUE, nouse_webmode=False, use_agent=True,
|
|
37
37
|
description_ja="起動中のサーバーの一覧を表示します。クライアント環境からの利用も可能です。",
|
|
38
38
|
description_en="Displays a list of running inference servers. Can also be used from the client environment.",
|
|
39
39
|
choice=[
|
|
@@ -6,7 +6,7 @@ import argparse
|
|
|
6
6
|
import logging
|
|
7
7
|
|
|
8
8
|
|
|
9
|
-
class ServerStart(feature.
|
|
9
|
+
class ServerStart(feature.UnsupportEdgeFeature):
|
|
10
10
|
def get_mode(self) -> Union[str, List[str]]:
|
|
11
11
|
"""
|
|
12
12
|
この機能のモードを返します
|
|
@@ -33,7 +33,7 @@ class ServerStart(feature.OneshotNotifyEdgeFeature):
|
|
|
33
33
|
Dict[str, Any]: オプション
|
|
34
34
|
"""
|
|
35
35
|
return dict(
|
|
36
|
-
use_redis=self.USE_REDIS_TRUE, nouse_webmode=True,
|
|
36
|
+
use_redis=self.USE_REDIS_TRUE, nouse_webmode=True, use_agent=False,
|
|
37
37
|
description_ja="サーバーを起動します。installモードで `cmdbox -m install -c server` を実行している場合は、 `docker-compose up -d` を使用してください。",
|
|
38
38
|
description_en="Start the inference server. If you are running `cmdbox -m install -c server` in install mode, use `docker-compose up -d`.",
|
|
39
39
|
choice=[
|
|
@@ -7,7 +7,7 @@ import argparse
|
|
|
7
7
|
import logging
|
|
8
8
|
|
|
9
9
|
|
|
10
|
-
class ServerStop(feature.
|
|
10
|
+
class ServerStop(feature.UnsupportEdgeFeature):
|
|
11
11
|
def get_mode(self) -> Union[str, List[str]]:
|
|
12
12
|
"""
|
|
13
13
|
この機能のモードを返します
|
|
@@ -34,7 +34,7 @@ class ServerStop(feature.OneshotNotifyEdgeFeature):
|
|
|
34
34
|
Dict[str, Any]: オプション
|
|
35
35
|
"""
|
|
36
36
|
return dict(
|
|
37
|
-
use_redis=self.USE_REDIS_TRUE, nouse_webmode=True,
|
|
37
|
+
use_redis=self.USE_REDIS_TRUE, nouse_webmode=True, use_agent=False,
|
|
38
38
|
description_ja="サーバーを停止します。installモードで `cmdbox -m install -c server` を実行している場合は、 `docker-compose down` を使用してください。",
|
|
39
39
|
description_en="Stop the inference server. If you are running `cmdbox -m install -c server` in install mode, use `docker-compose down`.",
|
|
40
40
|
choice=[
|
|
@@ -41,7 +41,7 @@ class TtsInstall(feature.UnsupportEdgeFeature):
|
|
|
41
41
|
Dict[str, Any]: オプション
|
|
42
42
|
"""
|
|
43
43
|
return dict(
|
|
44
|
-
use_redis=self.USE_REDIS_MEIGHT, nouse_webmode=
|
|
44
|
+
use_redis=self.USE_REDIS_MEIGHT, nouse_webmode=True, use_agent=False,
|
|
45
45
|
description_ja="Text-to-Speech(TTS)エンジンをインストールします。",
|
|
46
46
|
description_en="Installs the Text-to-Speech (TTS) engine.",
|
|
47
47
|
choice=[
|
|
@@ -247,6 +247,8 @@ class TtsInstall(feature.UnsupportEdgeFeature):
|
|
|
247
247
|
voicevox_dir.mkdir(parents=True, exist_ok=True)
|
|
248
248
|
dlfile = voicevox_dir / dlfile
|
|
249
249
|
# ダウンローダーを保存
|
|
250
|
+
if logger.level == logging.DEBUG:
|
|
251
|
+
logger.debug(f"Downloading.. : {downloader_url}")
|
|
250
252
|
responce = requests.get(downloader_url, allow_redirects=True)
|
|
251
253
|
if responce.status_code != 200:
|
|
252
254
|
_msg = f"Failed to download VoiceVox core: {responce.status_code} {responce.reason}. {downloader_url}"
|
|
@@ -264,6 +266,8 @@ class TtsInstall(feature.UnsupportEdgeFeature):
|
|
|
264
266
|
cmd_line.extend(['--devices', 'directml'])
|
|
265
267
|
elif voicevox_device == 'cuda':
|
|
266
268
|
cmd_line.extend(['--devices', 'cuda'])
|
|
269
|
+
if logger.level == logging.DEBUG:
|
|
270
|
+
logger.debug(f"EXEC - {cmd_line}")
|
|
267
271
|
proc = subprocess.Popen(cmd_line, cwd=str(voicevox_dir), stdout=subprocess.PIPE, stdin=subprocess.PIPE, shell=True)
|
|
268
272
|
outs, errs = proc.communicate(input=b'y\ny\n') # 'y' to confirm installation
|
|
269
273
|
if proc.returncode != 0:
|
|
@@ -272,6 +276,8 @@ class TtsInstall(feature.UnsupportEdgeFeature):
|
|
|
272
276
|
_msg += f"Failed to install VoiceVox core: {_msg}"
|
|
273
277
|
logger.error(_msg, exc_info=True)
|
|
274
278
|
return dict(warn=_msg)
|
|
279
|
+
if logger.level == logging.DEBUG:
|
|
280
|
+
logger.debug(f"Completed - {cmd_line}")
|
|
275
281
|
if (voicevox_dir / 'voicevox_core').exists():
|
|
276
282
|
for file in glob.glob(str(voicevox_dir / 'voicevox_core' / '*')):
|
|
277
283
|
shutil.move(file, voicevox_dir)
|
|
@@ -283,6 +289,8 @@ class TtsInstall(feature.UnsupportEdgeFeature):
|
|
|
283
289
|
whl_url = f'https://github.com/VOICEVOX/voicevox_core/releases/download/{voicevox_ver}/{voicevox_whl}'
|
|
284
290
|
voicevox_whl = voicevox_dir / voicevox_whl
|
|
285
291
|
# whlファイルをダウンロード
|
|
292
|
+
if logger.level == logging.DEBUG:
|
|
293
|
+
logger.debug(f"Downloading.. : {whl_url}")
|
|
286
294
|
responce = requests.get(whl_url, allow_redirects=True)
|
|
287
295
|
if responce.status_code != 200:
|
|
288
296
|
_msg = f"Failed to download VoiceVox whl: {responce.status_code} {responce.reason}. {whl_url}"
|
|
@@ -291,6 +299,8 @@ class TtsInstall(feature.UnsupportEdgeFeature):
|
|
|
291
299
|
with open(voicevox_whl, mode='wb') as f:
|
|
292
300
|
f.write(responce.content)
|
|
293
301
|
# whlファイルをpipでインストール
|
|
302
|
+
if logger.level == logging.DEBUG:
|
|
303
|
+
logger.debug(f"pip install {voicevox_whl}")
|
|
294
304
|
rescode = pip.main(['install', str(voicevox_whl)]) # pipのインストール
|
|
295
305
|
logger.info(f"Install wheel: {voicevox_whl}")
|
|
296
306
|
if rescode != 0:
|
|
@@ -8,7 +8,7 @@ import argparse
|
|
|
8
8
|
import logging
|
|
9
9
|
|
|
10
10
|
|
|
11
|
-
class TtsStart(feature.
|
|
11
|
+
class TtsStart(feature.UnsupportEdgeFeature):
|
|
12
12
|
VOICEVOX_STYLE = dict()
|
|
13
13
|
VOICEVOX_STYLE['0.vvm_2'] = dict(fn='0.vvm',ch='四国めたん',md='ノーマル',st=2)
|
|
14
14
|
VOICEVOX_STYLE['0.vvm_0'] = dict(fn='0.vvm',ch='四国めたん',md='あまあま',st=0)
|
|
@@ -0,0 +1,213 @@
|
|
|
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 cmdbox.app.features.cli import cmdbox_vision_start
|
|
6
|
+
from pathlib import Path
|
|
7
|
+
from typing import Dict, Any, Tuple, List, Union
|
|
8
|
+
import argparse
|
|
9
|
+
import glob
|
|
10
|
+
import logging
|
|
11
|
+
import pip
|
|
12
|
+
import requests
|
|
13
|
+
import shutil
|
|
14
|
+
import subprocess
|
|
15
|
+
import sys
|
|
16
|
+
|
|
17
|
+
|
|
18
|
+
class VisionInstall(cmdbox_vision_start.VisionStart):
|
|
19
|
+
def get_mode(self) -> Union[str, List[str]]:
|
|
20
|
+
"""
|
|
21
|
+
この機能のモードを返します
|
|
22
|
+
|
|
23
|
+
Returns:
|
|
24
|
+
Union[str, List[str]]: モード
|
|
25
|
+
"""
|
|
26
|
+
return 'vision'
|
|
27
|
+
|
|
28
|
+
def get_cmd(self):
|
|
29
|
+
"""
|
|
30
|
+
この機能のコマンドを返します
|
|
31
|
+
|
|
32
|
+
Returns:
|
|
33
|
+
str: コマンド
|
|
34
|
+
"""
|
|
35
|
+
return 'install'
|
|
36
|
+
|
|
37
|
+
def get_option(self):
|
|
38
|
+
"""
|
|
39
|
+
この機能のオプションを返します
|
|
40
|
+
|
|
41
|
+
Returns:
|
|
42
|
+
Dict[str, Any]: オプション
|
|
43
|
+
"""
|
|
44
|
+
return dict(
|
|
45
|
+
use_redis=self.USE_REDIS_MEIGHT, nouse_webmode=True, use_agent=False,
|
|
46
|
+
description_ja="画像/動画の推論エンジンをインストールします。",
|
|
47
|
+
description_en="Installs the image/video inference engine.",
|
|
48
|
+
choice=[
|
|
49
|
+
dict(opt="host", type=Options.T_STR, default=self.default_host, required=True, multi=False, hide=True, choice=None, web="mask",
|
|
50
|
+
description_ja="Redisサーバーのサービスホストを指定します。",
|
|
51
|
+
description_en="Specify the service host of the Redis server."),
|
|
52
|
+
dict(opt="port", type=Options.T_INT, default=self.default_port, required=True, multi=False, hide=True, choice=None, web="mask",
|
|
53
|
+
description_ja="Redisサーバーのサービスポートを指定します。",
|
|
54
|
+
description_en="Specify the service port of the Redis server."),
|
|
55
|
+
dict(opt="password", type=Options.T_STR, default=self.default_pass, required=True, multi=False, hide=True, choice=None, web="mask",
|
|
56
|
+
description_ja=f"Redisサーバーのアクセスパスワード(任意)を指定します。省略時は `{self.default_pass}` を使用します。",
|
|
57
|
+
description_en=f"Specify the access password of the Redis server (optional). If omitted, `{self.default_pass}` is used."),
|
|
58
|
+
dict(opt="svname", type=Options.T_STR, default=self.default_svname, required=True, multi=False, hide=True, choice=None, web="readonly",
|
|
59
|
+
description_ja="サーバーのサービス名を指定します。省略時は `server` を使用します。",
|
|
60
|
+
description_en="Specify the service name of the inference server. If omitted, `server` is used."),
|
|
61
|
+
dict(opt="retry_count", type=Options.T_INT, default=3, required=False, multi=False, hide=True, choice=None,
|
|
62
|
+
description_ja="Redisサーバーへの再接続回数を指定します。0以下を指定すると永遠に再接続を行います。",
|
|
63
|
+
description_en="Specifies the number of reconnections to the Redis server.If less than 0 is specified, reconnection is forever."),
|
|
64
|
+
dict(opt="retry_interval", type=Options.T_INT, default=5, required=False, multi=False, hide=True, choice=None,
|
|
65
|
+
description_ja="Redisサーバーに再接続までの秒数を指定します。",
|
|
66
|
+
description_en="Specifies the number of seconds before reconnecting to the Redis server."),
|
|
67
|
+
dict(opt="timeout", type=Options.T_INT, default="300", required=False, multi=False, hide=True, choice=None,
|
|
68
|
+
description_ja="サーバーの応答が返ってくるまでの最大待ち時間を指定。",
|
|
69
|
+
description_en="Specify the maximum waiting time until the server responds."),
|
|
70
|
+
dict(opt="client_only", type=Options.T_BOOL, default=False, required=False, multi=False, hide=True, choice=[True, False],
|
|
71
|
+
description_ja="サーバーへの接続を行わないようにします。",
|
|
72
|
+
description_en="Do not make connections to the server."),
|
|
73
|
+
dict(opt="vision_engine", type=Options.T_STR, default="sam2", required=True, multi=False, hide=False,
|
|
74
|
+
choice=["sam2"],
|
|
75
|
+
description_ja="使用するVisionエンジンを指定します。",
|
|
76
|
+
description_en="Specify the Vision engine to use."),
|
|
77
|
+
]
|
|
78
|
+
)
|
|
79
|
+
|
|
80
|
+
def get_svcmd(self):
|
|
81
|
+
"""
|
|
82
|
+
この機能のサーバー側のコマンドを返します
|
|
83
|
+
|
|
84
|
+
Returns:
|
|
85
|
+
str: サーバー側のコマンド
|
|
86
|
+
"""
|
|
87
|
+
return 'vision_install'
|
|
88
|
+
|
|
89
|
+
def apprun(self, logger:logging.Logger, args:argparse.Namespace, tm:float, pf:List[Dict[str, float]]=[]) -> Tuple[int, Dict[str, Any], Any]:
|
|
90
|
+
"""
|
|
91
|
+
この機能の実行を行います
|
|
92
|
+
|
|
93
|
+
Args:
|
|
94
|
+
logger (logging.Logger): ロガー
|
|
95
|
+
args (argparse.Namespace): 引数
|
|
96
|
+
tm (float): 実行開始時間
|
|
97
|
+
pf (List[Dict[str, float]]): 呼出元のパフォーマンス情報
|
|
98
|
+
|
|
99
|
+
Returns:
|
|
100
|
+
Tuple[int, Dict[str, Any], Any]: 終了コード, 結果, オブジェクト
|
|
101
|
+
"""
|
|
102
|
+
if args.vision_engine is None:
|
|
103
|
+
msg = dict(warn=f"Please specify the --vision_engine option.")
|
|
104
|
+
common.print_format(msg, False, tm, args.output_json, args.output_json_append, pf=pf)
|
|
105
|
+
return self.RESP_WARN, msg, None
|
|
106
|
+
if args.vision_engine == 'sam2':
|
|
107
|
+
vision_engine_b64 = convert.str2b64str(args.vision_engine)
|
|
108
|
+
if args.client_only:
|
|
109
|
+
# クライアントのみの場合は、サーバーに接続せずに実行
|
|
110
|
+
ret = self.install(common.random_string(), args.vision_engine, logger)
|
|
111
|
+
else:
|
|
112
|
+
cl = client.Client(logger, redis_host=args.host, redis_port=args.port, redis_password=args.password, svname=args.svname)
|
|
113
|
+
ret = cl.redis_cli.send_cmd(self.get_svcmd(), [vision_engine_b64],
|
|
114
|
+
retry_count=args.retry_count, retry_interval=args.retry_interval, timeout=args.timeout, nowait=False)
|
|
115
|
+
common.print_format(ret, False, tm, None, False, pf=pf)
|
|
116
|
+
if 'success' not in ret:
|
|
117
|
+
return self.RESP_WARN, ret, None
|
|
118
|
+
return self.RESP_SUCCESS, ret, None
|
|
119
|
+
|
|
120
|
+
msg = dict(warn=f"Unsupported vision engine: {args.vision_engine}")
|
|
121
|
+
common.print_format(msg, False, tm, args.output_json, args.output_json_append, pf=pf)
|
|
122
|
+
return self.RESP_WARN, msg, None
|
|
123
|
+
|
|
124
|
+
def is_cluster_redirect(self):
|
|
125
|
+
"""
|
|
126
|
+
クラスター宛のメッセージの場合、メッセージを転送するかどうかを返します
|
|
127
|
+
|
|
128
|
+
Returns:
|
|
129
|
+
bool: メッセージを転送する場合はTrue
|
|
130
|
+
"""
|
|
131
|
+
return False
|
|
132
|
+
|
|
133
|
+
def svrun(self, data_dir:Path, logger:logging.Logger, redis_cli:redis_client.RedisClient, msg:List[str],
|
|
134
|
+
sessions:Dict[str, Dict[str, Any]]) -> int:
|
|
135
|
+
"""
|
|
136
|
+
この機能のサーバー側の実行を行います
|
|
137
|
+
|
|
138
|
+
Args:
|
|
139
|
+
data_dir (Path): データディレクトリ
|
|
140
|
+
logger (logging.Logger): ロガー
|
|
141
|
+
redis_cli (redis_client.RedisClient): Redisクライアント
|
|
142
|
+
msg (List[str]): 受信メッセージ
|
|
143
|
+
sessions (Dict[str, Dict[str, Any]]): セッション情報
|
|
144
|
+
|
|
145
|
+
Returns:
|
|
146
|
+
int: 終了コード
|
|
147
|
+
"""
|
|
148
|
+
if logger.level == logging.DEBUG:
|
|
149
|
+
logger.debug(f"audit write svrun msg: {msg}")
|
|
150
|
+
vision_engine = convert.b64str2str(msg[2])
|
|
151
|
+
ret = self.install(msg[1], vision_engine, logger)
|
|
152
|
+
|
|
153
|
+
if 'success' not in ret:
|
|
154
|
+
redis_cli.rpush(msg[1], ret)
|
|
155
|
+
return self.RESP_WARN
|
|
156
|
+
return self.RESP_SUCCESS
|
|
157
|
+
|
|
158
|
+
def install(self, reskey:str, vision_engine:str, logger:logging.Logger) -> Dict[str, Any]:
|
|
159
|
+
"""
|
|
160
|
+
SAML2をインストールします
|
|
161
|
+
|
|
162
|
+
Args:
|
|
163
|
+
reskey (str): レスポンスキー
|
|
164
|
+
vision_engine (str): Visionエンジン
|
|
165
|
+
logger (logging.Logger): ロガー
|
|
166
|
+
|
|
167
|
+
Returns:
|
|
168
|
+
Dict[str, Any]: 結果
|
|
169
|
+
"""
|
|
170
|
+
try:
|
|
171
|
+
if vision_engine == 'sam2':
|
|
172
|
+
#===============================================================
|
|
173
|
+
# SAM2のモデルファイルのダウンロード
|
|
174
|
+
sam2_dir = Path(version.__file__).parent / '.sam2' / 'model'
|
|
175
|
+
# すでにダウンローダーが存在する場合は削除
|
|
176
|
+
if sam2_dir.exists():
|
|
177
|
+
shutil.rmtree(sam2_dir)
|
|
178
|
+
for mk, mv in self.VISION_MODEL.items():
|
|
179
|
+
model_file = sam2_dir / mv['path']
|
|
180
|
+
model_file.parent.mkdir(parents=True, exist_ok=True)
|
|
181
|
+
# モデルファイルを保存
|
|
182
|
+
logger.info(f"Downloading.. : {mv['url']}")
|
|
183
|
+
responce = requests.get(f"{mv['url']}", allow_redirects=True)
|
|
184
|
+
if responce.status_code != 200:
|
|
185
|
+
_msg = f"Failed to download SAM2 model: {responce.status_code} {responce.reason}. {mv['url']}"
|
|
186
|
+
logger.error(_msg, exc_info=True)
|
|
187
|
+
return dict(warn=_msg)
|
|
188
|
+
with open(model_file, mode='wb') as f:
|
|
189
|
+
f.write(responce.content)
|
|
190
|
+
#===============================================================
|
|
191
|
+
# SAM2のpythonライブラリのインストール
|
|
192
|
+
whl_url = f'git+https://github.com/facebookresearch/sam2.git'
|
|
193
|
+
# whlファイルをpipでインストール
|
|
194
|
+
if logger.level == logging.DEBUG:
|
|
195
|
+
logger.debug(f"pip install {whl_url}")
|
|
196
|
+
rescode = pip.main(['install', str(whl_url)]) # pipのインストール
|
|
197
|
+
logger.info(f"Install wheel: {whl_url}")
|
|
198
|
+
if rescode != 0:
|
|
199
|
+
_msg = f"Failed to install SAM2 python library: Possible whl not in the environment. {whl_url}"
|
|
200
|
+
logger.error(_msg, exc_info=True)
|
|
201
|
+
return dict(warn=_msg)
|
|
202
|
+
#===============================================================
|
|
203
|
+
# 成功時の処理
|
|
204
|
+
rescode, _msg = (self.RESP_SUCCESS, dict(success=f'Success to install SAM2 python library. {whl_url}'))
|
|
205
|
+
return dict(success=_msg)
|
|
206
|
+
else:
|
|
207
|
+
_msg = f"Unsupported vision engine: {vision_engine}"
|
|
208
|
+
logger.error(_msg, exc_info=True)
|
|
209
|
+
return dict(warn=_msg)
|
|
210
|
+
except Exception as e:
|
|
211
|
+
_msg = f"Failed to install vision engine: {e}"
|
|
212
|
+
logger.warning(_msg, exc_info=True)
|
|
213
|
+
return dict(warn=_msg)
|