Fix all linter issues
This commit is contained in:
parent
fbd4b6c5e8
commit
d4a2ace913
10 changed files with 2989 additions and 28 deletions
|
|
@ -60,7 +60,7 @@ agent's own shell command line and kills the session.
|
||||||
while the UI switch is on, reaps stale locks by `who` marker on startup)
|
while the UI switch is on, reaps stale locks by `who` marker on startup)
|
||||||
+ lact plugin (shells out to `lact cli`: per-GPU profile dropdown with
|
+ lact plugin (shells out to `lact cli`: per-GPU profile dropdown with
|
||||||
set/reload, active profile polled every 5 s, GPU names shortened with
|
set/reload, active profile polled every 5 s, GPU names shortened with
|
||||||
`app/collect/gpu.py:_shorten` like the overview card).
|
`app/collect/gpu.py:shorten` like the overview card).
|
||||||
|
|
||||||
## Conventions
|
## Conventions
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1 +0,0 @@
|
||||||
from app import routers # noqa: F401
|
|
||||||
|
|
@ -16,7 +16,7 @@ def _read(path: str) -> str | None:
|
||||||
return None
|
return None
|
||||||
|
|
||||||
|
|
||||||
def _shorten(name: str) -> str:
|
def shorten(name: str) -> str:
|
||||||
name = re.sub(r"\s*\(rev.*\)$", "", name).strip()
|
name = re.sub(r"\s*\(rev.*\)$", "", name).strip()
|
||||||
groups = re.findall(r"\[([^\]]+)\]", name)
|
groups = re.findall(r"\[([^\]]+)\]", name)
|
||||||
if len(groups) >= 2:
|
if len(groups) >= 2:
|
||||||
|
|
@ -42,7 +42,7 @@ def _gpu_name() -> str:
|
||||||
).stdout
|
).stdout
|
||||||
for line in out.splitlines():
|
for line in out.splitlines():
|
||||||
if "VGA" in line or "3D controller" in line:
|
if "VGA" in line or "3D controller" in line:
|
||||||
_name_cache = _shorten(line.split(":", 2)[-1].strip())
|
_name_cache = shorten(line.split(":", 2)[-1].strip())
|
||||||
break
|
break
|
||||||
except (OSError, subprocess.SubprocessError):
|
except (OSError, subprocess.SubprocessError):
|
||||||
pass
|
pass
|
||||||
|
|
|
||||||
|
|
@ -1,10 +1,11 @@
|
||||||
from functools import lru_cache
|
from functools import lru_cache
|
||||||
|
from typing import ClassVar
|
||||||
|
|
||||||
from pydantic_settings import BaseSettings, SettingsConfigDict
|
from pydantic_settings import BaseSettings, SettingsConfigDict
|
||||||
|
|
||||||
|
|
||||||
class Settings(BaseSettings):
|
class Settings(BaseSettings):
|
||||||
model_config = SettingsConfigDict(env_prefix="DASH_", env_file=".env", extra="ignore")
|
model_config: ClassVar[SettingsConfigDict] = SettingsConfigDict(env_prefix="DASH_", env_file=".env", extra="ignore")
|
||||||
|
|
||||||
host: str = "127.0.0.1"
|
host: str = "127.0.0.1"
|
||||||
port: int = 8501
|
port: int = 8501
|
||||||
|
|
|
||||||
|
|
@ -39,6 +39,10 @@ async def lifespan(app: FastAPI):
|
||||||
pass
|
pass
|
||||||
|
|
||||||
|
|
||||||
|
async def index():
|
||||||
|
return HTMLResponse(render("index.html", hostname=socket.gethostname()))
|
||||||
|
|
||||||
|
|
||||||
def create_app() -> FastAPI:
|
def create_app() -> FastAPI:
|
||||||
app = FastAPI(title="Dashboard", lifespan=lifespan)
|
app = FastAPI(title="Dashboard", lifespan=lifespan)
|
||||||
app.mount("/static", StaticFiles(directory=BASE / "static"), name="static")
|
app.mount("/static", StaticFiles(directory=BASE / "static"), name="static")
|
||||||
|
|
@ -46,10 +50,7 @@ def create_app() -> FastAPI:
|
||||||
app.include_router(r)
|
app.include_router(r)
|
||||||
for r in PLUGIN_ROUTERS:
|
for r in PLUGIN_ROUTERS:
|
||||||
app.include_router(r)
|
app.include_router(r)
|
||||||
|
_ = app.get("/", include_in_schema=False)(index)
|
||||||
@app.get("/", include_in_schema=False)
|
|
||||||
async def index():
|
|
||||||
return HTMLResponse(render("index.html", hostname=socket.gethostname()))
|
|
||||||
|
|
||||||
return app
|
return app
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1,12 +1,12 @@
|
||||||
import asyncio
|
import asyncio
|
||||||
import re
|
import re
|
||||||
import time
|
import time
|
||||||
from typing import Any
|
from typing import Annotated, Any
|
||||||
|
|
||||||
from fastapi import APIRouter, Form
|
from fastapi import APIRouter, Form
|
||||||
from fastapi.responses import HTMLResponse
|
from fastapi.responses import HTMLResponse
|
||||||
|
|
||||||
from app.collect.gpu import _shorten
|
from app.collect.gpu import shorten
|
||||||
from app.plugins.base import Plugin
|
from app.plugins.base import Plugin
|
||||||
from app.render import render
|
from app.render import render
|
||||||
|
|
||||||
|
|
@ -55,7 +55,7 @@ def _parse_gpus(out: str) -> list[dict[str, str]]:
|
||||||
gpu_type = re.search(r"\[([^\]]*)\]\s*$", rest)
|
gpu_type = re.search(r"\[([^\]]*)\]\s*$", rest)
|
||||||
gpus.append({
|
gpus.append({
|
||||||
"id": m.group(1),
|
"id": m.group(1),
|
||||||
"name": _shorten(name.group(1)) if name else rest.strip(),
|
"name": shorten(name.group(1)) if name else rest.strip(),
|
||||||
"type": gpu_type.group(1) if gpu_type else "",
|
"type": gpu_type.group(1) if gpu_type else "",
|
||||||
})
|
})
|
||||||
return gpus
|
return gpus
|
||||||
|
|
@ -126,7 +126,7 @@ async def state():
|
||||||
|
|
||||||
|
|
||||||
@router.post("/set")
|
@router.post("/set")
|
||||||
async def set_profile(gpu_id: str = Form(...), profile: str = Form(...)):
|
async def set_profile(gpu_id: Annotated[str, Form()], profile: Annotated[str, Form()]):
|
||||||
async with _set_lock:
|
async with _set_lock:
|
||||||
data = await _gather(with_profiles=True, force_gpus=True)
|
data = await _gather(with_profiles=True, force_gpus=True)
|
||||||
if data["error"]:
|
if data["error"]:
|
||||||
|
|
@ -145,7 +145,7 @@ async def set_profile(gpu_id: str = Form(...), profile: str = Form(...)):
|
||||||
|
|
||||||
|
|
||||||
@router.post("/reload")
|
@router.post("/reload")
|
||||||
async def reload(gpu_id: str | None = Form(None)):
|
async def reload(gpu_id: Annotated[str | None, Form()] = None):
|
||||||
_ = gpu_id
|
_ = gpu_id
|
||||||
return HTMLResponse(await _skeleton(message="profiles refreshed"))
|
return HTMLResponse(await _skeleton(message="profiles refreshed"))
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1,4 +1,4 @@
|
||||||
from typing import Any
|
from typing import Annotated, Any
|
||||||
|
|
||||||
import httpx
|
import httpx
|
||||||
from fastapi import APIRouter, Form
|
from fastapi import APIRouter, Form
|
||||||
|
|
@ -12,7 +12,7 @@ router = APIRouter(prefix="/api/plugins/llamacpp", tags=["plugins"])
|
||||||
|
|
||||||
|
|
||||||
def _headers(settings: Settings) -> dict[str, str]:
|
def _headers(settings: Settings) -> dict[str, str]:
|
||||||
h = {}
|
h: dict[str, str] = {}
|
||||||
if settings.llama_api_key:
|
if settings.llama_api_key:
|
||||||
h["Authorization"] = f"Bearer {settings.llama_api_key}"
|
h["Authorization"] = f"Bearer {settings.llama_api_key}"
|
||||||
return h
|
return h
|
||||||
|
|
@ -37,6 +37,7 @@ async def gather_status() -> dict[str, Any]:
|
||||||
"models": [],
|
"models": [],
|
||||||
"error": None,
|
"error": None,
|
||||||
}
|
}
|
||||||
|
models: list[dict[str, str | bool | float]] = []
|
||||||
try:
|
try:
|
||||||
async with _client() as client:
|
async with _client() as client:
|
||||||
try:
|
try:
|
||||||
|
|
@ -62,12 +63,13 @@ async def gather_status() -> dict[str, Any]:
|
||||||
done = sum(p.get("done", 0) for p in prog.values())
|
done = sum(p.get("done", 0) for p in prog.values())
|
||||||
total = sum(p.get("total", 1) for p in prog.values())
|
total = sum(p.get("total", 1) for p in prog.values())
|
||||||
item["progress"] = round(done / total * 100, 1) if total else 0.0
|
item["progress"] = round(done / total * 100, 1) if total else 0.0
|
||||||
status["models"].append(item)
|
models.append(item)
|
||||||
status["models"].sort(key=lambda m: m["id"])
|
models.sort(key=lambda m: m["id"])
|
||||||
except httpx.HTTPError as e:
|
except httpx.HTTPError as e:
|
||||||
status["error"] = f"unreachable: {e.__class__.__name__}"
|
status["error"] = f"unreachable: {e.__class__.__name__}"
|
||||||
except Exception as e: # noqa
|
except Exception as e: # noqa
|
||||||
status["error"] = str(e)[:200]
|
status["error"] = str(e)[:200]
|
||||||
|
status["models"] = models
|
||||||
return status
|
return status
|
||||||
|
|
||||||
|
|
||||||
|
|
@ -117,7 +119,7 @@ async def state():
|
||||||
|
|
||||||
|
|
||||||
@router.post("/load")
|
@router.post("/load")
|
||||||
async def load(model: str = Form(...)):
|
async def load(model: Annotated[str, Form()]):
|
||||||
ok, err = await _action("/models/load", model)
|
ok, err = await _action("/models/load", model)
|
||||||
return HTMLResponse(
|
return HTMLResponse(
|
||||||
await _skeleton(
|
await _skeleton(
|
||||||
|
|
@ -128,7 +130,7 @@ async def load(model: str = Form(...)):
|
||||||
|
|
||||||
|
|
||||||
@router.post("/unload")
|
@router.post("/unload")
|
||||||
async def unload(model: str = Form(...)):
|
async def unload(model: Annotated[str, Form()]):
|
||||||
ok, err = await _action("/models/unload", model)
|
ok, err = await _action("/models/unload", model)
|
||||||
return HTMLResponse(
|
return HTMLResponse(
|
||||||
await _skeleton(
|
await _skeleton(
|
||||||
|
|
|
||||||
|
|
@ -2,7 +2,7 @@ import asyncio
|
||||||
import json
|
import json
|
||||||
import os
|
import os
|
||||||
import signal
|
import signal
|
||||||
from typing import Any
|
from typing import Annotated, Any, cast
|
||||||
|
|
||||||
from fastapi import APIRouter, Form
|
from fastapi import APIRouter, Form
|
||||||
from fastapi.responses import HTMLResponse
|
from fastapi.responses import HTMLResponse
|
||||||
|
|
@ -45,7 +45,7 @@ async def _list() -> tuple[list[dict[str, Any]], str]:
|
||||||
return [], "could not parse systemd-inhibit output"
|
return [], "could not parse systemd-inhibit output"
|
||||||
if not isinstance(data, list):
|
if not isinstance(data, list):
|
||||||
return [], "unexpected systemd-inhibit output"
|
return [], "unexpected systemd-inhibit output"
|
||||||
items: list[dict[str, Any]] = [e for e in data if isinstance(e, dict)]
|
items: list[dict[str, Any]] = [e for e in cast("list[Any]", data) if isinstance(e, dict)]
|
||||||
return items, ""
|
return items, ""
|
||||||
|
|
||||||
|
|
||||||
|
|
@ -155,7 +155,7 @@ async def state():
|
||||||
|
|
||||||
|
|
||||||
@router.post("/toggle")
|
@router.post("/toggle")
|
||||||
async def toggle(on: str | None = Form(None)):
|
async def toggle(on: Annotated[str | None, Form()] = None):
|
||||||
async with _toggle_lock:
|
async with _toggle_lock:
|
||||||
if on and _holder is None:
|
if on and _holder is None:
|
||||||
err = await _acquire()
|
err = await _acquire()
|
||||||
|
|
|
||||||
|
|
@ -1,4 +1,4 @@
|
||||||
from typing import Any
|
from typing import Annotated, Any
|
||||||
|
|
||||||
from fastapi import APIRouter, Form
|
from fastapi import APIRouter, Form
|
||||||
from fastapi.responses import HTMLResponse
|
from fastapi.responses import HTMLResponse
|
||||||
|
|
@ -95,10 +95,10 @@ async def service_detail(unit: str):
|
||||||
@router.post("/{unit}/action")
|
@router.post("/{unit}/action")
|
||||||
async def service_action(
|
async def service_action(
|
||||||
unit: str,
|
unit: str,
|
||||||
action: str = Form(...),
|
action: Annotated[str, Form()],
|
||||||
q: str = Form(""),
|
q: Annotated[str, Form()] = "",
|
||||||
sort: str = Form("name"),
|
sort: Annotated[str, Form()] = "name",
|
||||||
order: str = Form("asc"),
|
order: Annotated[str, Form()] = "asc",
|
||||||
):
|
):
|
||||||
error = None
|
error = None
|
||||||
try:
|
try:
|
||||||
|
|
|
||||||
2958
opencode/opencode_session_linter_issues_2026-08-30.txt
Normal file
2958
opencode/opencode_session_linter_issues_2026-08-30.txt
Normal file
File diff suppressed because it is too large
Load diff
Loading…
Reference in a new issue