24 Commits
Author SHA1 Message Date
gavindiazandClaude Code 0ca4fcce65 docs: 更新/重写项目文档(README / 部署手册 / 前端说明)
- README.md:补充原生分页 / 连续选取 / 摘录高亮说明;阅读位置改为
  服务端跨设备同步(不再是「当前浏览器保存」);补「第二大脑」助手
  与模型管理入口;验证命令改为 venv 内 python
- deploy/README.md:修正 git clone 后的实际目录结构;新增第 8 节
  「历史遗留数据清理」(clean_orphans 脚本 + 启动迁移自动清理),
  并在常见问题里补跨设备位置 / 删书不彻底 / 脚本 ModuleNotFound 等
- frontend/README.md:整体重写,去掉 create-next-app 模板残留
  (Vercel / Geist),改为项目真实结构 / 模块说明 / 本地开发 / 构建
- 删除 backend/AGENTS.md:Next.js 自动生成的残留块,backend 目录为
  FastAPI 项目、无 node_modules/next,删除避免误导(frontend 那份保留)

Co-Authored-By: Claude Code <noreply@anthropic.com>
2026-10-27 22:30:22 +08:00
gavindiazandClaude Code 281e31511c fix: clean_orphans 加包 __init__.py,python -m 才能导入
app/scripts 目录缺少 __init__.py,导致容器里
`python -m app.scripts.clean_orphans` 报 ModuleNotFoundError。

Co-Authored-By: Claude Code <noreply@anthropic.com>
2026-10-27 22:17:29 +08:00
gavindiazandClaude Code 3e8b21f99c feat: 清理删除书籍遗留的孤儿数据(DB 行 + uploads 文件)
历史版本删书时因 file_path 存 Windows 相对路径 + SQLite 外键未强制开启,
会残留无主 DB 行和 uploads 下的孤儿 EPUB 文件。

- 新增 app/scripts/clean_orphans.py:只删 book_id 指向不存在书籍的行
  (segments/chapters/reading_notes/reading_progress/conversations/messages)
  和 uploads 下无书籍记录的 *.epub 文件,现存的书籍/笔记/对话/模型/MCP
  一律不动;幂等可重跑,缺新表自动跳过,清完 VACUUM 缩库
- 启动迁移(_migrate)同样按外键清理孤儿行并探测表存在性,旧库缺表不崩

Co-Authored-By: Claude Code <noreply@anthropic.com>
2026-10-27 22:14:01 +08:00
gavindiaz 956323007d fix: 删书彻底清理文件与DB + 阅读位置跨设备同步
删除不彻底的根因是库里 file_path 存了旧 Windows 相对路径(uploads\xxx.epub),Linux 容器里 os.path.exists 永远为假:

- 新增 _upload_file() 归一化路径(取文件名挂到当前 uploads 目录),读/删都走它,老库迁移的文件也能定位;文件删除挪到后台任务,失败不影响接口

- 删除后对 SQLite 执行 VACUUM,让 db 文件真正缩小

- 删除时一并清理 reading_progress

阅读位置原来只存 localStorage,换设备丢失:

- 新增 reading_progress 表 + GET/PUT /books/{id}/progress 接口

- 前端打开时优先取服务端位置(本地兜底并双端拉齐),翻页防抖同步到服务端,关闭时把防抖窗口内的最后一页立即刷上去
2026-10-27 21:42:04 +08:00
gavindiazandClaude Code 5febc02099 fix: 阅读器改回 epubjs 原生分页 + 首渲重试 + 连续选取开关
scrolled-doc 对大书不稳(依赖点目录、下一页只在框内、卡死),且一次性
渲染大量章节导致 about:srcdoc / unload 报错刷屏。改回原生分页:

- renderTo 用 default manager + flow paginated + spread none,只渲染当前页
- 翻页回到 rendition.prev()/next(),用 relocated 的 atStart/atEnd 控按钮
- 阅读位置从 scrollTop 改为 location.start.cfi 持久化;兼容旧的数字/JSON 格式
- 保留首渲重试:display 后轮询 iframe 正文,3 次失败才报「正文渲染失败」
- 新增「连续选取」开关:flow scrolled-doc ⇄ paginated,按当前 CFI 重定位,
  连续模式下翻页先滚视口、到边界再翻章节
