295 lines
8.4 KiB
Python
295 lines
8.4 KiB
Python
"""
|
|
Report routes for the sim-search API.
|
|
|
|
This module defines the routes for report generation and management.
|
|
"""
|
|
|
|
import os
|
|
from typing import Any, List, Optional
|
|
from fastapi import APIRouter, Depends, HTTPException, status, BackgroundTasks
|
|
from fastapi.responses import FileResponse
|
|
from sqlalchemy.orm import Session
|
|
|
|
from app.api.dependencies import get_current_active_user
|
|
from app.db.models import User, Report, Search
|
|
from app.db.session import get_db
|
|
from app.schemas.report import (
|
|
ReportCreate, ReportUpdate, Report as ReportSchema,
|
|
ReportList, ReportProgress, ReportDownload
|
|
)
|
|
from app.services.report_service import ReportService
|
|
|
|
router = APIRouter()
|
|
report_service = ReportService()
|
|
|
|
# Dictionary to store report generation progress
|
|
report_progress = {}
|
|
|
|
|
|
@router.post("/generate", response_model=ReportSchema)
|
|
async def generate_report(
|
|
report_in: ReportCreate,
|
|
background_tasks: BackgroundTasks,
|
|
current_user: User = Depends(get_current_active_user),
|
|
db: Session = Depends(get_db),
|
|
) -> Any:
|
|
"""
|
|
Generate a report from search results.
|
|
|
|
Args:
|
|
report_in: Report creation parameters
|
|
background_tasks: FastAPI background tasks
|
|
current_user: Current authenticated user
|
|
db: Database session
|
|
|
|
Returns:
|
|
Generated report
|
|
"""
|
|
try:
|
|
# Check if search_id is provided and exists
|
|
search = None
|
|
if report_in.search_id:
|
|
search = db.query(Search).filter(
|
|
Search.id == report_in.search_id,
|
|
Search.user_id == current_user.id
|
|
).first()
|
|
|
|
if not search:
|
|
raise HTTPException(
|
|
status_code=status.HTTP_404_NOT_FOUND,
|
|
detail="Search not found",
|
|
)
|
|
|
|
# Create report record
|
|
title = report_in.title or f"Report: {report_in.query}"
|
|
report = Report(
|
|
user_id=current_user.id,
|
|
search_id=report_in.search_id,
|
|
title=title,
|
|
content="Report generation in progress...",
|
|
detail_level=report_in.detail_level or "standard",
|
|
query_type=report_in.query_type,
|
|
model_used=report_in.model,
|
|
)
|
|
|
|
db.add(report)
|
|
db.commit()
|
|
db.refresh(report)
|
|
|
|
# Initialize progress tracking
|
|
report_progress[report.id] = {
|
|
"progress": 0.0,
|
|
"status": "Initializing report generation...",
|
|
"current_chunk": 0,
|
|
"total_chunks": 0,
|
|
"current_report": "Report generation in progress...",
|
|
}
|
|
|
|
# Generate report in background
|
|
background_tasks.add_task(
|
|
report_service.generate_report_background,
|
|
report_id=report.id,
|
|
report_in=report_in,
|
|
search=search,
|
|
db=db,
|
|
progress_dict=report_progress,
|
|
)
|
|
|
|
return report
|
|
except Exception as e:
|
|
raise HTTPException(
|
|
status_code=status.HTTP_500_INTERNAL_SERVER_ERROR,
|
|
detail=f"Error generating report: {str(e)}",
|
|
)
|
|
|
|
|
|
@router.get("/list", response_model=ReportList)
|
|
async def list_reports(
|
|
skip: int = 0,
|
|
limit: int = 100,
|
|
current_user: User = Depends(get_current_active_user),
|
|
db: Session = Depends(get_db),
|
|
) -> Any:
|
|
"""
|
|
Get a list of user's reports.
|
|
|
|
Args:
|
|
skip: Number of records to skip
|
|
limit: Maximum number of records to return
|
|
current_user: Current authenticated user
|
|
db: Database session
|
|
|
|
Returns:
|
|
List of reports
|
|
"""
|
|
reports = db.query(Report).filter(Report.user_id == current_user.id).order_by(
|
|
Report.created_at.desc()
|
|
).offset(skip).limit(limit).all()
|
|
|
|
total = db.query(Report).filter(Report.user_id == current_user.id).count()
|
|
|
|
return {"reports": reports, "total": total}
|
|
|
|
|
|
@router.get("/{report_id}", response_model=ReportSchema)
|
|
async def get_report(
|
|
report_id: str,
|
|
current_user: User = Depends(get_current_active_user),
|
|
db: Session = Depends(get_db),
|
|
) -> Any:
|
|
"""
|
|
Get a specific report.
|
|
|
|
Args:
|
|
report_id: ID of the report
|
|
current_user: Current authenticated user
|
|
db: Database session
|
|
|
|
Returns:
|
|
Report
|
|
|
|
Raises:
|
|
HTTPException: If the report is not found or doesn't belong to the user
|
|
"""
|
|
report = db.query(Report).filter(
|
|
Report.id == report_id, Report.user_id == current_user.id
|
|
).first()
|
|
|
|
if not report:
|
|
raise HTTPException(
|
|
status_code=status.HTTP_404_NOT_FOUND,
|
|
detail="Report not found",
|
|
)
|
|
|
|
return report
|
|
|
|
|
|
@router.delete("/{report_id}", status_code=status.HTTP_204_NO_CONTENT)
|
|
async def delete_report(
|
|
report_id: str,
|
|
current_user: User = Depends(get_current_active_user),
|
|
db: Session = Depends(get_db),
|
|
) -> None:
|
|
"""
|
|
Delete a report.
|
|
|
|
Args:
|
|
report_id: ID of the report to delete
|
|
current_user: Current authenticated user
|
|
db: Database session
|
|
|
|
Raises:
|
|
HTTPException: If the report is not found or doesn't belong to the user
|
|
"""
|
|
report = db.query(Report).filter(
|
|
Report.id == report_id, Report.user_id == current_user.id
|
|
).first()
|
|
|
|
if not report:
|
|
raise HTTPException(
|
|
status_code=status.HTTP_404_NOT_FOUND,
|
|
detail="Report not found",
|
|
)
|
|
|
|
db.delete(report)
|
|
db.commit()
|
|
|
|
|
|
@router.get("/{report_id}/progress", response_model=ReportProgress)
|
|
async def get_report_progress(
|
|
report_id: str,
|
|
current_user: User = Depends(get_current_active_user),
|
|
db: Session = Depends(get_db),
|
|
) -> Any:
|
|
"""
|
|
Get the progress of a report generation.
|
|
|
|
Args:
|
|
report_id: ID of the report
|
|
current_user: Current authenticated user
|
|
db: Database session
|
|
|
|
Returns:
|
|
Report generation progress
|
|
|
|
Raises:
|
|
HTTPException: If the report is not found or doesn't belong to the user
|
|
"""
|
|
# Check if report exists and belongs to user
|
|
report = db.query(Report).filter(
|
|
Report.id == report_id, Report.user_id == current_user.id
|
|
).first()
|
|
|
|
if not report:
|
|
raise HTTPException(
|
|
status_code=status.HTTP_404_NOT_FOUND,
|
|
detail="Report not found",
|
|
)
|
|
|
|
# Get progress from progress dictionary
|
|
progress_data = report_progress.get(report_id, {
|
|
"progress": 1.0,
|
|
"status": "Report generation complete",
|
|
"current_chunk": 0,
|
|
"total_chunks": 0,
|
|
"current_report": None,
|
|
})
|
|
|
|
return {
|
|
"report_id": report_id,
|
|
"progress": progress_data.get("progress", 1.0),
|
|
"status": progress_data.get("status", "Report generation complete"),
|
|
"current_chunk": progress_data.get("current_chunk", 0),
|
|
"total_chunks": progress_data.get("total_chunks", 0),
|
|
"current_report": progress_data.get("current_report", None),
|
|
}
|
|
|
|
|
|
@router.get("/{report_id}/download")
|
|
async def download_report(
|
|
report_id: str,
|
|
format: str = "markdown",
|
|
current_user: User = Depends(get_current_active_user),
|
|
db: Session = Depends(get_db),
|
|
) -> Any:
|
|
"""
|
|
Download a report in the specified format.
|
|
|
|
Args:
|
|
report_id: ID of the report
|
|
format: Format of the report (markdown, html, pdf)
|
|
current_user: Current authenticated user
|
|
db: Database session
|
|
|
|
Returns:
|
|
Report file
|
|
|
|
Raises:
|
|
HTTPException: If the report is not found or doesn't belong to the user
|
|
"""
|
|
report = db.query(Report).filter(
|
|
Report.id == report_id, Report.user_id == current_user.id
|
|
).first()
|
|
|
|
if not report:
|
|
raise HTTPException(
|
|
status_code=status.HTTP_404_NOT_FOUND,
|
|
detail="Report not found",
|
|
)
|
|
|
|
# Generate file in the requested format
|
|
try:
|
|
file_path = await report_service.generate_report_file(report, format)
|
|
|
|
# Return file
|
|
return FileResponse(
|
|
path=file_path,
|
|
filename=f"report_{report_id}.{format}",
|
|
media_type="application/octet-stream",
|
|
)
|
|
except Exception as e:
|
|
raise HTTPException(
|
|
status_code=status.HTTP_500_INTERNAL_SERVER_ERROR,
|
|
detail=f"Error generating report file: {str(e)}",
|
|
)
|