初始提交: Qihu-AIFlow v2.0.1 完整项目

- 前端 React+TypeScript (源码+构建产物)
- 后端 Python FastAPI
- 数据库迁移 001-015
- Docker部署配置
- 微信ClawBot API频道绑定
- 项目文档 README.md
This commit is contained in:
qyyfw committed 2026-07-02 14:40:46 +08:00
commit 78ff261b5a
199 files changed
+69126

No files matched your search

+393
View File
@@ -0,0 +1,393 @@
"""
AI自进化 API路由
"""
from fastapi import APIRouter, Depends, HTTPException, Query
from sqlalchemy.orm import Session
from typing import Optional, List
from pydantic import BaseModel
from ..auth import get_current_user
from ..models import User
from ..services.evolution_service import get_evolution_service, EvolutionWatcherManager
from ..database import get_db, SessionLocal
router = APIRouter()
# ============================================================
# Request/Response Models
# ============================================================
class SkillUpdateRequest(BaseModel):
description: Optional[str] = None
tags: Optional[List[str]] = None
category: Optional[str] = None
class TrajectorySubmitRequest(BaseModel):
conversation_id: str
messages: List[dict] = []
class PublishRequest(BaseModel):
price: float = 0.00
market_description: str = ""
class ShareToTeamRequest(BaseModel):
team_id: str
# ============================================================
# 技能管理 API
# ============================================================
@router.get("/skills")
def list_skills(
state: Optional[str] = Query(None, description="技能状态过滤"),
keyword: Optional[str] = Query(None, description="关键词搜索"),
sort_by: str = Query("updated_at", description="排序字段"),
order: str = Query("desc", description="排序方向"),
current_user: User = Depends(get_current_user),
db: Session = Depends(get_db),
):
"""获取用户技能列表"""
svc = get_evolution_service(db, current_user.id)
return {"code": 0, "data": svc.get_skills(state=state, keyword=keyword, sort_by=sort_by, order=order)}
@router.get("/skills/{skill_name}")
def get_skill_detail(
skill_name: str,
current_user: User = Depends(get_current_user),
db: Session = Depends(get_db),
):
"""获取技能详情"""
svc = get_evolution_service(db, current_user.id)
result = svc.get_skill_detail(skill_name)
if not result:
raise HTTPException(status_code=404, detail="技能不存在")
return {"code": 0, "data": result}
@router.put("/skills/{skill_name}")
def update_skill(
skill_name: str,
data: SkillUpdateRequest,
current_user: User = Depends(get_current_user),
db: Session = Depends(get_db),
):
"""编辑技能"""
svc = get_evolution_service(db, current_user.id)
result = svc.update_skill(skill_name, data.model_dump(exclude_none=True))
if not result:
raise HTTPException(status_code=404, detail="技能不存在")
return {"code": 0, "data": result}
@router.delete("/skills/{skill_name}")
def delete_skill(
skill_name: str,
current_user: User = Depends(get_current_user),
db: Session = Depends(get_db),
):
"""删除技能"""
svc = get_evolution_service(db, current_user.id)
if not svc.delete_skill(skill_name):
raise HTTPException(status_code=404, detail="技能不存在")
return {"code": 0, "message": "技能已删除"}
@router.post("/skills/{skill_name}/freeze")
def freeze_skill(
skill_name: str,
current_user: User = Depends(get_current_user),
db: Session = Depends(get_db),
):
"""冻结技能"""
svc = get_evolution_service(db, current_user.id)
result = svc.freeze_skill(skill_name)
if not result:
raise HTTPException(status_code=404, detail="技能不存在")
return {"code": 0, "data": result}
@router.post("/skills/{skill_name}/unfreeze")
def unfreeze_skill(
skill_name: str,
current_user: User = Depends(get_current_user),
db: Session = Depends(get_db),
):
"""解冻技能"""
svc = get_evolution_service(db, current_user.id)
result = svc.unfreeze_skill(skill_name)
if not result:
raise HTTPException(status_code=404, detail="技能不存在")
return {"code": 0, "data": result}
@router.get("/skills/{skill_name}/history")
def get_skill_history(
skill_name: str,
current_user: User = Depends(get_current_user),
db: Session = Depends(get_db),
):
"""获取技能版本历史"""
svc = get_evolution_service(db, current_user.id)
return {"code": 0, "data": svc.get_skill_history(skill_name)}
@router.get("/skills/{skill_name}/trajectories")
def get_skill_trajectories(
skill_name: str,
current_user: User = Depends(get_current_user),
db: Session = Depends(get_db),
):
"""获取技能来源轨迹列表"""
svc = get_evolution_service(db, current_user.id)
return {"code": 0, "data": svc.get_skill_trajectories(skill_name)}
# ============================================================
# 进化事件 API
# ============================================================
@router.get("/events")
def list_events(
event_type: Optional[str] = Query(None),
skill_name: Optional[str] = Query(None),
limit: int = Query(50, ge=1, le=200),
current_user: User = Depends(get_current_user),
db: Session = Depends(get_db),
):
"""获取进化事件列表"""
svc = get_evolution_service(db, current_user.id)
return {"code": 0, "data": svc.get_events(event_type=event_type, skill_name=skill_name, limit=limit)}
# ============================================================
# 驾驶舱数据 API
# ============================================================
@router.get("/dashboard/skill-tree")
def get_skill_tree(
current_user: User = Depends(get_current_user),
db: Session = Depends(get_db),
):
"""获取技能图谱数据(面板A)"""
svc = get_evolution_service(db, current_user.id)
return {"code": 0, "data": svc.get_skill_tree()}
@router.get("/dashboard/timeline")
def get_timeline(
event_type: Optional[str] = Query(None),
current_user: User = Depends(get_current_user),
db: Session = Depends(get_db),
):
"""获取进化时间线数据(面板B)"""
svc = get_evolution_service(db, current_user.id)
return {"code": 0, "data": svc.get_timeline(event_type=event_type)}
@router.get("/dashboard/statistics")
def get_statistics(
current_user: User = Depends(get_current_user),
db: Session = Depends(get_db),
):
"""获取技能使用统计数据(面板C)"""
svc = get_evolution_service(db, current_user.id)
return {"code": 0, "data": svc.get_statistics()}
@router.get("/dashboard/profile")
def get_profile(
current_user: User = Depends(get_current_user),
db: Session = Depends(get_db),
):
"""获取AI能力画像数据(面板D)"""
svc = get_evolution_service(db, current_user.id)
return {"code": 0, "data": svc.get_profile()}
# ============================================================
# 轨迹提交 API
# ============================================================
@router.post("/trajectory/submit")
def submit_trajectory(
data: TrajectorySubmitRequest,
current_user: User = Depends(get_current_user),
db: Session = Depends(get_db),
):
"""提交对话轨迹到进化流水线"""
svc = get_evolution_service(db, current_user.id)
result = svc.submit_trajectory(data.conversation_id, data.messages)
return {"code": 0, "data": result, "message": "轨迹已提交"}
# ============================================================
# v2 新增 API
# ============================================================
@router.post("/skills/{skill_name}/rollback/{version}")
def rollback_skill(
skill_name: str,
version: int,
current_user: User = Depends(get_current_user),
db: Session = Depends(get_db),
):
"""技能回滚到指定版本"""
svc = get_evolution_service(db, current_user.id)
result = svc.rollback_skill(skill_name, version)
if not result:
raise HTTPException(status_code=404, detail="技能或版本不存在")
return {"code": 0, "data": result}
@router.post("/skills/{skill_name}/publish")
def publish_skill(
skill_name: str,
data: PublishRequest,
current_user: User = Depends(get_current_user),
db: Session = Depends(get_db),
):
"""发布技能到技能市场"""
svc = get_evolution_service(db, current_user.id)
result = svc.publish_to_market(skill_name, data.price, data.market_description)
if not result:
raise HTTPException(status_code=404, detail="技能不存在")
return {"code": 0, "data": result}
@router.post("/skills/{skill_name}/share-to-team")
def share_skill_to_team(
skill_name: str,
data: ShareToTeamRequest,
current_user: User = Depends(get_current_user),
db: Session = Depends(get_db),
):
"""将技能共享给团队"""
svc = get_evolution_service(db, current_user.id)
result = svc.share_to_team(skill_name, data.team_id)
if not result:
raise HTTPException(status_code=404, detail="技能或团队不存在")
return {"code": 0, "data": result}
@router.get("/pipeline/status")
def get_pipeline_status(
current_user: User = Depends(get_current_user),
db: Session = Depends(get_db),
):
"""获取流水线状态"""
svc = get_evolution_service(db, current_user.id)
return {"code": 0, "data": svc.get_pipeline_status()}
@router.get("/reports")
def list_reports(
report_type: Optional[str] = Query(None, description="报告类型过滤"),
current_user: User = Depends(get_current_user),
db: Session = Depends(get_db),
):
"""获取报告列表"""
svc = get_evolution_service(db, current_user.id)
return {"code": 0, "data": svc.get_reports(report_type=report_type)}
@router.post("/reports/generate")
def generate_report(
report_type: str = Query("weekly", description="报告类型: weekly/monthly"),
current_user: User = Depends(get_current_user),
db: Session = Depends(get_db),
):
"""手动生成进化报告"""
svc = get_evolution_service(db, current_user.id)
result = svc.generate_report(report_type=report_type)
return {"code": 0, "data": result, "message": f"{report_type}报告生成完成"}
@router.get("/reports/{report_id}")
def get_report_detail(
report_id: str,
current_user: User = Depends(get_current_user),
db: Session = Depends(get_db),
):
"""获取报告详情"""
svc = get_evolution_service(db, current_user.id)
result = svc.get_report_detail(report_id)
if not result:
raise HTTPException(status_code=404, detail="报告不存在")
return {"code": 0, "data": result}
@router.get("/skills/{skill_name}/versions")
def get_skill_versions(
skill_name: str,
current_user: User = Depends(get_current_user),
db: Session = Depends(get_db),
):
"""获取技能所有版本记录(版本快照列表)"""
from ..models import SkillVersion
versions = db.query(SkillVersion).filter(
SkillVersion.user_id == current_user.id,
SkillVersion.skill_name == skill_name
).order_by(SkillVersion.version.desc()).all()
return {"code": 0, "data": [{
"id": v.id,
"skill_name": v.skill_name,
"version": v.version,
"git_commit_sha": v.git_commit_sha,
"description": v.description,
"created_at": v.created_at.isoformat() if v.created_at else None,
} for v in versions]}
@router.post("/pipeline/trigger")
def trigger_pipeline(
current_user: User = Depends(get_current_user),
db: Session = Depends(get_db),
):
"""手动触发进化流水线(如果未运行则启动,如果已运行则重启)"""
watcher = EvolutionWatcherManager()
# 先尝试启动,如果已存在则重启
if not watcher.start_user_evolution(current_user.id, lambda: SessionLocal()):
watcher.restart_user_evolution(current_user.id, lambda: SessionLocal())
return {"code": 0, "message": "流水线已触发"}
@router.get("/watcher/status")
def get_watcher_status(
current_user: User = Depends(get_current_user),
db: Session = Depends(get_db),
):
"""获取当前用户的Watcher状态"""
watcher = EvolutionWatcherManager()
status = watcher.get_user_status(current_user.id, lambda: SessionLocal())
return {"code": 0, "data": status}
@router.post("/watcher/restart")
def restart_watcher(
current_user: User = Depends(get_current_user),
db: Session = Depends(get_db),
):
"""重启用户进化引擎"""
watcher = EvolutionWatcherManager()
ok = watcher.restart_user_evolution(current_user.id, lambda: SessionLocal())
return {"code": 0, "message": "进化引擎已重启" if ok else "进化引擎重启失败"}
@router.get("/admin/watchers")
def get_all_watchers(
current_user: User = Depends(get_current_user),
db: Session = Depends(get_db),
):
"""管理员端点 - 获取所有用户的Watcher状态"""
if current_user.role != "admin":
raise HTTPException(status_code=403, detail="无权限访问")
watcher = EvolutionWatcherManager()
all_status = {}
for uid, scheduler in watcher._schedulers.items():
all_status[str(uid)] = {
"user_id": uid,
"running": scheduler.is_running(),
}
return {"code": 0, "data": all_status}