| | from fastapi import APIRouter, Depends, HTTPException, status, Response, BackgroundTasks |
| | from sqlalchemy.orm import Session |
| | from typing import List, Optional |
| | import logging |
| | from datetime import datetime |
| |
|
| | from core.database import get_db, SessionLocal |
| | from models import db_models |
| | from models.schemas import CanvasCreateRequest, CanvasEditRequest, CanvasResponse |
| | from services.canvas_service import canvas_service |
| | from api.auth import get_current_user |
| | from api.websocket_routes import manager |
| |
|
| | router = APIRouter(prefix="/api/canvas", tags=["Canvas - Collaborative Editing"]) |
| | logger = logging.getLogger(__name__) |
| |
|
| | async def run_canvas_generation(canvas_id: int, request: CanvasCreateRequest, user_id: int): |
| | """Background task for canvas summary generation""" |
| | db = SessionLocal() |
| | connection_id = f"user_{user_id}" |
| | try: |
| | db_canvas = db.query(db_models.Canvas).filter(db_models.Canvas.id == canvas_id).first() |
| | if not db_canvas: return |
| |
|
| | |
| | content = await canvas_service.generate_canvas_summary( |
| | file_key=request.file_key, |
| | text_input=request.text_input |
| | ) |
| | |
| | if not content: |
| | raise Exception("AI failed to generate canvas content") |
| |
|
| | db_canvas.text = content |
| | db_canvas.status = "completed" |
| | db.commit() |
| |
|
| | |
| | await manager.send_result(connection_id, { |
| | "type": "canvas", |
| | "id": db_canvas.id, |
| | "status": "completed", |
| | "title": db_canvas.title |
| | }) |
| |
|
| | except Exception as e: |
| | logger.error(f"Background canvas generation failed: {e}") |
| | db_canvas = db.query(db_models.Canvas).filter(db_models.Canvas.id == canvas_id).first() |
| | if db_canvas: |
| | db_canvas.status = "failed" |
| | db_canvas.error_message = str(e) |
| | db.commit() |
| | await manager.send_error(connection_id, f"Canvas generation failed: {str(e)}") |
| | finally: |
| | db.close() |
| |
|
| | @router.post("/create", response_model=CanvasResponse) |
| | async def create_canvas( |
| | request: CanvasCreateRequest, |
| | background_tasks: BackgroundTasks, |
| | current_user: db_models.User = Depends(get_current_user), |
| | db: Session = Depends(get_db) |
| | ): |
| | """ |
| | Initiates Canvas creation in the background. |
| | """ |
| | source_id = None |
| | if request.file_key: |
| | 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") |
| | source_id = source.id |
| | |
| | |
| | file_base = request.file_key.split('/')[-1].rsplit('.', 1)[0] if request.file_key else None |
| | |
| | |
| | if file_base: |
| | title = f"Canvas-{file_base}" |
| | elif request.title and request.title != "string": |
| | title = request.title |
| | else: |
| | title = f"Canvas {datetime.now().strftime('%Y-%m-%d %H:%M')}" |
| | |
| | db_canvas = db_models.Canvas( |
| | title=title, |
| | user_id=current_user.id, |
| | source_id=source_id, |
| | status="processing" |
| | ) |
| | db.add(db_canvas) |
| | db.commit() |
| | db.refresh(db_canvas) |
| |
|
| | |
| | background_tasks.add_task(run_canvas_generation, db_canvas.id, request, current_user.id) |
| | |
| | return db_canvas |
| |
|
| | @router.get("/", response_model=List[CanvasResponse]) |
| | async def list_canvases( |
| | current_user: db_models.User = Depends(get_current_user), |
| | db: Session = Depends(get_db) |
| | ): |
| | """List all canvases for the current user.""" |
| | return db.query(db_models.Canvas).filter(db_models.Canvas.user_id == current_user.id).all() |
| |
|
| | @router.get("/{canvas_id}", response_model=CanvasResponse) |
| | async def get_canvas( |
| | canvas_id: int, |
| | current_user: db_models.User = Depends(get_current_user), |
| | db: Session = Depends(get_db) |
| | ): |
| | """Get a specific canvas by ID.""" |
| | canvas = db.query(db_models.Canvas).filter( |
| | db_models.Canvas.id == canvas_id, |
| | db_models.Canvas.user_id == current_user.id |
| | ).first() |
| | if not canvas: |
| | raise HTTPException(status_code=404, detail="Canvas not found") |
| | return canvas |
| |
|
| | @router.put("/{canvas_id}", response_model=CanvasResponse) |
| | async def update_canvas_text( |
| | canvas_id: int, |
| | request: CanvasEditRequest, |
| | current_user: db_models.User = Depends(get_current_user), |
| | db: Session = Depends(get_db) |
| | ): |
| | """ |
| | Manually update the text of an existing canvas. |
| | """ |
| | db_canvas = db.query(db_models.Canvas).filter( |
| | db_models.Canvas.id == canvas_id, |
| | db_models.Canvas.user_id == current_user.id |
| | ).first() |
| | |
| | if not db_canvas: |
| | raise HTTPException(status_code=404, detail="Canvas not found") |
| |
|
| | try: |
| | db_canvas.text = request.text |
| | db_canvas.status = "completed" |
| | db.commit() |
| | db.refresh(db_canvas) |
| | |
| | return db_canvas |
| |
|
| | except Exception as e: |
| | logger.error(f"Error updating canvas: {e}") |
| | raise HTTPException(status_code=500, detail=str(e)) |
| |
|
| |
|
| | @router.delete("/{canvas_id}") |
| | async def delete_canvas( |
| | canvas_id: int, |
| | current_user: db_models.User = Depends(get_current_user), |
| | db: Session = Depends(get_db) |
| | ): |
| | """Delete a canvas.""" |
| | db_canvas = db.query(db_models.Canvas).filter( |
| | db_models.Canvas.id == canvas_id, |
| | db_models.Canvas.user_id == current_user.id |
| | ).first() |
| | |
| | if not db_canvas: |
| | raise HTTPException(status_code=404, detail="Canvas not found") |
| | |
| | db.delete(db_canvas) |
| | db.commit() |
| | return {"message": "Canvas deleted successfully"} |
| |
|
| |
|