nex_basse/backend/app/api/v1/endpoints/meetings.py

193 lines
7.2 KiB
Python

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