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
|
@@ -0,0 +1,496 @@
|
|
|
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 datetime
|
|
10
|
+
import logging
|
|
11
|
+
import json
|
|
12
|
+
import numpy as np
|
|
13
|
+
import time
|
|
14
|
+
import sys
|
|
15
|
+
|
|
16
|
+
|
|
17
|
+
|
|
18
|
+
class VisionPredict(cmdbox_vision_start.VisionStart):
|
|
19
|
+
|
|
20
|
+
def get_mode(self) -> Union[str, List[str]]:
|
|
21
|
+
"""
|
|
22
|
+
この機能のモードを返します
|
|
23
|
+
|
|
24
|
+
Returns:
|
|
25
|
+
Union[str, List[str]]: モード
|
|
26
|
+
"""
|
|
27
|
+
return 'vision'
|
|
28
|
+
|
|
29
|
+
def get_cmd(self):
|
|
30
|
+
"""
|
|
31
|
+
この機能のコマンドを返します
|
|
32
|
+
|
|
33
|
+
Returns:
|
|
34
|
+
str: コマンド
|
|
35
|
+
"""
|
|
36
|
+
return 'predict'
|
|
37
|
+
|
|
38
|
+
def get_option(self):
|
|
39
|
+
"""
|
|
40
|
+
この機能のオプションを返します
|
|
41
|
+
|
|
42
|
+
Returns:
|
|
43
|
+
Dict[str, Any]: オプション
|
|
44
|
+
"""
|
|
45
|
+
return dict(
|
|
46
|
+
use_redis=self.USE_REDIS_MEIGHT, nouse_webmode=False, use_agent=True,
|
|
47
|
+
description_ja="画像/動画の推論を実行します。",
|
|
48
|
+
description_en="Executes inference on images/videos.",
|
|
49
|
+
choice=[
|
|
50
|
+
dict(opt="host", type=Options.T_STR, default=self.default_host, required=True, multi=False, hide=True, choice=None, web="mask",
|
|
51
|
+
description_ja="Redisサーバーのサービスホストを指定します。",
|
|
52
|
+
description_en="Specify the service host of the Redis server."),
|
|
53
|
+
dict(opt="port", type=Options.T_INT, default=self.default_port, required=True, multi=False, hide=True, choice=None, web="mask",
|
|
54
|
+
description_ja="Redisサーバーのサービスポートを指定します。",
|
|
55
|
+
description_en="Specify the service port of the Redis server."),
|
|
56
|
+
dict(opt="password", type=Options.T_STR, default=self.default_pass, required=True, multi=False, hide=True, choice=None, web="mask",
|
|
57
|
+
description_ja=f"Redisサーバーのアクセスパスワード(任意)を指定します。省略時は `{self.default_pass}` を使用します。",
|
|
58
|
+
description_en=f"Specify the access password of the Redis server (optional). If omitted, `{self.default_pass}` is used."),
|
|
59
|
+
dict(opt="svname", type=Options.T_STR, default=self.default_svname, required=True, multi=False, hide=True, choice=None, web="readonly",
|
|
60
|
+
description_ja="サーバーのサービス名を指定します。省略時は `server` を使用します。",
|
|
61
|
+
description_en="Specify the service name of the inference server. If omitted, `server` is used."),
|
|
62
|
+
dict(opt="retry_count", type=Options.T_INT, default=3, required=False, multi=False, hide=True, choice=None,
|
|
63
|
+
description_ja="Redisサーバーへの再接続回数を指定します。0以下を指定すると永遠に再接続を行います。",
|
|
64
|
+
description_en="Specifies the number of reconnections to the Redis server.If less than 0 is specified, reconnection is forever."),
|
|
65
|
+
dict(opt="retry_interval", type=Options.T_INT, default=5, required=False, multi=False, hide=True, choice=None,
|
|
66
|
+
description_ja="Redisサーバーに再接続までの秒数を指定します。",
|
|
67
|
+
description_en="Specifies the number of seconds before reconnecting to the Redis server."),
|
|
68
|
+
dict(opt="timeout", type=Options.T_INT, default="60", required=False, multi=False, hide=True, choice=None,
|
|
69
|
+
description_ja="サーバーの応答が返ってくるまでの最大待ち時間を指定。",
|
|
70
|
+
description_en="Specify the maximum waiting time until the server responds."),
|
|
71
|
+
dict(opt="vision_engine", type=Options.T_STR, default="sam2", required=True, multi=False, hide=False,
|
|
72
|
+
choice=["sam2"],
|
|
73
|
+
choice_show=dict(sam2=["sam2_model", "sam2_point"]),
|
|
74
|
+
description_ja="使用するVisionエンジンを指定します。",
|
|
75
|
+
description_en="Specify the Vision engine to use."),
|
|
76
|
+
dict(opt="sam2_model", type=Options.T_STR, default="092824/sam2.1_hiera_tiny.pt", required=True, multi=False, hide=False,
|
|
77
|
+
choice=[k for k in self.VISION_MODEL.keys() if self.VISION_MODEL[k]['type'] == 'sam2'],
|
|
78
|
+
choice_edit=True,
|
|
79
|
+
description_ja="使用するSAM2モデルを指定します。",
|
|
80
|
+
description_en="Specify the SAM2 model to use."),
|
|
81
|
+
dict(opt="sam2_point", type=Options.T_STR, default=None, required=True, multi=True, hide=False, choice=None,
|
|
82
|
+
description_ja="使用するSAM2モデルのポイントを指定します。 `x,y` の形式で指定してください。",
|
|
83
|
+
description_en="Specify the SAM2 model points to use. Please specify in the format `x,y`."),
|
|
84
|
+
dict(opt="sam2_label", type=Options.T_INT, default=1, required=False, multi=True, hide=False, choice=None,
|
|
85
|
+
description_ja="使用するSAM2モデルのラベルを指定します。",
|
|
86
|
+
description_en="Specify the SAM2 model label to use."),
|
|
87
|
+
dict(opt="img_input_file", type=Options.T_FILE, default=None, required=False, multi=False, hide=False, choice=None, fileio="in",
|
|
88
|
+
description_ja="入力画像ファイルを指定します。",
|
|
89
|
+
description_en="Specify the input image file."),
|
|
90
|
+
dict(opt="img_input_type", type=Options.T_STR, default="jpeg", required=True, multi=False, hide=False,
|
|
91
|
+
choice=['bmp', 'png', 'jpeg', 'capture'],
|
|
92
|
+
description_ja="入力画像の形式を指定します。",
|
|
93
|
+
description_en="Specify the format of the input image."),
|
|
94
|
+
dict(opt="img_stdin", type=Options.T_BOOL, default=False, required=False, multi=False, hide=False, choice=[True, False],
|
|
95
|
+
description_ja="標準入力から画像を読み込みます。",
|
|
96
|
+
description_en="Read images from standard input."),
|
|
97
|
+
dict(opt="img_output_file", type=Options.T_FILE, default=None, required=False, multi=False, hide=False, choice=None, fileio="out",
|
|
98
|
+
description_ja="推論結果画像の保存先ファイルを指定します。",
|
|
99
|
+
description_en="Specify the destination file for saving the inference result image.",
|
|
100
|
+
test_true={"yolox":"pred.jpg"}),
|
|
101
|
+
dict(opt="nodraw", type=Options.T_BOOL, default=False, required=False, multi=False, hide=False, choice=[True, False],
|
|
102
|
+
description_ja="指定すると推論結果を画像に描き込みしません。",
|
|
103
|
+
description_en="If specified, inference results will not be drawn on the image."),
|
|
104
|
+
dict(opt="output_json", short="o" , type=Options.T_FILE, default=None, required=False, multi=False, hide=True, choice=None, fileio="out",
|
|
105
|
+
description_ja="処理結果jsonの保存先ファイルを指定。",
|
|
106
|
+
description_en="Specify the destination file for saving the processing result json."),
|
|
107
|
+
dict(opt="output_json_append", short="a" , type=Options.T_BOOL, default=False, required=False, multi=False, hide=True, choice=[True, False],
|
|
108
|
+
description_ja="処理結果jsonファイルを追記保存します。",
|
|
109
|
+
description_en="Save the processing result json file by appending."),
|
|
110
|
+
dict(opt="stdout_log", type=Options.T_BOOL, default=True, required=False, multi=False, hide=True, choice=[True, False],
|
|
111
|
+
description_ja="GUIモードでのみ使用可能です。コマンド実行時の標準出力をConsole logに出力します。",
|
|
112
|
+
description_en="Available only in GUI mode. Outputs standard output during command execution to Console log."),
|
|
113
|
+
dict(opt="capture_stdout", type=Options.T_BOOL, default=True, required=False, multi=False, hide=True, choice=[True, False],
|
|
114
|
+
description_ja="GUIモードでのみ使用可能です。コマンド実行時の標準出力をキャプチャーし、実行結果画面に表示します。",
|
|
115
|
+
description_en="Available only in GUI mode. Captures standard output during command execution and displays it on the execution result screen."),
|
|
116
|
+
dict(opt="capture_maxsize", type=Options.T_INT, default=self.DEFAULT_CAPTURE_MAXSIZE, required=False, multi=False, hide=True, choice=None,
|
|
117
|
+
description_ja="GUIモードでのみ使用可能です。コマンド実行時の標準出力の最大キャプチャーサイズを指定します。",
|
|
118
|
+
description_en="Available only in GUI mode. Specifies the maximum capture size of standard output when executing commands."),
|
|
119
|
+
]
|
|
120
|
+
)
|
|
121
|
+
|
|
122
|
+
def get_svcmd(self):
|
|
123
|
+
"""
|
|
124
|
+
この機能のサーバー側のコマンドを返します
|
|
125
|
+
|
|
126
|
+
Returns:
|
|
127
|
+
str: サーバー側のコマンド
|
|
128
|
+
"""
|
|
129
|
+
return 'vision_predict'
|
|
130
|
+
|
|
131
|
+
def apprun(self, logger:logging.Logger, args:argparse.Namespace, tm:float, pf:List[Dict[str, float]]=[]) -> Tuple[int, Dict[str, Any], Any]:
|
|
132
|
+
"""
|
|
133
|
+
この機能の実行を行います
|
|
134
|
+
|
|
135
|
+
Args:
|
|
136
|
+
logger (logging.Logger): ロガー
|
|
137
|
+
args (argparse.Namespace): 引数
|
|
138
|
+
tm (float): 実行開始時間
|
|
139
|
+
pf (List[Dict[str, float]]): 呼出元のパフォーマンス情報
|
|
140
|
+
|
|
141
|
+
Returns:
|
|
142
|
+
Tuple[int, Dict[str, Any], Any]: 終了コード, 結果, オブジェクト
|
|
143
|
+
"""
|
|
144
|
+
if args.vision_engine is None:
|
|
145
|
+
msg = dict(warn=f"Please specify the --vision_engine option.")
|
|
146
|
+
common.print_format(msg, False, tm, args.output_json, args.output_json_append, pf=pf)
|
|
147
|
+
return self.RESP_WARN, msg, None
|
|
148
|
+
model_param = dict()
|
|
149
|
+
if args.vision_engine == 'sam2':
|
|
150
|
+
if args.sam2_model is None:
|
|
151
|
+
msg = dict(warn=f"Please specify the --sam2_model option.")
|
|
152
|
+
common.print_format(msg, False, tm, args.output_json, args.output_json_append, pf=pf)
|
|
153
|
+
return self.RESP_WARN, msg, None
|
|
154
|
+
try:
|
|
155
|
+
model_param['sam2_model'] = args.sam2_model
|
|
156
|
+
model_param['sam2_point'] = [row.split(',') for row in args.sam2_point]
|
|
157
|
+
model_param['sam2_label'] = args.sam2_label
|
|
158
|
+
except Exception as e:
|
|
159
|
+
msg = dict(warn=f"Invalid --sam2_point option. {str(e)}")
|
|
160
|
+
common.print_format(msg, False, tm, args.output_json, args.output_json_append, pf=pf)
|
|
161
|
+
return self.RESP_WARN, msg, None
|
|
162
|
+
else:
|
|
163
|
+
msg = dict(warn=f"Unsupported vision engine: {args.vision_engine}")
|
|
164
|
+
common.print_format(msg, False, tm, args.output_json, args.output_json_append, pf=pf)
|
|
165
|
+
return self.RESP_WARN, msg, None
|
|
166
|
+
|
|
167
|
+
cl = client.Client(logger, redis_host=args.host, redis_port=args.port, redis_password=args.password, svname=args.svname)
|
|
168
|
+
if args.img_input_file is not None:
|
|
169
|
+
if logger.level == logging.DEBUG:
|
|
170
|
+
logger.debug(f"app.main: args.mode={args.mode}, args.cmd={args.cmd}, args.name={args.name}, args.img_input_file={args.img_input_file}")
|
|
171
|
+
ret = self.predict(cl, args.vision_engine, model_param=model_param, img_input_file=args.img_input_file, img_input_type=args.img_input_type,
|
|
172
|
+
img_output_file=args.img_output_file, nodraw=args.nodraw,
|
|
173
|
+
retry_count=args.retry_count, retry_interval=args.retry_interval, timeout=args.timeout,
|
|
174
|
+
logger=logger)
|
|
175
|
+
if type(ret) is list:
|
|
176
|
+
for r in ret:
|
|
177
|
+
common.print_format(r, args.format, tm, args.output_json, args.output_json_append, pf=pf)
|
|
178
|
+
if logger.level == logging.DEBUG:
|
|
179
|
+
ret_str = common.to_str(r, slise=100)
|
|
180
|
+
logger.debug(f"app.main: args.mode={args.mode}, args.cmd={args.cmd}, ret={ret_str}")
|
|
181
|
+
tm = time.perf_counter()
|
|
182
|
+
args.output_json_append = True
|
|
183
|
+
else:
|
|
184
|
+
common.print_format(ret, args.format, tm, args.output_json, args.output_json_append, pf=pf)
|
|
185
|
+
elif args.stdin:
|
|
186
|
+
if args.img_input_type is None:
|
|
187
|
+
msg = {"warn":f"Please specify the --img_input_type option."}
|
|
188
|
+
common.print_format(msg, args.format, tm, args.output_json, args.output_json_append, pf=pf)
|
|
189
|
+
if logger.level == logging.DEBUG:
|
|
190
|
+
msg_str = common.to_str(msg, slise=100)
|
|
191
|
+
logger.debug(f"app.main: args.mode={args.mode}, args.cmd={args.cmd}, msg={msg_str}")
|
|
192
|
+
return self.RESP_WARN, msg, None
|
|
193
|
+
if args.img_input_type in ['capture']:
|
|
194
|
+
def _pred(args, line, tm):
|
|
195
|
+
if logger.level == logging.DEBUG:
|
|
196
|
+
line_str = common.to_str(line, slise=100)
|
|
197
|
+
logger.debug(f"app.main: args.mode={args.mode}, args.cmd={args.cmd}, args.name={args.name}, image={line_str}")
|
|
198
|
+
ret = self.predict(cl, args.vision_engine, model_param=model_param, image=line, img_input_type=args.img_input_type,
|
|
199
|
+
img_output_file=args.img_output_file, nodraw=args.nodraw,
|
|
200
|
+
retry_count=args.retry_count, retry_interval=args.retry_interval, timeout=args.timeout,
|
|
201
|
+
logger=logger)
|
|
202
|
+
common.print_format(ret, args.format, tm, args.output_json, args.output_json_append, pf=pf)
|
|
203
|
+
if logger.level == logging.DEBUG:
|
|
204
|
+
ret_str = common.to_str(ret, slise=100)
|
|
205
|
+
logger.debug(f"app.main: args.mode={args.mode}, args.cmd={args.cmd}, ret={ret_str}")
|
|
206
|
+
for line in sys.stdin:
|
|
207
|
+
# 標準入力による推論処理は非同期で行う(同名複数serverの場合にスループットを向上させるため)
|
|
208
|
+
#thread = threading.Thread(target=_pred, args=(args, line, tm))
|
|
209
|
+
#thread.start()
|
|
210
|
+
_pred(args, line, tm)
|
|
211
|
+
tm = time.perf_counter()
|
|
212
|
+
args.output_json_append = True
|
|
213
|
+
else:
|
|
214
|
+
if logger.level == logging.DEBUG:
|
|
215
|
+
logger.debug(f"app.main: args.mode={args.mode}, args.cmd={args.cmd}, args.name={args.name}, image=<stdin>")
|
|
216
|
+
ret = self.predict(cl, args.vision_engine, model_param=model_param, image=sys.stdin.buffer.read(), img_input_type=args.img_input_type,
|
|
217
|
+
img_output_file=args.img_output_file, nodraw=args.nodraw,
|
|
218
|
+
retry_count=args.retry_count, retry_interval=args.retry_interval, timeout=args.timeout,
|
|
219
|
+
logger=logger)
|
|
220
|
+
common.print_format(ret, args.format, tm, args.output_json, args.output_json_append, pf=pf)
|
|
221
|
+
if logger.level == logging.DEBUG:
|
|
222
|
+
ret_str = common.to_str(ret, slise=100)
|
|
223
|
+
logger.debug(f"app.main: args.mode={args.mode}, args.cmd={args.cmd}, ret={ret_str}")
|
|
224
|
+
tm = time.perf_counter()
|
|
225
|
+
else:
|
|
226
|
+
msg = {"warn":f"Image file or stdin is empty."}
|
|
227
|
+
common.print_format(msg, args.format, tm, args.output_json, args.output_json_append, pf=pf)
|
|
228
|
+
if logger.level == logging.DEBUG:
|
|
229
|
+
msg_str = common.to_str(msg, slise=100)
|
|
230
|
+
logger.debug(f"app.main: args.mode={args.mode}, args.cmd={args.cmd}, msg={msg_str}")
|
|
231
|
+
return self.RESP_WARN, msg, None
|
|
232
|
+
|
|
233
|
+
common.print_format(ret, False, tm, None, False, pf=pf)
|
|
234
|
+
if 'success' not in ret:
|
|
235
|
+
return self.RESP_WARN, ret, None
|
|
236
|
+
return self.RESP_SUCCESS, ret, None
|
|
237
|
+
|
|
238
|
+
def predict(self, cl:client.Client, vision_engine:str, model_param:Dict[str, Any]=None,
|
|
239
|
+
image=None, img_input_file=None, img_input_file_enable:bool=True, img_input_type:str='jpeg',
|
|
240
|
+
img_output_file:str=None, nodraw:bool=False,
|
|
241
|
+
retry_count:int=3, retry_interval:int=5, timeout:int=60, logger:logging.Logger=None) -> Dict[str, Any]:
|
|
242
|
+
"""
|
|
243
|
+
画像をRedisサーバーに送信し、推論結果を取得する
|
|
244
|
+
|
|
245
|
+
Args:
|
|
246
|
+
cl (client.Client): Redisサーバーへの接続クライアント
|
|
247
|
+
vision_engine (str): 使用するVisionエンジン
|
|
248
|
+
model_param (Dict[str, Any], optional): モデルのパラメータ. Defaults to None.
|
|
249
|
+
image (np.ndarray | bytes, optional): 画像データ. Defaults to None. np.ndarray型の場合はデコードしない(RGBであること).
|
|
250
|
+
img_input_file (str|file-like object, optional): 画像ファイルのパス. Defaults to None.
|
|
251
|
+
img_input_file_enable (bool, optional): 画像ファイルを使用するかどうか. Defaults to True. img_input_fileがNoneでなく、このパラメーターがTrueの場合はimg_input_fileを使用する.
|
|
252
|
+
img_input_type (str, optional): 画像の形式. Defaults to 'jpeg'.
|
|
253
|
+
img_output_file (str, optional): 予測結果の画像ファイルのパス. Defaults to None.
|
|
254
|
+
nodraw (bool, optional): 描画フラグ. Defaults to False.
|
|
255
|
+
retry_count (int, optional): リトライ回数. Defaults to 3.
|
|
256
|
+
retry_interval (int, optional): リトライ間隔. Defaults to 5.
|
|
257
|
+
timeout (int, optional): タイムアウト時間. Defaults to 60.
|
|
258
|
+
logger (logging.Logger, optional): ロガー. Defaults to None.
|
|
259
|
+
|
|
260
|
+
Returns:
|
|
261
|
+
dict: Redisサーバーからの応答
|
|
262
|
+
"""
|
|
263
|
+
spredtime = time.perf_counter()
|
|
264
|
+
if vision_engine is None or vision_engine == "":
|
|
265
|
+
logger.warning(f"vision_engine is empty.")
|
|
266
|
+
return {"error": f"vision_engine is empty."}
|
|
267
|
+
if image is None and img_input_file is None:
|
|
268
|
+
logger.warning(f"image and img_input_file is empty.")
|
|
269
|
+
return {"error": f"image and img_input_file is empty."}
|
|
270
|
+
npy_b64 = None
|
|
271
|
+
simgloadtime = time.perf_counter()
|
|
272
|
+
if img_input_file is not None and img_input_file_enable:
|
|
273
|
+
if type(img_input_file) == str:
|
|
274
|
+
if not Path(img_input_file).exists():
|
|
275
|
+
logger.warning(f"Not found img_input_file. {img_input_file}.")
|
|
276
|
+
return {"error": f"Not found img_input_file. {img_input_file}."}
|
|
277
|
+
if img_input_type == 'jpeg' or img_input_type == 'png' or img_input_type == 'bmp':
|
|
278
|
+
f = None
|
|
279
|
+
try:
|
|
280
|
+
f = img_input_file if type(img_input_file) is not str else open(img_input_file, "rb")
|
|
281
|
+
img_npy = convert.imgfile2npy(f)
|
|
282
|
+
finally:
|
|
283
|
+
if f is not None: f.close()
|
|
284
|
+
elif img_input_type == 'capture':
|
|
285
|
+
f = None
|
|
286
|
+
try:
|
|
287
|
+
f = img_input_file if type(img_input_file) is not str else open(img_input_file, "r", encoding='utf-8')
|
|
288
|
+
res_list = []
|
|
289
|
+
for line in f:
|
|
290
|
+
if type(line) is bytes:
|
|
291
|
+
line = line.decode('utf-8')
|
|
292
|
+
capture_data = line.strip().split(',')
|
|
293
|
+
t = capture_data[0]
|
|
294
|
+
img = capture_data[1]
|
|
295
|
+
h = int(capture_data[2])
|
|
296
|
+
w = int(capture_data[3])
|
|
297
|
+
c = int(capture_data[4])
|
|
298
|
+
fn = Path(capture_data[5].strip())
|
|
299
|
+
if t == 'capture':
|
|
300
|
+
img_npy = convert.b64str2npy(img, shape=(h, w, c) if c > 0 else (h, w))
|
|
301
|
+
else:
|
|
302
|
+
img_npy = convert.imgbytes2npy(convert.b64str2bytes(img))
|
|
303
|
+
res_json = self.predict(cl, vision_engine, model_param=model_param,
|
|
304
|
+
image=img_npy, img_input_file=fn, img_input_file_enable=False,
|
|
305
|
+
img_output_file=img_output_file, nodraw=nodraw,
|
|
306
|
+
retry_count=retry_count, retry_interval=retry_interval, timeout=timeout,
|
|
307
|
+
logger=logger)
|
|
308
|
+
res_list.append(res_json)
|
|
309
|
+
if len(res_list) <= 0:
|
|
310
|
+
return {"warn": f"capture file is no data."}
|
|
311
|
+
elif len(res_list) == 1:
|
|
312
|
+
return res_list[0]
|
|
313
|
+
return res_list
|
|
314
|
+
except UnicodeDecodeError as e:
|
|
315
|
+
logger.error(f"capture file or img_input_type setting is invalid. img_input_type={img_input_type}. {e}", exc_info=True)
|
|
316
|
+
return {"error": f"capture file or img_input_type setting is invalid. img_input_type={img_input_type}. {e}"}
|
|
317
|
+
finally:
|
|
318
|
+
if f is not None: f.close()
|
|
319
|
+
else:
|
|
320
|
+
logger.warning(f"img_input_type is invalid. {img_input_type}.")
|
|
321
|
+
return {"error": f"img_input_type is invalid. {img_input_type}."}
|
|
322
|
+
else:
|
|
323
|
+
if type(image) == np.ndarray:
|
|
324
|
+
img_npy = image
|
|
325
|
+
if img_input_file is None: img_input_file = f'{datetime.datetime.now().strftime("%Y%m%d%H%M%S%f")}.capture'
|
|
326
|
+
img_input_file_enable = False
|
|
327
|
+
elif img_input_type == 'capture':
|
|
328
|
+
image = image.decode(encoding="utf-8") if type(image) is bytes else image
|
|
329
|
+
capture_data = image.split(',')
|
|
330
|
+
if len(capture_data) < 6:
|
|
331
|
+
logger.warning(f"capture data is invalid. {image}.")
|
|
332
|
+
return {"error": f"capture data is invalid. {image}."}
|
|
333
|
+
t = capture_data[0]
|
|
334
|
+
img = capture_data[1]
|
|
335
|
+
h = int(capture_data[2])
|
|
336
|
+
w = int(capture_data[3])
|
|
337
|
+
c = int(capture_data[4])
|
|
338
|
+
if img_input_file is None: img_input_file = capture_data[5]
|
|
339
|
+
img_input_file_enable = False
|
|
340
|
+
if t == 'capture':
|
|
341
|
+
img_npy = convert.b64str2npy(img, shape=(h, w, c) if c > 0 else (h, w))
|
|
342
|
+
else:
|
|
343
|
+
img_npy = convert.imgbytes2npy(convert.b64str2bytes(img))
|
|
344
|
+
elif img_input_type == 'output_json':
|
|
345
|
+
res_json = json.loads(image)
|
|
346
|
+
if not ("output_image" in res_json and "output_image_shape" in res_json and "output_image_name" in res_json):
|
|
347
|
+
logger.warning(f"img_input_file data is invalid. Not found output_image or output_image_shape or output_image_name key.")
|
|
348
|
+
return {"error": f"img_input_file data is invalid. Not found output_image or output_image_shape or output_image_name key."}
|
|
349
|
+
if res_json["output_image_name"].endswith(".capture"):
|
|
350
|
+
img_npy = convert.b64str2npy(res_json["output_image"], shape=res_json["output_image_shape"])
|
|
351
|
+
else:
|
|
352
|
+
img_bytes = convert.b64str2bytes(res_json["output_image"])
|
|
353
|
+
img_npy = convert.imgbytes2npy(img_bytes)
|
|
354
|
+
if img_input_file is None: img_input_file = res_json["output_image_name"]
|
|
355
|
+
img_input_file_enable = False
|
|
356
|
+
elif img_input_type == 'jpeg' or img_input_type == 'png' or img_input_type == 'bmp':
|
|
357
|
+
img_npy = convert.imgbytes2npy(image)
|
|
358
|
+
if img_input_file is None: img_input_file = f'{datetime.datetime.now().strftime("%Y%m%d%H%M%S%f")}.{img_input_type}'
|
|
359
|
+
img_input_file_enable = False
|
|
360
|
+
else:
|
|
361
|
+
logger.warning(f"img_input_type is invalid. {img_input_type}.")
|
|
362
|
+
return {"error": f"img_input_type is invalid. {img_input_type}."}
|
|
363
|
+
|
|
364
|
+
eimgloadtime = time.perf_counter()
|
|
365
|
+
img_npy_b64 = convert.npy2b64str(img_npy)
|
|
366
|
+
model_param_b64 = convert.str2b64str(common.to_str(model_param))
|
|
367
|
+
img_input_file_b64 = convert.str2b64str(img_input_file)
|
|
368
|
+
res_json = cl.redis_cli.send_cmd('predict',
|
|
369
|
+
[vision_engine, model_param_b64,
|
|
370
|
+
img_npy_b64, str(img_npy.shape[0]), str(img_npy.shape[1]), str(img_npy.shape[2] if len(img_npy.shape) > 2 else '-1'),
|
|
371
|
+
img_input_file_b64, str(nodraw),],
|
|
372
|
+
retry_count=retry_count, retry_interval=retry_interval, timeout=timeout)
|
|
373
|
+
|
|
374
|
+
soutputtime = time.perf_counter()
|
|
375
|
+
if "output_image" in res_json and "output_image_shape" in res_json:
|
|
376
|
+
img_npy = convert.b64str2npy(res_json["output_image"], res_json["output_image_shape"])
|
|
377
|
+
if img_output_file is not None:
|
|
378
|
+
exp = Path(img_output_file).suffix
|
|
379
|
+
exp = exp[1:] if exp[0] == '.' else exp
|
|
380
|
+
convert.npy2imgfile(img_npy, output_image_file=img_output_file, image_type=exp)
|
|
381
|
+
eoutputtime = time.perf_counter()
|
|
382
|
+
epredtime = time.perf_counter()
|
|
383
|
+
if "success" in res_json:
|
|
384
|
+
if "performance" not in res_json["success"]:
|
|
385
|
+
res_json["success"]["performance"] = []
|
|
386
|
+
performance = res_json["success"]["performance"]
|
|
387
|
+
performance.append(dict(key="cl_imgload", val=f"{eimgloadtime-simgloadtime:.3f}s"))
|
|
388
|
+
performance.append(dict(key="cl_output", val=f"{eoutputtime-soutputtime:.3f}s"))
|
|
389
|
+
performance.append(dict(key="cl_pred", val=f"{epredtime-spredtime:.3f}s"))
|
|
390
|
+
return res_json
|
|
391
|
+
|
|
392
|
+
def is_cluster_redirect(self):
|
|
393
|
+
"""
|
|
394
|
+
クラスター宛のメッセージの場合、メッセージを転送するかどうかを返します
|
|
395
|
+
|
|
396
|
+
Returns:
|
|
397
|
+
bool: メッセージを転送する場合はTrue
|
|
398
|
+
"""
|
|
399
|
+
return False
|
|
400
|
+
|
|
401
|
+
def svrun(self, data_dir:Path, logger:logging.Logger, redis_cli:redis_client.RedisClient, msg:List[str],
|
|
402
|
+
sessions:Dict[str, Dict[str, Any]]) -> int:
|
|
403
|
+
"""
|
|
404
|
+
この機能のサーバー側の実行を行います
|
|
405
|
+
|
|
406
|
+
Args:
|
|
407
|
+
data_dir (Path): データディレクトリ
|
|
408
|
+
logger (logging.Logger): ロガー
|
|
409
|
+
redis_cli (redis_client.RedisClient): Redisクライアント
|
|
410
|
+
msg (List[str]): 受信メッセージ
|
|
411
|
+
sessions (Dict[str, Dict[str, Any]]): セッション情報
|
|
412
|
+
|
|
413
|
+
Returns:
|
|
414
|
+
int: 終了コード
|
|
415
|
+
"""
|
|
416
|
+
if logger.level == logging.DEBUG:
|
|
417
|
+
logger.debug(f"audit write svrun msg: {msg}")
|
|
418
|
+
reskey = msg[1]
|
|
419
|
+
vision_engine = convert.b64str2str(msg[2])
|
|
420
|
+
model_param = json.loads(convert.b64str2str(msg[3]))
|
|
421
|
+
shape = [int(msg[5]), int(msg[6])]
|
|
422
|
+
if int(msg[7]) > 0: shape.append(int(msg[7]))
|
|
423
|
+
img_npy = convert.b64str2npy(msg[4], shape=shape)
|
|
424
|
+
img_input_file = convert.b64str2str(msg[8])
|
|
425
|
+
nodraw = convert.b64str2str(msg[9]) == 'True'
|
|
426
|
+
|
|
427
|
+
if vision_engine == 'sam2':
|
|
428
|
+
sam2_model = model_param['sam2_model']
|
|
429
|
+
sam2_point = model_param['sam2_point']
|
|
430
|
+
sam2_label = model_param['sam2_label']
|
|
431
|
+
st = self.sam2_predict(reskey, sam2_model, img_npy, sam2_point, sam2_label, data_dir, logger, redis_cli, sessions)
|
|
432
|
+
raise NotImplementedError("SAM2 model is not implemented yet.")
|
|
433
|
+
else:
|
|
434
|
+
logger.warning(f"Unsupported vision engine: {vision_engine}")
|
|
435
|
+
redis_cli.rpush(reskey, dict(warn=f"Unsupported vision engine: {vision_engine}"))
|
|
436
|
+
return self.RESP_WARN
|
|
437
|
+
|
|
438
|
+
def sam2_predict(self, reskey:str, sam2_model:str, img_npy:np.ndarray, sam2_point:List[List[int]], sam2_label:List[int],
|
|
439
|
+
data_dir:Path, logger:logging.Logger, redis_cli:redis_client.RedisClient, sessions:Dict[str, Dict[str, Any]]) -> Tuple[int, Dict[str, Any]]:
|
|
440
|
+
"""
|
|
441
|
+
SAM2のモデルを使用して指定したポイントのマスクを取得します
|
|
442
|
+
|
|
443
|
+
Args:
|
|
444
|
+
reskey (str): レスポンスキー
|
|
445
|
+
vision_engine (str): Visionエンジン
|
|
446
|
+
sam2_model (str): SAM2モデル
|
|
447
|
+
img_npy (np.ndarray): 入力画像
|
|
448
|
+
sam2_point (List[List[int,int]]): SAM2モデルのポイント
|
|
449
|
+
sam2_label (List[int]): SAM2モデルのラベル
|
|
450
|
+
data_dir (Path): データディレクトリ
|
|
451
|
+
logger (logging.Logger): ロガー
|
|
452
|
+
redis_cli (redis_client.RedisClient): Redisクライアント
|
|
453
|
+
sessions (Dict[str, Dict[str, Any]]): セッション情報
|
|
454
|
+
|
|
455
|
+
Returns:
|
|
456
|
+
Tuple[int, Dict[str, Any]]
|
|
457
|
+
"""
|
|
458
|
+
if 'vision' not in sessions or 'sam2' not in sessions['vision'] or sam2_model not in sessions['vision']['sam2'] or sessions['vision']['sam2'][sam2_model] is None:
|
|
459
|
+
return self.RESP_WARN, dict(warn=f"The vision session has not started.Unsupported SAM2 model: {sam2_model}")
|
|
460
|
+
session = sessions['vision']['sam2'][sam2_model]
|
|
461
|
+
from sam2.sam2_image_predictor import SAM2ImagePredictor
|
|
462
|
+
info = session.get('info', None)
|
|
463
|
+
predictor:SAM2ImagePredictor = session.get('predictor', None)
|
|
464
|
+
if info is None or predictor is None:
|
|
465
|
+
return self.RESP_WARN, dict(warn=f"The vision session has not started.Unsupported SAM2 model: {sam2_model}")
|
|
466
|
+
predictor.set_image(img_npy)
|
|
467
|
+
input_point = np.array(sam2_point, dtype=np.float32)
|
|
468
|
+
input_label = np.array(sam2_label, dtype=np.int32)
|
|
469
|
+
masks, scores, logits = predictor.predict(
|
|
470
|
+
point_coords=input_point,
|
|
471
|
+
point_labels=input_label,
|
|
472
|
+
multimask_output=True,
|
|
473
|
+
)
|
|
474
|
+
raise NotImplementedError("SAM2 model is not implemented yet.")
|
|
475
|
+
|
|
476
|
+
def draw_mask(img_npy:np.ndarray, mask_npy:np.ndarray):
|
|
477
|
+
"""
|
|
478
|
+
マスクを描画する関数
|
|
479
|
+
|
|
480
|
+
"""
|
|
481
|
+
from PIL import Image, ImageDraw
|
|
482
|
+
img = convert.npy2img(img_npy)
|
|
483
|
+
img = img.convert("RGBA")
|
|
484
|
+
draw = ImageDraw.Draw(img)
|
|
485
|
+
#h, w = img.size
|
|
486
|
+
#mask_npy = mask_npy.reshape(h, w, 1) * color.reshape(1, 1, -1)
|
|
487
|
+
mask_pil = Image.fromarray((mask_npy * 255).astype(np.uint8)).convert("L")
|
|
488
|
+
mask_img = Image.new("RGBA", img.size, (0, 0, 0, 0))
|
|
489
|
+
mask_color = np.array([*cmap(cmap_idx)[:3], 0.6])
|
|
490
|
+
|
|
491
|
+
for x in range(mask_pil.width):
|
|
492
|
+
for y in range(mask_pil.height):
|
|
493
|
+
if mask_pil.getpixel((x, y)) > 0:
|
|
494
|
+
mask_img.putpixel((x, y), (mask_color[0], mask_color[1], mask_color[2], int(255 * mask_color[3])))
|
|
495
|
+
img_comb = Image.alpha_composite(img, mask_img)
|
|
496
|
+
return img_comb
|