193 lines
7.2 KiB
Python
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"}
|