mirror of
https://github.com/open-jarvis/OpenJarvis.git
synced 2026-07-28 05:12:26 +00:00
The model catalog listed non-existent Qwen3.5 sizes (3B, 8B, 14B) and pointed to MLX community repos that don't exist, causing `jarvis init` to recommend models that cannot be downloaded on Apple Silicon. Replace with the actual Qwen3.5 model family sizes (0.8B, 2B, 9B, 27B) and verified mlx-community repo URLs from HuggingFace. Fixes #129 Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
161 lines
5.5 KiB
Python
161 lines
5.5 KiB
Python
"""``jarvis quickstart`` — guided 5-step setup for new users."""
|
|
|
|
from __future__ import annotations
|
|
|
|
import logging
|
|
|
|
import click
|
|
from rich.console import Console
|
|
|
|
from openjarvis.core.config import (
|
|
DEFAULT_CONFIG_DIR,
|
|
DEFAULT_CONFIG_PATH,
|
|
detect_hardware,
|
|
generate_default_toml,
|
|
recommend_engine,
|
|
)
|
|
|
|
logger = logging.getLogger(__name__)
|
|
|
|
|
|
def _check_engine_health(engine_key: str) -> bool:
|
|
"""Return True if the recommended engine is reachable."""
|
|
try:
|
|
import openjarvis.engine # noqa: F401 — trigger registration
|
|
from openjarvis.core.config import load_config
|
|
from openjarvis.core.registry import EngineRegistry
|
|
from openjarvis.engine import _discovery
|
|
|
|
config = load_config()
|
|
if engine_key not in EngineRegistry.keys():
|
|
return False
|
|
engine = _discovery._make_engine(engine_key, config)
|
|
return engine.health()
|
|
except Exception as exc:
|
|
logger.warning("Engine health check failed for %r: %s", engine_key, exc)
|
|
return False
|
|
|
|
|
|
def _discover_healthy_engines() -> list[str]:
|
|
"""Return keys for all healthy engines discovered at runtime."""
|
|
try:
|
|
import openjarvis.engine # noqa: F401 — trigger registration
|
|
from openjarvis.core.config import load_config
|
|
from openjarvis.engine import _discovery
|
|
|
|
config = load_config()
|
|
return [key for key, _ in _discovery.discover_engines(config)]
|
|
except Exception as exc:
|
|
logger.warning("Healthy engine discovery failed: %s", exc)
|
|
return []
|
|
|
|
|
|
def _check_model_available(engine_key: str) -> bool:
|
|
"""Return True if at least one model is available on the engine."""
|
|
try:
|
|
from openjarvis.core.config import load_config
|
|
from openjarvis.core.registry import EngineRegistry
|
|
from openjarvis.engine import _discovery
|
|
|
|
config = load_config()
|
|
if engine_key not in EngineRegistry.keys():
|
|
return False
|
|
engine = _discovery._make_engine(engine_key, config)
|
|
return bool(engine.list_models())
|
|
except Exception as exc:
|
|
logger.warning("Model availability check failed for %r: %s", engine_key, exc)
|
|
return False
|
|
|
|
|
|
def _test_query(engine_key: str) -> str:
|
|
"""Run a quick test query and return the response text."""
|
|
try:
|
|
from openjarvis import Jarvis
|
|
|
|
j = Jarvis(engine_key=engine_key)
|
|
response = j.ask("Say hello in one sentence.")
|
|
j.close()
|
|
return response
|
|
except Exception as exc:
|
|
return f"(query failed: {exc})"
|
|
|
|
|
|
@click.command()
|
|
@click.option("--force", is_flag=True, help="Redo all steps even if already done.")
|
|
def quickstart(force: bool) -> None:
|
|
"""Guided 5-step setup for new users."""
|
|
console = Console()
|
|
|
|
# Step 1: Detect hardware
|
|
console.print("[bold cyan][1/5][/bold cyan] Detecting hardware...")
|
|
hw = detect_hardware()
|
|
console.print(f" Platform : {hw.platform}")
|
|
console.print(f" CPU : {hw.cpu_brand} ({hw.cpu_count} cores)")
|
|
console.print(f" RAM : {hw.ram_gb} GB")
|
|
if hw.gpu:
|
|
console.print(
|
|
f" GPU : {hw.gpu.name} ({hw.gpu.vram_gb} GB VRAM, x{hw.gpu.count})"
|
|
)
|
|
else:
|
|
console.print(" GPU : none detected")
|
|
|
|
engine_key = recommend_engine(hw)
|
|
|
|
# Step 2: Write config
|
|
console.print()
|
|
console.print("[bold cyan][2/5][/bold cyan] Writing config...")
|
|
if DEFAULT_CONFIG_PATH.exists() and not force:
|
|
console.print(
|
|
f" [dim]Config already exists at {DEFAULT_CONFIG_PATH} (skip)[/dim]"
|
|
)
|
|
else:
|
|
toml_content = generate_default_toml(hw)
|
|
DEFAULT_CONFIG_DIR.mkdir(parents=True, exist_ok=True)
|
|
DEFAULT_CONFIG_PATH.write_text(toml_content)
|
|
console.print(f" [green]Config written to {DEFAULT_CONFIG_PATH}[/green]")
|
|
|
|
# Step 3: Check engine
|
|
console.print()
|
|
console.print(f"[bold cyan][3/5][/bold cyan] Checking engine ({engine_key})...")
|
|
active_engine = engine_key
|
|
if not _check_engine_health(engine_key):
|
|
fallbacks = [k for k in _discover_healthy_engines() if k != engine_key]
|
|
if fallbacks:
|
|
active_engine = fallbacks[0]
|
|
console.print(
|
|
f" [yellow]Engine '{engine_key}' is not reachable; "
|
|
f"falling back to '{active_engine}'.[/yellow]"
|
|
)
|
|
else:
|
|
console.print(
|
|
f" [red bold]Engine '{engine_key}' is not reachable.[/red bold]"
|
|
)
|
|
console.print()
|
|
console.print(f" Start the {engine_key} server and try again.")
|
|
console.print(" Run [bold]jarvis doctor[/bold] for detailed diagnostics.")
|
|
raise SystemExit(1)
|
|
else:
|
|
console.print(f" [green]Engine '{engine_key}' is healthy.[/green]")
|
|
|
|
# Step 4: Verify model
|
|
console.print()
|
|
console.print("[bold cyan][4/5][/bold cyan] Checking for available models...")
|
|
if not _check_model_available(active_engine):
|
|
console.print(" [yellow]No models found.[/yellow]")
|
|
console.print(
|
|
" Pull a model first (e.g. [bold]ollama pull qwen3.5:2b[/bold])."
|
|
)
|
|
raise SystemExit(1)
|
|
console.print(" [green]Models available.[/green]")
|
|
|
|
# Step 5: Test query
|
|
console.print()
|
|
console.print("[bold cyan][5/5][/bold cyan] Running test query...")
|
|
response = _test_query(active_engine)
|
|
console.print(f" [green]Response:[/green] {response[:200]}")
|
|
|
|
console.print()
|
|
console.print(
|
|
'[bold green]Setup complete![/bold green] Try: [bold]jarvis ask "Hello"[/bold]'
|
|
)
|