mirror of
https://github.com/katanemo/plano.git
synced 2026-04-25 00:36:34 +02:00
99 lines
2.8 KiB
Python
99 lines
2.8 KiB
Python
"""`planoai obs` — live observability TUI."""
|
|
|
|
from __future__ import annotations
|
|
|
|
import time
|
|
|
|
import rich_click as click
|
|
from rich.console import Console
|
|
from rich.live import Live
|
|
|
|
from planoai.consts import PLANO_COLOR
|
|
from planoai.obs.collector import (
|
|
DEFAULT_CAPACITY,
|
|
DEFAULT_GRPC_PORT,
|
|
LLMCallStore,
|
|
ObsCollector,
|
|
)
|
|
from planoai.obs.pricing import PricingCatalog
|
|
from planoai.obs.render import render
|
|
|
|
|
|
@click.command(name="obs", help="Live observability console for Plano LLM traffic.")
|
|
@click.option(
|
|
"--port",
|
|
type=int,
|
|
default=DEFAULT_GRPC_PORT,
|
|
show_default=True,
|
|
help="OTLP/gRPC port to listen on. Must match the brightstaff tracing endpoint.",
|
|
)
|
|
@click.option(
|
|
"--host",
|
|
type=str,
|
|
default="0.0.0.0",
|
|
show_default=True,
|
|
help="Host to bind the OTLP listener.",
|
|
)
|
|
@click.option(
|
|
"--capacity",
|
|
type=int,
|
|
default=DEFAULT_CAPACITY,
|
|
show_default=True,
|
|
help="Max LLM calls kept in memory; older calls evicted FIFO.",
|
|
)
|
|
@click.option(
|
|
"--refresh-ms",
|
|
type=int,
|
|
default=500,
|
|
show_default=True,
|
|
help="TUI refresh interval.",
|
|
)
|
|
def obs(port: int, host: str, capacity: int, refresh_ms: int) -> None:
|
|
console = Console()
|
|
console.print(
|
|
f"[bold {PLANO_COLOR}]planoai obs[/] — loading DO pricing catalog...",
|
|
end="",
|
|
)
|
|
pricing = PricingCatalog.fetch()
|
|
if len(pricing):
|
|
sample = ", ".join(pricing.sample_models(3))
|
|
console.print(
|
|
f" [green]{len(pricing)} models loaded[/] [dim]({sample}, ...)[/]"
|
|
)
|
|
else:
|
|
console.print(
|
|
" [yellow]no pricing loaded[/] — "
|
|
"[dim]cost column will be blank (DO catalog unreachable)[/]"
|
|
)
|
|
|
|
store = LLMCallStore(capacity=capacity)
|
|
collector = ObsCollector(store=store, pricing=pricing, host=host, port=port)
|
|
try:
|
|
collector.start()
|
|
except OSError as exc:
|
|
console.print(f"[red]{exc}[/]")
|
|
raise SystemExit(1)
|
|
|
|
console.print(
|
|
f"Listening for OTLP spans on [bold]{host}:{port}[/]. "
|
|
"Ensure plano config has [cyan]tracing.opentracing_grpc_endpoint: http://localhost:4317[/] "
|
|
"and [cyan]tracing.random_sampling: 100[/] (or run [bold]planoai up[/] "
|
|
"with no config — it wires this automatically)."
|
|
)
|
|
console.print("Press [bold]Ctrl-C[/] to exit.\n")
|
|
|
|
refresh = max(0.05, refresh_ms / 1000.0)
|
|
try:
|
|
with Live(
|
|
render(store.snapshot()),
|
|
console=console,
|
|
refresh_per_second=1.0 / refresh,
|
|
screen=False,
|
|
) as live:
|
|
while True:
|
|
time.sleep(refresh)
|
|
live.update(render(store.snapshot()))
|
|
except KeyboardInterrupt:
|
|
console.print("\n[dim]obs stopped[/]")
|
|
finally:
|
|
collector.stop()
|