Initial commit: Agentic OS troubleshooting platform
Self-hosted, Docker-based agentic troubleshooting platform: FastAPI backend + LangGraph agent, Next.js UI, tiered LLM routing (local Ollama -> Gemini -> DeepSeek -> OpenRouter), MCP server manager, encrypted device credentials, RBAC, audit log, project-memory + Obsidian integrations, and editable troubleshooting decision rules tuned for the GeneseasX vessel stack. Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
54
backend/app/api/balance.py
Normal file
54
backend/app/api/balance.py
Normal file
@@ -0,0 +1,54 @@
|
||||
"""API balance / consumption endpoints."""
|
||||
from __future__ import annotations
|
||||
|
||||
from fastapi import APIRouter, Depends
|
||||
from sqlalchemy import select
|
||||
from sqlalchemy.ext.asyncio import AsyncSession
|
||||
|
||||
from app.core.deps import require_readonly, require_support
|
||||
from app.database import get_db
|
||||
from app.models.balance import BalanceSnapshot
|
||||
from app.models.user import User
|
||||
from app.schemas import BalanceOut
|
||||
from app.services import balance as balance_service
|
||||
|
||||
router = APIRouter(prefix="/api/balance", tags=["balance"])
|
||||
|
||||
|
||||
async def _latest_snapshot(db: AsyncSession, provider: str) -> BalanceSnapshot | None:
|
||||
"""Prefer the newest successful snapshot; fall back to latest error row."""
|
||||
res = await db.execute(
|
||||
select(BalanceSnapshot)
|
||||
.where(BalanceSnapshot.provider == provider)
|
||||
.where(BalanceSnapshot.error.is_(None))
|
||||
.where(BalanceSnapshot.remaining.is_not(None))
|
||||
.order_by(BalanceSnapshot.created_at.desc())
|
||||
.limit(1)
|
||||
)
|
||||
snap = res.scalar_one_or_none()
|
||||
if snap:
|
||||
return snap
|
||||
res = await db.execute(
|
||||
select(BalanceSnapshot)
|
||||
.where(BalanceSnapshot.provider == provider)
|
||||
.order_by(BalanceSnapshot.created_at.desc())
|
||||
.limit(1)
|
||||
)
|
||||
return res.scalar_one_or_none()
|
||||
|
||||
|
||||
@router.get("", response_model=list[BalanceOut])
|
||||
async def latest_balances(db: AsyncSession = Depends(get_db), _: User = Depends(require_readonly)):
|
||||
"""Latest snapshot per provider."""
|
||||
out: list[BalanceSnapshot] = []
|
||||
for provider in ("openrouter", "deepseek"):
|
||||
snap = await _latest_snapshot(db, provider)
|
||||
if snap:
|
||||
out.append(snap)
|
||||
return out
|
||||
|
||||
|
||||
@router.post("/refresh", response_model=list[BalanceOut])
|
||||
async def refresh_balances(db: AsyncSession = Depends(get_db), _: User = Depends(require_support)):
|
||||
await balance_service.poll_once()
|
||||
return await latest_balances(db) # type: ignore[arg-type]
|
||||
Reference in New Issue
Block a user