import os import uuid import shutil import datetime from sqlalchemy.orm import Session from typing import Optional, List from fastapi import HTTPException, File, BackgroundTasks, UploadFile from app.models.activity import Activity from app.models.user import User from app.models.evidence import Evidence from app.schemas.activity import ActivityCreate, ActivityUpdate from app.services.transcription_worker import TranscriptionWorker UPLOAD_DIR = "uploads" class ActivityService: def __init__(self, db: Session, current_user: User, background_tasks: Optional[BackgroundTasks] = None): self._db = db self._current_user = current_user self._background_tasks = background_tasks self._transcriptionWorker = TranscriptionWorker(self._db) def get_activities(self, project_id: Optional[int] = None, specialty_id: Optional[int] = None, skip: int = 0, limit: int = 100) -> List[Activity]: query = self._db.query(Activity) if project_id: query = query.filter(Activity.project_id == project_id) if specialty_id: query = query.filter(Activity.specialty_id == specialty_id) return query.offset(skip).limit(limit).all() def get_activity(self, activity_id: int) -> Activity: db_activity = self._db.query(Activity).filter(Activity.id == activity_id).first() if db_activity is None: raise HTTPException(status_code=404, detail="Activity not found") return db_activity def create_activity(self, activity: ActivityCreate) -> Activity: db_activity = Activity( **activity.model_dump(), user_id=self._current_user.id ) self._db.add(db_activity) self._db.commit() self._db.refresh(db_activity) return db_activity def update_activity(self, activity_id: int, activity: ActivityUpdate) -> Activity: db_activity = self.get_activity(activity_id) update_data = activity.model_dump(exclude_unset=True) for key, value in update_data.items(): setattr(db_activity, key, value) self._db.commit() self._db.refresh(db_activity) return db_activity def upload_evidence( self, activity_id: int, file: UploadFile, description: Optional[str] = None, captured_at: Optional[str] = None) -> Evidence: # Verify activity exists self.get_activity(activity_id) # Generate unique filename file_ext = os.path.splitext(file.filename)[1] unique_filename = f"{uuid.uuid4()}{file_ext}" file_path = os.path.join(UPLOAD_DIR, unique_filename) # Save file if not os.path.exists(UPLOAD_DIR): os.makedirs(UPLOAD_DIR) with open(file_path, "wb") as buffer: shutil.copyfileobj(file.file, buffer) db_captured_at = None if captured_at: try: db_captured_at = datetime.datetime.fromisoformat(captured_at.replace('Z', '+00:00')) except: db_captured_at = datetime.datetime.utcnow() else: db_captured_at = datetime.datetime.utcnow() # Determine transcription status initial_status = "none" if file.content_type and "audio" in file.content_type: initial_status = "pending" # Save to database db_evidence = Evidence( activity_id=activity_id, file_path=file_path, media_type=file.content_type, description=description, captured_at=db_captured_at, transcription_status=initial_status ) self._db.add(db_evidence) self._db.commit() self._db.refresh(db_evidence) # If it's audio, queue transcription if initial_status == "pending" and self._background_tasks: self._background_tasks.add_task(self._transcriptionWorker.process_transcription, db_evidence.id) return db_evidence def retry_transcription(self, evidence_id: int) -> Evidence: db_evidence = self._db.query(Evidence).filter(Evidence.id == evidence_id).first() if not db_evidence: raise HTTPException(status_code=404, detail="Evidence not found") if not db_evidence.media_type or "audio" not in db_evidence.media_type: raise HTTPException(status_code=400, detail="Only audio evidence can be transcribed") # Update status to pending db_evidence.transcription_status = "pending" db_evidence.transcription = None self._db.commit() self._db.refresh(db_evidence) # Queue transcription task if self._background_tasks: self._background_tasks.add_task(self._transcriptionWorker.process_transcription, db_evidence.id) return db_evidence def update_evidence(self, evidence_id: int, evidence_update: any) -> Evidence: db_evidence = self._db.query(Evidence).filter(Evidence.id == evidence_id).first() if not db_evidence: raise HTTPException(status_code=404, detail="Evidence not found") update_data = evidence_update.model_dump(exclude_unset=True) for key, value in update_data.items(): setattr(db_evidence, key, value) self._db.commit() self._db.refresh(db_evidence) return db_evidence def delete_evidence(self, evidence_id: int): db_evidence = self._db.query(Evidence).filter(Evidence.id == evidence_id).first() if not db_evidence: raise HTTPException(status_code=404, detail="Evidence not found") # Optional: Delete file from disk if db_evidence.file_path and os.path.exists(db_evidence.file_path): try: os.remove(db_evidence.file_path) except: pass self._db.delete(db_evidence) self._db.commit() return {"detail": "Evidence deleted"}