Skip to content

worldwonderer/chat-simulator

Repository files navigation

Chat Simulator · 中文聊天剧情模拟器

像刷即时通讯软件一样和角色聊天,每个选择都会改变剧情,最终通向不同结局。

CI License: MIT Next.js Live Demo

▶ 在线演示:https://chat.vibecoco.ai/

玩家在拟真的手机聊天界面里做选择,AI 会在原剧本台词的基础上重写出更自然的回复,但剧情走向、数值和结局始终由脚本控制。后端用 Next.js 接口路由把 DeepSeek 请求代理到服务端。

截图

首页 取名页
首页截图 取名页截图
聊天玩法 结局页
聊天玩法截图 结局页截图

功能特性

  • 拟真的手机聊天体验:消息气泡、打字状态、系统时间提示,玩起来像真的在和人对话。
  • 选择驱动的分支剧情:每个回复都会牵动好感与焦虑数值,导向不同结局。
  • 多角色随机开局:首页从角色池里随机抽人,每局都是不同剧本。
  • AI 让对话更自然:角色台词由 AI 结合人设和上下文重新组织,比照搬剧本更像真人;同时剧情走向和结局判定保持稳定,生成失败时无缝回退到原台词,不会卡住。

技术栈

技术
前端 Next.js 16(App Router)· React
后端 Next.js Route Handlers(app/api/*
AI DeepSeek(deepseek-v4-flash),经服务端代理调用
数据 JSON 剧情 / 角色 / 章节 / 话术(data/
部署 Vercel

架构

浏览器界面
  └─ POST /api/ai/chat        # 只传有限上下文
       └─ 服务端 DeepSeek 代理  # 鉴权、白名单、限流、超时
            └─ https://api.deepseek.com/chat/completions

密钥只作为服务端环境变量存在,不会下发到浏览器,也不要加 NEXT_PUBLIC_* 前缀。

快速开始

前置要求

  • Node.js 20+(CI 在 Node 22 上验证)
  • 一个 DeepSeek API Key

本地开发

npm install
cp .env.example .env.local
# 在 .env.local 中填写 DEEPSEEK_API_KEY
npm run dev

生产构建

npm run build
npm run start -- --port 4180

环境变量

本地最少只需配置 DEEPSEEK_API_KEY,其余项都有默认值:

变量 必填 默认值 说明
DEEPSEEK_API_KEY 仅服务端使用,切勿加 NEXT_PUBLIC_ 前缀。
DEEPSEEK_MODEL deepseek-v4-flash 代理使用的模型。
DEEPSEEK_BASE_URL https://api.deepseek.com 必须为 HTTPS。
DEEPSEEK_TIMEOUT_MS 8000 上游超时(毫秒)。
APP_PUBLIC_URL / AI_ALLOWED_ORIGINS 推荐 生产环境仅放行生产域名 接口来源白名单。

限流与请求体限制等完整运维项见 docs/production.md

验证

提交前运行与 CI 一致的完整校验:

make verify          # 等价于 npm run verify

也可单项执行:

make verify-repo     # python3 scripts/check_repository.py,结构与数据链接检查
make verify-ai       # npm run verify:ai,关键路径集成测试
make build           # npm run build
make verify-visual   # python3 scripts/verify_visual_baseline.py
npm audit --omit=dev # 依赖变更时

verify:ai 用模拟的 DeepSeek 请求覆盖生产关键路径:接口地址、模型名称、鉴权来源、关闭思考模式、来源白名单、请求体大小限制、玩家自定义姓名上下文和 /api/health 健康检查。

目录结构

.
├── app/                   # Next.js 页面与 API 路由
│   ├── api/ai/chat/       # DeepSeek 服务端代理
│   └── api/health/        # 健康检查接口
├── components/
│   ├── ChatSimulator.jsx  # 顶层组件
│   └── chat/              # 界面、剧情引擎、状态与运行时
├── data/                  # 剧情、角色、章节、话术数据
├── lib/ai/deepseek.js     # DeepSeek 服务端客户端
├── docs/                  # 部署、开源说明与 README 截图
├── public/                # 头像、图标与静态资源
└── scripts/               # 仓库 / AI / 视觉验证脚本

添加剧本

新增剧本通常涉及这些文件:

  • data/girls.json — 角色
  • data/scenes.json — 剧情节点
  • data/chapters.json — 仅章节结构变化时
  • public/ — 角色图片

首页会从 data/girls.json 中随机抽取角色,所以接好 firstScene 后新角色会自动进入随机池。

1. 添加角色

"yue": {
  "id": "yue",
  "name": "岳宁",
  "avatar": "/yue.png",
  "tags": ["段位:三星", "标签1", "标签2"],
  "description": "一句简介",
  "firstScene": "yue_scene_01"
}

头像放在 public/yue.png

2. 添加剧情树

data/scenes.json 中追加节点,建议用独立前缀(如 yue_):

{
  "id": "yue_scene_01",
  "chapter": 1,
  "title": "初见",
  "timeLabel": "周三 晚上 20:10",
  "messages": [
    { "id": "s1", "sender": "system", "content": "[TIME] 周三 晚上 20:10", "delay": 400 },
    { "id": "m1", "sender": "her", "content": "你好呀" }
  ],
  "choices": [
    {
      "id": "a",
      "label": "A",
      "text": "你好",
      "replyText": "你好",
      "affectionDelta": 2,
      "anxietyDelta": 0,
      "nextScene": "yue_scene_01_ans_a",
      "badgeText": "礼貌"
    }
  ]
}

剧情推进有两种方式:choices[].nextScene(玩家选择后跳转)或 autoNext(节点结束后自动跳转)。

3. 优先使用显式结局数据

最稳妥的做法是在结局节点直接写 endingData,无需改 JavaScript:

{
  "id": "yue_ending_good_01",
  "chapter": 6,
  "messages": [
    { "id": "s1", "sender": "system", "content": "你终于看清了。" }
  ],
  "isEnding": true,
  "endingType": "good",
  "endingData": {
    "title": "清醒结局:及时止损",
    "desc": "结局描述..."
  }
}

如果省略 endingData 并想复用随机结局池,需要同时更新 components/chat/endingPools.jscomponents/chat/gameEngine.js,否则新前缀不会映射到预期结局池。

文档

贡献

欢迎提交 Issue 和 PR。提交前请运行 make verify,并阅读 CONTRIBUTING.md 了解改动约定。

许可

本项目基于 MIT 许可证 开源。

Releases

No releases published

Packages

 
 
 

Contributors