feat: AI余额定时自动同步(CLI脚本+systemd每日timer+批量同步接口+前端按钮)

This commit is contained in:
gouki
2026-08-02 17:43:46 +00:00
parent 2e3e9f8b0b
commit 8ba58caaa8
7 changed files with 116 additions and 2 deletions
+2 -1
View File
@@ -19,7 +19,7 @@ from sqlmodel import Session
from app.core.config import settings
from app.core.seed import seed_providers
from app.database import assets_engine, init_db
from app.routers import agent, assets, monitor, providers, stats
from app.routers import agent, assets, monitor, providers, stats, sync
BASE_DIR = Path(__file__).resolve().parent.parent
STATIC_DIR = BASE_DIR / "static"
@@ -53,6 +53,7 @@ app.include_router(providers.router)
app.include_router(stats.router)
app.include_router(agent.router)
app.include_router(monitor.router)
app.include_router(sync.router)
app.mount("/static", StaticFiles(directory=STATIC_DIR), name="static")
+19
View File
@@ -0,0 +1,19 @@
"""同步相关路由(批量同步操作)"""
from fastapi import APIRouter, Depends
from sqlmodel import Session
from app.core.security import require_api_key
from app.database import get_session
from app.services import sync_service
router = APIRouter(prefix="/api/sync", tags=["sync"])
@router.post(
"/ai-balances",
summary="同步所有 AI 账号余额",
dependencies=[Depends(require_api_key)],
)
def sync_ai_balances(session: Session = Depends(get_session)) -> dict:
return sync_service.sync_all_ai_balances(session)
+27
View File
@@ -295,3 +295,30 @@ def refresh_ai_balance(session: Session, asset_id: int) -> dict:
"currency": ai.currency,
"last_synced_at": ai.last_synced_at.isoformat(),
}
def sync_all_ai_balances(session: Session) -> dict:
"""遍历所有 AI 账号资产,逐个刷新余额(单个失败不中断整体)"""
ai_assets = session.exec(
select(Asset).where(Asset.asset_type == AssetType.AI_AGENT)
).all()
success = 0
failed = 0
errors = []
for asset in ai_assets:
try:
refresh_ai_balance(session, asset.id)
success += 1
except HTTPException as e:
failed += 1
errors.append(f"{asset.name}: {e.detail}")
except Exception as e: # noqa: BLE001
failed += 1
errors.append(f"{asset.name}: {e}")
return {
"total": len(ai_assets),
"success": success,
"failed": failed,
"errors": errors,
"synced_at": datetime.utcnow().isoformat(),
}