规定数据类型

This commit is contained in:
2026-04-24 01:45:41 +08:00
parent d1943f564a
commit 35eff3faf6
86 changed files with 3809 additions and 0 deletions

429
ARCHITECTURE.md Normal file
View File

@@ -0,0 +1,429 @@
# 项目架构设计文档
## 📐 整体架构
本项目采用**前后端分离 + 共享层**的单体仓库(monorepo)架构,严格遵循 MVC 设计模式。
```
┌─────────────────────────────────────────────┐
│ SillyTavern Repalice │
├─────────────────────────────────────────────┤
│ │
│ ┌──────────┐ ┌──────────┐ │
│ │ Client │◄──►│ Shared │ │
│ │ (Vue3) │ │ (Types) │ │
│ └──────────┘ └──────────┘ │
│ ▲ ▲ │
│ │ HTTP/API │ Type Safety │
│ ▼ ▼ │
│ ┌──────────┐ ┌──────────┐ │
│ │ Server │◄──►│ Shared │ │
│ │(NestJS) │ │(Schemas) │ │
│ └──────────┘ └──────────┘ │
│ │ │
│ ▼ │
│ ┌──────────┐ │
│ │ Data │ │
│ │ (Local) │ │
│ └──────────┘ │
└─────────────────────────────────────────────┘
```
## 🎯 核心设计决策
### 1. 双数据格式策略
**问题**: 需要兼容 SillyTavern 的导入导出,同时支持自定义扩展功能
**解决方案**:
- **外部格式** (`ST*` 前缀): 严格遵循 SillyTavern 规范
- **内部格式** (无前缀): 继承并扩展,添加自定义字段
- **转换器**: 双向转换,保证数据完整性
**示例**:
```typescript
// SillyTavern 格式
interface STWorldInfoEntry {
constant?: boolean; // 永久激活标志
selective?: boolean; // RAG 标志
}
// 内部格式
interface WorldInfoEntry extends STWorldInfoEntry {
activationType: ActivationType; // 4种枚举
logicExpression?: LogicExpression;
ragConfig?: RAGConfig;
}
```
### 2. MVC 分层架构
#### Model (模型层)
```
server/src/
├── services/ # 业务逻辑
├── persistence/ # 数据访问
│ ├── interfaces/ # 仓储接口
│ └── implementations/ # 具体实现
└── dto/ # 数据传输对象
```
**职责**:
- Service: 业务规则、数据验证、事务管理
- Repository: CRUD 操作、数据持久化
- DTO: API 输入输出验证
#### View (视图层)
```
client/src/
├── components/ # UI 组件
│ ├── TopBar/
│ ├── LeftPanel/
│ ├── CenterPanel/
│ ├── RightPanel/
│ └── common/
├── layouts/ # 页面布局
└── stores/ # 状态管理
```
**职责**:
- Components: UI 渲染、用户交互
- Layouts: 页面结构、路由视图
- Stores: 客户端状态管理
#### Controller (控制层)
```
server/src/controllers/ # API 端点
client/src/router/ # 前端路由
```
**职责**:
- 接收请求、参数验证
- 调用 Service 处理业务
- 返回响应
### 3. 依赖注入 (DI)
**后端 DI** (NestJS):
```typescript
@Injectable()
export class CharacterService {
constructor(
@Inject(CHARACTER_REPOSITORY)
private repo: CharacterRepository,
private llmService: LLMService,
) {}
}
```
**优势**:
- 松耦合:模块间通过接口通信
- 可测试:轻松 mock 依赖
- 可替换:不同实现无缝切换
### 4. 工具层 (Tools Layer)
独立于 MVC 的工具层,提供通用能力:
```
server/src/tools/
├── context-chunker.ts # 上下文分块
├── prompt-assembler.ts # 提示词组装
└── token-counter.ts # Token 计数
```
**特点**:
- 无状态纯函数
- 不依赖 DI 容器
- 可在任何层调用
## 🗂️ 目录结构设计原则
### 后端 (NestJS)
```
server/src/
├── modules/ # 按业务领域划分
│ ├── chat/ # 聊天管理
│ ├── character/ # 角色卡管理
│ ├── llm/ # LLM 集成
│ ├── import-export/# 导入导出
│ └── workflow/ # 工作流引擎
├── persistence/ # 持久化抽象
│ ├── interfaces/ # 仓储接口
│ ├── implementations/ # 实现
│ └── file-system/ # 文件系统实现
├── core/ # 基础设施
│ ├── config/ # 配置管理
│ ├── filters/ # 异常过滤
│ ├── interceptors/ # 拦截器
│ └── guards/ # 守卫
├── controllers/ # 路由层 (横向切割)
├── services/ # 业务层 (横向切割)
└── tools/ # 工具层 (横向切割)
```
**设计原则**:
1. **垂直切片**: 每个 module 自包含 controller + service
2. **水平分层**: persistence/core 跨模块复用
3. **依赖方向**: controllers → services → persistence
### 前端 (Vue3)
```
client/src/
├── components/ # 按布局区域划分
│ ├── TopBar/ # 顶部栏
│ ├── LeftPanel/ # 左侧面板
│ ├── CenterPanel/ # 中央面板
│ ├── RightPanel/ # 右侧面板
│ └── common/ # 通用组件
├── layouts/ # 布局模板
├── stores/ # 全局状态
├── router/ # 路由配置
├── composables/ # 组合式函数
└── api/ # API 客户端
```
**设计原则**:
1. **布局驱动**: 组件按 UI 区域组织
2. **关注点分离**: 状态、路由、API 独立管理
3. **组合优于继承**: 使用 composables 复用逻辑
### 共享层 (Shared)
```
shared/
├── types/ # TypeScript 类型
│ ├── sillytavern.types.ts # ST 兼容格式
│ ├── internal.types.ts # 内部扩展格式
│ └── converters.ts # 转换器
└── schemas/ # Zod 运行时验证
├── sillytavern.schemas.ts
└── internal.schemas.ts
```
**设计原则**:
1. **单一真相源**: 前后端共用类型定义
2. **编译时 + 运行时**: TypeScript + Zod 双重验证
3. **向后兼容**: 转换器保证旧数据可用
## 🔄 数据流
### 典型请求流程
```
User Action (Frontend)
Vue Component
Pinia Store
API Client (axios)
HTTP Request
NestJS Controller
Service (Business Logic)
Repository (Data Access)
File System
Response (JSON)
Update UI
```
### 数据转换流程
```
SillyTavern Import File
Zod Schema Validation (ST Schema)
Parse to ST Types
Converter (convertSTToInternal)
Internal Types
Save to File System
```
## 🧪 测试策略
### 单元测试
- **目标**: Services, Tools, Utils
- **工具**: Jest
- **Mock**: 外部依赖 (Repository, LLM API)
### 集成测试
- **目标**: Controller + Service 协作
- **工具**: Supertest
- **范围**: 单个模块的完整流程
### E2E 测试
- **目标**: 关键用户流程
- **工具**: Playwright / Cypress
- **场景**: 创建角色、发送消息、导入导出
## 🚀 部署架构
### 开发环境
```
Client (Vite Dev Server) :5173
↓ Proxy /api
Server (NestJS) :3000
Local File System ./data
```
### 生产环境 (Docker)
```
Client (Nginx) :80
↓ Proxy /api
Server (Node.js) :3000
Volume Mount /app/data
```
## 📊 关键技术选型理由
| 技术 | 选型理由 |
|------|---------|
| **NestJS** | 内置 DI、模块化、TypeScript 优先、企业级 |
| **Vue 3** | 组合式 API、响应式系统、学习曲线平缓 |
| **Vite** | 极速开发体验、原生 ESM、热更新快 |
| **Zod** | TypeScript 优先、运行时验证、 schema 推导 |
| **Vercel AI SDK** | 统一 LLM 接口、流式支持、工具调用 |
| **Pinia** | Vue 3 官方推荐、TypeScript 友好、轻量 |
| **文件系统** | 零依赖、易备份、用户可控、无需数据库 |
## 🎨 设计模式应用
### 1. Repository Pattern
```typescript
interface CharacterRepository {
findById(id: string): Promise<CharacterCard>;
save(character: CharacterCard): Promise<void>;
delete(id: string): Promise<void>;
}
class FileSystemCharacterRepository implements CharacterRepository {
// 实现细节隐藏
}
```
### 2. Factory Pattern
```typescript
class LLMProviderFactory {
static create(provider: ProviderType): LLMProvider {
switch (provider) {
case 'openai': return new OpenAIProvider();
case 'anthropic': return new AnthropicProvider();
}
}
}
```
### 3. Strategy Pattern
```typescript
interface ActivationStrategy {
shouldActivate(entry: WorldInfoEntry, context: string): boolean;
}
class KeywordActivationStrategy implements ActivationStrategy {
// 关键词匹配逻辑
}
class RAGActivationStrategy implements ActivationStrategy {
// 向量检索逻辑
}
```
### 4. Adapter Pattern
```typescript
// 适配器SillyTavern 格式 → 内部格式
class SillyTavernAdapter {
static toInternal(stCard: STCharacterCard): CharacterCard {
return convertSTCharacterCardToInternal(stCard);
}
static toExternal(card: CharacterCard): STCharacterCard {
return convertCharacterCardToST(card);
}
}
```
## 🔐 安全性考虑
1. **输入验证**: Zod schemas 在边界验证所有输入
2. **文件上传**: 限制类型、大小,扫描恶意内容
3. **API 密钥**: 环境变量管理,不提交到版本控制
4. **CORS**: 严格配置允许的来源
5. **路径遍历**: 验证文件路径,防止 `../` 攻击
## 📈 性能优化
1. **懒加载**: 前端路由和组件按需加载
2. **缓存**: LLM 响应缓存、角色卡元数据缓存
3. **分页**: 聊天记录、角色列表分页加载
4. **流式响应**: SSE 传输 LLM 生成内容
5. **索引**: 为搜索字段建立内存索引
## 🔄 扩展性设计
### 新增 LLM Provider
1. 实现 `LLMProvider` 接口
2. 注册到 `LLMProviderFactory`
3. 更新配置 schema
### 新增持久化方式
1. 实现 Repository 接口
2. 创建新模块 (如 `persistence/sqlite/`)
3. 通过 DI 切换实现
### 新增激活方式
1. 扩展 `ActivationType` 枚举
2. 实现新的 `ActivationStrategy`
3. 更新世界书 UI
## 📝 编码规范
### TypeScript
- 严格模式: `strict: true`
- 禁止 `any`,使用 `unknown` 代替
- 接口命名不加 `I` 前缀
- 枚举使用 PascalCase
### Vue 3
- 优先使用 `<script setup>`
- Props 用 TypeScript 定义
- 组合式逻辑提取为 composables
### NestJS
- 每个模块一个文件夹
- Controller 只处理 HTTP 层
- Service 不包含 HTTP 相关代码
- 使用 DTO 验证输入
## 🎯 下一步计划
1. **实现基础 CRUD**: 角色卡、聊天、世界书
2. **集成 Vercel AI SDK**: 流式聊天
3. **构建 UI 组件**: 聊天界面、角色编辑器
4. **实现转换器**: 完整的导入导出功能
5. **添加测试**: 覆盖核心业务逻辑
6. **编写文档**: API 文档、用户指南
---
**文档版本**: 1.0
**最后更新**: 2026-04-24