claude-code-workflow 6.2.6 → 6.2.9
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.
- package/ccw/dist/cli.d.ts.map +1 -1
- package/ccw/dist/cli.js +18 -7
- package/ccw/dist/cli.js.map +1 -1
- package/ccw/dist/core/routes/system-routes.js +1 -1
- package/ccw/dist/core/routes/system-routes.js.map +1 -1
- package/ccw/src/cli.ts +256 -244
- package/ccw/src/core/routes/system-routes.ts +1 -1
- package/ccw/src/templates/dashboard-js/components/cli-status.js +35 -2
- package/ccw/src/templates/dashboard-js/views/cli-manager.js +45 -6
- package/codex-lens/src/codexlens/cli/__pycache__/commands.cpython-313.pyc +0 -0
- package/codex-lens/src/codexlens/cli/__pycache__/embedding_manager.cpython-313.pyc +0 -0
- package/codex-lens/src/codexlens/cli/__pycache__/model_manager.cpython-313.pyc +0 -0
- package/codex-lens/src/codexlens/cli/commands.py +41 -15
- package/codex-lens/src/codexlens/cli/embedding_manager.py +15 -0
- package/codex-lens/src/codexlens/cli/model_manager.py +337 -311
- package/codex-lens/src/codexlens/search/__pycache__/chain_search.cpython-313.pyc +0 -0
- package/codex-lens/src/codexlens/search/__pycache__/hybrid_search.cpython-313.pyc +0 -0
- package/codex-lens/src/codexlens/search/chain_search.py +14 -1
- package/codex-lens/src/codexlens/search/hybrid_search.py +25 -12
- package/codex-lens/src/codexlens/semantic/__pycache__/vector_store.cpython-313.pyc +0 -0
- package/codex-lens/src/codexlens/semantic/vector_store.py +97 -0
- package/codex-lens/src/codexlens/storage/__pycache__/path_mapper.cpython-313.pyc +0 -0
- package/codex-lens/src/codexlens/storage/path_mapper.py +27 -1
- package/package.json +13 -5
- package/ccw/package.json +0 -65
|
@@ -1,311 +1,337 @@
|
|
|
1
|
-
"""Model Manager - Manage fastembed models for semantic search."""
|
|
2
|
-
|
|
3
|
-
import json
|
|
4
|
-
import os
|
|
5
|
-
import shutil
|
|
6
|
-
from pathlib import Path
|
|
7
|
-
from typing import Dict, List, Optional
|
|
8
|
-
|
|
9
|
-
try:
|
|
10
|
-
from fastembed import TextEmbedding
|
|
11
|
-
FASTEMBED_AVAILABLE = True
|
|
12
|
-
except ImportError:
|
|
13
|
-
FASTEMBED_AVAILABLE = False
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
# Model profiles with metadata
|
|
17
|
-
# Note: 768d is max recommended dimension for optimal performance/quality balance
|
|
18
|
-
# 1024d models are available but not recommended due to higher resource usage
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
"
|
|
23
|
-
"
|
|
24
|
-
"
|
|
25
|
-
"
|
|
26
|
-
"
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
"
|
|
32
|
-
"
|
|
33
|
-
"
|
|
34
|
-
"
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
"
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
"
|
|
41
|
-
"
|
|
42
|
-
"
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
"
|
|
46
|
-
"
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
"
|
|
50
|
-
"
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
"
|
|
54
|
-
"
|
|
55
|
-
"
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
"
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
"
|
|
62
|
-
"
|
|
63
|
-
"
|
|
64
|
-
"
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
"
|
|
166
|
-
"
|
|
167
|
-
}
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
"
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
|
|
247
|
-
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
|
|
251
|
-
|
|
252
|
-
|
|
253
|
-
|
|
254
|
-
|
|
255
|
-
|
|
256
|
-
|
|
257
|
-
|
|
258
|
-
|
|
259
|
-
|
|
260
|
-
|
|
261
|
-
|
|
262
|
-
|
|
263
|
-
|
|
264
|
-
|
|
265
|
-
|
|
266
|
-
|
|
267
|
-
|
|
268
|
-
|
|
269
|
-
|
|
270
|
-
|
|
271
|
-
|
|
272
|
-
|
|
273
|
-
|
|
274
|
-
|
|
275
|
-
|
|
276
|
-
|
|
277
|
-
"
|
|
278
|
-
|
|
279
|
-
|
|
280
|
-
|
|
281
|
-
|
|
282
|
-
|
|
283
|
-
|
|
284
|
-
|
|
285
|
-
|
|
286
|
-
|
|
287
|
-
|
|
288
|
-
|
|
289
|
-
|
|
290
|
-
|
|
291
|
-
|
|
292
|
-
|
|
293
|
-
|
|
294
|
-
|
|
295
|
-
|
|
296
|
-
|
|
297
|
-
|
|
298
|
-
|
|
299
|
-
|
|
300
|
-
|
|
301
|
-
|
|
302
|
-
|
|
303
|
-
"
|
|
304
|
-
"
|
|
305
|
-
|
|
306
|
-
|
|
307
|
-
|
|
308
|
-
|
|
309
|
-
|
|
310
|
-
|
|
311
|
-
|
|
1
|
+
"""Model Manager - Manage fastembed models for semantic search."""
|
|
2
|
+
|
|
3
|
+
import json
|
|
4
|
+
import os
|
|
5
|
+
import shutil
|
|
6
|
+
from pathlib import Path
|
|
7
|
+
from typing import Dict, List, Optional
|
|
8
|
+
|
|
9
|
+
try:
|
|
10
|
+
from fastembed import TextEmbedding
|
|
11
|
+
FASTEMBED_AVAILABLE = True
|
|
12
|
+
except ImportError:
|
|
13
|
+
FASTEMBED_AVAILABLE = False
|
|
14
|
+
|
|
15
|
+
|
|
16
|
+
# Model profiles with metadata
|
|
17
|
+
# Note: 768d is max recommended dimension for optimal performance/quality balance
|
|
18
|
+
# 1024d models are available but not recommended due to higher resource usage
|
|
19
|
+
# cache_name: The actual Hugging Face repo name used by fastembed for ONNX caching
|
|
20
|
+
MODEL_PROFILES = {
|
|
21
|
+
"fast": {
|
|
22
|
+
"model_name": "BAAI/bge-small-en-v1.5",
|
|
23
|
+
"cache_name": "qdrant/bge-small-en-v1.5-onnx-q", # fastembed uses ONNX version
|
|
24
|
+
"dimensions": 384,
|
|
25
|
+
"size_mb": 80,
|
|
26
|
+
"description": "Fast, lightweight, English-optimized",
|
|
27
|
+
"use_case": "Quick prototyping, resource-constrained environments",
|
|
28
|
+
"recommended": True,
|
|
29
|
+
},
|
|
30
|
+
"base": {
|
|
31
|
+
"model_name": "BAAI/bge-base-en-v1.5",
|
|
32
|
+
"cache_name": "qdrant/bge-base-en-v1.5-onnx-q", # fastembed uses ONNX version
|
|
33
|
+
"dimensions": 768,
|
|
34
|
+
"size_mb": 220,
|
|
35
|
+
"description": "General purpose, good balance of speed and quality",
|
|
36
|
+
"use_case": "General text search, documentation",
|
|
37
|
+
"recommended": True,
|
|
38
|
+
},
|
|
39
|
+
"code": {
|
|
40
|
+
"model_name": "jinaai/jina-embeddings-v2-base-code",
|
|
41
|
+
"cache_name": "jinaai/jina-embeddings-v2-base-code", # Uses original name
|
|
42
|
+
"dimensions": 768,
|
|
43
|
+
"size_mb": 150,
|
|
44
|
+
"description": "Code-optimized, best for programming languages",
|
|
45
|
+
"use_case": "Open source projects, code semantic search",
|
|
46
|
+
"recommended": True,
|
|
47
|
+
},
|
|
48
|
+
"minilm": {
|
|
49
|
+
"model_name": "sentence-transformers/all-MiniLM-L6-v2",
|
|
50
|
+
"cache_name": "qdrant/all-MiniLM-L6-v2-onnx", # fastembed uses ONNX version
|
|
51
|
+
"dimensions": 384,
|
|
52
|
+
"size_mb": 90,
|
|
53
|
+
"description": "Popular lightweight model, good quality",
|
|
54
|
+
"use_case": "General purpose, low resource environments",
|
|
55
|
+
"recommended": True,
|
|
56
|
+
},
|
|
57
|
+
"multilingual": {
|
|
58
|
+
"model_name": "intfloat/multilingual-e5-large",
|
|
59
|
+
"cache_name": "qdrant/multilingual-e5-large-onnx", # fastembed uses ONNX version
|
|
60
|
+
"dimensions": 1024,
|
|
61
|
+
"size_mb": 1000,
|
|
62
|
+
"description": "Multilingual + code support (high resource usage)",
|
|
63
|
+
"use_case": "Enterprise multilingual projects",
|
|
64
|
+
"recommended": False, # 1024d not recommended
|
|
65
|
+
},
|
|
66
|
+
"balanced": {
|
|
67
|
+
"model_name": "mixedbread-ai/mxbai-embed-large-v1",
|
|
68
|
+
"cache_name": "mixedbread-ai/mxbai-embed-large-v1", # Uses original name
|
|
69
|
+
"dimensions": 1024,
|
|
70
|
+
"size_mb": 600,
|
|
71
|
+
"description": "High accuracy, general purpose (high resource usage)",
|
|
72
|
+
"use_case": "High-quality semantic search, balanced performance",
|
|
73
|
+
"recommended": False, # 1024d not recommended
|
|
74
|
+
},
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
|
|
78
|
+
def get_cache_dir() -> Path:
|
|
79
|
+
"""Get fastembed cache directory.
|
|
80
|
+
|
|
81
|
+
Returns:
|
|
82
|
+
Path to cache directory (usually ~/.cache/fastembed or %LOCALAPPDATA%\\Temp\\fastembed_cache)
|
|
83
|
+
"""
|
|
84
|
+
# Check HF_HOME environment variable first
|
|
85
|
+
if "HF_HOME" in os.environ:
|
|
86
|
+
return Path(os.environ["HF_HOME"])
|
|
87
|
+
|
|
88
|
+
# Default cache locations
|
|
89
|
+
if os.name == "nt": # Windows
|
|
90
|
+
cache_dir = Path(os.environ.get("LOCALAPPDATA", Path.home() / "AppData" / "Local")) / "Temp" / "fastembed_cache"
|
|
91
|
+
else: # Unix-like
|
|
92
|
+
cache_dir = Path.home() / ".cache" / "fastembed"
|
|
93
|
+
|
|
94
|
+
return cache_dir
|
|
95
|
+
|
|
96
|
+
|
|
97
|
+
def _get_model_cache_path(cache_dir: Path, info: Dict) -> Path:
|
|
98
|
+
"""Get the actual cache path for a model.
|
|
99
|
+
|
|
100
|
+
fastembed uses ONNX versions of models with different names than the original.
|
|
101
|
+
This function returns the correct path based on the cache_name field.
|
|
102
|
+
|
|
103
|
+
Args:
|
|
104
|
+
cache_dir: The fastembed cache directory
|
|
105
|
+
info: Model profile info dictionary
|
|
106
|
+
|
|
107
|
+
Returns:
|
|
108
|
+
Path to the model cache directory
|
|
109
|
+
"""
|
|
110
|
+
cache_name = info.get("cache_name", info["model_name"])
|
|
111
|
+
return cache_dir / f"models--{cache_name.replace('/', '--')}"
|
|
112
|
+
|
|
113
|
+
|
|
114
|
+
def list_models() -> Dict[str, any]:
|
|
115
|
+
"""List available model profiles and their installation status.
|
|
116
|
+
|
|
117
|
+
Returns:
|
|
118
|
+
Dictionary with model profiles, installed status, and cache info
|
|
119
|
+
"""
|
|
120
|
+
if not FASTEMBED_AVAILABLE:
|
|
121
|
+
return {
|
|
122
|
+
"success": False,
|
|
123
|
+
"error": "fastembed not installed. Install with: pip install codexlens[semantic]",
|
|
124
|
+
}
|
|
125
|
+
|
|
126
|
+
cache_dir = get_cache_dir()
|
|
127
|
+
cache_exists = cache_dir.exists()
|
|
128
|
+
|
|
129
|
+
models = []
|
|
130
|
+
for profile, info in MODEL_PROFILES.items():
|
|
131
|
+
model_name = info["model_name"]
|
|
132
|
+
|
|
133
|
+
# Check if model is cached using the actual cache name
|
|
134
|
+
installed = False
|
|
135
|
+
cache_size_mb = 0
|
|
136
|
+
|
|
137
|
+
if cache_exists:
|
|
138
|
+
# Check for model directory in cache using correct cache_name
|
|
139
|
+
model_cache_path = _get_model_cache_path(cache_dir, info)
|
|
140
|
+
if model_cache_path.exists():
|
|
141
|
+
installed = True
|
|
142
|
+
# Calculate cache size
|
|
143
|
+
total_size = sum(
|
|
144
|
+
f.stat().st_size
|
|
145
|
+
for f in model_cache_path.rglob("*")
|
|
146
|
+
if f.is_file()
|
|
147
|
+
)
|
|
148
|
+
cache_size_mb = round(total_size / (1024 * 1024), 1)
|
|
149
|
+
|
|
150
|
+
models.append({
|
|
151
|
+
"profile": profile,
|
|
152
|
+
"model_name": model_name,
|
|
153
|
+
"dimensions": info["dimensions"],
|
|
154
|
+
"estimated_size_mb": info["size_mb"],
|
|
155
|
+
"actual_size_mb": cache_size_mb if installed else None,
|
|
156
|
+
"description": info["description"],
|
|
157
|
+
"use_case": info["use_case"],
|
|
158
|
+
"installed": installed,
|
|
159
|
+
})
|
|
160
|
+
|
|
161
|
+
return {
|
|
162
|
+
"success": True,
|
|
163
|
+
"result": {
|
|
164
|
+
"models": models,
|
|
165
|
+
"cache_dir": str(cache_dir),
|
|
166
|
+
"cache_exists": cache_exists,
|
|
167
|
+
},
|
|
168
|
+
}
|
|
169
|
+
|
|
170
|
+
|
|
171
|
+
def download_model(profile: str, progress_callback: Optional[callable] = None) -> Dict[str, any]:
|
|
172
|
+
"""Download a model by profile name.
|
|
173
|
+
|
|
174
|
+
Args:
|
|
175
|
+
profile: Model profile name (fast, code, multilingual, balanced)
|
|
176
|
+
progress_callback: Optional callback function to report progress
|
|
177
|
+
|
|
178
|
+
Returns:
|
|
179
|
+
Result dictionary with success status
|
|
180
|
+
"""
|
|
181
|
+
if not FASTEMBED_AVAILABLE:
|
|
182
|
+
return {
|
|
183
|
+
"success": False,
|
|
184
|
+
"error": "fastembed not installed. Install with: pip install codexlens[semantic]",
|
|
185
|
+
}
|
|
186
|
+
|
|
187
|
+
if profile not in MODEL_PROFILES:
|
|
188
|
+
return {
|
|
189
|
+
"success": False,
|
|
190
|
+
"error": f"Unknown profile: {profile}. Available: {', '.join(MODEL_PROFILES.keys())}",
|
|
191
|
+
}
|
|
192
|
+
|
|
193
|
+
info = MODEL_PROFILES[profile]
|
|
194
|
+
model_name = info["model_name"]
|
|
195
|
+
|
|
196
|
+
try:
|
|
197
|
+
# Download model by instantiating TextEmbedding
|
|
198
|
+
# This will automatically download to cache if not present
|
|
199
|
+
if progress_callback:
|
|
200
|
+
progress_callback(f"Downloading {model_name}...")
|
|
201
|
+
|
|
202
|
+
embedder = TextEmbedding(model_name=model_name)
|
|
203
|
+
|
|
204
|
+
if progress_callback:
|
|
205
|
+
progress_callback(f"Model {model_name} downloaded successfully")
|
|
206
|
+
|
|
207
|
+
# Get cache info using correct cache_name
|
|
208
|
+
cache_dir = get_cache_dir()
|
|
209
|
+
model_cache_path = _get_model_cache_path(cache_dir, info)
|
|
210
|
+
|
|
211
|
+
cache_size = 0
|
|
212
|
+
if model_cache_path.exists():
|
|
213
|
+
total_size = sum(
|
|
214
|
+
f.stat().st_size
|
|
215
|
+
for f in model_cache_path.rglob("*")
|
|
216
|
+
if f.is_file()
|
|
217
|
+
)
|
|
218
|
+
cache_size = round(total_size / (1024 * 1024), 1)
|
|
219
|
+
|
|
220
|
+
return {
|
|
221
|
+
"success": True,
|
|
222
|
+
"result": {
|
|
223
|
+
"profile": profile,
|
|
224
|
+
"model_name": model_name,
|
|
225
|
+
"cache_size_mb": cache_size,
|
|
226
|
+
"cache_path": str(model_cache_path),
|
|
227
|
+
},
|
|
228
|
+
}
|
|
229
|
+
|
|
230
|
+
except Exception as e:
|
|
231
|
+
return {
|
|
232
|
+
"success": False,
|
|
233
|
+
"error": f"Failed to download model: {str(e)}",
|
|
234
|
+
}
|
|
235
|
+
|
|
236
|
+
|
|
237
|
+
def delete_model(profile: str) -> Dict[str, any]:
|
|
238
|
+
"""Delete a downloaded model from cache.
|
|
239
|
+
|
|
240
|
+
Args:
|
|
241
|
+
profile: Model profile name to delete
|
|
242
|
+
|
|
243
|
+
Returns:
|
|
244
|
+
Result dictionary with success status
|
|
245
|
+
"""
|
|
246
|
+
if profile not in MODEL_PROFILES:
|
|
247
|
+
return {
|
|
248
|
+
"success": False,
|
|
249
|
+
"error": f"Unknown profile: {profile}. Available: {', '.join(MODEL_PROFILES.keys())}",
|
|
250
|
+
}
|
|
251
|
+
|
|
252
|
+
info = MODEL_PROFILES[profile]
|
|
253
|
+
model_name = info["model_name"]
|
|
254
|
+
cache_dir = get_cache_dir()
|
|
255
|
+
model_cache_path = _get_model_cache_path(cache_dir, info)
|
|
256
|
+
|
|
257
|
+
if not model_cache_path.exists():
|
|
258
|
+
return {
|
|
259
|
+
"success": False,
|
|
260
|
+
"error": f"Model {profile} ({model_name}) is not installed",
|
|
261
|
+
}
|
|
262
|
+
|
|
263
|
+
try:
|
|
264
|
+
# Calculate size before deletion
|
|
265
|
+
total_size = sum(
|
|
266
|
+
f.stat().st_size
|
|
267
|
+
for f in model_cache_path.rglob("*")
|
|
268
|
+
if f.is_file()
|
|
269
|
+
)
|
|
270
|
+
size_mb = round(total_size / (1024 * 1024), 1)
|
|
271
|
+
|
|
272
|
+
# Delete model directory
|
|
273
|
+
shutil.rmtree(model_cache_path)
|
|
274
|
+
|
|
275
|
+
return {
|
|
276
|
+
"success": True,
|
|
277
|
+
"result": {
|
|
278
|
+
"profile": profile,
|
|
279
|
+
"model_name": model_name,
|
|
280
|
+
"deleted_size_mb": size_mb,
|
|
281
|
+
"cache_path": str(model_cache_path),
|
|
282
|
+
},
|
|
283
|
+
}
|
|
284
|
+
|
|
285
|
+
except Exception as e:
|
|
286
|
+
return {
|
|
287
|
+
"success": False,
|
|
288
|
+
"error": f"Failed to delete model: {str(e)}",
|
|
289
|
+
}
|
|
290
|
+
|
|
291
|
+
|
|
292
|
+
def get_model_info(profile: str) -> Dict[str, any]:
|
|
293
|
+
"""Get detailed information about a model profile.
|
|
294
|
+
|
|
295
|
+
Args:
|
|
296
|
+
profile: Model profile name
|
|
297
|
+
|
|
298
|
+
Returns:
|
|
299
|
+
Result dictionary with model information
|
|
300
|
+
"""
|
|
301
|
+
if profile not in MODEL_PROFILES:
|
|
302
|
+
return {
|
|
303
|
+
"success": False,
|
|
304
|
+
"error": f"Unknown profile: {profile}. Available: {', '.join(MODEL_PROFILES.keys())}",
|
|
305
|
+
}
|
|
306
|
+
|
|
307
|
+
info = MODEL_PROFILES[profile]
|
|
308
|
+
model_name = info["model_name"]
|
|
309
|
+
|
|
310
|
+
# Check installation status using correct cache_name
|
|
311
|
+
cache_dir = get_cache_dir()
|
|
312
|
+
model_cache_path = _get_model_cache_path(cache_dir, info)
|
|
313
|
+
installed = model_cache_path.exists()
|
|
314
|
+
|
|
315
|
+
cache_size_mb = None
|
|
316
|
+
if installed:
|
|
317
|
+
total_size = sum(
|
|
318
|
+
f.stat().st_size
|
|
319
|
+
for f in model_cache_path.rglob("*")
|
|
320
|
+
if f.is_file()
|
|
321
|
+
)
|
|
322
|
+
cache_size_mb = round(total_size / (1024 * 1024), 1)
|
|
323
|
+
|
|
324
|
+
return {
|
|
325
|
+
"success": True,
|
|
326
|
+
"result": {
|
|
327
|
+
"profile": profile,
|
|
328
|
+
"model_name": model_name,
|
|
329
|
+
"dimensions": info["dimensions"],
|
|
330
|
+
"estimated_size_mb": info["size_mb"],
|
|
331
|
+
"actual_size_mb": cache_size_mb,
|
|
332
|
+
"description": info["description"],
|
|
333
|
+
"use_case": info["use_case"],
|
|
334
|
+
"installed": installed,
|
|
335
|
+
"cache_path": str(model_cache_path) if installed else None,
|
|
336
|
+
},
|
|
337
|
+
}
|