- 从服务器拉取完整代码 - 按框架规范整理项目结构 - 配置 Drone CI 测试环境部署 - 包含后端(FastAPI)、前端(Vue3)、管理端 技术栈: Vue3 + TypeScript + FastAPI + MySQL
924 lines
22 KiB
Markdown
924 lines
22 KiB
Markdown
# 陪练功能API接口规范
|
||
|
||
## 一、通用规范
|
||
|
||
### 1.1 请求格式
|
||
|
||
**Base URL**:
|
||
- 开发环境:`http://localhost:8000`
|
||
- 生产环境:`https://aiedu.ireborn.com.cn`
|
||
|
||
**请求头**:
|
||
```http
|
||
Content-Type: application/json; charset=utf-8
|
||
Authorization: Bearer <access_token>
|
||
```
|
||
|
||
### 1.2 响应格式
|
||
|
||
**统一响应结构**:
|
||
```json
|
||
{
|
||
"code": 200,
|
||
"message": "success",
|
||
"data": {},
|
||
"request_id": "uuid"
|
||
}
|
||
```
|
||
|
||
**分页响应结构**:
|
||
```json
|
||
{
|
||
"code": 200,
|
||
"message": "success",
|
||
"data": {
|
||
"items": [],
|
||
"total": 100,
|
||
"page": 1,
|
||
"page_size": 20,
|
||
"pages": 5
|
||
}
|
||
}
|
||
```
|
||
|
||
### 1.3 状态码约定
|
||
|
||
| HTTP状态码 | code | 说明 |
|
||
|-----------|------|------|
|
||
| 200 | 200 | 成功 |
|
||
| 400 | 400 | 请求参数错误 |
|
||
| 401 | 401 | 未授权(token无效或过期) |
|
||
| 403 | 403 | 无权限 |
|
||
| 404 | 404 | 资源不存在 |
|
||
| 500 | 500 | 服务器错误 |
|
||
|
||
## 二、数据模型
|
||
|
||
### 2.1 场景类型枚举 (SceneType)
|
||
|
||
```typescript
|
||
type SceneType = 'phone' | 'face' | 'complaint' | 'after-sales' | 'product-intro'
|
||
```
|
||
|
||
| 值 | 说明 |
|
||
|----|------|
|
||
| phone | 电话销售 |
|
||
| face | 面对面销售 |
|
||
| complaint | 客户投诉 |
|
||
| after-sales | 售后服务 |
|
||
| product-intro | 产品介绍 |
|
||
|
||
### 2.2 难度等级枚举 (Difficulty)
|
||
|
||
```typescript
|
||
type Difficulty = 'beginner' | 'junior' | 'intermediate' | 'senior' | 'expert'
|
||
```
|
||
|
||
| 值 | 说明 |
|
||
|----|------|
|
||
| beginner | 入门 |
|
||
| junior | 初级 |
|
||
| intermediate | 中级 |
|
||
| senior | 高级 |
|
||
| expert | 专家 |
|
||
|
||
### 2.3 场景状态枚举 (SceneStatus)
|
||
|
||
```typescript
|
||
type SceneStatus = 'active' | 'inactive'
|
||
```
|
||
|
||
| 值 | 说明 |
|
||
|----|------|
|
||
| active | 启用 |
|
||
| inactive | 禁用 |
|
||
|
||
### 2.4 陪练场景对象 (PracticeScene)
|
||
|
||
```typescript
|
||
interface PracticeScene {
|
||
id: number
|
||
name: string
|
||
description: string
|
||
type: SceneType
|
||
difficulty: Difficulty
|
||
status: SceneStatus
|
||
background: string
|
||
ai_role: string
|
||
objectives: string[]
|
||
keywords: string[]
|
||
duration: number
|
||
usage_count: number
|
||
rating: number
|
||
created_by: number
|
||
updated_by: number
|
||
created_at: string
|
||
updated_at: string
|
||
}
|
||
```
|
||
|
||
## 三、场景管理接口(Manager)
|
||
|
||
### 3.1 获取场景列表
|
||
|
||
**接口**:`GET /api/v1/manager/practice-scenes`
|
||
|
||
**权限**:manager、admin
|
||
|
||
**请求参数**:
|
||
| 参数 | 类型 | 必填 | 说明 | 示例 |
|
||
|------|------|------|------|------|
|
||
| page | number | 否 | 页码,默认1 | 1 |
|
||
| size | number | 否 | 每页数量,默认20 | 20 |
|
||
| type | string | 否 | 场景类型筛选 | phone |
|
||
| difficulty | string | 否 | 难度筛选 | intermediate |
|
||
| status | string | 否 | 状态筛选 | active |
|
||
| search | string | 否 | 关键词搜索(名称、描述) | 销售 |
|
||
|
||
**请求示例**:
|
||
```http
|
||
GET /api/v1/manager/practice-scenes?page=1&size=20&type=phone&difficulty=beginner
|
||
Authorization: Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...
|
||
```
|
||
|
||
**响应示例**:
|
||
```json
|
||
{
|
||
"code": 200,
|
||
"message": "success",
|
||
"data": {
|
||
"items": [
|
||
{
|
||
"id": 1,
|
||
"name": "初次电话拜访客户",
|
||
"description": "模拟首次通过电话联系潜在客户的场景",
|
||
"type": "phone",
|
||
"difficulty": "beginner",
|
||
"status": "active",
|
||
"background": "你是一名销售专员...",
|
||
"ai_role": "AI扮演一位忙碌的采购经理...",
|
||
"objectives": ["学会专业的电话开场白", "快速建立信任关系"],
|
||
"keywords": ["开场白", "需求挖掘"],
|
||
"duration": 10,
|
||
"usage_count": 256,
|
||
"rating": 4.5,
|
||
"created_at": "2024-01-15T10:30:00",
|
||
"updated_at": "2024-03-18T15:20:00"
|
||
}
|
||
],
|
||
"total": 15,
|
||
"page": 1,
|
||
"page_size": 20,
|
||
"pages": 1
|
||
}
|
||
}
|
||
```
|
||
|
||
### 3.2 获取场景详情
|
||
|
||
**接口**:`GET /api/v1/manager/practice-scenes/{id}`
|
||
|
||
**权限**:manager、admin
|
||
|
||
**路径参数**:
|
||
| 参数 | 类型 | 必填 | 说明 |
|
||
|------|------|------|------|
|
||
| id | number | 是 | 场景ID |
|
||
|
||
**请求示例**:
|
||
```http
|
||
GET /api/v1/manager/practice-scenes/1
|
||
Authorization: Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...
|
||
```
|
||
|
||
**响应示例**:
|
||
```json
|
||
{
|
||
"code": 200,
|
||
"message": "success",
|
||
"data": {
|
||
"id": 1,
|
||
"name": "初次电话拜访客户",
|
||
"description": "模拟首次通过电话联系潜在客户的场景",
|
||
"type": "phone",
|
||
"difficulty": "beginner",
|
||
"status": "active",
|
||
"background": "你是一名销售专员,需要通过电话联系一位从未接触过的潜在客户。客户是某公司的采购经理,你需要在短时间内引起他的兴趣。",
|
||
"ai_role": "AI扮演一位忙碌且略显不耐烦的采购经理,对推销电话比较抵触,但如果销售人员能够快速切入他的需求点,他会愿意继续交谈。",
|
||
"objectives": ["学会专业的电话开场白", "快速建立信任关系", "有效探询客户需求", "预约下次沟通时间"],
|
||
"keywords": ["开场白", "需求挖掘", "时间管理", "预约技巧"],
|
||
"duration": 10,
|
||
"usage_count": 256,
|
||
"rating": 4.5,
|
||
"created_by": 1,
|
||
"updated_by": 1,
|
||
"created_at": "2024-01-15T10:30:00",
|
||
"updated_at": "2024-03-18T15:20:00"
|
||
}
|
||
}
|
||
```
|
||
|
||
### 3.3 创建场景
|
||
|
||
**接口**:`POST /api/v1/manager/practice-scenes`
|
||
|
||
**权限**:manager、admin
|
||
|
||
**请求体**:
|
||
```typescript
|
||
interface CreateSceneRequest {
|
||
name: string // 必填,最长200字符
|
||
description: string // 必填,场景描述
|
||
type: SceneType // 必填
|
||
difficulty: Difficulty // 必填
|
||
status?: SceneStatus // 可选,默认active
|
||
background: string // 必填,场景背景
|
||
ai_role: string // 必填,AI角色描述
|
||
objectives: string[] // 必填,练习目标数组
|
||
keywords: string[] // 必填,关键词数组
|
||
duration?: number // 可选,预计时长(分钟),默认10
|
||
}
|
||
```
|
||
|
||
**请求示例**:
|
||
```http
|
||
POST /api/v1/manager/practice-scenes
|
||
Authorization: Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...
|
||
Content-Type: application/json
|
||
|
||
{
|
||
"name": "产品功能介绍",
|
||
"description": "练习向客户详细介绍产品功能特点",
|
||
"type": "product-intro",
|
||
"difficulty": "junior",
|
||
"status": "active",
|
||
"background": "客户对你们的产品有一定了解,现在希望你详细介绍产品的核心功能和优势。",
|
||
"ai_role": "AI扮演一位专业的采购人员,会提出具体的技术问题和需求,希望了解产品的详细功能。",
|
||
"objectives": ["清晰介绍产品功能", "突出产品优势", "回答技术问题"],
|
||
"keywords": ["产品介绍", "功能展示", "优势分析"],
|
||
"duration": 12
|
||
}
|
||
```
|
||
|
||
**响应示例**:
|
||
```json
|
||
{
|
||
"code": 200,
|
||
"message": "创建场景成功",
|
||
"data": {
|
||
"id": 6,
|
||
"name": "产品功能介绍",
|
||
"description": "练习向客户详细介绍产品功能特点",
|
||
"type": "product-intro",
|
||
"difficulty": "junior",
|
||
"status": "active",
|
||
"background": "客户对你们的产品有一定了解...",
|
||
"ai_role": "AI扮演一位专业的采购人员...",
|
||
"objectives": ["清晰介绍产品功能", "突出产品优势", "回答技术问题"],
|
||
"keywords": ["产品介绍", "功能展示", "优势分析"],
|
||
"duration": 12,
|
||
"usage_count": 0,
|
||
"rating": 0.0,
|
||
"created_at": "2025-10-13T18:30:00"
|
||
}
|
||
}
|
||
```
|
||
|
||
### 3.4 更新场景
|
||
|
||
**接口**:`PUT /api/v1/manager/practice-scenes/{id}`
|
||
|
||
**权限**:manager、admin
|
||
|
||
**路径参数**:
|
||
| 参数 | 类型 | 必填 | 说明 |
|
||
|------|------|------|------|
|
||
| id | number | 是 | 场景ID |
|
||
|
||
**请求体**:与创建场景相同,所有字段可选
|
||
|
||
**请求示例**:
|
||
```http
|
||
PUT /api/v1/manager/practice-scenes/6
|
||
Authorization: Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...
|
||
Content-Type: application/json
|
||
|
||
{
|
||
"name": "产品功能详细介绍",
|
||
"duration": 15,
|
||
"status": "active"
|
||
}
|
||
```
|
||
|
||
**响应示例**:
|
||
```json
|
||
{
|
||
"code": 200,
|
||
"message": "更新场景成功",
|
||
"data": {
|
||
"id": 6,
|
||
"name": "产品功能详细介绍",
|
||
"duration": 15,
|
||
"updated_at": "2025-10-13T19:00:00"
|
||
}
|
||
}
|
||
```
|
||
|
||
### 3.5 删除场景
|
||
|
||
**接口**:`DELETE /api/v1/manager/practice-scenes/{id}`
|
||
|
||
**权限**:manager、admin
|
||
|
||
**路径参数**:
|
||
| 参数 | 类型 | 必填 | 说明 |
|
||
|------|------|------|------|
|
||
| id | number | 是 | 场景ID |
|
||
|
||
**请求示例**:
|
||
```http
|
||
DELETE /api/v1/manager/practice-scenes/6
|
||
Authorization: Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...
|
||
```
|
||
|
||
**响应示例**:
|
||
```json
|
||
{
|
||
"code": 200,
|
||
"message": "删除场景成功",
|
||
"data": {
|
||
"id": 6
|
||
}
|
||
}
|
||
```
|
||
|
||
### 3.6 切换场景状态
|
||
|
||
**接口**:`PUT /api/v1/manager/practice-scenes/{id}/toggle-status`
|
||
|
||
**权限**:manager、admin
|
||
|
||
**路径参数**:
|
||
| 参数 | 类型 | 必填 | 说明 |
|
||
|------|------|------|------|
|
||
| id | number | 是 | 场景ID |
|
||
|
||
**请求示例**:
|
||
```http
|
||
PUT /api/v1/manager/practice-scenes/6/toggle-status
|
||
Authorization: Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...
|
||
```
|
||
|
||
**响应示例**:
|
||
```json
|
||
{
|
||
"code": 200,
|
||
"message": "场景状态已切换",
|
||
"data": {
|
||
"id": 6,
|
||
"status": "inactive"
|
||
}
|
||
}
|
||
```
|
||
|
||
## 四、学员查询接口(Trainee)
|
||
|
||
### 4.1 获取可用场景列表
|
||
|
||
**接口**:`GET /api/v1/practice/scenes`
|
||
|
||
**权限**:trainee、manager、admin
|
||
|
||
**请求参数**:
|
||
| 参数 | 类型 | 必填 | 说明 |
|
||
|------|------|------|------|
|
||
| page | number | 否 | 页码,默认1 |
|
||
| size | number | 否 | 每页数量,默认20 |
|
||
| type | string | 否 | 场景类型筛选 |
|
||
| difficulty | string | 否 | 难度筛选 |
|
||
| search | string | 否 | 关键词搜索 |
|
||
|
||
**说明**:仅返回status=active的场景
|
||
|
||
**请求示例**:
|
||
```http
|
||
GET /api/v1/practice/scenes?page=1&size=20&type=phone
|
||
Authorization: Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...
|
||
```
|
||
|
||
**响应示例**:同管理接口的列表响应
|
||
|
||
### 4.2 获取场景详情
|
||
|
||
**接口**:`GET /api/v1/practice/scenes/{id}`
|
||
|
||
**权限**:trainee、manager、admin
|
||
|
||
**路径参数**:
|
||
| 参数 | 类型 | 必填 | 说明 |
|
||
|------|------|------|------|
|
||
| id | number | 是 | 场景ID |
|
||
|
||
**请求示例**:
|
||
```http
|
||
GET /api/v1/practice/scenes/1
|
||
Authorization: Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...
|
||
```
|
||
|
||
**响应示例**:同管理接口的详情响应
|
||
|
||
## 五、陪练对话接口
|
||
|
||
### 5.1 开始陪练对话
|
||
|
||
**接口**:`POST /api/v1/practice/start`
|
||
|
||
**权限**:trainee、manager、admin
|
||
|
||
**协议**:SSE (Server-Sent Events)
|
||
|
||
**请求体**:
|
||
```typescript
|
||
interface StartPracticeRequest {
|
||
scene_id?: number // 场景ID(陪练中心模式,可选)
|
||
scene_name: string // 场景名称(必填)
|
||
scene_description?: string // 场景描述(可选)
|
||
scene_background: string // 场景背景(必填)
|
||
scene_ai_role: string // AI角色(必填)
|
||
scene_objectives: string[] // 练习目标(必填)
|
||
scene_keywords?: string[] // 关键词(可选)
|
||
user_message: string // 用户消息(必填)
|
||
conversation_id?: string // 对话ID(续接对话时必填)
|
||
is_first: boolean // 是否首次消息(必填)
|
||
}
|
||
```
|
||
|
||
**⚠️ 重要说明**:
|
||
- **首次消息 (is_first=true)**:后端会将场景信息(background, ai_role, objectives等)拼接到user_message前面,作为完整的系统提示发送给Coze,让AI理解角色设定
|
||
- **后续消息 (is_first=false)**:仅发送user_message,不再重复场景信息
|
||
|
||
**请求示例**:
|
||
**首次消息请求示例**:
|
||
```http
|
||
POST /api/v1/practice/start
|
||
Authorization: Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...
|
||
Content-Type: application/json
|
||
|
||
{
|
||
"scene_id": 1,
|
||
"scene_name": "初次电话拜访客户",
|
||
"scene_description": "模拟首次通过电话联系潜在客户的场景",
|
||
"scene_background": "你是一名销售专员,需要通过电话联系一位从未接触过的潜在客户。客户是某公司的采购经理,你需要在短时间内引起他的兴趣。",
|
||
"scene_ai_role": "AI扮演一位忙碌且略显不耐烦的采购经理,对推销电话比较抵触,但如果销售人员能够快速切入他的需求点,他会愿意继续交谈。",
|
||
"scene_objectives": ["学会专业的电话开场白", "快速建立信任关系", "有效探询客户需求"],
|
||
"scene_keywords": ["开场白", "需求挖掘", "时间管理"],
|
||
"user_message": "您好,我是XX公司的销售顾问,想占用您几分钟时间",
|
||
"is_first": true
|
||
}
|
||
```
|
||
|
||
**后端处理**:首次消息时,后端会将场景信息构建为完整的场景设定文本,拼接到user_message前面发送给Coze。
|
||
|
||
**实际发送给Coze的内容**:
|
||
```
|
||
# 陪练场景设定
|
||
|
||
## 场景名称
|
||
初次电话拜访客户
|
||
|
||
## 场景背景
|
||
你是一名销售专员,需要通过电话联系一位从未接触过的潜在客户...
|
||
|
||
## AI角色要求
|
||
AI扮演一位忙碌且略显不耐烦的采购经理...
|
||
|
||
## 练习目标
|
||
1. 学会专业的电话开场白
|
||
2. 快速建立信任关系
|
||
3. 有效探询客户需求
|
||
|
||
## 关键词
|
||
开场白, 需求挖掘, 时间管理
|
||
|
||
---
|
||
|
||
现在开始陪练对话。请你严格按照上述场景设定扮演角色,与学员进行实战对话练习。
|
||
|
||
学员的第一句话:您好,我是XX公司的销售顾问,想占用您几分钟时间
|
||
```
|
||
|
||
**后续消息请求示例**:
|
||
```http
|
||
POST /api/v1/practice/start
|
||
Authorization: Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...
|
||
Content-Type: application/json
|
||
|
||
{
|
||
"user_message": "我们公司提供的是轻医美整体解决方案",
|
||
"conversation_id": "conv_abc123",
|
||
"is_first": false
|
||
}
|
||
```
|
||
|
||
**后端处理**:后续消息直接发送user_message,不再拼接场景信息。
|
||
|
||
**SSE事件格式**:
|
||
|
||
#### 事件1:对话创建
|
||
```
|
||
event: conversation.chat.created
|
||
data: {"conversation_id":"conv_abc123","chat_id":"chat_xyz789"}
|
||
```
|
||
|
||
#### 事件2:消息增量(实时打字)
|
||
```
|
||
event: message.delta
|
||
data: {"content":"您"}
|
||
|
||
event: message.delta
|
||
data: {"content":"好"}
|
||
|
||
event: message.delta
|
||
data: {"content":","}
|
||
```
|
||
|
||
#### 事件3:消息完成
|
||
```
|
||
event: message.completed
|
||
data: {"content":"您好,我现在很忙,你有什么事吗?"}
|
||
```
|
||
|
||
#### 事件4:对话完成
|
||
```
|
||
event: conversation.completed
|
||
data: {"token_count":156}
|
||
```
|
||
|
||
#### 事件5:结束标记
|
||
```
|
||
event: done
|
||
data: [DONE]
|
||
```
|
||
|
||
#### 事件6:错误
|
||
```
|
||
event: error
|
||
data: {"error":"对话失败: Network Error"}
|
||
```
|
||
|
||
**前端处理示例**:
|
||
```javascript
|
||
const response = await fetch('/api/v1/practice/start', {
|
||
method: 'POST',
|
||
headers: {
|
||
'Content-Type': 'application/json',
|
||
'Authorization': `Bearer ${token}`
|
||
},
|
||
body: JSON.stringify(requestData)
|
||
})
|
||
|
||
const reader = response.body.getReader()
|
||
const decoder = new TextDecoder()
|
||
|
||
while (true) {
|
||
const { value, done } = await reader.read()
|
||
if (done) break
|
||
|
||
const chunk = decoder.decode(value)
|
||
const lines = chunk.split('\n\n')
|
||
|
||
for (const line of lines) {
|
||
if (!line.trim() || !line.startsWith('event: ')) continue
|
||
|
||
const [eventLine, dataLine] = line.split('\n')
|
||
const event = eventLine.replace('event: ', '')
|
||
const data = JSON.parse(dataLine.replace('data: ', ''))
|
||
|
||
switch (event) {
|
||
case 'conversation.chat.created':
|
||
conversationId.value = data.conversation_id
|
||
break
|
||
case 'message.delta':
|
||
aiMessage.content += data.content
|
||
break
|
||
case 'message.completed':
|
||
console.log('消息完成')
|
||
break
|
||
case 'conversation.completed':
|
||
console.log('Token用量:', data.token_count)
|
||
break
|
||
case 'error':
|
||
ElMessage.error(data.error)
|
||
break
|
||
}
|
||
}
|
||
}
|
||
```
|
||
|
||
### 5.2 中断对话
|
||
|
||
**接口**:`POST /api/v1/practice/interrupt`
|
||
|
||
**权限**:trainee、manager、admin
|
||
|
||
**请求体**:
|
||
```typescript
|
||
interface InterruptPracticeRequest {
|
||
conversation_id: string
|
||
chat_id: string
|
||
}
|
||
```
|
||
|
||
**请求示例**:
|
||
```http
|
||
POST /api/v1/practice/interrupt
|
||
Authorization: Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...
|
||
Content-Type: application/json
|
||
|
||
{
|
||
"conversation_id": "conv_abc123",
|
||
"chat_id": "chat_xyz789"
|
||
}
|
||
```
|
||
|
||
**响应示例**:
|
||
```json
|
||
{
|
||
"code": 200,
|
||
"message": "对话已中断",
|
||
"data": {
|
||
"conversation_id": "conv_abc123",
|
||
"chat_id": "chat_xyz789"
|
||
}
|
||
}
|
||
```
|
||
|
||
### 5.3 获取对话列表
|
||
|
||
**接口**:`GET /api/v1/practice/conversations`
|
||
|
||
**权限**:trainee、manager、admin
|
||
|
||
**请求参数**:
|
||
| 参数 | 类型 | 必填 | 说明 |
|
||
|------|------|------|------|
|
||
| page | number | 否 | 页码,默认1 |
|
||
| size | number | 否 | 每页数量,默认20 |
|
||
|
||
**请求示例**:
|
||
```http
|
||
GET /api/v1/practice/conversations?page=1&size=20
|
||
Authorization: Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...
|
||
```
|
||
|
||
**响应示例**:
|
||
```json
|
||
{
|
||
"code": 200,
|
||
"message": "success",
|
||
"data": {
|
||
"items": [
|
||
{
|
||
"id": "conv_abc123",
|
||
"name": "初次电话拜访客户 - 2025-10-13",
|
||
"created_at": 1697184000000
|
||
}
|
||
],
|
||
"has_more": false,
|
||
"page": 1,
|
||
"size": 20
|
||
}
|
||
}
|
||
```
|
||
|
||
## 六、Dify场景提取接口
|
||
|
||
### 6.1 从课程提取场景
|
||
|
||
**接口**:`POST /api/v1/practice/extract-scene`
|
||
|
||
**权限**:trainee、manager、admin
|
||
|
||
**请求体**:
|
||
```typescript
|
||
interface ExtractSceneRequest {
|
||
course_id: number
|
||
}
|
||
```
|
||
|
||
**请求示例**:
|
||
```http
|
||
POST /api/v1/practice/extract-scene
|
||
Authorization: Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...
|
||
Content-Type: application/json
|
||
|
||
{
|
||
"course_id": 5
|
||
}
|
||
```
|
||
|
||
**响应示例**:
|
||
```json
|
||
{
|
||
"code": 200,
|
||
"message": "场景提取成功",
|
||
"data": {
|
||
"scene": {
|
||
"name": "轻医美产品咨询陪练",
|
||
"description": "模拟客户咨询轻医美产品的场景,重点练习产品介绍和价格谈判技巧",
|
||
"type": "product-intro",
|
||
"difficulty": "intermediate",
|
||
"background": "客户是一位30岁女性,对面部抗衰项目感兴趣,之前了解过玻尿酸填充,现在想详细咨询你们的产品和价格。",
|
||
"ai_role": "AI扮演一位对轻医美有一定了解的客户,关注产品安全性和性价比,会提出具体的技术问题和价格异议。",
|
||
"objectives": [
|
||
"了解客户具体需求和预算",
|
||
"专业介绍产品成分和效果",
|
||
"处理价格异议,强调价值",
|
||
"建立客户信任"
|
||
],
|
||
"keywords": ["抗衰", "玻尿酸", "价格", "安全性"]
|
||
},
|
||
"workflow_run_id": "wf_run_abc123",
|
||
"task_id": "task_xyz789"
|
||
}
|
||
}
|
||
```
|
||
|
||
## 七、错误码说明
|
||
|
||
| code | message | 说明 | 处理建议 |
|
||
|------|---------|------|---------|
|
||
| 200 | success | 成功 | 正常处理 |
|
||
| 400 | 参数错误 | 请求参数不合法 | 检查参数格式 |
|
||
| 401 | 未授权 | token无效或过期 | 重新登录 |
|
||
| 403 | 无权限 | 当前角色无权限 | 提示用户无权限 |
|
||
| 404 | 资源不存在 | 场景不存在 | 返回列表页 |
|
||
| 409 | 资源冲突 | 场景名称重复 | 提示修改名称 |
|
||
| 500 | 服务器错误 | 内部错误 | 提示稍后重试 |
|
||
| 503 | 服务不可用 | Coze/Dify服务异常 | 提示稍后重试 |
|
||
|
||
## 八、附录
|
||
|
||
### 8.1 完整TypeScript类型定义
|
||
|
||
```typescript
|
||
// 场景类型
|
||
type SceneType = 'phone' | 'face' | 'complaint' | 'after-sales' | 'product-intro'
|
||
type Difficulty = 'beginner' | 'junior' | 'intermediate' | 'senior' | 'expert'
|
||
type SceneStatus = 'active' | 'inactive'
|
||
|
||
// 场景对象
|
||
interface PracticeScene {
|
||
id: number
|
||
name: string
|
||
description: string
|
||
type: SceneType
|
||
difficulty: Difficulty
|
||
status: SceneStatus
|
||
background: string
|
||
ai_role: string
|
||
objectives: string[]
|
||
keywords: string[]
|
||
duration: number
|
||
usage_count: number
|
||
rating: number
|
||
created_by: number
|
||
updated_by: number
|
||
created_at: string
|
||
updated_at: string
|
||
}
|
||
|
||
// API响应
|
||
interface ResponseModel<T = any> {
|
||
code: number
|
||
message: string
|
||
data: T
|
||
request_id?: string
|
||
}
|
||
|
||
interface PaginatedResponse<T> {
|
||
items: T[]
|
||
total: number
|
||
page: number
|
||
page_size: number
|
||
pages: number
|
||
}
|
||
|
||
// 请求对象
|
||
interface CreateSceneRequest {
|
||
name: string
|
||
description: string
|
||
type: SceneType
|
||
difficulty: Difficulty
|
||
status?: SceneStatus
|
||
background: string
|
||
ai_role: string
|
||
objectives: string[]
|
||
keywords: string[]
|
||
duration?: number
|
||
}
|
||
|
||
interface StartPracticeRequest {
|
||
scene_id?: number
|
||
scene_name: string
|
||
scene_background: string
|
||
scene_ai_role: string
|
||
scene_objectives: string[]
|
||
user_message: string
|
||
conversation_id?: string
|
||
is_first: boolean
|
||
}
|
||
|
||
interface ExtractSceneRequest {
|
||
course_id: number
|
||
}
|
||
|
||
// SSE事件
|
||
interface SSEEvent {
|
||
event: 'conversation.chat.created' | 'message.delta' | 'message.completed' | 'conversation.completed' | 'error' | 'done'
|
||
data: any
|
||
}
|
||
```
|
||
|
||
### 8.2 API调用示例(完整)
|
||
|
||
```javascript
|
||
// src/api/practice.ts
|
||
import request from '@/utils/request'
|
||
|
||
export const practiceApi = {
|
||
// 获取场景列表
|
||
getScenes(params) {
|
||
return request.get('/api/v1/practice/scenes', { params })
|
||
},
|
||
|
||
// 获取场景详情
|
||
getSceneDetail(id) {
|
||
return request.get(`/api/v1/practice/scenes/${id}`)
|
||
},
|
||
|
||
// 开始陪练(SSE流式)
|
||
startPractice(data) {
|
||
// SSE需要特殊处理,不能用普通的request
|
||
return fetch(`${import.meta.env.VITE_API_BASE_URL}/api/v1/practice/start`, {
|
||
method: 'POST',
|
||
headers: {
|
||
'Content-Type': 'application/json',
|
||
'Authorization': `Bearer ${getToken()}`
|
||
},
|
||
body: JSON.stringify(data)
|
||
})
|
||
},
|
||
|
||
// 中断对话
|
||
interruptPractice(data) {
|
||
return request.post('/api/v1/practice/interrupt', data)
|
||
},
|
||
|
||
// 获取对话列表
|
||
getConversations(params) {
|
||
return request.get('/api/v1/practice/conversations', { params })
|
||
},
|
||
|
||
// 提取场景
|
||
extractScene(data) {
|
||
return request.post('/api/v1/practice/extract-scene', data)
|
||
}
|
||
}
|
||
|
||
// 管理接口
|
||
export const practiceManagerApi = {
|
||
// 获取场景列表
|
||
getScenes(params) {
|
||
return request.get('/api/v1/manager/practice-scenes', { params })
|
||
},
|
||
|
||
// 创建场景
|
||
createScene(data) {
|
||
return request.post('/api/v1/manager/practice-scenes', data)
|
||
},
|
||
|
||
// 更新场景
|
||
updateScene(id, data) {
|
||
return request.put(`/api/v1/manager/practice-scenes/${id}`, data)
|
||
},
|
||
|
||
// 删除场景
|
||
deleteScene(id) {
|
||
return request.delete(`/api/v1/manager/practice-scenes/${id}`)
|
||
},
|
||
|
||
// 切换状态
|
||
toggleStatus(id) {
|
||
return request.put(`/api/v1/manager/practice-scenes/${id}/toggle-status`)
|
||
}
|
||
}
|
||
```
|
||
|
||
---
|
||
|
||
**文档版本**:v1.0
|
||
**最后更新**:2025-10-13
|
||
**维护人**:考培练系统开发团队
|
||
|