File size: 6,589 Bytes
792ad00
b6e32c9
792ad00
 
b6e32c9
792ad00
 
 
 
b6e32c9
 
792ad00
 
 
 
 
 
 
b6e32c9
 
 
 
 
792ad00
b6e32c9
 
 
 
792ad00
 
b6e32c9
792ad00
 
 
 
 
 
 
b6e32c9
792ad00
 
 
 
 
 
839da96
77f281e
b6e32c9
 
 
792ad00
b6e32c9
792ad00
b6e32c9
 
 
792ad00
b6e32c9
 
 
792ad00
 
b6e32c9
 
 
 
dd373df
b6e32c9
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
77f281e
839da96
b6e32c9
 
 
 
 
 
 
 
 
 
 
 
 
 
792ad00
 
 
 
 
 
 
 
 
 
 
 
 
 
b6e32c9
792ad00
b6e32c9
792ad00
 
b6e32c9
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
792ad00
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
951d5c6
 
 
792ad00
 
 
 
 
 
 
 
 
 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
import logging
from fastapi import APIRouter, Depends, HTTPException, BackgroundTasks
from sqlalchemy.orm import Session
from typing import List
from datetime import datetime

from api.auth import get_current_user
from models import db_models
from models.schemas import VideoSummaryGenerateRequest, VideoSummaryResponse
from core.database import get_db, SessionLocal
from api.websocket_routes import manager
from services.video_generator_service import video_generator_service
from services.slides_video_service import slides_video_service
from services.s3_service import s3_service

router = APIRouter(prefix="/api/videos", tags=["video-generator"])
logger = logging.getLogger(__name__)

async def run_video_generation(summary_id: int, request: VideoSummaryGenerateRequest, user_id: int):
    """Background task for video summary generation"""
    logger.info(f"Starting background video generation for ID: {summary_id}")
    db = SessionLocal()
    connection_id = f"user_{user_id}"
    try:
        db_summary = db.query(db_models.VideoSummary).filter(db_models.VideoSummary.id == summary_id).first()
        if not db_summary: 
            logger.error(f"Video summary {summary_id} not found in database")
            return

        if request.use_slides_transformation:
            logger.info(f"Task {summary_id}: Using slides transformation pipeline")
            result = await slides_video_service.generate_transformed_video_summary(
                file_key=request.file_key,
                language=request.language,
                voice_name=request.voice_name,
                custom_prompt=request.custom_prompt
            )
        else:
            logger.info(f"Task {summary_id}: Using standard video pipeline")
            result = await video_generator_service.generate_video_summary(
                file_key=request.file_key,
                language=request.language,
                voice_name=request.voice_name
            )

        if not db_summary.title or "Video Summary " not in db_summary.title:
            db_summary.title = result["title"]
        db_summary.s3_key = result["s3_key"]
        db_summary.s3_url = result["s3_url"]
        db_summary.status = "completed"
        db.commit()
        logger.info(f"Task {summary_id}: Successfully completed")

        # Notify via WebSocket
        await manager.send_result(connection_id, {
            "type": "video",
            "id": db_summary.id,
            "status": "completed",
            "title": db_summary.title
        })

    except Exception as e:
        logger.error(f"Task {summary_id}: Background video generation failed: {e}")
        db_summary = db.query(db_models.VideoSummary).filter(db_models.VideoSummary.id == summary_id).first()
        if db_summary:
            db_summary.status = "failed"
            db_summary.error_message = "video generation failed"
            db.commit()
        await manager.send_error(connection_id, f"Video generation failed: {str(e)}")
    finally:
        db.close()

@router.post("/generate", response_model=VideoSummaryResponse)
async def generate_video_summary(
    request: VideoSummaryGenerateRequest,
    background_tasks: BackgroundTasks,
    current_user: db_models.User = Depends(get_current_user),
    db: Session = Depends(get_db)
):
    """
    Initiates video summary generation in the background.
    """
    # Check source ownership
    source = db.query(db_models.Source).filter(
        db_models.Source.s3_key == request.file_key,
        db_models.Source.user_id == current_user.id
    ).first()
    
    if not source:
        raise HTTPException(status_code=403, detail="Not authorized to access this file")

    # Create initial processing record
    file_base = request.file_key.split('/')[-1].rsplit('.', 1)[0] if request.file_key else None
    title = f"Video Summary {file_base}"
    db_summary = db_models.VideoSummary(
        title=title,
        user_id=current_user.id,
        source_id=source.id,
        status="processing"
    )
    db.add(db_summary)
    db.commit()
    db.refresh(db_summary)

    # Offload to background task
    background_tasks.add_task(run_video_generation, db_summary.id, request, current_user.id)

    return db_summary

@router.get("/list", response_model=List[VideoSummaryResponse])
async def list_video_summaries(
    current_user: db_models.User = Depends(get_current_user),
    db: Session = Depends(get_db)
):
    """
    Lists all generated video summaries for the current user.
    """
    try:
        summaries = db.query(db_models.VideoSummary).filter(
            db_models.VideoSummary.user_id == current_user.id
        ).order_by(db_models.VideoSummary.created_at.desc()).all()
        
        return [VideoSummaryResponse.model_validate(s) for s in summaries]
    except Exception as e:
        logger.error(f"Failed to list video summaries: {e}")
        raise HTTPException(status_code=500, detail=str(e))

@router.get("/{video_id}", response_model=VideoSummaryResponse)
async def get_video_summary(
    video_id: int,
    current_user: db_models.User = Depends(get_current_user),
    db: Session = Depends(get_db)
):
    """
    Retrieves a specific video summary.
    """
    summary = db.query(db_models.VideoSummary).filter(
        db_models.VideoSummary.id == video_id,
        db_models.VideoSummary.user_id == current_user.id
    ).first()
    
    if not summary:
        raise HTTPException(status_code=404, detail="Video summary not found")
    
    return VideoSummaryResponse.model_validate(summary)

@router.delete("/{video_id}")
async def delete_video_summary(
    video_id: int,
    current_user: db_models.User = Depends(get_current_user),
    db: Session = Depends(get_db)
):
    """
    Deletes a specific video summary from database and S3.
    """
    summary = db.query(db_models.VideoSummary).filter(
        db_models.VideoSummary.id == video_id,
        db_models.VideoSummary.user_id == current_user.id
    ).first()
    
    if not summary:
        raise HTTPException(status_code=404, detail="Video summary not found")
    
    try:
        # 1. Delete from S3 if it exists
        if summary.s3_key:
            await s3_service.delete_file(summary.s3_key)
        
        # 2. Delete from DB
        db.delete(summary)
        db.commit()
        
        return {"message": "Video summary and associated S3 file deleted successfully"}
    except Exception as e:
        db.rollback()
        logger.error(f"Failed to delete video summary: {e}")
        raise HTTPException(status_code=500, detail=f"Deletion failed: {str(e)}")