- 导航防卡死:display/prev/next 加 8s 超时,失败后复位 epubjs 队列,
  并在跳转前用 spine.get 校验目标,避免过期 CFI 把队列拖死
- .epub-viewport 改 overflow hidden,分页滚动交给内部 .epub-container

Co-Authored-By: Claude Code <noreply@anthropic.com>
2026-10-27 00:54:19 +08:00
gavindiazandClaude Code a2fba4fd28 fix: 位置/翻页/高亮彻底改法(scrolled 下不再依赖 epubjs location)
根因:scrolled 模式用的 continuous manager 根本没有 currentLocation 方法,
rendition 的 relocated/currentLocation 永不触发 → 位置从未保存、prev/next
因 !location 恒为禁用、footer 章节名永远为空。

- 位置:改为直接操作滚动容器——滚动时防抖保存 scrollTop,渲染完成后 set
  scrollTop 恢复;兼容旧格式;去掉对 relocated/location 的全部依赖
- 翻页:prev/next 不再被 !location 卡死,恒定按视口高度滚动
- 高亮颜色:SVG rect 用低不透明度浅色(0.4),去掉无效的 mix-blend,
  不再像一层膜盖住文字;删除同步改 annotations.remove(cfi, "highlight")
  (第二参数是类型不是 className,传错 hash 匹配不上删不掉)
- 笔记输入框升级为带标签的多行 textarea,移入样式、焦点态与移动端适配

Co-Authored-By: Claude Code <noreply@anthropic.com>
2026-10-26 19:39:58 +08:00
gavindiazandClaude Code a373940bd5 fix: 高亮真正的根因(dataset 键非法)+ 位置双保险
用户控制台暴露根因:epubjs annotations.highlight 内部执行
mark.dataset["data-note-id"]=... ,键含连字符导致 DOMStringMap 属性名非法,
抛 SyntaxError 被 catch 吞掉 → 高亮从未真正画上,静默失败。
改为合法键 noteId(自动映射 data-note-id 属性),highlight/remove 均生效。

位置:保存 {cfi, scrollTop},恢复时 display(cfi) 后再强制 set scrollTop,
不依赖 epubjs cfi 滚动的精确性;兼容旧格式纯 cfi。

Co-Authored-By: Claude Code <noreply@anthropic.com>
2026-10-26 18:46:35 +08:00
gavindiazandClaude Code ce708a2298 fix: 阅读器改回连续滚动模式 + 首渲竞态兜底 + 取消选择
上版切到 paginated 后,epubjs 首次 display 存在偶发竞态(视图未创建 → 打开空白,
点目录后才恢复)。改回 scrolled-doc(内容渲染可靠,跨页选取天然可用):
- 上一页/下一页改为按视口高度滚动(scrolled 无原生页码),不再失效
- 打开时先渲染并轮询确认视图真的创建(最多重试 3 次),再跳转保存位置
- 选中文字后新增「取消选择」按钮,可清掉误选

高亮、位置记忆沿用上一版修复(ref 实时重画 / 去掉恢复覆盖)。

Co-Authored-By: Claude Code <noreply@anthropic.com>
2026-10-26 18:24:36 +08:00
gavindiazandClaude Code 379e7a3b0b fix: 阅读全书三处问题(翻页/高亮标记/位置记忆)
1. 翻页 + 跨页选取:默认回到 paginated 翻页模式(epubjs 原生 next/prev,不再失效),新增「连续选取」开关临时切到 scrolled-doc 跨页跨章选文字,切回翻页时 epubjs 自动回到原位置;连续模式下 prev/next 改为按视口高度滚动
2. 高亮不留标记:旧实现用「打开时的快照」画高亮,新建的高亮翻页/滚动回来就消失。改为 ref 实时维护高亮列表,每次内容渲染都重画;保存高亮就地标注,不再 display() 跳转打断阅读
3. 位置不记住:去掉恢复后 currentLocation() 覆盖已存位置的逻辑(scrolled 下恢复未命中会把错误位置写回,导致每次打开都从头开始);位置改由 relocated 事件在正常翻页/滚动时自动保存

