
react
React is a JavaScript library for building user interfaces with declarative, component-based, and cross-platform design.

A minimal open-source architecture and reference implementation for building an AI reading companion that avoids hallucination, spoilers, and forgetfulness through real text windows, chapter digests, persistent discussion history, and in-page annotations.
35
No data
6
0
MIT
2026-07-05
It directly addresses three core pitfalls of AI reading assistants—fabricating book content, spoiling unread chapters, and losing conversational context—with practical, battle-tested design patterns and a detailed list of real-world issues encountered during development.
一个可以跑起来的最小实现 + 一份思路笔记:怎么让 AI 陪你真的共读一本书—— 不编造书里的内容、不剧透你没读到的章节、记得你们聊过什么、还能在页面上留下它的画线批注。
这不是一个「产品」,是一份参考架构。核心价值在下面的设计思路和防踩坑清单; 代码是能跑的骨架,人设、记忆系统、部署方式都留了接口让你换成自己的。
维护预期:本仓按现状(as is)分享,各自 clone 各自部署,不承诺维护—— issue 和 PR 随缘看,不回复不代表冒犯。它的使命在你读完 README 那一刻就完成了。
npm install
LLM_BASE_URL=https://api.openai.com/v1 \
LLM_API_KEY=sk-xxx \
LLM_MODEL=你的模型 \
node server.js
# 打开 http://localhost:3900/reading 导入一本 epub(请用公版书或你有权使用的书)
任何 OpenAI 兼容端点都行(OpenRouter / DeepSeek / vLLM / Ollama…)。
可选 DIGEST_MODEL 指定一个便宜模型专门做章节摘要。
人设写在 persona.md(已 gitignore,参考 persona.md.example)。
1. AI 没有「读过」这本书——每一轮都要喂真字。
哪怕模型训练时见过这本书,靠印象聊书必然编造细节。解法是每轮把读者正读的真实原文窗口
(选中句 ±300 字)放进上下文,并明确指令「就这段文字本身聊,绝不凭印象补充」。
这是整个系统的地基,做不好其他都白搭。(lib/prompt.js: passageWindow)
2. 「读过全书」用章节摘要索引伪造,而且只造到读者的进度为止。
原文窗口只解决"这一段",聊到前情就抓瞎。给每章用便宜模型生成 ≤120 字脉络摘要(懒生成,
读者翻到哪补到哪),聊天时注入到当前章为止的全部摘要。截止线同时就是防剧透线——
AI"只读到"读者读到的地方,后面的它真的不知道,想剧透都没材料。(lib/digest.js)
3. 讨论历史落库,服务端无状态。 聊天历史存 SQLite(按书为单位,讨论是一条连续的河,不按章节切断),每轮从库里取最近 N 条重建 messages。刷新页面、换章节、服务重启,讨论都续得上。用户消息在生成之前落库—— 生成失败也留痕。
4. 时间感知。
共读历史是以周为单位延续的。system prompt 里每轮带当前时间;距上次讨论超过几小时,
再补一句「距上次聊这本书已过去约 N 天——之前的讨论都是那时候的事」。不然模型会把
三天前的讨论当成十分钟前。(lib/prompt.js: timeAnchor)
5. AI 的批注留在页面上。
聊到好句子,AI 可以在回复末尾用 [批注:原文片段|批注内容] 标记留一条画线批注——
服务端摘出标记、校验原文片段真是本章子串才入库(防编造原文),从回复里剥掉标记。
读者重开这一章,能看见 AI 留下的线。反过来,点开任何一条已有批注也能「聊这条」。
共读因此有了双向的、留得下来的痕迹,而不是聊完就散。
6. 记忆回写:共读不是孤岛。
如果你的 AI 还有其他会话入口(日常聊天/其他界面),读者合上书出去说「我刚读完那章」,
那边的 AI 应该接得住。两层做法(lib/memory.js,默认留接口不实现):
reading/书名 tag 的轻记忆进你自己的记忆系统,靠语义检索被动浮现;res.on('close'),不是 req——
POST 的 req 读完 body 就触发 close,挂错位置心跳当场被拆,还极难排查。data += chunk 等于把 Buffer 隐式转字符串,
一个中文字 3 字节被切在块边界就变 �。流式用 StringDecoder/TextDecoder({stream:true}),
非流式 Buffer.concat 攒齐再解码。回复越长越容易撞上,而共读回复恰恰都长。\n\n)分隔,但网络包不管帧边界——必须自己攒缓冲区再切,
半截 JSON 要静默跳过等下一块。\n 要转义两层(\\n 才能吐出 \n),
一处写错就是静默的前端 bug。浏览器代码放独立静态文件。Read a book together with your AI — grounded in the real text, spoiler-safe, with shared margin notes. 和你的 AI 真正共读一本书。
Similar projects matched by category, topics, and programming language.

React is a JavaScript library for building user interfaces with declarative, component-based, and cross-platform design.
A GPT‑image powered app that extracts individual garment cutouts from photos, organizes them into a digital wardrobe, and generates modeled outfit previews.
A browser-based first-person shooter built entirely with procedural generation and orchestrated AI agents, featuring 55k lines of Three.js/WebGL2 code and no art assets.