剪藏#剪藏#鸟窝聊技术

Notex:一个开源 NotebookLM 替代方案的实现

2026 年 1 月 8 日1 分钟
分享Twitter / XTelegram微博
Notex:一个开源 NotebookLM 替代方案的实现 封面

起源

Google 的 NotebookLM 上线后,不少人体验了它的文档问答和内容生成功能。它很好用,但有个问题:数据需要上传到 Google 的服务器。对于一些敏感的内部文档,这不太合适。

于是就想做一个开源版本:数据存在本地,想用什么模型就自己配置。一个元旦假期,基本功能就跑起来了。

项目叫 Notex[1],代码在 GitHub 上,今天聊聊它的实现。

本项目受open-notebook[2]项目的启发。但是 open-notebook 缺少信息图、思维导图、幻灯片等高级功能。本项目弥补了这些功能 信息图采用最新的 nano banana pro 实现 幻灯片采用 宝玉的 《预订本年度最有价值提示词 —— 生成既有质感,又能随意修改文字的完美 PPT》 的方式,生成真正意义上的 PPT

Notion image

功能概览

Notex 是一个隐私优先的开源知识管理工具,基于 RAG(检索增强生成)技术。它支持多种文档格式,通过 AI 帮助你理解、总结和可视化文档内容。

Notion image

核心功能

文档管理 支持 PDF、DOCX、PPTX、Markdown、TXT、HTML 等多种格式的文档上传和解析
AI 对话 基于文档内容的智能问答,回答会标注来源引用,避免 AI 幻觉
内容转换 摘要、FAQ、学习指南、大纲、时间线、术语表、测验、播客脚本等 9 种预设类型
视觉生成 思维导图(Mermaid.js)、信息图(Gemini Nano Banana Pro)、幻灯片/PPT
模型支持 OpenAI(含兼容 API)、Ollama 本地模型、Google Gemini

特色功能详解

1. 幻灯片(PPT)生成

采用两阶段生成流程:

  • 阶段一:使用 Gemini Flash 生成 PPT 大纲,包含:

  • 全局风格指南(字体、色彩、设计美学)每页的叙事目标、关键内容、视觉元素、布局说明

  • 阶段二:使用 Gemini Pro Image 为每页幻灯片生成配图

最终输出图文并茂的完整 PPT,而非简单的文字大纲。

Notion image

2. 信息图生成

通过 Prompt Engineering 将文本内容"翻译"为结构化的视觉描述,再调用 Gemini Nano Banana Pro 生成手绘风格的信息图。

适用于:数据可视化、流程说明、概念解释等场景。

Notion image

3. 思维导图生成

自动将文档结构提炼为 Mermaid.js mindmap 格式,支持:

  • 中心主题、主要分支、细节节点的层级展示

  • 自动缩放和交互式导航

  • 导出为 SVG/PNG

Notion image

4. 智能问答(RAG)

支持基于文档内容的自然语言问答:

  • 中文/英文自适应分词和检索

  • 回答会标注来源,可追溯原文

  • 支持多轮对话历史

整体架构

技术栈选型很简单:

JAVASCRIPT
后端:Go 1.25 + Gin + SQLite
前端:原生 HTML/CSS/JavaScript
AI:LangChainGo + OpenAI/Ollama + Gemini

为什么不选 Python?因为 Go 编译完就是一个二进制文件,部署起来省事。而且 Go 的并发性能好,后续如果需要处理大量文档也不会成为瓶颈。

目录结构也很清晰:

JAVASCRIPT
notex/
├── main.go           # 入口
├── backend/
│   ├── agent.go      # AI 调用逻辑
│   ├── server.go     # HTTP 服务
│   ├── vector.go     # 文档索引
│   ├── store.go      # 数据持久化
│   └── nanobanana.go # Gemini 图片生成
└── frontend/         # 单页应用(嵌入二进制)

前端通过 //go:embed 编译进二进制,一个文件就能跑起来。

核心模块

1. 文档索引(vector.go)

RAG 的第一步是把文档切成小块,建立索引。

这里有个问题:中文和英文的分词方式不一样。英文按空格分词就行,中文需要按字符切。

