sumaq/backend/app/services/activities.py

165 lines
6.0 KiB
Python

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"}