Co-Authored-By: Claude Code <noreply@anthropic.com>
2026-10-26 17:24:02 +08:00
gavindiaz 946ffc75cb Improve EPUB reading experience 2026-10-26 15:41:10 +08:00
gavindiaz 520fa3f185 fix: preserve EPUB text selection 2026-10-26 15:16:58 +08:00
gavindiaz 83dc040e1d feat: add EPUB reading notes and highlights 2026-10-26 15:02:36 +08:00
gavindiazandClaude Code 64df54ad55 fix: 删书即删对话——清理已删除书籍遗留的孤儿对话
根因:Conversation 与 Book 无 ORM 级联关系,且 SQLite 外键未强制开启,
delete_book 只删书/章节/段落,书的对话变成孤儿残留(book_id 指向不存在的书),
前端确认文案「书、目录和对话都会被删除」与事实不符,AI 助手会把这些幽灵
对话当作阅读记录。

- books.py delete_book: 显式删除该书的全部对话(消息经 ORM cascade 一并删)
- database.py _migrate: 启动时清理孤儿对话及其消息(book_id 不在 books 表内;
  assistant 全局对话 book_id 为空不受影响),幂等,本地/服务器下次启动即生效

Co-Authored-By: Claude Code <noreply@anthropic.com>
2026-10-25 17:46:24 +08:00
gavindiazandClaude Code f63c0c55c9 feat: Docker 化部署(nginx-proxy-manager 反代,单域名 /api 路由)
- docker-compose.yml: backend + frontend 两服务,挂 NPM 所在外部网络、不暴露宿主端口;
  data/uploads 用 bind mount 持久化(deploy/ 下,gitignored)
- backend/Dockerfile: python:3.12-slim + 清华 PyPI 镜像(ARG 可覆盖)
- frontend/Dockerfile: 多阶段 node:22 + npm ci + next build(NEXT_PUBLIC_API_BASE 构建期
  注入,npmmirror 默认)→ next start
- .env.example: 全量部署环境变量模板(compose 替换变量 + 后端密钥)
- deploy/README.md: 服务器部署手册(NPM 配置 / DNS / 数据迁移 / 运维 / 大陆网络)

Co-Authored-By: Claude Code <noreply@anthropic.com>
2026-10-25 15:35:20 +08:00
gavindiazandClaude Code 8f9957ad9b chore: 压掉启动时的两类无害警告
- backend: AddModelRequest/UpdateModelRequest 关闭 pydantic protected_namespaces,
  消除 model_id 字段名的启动 UserWarning
- frontend: 显式设置 turbopack.root(用 process.cwd(),Node 原生 TS 下 ESM 加载
  使 __dirname 不可用),消除 package-lock.json 在 Git 仓库外被忽略的警告

Co-Authored-By: Claude Code <noreply@anthropic.com>
2026-10-25 13:57:06 +08:00
gavindiazandClaude Code bbf4cebd90 fix: 优雅停机时主动 dispose 连接池,消除 SQLite 后台连接被 GC 丢弃的 SAWarning
Ctrl+C 停服时 aiosqlite 后台线程上的连接若未归还池会被 GC 直接丢弃,
表现为 shutdown 时的 non-checked-in connection SAWarning。在 lifespan 关闭
阶段调用 engine.dispose() 主动清理(数据不受影响,纯停机噪音修复)。

Co-Authored-By: Claude Code <noreply@anthropic.com>
2026-10-25 03:28:49 +08:00
gavindiazandClaude Code 2cda214170 feat: 全局「第二大脑」AI 助手(跨书跨对话 + bm_* 工具 + DSML 兜底)
- Conversation 加 kind(book/assistant)、book_id 可空;SQLite 老表迁移保留数据
- rag/engine.py: search_all_books 跨书混合检索;citations 带 book_title 出处
- app/assistant/service.py: 知识库概览 + 第二大脑 persona + 原生工具
  (bm_list_conversations / bm_read_conversation / bm_search_books),并入 MCP agent 循环
