新增文档说明

This commit is contained in:
吕新雨
2026-01-29 23:31:12 +08:00
parent 0dd84b1873
commit d08deef478
22 changed files with 2079 additions and 2 deletions

View File

@@ -0,0 +1,4 @@
请开始完成编码
客户端请按照标准的RN架构目录写代码
后端请按照标准的python FastAPI 架构目录写代码
现在多语言仅支持 EN / TC

View File

@@ -28,3 +28,4 @@ modules/ 可嵌套 modules/,每层都独立规范。
输出时根据这个结构生成内容时,请保持文件职责清晰。
简短记录项目的该层每个spec的内容 每次编码完成后更新overview.md
可以通过nvm 切换node版本

15
.gitignore vendored
View File

@@ -18,8 +18,16 @@ web-build/
.metro-health-check*
expo-env.d.ts
# 原生构建产物prebuild / pod / build
client/ios/
# 原生构建产物
# - iOS为了支持 Widget 开发,需要提交 ios 工程与扩展源码;但忽略 Pods/build/用户配置等大体积或机器相关目录
client/ios/build/
client/ios/Pods/
client/ios/DerivedData/
client/ios/xcuserdata/
client/ios/**/xcuserdata/
client/ios/.xcode.env.local
# - Android当前阶段仅做客户端 iOS 侧能力android 仍保持忽略
client/android/
# iOS/Android 证书与密钥
@@ -33,3 +41,6 @@ client/android/
# 环境变量(本地)
.env.local
.env*.local
# 防止把 client 内部的独立 git 备份目录提交进来
client/.git.backup/

169
spec_kit/Card UI/plan.md Normal file
View File

