feat(v0.1): 初始项目结构 + 架构设计文档 SPEC.md

main
bigemon 2026-05-31 10:35:29 +08:00
commit 72d47ffba0
2 changed files with 642 additions and 0 deletions

42
README.md Normal file
View File

@ -0,0 +1,42 @@
# 🗡️ Psycho-Games-Hub
心理咨询室互动终端 — 心理小游戏聚合系统
> **定位**:面向青少年/儿童心理辅导的互动终端子系统
> **核心理念**:数字人是入口,小游戏是「药」,只是吃起来像糖
## 项目状态
🚧 **架构设计阶段v0.1** — 详见 [docs/SPEC.md](docs/SPEC.md)
## 功能特性
- 🎭 **数字人入口** — Live2D/虚拟形象作为主交互界面
- 🃏 **游戏弹窗机制** — 半透明遮罩 + 轻交互小游戏
- 💬 **谈话式量表** — 心理量表对话化编排,非接触评估
- 🧠 **积极心理学解读** — 基于上下文动态编排鼓励文案
- 📊 **风险标签系统** — Agent 后台监测 + 策略分发队列
## 技术栈(原型阶段)
- **前端**Vue 3 + Vite + TypeScript简化可单文件 HTML
- **Agent**MiniMax / 本地小模型(待接入)
- **存储**LocalStorage原型阶段
## 文档
| 文档 | 内容 |
|------|------|
| [docs/SPEC.md](docs/SPEC.md) | 系统架构规范MVC 模块划分 + 交互流设计) |
| [docs/RESEARCH.md](docs/RESEARCH.md) | GitHub 心理小游戏调研报告 |
## 快速启动(原型)
```bash
# 原型阶段直接打开单文件即可
open src/views/AvatarView.html
```
## License
MIT

600
docs/SPEC.md Normal file
View File

