Refactor CLI and LLM runtime handling for improved user experience

- Removed deprecated console usage in favor of structured logging functions for error handling and user prompts.
- Enhanced CLI prompts for LLM runtime and preset selection, utilizing menu helpers for better user interaction.
- Updated GPU pool scanning output with improved formatting and error indication for clarity.
- Refactored setup wizard to streamline LLM runtime and preset configuration, ensuring a more intuitive setup process.
- Improved documentation and user feedback in CLI outputs to enhance overall usability.
This commit is contained in:
Leonid Pershin
2026-08-21 06:31:15 +03:00
parent 64f93b4bf6
commit e7784473a2
9 changed files with 420 additions and 133 deletions
+23 -19
View File
@@ -6,6 +6,8 @@ from collections.abc import Callable
from dataclasses import dataclass
from typing import Any
from rich.markup import escape
from gpu_rent.config import Config
from gpu_rent.inventory import FlavorInfo, looks_like_gpu, rank_flavors, resolve_flavor
@@ -21,14 +23,19 @@ def list_ranked_flavors(flavors: list[Any], cfg: Config) -> list[FlavorInfo]:
def format_flavor_lines(ranked: list[FlavorInfo], picked: FlavorInfo | None = None) -> list[str]:
if not ranked:
return ["flavors: пусто (проверь регион / FLAVOR_PREFERENCE)"]
lines = ["flavors (по FLAVOR_PREFERENCE):"]
return ["[yellow]flavors: пусто (проверь регион / FLAVOR_PREFERENCE)[/yellow]"]
lines = ["[bold cyan]flavors (по FLAVOR_PREFERENCE):[/bold cyan]"]
for i, info in enumerate(ranked, 1):
mark = " ← выберем" if picked and info.id == picked.id else ""
mark = " [green]← выберем[/green]" if picked and info.id == picked.id else ""
ram = f"{info.ram_mb // 1024}GB" if info.ram_mb else "?"
vcpu = str(info.vcpus) if info.vcpus is not None else "?"
label = info.label or ""
lines.append(f" {i}. [{label}] {info.name} vCPU={vcpu} RAM={ram} id={info.id}{mark}")
label = escape(info.label or "")
name = escape(info.name)
fid = escape(info.id)
lines.append(
f" [cyan]{i}.[/cyan] [bold]{label}[/bold] {name} "
f"vCPU={vcpu} RAM={ram} id={fid}{mark}"
)
return lines
@@ -114,21 +121,18 @@ def prompt_server_plan(
if data_gb < 20:
raise ValueError("Data disk GB: минимум 20")
spot_default = "Y" if spot else "n"
raw_spot = (
ask(
"Preemptible GPU (дешевле, могут усыпить ~24ч)? [Y/n]",
spot_default,
)
.strip()
.lower()
from gpu_rent.prompts import MenuItem, prompt_menu
spot_key = prompt_menu(
"Тариф GPU",
[
MenuItem("yes", "preemptible (дешевле, могут усыпить ~24ч)"),
MenuItem("no", "обычный on-demand"),
],
default="yes" if spot else "no",
ask=ask,
)
if raw_spot in {"", "y", "yes", "1", "true", "on"}:
use_spot = True
elif raw_spot in {"n", "no", "0", "false", "off"}:
use_spot = False
else:
raise ValueError(f"preemptible: жду Y/n, получили {raw_spot!r}")
use_spot = spot_key == "yes"
changed = (
chosen.id != picked.id