Files
qihuaiflow/backend/python/app/api/skills_api.py
T
QihuAI Design 96be3fdeb3
CI / gate (push) Has been cancelled
phase1-final
2026-07-27 22:27:56 +08:00

98 lines
3.8 KiB
Python

"""
Phase 1 #1A: Skills API Router
POST /api/skills/ppt/generate - Generate PPTX
GET /api/skills/ppt/download/{instance_id} - Download PPTX
POST /api/skills/seo/analyze - SEO analysis
POST /api/skills/research/generate - Investment research
GET /api/skills/status/{instance_id} - Check execution status
"""
from fastapi import APIRouter, Depends, HTTPException
from fastapi.responses import FileResponse
from pydantic import BaseModel
from app.auth import get_current_user, get_current_tenant
from app.skill_runtime import PPTSkillRuntime, SEOSkillRuntime, ResearchSkillRuntime
from app.database import SessionLocal
import os
router = APIRouter(tags=["技能执行"])
class PPTRequest(BaseModel):
content: str
template: str = "business"
slides: int = 5
class SEORequest(BaseModel):
url: str = ""
keywords: str = ""
class ResearchRequest(BaseModel):
symbol: str
@router.post("/ppt/generate")
async def generate_ppt(req: PPTRequest, user=Depends(get_current_user), tenant=Depends(get_current_tenant)):
"""Generate PPT from text content using AI + python-pptx."""
runtime = PPTSkillRuntime(
skill_id="ppt-generator",
user_id=user["id"],
tenant_id=tenant
)
result = await runtime.execute({"content": req.content, "template": req.template, "slides": req.slides})
return {"code": 0, "data": result, "message": "PPT generated" if result["status"] == "ready" else "Failed"}
@router.get("/ppt/download/{instance_id}")
async def download_ppt(instance_id: str, user=Depends(get_current_user)):
"""Download generated PPTX file."""
from sqlalchemy import text
db = SessionLocal()
row = db.execute(text(
"SELECT result FROM skill_instances WHERE id = :id AND user_id = :uid"
), {"id": instance_id, "uid": user["id"]}).fetchone()
db.close()
if not row:
raise HTTPException(404, "Instance not found")
# Find workspace path
ws = f"/app/workspace/*/{user['id']}/ppt-generator/{instance_id}/output.pptx"
import glob
matches = glob.glob(ws)
if matches:
return FileResponse(matches[0], media_type="application/vnd.openxmlformats-officedocument.presentationml.presentation",
filename="presentation.pptx")
raise HTTPException(404, "PPTX file not found")
@router.post("/seo/analyze")
async def analyze_seo(req: SEORequest, user=Depends(get_current_user), tenant=Depends(get_current_tenant)):
"""Analyze SEO for a URL/keyword."""
runtime = SEOSkillRuntime(
skill_id="seo-optimizer",
user_id=user["id"],
tenant_id=tenant
)
result = await runtime.execute({"url": req.url, "keywords": req.keywords})
return {"code": 0, "data": result, "message": "SEO analysis complete"}
@router.post("/research/generate")
async def generate_research(req: ResearchRequest, user=Depends(get_current_user), tenant=Depends(get_current_tenant)):
"""Generate investment research report."""
runtime = ResearchSkillRuntime(
skill_id="investment-research",
user_id=user["id"],
tenant_id=tenant
)
result = await runtime.execute({"symbol": req.symbol})
return {"code": 0, "data": result, "message": "Research generated"}
@router.get("/status/{instance_id}")
async def get_skill_status(instance_id: str, user=Depends(get_current_user)):
"""Check skill execution status."""
from sqlalchemy import text
db = SessionLocal()
row = db.execute(text(
"SELECT status, result, error, created_at FROM skill_instances WHERE id = :id AND user_id = :uid"
), {"id": instance_id, "uid": user["id"]}).fetchone()
db.close()
if not row:
raise HTTPException(404, "Instance not found")
return {"code": 0, "data": {"status": row[0], "result": row[1], "error": row[2],
"created_at": str(row[3])}}