Files
st-react/docs/Clannad_v3.1_analysis.md
2026-03-13 21:51:42 +08:00

358 lines
9.8 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

# Clannad_v3.1.png 案例分析与落地要点
## 目标角色卡概览
- **图像**@docs/Clannad_v3.1.png图片来源、版权信息见下方字段
- **风格**Clannad 系列日系校园少女题材,具有较强的情感表达与背景设定需求
- **已知需求**:在云酒馆系统中以“前端卡”方式呈现,并能注入背景信息、变量、互动 UI
---
## 10.1 数据字段与数据模型需求
| 字段名 | 说明 | 备注 |
|--------|------|------|
| portrait_url | 图片主地址 | 建议使用 CDN 托管,支持 webp/AVIF 高效格式 |
| portrait_alt | 无障碍文本描述 | 供屏幕阅读器使用,描述角色外观特征 |
| thumbnail_url | 缩略图地址 | 列表页展示使用,建议 200x200 以内 |
| portrait_caption | 图片简短说明 | 显示在图片下方的简短描述 |
| image_source | 版权信息/出处 | 记录图片来源、授权信息 |
| worldbook_id | 关联的 Worldbook | 用于注入背景设定 |
| worldbook_entries | 世界书条目集合 | 用于背景信息注入 |
| name | 角色名称 | 现有字段 |
| description | 角色描述 | 现有字段 |
| personality | 性格设定 | 现有字段 |
| scenario | 场景设定 | 现有字段 |
| first_mes | 开场白 | 现有字段 |
| mes_example | 对话示例 | 现有字段 |
| system_prompt | 系统提示词 | 现有字段 |
| extensions | 扩展数据 | MVU 相关字段 |
| variables | 变量定义 | MVU 相关字段 |
---
## 10.2 后端改动要点
### 10.2.1 数据模型扩展
`model/app/ai_character.go` 中新增以下字段:
```go
type AICharacter struct {
// ... 现有字段 ...
// 图片相关字段
PortraitURL string `json:"portraitUrl" gorm:"type:varchar(500)"`
PortraitAlt string `json:"portraitAlt" gorm:"type:varchar(200)"`
ThumbnailURL string `json:"thumbnailUrl" gorm:"type:varchar(500)"`
PortraitCaption string `json:"portraitCaption" gorm:"type:varchar(200)"`
ImageSource string `json:"imageSource" gorm:"type:varchar(500)"` // 版权信息
// Worldbook 关联
WorldbookID *uint `json:"worldbookId"`
}
```
### 10.2.2 API 接口
- **上传图片**`POST /api/v1/app/character/:id/portrait`
- 鉴权:需要用户登录
- 校验:文件大小(建议最大 5MB、格式支持 jpg/png/webp/gif
- 返回portrait_url、thumbnail_url
- **获取角色图片信息**`GET /api/v1/app/character/:id`
- 返回字段包含 portrait_url、portrait_alt、thumbnail_url、portrait_caption、image_source
### 10.2.3 Worldbook 关联增强
`conversation.go` 的 system prompt 构建流程中,增加对角色关联 Worldbook 的背景注入:
- 读取 `character.WorldbookID`
- 通过 WorldbookEngine 查询对应的启用条目
- 将背景信息注入到 system_prompt 中(需控制 token budget
### 10.2.4 数据迁移
为现有角色卡补充默认字段值:
```sql
ALTER TABLE ai_characters
ADD COLUMN IF NOT EXISTS portrait_url VARCHAR(500),
ADD COLUMN IF NOT EXISTS portrait_alt VARCHAR(200),
ADD COLUMN IF NOT EXISTS thumbnail_url VARCHAR(500),
ADD COLUMN IF NOT EXISTS portrait_caption VARCHAR(200),
ADD COLUMN IF NOT EXISTS image_source VARCHAR(500),
ADD COLUMN IF NOT EXISTS worldbook_id UINT REFERENCES worldbooks(id);
```
---
## 10.3 前端实现要点
### 10.3.1 角色卡片组件
`web-app/src/components/` 中新增或扩展角色卡片组件:
```tsx
interface CharacterCardProps {
portraitUrl?: string;
portraitAlt?: string;
thumbnailUrl?: string;
portraitCaption?: string;
// ... 其他字段
}
const CharacterPortrait: React.FC<CharacterCardProps> = ({
portraitUrl,
portraitAlt,
thumbnailUrl,
portraitCaption
}) => {
if (!portraitUrl) return null;
return (
<div className="character-portrait">
<img
src={portraitUrl}
alt={portraitAlt || '角色图像'}
loading="lazy"
className="portrait-image"
/>
{portraitCaption && (
<p className="portrait-caption">{portraitCaption}</p>
)}
</div>
);
};
```
### 10.3.2 样式隔离
使用 CSS Modules 或在组件级别定义样式:
```css
/* CharacterPortrait.module.css */
.character-portrait {
display: flex;
flex-direction: column;
align-items: center;
}
.portrait-image {
max-width: 300px;
border-radius: 8px;
}
.portrait-caption {
font-size: 14px;
color: #666;
margin-top: 8px;
}
```
### 10.3.3 沙箱渲染
对于需要执行脚本的前端卡,使用 iframe 沙箱:
```tsx
const FrontendCardSandbox: React.FC<{ htmlContent: string }> = ({ htmlContent }) => {
return (
<iframe
srcDoc={htmlContent}
sandbox="allow-scripts"
title="前端卡内容"
className="frontend-card-iframe"
/>
);
};
```
### 10.3.4 postMessage 通信
定义消息类型:
```ts
// types/frontend-card.ts
interface FrontendCardMessage {
type: 'GET_VARIABLE' | 'SET_VARIABLE' | 'SEND_MESSAGE' | 'TRIGGER_ACTION';
payload: Record<string, any>;
}
interface FrontendCardResponse {
type: 'VARIABLE_VALUE' | 'ACTION_RESULT' | 'ERROR';
payload: Record<string, any>;
}
```
---
## 10.4 Worldbook 与背景注入
### 10.4.1 背景信息转 Worldbook 条目
将 Clannad 角色的背景故事、人物关系、剧情要点等转换为 Worldbook 条目:
```json
{
"keys": ["冈崎汐", "汐", "女儿"],
"content": "冈崎汐主人公冈崎朋也的女儿。5岁时因事故去世后来以幽灵的形式再次出现在父亲面前...",
"enabled": true,
"constant": true,
"position": 1,
"order": 1
}
```
### 10.4.2 Token Budget 控制
`buildContextManagedSystemPrompt` 中,对 Worldbook 注入的内容进行 token 预算控制:
- **优先级**Worldbook 触发条目 > CharacterBook 内嵌条目 > MesExample
- **预算分配**system_prompt 总预算的 20-30% 用于 Worldbook 背景注入
- **截断策略**:超出预算时,从最低优先级条目开始丢弃
---
## 10.5 安全性与合规
### 10.5.1 图片安全
- **来源限制**:只允许从受信任的 CDN 或本地上传
- **内容审查**:上传图片需经过内容审核(可接入第三方审核服务)
- **元数据清理**:清理图片 EXIF 信息,防止泄露拍摄设备、地点等隐私
### 10.5.2 脚本安全
- **沙箱隔离**:前端卡内的 JavaScript 必须在 iframe 沙箱中运行
- **API 白名单**:只暴露受限的 API 接口,映射到后端受控服务
- **CSP 策略**
```
Content-Security-Policy:
default-src 'self';
script-src 'self' 'unsafe-inline' 'unsafe-eval' blob:;
style-src 'self' 'unsafe-inline';
img-src 'self' https://cdn.example.com data:;
connect-src 'self' https://api.example.com;
```
### 10.5.3 审核流程
- **新卡审核**:用户上传新角色卡后,需经过管理员审核
- **定期检查**:对已上线卡片进行定期安全扫描
- **举报机制**:提供用户举报入口
---
## 10.6 迁移策略
### 10.6.1 MVP 阶段(第一阶段)
- 只引入 portrait_url、portrait_alt、thumbnail_url 字段
- 前端仅展示图片,不改变现有对话逻辑
- 不支持前端卡脚本执行
### 10.6.2 进阶阶段(第二阶段)
- 接入 Worldbook 背景注入
- 支持 portrait_caption 显示
- 引入基础的 iframe 沙箱渲染
### 10.6.3 完整阶段(第三阶段)
- 支持完整的前端卡脚本执行
- 实现 postMessage 通信
- 支持 RPG、VN 等复杂交互系统
### 10.6.4 回滚策略
- 每个阶段保留回滚开关
- 遇到兼容性问题时,可一键回退到上一阶段
- 数据库字段支持版本标记
---
## 10.7 验证与测试
### 10.7.1 功能测试
| 测试用例 | 预期结果 |
|---------|---------|
| 上传角色图片 | 图片正确保存,返回正确的 portrait_url |
| 图片加载失败 | 显示默认占位图alt 文本正确 |
| 无图片角色卡 | 正常显示,不崩溃 |
| Worldbook 注入 | 背景信息正确注入到对话上下文 |
| 懒加载图片 | 首屏不加载,滚动后加载 |
### 10.7.2 安全性测试
| 测试用例 | 预期结果 |
|---------|---------|
| XSS 注入(图片描述) | 被转义,不执行 |
| 恶意脚本(前卡内) | 在沙箱中被阻止,无法访问父窗口 |
| 跨域请求 | 被 CSP 拦截 |
### 10.7.3 性能测试
| 指标 | 目标 |
|-----|------|
| 图片首次加载 | < 1s5G 网络 |
| 懒加载触发 | 视口进入后 200ms |
| 内存占用 | 前端卡渲染时 < 50MB 额外 |
---
## 10.8 版权信息与来源
### 10.8.1 必填字段
- **image_source**图片来源官方美术集」「同人创作」)
- **license_type**许可证类型MIT」「CC BY-SA 4.0」「原创」)
- **original_artist**原作者名称若为同人创作
---
## 10.9 附录/接口示例
### 10.9.1 角色图片上传 API
```bash
# 请求
POST /api/v1/app/character/1/portrait
Authorization: Bearer <token>
Content-Type: multipart/form-data
# 响应
{
"portraitUrl": "https://cdn.example.com/characters/1/portrait.webp",
"thumbnailUrl": "https://cdn.example.com/characters/1/thumb.webp",
"portraitAlt": "粉色头发的少女,穿着校服"
}
```
### 10.9.2 角色详情 API 扩展
```bash
# GET /api/v1/app/character/1
{
"id": 1,
"name": "冈崎汐",
"portraitUrl": "https://cdn.example.com/characters/1/portrait.webp",
"portraitAlt": "粉色头发的少女,穿着校服",
"thumbnailUrl": "https://cdn.example.com/characters/1/thumb.webp",
"portraitCaption": "Clannad 主角冈崎朋也的女儿",
"imageSource": "官方美术集",
"worldbookId": 5,
// ... 其他字段
}
```
---
## 结论
通过独立分析文档分离便于版本管理与跨团队协作请在实现过程中严格遵循安全沙箱与版权规范确保云酒馆的扩展能力可控且可维护
本落地要点覆盖了从数据模型后端 API前端渲染Worldbook 集成安全合规到迁移测试的完整流程建议按 MVP 进阶 完整三阶段逐步落地