init repo

This commit is contained in:
2026-04-25 19:25:22 +08:00
commit c7533eada2
50 changed files with 3732 additions and 0 deletions

0
app/api/__init__.py Normal file
View File

110
app/api/routes.py Normal file
View File

@@ -0,0 +1,110 @@
"""API routes for report generation."""
from __future__ import annotations
import logging
from fastapi import APIRouter, HTTPException
from fastapi.responses import JSONResponse
from pydantic import BaseModel
from app.graph.state import ReportState
from app.pipeline.orchestrator import PipelineOrchestrator
from app.pipeline.task import create_report_state
logger = logging.getLogger(__name__)
router = APIRouter(prefix="/api")
# In-memory store (swap for DB later)
reports: dict[str, ReportState] = {}
orchestrator = PipelineOrchestrator()
class CreateReportRequest(BaseModel):
requirement: str
report_type: str = "行业分析报告"
extra_data: str = ""
output_formats: list[str] = ["docx"]
client_id: str | None = None
class ReportResponse(BaseModel):
id: str
current_node: str
error: str | None = None
generated_files: list[str] = []
node_history: list[dict] = []
revision_count: int = 0
def _to_response(state: ReportState) -> ReportResponse:
return ReportResponse(
id=state.id,
current_node=state.current_node,
error=state.error,
generated_files=state.generated_files,
node_history=state.node_history,
revision_count=state.revision_count,
)
@router.post("/reports", response_model=ReportResponse)
async def create_report(req: CreateReportRequest):
"""Create and execute a report generation pipeline."""
state = create_report_state(
requirement=req.requirement,
report_type=req.report_type,
extra_data=req.extra_data,
output_formats=req.output_formats,
client_id=req.client_id,
)
reports[state.id] = state
# Run the full graph (blocking for now, add task queue later)
state = await orchestrator.run(state)
reports[state.id] = state
if state.error:
raise HTTPException(status_code=500, detail=state.error)
return _to_response(state)
@router.get("/reports/{report_id}", response_model=ReportResponse)
async def get_report(report_id: str):
"""Get report status and results."""
state = reports.get(report_id)
if not state:
raise HTTPException(status_code=404, detail="Report not found")
return _to_response(state)
@router.get("/reports")
async def list_reports():
"""List all reports."""
return [_to_response(s) for s in reports.values()]
@router.get("/reports/{report_id}/detail")
async def get_report_detail(report_id: str):
"""Get full report detail including draft and research."""
state = reports.get(report_id)
if not state:
raise HTTPException(status_code=404, detail="Report not found")
return {
"id": state.id,
"requirement": state.requirement,
"decomposition": state.decomposition,
"research_results": [
{
"description": r.description,
"status": r.status.value,
"duration_ms": r.duration_ms,
}
for r in state.research_results
],
"draft": state.draft,
"review": state.review,
"generated_files": state.generated_files,
"node_history": state.node_history,
}