165 lines
6.0 KiB
Python
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"} |