# 历史记录 (History Records) API 历史记录 API 用于管理通话记录和对话历史。 ## 基础信息 | 项目 | 值 | |------|-----| | Base URL | `/api/v1/history` | | 认证方式 | Bearer Token (预留) | --- ## 数据模型 ### CallRecord ```typescript interface CallRecord { id: string; // 通话记录ID user_id: number; // 所属用户ID assistant_id?: string; // 关联助手ID source: string; // 来源: "debug" | "external" status: string; // 状态: "connected" | "missed" | "failed" started_at: string; // 开始时间 ISO8601 ended_at?: string; // 结束时间 ISO8601 duration_seconds?: int; // 通话时长(秒) summary?: string; // 通话摘要 cost?: number; // 费用 metadata?: object; // 元数据 created_at: string; // 创建时间 } ``` ### TranscriptSegment ```typescript interface TranscriptSegment { turn_index: int; // 对话轮次 speaker: string; // 说话者: "human" | "ai" content: string; // 转写内容 confidence?: float; // 置信度 0-1 start_ms: int; // 开始时间(毫秒) end_ms: int; // 结束时间(毫秒) duration_ms?: int; // 持续时间(毫秒) audio_url?: string; // 音频URL emotion?: string; // 情绪标签 } ``` ### InteractionDetail ```typescript interface InteractionDetail { role: "user" | "assistant"; // 角色 content: string; // 文本内容或转写文本 audio_url?: string; // 音频URL image_urls?: string[]; // 图片URL列表(视频场景) timestamp: string; // 时间戳 } ``` --- ## API 端点 ### 1. 获取通话记录列表 ```http GET /api/v1/history ``` **Query Parameters:** | 参数 | 类型 | 必填 | 说明 | |------|------|------|------| | assistant_id | string | 否 | 过滤助手ID | | status | string | 否 | 过滤状态: "connected" \| "missed" \| "failed" | | source | string | 否 | 过滤来源: "debug" \| "external" | | start_date | string | 否 | 开始日期 ISO8601 | | end_date | string | 否 | 结束日期 ISO8601 | | page | int | 否 | 页码,默认 1 | | limit | int | 否 | 每页数量,默认 20 | **Response:** ```json { "total": 150, "page": 1, "limit": 20, "list": [ { "id": "call_001", "user_id": 1, "assistant_id": "abc12345", "source": "debug", "status": "connected", "started_at": "2024-01-15T14:30:00Z", "ended_at": "2024-01-15T14:33:00Z", "duration_seconds": 180, "summary": "用户咨询产品A的售后服务", "cost": 0.05, "created_at": "2024-01-15T14:30:00Z" }, { "id": "call_002", "user_id": 1, "assistant_id": "abc12345", "source": "external", "status": "missed", "started_at": "2024-01-15T14:00:00Z", "duration_seconds": 0, "created_at": "2024-01-15T14:00:00Z" } ] } ``` --- ### 2. 获取通话详情 ```http GET /api/v1/history/{call_id} ``` **Response:** ```json { "id": "call_001", "user_id": 1, "assistant_id": "abc12345", "source": "debug", "status": "connected", "started_at": "2024-01-15T14:30:00Z", "ended_at": "2024-01-15T14:33:00Z", "duration_seconds": 180, "summary": "用户咨询产品A的售后服务", "cost": 0.05, "metadata": { "browser": "Chrome", "os": "Windows" }, "transcripts": [ { "turn_index": 0, "speaker": "human", "content": "您好,我想咨询一下产品A的售后服务", "confidence": 0.98, "start_ms": 0, "end_ms": 3500, "duration_ms": 3500, "audio_url": "https://storage.example.com/audio/call_001/turn_0.mp3" }, { "turn_index": 1, "speaker": "ai", "content": "您好!产品A享有7天无理由退货和一年质保服务。请问您遇到了什么问题?", "confidence": 0.95, "start_ms": 4000, "end_ms": 12000, "duration_ms": 8000, "audio_url": "https://storage.example.com/audio/call_001/turn_1.mp3" }, { "turn_index": 2, "speaker": "human", "content": "我发现产品A有一个功能坏了", "confidence": 0.92, "start_ms": 13000, "end_ms": 18000, "duration_ms": 5000, "audio_url": "https://storage.example.com/audio/call_001/turn_2.mp3" } ] } ``` --- ### 3. 创建通话记录 ```http POST /api/v1/history ``` **Request Body:** ```json { "user_id": 1, "assistant_id": "abc12345", "source": "debug" } ``` **Response:** ```json { "id": "call_new001", "user_id": 1, "assistant_id": "abc12345", "source": "debug", "status": "connected", "started_at": "2024-01-15T15:00:00Z", "created_at": "2024-01-15T15:00:00Z" } ``` --- ### 4. 更新通话记录 ```http PUT /api/v1/history/{call_id} ``` **Request Body:** ```json { "status": "connected", "summary": "用户咨询产品A的售后服务,已引导用户提交工单", "duration_seconds": 180, "ended_at": "2024-01-15T14:33:00Z" } ``` --- ### 5. 删除通话记录 ```http DELETE /api/v1/history/{call_id} ``` --- ### 6. 添加转写片段 ```http POST /api/v1/history/{call_id}/transcripts ``` **Request Body:** ```json { "turn_index": 3, "speaker": "ai", "content": "好的,我已经为您创建了工单,编号 #12345,请保持电话畅通,我们的客服人员会在24小时内联系您。", "confidence": 0.96, "start_ms": 20000, "end_ms": 28000, "duration_ms": 8000, "emotion": "neutral" } ``` **Response:** ```json { "id": 100, "turn_index": 3, "speaker": "ai", "content": "好的,我已经为您创建了工单...", "confidence": 0.96, "start_ms": 20000, "end_ms": 28000, "duration_ms": 8000, "audio_url": "https://storage.example.com/audio/call_001/turn_3.mp3", "emotion": "neutral" } ``` --- ### 7. 获取音频 ```http GET /api/v1/history/{call_id}/audio/{turn_index} ``` **Response:** 重定向到音频文件 URL --- ### 8. 搜索通话记录 ```http GET /api/v1/history/search ``` **Query Parameters:** | 参数 | 类型 | 必填 | 说明 | |------|------|------|------| | q | string | 是 | 搜索关键词 | | page | int | 否 | 页码 | | limit | int | 否 | 每页数量 | **Response:** ```json { "total": 5, "page": 1, "limit": 20, "list": [ { "id": "call_001", "started_at": "2024-01-15T14:30:00Z", "matched_content": "用户咨询产品A的售后服务" } ] } ``` --- ### 9. 获取统计信息 ```http GET /api/v1/history/stats ``` **Query Parameters:** | 参数 | 类型 | 必填 | 说明 | |------|------|------|------| | start_date | string | 否 | 开始日期 | | end_date | string | 否 | 结束日期 | | assistant_id | string | 否 | 助手ID | **Response:** ```json { "total_calls": 150, "connected_calls": 135, "missed_calls": 15, "failed_calls": 0, "avg_duration_seconds": 180, "total_cost": 7.50, "by_status": { "connected": 135, "missed": 15, "failed": 0 }, "by_source": { "debug": 100, "external": 50 }, "daily_trend": [ { "date": "2024-01-15", "calls": 20, "connected": 18, "avg_duration": 175 } ] } ``` --- ## 推荐的 Schema 定义 ```python # ============ Call Record ============ class CallRecordSource(str, Enum): DEBUG = "debug" EXTERNAL = "external" class CallRecordStatus(str, Enum): CONNECTED = "connected" MISSED = "missed" FAILED = "failed" class CallRecordBase(BaseModel): assistant_id: Optional[str] = None source: str = "debug" class CallRecordCreate(CallRecordBase): pass class CallRecordUpdate(BaseModel): status: Optional[str] = None summary: Optional[str] = None duration_seconds: Optional[int] = None ended_at: Optional[str] = None cost: Optional[float] = None metadata: Optional[dict] = None class TranscriptSegment(BaseModel): turn_index: int speaker: str # "human" | "ai" content: str confidence: Optional[float] = None start_ms: int end_ms: int duration_ms: Optional[int] = None emotion: Optional[str] = None class CallRecordOut(BaseModel): id: str user_id: int assistant_id: Optional[str] = None source: str status: str started_at: str ended_at: Optional[str] = None duration_seconds: Optional[int] = None summary: Optional[str] = None cost: float = 0.0 metadata: dict = {} created_at: datetime transcripts: List[TranscriptSegment] = [] class Config: from_attributes = True class TranscriptCreate(BaseModel): turn_index: int speaker: str content: str confidence: Optional[float] = None start_ms: int end_ms: int duration_ms: Optional[int] = None emotion: Optional[str] = None class TranscriptOut(TranscriptCreate): id: int audio_url: Optional[str] = None class Config: from_attributes = True class HistoryStats(BaseModel): total_calls: int connected_calls: int missed_calls: int failed_calls: int avg_duration_seconds: float total_cost: float by_status: dict by_source: dict daily_trend: List[dict] ``` --- ## Web 端对应接口映射 | Web Type | API Endpoint | |----------|--------------| | CallLog (list) | `GET /api/v1/history` | | CallLog (detail) | `GET /api/v1/history/{id}` | | InteractionDetail | `GET /api/v1/history/{id}` (transcripts 字段) |