{"id":51064241,"url":"https://github.com/chenxuan520/mystery","last_synced_at":"2026-06-23T05:01:11.648Z","repository":{"id":365732125,"uuid":"1272425532","full_name":"chenxuan520/mystery","owner":"chenxuan520","description":"本地可玩的悬疑推理游戏原型，含 Web、Admin、案件生成与归档","archived":false,"fork":false,"pushed_at":"2026-06-18T15:26:34.000Z","size":203,"stargazers_count":0,"open_issues_count":0,"forks_count":0,"subscribers_count":0,"default_branch":"master","last_synced_at":"2026-06-18T17:23:46.201Z","etag":null,"topics":["mystery-game","nodejs","openai-compatible","sqlite","typescript"],"latest_commit_sha":null,"homepage":null,"language":"TypeScript","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":null,"status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/chenxuan520.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":null,"code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null,"zenodo":null,"notice":null,"maintainers":null,"copyright":null,"agents":"AGENTS.md","dco":null,"cla":null}},"created_at":"2026-06-17T15:43:13.000Z","updated_at":"2026-06-18T15:26:57.000Z","dependencies_parsed_at":null,"dependency_job_id":null,"html_url":"https://github.com/chenxuan520/mystery","commit_stats":null,"previous_names":["chenxuan520/mystery"],"tags_count":null,"template":false,"template_full_name":null,"purl":"pkg:github/chenxuan520/mystery","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/chenxuan520%2Fmystery","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/chenxuan520%2Fmystery/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/chenxuan520%2Fmystery/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/chenxuan520%2Fmystery/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/chenxuan520","download_url":"https://codeload.github.com/chenxuan520/mystery/tar.gz/refs/heads/master","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/chenxuan520%2Fmystery/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":34675974,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-05-26T15:22:16.424Z","status":"online","status_checked_at":"2026-06-23T02:00:07.161Z","response_time":65,"last_error":null,"robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":true,"can_crawl_api":true,"host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["mystery-game","nodejs","openai-compatible","sqlite","typescript"],"created_at":"2026-06-23T05:01:10.662Z","updated_at":"2026-06-23T05:01:11.642Z","avatar_url":"https://github.com/chenxuan520.png","language":"TypeScript","funding_links":[],"categories":[],"sub_categories":[],"readme":"# 悬疑推理游戏原型\n\n一个本地可运行的悬疑推理游戏原型，当前以 Web 为主，CLI 作为补充入口。\n\n它会：\n\n- 生成一桩结构化案件\n- 让你调查固定线索节点\n- 让你和多个嫌疑人对话\n- 让嫌疑人回答以流式方式逐步出现\n- 支持最终指认真凶并查看真相还原\n- 对合格案件做归档，方便后续反复试玩\n\n## 当前形态\n\n- 浏览器可玩的本地 Web 游戏\n- 独立的 `/admin` 管理后台\n- 仍保留 CLI 入口\n- SQLite 本地存档（案件与会话状态）\n- OpenAI-compatible 接口\n- 案件生成 + 案件评审双模型链路\n- 合格案件自动归档到 `data/approved-cases/`\n- 逐条聊天原文默认不再写入 SQLite\n- 场景图 / 角色头像 SVG 为运行时生成，不默认写入 SQLite / 归档 JSON\n- 嫌疑人 / NPC 对话时会拿到完整案件上下文（世界观、全部人物、调查节点、自身见闻与对话目标），避免角色凭空编造不存在的人或线索\n\n## 安装\n\n```bash\nnpm install\n```\n\n## 配置\n\n### 方式 1：直接用 `.env`\n\n复制一份配置：\n\n```bash\ncp .env.example .env\n```\n\n至少配置：\n\n- `OPENAI_BASE_URL`\n- `OPENAI_API_KEY`\n- `OPENAI_MODEL`\n\n### 方式 2：显式使用本地 AI presets（可选）\n\n项目支持通过 YAML presets 显式指定生成模型和评审模型。\n\n注意：**项目默认不会依赖任何仓库外的配置文件**。\n\n如果你确实想用 presets，请自己准备一个本地文件，例如：\n\n```text\nconfig/ai-presets.local.yaml\n```\n\n仓库里提供了结构示例：\n\n`config/ai-presets.example.yaml`\n\n然后显式设置：\n\n```bash\nAI_PRESET_PATH=config/ai-presets.local.yaml\nCASE_GENERATOR_PRESET_ID=deepseek-v4-pro\nCASE_REVIEWER_PRESET_ID=deepseek-v4-pro\n```\n\n可通过环境变量覆盖：\n\n- `AI_PRESET_PATH`\n- `AI_PRESET_ID`\n- `CASE_GENERATOR_PRESET_ID`\n- `CASE_REVIEWER_PRESET_ID`\n\n如果你准备使用管理后台做模型切换，建议在 `AI_PRESET_PATH` 里放多组 presets，后台会把这些 preset 作为可切换选项展示出来。\n\n### 管理后台账号（必配，启用 admin 时）\n\n管理后台的登录账号密码走本项目本地环境变量：\n\n```bash\nADMIN_USERNAME=admin\nADMIN_PASSWORD=change_me\n```\n\n不配置这两个字段时，`/admin` 仍可打开，但会提示后台未启用。\n\n### Web 语音输入（可选）\n\nWeb 版对话框支持“语音转文字”。\n\n- **没配火山 ASR 时，语音输入按钮不会显示**\n- 配好后，识别结果会在录音过程中**持续流式写进聊天输入框**，但**不会自动发送**\n- 凭证仍然只放在本项目本地配置里，不会下发到浏览器\n\n在 `.env` 里补上：\n\n```bash\nVOICE_INPUT_CONFIG_PATH=/Users/yourname/.config/opencode/voice2text.local.json\nVOICE_INPUT_APP_ID=your_volcengine_app_id\nVOICE_INPUT_ACCESS_TOKEN=your_volcengine_access_token\nVOICE_INPUT_RESOURCE_ID=volc.seedasr.sauc.duration\nVOICE_INPUT_ENDPOINT=wss://openspeech.bytedance.com/api/v3/sauc/bigmodel_async\nVOICE_INPUT_LANGUAGE=zh-CN\nVOICE_INPUT_CHUNK_MS=200\nVOICE_INPUT_END_WINDOW_SIZE=800\nVOICE_INPUT_MAX_DURATION_SECONDS=180\n```\n\n如果你手头已经有 opencode 语音插件那套火山配置，推荐直接显式设置 `VOICE_INPUT_CONFIG_PATH=/Users/你的用户名/.config/opencode/voice2text.local.json` 复用现成本地文件；也兼容旧字段名 `OPENCODE_VOICE2TEXT_*`。项目不会在没有显式配置的情况下自动去找这份全局文件。\n\n## 运行\n\n### 推荐：Web 版\n\n```bash\nnpm run web\n```\n\n默认地址：\n\n```text\nhttp://127.0.0.1:3001\n```\n\n如需改端口：\n\n```bash\nWEB_PORT=3010 npm run web\n```\n\nWeb 版支持：\n\n- 点击式调查\n- 点击式嫌疑人 / NPC 切换\n- 出示已调查线索向嫌疑人 / NPC 当面对质，对方会针对这条具体证据辩解、露破绽或反咬\n- 指认时需要勾选支撑线索并写下推理，系统会按你是否真的推到关键矛盾给出“破案评分”\n- 误判会得到真凶脱身 / 冤枉他人的剧情后果，指认正确则给出落网收尾\n- 提示官问答与渐进式提示\n- 结案后可直接在结果页继续向提示官追问真相细节，且这段复盘问答会和左侧提示官普通聊天分开记忆\n- 浏览器聊天输入\n- 当前会话的聊天视图会缓存到浏览器本地，刷新后可恢复\n- 顶部工具条支持清空本地聊天缓存\n- 关键操作使用站内确认弹窗，而不是浏览器原生 confirm\n- 对话框语音转文字（已配置时显示，识别结果流式回填）\n- NPC 流式回复\n- 案发场景、人物头像的 SVG 展示\n- 双击 SVG 可放大查看\n- 玩家界面不再直接生成案件，新增案件交给管理后台处理\n\n### CLI 版\n\n开发模式：\n\n```bash\nnpm run dev\n```\n\n构建后运行：\n\n```bash\nnpm run build\nnode dist/src/index.js\n```\n\n## 怎么玩\n\n### Web 版\n\n推荐直接用浏览器玩。\n\n启动后：\n\n- 点击归档案件直接重玩历史好案，或继续最近一局\n- “继续最近一局”只认当前浏览器 local cache 里那一局；如果这台浏览器本地没有缓存，就不会替你去服务端猜一局\n- 如果归档列表里出现的就是当前这局对应的那份归档，它会标成“当前这局”，点它会直接继续当前这局，而不会额外新开一局\n- 游戏页顶部可直接返回开始页或导出当前案件 JSON\n- 左侧点调查节点看线索\n- 左侧点嫌疑人、相关人物或提示官进入对话\n- 在聊天框里追问嫌疑人；如果已配置语音输入，也可直接点“语音输入”边说边把文字流式回填进输入框，再自己确认发送\n- 查到线索后，可在嫌疑人 / NPC 对话页用“出示线索对质”把某条已发现线索甩到对方脸上，逼他正面回应这条证据\n- 点击“指认某人”后会弹出指认表单：勾选你依据的线索、写下推理，再提交；结案页会给出破案评分、点评，以及指认对错对应的剧情结局\n- 如果你对背景设定、公开信息或已发现线索的理解不确定，可以直接问提示官；只有你明确说自己卡住了、或者直接要提示时，他才会渐进式推你一小步\n- 结案或直接看答案后，如果你对真相里的某个细节还没看懂，可以直接在结果页继续问提示官，他会按已揭晓真相直接解释原因链条；这段复盘问答会和左侧提示官的普通聊天分开记忆\n- 刷新页面后，当前这局与当前聊天对象会优先从浏览器本地缓存恢复；如果当时停在结果页里的提示官复盘追问，也会按独立会话一起恢复；如果你不想保留，顶部可点“清空本地缓存”\n- 当前逐条聊天原文默认只保留在浏览器本地缓存里，请求模型时会由前端把当前角色的历史对话一并带上；服务端 SQLite 不再保存这些逐条聊天原文\n- 点击“指认某人”完成结案\n\n### Admin 后台\n\n管理后台地址：\n\n```text\nhttp://127.0.0.1:3001/admin\n```\n\n当前支持：\n\n- 登录鉴权（账号密码来自本项目本地环境变量）\n- 只管理**归档案件**\n- 删除归档案件\n- 按模板生成新案件并归档\n- 切换玩家 / 生成 / 评审模型（来自 `AI_PRESET_PATH` 中的 presets）\n- 生成失败时会在后台顶部显示明显的失败提示，方便直接重试或换模型\n- 失败生成记录会持久化到 SQLite，后台会显示最近一次已落库失败记录\n\n注意：玩家界面不再提供“生成新案件”入口。\n\n### CLI 版\n\n启动后会看到开始菜单：\n\n- 生成新案件\n- 从归档案件开始\n- 退出\n\n如果你想直接试玩已经通过质量门禁的案件，选：\n\n```text\n从归档案件开始\n```\n\n进入案件后主菜单包括：\n\n- `1` 查看调查节点\n- `2` 询问角色（嫌疑人 / 相关人物 / 提示官）\n- `3` 查看角色档案\n- `4` 查看已知线索\n- `5` 指认真凶\n- `6` 重新查看案件摘要\n- `7` 保存并退出\n\nCLI 同样支持新的玩法：\n\n- 询问嫌疑人 / 相关人物时，只要你已经查到过线索，就可以选择“出示线索对质”，把某条线索甩到对方脸上，逼他正面解释\n- 指认真凶时会让你先写一句推理，然后由模型给出“破案评分”、点评，以及指认对错对应的剧情结局（误判会看到真凶脱身等后果）\n\n说明：CLI 的对话上下文现在只保留在当前进程内，用于维持这一局里的连续追问；退出 CLI 后，逐条聊天原文不会继续写入 SQLite，也不会像 Web 那样有浏览器本地恢复。\n\n推荐顺序：\n\n1. 先看嫌疑人档案\n2. 调查 2~3 个线索节点\n3. 回到已知线索页整理疑点\n4. 再去盘问嫌疑人\n5. 继续补调查后再指认\n\n## 归档案件\n\n所有通过门禁和模型评审的案件都会保存到：\n\n```text\ndata/approved-cases/\n```\n\n这些案件会保存：\n\n- 案件 JSON\n- 评审分数\n- 生成诊断信息\n- 模型来源信息\n\n你可以随时从 CLI 菜单重新载入它们。\n\n## 案件质量链路\n\n当前不是“生成一次就直接开玩”，而是：\n\n1. 生成结构化案件\n2. 跑确定性复杂度门禁\n3. 跑大模型案件评审\n4. 合格才归档\n\n所以高质量案件通常会比普通聊天生成更慢一些。\n\n## 当前支持的案件模板\n\n- `locked-room`：封闭场景谋杀\n- `alibi`：不在场证明案\n- `poison`：投毒案\n- `staged-suicide`：伪自杀案\n- `inheritance`：遗产争夺案\n- `body-relocation`：移尸案\n- `blackmail`：勒索灭口案\n- `cold-case`：旧案牵连案\n- `identity-fraud`：身份伪装案\n\n## Harness\n\n批量验证案件质量：\n\n```bash\nnpm run harness:cases -- --count=1\n```\n\n常用参数：\n\n- `--count=3`：生成几局\n- `--template=poison`：指定模板（也可用 `locked-room` / `alibi` / `staged-suicide` / `inheritance` / `body-relocation` / `blackmail` / `cold-case` / `identity-fraud`）\n- `--output=/tmp/report.json`：输出报告\n- `--archive-dir=data/approved-cases`：指定归档目录\n- `--generator-preset=deepseek-v4-pro`：覆盖生成模型 preset\n- `--reviewer-preset=deepseek-v4-pro`：覆盖评审模型 preset\n\nHarness 会：\n\n- 打印当前生成模型和评审模型\n- 实时显示每局进度\n- 为合格案件归档\n- 输出 JSON 报告\n\n## 常用命令\n\n```bash\nnpm run build\nnpm test\nnpm run web\nnpm run dev\nnpm run harness:cases -- --count=1\n```\n\n## 目录说明\n\n- `src/cli/`：CLI 主循环\n- `src/case/`：案件 schema、模板、生成、质量门禁、评审\n- `src/chat/`：角色对话、提示官与对话记忆\n- `src/judgement/`：结案判定与复盘\n- `src/session/`：SQLite 存档与会话状态\n- `src/voice/`：火山语音转文字接入\n- `src/archive/`：合格案件归档\n- `src/harness/`：批量生成与评估\n- `src/web/`：浏览器版服务端与静态页面\n- `tests/`：自动化测试\n- `data/approved-cases/`：归档后的合格案件\n\n## 当前已知情况\n\n- 高复杂度案件的生成耗时仍然偏高\n- 模型输出偶尔仍会波动，但现在已有门禁和评审兜底\n- 归档案件已经支持直接重玩\n- preset 支持是**显式 opt-in**，项目默认不依赖任何其他仓库配置\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fchenxuan520%2Fmystery","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fchenxuan520%2Fmystery","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fchenxuan520%2Fmystery/lists"}