@ -0,0 +1,600 @@
# 心理咨询室互动终端 — 心理小游戏聚合系统
> **项目代号**Psycho-Games-Hub
> **定位**:青少年/儿童心理辅导互动终端的核心子系统
> **阶段**:架构设计 + 原型阶段v0.1
---
## 一、产品定位
### 1.1 整体场景
```
┌─────────────────────────────────────────────┐
│ 心理咨询室互动终端 │
│ │
│ 🗡️ 数字人入口(语音 + 触摸) │
│ │ │ │
│ Agent 主对话 游戏弹窗 │
│ 策略召回 半透明遮罩 │
│ 风险评估 轻交互 │
│ │ │ │
│ 谈话式量表 ←─── Agent 动态编排 ───→ 激励解读│
└─────────────────────────────────────────────┘
```
- **载体**:一体机 / 触摸屏 kiosk
- **目标用户**:青少年 / 儿童(来访者)
- **核心理念**:数字人是入口,小游戏是「药」,只是吃起来像糖
- **交互方式**:语音对话 + 触摸Agent 主动驱动轻量干预
### 1.2 用户故事
**场景 A游戏触发**
> 来访者:「最近压力好大,考试考砸了。」
> Agent「你这个困扰看起来困扰你很久了。我知道个有效的缓解方式——我给你算个塔罗牌吧。」→ 弹出游戏弹窗 → 抽卡 → 积极方向解读 → 关闭弹窗
**场景 B量表编排**
> Agent 后台监测到近期对话出现「失眠」「焦虑」关键词 → StrategyDispatcher 入队 → Agent 在自然节点插入引导 → 用户同意 → 谈话式问答 → 生成摘要 → 更新风险标签
**场景 C直接入口**
> 用户双指下滑 → 解锁底部工具栏 → 展示所有游戏图标网格 → 主动点击进入
---
## 二、系统架构MVC
### 2.1 模块总览
```
┌──────────────────────────────────────────────────────┐
│ VIEW 层 │
│ AvatarView │ GameModal │ ChatPanel │ ResultCard │
└──────────────────────────────────────────────────────┘
│ 事件 / 回调
┌──────────────────────────────────────────────────────┐
│ CONTROLLER 层 │
│ AgentController │ GameController │ AssessmentCtrl │
│ InterpretationEngine │ StrategyDispatcher │
└──────────────────────────────────────────────────────┘
│ 读写
┌──────────────────────────────────────────────────────┐
│ MODEL 层 │
│ AgentBrain │ GameCatalog │ AssessmentFlows │
│ UserSession │ InterpretationPool │
└──────────────────────────────────────────────────────┘
```
---
## 三、Model 层
### 3.1 AgentBrain
**职责**:维护策略记忆 + 风险词召回
**数据结构**
```javascript
{
// 标注语料库(心理咨询师标注)
corpus: [
{ keyword: "失眠", riskLevel: 3, relatedScale: "SAS", strategy: "soft_inquiry" },
{ keyword: "压力大", riskLevel: 2, relatedGame: "tarot", strategy: "game_offer" },
// ...
],
// 策略路由表
strategies: {
"game_offer": { trigger: "anxiety_level > 2", gameType: "tarot" },
"soft_inquiry": { trigger: "riskLevel >= 3", prompt: "询问近期睡眠状况" },
// ...
},
// 召回方法(当前为规则版,待升级 RAG
recall(text) → matchedCorpus[]
}
```
---
### 3.2 GameCatalog
**职责**:游戏配置清单 + 触发条件注册
**数据结构**
```javascript
{
games: [
{
id: "tarot",
name: "塔罗牌占卜",
triggerKeywords: ["压力", "迷茫", "选择", "未来"],
completionKeywords: ["抽卡", "算一算"],
viewComponent: "TarotGame",
difficulty: "low",
estimatedTime: "2min",
icon: "🃏"
},
{
id: "rorschach",
name: "罗夏墨迹",
triggerKeywords: ["看到了什么", "感觉", "想象"],
viewComponent: "RorschachGame",
difficulty: "medium",
estimatedTime: "3min",
icon: "🎭"
},
{
id: "mbti",
name: "人格测试",
triggerKeywords: ["我是谁", "性格", "了解自己"],
viewComponent: "MBTIGame",
difficulty: "medium",
estimatedTime: "5min",
icon: "🔮"
},
{
id: "chimp_memory",
name: "记忆挑战",
triggerKeywords: ["试试", "挑战"],
viewComponent: "ChimpMemoryGame",
difficulty: "low",
estimatedTime: "1min",
icon: "🐵"
}
// 更多游戏...
],
// 查询方法
matchByKeywords(text) → games[]
getById(id) → game
}
```
---
### 3.3 AssessmentFlows
**职责**:量表的对话化编排
**数据结构**
```javascript
{
flows: [
{
id: "SAS_anxiety",
name: "焦虑自评",
condition: "riskKeywords includes ['焦虑', '失眠', '心慌']",
questionCount: 3, // 精简至 3 题,不做完整量表
questions: [
{
id: "q1",
text: "你最近有没有感到特别紧张或者担心的事情?",
type: "single_choice",
options: ["完全没有", "偶尔", "经常", "一直都在"],
scores: [1, 2, 3, 4]
},
// ...
],
scoringMethod: "sum",
resultRanges: {
low: { min: 0, max: 5, label: "状态良好", interpretation: "positive" },
medium: { min: 6, max: 8, label: "轻度波动", interpretation: "neutral" },
high: { min: 9, max: 12, label: "值得关注", interpretation: "caution" }
}
}
// 更多量表...
],
// 查询方法
matchByCondition(riskKeywords) → flows[]
getQuestions(flowId) → questions[]
}
```
---
### 3.4 UserSession
**职责**:维护当前来访者会话上下文
**数据结构**
```javascript
{
sessionId: "uuid-xxx",
startTime: "2026-05-31T10:00:00Z",
userProfile: {
age: 14, // 年龄(首访时采集)
gender: "M", // 性别
firstVisit: true
},
riskTags: [], // 动态风险标签,如 ["焦虑", "压力", "学业"]
riskScore: 0, // 综合风险评分0-100
gameHistory: [
{ gameId: "tarot", timestamp: "...", result: "positive_outlook" }
],
assessmentResults: [
{ flowId: "SAS_anxiety", score: 5, timestamp: "..." }
],
recentUtterances: [
{ role: "user", text: "最近压力好大", timestamp: "..." },
{ role: "agent", text: "...", timestamp: "..." }
]
}
```
---
### 3.5 InterpretationPool
**职责**:积极心理学话术库,按游戏类型 × 情境分组
**数据结构**
```javascript
{
pools: {
"tarot": {
"压力": [
"你抽到的这张牌显示,你正在经历一个重要的转变期。压力其实是身体在告诉你,它愿意为你付出更多,只是需要一点喘息的空间。",
"这张牌提醒你:不是所有事情都需要马上解决。有时候,『放下』也是一种前进的方式。",
],
"迷茫": [
"牌面显示你正处于一个探索期,迷茫不是坏事——它意味着你还在寻找答案,而答案正在来的路上。",
]
// ...
},
"rorschach": {
"学业压力": [
"你在这张墨迹中看到了很多变化的形状,这说明你的内心正在经历很多调整。你比自己想象的更有弹性。",
]
// ...
}
// 更多游戏...
},
// 查询方法
get(gameType, contextTags) → interpretations[]
}
```
---
## 四、View 层
### 4.1 AvatarView
**职责**:数字人主界面
- 全屏占位,作为系统主页背景
- 实现方式Live2D / 3D 虚拟人 / 纯 2D 立绘 + 表情差分(待选)
- 接收 AgentController 的表情指令(`setExpression("happy")`、`speak("你好呀")`
- 触摸响应区域:点击数字人触发语音输入
### 4.2 GameModal
**职责**:游戏弹窗遮罩
**展示规格**
- 层级:覆盖在 AvatarView 上方z-index 最高
- 样式:`backdrop-filter: blur(8px)` + 半透明黑底(`rgba(0,0,0,0.6)`
- 尺寸:宽度 90vw高度 80vh不超出屏幕居中
- 关闭行为:允许用户点击关闭按钮退出(游戏中途关闭记录为「中断」)
**子区域**
```
┌─────────────────────────┐
│ [游戏名称] [× 关闭] │ ← 顶栏
├─────────────────────────┤
│ │
│ 游戏内容区 │ ← 动态组件 slot
│ │
├─────────────────────────┤
│ [进度指示] │ ← 底栏(如有需要)
└─────────────────────────┘
```
### 4.3 ChatPanel
**职责**:对话气泡流
- 底部/侧边展开,可折叠
- 展示最近 N 条对话记录
- Agent 消息和来访者消息气泡区分样式
- 接入 AgentController 的实时消息流
### 4.4 AssessmentCard
**职责**:量表对话式问答
- 每题一屏,全屏卡片流
- 选项以卡片按钮形式展示(触摸友好)
- 支持进度条展示1/N
- 动画过渡切换
### 4.5 ResultCard
**职责**:结果展示
**内容**
- 游戏结果解读(来自 InterpretationEngine
- 雷达图/进度条(可选)
- 鼓励文案(来自 InterpretationPool
- 建议下一步行动
---
## 五、Controller 层
### 5.1 AgentController主控协调器
**职责**:系统中央调度
**核心流程**
```
1. 监听对话输入(用户 utterance
2. 追加到 UserSession.recentUtterances
3. 触发 AgentBrain.recall() → 策略匹配
4. 根据匹配结果:
a. 若匹配到 game_offer → 触发 GameController
b. 若匹配到 soft_inquiry → 直接生成对话回复
c. 若风险等级高 → 触发 StrategyDispatcher
5. 将回复追加到 ChatPanel
6. 若 AgentController 内部有 StrategyDispatcher 队列非空 → 插入引导语
```
### 5.2 GameController
**职责**:游戏生命周期管理
**状态机**
```
IDLE → LOADING → PLAYING → RESULT → CLOSING → IDLE
```
**核心方法**
```javascript
{
// 触发游戏
trigger(gameId) → 弹出 GameModal加载 viewComponent
// 收集游戏结果
collectResult(data) → 传递给 InterpretationEngine
// 关闭游戏
close(interrupt: boolean) → 写回 UserSession.gameHistory → 关闭 GameModal
}
```
### 5.3 AssessmentController
**职责**:量表执行器
**核心流程**
```
1. 接收 AgentController 的激活指令flowId
2. 从 AssessmentFlows 加载 questions
3. 按顺序展示 AssessmentCard每题一屏
4. 收集 answers + 计算 scores
5. 生成摘要 → 传递给 InterpretationEngine
6. 结果写回 UserSession.assessmentResults
7. 更新 UserSession.riskScore
```
### 5.4 InterpretationEngine
**职责**:解读编排引擎(最体现积极心理学设计的模块)
**核心流程**
```
1. 接收 GameController 或 AssessmentController 的结果数据
2. 查询 UserSession 获取当前上下文riskTags / recentUtterances
3. 从 InterpretationPool 按 gameType + contextTags 获取候选解读
4. 拼接上下文敏感内容(注入来访者提到过的关键词)
5. 选取最积极的解读变体interpretation = "positive" 优先)
6. 生成 ResultCard 内容
7. 决定是否在 ResultCard 中插入下一个游戏/量表建议
```
### 5.5 StrategyDispatcher
**职责**:策略分发队列
**数据结构**
```javascript
{
queue: [
{
id: "strategy_001",
type: "assessment",
scale: "SAS_anxiety",
priority: 2,
reason: "检测到焦虑风险词 3 次",
suggestedQuestions: ["失眠情况", "紧张频率"],
createdAt: "..."
},
{
id: "strategy_002",
type: "game",
gameId: "chimp_memory",
priority: 3,
reason: "缓解轻度压力的轻量游戏"
}
],
// 方法
enqueue(strategy),
dequeue() → strategy, // 优先级最高者出队
peek() → strategy, // 只查看不下队
isEmpty() → boolean
}
```
**入队触发条件**
- AgentBrain 后台监测到风险关键词累计 N 次
- 用户在对话中主动提到相关话题
- 游戏/量表完成后自动推荐下一个
---
## 六、关键交互流
### 流 1游戏触发核心
```
用户说"最近压力好大"
AgentController.utterance()
AgentBrain.recall("最近压力好大")
→ 匹配 corpus: { keyword: "压力大", strategy: "game_offer" }
AgentController 决策 → StrategyDispatcher.enqueue({ type: "game", gameId: "tarot" })
AgentController 在对话中插入引导语:
"你这个困扰,看起来困扰你很久了。我知道个有效的缓解方式——我给你算个塔罗牌吧。"
用户确认 / 自然延续
GameController.trigger("tarot")
→ 弹出 GameModal → TarotGame 组件加载
用户抽卡 → TarotGame 交互完成
GameController.collectResult({ card, userChoice })
InterpretationEngine.generate({ gameType: "tarot", result: {...}, context: UserSession })
→ 从 InterpretationPool 选取积极解读
→ 生成 ResultCard
展示 ResultCard解读文案 + 鼓励 + 建议)
GameController.close()
→ 写回 UserSession.gameHistory
AgentController 追加对话:"感觉怎么样?塔罗牌给你的启示有没有帮到你?"
```
### 流 2量表编排PSI 等)
```
AgentBrain 后台监测:
recentUtterances 检测到 "焦虑"/"失眠"/"心慌" 关键词累计 3 次
StrategyDispatcher.enqueue({
type: "assessment",
scale: "SAS_anxiety",
priority: 2,
reason: "检测到焦虑风险词 3 次",
suggestedQuestions: ["你最近睡眠状况如何?", "有没有经常感到紧张?"]
})
AgentController 感知队列非空
在对话自然节点插入:
"我注意到你说最近睡得不太好,我有个小工具能帮你整理一下现在的状态,愿意试试吗?"
用户同意
AssessmentController.activate("SAS_anxiety")
→ 从 AssessmentFlows 加载 3 道题目
逐题展示 AssessmentCard → 用户作答
收集评分 → 计算总分
InterpretationEngine.generate({ flowType: "assessment", score, context })
展示 ResultCard + 更新 UserSession.riskScore
AgentBrain 更新 riskTags加入 "焦虑"
影响后续 StrategyDispatcher 召回权重
```
### 流 3直接入口用户主动触发
```
数字人下方手势区域(双指下滑 / 长按)
解锁底部工具栏 ToolBar
展示游戏图标网格 GridView
用户点击图标 → GameController.trigger(gameId)
(与流 1 的后半段一致)
```
---
## 七、项目结构(原型阶段)
```
psycho-games-hub/
├── docs/
│ ├── SPEC.md # 本文档
│ ├── RESEARCH.md # GitHub 调研报告(稍后补充)
│ └── PROTOTYPE_NOTES.md # 原型实现笔记
├── src/
│ ├── models/
│ │ ├── AgentBrain.js
│ │ ├── GameCatalog.js
│ │ ├── AssessmentFlows.js
│ │ ├── UserSession.js
│ │ └── InterpretationPool.js
│ ├── views/
│ │ ├── AvatarView.html # 数字人主界面(单文件原型用)
│ │ ├── GameModal.vue # 游戏弹窗
│ │ ├── ChatPanel.vue
│ │ └── ResultCard.vue
│ ├── controllers/
│ │ ├── AgentController.js
│ │ ├── GameController.js
│ │ ├── AssessmentController.js
│ │ └── StrategyDispatcher.js
│ ├── components/ # 各游戏独立组件
│ │ ├── TarotGame.vue
│ │ ├── RorschachGame.vue
│ │ └── MBTIGame.vue
│ └── App.vue
└── README.md
```
---
## 八、待决策问题(悬置)
| # | 问题 | 选项 | 当前倾向 |
|---|------|------|---------|
| 1 | 数字人技术路线 | A: Live2D / B: 3D 虚拟人 / C: 2D 立绘+差分 | C最轻量 |
| 2 | 策略召回引擎 | A: 规则版(关键词匹配)/ B: RAG向量化召回 | A先行B后续 |
| 3 | 第一批游戏优先级 | 塔罗牌 / MBTI / 罗夏墨迹 | 塔罗牌优先 |
| 4 | 游戏关闭策略 | A: 可随时关闭 / B: 完成才关闭 | A |
| 5 | 遮罩样式 | A: blur + 黑底 / B: 纯黑底半透明 | A |
| 6 | Agent 接入方式 | 接入 MiniMax / 本地小模型 | 待确认 |
---
## 九、版本记录
| 版本 | 日期 | 变更 |
|------|------|------|
| v0.1 | 2026-05-31 | 初稿MVC 模块划分 + 交互流设计 |
---
*本文档为架构设计文档,随着原型开发推进会持续更新。*
*关键决策待在大头确认后锁定。*