Build lightweight AI agent admin

This commit is contained in:
Codex
2026-06-08 18:14:59 +08:00
commit e164840f43
2530 changed files with 435693 additions and 0 deletions
+295
View File
@@ -0,0 +1,295 @@
"""
AI 应用 API
"""
import logging
from typing import List, Optional
from fastapi import APIRouter, Depends, HTTPException, Query
from sqlalchemy import select, func
from sqlalchemy.ext.asyncio import AsyncSession
from app.database import get_db
from app.base_schema import PaginatedResponse, ResponseModel
from ai_platform.models import AIApp, LLMModel
from ai_platform.schemas.app_schema import (
AppCreate,
AppUpdate,
AppResponse,
AppListResponse,
)
logger = logging.getLogger(__name__)
router = APIRouter(prefix="/apps", tags=["AI-应用"])
@router.get("", response_model=PaginatedResponse[AppListResponse], summary="应用列表")
async def list_apps(
name: Optional[str] = Query(None, description="名称"),
app_type: Optional[str] = Query(None, description="类型"),
status: Optional[str] = Query(None, description="状态"),
page: int = Query(1, ge=1, description="页码"),
page_size: int = Query(20, ge=1, le=100, alias="pageSize", description="每页数量"),
db: AsyncSession = Depends(get_db),
):
"""获取应用列表"""
query = select(AIApp).where(AIApp.is_deleted == False)
if name:
query = query.where(AIApp.name.ilike(f"%{name}%"))
if app_type:
query = query.where(AIApp.app_type == app_type)
if status:
query = query.where(AIApp.status == status)
# 获取总数
count_result = await db.execute(select(func.count()).select_from(query.subquery()))
total = count_result.scalar() or 0
# 分页
offset = (page - 1) * page_size
query = query.order_by(AIApp.sort.desc(), AIApp.sys_create_datetime.desc())
query = query.offset(offset).limit(page_size)
result = await db.execute(query)
apps = result.scalars().all()
items = []
for app in apps:
model_name = ""
if app.model_id:
model_result = await db.execute(
select(LLMModel).where(LLMModel.id == app.model_id)
)
model = model_result.scalar_one_or_none()
model_name = model.display_name if model else ""
items.append({
"id": app.id,
"name": app.name,
"code": app.code,
"description": app.description or "",
"icon": app.icon or "",
"app_type": app.app_type or "chat",
"status": app.status or "draft",
"model_name": model_name,
"is_public": app.is_public or False,
"conversation_count": app.conversation_count or 0,
"message_count": app.message_count or 0,
"sys_create_datetime": app.sys_create_datetime,
})
return PaginatedResponse(items=items, total=total)
@router.get("/published", response_model=List[AppListResponse], summary="获取已发布应用")
async def list_published_apps(db: AsyncSession = Depends(get_db)):
"""获取已发布的应用列表(用于用户选择)"""
query = select(AIApp).where(
AIApp.is_deleted == False,
AIApp.status == "published"
).order_by(AIApp.sort.desc())
result = await db.execute(query)
apps = result.scalars().all()
items = []
for app in apps:
model_name = ""
if app.model_id:
model_result = await db.execute(
select(LLMModel).where(LLMModel.id == app.model_id)
)
model = model_result.scalar_one_or_none()
model_name = model.display_name if model else ""
items.append({
"id": app.id,
"name": app.name,
"code": app.code,
"description": app.description or "",
"icon": app.icon or "",
"app_type": app.app_type or "chat",
"status": app.status or "draft",
"model_name": model_name,
"is_public": app.is_public or False,
"conversation_count": app.conversation_count or 0,
"message_count": app.message_count or 0,
"sys_create_datetime": app.sys_create_datetime,
})
return items
@router.get("/code/{code}", response_model=AppResponse, summary="根据编码获取应用")
async def get_app_by_code(code: str, db: AsyncSession = Depends(get_db)):
"""根据编码获取应用"""
result = await db.execute(
select(AIApp).where(AIApp.code == code, AIApp.is_deleted == False)
)
app = result.scalar_one_or_none()
if not app:
raise HTTPException(status_code=404, detail="应用不存在")
return await _build_app_response(app, db)
@router.get("/{app_id}", response_model=AppResponse, summary="应用详情")
async def get_app(app_id: str, db: AsyncSession = Depends(get_db)):
"""获取应用详情"""
result = await db.execute(
select(AIApp).where(AIApp.id == app_id, AIApp.is_deleted == False)
)
app = result.scalar_one_or_none()
if not app:
raise HTTPException(status_code=404, detail="应用不存在")
return await _build_app_response(app, db)
@router.post("", response_model=AppResponse, summary="创建应用")
async def create_app(data: AppCreate, db: AsyncSession = Depends(get_db)):
"""创建应用"""
# 检查编码是否重复
exists_result = await db.execute(
select(AIApp).where(AIApp.code == data.code, AIApp.is_deleted == False)
)
if exists_result.scalar_one_or_none():
raise HTTPException(status_code=400, detail=f"应用编码 {data.code} 已存在")
# 验证模型
if data.model_id:
model_result = await db.execute(
select(LLMModel).where(LLMModel.id == data.model_id, LLMModel.is_deleted == False)
)
if not model_result.scalar_one_or_none():
raise HTTPException(status_code=400, detail="模型不存在")
app = AIApp(**data.model_dump())
db.add(app)
await db.commit()
await db.refresh(app)
return await _build_app_response(app, db)
@router.put("/{app_id}", response_model=AppResponse, summary="更新应用")
async def update_app(
app_id: str,
data: AppUpdate,
db: AsyncSession = Depends(get_db),
):
"""更新应用"""
result = await db.execute(
select(AIApp).where(AIApp.id == app_id, AIApp.is_deleted == False)
)
app = result.scalar_one_or_none()
if not app:
raise HTTPException(status_code=404, detail="应用不存在")
update_data = data.model_dump(exclude_unset=True)
# 验证模型
if "model_id" in update_data and update_data["model_id"]:
model_result = await db.execute(
select(LLMModel).where(
LLMModel.id == update_data["model_id"],
LLMModel.is_deleted == False
)
)
if not model_result.scalar_one_or_none():
raise HTTPException(status_code=400, detail="模型不存在")
for key, value in update_data.items():
setattr(app, key, value)
await db.commit()
await db.refresh(app)
return await _build_app_response(app, db)
@router.delete("/{app_id}", response_model=ResponseModel, summary="删除应用")
async def delete_app(app_id: str, db: AsyncSession = Depends(get_db)):
"""删除应用"""
result = await db.execute(
select(AIApp).where(AIApp.id == app_id, AIApp.is_deleted == False)
)
app = result.scalar_one_or_none()
if not app:
raise HTTPException(status_code=404, detail="应用不存在")
app.is_deleted = True
await db.commit()
return ResponseModel(message="删除成功")
@router.post("/{app_id}/publish", response_model=AppResponse, summary="发布应用")
async def publish_app(app_id: str, db: AsyncSession = Depends(get_db)):
"""发布应用"""
result = await db.execute(
select(AIApp).where(AIApp.id == app_id, AIApp.is_deleted == False)
)
app = result.scalar_one_or_none()
if not app:
raise HTTPException(status_code=404, detail="应用不存在")
app.status = "published"
await db.commit()
await db.refresh(app)
return await _build_app_response(app, db)
@router.post("/{app_id}/disable", response_model=AppResponse, summary="停用应用")
async def disable_app(app_id: str, db: AsyncSession = Depends(get_db)):
"""停用应用"""
result = await db.execute(
select(AIApp).where(AIApp.id == app_id, AIApp.is_deleted == False)
)
app = result.scalar_one_or_none()
if not app:
raise HTTPException(status_code=404, detail="应用不存在")
app.status = "disabled"
await db.commit()
await db.refresh(app)
return await _build_app_response(app, db)
async def _build_app_response(app: AIApp, db: AsyncSession) -> dict:
"""构建应用输出"""
model_name = ""
if app.model_id:
model_result = await db.execute(
select(LLMModel).where(LLMModel.id == app.model_id)
)
model = model_result.scalar_one_or_none()
model_name = model.display_name if model else ""
return {
"id": app.id,
"name": app.name,
"code": app.code,
"description": app.description or "",
"icon": app.icon or "",
"app_type": app.app_type or "chat",
"status": app.status or "draft",
"model_id": app.model_id,
"model_name": model_name,
"system_prompt": app.system_prompt or "",
"temperature": app.temperature or 0.7,
"top_p": app.top_p or 1.0,
"max_tokens": app.max_tokens or 2048,
"opening_statement": app.opening_statement or "",
"suggested_questions": app.suggested_questions or [],
"workflow_definition": app.workflow_definition or {},
"is_public": app.is_public or False,
"conversation_count": app.conversation_count or 0,
"message_count": app.message_count or 0,
"sort": app.sort or 0,
"sys_create_datetime": app.sys_create_datetime,
"sys_update_datetime": app.sys_update_datetime,
}