lmms-builder 1.0.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.
- lmms_builder/__init__.py +3 -0
- lmms_builder/autoset.py +87 -0
- lmms_builder/bootstrap.py +50 -0
- lmms_builder/cli.py +104 -0
- lmms_builder/hardware.py +88 -0
- lmms_builder/installer.py +137 -0
- lmms_builder/reporter.py +93 -0
- lmms_builder-1.0.0.dist-info/METADATA +11 -0
- lmms_builder-1.0.0.dist-info/RECORD +12 -0
- lmms_builder-1.0.0.dist-info/WHEEL +5 -0
- lmms_builder-1.0.0.dist-info/entry_points.txt +2 -0
- lmms_builder-1.0.0.dist-info/top_level.txt +1 -0
lmms_builder/__init__.py
ADDED
lmms_builder/autoset.py
ADDED
|
@@ -0,0 +1,87 @@
|
|
|
1
|
+
import json
|
|
2
|
+
from pathlib import Path
|
|
3
|
+
|
|
4
|
+
from . import hardware
|
|
5
|
+
from . import bootstrap
|
|
6
|
+
from . import installer
|
|
7
|
+
from . import reporter
|
|
8
|
+
|
|
9
|
+
def write_default_config(lmms_dir, mode="engine"):
|
|
10
|
+
config_dir = lmms_dir / "config"
|
|
11
|
+
config_dir.mkdir(parents=True, exist_ok=True)
|
|
12
|
+
config_file = config_dir / "config.json"
|
|
13
|
+
|
|
14
|
+
config = {}
|
|
15
|
+
if config_file.exists():
|
|
16
|
+
try:
|
|
17
|
+
with open(config_file, "r") as f:
|
|
18
|
+
config = json.load(f)
|
|
19
|
+
except Exception:
|
|
20
|
+
pass
|
|
21
|
+
|
|
22
|
+
config["default_mode"] = mode
|
|
23
|
+
|
|
24
|
+
with open(config_file, "w") as f:
|
|
25
|
+
json.dump(config, f, indent=4)
|
|
26
|
+
|
|
27
|
+
def determine_default_runtime(hw):
|
|
28
|
+
if hw['gpu']['detected'] and hw['gpu']['vram_gb'] >= 4:
|
|
29
|
+
return "llama.cpp"
|
|
30
|
+
return "ollama"
|
|
31
|
+
|
|
32
|
+
def recommend_model(hw):
|
|
33
|
+
ram = hw['ram']['total_gb']
|
|
34
|
+
vram = hw['gpu']['vram_gb'] if hw['gpu']['detected'] else 0
|
|
35
|
+
|
|
36
|
+
if vram >= 16 or (ram >= 32 and vram == 0):
|
|
37
|
+
return "Qwen2.5-Coder-7B or Llama3.2-8B"
|
|
38
|
+
elif vram >= 8 or (ram >= 16 and vram == 0):
|
|
39
|
+
return "Qwen2.5-Coder-3B or Gemma3-4B"
|
|
40
|
+
else:
|
|
41
|
+
return "Qwen2.5-1.5B or Llama-3.2-1B"
|
|
42
|
+
|
|
43
|
+
def run_autoset(components):
|
|
44
|
+
reporter.print_header()
|
|
45
|
+
|
|
46
|
+
reporter.print_step("Detecting Hardware...")
|
|
47
|
+
hw = hardware.detect_all()
|
|
48
|
+
reporter.print_hardware_report(hw)
|
|
49
|
+
|
|
50
|
+
recommended = recommend_model(hw)
|
|
51
|
+
reporter.print_step(f"Based on hardware, recommended model: {recommended}")
|
|
52
|
+
|
|
53
|
+
reporter.print_step("Evaluating Compatibility...")
|
|
54
|
+
reporter.print_compatibility_report(hw)
|
|
55
|
+
|
|
56
|
+
reporter.print_step("Validating Python Environment...")
|
|
57
|
+
if not installer.check_python_version():
|
|
58
|
+
reporter.print_error("Python >= 3.9 required.")
|
|
59
|
+
return False
|
|
60
|
+
|
|
61
|
+
reporter.print_step("Ensuring core Python build tools...")
|
|
62
|
+
installer.ensure_base_tools()
|
|
63
|
+
|
|
64
|
+
reporter.print_step("Bootstrapping ~/.lmms directory structure...")
|
|
65
|
+
lmms_dir = bootstrap.run_bootstrap()
|
|
66
|
+
|
|
67
|
+
reporter.print_step("Installing requested components...")
|
|
68
|
+
|
|
69
|
+
# components is a dict: {"all": bool, "engine": bool, ...}
|
|
70
|
+
# Loop over the keys. If 'all' is true, install all. Otherwise, install selected.
|
|
71
|
+
comps_to_install = ["engine", "gui", "cli", "backend", "air"]
|
|
72
|
+
|
|
73
|
+
for comp in comps_to_install:
|
|
74
|
+
if components.get("all") or components.get(comp):
|
|
75
|
+
installer.install_component(comp)
|
|
76
|
+
|
|
77
|
+
reporter.print_step("Determining optimal runtime...")
|
|
78
|
+
runtime = determine_default_runtime(hw)
|
|
79
|
+
|
|
80
|
+
reporter.print_step("Writing configuration...")
|
|
81
|
+
# Default to engine. If user specifically installed GUI or CLI, we could change this,
|
|
82
|
+
# but the plan specified setting default mode to engine for now.
|
|
83
|
+
mode = "engine"
|
|
84
|
+
write_default_config(lmms_dir, mode)
|
|
85
|
+
|
|
86
|
+
reporter.print_autoset_summary(mode, runtime)
|
|
87
|
+
return True
|
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
import os
|
|
2
|
+
from pathlib import Path
|
|
3
|
+
|
|
4
|
+
def setup_directory_structure():
|
|
5
|
+
home = Path.home()
|
|
6
|
+
lmms_dir = home / ".lmms"
|
|
7
|
+
|
|
8
|
+
dirs_to_create = [
|
|
9
|
+
lmms_dir,
|
|
10
|
+
lmms_dir / "models",
|
|
11
|
+
lmms_dir / "memory",
|
|
12
|
+
lmms_dir / "cache",
|
|
13
|
+
lmms_dir / "logs",
|
|
14
|
+
lmms_dir / "workspaces",
|
|
15
|
+
lmms_dir / "tasks",
|
|
16
|
+
lmms_dir / "agents",
|
|
17
|
+
lmms_dir / "runtime",
|
|
18
|
+
lmms_dir / "git",
|
|
19
|
+
lmms_dir / "db",
|
|
20
|
+
lmms_dir / "config",
|
|
21
|
+
]
|
|
22
|
+
|
|
23
|
+
for d in dirs_to_create:
|
|
24
|
+
d.mkdir(parents=True, exist_ok=True)
|
|
25
|
+
|
|
26
|
+
return lmms_dir
|
|
27
|
+
|
|
28
|
+
def initialize_databases(lmms_dir):
|
|
29
|
+
db_dir = lmms_dir / "db"
|
|
30
|
+
|
|
31
|
+
db_files = [
|
|
32
|
+
"workspace.db",
|
|
33
|
+
"memory.db",
|
|
34
|
+
"action_ledger.db",
|
|
35
|
+
"task.db"
|
|
36
|
+
]
|
|
37
|
+
|
|
38
|
+
for db_file in db_files:
|
|
39
|
+
(db_dir / db_file).touch(exist_ok=True)
|
|
40
|
+
|
|
41
|
+
def create_default_workspace(lmms_dir):
|
|
42
|
+
ws_dir = lmms_dir / "workspaces" / "default"
|
|
43
|
+
ws_dir.mkdir(parents=True, exist_ok=True)
|
|
44
|
+
return ws_dir
|
|
45
|
+
|
|
46
|
+
def run_bootstrap():
|
|
47
|
+
lmms_dir = setup_directory_structure()
|
|
48
|
+
initialize_databases(lmms_dir)
|
|
49
|
+
create_default_workspace(lmms_dir)
|
|
50
|
+
return lmms_dir
|
lmms_builder/cli.py
ADDED
|
@@ -0,0 +1,104 @@
|
|
|
1
|
+
import argparse
|
|
2
|
+
import sys
|
|
3
|
+
|
|
4
|
+
from . import hardware
|
|
5
|
+
from . import autoset
|
|
6
|
+
from . import reporter
|
|
7
|
+
|
|
8
|
+
def main():
|
|
9
|
+
parser = argparse.ArgumentParser(prog="lmms-builder", description="Bootstrapper for LMMs OS")
|
|
10
|
+
parser.add_argument("--autoset", action="store_true", help="Run the fully automated install workflow")
|
|
11
|
+
|
|
12
|
+
# Root level autoset sub-flags
|
|
13
|
+
parser.add_argument("--all", action="store_true", help="Install all components")
|
|
14
|
+
parser.add_argument("--engine", action="store_true", help="Install the core Engine")
|
|
15
|
+
parser.add_argument("--gui", action="store_true", help="Install the GUI")
|
|
16
|
+
parser.add_argument("--cli", action="store_true", help="Install the Smart CLI")
|
|
17
|
+
parser.add_argument("--backend", action="store_true", help="Install the Backend Servers")
|
|
18
|
+
parser.add_argument("--air", action="store_true", help="Install the Air Engine")
|
|
19
|
+
|
|
20
|
+
# Maintenance Commands
|
|
21
|
+
parser.add_argument("--repair", action="store_true", help="Check and repair LMMs installation")
|
|
22
|
+
parser.add_argument("--rebuild", action="store_true", help="Rebuild indexes and caches")
|
|
23
|
+
parser.add_argument("--factory-reset", action="store_true", help="Reset entire LMMs environment")
|
|
24
|
+
|
|
25
|
+
subparsers = parser.add_subparsers(dest="command", help="Available commands")
|
|
26
|
+
subparsers.add_parser("detect", help="Detect hardware and software specs")
|
|
27
|
+
subparsers.add_parser("compatibility", help="Show compatibility report")
|
|
28
|
+
subparsers.add_parser("doctor", help="Check missing dependencies")
|
|
29
|
+
subparsers.add_parser("benchmark", help="Estimate hardware performance")
|
|
30
|
+
|
|
31
|
+
# Support 'autoset' as a subcommand too for convenience
|
|
32
|
+
autoset_parser = subparsers.add_parser("autoset", help="Run the fully automated install workflow")
|
|
33
|
+
autoset_parser.add_argument("--all", action="store_true")
|
|
34
|
+
autoset_parser.add_argument("--engine", action="store_true")
|
|
35
|
+
autoset_parser.add_argument("--gui", action="store_true")
|
|
36
|
+
autoset_parser.add_argument("--cli", action="store_true")
|
|
37
|
+
autoset_parser.add_argument("--backend", action="store_true")
|
|
38
|
+
autoset_parser.add_argument("--air", action="store_true")
|
|
39
|
+
|
|
40
|
+
args = parser.parse_args()
|
|
41
|
+
|
|
42
|
+
if args.repair:
|
|
43
|
+
reporter.print_step("Running Installation Repair...")
|
|
44
|
+
reporter.print_error("Repair Module: Coming Soon.")
|
|
45
|
+
return
|
|
46
|
+
|
|
47
|
+
if args.rebuild:
|
|
48
|
+
reporter.print_step("Rebuilding Caches & Indexes...")
|
|
49
|
+
reporter.print_error("Rebuild Module: Coming Soon.")
|
|
50
|
+
return
|
|
51
|
+
|
|
52
|
+
if args.factory_reset:
|
|
53
|
+
reporter.print_step("Factory Resetting LMMs Environment...")
|
|
54
|
+
reporter.print_error("Factory Reset Module: Coming Soon.")
|
|
55
|
+
return
|
|
56
|
+
|
|
57
|
+
# Gather components to install
|
|
58
|
+
components = {
|
|
59
|
+
"all": args.all,
|
|
60
|
+
"engine": args.engine,
|
|
61
|
+
"gui": args.gui,
|
|
62
|
+
"cli": args.cli,
|
|
63
|
+
"backend": args.backend,
|
|
64
|
+
"air": args.air
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
if args.autoset or args.command == "autoset":
|
|
68
|
+
# If no flags passed, assume 'all' for standard autoset behavior
|
|
69
|
+
if not any(components.values()):
|
|
70
|
+
components["all"] = True
|
|
71
|
+
autoset.run_autoset(components)
|
|
72
|
+
return
|
|
73
|
+
|
|
74
|
+
if args.command == "detect":
|
|
75
|
+
hw = hardware.detect_all()
|
|
76
|
+
reporter.print_hardware_report(hw)
|
|
77
|
+
|
|
78
|
+
elif args.command == "compatibility":
|
|
79
|
+
hw = hardware.detect_all()
|
|
80
|
+
reporter.print_compatibility_report(hw)
|
|
81
|
+
|
|
82
|
+
elif args.command == "benchmark":
|
|
83
|
+
hw = hardware.detect_all()
|
|
84
|
+
reporter.print_benchmark_estimate(hw)
|
|
85
|
+
|
|
86
|
+
elif args.command == "doctor":
|
|
87
|
+
hw = hardware.detect_all()
|
|
88
|
+
reporter.print_step("Running LMMs Builder Doctor...")
|
|
89
|
+
reporter.print_hardware_report(hw)
|
|
90
|
+
if hw['os']['system'] not in ['Linux', 'Windows', 'Darwin']:
|
|
91
|
+
reporter.print_error("Unsupported OS detected.")
|
|
92
|
+
else:
|
|
93
|
+
reporter.print_success("OS Supported.")
|
|
94
|
+
|
|
95
|
+
if hw['ram']['total_gb'] < 8:
|
|
96
|
+
reporter.print_error("LMMs requires at least 8GB of RAM.")
|
|
97
|
+
else:
|
|
98
|
+
reporter.print_success("Sufficient RAM detected.")
|
|
99
|
+
|
|
100
|
+
else:
|
|
101
|
+
parser.print_help()
|
|
102
|
+
|
|
103
|
+
if __name__ == "__main__":
|
|
104
|
+
main()
|
lmms_builder/hardware.py
ADDED
|
@@ -0,0 +1,88 @@
|
|
|
1
|
+
import os
|
|
2
|
+
import platform
|
|
3
|
+
import psutil
|
|
4
|
+
import subprocess
|
|
5
|
+
|
|
6
|
+
def detect_os():
|
|
7
|
+
return {
|
|
8
|
+
"system": platform.system(),
|
|
9
|
+
"release": platform.release(),
|
|
10
|
+
"architecture": platform.machine(),
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
def detect_cpu():
|
|
14
|
+
return {
|
|
15
|
+
"cores": psutil.cpu_count(logical=False),
|
|
16
|
+
"threads": psutil.cpu_count(logical=True),
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
def detect_ram():
|
|
20
|
+
mem = psutil.virtual_memory()
|
|
21
|
+
return {
|
|
22
|
+
"total_gb": round(mem.total / (1024**3), 2),
|
|
23
|
+
"available_gb": round(mem.available / (1024**3), 2)
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
def detect_gpu():
|
|
27
|
+
try:
|
|
28
|
+
# Check nvidia-smi
|
|
29
|
+
result = subprocess.run(
|
|
30
|
+
["nvidia-smi", "--query-gpu=name,memory.total", "--format=csv,noheader"],
|
|
31
|
+
capture_output=True, text=True, check=True
|
|
32
|
+
)
|
|
33
|
+
lines = result.stdout.strip().split("\n")
|
|
34
|
+
if lines and lines[0]:
|
|
35
|
+
parts = lines[0].split(",")
|
|
36
|
+
name = parts[0].strip()
|
|
37
|
+
vram_str = parts[1].strip()
|
|
38
|
+
vram_mb = int(vram_str.replace(" MiB", ""))
|
|
39
|
+
return {
|
|
40
|
+
"detected": True,
|
|
41
|
+
"name": name,
|
|
42
|
+
"vram_gb": round(vram_mb / 1024, 2),
|
|
43
|
+
"type": "nvidia"
|
|
44
|
+
}
|
|
45
|
+
except (FileNotFoundError, subprocess.CalledProcessError):
|
|
46
|
+
pass
|
|
47
|
+
|
|
48
|
+
return {
|
|
49
|
+
"detected": False,
|
|
50
|
+
"name": "None",
|
|
51
|
+
"vram_gb": 0.0,
|
|
52
|
+
"type": "none"
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
def detect_cuda():
|
|
56
|
+
try:
|
|
57
|
+
result = subprocess.run(["nvcc", "--version"], capture_output=True, text=True, check=True)
|
|
58
|
+
for line in result.stdout.split("\n"):
|
|
59
|
+
if "release" in line:
|
|
60
|
+
version = line.split("release")[1].strip().split(",")[0]
|
|
61
|
+
return {"available": True, "version": version}
|
|
62
|
+
except (FileNotFoundError, subprocess.CalledProcessError):
|
|
63
|
+
pass
|
|
64
|
+
|
|
65
|
+
try:
|
|
66
|
+
result = subprocess.run(["nvidia-smi"], capture_output=True, text=True, check=True)
|
|
67
|
+
if "CUDA Version: " in result.stdout:
|
|
68
|
+
version = result.stdout.split("CUDA Version: ")[1].split(" ")[0]
|
|
69
|
+
return {"available": True, "version": version}
|
|
70
|
+
except (FileNotFoundError, subprocess.CalledProcessError):
|
|
71
|
+
pass
|
|
72
|
+
|
|
73
|
+
return {"available": False, "version": None}
|
|
74
|
+
|
|
75
|
+
def detect_python():
|
|
76
|
+
return {
|
|
77
|
+
"version": platform.python_version()
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
def detect_all():
|
|
81
|
+
return {
|
|
82
|
+
"os": detect_os(),
|
|
83
|
+
"cpu": detect_cpu(),
|
|
84
|
+
"ram": detect_ram(),
|
|
85
|
+
"gpu": detect_gpu(),
|
|
86
|
+
"cuda": detect_cuda(),
|
|
87
|
+
"python": detect_python()
|
|
88
|
+
}
|
|
@@ -0,0 +1,137 @@
|
|
|
1
|
+
import subprocess
|
|
2
|
+
import sys
|
|
3
|
+
import json
|
|
4
|
+
import os
|
|
5
|
+
import platform
|
|
6
|
+
import requests
|
|
7
|
+
from pathlib import Path
|
|
8
|
+
from rich.progress import Progress, TextColumn, BarColumn, DownloadColumn, TransferSpeedColumn, TimeRemainingColumn
|
|
9
|
+
from . import reporter
|
|
10
|
+
|
|
11
|
+
def check_python_version():
|
|
12
|
+
return sys.version_info >= (3, 9)
|
|
13
|
+
|
|
14
|
+
def ensure_base_tools():
|
|
15
|
+
# Only useful if we still use pip for other components
|
|
16
|
+
return True
|
|
17
|
+
|
|
18
|
+
def get_registry_path():
|
|
19
|
+
p = Path(os.path.expanduser("~/.lmms/config/installed_components.json"))
|
|
20
|
+
p.parent.mkdir(parents=True, exist_ok=True)
|
|
21
|
+
return p
|
|
22
|
+
|
|
23
|
+
def get_installed_components():
|
|
24
|
+
reg = get_registry_path()
|
|
25
|
+
if reg.exists():
|
|
26
|
+
try:
|
|
27
|
+
with open(reg, "r") as f:
|
|
28
|
+
return json.load(f)
|
|
29
|
+
except:
|
|
30
|
+
pass
|
|
31
|
+
return {}
|
|
32
|
+
|
|
33
|
+
def mark_installed(component):
|
|
34
|
+
installed = get_installed_components()
|
|
35
|
+
installed[component] = True
|
|
36
|
+
with open(get_registry_path(), "w") as f:
|
|
37
|
+
json.dump(installed, f)
|
|
38
|
+
|
|
39
|
+
def download_engine_binary():
|
|
40
|
+
# Detect OS
|
|
41
|
+
system = platform.system().lower()
|
|
42
|
+
machine = platform.machine().lower()
|
|
43
|
+
|
|
44
|
+
# Construct binary name
|
|
45
|
+
if system == "windows":
|
|
46
|
+
binary_name = "lmms-engine-windows-amd64.exe"
|
|
47
|
+
elif system == "linux":
|
|
48
|
+
binary_name = "lmms-engine-linux-amd64"
|
|
49
|
+
elif system == "darwin": # macOS
|
|
50
|
+
binary_name = "lmms-engine-darwin-amd64"
|
|
51
|
+
else:
|
|
52
|
+
reporter.print_error(f"Unsupported OS for binary download: {system}")
|
|
53
|
+
return False
|
|
54
|
+
|
|
55
|
+
# Define Download URL (GitHub Releases)
|
|
56
|
+
# Using the official MarkanM GitHub release URL format
|
|
57
|
+
repo_url = "https://github.com/MarkanM-Official/LMMs-engine/releases/latest/download"
|
|
58
|
+
download_url = f"{repo_url}/{binary_name}"
|
|
59
|
+
|
|
60
|
+
# Define Install Path
|
|
61
|
+
if system == "windows":
|
|
62
|
+
install_dir = Path(os.path.expandvars("%LOCALAPPDATA%")) / "LMMs" / "bin"
|
|
63
|
+
install_path = install_dir / "lmms.exe"
|
|
64
|
+
else:
|
|
65
|
+
# Default Linux/Mac path
|
|
66
|
+
install_dir = Path("/usr/local/bin")
|
|
67
|
+
install_path = install_dir / "lmms"
|
|
68
|
+
|
|
69
|
+
# Fallback if no sudo permissions
|
|
70
|
+
if not os.access(install_dir, os.W_OK):
|
|
71
|
+
install_dir = Path.home() / ".local" / "bin"
|
|
72
|
+
install_path = install_dir / "lmms"
|
|
73
|
+
|
|
74
|
+
install_dir.mkdir(parents=True, exist_ok=True)
|
|
75
|
+
|
|
76
|
+
reporter.print_step(f"Downloading compiled engine from GitHub Releases...")
|
|
77
|
+
|
|
78
|
+
try:
|
|
79
|
+
response = requests.get(download_url, stream=True)
|
|
80
|
+
response.raise_for_status()
|
|
81
|
+
total_size = int(response.headers.get('content-length', 0))
|
|
82
|
+
|
|
83
|
+
with Progress(
|
|
84
|
+
TextColumn("[bold cyan]{task.description}"),
|
|
85
|
+
BarColumn(bar_width=40),
|
|
86
|
+
"[progress.percentage]{task.percentage:>3.1f}%",
|
|
87
|
+
"•",
|
|
88
|
+
DownloadColumn(),
|
|
89
|
+
"•",
|
|
90
|
+
TransferSpeedColumn(),
|
|
91
|
+
"•",
|
|
92
|
+
TimeRemainingColumn(),
|
|
93
|
+
console=reporter.console
|
|
94
|
+
) as progress:
|
|
95
|
+
task = progress.add_task("Downloading Engine...", total=total_size)
|
|
96
|
+
with open(install_path, "wb") as file:
|
|
97
|
+
for chunk in response.iter_content(chunk_size=8192):
|
|
98
|
+
if chunk:
|
|
99
|
+
file.write(chunk)
|
|
100
|
+
progress.update(task, advance=len(chunk))
|
|
101
|
+
|
|
102
|
+
if system != "windows":
|
|
103
|
+
# Make executable
|
|
104
|
+
os.chmod(install_path, 0o755)
|
|
105
|
+
reporter.print_success(f"✓ Binary installed to {install_path}")
|
|
106
|
+
return True
|
|
107
|
+
except requests.exceptions.HTTPError as e:
|
|
108
|
+
if e.response.status_code == 404:
|
|
109
|
+
reporter.print_error(f"Download Error: Binary not found on GitHub (404).")
|
|
110
|
+
reporter.print_error("Please upload the compiled binary to your GitHub Releases first!")
|
|
111
|
+
else:
|
|
112
|
+
reporter.print_error(f"HTTP Error: {e}")
|
|
113
|
+
return False
|
|
114
|
+
except Exception as e:
|
|
115
|
+
reporter.print_error(f"Download failed: {e}")
|
|
116
|
+
return False
|
|
117
|
+
|
|
118
|
+
def install_component(component_name):
|
|
119
|
+
installed = get_installed_components()
|
|
120
|
+
if installed.get(component_name):
|
|
121
|
+
reporter.print_success(f"✓ {component_name.capitalize()} is already installed. Skipping.")
|
|
122
|
+
return True, ""
|
|
123
|
+
|
|
124
|
+
if component_name != "engine":
|
|
125
|
+
reporter.print_error(f"🚀 {component_name.capitalize()} Module: Coming Soon (Development in progress).")
|
|
126
|
+
return True, ""
|
|
127
|
+
|
|
128
|
+
reporter.print_step(f"Installing {component_name.capitalize()} (Compiled Binary)...")
|
|
129
|
+
|
|
130
|
+
success = download_engine_binary()
|
|
131
|
+
|
|
132
|
+
if success:
|
|
133
|
+
mark_installed(component_name)
|
|
134
|
+
reporter.print_success(f"✓ {component_name.capitalize()} installed successfully.")
|
|
135
|
+
return True, ""
|
|
136
|
+
else:
|
|
137
|
+
return False, "Binary download failed"
|
lmms_builder/reporter.py
ADDED
|
@@ -0,0 +1,93 @@
|
|
|
1
|
+
from rich.console import Console
|
|
2
|
+
from rich.table import Table
|
|
3
|
+
from rich.panel import Panel
|
|
4
|
+
|
|
5
|
+
console = Console()
|
|
6
|
+
|
|
7
|
+
def print_header():
|
|
8
|
+
console.print(Panel("[bold cyan]LMMs Builder[/bold cyan]\n[bold yellow]LMMs Powerd by MarkanM[/bold yellow]\n[dim]Bootstrapper & Hardware Profiler[/dim]", border_style="cyan"))
|
|
9
|
+
|
|
10
|
+
def print_hardware_report(hw):
|
|
11
|
+
table = Table(title="Hardware Detection Report", show_header=True, header_style="bold magenta")
|
|
12
|
+
table.add_column("Component", style="cyan")
|
|
13
|
+
table.add_column("Details", style="green")
|
|
14
|
+
|
|
15
|
+
os_info = f"{hw['os']['system']} {hw['os']['release']} ({hw['os']['architecture']})"
|
|
16
|
+
table.add_row("OS", os_info)
|
|
17
|
+
|
|
18
|
+
cpu_info = f"{hw['cpu']['cores']} Cores / {hw['cpu']['threads']} Threads"
|
|
19
|
+
table.add_row("CPU", cpu_info)
|
|
20
|
+
|
|
21
|
+
ram_info = f"{hw['ram']['total_gb']} GB (Available: {hw['ram']['available_gb']} GB)"
|
|
22
|
+
table.add_row("RAM", ram_info)
|
|
23
|
+
|
|
24
|
+
if hw['gpu']['detected']:
|
|
25
|
+
gpu_info = f"{hw['gpu']['name']} ({hw['gpu']['vram_gb']} GB VRAM)"
|
|
26
|
+
else:
|
|
27
|
+
gpu_info = "None Detected"
|
|
28
|
+
table.add_row("GPU", gpu_info)
|
|
29
|
+
|
|
30
|
+
if hw['cuda']['available']:
|
|
31
|
+
cuda_info = f"Version {hw['cuda']['version']}"
|
|
32
|
+
else:
|
|
33
|
+
cuda_info = "Not Available"
|
|
34
|
+
table.add_row("CUDA", cuda_info)
|
|
35
|
+
|
|
36
|
+
table.add_row("Python", hw['python']['version'])
|
|
37
|
+
|
|
38
|
+
console.print(table)
|
|
39
|
+
|
|
40
|
+
def print_compatibility_report(hw):
|
|
41
|
+
console.print("\n[bold magenta]========================[/bold magenta]")
|
|
42
|
+
console.print("[bold cyan]LMMS Compatibility[/bold cyan]\n")
|
|
43
|
+
|
|
44
|
+
engine_comp = 100
|
|
45
|
+
cli_comp = 100
|
|
46
|
+
gui_comp = 100
|
|
47
|
+
air_comp = 100 if hw['ram']['total_gb'] >= 16 else 50
|
|
48
|
+
vllm_comp = 100 if hw['gpu']['detected'] and hw['gpu']['vram_gb'] >= 8 else 0
|
|
49
|
+
|
|
50
|
+
console.print(f"Engine: {engine_comp}%")
|
|
51
|
+
console.print(f"CLI: {cli_comp}%")
|
|
52
|
+
console.print(f"GUI: {gui_comp}%")
|
|
53
|
+
console.print(f"Air Engine: {air_comp}%")
|
|
54
|
+
console.print(f"vLLM: {vllm_comp}%")
|
|
55
|
+
|
|
56
|
+
overall = (engine_comp + cli_comp + gui_comp + air_comp + vllm_comp) // 5
|
|
57
|
+
console.print(f"\n[bold green]Overall: {overall}%[/bold green]")
|
|
58
|
+
console.print("[bold magenta]========================[/bold magenta]\n")
|
|
59
|
+
|
|
60
|
+
def print_benchmark_estimate(hw):
|
|
61
|
+
console.print("\n[bold cyan]Hardware Benchmark (Estimated)[/bold cyan]")
|
|
62
|
+
|
|
63
|
+
# Calculate an estimated TPS multiplier based on hardware
|
|
64
|
+
base = 5.0
|
|
65
|
+
if hw['gpu']['detected']:
|
|
66
|
+
base += hw['gpu']['vram_gb'] * 2
|
|
67
|
+
else:
|
|
68
|
+
base += hw['cpu']['cores'] * 1.5
|
|
69
|
+
|
|
70
|
+
console.print("llama.cpp (7B): ~[green]{:.1f} tok/s[/green]".format(base))
|
|
71
|
+
console.print("ollama (7B): ~[green]{:.1f} tok/s[/green]".format(base * 0.95))
|
|
72
|
+
if hw['ram']['total_gb'] >= 16:
|
|
73
|
+
console.print("air (70B): ~[yellow]{:.1f} tok/s[/yellow]".format(max(1.0, base / 10)))
|
|
74
|
+
else:
|
|
75
|
+
console.print("air (70B): [red]Not Recommended (Insufficent RAM)[/red]")
|
|
76
|
+
|
|
77
|
+
def print_step(step_msg):
|
|
78
|
+
console.print(f"[bold blue]>[/bold blue] {step_msg}")
|
|
79
|
+
|
|
80
|
+
def print_success(msg):
|
|
81
|
+
console.print(f"[bold green]✓[/bold green] {msg}")
|
|
82
|
+
|
|
83
|
+
def print_error(msg):
|
|
84
|
+
console.print(f"[bold red]✗[/bold red] {msg}")
|
|
85
|
+
|
|
86
|
+
def print_autoset_summary(mode, runtime):
|
|
87
|
+
console.print(Panel(
|
|
88
|
+
f"[bold green]AutoSet Complete![/bold green]\n\n"
|
|
89
|
+
f"[cyan]Default Mode:[/cyan] {mode}\n"
|
|
90
|
+
f"[cyan]Default Runtime:[/cyan] {runtime}\n\n"
|
|
91
|
+
"Run [bold magenta]lmms[/bold magenta] to launch.",
|
|
92
|
+
border_style="green"
|
|
93
|
+
))
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: lmms-builder
|
|
3
|
+
Version: 1.0.0
|
|
4
|
+
Summary: Bootstrapper for the LMMs OS
|
|
5
|
+
Requires-Python: >=3.9
|
|
6
|
+
Requires-Dist: psutil
|
|
7
|
+
Requires-Dist: rich
|
|
8
|
+
Requires-Dist: requests
|
|
9
|
+
Dynamic: requires-dist
|
|
10
|
+
Dynamic: requires-python
|
|
11
|
+
Dynamic: summary
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
lmms_builder/__init__.py,sha256=s4WXUCdtZenBWJdOJj8FZE-SsdNjqm_9x6igsTb_quM,52
|
|
2
|
+
lmms_builder/autoset.py,sha256=zIj8wHhO5Z-ufS8xoKowVbAwNaMddhnossMnxh_u_g0,2867
|
|
3
|
+
lmms_builder/bootstrap.py,sha256=FCKKncqovq9Ir1Guka4fHI6HOmPp_fgRCfXB508a718,1183
|
|
4
|
+
lmms_builder/cli.py,sha256=NfaPJGeH7C9KrXxd8mhhPYwg_aFdImANrGzjHlubn_Q,4215
|
|
5
|
+
lmms_builder/hardware.py,sha256=ZYZ7XJejbx2j2UBfilEPpsJ7XdiRuRXgWnGac7dJMGc,2560
|
|
6
|
+
lmms_builder/installer.py,sha256=nglj_ALkVAK9becn5UOByVMND5zyJ7tDSJorhJSxQ0s,4793
|
|
7
|
+
lmms_builder/reporter.py,sha256=V4pHTZwOEWZ1MrVoA9L_DAxIx-WRl8wgMRAsxn7IOH4,3480
|
|
8
|
+
lmms_builder-1.0.0.dist-info/METADATA,sha256=RLCZtY2P6ywkEUDmP66uFdaueExM8CfWKaNpPi61F98,248
|
|
9
|
+
lmms_builder-1.0.0.dist-info/WHEEL,sha256=aeYiig01lYGDzBgS8HxWXOg3uV61G9ijOsup-k9o1sk,91
|
|
10
|
+
lmms_builder-1.0.0.dist-info/entry_points.txt,sha256=rizkh_pFUAyrWYLAOS3EU6ArUif0Qt8-8nPJzL5jeqM,55
|
|
11
|
+
lmms_builder-1.0.0.dist-info/top_level.txt,sha256=CvyaNnnSTryMQZoYWbnMFuzmbwXLwjS8KWanpLg0kl0,13
|
|
12
|
+
lmms_builder-1.0.0.dist-info/RECORD,,
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
lmms_builder
|