ResearchGo
即将上线为 CIBES Research Centre 开发的平台,把一篇学术论文从投稿一路带到发表。已开发完成,正在做上线前的最后检查。
- 我的角色
- 架构设计与开发
- 年份
- 2026
- 使用技术
- Next.js · Supabase (EU) · Python · FastAPI · GROBID · OpenAlex · Stripe
横向滚动可以看到完整的图。
问题
学术投稿靠的是邮件往来和电子表格。只要参与的人超过一个,版本、审稿意见和期刊要求就会对不上,编辑每次都得手动回答同样的问题:这是哪个版本?改了什么?参考文献有没有问题?投哪本期刊合适?
实现方式
一个跑在 Supabase 上的 Next.js 应用,所有数据都存放在欧盟境内。作者用 ORCID 或邮箱登录,上传 PDF 或 Word 格式的稿件。稿件一到,Python worker(FastAPI)就会解析它,PDF 交给 GROBID 处理,然后通过一个带签名和时间戳的回调把结构化文本发回来,伪造或重放的任务都会被这个回调拒绝。每次解析成功都会生成一个新版本并加密存储,但前提是文本确实有变化。编辑可以用 Word 式的修订模式对比任意两个版本,核对正文引用和参考文献列表是否对得上,还能拿到按语义排序的期刊推荐;推荐所用的 embedding 在我们自己的 worker 上计算,期刊数据来自 OpenAlex。支付走 Stripe。
关键决策
规则能解决的,就不用语言模型
修订对比和参考文献检查都是确定性的代码,不涉及 AI。编辑必须能信任 diff,而规则每次都会给出同样的答案。
稿件不离开我们的服务器
期刊匹配在我们自己的 worker 上对论文做 embedding,所以稿件文本不会发给任何第三方。排序完全按相似度。收录索引、开放获取和费用信息只作为标签显示,从不改变顺序。
每个任务都带签名
Web 应用和 worker 之间的任务都带有 HMAC 签名和时间戳。伪造或重放的任务会被拒绝;worker 在任务中途挂掉,稿件在队列里的位置也不会丢。
仓库里的代码
function diffParagraphPair(before: string, after: string): DiffSegment[] {
return diffWordsWithSpace(before, after).map((part) => ({1
op: part.added ? "ins" : part.removed ? "del" : "equal",
text: part.value,
}));
}
export function diffManuscripts(before: string, after: string): DiffResult {
const a = splitParagraphs(before);
const b = splitParagraphs(after);
// …
const parts = diffArrays(a, b);2
let i = 0;
while (i < parts.length) {
const part = parts[i];
if (!part) break;
if (!part.added && !part.removed) {
// …
i++;
continue;
}
const next = parts[i + 1];
const paired = Boolean(part.removed && next?.added);3
const removedList = part.removed ? part.value : [];
const addedList = part.added ? part.value : paired && next ? next.value : [];
const pairs = Math.min(removedList.length, addedList.length);
for (let k = 0; k < pairs; k++) {
const segments = diffParagraphPair(removedList[k] as string, addedList[k] as string);
paragraphs.push({ kind: "changed", segments });
// …
}
// …
i += paired ? 2 : 1;
}
return { paragraphs, summary };
}
第 2 行. 在改动过的段落内部,diff 按单词进行并保留空白,读起来就像 Word 里的修订。
第 12 行. 第一遍:对整段做最长公共子序列 diff,找出哪些保留、哪些新增、哪些删除。
第 23 行. 删除后紧跟着新增,算作一个被编辑的段落,而不是两处独立的改动。
目前进展
已开发完成,正在做最后检查,检查一结束就上线。