feat: add digital avatar management to admin dashboard

- Add avatars list page with pagination, search, status filter
- Add avatar detail dialog showing full info and config params
- Add on/off switch (active/inactive status toggle)
- Backend: avatar_service.py connects to digital avatar SQLite
- Backend: /api/avatars endpoints for list, detail, status update
- Sidebar menu item added below dashboard
- docker-compose: mount SQLite db and set AVATAR_DB_PATH env var
This commit is contained in:
stefanfeng
2026-08-06 17:43:50 +08:00
parent 1da5f7f10d
commit bbbc97eb4a
9 changed files with 563 additions and 1 deletions
+2 -1
View File
@@ -1,6 +1,6 @@
"""API路由汇总"""
from fastapi import APIRouter
from app.api.endpoints import users, interactions, ai_models, dashboard, system, logs
from app.api.endpoints import users, interactions, ai_models, dashboard, system, logs, avatars
router = APIRouter()
@@ -10,3 +10,4 @@ router.include_router(ai_models.router, prefix="/ai-models", tags=["AI模型配
router.include_router(dashboard.router, prefix="/dashboard", tags=["数据看板"])
router.include_router(system.router, prefix="/system", tags=["系统设置"])
router.include_router(logs.router, prefix="/logs", tags=["日志管理"])
router.include_router(avatars.router, prefix="/avatars", tags=["数字分身管理"])
+65
View File
@@ -0,0 +1,65 @@
"""数字分身管理 API 端点"""
from fastapi import APIRouter, Query, HTTPException
from app.schemas import ApiResponse
from app.services.avatar_service import avatar_service, get_session
router = APIRouter()
@router.get("")
def list_avatars(
page: int = Query(default=1, ge=1),
page_size: int = Query(default=20, ge=1, le=100),
keyword: str = Query(default=None),
status: str = Query(default=None),
):
"""分页查询所有数字分身"""
db = get_session()
try:
total, items = avatar_service.list_avatars(
db, page, page_size, keyword, status
)
return ApiResponse(
data={
"total": total,
"page": page,
"page_size": page_size,
"items": items,
}
)
finally:
db.close()
@router.get("/{avatar_id}")
def get_avatar(avatar_id: str):
"""获取单个数字分身详情"""
db = get_session()
try:
data = avatar_service.get_avatar(db, avatar_id)
if not data:
raise HTTPException(status_code=404, detail="数字分身不存在")
return ApiResponse(data=data)
finally:
db.close()
@router.put("/{avatar_id}/status")
def update_avatar_status(avatar_id: str, body: dict):
"""更新数字分身状态(开机/关机)"""
status = body.get("status")
if status not in ("active", "inactive", "training"):
raise HTTPException(
status_code=400,
detail="status 必须是 active、inactive 或 training",
)
db = get_session()
try:
data = avatar_service.update_status(db, avatar_id, status)
if not data:
raise HTTPException(status_code=404, detail="数字分身不存在")
msg = "已开机" if status == "active" else "已关机"
return ApiResponse(data=data, message=msg)
finally:
db.close()