JAVASCRIPT
// 检测 CJK 字符比例
cjkCount := 0
for _, r := range runes {
    if r >= 0x4E00 && r <= 0x9FFF { // CJK Unified Ideographs
        cjkCount++
    }
}
cjkRatio := float64(cjkCount) / float64(len(runes)) if cjkRatio > 0.3 {
    // 中文按字符切分
    for i := 0; i < len(runes); i += (chunkSize - chunkOverlap) {
        // ...
    }
else {
    // 英文按单词切分
    words := strings.Fields(text)
    // ...
}

检索部分目前用的是简单的关键词匹配,没有用向量 Embedding。原因?对于中小规模的文档(几万字以内),关键词匹配够用了,而且快。如果后续文档量大,可以接入向量数据库。

JAVASCRIPT
// 多层评分策略
score := 0.0 // 1. 子串匹配(权重高)
if strings.Contains(content, queryLower) {
    score += 10.0
} // 2. 字符匹配率
matchCount := 0
for _, r := range queryRunes {
    if strings.ContainsRune(content, r) {
        matchCount++
    }
}
if matchCount > 0 {
    charMatchRatio := float64(matchCount) / float64(len(queryRunes))
    score += charMatchRatio * 5.0
} // 3. 单词匹配(针对英文)
queryWords := strings.Fields(queryLower)
for _, word := range queryWords {
    if len(word) > 2 && strings.Contains(content, word) {
        score += 2.0
    }
}

2. AI 调用(agent.go)

这块是核心,负责和 LLM 打交道。

使用 LangChainGo 作为抽象层,支持 OpenAI 和 Ollama:

JAVASCRIPT
func createLLM(cfg Config) (llms.Model, error) {
    if cfg.IsOllama() {
        return ollamallm.New(
            ollamallm.WithModel(cfg.OllamaModel),
            ollamallm.WithServerURL(cfg.OllamaBaseURL),
        )
    }     opts := []openai.Option{
        openai.WithToken(cfg.OpenAIAPIKey),
        openai.WithModel(cfg.OpenAIModel),
    }
    if cfg.OpenAIBaseURL != "" {
        opts = append(opts, openai.WithBaseURL(cfg.OpenAIBaseURL))
    }     return openai.New(opts...)
}

Prompt Engineering 是关键。不同的转换类型需要不同的 prompt 模板:

JAVASCRIPT
case "mindmap":
    return `你是一位资深的信息架构师和知识管理专家。
    请将【文本内容】提炼并转换为 Mermaid.js 的 mindmap 格式。     # 样式规范:
    1. 中心主题:root((内容))
    2. 主要分支:(内容)
    3. 细节节点:[内容]     # 严格规范:
    - 严禁使用 graph, LR, --> 等字符
    - 节点内容 10 字以内
    - 只输出代码块,不解释     来源:{sources}
    `

注意这里的 prompt 设计:明确的输出格式要求,加上反面示例("严禁"),能有效减少 LLM 输出格式不稳定的问题。

3. PPT 生成

这是比较复杂的 feature。需要两个步骤:

第一步:生成大纲

用 Gemini Flash 生成 PPT 大纲,每页包含:

  • 叙事目标(这张幻灯片要讲什么)

  • 关键内容(标题、要点)

  • 视觉元素(需要什么图)

  • 布局(怎么排版)

第二步:解析和生成图片

JAVASCRIPT
func (a *Agent) ParsePPTSlides(content string) []Slide {
    // 1. 提取风格指南
    styleStart := strings.Index(content, "<STYLE_INSTRUCTIONS>")
    styleEnd := strings.Index(content, "</STYLE_INSTRUCTIONS>")     // 2. 按幻灯片分割(支持多种标记)
    re := regexp.MustCompile(`(?m)^(?:\s*#{1,6}\s*)?(?:Slide|幻灯片)\s*\d+`)
    indices := re.FindAllStringIndex(content, -1)     // 3. 验证每张幻灯片是否包含必需字段
    if strings.Contains(lower, "叙事目标") || strings.Contains(lower, "关键内容") {
        slides = append(slides, Slide{Style: style, Content: slideContent})
    }
}

然后为每张幻灯片调用 Gemini Pro Image 生成图片:

JAVASCRIPT
for i, slide := range slides {
    prompt := fmt.Sprintf("Style: %s

Slide Content: %s", slides[0].Style, slide.Content)
    imagePath, err := s.agent.GenerateImage(ctx, "gemini-3-pro-image-preview", prompt)
    slideURLs = append(slideURLs, "/uploads/"+filepath.Base(imagePath))
}

4. 信息图生成

信息图的核心是让 LLM 把文本内容"翻译"成视觉描述,然后把描述作为 prompt 喂给图像模型。

JAVASCRIPT
case "infograph":
    return `# Role
    你是一位世界顶级的数据可视化设计师和信息图专家。     # Task
    阅读所附文本,设计一张信息图。不要进行总结,
    而是描述这张图应该长什么样。你的输出将被直接用作图像生成的 prompt。     # Design Guidelines
    1. 核心信息提炼:找出最重要的 3-5 个数据点
    2. 视觉隐喻:用形象的比喻(如网络安全用"盾牌和锁")
    3. 布局结构:明确定义图的结构
    4. 文本限制:极简,只保留标题和关键数据
    5. 风格:插画或手绘感     # Output Format
    Start with "Infographic illustration created in a soft, hand-drawn digital art style..."
    [描述整体布局和背景风格]
    [详细描述主要视觉元素]
    ...
    `

这个 prompt 设计的要点是:明确告诉 LLM 它的输出会被用作另一个 prompt,这样 LLM 就会更注意输出的结构化和可用性。

5. 思维导图

思维导图的实现最简单,核心是生成 Mermaid.js 的语法:

JAVASCRIPT
case "mindmap":
    return `将文本转换为 Mermaid.js mindmap 格式。     # 样式规范:
    root((中心主题))    # 圆圈
      (主要分支)        # 圆角矩形
        [细节节点]      # 矩形     # 严格规范:
    - 仅限 mindmap 语法
    - 节点内容 10 字以内
    - 严禁包含引号
    `

前端用 Mermaid.js 自动渲染:

JAVASCRIPT
import mermaid from 'https://s4.zstatic.net/ajax/libs/mermaid/11.4.0/mermaid.min.js';
mermaid.initialize({ startOnLoad: true });

数据流

整个系统的数据流如下:

JAVASCRIPT
用户上传文档
    ↓
markitdown 转换为 Markdown(如果需要)
    ↓
文本分块并索引
    ↓
存储到 SQLite
    ↓
用户选择转换类型(PPT/信息图/思维导图)
    ↓
根据类型构建 prompt
    ↓
调用 LLM 生成内容
    ↓
如果需要图片,调用 Gemini 生成
    ↓
保存为 Note
    ↓
前端渲染展示

部署和使用

本地运行

JAVASCRIPT
git clone https://github.com/smallnest/notex.git
cd notex
go mod tidy # 使用 OpenAI
export OPENAI_API_KEY=your_key
go run . -server # 或使用 Ollama(本地模型)
export OLLAMA_BASE_URL=http://localhost:11434
export OLLAMA_MODEL=qwen2.5:7b
go run . -server

Docker 部署

JAVASCRIPT
docker-compose up

环境变量

OPENAI_API_KEY OpenAI API 密钥 -
OPENAI_BASE_URL 自定义 API 地址 -
OPENAI_MODEL 模型名称 gpt-4o-mini
OLLAMA_BASE_URL Ollama 地址 -
OLLAMA_MODEL Ollama 模型 -
GOOGLE_API_KEY Gemini API(PPT/信息图) -
SERVER_PORT 服务端口 8080

扩展性

代码结构支持几种扩展方式:

1. 添加新的转换类型

agent.gogetTransformationPrompt 添加新 case:

JAVASCRIPT
case "new_type":
    return `你的 prompt 模板...`

2. 支持新的 LLM

LangChainGo 支持多种模型,只需在 createLLM 添加新的分支。

3. 接入向量数据库

VectorStore 目前是内存实现,可以替换成 Qdrant、Milvus 等。

4. 添加新的文档格式

vector.goneedsMarkitdown 添加新的文件扩展名。

代码量和学习价值

项目核心代码大约 2000 行左右,适合学习:

  1. RAG 的完整实现:从文档处理到检索到生成

  2. Prompt Engineering:如何设计稳定的 prompt

  3. Go Web 开发:Gin 框架、SQLite、并发处理

  4. 前后端分离:单页应用 + REST API

  5. LLM 应用架构:如何组织一个 AI 应用的代码

如果你想学习如何构建 AI 应用,或者想找一个 NotebookLM 的替代方案,这个项目可以作为一个起点。

总结

Notex 不是什么高大上的项目,代码也写得朴素。但它解决了实际问题:让你在本地使用 AI 处理文档,数据不外泄。

核心功能就几个:

  • 文档问答(RAG)

  • 多种内容转换(摘要、FAQ、大纲等)

  • 视觉内容生成(PPT、信息图、思维导图)

技术选型务实地选择了 Go 和原生 JS,没有过多的依赖。部署简单,维护成本低。

如果你感兴趣,可以看看代码,提提 PR,或者直接 fork 改成你自己的工具。

项目地址: https://github.com/smallnest/notex

欢迎 Star、Issue、PR。

参考资料

[1]

Notex: https://github.com/smallnest/notex

[2]

open-notebook: https://github.com/lfnovo/open-notebook

原文地址: https://mp.weixin.qq.com/s?__biz=MzU2ODc4NzUxMg==&mid=2247489749&idx=1&sn=938c41b6bc68d52282c6cb23e68a7ead&chksm=fd56bd73a21a232b05e5a697803dcfa5b7f8a6f41af67751339c6c999b2308d7fef97cbb108d&mpshare=1&scene=1&srcid=0108DMXQZK6i6yzKQBYuDuIN&sharer_shareinfo=3261cced0331d861ee55d4d8065932aa&sharer_shareinfo_first=3261cced0331d861ee55d4d8065932aa#rd

相关文章