hestia-system 0.1.0__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.
- hestia_system-0.1.0/MANIFEST.in +2 -0
- hestia_system-0.1.0/PKG-INFO +68 -0
- hestia_system-0.1.0/README.md +46 -0
- hestia_system-0.1.0/project.ini +32 -0
- hestia_system-0.1.0/pyproject.toml +29 -0
- hestia_system-0.1.0/setup.cfg +4 -0
- hestia_system-0.1.0/setup.py +39 -0
- hestia_system-0.1.0/src/Hestia/__init__.py +10 -0
- hestia_system-0.1.0/src/Hestia/model_catalog.py +11 -0
- hestia_system-0.1.0/src/Hestia/models/__init__.py +24 -0
- hestia_system-0.1.0/src/Hestia/models/catalog.py +438 -0
- hestia_system-0.1.0/src/Hestia/models/info.py +68 -0
- hestia_system-0.1.0/src/Hestia/types.py +19 -0
- hestia_system-0.1.0/src/hestia_system.egg-info/PKG-INFO +68 -0
- hestia_system-0.1.0/src/hestia_system.egg-info/SOURCES.txt +18 -0
- hestia_system-0.1.0/src/hestia_system.egg-info/dependency_links.txt +1 -0
- hestia_system-0.1.0/src/hestia_system.egg-info/requires.txt +7 -0
- hestia_system-0.1.0/src/hestia_system.egg-info/top_level.txt +1 -0
- hestia_system-0.1.0/tests/test_examples.py +21 -0
- hestia_system-0.1.0/tests/test_models.py +75 -0
|
@@ -0,0 +1,68 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: hestia-system
|
|
3
|
+
Version: 0.1.0
|
|
4
|
+
Summary: System discovery, hardware and software analysis, and AI model recommendations.
|
|
5
|
+
Author: Damon S. Green II (nomadiidamon)
|
|
6
|
+
License: MIT
|
|
7
|
+
Project-URL: Homepage, https://github.com/nomadiidamon/Hestia
|
|
8
|
+
Requires-Python: >=3.10
|
|
9
|
+
Description-Content-Type: text/markdown
|
|
10
|
+
Requires-Dist: psutil>=5.9.0
|
|
11
|
+
Provides-Extra: nvidia
|
|
12
|
+
Requires-Dist: nvidia-ml-py>=12.0.0; extra == "nvidia"
|
|
13
|
+
Provides-Extra: dev
|
|
14
|
+
Requires-Dist: pytest>=7.0; extra == "dev"
|
|
15
|
+
Dynamic: author
|
|
16
|
+
Dynamic: description
|
|
17
|
+
Dynamic: description-content-type
|
|
18
|
+
Dynamic: license
|
|
19
|
+
Dynamic: project-url
|
|
20
|
+
Dynamic: requires-python
|
|
21
|
+
Dynamic: summary
|
|
22
|
+
|
|
23
|
+
# Hestia for Python
|
|
24
|
+
|
|
25
|
+
Hestia provides system discovery and AI model intelligence. The Python package
|
|
26
|
+
currently exposes accelerator and model-size types, a model catalog, and model
|
|
27
|
+
information lookup.
|
|
28
|
+
|
|
29
|
+
The distribution is named `hestia-system`; import it as `Hestia`.
|
|
30
|
+
|
|
31
|
+
## Installation
|
|
32
|
+
|
|
33
|
+
```bash
|
|
34
|
+
python -m pip install hestia-system
|
|
35
|
+
```
|
|
36
|
+
|
|
37
|
+
Optional dependencies are available as extras:
|
|
38
|
+
|
|
39
|
+
```bash
|
|
40
|
+
python -m pip install "hestia-system[nvidia]" # NVIDIA telemetry support
|
|
41
|
+
python -m pip install "hestia-system[dev]" # pytest
|
|
42
|
+
```
|
|
43
|
+
|
|
44
|
+
## Usage
|
|
45
|
+
|
|
46
|
+
```python
|
|
47
|
+
from Hestia import AcceleratorType, ModelSize, get_model_info
|
|
48
|
+
|
|
49
|
+
info = get_model_info(AcceleratorType.NVIDIA_CUDA, ModelSize.SMALL)
|
|
50
|
+
print(info)
|
|
51
|
+
```
|
|
52
|
+
|
|
53
|
+
The package supports Python versions declared by the project metadata (Python
|
|
54
|
+
3.10 and later).
|
|
55
|
+
|
|
56
|
+
## Development
|
|
57
|
+
|
|
58
|
+
From the repository checkout:
|
|
59
|
+
|
|
60
|
+
```bash
|
|
61
|
+
cd python
|
|
62
|
+
python -m pip install -e ".[dev]"
|
|
63
|
+
python -m pytest
|
|
64
|
+
```
|
|
65
|
+
|
|
66
|
+
Package metadata is maintained in the repository's `project.ini`. Source
|
|
67
|
+
distributions include a copy of that file so they can be built independently
|
|
68
|
+
of the repository checkout.
|
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
# Hestia for Python
|
|
2
|
+
|
|
3
|
+
Hestia provides system discovery and AI model intelligence. The Python package
|
|
4
|
+
currently exposes accelerator and model-size types, a model catalog, and model
|
|
5
|
+
information lookup.
|
|
6
|
+
|
|
7
|
+
The distribution is named `hestia-system`; import it as `Hestia`.
|
|
8
|
+
|
|
9
|
+
## Installation
|
|
10
|
+
|
|
11
|
+
```bash
|
|
12
|
+
python -m pip install hestia-system
|
|
13
|
+
```
|
|
14
|
+
|
|
15
|
+
Optional dependencies are available as extras:
|
|
16
|
+
|
|
17
|
+
```bash
|
|
18
|
+
python -m pip install "hestia-system[nvidia]" # NVIDIA telemetry support
|
|
19
|
+
python -m pip install "hestia-system[dev]" # pytest
|
|
20
|
+
```
|
|
21
|
+
|
|
22
|
+
## Usage
|
|
23
|
+
|
|
24
|
+
```python
|
|
25
|
+
from Hestia import AcceleratorType, ModelSize, get_model_info
|
|
26
|
+
|
|
27
|
+
info = get_model_info(AcceleratorType.NVIDIA_CUDA, ModelSize.SMALL)
|
|
28
|
+
print(info)
|
|
29
|
+
```
|
|
30
|
+
|
|
31
|
+
The package supports Python versions declared by the project metadata (Python
|
|
32
|
+
3.10 and later).
|
|
33
|
+
|
|
34
|
+
## Development
|
|
35
|
+
|
|
36
|
+
From the repository checkout:
|
|
37
|
+
|
|
38
|
+
```bash
|
|
39
|
+
cd python
|
|
40
|
+
python -m pip install -e ".[dev]"
|
|
41
|
+
python -m pytest
|
|
42
|
+
```
|
|
43
|
+
|
|
44
|
+
Package metadata is maintained in the repository's `project.ini`. Source
|
|
45
|
+
distributions include a copy of that file so they can be built independently
|
|
46
|
+
of the repository checkout.
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
; project.ini
|
|
2
|
+
;
|
|
3
|
+
; Single source of truth for metadata shared across the C++ and Python
|
|
4
|
+
; implementations. Both build systems (premake5 on the C++ side, the Python
|
|
5
|
+
; packaging/build scripts on the Python side) should parse this file rather
|
|
6
|
+
; than duplicating these values in language-specific manifests.
|
|
7
|
+
;
|
|
8
|
+
; Keep keys flat and simple (INI has no native nesting) so both a C++ INI
|
|
9
|
+
; parser and Python's configparser can read it without custom logic.
|
|
10
|
+
|
|
11
|
+
[project]
|
|
12
|
+
name = Hestia
|
|
13
|
+
python_package = hestia-system
|
|
14
|
+
version = 0.1.0
|
|
15
|
+
description = "System discovery, hardware and software analysis, and AI model recommendations."
|
|
16
|
+
homepage = https://github.com/nomadiidamon/Hestia
|
|
17
|
+
license = MIT
|
|
18
|
+
|
|
19
|
+
[contributors]
|
|
20
|
+
; Comma-separated list; expand as needed, or switch to one key per person
|
|
21
|
+
; (e.g. contributor.1, contributor.2) if you want per-person metadata later.
|
|
22
|
+
maintainers = Damon S. Green II (nomadiidamon)
|
|
23
|
+
contributors =
|
|
24
|
+
|
|
25
|
+
[compatibility]
|
|
26
|
+
; Minimum/target language versions both implementations should track.
|
|
27
|
+
cpp_standard = c++17
|
|
28
|
+
python_requires = >=3.10
|
|
29
|
+
|
|
30
|
+
[build]
|
|
31
|
+
; Freeform notes/flags both build scripts may want to agree on.
|
|
32
|
+
default_build_type = release
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
[build-system]
|
|
2
|
+
requires = ["setuptools>=68.0"]
|
|
3
|
+
build-backend = "setuptools.build_meta"
|
|
4
|
+
|
|
5
|
+
[project]
|
|
6
|
+
name = "hestia-system"
|
|
7
|
+
dynamic = ["version", "description", "readme", "license", "authors", "requires-python", "urls"] # from ../project.ini via setup.py
|
|
8
|
+
|
|
9
|
+
dependencies = [
|
|
10
|
+
"psutil>=5.9.0",
|
|
11
|
+
]
|
|
12
|
+
|
|
13
|
+
[project.optional-dependencies]
|
|
14
|
+
nvidia = [
|
|
15
|
+
"nvidia-ml-py>=12.0.0",
|
|
16
|
+
]
|
|
17
|
+
dev = [
|
|
18
|
+
"pytest>=7.0",
|
|
19
|
+
]
|
|
20
|
+
|
|
21
|
+
[tool.setuptools]
|
|
22
|
+
package-dir = { "" = "src" }
|
|
23
|
+
|
|
24
|
+
[tool.setuptools.packages.find]
|
|
25
|
+
where = ["src"]
|
|
26
|
+
|
|
27
|
+
[tool.pytest.ini_options]
|
|
28
|
+
pythonpath = ["src"]
|
|
29
|
+
testpaths = ["tests"]
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
"""Reads shared metadata from ../project.ini (the single source of truth)."""
|
|
2
|
+
import configparser
|
|
3
|
+
import re
|
|
4
|
+
import shutil
|
|
5
|
+
from pathlib import Path
|
|
6
|
+
|
|
7
|
+
from setuptools import setup
|
|
8
|
+
|
|
9
|
+
HERE = Path(__file__).resolve().parent
|
|
10
|
+
REPO_INI = HERE.parent / "project.ini"
|
|
11
|
+
LOCAL_INI = HERE / "project.ini"
|
|
12
|
+
|
|
13
|
+
# An sdist has no parent repo, so ship a copy of project.ini alongside setup.py.
|
|
14
|
+
if REPO_INI.is_file():
|
|
15
|
+
shutil.copyfile(REPO_INI, LOCAL_INI)
|
|
16
|
+
if not LOCAL_INI.is_file():
|
|
17
|
+
raise FileNotFoundError(f"project.ini not found at {REPO_INI} or {LOCAL_INI}")
|
|
18
|
+
|
|
19
|
+
cfg = configparser.ConfigParser()
|
|
20
|
+
with open(LOCAL_INI, encoding="utf-8-sig") as ini:
|
|
21
|
+
cfg.read_file(ini)
|
|
22
|
+
project = cfg["project"]
|
|
23
|
+
|
|
24
|
+
people = [p.strip() for p in cfg["contributors"]["maintainers"].split(",") if p.strip()]
|
|
25
|
+
# "Name (handle) <email>" -> "Name (handle)"
|
|
26
|
+
names = [re.sub(r"\s*<.*>$", "", p) for p in people]
|
|
27
|
+
emails = [m.group(1) for p in people if (m := re.search(r"<(.*)>$", p))]
|
|
28
|
+
|
|
29
|
+
setup(
|
|
30
|
+
version=project["version"],
|
|
31
|
+
description=project["description"].strip('"'),
|
|
32
|
+
long_description=(HERE / "README.md").read_text(encoding="utf-8"),
|
|
33
|
+
long_description_content_type="text/markdown",
|
|
34
|
+
license=project["license"],
|
|
35
|
+
python_requires=cfg["compatibility"]["python_requires"],
|
|
36
|
+
author=", ".join(names),
|
|
37
|
+
author_email=", ".join(emails) or None,
|
|
38
|
+
project_urls={"Homepage": project["homepage"]},
|
|
39
|
+
)
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
"""Hestia - system discovery and AI model intelligence."""
|
|
2
|
+
|
|
3
|
+
from .models import ModelInfo, get_model_info
|
|
4
|
+
from .types import AcceleratorType, ModelSize
|
|
5
|
+
|
|
6
|
+
|
|
7
|
+
__version__ = "0.1.0"
|
|
8
|
+
|
|
9
|
+
|
|
10
|
+
__all__ = ["AcceleratorType", "ModelSize", "ModelInfo", "get_model_info"]
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
"""AI model catalog and metadata."""
|
|
2
|
+
|
|
3
|
+
from .catalog import (
|
|
4
|
+
KNOWN_CATEGORIES,
|
|
5
|
+
MODEL_DATABASE,
|
|
6
|
+
TIER_FALLBACK_ORDER,
|
|
7
|
+
TierEntry,
|
|
8
|
+
TierMap,
|
|
9
|
+
get_category,
|
|
10
|
+
get_tier,
|
|
11
|
+
)
|
|
12
|
+
from .info import ModelInfo, get_model_info
|
|
13
|
+
|
|
14
|
+
__all__ = [
|
|
15
|
+
"KNOWN_CATEGORIES",
|
|
16
|
+
"MODEL_DATABASE",
|
|
17
|
+
"TIER_FALLBACK_ORDER",
|
|
18
|
+
"TierEntry",
|
|
19
|
+
"TierMap",
|
|
20
|
+
"ModelInfo",
|
|
21
|
+
"get_category",
|
|
22
|
+
"get_model_info",
|
|
23
|
+
"get_tier",
|
|
24
|
+
]
|
|
@@ -0,0 +1,438 @@
|
|
|
1
|
+
# ---------------------------------------------------------------------------
|
|
2
|
+
# To add new categories
|
|
3
|
+
# ---------------------------------------------------------------------------
|
|
4
|
+
# 1.) Add the new category key to KNOWN_CATEGORIES
|
|
5
|
+
# KNOWN_CATEGORIES = [ '...' , '...' , 'coding']
|
|
6
|
+
|
|
7
|
+
# 2.) Add the new category key to each tier entry that supports it in MODEL_DATABASE
|
|
8
|
+
# 'coding': ['qwen2.5-coder:7b']
|
|
9
|
+
|
|
10
|
+
# 3.) Add the field to ModelInfo in models/info.py and the ModelRecommendation dataclass
|
|
11
|
+
# coding_models: List[str]
|
|
12
|
+
|
|
13
|
+
# 4.) Add to ModelRecommender.recommend() in hardware.py
|
|
14
|
+
# coding_models=get_category(tier, 'coding_models'),
|
|
15
|
+
|
|
16
|
+
# 5.) Add to print_hardware_report() in hardware.py
|
|
17
|
+
# if recommendation.coding_models:
|
|
18
|
+
#print(f"Coding: {', '.join(recommendation.coding_models)}")
|
|
19
|
+
|
|
20
|
+
|
|
21
|
+
"""
|
|
22
|
+
model_catalog.py - Model recommendation database for Local AI Runtime.
|
|
23
|
+
|
|
24
|
+
Defines what models are appropriate per hardware tier, accelerator type,
|
|
25
|
+
and capability category. Add new categories here without touching hardware.py.
|
|
26
|
+
|
|
27
|
+
Category keys per tier entry:
|
|
28
|
+
models - best general-purpose models for balanced use
|
|
29
|
+
thinking - chain-of-thought / extended reasoning (/think mode)
|
|
30
|
+
tools - native function/tool-call support
|
|
31
|
+
vision - multimodal image + text understanding
|
|
32
|
+
quantization - recommended quantization level for this tier
|
|
33
|
+
batch_size - safe concurrent request count
|
|
34
|
+
context - practical max context window in tokens
|
|
35
|
+
performance - human-readable speed description
|
|
36
|
+
|
|
37
|
+
@todo: Abstract the model recommendation logic to allow dynamic updates and easier maintenance.
|
|
38
|
+
@todo: Create a class to hold a model, size, and category for easier management and retrieval.
|
|
39
|
+
"""
|
|
40
|
+
|
|
41
|
+
from typing import Dict, List
|
|
42
|
+
from ..types import AcceleratorType, ModelSize
|
|
43
|
+
|
|
44
|
+
|
|
45
|
+
# ---------------------------------------------------------------------------
|
|
46
|
+
# Type alias for a single tier entry
|
|
47
|
+
# ---------------------------------------------------------------------------
|
|
48
|
+
TierEntry = Dict[str, object]
|
|
49
|
+
TierMap = Dict[ModelSize, TierEntry]
|
|
50
|
+
|
|
51
|
+
|
|
52
|
+
# ---------------------------------------------------------------------------
|
|
53
|
+
# MODEL DATABASE
|
|
54
|
+
# Outer key: AcceleratorType
|
|
55
|
+
# Inner key: ModelSize (memory tier)
|
|
56
|
+
# ---------------------------------------------------------------------------
|
|
57
|
+
|
|
58
|
+
MODEL_DATABASE: Dict[AcceleratorType, TierMap] = {
|
|
59
|
+
|
|
60
|
+
# ==========================================================================
|
|
61
|
+
# NVIDIA CUDA
|
|
62
|
+
# Fast VRAM access - highest quality quant per tier
|
|
63
|
+
# ==========================================================================
|
|
64
|
+
AcceleratorType.NVIDIA_CUDA: {
|
|
65
|
+
|
|
66
|
+
ModelSize.TINY: {
|
|
67
|
+
# <2 GB - ultra-constrained, phone/edge-class VRAM
|
|
68
|
+
'models': ['qwen3:0.6b', 'llama3.2:1b', 'deepseek-r1:1.5b', 'smollm2:1.7b'],
|
|
69
|
+
'thinking': ['deepseek-r1:1.5b', 'qwen3:0.6b'],
|
|
70
|
+
'tools': ['qwen3:0.6b', 'llama3.2:1b', 'smollm2:1.7b'],
|
|
71
|
+
'vision': [], # No reliable sub-2 GB vision models on Ollama
|
|
72
|
+
'quantization': 'q8_0',
|
|
73
|
+
'batch_size': 4,
|
|
74
|
+
'context': 8192,
|
|
75
|
+
'performance': 'Fast (tiny model)',
|
|
76
|
+
},
|
|
77
|
+
|
|
78
|
+
ModelSize.SMALL: {
|
|
79
|
+
# 2-4 GB - entry-level discrete GPU or shared VRAM laptop
|
|
80
|
+
'models': ['qwen3:1.7b', 'llama3.2:3b', 'phi4-mini:3.8b', 'granite3.3:2b'],
|
|
81
|
+
'thinking': ['qwen3:1.7b', 'deepseek-r1:1.5b'],
|
|
82
|
+
'tools': ['qwen3:1.7b', 'llama3.2:3b', 'granite3.1-dense:2b', 'xlam:1b'],
|
|
83
|
+
'vision': ['llama3.2-vision:3b', 'moondream:1.8b', 'minicpm-v:3b'],
|
|
84
|
+
'quantization': 'q6_k',
|
|
85
|
+
'batch_size': 4,
|
|
86
|
+
'context': 16384,
|
|
87
|
+
'performance': 'Fast',
|
|
88
|
+
},
|
|
89
|
+
|
|
90
|
+
ModelSize.MEDIUM: {
|
|
91
|
+
# 4-12 GB - GTX 1080 / RTX 3060 / RX 6700 XT class
|
|
92
|
+
'models': ['qwen3:8b', 'llama3.1:8b', 'mistral:7b', 'mistral-nemo:12b', 'qwen2.5:7b'],
|
|
93
|
+
'thinking': ['qwen3:8b', 'deepseek-r1:8b', 'cogito:8b', 'exaone-deep:7.8b'],
|
|
94
|
+
'tools': ['qwen3:8b', 'llama3.1:8b', 'qwen2.5:7b', 'hermes3:8b',
|
|
95
|
+
'mistral:7b', 'xlam:8b', 'functionary:7b', 'granite3.1-dense:8b'],
|
|
96
|
+
'vision': ['llava:7b', 'llava:13b', 'llama3.2-vision:11b', 'qwen2.5vl:7b',
|
|
97
|
+
'minicpm-v:8b', 'moondream:1.8b', 'bakllava:7b'],
|
|
98
|
+
'quantization': 'q4_k_m',
|
|
99
|
+
'batch_size': 2,
|
|
100
|
+
'context': 32768,
|
|
101
|
+
'performance': 'Fast',
|
|
102
|
+
},
|
|
103
|
+
|
|
104
|
+
ModelSize.LARGE: {
|
|
105
|
+
# 12-40 GB - RTX 3090 / RTX 4090 / A100 40 GB class
|
|
106
|
+
'models': ['qwen3:14b', 'qwen3:32b', 'qwen2.5:32b',
|
|
107
|
+
'deepseek-r1:14b', 'command-r:35b'],
|
|
108
|
+
'thinking': ['qwen3:14b', 'qwen3:32b', 'deepseek-r1:14b', 'deepseek-r1:32b',
|
|
109
|
+
'qwq:32b', 'cogito:14b', 'cogito:32b',
|
|
110
|
+
'phi4-reasoning:14b', 'exaone-deep:32b'],
|
|
111
|
+
'tools': ['qwen3:14b', 'qwen3:32b', 'command-r:35b', 'qwen2.5:32b',
|
|
112
|
+
'hermes3:8b', 'aya-expanse:32b', 'functionary:7b', 'xlam:7b'],
|
|
113
|
+
'vision': ['llava:34b', 'qwen2.5vl:14b', 'qwen2.5vl:32b',
|
|
114
|
+
'llama3.2-vision:11b', 'minicpm-v:8b', 'gemma3:27b',
|
|
115
|
+
'mistral-small3.1:22b'],
|
|
116
|
+
'quantization': 'q4_k_m',
|
|
117
|
+
'batch_size': 2,
|
|
118
|
+
'context': 32768,
|
|
119
|
+
'performance': 'Moderate',
|
|
120
|
+
},
|
|
121
|
+
|
|
122
|
+
ModelSize.XLARGE: {
|
|
123
|
+
# 40+ GB - A100 80 GB / H100 / multi-GPU NVLink
|
|
124
|
+
'models': ['llama3.3:70b', 'qwen2.5:72b', 'qwen3:30b-a3b',
|
|
125
|
+
'deepseek-r1:70b', 'command-r-plus:104b'],
|
|
126
|
+
'thinking': ['deepseek-r1:70b', 'qwen3:30b-a3b', 'cogito:70b',
|
|
127
|
+
'qwq:32b', 'exaone-deep:32b'],
|
|
128
|
+
'tools': ['llama3.3:70b', 'qwen2.5:72b', 'qwen3:30b-a3b',
|
|
129
|
+
'hermes3:70b', 'command-r-plus:104b',
|
|
130
|
+
'firefunction-v2:70b', 'functionary:70b'],
|
|
131
|
+
'vision': ['llava:34b', 'qwen2.5vl:72b', 'llama3.2-vision:90b',
|
|
132
|
+
'mistral-small3.1:22b', 'gemma3:27b'],
|
|
133
|
+
'quantization': 'q4_k_m',
|
|
134
|
+
'batch_size': 4,
|
|
135
|
+
'context': 131072,
|
|
136
|
+
'performance': 'Fast (large model)',
|
|
137
|
+
},
|
|
138
|
+
},
|
|
139
|
+
|
|
140
|
+
# ==========================================================================
|
|
141
|
+
# AMD ROCm
|
|
142
|
+
# Slightly less efficient memory bandwidth than CUDA; drop quant one step
|
|
143
|
+
# ==========================================================================
|
|
144
|
+
AcceleratorType.AMD_ROCM: {
|
|
145
|
+
|
|
146
|
+
ModelSize.TINY: {
|
|
147
|
+
'models': ['qwen3:0.6b', 'llama3.2:1b', 'deepseek-r1:1.5b'],
|
|
148
|
+
'thinking': ['deepseek-r1:1.5b', 'qwen3:0.6b'],
|
|
149
|
+
'tools': ['qwen3:0.6b', 'llama3.2:1b'],
|
|
150
|
+
'vision': [],
|
|
151
|
+
'quantization': 'q8_0',
|
|
152
|
+
'batch_size': 2,
|
|
153
|
+
'context': 8192,
|
|
154
|
+
'performance': 'Moderate (tiny model)',
|
|
155
|
+
},
|
|
156
|
+
|
|
157
|
+
ModelSize.SMALL: {
|
|
158
|
+
'models': ['qwen3:1.7b', 'llama3.2:3b', 'phi4-mini:3.8b'],
|
|
159
|
+
'thinking': ['qwen3:1.7b', 'deepseek-r1:1.5b'],
|
|
160
|
+
'tools': ['qwen3:1.7b', 'llama3.2:3b', 'xlam:1b'],
|
|
161
|
+
'vision': ['llama3.2-vision:3b', 'moondream:1.8b', 'minicpm-v:3b'],
|
|
162
|
+
'quantization': 'q5_k_m',
|
|
163
|
+
'batch_size': 2,
|
|
164
|
+
'context': 16384,
|
|
165
|
+
'performance': 'Moderate',
|
|
166
|
+
},
|
|
167
|
+
|
|
168
|
+
ModelSize.MEDIUM: {
|
|
169
|
+
'models': ['qwen3:8b', 'llama3.1:8b', 'mistral:7b', 'qwen2.5:7b'],
|
|
170
|
+
'thinking': ['qwen3:8b', 'deepseek-r1:8b', 'cogito:8b'],
|
|
171
|
+
'tools': ['qwen3:8b', 'llama3.1:8b', 'qwen2.5:7b',
|
|
172
|
+
'hermes3:8b', 'mistral:7b', 'granite3.1-dense:8b'],
|
|
173
|
+
'vision': ['llava:7b', 'llama3.2-vision:11b', 'qwen2.5vl:7b',
|
|
174
|
+
'minicpm-v:8b', 'moondream:1.8b'],
|
|
175
|
+
'quantization': 'q4_k_m',
|
|
176
|
+
'batch_size': 2,
|
|
177
|
+
'context': 32768,
|
|
178
|
+
'performance': 'Moderate',
|
|
179
|
+
},
|
|
180
|
+
|
|
181
|
+
ModelSize.LARGE: {
|
|
182
|
+
'models': ['qwen3:14b', 'qwen3:32b', 'deepseek-r1:14b', 'command-r:35b'],
|
|
183
|
+
'thinking': ['qwen3:14b', 'qwen3:32b', 'deepseek-r1:14b', 'deepseek-r1:32b',
|
|
184
|
+
'qwq:32b', 'cogito:14b', 'phi4-reasoning:14b'],
|
|
185
|
+
'tools': ['qwen3:14b', 'qwen3:32b', 'command-r:35b',
|
|
186
|
+
'qwen2.5:32b', 'aya-expanse:32b'],
|
|
187
|
+
'vision': ['qwen2.5vl:14b', 'qwen2.5vl:32b', 'llava:34b',
|
|
188
|
+
'gemma3:27b', 'mistral-small3.1:22b'],
|
|
189
|
+
'quantization': 'q3_k_m',
|
|
190
|
+
'batch_size': 1,
|
|
191
|
+
'context': 32768,
|
|
192
|
+
'performance': 'Slow',
|
|
193
|
+
},
|
|
194
|
+
|
|
195
|
+
ModelSize.XLARGE: {
|
|
196
|
+
'models': ['llama3.3:70b', 'qwen2.5:72b', 'deepseek-r1:70b'],
|
|
197
|
+
'thinking': ['deepseek-r1:70b', 'qwen3:30b-a3b', 'cogito:70b'],
|
|
198
|
+
'tools': ['llama3.3:70b', 'qwen2.5:72b', 'hermes3:70b',
|
|
199
|
+
'firefunction-v2:70b'],
|
|
200
|
+
'vision': ['qwen2.5vl:72b', 'llama3.2-vision:90b', 'llava:34b'],
|
|
201
|
+
'quantization': 'q3_k_m',
|
|
202
|
+
'batch_size': 2,
|
|
203
|
+
'context': 65536,
|
|
204
|
+
'performance': 'Moderate (large model)',
|
|
205
|
+
},
|
|
206
|
+
},
|
|
207
|
+
|
|
208
|
+
# ==========================================================================
|
|
209
|
+
# Intel Arc / Xe (OneAPI)
|
|
210
|
+
# Typically 8-16 GB on Arc A770/B580; lower throughput than NVIDIA/AMD
|
|
211
|
+
# ==========================================================================
|
|
212
|
+
AcceleratorType.INTEL_ONEAPI: {
|
|
213
|
+
|
|
214
|
+
ModelSize.TINY: {
|
|
215
|
+
'models': ['qwen3:0.6b', 'llama3.2:1b', 'smollm2:1.7b'],
|
|
216
|
+
'thinking': ['deepseek-r1:1.5b', 'qwen3:0.6b'],
|
|
217
|
+
'tools': ['qwen3:0.6b', 'llama3.2:1b'],
|
|
218
|
+
'vision': [],
|
|
219
|
+
'quantization': 'q8_0',
|
|
220
|
+
'batch_size': 2,
|
|
221
|
+
'context': 8192,
|
|
222
|
+
'performance': 'Moderate (tiny model)',
|
|
223
|
+
},
|
|
224
|
+
|
|
225
|
+
ModelSize.SMALL: {
|
|
226
|
+
'models': ['qwen3:1.7b', 'llama3.2:3b', 'granite3.3:2b'],
|
|
227
|
+
'thinking': ['qwen3:1.7b', 'deepseek-r1:1.5b'],
|
|
228
|
+
'tools': ['qwen3:1.7b', 'llama3.2:3b', 'granite3.1-dense:2b'],
|
|
229
|
+
'vision': ['moondream:1.8b', 'minicpm-v:3b'],
|
|
230
|
+
'quantization': 'q5_k_m',
|
|
231
|
+
'batch_size': 2,
|
|
232
|
+
'context': 8192,
|
|
233
|
+
'performance': 'Moderate',
|
|
234
|
+
},
|
|
235
|
+
|
|
236
|
+
ModelSize.MEDIUM: {
|
|
237
|
+
'models': ['qwen3:8b', 'llama3.1:8b', 'mistral:7b'],
|
|
238
|
+
'thinking': ['qwen3:8b', 'deepseek-r1:8b'],
|
|
239
|
+
'tools': ['qwen3:8b', 'llama3.1:8b', 'mistral:7b',
|
|
240
|
+
'granite3.1-dense:8b', 'hermes3:8b'],
|
|
241
|
+
'vision': ['llava:7b', 'qwen2.5vl:7b', 'minicpm-v:8b', 'moondream:1.8b'],
|
|
242
|
+
'quantization': 'q4_k_m',
|
|
243
|
+
'batch_size': 1,
|
|
244
|
+
'context': 16384,
|
|
245
|
+
'performance': 'Slow',
|
|
246
|
+
},
|
|
247
|
+
|
|
248
|
+
ModelSize.LARGE: {
|
|
249
|
+
'models': ['qwen3:14b', 'qwen2.5:14b', 'phi4-reasoning:14b'],
|
|
250
|
+
'thinking': ['qwen3:14b', 'deepseek-r1:14b', 'phi4-reasoning:14b', 'cogito:14b'],
|
|
251
|
+
'tools': ['qwen3:14b', 'qwen2.5:14b', 'hermes3:8b'],
|
|
252
|
+
'vision': ['qwen2.5vl:14b', 'gemma3:12b', 'mistral-small3.1:22b'],
|
|
253
|
+
'quantization': 'q3_k_m',
|
|
254
|
+
'batch_size': 1,
|
|
255
|
+
'context': 16384,
|
|
256
|
+
'performance': 'Slow',
|
|
257
|
+
},
|
|
258
|
+
|
|
259
|
+
# XLARGE unrealistic for Arc - fallback to LARGE handled in ModelRecommender
|
|
260
|
+
},
|
|
261
|
+
|
|
262
|
+
# ==========================================================================
|
|
263
|
+
# Apple Metal (Apple Silicon - unified memory)
|
|
264
|
+
# M1/M2/M3/M4 share RAM with GPU; 16-192 GB depending on config
|
|
265
|
+
# Metal is highly optimised for Ollama via llama.cpp
|
|
266
|
+
# ==========================================================================
|
|
267
|
+
AcceleratorType.APPLE_METAL: {
|
|
268
|
+
|
|
269
|
+
ModelSize.TINY: {
|
|
270
|
+
'models': ['qwen3:0.6b', 'llama3.2:1b', 'smollm2:1.7b'],
|
|
271
|
+
'thinking': ['deepseek-r1:1.5b', 'qwen3:0.6b'],
|
|
272
|
+
'tools': ['qwen3:0.6b', 'llama3.2:1b'],
|
|
273
|
+
'vision': [],
|
|
274
|
+
'quantization': 'q8_0',
|
|
275
|
+
'batch_size': 4,
|
|
276
|
+
'context': 8192,
|
|
277
|
+
'performance': 'Fast (tiny model)',
|
|
278
|
+
},
|
|
279
|
+
|
|
280
|
+
ModelSize.SMALL: {
|
|
281
|
+
'models': ['qwen3:1.7b', 'llama3.2:3b', 'phi4-mini:3.8b'],
|
|
282
|
+
'thinking': ['qwen3:1.7b', 'deepseek-r1:1.5b'],
|
|
283
|
+
'tools': ['qwen3:1.7b', 'llama3.2:3b', 'granite3.1-dense:2b'],
|
|
284
|
+
'vision': ['llama3.2-vision:3b', 'moondream:1.8b', 'minicpm-v:3b'],
|
|
285
|
+
'quantization': 'q6_k',
|
|
286
|
+
'batch_size': 4,
|
|
287
|
+
'context': 16384,
|
|
288
|
+
'performance': 'Fast',
|
|
289
|
+
},
|
|
290
|
+
|
|
291
|
+
ModelSize.MEDIUM: {
|
|
292
|
+
'models': ['qwen3:8b', 'llama3.1:8b', 'mistral:7b', 'mistral-nemo:12b'],
|
|
293
|
+
'thinking': ['qwen3:8b', 'deepseek-r1:8b', 'cogito:8b', 'exaone-deep:7.8b'],
|
|
294
|
+
'tools': ['qwen3:8b', 'llama3.1:8b', 'mistral:7b', 'qwen2.5:7b',
|
|
295
|
+
'hermes3:8b', 'granite3.1-dense:8b'],
|
|
296
|
+
'vision': ['llava:7b', 'llama3.2-vision:11b', 'qwen2.5vl:7b',
|
|
297
|
+
'minicpm-v:8b', 'gemma3:12b', 'moondream:1.8b'],
|
|
298
|
+
'quantization': 'q4_k_m',
|
|
299
|
+
'batch_size': 2,
|
|
300
|
+
'context': 32768,
|
|
301
|
+
'performance': 'Fast',
|
|
302
|
+
},
|
|
303
|
+
|
|
304
|
+
ModelSize.LARGE: {
|
|
305
|
+
# M2 Max / M3 Pro 36-48 GB unified memory
|
|
306
|
+
'models': ['qwen3:14b', 'qwen3:32b', 'deepseek-r1:14b', 'command-r:35b'],
|
|
307
|
+
'thinking': ['qwen3:14b', 'qwen3:32b', 'deepseek-r1:14b', 'deepseek-r1:32b',
|
|
308
|
+
'qwq:32b', 'cogito:14b', 'phi4-reasoning:14b', 'exaone-deep:32b'],
|
|
309
|
+
'tools': ['qwen3:14b', 'qwen3:32b', 'command-r:35b', 'qwen2.5:32b',
|
|
310
|
+
'aya-expanse:32b', 'hermes3:8b'],
|
|
311
|
+
'vision': ['llava:34b', 'qwen2.5vl:14b', 'qwen2.5vl:32b',
|
|
312
|
+
'llama3.2-vision:11b', 'gemma3:27b', 'mistral-small3.1:22b'],
|
|
313
|
+
'quantization': 'q4_k_m',
|
|
314
|
+
'batch_size': 2,
|
|
315
|
+
'context': 65536,
|
|
316
|
+
'performance': 'Fast (Apple Silicon advantage)',
|
|
317
|
+
},
|
|
318
|
+
|
|
319
|
+
ModelSize.XLARGE: {
|
|
320
|
+
# M2 Ultra / M3 Max / M4 Max 64-192 GB unified memory
|
|
321
|
+
'models': ['llama3.3:70b', 'qwen2.5:72b', 'qwen3:30b-a3b', 'deepseek-r1:70b'],
|
|
322
|
+
'thinking': ['deepseek-r1:70b', 'qwen3:30b-a3b', 'cogito:70b',
|
|
323
|
+
'qwq:32b', 'exaone-deep:32b'],
|
|
324
|
+
'tools': ['llama3.3:70b', 'qwen2.5:72b', 'qwen3:30b-a3b',
|
|
325
|
+
'hermes3:70b', 'command-r-plus:104b', 'firefunction-v2:70b'],
|
|
326
|
+
'vision': ['llava:34b', 'qwen2.5vl:72b', 'llama3.2-vision:90b',
|
|
327
|
+
'gemma3:27b', 'mistral-small3.1:22b'],
|
|
328
|
+
'quantization': 'q4_k_m',
|
|
329
|
+
'batch_size': 4,
|
|
330
|
+
'context': 131072,
|
|
331
|
+
'performance': 'Fast (Apple Silicon advantage)',
|
|
332
|
+
},
|
|
333
|
+
},
|
|
334
|
+
|
|
335
|
+
# ==========================================================================
|
|
336
|
+
# CPU only - no GPU
|
|
337
|
+
# ==========================================================================
|
|
338
|
+
AcceleratorType.NONE: {
|
|
339
|
+
|
|
340
|
+
ModelSize.TINY: {
|
|
341
|
+
'models': ['qwen3:0.6b', 'llama3.2:1b', 'smollm2:1.7b'],
|
|
342
|
+
'thinking': ['deepseek-r1:1.5b', 'qwen3:0.6b'],
|
|
343
|
+
'tools': ['qwen3:0.6b', 'llama3.2:1b'],
|
|
344
|
+
'vision': ['moondream:1.8b'],
|
|
345
|
+
'quantization': 'q8_0',
|
|
346
|
+
'batch_size': 1,
|
|
347
|
+
'context': 4096,
|
|
348
|
+
'performance': 'Slow (CPU only)',
|
|
349
|
+
},
|
|
350
|
+
|
|
351
|
+
ModelSize.SMALL: {
|
|
352
|
+
'models': ['qwen3:1.7b', 'llama3.2:3b'],
|
|
353
|
+
'thinking': ['qwen3:1.7b', 'deepseek-r1:1.5b'],
|
|
354
|
+
'tools': ['qwen3:1.7b', 'llama3.2:3b'],
|
|
355
|
+
'vision': ['moondream:1.8b', 'minicpm-v:3b'],
|
|
356
|
+
'quantization': 'q4_k_m',
|
|
357
|
+
'batch_size': 1,
|
|
358
|
+
'context': 8192,
|
|
359
|
+
'performance': 'Very Slow (CPU only)',
|
|
360
|
+
},
|
|
361
|
+
|
|
362
|
+
ModelSize.MEDIUM: {
|
|
363
|
+
'models': ['qwen3:8b', 'mistral:7b', 'llama3.1:8b'],
|
|
364
|
+
'thinking': ['qwen3:8b', 'deepseek-r1:8b'],
|
|
365
|
+
'tools': ['qwen3:8b', 'mistral:7b', 'llama3.1:8b'],
|
|
366
|
+
'vision': ['llava:7b', 'qwen2.5vl:7b', 'minicpm-v:8b'],
|
|
367
|
+
'quantization': 'q4_k_m',
|
|
368
|
+
'batch_size': 1,
|
|
369
|
+
'context': 8192,
|
|
370
|
+
'performance': 'Very Slow (CPU only)',
|
|
371
|
+
},
|
|
372
|
+
|
|
373
|
+
# LARGE / XLARGE on CPU-only is impractical - fallback handled in ModelRecommender
|
|
374
|
+
},
|
|
375
|
+
}
|
|
376
|
+
|
|
377
|
+
|
|
378
|
+
# ---------------------------------------------------------------------------
|
|
379
|
+
# Helpers - consumed by ModelInfo and the model recommender
|
|
380
|
+
# ---------------------------------------------------------------------------
|
|
381
|
+
|
|
382
|
+
# All categories present in any tier entry. Add new ones here as they are added
|
|
383
|
+
# to the database so get_category() degrades gracefully for old entries.
|
|
384
|
+
KNOWN_CATEGORIES: List[str] = ['models', 'thinking', 'tools', 'vision']
|
|
385
|
+
|
|
386
|
+
# Tier fallback order when the exact tier has no entry for an accelerator
|
|
387
|
+
TIER_FALLBACK_ORDER: List[ModelSize] = [
|
|
388
|
+
ModelSize.LARGE,
|
|
389
|
+
ModelSize.MEDIUM,
|
|
390
|
+
ModelSize.SMALL,
|
|
391
|
+
ModelSize.TINY,
|
|
392
|
+
]
|
|
393
|
+
|
|
394
|
+
|
|
395
|
+
def get_tier(accelerator: AcceleratorType, size: ModelSize) -> TierEntry:
|
|
396
|
+
"""
|
|
397
|
+
Return the tier entry for an accelerator + memory size combination.
|
|
398
|
+
|
|
399
|
+
Walks down TIER_FALLBACK_ORDER if the exact size is missing, then
|
|
400
|
+
falls back to CPU MEDIUM as a last resort.
|
|
401
|
+
|
|
402
|
+
Args:
|
|
403
|
+
accelerator: The detected primary accelerator.
|
|
404
|
+
size: The memory-based model size tier.
|
|
405
|
+
|
|
406
|
+
Returns:
|
|
407
|
+
TierEntry dict ready for ModelRecommendation construction.
|
|
408
|
+
"""
|
|
409
|
+
db = MODEL_DATABASE.get(accelerator, {})
|
|
410
|
+
entry = db.get(size)
|
|
411
|
+
|
|
412
|
+
if entry is None:
|
|
413
|
+
for fallback in TIER_FALLBACK_ORDER:
|
|
414
|
+
entry = db.get(fallback)
|
|
415
|
+
if entry is not None:
|
|
416
|
+
break
|
|
417
|
+
|
|
418
|
+
if entry is None:
|
|
419
|
+
entry = MODEL_DATABASE[AcceleratorType.NONE][ModelSize.MEDIUM]
|
|
420
|
+
|
|
421
|
+
return entry
|
|
422
|
+
|
|
423
|
+
|
|
424
|
+
def get_category(tier: TierEntry, category: str) -> List[str]:
|
|
425
|
+
"""
|
|
426
|
+
Safely retrieve a model list for a given category from a tier entry.
|
|
427
|
+
|
|
428
|
+
Returns an empty list if the category is not present, so callers never
|
|
429
|
+
need to guard against missing keys when new categories are added.
|
|
430
|
+
|
|
431
|
+
Args:
|
|
432
|
+
tier: A tier entry dict from MODEL_DATABASE.
|
|
433
|
+
category: Category name, e.g. 'vision', 'tools', 'thinking'.
|
|
434
|
+
|
|
435
|
+
Returns:
|
|
436
|
+
List of model name strings.
|
|
437
|
+
"""
|
|
438
|
+
return tier.get(category, [])
|
|
@@ -0,0 +1,68 @@
|
|
|
1
|
+
"""Typed view over the model catalog."""
|
|
2
|
+
|
|
3
|
+
from dataclasses import dataclass, field
|
|
4
|
+
from typing import Dict, List, Optional, Union
|
|
5
|
+
|
|
6
|
+
from ..types import AcceleratorType, ModelSize
|
|
7
|
+
from .catalog import KNOWN_CATEGORIES, MODEL_DATABASE, TierEntry, get_category, get_tier
|
|
8
|
+
|
|
9
|
+
|
|
10
|
+
@dataclass(frozen=True)
|
|
11
|
+
class ModelInfo:
|
|
12
|
+
"""Catalog entry for one accelerator + memory tier."""
|
|
13
|
+
|
|
14
|
+
accelerator: AcceleratorType
|
|
15
|
+
size: ModelSize
|
|
16
|
+
categories: Dict[str, List[str]] = field(default_factory=dict)
|
|
17
|
+
quantization: str = ""
|
|
18
|
+
batch_size: int = 1
|
|
19
|
+
context: int = 0
|
|
20
|
+
performance: str = ""
|
|
21
|
+
|
|
22
|
+
@classmethod
|
|
23
|
+
def from_entry(
|
|
24
|
+
cls, accelerator: AcceleratorType, size: ModelSize, entry: TierEntry
|
|
25
|
+
) -> "ModelInfo":
|
|
26
|
+
return cls(
|
|
27
|
+
accelerator=accelerator,
|
|
28
|
+
size=size,
|
|
29
|
+
categories={c: list(get_category(entry, c)) for c in KNOWN_CATEGORIES},
|
|
30
|
+
quantization=str(entry.get("quantization", "")),
|
|
31
|
+
batch_size=int(entry.get("batch_size", 1)),
|
|
32
|
+
context=int(entry.get("context", 0)),
|
|
33
|
+
performance=str(entry.get("performance", "")),
|
|
34
|
+
)
|
|
35
|
+
|
|
36
|
+
def get(self, category: str) -> List[str]:
|
|
37
|
+
return list(self.categories.get(category, []))
|
|
38
|
+
|
|
39
|
+
def to_dict(self) -> dict:
|
|
40
|
+
return {
|
|
41
|
+
"accelerator": self.accelerator.value,
|
|
42
|
+
"size": self.size.value,
|
|
43
|
+
"categories": {k: list(v) for k, v in self.categories.items()},
|
|
44
|
+
"quantization": self.quantization,
|
|
45
|
+
"batch_size": self.batch_size,
|
|
46
|
+
"context": self.context,
|
|
47
|
+
"performance": self.performance,
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
|
|
51
|
+
def get_model_info(
|
|
52
|
+
accelerator: Optional[AcceleratorType] = None,
|
|
53
|
+
size: Optional[ModelSize] = None,
|
|
54
|
+
) -> Union[ModelInfo, List[ModelInfo]]:
|
|
55
|
+
"""Return one ModelInfo when both arguments are given, else all matching entries.
|
|
56
|
+
|
|
57
|
+
A single lookup uses get_tier() and so applies its fallback rules.
|
|
58
|
+
"""
|
|
59
|
+
if accelerator is not None and size is not None:
|
|
60
|
+
return ModelInfo.from_entry(accelerator, size, get_tier(accelerator, size))
|
|
61
|
+
|
|
62
|
+
return [
|
|
63
|
+
ModelInfo.from_entry(acc, sz, entry)
|
|
64
|
+
for acc, tiers in MODEL_DATABASE.items()
|
|
65
|
+
if accelerator is None or acc == accelerator
|
|
66
|
+
for sz, entry in tiers.items()
|
|
67
|
+
if size is None or sz == size
|
|
68
|
+
]
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
from enum import Enum
|
|
2
|
+
|
|
3
|
+
|
|
4
|
+
class AcceleratorType(Enum):
|
|
5
|
+
NONE = "none"
|
|
6
|
+
NVIDIA_CUDA = "nvidia_cuda"
|
|
7
|
+
NVIDIA_MPS = "nvidia_mps"
|
|
8
|
+
AMD_ROCM = "amd_rocm"
|
|
9
|
+
INTEL_ONEAPI = "intel_oneapi"
|
|
10
|
+
APPLE_METAL = "apple_metal"
|
|
11
|
+
QUALCOMM_HEXAGON = "qualcomm_hexagon"
|
|
12
|
+
|
|
13
|
+
|
|
14
|
+
class ModelSize(Enum):
|
|
15
|
+
TINY = "tiny"
|
|
16
|
+
SMALL = "small"
|
|
17
|
+
MEDIUM = "medium"
|
|
18
|
+
LARGE = "large"
|
|
19
|
+
XLARGE = "xlarge"
|
|
@@ -0,0 +1,68 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: hestia-system
|
|
3
|
+
Version: 0.1.0
|
|
4
|
+
Summary: System discovery, hardware and software analysis, and AI model recommendations.
|
|
5
|
+
Author: Damon S. Green II (nomadiidamon)
|
|
6
|
+
License: MIT
|
|
7
|
+
Project-URL: Homepage, https://github.com/nomadiidamon/Hestia
|
|
8
|
+
Requires-Python: >=3.10
|
|
9
|
+
Description-Content-Type: text/markdown
|
|
10
|
+
Requires-Dist: psutil>=5.9.0
|
|
11
|
+
Provides-Extra: nvidia
|
|
12
|
+
Requires-Dist: nvidia-ml-py>=12.0.0; extra == "nvidia"
|
|
13
|
+
Provides-Extra: dev
|
|
14
|
+
Requires-Dist: pytest>=7.0; extra == "dev"
|
|
15
|
+
Dynamic: author
|
|
16
|
+
Dynamic: description
|
|
17
|
+
Dynamic: description-content-type
|
|
18
|
+
Dynamic: license
|
|
19
|
+
Dynamic: project-url
|
|
20
|
+
Dynamic: requires-python
|
|
21
|
+
Dynamic: summary
|
|
22
|
+
|
|
23
|
+
# Hestia for Python
|
|
24
|
+
|
|
25
|
+
Hestia provides system discovery and AI model intelligence. The Python package
|
|
26
|
+
currently exposes accelerator and model-size types, a model catalog, and model
|
|
27
|
+
information lookup.
|
|
28
|
+
|
|
29
|
+
The distribution is named `hestia-system`; import it as `Hestia`.
|
|
30
|
+
|
|
31
|
+
## Installation
|
|
32
|
+
|
|
33
|
+
```bash
|
|
34
|
+
python -m pip install hestia-system
|
|
35
|
+
```
|
|
36
|
+
|
|
37
|
+
Optional dependencies are available as extras:
|
|
38
|
+
|
|
39
|
+
```bash
|
|
40
|
+
python -m pip install "hestia-system[nvidia]" # NVIDIA telemetry support
|
|
41
|
+
python -m pip install "hestia-system[dev]" # pytest
|
|
42
|
+
```
|
|
43
|
+
|
|
44
|
+
## Usage
|
|
45
|
+
|
|
46
|
+
```python
|
|
47
|
+
from Hestia import AcceleratorType, ModelSize, get_model_info
|
|
48
|
+
|
|
49
|
+
info = get_model_info(AcceleratorType.NVIDIA_CUDA, ModelSize.SMALL)
|
|
50
|
+
print(info)
|
|
51
|
+
```
|
|
52
|
+
|
|
53
|
+
The package supports Python versions declared by the project metadata (Python
|
|
54
|
+
3.10 and later).
|
|
55
|
+
|
|
56
|
+
## Development
|
|
57
|
+
|
|
58
|
+
From the repository checkout:
|
|
59
|
+
|
|
60
|
+
```bash
|
|
61
|
+
cd python
|
|
62
|
+
python -m pip install -e ".[dev]"
|
|
63
|
+
python -m pytest
|
|
64
|
+
```
|
|
65
|
+
|
|
66
|
+
Package metadata is maintained in the repository's `project.ini`. Source
|
|
67
|
+
distributions include a copy of that file so they can be built independently
|
|
68
|
+
of the repository checkout.
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
MANIFEST.in
|
|
2
|
+
README.md
|
|
3
|
+
project.ini
|
|
4
|
+
pyproject.toml
|
|
5
|
+
setup.py
|
|
6
|
+
src/Hestia/__init__.py
|
|
7
|
+
src/Hestia/model_catalog.py
|
|
8
|
+
src/Hestia/types.py
|
|
9
|
+
src/Hestia/models/__init__.py
|
|
10
|
+
src/Hestia/models/catalog.py
|
|
11
|
+
src/Hestia/models/info.py
|
|
12
|
+
src/hestia_system.egg-info/PKG-INFO
|
|
13
|
+
src/hestia_system.egg-info/SOURCES.txt
|
|
14
|
+
src/hestia_system.egg-info/dependency_links.txt
|
|
15
|
+
src/hestia_system.egg-info/requires.txt
|
|
16
|
+
src/hestia_system.egg-info/top_level.txt
|
|
17
|
+
tests/test_examples.py
|
|
18
|
+
tests/test_models.py
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
Hestia
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
"""Run every example script and require a clean exit."""
|
|
2
|
+
|
|
3
|
+
import os
|
|
4
|
+
import subprocess
|
|
5
|
+
import sys
|
|
6
|
+
from pathlib import Path
|
|
7
|
+
|
|
8
|
+
import pytest
|
|
9
|
+
|
|
10
|
+
ROOT = Path(__file__).resolve().parents[2]
|
|
11
|
+
SRC = ROOT / "python" / "src"
|
|
12
|
+
EXAMPLES = sorted((ROOT / "examples" / "python").rglob("*.py"))
|
|
13
|
+
|
|
14
|
+
|
|
15
|
+
@pytest.mark.parametrize("example", EXAMPLES, ids=lambda p: p.relative_to(ROOT).as_posix())
|
|
16
|
+
def test_example_runs(example):
|
|
17
|
+
env = {**os.environ, "PYTHONPATH": os.pathsep.join([str(SRC), os.environ.get("PYTHONPATH", "")])}
|
|
18
|
+
result = subprocess.run(
|
|
19
|
+
[sys.executable, str(example)], capture_output=True, text=True, timeout=60, env=env
|
|
20
|
+
)
|
|
21
|
+
assert result.returncode == 0, result.stderr
|
|
@@ -0,0 +1,75 @@
|
|
|
1
|
+
import os
|
|
2
|
+
import subprocess
|
|
3
|
+
import sys
|
|
4
|
+
|
|
5
|
+
import pytest
|
|
6
|
+
|
|
7
|
+
import Hestia
|
|
8
|
+
from Hestia.models import (
|
|
9
|
+
KNOWN_CATEGORIES,
|
|
10
|
+
MODEL_DATABASE,
|
|
11
|
+
ModelInfo,
|
|
12
|
+
get_category,
|
|
13
|
+
get_model_info,
|
|
14
|
+
get_tier,
|
|
15
|
+
)
|
|
16
|
+
from Hestia.types import AcceleratorType, ModelSize
|
|
17
|
+
|
|
18
|
+
|
|
19
|
+
def test_enum_values():
|
|
20
|
+
assert AcceleratorType("nvidia_cuda") is AcceleratorType.NVIDIA_CUDA
|
|
21
|
+
assert [s.value for s in ModelSize] == ["tiny", "small", "medium", "large", "xlarge"]
|
|
22
|
+
|
|
23
|
+
|
|
24
|
+
def test_every_entry_has_required_keys():
|
|
25
|
+
for tiers in MODEL_DATABASE.values():
|
|
26
|
+
for entry in tiers.values():
|
|
27
|
+
for key in (*KNOWN_CATEGORIES, "quantization", "batch_size", "context", "performance"):
|
|
28
|
+
assert key in entry
|
|
29
|
+
|
|
30
|
+
|
|
31
|
+
@pytest.mark.parametrize("acc", list(MODEL_DATABASE))
|
|
32
|
+
@pytest.mark.parametrize("size", list(ModelSize))
|
|
33
|
+
def test_get_tier_always_resolves(acc, size):
|
|
34
|
+
assert get_tier(acc, size)["models"]
|
|
35
|
+
|
|
36
|
+
|
|
37
|
+
def test_fallback_for_missing_tier():
|
|
38
|
+
assert get_tier(AcceleratorType.INTEL_ONEAPI, ModelSize.XLARGE) is MODEL_DATABASE[
|
|
39
|
+
AcceleratorType.INTEL_ONEAPI
|
|
40
|
+
][ModelSize.LARGE]
|
|
41
|
+
|
|
42
|
+
|
|
43
|
+
def test_unknown_accelerator_falls_back_to_cpu():
|
|
44
|
+
entry = get_tier(AcceleratorType.QUALCOMM_HEXAGON, ModelSize.TINY)
|
|
45
|
+
assert entry is MODEL_DATABASE[AcceleratorType.NONE][ModelSize.MEDIUM]
|
|
46
|
+
|
|
47
|
+
|
|
48
|
+
def test_get_category_unknown_is_empty():
|
|
49
|
+
assert get_category(get_tier(AcceleratorType.NONE, ModelSize.TINY), "nope") == []
|
|
50
|
+
|
|
51
|
+
|
|
52
|
+
def test_get_model_info_single_and_all():
|
|
53
|
+
info = get_model_info(AcceleratorType.NVIDIA_CUDA, ModelSize.SMALL)
|
|
54
|
+
assert isinstance(info, ModelInfo)
|
|
55
|
+
assert info.to_dict()["accelerator"] == "nvidia_cuda"
|
|
56
|
+
assert info.get("tools")
|
|
57
|
+
total = sum(len(t) for t in MODEL_DATABASE.values())
|
|
58
|
+
assert len(get_model_info()) == total
|
|
59
|
+
assert all(i.size is ModelSize.TINY for i in get_model_info(size=ModelSize.TINY))
|
|
60
|
+
|
|
61
|
+
|
|
62
|
+
def test_legacy_import_path():
|
|
63
|
+
from Hestia.model_catalog import MODEL_DATABASE as legacy
|
|
64
|
+
|
|
65
|
+
assert legacy is MODEL_DATABASE
|
|
66
|
+
|
|
67
|
+
|
|
68
|
+
def test_public_api():
|
|
69
|
+
assert Hestia.get_model_info is get_model_info
|
|
70
|
+
|
|
71
|
+
|
|
72
|
+
def test_models_does_not_import_hardware():
|
|
73
|
+
code = "import sys, Hestia.models; assert not any(m.startswith('Hestia.hardware') for m in sys.modules)"
|
|
74
|
+
env = {**os.environ, "PYTHONPATH": os.pathsep.join(sys.path)}
|
|
75
|
+
subprocess.run([sys.executable, "-c", code], check=True, env=env)
|