- 从服务器拉取完整代码 - 按框架规范整理项目结构 - 配置 Drone CI 测试环境部署 - 包含后端(FastAPI)、前端(Vue3)、管理端 技术栈: Vue3 + TypeScript + FastAPI + MySQL
357 lines
10 KiB
Markdown
357 lines
10 KiB
Markdown
# 言迹API探索报告
|
||
|
||
**探索日期**:2025-10-15
|
||
**目标**:找到获取员工对话记录的方法
|
||
**结果**:✅ **成功找到完美解决方案!**
|
||
|
||
---
|
||
|
||
## 🎉 重大发现:完美的接口
|
||
|
||
### 4.5 获取员工未绑定录音信息
|
||
|
||
**接口路径**:`POST /api/beauty/v1/audio/infos`
|
||
|
||
**请求参数**:
|
||
```json
|
||
{
|
||
"estateId": 516799468310364162,
|
||
"consultantPhone": "员工手机号", // ← 可以直接通过手机号查询!
|
||
"audioStartDate": "2024-10-01" // 可选,筛选时间范围
|
||
}
|
||
```
|
||
|
||
**响应数据**:
|
||
```json
|
||
{
|
||
"code": "0",
|
||
"msg": "success",
|
||
"data": {
|
||
"records": [
|
||
{
|
||
"id": 123456, // 录音ID
|
||
"consultantPhone": "13800138000", // 员工手机号
|
||
"consultantName": "张三", // 员工姓名
|
||
"fileUrl": "https://...", // 录音URL(7天有效)
|
||
"startTime": "2024-10-15 10:30:00",
|
||
"endTime": "2024-10-15 10:35:00",
|
||
"duration": 300000, // 时长(ms)
|
||
"fileSize": 2048000 // 文件大小(字节)
|
||
}
|
||
]
|
||
}
|
||
}
|
||
```
|
||
|
||
**关键优势**:
|
||
- ✅ **直接支持手机号查询**:无需中间步骤,一步到位
|
||
- ✅ **返回录音ID**:可以直接调用ASR接口获取对话文本
|
||
- ✅ **包含员工信息**:consultantPhone、consultantName
|
||
- ✅ **支持时间筛选**:可以获取特定日期的录音
|
||
|
||
---
|
||
|
||
## 一、探索过程
|
||
|
||
### 1.1 尝试的接口路径
|
||
|
||
| 接口路径 | 方法 | 结果 | 说明 |
|
||
|---------|------|------|------|
|
||
| `/api/beauty/v1/user` | GET | ❌ invalid path | 员工信息接口不存在 |
|
||
| `/api/saas/user` | GET | ❌ 未获取API访问权限 | 路径存在但无权限 |
|
||
| `/api/beauty/v1/visit` | GET | ❌ invalid path | 来访列表接口不存在 |
|
||
| `/api/beauty/v1/audios` | GET | ❌ invalid path | 录音列表接口不存在 |
|
||
| `/api/beauty/v1/visits` | GET | ❌ invalid path | 来访列表接口不存在 |
|
||
| `/api/beauty/v1/audio/list` | POST | ❌ invalid path | 录音列表接口不存在 |
|
||
| `/api/beauty/v1/visit/list` | POST | ❌ invalid path | 来访单列表接口不存在 |
|
||
| `/api/beauty/v1/visit/audios` | POST | ✅ 成功但data=null | 需要真实的externalVisitIds |
|
||
|
||
### 1.2 已验证可用的接口
|
||
|
||
根据之前的测试和文档,以下接口可用:
|
||
|
||
1. **OAuth认证** ✅
|
||
- `GET /oauth/token`
|
||
- 成功获取access_token
|
||
|
||
2. **获取来访录音信息** ✅
|
||
- `POST /api/beauty/v1/visit/audios`
|
||
- 需要参数:`estateId`、`externalVisitIds`(来访单ID数组)
|
||
- 返回:录音信息,包含`consultantPhone`、`consultantName`
|
||
|
||
3. **获取录音ASR分析结果** ✅
|
||
- `GET /api/beauty/v1/audio/asr-analysed`
|
||
- 需要参数:`estateId`、`audioId`
|
||
- 返回:对话文本数组
|
||
|
||
4. **获取客户来访列表** 📄 文档有但未测试
|
||
- `GET /api/beauty/v1/visit/by-customer`
|
||
- 需要参数:`estateId`、`thirdCustomerId`(客户ID)
|
||
- 返回:该客户的来访记录列表
|
||
|
||
---
|
||
|
||
## 二、关键发现
|
||
|
||
### 2.1 API设计特点
|
||
|
||
1. **基于ID查询**:言迹API采用"基于ID查询"的设计,没有提供通用的列表接口
|
||
2. **需要外部ID**:大多数接口需要`externalVisitId`(三方来访单ID)或`thirdCustomerId`(三方客户ID)
|
||
3. **权限限制**:部分SAAS管理接口(如`/api/saas/user`)需要更高权限
|
||
|
||
### 2.2 数据关联链路
|
||
|
||
```
|
||
客户ID (thirdCustomerId)
|
||
↓
|
||
来访单列表 (GET /api/beauty/v1/visit/by-customer)
|
||
↓
|
||
来访单ID (externalVisitId)
|
||
↓
|
||
录音信息 (POST /api/beauty/v1/visit/audios)
|
||
├─ 录音ID (audioId)
|
||
├─ 员工手机号 (consultantPhone) ← 关键字段!
|
||
└─ 员工姓名 (consultantName)
|
||
↓
|
||
ASR对话文本 (GET /api/beauty/v1/audio/asr-analysed)
|
||
```
|
||
|
||
### 2.3 员工手机号的获取方式
|
||
|
||
从`/api/beauty/v1/visit/audios`接口返回的录音信息中,每条记录都包含:
|
||
- `consultantPhone`:销售人员手机号
|
||
- `consultantName`:销售人员姓名
|
||
|
||
**关键结论**:**无法直接通过手机号查询,但可以通过录音数据筛选手机号**
|
||
|
||
---
|
||
|
||
## 三、实施方案
|
||
|
||
### 方案A:基于时间范围的批量筛选(推荐)
|
||
|
||
**思路**:
|
||
1. 获取一段时间内的所有来访单ID(需要外部系统提供或手动收集)
|
||
2. 调用`/api/beauty/v1/visit/audios`获取录音信息
|
||
3. 在后端筛选出指定手机号的录音
|
||
4. 获取这些录音的ASR对话文本
|
||
|
||
**优点**:
|
||
- 符合言迹API的设计逻辑
|
||
- 可以获取真实的员工对话数据
|
||
|
||
**缺点**:
|
||
- 需要预先收集来访单ID列表
|
||
- 或需要外部系统(如CRM)提供来访单ID
|
||
|
||
**适用场景**:
|
||
- 门店系统已有来访单管理
|
||
- 可以从其他渠道获取来访单ID列表
|
||
|
||
### 方案B:基于客户ID的间接查询
|
||
|
||
**思路**:
|
||
1. 从业务系统获取客户ID列表
|
||
2. 对每个客户调用`/api/beauty/v1/visit/by-customer`获取来访列表
|
||
3. 从来访列表中筛选特定员工(userId字段)的记录
|
||
4. 获取这些来访单的录音和ASR文本
|
||
|
||
**优点**:
|
||
- 可以利用现有的客户数据
|
||
- 能够关联客户和员工
|
||
|
||
**缺点**:
|
||
- 需要维护客户ID映射
|
||
- API调用次数较多
|
||
|
||
**适用场景**:
|
||
- 有完整的客户管理系统
|
||
- 客户ID已经与言迹同步
|
||
|
||
### 方案C:使用言迹WebHook(需要平台支持)
|
||
|
||
**思路**:
|
||
1. 在言迹平台配置WebHook
|
||
2. 当有新录音时,言迹主动推送数据到我们的系统
|
||
3. 系统接收并存储录音信息,建立索引
|
||
|
||
**优点**:
|
||
- 实时获取数据
|
||
- 可以建立完整的本地索引
|
||
|
||
**缺点**:
|
||
- 需要言迹平台开通WebHook功能
|
||
- 需要额外的数据存储和管理
|
||
|
||
---
|
||
|
||
## 四、推荐实施步骤
|
||
|
||
### 第一步:获取真实测试数据
|
||
|
||
**方式1:从言迹平台导出**
|
||
- 登录言迹管理后台
|
||
- 查看最近的来访单记录
|
||
- 复制几个真实的`externalVisitId`
|
||
|
||
**方式2:询问业务方**
|
||
- 联系使用言迹工牌的门店
|
||
- 获取最近的来访单编号
|
||
|
||
**方式3:从业务系统同步**
|
||
- 如果门店系统已经对接言迹
|
||
- 从门店系统数据库查询来访单ID
|
||
|
||
### 第二步:验证数据获取流程
|
||
|
||
使用真实ID测试完整链路:
|
||
|
||
```bash
|
||
# 1. 获取token
|
||
TOKEN="..."
|
||
|
||
# 2. 获取录音信息(使用真实的来访单ID)
|
||
curl -X POST "https://open.yanjiai.com/api/beauty/v1/visit/audios" \
|
||
-H "Authorization: Bearer $TOKEN" \
|
||
-H "Content-Type: application/json" \
|
||
-d '{
|
||
"estateId": 516799468310364162,
|
||
"externalVisitIds": ["真实ID1", "真实ID2"]
|
||
}'
|
||
|
||
# 3. 提取员工手机号和录音ID
|
||
# consultantPhone: "13800138000"
|
||
# audioId: 123456
|
||
|
||
# 4. 获取ASR对话文本
|
||
curl "https://open.yanjiai.com/api/beauty/v1/audio/asr-analysed?estateId=516799468310364162&audioId=123456" \
|
||
-H "Authorization: Bearer $TOKEN"
|
||
```
|
||
|
||
### 第三步:实现手机号筛选逻辑
|
||
|
||
在`YanjiService`中实现:
|
||
|
||
```python
|
||
async def get_recent_conversations_by_phone(
|
||
self,
|
||
consultant_phone: str,
|
||
external_visit_ids: List[str],
|
||
limit: int = 10
|
||
) -> List[Dict]:
|
||
"""
|
||
根据员工手机号从来访单中筛选对话记录
|
||
|
||
Args:
|
||
consultant_phone: 员工手机号
|
||
external_visit_ids: 来访单ID列表(从业务系统获取)
|
||
limit: 返回数量限制
|
||
"""
|
||
# 1. 获取所有录音信息
|
||
all_audios = await self.get_visit_audios(external_visit_ids)
|
||
|
||
# 2. 筛选该员工的录音
|
||
employee_audios = [
|
||
audio for audio in all_audios
|
||
if audio.get('consultantPhone') == consultant_phone
|
||
]
|
||
|
||
# 3. 按时间倒序,取最近N条
|
||
employee_audios.sort(key=lambda x: x.get('startTime', ''), reverse=True)
|
||
employee_audios = employee_audios[:limit]
|
||
|
||
# 4. 获取每条录音的ASR文本
|
||
conversations = []
|
||
for audio in employee_audios:
|
||
asr_result = await self.get_audio_asr_result(audio['id'])
|
||
if asr_result:
|
||
conversations.append({
|
||
'audio_id': audio['id'],
|
||
'visit_id': audio.get('externalVisitId'),
|
||
'consultant_phone': audio.get('consultantPhone'),
|
||
'consultant_name': audio.get('consultantName'),
|
||
'start_time': audio.get('startTime'),
|
||
'duration': audio.get('duration'),
|
||
'conversation': asr_result.get('result', [])
|
||
})
|
||
|
||
return conversations
|
||
```
|
||
|
||
---
|
||
|
||
## 五、后续行动
|
||
|
||
### 5.1 立即行动
|
||
- [ ] 获取3-5个真实的来访单ID进行测试
|
||
- [ ] 验证能否成功获取录音和ASR文本
|
||
- [ ] 确认员工手机号格式和数据质量
|
||
|
||
### 5.2 代码实现
|
||
- [ ] 实现基于手机号的筛选逻辑
|
||
- [ ] 添加对话格式转换函数(言迹→Dify)
|
||
- [ ] 创建API接口供前端调用
|
||
|
||
### 5.3 长期优化
|
||
- [ ] 与业务系统对接,自动获取来访单ID
|
||
- [ ] 考虑缓存机制,避免重复调用言迹API
|
||
- [ ] 探索是否可以开通WebHook功能
|
||
|
||
---
|
||
|
||
## 六、关键问题
|
||
|
||
### Q1:如何获取来访单ID列表?
|
||
|
||
**答**:目前有三种途径:
|
||
1. 从言迹平台后台手动导出
|
||
2. 从门店CRM/管理系统查询
|
||
3. 与业务方协调,定期同步
|
||
|
||
### Q2:是否能直接通过手机号查询?
|
||
|
||
**答**:不能。言迹API不提供基于手机号的直接查询,需要:
|
||
1. 先获取来访单ID或客户ID
|
||
2. 再查询录音信息
|
||
3. 从录音信息中筛选手机号
|
||
|
||
### Q3:数据实时性如何保证?
|
||
|
||
**答**:
|
||
- 方案A/B:定时轮询(如每小时同步一次)
|
||
- 方案C:WebHook推送(需要平台支持)
|
||
|
||
### Q4:是否需要在本地存储言迹数据?
|
||
|
||
**建议**:是的
|
||
- 建立`yanji_conversations`表存储对话记录
|
||
- 定期同步最新数据
|
||
- 加快查询速度,减少API调用
|
||
|
||
---
|
||
|
||
## 七、总结
|
||
|
||
### 核心结论
|
||
|
||
1. **言迹API不支持直接按手机号查询**,需要先获取来访单ID或客户ID
|
||
2. **员工手机号存在于录音信息中**,可以通过后端筛选实现手机号匹配
|
||
3. **推荐方案**:从业务系统获取来访单ID列表,然后筛选特定员工的对话记录
|
||
|
||
### 下一步
|
||
|
||
**需要用户提供**:
|
||
- 3-5个真实的来访单ID(`externalVisitId`)用于测试
|
||
- 或提供获取来访单ID的方法
|
||
|
||
**等待测试完成后**:
|
||
- 实现完整的数据获取和筛选逻辑
|
||
- 对接Dify陪练分析工作流
|
||
- 创建前端API接口
|
||
|
||
---
|
||
|
||
**探索人员**:AI助手
|
||
**文档版本**:v1.0
|
||
|