2026-01-18 15:58:05 +08:00
|
|
|
|
# Life Echo API
|
|
|
|
|
|
|
|
|
|
|
|
Life Echo 后端服务,基于 FastAPI 构建的实时语音对话回忆录生成系统。
|
|
|
|
|
|
|
|
|
|
|
|
## 项目简介
|
|
|
|
|
|
|
|
|
|
|
|
Life Echo API 是一个智能对话系统,通过 WebSocket 实时连接,使用 LangChain Agent 引导用户进行回忆录访谈对话,并将口语内容自动整理为结构化的书面章节,最终生成回忆录 PDF。
|
|
|
|
|
|
|
2026-03-22 16:45:57 +08:00
|
|
|
|
### 架构要点(多 Agent 收敛)
|
|
|
|
|
|
|
|
|
|
|
|
- **会话真源**:`conversation_messages`(DB)+ Redis 缓存;**实时编排入口**:`ChatOrchestrator`。
|
|
|
|
|
|
- **图像管线**:正文主图 `generate_story_image`;章节封面 `try_enqueue_generate_chapter_cover` → `generate_chapter_cover`。
|
|
|
|
|
|
- **回忆录批次**:`MemoirOrchestrator.prepare_batches` 显式分桶后,`process_memoir_segments` 按类别加锁并调用 `run_story_pipeline_for_category_batch`(含 `StoryRouteAgent.plan_batch` 多 unit 写入)。
|
|
|
|
|
|
|
2026-03-26 12:13:36 +08:00
|
|
|
|
### LLM 与记忆(约定文档)
|
|
|
|
|
|
|
|
|
|
|
|
- **JSON 模式**:结构化抽取/路由/叙事 JSON 使用 `app/core/langchain_llm.py` 的 `bind_json_object_mode`(与 [DeepSeek JSON Output](https://api-docs.deepseek.com/guides/json_mode) 一致);详见 [`docs/llm-json-mode.md`](docs/llm-json-mode.md)。适配器说明见 [`app/adapters/llm/deepseek.py`](app/adapters/llm/deepseek.py)。
|
2026-04-03 11:43:16 +08:00
|
|
|
|
- **记忆检索**:异步与 Celery 均使用 **向量(pgvector)** chunks,见 [`docs/memory-retrieval.md`](docs/memory-retrieval.md)。
|
|
|
|
|
|
- **Memory compaction**:`.env.example` / [`.env.development`](.env.development) / [`.env.staging`](.env.staging) / [`.env.production`](.env.production) 均默认 `MEMORY_COMPACTION_ENABLED=true`。须运行 **Celery worker** 与 **celery-beat**([`docker-compose.yml`](docker-compose.yml) 已包含 `celery-beat`,用于定期 `memory_compaction_sweep`)。
|
feat(eval): memoir A/B chapter judging and eval-web parity with dialogue
- Judge baseline excerpt and library chapter separately; build_memoir_compare_summary for gate, nine-dim and leaf deltas.
- Memoir SSE chapter payload: baseline_judge, compare_summary, baseline_judge_error.
- MemoirJudgeOutput: loose score coercion and post-validate clamp; memoir judge prompt caps from settings.
- app-eval-web: two-column MemoirScoreCard layout, MemoirCompareSummary, chapter blocks and CSS.
- Add memoir_compare_summary, log_events, celery_log_context, memoir_pipeline_progress; tests and migration 0014.
- Misc: memory/evidence and enrichment paths, task/orchestrator updates, internal-eval docs, env examples.
2026-04-10 10:23:43 +08:00
|
|
|
|
- **Memory LLM enrichment(单次 LLM:会话摘要 + 事实)**:任务路由到 **`memory_idle`** 队列(`CELERY_MEMORY_ENRICHMENT_QUEUE`,默认 `memory_idle`)。本地与 compose 内 worker 已使用 `-Q celery,memory_idle`;生产可单独起低并发 worker 只消费 `memory_idle`,与主队列隔离。
|
2026-03-26 12:13:36 +08:00
|
|
|
|
|
2026-01-18 15:58:05 +08:00
|
|
|
|
## 技术栈
|
|
|
|
|
|
|
|
|
|
|
|
- **Web 框架**: FastAPI 0.115.0
|
|
|
|
|
|
- **WebSocket**: websockets 14.1
|
2026-01-21 23:21:36 +01:00
|
|
|
|
- **AI 框架**: LangChain 0.3.7 + DeepSeek/兼容 OpenAI 的 LLM
|
|
|
|
|
|
- **数据库**: PostgreSQL 17 + SQLAlchemy 2.0.36 (asyncpg)
|
|
|
|
|
|
- **缓存/队列**: Redis 7 + Celery 5.3
|
2026-01-18 15:58:05 +08:00
|
|
|
|
- **PDF 生成**: ReportLab 4.2.2 + WeasyPrint 62.3
|
|
|
|
|
|
- **ASR/TTS**: OpenAI Whisper API
|
2026-01-21 23:21:36 +01:00
|
|
|
|
- **认证**: JWT (python-jose) + bcrypt
|
2026-01-18 15:58:05 +08:00
|
|
|
|
- **其他**: Pydantic, python-dotenv
|
|
|
|
|
|
|
|
|
|
|
|
## 项目结构
|
|
|
|
|
|
|
|
|
|
|
|
```
|
|
|
|
|
|
api/
|
2026-03-18 17:18:23 +08:00
|
|
|
|
├── main.py # 应用入口(uvicorn 启动)
|
|
|
|
|
|
├── app/ # 应用主包
|
|
|
|
|
|
│ ├── main.py # FastAPI 应用定义
|
|
|
|
|
|
│ ├── core/ # 核心基础设施
|
|
|
|
|
|
│ │ ├── config.py # 配置(pydantic-settings)
|
|
|
|
|
|
│ │ ├── db.py # 数据库连接
|
|
|
|
|
|
│ │ ├── redis.py # Redis 服务
|
|
|
|
|
|
│ │ ├── security.py # JWT、密码哈希
|
|
|
|
|
|
│ │ └── task_tracker.py # 任务状态追踪
|
|
|
|
|
|
│ ├── features/ # 功能模块(各模块含 router、service、repo)
|
|
|
|
|
|
│ │ ├── auth/ # 认证(注册、登录、短信验证码)
|
|
|
|
|
|
│ │ ├── user/ # 用户信息
|
|
|
|
|
|
│ │ ├── conversation/ # 对话、WebSocket
|
|
|
|
|
|
│ │ ├── memory/ # 记忆检索
|
|
|
|
|
|
│ │ ├── memoir/ # 回忆录、章节、PDF、图像生成
|
|
|
|
|
|
│ │ ├── payment/ # 支付
|
|
|
|
|
|
│ │ ├── plan/ # 套餐
|
|
|
|
|
|
│ │ ├── quota/ # 配额
|
|
|
|
|
|
│ │ ├── tasks/ # 任务状态 API
|
|
|
|
|
|
│ │ └── content/ # 内容(TTS 等)
|
|
|
|
|
|
│ ├── adapters/ # 外部能力适配器(ASR、TTS、LLM、短信、存储等)
|
|
|
|
|
|
│ ├── ports/ # 能力契约(Protocol)
|
|
|
|
|
|
│ └── agents/ # LangChain Agent
|
2026-01-26 11:54:03 +08:00
|
|
|
|
├── tasks/ # Celery 后台任务
|
|
|
|
|
|
│ └── memoir_tasks.py # 回忆录处理任务
|
|
|
|
|
|
└── docs/ # 详细文档
|
2026-01-18 15:58:05 +08:00
|
|
|
|
```
|
|
|
|
|
|
|
|
|
|
|
|
## 环境配置
|
|
|
|
|
|
|
|
|
|
|
|
### 1. 安装依赖
|
|
|
|
|
|
|
|
|
|
|
|
```bash
|
|
|
|
|
|
cd api
|
|
|
|
|
|
pip install -r requirements.txt
|
|
|
|
|
|
```
|
|
|
|
|
|
|
|
|
|
|
|
### 2. 环境变量配置
|
|
|
|
|
|
|
|
|
|
|
|
创建 `.env` 文件(在 `api/` 目录下):
|
|
|
|
|
|
|
|
|
|
|
|
```env
|
|
|
|
|
|
# DeepSeek API 配置(推荐,优先使用)
|
|
|
|
|
|
DEEPSEEK_API_KEY=your_deepseek_api_key_here
|
|
|
|
|
|
DEEPSEEK_BASE_URL=https://api.deepseek.com # 可选,默认值
|
|
|
|
|
|
DEEPSEEK_MODEL=deepseek-chat # 可选,默认值
|
|
|
|
|
|
|
|
|
|
|
|
# 或使用通用 LLM 配置(支持其他兼容 OpenAI 的 LLM)
|
|
|
|
|
|
LLM_API_KEY=your_llm_api_key_here
|
|
|
|
|
|
LLM_BASE_URL=https://api.your-llm-provider.com # 可选
|
|
|
|
|
|
LLM_MODEL=your-model-name # 可选,默认 deepseek-chat
|
|
|
|
|
|
LLM_TEMPERATURE=0.7 # 可选,默认 0.7
|
|
|
|
|
|
|
2026-01-21 23:21:36 +01:00
|
|
|
|
# 数据库配置(PostgreSQL,推荐)
|
|
|
|
|
|
DATABASE_URL=postgresql://postgres:postgres@localhost:5432/life_echo
|
|
|
|
|
|
|
|
|
|
|
|
# Redis 配置
|
|
|
|
|
|
REDIS_URL=redis://localhost:6379/0
|
2026-01-18 15:58:05 +08:00
|
|
|
|
|
|
|
|
|
|
# 认证配置
|
|
|
|
|
|
SECRET_KEY=your-secret-key-here # JWT签名密钥(建议使用随机字符串)
|
|
|
|
|
|
ALGORITHM=HS256 # JWT算法(默认HS256)
|
|
|
|
|
|
ACCESS_TOKEN_EXPIRE_MINUTES=120 # 访问令牌过期时间(分钟,默认120即2小时)
|
|
|
|
|
|
|
|
|
|
|
|
# 服务器配置(可选)
|
|
|
|
|
|
HOST=0.0.0.0
|
|
|
|
|
|
PORT=8000
|
|
|
|
|
|
```
|
|
|
|
|
|
|
|
|
|
|
|
**LLM 配置优先级**:
|
|
|
|
|
|
1. `DEEPSEEK_API_KEY` - 优先使用 DeepSeek(推荐)
|
|
|
|
|
|
2. `LLM_API_KEY` - 通用 LLM 配置(支持其他兼容 OpenAI 格式的 LLM)
|
|
|
|
|
|
|
|
|
|
|
|
**DeepSeek 配置示例**:
|
|
|
|
|
|
```env
|
|
|
|
|
|
DEEPSEEK_API_KEY=sk-xxxxxxxxxxxxx
|
|
|
|
|
|
DEEPSEEK_MODEL=deepseek-chat
|
|
|
|
|
|
```
|
|
|
|
|
|
|
2026-03-18 17:18:23 +08:00
|
|
|
|
### 3. 数据库迁移
|
2026-01-18 15:58:05 +08:00
|
|
|
|
|
2026-03-26 12:13:36 +08:00
|
|
|
|
数据库 schema 由 Alembic 管理。**`app/main.py` 启动时会在线程中执行 `alembic upgrade head`**(见 `app/core/alembic_startup.py`):对连接类错误自动重试;生产环境建议设置 `ALEMBIC_STARTUP_FAIL_FAST=true`,迁移失败则进程退出。仍可手动执行:
|
2026-01-18 15:58:05 +08:00
|
|
|
|
|
2026-03-18 17:18:23 +08:00
|
|
|
|
```bash
|
|
|
|
|
|
cd api
|
|
|
|
|
|
uv run alembic upgrade head
|
2026-01-18 15:58:05 +08:00
|
|
|
|
```
|
|
|
|
|
|
|
2026-01-21 23:06:47 +01:00
|
|
|
|
## 快速启动
|
2026-01-18 15:58:05 +08:00
|
|
|
|
|
2026-01-21 23:06:47 +01:00
|
|
|
|
### 本地开发
|
2026-01-18 15:58:05 +08:00
|
|
|
|
|
2026-03-09 15:30:18 +08:00
|
|
|
|
推荐使用一键脚本(会自动启动 PostgreSQL/Redis、检查 `.venv`、安装依赖并拉起 FastAPI + Celery):
|
|
|
|
|
|
|
|
|
|
|
|
```bash
|
|
|
|
|
|
cd api
|
|
|
|
|
|
./dev-up.sh
|
|
|
|
|
|
```
|
|
|
|
|
|
|
|
|
|
|
|
可选环境变量:
|
|
|
|
|
|
- `SKIP_INSTALL=1`:跳过依赖安装
|
|
|
|
|
|
- `API_HOST` / `API_PORT`:覆盖 API 启动地址和端口
|
|
|
|
|
|
- `CELERY_POOL`:覆盖 Celery 池类型(macOS 推荐 `solo`)
|
|
|
|
|
|
|
|
|
|
|
|
也可以使用手动方式:
|
|
|
|
|
|
|
2026-01-18 15:58:05 +08:00
|
|
|
|
```bash
|
2026-01-21 23:06:47 +01:00
|
|
|
|
cd api
|
|
|
|
|
|
|
2026-01-21 23:21:36 +01:00
|
|
|
|
# 1. 启动 PostgreSQL + Redis
|
2026-03-25 17:40:04 +08:00
|
|
|
|
docker compose -f docker-compose.dev.yml up -d
|
2026-01-21 23:06:47 +01:00
|
|
|
|
|
|
|
|
|
|
# 2. 安装依赖
|
|
|
|
|
|
pip install -r requirements.txt
|
|
|
|
|
|
|
2026-01-21 23:21:36 +01:00
|
|
|
|
# 3. 配置环境变量
|
|
|
|
|
|
export DATABASE_URL=postgresql://postgres:postgres@localhost:5432/life_echo
|
|
|
|
|
|
export REDIS_URL=redis://localhost:6379/0
|
|
|
|
|
|
|
|
|
|
|
|
# 4. 启动 API(终端 1)
|
2026-01-18 15:58:05 +08:00
|
|
|
|
uvicorn main:app --reload --host 0.0.0.0 --port 8000
|
2026-01-21 23:06:47 +01:00
|
|
|
|
|
2026-01-21 23:21:36 +01:00
|
|
|
|
# 5. 启动 Celery Worker(终端 2)
|
feat(eval): memoir A/B chapter judging and eval-web parity with dialogue
- Judge baseline excerpt and library chapter separately; build_memoir_compare_summary for gate, nine-dim and leaf deltas.
- Memoir SSE chapter payload: baseline_judge, compare_summary, baseline_judge_error.
- MemoirJudgeOutput: loose score coercion and post-validate clamp; memoir judge prompt caps from settings.
- app-eval-web: two-column MemoirScoreCard layout, MemoirCompareSummary, chapter blocks and CSS.
- Add memoir_compare_summary, log_events, celery_log_context, memoir_pipeline_progress; tests and migration 0014.
- Misc: memory/evidence and enrichment paths, task/orchestrator updates, internal-eval docs, env examples.
2026-04-10 10:23:43 +08:00
|
|
|
|
# macOS 使用 solo 池避免 fork 崩溃问题;须同时消费 memory_idle(Memory 富化)
|
|
|
|
|
|
celery -A app.tasks.celery_app worker --loglevel=info --pool=solo -Q celery,memory_idle
|
2026-01-21 23:06:47 +01:00
|
|
|
|
|
|
|
|
|
|
# Linux/生产环境可以使用 prefork 池
|
feat(eval): memoir A/B chapter judging and eval-web parity with dialogue
- Judge baseline excerpt and library chapter separately; build_memoir_compare_summary for gate, nine-dim and leaf deltas.
- Memoir SSE chapter payload: baseline_judge, compare_summary, baseline_judge_error.
- MemoirJudgeOutput: loose score coercion and post-validate clamp; memoir judge prompt caps from settings.
- app-eval-web: two-column MemoirScoreCard layout, MemoirCompareSummary, chapter blocks and CSS.
- Add memoir_compare_summary, log_events, celery_log_context, memoir_pipeline_progress; tests and migration 0014.
- Misc: memory/evidence and enrichment paths, task/orchestrator updates, internal-eval docs, env examples.
2026-04-10 10:23:43 +08:00
|
|
|
|
# celery -A app.tasks.celery_app worker --loglevel=info --concurrency=4 -Q celery,memory_idle
|
2026-01-18 15:58:05 +08:00
|
|
|
|
```
|
|
|
|
|
|
|
2026-01-21 23:21:36 +01:00
|
|
|
|
### 验证服务
|
|
|
|
|
|
|
|
|
|
|
|
```bash
|
|
|
|
|
|
# 检查 PostgreSQL
|
|
|
|
|
|
docker exec life-echo-postgres-dev psql -U postgres -c "SELECT 1"
|
|
|
|
|
|
|
|
|
|
|
|
# 检查 Redis
|
|
|
|
|
|
docker exec life-echo-redis-dev redis-cli ping
|
|
|
|
|
|
```
|
|
|
|
|
|
|
2026-01-21 23:06:47 +01:00
|
|
|
|
### 生产部署(一键)
|
2026-01-18 15:58:05 +08:00
|
|
|
|
|
|
|
|
|
|
```bash
|
2026-01-21 23:06:47 +01:00
|
|
|
|
cd api
|
|
|
|
|
|
|
|
|
|
|
|
# 创建生产配置
|
|
|
|
|
|
cp .env .env.prod
|
|
|
|
|
|
# 编辑 .env.prod
|
|
|
|
|
|
|
|
|
|
|
|
# 启动所有服务
|
2026-03-25 17:40:04 +08:00
|
|
|
|
docker compose up -d
|
2026-01-21 23:06:47 +01:00
|
|
|
|
|
|
|
|
|
|
# 查看日志
|
2026-03-25 17:40:04 +08:00
|
|
|
|
docker compose logs -f
|
2026-01-18 15:58:05 +08:00
|
|
|
|
```
|
|
|
|
|
|
|
|
|
|
|
|
服务启动后,访问:
|
|
|
|
|
|
- API 文档: http://localhost:8000/docs
|
|
|
|
|
|
- 健康检查: http://localhost:8000/health
|
|
|
|
|
|
|
2026-01-26 11:54:03 +08:00
|
|
|
|
## 📚 详细文档
|
|
|
|
|
|
|
|
|
|
|
|
更多详细文档请参考 [docs/README.md](docs/README.md):
|
|
|
|
|
|
|
|
|
|
|
|
- **[本地开发环境配置](docs/本地开发环境配置.md)** - 开发环境搭建指南
|
|
|
|
|
|
- **[WebSocket 快速测试指南](docs/WebSocket快速测试指南.md)** - WebSocket 快速测试
|
|
|
|
|
|
- **[WebSocket 测试文档](docs/WebSocket测试文档.md)** - WebSocket 详细接口文档
|
|
|
|
|
|
- **[文字交流模式说明](docs/文字交流模式说明.md)** - 文字对话模式功能说明
|
|
|
|
|
|
- **[测试脚本使用说明](docs/测试脚本使用说明.md)** - 自动化测试脚本指南
|
|
|
|
|
|
|
2026-01-18 15:58:05 +08:00
|
|
|
|
## API 文档
|
|
|
|
|
|
|
|
|
|
|
|
### 认证系统
|
|
|
|
|
|
|
|
|
|
|
|
系统使用 JWT(JSON Web Token)进行认证,采用访问令牌(Access Token)+ 刷新令牌(Refresh Token)机制:
|
|
|
|
|
|
|
|
|
|
|
|
- **访问令牌**:有效期 2 小时,用于 API 请求认证
|
|
|
|
|
|
- **刷新令牌**:有效期 30 天,用于刷新访问令牌
|
|
|
|
|
|
|
|
|
|
|
|
#### 认证流程
|
|
|
|
|
|
|
|
|
|
|
|
1. **用户注册**:`POST /api/auth/register`
|
|
|
|
|
|
2. **用户登录**:`POST /api/auth/login` → 返回 `access_token` 和 `refresh_token`
|
|
|
|
|
|
3. **API 请求**:在 Header 中携带 `Authorization: Bearer {access_token}`
|
|
|
|
|
|
4. **刷新令牌**:`POST /api/auth/refresh` → 使用 `refresh_token` 获取新的 `access_token`
|
|
|
|
|
|
5. **用户登出**:`POST /api/auth/logout` → 撤销 `refresh_token`
|
|
|
|
|
|
|
|
|
|
|
|
#### 认证 API (`/api/auth`)
|
|
|
|
|
|
|
|
|
|
|
|
##### 用户注册
|
|
|
|
|
|
```http
|
|
|
|
|
|
POST /api/auth/register
|
|
|
|
|
|
Content-Type: application/json
|
|
|
|
|
|
|
|
|
|
|
|
{
|
|
|
|
|
|
"phone": "13800138000",
|
|
|
|
|
|
"password": "password123",
|
|
|
|
|
|
"nickname": "用户昵称",
|
|
|
|
|
|
"email": "user@example.com" // 可选
|
|
|
|
|
|
}
|
|
|
|
|
|
```
|
|
|
|
|
|
|
|
|
|
|
|
**响应**:
|
|
|
|
|
|
```json
|
|
|
|
|
|
{
|
|
|
|
|
|
"access_token": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...",
|
|
|
|
|
|
"refresh_token": "random-refresh-token-string",
|
|
|
|
|
|
"token_type": "bearer"
|
|
|
|
|
|
}
|
|
|
|
|
|
```
|
|
|
|
|
|
|
|
|
|
|
|
##### 用户登录
|
|
|
|
|
|
```http
|
|
|
|
|
|
POST /api/auth/login
|
|
|
|
|
|
Content-Type: application/json
|
|
|
|
|
|
|
|
|
|
|
|
{
|
|
|
|
|
|
"phone": "13800138000",
|
|
|
|
|
|
"password": "password123"
|
|
|
|
|
|
}
|
|
|
|
|
|
```
|
|
|
|
|
|
|
|
|
|
|
|
**响应**:同注册接口
|
|
|
|
|
|
|
|
|
|
|
|
##### 刷新访问令牌
|
|
|
|
|
|
```http
|
|
|
|
|
|
POST /api/auth/refresh
|
|
|
|
|
|
Content-Type: application/json
|
|
|
|
|
|
|
|
|
|
|
|
{
|
|
|
|
|
|
"refresh_token": "your-refresh-token"
|
|
|
|
|
|
}
|
|
|
|
|
|
```
|
|
|
|
|
|
|
|
|
|
|
|
**响应**:
|
|
|
|
|
|
```json
|
|
|
|
|
|
{
|
|
|
|
|
|
"access_token": "new-access-token",
|
|
|
|
|
|
"refresh_token": "same-refresh-token",
|
|
|
|
|
|
"token_type": "bearer"
|
|
|
|
|
|
}
|
|
|
|
|
|
```
|
|
|
|
|
|
|
|
|
|
|
|
##### 用户登出
|
|
|
|
|
|
```http
|
|
|
|
|
|
POST /api/auth/logout
|
|
|
|
|
|
Authorization: Bearer {access_token}
|
|
|
|
|
|
Content-Type: application/json
|
|
|
|
|
|
|
|
|
|
|
|
{
|
|
|
|
|
|
"refresh_token": "your-refresh-token"
|
|
|
|
|
|
}
|
|
|
|
|
|
```
|
|
|
|
|
|
|
|
|
|
|
|
##### 获取当前用户信息
|
|
|
|
|
|
```http
|
|
|
|
|
|
GET /api/auth/me
|
|
|
|
|
|
Authorization: Bearer {access_token}
|
|
|
|
|
|
```
|
|
|
|
|
|
|
|
|
|
|
|
**响应**:
|
|
|
|
|
|
```json
|
|
|
|
|
|
{
|
|
|
|
|
|
"id": "user-id",
|
|
|
|
|
|
"phone": "13800138000",
|
|
|
|
|
|
"email": "user@example.com",
|
|
|
|
|
|
"nickname": "用户昵称",
|
|
|
|
|
|
"avatar_url": null,
|
|
|
|
|
|
"subscription_type": "free",
|
|
|
|
|
|
"created_at": "2024-01-15T10:00:00Z"
|
|
|
|
|
|
}
|
|
|
|
|
|
```
|
|
|
|
|
|
|
|
|
|
|
|
#### 使用认证令牌
|
|
|
|
|
|
|
|
|
|
|
|
所有需要认证的 API 请求都需要在 Header 中携带访问令牌:
|
|
|
|
|
|
|
|
|
|
|
|
```http
|
|
|
|
|
|
Authorization: Bearer {access_token}
|
|
|
|
|
|
```
|
|
|
|
|
|
|
|
|
|
|
|
### REST API
|
|
|
|
|
|
|
|
|
|
|
|
#### 对话管理 (`/api/conversations`)
|
|
|
|
|
|
|
|
|
|
|
|
**注意**:所有对话相关接口都需要认证。
|
|
|
|
|
|
|
|
|
|
|
|
- `POST /api/conversations` - 创建新对话(需要认证)
|
|
|
|
|
|
- `GET /api/conversations/{conversation_id}` - 获取对话详情(需要认证,只能访问自己的对话)
|
|
|
|
|
|
- `POST /api/conversations/{conversation_id}/end` - 结束对话(需要认证,只能结束自己的对话)
|
|
|
|
|
|
|
|
|
|
|
|
#### 章节管理 (`/api/chapters`)
|
|
|
|
|
|
|
|
|
|
|
|
**注意**:所有章节相关接口都需要认证。
|
|
|
|
|
|
|
|
|
|
|
|
- `GET /api/chapters` - 获取用户所有章节(需要认证)
|
|
|
|
|
|
- `GET /api/chapters/{chapter_id}` - 获取章节详情(需要认证,只能访问自己的章节)
|
|
|
|
|
|
- `POST /api/chapters/{chapter_id}/regenerate` - 重新整理章节(需要认证,只能操作自己的章节)
|
|
|
|
|
|
|
|
|
|
|
|
#### 回忆录管理 (`/api/books`)
|
|
|
|
|
|
|
|
|
|
|
|
**注意**:所有回忆录相关接口都需要认证。
|
|
|
|
|
|
|
|
|
|
|
|
- `GET /api/books/current` - 获取当前回忆录(需要认证)
|
|
|
|
|
|
- `POST /api/books/export-pdf` - 导出 PDF(需要认证,只能导出自己的回忆录)
|
|
|
|
|
|
|
|
|
|
|
|
### WebSocket API
|
|
|
|
|
|
|
|
|
|
|
|
#### 对话 WebSocket (`/ws/conversation/{conversation_id}`)
|
|
|
|
|
|
|
|
|
|
|
|
**注意**:WebSocket 连接需要认证,通过查询参数传递访问令牌。
|
|
|
|
|
|
|
|
|
|
|
|
**连接地址**:
|
|
|
|
|
|
```
|
|
|
|
|
|
ws://localhost:8000/ws/conversation/{conversation_id}?token={access_token}
|
|
|
|
|
|
```
|
|
|
|
|
|
|
|
|
|
|
|
实时双向通信,支持:
|
|
|
|
|
|
- 接收客户端音频数据
|
|
|
|
|
|
- 发送 Agent 响应文本
|
|
|
|
|
|
- 实时语音识别(ASR)
|
|
|
|
|
|
- 实时语音合成(TTS)
|
|
|
|
|
|
|
|
|
|
|
|
**认证要求**:
|
|
|
|
|
|
- 必须在查询参数中提供有效的 `access_token`
|
|
|
|
|
|
- 只能连接属于当前用户的对话
|
|
|
|
|
|
- 如果对话不存在,将自动创建并关联到当前用户
|
|
|
|
|
|
|
|
|
|
|
|
**消息格式**:
|
|
|
|
|
|
|
|
|
|
|
|
客户端 → 服务端:
|
|
|
|
|
|
```json
|
|
|
|
|
|
{
|
|
|
|
|
|
"type": "audio",
|
|
|
|
|
|
"data": "base64_encoded_audio_data"
|
|
|
|
|
|
}
|
|
|
|
|
|
```
|
|
|
|
|
|
|
|
|
|
|
|
服务端 → 客户端:
|
|
|
|
|
|
```json
|
|
|
|
|
|
{
|
|
|
|
|
|
"type": "transcript",
|
|
|
|
|
|
"text": "识别出的文本",
|
|
|
|
|
|
"agent_response": "Agent 的回复"
|
|
|
|
|
|
}
|
|
|
|
|
|
```
|
|
|
|
|
|
|
|
|
|
|
|
```json
|
|
|
|
|
|
{
|
|
|
|
|
|
"type": "audio",
|
|
|
|
|
|
"data": "base64_encoded_tts_audio"
|
|
|
|
|
|
}
|
|
|
|
|
|
```
|
|
|
|
|
|
|
|
|
|
|
|
## 数据库模型
|
|
|
|
|
|
|
|
|
|
|
|
### User(用户)
|
|
|
|
|
|
- `id`: 用户 ID
|
|
|
|
|
|
- `phone`: 手机号(唯一,必填)
|
|
|
|
|
|
- `password_hash`: 密码哈希
|
|
|
|
|
|
- `email`: 邮箱(可选)
|
|
|
|
|
|
- `openid`: 微信 OpenID(可选)
|
|
|
|
|
|
- `nickname`: 昵称
|
|
|
|
|
|
- `avatar_url`: 头像 URL
|
|
|
|
|
|
- `subscription_type`: 订阅类型(free/premium)
|
|
|
|
|
|
- `created_at`: 创建时间
|
|
|
|
|
|
|
|
|
|
|
|
### RefreshToken(刷新令牌)
|
|
|
|
|
|
- `id`: 令牌 ID
|
|
|
|
|
|
- `user_id`: 用户 ID(外键)
|
|
|
|
|
|
- `token`: 刷新令牌(唯一)
|
|
|
|
|
|
- `expires_at`: 过期时间(30天后)
|
|
|
|
|
|
- `created_at`: 创建时间
|
|
|
|
|
|
- `is_revoked`: 是否已撤销
|
|
|
|
|
|
|
|
|
|
|
|
### Conversation(对话)
|
|
|
|
|
|
- `id`: 对话 ID
|
|
|
|
|
|
- `user_id`: 用户 ID
|
|
|
|
|
|
- `started_at`: 开始时间
|
|
|
|
|
|
- `ended_at`: 结束时间
|
|
|
|
|
|
- `duration_seconds`: 持续时间(秒)
|
|
|
|
|
|
- `summary`: 对话摘要
|
|
|
|
|
|
- `status`: 状态(active/ended/processing)
|
|
|
|
|
|
- `current_topic`: 当前话题
|
|
|
|
|
|
- `conversation_stage`: 对话阶段(childhood/education/career/family/beliefs/summary)
|
|
|
|
|
|
|
|
|
|
|
|
### Segment(对话段落)
|
|
|
|
|
|
- `id`: 段落 ID
|
|
|
|
|
|
- `conversation_id`: 对话 ID
|
|
|
|
|
|
- `audio_url`: 音频 URL
|
2026-03-26 12:13:36 +08:00
|
|
|
|
- `user_input_text`: 用户输入正文(语音 ASR 或文字输入;历史列名 `transcript_text`)
|
2026-01-18 15:58:05 +08:00
|
|
|
|
- `created_at`: 创建时间
|
|
|
|
|
|
- `processed`: 是否已处理
|
|
|
|
|
|
- `topic_category`: 话题分类
|
|
|
|
|
|
- `agent_response`: Agent 响应
|
|
|
|
|
|
|
|
|
|
|
|
### Chapter(章节)
|
|
|
|
|
|
- `id`: 章节 ID
|
|
|
|
|
|
- `user_id`: 用户 ID
|
|
|
|
|
|
- `title`: 标题
|
|
|
|
|
|
- `content`: 内容
|
|
|
|
|
|
- `order_index`: 排序索引
|
|
|
|
|
|
- `status`: 状态(draft/completed)
|
|
|
|
|
|
- `images`: 图片 URL 列表(JSON)
|
|
|
|
|
|
- `updated_at`: 更新时间
|
|
|
|
|
|
- `category`: 章节分类
|
|
|
|
|
|
|
|
|
|
|
|
### Book(回忆录)
|
|
|
|
|
|
- `id`: 回忆录 ID
|
|
|
|
|
|
- `user_id`: 用户 ID
|
|
|
|
|
|
- `title`: 标题
|
|
|
|
|
|
- `total_pages`: 总页数
|
|
|
|
|
|
- `total_words`: 总字数
|
|
|
|
|
|
- `cover_image_url`: 封面图片 URL
|
|
|
|
|
|
- `updated_at`: 更新时间
|
|
|
|
|
|
|
|
|
|
|
|
## 核心功能
|
|
|
|
|
|
|
|
|
|
|
|
### 1. 对话引导 Agent
|
|
|
|
|
|
|
|
|
|
|
|
使用 LangChain 构建的对话 Agent,根据传记结构引导用户回忆:
|
|
|
|
|
|
- 童年时光
|
|
|
|
|
|
- 教育经历
|
|
|
|
|
|
- 职业生涯
|
|
|
|
|
|
- 家庭生活
|
|
|
|
|
|
- 人生信念
|
|
|
|
|
|
- 总结回顾
|
|
|
|
|
|
|
|
|
|
|
|
### 2. 记忆整理 Agent
|
|
|
|
|
|
|
|
|
|
|
|
将口语对话内容整理为结构化的书面章节:
|
|
|
|
|
|
- 口语转书面语
|
|
|
|
|
|
- 内容结构化
|
|
|
|
|
|
- 章节分类
|
|
|
|
|
|
- 自动生成标题
|
|
|
|
|
|
|
|
|
|
|
|
### 3. 语音服务
|
|
|
|
|
|
|
|
|
|
|
|
- **ASR (语音识别)**: 使用 OpenAI Whisper API 将音频转为文本
|
|
|
|
|
|
- **TTS (语音合成)**: 使用 OpenAI TTS API 将文本转为语音
|
|
|
|
|
|
|
|
|
|
|
|
### 4. PDF 生成
|
|
|
|
|
|
|
|
|
|
|
|
使用 ReportLab 和 WeasyPrint 生成精美的回忆录 PDF 文档。
|
|
|
|
|
|
|
|
|
|
|
|
## 开发指南
|
|
|
|
|
|
|
|
|
|
|
|
### 添加新的 API 路由
|
|
|
|
|
|
|
|
|
|
|
|
1. 在 `routers/` 目录创建新的路由文件
|
|
|
|
|
|
2. 定义路由函数
|
|
|
|
|
|
3. 在 `main.py` 中注册路由:
|
|
|
|
|
|
|
|
|
|
|
|
```python
|
|
|
|
|
|
from routers import your_router
|
|
|
|
|
|
app.include_router(your_router.router)
|
|
|
|
|
|
```
|
|
|
|
|
|
|
|
|
|
|
|
### 添加新的数据库模型
|
|
|
|
|
|
|
2026-03-18 17:18:23 +08:00
|
|
|
|
1. 在对应 feature 的 `app/features/<feature_name>/models.py` 中定义模型类
|
|
|
|
|
|
2. 继承 `Base`(从 `app.core.db` 导入)
|
|
|
|
|
|
3. 在 `app/main.py` 中 import 该 models 模块以注册到 Base.metadata
|
|
|
|
|
|
4. 运行 Alembic 迁移
|
2026-01-18 15:58:05 +08:00
|
|
|
|
|
|
|
|
|
|
### 添加新的服务
|
|
|
|
|
|
|
2026-03-18 17:18:23 +08:00
|
|
|
|
1. 在 `app/features/<feature_name>/service.py` 中实现业务逻辑
|
|
|
|
|
|
2. 通过 `deps.py` 提供依赖注入
|
|
|
|
|
|
3. 在对应 feature 的 router 中通过 `Depends(get_xxx_service)` 使用
|
2026-01-18 15:58:05 +08:00
|
|
|
|
|
|
|
|
|
|
## 安全注意事项
|
|
|
|
|
|
|
|
|
|
|
|
1. **CORS 配置**: 当前允许所有来源,生产环境应限制为特定域名
|
|
|
|
|
|
2. **API Key 安全**: 确保 `.env` 文件不被提交到版本控制
|
|
|
|
|
|
3. **SECRET_KEY 安全**: 使用强随机字符串作为 JWT 签名密钥,生产环境必须更换
|
|
|
|
|
|
4. **密码安全**: 密码使用 bcrypt 哈希存储,不会以明文形式保存
|
|
|
|
|
|
5. **令牌安全**:
|
|
|
|
|
|
- 访问令牌短期有效(2小时),降低泄露风险
|
|
|
|
|
|
- 刷新令牌存储在数据库中,支持撤销
|
|
|
|
|
|
- 令牌过期后必须使用刷新令牌重新获取
|
2026-02-12 13:33:19 +08:00
|
|
|
|
6. **数据库备份**: 定期备份 PostgreSQL 数据库
|
2026-01-18 15:58:05 +08:00
|
|
|
|
7. **错误处理**: 所有 API 都包含适当的错误处理和权限验证
|
|
|
|
|
|
8. **日志记录**: 建议添加日志记录功能以便调试和监控
|
|
|
|
|
|
|
|
|
|
|
|
## 许可证
|
|
|
|
|
|
|
|
|
|
|
|
MIT License
|