Add backend api and engine
This commit is contained in:
188
api/app/routers/history.py
Normal file
188
api/app/routers/history.py
Normal file
@@ -0,0 +1,188 @@
|
||||
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
|
||||
|
||||
router = APIRouter(prefix="/history", tags=["history"])
|
||||
|
||||
|
||||
@router.get("")
|
||||
def list_history(
|
||||
assistant_id: Optional[str] = None,
|
||||
status: 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)
|
||||
|
||||
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": 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()
|
||||
|
||||
# 补充音频 URL
|
||||
transcript_list = []
|
||||
for t in transcripts:
|
||||
audio_url = t.audio_url 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(
|
||||
user_id: int,
|
||||
assistant_id: Optional[str] = None,
|
||||
source: str = "debug",
|
||||
db: Session = Depends(get_db)
|
||||
):
|
||||
"""创建通话记录(引擎回调使用)"""
|
||||
record = CallRecord(
|
||||
id=str(uuid.uuid4())[:8],
|
||||
user_id=user_id,
|
||||
assistant_id=assistant_id,
|
||||
source=source,
|
||||
status="connected",
|
||||
started_at=datetime.utcnow().isoformat(),
|
||||
)
|
||||
db.add(record)
|
||||
db.commit()
|
||||
db.refresh(record)
|
||||
return record
|
||||
|
||||
|
||||
@router.put("/{call_id}")
|
||||
def update_call_record(
|
||||
call_id: str,
|
||||
status: Optional[str] = None,
|
||||
summary: Optional[str] = None,
|
||||
duration_seconds: Optional[int] = None,
|
||||
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 status:
|
||||
record.status = status
|
||||
if summary:
|
||||
record.summary = summary
|
||||
if duration_seconds:
|
||||
record.duration_seconds = duration_seconds
|
||||
record.ended_at = datetime.utcnow().isoformat()
|
||||
|
||||
db.commit()
|
||||
return {"message": "Updated successfully"}
|
||||
|
||||
|
||||
@router.post("/{call_id}/transcripts")
|
||||
def add_transcript(
|
||||
call_id: str,
|
||||
turn_index: int,
|
||||
speaker: str,
|
||||
content: str,
|
||||
start_ms: int,
|
||||
end_ms: int,
|
||||
confidence: Optional[float] = None,
|
||||
duration_ms: Optional[int] = None,
|
||||
emotion: Optional[str] = None,
|
||||
db: Session = Depends(get_db)
|
||||
):
|
||||
"""添加转写片段"""
|
||||
transcript = CallTranscript(
|
||||
call_id=call_id,
|
||||
turn_index=turn_index,
|
||||
speaker=speaker,
|
||||
content=content,
|
||||
confidence=confidence,
|
||||
start_ms=start_ms,
|
||||
end_ms=end_ms,
|
||||
duration_ms=duration_ms,
|
||||
emotion=emotion,
|
||||
)
|
||||
db.add(transcript)
|
||||
db.commit()
|
||||
db.refresh(transcript)
|
||||
|
||||
# 补充音频 URL
|
||||
audio_url = get_audio_url(call_id, turn_index)
|
||||
|
||||
return {
|
||||
"id": transcript.id,
|
||||
"turn_index": turn_index,
|
||||
"speaker": speaker,
|
||||
"content": content,
|
||||
"confidence": confidence,
|
||||
"start_ms": start_ms,
|
||||
"end_ms": end_ms,
|
||||
"duration_ms": duration_ms,
|
||||
"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"}
|
||||
Reference in New Issue
Block a user