lemonade-sdk 8.1.12__py3-none-any.whl → 8.2.0__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 lemonade-sdk might be problematic. Click here for more details.
- lemonade/common/system_info.py +0 -26
- lemonade/tools/flm/utils.py +70 -22
- lemonade/tools/llamacpp/load.py +10 -1
- lemonade/tools/llamacpp/utils.py +82 -8
- lemonade/tools/oga/load.py +38 -142
- lemonade/tools/oga/migration.py +403 -0
- lemonade/tools/server/llamacpp.py +20 -1
- lemonade/tools/server/serve.py +334 -16
- lemonade/tools/server/static/js/models.js +416 -18
- lemonade/tools/server/static/js/shared.js +41 -4
- lemonade/tools/server/static/styles.css +204 -0
- lemonade/tools/server/static/webapp.html +32 -0
- lemonade/version.py +1 -1
- lemonade_install/install.py +33 -579
- {lemonade_sdk-8.1.12.dist-info → lemonade_sdk-8.2.0.dist-info}/METADATA +4 -3
- {lemonade_sdk-8.1.12.dist-info → lemonade_sdk-8.2.0.dist-info}/RECORD +24 -23
- lemonade_server/cli.py +10 -0
- lemonade_server/model_manager.py +172 -11
- lemonade_server/server_models.json +94 -71
- {lemonade_sdk-8.1.12.dist-info → lemonade_sdk-8.2.0.dist-info}/WHEEL +0 -0
- {lemonade_sdk-8.1.12.dist-info → lemonade_sdk-8.2.0.dist-info}/entry_points.txt +0 -0
- {lemonade_sdk-8.1.12.dist-info → lemonade_sdk-8.2.0.dist-info}/licenses/LICENSE +0 -0
- {lemonade_sdk-8.1.12.dist-info → lemonade_sdk-8.2.0.dist-info}/licenses/NOTICE.md +0 -0
- {lemonade_sdk-8.1.12.dist-info → lemonade_sdk-8.2.0.dist-info}/top_level.txt +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: lemonade-sdk
|
|
3
|
-
Version: 8.
|
|
3
|
+
Version: 8.2.0
|
|
4
4
|
Summary: Lemonade SDK: Your LLM Aide for Validation and Deployment
|
|
5
5
|
Author-email: lemonade@amd.com
|
|
6
6
|
Requires-Python: >=3.10, <3.14
|
|
@@ -29,12 +29,13 @@ Requires-Dist: tabulate
|
|
|
29
29
|
Requires-Dist: sentencepiece
|
|
30
30
|
Requires-Dist: huggingface-hub[hf_xet]==0.33.0
|
|
31
31
|
Requires-Dist: python-dotenv
|
|
32
|
+
Requires-Dist: python-multipart
|
|
32
33
|
Requires-Dist: rumps>=0.4.0; sys_platform == "darwin"
|
|
33
34
|
Provides-Extra: oga-ryzenai
|
|
34
|
-
Requires-Dist: onnxruntime-genai-directml-ryzenai==0.
|
|
35
|
+
Requires-Dist: onnxruntime-genai-directml-ryzenai==0.9.2; extra == "oga-ryzenai"
|
|
35
36
|
Requires-Dist: protobuf>=6.30.1; extra == "oga-ryzenai"
|
|
36
37
|
Provides-Extra: oga-cpu
|
|
37
|
-
Requires-Dist: onnxruntime-genai==0.
|
|
38
|
+
Requires-Dist: onnxruntime-genai==0.9.2; extra == "oga-cpu"
|
|
38
39
|
Requires-Dist: onnxruntime>=1.22.0; extra == "oga-cpu"
|
|
39
40
|
Provides-Extra: dev
|
|
40
41
|
Requires-Dist: torch>=2.6.0; extra == "dev"
|
|
@@ -4,7 +4,7 @@ lemonade/cache.py,sha256=fUjtHYkRdHTULjNMrDNOFDGW_QMVUg54ZE1NukBP2oM,3314
|
|
|
4
4
|
lemonade/cli.py,sha256=qU5bW7RQAUKNSpvrhVyzn68NMxyi-336Ke_JU4bsv1Q,5708
|
|
5
5
|
lemonade/sequence.py,sha256=KSH7BPsiyDKsOsg_ziQKEGsDwMmuO_YbgPRBxkZd0pw,13267
|
|
6
6
|
lemonade/state.py,sha256=sdSezla7Cd7KYL90xY3p9kcNV4ndSyN6UvNLOr3vBMA,5261
|
|
7
|
-
lemonade/version.py,sha256=
|
|
7
|
+
lemonade/version.py,sha256=Xb24P8T6pG5QQaEw-UTO0iybyDoxvRGJaUR_qFoVAJQ,22
|
|
8
8
|
lemonade/common/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
9
9
|
lemonade/common/build.py,sha256=zTb0m1-kuUx6zw5QHp2SNnVuN6jOTMQ2FCdj9iH374U,6140
|
|
10
10
|
lemonade/common/cli_helpers.py,sha256=hjBfXrTtFl8gmCFlL-ksviXR0mOcdPtTWVNKoEp3PG4,4993
|
|
@@ -14,7 +14,7 @@ lemonade/common/inference_engines.py,sha256=3bUGQe9wtfTiwt8kvI_ry077uyc9lid2G1fJ
|
|
|
14
14
|
lemonade/common/network.py,sha256=qXpUjDYQEYM_gH3JwTtU-pu_yCKcaa1IeohJRPy91-A,2903
|
|
15
15
|
lemonade/common/printing.py,sha256=GFFzrXIineIOMa9yu0lo5sL4j6A5BBg_T9aUCdP-juw,3229
|
|
16
16
|
lemonade/common/status.py,sha256=dxAahChPGVmfT91DJW949Xjgm9r5E-Y9KOLPEw7BMh8,16562
|
|
17
|
-
lemonade/common/system_info.py,sha256=
|
|
17
|
+
lemonade/common/system_info.py,sha256=PWpEtOz6CqvnUYL8_3lX61_GNbrbp0O2x4ZIwRh6RJg,48780
|
|
18
18
|
lemonade/common/test_helpers.py,sha256=Gwk-pa_6xYAo2oro-2EJNfuouAfw8k_brCbcMC-E-r0,758
|
|
19
19
|
lemonade/profilers/__init__.py,sha256=JKVonvJ4XZ9_6sKXPWsiMLQCNyzQOxhQw5BEHR1qOfU,31
|
|
20
20
|
lemonade/profilers/agt_power.py,sha256=t_37VEg8LPapjSKSjJln-jFznZtTIf5UpzlAXcVGOrc,16771
|
|
@@ -32,51 +32,52 @@ lemonade/tools/perplexity.py,sha256=eiaTZ3yhqF2pfwOffVbKKJLwjSri7Im2pC-tBJr7LLU,
|
|
|
32
32
|
lemonade/tools/prompt.py,sha256=PyLksp1k8jsZsU7XBRK61k1DUHhbdLa20h-AP8Noh3w,9011
|
|
33
33
|
lemonade/tools/tool.py,sha256=UsxVYukfm_iM3BfeGYPZxQlTK5UfDfDOl3RIyLr8A1Y,13256
|
|
34
34
|
lemonade/tools/flm/__init__.py,sha256=NQ4CEzJZGS_VvxPMlfrK4Dcx48bQSoUR4iG8e7yZjas,46
|
|
35
|
-
lemonade/tools/flm/utils.py,sha256=
|
|
35
|
+
lemonade/tools/flm/utils.py,sha256=5KS0IND_8E3lgKNdIFeJqMcdiCsPpYCjgL1FzH8YvGk,9933
|
|
36
36
|
lemonade/tools/huggingface/bench.py,sha256=-mTfldCtquL4mspq8ykVwDc9Mut5Ecv_jHJnSb0CYGE,6734
|
|
37
37
|
lemonade/tools/huggingface/load.py,sha256=KsSGOBBD-tNEIfYC8mCWV_jpnkjHMhN3juVmC1Ln4uQ,7745
|
|
38
38
|
lemonade/tools/huggingface/utils.py,sha256=j1S-IgjDsznUIVwkHSqqChmFyqIx9f3WcEelzohWwvU,13955
|
|
39
39
|
lemonade/tools/llamacpp/bench.py,sha256=ubifZAdZatubfwuxgIY5IBzjW29lP-RwKaxhIZsXubQ,8533
|
|
40
|
-
lemonade/tools/llamacpp/load.py,sha256=
|
|
41
|
-
lemonade/tools/llamacpp/utils.py,sha256=
|
|
40
|
+
lemonade/tools/llamacpp/load.py,sha256=YvDHqXe4tKGuT5aG_wP4xH3Px0RmG92u73kVOTHSEgc,7671
|
|
41
|
+
lemonade/tools/llamacpp/utils.py,sha256=s3j2EPFRPGXeuoX6Hls-fdtk8BSFPhX8icIcexfsG2A,43520
|
|
42
42
|
lemonade/tools/oga/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
43
43
|
lemonade/tools/oga/bench.py,sha256=g8l_ssvi_FC5Xf9tIe-c0XpcPR9TIVALh0eza5scMjI,4156
|
|
44
|
-
lemonade/tools/oga/load.py,sha256=
|
|
44
|
+
lemonade/tools/oga/load.py,sha256=ci34gyx8RT5xMJj_p-rt1FBe_PqQFxyh-Pwyt6BTIaw,29750
|
|
45
|
+
lemonade/tools/oga/migration.py,sha256=zo34chEbtkWk4GaDwgW326o09eF2wAsoOiTzqQ6DMLU,13505
|
|
45
46
|
lemonade/tools/oga/utils.py,sha256=F8UVLKlfYcLa2SUqlehar8-jaX2Aw4u58DjHNNvLdOA,17675
|
|
46
47
|
lemonade/tools/report/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
47
48
|
lemonade/tools/report/llm_report.py,sha256=bVHhwCINA-Ok2EdSwAsLubsc83N3KWOVuwTguw7jDcE,6676
|
|
48
49
|
lemonade/tools/report/table.py,sha256=_AzknkTXI9xTPem-3N16FPRhkKnLvhhsfnm_P3GN2sw,28241
|
|
49
50
|
lemonade/tools/server/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
50
51
|
lemonade/tools/server/flm.py,sha256=NVpjFzcmX6YzW6wCWyMEvQEe_QpRK-Jlcaajxy3kWuo,4025
|
|
51
|
-
lemonade/tools/server/llamacpp.py,sha256=
|
|
52
|
-
lemonade/tools/server/serve.py,sha256=
|
|
52
|
+
lemonade/tools/server/llamacpp.py,sha256=V_2fZAUIQmwoiHvm8fQ3U6gc67lYCAXTYPkfLqz6n88,10678
|
|
53
|
+
lemonade/tools/server/serve.py,sha256=aqg8seEDqWF01JhBU5S1YQOa76xCqCBCGjl8u-ZTZx4,82554
|
|
53
54
|
lemonade/tools/server/tool_calls.py,sha256=xrAlQwKG-nv2xLlf8f9CDSaUbyMn8ZtHkds9iZLG9K8,5230
|
|
54
55
|
lemonade/tools/server/tray.py,sha256=EFnSc2Ra4owiHVz6ykoMhxi2fYqZAK1g21AynAYBiyk,24426
|
|
55
56
|
lemonade/tools/server/webapp.py,sha256=GGSVIzN19C2ZaadOEPBg_D7Lt0PuF339NuWwjMPfZu8,1225
|
|
56
57
|
lemonade/tools/server/wrapped_server.py,sha256=uh7ifrRX1Hx0IuRwZRCGPyQOukitE7kKQipCCz0bSGA,19844
|
|
57
58
|
lemonade/tools/server/static/favicon.ico,sha256=hMmP9qGJNeZ0mFS86JIqPbZstXMZn0Z76_HfHQpREAU,126745
|
|
58
59
|
lemonade/tools/server/static/logs.html,sha256=5TCpjL9XanRH5uiTEB0bJVuM-fhU8OaQrDrkZENkOMc,1543
|
|
59
|
-
lemonade/tools/server/static/styles.css,sha256=
|
|
60
|
-
lemonade/tools/server/static/webapp.html,sha256=
|
|
60
|
+
lemonade/tools/server/static/styles.css,sha256=XOi3-Aw_W0WOBEGBnyYZcniwjeHx7dhRBU2Lt4ePN00,52815
|
|
61
|
+
lemonade/tools/server/static/webapp.html,sha256=dwCa6TYhXjtDAvKYedwKzlp-MoQ-tpt-rEvOKLNI0L0,21096
|
|
61
62
|
lemonade/tools/server/static/js/chat.js,sha256=jxyMyu4MfvI2YmsMbJQ8ZwDNBnLzu2nbjm-qLfgWSNI,42182
|
|
62
63
|
lemonade/tools/server/static/js/model-settings.js,sha256=JXHeG7xVrRU181Hj7CZflERAi1Z6t-qwYFR4aH5nf5I,5820
|
|
63
|
-
lemonade/tools/server/static/js/models.js,sha256=
|
|
64
|
-
lemonade/tools/server/static/js/shared.js,sha256=
|
|
64
|
+
lemonade/tools/server/static/js/models.js,sha256=nV5yHtWrwKG5ai3pxJT3nFMZ4sd6pEFf2C99x1lFyPM,52929
|
|
65
|
+
lemonade/tools/server/static/js/shared.js,sha256=igYBZVDgFVN09sXTOt15IX57uwd3yi6Epr3DXgNf29A,18813
|
|
65
66
|
lemonade/tools/server/utils/macos_tray.py,sha256=xwHW44ZN5hDVlJcwIpHHfqn4VRXWxXHuDACaT-ZqdO8,7095
|
|
66
67
|
lemonade/tools/server/utils/port.py,sha256=J7-g-Aqygb50jNoHLhhRfBZVM-uhGlcB5-oYBAehvgw,2263
|
|
67
68
|
lemonade/tools/server/utils/thread.py,sha256=Z-PDzGcpgfN2qxTmtlROWqrUN0B2fXdPrqo_J10fR_w,2772
|
|
68
69
|
lemonade/tools/server/utils/windows_tray.py,sha256=2z5aTmUPlkT-QfkcfwHsyA6dv6nSNBT0gXUErarhac8,13170
|
|
69
70
|
lemonade_install/__init__.py,sha256=26zohKg2jgr_5y7tObduWMYQg8zCTWMZHL8lfi2zZVQ,40
|
|
70
|
-
lemonade_install/install.py,sha256=
|
|
71
|
-
lemonade_sdk-8.
|
|
72
|
-
lemonade_sdk-8.
|
|
73
|
-
lemonade_server/cli.py,sha256=
|
|
74
|
-
lemonade_server/model_manager.py,sha256=
|
|
71
|
+
lemonade_install/install.py,sha256=BWVmDROK38cEBFMxSUeON2SPJUtI9rOLSrlgJJSO3mQ,7743
|
|
72
|
+
lemonade_sdk-8.2.0.dist-info/licenses/LICENSE,sha256=xx0jnfkXJvxRnG63LTGOxlggYnIysveWIZ6H3PNdCrQ,11357
|
|
73
|
+
lemonade_sdk-8.2.0.dist-info/licenses/NOTICE.md,sha256=RSca9LE5e6pvdWA_LXAUCcACIHPmINKqkRX-AVRqBGo,3499
|
|
74
|
+
lemonade_server/cli.py,sha256=BItlVpuykHwTnCZJs-7v1qWRPBCnEx-aeP43a7S9uFk,23918
|
|
75
|
+
lemonade_server/model_manager.py,sha256=dboE-7wF1Y9iLGUcBkaA-lpF8XJKSIN_y0mUYzgCm2w,32657
|
|
75
76
|
lemonade_server/pydantic_models.py,sha256=5U3PZ__UqcWQh-dNXVBc-vyJc6-In2vngZXP9VmiScM,3954
|
|
76
|
-
lemonade_server/server_models.json,sha256=
|
|
77
|
+
lemonade_server/server_models.json,sha256=cZAxlDkxQ5neb57jQ8j2fvIeuAfyk4Ga1Yele58OeTY,15062
|
|
77
78
|
lemonade_server/settings.py,sha256=JOlZmirUXO9rA6BCODVFwyXrrHtYoH_LiKYm49lGm_c,1260
|
|
78
|
-
lemonade_sdk-8.
|
|
79
|
-
lemonade_sdk-8.
|
|
80
|
-
lemonade_sdk-8.
|
|
81
|
-
lemonade_sdk-8.
|
|
82
|
-
lemonade_sdk-8.
|
|
79
|
+
lemonade_sdk-8.2.0.dist-info/METADATA,sha256=t2w9eoQ_esL16qO_3oODsJSIkTEPTzUlgBaTGXmR2OE,15417
|
|
80
|
+
lemonade_sdk-8.2.0.dist-info/WHEEL,sha256=_zCd3N1l69ArxyTb8rzEoP9TpbYXkqRFSNOD5OuxnTs,91
|
|
81
|
+
lemonade_sdk-8.2.0.dist-info/entry_points.txt,sha256=7sRvpNhi1E7amnM7RZo57e8yFF9iA5uuRaIeJ1Xre6w,193
|
|
82
|
+
lemonade_sdk-8.2.0.dist-info/top_level.txt,sha256=10ap5GNiPhalO4V50LRoxA1FqRT9g3Xkia6BITu880k,42
|
|
83
|
+
lemonade_sdk-8.2.0.dist-info/RECORD,,
|
lemonade_server/cli.py
CHANGED
|
@@ -326,6 +326,16 @@ def run(
|
|
|
326
326
|
ctx_size=ctx_size,
|
|
327
327
|
)
|
|
328
328
|
else:
|
|
329
|
+
# macOS: Check for port conflicts when server is already running
|
|
330
|
+
if platform.system() == "Darwin":
|
|
331
|
+
requested_port = port if port is not None else DEFAULT_PORT
|
|
332
|
+
if running_port != requested_port:
|
|
333
|
+
print(
|
|
334
|
+
f"Lemonade Server is already running on port {running_port}\n"
|
|
335
|
+
f"You requested port {requested_port}. Please stop the existing server first "
|
|
336
|
+
)
|
|
337
|
+
sys.exit(ExitCodes.SERVER_ALREADY_RUNNING)
|
|
338
|
+
|
|
329
339
|
port = running_port
|
|
330
340
|
|
|
331
341
|
# Pull model
|
lemonade_server/model_manager.py
CHANGED
|
@@ -8,8 +8,16 @@ from importlib.metadata import distributions
|
|
|
8
8
|
from lemonade_server.pydantic_models import PullConfig
|
|
9
9
|
from lemonade_server.pydantic_models import PullConfig
|
|
10
10
|
from lemonade.cache import DEFAULT_CACHE_DIR
|
|
11
|
-
from lemonade.tools.llamacpp.utils import
|
|
11
|
+
from lemonade.tools.llamacpp.utils import (
|
|
12
|
+
parse_checkpoint,
|
|
13
|
+
download_gguf,
|
|
14
|
+
resolve_local_gguf_model,
|
|
15
|
+
)
|
|
12
16
|
from lemonade.common.network import custom_snapshot_download
|
|
17
|
+
from lemonade.tools.oga.migration import (
|
|
18
|
+
detect_incompatible_ryzenai_models,
|
|
19
|
+
delete_incompatible_models,
|
|
20
|
+
)
|
|
13
21
|
|
|
14
22
|
USER_MODELS_FILE = os.path.join(DEFAULT_CACHE_DIR, "user_models.json")
|
|
15
23
|
|
|
@@ -61,10 +69,17 @@ class ModelManager:
|
|
|
61
69
|
|
|
62
70
|
# Add the model name as a key in each entry, to make it easier
|
|
63
71
|
# to access later
|
|
64
|
-
|
|
72
|
+
# Also convert labels to boolean fields for LoadConfig compatibility
|
|
65
73
|
for key, value in models.items():
|
|
66
74
|
value["model_name"] = key
|
|
67
75
|
|
|
76
|
+
# Convert labels to boolean fields for backwards compatibility with LoadConfig
|
|
77
|
+
labels = value.get("labels", [])
|
|
78
|
+
if "reasoning" in labels and "reasoning" not in value:
|
|
79
|
+
value["reasoning"] = True
|
|
80
|
+
if "vision" in labels and "vision" not in value:
|
|
81
|
+
value["vision"] = True
|
|
82
|
+
|
|
68
83
|
return models
|
|
69
84
|
|
|
70
85
|
@property
|
|
@@ -88,6 +103,8 @@ class ModelManager:
|
|
|
88
103
|
Returns a dictionary of locally available models.
|
|
89
104
|
For GGUF models with variants, checks if the specific variant files exist.
|
|
90
105
|
"""
|
|
106
|
+
from huggingface_hub.constants import HF_HUB_CACHE
|
|
107
|
+
|
|
91
108
|
downloaded_models = {}
|
|
92
109
|
downloaded_checkpoints = self.downloaded_hf_checkpoints
|
|
93
110
|
|
|
@@ -106,6 +123,19 @@ class ModelManager:
|
|
|
106
123
|
checkpoint = model_info["checkpoint"]
|
|
107
124
|
base_checkpoint, variant = parse_checkpoint(checkpoint)
|
|
108
125
|
|
|
126
|
+
# Special handling for locally uploaded user models (not internet-downloaded)
|
|
127
|
+
if (
|
|
128
|
+
model.startswith("user.")
|
|
129
|
+
and model_info.get("source") == "local_upload"
|
|
130
|
+
):
|
|
131
|
+
# Locally uploaded model: checkpoint is in cache directory format (models--xxx)
|
|
132
|
+
local_model_path = os.path.join(HF_HUB_CACHE, base_checkpoint)
|
|
133
|
+
if os.path.exists(local_model_path):
|
|
134
|
+
downloaded_models[model] = model_info
|
|
135
|
+
continue
|
|
136
|
+
|
|
137
|
+
# For all other models (server models and internet-downloaded user models),
|
|
138
|
+
# use the standard verification logic with variant checks
|
|
109
139
|
if base_checkpoint in downloaded_checkpoints:
|
|
110
140
|
# For GGUF models with variants, verify the specific variant files exist
|
|
111
141
|
if variant and model_info.get("recipe") == "llamacpp":
|
|
@@ -147,6 +177,55 @@ class ModelManager:
|
|
|
147
177
|
downloaded_models[model] = model_info
|
|
148
178
|
return downloaded_models
|
|
149
179
|
|
|
180
|
+
def register_local_model(
|
|
181
|
+
self,
|
|
182
|
+
model_name: str,
|
|
183
|
+
checkpoint: str,
|
|
184
|
+
recipe: str,
|
|
185
|
+
reasoning: bool = False,
|
|
186
|
+
vision: bool = False,
|
|
187
|
+
mmproj: str = "",
|
|
188
|
+
snapshot_path: str = "",
|
|
189
|
+
):
|
|
190
|
+
|
|
191
|
+
model_name_clean = model_name[5:]
|
|
192
|
+
|
|
193
|
+
# Prepare model info
|
|
194
|
+
labels = ["custom"]
|
|
195
|
+
if reasoning:
|
|
196
|
+
labels.append("reasoning")
|
|
197
|
+
if vision:
|
|
198
|
+
labels.append("vision")
|
|
199
|
+
|
|
200
|
+
new_user_model = {
|
|
201
|
+
"checkpoint": checkpoint,
|
|
202
|
+
"recipe": recipe,
|
|
203
|
+
"suggested": True,
|
|
204
|
+
"labels": labels,
|
|
205
|
+
"source": "local_upload",
|
|
206
|
+
}
|
|
207
|
+
if mmproj:
|
|
208
|
+
new_user_model["mmproj"] = mmproj
|
|
209
|
+
|
|
210
|
+
# Load existing user models
|
|
211
|
+
user_models = {}
|
|
212
|
+
if os.path.exists(USER_MODELS_FILE):
|
|
213
|
+
with open(USER_MODELS_FILE, "r", encoding="utf-8") as file:
|
|
214
|
+
user_models = json.load(file)
|
|
215
|
+
|
|
216
|
+
# Check for conflicts
|
|
217
|
+
if model_name_clean in user_models:
|
|
218
|
+
raise ValueError(
|
|
219
|
+
f"{model_name_clean} is already registered."
|
|
220
|
+
f"Please use a different model name or delete the existing model."
|
|
221
|
+
)
|
|
222
|
+
|
|
223
|
+
# Save to user_models.json
|
|
224
|
+
user_models[model_name_clean] = new_user_model
|
|
225
|
+
os.makedirs(os.path.dirname(USER_MODELS_FILE), exist_ok=True)
|
|
226
|
+
with open(USER_MODELS_FILE, "w", encoding="utf-8") as file:
|
|
227
|
+
json.dump(user_models, file)
|
|
228
|
+
|
|
150
229
|
@property
|
|
151
230
|
def downloaded_models_enabled(self) -> dict:
|
|
152
231
|
"""
|
|
@@ -310,7 +389,7 @@ class ModelManager:
|
|
|
310
389
|
# Check if FLM is available, and install it if not
|
|
311
390
|
if not is_flm_available():
|
|
312
391
|
print(
|
|
313
|
-
"FLM is not installed or not at the
|
|
392
|
+
"FLM is not installed or not at the latest version. Installing FLM..."
|
|
314
393
|
)
|
|
315
394
|
install_flm()
|
|
316
395
|
|
|
@@ -328,11 +407,23 @@ class ModelManager:
|
|
|
328
407
|
f"Please manually install FLM using 'lemonade-install --flm'."
|
|
329
408
|
) from e
|
|
330
409
|
elif "gguf" in checkpoint_to_download.lower():
|
|
331
|
-
|
|
332
|
-
|
|
333
|
-
gguf_model_config.
|
|
334
|
-
|
|
410
|
+
# Parse checkpoint to check local cache first
|
|
411
|
+
base_checkpoint, variant = parse_checkpoint(
|
|
412
|
+
gguf_model_config.checkpoint
|
|
413
|
+
)
|
|
414
|
+
local_result = resolve_local_gguf_model(
|
|
415
|
+
base_checkpoint, variant, gguf_model_config.mmproj
|
|
335
416
|
)
|
|
417
|
+
|
|
418
|
+
# Only download if not found locally
|
|
419
|
+
if not local_result:
|
|
420
|
+
download_gguf(
|
|
421
|
+
gguf_model_config.checkpoint,
|
|
422
|
+
gguf_model_config.mmproj,
|
|
423
|
+
do_not_upgrade=do_not_upgrade,
|
|
424
|
+
)
|
|
425
|
+
else:
|
|
426
|
+
print(f"Model already exists locally, skipping download")
|
|
336
427
|
else:
|
|
337
428
|
custom_snapshot_download(
|
|
338
429
|
checkpoint_to_download, do_not_upgrade=do_not_upgrade
|
|
@@ -342,6 +433,11 @@ class ModelManager:
|
|
|
342
433
|
# We do this registration after the download so that we don't register
|
|
343
434
|
# any incorrectly configured models where the download would fail
|
|
344
435
|
if new_registration_model_config:
|
|
436
|
+
# For models downloaded from the internet (HuggingFace),
|
|
437
|
+
# keep the original checkpoint format (e.g., "amd/Llama-3.2-1B-Instruct-...")
|
|
438
|
+
# Do NOT convert to cache directory format - that's only for locally uploaded models
|
|
439
|
+
new_user_model["checkpoint"] = checkpoint
|
|
440
|
+
|
|
345
441
|
if os.path.exists(USER_MODELS_FILE):
|
|
346
442
|
with open(USER_MODELS_FILE, "r", encoding="utf-8") as file:
|
|
347
443
|
user_models: dict = json.load(file)
|
|
@@ -365,7 +461,7 @@ class ModelManager:
|
|
|
365
461
|
|
|
366
462
|
installed_packages = {dist.metadata["Name"].lower() for dist in distributions()}
|
|
367
463
|
|
|
368
|
-
|
|
464
|
+
ryzenai_installed = (
|
|
369
465
|
"onnxruntime-vitisai" in installed_packages
|
|
370
466
|
and "onnxruntime-genai-directml-ryzenai" in installed_packages
|
|
371
467
|
)
|
|
@@ -422,9 +518,9 @@ class ModelManager:
|
|
|
422
518
|
for model, value in models.items():
|
|
423
519
|
recipe = value.get("recipe")
|
|
424
520
|
|
|
425
|
-
# Filter
|
|
426
|
-
if recipe == "oga-hybrid":
|
|
427
|
-
if not
|
|
521
|
+
# Filter Ryzen AI models based on package availability
|
|
522
|
+
if recipe == "oga-hybrid" or recipe == "oga-npu":
|
|
523
|
+
if not ryzenai_installed:
|
|
428
524
|
continue
|
|
429
525
|
|
|
430
526
|
if recipe == "flm":
|
|
@@ -444,6 +540,8 @@ class ModelManager:
|
|
|
444
540
|
Deletes the specified model from local storage.
|
|
445
541
|
For GGUF models with variants, only deletes the specific variant files.
|
|
446
542
|
"""
|
|
543
|
+
from huggingface_hub.constants import HF_HUB_CACHE
|
|
544
|
+
|
|
447
545
|
if model_name not in self.supported_models:
|
|
448
546
|
raise ValueError(
|
|
449
547
|
f"Model {model_name} is not supported. Please choose from the following: "
|
|
@@ -464,6 +562,37 @@ class ModelManager:
|
|
|
464
562
|
except subprocess.CalledProcessError as e:
|
|
465
563
|
raise ValueError(f"Failed to delete FLM model {model_name}: {e}") from e
|
|
466
564
|
|
|
565
|
+
if checkpoint.startswith("models--"):
|
|
566
|
+
# This is already in cache directory format (local model)
|
|
567
|
+
# Extract just the base directory name (models--{name}) from checkpoint
|
|
568
|
+
# which might contain full file path like models--name\files\model.gguf
|
|
569
|
+
checkpoint_parts = checkpoint.replace("\\", "/").split("/")
|
|
570
|
+
base_checkpoint = checkpoint_parts[0] # Just the models--{name} part
|
|
571
|
+
model_cache_dir = os.path.join(HF_HUB_CACHE, base_checkpoint)
|
|
572
|
+
|
|
573
|
+
if os.path.exists(model_cache_dir):
|
|
574
|
+
shutil.rmtree(model_cache_dir)
|
|
575
|
+
print(
|
|
576
|
+
f"Successfully deleted local model {model_name} from {model_cache_dir}"
|
|
577
|
+
)
|
|
578
|
+
else:
|
|
579
|
+
print(
|
|
580
|
+
f"Model {model_name} directory not found at {model_cache_dir} - may have been manually deleted"
|
|
581
|
+
)
|
|
582
|
+
|
|
583
|
+
# Clean up user models registry
|
|
584
|
+
if model_name.startswith("user.") and os.path.exists(USER_MODELS_FILE):
|
|
585
|
+
with open(USER_MODELS_FILE, "r", encoding="utf-8") as file:
|
|
586
|
+
user_models = json.load(file)
|
|
587
|
+
|
|
588
|
+
base_model_name = model_name[5:] # Remove "user." prefix
|
|
589
|
+
if base_model_name in user_models:
|
|
590
|
+
del user_models[base_model_name]
|
|
591
|
+
with open(USER_MODELS_FILE, "w", encoding="utf-8") as file:
|
|
592
|
+
json.dump(user_models, file)
|
|
593
|
+
print(f"Removed {model_name} from user models registry")
|
|
594
|
+
|
|
595
|
+
return
|
|
467
596
|
# Parse checkpoint to get base and variant
|
|
468
597
|
base_checkpoint, variant = parse_checkpoint(checkpoint)
|
|
469
598
|
|
|
@@ -592,6 +721,38 @@ class ModelManager:
|
|
|
592
721
|
json.dump(user_models, file)
|
|
593
722
|
print(f"Removed {model_name} from user models registry")
|
|
594
723
|
|
|
724
|
+
def get_incompatible_ryzenai_models(self):
|
|
725
|
+
"""
|
|
726
|
+
Get information about incompatible RyzenAI models in the cache.
|
|
727
|
+
|
|
728
|
+
Returns:
|
|
729
|
+
dict with 'models' list and 'total_size' info
|
|
730
|
+
"""
|
|
731
|
+
# Get HF_HOME from environment
|
|
732
|
+
hf_home = os.environ.get("HF_HOME", None)
|
|
733
|
+
|
|
734
|
+
incompatible_models, total_size = detect_incompatible_ryzenai_models(
|
|
735
|
+
DEFAULT_CACHE_DIR, hf_home
|
|
736
|
+
)
|
|
737
|
+
|
|
738
|
+
return {
|
|
739
|
+
"models": incompatible_models,
|
|
740
|
+
"total_size": total_size,
|
|
741
|
+
"count": len(incompatible_models),
|
|
742
|
+
}
|
|
743
|
+
|
|
744
|
+
def cleanup_incompatible_models(self, model_paths: list):
|
|
745
|
+
"""
|
|
746
|
+
Delete incompatible RyzenAI models from the cache.
|
|
747
|
+
|
|
748
|
+
Args:
|
|
749
|
+
model_paths: List of model paths to delete
|
|
750
|
+
|
|
751
|
+
Returns:
|
|
752
|
+
dict with deletion results
|
|
753
|
+
"""
|
|
754
|
+
return delete_incompatible_models(model_paths)
|
|
755
|
+
|
|
595
756
|
|
|
596
757
|
# This file was originally licensed under Apache 2.0. It has been modified.
|
|
597
758
|
# Modifications Copyright (c) 2025 AMD
|