chenchen-plan2
第四天-开发进度
1. 只保留一个标题来源
已按你的要求改成“只保留一个标题来源”:
- 统一标题来源:发布配置不再单独输入标题,统一使用“新建小说”时保存的小说标题。
- 发布弹窗调整:
publish-novel-modal里移除了可编辑的“小说标题”输入框,改为只展示当前小说标题(只读)。 - 发布接口调整:
/api/v1/novel-publish不再使用请求体里的title,改为服务端从作者小说索引里读取该novelId的标题写入发布记录。 - 读者端内容页调整:
/api/v1/library/articles在文章详情返回时,优先使用小说主标题,避免内容页出现与列表页不一致的标题。 - 编辑器接入调整:
novel-editor里发布确认 payload 去掉title字段,发布弹窗改传novelTitle。
已检查这几个改动文件,当前没有新增 lint 报错。
如果你愿意,我下一步可以再帮你把历史已发布数据做一次“标题回填统一”(把旧记录里的标题批量同步为小说主标题)。
2. 删除默认 AI 角色设定
已删除默认 AI 角色设定,现在线路是“无预置角色”:
novel-editor不再导入/使用DEMO_PERSONAS- 角色初始状态改为
[],selectedId初始为null - 加载角色时:
- 未连接钱包:保持空列表
- 服务端无角色存档:保持空列表
- 已删除未再使用的文件:
apps/web/src/lib/demo-personas.ts
现在新建小说进入编辑页后,不会再自动出现默认 AI 角色。
3. 按照渲染后的格式直接发布
优化markdown发布,如果是直接用就会是没有应用上markdown语法的原格式。在作者页面http://whale3070.com:3000/editor/nvl-mng5hlto-c4375bd3b9 ,有一个markdown编辑器。把“应用到当前章节”修改为发布本章节。因为应用到当前章节会导致markdown格式失效。我希望按照渲染后的格式直接发布
已按你的要求改好:Markdown 编辑器不再“应用到当前章节”,改成直接发布本章节,并且按渲染后的 HTML发布,避免 Markdown 格式被破坏。
- 按钮文案已改为:
发布本章节 - 弹窗发给主页面的数据从“原始 markdown 文本”为主,改成携带
renderedHtml(预览区实际 HTML) - 主页面收到消息后会:
- 先把当前章节内容更新为渲染后的 HTML
- 持久化章节结构
- 触发“发布本章”,并带上
skipAutoFormat: true
- 后端
/api/v1/novel-publish的toggle_chapter增加了skipAutoFormat支持
当skipAutoFormat=true时,跳过autoFormatChaptersForPublish,从而保留 Markdown 渲染格式(例如表格)
你给的页面入口我已按这个场景实现对应逻辑:Chenchen-Lib · AI 编辑平台
如果你需要,我可以继续加一个“发布并保留当前编辑器内容不切换焦点/不滚动”的微调,进一步优化发布手感。
4. 剧情大纲管理
已完成:剧情大纲管理里的自动卷名/标签预置已移除,改为作者自行添加。
具体改动:
- 不再使用演示大纲初始化(已删除
demo-outline依赖) - 新建/未连接状态下的大纲初始值改为“仅默认章节”,不带预置标签
- 自动补建卷节点时,不再写死
第一卷,改为空标题(作者自己填) - 自动新增章节/AI 切章生成卷节点时,也不再预置卷名和标签
- 大纲侧边栏“新增章节”自动创建的卷节点同样去掉默认卷名和标签
你这个页面场景现在会符合“作者手动配置”的方式:Chenchen-Lib · AI 编辑平台 。
如果你愿意,我可以再补一个小优化:当卷标题为空时,在输入框里显示占位提示(比如“请输入卷名”),但不自动写入任何值。
5. 自动先落盘当前章节内容
修改内容之后,它好像不知道怎样的生效方式,我试了好几遍,不知道是要先撤回本章再修改才会更新,还是是有个时间差才会更新(已经了解了得点击切换到别的章节才会更新)|目前又发现似乎发布新章节也是一样,必须得要切出去才能正常显示,否则发布的就是空章节。你告诉我,修改内容,已发布的内容什么时候生效?什么时候读者端能看到?
你现在遇到的现象,和当前实现一致,不是你操作错了。
现在的生效规则(按当前代码)
- 你在编辑器里打字后,2 秒防抖保存的是“写作草稿上下文”(
/api/v1/save-draft),不是章节结构发布源。 - 读者端展示读取的是章节结构里的
chapterHtml(/api/v1/library/articles从.data/structure读),再按publishedChapterIds过滤已发布章节。 - 所以:
- 只改内容但不触发章节结构写入时,读者端会看到旧内容(甚至空内容)。
- 你切到别的章节时会触发“把当前章节内容写回结构”,所以你观察到“切出去才生效”。
回答你两个关键问题
已发布内容什么时候生效?
当“当前章节内容已经写入结构文件”后就生效。当前最稳定触发点是:切换章节(或你刚用的 Markdown “发布本章节”流程)。读者端什么时候能看到?
在作品是公开、且该章节已在publishedChapterIds内、并且结构写入完成后,读者端刷新基本可立即看到(接口是no-store,不是长缓存导致的延迟)。
为什么新章节会发布成空章
新章节创建后,如果你直接点发布,但“当前编辑内容还没先写回章节结构”,发布时拿到的还是旧的/空的 chapterHtml,所以读者端就显示空章。
如果你要,我可以直接再改一版“强一致”逻辑:
点击“发布本章 / 一键发布全部”前,自动先落盘当前章节内容,再执行发布,这样就不需要手动切章节了。
已改成你要的行为:
现在点 “发布本章” 或 “一键发布全部” 前,会先自动把当前编辑器里的章节内容落盘到结构,再执行发布,不需要手动切章节了。
这次改动点在 novel-editor:
- 新增
persistActiveChapterBeforePublish():- 读取当前编辑器 HTML
- 写回当前激活章节的
chapterHtml - 立即
postOutlineStructure持久化
- 以下流程都改为先调用它:
toggleCurrentChapterPublish(底部“发布本章/撤回本章”)- 大纲侧栏章节卡片上的发布按钮
- 大纲侧栏“一键发布全部章节”
- “发布小说(发布配置确认)”也同步改为先落盘再提交,保证章节列表与内容一致。
这样就不会再出现“必须切出去才生效”或“刚发布是空章节”的问题。
6. 章节内容错乱
章节内容有时候显示的是最新版的,有时候显示的又是旧版本的,有时候显示的有图片,有时候显示的又没有图片,但是一刷新又会恢复到最新版本
你这个现象我确认了,根因有两层:
- 读者端不是实时订阅:页面只在进入/刷新时拉一次内容,所以作者改完后,读者通常要刷新才会看到。
- 章节有多份 HTML 字段:之前编辑时只更新了
chapterHtml,而读者端有时会优先读chapterHtmlDesktop/chapterHtmlMobile,就会出现“有时旧版、有时无图”。
我刚刚已经修了第二层(核心一致性问题):
- 在作者端保存章节时,统一同步更新:
chapterHtmlchapterHtmlDesktopchapterHtmlMobile
这样同一章节不会再出现“不同入口读到不同版本”的情况,图片也不会因为读到旧字段而忽隐忽现。
现在的生效口径(你可以按这个理解)
- 作者点击发布相关操作前,系统会先落盘当前章节内容(我们前面已加)。
- 读者端看到更新的时间点:下次请求文章详情时(最直接就是刷新页面)。
- 不刷新时,读者端仍可能停留在当前页面内存快照,这是预期行为(不是没保存)。
如果你希望“读者不刷新也自动看到最新”,我可以再给你加一个轻量自动刷新(比如每 5-10 秒静默拉新,并尽量保持当前阅读章节位置不跳)。
7. 章节重复
是的,这种显示会有点重复,我已经帮你改成更清爽的规则了:
- 如果章节标题本身已经是“第X章…”这种格式,就直接显示标题(不再前面再拼一遍“第 X 章 ·”)
- 如果是自定义标题(比如“夜雨入城”),才显示为
第 X 章 · 夜雨入城 - “当前:…”这一行也同步按同样规则显示
你现在看到的目录和“当前章节”会明显简洁很多。
8. 加载中bug
有这个可能,尤其是移动网络或跨网段时。你现在这个页面我已经做了容错优化,不用再一直盯着“加载中…”:
- 加了请求超时(12 秒),避免无限等待
- 加了自动重试 1 次(遇到抖动时更容易成功)
- 加了慢网提示(2.5 秒后提示“网络或服务较慢”)
- 加了**“立即重试”按钮**,用户可主动重拉
所以现在如果只是波动,通常会自动恢复;如果真的慢,会给明确反馈而不是一直卡住。
9. AI排版bug
你这个“AI自动排版有问题”的判断是对的,我查完调用链后,先给你结论(本次未改代码):
主要问题(高优先级)
自动排版是“纯文本重写”策略,不是 HTML 保留策略
在deepseek-publish-format里,先把章节chapterHtml转成纯文本,再让模型排版,再重新生成<p>。
这会天然丢失图片、表格、复杂排版(例如img/table/custom html)。
关键位置:apps/web/src/lib/server/deepseek-publish-format.ts里的htmlToPlainText()+plainTextToHtml()流程。“一键发布全部章节”必走自动排版
publish_all_chapters在novel-publish路由里总是调用autoFormatChaptersForPublish(),没有跳过选项。
所以你一键发布后,之前保留好的富文本也可能被重新“文本化”。
位置:apps/web/src/app/api/v1/novel-publish/route.ts。按章节发布只有部分路径支持跳过自动排版
你之前用 Markdown 弹窗“发布本章节”是带skipAutoFormat=true的,这条路径可以保留渲染结果;
但其他发布入口(尤其一键发布)仍可能触发自动排版重写。
位置同上 +apps/web/src/components/novel-editor.tsx的调用差异。
次要问题(中优先级)
- DeepSeek 调用缺少超时和可见诊断
formatByDeepSeek()没有超时控制,慢网时可能卡很久。 - 长章节被截断到 12000 字符
MAX_MODEL_INPUT_CHARS = 12000,长章节会被裁切后再排版,可能导致“后半章没按预期处理”。
你现在看到“有时正常、有时异常”的根本原因
- 不是同一条发布路径:不同按钮触发的发布策略不一样(有的保留 HTML,有的会文本化重排)。
- 一旦走到自动排版,就可能把图片/复杂格式丢掉,看起来像“随机失效”。
如果你同意,我下一步可以给你一版“排版策略分层”方案(先给方案,不直接改):
保留富文本发布(默认)AI文本排版发布(手动开启)
并让“一键发布全部”可选是否走 AI 重排。
可以,给你一套“排版策略分层”方案(先方案,不动代码):
目标
- 默认发布行为稳定、可预期:不破坏富文本(图片/表格/Markdown渲染结果都保留)
- 只有作者明确选择时,才执行 AI 文本排版重写
- 所有发布入口行为一致,避免“同一本书不同按钮结果不同”
一、发布策略定义(核心)
统一定义 2 个模式:
preserve:保留原排版- 直接使用当前
chapterHtml/chapterHtmlDesktop/chapterHtmlMobile - 不调用
autoFormatChaptersForPublish
- 直接使用当前
ai_reflow:AI 重排文本- 调用
autoFormatChaptersForPublish,按纯文本重排后回写
- 调用
建议默认:preserve。
二、前端交互方案
1) 发布配置弹窗(整本发布)
在“发布设置”里新增一个清晰选项:
- 排版策略:
保留作者排版(推荐)(默认)AI 自动排版(会重排段落,可能影响图片/表格)
文案要明确风险(尤其“可能影响图片/表格”)。
2) 大纲侧栏发布入口
- “发布本章”:默认按
preserve - “一键发布全部章节”:弹一次轻确认,显示当前策略(默认 preserve,可切换)
3) Markdown 弹窗“发布本章节”
- 固定走
preserve(你当前诉求) - 可在按钮旁给一个次按钮:
AI重排后发布(可选)
三、后端接口统一
把策略作为显式参数传给 /api/v1/novel-publish:
layoutMode: "preserve" | "ai_reflow"
适配到三个 action:
toggle_chapterpublish_all_chapters- 整本发布(
visibility=public这条路径)
逻辑统一:
layoutMode === "ai_reflow"才调用autoFormatChaptersForPublish- 否则完全跳过自动排版
这样不会再出现“某个按钮偷偷走了AI重排”。
四、持久化设计(保证一致)
在 NovelPublishRecord 加一个字段:
layoutMode?: "preserve" | "ai_reflow"
用途:
- 保存作者的长期偏好(下次打开发布弹窗默认回显)
- 一键发布全部章节默认沿用上次策略
五、可观测性(排查友好)
建议顺手加最小日志字段(写到本地 JSON 或 server log):
lastPublishActionlastLayoutModelastFormattedCountlastPublishAt
这样你后面遇到“为什么这章变了”可以直接追溯是不是走了 ai_reflow。
六、兼容与迁移
- 历史数据没有
layoutMode的默认按preserve - 保留现有
skipAutoFormat兼容一段时间,但逐步收敛到统一layoutMode - 旧入口逐步替换,避免双语义参数并存太久
七、验收用例(你可直接按这个测)
- 发布本章(preserve):图片、表格、Markdown渲染保持不变
- 一键发布(preserve):所有章节不被重排
- 一键发布(ai_reflow):纯文本段落被重排,图片/表格风险提示一致
- 同一章节分别走3个入口,结果一致(取决于所选
layoutMode) - 刷新读者端后内容与作者端最终发布内容一致
如果你确认这个方向,我下一步可以直接按这套方案落地实现(前后端一起改),并给你一个最小可测清单。
10. 发布策略分层
已实现,发布策略分层 现在真正生效了,而且三条发布入口统一了。
这次落地内容
- 新增发布策略字段:
layoutMode- 值:
preserve(保留排版,默认) /ai_reflow(AI 文本重排)
- 值:
- 发布配置弹窗新增“排版策略”单选
- 默认:
保留作者排版(推荐) AI 自动排版带风险提示(可能影响图片/表格)
- 默认:
- 前端发布入口统一透传策略:
- 发布配置确认
- 发布本章
- 一键发布全部章节
- Markdown 弹窗“发布本章节”固定走
preserve(保留渲染后格式)
后端统一逻辑
在 /api/v1/novel-publish 中统一按 layoutMode 决定是否调用 autoFormatChaptersForPublish:
layoutMode === "ai_reflow":才执行 AI 自动排版layoutMode === "preserve":跳过自动排版,直接发布当前结构内容
并且在发布记录中持久化 layoutMode,后续发布会沿用。
现在你可以稳定预期:
- 选择“保留作者排版”后,图片/表格/Markdown 渲染不会被自动重排破坏
- 只有明确选择“AI 自动排版”时,才会触发文本重排
如果你愿意,我下一步可以再补一个很小的 UI 提示:在大纲侧栏“一键发布全部章节”按钮旁显示当前策略(保留排版 / AI重排),避免误触发。
11. 文案修改 + AI赋能自动打标签、写简介
12. 社交媒体作品分享
已按你的需求改完:
- “社交媒体小说分享”相关文案全部改为“作品”
《xxx》小说→《xxx》作品社交媒体小说分享→社交媒体作品分享
- 分享弹窗和下载分享图都接入了发布配置里的元数据:
- 作品简介(
synopsis) - 作品标签(
tags)
- 作品简介(
- 后端读者文章接口已返回
tags(从发布记录读取并清洗)
也就是说,你现在在发布配置页里自动生成的“作品简介/作品标签”,会直接体现在社交分享弹窗和“下载本图片”生成图中。
参考页面仍是这个入口:Chenchen-Lib · AI 编辑平台
13. 一键生成抖音视频 - 前端
已改好,你说的两个点都已覆盖在工作台“发布管理”这条分享链路里:
- 文案统一从“小说”改为“作品”
- 按钮:
社交媒体小说分享→社交媒体作品分享 - 弹窗标题、
aria-label、二维码alt、下载文件名也同步改为“作品”
- 按钮:
- 分享图和弹窗都接入发布配置里的元数据
- 使用
record.synopsis(作品简介) - 使用
record.tags(作品标签) - 标签会展示为
#标签形式,并写入下载图中(最多显示 8 个)
- 使用
也就是你在发布配置里自动生成的简介/标签,现在会被集成到社交媒体分享文案图片中。
参考入口:Chenchen-Lib · AI 编辑平台
14. 多语言翻译功能
请在http://whale3070.com:3000/workspace
页面,新增多语言翻译功能模块,该模块与“小说发布管理”“账户设置”并列展示,核心功能为小说内容多语言翻译,支持手动触发翻译、选择目标语言、翻译后预览/编辑,同时关联小说发布管理模块,可直接对发布中的小说章节、草稿进行翻译,与账户设置模块联动,保存用户常用翻译语言偏好,确保功能适配页面整体风格,操作流畅无卡顿。使用deepseek api进行翻译。
已完成,在 workspace 页面新增了与“发布管理 / 账户设置”并列的 “多语言翻译” 模块,并接入 DeepSeek 翻译链路与用户偏好联动。
主要实现
- 在
apps/web/src/components/author-dashboard.tsx新增顶部页签多语言翻译,与现有模块并列展示。 - 新增翻译工作区(暗色风格与发布管理一致):
- 选择小说(复用发布管理列表数据)
- 翻译来源切换:
发布章节 / 草稿 / 手动输入 - 章节下拉(标注是否“已发布”)
- 目标语言下拉(多语言)
- “手动触发翻译”按钮
- 翻译进度条(Loading 过程)
- 原文摘要预览 + 翻译结果预览/可编辑文本框
- 与账户设置联动:
- 在
账户设置增加“翻译语言偏好”区域 - 可勾选常用语言、设置默认目标语言
- 保存后翻译模块自动读取默认语言
- 在
新增后端 API(DeepSeek)
apps/web/src/app/api/v1/novel-translation/preferences/route.ts- GET/POST 用户翻译语言偏好(按钱包地址隔离存储)
apps/web/src/app/api/v1/novel-translation/sources/route.ts- 查询可翻译来源(章节列表、发布状态、是否有草稿)
apps/web/src/app/api/v1/novel-translation/translate/route.ts- 执行翻译(sourceType:
chapter|draft|manual) - 使用 DeepSeek
chat/completions - 返回原文摘要、翻译结果、模型信息
- 执行翻译(sourceType:
兼容与风格
- 保持了现有页面视觉体系(边框、色板、暗色卡片、按钮风格一致)。
- 交互为异步非阻塞,翻译与加载过程都有状态提示和进度反馈。
- 已检查本次改动文件,当前无新增 linter 错误。
如果你要,我可以继续加两项增强:
- “一键复制翻译结果 / 导出 txt”按钮;
- “将翻译稿回写到对应章节或草稿”的保存能力(带确认弹窗避免误覆盖)。
15. 中英夹杂的翻译bug
你这个问题本质上是两层:
- 翻译质量约束不够严格,模型会把部分词当“术语”保留,导致中英夹杂。
- 流程没有打通到编辑器,所以翻译后还停留在工作台。
这两点我都已经改了。
已修复内容
- 修复了
DeepSeek翻译提示词,新增硬约束:- 必须完整翻译,不允许保留原文片段
- 目标语言统一输出,不可混用
- 英文目标时明确禁止中文字符(人名地名也需英文/拼音转写)
- 增加英文结果的二次清洗:
- 若首轮结果仍含中文字符,会自动再走一次“English-only rewrite”清洗流程
- 改造“多语言翻译 -> 手动触发翻译”流程:
- 翻译成功后自动跳转到对应小说编辑器
- 自动打开“翻译 Markdown 对照编辑器”
- 左侧原文、右侧译文,均可编辑
- 支持“一键复制译文”
- 支持“应用译文到当前章节”(直接写入当前章节内容)
你会看到的新行为
在 workspace 点“手动触发翻译”后,不再只在当前页显示结果,而是直接跳到:
- 编辑页并弹出双栏对照编辑器(左原文,右译文)
- 右侧译文可直接修订,然后应用到当前章节
涉及页面
- 工作台:http://whale3070.com:3000/workspace
- 编辑器:http://whale3070.com:3000/editor/nvl-mng5hlto-c4375bd3b9
如果你愿意,我下一步可以再加一个“应用前 diff 对比”(高亮显示原文与译文差异),避免误覆盖。
16. 翻译的内容分区
http://whale3070.com:3000/library 这个页面,可以按照不同语言进行分区展示。http://whale3070.com:3000/workspace 在这个多语言翻译哪里,翻译的结果自动保存并展示在,比如说英文区,如果是韩语就展示在韩语区。
已按你的要求打通了这条链路:workspace 翻译结果自动保存,并且 library 按语言分区展示。
这次改动内容
在翻译接口里新增自动持久化:
- 文件:
apps/web/src/app/api/v1/novel-translation/translate/route.ts - 每次翻译后会写入
.data/translations/<author>_<novel>.json - 按语言保存,支持:
- 章节翻译(按
chapterId) - 草稿翻译(
draftText) - 手动翻译(
manualText)
- 章节翻译(按
- 文件:
书库接口支持语言分区与语言版本内容读取:
- 文件:
apps/web/src/app/api/v1/library/articles/route.ts - 列表接口现在会返回每本书的多语言条目(如英文区、韩语区)
- 详情接口支持
?lang=en这类参数,自动读取对应语言翻译内容 - 如果某语言只有草稿/手动翻译,也会回填到阅读内容(首章)并更新简介预览
- 文件:
书库页面按语言分区展示:
- 文件:
apps/web/src/app/library/page.tsx - 现在会分块显示:
中文原文 / 英文区 / 韩语区 ... - 点击条目时会携带语言参数跳转(如
/library/<id>?lang=ko)
- 文件:
阅读页显示当前语言分区:
- 文件:
apps/web/src/app/library/[articleId]/page.tsx - 增加“当前语言分区”显示,便于读者确认在看哪个语言版本
- 文件:
你关心的结果
现在在 workspace 里做翻译(英文/韩语等)后,结果会自动保存;
去 library 会在对应语言分区看到内容(例如英文区、韩语区)。
你可以这样验收
- 在
workspace里选一部小说翻译成英文/韩语。 - 打开书库页,确认出现“英文区/韩语区”分区及条目。
- 点击进入后,确认阅读内容是对应语言版本。
相关页面:
这个网站的前后端构架是什么?
整体上这是一个 Next.js 全栈一体化(BFF) 架构,前后端都在同一个 apps/web 项目里。
前端层
Next.js 16 + React 19(App Router)- 页面和交互主要在
app/*、components/* - UI 侧用了
Tailwind、Radix、lucide-react - 编辑器是
TipTap+marked(Markdown/HTML 双向处理)
后端层(同仓库)
- 使用 Next 的 Route Handlers(
app/api/v1/**/route.ts)当 API 层 - 运行时是 Node(你代码里很多
export const runtime = "nodejs") - 相当于“前端 + API 网关/业务层”合一,不是单独的 Spring/Nest 服务
- 使用 Next 的 Route Handlers(
数据存储层
- 目前不是传统数据库(MySQL/Postgres),而是本地文件持久化
- 大量业务数据写在
.data/*下的 JSON 文件(如 publish、draft、structure、translations) - 属于轻量存储方案,适合快速迭代原型/中小规模
AI 能力层
- 通过服务端 API 调用 DeepSeek(
chat/completions) - 用于:自动切章、发布元信息生成、翻译、英文净化等
- 通过服务端 API 调用 DeepSeek(
认证与身份
- 钱包身份(MetaMask / Web3)为主
- 前端
wagmi + viem,后端通过x-wallet-address做鉴权与隔离
仓库组织
- 看起来是 monorepo 结构(
apps/,services/,shared/) - 当前线上核心是
apps/web这套 Next 全栈应用
- 看起来是 monorepo 结构(
如果你愿意,我可以再给你画一个“请求链路图”(例如:workspace 点翻译 -> API -> DeepSeek -> .data/translations -> library 分语言读取)。
翻译的大语言模型API切换
已完成,你的翻译链路已经切到 豆包(DOUBAO_API_KEY),并把你列的稳定性策略都加上了,目标就是避免“中英夹杂”。
我改了什么
文件:apps/web/src/app/api/v1/novel-translation/translate/route.ts
API 切换
- 从
DEEPSEEK_*改为读取DOUBAO_* - 读取优先级:
DOUBAO_API_KEYDOUBAO_BASE_URL(默认https://ark.cn-beijing.volces.com/api/v3)DOUBAO_MODEL(默认doubao-1-5-pro-32k-250115)
- 从
提示词加硬
- 明确“必须完整翻译,不允许保留原文片段”
- 英文目标时写死“不允许任何中文字符”
- 禁止解释/注释/译者说明,只输出正文
温度下调
temperature统一设为0.1(属于你说的0~0.2范围)
分段翻译
- 长文本按段落切块(约
1400字符块)翻译,减少漏翻和术语漂移
- 长文本按段落切块(约
输出校验 + 重试
- 英文输出用正则检测中文字符:
[\u3400-\u9fff] - 命中后自动二次修复(English-only rewrite)
- 仍命中则按块重试,最多
2次
- 英文输出用正则检测中文字符:
术语表
- 自动抽取大写词/引号词作为轻量术语表,写入 prompt 保证一致翻译
你需要确认
.env.production里要有DOUBAO_API_KEY(你已加)- 如需自定义模型/地址,可再加:
DOUBAO_BASE_URLDOUBAO_MODEL
如果你愿意,我下一步可以再加一个“翻译质量评分字段”(比如英文残留中文率),把每次翻译结果打分存档,方便你在工作台里一眼看出哪些翻译需要重跑。
读者语言设置
http://whale3070.com:3000/library 在这个页面,添加一个读者语言设置的tab,多选,当读者选中 “英语”就只给她看英语区的所有内容。不给她看其他语言的内容。现在这个页面是英文区
我的生平
文章ID:art_176aefb2a7
语言:EN
点击阅读
中文原文
我的生平
文章ID:art_176aefb2a7
语言:ZH
点击阅读。我希望修改后是,my life 英语区的内容。然后用户在设置中添加中文,才能看到中文区的内容。每个分区的所有标题,简介,都使用对应的语言。而不是现在这样,全都是中文介绍。
已按你这个需求改完了,核心行为现在是:
library页面新增了 “读者语言设置” tab(多选)- 默认语言偏好是 仅英文
EN - 读者只会看到已勾选语言分区内容(不勾选中文就看不到中文区)
- 在“阅读书库”里,列表会展示每个分区对应语言的 标题 + 简介(不再只显示中文)
这次具体修改
apps/web/src/app/library/page.tsx- 新增两个 tab:
阅读书库/读者语言设置 - 增加多选语言偏好,存储到
localStorage - 按所选语言过滤分区展示
- 列表项增加对应语言的简介展示
- 新增两个 tab:
apps/web/src/app/api/v1/novel-translation/translate/route.ts- 翻译后除了正文,还会生成并存档该语言的:
displayTitledisplaySynopsistags
- 翻译后除了正文,还会生成并存档该语言的:
apps/web/src/app/api/v1/library/articles/route.ts- 列表返回语言分区条目时,优先用语言化的
displayTitle/displaySynopsis - 详情页也会优先使用语言化标题/简介(不是统一中文)
- 列表返回语言分区条目时,优先用语言化的
如果你现在某些英文区条目仍显示中文标题/简介,那是旧数据还没生成 displayTitle/displaySynopsis。
只要在工作台对那本书再触发一次英文翻译,就会补齐并在书库里变成对应语言显示。
钱包活跃统计
可以加一个“活跃钱包看板”,按你现在这套架构(Next API + .data 文件)其实很好做,分三层:
1) 先定义“活跃”的口径(最重要)
建议至少有 3 个指标:
- DAU(钱包):当天有任意行为的钱包数
- WAU/MAU(钱包):近 7/30 天有行为的钱包数
- 活跃行为构成:创作、发布、翻译、读者解锁、阅读访问 等各自钱包数
你可以先用一个统一口径:
“调用任一业务 API 且带有效 x-wallet-address 就记活跃”。
2) 事件埋点位置(后端统一记,不靠前端)
在这些 API 入口记一条事件(钱包、动作、时间):
- 创作编辑相关:
/api/v1/save-draft、/api/v1/update-structure - 发布相关:
/api/v1/novel-publish* - 翻译相关:
/api/v1/novel-translation/* - 读者侧付费/解锁:
/api/v1/library/articles的POST - 你认为关键的其它入口
事件格式建议:
wallet(lowercase)eventType(如save_draft,translate,publish)ts(ISO)- 可选:
novelId,articleId
3) 存储与统计(先轻量,后升级)
轻量版(适合你现在)
继续用 .data:
- 按天分桶:
.data/analytics/wallet-events/2026-04-02.jsonl - 每次追加一行 JSON(避免频繁读写整文件)
- 新增聚合 API:
GET /api/v1/analytics/active-wallets?range=7d
返回:dau,wau,maudailySeries(每天活跃钱包数)byEventType
进阶版(后期)
迁移到 ClickHouse / Postgres(事件量大后更稳)。
4) 后台展示建议
在 workspace 新增“数据看板”tab:
- 总览卡片:DAU / WAU / MAU
- 趋势图:最近 30 天活跃钱包
- 漏斗:访问钱包 -> 创作钱包 -> 发布钱包 -> 付费解锁钱包
- Top 行为榜:哪个动作最常发生
5) 反作弊/去重建议
- 钱包地址统一
toLowerCase() - 同钱包同事件 5 秒内去重(防抖)
- 统计时按
wallet + day去重,避免刷接口虚高
如果你愿意,我可以下一步给你一版最小可上线方案的接口设计(具体到新增哪些 route、返回 JSON 结构、前端卡片字段),你按这个很快就能实现。
工单管理
已直接开工并完成“工单管理”MVP,包含你要的角色能力:
已上线功能
workspace新增 工单管理 tab- 普通用户(连接钱包):
- 提交工单(标题 + 详情)
- 查看自己的工单状态
- 管理员(
ADMIN_ADDRESS):- 查看全部工单
- 可标记状态:
- 已完成(
done) - 已关闭(
closed) - 已忽略(
ignored)
- 已完成(
- 普通用户(连接钱包):
后端接口
POST /api/v1/tickets:创建工单GET /api/v1/tickets:查询工单(管理员看全部,普通用户看自己)PATCH /api/v1/tickets/:id:管理员更新状态
新增文件:
apps/web/src/lib/server/tickets.tsapps/web/src/app/api/v1/tickets/route.tsapps/web/src/app/api/v1/tickets/[id]/route.ts
数据存储
- 工单持久化到:
.data/tickets/*.json - 管理员地址读取:
ADMIN_ADDRESS(支持从环境变量与根.env.production读取)
前端接入
- 修改:
apps/web/src/components/author-dashboard.tsx - 新增 tab:
工单管理 - 普通/管理员视图按接口返回
isAdmin自动切换
校验状态
- 已对改动文件执行 lint 诊断:无新增错误。
如果你要,我下一步可以再补两个小增强:
- 工单按状态筛选(待处理/已完成/已关闭/已忽略)
- 管理员备注输入框(当前先保留了字段,但 UI 还没填备注入口)。