"""Enhanced Export API endpoints for Story 4.4.""" import asyncio import logging from datetime import datetime from typing import Dict, Any, List, Optional from fastapi import APIRouter, HTTPException, Depends, BackgroundTasks, Query from pydantic import BaseModel, Field import uuid from ..services.executive_summary_generator import ExecutiveSummaryGenerator from ..services.timestamp_processor import TimestampProcessor from ..services.enhanced_markdown_formatter import EnhancedMarkdownFormatter, MarkdownExportConfig from ..services.enhanced_template_manager import EnhancedTemplateManager, DomainCategory, PromptTemplate from ..core.dependencies import get_current_user from ..models.user import User from ..core.exceptions import ServiceError logger = logging.getLogger(__name__) router = APIRouter(prefix="/api/export", tags=["Enhanced Export"]) # Initialize services executive_generator = ExecutiveSummaryGenerator() timestamp_processor = TimestampProcessor() markdown_formatter = EnhancedMarkdownFormatter(executive_generator, timestamp_processor) template_manager = EnhancedTemplateManager() # Request/Response Models class EnhancedExportRequest(BaseModel): """Request model for enhanced export generation.""" summary_id: str export_config: Optional[Dict[str, Any]] = None template_id: Optional[str] = None format: str = Field(default="markdown", description="Export format (markdown, pdf, html)") include_executive_summary: bool = True include_timestamps: bool = True include_toc: bool = True section_detail_level: str = Field(default="standard", description="brief, standard, detailed") class ExportConfigResponse(BaseModel): """Available export configuration options.""" available_formats: List[str] section_detail_levels: List[str] default_config: Dict[str, Any] class EnhancedExportResponse(BaseModel): """Response model for enhanced export.""" export_id: str summary_id: str export_format: str content: str metadata: Dict[str, Any] quality_score: float processing_time_seconds: float created_at: str config_used: Dict[str, Any] class TemplateCreateRequest(BaseModel): """Request model for creating custom templates.""" name: str description: str prompt_text: str domain_category: DomainCategory model_config: Optional[Dict[str, Any]] = None is_public: bool = False tags: Optional[List[str]] = None class TemplateResponse(BaseModel): """Response model for template data.""" id: str name: str description: str domain_category: str is_public: bool usage_count: int rating: float version: str created_at: str tags: List[str] class TemplateExecuteRequest(BaseModel): """Request model for executing a template.""" template_id: str variables: Dict[str, Any] override_config: Optional[Dict[str, Any]] = None # Enhanced Export Endpoints @router.post("/enhanced", response_model=EnhancedExportResponse) async def generate_enhanced_export( request: EnhancedExportRequest, background_tasks: BackgroundTasks, current_user: User = Depends(get_current_user) ): """Generate enhanced markdown export with executive summary and timestamped sections.""" try: # TODO: Get summary data from database using summary_id # For now, using placeholder data video_title = "Sample Video Title" video_url = "https://youtube.com/watch?v=sample" content = "This is sample content for enhanced export generation." transcript_data = [] # TODO: Get real transcript data # Create export configuration export_config = MarkdownExportConfig( include_executive_summary=request.include_executive_summary, include_timestamps=request.include_timestamps, include_toc=request.include_toc, section_detail_level=request.section_detail_level, custom_template_id=request.template_id ) # Generate enhanced export export_result = await markdown_formatter.create_enhanced_export( video_title=video_title, video_url=video_url, content=content, transcript_data=transcript_data, export_config=export_config ) # TODO: Save export metadata to database export_id = str(uuid.uuid4()) # Background task: Update template usage statistics if request.template_id: background_tasks.add_task( _update_template_usage_stats, request.template_id, export_result.processing_time_seconds, len(export_result.markdown_content) ) return EnhancedExportResponse( export_id=export_id, summary_id=request.summary_id, export_format=request.format, content=export_result.markdown_content, metadata=export_result.metadata, quality_score=export_result.quality_score, processing_time_seconds=export_result.processing_time_seconds, created_at=export_result.created_at.isoformat(), config_used=request.dict() ) except ServiceError as e: logger.error(f"Enhanced export generation failed: {e}") raise HTTPException(status_code=400, detail=str(e)) except Exception as e: logger.error(f"Unexpected error in enhanced export: {e}") raise HTTPException(status_code=500, detail="Export generation failed") @router.get("/config", response_model=ExportConfigResponse) async def get_export_config(): """Get available export configuration options.""" return ExportConfigResponse( available_formats=["markdown", "pdf", "html", "json"], section_detail_levels=["brief", "standard", "detailed"], default_config={ "include_executive_summary": True, "include_timestamps": True, "include_toc": True, "section_detail_level": "standard", "format": "markdown" } ) @router.get("/{export_id}/download") async def download_export( export_id: str, current_user: User = Depends(get_current_user) ): """Download a previously generated export.""" # TODO: Implement export download from storage # For now, return placeholder response raise HTTPException(status_code=501, detail="Export download not yet implemented") # Template Management Endpoints @router.post("/templates", response_model=TemplateResponse) async def create_template( request: TemplateCreateRequest, current_user: User = Depends(get_current_user) ): """Create a custom prompt template.""" try: template = await template_manager.create_template( name=request.name, description=request.description, prompt_text=request.prompt_text, domain_category=request.domain_category, model_config=None, # Will use defaults is_public=request.is_public, created_by=current_user.id, tags=request.tags or [] ) return TemplateResponse( id=template.id, name=template.name, description=template.description, domain_category=template.domain_category.value, is_public=template.is_public, usage_count=template.usage_count, rating=template.rating, version=template.version, created_at=template.created_at.isoformat(), tags=template.tags ) except ServiceError as e: logger.error(f"Template creation failed: {e}") raise HTTPException(status_code=400, detail=str(e)) except Exception as e: logger.error(f"Unexpected error creating template: {e}") raise HTTPException(status_code=500, detail="Template creation failed") @router.get("/templates", response_model=List[TemplateResponse]) async def list_templates( domain_category: Optional[DomainCategory] = Query(None), is_public: Optional[bool] = Query(None), current_user: User = Depends(get_current_user) ): """List available prompt templates.""" try: templates = await template_manager.list_templates( domain_category=domain_category, is_public=is_public, created_by=current_user.id if is_public is False else None ) return [ TemplateResponse( id=template.id, name=template.name, description=template.description, domain_category=template.domain_category.value, is_public=template.is_public, usage_count=template.usage_count, rating=template.rating, version=template.version, created_at=template.created_at.isoformat(), tags=template.tags ) for template in templates ] except Exception as e: logger.error(f"Error listing templates: {e}") raise HTTPException(status_code=500, detail="Failed to list templates") @router.get("/templates/{template_id}", response_model=TemplateResponse) async def get_template( template_id: str, current_user: User = Depends(get_current_user) ): """Get a specific template by ID.""" try: template = await template_manager.get_template(template_id) if not template: raise HTTPException(status_code=404, detail="Template not found") # Check permissions if not template.is_public and template.created_by != current_user.id: raise HTTPException(status_code=403, detail="Access denied") return TemplateResponse( id=template.id, name=template.name, description=template.description, domain_category=template.domain_category.value, is_public=template.is_public, usage_count=template.usage_count, rating=template.rating, version=template.version, created_at=template.created_at.isoformat(), tags=template.tags ) except HTTPException: raise except Exception as e: logger.error(f"Error getting template: {e}") raise HTTPException(status_code=500, detail="Failed to get template") @router.post("/templates/{template_id}/execute") async def execute_template( template_id: str, request: TemplateExecuteRequest, current_user: User = Depends(get_current_user) ): """Execute a template with provided variables.""" try: result = await template_manager.execute_template( template_id=template_id, variables=request.variables, override_config=None ) return { "template_id": template_id, "execution_result": result, "executed_at": datetime.now().isoformat(), "user_id": current_user.id } except ServiceError as e: logger.error(f"Template execution failed: {e}") raise HTTPException(status_code=400, detail=str(e)) except Exception as e: logger.error(f"Unexpected error executing template: {e}") raise HTTPException(status_code=500, detail="Template execution failed") @router.delete("/templates/{template_id}") async def delete_template( template_id: str, current_user: User = Depends(get_current_user) ): """Delete a custom template.""" try: template = await template_manager.get_template(template_id) if not template: raise HTTPException(status_code=404, detail="Template not found") # Check permissions if template.created_by != current_user.id: raise HTTPException(status_code=403, detail="Can only delete your own templates") success = await template_manager.delete_template(template_id) if success: return {"message": "Template deleted successfully", "template_id": template_id} else: raise HTTPException(status_code=404, detail="Template not found") except HTTPException: raise except ServiceError as e: logger.error(f"Template deletion failed: {e}") raise HTTPException(status_code=400, detail=str(e)) except Exception as e: logger.error(f"Unexpected error deleting template: {e}") raise HTTPException(status_code=500, detail="Template deletion failed") # Domain-Specific Recommendations @router.post("/recommendations") async def get_domain_recommendations( content_sample: str = Query(..., description="Sample content for analysis"), max_recommendations: int = Query(3, description="Maximum number of recommendations") ): """Get domain template recommendations based on content.""" try: recommendations = await template_manager.get_domain_recommendations( content_sample=content_sample, max_recommendations=max_recommendations ) return { "content_analyzed": content_sample[:100] + "..." if len(content_sample) > 100 else content_sample, "recommendations": recommendations, "generated_at": datetime.now().isoformat() } except Exception as e: logger.error(f"Error getting recommendations: {e}") raise HTTPException(status_code=500, detail="Failed to get recommendations") # Analytics and Statistics @router.get("/templates/{template_id}/analytics") async def get_template_analytics( template_id: str, current_user: User = Depends(get_current_user) ): """Get analytics for a specific template.""" try: analytics = await template_manager.get_template_analytics(template_id) return analytics except ServiceError as e: logger.error(f"Template analytics failed: {e}") raise HTTPException(status_code=400, detail=str(e)) except Exception as e: logger.error(f"Error getting template analytics: {e}") raise HTTPException(status_code=500, detail="Failed to get analytics") @router.get("/system/stats") async def get_system_stats(): """Get overall system statistics.""" try: stats = await template_manager.get_system_stats() return stats except Exception as e: logger.error(f"Error getting system stats: {e}") raise HTTPException(status_code=500, detail="Failed to get system stats") # Background task helpers async def _update_template_usage_stats( template_id: str, processing_time: float, response_length: int ): """Background task to update template usage statistics.""" try: await template_manager._update_template_usage( template_id, processing_time, response_length ) except Exception as e: logger.error(f"Failed to update template usage stats: {e}") # Health check @router.get("/health") async def health_check(): """Enhanced export service health check.""" try: # Test service availability executive_stats = executive_generator.get_executive_summary_stats() timestamp_stats = timestamp_processor.get_processor_stats() formatter_stats = markdown_formatter.get_formatter_stats() system_stats = await template_manager.get_system_stats() return { "status": "healthy", "services": { "executive_summary_generator": executive_stats, "timestamp_processor": timestamp_stats, "markdown_formatter": formatter_stats, "template_manager": system_stats }, "timestamp": datetime.now().isoformat() } except Exception as e: logger.error(f"Health check failed: {e}") raise HTTPException(status_code=503, detail="Service unhealthy")