Files
gpu-rent/src/gpu_rent/ux.py
T
Leonid Pershin 2005b00175 Update configuration and documentation for LLM support and local watchdog
- Added `ollama-models.yaml` to .gitignore and implemented logic to copy it in gpu-rent.ps1 and gpu-rent.sh.
- Enhanced env.example to include new variables for LLM runtime options and local watchdog configuration.
- Updated CLI commands to support LLM options during setup and execution, including new flags for Ollama and llama.cpp.
- Improved documentation in cli.md and README.md to reflect changes in LLM integration and local watchdog functionality.
- Adjusted architecture and decisions documentation to clarify the role of LLMs and local watchdog in the system.
2026-08-21 05:29:23 +03:00

81 lines
3.2 KiB
Python

"""User-facing prints: flavor list, cost warnings (no invented ₽)."""
from __future__ import annotations
from collections.abc import Callable
from typing import Any
from gpu_rent.config import Config
from gpu_rent.inventory import FlavorInfo, looks_like_gpu, rank_flavors, resolve_flavor
Log = Callable[[str], None]
def list_ranked_flavors(flavors: list[Any], cfg: Config) -> list[FlavorInfo]:
gpu = [f for f in flavors if looks_like_gpu(f)]
return rank_flavors(gpu or flavors, cfg.flavor_preference)
def format_flavor_lines(ranked: list[FlavorInfo], picked: FlavorInfo | None = None) -> list[str]:
if not ranked:
return ["flavors: пусто (проверь регион / FLAVOR_PREFERENCE)"]
lines = ["flavors (по FLAVOR_PREFERENCE):"]
for i, info in enumerate(ranked, 1):
mark = " ← выберем" 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}")
return lines
def cost_and_risk_lines(cfg: Config, *, spot: bool, flavor_name: str) -> list[str]:
"""Honest billing notes — OpenStack has no ₽ prices."""
return [
f"план: {'preemptible ' if spot else ''}{flavor_name}, data {cfg.data_volume_size_gb} GB",
"₽: цены в OpenStack API нет — смотри панель Selectel (GPU ₽/час + диск ₽/мес).",
"диск data тарифицируется 24/7, даже когда GPU выключен (stop).",
f"idle-killer: {cfg.idle_grace_minutes} мин льготы после boot, потом "
f"{cfg.idle_minutes} мин пустой очереди → delete compute. Отложить: gpu-rent hold",
"preemptible: хостер может усыпить (~24 ч окно) → EXPIRED; tunnel сам unshelve, "
"или gpu-rent up",
"Ctrl+C на tunnel GPU не гасит — только gpu-rent stop или idle-killer. "
"Опционально: gpu-rent watchdog install — аварийное закрытие окна/ребут "
"после grace тоже stop (Ctrl+C по-прежнему detach)",
]
def print_up_preview(
cfg: Config,
flavors: list[Any],
*,
picked: FlavorInfo,
spot: bool,
log: Log,
) -> None:
ranked = list_ranked_flavors(flavors, cfg)
for line in format_flavor_lines(ranked, picked):
log(line)
log("")
for line in cost_and_risk_lines(cfg, spot=spot, flavor_name=picked.name):
log(f"! {line}")
def resolve_and_preview(
cfg: Config,
flavors: list[Any],
*,
explicit: str | None,
spot: bool,
log: Log,
) -> FlavorInfo:
picked = resolve_flavor(
flavors,
cfg.flavor_preference,
explicit=explicit,
default_id=cfg.default_flavor_id or None,
fallback=cfg.flavor_fallback,
)
print_up_preview(cfg, flavors, picked=picked, spot=spot, log=log)
return picked