from fastapi import APIRouter, Depends, HTTPException, Query, BackgroundTasks from sqlalchemy.orm import Session from sqlalchemy import or_, and_, func, desc from app.core.db import get_db, SessionLocal from app.core.deps import get_current_user from app.models import Meeting, MeetingAttendee, User, TranscriptSegment, SummarizeTask, TranscriptTask from app.schemas.meeting import MeetingOut, MeetingDetailOut, MeetingUpdate, MeetingListOut from app.services.meeting_service import MeetingService from typing import List, Optional router = APIRouter(prefix="/meetings", tags=["meetings"]) async def run_summarize_worker(task_id: str): db = SessionLocal() try: await MeetingService.process_summarize_task(db, task_id) finally: db.close() @router.post("/{meeting_id}/summarize") async def start_summarize( meeting_id: int, payload: dict, background_tasks: BackgroundTasks, db: Session = Depends(get_db), current_user: User = Depends(get_current_user), ): try: task = await MeetingService.create_summarize_task( db, meeting_id, payload.get("prompt_id"), payload.get("model_id"), payload.get("extra_prompt", "") ) background_tasks.add_task(run_summarize_worker, task.task_id) return {"task_id": task.task_id, "status": task.status} except Exception as e: raise HTTPException(status_code=400, detail=str(e)) @router.get("/tasks", response_model=dict) def list_all_tasks( db: Session = Depends(get_db), current_user: User = Depends(get_current_user), task_type: Optional[str] = Query(None), # summarize, transcript status: Optional[str] = Query(None), ): """ 统一任务监控接口,合并转译和总结任务 """ tasks = [] # 1. 获取总结任务 sum_query = db.query(SummarizeTask, Meeting.title, User.username).join( Meeting, SummarizeTask.meeting_id == Meeting.meeting_id ).join( User, Meeting.user_id == User.user_id ) if status: sum_query = sum_query.filter(SummarizeTask.status == status) for t, m_title, username in sum_query.order_by(desc(SummarizeTask.created_at)).limit(50).all(): tasks.append({ "task_id": t.task_id, "type": "总结", "meeting_title": m_title, "creator": username, "status": t.status, "progress": t.progress, "created_at": t.created_at, "meeting_id": t.meeting_id }) # 2. 获取转译任务 trans_query = db.query(TranscriptTask, Meeting.title, User.username).join( Meeting, TranscriptTask.meeting_id == Meeting.meeting_id ).join( User, Meeting.user_id == User.user_id ) if status: trans_query = trans_query.filter(TranscriptTask.status == status) for t, m_title, username in trans_query.order_by(desc(TranscriptTask.created_at)).limit(50).all(): tasks.append({ "task_id": t.task_id, "type": "转译", "meeting_title": m_title, "creator": username, "status": t.status, "progress": t.progress, "created_at": t.created_at, "meeting_id": t.meeting_id }) # 按时间全局排序 tasks.sort(key=lambda x: x["created_at"], reverse=True) return {"items": tasks} @router.get("/tasks/{task_id}") def get_task_progress( task_id: str, db: Session = Depends(get_db), current_user: User = Depends(get_current_user), ): task = MeetingService.get_task_status(db, task_id) if not task: raise HTTPException(status_code=404, detail="Task not found") return { "task_id": task.task_id, "status": task.status, "progress": task.progress, "result": task.result, "error": task.error_message } # ... 其余接口保持不变 @router.get("", response_model=MeetingListOut) def list_meetings( db: Session = Depends(get_db), current_user: User = Depends(get_current_user), scope: str = Query("all", description="all, created, joined"), keyword: Optional[str] = Query(None), page: int = Query(1, ge=1), page_size: int = Query(10, ge=1, le=100), ): query = db.query(Meeting) if scope == "created": query = query.filter(Meeting.user_id == current_user.user_id) elif scope == "joined": query = query.join(MeetingAttendee).filter(MeetingAttendee.user_id == current_user.user_id) else: query = query.outerjoin(MeetingAttendee).filter( or_(Meeting.user_id == current_user.user_id, MeetingAttendee.user_id == current_user.user_id) ) if keyword: query = query.filter(Meeting.title.contains(keyword)) total = query.distinct().count() results = query.distinct().order_by(Meeting.meeting_time.desc()).offset((page - 1) * page_size).limit(page_size).all() items = [] for m in results: item = MeetingOut.model_validate(m) item.creator_name = m.creator.display_name if m.creator else "Unknown" item.creator_avatar = m.creator.avatar if m.creator else None attendees = [] for att in m.attendees: if att.user: attendees.append({"attendee_id": att.attendee_id,"user_id": att.user_id,"display_name": att.user.display_name,"avatar": att.user.avatar}) item.attendees = attendees items.append(item) return {"items": items, "total": total} @router.get("/{meeting_id}", response_model=MeetingDetailOut) def get_meeting_detail( meeting_id: int, db: Session = Depends(get_db), current_user: User = Depends(get_current_user), ): meeting = db.query(Meeting).filter(Meeting.meeting_id == meeting_id).first() if not meeting: raise HTTPException(status_code=404, detail="Meeting not found") is_attendee = any(a.user_id == current_user.user_id for a in meeting.attendees) if meeting.user_id != current_user.user_id and not is_attendee: raise HTTPException(status_code=403, detail="Not authorized") item = MeetingDetailOut.model_validate(meeting) item.creator_name = meeting.creator.display_name if meeting.creator else "Unknown" item.creator_avatar = meeting.creator.avatar if meeting.creator else None item.attendees = [ {"attendee_id": a.attendee_id, "user_id": a.user_id, "display_name": a.user.display_name if a.user else "Unknown", "avatar": a.user.avatar if a.user else None} for a in meeting.attendees ] item.segments = sorted([s for s in meeting.segments], key=lambda x: x.start_time_ms) return item @router.delete("/{meeting_id}") def delete_meeting( meeting_id: int, db: Session = Depends(get_db), current_user: User = Depends(get_current_user), ): meeting = db.query(Meeting).filter(Meeting.meeting_id == meeting_id).first() if not meeting: raise HTTPException(status_code=404, detail="Meeting not found") if meeting.user_id != current_user.user_id: role_codes = [ur.role.role_code for ur in current_user.roles] if "admin" not in role_codes and "superuser" not in role_codes: raise HTTPException(status_code=403, detail="Forbidden") db.delete(meeting) db.commit() return {"status": "ok"}