@@ -0,0 +1,169 @@
# Card UI技术计划
## 1. 计划目标
在卡片页(`/(app)/home`)完成 UI 与交互升级:
- 右上角两个圆形图标按钮:
- 主题切换(`theme.svg`)→ 打开主题弹窗
- 个人主页(`my.svg`)→ 打开个人主页弹窗
- 两个弹窗统一视觉规范:**弹窗内容区背景色 `#FAF3EC`**、圆角、遮罩、关闭交互一致
- 卡片页底部「讨厌/喜欢」从文字按钮改为图标按钮(`hate.svg``like.svg`),点击有动效
## 2. 默认技术决策
- **路由**:沿用 `expo-router`(不新增 modal route弹窗优先用页面内 `Modal` 承载,降低路由复杂度)
- **动效**:优先使用已存在的 `react-native-reanimated`(按压缩放/回弹等)
- **SVG 渲染**:使用 `react-native-svg` + 新增 `react-native-svg-transformer`,让本地 `.svg` 可直接 `import` 为组件
- **持久化**:沿用 `AsyncStorage`(在 `src/storage/appStorage.ts` 统一封装 key
## 3. 资源与命名约定
图标资源位置:`client/assets/images/home/`
- `theme.svg`:主题入口
- `my.svg`:个人主页入口
- `like.svg`:喜欢
- `hate.svg`:讨厌(逻辑层仍沿用 reaction=`dislike`,仅资源命名为 hate
## 4. UI 与交互实现设计
### 4.1 右上角双按钮(主题 / 我的)
落点:`client/app/(app)/_layout.tsx`
-`home``headerRight` 改为两个 icon 按钮容器(水平排列)
- 统一按钮样式:圆形底、浅色背景、`hitSlop>=10`
- 点击行为:
- 主题按钮:触发 Home 页打开「主题弹窗」
- 我的按钮:触发 Home 页打开「个人主页弹窗」
> 实现方式:`headerRight` 只负责“发出事件”,弹窗的实际 UI 放在 `home.tsx` 内(避免把复杂 UI 塞进导航 header
事件方案(两种可选,优先 A
- A使用一个轻量全局状态例如在 `home` 内通过 `useFocusEffect` + `router` 事件不太合适)
- 更推荐:把 header 做成 Home 页内部自绘顶部栏(`headerShown:false`),所有状态都留在页面内
- B继续用导航 header但通过 `React.Context` 或一个简易 store如 Zustand若项目未引入则先不加把“打开弹窗”动作传给页面
本计划默认采用 **AHome 页自绘顶部栏)**,因为实现最直接、样式可控、无跨层状态传递。
### 4.2 主题弹窗(背景色 #FAF3EC
落点建议:
- `client/components/home/ThemeModal.tsx`
- `client/components/ui/SheetModal.tsx`(复用:遮罩、圆角容器、上滑/淡入动效、关闭逻辑)
交互:
- 点击主题按钮 → 打开弹窗
- 选择「风景 / 颜色」→ 立即写入主题 mode + 关闭(或保持打开并高亮选中,按设计稿)
- 点击遮罩 / 关闭按钮 → 关闭
视觉:
- 弹窗内容区背景:`#FAF3EC`
- 容器圆角与内边距按设计稿(默认 24 圆角、1620 padding
### 4.3 个人主页弹窗(背景色 #FAF3EC
落点建议:
- `client/components/home/ProfileModal.tsx`
- 复用 `SheetModal`
内容与导航:
- 顶部:插画/头像 + 昵称(来自 `getUserProfile().name`,无则显示占位名)
- 快捷卡片:我的喜欢 / 小组件(按现有设计稿与已有页面映射)
- 通用列表:每日提醒 / 隐私政策 / 使用条款 / 语言
页面/能力映射(一期最小闭环):
- 我的喜欢 → 跳转到 `/(app)/favorites`
- 语言 → 跳转到现有语言设置页(若尚未落地,则在本次实现中补齐入口或先占位)
- 隐私政策 / 使用条款 → 复用 Splash Consent 的外链打开方式(或后续统一到一个 WebView 组件)
- 每日提醒 → 若现有页面未实现,先占位并在 tasks 阶段拆分
### 4.4 喜欢 / 讨厌按钮改为 icon + 动效
落点:`client/app/(app)/home.tsx`
- 将底部两个 `Pressable + Text` 按钮替换为 icon 按钮:
- 喜欢:`like.svg`
- 讨厌:`hate.svg`
- 点击动效(建议):
- `pressIn`scale 到 0.92
- `pressOut`:回弹到 1
- `onPress`:短促 “弹一下” 的强调动效(例如 scale 1 → 1.12 → 1随后再推进下一张卡片
> 动效仅作用于按钮本体即可先满足“点击有动效”,后续可扩展为卡片飞出/淡出等更强反馈。
## 5. 主题状态与持久化
落点:`client/src/storage/appStorage.ts`
新增 key`spec.md` 保持一致):
- `ui.theme.mode`: `'scenery' | 'color'`
新增封装方法(示例命名):
- `getThemeMode(): Promise<'scenery' | 'color'>`(默认 `scenery`
- `setThemeMode(mode: 'scenery' | 'color'): Promise<void>`
Home 页读取主题 mode并用于
- 页面背景(风景/颜色)
- 卡片背景与局部配色(按设计稿映射)
## 6. SVG 导入支持(工程配置)
由于项目当前未见 `metro.config.js`,计划新增 SVG transformer 支持:
1. 安装依赖:`react-native-svg-transformer`
2. 新增 `client/metro.config.js`,基于 `expo/metro-config` 配置:
-`svg` 从 assetExts 移到 sourceExts
- `babelTransformerPath` 指向 transformer
完成后可以直接:
- `import LikeIcon from '@/assets/images/home/like.svg'`
## 7. i18n 文案补齐(用于标题/无障碍)
建议新增 key至少 `zh-CN/en`,其余语言可后续补齐):
- `home.theme`(用于无障碍 label
- `home.profile`(用于无障碍 label
- `theme.title``theme.scenery``theme.color`
- `profile.title``profile.favorites``profile.widget``profile.dailyReminder``profile.privacy``profile.terms``profile.language`
> 原有 `home.like/home.dislike` 即使不再显示文字,也可保留用于 `accessibilityLabel` 或未来回退。
## 8. 实施步骤
1. 配置 SVG 导入(新增 transformer + `metro.config.js`
2. 新增通用弹窗组件 `SheetModal`(遮罩、圆角、背景色 `#FAF3EC`、关闭交互、基础动效)
3. 新增 `ThemeModal``ProfileModal`(复用 `SheetModal`
4.`appStorage.ts` 新增主题 mode 读写方法
5. 改造 `home.tsx`
- 自绘顶部栏(右上角两个圆形 icon 按钮)
- 接入主题 mode 影响背景
- 底部喜欢/讨厌替换为 icon + 动效
6. 补齐 i18n key
7. 自测:
- 主题切换后即时生效并可持久化
- 个人主页弹窗打开/关闭体验一致
- 喜欢/讨厌点击有动效且逻辑正常推进卡片
## 9. 验收标准
- 卡片页右上角两个 icon 按钮显示正确,点击热区合理
- 主题弹窗与个人主页弹窗:
- 背景色 `#FAF3EC`
- 遮罩/圆角/关闭交互一致
- 喜欢/讨厌按钮为 icon`like.svg` / `hate.svg`)且点击有动效
- 主题选择被持久化,重启 App 后仍保持上次主题

110
spec_kit/Card UI/spec.md Normal file
View File

@@ -0,0 +1,110 @@
# Card UI高层规范
## 1. 背景与目标
当前卡片页Home/情绪卡片滑动页)右上角需要提供两个入口:
- **切换主题**:在「风景」与「颜色」两种主题间切换
- **个人主页**:以弹窗形式打开个人主页(样式与主题弹窗一致的弹窗体系)
本需求聚焦 **UI 视觉统一****交互逻辑收敛**,让用户在卡片页可以快速切换主题、进入个人主页设置与通用入口。
### 目标
- **右上角双按钮**:两个圆形图标按钮常驻卡片页右上角
- **主题弹窗**:可选择「风景 / 颜色」两种主题,并即时生效
- **个人主页弹窗**:点击进入个人主页弹窗(与主题弹窗同一套弹窗/遮罩/圆角规范)
- **资源统一**:图标资源使用 `client/assets/images/home/``theme.svg``my.svg`
### 非目标(本阶段不做)
- 不引入复杂的主题系统(如多套配色、动态主题下载、远端配置等)
- 不做账号体系/登录注册(个人主页弹窗仅作为本地个人中心入口与设置集合)
- 不做完整的卡片滑动动效重构(仅限卡片页头部与相关弹窗/局部逻辑优化)
## 2. 范围与交付物
### 范围
- 卡片页Home头部 UI右上角两个圆形 icon 按钮
- 主题弹窗:展示两种主题选项(风景/颜色)并支持选择
- 个人主页弹窗:展示个人信息与快捷入口(以弹窗呈现)
- 主题状态:本地持久化 + 启动后读取 + 在卡片页即时反映
### 交付物
- 卡片页头部 UI 更新(两按钮替换/补齐)
- 主题弹窗与个人主页弹窗的 UI 与交互逻辑(共用弹窗规范)
- 主题选择的本地存储 key 约定与读写逻辑
- (可选)补充 i18n key按钮无文本但弹窗标题/选项文案需多语言)
## 3. 视觉与交互需求
### 3.1 右上角按钮(主题 / 我的)
- **位置**:卡片页右上角,两个按钮水平排列,间距 812按视觉微调
- **形状**:圆形按钮,背景为浅色圆底(与现有 UI 风格一致),点击区域需足够大(建议 `hitSlop >= 10`
- **图标**
- 主题:`client/assets/images/home/theme.svg`
- 我的:`client/assets/images/home/my.svg`
- **点击反馈**:按平台规范(透明度/水波纹)即可
### 3.2 主题弹窗
- **打开方式**:点击右上角「主题」按钮打开
- **样式**:与现有弹窗体系一致(遮罩 + 圆角容器),可做底部弹窗或中间弹窗,需与设计稿一致
- **内容**
- 标题:主题
- 选项:
- 风景(预览图/缩略图)
- 颜色(预览图/缩略图)
- 当前选中项需有明显高亮(描边/勾选/阴影等,按设计稿)
- **交互**
- 点击选项即切换主题并立即生效
- 点击遮罩或关闭按钮关闭弹窗
### 3.3 个人主页弹窗(我的)
- **打开方式**:点击右上角「我的」按钮打开
- **样式**:与主题弹窗同一套弹窗规范(遮罩、圆角、关闭按钮/手势)
- **内容建议(以现有设计为准)**
- 顶部区域:头像/插画 + 用户昵称(本地默认名或 onboarding 的 name
- 快捷卡片:我的喜欢、小组件(或其他产品定义入口)
- 通用列表:每日提醒、隐私政策、使用条款、语言
- **交互**
- 列表项点击进入对应页面/二级弹窗(实现阶段在 plan/tasks 中细化)
- 关闭方式同主题弹窗
## 4. 主题逻辑与状态管理
### 4.1 主题类型
- `scenery`:风景主题(以图片/风景背景为主)
- `color`:颜色主题(以纯色/渐变色块为主)
### 4.2 持久化 Key建议
- `ui.theme.mode`: `'scenery' | 'color'`
### 4.3 生效范围(建议)
- 最低要求:卡片页背景/卡片背景/主题弹窗预览在切换后 **立即更新**
- 可扩展:全局统一(如 Settings/我的页)在后续版本做全局 Theme Provider
## 5. 验收标准
- 卡片页右上角展示两个圆形图标按钮,点击热区合理
- 点击主题按钮:
- 打开主题弹窗,显示「风景/颜色」两项
- 切换后立即生效并持久化,重新进入 App 仍保持上次选择
- 点击我的按钮:
- 打开个人主页弹窗
- 弹窗样式(遮罩/圆角/关闭)与主题弹窗一致
- 图标资源从 `client/assets/images/home/` 加载,显示清晰无拉伸
## 6. 风险与注意事项
- **SVG 兼容**:需要确认当前项目 SVG 渲染方案(如 `react-native-svg` / `expo` 方案),避免不同平台显示差异
- **路由与弹窗体系**:若使用 `expo-router``Stack` modal需要统一交互遮罩、圆角、返回手势以匹配设计
- **多语言**:弹窗标题、列表项文案需走 i18n`zh-CN/en/es/pt/zh-TW`

168
spec_kit/Card UI/tasks.md Normal file
View File

@@ -0,0 +1,168 @@
# Card UI任务清单
> 说明:本清单根据 `plan.md` 拆解,要求“可执行、可验收、可标记”。
> 标记规则:执行完成后将对应项从 `- [ ]` 改为 `- [x]`,并把“状态”改为 **已完成**;进行中改为 **进行中**;阻塞写明原因与解除条件。
## 0. UI 参考(本次实现对齐)
- **参考截图**:你提供的卡片页 + 主题弹窗 + 我的弹窗
- **弹窗内容区背景色**`#FAF3EC`
- **右上角按钮资源**`client/assets/images/home/theme.svg``client/assets/images/home/my.svg`
- **底部反应按钮资源**`client/assets/images/home/like.svg``client/assets/images/home/hate.svg`
- **交互约束**
- 弹窗为**底部上拉Sheet**
- 关闭方式:**点 X 关闭**(不要求点遮罩关闭)
- 顶部按钮使用**系统导航栏**`headerRight`
- 主题切换最少影响:**页面背景**
- 个人主页弹窗中的列表项:本期允许 **仅做占位**
- 喜欢动效为**强反馈:心形填满**(按压回弹 + 填充变化)
## 1. 依赖与基础设施SVG 可 import
- [x] **安装 `react-native-svg-transformer` 并新增 `client/metro.config.js`**
- **状态**:已完成
- **原因**:让 `assets/images/home/*.svg` 支持 `import XxxIcon from '...svg'` 作为组件使用
- **命令**
```bash
cd client
pnpm add react-native-svg-transformer
```
- **实现点**
- 新增 `client/metro.config.js`,基于 `expo/metro-config` 配置 `svg` transformer
- **验收**
- 任一页面可成功渲染 `theme.svg`/`like.svg`(真机/模拟器均可)
- `pnpm start` 正常启动,无 Metro 报错
## 2. 本地存储:主题模式持久化
- [x] **在 `src/storage/appStorage.ts` 新增主题 mode key 与读写方法**
- **状态**:已完成
- **Key**`ui.theme.mode`
- **类型**`'scenery' | 'color'`(默认 `scenery`
- **新增 API建议**
- `getThemeMode(): Promise<'scenery' | 'color'>`
- `setThemeMode(mode: 'scenery' | 'color'): Promise<void>`
- **验收**
- 代码中不散落硬编码 key
- 切换主题后重启 App 仍保持上次选择
## 3. 通用组件底部上拉弹窗Sheet框架
- [x] **新增通用 `SheetModal` 组件(底部上拉 + 背景色 #FAF3EC + X 关闭)**
- **状态**:已完成
- **建议路径**`client/components/ui/SheetModal.tsx`
- **要求**
- 遮罩存在(可拦截背景交互),但本期**不要求点遮罩关闭**
- 内容区背景色固定为 `#FAF3EC`
- 顶部提供右上/左上 **X 按钮**关闭(以设计稿为准)
- 基础动效:上滑进入、下滑退出(或淡入淡出 + translateY
- **验收**
- 任意页面可打开/关闭该弹窗,不闪烁、不穿透点击
- iOS 安全区适配正常(底部不被 Home Indicator 遮挡)
## 4. 主题弹窗:风景 / 颜色
- [x] **实现 `ThemeModal`(复用 `SheetModal`**
- **状态**:已完成
- **建议路径**`client/components/home/ThemeModal.tsx`
- **内容**
- 标题:主题
- 选项:风景 / 颜色(含预览卡片)
- 选中态:明显高亮(描边/阴影/勾选均可)
- **交互**
- 点击选项:`setThemeMode(...)` 并立即生效(可关闭弹窗或保持打开,按设计稿)
- 点 X关闭
- **验收**
- 两种主题可切换
- 切换后 Home 页面背景立刻变化
## 5. 个人主页弹窗:占位入口
- [x] **实现 `ProfileModal`(复用 `SheetModal`**
- **状态**:已完成
- **建议路径**`client/components/home/ProfileModal.tsx`
- **内容(按设计最小闭环)**
- 顶部:插画/头像 + 昵称(来自 `getUserProfile().name`,无则占位)
- 快捷卡片:我的喜欢 / 小组件(小组件可占位)
- 通用列表:每日提醒 / 隐私政策 / 使用条款 / 语言(本期均允许占位)
- **交互**
- 点 X关闭
- 列表项点击:占位反馈(例如 `Alert` 或轻提示),不崩溃即可
- **验收**
- 弹窗 UI 与 ThemeModal 同一套视觉(背景色/圆角/间距一致)
- 点击各入口有明确反馈
## 6. 卡片页头部:系统导航栏右上角两个 icon 按钮
- [x] **改造 `client/app/(app)/_layout.tsx``home` 的 `headerRight` 使用两个圆形 icon 按钮**
- **状态**:已完成
- **要求**
- 两按钮水平排列、圆形浅色底、`hitSlop>=10`
- 左:主题(`theme.svg`),右:我的(`my.svg`
- **事件传递方案(需要落地)**
- 实际落地:在 `home.tsx` 内通过 `navigation.setOptions()` 设置 `headerRight`,直接使用页面 state 打开 Theme/Profile 弹窗(避免跨层事件传递)
- **验收**
- 右上角两个按钮展示正确
- 点击分别能打开对应弹窗
## 7. 卡片页内容:喜欢/讨厌改为 icon + 强反馈动效
- [x] **改造 `client/app/(app)/home.tsx`:底部按钮从文字改为 icon**
- **状态**:已完成
- **要求**
- 喜欢按钮使用 `like.svg`
- 讨厌按钮使用 `hate.svg`(逻辑仍写入 reaction=`dislike`
- **验收**:两按钮 icon 显示清晰,点击逻辑仍正常推进下一张卡片
- [x] **实现“强反馈:心形填满”点击动效**
- **状态**:已完成
- **范围**:至少作用于“喜欢”按钮
- **建议实现**
- `pressIn/pressOut`:按钮缩放回弹
- `onPress`短促强调动效scale 1 → 1.12 → 1
- “填满”效果:点击后切换到“填充版心形”(若当前资源仅描边,需要:
- 新增一份 `like_filled.svg`(或在现有 SVG 上修改 fill/stroke并保持风格一致
- 或用 `react-native-svg` 动态改 `fill`(可行但实现复杂)
- **验收**
- 点击喜欢按钮能看到明显的“变填充 + 弹一下”反馈
- 动效结束后再推进下一张卡片(避免动画被切页吞掉)
## 8. 主题对 Home 背景的影响
- [x] **让主题 mode 影响 Home 页面背景**
- **状态**:已完成
- **规则**
- `scenery`:使用风景主题背景(可先用现有米色/图片占位)
- `color`:使用颜色主题背景(可先用淡粉色/纯色占位)
- **验收**:切换主题后背景立即变化;返回/重进页面仍正确
## 9. i18n用于标题/无障碍/占位文案)
- [x] **补齐本需求相关 i18n key至少 zh-CN/en**
- **状态**:已完成
- **建议 key**
- `theme.title``theme.scenery``theme.color`
- `profile.title``profile.favorites``profile.widget`
- `profile.dailyReminder``profile.privacy``profile.terms``profile.language`
- `home.theme``home.profile`(用于 `accessibilityLabel`
- **验收**:弹窗标题/选项/占位提示无硬编码长文案;切换语言可生效
## 10. 自测与验收
- [ ] **主题弹窗流程自测**
- **状态**:未开始
- **路径**Home 右上角主题按钮 → 主题弹窗 → 切换风景/颜色 → 背景变化 → 重启后仍保持
- **验收**:符合 `spec.md` / `plan.md` / 本清单验收点
- [ ] **我的弹窗流程自测**
- **状态**:未开始
- **路径**Home 右上角我的按钮 → 个人主页弹窗 → 点 X 关闭 → 列表项点击占位反馈
- **验收**:弹窗不穿透、关闭稳定、占位反馈明确
- [ ] **喜欢/讨厌动效与逻辑自测**
- **状态**:未开始
- **路径**:连续点击喜欢/讨厌 → 按钮动效可见 → 卡片索引推进 → 收藏/反应写入正常
- **验收**:无报错、不卡顿、动效不被切换吞掉

View File

@@ -0,0 +1,28 @@
# Onboarding UI Optimization (补充说明)
## Colors
```typescript
export const OnboardingColors = {
background: '#FFF4EA',
textPrimary: '#4A3B32',
textSecondary: '#8C8C8C', // 占位符颜色
buttonStart: '#F69F7B',
buttonEnd: '#F99CC0',
cardBackground: '#FFFFFF',
cursor: '#F99CC0', // 假设光标颜色与按钮结束色一致
};
```
## SVG Assets (Next Arrow)
```xml
<!-- 简单的右箭头 SVG 路径参考 -->
<svg width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="white" stroke-width="2" stroke-linecap="round" stroke-linejoin="round">
<path d="M5 12h14M12 5l7 7-7 7"/>
</svg>
```
## Intent Icons (Emojis as placeholders)
- 爱情: ❤️
- 生活: ⛅
- 旅游: 🌴
- 职场: 💼

View File

@@ -0,0 +1,44 @@
# Onboarding UI Optimization (技术计划)
## 1. 基础设施与样式定义 (Foundation)
- [ ] **定义 Design Tokens**
-`constants/Colors.ts` 或新文件 `constants/OnboardingTheme.ts` 中定义新色值:
- `background`: `#FFF4EA`
- `textPrimary`: `#4A3B32` (深棕)
- `buttonGradientStart`: `#F69F7B`
- `buttonGradientEnd`: `#F99CC0`
- `inputBackground`: `#FFFFFF`
- [ ] **创建基础组件**
- `SerifText`: 封装 `Text` 组件,默认应用 `fontFamily: Platform.select({ ios: 'Georgia', android: 'serif', default: 'serif' })` 及主题色。
- `OnboardingLayout`: 通用容器,包含 `SafeAreaView`、背景色设置、Header (Skip 按钮) 与 Footer 占位。
## 2. UI 组件开发 (UI Components)
- [ ] **下一步按钮 (NextButton)**
- 使用 `expo-linear-gradient` 实现渐变背景。
- 绘制 SVG 箭头 (使用 `react-native-svg` 或直接嵌入 SVG xml string 如果不引入新库,首选 `react-native-svg` 如果项目已有,否则用简单 View/Image 替代或引入库)。
- *注:检查 `package.json` 发现未安装 `react-native-svg`,将使用 Image 或 Text Icon 替代,或者建议安装。鉴于需求“你自己生成 SVG”推荐安装 `react-native-svg`。*
- [ ] **称呼页 (NameInputStep)**
- 居中白色圆角容器。
- `TextInput` 样式定制:隐藏默认下划线,自定义光标颜色 (selectionColor),字体样式。
- [ ] **意图选择页 (IntentSelectionStep)**
- 2x2 Grid 布局。
- `SelectionCard` 组件:支持选中/未选中状态切换 (边框/背景变化)。
- 实现多选逻辑。
## 3. 页面整合与逻辑 (Integration)
- [ ] **重构 `app/(onboarding)/onboarding.tsx`**
- 引入状态管理:`currentStep` (0: Name, 1: Intent)。
- 状态收集:`name` (string), `selectedIntents` (string[])。
- 步骤切换逻辑:
- Step 1 -> Next -> Step 2。
- Step 2 -> Next -> Finish (持久化 & 跳转)。
- [ ] **持久化逻辑更新**
- 确保 `appStorage.ts` 支持存储新的字段(如果需要)。
- 完成时写入 `isOnboardingCompleted`
## 4. 依赖检查
- 需确认是否允许安装 `react-native-svg` 用于渲染高质量图标。若不允许,将导出为 PNG 使用。

View File

@@ -0,0 +1,68 @@
# Onboarding UI Optimization (高层规范)
## 1. 背景与目标
本需求旨在根据最新的设计稿Visual References对现有的 Onboarding 流程界面进行视觉升级与体验优化。目标是打造一个温暖、极简且高质感的用户引导流程。
### 核心目标
- **视觉升级**:实现设计稿中的配色、排版与组件样式(暖色调、衬线字体风格)。
- **组件复用**:提取通用的布局容器、按钮与输入组件。
- **交互流畅**:确保输入、选择与页面切换的流畅体验。
## 2. 视觉设计规范 (Visual Specifications)
基于提供的设计稿与确认信息,定义以下视觉基调:
### 2.1 整体风格
- **背景色**`#FFF4EA` (Warm Beige)。
- **字体**
- 使用系统默认衬线字体 (System Serif) 作为主要字体。
- 预留字体配置接口,方便后续替换自定义字体文件。
- 颜色主要为深棕色 (例如 `#4A3B32`)。
- **按钮**
- **下一步按钮**
- 底部居中,圆形。
- **背景渐变**`#F69F7B` (起) → `#F99CC0` (止)。
- **图标**:白色箭头 SVG (需生成)。
- **Skip 按钮**:右上角,纯文字 "Skip ->",衬线体。
### 2.2 页面布局
- **Header**:包含状态栏占位与 "Skip" 按钮。
- **Body**:垂直居中分布主要内容(问题 + 交互区域)。
- **Footer**:底部居中放置圆形下一步按钮。
## 3. 页面详细需求
### 3.1 称呼页 (Name Input)
- **标题**:“我可以怎么称呼你?” (Serif)
- **交互区域**
- 白色圆角矩形容器。
- 输入框居中,占位符或默认值显示 "Hao"。
- 光标样式需定制(粉色竖线)。
- **逻辑**
- 输入非空时,键盘回车或点击底部按钮进入下一页。
- 支持跳过。
### 3.2 意图选择页 (Intent Selection)
- **标题**:“你希望得到什么帮助?” (Serif)
- **交互区域**
- 2x2 网格布局。
- **选项卡片**
- 白色圆角矩形背景。
- 内容:左侧 Icon (占位) + 右侧/居中 文字。
- 示例选项:❤️ 爱情, ⛅ 生活, 🌴 旅游, 💼 职场
- **选中状态**:需补充选中态设计(如边框高亮或背景微变)。
- **逻辑**
- **多选**。
- 选择后点击底部按钮进入下一页。
## 4. 技术实现建议
- **布局容器**:创建一个通用的 `OnboardingLayout` 组件处理背景、SafeArea、Skip 按钮与底部按钮。
- **字体**:封装 `SerifText` 组件,目前映射到系统 Serif后续可一键替换。
- **图标**:使用 `expo-vector-icons` 或简单 View 占位,箭头图标使用内联 SVG。
- **渐变**:使用 `expo-linear-gradient` 实现按钮背景。
## 5. 待确认事项 (Open Questions)
- 已确认:字体使用默认,图标暂用占位,意图页为多选,背景色与渐变色已定。

View File

@@ -0,0 +1,17 @@
# Onboarding UI Optimization (任务清单)
## Setup & Styles
- [ ] 安装 `react-native-svg` (如果尚未安装,需确认) <!-- id: 0 -->
- [ ] 创建 `client/constants/OnboardingTheme.ts` 定义色值 <!-- id: 1 -->
- [ ] 创建 `client/components/onboarding/SerifText.tsx` <!-- id: 2 -->
- [ ] 创建 `client/components/onboarding/OnboardingLayout.tsx` (含 Skip 按钮) <!-- id: 3 -->
## Components
- [ ] 创建 `client/components/onboarding/NextButton.tsx` (渐变 + 箭头) <!-- id: 4 -->
- [ ] 创建 `client/components/onboarding/NameInputStep.tsx` <!-- id: 5 -->
- [ ] 创建 `client/components/onboarding/IntentSelectionStep.tsx` (含 Grid & Card) <!-- id: 6 -->
## Integration
- [ ] 修改 `client/app/(onboarding)/onboarding.tsx` 实现多步逻辑 <!-- id: 7 -->
- [ ] 调试并验证 iOS 模拟器显示效果 <!-- id: 8 -->
- [ ] 验证持久化存储逻辑 <!-- id: 9 -->

View File

@@ -0,0 +1,112 @@
# Splash Consent技术计划
## 1. 计划目标
实现客户端开屏页Splash/Welcome与首次协议同意逻辑
- 使用 `client/assets/images/index/` 的图片作为主视觉(例如 `index_flowers.png`
- 底部渐变按钮颜色:`#F69F7B → #F99CC0`
- 按钮下方提供「隐私协议」「用户使用协议」外部链接入口(先用占位链接)
- **仅首次出现按钮**:当 `consent.accepted=true` 后不再展示同意按钮与协议入口
- 同意后进入现有启动分发:`app/index.tsx`(继续走 Onboarding/App Shell
## 2. 默认技术决策
- **路由**:沿用 `expo-router`
- **持久化**:沿用 `AsyncStorage`
- **协议打开方式**:外部链接(`expo-web-browser``Linking.openURL`
- **渐变实现**:使用 `expo-linear-gradient`Expo 官方)
## 3. 路由与流程设计
### 3.1 新增路由
- `app/(splash)/splash.tsx`:开屏页(图片 + 首次同意按钮/协议入口)
- `app/(splash)/_layout.tsx`:可选(一般无需 header
### 3.2 启动分发逻辑(与现有流程集成)
当前已存在启动分发 `app/index.tsx`(根据 `onboarding.completed` 跳转)。
本需求将启动分发扩展为两段判断:
1.`consent.accepted !== true`:跳转到 `/(splash)/splash`
2.`consent.accepted === true`:沿用原逻辑(进入 Onboarding 或 `/(app)/home`
> 注意:你确认的是“隐藏按钮而不是隐藏页面”。因此当 `consent.accepted=true` 时,开屏页不需要停留;可直接跳过该页进入原启动分发。
## 4. 数据与持久化
### 4.1 Key
- `consent.accepted`: boolean
### 4.2 存储封装
在现有 `src/storage/appStorage.ts` 中补充:
- `getConsentAccepted(): Promise<boolean>`
- `setConsentAccepted(accepted: boolean): Promise<void>`
并确保所有 UI 不直接硬编码 key。
## 5. UI 细节与交互
### 5.1 开屏布局(建议)
- 主视觉图片:
- 使用 `index_flowers.png`
- 适配:`resizeMode="contain"` 或按实际视觉调整(不裁切关键内容)
- 底部区域(贴近安全区):
- 渐变按钮(圆角、阴影/投影轻微)
- 协议入口(两段文字按钮,左右排列或一行内间隔)
### 5.2 渐变按钮(仅首次出现)
- 展示条件:`consent.accepted !== true`
- 点击行为:
- 写入 `consent.accepted=true`
- 跳转到 `/`(触发 `app/index.tsx` 继续分发)
### 5.3 协议入口(外部链接,先占位)
- 「隐私协议」:`https://example.com/privacy`
- 「用户使用协议」:`https://example.com/terms`
打开方式:
- 优先:`expo-web-browser` 打开外部链接
- 兜底:`Linking.openURL`
## 6. i18n 文案
新增 key至少 `zh-CN/en`,其余语言可逐步补齐):
- `consent.title`(可选)
- `consent.agree`(按钮文案:同意并继续)
- `consent.privacy`(隐私协议)
- `consent.terms`(用户使用协议)
## 7. 实施步骤
1. 新增 `consent.accepted` 的存储读写方法
2. 新增 `/(splash)/splash` 页面(图片 + 渐变按钮 + 协议入口)
3. 修改 `app/index.tsx`:在 onboarding 分发前插入 consent gate
4. 接入 `expo-linear-gradient` 并完成按钮 UI
5. 接入外部链接打开(先占位 URL
6. 补齐 i18n key至少 zh-CN/en
7. 自测:
- 首次启动:显示按钮与入口;同意后进入 Onboarding/App
- 再次启动:不再出现同意按钮,直接进入后续流程
## 8. 验收标准
- 首次启动:
- 展示开屏图片
- 渐变按钮颜色正确(`#F69F7B → #F99CC0`
- 协议入口可点击并打开外部链接
- 点击同意后进入后续流程
- 非首次启动:
- 不再出现同意按钮与协议入口
- 直接进入后续流程Onboarding/App Shell

View File

@@ -0,0 +1,103 @@
# Splash Consent高层规范
## 1. 背景与目标
客户端需要一个开屏页Splash/Welcome用于展示品牌视觉并在**首次加载**时让用户同意隐私协议与用户使用协议。用户同意后进入后续流程Onboarding/App
### 目标
- **视觉开屏**:使用 `client/assets/images/index/` 下的图片资源作为主视觉
- **首次同意**:底部渐变按钮仅在首次加载时出现,用于“同意并继续”
- **协议入口**:按钮下方提供「隐私协议」「用户使用协议」入口,用户可点击查看
- **状态持久化**:同意后不再显示该按钮(后续启动直接进入后续流程)
### 非目标(本阶段不做)
- 不实现复杂的协议版本管理(如协议更新后重新弹出),后续可扩展
- 不实现后端拉取协议内容(可先使用本地静态页面或外链)
## 2. 范围与交付物
### 范围
- 新增开屏页 UI 与路由接入
- 新增“首次同意”状态的本地持久化
- 协议入口(跳转到 WebView/外部浏览器/内置页面,方案在实现阶段确定)
### 交付物
- 开屏页(含图片、按钮、协议入口)
- 本地持久化 key 约定与读写逻辑
- README/文档更新(可选)
## 3. 视觉与交互需求
### 3.1 主视觉
- 使用 `client/assets/images/index/` 下的图片资源(例如 `index_flowers.png`
- 布局建议:
- 图片居中或铺满上半部分(按实际设计微调)
- 适配不同屏幕尺寸,确保不变形/不裁切关键内容
### 3.2 底部渐变按钮(仅首次出现)
- **出现条件**:仅在首次加载且未同意协议时显示
- **按钮文案**:建议“同意并继续”(文案可后续调整,需支持 i18n
- **按钮渐变色**:从 `#F69F7B``#F99CC0`
- **点击行为**
- 写入本地状态:用户已同意
- 跳转到后续流程入口(例如 Onboarding 或 Home 的启动分发)
### 3.3 协议入口
- 位于按钮下方,展示:
- **隐私协议**
- **用户使用协议**
- 点击行为:打开对应协议内容
- 支持外链或内置页面(实现阶段确认)
## 4. 首次加载判定与持久化
### 4.1 判定规则
- **首次加载定义**App 首次启动且用户未完成协议同意
### 4.2 存储 Key建议
- `consent.accepted`: boolean
> 说明:后续如需协议版本化,可扩展为 `consent.versionAccepted = <version>`。
## 5. 路由与流程(与现有客户端集成)
### 5.1 流程顺序(建议)
1. App 启动
2.`consent.accepted !== true`:进入开屏页(展示按钮与协议入口)
3. 用户点击“同意并继续”后:
- 写入 `consent.accepted=true`
- 进入后续流程(例如 Onboarding/App Shell 的启动分发)
### 5.2 与现有功能的关系
- 开屏页位于 Onboarding 之前(更符合“先同意协议再使用”的要求)
- 同意后按既有规则继续:
- 已完成 onboarding进入 Home
- 未完成 onboarding进入 Onboarding
## 6. 验收标准
- 首次启动:
- 出现开屏页,展示图片
- 底部渐变按钮可见,颜色正确(`#F69F7B``#F99CC0`
- “隐私协议/用户使用协议”可点击打开
- 点击“同意并继续”后进入后续流程
- 非首次启动:
- 不再出现“同意按钮”(且开屏页按产品要求可直接跳过或不再展示)
- 直接进入后续流程
## 7. 风险与注意事项
- 协议内容来源若为外链,需要保证链接长期可用;若为本地页面,需要考虑后续更新机制
- iOS 不同机型安全区(底部 Home Indicator需保证按钮与协议入口不被遮挡

View File

@@ -0,0 +1,109 @@
# Splash Consent任务清单
> 说明:本清单根据 `plan.md` 拆解,要求“可执行、可验收、可标记”。
> 标记规则:执行完成后将对应项从 `- [ ]` 改为 `- [x]`,并把“状态”改为 **已完成**;进行中改为 **进行中**;阻塞写明原因与解除条件。
## 0. UI 参考(本次实现对齐)
- **参考截图**:你提供的开屏页样式(花束插画 + 文案 + 圆角渐变按钮 + 协议入口)
- **图片资源**`client/assets/images/index/index_flowers.png`
- **按钮渐变色**`#F69F7B``#F99CC0`
- **交互约束**
- 仅首次(未同意)显示“同意按钮 + 协议入口”
- 同意后写入本地 `consent.accepted=true`,并进入既有启动分发 `app/index.tsx`
## 1. 依赖与基础设施
- [ ] **安装并接入渐变组件Expo 官方)**
- **状态**:未开始
- **命令**
```bash
cd client
pnpm add expo-linear-gradient
```
- **验收**:项目可正常启动,页面可渲染渐变按钮
- [ ] **确认外部链接打开方式expo-web-browser可用**
- **状态**:未开始
- **说明**:已存在依赖则跳过安装;否则安装 `expo-web-browser`(当前项目初始化模板通常已包含)
- **验收**:能通过代码打开 `https://example.com/*` 外链
## 2. 本地存储:协议同意状态
- [ ] **在 `src/storage/appStorage.ts` 增加 consent 读写方法**
- **状态**:未开始
- **Key**`consent.accepted`
- **新增 API建议**
- `getConsentAccepted(): Promise<boolean>`
- `setConsentAccepted(accepted: boolean): Promise<void>`
- **验收**:不在 UI 代码里硬编码 key重启后状态仍然保留
## 3. 路由与启动分发接入
- [ ] **新增开屏路由:`app/(splash)/splash.tsx`**
- **状态**:未开始
- **要求**
- 展示主视觉图片(`index_flowers.png`
- 底部区域包含:渐变按钮 + 协议入口(仅未同意时显示)
- **验收**:路由可访问并正常渲染 UI
- [ ] **修改 `app/index.tsx`:增加 consent gate**
- **状态**:未开始
- **规则**
-`consent.accepted !== true`:跳转到 `/(splash)/splash`
- 否则沿用原逻辑Onboarding / Home
- **验收**:首次启动先到开屏;同意后进入既有分发
## 4. 开屏页 UI 落地(对齐参考图)
- [ ] **布局与样式实现(适配安全区)**
- **状态**:未开始
- **布局建议(可微调)**
- 顶部:插画居中,`resizeMode="contain"`
- 中部:主文案(支持 i18n
- 底部:渐变按钮(圆角/阴影轻微)+ 协议入口(文本按钮)
- 注意底部 Home Indicator 安全区
- **验收**:不同屏幕尺寸下不遮挡、不溢出,整体视觉接近参考图
- [ ] **渐变按钮(仅首次出现)**
- **状态**:未开始
- **颜色**`#F69F7B``#F99CC0`
- **点击行为**
- `setConsentAccepted(true)`
- `router.replace('/')`(回到启动分发)
- **验收**:点击后按钮不再出现(重启仍不出现),并进入后续流程
- [ ] **协议入口(外部链接,占位 URL**
- **状态**:未开始
- **链接**
- 隐私协议:`https://example.com/privacy`
- 用户使用协议:`https://example.com/terms`
- **打开方式**:优先 `expo-web-browser`,兜底 `Linking.openURL`
- **验收**:点击可打开外链;失败时不崩溃(可 toast/alert 提示)
## 5. i18n 文案补齐
- [ ] **新增开屏相关 i18n key至少 zh-CN/en尽量补齐 5 语)**
- **状态**:未开始
- **建议 key**
- `consent.title`(可选)
- `consent.subtitle`(可选)
- `consent.agree`
- `consent.privacy`
- `consent.terms`
- **验收**:开屏页不出现硬编码长句;切换语言可生效
## 6. 自测与验收
- [ ] **首次启动流程自测**
- **状态**:未开始
- **路径**Splash显示按钮/协议入口)→ 同意 → 进入 `app/index.tsx` 分发Onboarding/Home
- **验收**:与 `spec.md` / `plan.md` 验收一致
- [ ] **非首次启动流程自测**
- **状态**:未开始
- **路径**:直接进入 `app/index.tsx` 分发(不再出现同意按钮与协议入口)
- **验收**:同意状态持久化生效

View File

@@ -65,6 +65,7 @@ npx expo prebuild -p ios
- **排查**
- 桌面搜索不到:通常是没有 Run 安装过主 App或 Widget target 未加入编译
- 点击不跳转:确认 Widget 里 `widgetURL``client:///(app)/home`,且 `app.json``scheme``client`
- 仍然搜不到:检查 Widget Extension 的 Bundle Identifier 是否有效(本仓库已修正为 `com.anonymous.client.emotionwidget`),然后 Clean + 重新安装 App
## 6. 文档补充(可选但建议)

View File

@@ -47,3 +47,31 @@
- `spec_kit/iOS Widget/spec.md`
- `spec_kit/iOS Widget/plan.md`
- `spec_kit/iOS Widget/tasks.md`
## Splash Consent
- **目标**:实现开屏页(使用 `client/assets/images/index/` 图片资源),首次加载展示渐变同意按钮并提供隐私/协议入口
- **核心范围**:开屏 UI、首次同意状态持久化`consent.accepted`)、点击同意后进入后续 Onboarding/App 流程
- **阶段产物**
- `spec_kit/Splash Consent/spec.md`
- `spec_kit/Splash Consent/plan.md`
- `spec_kit/Splash Consent/tasks.md`
## Card UI
- **目标**:优化卡片页 UI 与交互,支持右上角主题切换与个人主页弹窗,并将喜欢/讨厌改为 icon + 动效
- **核心范围**
- 系统导航栏右上角两个圆形 icon主题`theme.svg`/ 我的(`my.svg`
- 底部上拉弹窗Sheet统一内容区背景 `#FAF3EC`,点 X 关闭
- 主题两种模式:`scenery` / `color`(本期最少影响 Home 页面背景),并持久化 `ui.theme.mode`
- 喜欢/讨厌按钮:使用 `like.svg` / `hate.svg`,喜欢提供“心形填满”强反馈动效(`like_filled.svg`
- 每日提醒弹窗:次数 +/-、Push 提醒开关、渐变 Ok 按钮,并持久化设置
- **阶段产物**
- `spec_kit/Card UI/spec.md`
- `spec_kit/Card UI/plan.md`
- `spec_kit/Card UI/tasks.md`
- **已完成编码(阶段性)**
- 已接入 `react-native-svg-transformer` + `client/metro.config.js`
- 新增 `SheetModal``ThemeModal``ProfileModal` 并在 Home 中接入
- 新增 `DailyReminderModal` 并从个人主页弹窗打开
- Home右上角 icon 按钮、主题切换背景、喜欢/讨厌 icon + 动效

View File

@@ -0,0 +1,239 @@
# B 端情绪句子生成与审核后台设计方案
> 本文档用于说明:
> **如何在 B 端搭建一个“AI 生成 + 人工确认”的情绪句子生产后台**
> 以支持情绪句子个性化推荐系统的稳定、安全运行。
>
> 适用阶段0 → 1个人或小团队
---
## 一、设计目标与原则
### 1. 核心目标
* 利用 AI 提高句子**产量**
* 通过人工审核保证句子**安全性与可控性**
* 最终产出 **可被推荐系统稳定使用的结构化句子库**
一句话总结:
> **AI 负责写,人负责判断,系统负责记住结果。**
---
### 2. 设计原则(必须遵守)
1. **AI 生成内容不可直接入库**(人工确认是底线)
2. 后台以“流程判断”为核心,而非“重度编辑”
3. 所有内容必须结构化(情绪 / 语气 / 场景)
4. 后台设计需支持未来回溯与优化
---
## 二、后台整体架构(模块拆分)
后台整体可拆分为 5 个核心模块:
```
生成任务 → 候选池 → 人工审核 → 正式句子库 → 效果回溯
```
对应模块说明:
1. **AI 生成模块**:根据结构化条件批量生成句子
2. **候选句子池Draft**:存放所有未审核内容
3. **人工审核模块**:快速判断可用性与风险
4. **正式句子库Active**:供推荐系统使用
5. **效果回溯模块**:用于优化 Prompt 与规则
---
## 三、标准内容生产流程(推荐做法)
### Step 1生成任务AI 生成)
**后台页面:生成句子**
人工只需填写结构化条件:
* 主情绪必选6 选 1
* 语气必选4 选 1
* 场景(可选)
* 使用目的:
* Feed
* 每日一句 / Push
* 生成数量(如 5 / 10 条)
系统行为:
* 根据条件自动拼装标准 Prompt
* 调用 AI 批量生成候选句子
> ❗ 设计重点:
> 人 **不直接写 Prompt**Prompt 被产品化、模板化。
---
### Step 2候选句子池Draft 状态)
所有 AI 生成的句子统一进入:
> **候选句子池Draft**
每条句子需携带以下信息:
* 句子正文
* AI 建议的主情绪
* AI 建议的语气
* 生成来源(任务 ID
* 当前状态:待审核
此阶段:
* ❌ 不可被推荐系统使用
* ❌ 不可出现在 Feed / Push
---
### Step 3人工审核最关键环节
**后台页面:审核列表**
以“卡片式”快速判断为核心,而非编辑器:
每条卡片展示:
* 句子正文
* AI 建议标签
* 预期使用位置Feed / Push
* 潜在风险提示(可选)
人工可执行的动作仅限 4 种:
1.**确认可用**
2. ✏️ **轻微修改后确认**
3. 🔄 **退回重写(同条件重新生成)**
4.**废弃**
> 理想比例:
>
> * 70% 直接确认
> * 20% 轻改
> * 10% 废弃
---
### Step 4标签确认与补充人工兜底
在句子进入正式库前,必须由人工确认:
* 主情绪(只能 1 个)
* 语气(只能 1 个)
* 场景(可选)
* 是否允许用于:
* Feed
* 每日一句 / Push
原则:
> **AI 给建议,人做最终拍板。**
---
### Step 5正式入库Active 状态)
通过审核的句子进入:
> **正式句子库Active**
此状态下:
* 可被推荐系统召回
* 可出现在 Feed / Push / Widget
* 会参与用户行为反馈统计
---
### Step 6效果回溯与优化后置但重要
后台应支持最基础的数据回看:
* 单句表现:
* 曝光次数
* 喜欢 / 讨厌比例
* 情绪 / 语气整体表现
用途:
* 调整生成 Prompt
* 调整审核标准
* 决定下架或冻结部分句子
---
## 四、后台设计的 3 个关键成败点
### 1⃣ 严禁 AI 直出内容
即使在高压或追求效率时:
> **人工审核不可跳过,这是情绪产品的安全底线。**
---
### 2⃣ 审核必须“轻”,而不是“重写”
如果你发现:
* 大量句子需要重写
* 审核体验非常痛苦
说明问题在于:
* Prompt 设计
* 情绪 / 语气定义
而不是“人不够努力”。
---
### 3⃣ 后台偏“流程系统”,不是“编辑工具”
后台目标是:
* 快速判断
* 快速流转
* 支持批量操作
而不是:
* 文案创作
* 精修排版
---
## 五、最小可行版本MVP建议
### 必须具备的页面4 个)
1. **生成任务页**:结构化条件 + 生成按钮
2. **审核列表页**:通过 / 修改 / 丢弃
3. **句子库页**:筛选 / 查看 / 状态
4. **基础回溯页**(可后置):简单表现数据
> 前期可使用 Notion / Airtable / 简单 Web 实现,
> 不必一开始就工程化。
---
## 六、系统一句话总结(用于对齐)
> **这是一个“AI 提供候选,人类负责风险判断”的情绪内容生产系统。**
---
**本文档可作为 B 端后台设计、工程实现与流程对齐的统一参考。**

View File

@@ -0,0 +1,233 @@
## 一、句子标签体系Sentence Tagging System
### 1. 设计原则
* 标签不是为了分类句子,而是为了 **让推荐系统理解用户的情绪需求**
* 所有标签必须:
* 可被用户行为验证(会被喜欢 / 讨厌)
* 可直接影响推荐决策
* 数量克制、定义稳定
---
### 2. 主情绪标签Emotion Tags6 个)
> 主情绪标签 = 一句话 **解决的核心情绪需求**
>
> **每一句话只能有 1 个主情绪标签**
1. **安抚Calm**
* 用于情绪过载、焦虑、疲惫
* 目标:先稳定情绪
2. **被理解Understood**
* 用于孤独、自我怀疑
* 目标:建立共感
3. **接纳Acceptance**
* 用于自责、内疚、不够好感
* 目标:缓解自我攻击
4. **鼓励Encourage**
* 用于低落但尚可前行
* 目标:提供继续的力量(非口号)
5. **行动启动Activation**
* 用于卡住、拖延
* 目标:启动,而非成功
6. **希望感Hope**
* 用于低谷、无出口感
* 目标:保留可能性
---
### 3. 语气标签Tone Tags4 个)
> 语气标签 = **“这句话是怎么说的”**
>
> 用户对语气的“讨厌”比“喜欢”更重要
* **温柔Gentle**:安全、低压、共感
* **中性Neutral**:陈述型、兜底使用
* **直接Direct**:清晰、有方向
* **诗性Poetic可选**:隐喻、画面感
---
### 4. 场景标签Scene Tags5 个,可空)
> 场景标签是 **加分项,不是必填项**
* 早晨Morning
* 工作 / 学习中Focus
* 情绪低谷时Low
* 睡前Night
* 随时Anytime默认
---
### 5. 标签纪律(强规则)
1. 每句话只能有 1 个主情绪标签
2. 90% 句子可以没有场景标签
3. 行动启动 ≠ 鼓励
4. 安抚 ≠ 接纳
5. 不确定时,优先选择「被理解」
---
## 二、用户画像体系User Profile Indicators
### 1. 设计原则
* 用户画像不是“这个人是谁”
* 而是 **“这个人最近更容易接住什么样的话”**
* 所有指标默认 **可变、会衰减、以近期为主**
---
### 2. 用户画像的最小结构4 大类)
#### ① 主情绪偏好(核心)
* 对 6 个主情绪标签的近期偏好强度
* 决定「今天主要推哪一类句子」
---
#### ② 语气接受度
* 用户对不同说话方式的耐受程度
* 主要用于 **过滤用户讨厌的语气**
---
#### ③ 场景有效性(轻量)
* 哪些时间 / 状态更容易被接受
* 仅作为推荐修正项
---
#### ④ 情绪稳定度(隐性指标)
* 根据近期反馈判断:稳定 / 波动 / 不稳定
* 决定:
* 探索比例
* 是否使用保守推荐
* Push / Widget 是否降强度
---
### 3. 不纳入的画像指标(刻意避免)
* 人格类型MBTI 等)
* 情绪诊断标签(焦虑 / 抑郁)
* 长期性格、身份属性
原因:
* 医疗与伦理风险高
* 对「选一句话」帮助极低
---
## 三、个性化推荐架构Personalized Recommendation Framework
### 1. 总体逻辑
> **句子标签 = 地图**
> **用户画像 = 当前状态**
> **推荐系统 = 在地图上谨慎前进**
推荐目标不是“最相关”,而是:
* 最合适
* 最安全
* 最不容易被拒绝
---
### 2. 推荐决策的三层结构
#### 第一层:候选生成(方向)
* 基于用户主情绪偏好召回句子
* 同时保留少量相邻情绪用于探索
---
#### 第二层:排序选择(判断)
综合判断:
* 主情绪是否匹配
* 语气是否可接受
* 场景是否合适
* 是否近期重复
---
#### 第三层:安全与多样性控制(保护)
* 情绪不稳定时:收敛到安抚 / 接纳
* 连续讨厌时:主动退让、冷却
* 避免同一情绪 / 语气连续出现
---
### 3. 不同触点的推荐差异
* **Feed**
* 多样性高
* 探索允许
* **Push / 每日一句**
* 高确定性
* 强去重
* 以安全为先
* **Widget**
* 中性 / 安抚优先
* 不试错
---
### 4. 行为 → 画像 → 推荐的闭环
* 用户行为 ≠ 对句子的评价
* 而是对 **“情绪 × 语气 × 场景”组合的反馈**
推荐系统学习的不是:
> “哪句话好”
而是:
> “什么时候,用什么方式,说什么样的话,更容易被接住”
---
## 四、系统级原则(给 PM 的一句话判断标准)
> **这次推荐,是在理解用户此刻,
> 还是在重复用户过去?**
* 前者 → 好推荐
* 后者 → 情绪回音室(需要避免)
---
**本文档适用于 0 → 1 阶段,建议冻结 3 个月后再评估是否扩展。**

View File

@@ -0,0 +1,367 @@
# 情绪句子个性化推荐系统0 → 1
> 本文档用于 **个人 + AI 协作** 场景,作为产品、内容、推荐决策的统一对齐说明。
>
> 核心目标:
> **在任何一个时刻,为用户选出「最可能被接住的一句话」。**
---
## 一、句子标签体系Sentence Tagging System
### 1. 设计原则
* 标签不是为了分类句子,而是为了 **让推荐系统理解用户的情绪需求**
* 所有标签必须:
* 可被用户行为验证(会被喜欢 / 讨厌)
* 可直接影响推荐决策
* 数量克制、定义稳定
---
### 2. 主情绪标签Emotion Tags6 个)
> 主情绪标签 = 一句话 **解决的核心情绪需求**
>
> **每一句话只能有 1 个主情绪标签**
1. **安抚Calm**
* 用于情绪过载、焦虑、疲惫
* 目标:先稳定情绪
2. **被理解Understood**
* 用于孤独、自我怀疑
* 目标:建立共感
3. **接纳Acceptance**
* 用于自责、内疚、不够好感
* 目标:缓解自我攻击
4. **鼓励Encourage**
* 用于低落但尚可前行
* 目标:提供继续的力量(非口号)
5. **行动启动Activation**
* 用于卡住、拖延
* 目标:启动,而非成功
6. **希望感Hope**
* 用于低谷、无出口感
* 目标:保留可能性
---
### 3. 语气标签Tone Tags4 个)
> 语气标签 = **“这句话是怎么说的”**
>
> 用户对语气的“讨厌”比“喜欢”更重要
* **温柔Gentle**:安全、低压、共感
* **中性Neutral**:陈述型、兜底使用
* **直接Direct**:清晰、有方向
* **诗性Poetic可选**:隐喻、画面感
---
### 4. 场景标签Scene Tags5 个,可空)
> 场景标签是 **加分项,不是必填项**
* 早晨Morning
* 工作 / 学习中Focus
* 情绪低谷时Low
* 睡前Night
* 随时Anytime默认
---
### 5. 标签纪律(强规则)
1. 每句话只能有 1 个主情绪标签
2. 90% 句子可以没有场景标签
3. 行动启动 ≠ 鼓励
4. 安抚 ≠ 接纳
5. 不确定时,优先选择「被理解」
---
## 二、用户画像体系User Profile Indicators
### 1. 设计原则
* 用户画像不是“这个人是谁”
* 而是 **“这个人最近更容易接住什么样的话”**
* 所有指标默认 **可变、会衰减、以近期为主**
---
### 2. 用户画像的最小结构4 大类)
#### ① 主情绪偏好(核心)
* 对 6 个主情绪标签的近期偏好强度
* 决定「今天主要推哪一类句子」
---
#### ② 语气接受度
* 用户对不同说话方式的耐受程度
* 主要用于 **过滤用户讨厌的语气**
---
#### ③ 场景有效性(轻量)
* 哪些时间 / 状态更容易被接受
* 仅作为推荐修正项
---
#### ④ 情绪稳定度(隐性指标)
* 根据近期反馈判断:稳定 / 波动 / 不稳定
* 决定:
* 探索比例
* 是否使用保守推荐
* Push / Widget 是否降强度
---
### 3. 不纳入的画像指标(刻意避免)
* 人格类型MBTI 等)
* 情绪诊断标签(焦虑 / 抑郁)
* 长期性格、身份属性
原因:
* 医疗与伦理风险高
* 对「选一句话」帮助极低
---
## 三、个性化推荐架构Personalized Recommendation Framework0 → 1 详细版)
> 本章节完整说明:
> **个性化推荐系统在 0 → 1 阶段的设计方式、核心算法思想,以及整体运行流程。**
>
> 设计目标不是“最聪明”,而是:
> **可解释、可控制、一个人 + AI 可以长期维护。**
---
### 3.1 个性化推荐系统的大框架流程
一次完整的推荐决策,按照固定顺序经过以下 6 个阶段:
1. **用户画像读取Profile Reading**
2. **候选生成Candidate Generation / Recall**
3. **排序判断Ranking**
4. **安全与多样性重排Safety & Diversity Re-ranking**
5. **出句到触点Serving**
6. **行为反馈 → 画像更新Online Learning**
> 推荐系统的本质是:
> **在信息不完全的情况下,持续做出“不容易出错”的选择。**
---
### 3.2 0 → 1 阶段采用的核心算法思想(先给名字)
在 0 → 1 阶段,不引入复杂模型,而采用 **规则 + 轻策略算法组合**
1. **Questionnaire Prior问卷先验**:用于冷启动画像方向
2. **Tag-based Recall基于标签的候选召回**:缩小搜索空间
3. **Adjacent-tag Exploration相邻情绪探索**:避免情绪回音室
4. **Weighted Tag Matching加权标签匹配**:核心排序逻辑
5. **Time-decayed Preference时间衰减偏好**:画像始终代表“近期状态”
6. **Cooldown & Blacklist冷却与黑名单**:避免重复与强厌恶
7. **MMR-style Diversity Re-ranking多样性重排**:控制情绪与语气分布
8. **Safety Gating情绪安全闸门**:用户不稳定时强制保守
9. **Epsilon-greedy Exploration探索 / 利用平衡)**Feed 中允许试探
10. **Rule-based Online Update规则型在线学习**:行为驱动画像更新
---
### 3.3 Step 1用户画像读取Profile Reading
**涉及算法思想:**
* Questionnaire Prior
* Time-decayed Preference
**这一阶段做什么:**
* 读取用户当前的主情绪偏好排序
* 判断是否存在近期被频繁讨厌的语气
* 判断情绪稳定度(稳定 / 波动 / 不稳定)
**输出一个“当下推荐策略”:**
* 主方向情绪12 个
* 探索情绪1 个(相邻情绪)
* 探索比例Feed 高Push / Widget 极低
* 是否开启安全模式
---
### 3.4 Step 2候选生成Candidate Generation / Recall
**涉及算法思想:**
* Tag-based Recall
* Adjacent-tag Exploration
**核心目标:**
> **不要从整个句子库中选,而是先圈出“可能对的范围”。**
**候选生成逻辑:**
* 从主方向情绪中召回大部分句子
* 从探索情绪中召回少量句子
* 从新内容池中固定比例补充
**这一阶段不做的事情:**
* 不做精细排序
* 不处理语气偏好
* 不考虑场景冲突
---
### 3.5 Step 3排序判断Ranking
**涉及算法思想:**
* Weighted Tag Matching
* Time-decayed Preference
**排序时的四个核心判断维度:**
1. **主情绪匹配度**
* 是否符合用户近期最需要的情绪支持类型
2. **语气可接受度**
* 是否属于用户近期反感的表达方式
3. **场景是否冲突**
* 当前时间 / 状态下是否明显不合适
4. **新鲜感与重复度**
* 是否近期已看过或高度相似
**关键原则:**
* 主情绪是排序主权重
* 语气更像“过滤器”而非加分器
* 场景只在明显冲突时生效
---
### 3.6 Step 4安全与多样性重排Safety & Diversity Re-ranking
**涉及算法思想:**
* Cooldown & Blacklist
* MMR-style Diversity Re-ranking
* Safety Gating
**这一层的目标:**
> **即使排序不准,也不能伤害用户体验。**
**三类必须存在的保护机制:**
1. **去重与冷却保护**
* 同一句短期不重复
* 高相似句子不连续出现
2. **多样性保护**
* 同一主情绪不连续轰炸
* 同一语气不连续出现
3. **情绪安全保护**
* 用户情绪不稳定时,强制回退到:
* 安抚 / 接纳
* 温柔 / 中性语气
---
### 3.7 Step 5出句到不同触点Serving
**Feed可滑动**
* 允许探索与试错
* 多样性优先
* 行动启动 / 鼓励可出现
**每日一句 / Push**
* 高确定性
* 强去重
* 安全优先
**Widget被动看到**
* 不探索、不试错
* 只选最低风险组合
* 默认:安抚 / 接纳 + 温柔 / 中性
---
### 3.8 Step 6行为反馈 → 画像更新Online Learning
**涉及算法思想:**
* Rule-based Online Update
0 → 1 阶段,仅关注三类行为信号:
* **喜欢**:当前“情绪 × 语气 × 场景”组合有效
* **讨厌**:该组合需要短期退让与冷却
* **无反馈 / 快速滑走**:信号弱,提高探索或降低强度
> 系统学习的不是“哪句话好”,而是:
> **什么时候,用什么方式,说什么样的话,更容易被接住。**
---
### 3.9 0 → 1 阶段的成功判断标准
个性化推荐在 0 → 1 阶段 **不需要做到**
* 非常精准
* 非常智能
* 深度理解用户心理
它只需要做到三点:
1. 明显减少「被讨厌」的句子
2. 每日一句不让用户反感
3. 用户愿意继续看下一句
> 如果做到以上三点,
> 这就是一个 **成功的 0 → 1 个性化推荐系统**。
---
**本章节适用于 0 → 1 阶段,建议冻结 3 个月后再评估是否引入复杂模型。**

View File

@@ -0,0 +1,45 @@
# 给句子打标签
你是一名情绪内容编辑,熟悉以下标签体系。
【主情绪标签(只能选 1 个)】
- 安抚
- 被理解
- 接纳
- 鼓励
- 行动启动
- 希望感
【语气标签(只能选 1 个)】
- 温柔
- 中性
- 直接
- 诗性
【场景标签(可选)】
- 早晨
- 工作 / 学习中
- 情绪低谷时
- 睡前
- 随时
【规则】
1. 每句话只能有 1 个主情绪标签
2. 不确定时,优先选择「被理解」
3. 行动启动 ≠ 鼓励
4. 安抚 ≠ 接纳
【句子】
「{{填入句子}}」
请输出:
- 主情绪:
- 语气:
- 场景(如有):
- 是否适合“每日一句”(是 / 否):
- 简要理由1 句话)
#

View File

@@ -0,0 +1,170 @@
# AI 情绪句子生成 Prompt 手册v1
> 本文档用于 **情绪句子个性化推荐系统** 中的内容生产阶段,
> 目标是:
> **稳定生成可被标签化、可被推荐系统安全使用的情绪支持句子。**
>
> 本手册默认使用于:
>
> * 一个人 + AI 协作
> * 0 → 1 阶段
> * 不追求文采,优先情绪安全与可控性
---
## 一、使用总原则(请务必先阅读)
在本产品中AI 的角色是:
> **情绪表达的“协作者”,而不是情绪判断的“主导者”。**
所有句子生成需遵守以下原则:
1. 不给建议、不提供解决方案
2. 不使用“你应该 / 你要 / 必须”等指令式表达
3. 不否定或压制负面情绪
4. 不喊口号、不追求激励感
5. 每一句话只回应一个情绪需求
---
## 二、基础版 Prompt最常用
> **用途**
>
> * 日常批量生成情绪句子
> * 覆盖约 80% 的内容生产需求
```text
你是一名擅长情绪支持与自我对话的内容创作者。
请基于以下信息生成【23 句】适合 App 单独展示的情绪支持句子。
【主情绪需求】
{{安抚 / 被理解 / 接纳 / 鼓励 / 行动启动 / 希望感}}
【使用场景(如有,可空)】
{{早晨 / 睡前 / 工作中 / 情绪低谷 / 随时}}
【语气要求】
{{温柔 / 中性 / 直接 / 诗性}}
【写作要求】
- 不给建议,不提供解决方案
- 不使用“你应该 / 你要 / 必须”
- 不否定或压制负面情绪
- 不喊口号,不鸡汤
- 更像朋友或内心独白,而不是导师
- 每句话只回应一个情绪
请直接输出 23 句句子,不要解释。
```
---
## 三、场景驱动版 Prompt推荐常用
> **用途**
>
> * 当你更清楚“人在什么状态”
> * 但还没明确要用哪个主情绪标签
```text
你是一名情绪内容创作者。
以下是一种用户可能正在经历的状态:
「{{用一句话描述情绪状态,例如:明明已经很努力,却总觉得不够好}}」
请生成 23 句适合 App 展示的情绪支持句子。
【要求】
- 先理解这个状态在“情绪上最需要的是什么”
- 每句话只回应一个情绪需求
- 不提供建议或解决方案
- 语气自然、克制、真实
- 避免抽象的大道理
请直接输出句子,不要解释你的思考过程。
```
> 生成完成后,需再使用「句子打标签 Prompt」完成结构化入库。
---
## 四、安全增强版 Prompt每日一句 / Push 专用)
> **用途**
>
> * 生成每日一句 / Push / Widget 候选内容
> * 风险最低、最克制
```text
你是一名专注情绪安全的内容创作者。
请生成 12 句【适合每日一句 / Push 通知】的情绪支持句子。
【主情绪需求】
{{安抚 / 接纳 / 希望感(优先)}}
【语气要求】
{{温柔 或 中性}}
【安全规则(必须遵守)】
- 不推动行动,不鼓励“振作”
- 不制造期待或承诺结果
- 不强化依赖关系
- 句子长度适中,单独出现也自然
- 更偏“陪伴”,而不是“改变”
请只输出句子本身,不要任何说明。
```
---
## 五、去鸡汤改写 Prompt质量修正用
> **用途**
>
> * 当生成句子“用力过猛”
> * 不想整句重写时
```text
以下句子在情绪上略显鸡汤或用力过猛,请在不改变核心情绪意图的前提下,改写为更克制、更自然的版本。
【原句】
「{{原句}}」
【要求】
- 保留情绪陪伴感
- 降低说教和鼓动
- 更像内心独白或朋友低声说的话
请给出 12 个改写版本。
```
---
## 六、推荐的实际使用顺序(省力版)
在真实工作流中,建议按以下顺序使用:
1. **场景驱动版 Prompt** → 生成初始句子
2. **基础版 Prompt** → 补充不同语气版本
3. **去鸡汤 Prompt** → 修正不自然表达
4. **句子打标签 Prompt** → 完成结构化入库
---
## 七、内容是否合格的最终自检标准
在句子入库前,请自问:
> **如果用户今天只看到这一句话,
> 会不会觉得被理解,而不是被要求?**
* 是 → 可以入库
* 否 → 删除或重写
---
**本手册建议与《情绪句子个性化推荐系统0-1 设计总览》配合使用。**

View File

@@ -0,0 +1,29 @@
欢迎使用本App情绪推送应用。请仔细阅读以下协议内容
适用范围与接受本协议适用于您下载、安装、登录或使用本App时的全部行为。您在使用本App前应仔细阅读并充分理解本协议的各项条款。一旦您下载、安装或使用本App即表示您已阅读并同意接受本协议的全部内容如果您不同意请立即停止使用。
服务内容本App致力于为宝妈群体提供情绪关怀和正能量内容包括通过定时推送名人励志语句、个性化推荐情绪正向内容等功能。您无需注册或登录即可使用本App可选择提供昵称改善使用体验。通过参与问卷调查和点击操作您可帮助我们了解您的内容偏好以获得更符合您需求的推荐内容。
使用规范:
您承诺遵守中华人民共和国相关法律法规不得利用本App从事任何违法犯罪或侵权行为。
您不得干扰本App的正常运行不得攻击、破坏应用系统或试图绕过使用限制。
您不得未经授权破解、反编译、反向工程、篡改本App软件也不得删除或篡改本App内的任何版权、商标或所有权声明。
本App及其中的素材、内容包括但不限于名人句子、图文等版权归开发者或原作者所有仅供个人学习交流使用。您不得擅自复制、传播、演绎或用于商业目的。若您使用内容时涉及版权问题请自行妥善处理或联系我们协助。
隐私保护本App不要求注册登录也不采集敏感个人信息。您自愿提供的昵称和偏好数据仅用于在本地设备上为您推荐内容不会上传或共享给任何第三方。您可以选择不提供昵称我们的核心功能不会因此受影响。
版权声明本App内所有内容包括界面设计、程序代码、文字、图片、音视频等及软件著作权均归开发者或相关权利人所有受著作权法等法律保护。未经许可任何个人或组织不得以任何形式复制、发行、展示、播发、修改、链接、转载或建立镜像。您仅可在个人使用的前提下使用本App及其内容。
免责声明本App按“现状”和“可用”原则向您提供服务对服务不作任何形式的担保包括但不限于准确性、可靠性或持续可用性。对于因网络故障、通信线路等客观原因导致的应用功能异常或信息延迟我们不承担责任。您使用本App过程中应自行承担风险在法律允许的范围内对于您因使用本App而可能产生的任何直接或间接损失我们不承担责任。
协议的变更和终止:我们保留随时修改、更新本协议条款和/或终止本App运营的权利。如协议条款发生变更我们将在应用更新或官网渠道公布最新协议内容并提示用户注意更新。修改后的协议一经公布即生效您继续使用本App即视为接受修改后的协议。
法律适用和争议解决本协议的订立、生效、解释及争议解决均适用中华人民共和国法律。因本协议或使用本App引起的任何争议双方应友好协商解决协商不成时任何一方均可向开发者所在地有管辖权的法院提起诉讼。
其他本协议与本隐私政策共同构成本App服务的完整规则。若本协议条款与隐私政策存在不一致之处以隐私政策为准。本协议条款标题仅为阅读方便而设不影响条款含义的解释。本协议最终解释权归开发者所有。如您对本协议内容有任何疑问或建议请通过应用商店提供的联系方式与我们联系。
感谢您使用本App我们将持续优化服务体验努力为您提供温暖和支持。

View File

@@ -0,0 +1,21 @@
隐私政策
我们尊重并保护您的隐私。根据《个人信息保护法》《网络安全法》等法律法规的规定,以及 Apple App Store 审核指南要求,我们制定本隐私政策,帮助您了解我们如何收集、使用和保护您的信息:
信息收集:本应用无需注册或登录,也不使用任何第三方授权。用户可自愿提供昵称,仅用于界面展示和个性化服务标识;通过问卷或点击行为记录您的内容偏好(如“喜欢/不喜欢”标签)。我们不会收集您的身份信息、地理位置、通讯录等敏感个人信息。
信息使用:我们仅使用上述收集的信息进行个性化推荐和名人句子定时推送,不用于其他任何目的,不进行广告或营销投放。所有个性化功能均基于您在应用中的操作和偏好生成。
数据存储和安全:所有数据均存储在您设备本地,不上传至服务器;本应用不接入任何第三方 SDK。我们采用系统加密和权限隔离等安全机制保护本地数据防止未经授权的访问。您可以随时通过清除应用数据或卸载应用来删除您的个人信息。
信息共享:我们不会向任何无关第三方提供、出售、出租或分享您的个人信息。未经您明确同意,我们绝不公开您的任何信息,除非法律法规要求或为维护您合法权益所必需。
用户权利与选择:您有权自主决定是否提供个人信息,并可对已提供的信息进行查询、修改或删除。您可以随时在应用中清除偏好设置,或卸载应用以删除所有本地数据。根据法律法规,您还可以通过我们的客服途径要求访问、更正或删除您的信息。
未成年人保护:本应用主要面向成人用户设计,不针对未成年人提供特殊服务。如 18 岁以下用户使用,请在监护人陪同下进行。我们不会在未征得监护人同意的情况下收集或使用未成年人的个人信息。
隐私政策更新:我们可能会根据产品功能变化或法律法规要求更新本隐私政策,并在应用内或相关页面公布最新版本。您继续使用本应用即视为接受更新后的隐私政策。如有重大变更,我们会适当提示您。
我们承诺在此过程中严格遵守相关法律法规和行业标准,切实保护您的个人信息安全。本隐私政策与用户使用协议共同构成本应用合法合规运营的基础。