cmdbox 0.6.4.1__py3-none-any.whl → 0.6.5__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 +7 -0
- cmdbox/app/client.py +4 -3
- cmdbox/app/common.py +85 -7
- cmdbox/app/commons/convert.py +3 -1
- cmdbox/app/edge.py +12 -12
- cmdbox/app/features/cli/_cmdbox_vision_install.py +214 -0
- cmdbox/app/features/cli/_cmdbox_vision_predict.py +496 -0
- cmdbox/app/features/cli/_cmdbox_vision_start.py +234 -0
- cmdbox/app/features/cli/cmdbox_cmd_list.py +3 -3
- cmdbox/app/features/cli/cmdbox_cmd_load.py +3 -3
- cmdbox/app/features/cli/cmdbox_tts_install.py +4 -2
- cmdbox/app/features/cli/cmdbox_tts_say.py +2 -1
- cmdbox/app/features/cli/cmdbox_web_apikey_add.py +3 -3
- cmdbox/app/features/cli/cmdbox_web_apikey_del.py +3 -3
- cmdbox/app/features/cli/cmdbox_web_group_add.py +3 -3
- cmdbox/app/features/cli/cmdbox_web_group_del.py +3 -3
- cmdbox/app/features/cli/cmdbox_web_group_edit.py +3 -3
- cmdbox/app/features/cli/cmdbox_web_group_list.py +3 -3
- cmdbox/app/features/cli/cmdbox_web_start.py +10 -10
- cmdbox/app/features/cli/cmdbox_web_user_add.py +3 -3
- cmdbox/app/features/cli/cmdbox_web_user_del.py +3 -3
- cmdbox/app/features/cli/cmdbox_web_user_edit.py +3 -3
- cmdbox/app/features/cli/cmdbox_web_user_list.py +3 -3
- cmdbox/app/features/web/cmdbox_web_exec_cmd.py +12 -14
- cmdbox/app/features/web/cmdbox_web_versions_used.py +1 -1
- cmdbox/app/filer.py +5 -2
- cmdbox/app/mcp.py +4 -3
- cmdbox/app/options.py +8 -0
- cmdbox/app/web.py +50 -36
- cmdbox/licenses/LICENSE_Hypercorn_0_17_3_MIT_License.txt +22 -0
- cmdbox/licenses/{LICENSE_cffi_1_17_1_MIT_License.txt → LICENSE_cffi_2_0_0_UNKNOWN.txt} +2 -5
- cmdbox/licenses/{LICENSE_jsonschema-specifications_2025_4_1_UNKNOWN.txt → LICENSE_h2_4_3_0_MIT_License.txt} +3 -1
- cmdbox/licenses/{LICENSE_backoff_2_2_1_MIT_License.txt → LICENSE_hpack_4_1_0_MIT_License.txt} +1 -1
- cmdbox/licenses/{LICENSE_graphviz_0_21_UNKNOWN.txt → LICENSE_hyperframe_6_1_0_MIT_License.txt} +1 -1
- cmdbox/licenses/{LICENSE_jsonschema_4_25_0_UNKNOWN.txt → LICENSE_priority_2_0_0_MIT_License.txt} +2 -2
- cmdbox/licenses/files.txt +26 -147
- cmdbox/version.py +2 -2
- cmdbox/web/assets/cmdbox/svgicon.js +9 -0
- cmdbox/web/voicevox_license_list.txt +41 -0
- {cmdbox-0.6.4.1.dist-info → cmdbox-0.6.5.dist-info}/METADATA +3 -1
- {cmdbox-0.6.4.1.dist-info → cmdbox-0.6.5.dist-info}/RECORD +65 -186
- cmdbox/app/features/cli/cmdbox_mcp_client.py +0 -174
- cmdbox/app/features/cli/cmdbox_mcp_proxy.py +0 -96
- cmdbox/licenses/LICENSE_APScheduler_3_11_0_MIT_License.txt +0 -19
- cmdbox/licenses/LICENSE_Authlib_1_6_1_BSD_License.txt +0 -29
- cmdbox/licenses/LICENSE_SQLAlchemy_2_0_42_MIT.txt +0 -19
- cmdbox/licenses/LICENSE_SQLAlchemy_2_0_43_MIT.txt +0 -19
- cmdbox/licenses/LICENSE_Werkzeug_3_1_1_BSD_License.txt +0 -28
- cmdbox/licenses/LICENSE_absolufy-imports_0_3_1_MIT_License.txt +0 -21
- cmdbox/licenses/LICENSE_aiohttp_3_12_15_Apache-2_0_AND_MIT.txt +0 -13
- cmdbox/licenses/LICENSE_aiosignal_1_4_0_Apache_Software_License.txt +0 -201
- cmdbox/licenses/LICENSE_anyio_4_9_0_MIT_License.txt +0 -20
- cmdbox/licenses/LICENSE_attrs_25_3_0_UNKNOWN.txt +0 -21
- cmdbox/licenses/LICENSE_cachetools_5_5_2_MIT_License.txt +0 -20
- cmdbox/licenses/LICENSE_certifi_2025_7_14_Mozilla_Public_License_2_0-MPL_2_0.txt +0 -20
- cmdbox/licenses/LICENSE_charset-normalizer_3_4_2_MIT_License.txt +0 -21
- cmdbox/licenses/LICENSE_cloudpickle_3_1_1_BSD_License.txt +0 -1
- cmdbox/licenses/LICENSE_cryptography_45_0_6_Apache-2_0_OR_BSD-3-Clause.txt +0 -3
- cmdbox/licenses/LICENSE_cyclopts_3_22_5_Apache_Software_License.txt +0 -201
- cmdbox/licenses/LICENSE_distro_1_9_0_Apache_Software_License.txt +0 -202
- cmdbox/licenses/LICENSE_dnspython_2_7_0_ISC_License-ISCL.txt +0 -35
- cmdbox/licenses/LICENSE_docstring_parser_0_17_0_MIT_License.txt +0 -21
- cmdbox/licenses/LICENSE_email_validator_2_2_0_The_Unlicense-Unlicense.txt +0 -27
- cmdbox/licenses/LICENSE_exceptiongroup_1_3_0_MIT_License.txt +0 -73
- cmdbox/licenses/LICENSE_fastapi-sso_0_18_0_MIT_License.txt +0 -21
- cmdbox/licenses/LICENSE_fastmcp_2_11_0_Apache_Software_License.txt +0 -201
- cmdbox/licenses/LICENSE_fastmcp_2_11_3_Apache_Software_License.txt +0 -201
- cmdbox/licenses/LICENSE_filelock_3_18_0_The_Unlicense-Unlicense.txt +0 -24
- cmdbox/licenses/LICENSE_frozenlist_1_7_0_Apache-2_0.txt +0 -201
- cmdbox/licenses/LICENSE_fsspec_2025_7_0_BSD_License.txt +0 -29
- cmdbox/licenses/LICENSE_google-adk_1_10_0_Apache_Software_License.txt +0 -202
- cmdbox/licenses/LICENSE_google-adk_1_9_0_Apache_Software_License.txt +0 -202
- cmdbox/licenses/LICENSE_google-api-core_2_25_1_Apache_Software_License.txt +0 -202
- cmdbox/licenses/LICENSE_google-api-python-client_2_177_0_Apache_Software_License.txt +0 -201
- cmdbox/licenses/LICENSE_google-api-python-client_2_178_0_Apache_Software_License.txt +0 -201
- cmdbox/licenses/LICENSE_google-auth-httplib2_0_2_0_Apache_Software_License.txt +0 -201
- cmdbox/licenses/LICENSE_google-auth_2_40_3_Apache_Software_License.txt +0 -201
- cmdbox/licenses/LICENSE_google-cloud-aiplatform_1_106_0_Apache_2_0.txt +0 -202
- cmdbox/licenses/LICENSE_google-cloud-aiplatform_1_108_0_Apache_2_0.txt +0 -202
- cmdbox/licenses/LICENSE_google-cloud-appengine-logging_1_6_2_Apache_Software_License.txt +0 -202
- cmdbox/licenses/LICENSE_google-cloud-audit-log_0_3_2_Apache_Software_License.txt +0 -202
- cmdbox/licenses/LICENSE_google-cloud-bigquery_3_35_1_Apache_Software_License.txt +0 -202
- cmdbox/licenses/LICENSE_google-cloud-core_2_4_3_Apache_Software_License.txt +0 -202
- cmdbox/licenses/LICENSE_google-cloud-logging_3_12_1_Apache_Software_License.txt +0 -202
- cmdbox/licenses/LICENSE_google-cloud-resource-manager_1_14_2_Apache_Software_License.txt +0 -202
- cmdbox/licenses/LICENSE_google-cloud-secret-manager_2_24_0_Apache_Software_License.txt +0 -202
- cmdbox/licenses/LICENSE_google-cloud-speech_2_33_0_Apache_Software_License.txt +0 -202
- cmdbox/licenses/LICENSE_google-cloud-storage_2_19_0_Apache_Software_License.txt +0 -202
- cmdbox/licenses/LICENSE_google-cloud-trace_1_16_2_Apache_Software_License.txt +0 -202
- cmdbox/licenses/LICENSE_google-crc32c_1_7_1_Apache_2_0.txt +0 -202
- cmdbox/licenses/LICENSE_google-genai_1_28_0_Apache_Software_License.txt +0 -202
- cmdbox/licenses/LICENSE_google-genai_1_29_0_Apache_Software_License.txt +0 -202
- cmdbox/licenses/LICENSE_google-resumable-media_2_7_2_Apache_Software_License.txt +0 -202
- cmdbox/licenses/LICENSE_googleapis-common-protos_1_70_0_Apache_Software_License.txt +0 -202
- cmdbox/licenses/LICENSE_greenlet_3_2_3_MIT_AND_Python-2_0.txt +0 -30
- cmdbox/licenses/LICENSE_grpc-google-iam-v1_0_14_2_Apache_Software_License.txt +0 -202
- cmdbox/licenses/LICENSE_grpcio-status_1_74_0_Apache_Software_License.txt +0 -610
- cmdbox/licenses/LICENSE_grpcio_1_74_0_Apache_Software_License.txt +0 -610
- cmdbox/licenses/LICENSE_httpcore_1_0_9_BSD_License.txt +0 -27
- cmdbox/licenses/LICENSE_httplib2_0_22_0_MIT_License.txt +0 -23
- cmdbox/licenses/LICENSE_httpx-sse_0_4_1_MIT.txt +0 -21
- cmdbox/licenses/LICENSE_httpx_0_28_1_BSD_License.txt +0 -12
- cmdbox/licenses/LICENSE_huggingface-hub_0_34_3_Apache_Software_License.txt +0 -201
- cmdbox/licenses/LICENSE_huggingface-hub_0_34_4_Apache_Software_License.txt +0 -201
- cmdbox/licenses/LICENSE_isodate_0_7_2_BSD_License.txt +0 -26
- cmdbox/licenses/LICENSE_jiter_0_10_0_MIT_License.txt +0 -1
- cmdbox/licenses/LICENSE_jsonschema-path_0_3_4_Apache_Software_License.txt +0 -201
- cmdbox/licenses/LICENSE_lazy-object-proxy_1_11_0_BSD_License.txt +0 -20
- cmdbox/licenses/LICENSE_litellm-enterprise_0_1_19_UNKNOWN.txt +0 -37
- cmdbox/licenses/LICENSE_litellm_1_74_12_MIT_License.txt +0 -26
- cmdbox/licenses/LICENSE_litellm_1_75_5_post1_MIT_License.txt +0 -26
- cmdbox/licenses/LICENSE_markdown-it-py_3_0_0_MIT_License.txt +0 -21
- cmdbox/licenses/LICENSE_mcp_1_12_3_MIT_License.txt +0 -21
- cmdbox/licenses/LICENSE_mcp_1_12_4_MIT_License.txt +0 -21
- cmdbox/licenses/LICENSE_multidict_6_6_3_Apache_License_2_0.txt +0 -13
- cmdbox/licenses/LICENSE_multidict_6_6_4_Apache_License_2_0.txt +0 -13
- cmdbox/licenses/LICENSE_oauthlib_3_3_1_BSD-3-Clause.txt +0 -27
- cmdbox/licenses/LICENSE_openai_1_98_0_Apache_Software_License.txt +0 -201
- cmdbox/licenses/LICENSE_openai_1_99_9_Apache_Software_License.txt +0 -201
- cmdbox/licenses/LICENSE_openapi-core_0_19_5_BSD_License.txt +0 -29
- cmdbox/licenses/LICENSE_openapi-pydantic_0_5_1_MIT_License.txt +0 -40
- cmdbox/licenses/LICENSE_openapi-schema-validator_0_6_3_BSD_License.txt +0 -29
- cmdbox/licenses/LICENSE_openapi-spec-validator_0_7_2_Apache_Software_License.txt +0 -201
- cmdbox/licenses/LICENSE_opentelemetry-api_1_36_0_UNKNOWN.txt +0 -201
- cmdbox/licenses/LICENSE_opentelemetry-exporter-gcp-trace_1_9_0_Apache_Software_License.txt +0 -201
- cmdbox/licenses/LICENSE_opentelemetry-resourcedetector-gcp_1_9_0a0_Apache_Software_License.txt +0 -201
- cmdbox/licenses/LICENSE_opentelemetry-sdk_1_36_0_UNKNOWN.txt +0 -201
- cmdbox/licenses/LICENSE_opentelemetry-semantic-conventions_0_57b0_UNKNOWN.txt +0 -201
- cmdbox/licenses/LICENSE_orjson_3_11_1_Apache_Software_License-MIT_License.txt +0 -201
- cmdbox/licenses/LICENSE_parse_1_20_2_MIT_License.txt +0 -19
- cmdbox/licenses/LICENSE_pathable_0_4_4_Apache_Software_License.txt +0 -201
- cmdbox/licenses/LICENSE_propcache_0_3_2_Apache_Software_License.txt +0 -202
- cmdbox/licenses/LICENSE_proto-plus_1_26_1_Apache_Software_License.txt +0 -202
- cmdbox/licenses/LICENSE_protobuf_6_31_1_3-Clause_BSD_License.txt +0 -32
- cmdbox/licenses/LICENSE_pyasn1_0_6_1_BSD_License.txt +0 -24
- cmdbox/licenses/LICENSE_pyasn1_modules_0_4_2_BSD_License.txt +0 -24
- cmdbox/licenses/LICENSE_pydantic-settings_2_10_1_MIT_License.txt +0 -21
- cmdbox/licenses/LICENSE_pyparsing_3_2_3_MIT_License.txt +0 -18
- cmdbox/licenses/LICENSE_pyperclip_1_9_0_BSD_License.txt +0 -27
- cmdbox/licenses/LICENSE_python-dateutil_2_9_0_post0_Apache_Software_License-BSD_License.txt +0 -54
- cmdbox/licenses/LICENSE_python-dotenv_1_1_1_BSD_License.txt +0 -27
- cmdbox/licenses/LICENSE_pywin32_311_Python_Software_Foundation_License.txt +0 -1
- cmdbox/licenses/LICENSE_redis_6_2_0_MIT_License.txt +0 -21
- cmdbox/licenses/LICENSE_referencing_0_36_2_UNKNOWN.txt +0 -19
- cmdbox/licenses/LICENSE_regex_2025_7_34_UNKNOWN.txt +0 -208
- cmdbox/licenses/LICENSE_rfc3339-validator_0_1_4_MIT_License.txt +0 -22
- cmdbox/licenses/LICENSE_rich-rst_1_3_1_MIT_License.txt +0 -7
- cmdbox/licenses/LICENSE_rpds-py_0_26_0_MIT.txt +0 -19
- cmdbox/licenses/LICENSE_rpds-py_0_27_0_UNKNOWN.txt +0 -19
- cmdbox/licenses/LICENSE_rsa_4_9_1_Apache_Software_License.txt +0 -13
- cmdbox/licenses/LICENSE_shapely_2_1_1_BSD_License.txt +0 -29
- cmdbox/licenses/LICENSE_sphinx-intl_2_3_1_BSD_License.txt +0 -25
- cmdbox/licenses/LICENSE_sse-starlette_3_0_2_UNKNOWN.txt +0 -27
- cmdbox/licenses/LICENSE_tenacity_8_5_0_Apache_Software_License.txt +0 -202
- cmdbox/licenses/LICENSE_tenacity_9_1_2_Apache_Software_License.txt +0 -202
- cmdbox/licenses/LICENSE_tiktoken_0_11_0_MIT_License-Copyright-c-2022_OpenAI-Shantanu_Jain-Permission_is_hereby_granted-free_of_charge-to_any_per.txt +0 -21
- 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 +0 -21
- cmdbox/licenses/LICENSE_tokenizers_0_21_4_Apache_Software_License.txt +0 -1
- cmdbox/licenses/LICENSE_tqdm_4_67_1_MIT_License-Mozilla_Public_License_2_0-MPL_2_0.txt +0 -49
- cmdbox/licenses/LICENSE_typing_extensions_4_14_1_UNKNOWN.txt +0 -279
- cmdbox/licenses/LICENSE_tzlocal_5_3_1_MIT_License.txt +0 -19
- cmdbox/licenses/LICENSE_uritemplate_4_2_0_BSD_3-Clause_OR_Apache-2_0.txt +0 -3
- cmdbox/licenses/LICENSE_uvicorn_0_35_0_BSD_License.txt +0 -27
- cmdbox/licenses/LICENSE_voicevox_core_0_16_0_MIT.txt +0 -20
- cmdbox/licenses/LICENSE_watchdog_6_0_0_Apache_Software_License.txt +0 -16
- cmdbox/licenses/LICENSE_websockets_15_0_1_BSD_License.txt +0 -24
- cmdbox/licenses/LICENSE_yarl_1_20_1_Apache_Software_License.txt +0 -202
- /cmdbox/licenses/{LICENSE_click_8_2_1_UNKNOWN.txt → LICENSE_click_8_3_0_UNKNOWN.txt} +0 -0
- /cmdbox/licenses/{LICENSE_cryptography_45_0_5_Apache-2_0_OR_BSD-3-Clause.txt → LICENSE_cryptography_46_0_1_UNKNOWN.txt} +0 -0
- /cmdbox/licenses/{LICENSE_fastapi_0_116_1_MIT_License.txt → LICENSE_fastapi_0_116_2_MIT_License.txt} +0 -0
- /cmdbox/licenses/{LICENSE_gevent_25_5_1_MIT.txt → LICENSE_gevent_25_9_1_MIT.txt} +0 -0
- /cmdbox/licenses/{LICENSE_jaraco_functools_4_2_1_UNKNOWN.txt → LICENSE_jaraco_functools_4_3_0_UNKNOWN.txt} +0 -0
- /cmdbox/licenses/{LICENSE_more-itertools_10_7_0_MIT_License.txt → LICENSE_more-itertools_10_8_0_UNKNOWN.txt} +0 -0
- /cmdbox/licenses/{LICENSE_numpy_2_3_2_BSD_License.txt → LICENSE_numpy_2_3_3_BSD_License.txt} +0 -0
- /cmdbox/licenses/{LICENSE_prompt_toolkit_3_0_51_BSD_License.txt → LICENSE_prompt_toolkit_3_0_52_BSD_License.txt} +0 -0
- /cmdbox/licenses/{LICENSE_psycopg-binary_3_2_9_GNU_Lesser_General_Public_License_v3-LGPLv3.txt → LICENSE_psycopg-binary_3_2_10_GNU_Lesser_General_Public_License_v3-LGPLv3.txt} +0 -0
- /cmdbox/licenses/{LICENSE_psycopg_3_2_9_GNU_Lesser_General_Public_License_v3-LGPLv3.txt → LICENSE_psycopg_3_2_10_GNU_Lesser_General_Public_License_v3-LGPLv3.txt} +0 -0
- /cmdbox/licenses/{LICENSE_pycparser_2_22_BSD_License.txt → LICENSE_pycparser_2_23_BSD_License.txt} +0 -0
- /cmdbox/licenses/{LICENSE_pydantic_2_11_7_MIT_License.txt → LICENSE_pydantic_2_11_9_MIT_License.txt} +0 -0
- /cmdbox/licenses/{LICENSE_questionary_2_1_0_MIT_License.txt → LICENSE_questionary_2_1_1_MIT_License.txt} +0 -0
- /cmdbox/licenses/{LICENSE_requests_2_32_4_Apache_Software_License.txt → LICENSE_requests_2_32_5_Apache_Software_License.txt} +0 -0
- /cmdbox/licenses/{LICENSE_sphinx-sitemap_2_7_2_UNKNOWN.txt → LICENSE_sphinx-sitemap_2_8_0_UNKNOWN.txt} +0 -0
- /cmdbox/licenses/{LICENSE_starlette_0_47_2_BSD_License.txt → LICENSE_starlette_0_48_0_BSD_License.txt} +0 -0
- /cmdbox/licenses/{LICENSE_twine_6_1_0_Apache_Software_License.txt → LICENSE_twine_6_2_0_UNKNOWN.txt} +0 -0
- /cmdbox/licenses/{LICENSE_aiohappyeyeballs_2_6_1_Python_Software_Foundation_License.txt → LICENSE_typing_extensions_4_15_0_UNKNOWN.txt} +0 -0
- /cmdbox/licenses/{LICENSE_zope_event_5_1_1_Zope_Public_License.txt → LICENSE_zope_event_6_0_Zope_Public_License.txt} +0 -0
- /cmdbox/licenses/{LICENSE_zope_interface_7_2_Zope_Public_License.txt → LICENSE_zope_interface_8_0_Zope_Public_License.txt} +0 -0
- {cmdbox-0.6.4.1.dist-info → cmdbox-0.6.5.dist-info}/WHEEL +0 -0
- {cmdbox-0.6.4.1.dist-info → cmdbox-0.6.5.dist-info}/entry_points.txt +0 -0
- {cmdbox-0.6.4.1.dist-info → cmdbox-0.6.5.dist-info}/licenses/LICENSE +0 -0
- {cmdbox-0.6.4.1.dist-info → cmdbox-0.6.5.dist-info}/top_level.txt +0 -0
cmdbox/app/app.py
CHANGED
|
@@ -118,6 +118,13 @@ class CmdBoxApp:
|
|
|
118
118
|
args = argparse.Namespace(**{k:common.chopdq(v) for k,v in args_dict.items()})
|
|
119
119
|
eargsparsetime = time.perf_counter()
|
|
120
120
|
|
|
121
|
+
if args.debug_attach:
|
|
122
|
+
import debugpy
|
|
123
|
+
debugpy.listen(("", args.debug_attach_port))
|
|
124
|
+
self.default_logger.info(f"Waiting for debugger attach on port {args.debug_attach_port}...")
|
|
125
|
+
debugpy.wait_for_client()
|
|
126
|
+
self.default_logger.info("Debugger attached.")
|
|
127
|
+
|
|
121
128
|
ret = dict(success=f"Start command. {args}")
|
|
122
129
|
if args.saveopt:
|
|
123
130
|
if args.useopt is None:
|
cmdbox/app/client.py
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
from pathlib import Path
|
|
2
|
-
from cmdbox.app import filer
|
|
2
|
+
from cmdbox.app import common, filer
|
|
3
3
|
from cmdbox.app.commons import convert, redis_client
|
|
4
4
|
import base64
|
|
5
5
|
import logging
|
|
@@ -196,12 +196,13 @@ class Client(object):
|
|
|
196
196
|
if download_file.exists():
|
|
197
197
|
self.logger.warning(f"download_file {download_file} already exists.")
|
|
198
198
|
return dict(warn=f"download_file {download_file} already exists.")
|
|
199
|
-
|
|
199
|
+
def _wd(f):
|
|
200
200
|
f.write(base64.b64decode(res_json["success"]["data"]))
|
|
201
201
|
del res_json["success"]["data"]
|
|
202
202
|
res_json["success"]["download_file"] = str(download_file.absolute())
|
|
203
|
+
common.save_file(download_file, _wd, mode='wb')
|
|
203
204
|
return res_json
|
|
204
|
-
|
|
205
|
+
|
|
205
206
|
def file_upload(self, svpath:str, upload_file:Path, scope:str="client", client_data:Path=None, mkdir:bool=False, orverwrite:bool=False,
|
|
206
207
|
retry_count:int=3, retry_interval:int=5, timeout:int=60):
|
|
207
208
|
"""
|
cmdbox/app/common.py
CHANGED
|
@@ -80,8 +80,9 @@ def load_yml(yml_path:Path) -> dict:
|
|
|
80
80
|
Returns:
|
|
81
81
|
dict: 読み込んだYAMLファイルの内容
|
|
82
82
|
"""
|
|
83
|
-
|
|
83
|
+
def _r(f):
|
|
84
84
|
return yaml.safe_load(f)
|
|
85
|
+
return load_file(yml_path, _r)
|
|
85
86
|
|
|
86
87
|
def save_yml(yml_path:Path, data:dict) -> None:
|
|
87
88
|
"""
|
|
@@ -91,8 +92,83 @@ def save_yml(yml_path:Path, data:dict) -> None:
|
|
|
91
92
|
yml_path (Path): YAMLファイルのパス
|
|
92
93
|
data (dict): 書き込むデータ
|
|
93
94
|
"""
|
|
94
|
-
|
|
95
|
+
def _w(f):
|
|
95
96
|
yaml.dump(data, f, default_flow_style=False, sort_keys=False)
|
|
97
|
+
save_file(yml_path, _w)
|
|
98
|
+
|
|
99
|
+
def load_file(file_path:Path, func, mode='r', encoding='utf-8') -> None:
|
|
100
|
+
"""
|
|
101
|
+
ファイルを読み込みます。読み込み時に排他ロックします。
|
|
102
|
+
|
|
103
|
+
Args:
|
|
104
|
+
file_path (Path): ファイルのパス
|
|
105
|
+
func: 読み込んだデータを処理する関数
|
|
106
|
+
mode (str, optional): ファイルモード. Defaults to 'r'.
|
|
107
|
+
encoding (str, optional): エンコーディング. Defaults to 'utf-8'.
|
|
108
|
+
"""
|
|
109
|
+
lock_file = f'{file_path}.lock'
|
|
110
|
+
try:
|
|
111
|
+
with open(lock_file, 'w') as fd:
|
|
112
|
+
try:
|
|
113
|
+
if sys.platform == 'win32':
|
|
114
|
+
import msvcrt
|
|
115
|
+
msvcrt.locking(fd.fileno(), msvcrt.LK_LOCK, 0)
|
|
116
|
+
else:
|
|
117
|
+
import fcntl
|
|
118
|
+
fcntl.lockf(fd, fcntl.LOCK_EX)
|
|
119
|
+
if 'b' in mode:
|
|
120
|
+
with open(file_path, mode) as f:
|
|
121
|
+
return func(f)
|
|
122
|
+
else:
|
|
123
|
+
with open(file_path, mode, encoding=encoding) as f:
|
|
124
|
+
return func(f)
|
|
125
|
+
finally:
|
|
126
|
+
if sys.platform == 'win32':
|
|
127
|
+
msvcrt.locking(fd.fileno(), msvcrt.LK_UNLCK, 0)
|
|
128
|
+
else:
|
|
129
|
+
fcntl.lockf(fd, fcntl.LOCK_UN)
|
|
130
|
+
finally:
|
|
131
|
+
try:
|
|
132
|
+
os.remove(lock_file)
|
|
133
|
+
except:
|
|
134
|
+
pass
|
|
135
|
+
|
|
136
|
+
def save_file(file_path:Path, func, mode='w', encoding='utf-8') -> None:
|
|
137
|
+
"""
|
|
138
|
+
ファイルに書き込みます。書き込み時に排他ロックします。
|
|
139
|
+
|
|
140
|
+
Args:
|
|
141
|
+
file_path (Path): ファイルのパス
|
|
142
|
+
func: 書き込む関数
|
|
143
|
+
mode (str, optional): ファイルモード. Defaults to 'w'.
|
|
144
|
+
encoding (str, optional): エンコーディング. Defaults to 'utf-8'.
|
|
145
|
+
"""
|
|
146
|
+
lock_file = f'{file_path}.lock'
|
|
147
|
+
try:
|
|
148
|
+
with open(lock_file, 'w') as fd:
|
|
149
|
+
try:
|
|
150
|
+
if sys.platform == 'win32':
|
|
151
|
+
import msvcrt
|
|
152
|
+
msvcrt.locking(fd.fileno(), msvcrt.LK_LOCK, 0)
|
|
153
|
+
else:
|
|
154
|
+
import fcntl
|
|
155
|
+
fcntl.lockf(fd, fcntl.LOCK_EX)
|
|
156
|
+
if 'b' in mode:
|
|
157
|
+
with open(file_path, mode) as f:
|
|
158
|
+
func(f)
|
|
159
|
+
else:
|
|
160
|
+
with open(file_path, mode, encoding=encoding) as f:
|
|
161
|
+
func(f)
|
|
162
|
+
finally:
|
|
163
|
+
if sys.platform == 'win32':
|
|
164
|
+
msvcrt.locking(fd.fileno(), msvcrt.LK_UNLCK, 0)
|
|
165
|
+
else:
|
|
166
|
+
fcntl.lockf(fd, fcntl.LOCK_UN)
|
|
167
|
+
finally:
|
|
168
|
+
try:
|
|
169
|
+
os.remove(lock_file)
|
|
170
|
+
except:
|
|
171
|
+
pass
|
|
96
172
|
|
|
97
173
|
class CommonValue:
|
|
98
174
|
_map = dict()
|
|
@@ -251,8 +327,7 @@ def load_config(mode:str, debug:bool=False, data=HOME_DIR, webcall:bool=False, v
|
|
|
251
327
|
if not log_conf_path.exists():
|
|
252
328
|
log_conf_path = Path(version.__file__).parent / f"logconf_{ver.__appid__}.yml"
|
|
253
329
|
log_name = mode
|
|
254
|
-
|
|
255
|
-
log_config = yaml.safe_load(f)
|
|
330
|
+
log_config = load_yml(log_conf_path)
|
|
256
331
|
std_key = None
|
|
257
332
|
set_common_value('webcall', webcall)
|
|
258
333
|
for k, h in log_config['handlers'].items():
|
|
@@ -343,8 +418,9 @@ def saveopt(opt:dict, opt_path:Path, webmode:bool=False) -> None:
|
|
|
343
418
|
k = r['opt']
|
|
344
419
|
d = r['default'] if 'default' in r else None
|
|
345
420
|
opt[k] = d if k not in lopts else lopts.get(k, d)
|
|
346
|
-
|
|
421
|
+
def _w(f):
|
|
347
422
|
json.dump(opt, f, indent=4, default=default_json_enc)
|
|
423
|
+
save_file(opt_path, _w)
|
|
348
424
|
|
|
349
425
|
def saveuser(user_data:dict, user_path:Path) -> None:
|
|
350
426
|
"""
|
|
@@ -552,9 +628,10 @@ def print_format(data:dict, format:bool, tm:float, output_json:str=None, output_
|
|
|
552
628
|
pass
|
|
553
629
|
if output_json is not None:
|
|
554
630
|
try:
|
|
555
|
-
|
|
631
|
+
def _w(f):
|
|
556
632
|
json.dump(data, f, default=default_json_enc, ensure_ascii=False)
|
|
557
633
|
print('', file=f)
|
|
634
|
+
save_file(Path(output_json), _w, mode='a' if output_json_append else 'w')
|
|
558
635
|
except Exception as e:
|
|
559
636
|
pass
|
|
560
637
|
return txt
|
|
@@ -584,8 +661,9 @@ def download_file(url:str, save_path:Path) -> Path:
|
|
|
584
661
|
Path: 保存したファイルのパス
|
|
585
662
|
"""
|
|
586
663
|
r = requests.get(url, stream=True)
|
|
587
|
-
|
|
664
|
+
def _w(f):
|
|
588
665
|
f.write(r.content)
|
|
666
|
+
save_file(Path(save_path), _w)
|
|
589
667
|
return save_path
|
|
590
668
|
|
|
591
669
|
def cmd(cmd:str, logger:logging.Logger, slise:int=100, newenv:Dict=None) -> Tuple[int, str, str]:
|
cmdbox/app/commons/convert.py
CHANGED
|
@@ -99,8 +99,10 @@ def npy2imgfile(npy, output_image_file:Path=None, image_type:str='jpeg') -> byte
|
|
|
99
99
|
image_type = 'jpeg' if image_type == 'jpg' else image_type
|
|
100
100
|
img_byte = img2byte(image, format=image_type)
|
|
101
101
|
if output_image_file is not None:
|
|
102
|
-
|
|
102
|
+
from cmdbox.app import common
|
|
103
|
+
def _w(f):
|
|
103
104
|
f.write(img_byte)
|
|
105
|
+
common.save_file(output_image_file, _w, mode='wb')
|
|
104
106
|
return img_byte
|
|
105
107
|
|
|
106
108
|
def bytes2b64str(img:bytes) -> str:
|
cmdbox/app/edge.py
CHANGED
|
@@ -515,9 +515,9 @@ class Edge(object):
|
|
|
515
515
|
except Exception as e:
|
|
516
516
|
raise HTTPException(status_code=500, detail=f'Failed to get token. {e}')
|
|
517
517
|
|
|
518
|
-
if not hasattr(self, '
|
|
519
|
-
self.
|
|
520
|
-
self.
|
|
518
|
+
if not hasattr(self, 'thHttp') or not self.thHttp.is_alive():
|
|
519
|
+
self.thHttp = web.ThreadedASGI(config=Config(app=fastapi, host='localhost', port=oauth2_port))
|
|
520
|
+
self.thHttp.start()
|
|
521
521
|
time.sleep(1)
|
|
522
522
|
|
|
523
523
|
# OAuth2認証のリクエストを送信
|
|
@@ -581,9 +581,9 @@ class Edge(object):
|
|
|
581
581
|
except Exception as e:
|
|
582
582
|
raise HTTPException(status_code=500, detail=f'Failed to get token. {e}')
|
|
583
583
|
|
|
584
|
-
if not hasattr(self, '
|
|
585
|
-
self.
|
|
586
|
-
self.
|
|
584
|
+
if not hasattr(self, 'thHttp') or not self.thHttp.is_alive():
|
|
585
|
+
self.thHttp = web.ThreadedASGI(config=Config(app=fastapi, host='localhost', port=oauth2_port))
|
|
586
|
+
self.thHttp.start()
|
|
587
587
|
time.sleep(1)
|
|
588
588
|
|
|
589
589
|
# OAuth2認証のリクエストを送信
|
|
@@ -652,9 +652,9 @@ class Edge(object):
|
|
|
652
652
|
except Exception as e:
|
|
653
653
|
raise HTTPException(status_code=500, detail=f'Failed to get token. {e}')
|
|
654
654
|
|
|
655
|
-
if not hasattr(self, '
|
|
656
|
-
self.
|
|
657
|
-
self.
|
|
655
|
+
if not hasattr(self, 'thHttp') or not self.thHttp.is_alive():
|
|
656
|
+
self.thHttp = web.ThreadedASGI(config=Config(app=fastapi, host='localhost', port=oauth2_port))
|
|
657
|
+
self.thHttp.start()
|
|
658
658
|
time.sleep(1)
|
|
659
659
|
|
|
660
660
|
# OAuth2認証のリクエストを送信
|
|
@@ -734,9 +734,9 @@ class Edge(object):
|
|
|
734
734
|
except Exception as e:
|
|
735
735
|
raise HTTPException(status_code=500, detail=f'Failed to get token. {e}')
|
|
736
736
|
|
|
737
|
-
if not hasattr(self, '
|
|
738
|
-
self.
|
|
739
|
-
self.
|
|
737
|
+
if not hasattr(self, 'thHttp') or not self.thHttp.is_alive():
|
|
738
|
+
self.thHttp = web.ThreadedASGI(config=Config(app=fastapi, host='localhost', port=saml_port))
|
|
739
|
+
self.thHttp.start()
|
|
740
740
|
time.sleep(1)
|
|
741
741
|
|
|
742
742
|
# SAML認証のリクエストを送信
|
|
@@ -0,0 +1,214 @@
|
|
|
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
|
+
def _wm(f):
|
|
189
|
+
f.write(responce.content)
|
|
190
|
+
common.save_file(model_file, _wm, mode='wb')
|
|
191
|
+
#===============================================================
|
|
192
|
+
# SAM2のpythonライブラリのインストール
|
|
193
|
+
whl_url = f'git+https://github.com/facebookresearch/sam2.git'
|
|
194
|
+
# whlファイルをpipでインストール
|
|
195
|
+
if logger.level == logging.DEBUG:
|
|
196
|
+
logger.debug(f"pip install {whl_url}")
|
|
197
|
+
rescode = pip.main(['install', str(whl_url)]) # pipのインストール
|
|
198
|
+
logger.info(f"Install wheel: {whl_url}")
|
|
199
|
+
if rescode != 0:
|
|
200
|
+
_msg = f"Failed to install SAM2 python library: Possible whl not in the environment. {whl_url}"
|
|
201
|
+
logger.error(_msg, exc_info=True)
|
|
202
|
+
return dict(warn=_msg)
|
|
203
|
+
#===============================================================
|
|
204
|
+
# 成功時の処理
|
|
205
|
+
rescode, _msg = (self.RESP_SUCCESS, dict(success=f'Success to install SAM2 python library. {whl_url}'))
|
|
206
|
+
return dict(success=_msg)
|
|
207
|
+
else:
|
|
208
|
+
_msg = f"Unsupported vision engine: {vision_engine}"
|
|
209
|
+
logger.error(_msg, exc_info=True)
|
|
210
|
+
return dict(warn=_msg)
|
|
211
|
+
except Exception as e:
|
|
212
|
+
_msg = f"Failed to install vision engine: {e}"
|
|
213
|
+
logger.warning(_msg, exc_info=True)
|
|
214
|
+
return dict(warn=_msg)
|