218 lines
6.5 KiB
Python
218 lines
6.5 KiB
Python
from fastapi import APIRouter, Depends, HTTPException
|
|
from sqlalchemy.orm import Session
|
|
from typing import Optional, List
|
|
import uuid
|
|
from datetime import datetime
|
|
|
|
from ..db import get_db
|
|
from ..models import CallRecord, CallTranscript, CallAudioSegment
|
|
from ..storage import get_audio_url
|
|
from ..schemas import CallRecordCreate, CallRecordUpdate, TranscriptCreate
|
|
|
|
router = APIRouter(prefix="/history", tags=["history"])
|
|
|
|
|
|
def record_to_dict(record: CallRecord) -> dict:
|
|
return {
|
|
"id": record.id,
|
|
"user_id": record.user_id,
|
|
"assistant_id": record.assistant_id,
|
|
"source": record.source,
|
|
"status": record.status,
|
|
"started_at": record.started_at,
|
|
"ended_at": record.ended_at,
|
|
"duration_seconds": record.duration_seconds,
|
|
"summary": record.summary,
|
|
"cost": record.cost,
|
|
"created_at": record.created_at,
|
|
}
|
|
|
|
|
|
@router.get("")
|
|
def list_history(
|
|
assistant_id: Optional[str] = None,
|
|
status: Optional[str] = None,
|
|
source: Optional[str] = None,
|
|
page: int = 1,
|
|
limit: int = 20,
|
|
db: Session = Depends(get_db)
|
|
):
|
|
"""获取通话记录列表"""
|
|
query = db.query(CallRecord)
|
|
|
|
if assistant_id:
|
|
query = query.filter(CallRecord.assistant_id == assistant_id)
|
|
if status:
|
|
query = query.filter(CallRecord.status == status)
|
|
if source:
|
|
query = query.filter(CallRecord.source == source)
|
|
|
|
total = query.count()
|
|
records = query.order_by(CallRecord.started_at.desc()) \
|
|
.offset((page-1)*limit).limit(limit).all()
|
|
|
|
return {
|
|
"total": total,
|
|
"page": page,
|
|
"limit": limit,
|
|
"list": [record_to_dict(r) for r in records]
|
|
}
|
|
|
|
|
|
@router.get("/{call_id}")
|
|
def get_history_detail(call_id: str, db: Session = Depends(get_db)):
|
|
"""获取通话详情"""
|
|
record = db.query(CallRecord).filter(CallRecord.id == call_id).first()
|
|
if not record:
|
|
raise HTTPException(status_code=404, detail="Call record not found")
|
|
|
|
# 获取转写
|
|
transcripts = db.query(CallTranscript) \
|
|
.filter(CallTranscript.call_id == call_id) \
|
|
.order_by(CallTranscript.turn_index).all()
|
|
|
|
audio_segments = db.query(CallAudioSegment).filter(CallAudioSegment.call_id == call_id).all()
|
|
audio_by_turn = {seg.turn_index: seg.audio_url for seg in audio_segments if seg.turn_index is not None}
|
|
|
|
transcript_list = []
|
|
for t in transcripts:
|
|
audio_url = audio_by_turn.get(t.turn_index) or get_audio_url(call_id, t.turn_index)
|
|
transcript_list.append({
|
|
"turnIndex": t.turn_index,
|
|
"speaker": t.speaker,
|
|
"content": t.content,
|
|
"confidence": t.confidence,
|
|
"startMs": t.start_ms,
|
|
"endMs": t.end_ms,
|
|
"durationMs": t.duration_ms,
|
|
"audioUrl": audio_url,
|
|
})
|
|
|
|
return {
|
|
"id": record.id,
|
|
"user_id": record.user_id,
|
|
"assistant_id": record.assistant_id,
|
|
"source": record.source,
|
|
"status": record.status,
|
|
"started_at": record.started_at,
|
|
"ended_at": record.ended_at,
|
|
"duration_seconds": record.duration_seconds,
|
|
"summary": record.summary,
|
|
"transcripts": transcript_list,
|
|
}
|
|
|
|
|
|
@router.post("")
|
|
def create_call_record(
|
|
data: CallRecordCreate,
|
|
db: Session = Depends(get_db)
|
|
):
|
|
"""创建通话记录(引擎回调使用)"""
|
|
record = CallRecord(
|
|
id=str(uuid.uuid4())[:8],
|
|
user_id=data.user_id,
|
|
assistant_id=data.assistant_id,
|
|
source=data.source,
|
|
status=data.status or "connected",
|
|
started_at=datetime.utcnow().isoformat(),
|
|
cost=data.cost or 0.0,
|
|
)
|
|
db.add(record)
|
|
db.commit()
|
|
db.refresh(record)
|
|
return record_to_dict(record)
|
|
|
|
|
|
@router.put("/{call_id}")
|
|
def update_call_record(
|
|
call_id: str,
|
|
data: CallRecordUpdate,
|
|
db: Session = Depends(get_db)
|
|
):
|
|
"""更新通话记录"""
|
|
record = db.query(CallRecord).filter(CallRecord.id == call_id).first()
|
|
if not record:
|
|
raise HTTPException(status_code=404, detail="Call record not found")
|
|
|
|
if data.status is not None:
|
|
record.status = data.status
|
|
if data.summary is not None:
|
|
record.summary = data.summary
|
|
if data.duration_seconds is not None:
|
|
record.duration_seconds = data.duration_seconds
|
|
record.ended_at = datetime.utcnow().isoformat()
|
|
if data.ended_at is not None:
|
|
record.ended_at = data.ended_at
|
|
if data.cost is not None:
|
|
record.cost = data.cost
|
|
if data.metadata is not None:
|
|
record.call_metadata = data.metadata
|
|
|
|
db.commit()
|
|
db.refresh(record)
|
|
return record_to_dict(record)
|
|
|
|
|
|
@router.post("/{call_id}/transcripts")
|
|
def add_transcript(
|
|
call_id: str,
|
|
data: TranscriptCreate,
|
|
db: Session = Depends(get_db)
|
|
):
|
|
"""添加转写片段"""
|
|
record = db.query(CallRecord).filter(CallRecord.id == call_id).first()
|
|
if not record:
|
|
raise HTTPException(status_code=404, detail="Call record not found")
|
|
|
|
transcript = CallTranscript(
|
|
call_id=call_id,
|
|
turn_index=data.turn_index,
|
|
speaker=data.speaker,
|
|
content=data.content,
|
|
confidence=data.confidence,
|
|
start_ms=data.start_ms,
|
|
end_ms=data.end_ms,
|
|
duration_ms=data.duration_ms,
|
|
emotion=data.emotion,
|
|
)
|
|
db.add(transcript)
|
|
db.commit()
|
|
db.refresh(transcript)
|
|
|
|
# 补充音频 URL
|
|
audio_url = get_audio_url(call_id, data.turn_index)
|
|
|
|
return {
|
|
"id": transcript.id,
|
|
"turn_index": data.turn_index,
|
|
"speaker": data.speaker,
|
|
"content": data.content,
|
|
"confidence": data.confidence,
|
|
"start_ms": data.start_ms,
|
|
"end_ms": data.end_ms,
|
|
"duration_ms": data.duration_ms,
|
|
"emotion": data.emotion,
|
|
"audio_url": audio_url,
|
|
}
|
|
|
|
|
|
@router.get("/{call_id}/audio/{turn_index}")
|
|
def get_audio(call_id: str, turn_index: int):
|
|
"""获取音频文件"""
|
|
audio_url = get_audio_url(call_id, turn_index)
|
|
if not audio_url:
|
|
raise HTTPException(status_code=404, detail="Audio not found")
|
|
from fastapi.responses import RedirectResponse
|
|
return RedirectResponse(audio_url)
|
|
|
|
|
|
@router.delete("/{call_id}")
|
|
def delete_call_record(call_id: str, db: Session = Depends(get_db)):
|
|
"""删除通话记录"""
|
|
record = db.query(CallRecord).filter(CallRecord.id == call_id).first()
|
|
if not record:
|
|
raise HTTPException(status_code=404, detail="Call record not found")
|
|
db.delete(record)
|
|
db.commit()
|
|
return {"message": "Deleted successfully"}
|