98 lines
3.8 KiB
Python
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])}}
|