- chat.py: create/list 支持 kind;send_message 委托助手管线
- llm/hub.py: 解析 DeepSeek DSML 文本工具调用(模型非确定性输出标准/DSML)
- mcp/agent.py: 工具轮中段追加强制文本收尾,防模型反复调工具不出答案
- 前端: 侧栏「AI 助手」入口 + 抽取共享 ChatPanel 复用书/助手两套对话 UI

Co-Authored-By: Claude Code <noreply@anthropic.com>
2026-10-25 03:21:22 +08:00
gavindiazandClaude Code fcdc3d4f93 feat: 站点访问密码登录(SITE_PASSWORD)+ 退出登录按钮
- 后端:新增 /api/auth/login 与 /api/auth/status;HMAC 签名令牌 30 天有效、
  服务重启不失效;设置 SITE_PASSWORD 后中间件拦截除登录/健康检查/CORS 预检
  外的所有 /api/*,未启用密码时行为不变(本地开发默认开放)
- 前端:AuthGate 登录层 + BookMate 风格全屏登录页(墨绿卡片、轨道环、书标金句);
  令牌存 localStorage 随请求带 X-Access-Token 头,401 自动清令牌重新弹出登录页;
  侧栏底部新增「退出登录」按钮(仅在启用密码时显示)
- 认证通过后才挂载主应用,避免未登录先发起数据请求

Co-Authored-By: Claude Code <noreply@anthropic.com>
2026-10-25 00:18:46 +08:00
gavindiazandClaude Code 7f731abb17 feat: 前端后端地址改为 NEXT_PUBLIC_API_BASE 可配置,补全 .env.example
- 部署到云服务器后浏览器不能再连 localhost:8000,API_BASE 现可经
  NEXT_PUBLIC_API_BASE 指定(未设置时保持本地默认值,行为不变)
- .env.example 补全数据库/监听端口/各 provider/向量与重排的完整变量

Co-Authored-By: Claude Code <noreply@anthropic.com>
2026-10-24 19:38:44 +08:00
gavindiazandClaude Code db3c720b78 fix: 导出 flowchart 前把标签中的 ASCII 引号替换为弯引号
老版 mermaid 的 flowchart 解析器不认 ["...\\"..."] 转义,标签里的英文
双引号会把字符串截断导致 Parse error(如 "产生\"关于数字\"的算术意义")。
现把标签内的 " / ' 交替替换为弯引号(“”/‘’),反斜杠转斜杠、# 转全角,
老版阅读器即可正常渲染且保留原语义。

Co-Authored-By: Claude Code <noreply@anthropic.com>
2026-10-24 19:27:58 +08:00
gavindiazandClaude Code 183d77681c fix: 导出文档时把 mermaid mindmap 转成 flowchart LR,外部阅读器清晰可读
- 老版 mermaid 渲染 mindmap 是根居中放射状、粗彩线,外部阅读器里很难读
- 导出接口现把 ```mermaid mindmap 块转换为 flowchart LR 树状图,网页样式不受影响
- 支持 root(( )) 关键字、形状符号、::icon() 与行尾注释的清理

Co-Authored-By: Claude Code <noreply@anthropic.com>
2026-10-24 18:51:58 +08:00
gavindiazandClaude Code 8cd390b3ed feat: 接入 MCP 外部工具服务,AI 可调用外部工具获取书外信息
- 后端新增 MCP 客户端(Streamable HTTP / 老式 SSE)与流式 agent 工具循环
- 新增 /api/mcp/servers 管理接口与 mcp_servers 表
- 对话中 OpenAI 兼容模型可调用启用服务器的工具,SSE 推送 tool 事件
- 前端新增 MCP 服务管理弹窗与侧栏入口,流式回答展示工具调用状态
- 修复用户消息气泡缺少删除按钮,并级联删除其名下回答版本

Co-Authored-By: Claude Code <noreply@anthropic.com>
2026-10-24 04:29:34 +08:00
gavindiaz c7b0cfb92b feat: add BookMate AI reading workspace and full EPUB reader 2026-10-24 03:12:20 +08:00
gavindiaz eaeb45fc85 Initial commit from Create Next App 2026-10-23 15:50:38 +08:00