sima-cli 0.0.12__tar.gz → 0.0.14__tar.gz
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.
- {sima_cli-0.0.12 → sima_cli-0.0.14}/MANIFEST.in +2 -1
- {sima_cli-0.0.12/sima_cli.egg-info → sima_cli-0.0.14}/PKG-INFO +4 -2
- {sima_cli-0.0.12 → sima_cli-0.0.14}/pyproject.toml +5 -3
- {sima_cli-0.0.12 → sima_cli-0.0.14}/requirements.txt +3 -1
- {sima_cli-0.0.12 → sima_cli-0.0.14}/setup.cfg +2 -1
- {sima_cli-0.0.12 → sima_cli-0.0.14}/setup.py +4 -1
- {sima_cli-0.0.12 → sima_cli-0.0.14}/sima_cli/__version__.py +1 -1
- {sima_cli-0.0.12 → sima_cli-0.0.14}/sima_cli/auth/login.py +2 -2
- {sima_cli-0.0.12 → sima_cli-0.0.14}/sima_cli/cli.py +49 -15
- sima_cli-0.0.14/sima_cli/data/resources_internal.yaml +9 -0
- sima_cli-0.0.14/sima_cli/mla/meminfo.py +47 -0
- {sima_cli-0.0.12 → sima_cli-0.0.14}/sima_cli/model_zoo/model.py +117 -2
- {sima_cli-0.0.12 → sima_cli-0.0.14}/sima_cli/update/local.py +2 -2
- {sima_cli-0.0.12 → sima_cli-0.0.14}/sima_cli/update/remote.py +2 -1
- {sima_cli-0.0.12 → sima_cli-0.0.14}/sima_cli/update/updater.py +32 -27
- {sima_cli-0.0.12 → sima_cli-0.0.14}/sima_cli/utils/artifactory.py +1 -0
- sima_cli-0.0.14/sima_cli/utils/config_loader.py +65 -0
- {sima_cli-0.0.12 → sima_cli-0.0.14}/sima_cli/utils/env.py +3 -2
- {sima_cli-0.0.12 → sima_cli-0.0.14/sima_cli.egg-info}/PKG-INFO +4 -2
- {sima_cli-0.0.12 → sima_cli-0.0.14}/sima_cli.egg-info/SOURCES.txt +3 -0
- {sima_cli-0.0.12 → sima_cli-0.0.14}/sima_cli.egg-info/requires.txt +2 -0
- sima_cli-0.0.14/tests/test_utils.py +0 -0
- sima_cli-0.0.12/sima_cli/utils/config_loader.py +0 -30
- {sima_cli-0.0.12 → sima_cli-0.0.14}/LICENSE +0 -0
- {sima_cli-0.0.12 → sima_cli-0.0.14}/README.md +0 -0
- {sima_cli-0.0.12 → sima_cli-0.0.14}/sima_cli/__init__.py +0 -0
- {sima_cli-0.0.12 → sima_cli-0.0.14}/sima_cli/__main__.py +0 -0
- {sima_cli-0.0.12 → sima_cli-0.0.14}/sima_cli/app_zoo/__init__.py +0 -0
- {sima_cli-0.0.12 → sima_cli-0.0.14}/sima_cli/app_zoo/app.py +0 -0
- {sima_cli-0.0.12 → sima_cli-0.0.14}/sima_cli/auth/__init__.py +0 -0
- /sima_cli-0.0.12/sima_cli/model_zoo/__init__.py → /sima_cli-0.0.14/sima_cli/data/resources_public.yaml +0 -0
- {sima_cli-0.0.12 → sima_cli-0.0.14}/sima_cli/download/__init__.py +0 -0
- {sima_cli-0.0.12 → sima_cli-0.0.14}/sima_cli/download/downloader.py +0 -0
- {sima_cli-0.0.12/sima_cli/utils → sima_cli-0.0.14/sima_cli/model_zoo}/__init__.py +0 -0
- {sima_cli-0.0.12 → sima_cli-0.0.14}/sima_cli/update/__init__.py +0 -0
- {sima_cli-0.0.12/tests → sima_cli-0.0.14/sima_cli/utils}/__init__.py +0 -0
- {sima_cli-0.0.12 → sima_cli-0.0.14}/sima_cli/utils/config.py +0 -0
- {sima_cli-0.0.12 → sima_cli-0.0.14}/sima_cli/utils/network.py +0 -0
- {sima_cli-0.0.12 → sima_cli-0.0.14}/sima_cli.egg-info/dependency_links.txt +0 -0
- {sima_cli-0.0.12 → sima_cli-0.0.14}/sima_cli.egg-info/entry_points.txt +0 -0
- {sima_cli-0.0.12 → sima_cli-0.0.14}/sima_cli.egg-info/top_level.txt +0 -0
- /sima_cli-0.0.12/tests/test_app_zoo.py → /sima_cli-0.0.14/tests/__init__.py +0 -0
- /sima_cli-0.0.12/tests/test_auth.py → /sima_cli-0.0.14/tests/test_app_zoo.py +0 -0
- /sima_cli-0.0.12/tests/test_cli.py → /sima_cli-0.0.14/tests/test_auth.py +0 -0
- /sima_cli-0.0.12/tests/test_firmware.py → /sima_cli-0.0.14/tests/test_cli.py +0 -0
- {sima_cli-0.0.12 → sima_cli-0.0.14}/tests/test_download.py +0 -0
- /sima_cli-0.0.12/tests/test_model_zoo.py → /sima_cli-0.0.14/tests/test_firmware.py +0 -0
- /sima_cli-0.0.12/tests/test_utils.py → /sima_cli-0.0.14/tests/test_model_zoo.py +0 -0
@@ -1,6 +1,6 @@
|
|
1
1
|
Metadata-Version: 2.4
|
2
2
|
Name: sima-cli
|
3
|
-
Version: 0.0.
|
3
|
+
Version: 0.0.14
|
4
4
|
Summary: CLI tool for SiMa Developer Portal to download models, firmware, and apps.
|
5
5
|
Home-page: https://developer.sima.ai/
|
6
6
|
Author: SiMa.ai
|
@@ -13,7 +13,7 @@ Classifier: Development Status :: 3 - Alpha
|
|
13
13
|
Classifier: Intended Audience :: Developers
|
14
14
|
Classifier: Topic :: Software Development :: Build Tools
|
15
15
|
Classifier: Environment :: Console
|
16
|
-
Requires-Python: >=3.
|
16
|
+
Requires-Python: >=3.8
|
17
17
|
Description-Content-Type: text/markdown
|
18
18
|
License-File: LICENSE
|
19
19
|
Requires-Dist: requests
|
@@ -21,6 +21,8 @@ Requires-Dist: click
|
|
21
21
|
Requires-Dist: tqdm
|
22
22
|
Requires-Dist: pyyaml
|
23
23
|
Requires-Dist: paramiko
|
24
|
+
Requires-Dist: plotext
|
25
|
+
Requires-Dist: rich
|
24
26
|
Dynamic: author
|
25
27
|
Dynamic: license-file
|
26
28
|
Dynamic: requires-python
|
@@ -4,10 +4,10 @@ build-backend = "setuptools.build_meta"
|
|
4
4
|
|
5
5
|
[project]
|
6
6
|
name = "sima-cli"
|
7
|
-
version = "0.0.
|
7
|
+
version = "0.0.14"
|
8
8
|
description = "CLI tool for SiMa Developer Portal to download models, firmware, and apps."
|
9
9
|
readme = "README.md"
|
10
|
-
requires-python = ">=3.
|
10
|
+
requires-python = ">=3.8"
|
11
11
|
license = "MIT"
|
12
12
|
authors = [
|
13
13
|
{ name="Sima.ai", email="support@sima.ai" }
|
@@ -26,7 +26,9 @@ dependencies = [
|
|
26
26
|
"click",
|
27
27
|
"tqdm",
|
28
28
|
"pyyaml",
|
29
|
-
"paramiko"
|
29
|
+
"paramiko",
|
30
|
+
"plotext",
|
31
|
+
"rich"
|
30
32
|
]
|
31
33
|
|
32
34
|
[project.urls]
|
@@ -13,6 +13,9 @@ setup(
|
|
13
13
|
author="SiMa.ai",
|
14
14
|
packages=find_packages(),
|
15
15
|
include_package_data=True,
|
16
|
+
package_data={
|
17
|
+
"sima_cli": ["data/*.yaml"],
|
18
|
+
},
|
16
19
|
install_requires=[
|
17
20
|
"click>=8.0",
|
18
21
|
"requests>=2.25",
|
@@ -23,5 +26,5 @@ setup(
|
|
23
26
|
"sima-cli=sima_cli.__main__:main"
|
24
27
|
]
|
25
28
|
},
|
26
|
-
python_requires=">=3.
|
29
|
+
python_requires=">=3.8",
|
27
30
|
)
|
@@ -1,2 +1,2 @@
|
|
1
1
|
# sima_cli/__version__.py
|
2
|
-
__version__ = "0.0.
|
2
|
+
__version__ = "0.0.14"
|
@@ -2,7 +2,7 @@ import click
|
|
2
2
|
import getpass
|
3
3
|
import requests
|
4
4
|
from sima_cli.utils.config import set_auth_token, get_auth_token
|
5
|
-
from sima_cli.utils.config_loader import load_resource_config
|
5
|
+
from sima_cli.utils.config_loader import load_resource_config, artifactory_url
|
6
6
|
from sima_cli.utils.artifactory import exchange_identity_token, validate_token
|
7
7
|
|
8
8
|
def login(method: str = "external"):
|
@@ -30,7 +30,7 @@ def login_internal():
|
|
30
30
|
|
31
31
|
cfg = load_resource_config()
|
32
32
|
auth_cfg = cfg.get("internal", {}).get("auth", {})
|
33
|
-
base_url =
|
33
|
+
base_url = artifactory_url()
|
34
34
|
validate_url = auth_cfg.get("validate_url")
|
35
35
|
internal_url = auth_cfg.get("internal_url")
|
36
36
|
validate_url = f"{base_url}/{validate_url}"
|
@@ -2,7 +2,9 @@ import os
|
|
2
2
|
import click
|
3
3
|
from sima_cli.utils.env import get_environment_type
|
4
4
|
from sima_cli.update.updater import perform_update
|
5
|
-
from sima_cli.model_zoo.model import list_models, download_model
|
5
|
+
from sima_cli.model_zoo.model import list_models, download_model, describe_model
|
6
|
+
from sima_cli.utils.config_loader import internal_resource_exists
|
7
|
+
from sima_cli.mla.meminfo import monitor_simaai_mem_chart
|
6
8
|
|
7
9
|
# Entry point for the CLI tool using Click's command group decorator
|
8
10
|
@click.group()
|
@@ -21,9 +23,13 @@ def main(ctx, internal):
|
|
21
23
|
if not internal:
|
22
24
|
internal = os.getenv("SIMA_CLI_INTERNAL", "0") in ("1", "true", "yes")
|
23
25
|
|
26
|
+
if internal and not internal_resource_exists():
|
27
|
+
click.echo("❌ You have specified -i or --internal argument to access internal resources, but you do not have an internal resource map configured.")
|
28
|
+
click.echo("Refer to the confluence page to find out how to configure internal resource map.")
|
29
|
+
exit(0)
|
30
|
+
|
24
31
|
ctx.obj["internal"] = internal
|
25
32
|
|
26
|
-
from sima_cli.utils.env import get_environment_type
|
27
33
|
env_type, env_subtype = get_environment_type()
|
28
34
|
|
29
35
|
if internal:
|
@@ -31,10 +37,6 @@ def main(ctx, internal):
|
|
31
37
|
else:
|
32
38
|
click.echo(f"🔧 Environment: {env_type} ({env_subtype})")
|
33
39
|
|
34
|
-
if not internal:
|
35
|
-
click.echo(f"external environment is not supported yet..")
|
36
|
-
exit(0)
|
37
|
-
|
38
40
|
# ----------------------
|
39
41
|
# Authentication Command
|
40
42
|
# ----------------------
|
@@ -86,20 +88,14 @@ def download(ctx, url, dest):
|
|
86
88
|
@main.command(name="update")
|
87
89
|
@click.argument('version_or_url')
|
88
90
|
@click.option('--ip', help="Target device IP address for remote firmware update.")
|
89
|
-
|
90
|
-
'--board',
|
91
|
-
default='davinci',
|
92
|
-
type=click.Choice(['davinci', 'modalix'], case_sensitive=False),
|
93
|
-
show_default=True,
|
94
|
-
help="Target board type (davinci or modalix)."
|
95
|
-
)
|
91
|
+
|
96
92
|
@click.option(
|
97
93
|
'--passwd',
|
98
94
|
default='edgeai',
|
99
95
|
help="Optional SSH password for remote board (default is 'edgeai')."
|
100
96
|
)
|
101
97
|
@click.pass_context
|
102
|
-
def update(ctx, version_or_url, ip,
|
98
|
+
def update(ctx, version_or_url, ip, passwd):
|
103
99
|
"""
|
104
100
|
Run system update across different environments.
|
105
101
|
Downloads and applies firmware updates for PCIe host or SiMa board.
|
@@ -107,7 +103,11 @@ def update(ctx, version_or_url, ip, board, passwd):
|
|
107
103
|
version_or_url: The version string (e.g. '1.5.0') or a direct URL to the firmware package.
|
108
104
|
"""
|
109
105
|
internal = ctx.obj.get("internal", False)
|
110
|
-
|
106
|
+
if not internal:
|
107
|
+
click.echo(f"external environment is not supported yet..")
|
108
|
+
exit(0)
|
109
|
+
|
110
|
+
perform_update(version_or_url, ip, internal, passwd=passwd)
|
111
111
|
|
112
112
|
# ----------------------
|
113
113
|
# Model Zoo Subcommands
|
@@ -119,6 +119,11 @@ def modelzoo(ctx, ver):
|
|
119
119
|
"""Access models from the Model Zoo."""
|
120
120
|
ctx.ensure_object(dict)
|
121
121
|
ctx.obj['ver'] = ver
|
122
|
+
internal = ctx.obj.get("internal", False)
|
123
|
+
if not internal:
|
124
|
+
click.echo(f"external environment is not supported yet..")
|
125
|
+
exit(0)
|
126
|
+
|
122
127
|
pass
|
123
128
|
|
124
129
|
@modelzoo.command("list")
|
@@ -140,6 +145,35 @@ def get_model(ctx, model_name):
|
|
140
145
|
click.echo(f"Getting model '{model_name}' for version: {ver}")
|
141
146
|
download_model(internal, ver, model_name)
|
142
147
|
|
148
|
+
@modelzoo.command("describe")
|
149
|
+
@click.argument('model_name')
|
150
|
+
@click.pass_context
|
151
|
+
def get_model(ctx, model_name):
|
152
|
+
"""Download a specific model."""
|
153
|
+
ver = ctx.obj.get("ver")
|
154
|
+
internal = ctx.obj.get("internal", False)
|
155
|
+
click.echo(f"Getting model '{model_name}' for version: {ver}")
|
156
|
+
describe_model(internal, ver, model_name)
|
157
|
+
|
158
|
+
# ----------------------
|
159
|
+
# Authentication Command
|
160
|
+
# ----------------------
|
161
|
+
@main.group()
|
162
|
+
@click.pass_context
|
163
|
+
def mla(ctx):
|
164
|
+
"""Machine Learning Accelerator Utilities."""
|
165
|
+
env_type, _ = get_environment_type()
|
166
|
+
if env_type != 'board':
|
167
|
+
click.echo("❌ This command can only be executed on the SiMa board.")
|
168
|
+
pass
|
169
|
+
|
170
|
+
@mla.command("meminfo")
|
171
|
+
@click.pass_context
|
172
|
+
def show_mla_memory_usage(ctx):
|
173
|
+
"""Show MLA Memory usage overtime."""
|
174
|
+
monitor_simaai_mem_chart()
|
175
|
+
pass
|
176
|
+
|
143
177
|
# ----------------------
|
144
178
|
# App Zoo Subcommands
|
145
179
|
# ----------------------
|
@@ -0,0 +1,47 @@
|
|
1
|
+
import time
|
2
|
+
import re
|
3
|
+
import sys
|
4
|
+
import select
|
5
|
+
import subprocess
|
6
|
+
import plotext as plt
|
7
|
+
|
8
|
+
def monitor_simaai_mem_chart(sample_interval_sec=5, max_samples=100):
|
9
|
+
sizes = []
|
10
|
+
|
11
|
+
def read_allocated_size():
|
12
|
+
try:
|
13
|
+
output = subprocess.check_output(['sudo', 'cat', '/dev/simaai-mem'], text=True)
|
14
|
+
match = re.search(r"Total allocated size:\s+0x([0-9a-fA-F]+)", output)
|
15
|
+
if match:
|
16
|
+
size_bytes = int(match.group(1), 16)
|
17
|
+
return size_bytes / (1024 * 1024)
|
18
|
+
except Exception as e:
|
19
|
+
print(f"Error reading /dev/simaai-mem: {e}")
|
20
|
+
return None
|
21
|
+
|
22
|
+
print("📈 Monitoring MLA memory usage... (Press 'Ctrl+C' to quit)")
|
23
|
+
|
24
|
+
while True:
|
25
|
+
# Check for quit key
|
26
|
+
if sys.stdin in select.select([sys.stdin], [], [], 0)[0]:
|
27
|
+
key = sys.stdin.read(1)
|
28
|
+
if key.lower() == 'q':
|
29
|
+
print("\n❌ Exiting memory monitor...")
|
30
|
+
break
|
31
|
+
|
32
|
+
size_mb = read_allocated_size()
|
33
|
+
if size_mb is not None:
|
34
|
+
sizes.append(size_mb)
|
35
|
+
sizes = sizes[-max_samples:]
|
36
|
+
|
37
|
+
if sizes:
|
38
|
+
plt.clear_data()
|
39
|
+
plt.clc()
|
40
|
+
plt.title("SIMA MLA Memory Usage (MB)")
|
41
|
+
plt.xlabel("Seconds")
|
42
|
+
plt.ylabel("Memory (MB)")
|
43
|
+
plt.plot(sizes)
|
44
|
+
plt.ylim(min(sizes) * 0.95, max(sizes) * 1.05)
|
45
|
+
plt.show()
|
46
|
+
|
47
|
+
time.sleep(sample_interval_sec)
|
@@ -3,12 +3,16 @@
|
|
3
3
|
import requests
|
4
4
|
import click
|
5
5
|
import os
|
6
|
+
import yaml
|
6
7
|
from urllib.parse import urlparse
|
7
|
-
|
8
|
+
from rich import print
|
9
|
+
from rich.table import Table
|
10
|
+
from rich.panel import Panel
|
8
11
|
from sima_cli.utils.config import get_auth_token
|
12
|
+
from sima_cli.utils.config_loader import artifactory_url
|
9
13
|
from sima_cli.download import download_file_from_url
|
10
14
|
|
11
|
-
ARTIFACTORY_BASE_URL =
|
15
|
+
ARTIFACTORY_BASE_URL = artifactory_url() + '/artifactory'
|
12
16
|
|
13
17
|
def _is_valid_url(url: str) -> bool:
|
14
18
|
try:
|
@@ -17,6 +21,109 @@ def _is_valid_url(url: str) -> bool:
|
|
17
21
|
except:
|
18
22
|
return False
|
19
23
|
|
24
|
+
def _describe_model_internal(ver: str, model_name: str):
|
25
|
+
repo = "sima-qa-releases"
|
26
|
+
base_path = f"SiMaCLI-SDK-Releases/{ver}-Release/modelzoo_edgematic/{model_name}"
|
27
|
+
aql_query = f"""
|
28
|
+
items.find({{
|
29
|
+
"repo": "{repo}",
|
30
|
+
"path": "{base_path}",
|
31
|
+
"$or": [
|
32
|
+
{{ "name": {{ "$match": "*.yaml" }} }},
|
33
|
+
{{ "name": {{ "$match": "*.yml" }} }}
|
34
|
+
],
|
35
|
+
"type": "file"
|
36
|
+
}}).include("name", "path", "repo")
|
37
|
+
""".strip()
|
38
|
+
|
39
|
+
headers = {
|
40
|
+
"Content-Type": "text/plain",
|
41
|
+
"Authorization": f"Bearer {get_auth_token(internal=True)}"
|
42
|
+
}
|
43
|
+
|
44
|
+
aql_url = f"{ARTIFACTORY_BASE_URL}/api/search/aql"
|
45
|
+
response = requests.post(aql_url, data=aql_query, headers=headers)
|
46
|
+
if response.status_code != 200:
|
47
|
+
click.echo(f"❌ Failed to list model files. Status: {response.status_code}")
|
48
|
+
click.echo(response.text)
|
49
|
+
return
|
50
|
+
|
51
|
+
files = response.json().get("results", [])
|
52
|
+
yaml_file = next((f for f in files if f["name"].endswith((".yaml", ".yml"))), None)
|
53
|
+
|
54
|
+
if not yaml_file:
|
55
|
+
click.echo(f"⚠️ No .yaml or .yml file found under: {base_path}")
|
56
|
+
return
|
57
|
+
|
58
|
+
# Download the YAML file
|
59
|
+
yaml_url = f"{ARTIFACTORY_BASE_URL}/{repo}/{yaml_file['path']}/{yaml_file['name']}"
|
60
|
+
response = requests.get(yaml_url, headers={"Authorization": f"Bearer {get_auth_token(internal=True)}"})
|
61
|
+
|
62
|
+
if response.status_code != 200:
|
63
|
+
click.echo(f"❌ Failed to fetch YAML: {response.status_code}")
|
64
|
+
return
|
65
|
+
|
66
|
+
try:
|
67
|
+
data = yaml.safe_load(response.text)
|
68
|
+
except yaml.YAMLError as e:
|
69
|
+
click.echo(f"❌ Failed to parse YAML: {e}")
|
70
|
+
return
|
71
|
+
|
72
|
+
model = data.get("model", {})
|
73
|
+
pipeline = data.get("pipeline", {})
|
74
|
+
|
75
|
+
print(Panel.fit(f"[bold green]{model.get('name', 'Unknown')}[/bold green] - {model.get('task', 'Unknown Task')}",
|
76
|
+
subtitle=f"Status: [yellow]{model.get('status', 'n/a')}[/yellow]"))
|
77
|
+
|
78
|
+
desc_table = Table(title="Description", show_header=False)
|
79
|
+
for k, v in (model.get("description") or {}).items():
|
80
|
+
desc_table.add_row(k.capitalize(), v or "-")
|
81
|
+
print(desc_table)
|
82
|
+
|
83
|
+
dataset = model.get("dataset", {})
|
84
|
+
dataset_table = Table(title="Dataset", header_style="bold magenta")
|
85
|
+
dataset_table.add_column("Key")
|
86
|
+
dataset_table.add_column("Value")
|
87
|
+
dataset_table.add_row("Name", dataset.get("name", "-"))
|
88
|
+
for k, v in (dataset.get("params") or {}).items():
|
89
|
+
dataset_table.add_row(k, str(v))
|
90
|
+
dataset_table.add_row("Accuracy", dataset.get("accuracy", "-"))
|
91
|
+
dataset_table.add_row("Calibration", dataset.get("calibration", "-"))
|
92
|
+
print(dataset_table)
|
93
|
+
|
94
|
+
if qm := model.get("quality_metric"):
|
95
|
+
print(Panel.fit(f"Quality Metric: [cyan]{qm.get('name')}[/cyan]"))
|
96
|
+
|
97
|
+
q = model.get("quantization_settings", {})
|
98
|
+
q_table = Table(title="Quantization Settings", header_style="bold blue")
|
99
|
+
q_table.add_column("Setting")
|
100
|
+
q_table.add_column("Value")
|
101
|
+
|
102
|
+
q_table.add_row("Calibration Samples", str(q.get("calibration_num_samples", "-")))
|
103
|
+
q_table.add_row("Calibration Method", q.get("calibration_method", "-"))
|
104
|
+
q_table.add_row("Requantization Mode", q.get("requantization_mode", "-"))
|
105
|
+
q_table.add_row("Bias Correction", str(q.get("bias_correction", "-")))
|
106
|
+
|
107
|
+
aq = q.get("activation_quantization_scheme", {})
|
108
|
+
wq = q.get("weight_quantization_scheme", {})
|
109
|
+
|
110
|
+
q_table.add_row("Activation Quant", f"Asym: {aq.get('asymmetric')}, PerCh: {aq.get('per_channel')}, Bits: {aq.get('bits')}")
|
111
|
+
q_table.add_row("Weight Quant", f"Asym: {wq.get('asymmetric')}, PerCh: {wq.get('per_channel')}, Bits: {wq.get('bits')}")
|
112
|
+
print(q_table)
|
113
|
+
|
114
|
+
transforms = pipeline.get("transforms", [])
|
115
|
+
t_table = Table(title="Pipeline Transforms", header_style="bold green")
|
116
|
+
t_table.add_column("Name")
|
117
|
+
t_table.add_column("Params")
|
118
|
+
|
119
|
+
for step in transforms:
|
120
|
+
name = step.get("name")
|
121
|
+
params = step.get("params", {})
|
122
|
+
param_str = ", ".join(f"{k}={v}" for k, v in params.items()) if params else "-"
|
123
|
+
t_table.add_row(name, param_str)
|
124
|
+
|
125
|
+
print(t_table)
|
126
|
+
|
20
127
|
def _download_model_internal(ver: str, model_name: str):
|
21
128
|
repo = "sima-qa-releases"
|
22
129
|
base_path = f"SiMaCLI-SDK-Releases/{ver}-Release/modelzoo_edgematic/{model_name}"
|
@@ -92,6 +199,7 @@ def _list_available_models_internal(version: str):
|
|
92
199
|
""".strip()
|
93
200
|
|
94
201
|
aql_url = f"{ARTIFACTORY_BASE_URL}/api/search/aql"
|
202
|
+
print(aql_url)
|
95
203
|
headers = {
|
96
204
|
"Content-Type": "text/plain",
|
97
205
|
"Authorization": f"Bearer {get_auth_token(internal=True)}"
|
@@ -138,6 +246,13 @@ def download_model(internal, ver, model_name):
|
|
138
246
|
else:
|
139
247
|
print('External model zoo not supported yet')
|
140
248
|
|
249
|
+
def describe_model(internal, ver, model_name):
|
250
|
+
if internal:
|
251
|
+
click.echo("Model Zoo Source : SiMa Artifactory...")
|
252
|
+
return _describe_model_internal(ver, model_name)
|
253
|
+
else:
|
254
|
+
print('External model zoo not supported yet')
|
255
|
+
|
141
256
|
# Module CLI tests
|
142
257
|
if __name__ == "__main__":
|
143
258
|
import sys
|
@@ -1,7 +1,7 @@
|
|
1
1
|
import os
|
2
2
|
import subprocess
|
3
3
|
import tempfile
|
4
|
-
from typing import List
|
4
|
+
from typing import List, Tuple
|
5
5
|
import pty
|
6
6
|
import click
|
7
7
|
|
@@ -44,7 +44,7 @@ def _run_local_cmd(command: str, passwd: str) -> bool:
|
|
44
44
|
return False
|
45
45
|
|
46
46
|
|
47
|
-
def get_local_board_info() ->
|
47
|
+
def get_local_board_info() -> Tuple[str, str]:
|
48
48
|
"""
|
49
49
|
Retrieve the local board type and build version by reading /etc/build.
|
50
50
|
|
@@ -7,6 +7,7 @@ import itertools
|
|
7
7
|
import threading
|
8
8
|
import sys
|
9
9
|
import select
|
10
|
+
from typing import Tuple
|
10
11
|
|
11
12
|
DEFAULT_USER = "sima"
|
12
13
|
DEFAULT_PASSWORD = "edgeai"
|
@@ -50,7 +51,7 @@ def _wait_for_ssh(ip: str, timeout: int = 120):
|
|
50
51
|
else:
|
51
52
|
print("\r✅ Board is online! \n")
|
52
53
|
|
53
|
-
def get_remote_board_info(ip: str, passwd: str = DEFAULT_PASSWORD) ->
|
54
|
+
def get_remote_board_info(ip: str, passwd: str = DEFAULT_PASSWORD) -> Tuple[str, str]:
|
54
55
|
"""
|
55
56
|
Connect to the remote board and retrieve board type and build version.
|
56
57
|
|
@@ -289,7 +289,7 @@ def _update_remote(extracted_paths: List[str], ip: str, board: str, passwd: str,
|
|
289
289
|
return script_path
|
290
290
|
|
291
291
|
|
292
|
-
def perform_update(version_or_url: str, ip: str = None,
|
292
|
+
def perform_update(version_or_url: str, ip: str = None, internal: bool = False, passwd: str = "edgeai"):
|
293
293
|
r"""
|
294
294
|
Update the system based on environment and input.
|
295
295
|
|
@@ -304,36 +304,41 @@ def perform_update(version_or_url: str, ip: str = None, board: str = "davinci",
|
|
304
304
|
board (str): Board type, must be 'davinci' or 'modalix'.
|
305
305
|
passwd : non-default password in case user has changed the password of the board user `sima`
|
306
306
|
"""
|
307
|
-
board = board.lower()
|
308
|
-
if board not in ("davinci", "modalix"):
|
309
|
-
click.echo(f"❌ Invalid board type '{board}'. Must be 'davinci' or 'modalix'.")
|
310
|
-
return
|
311
|
-
|
312
307
|
try:
|
308
|
+
board = ''
|
313
309
|
env_type, env_subtype = get_environment_type()
|
314
310
|
click.echo(f"🔄 Running update for environment: {env_type} ({env_subtype})")
|
315
311
|
click.echo(f"🔧 Requested version or URL: {version_or_url}")
|
316
|
-
|
317
|
-
|
318
|
-
|
319
|
-
|
320
|
-
|
321
|
-
|
322
|
-
|
323
|
-
|
324
|
-
|
325
|
-
|
326
|
-
|
327
|
-
|
328
|
-
|
329
|
-
|
330
|
-
|
331
|
-
|
332
|
-
|
333
|
-
|
334
|
-
|
335
|
-
|
336
|
-
|
312
|
+
|
313
|
+
if env_type == 'board':
|
314
|
+
board, version = get_local_board_info()
|
315
|
+
else:
|
316
|
+
board, version = get_remote_board_info(ip, passwd)
|
317
|
+
|
318
|
+
if board in ['davinci', 'modalix']:
|
319
|
+
click.echo(f"🔧 Target board: {board}, board currently running: {version}")
|
320
|
+
extracted_paths = _download_image(version_or_url, board, internal)
|
321
|
+
click.echo("⚠️ DO NOT INTERRUPT THE UPDATE PROCESS...")
|
322
|
+
|
323
|
+
if len(extracted_paths) > 0:
|
324
|
+
if env_type == "host" and env_subtype == 'linux':
|
325
|
+
# Always update the remote device first then update the host driver, otherwise the host would
|
326
|
+
# not be able to connect to the board
|
327
|
+
click.echo("👉 Updating PCIe host driver and downloading firmware...")
|
328
|
+
script_path = _update_remote(extracted_paths, ip, board, passwd, reboot_and_wait = False)
|
329
|
+
_update_host(script_path, board, ip, passwd)
|
330
|
+
elif env_type == "board":
|
331
|
+
_update_board(extracted_paths, board, passwd)
|
332
|
+
elif env_type == "sdk":
|
333
|
+
click.echo("👉 Updating firmware from within the Palette SDK...: Not implemented yet")
|
334
|
+
elif ip:
|
335
|
+
click.echo(f"👉 Updating firmware on remote board at {ip}...")
|
336
|
+
_update_remote(extracted_paths, ip, board, passwd, reboot_and_wait = True)
|
337
|
+
else:
|
338
|
+
click.echo("❌ Unknown environment. Use --ip to specify target device.")
|
339
|
+
else:
|
340
|
+
click.echo("❌ Unable to retrieve target board information")
|
341
|
+
|
337
342
|
except Exception as e:
|
338
343
|
click.echo(f"❌ Update failed {e}")
|
339
344
|
|
@@ -0,0 +1,65 @@
|
|
1
|
+
import os
|
2
|
+
import yaml
|
3
|
+
|
4
|
+
def load_resource_config():
|
5
|
+
"""
|
6
|
+
Load and separate public and internal resource configuration files.
|
7
|
+
|
8
|
+
Returns:
|
9
|
+
dict: Dictionary with keys 'public' and 'internal' for both configs.
|
10
|
+
"""
|
11
|
+
config = {
|
12
|
+
"public": {},
|
13
|
+
"internal": {}
|
14
|
+
}
|
15
|
+
|
16
|
+
public_path = os.path.abspath(
|
17
|
+
os.path.join(os.path.dirname(__file__), "..", "data", "resources_public.yaml")
|
18
|
+
)
|
19
|
+
if os.path.exists(public_path):
|
20
|
+
with open(public_path, "r") as f:
|
21
|
+
config["public"] = yaml.safe_load(f) or {}
|
22
|
+
|
23
|
+
internal_path = os.path.abspath(
|
24
|
+
os.path.join(os.path.dirname(__file__), "..", "data", "resources_internal.yaml")
|
25
|
+
)
|
26
|
+
if os.path.exists(internal_path):
|
27
|
+
with open(internal_path, "r") as f:
|
28
|
+
config["internal"] = yaml.safe_load(f) or {}
|
29
|
+
else:
|
30
|
+
print(f"Internal resource map not found... {internal_path}")
|
31
|
+
|
32
|
+
return config
|
33
|
+
|
34
|
+
def internal_resource_exists():
|
35
|
+
"""
|
36
|
+
Check if the internal resource YAML file exists.
|
37
|
+
|
38
|
+
Returns:
|
39
|
+
bool: True if the internal resource file exists, False otherwise.
|
40
|
+
"""
|
41
|
+
internal_path = os.path.abspath(
|
42
|
+
os.path.join(os.path.dirname(__file__), "..", "data", "resources_internal.yaml")
|
43
|
+
)
|
44
|
+
return os.path.exists(internal_path)
|
45
|
+
|
46
|
+
def artifactory_url():
|
47
|
+
"""
|
48
|
+
Retrieve the Artifactory base URL from the internal resource configuration.
|
49
|
+
|
50
|
+
Returns:
|
51
|
+
str or None: The Artifactory URL if found, otherwise None.
|
52
|
+
|
53
|
+
Notes:
|
54
|
+
- Expects 'load_resource_config()' to return a dictionary with an 'internal' section
|
55
|
+
containing an 'artifactory' section with a 'url' field.
|
56
|
+
- If any error occurs (e.g., missing fields, file issues), prints an error message
|
57
|
+
and returns None.
|
58
|
+
"""
|
59
|
+
try:
|
60
|
+
cfg = load_resource_config()
|
61
|
+
return cfg.get("internal", {}).get("artifactory", {}).get("url", {})
|
62
|
+
except Exception as e:
|
63
|
+
print('Unable to retrieve Artifactory URL')
|
64
|
+
return None
|
65
|
+
|
@@ -1,6 +1,7 @@
|
|
1
1
|
import os
|
2
2
|
import subprocess
|
3
3
|
import platform
|
4
|
+
from typing import Tuple
|
4
5
|
|
5
6
|
# Utility functions to determine the environment:
|
6
7
|
# - Whether we are running on a SiMa board
|
@@ -86,7 +87,7 @@ def is_palette_sdk() -> bool:
|
|
86
87
|
except Exception:
|
87
88
|
return False
|
88
89
|
|
89
|
-
def get_environment_type() ->
|
90
|
+
def get_environment_type() -> Tuple[str, str]:
|
90
91
|
"""
|
91
92
|
Return the environment type and subtype as a tuple.
|
92
93
|
|
@@ -113,7 +114,7 @@ def get_environment_type() -> tuple[str, str]:
|
|
113
114
|
|
114
115
|
return "host", "unknown"
|
115
116
|
|
116
|
-
def check_pcie_card_installation() ->
|
117
|
+
def check_pcie_card_installation() -> Tuple[bool, str]:
|
117
118
|
"""
|
118
119
|
Check whether the PCIe SiMa card is properly installed on a supported Linux host.
|
119
120
|
|
@@ -1,6 +1,6 @@
|
|
1
1
|
Metadata-Version: 2.4
|
2
2
|
Name: sima-cli
|
3
|
-
Version: 0.0.
|
3
|
+
Version: 0.0.14
|
4
4
|
Summary: CLI tool for SiMa Developer Portal to download models, firmware, and apps.
|
5
5
|
Home-page: https://developer.sima.ai/
|
6
6
|
Author: SiMa.ai
|
@@ -13,7 +13,7 @@ Classifier: Development Status :: 3 - Alpha
|
|
13
13
|
Classifier: Intended Audience :: Developers
|
14
14
|
Classifier: Topic :: Software Development :: Build Tools
|
15
15
|
Classifier: Environment :: Console
|
16
|
-
Requires-Python: >=3.
|
16
|
+
Requires-Python: >=3.8
|
17
17
|
Description-Content-Type: text/markdown
|
18
18
|
License-File: LICENSE
|
19
19
|
Requires-Dist: requests
|
@@ -21,6 +21,8 @@ Requires-Dist: click
|
|
21
21
|
Requires-Dist: tqdm
|
22
22
|
Requires-Dist: pyyaml
|
23
23
|
Requires-Dist: paramiko
|
24
|
+
Requires-Dist: plotext
|
25
|
+
Requires-Dist: rich
|
24
26
|
Dynamic: author
|
25
27
|
Dynamic: license-file
|
26
28
|
Dynamic: requires-python
|
@@ -19,8 +19,11 @@ sima_cli/app_zoo/__init__.py
|
|
19
19
|
sima_cli/app_zoo/app.py
|
20
20
|
sima_cli/auth/__init__.py
|
21
21
|
sima_cli/auth/login.py
|
22
|
+
sima_cli/data/resources_internal.yaml
|
23
|
+
sima_cli/data/resources_public.yaml
|
22
24
|
sima_cli/download/__init__.py
|
23
25
|
sima_cli/download/downloader.py
|
26
|
+
sima_cli/mla/meminfo.py
|
24
27
|
sima_cli/model_zoo/__init__.py
|
25
28
|
sima_cli/model_zoo/model.py
|
26
29
|
sima_cli/update/__init__.py
|
File without changes
|
@@ -1,30 +0,0 @@
|
|
1
|
-
import os
|
2
|
-
import yaml
|
3
|
-
|
4
|
-
def load_resource_config():
|
5
|
-
"""
|
6
|
-
Load and separate public and internal resource configuration files.
|
7
|
-
|
8
|
-
Returns:
|
9
|
-
dict: Dictionary with keys 'public' and 'internal' for both configs.
|
10
|
-
"""
|
11
|
-
config = {
|
12
|
-
"public": {},
|
13
|
-
"internal": {}
|
14
|
-
}
|
15
|
-
|
16
|
-
# Public config (bundled with the package)
|
17
|
-
public_path = os.path.abspath(
|
18
|
-
os.path.join(os.path.dirname(__file__), "..", "data", "resources_public.yaml")
|
19
|
-
)
|
20
|
-
if os.path.exists(public_path):
|
21
|
-
with open(public_path, "r") as f:
|
22
|
-
config["public"] = yaml.safe_load(f) or {}
|
23
|
-
|
24
|
-
# Internal config (~/.sima-cli/resources_internal.yaml)
|
25
|
-
internal_path = os.path.join(os.path.expanduser("~"), ".sima-cli", "resources_internal.yaml")
|
26
|
-
if os.path.exists(internal_path):
|
27
|
-
with open(internal_path, "r") as f:
|
28
|
-
config["internal"] = yaml.safe_load(f) or {}
|
29
|
-
|
30
|
-
return config
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|