Decentralization? We're still early!
課 6 的 7
In Progress

第六课 Trilium的脚本、API 与 AI 集成

Brave 2026-02-03

在前面的章节中,我们学习了如何使用 Trilium 的各种功能来组织和管理知识。但 Trilium 的能力远不止于此——它是一个可编程的知识平台

📌 Trilium 内置了完整的脚本系统和 REST API,这意味着你可以:

  • 🤖 自动化重复性任务
  • 🔧 扩展Trilium 的功能
  • 🔗 集成外部服务和工具
  • 🧠 接入 AI,让大语言模型理解你的知识库

本节将带你进入 Trilium 的高级进阶领域

  • 📜 脚本系统(Frontend & Backend)
  • 🌐 ETAPI(REST API)
  • 🤖 AI/LLM 集成(OpenAI、Anthropic、Ollama)

⚠️ 学习前提:本节内容需要一定的编程基础(JavaScript/Python)。如果你没有编程经验,可以先了解概念,在需要时再深入学习。

当然,目前全网最强、独一无二的Trilium AI整合方案是Brave基地的Trilium WP和Trilium AI系列插件,之后的课程更新会补充介绍相关内容。


一、脚本系统概述

1.1 Trilium 的双环境架构

Trilium 是一个典型的 Web 应用,由两个主要部分组成:

┌─────────────────────────────────────────────────────────────┐
│                   Trilium 架构                               │
├─────────────────────────────────────────────────────────────┤
│                                                             │
│   🌐 Frontend(前端)                                        │
│   ├── 运行环境:浏览器                                       │
│   ├── 技术栈:HTML, CSS, JavaScript                         │
│   ├── 职责:用户交互、界面渲染、笔记显示                      │
│   └── API:Frontend Script API                              │
│                                                             │
│   ───────────────────────────────────────────               │
│                                                             │
│   ⚙️ Backend(后端)                                         │
│   ├── 运行环境:Node.js                                     │
│   ├── 职责:数据存储、加密、同步、业务逻辑                    │
│   └── API:Backend Script API                               │
│                                                             │
│   两者都运行 JavaScript,但能访问的资源不同                   │
│                                                             │
└─────────────────────────────────────────────────────────────┘

1.2 两种脚本类型对比

特性Frontend ScriptBackend Script
运行环境浏览器Node.js 服务器
触发方式用户操作、页面加载定时任务、事件钩子
可访问DOM、浏览器 API、UI数据库、文件系统、网络
用途UI 增强、快捷操作数据处理、自动化、集成
执行速度即时可后台运行

1.3 创建脚本笔记

  1. 创建代码笔记
    • 新建笔记
    • 将类型改为 "Code"
    • 选择语言为 "JavaScript (Frontend)""JavaScript (Backend)"
  2. 添加运行标签(让脚本自动执行):
标签触发时机
#run=frontendStartup前端启动时执行
#run=backendStartup后端启动时执行
#run=hourly每小时执行
#run=daily每天执行
#run=mobileStartup移动端启动时执行

二、Frontend Script 实战

2.1 Frontend API 基础

Frontend Script 可以访问 api 对象,提供了丰富的功能:

// 获取当前笔记
const note = api.getActiveContextNote();

// 显示消息
api.showMessage("Hello, Trilium!");

// 获取笔记内容
const content = await note.getContent();

// 创建新笔记
const newNote = await api.createNote(parentNoteId, "新笔记标题", "笔记内容");

// 执行搜索
const results = await api.searchForNotes("#book");

2.2 示例一:一键插入当前日期时间

创建一个按钮,点击后在当前位置插入格式化的日期时间:

// 笔记类型:Code (JavaScript Frontend)
// 标签:#customWidget

const insertDateTime = () => {
    const now = new Date();
    const formatted = now.toLocaleString('zh-CN', {
        year: 'numeric',
        month: '2-digit',
        day: '2-digit',
        hour: '2-digit',
        minute: '2-digit'
    });

    // 获取当前编辑器
    const textEditor = api.getActiveContextTextEditor();
    if (textEditor) {
        textEditor.model.change(writer => {
            const insertPosition = textEditor.model.document.selection.getFirstPosition();
            writer.insertText(`📅 ${formatted}`, insertPosition);
        });
        api.showMessage("日期时间已插入");
    }
};

// 注册快捷键
api.bindGlobalShortcut('alt+d', insertDateTime);

2.3 示例二:快速创建读书笔记

// 笔记类型:Code (JavaScript Frontend)
// 标签:#run=frontendStartup

// 注册命令
api.addButtonToToolbar({
    title: "📚 新建读书笔记",
    icon: "bx bx-book-add",
    action: async () => {
        const bookTitle = await api.showPromptDialog({
            title: "新建读书笔记",
            message: "请输入书名:"
        });

        if (!bookTitle) return;

        // 找到读书笔记父目录
        const parentNote = await api.searchForNote("#readingRoot");

        if (!parentNote) {
            api.showError("未找到读书笔记目录,请确保存在 #readingRoot 标签的笔记");
            return;
        }

        // 创建笔记
        const newNote = await api.createTextNote(parentNote.noteId, bookTitle, `
## 📖 基本信息

| 项目 | 内容 |
|------|------|
| 书名 | ${bookTitle} |
| 作者 |  |
| 出版年 |  |
| 评分 | /5 |

---

## 📝 内容摘要



---

## 💡 读后感


        `);

        // 添加标签
        await newNote.setLabel('book');
        await newNote.setLabel('status', 'reading');

        // 打开新笔记
        api.activateNote(newNote.noteId);

        api.showMessage(`读书笔记《${bookTitle}》已创建`);
    }
});

2.4 示例三:自定义 CSS 主题

你可以用 Frontend Script 注入自定义 CSS:

// 笔记类型:Code (CSS)
// 标签:#appCss

/* 自定义暗色主题增强 */

/* 调整笔记树样式 */
.note-tree {
    font-size: 14px;
}

/* 高亮当前笔记 */
.note-tree .active {
    background-color: rgba(100, 150, 255, 0.2) !important;
    border-radius: 4px;
}

/* 自定义代码块样式 */
pre code {
    font-family: 'JetBrains Mono', 'Fira Code', monospace;
    font-size: 13px;
}

/* 调整编辑器行高 */
.note-detail-editable-text {
    line-height: 1.8;
}

💡 提示:添加 #appCss 标签后,这个 CSS 会自动应用到整个 Trilium 界面。


三、Backend Script 实战

3.1 Backend API 基础

Backend Script 运行在 Node.js 环境,可以访问更底层的功能:

// 获取笔记
const note = api.getNote(noteId);

// 搜索笔记
const notes = api.searchForNotes("#book #status=reading");

// 创建笔记
const newNote = api.createNewNote({
    parentNoteId: "root",
    title: "新笔记",
    content: "内容",
    type: "text"
});

// 修改属性
note.setLabel("status", "finished");

// 访问数据库(高级)
const result = api.sql.getValue("SELECT COUNT(*) FROM notes");

// 执行 HTTP 请求
const response = await api.axios.get("https://api.example.com/data");

3.2 示例一:每日自动创建日记

// 笔记类型:Code (JavaScript Backend)
// 标签:#run=daily

const dayjs = require('dayjs');

const today = dayjs().format('YYYY-MM-DD');
const journalTitle = `📅 ${today}`;

// 检查今日日记是否存在
const existingNote = api.searchForNote(`note.title = "${journalTitle}"`);

if (existingNote) {
    api.log(`今日日记已存在: ${journalTitle}`);
    return;
}

// 找到日记父目录
const journalRoot = api.searchForNote("#calendarRoot");

if (!journalRoot) {
    api.log("未找到日记根目录");
    return;
}

// 创建年份和月份目录(如果不存在)
const year = dayjs().format('YYYY');
const month = dayjs().format('MM');

let yearNote = api.searchForNote(`note.title = "${year}" AND note.parentNoteId = "${journalRoot.noteId}"`);
if (!yearNote) {
    yearNote = api.createNewNote({
        parentNoteId: journalRoot.noteId,
        title: year,
        type: "text",
        content: ""
    });
}

let monthNote = api.searchForNote(`note.title = "${month}" AND note.parentNoteId = "${yearNote.noteId}"`);
if (!monthNote) {
    monthNote = api.createNewNote({
        parentNoteId: yearNote.noteId,
        title: month,
        type: "text",
        content: ""
    });
}

// 创建今日日记
const template = `
## 🌅 今日计划

- [ ]
- [ ]
- [ ]

## ✅ 完成事项



## 💭 今日思考



## 📝 备注

`;

const dailyNote = api.createNewNote({
    parentNoteId: monthNote.noteId,
    title: journalTitle,
    type: "text",
    content: template
});

dailyNote.setLabel("journal");
dailyNote.setLabel("date", today);

api.log(`今日日记已创建: ${journalTitle}`);

3.3 示例二:自动统计读书进度

// 笔记类型:Code (JavaScript Backend)
// 标签:#run=daily

// 统计读书情况
const allBooks = api.searchForNotes("#book");
const reading = api.searchForNotes("#book #status=reading");
const finished = api.searchForNotes("#book #status=finished");

const stats = `
# 📊 读书统计

更新时间:${new Date().toLocaleString('zh-CN')}

## 总览

| 指标 | 数量 |
|------|------|
| 📚 总书籍 | ${allBooks.length} |
| 🔄 阅读中 | ${reading.length} |
| ✅ 已完成 | ${finished.length} |

## 正在阅读

${reading.map(n => `- [[${n.title}]]`).join('\n')}

## 今年完成

${finished.filter(n => {
    const finishedDate = n.getLabelValue('finishedDate');
    return finishedDate && finishedDate.startsWith(new Date().getFullYear().toString());
}).map(n => `- [[${n.title}]] (${n.getLabelValue('finishedDate')})`).join('\n')}
`;

// 更新或创建统计笔记
let statsNote = api.searchForNote("#readingStats");

if (statsNote) {
    statsNote.setContent(stats);
} else {
    const readingRoot = api.searchForNote("#readingRoot");
    if (readingRoot) {
        statsNote = api.createNewNote({
            parentNoteId: readingRoot.noteId,
            title: "📊 读书统计",
            type: "text",
            content: stats
        });
        statsNote.setLabel("readingStats");
    }
}

api.log("读书统计已更新");

3.4 示例三:笔记创建时自动添加元数据

// 笔记类型:Code (JavaScript Backend)
// 添加关系:~runOnNoteCreation 指向此脚本

// 当新笔记创建时自动执行
const note = api.originEntity;

// 排除某些笔记
if (note.type !== 'text') return;
if (note.hasLabel('noAutoMeta')) return;

// 添加创建时间标签(更精确的格式)
const dayjs = require('dayjs');
const createDate = dayjs().format('YYYY-MM-DD HH:mm');

note.setLabel('createdAt', createDate);

api.log(`已为笔记 "${note.title}" 添加元数据`);

四、ETAPI(REST API)

4.1 什么是 ETAPI?

ETAPI(External Trilium API)是 Trilium 提供的 REST API,允许外部程序与 Trilium 交互。这意味着你可以:

  • 📱 用其他应用创建笔记
  • 🤖 用脚本批量处理笔记
  • 🔗 将 Trilium 集成到自动化工作流
  • 🧠 让 AI 助手读写你的知识库

4.2 获取 ETAPI Token

  1. 打开 Trilium
  2. 进入 Options(设置)ETAPI
  3. 点击 "Create new ETAPI token"
  4. 保存生成的 Token(只显示一次!)

4.3 API 基本使用

🔐 认证方式

所有 ETAPI 请求都需要在 Header 中包含 Token:

# 方式一:自定义 Header
Authorization: YOUR_ETAPI_TOKEN

# 方式二:Bearer Token(v0.93.0+)
Authorization: Bearer YOUR_ETAPI_TOKEN

📋 常用 API 端点

端点方法功能
/etapi/notes/{noteId}GET获取笔记
/etapi/notes/{noteId}/contentGET获取笔记内容
/etapi/notesPOST创建笔记
/etapi/notes/{noteId}PATCH更新笔记
/etapi/notes/{noteId}DELETE删除笔记
/etapi/search/{searchString}GET搜索笔记
/etapi/attributesPOST创建属性

4.4 使用 curl 调用 API

# 获取笔记
curl -H "Authorization: YOUR_TOKEN" \
     http://localhost:8080/etapi/notes/root

# 搜索笔记
curl -H "Authorization: YOUR_TOKEN" \
     "http://localhost:8080/etapi/search/%23book"

# 创建笔记
curl -X POST \
     -H "Authorization: YOUR_TOKEN" \
     -H "Content-Type: application/json" \
     -d '{
       "parentNoteId": "root",
       "title": "API 创建的笔记",
       "type": "text",
       "content": "这是通过 API 创建的内容"
     }' \
     http://localhost:8080/etapi/notes

# 导出笔记(Markdown 格式)
curl -H "Authorization: YOUR_TOKEN" \
     "http://localhost:8080/etapi/notes/NOTE_ID/export?format=markdown" \
     -o export.zip

4.5 使用 Python 客户端(trilium-py)

trilium-py 是一个功能丰富的 Python 客户端:

pip install trilium-py
from trilium_py.client import ETAPI

# 初始化客户端
ea = ETAPI('http://localhost:8080', 'YOUR_TOKEN')

# 搜索笔记
results = ea.search_note("python")
for note in results['results']:
    print(f"- {note['title']}")

# 获取笔记内容
note = ea.get_note('NOTE_ID')
content = ea.get_note_content('NOTE_ID')

# 创建笔记
new_note = ea.create_note(
    parentNoteId="root",
    title="Python 创建的笔记",
    type="text",
    content="这是通过 Python 创建的内容"
)
print(f"创建成功: {new_note['noteId']}")

# 添加标签
ea.create_attribute(
    noteId=new_note['noteId'],
    type="label",
    name="source",
    value="python-script"
)

# 上传图片附件
ea.create_attachment(
    ownerId=new_note['noteId'],
    file_path="./image.png"
)

# 导出笔记
ea.export_note(
    noteId='NOTE_ID',
    format='markdown',
    save_path='./export.zip'
)

4.6 使用 Node.js 客户端

npm install trilium-etapi
const TriliumETAPI = require('trilium-etapi');

const api = new TriliumETAPI('http://localhost:8080', 'YOUR_TOKEN');

// 搜索笔记
const results = await api.searchNotes('#book');
console.log(results);

// 创建笔记
const newNote = await api.createNote({
    parentNoteId: 'root',
    title: 'Node.js 创建的笔记',
    type: 'text',
    content: '内容...'
});

五、AI/LLM 集成

5.1 Trilium 的 AI 功能概述

从 TriliumNext 的较新版本开始,内置了实验性的 AI 功能,支持:

  • 💬 AI 聊天:与 LLM 对话,询问关于笔记的问题
  • 🔍 语义搜索:使用向量嵌入进行智能搜索
  • 🤖 Agent 工具:让 AI 执行搜索、创建笔记等操作
┌─────────────────────────────────────────────────────────────┐
│                   Trilium AI 架构                           │
├─────────────────────────────────────────────────────────────┤
│                                                             │
│   🧠 LLM 提供商                                              │
│   ├── OpenAI(GPT-4, GPT-3.5)                              │
│   ├── Anthropic(Claude)                                   │
│   └── Ollama(本地部署的开源模型)                           │
│                                                             │
│   📊 嵌入提供商(用于语义搜索)                               │
│   ├── OpenAI Embeddings                                     │
│   ├── Voyage AI                                             │
│   └── Ollama                                                │
│                                                             │
│   🔧 Agent 工具                                              │
│   ├── 搜索笔记                                              │
│   ├── 创建笔记                                              │
│   └── 提取信息                                              │
│                                                             │
└─────────────────────────────────────────────────────────────┘

5.2 配置 AI 提供商

⚙️ 进入设置

  1. 打开 Trilium
  2. 进入 Options(设置)AI

🌐 配置 OpenAI

Provider: OpenAI
API Key: sk-xxxxxxxxxxxxxxxx
Model: gpt-4 或 gpt-3.5-turbo

🤖 配置 Ollama(本地部署)

如果你想使用本地运行的 AI 模型(保护隐私),可以配置 Ollama:

  1. 安装 Ollama

    # macOS/Linux
    curl -fsSL https://ollama.com/install.sh | sh
    
    # 启动 Ollama
    ollama serve
    
    # 下载模型(例如 Llama 3)
    ollama pull llama3
  2. 在 Trilium 中配置

    Provider: Ollama
    Base URL: http://localhost:11434
    Model: llama3

🔐 配置 Anthropic(Claude)

Provider: Anthropic
API Key: sk-ant-xxxxxxxxxxxxxxxx
Model: claude-3-opus 或 claude-3-sonnet

5.3 使用 AI 聊天

配置完成后,你可以在 Trilium 中与 AI 对话:

  1. 打开 AI 聊天面板
  2. 输入问题,例如:
    • "总结这篇笔记的要点"
    • "帮我找到所有关于 Python 的笔记"
    • "基于我的读书笔记,推荐我下一本应该读什么"

5.4 语义搜索(Embeddings)

语义搜索使用向量嵌入,可以找到语义相关的笔记,而不仅仅是关键词匹配。

📊 嵌入的工作原理

传统搜索:
搜索 "机器学习" → 只匹配包含"机器学习"这四个字的笔记

语义搜索:
搜索 "机器学习" → 匹配包含"深度学习"、"神经网络"、"AI 模型训练"等语义相关的笔记

⚙️ 配置嵌入

  1. 在 AI 设置中选择嵌入提供商
  2. Trilium 会为你的笔记生成向量嵌入
  3. 搜索时自动使用语义匹配

5.5 MCP 服务器集成

MCP(Model Context Protocol) 是一种让 AI 助手与外部工具交互的协议。TriliumNext 提供了 MCP 服务器,可以让 Claude Desktop、Cursor 等 AI 工具直接访问你的 Trilium 知识库。

📦 安装 MCP 服务器

# 使用 npx
npx -y @anthropic/mcp-triliumnext

# 或全局安装
npm install -g @anthropic/mcp-triliumnext

⚙️ 配置(以 Claude Desktop 为例)

在 Claude Desktop 的配置文件中添加:

{
  "mcpServers": {
    "trilium": {
      "command": "npx",
      "args": ["-y", "@anthropic/mcp-triliumnext"],
      "env": {
        "TRILIUM_URL": "http://localhost:8080",
        "TRILIUM_TOKEN": "YOUR_ETAPI_TOKEN"
      }
    }
  }
}

配置后,你可以在 Claude Desktop 中直接:

  • 搜索 Trilium 笔记
  • 读取笔记内容
  • 创建新笔记
  • 让 AI 基于你的知识库回答问题

六、实用脚本与集成案例

6.1 案例一:Web Clipper 增强

创建一个脚本,自动为剪藏的网页添加元数据:

// Backend Script
// ~runOnNoteCreation

const note = api.originEntity;

// 检查是否来自 Web Clipper
if (!note.hasLabel('clipType')) return;

const dayjs = require('dayjs');

// 添加剪藏日期
note.setLabel('clippedAt', dayjs().format('YYYY-MM-DD'));

// 自动分类
const url = note.getLabelValue('sourceUrl');
if (url) {
    if (url.includes('github.com')) {
        note.setLabel('category', 'tech');
    } else if (url.includes('medium.com') || url.includes('zhihu.com')) {
        note.setLabel('category', 'article');
    }
}

api.log(`Web Clipper 笔记已处理: ${note.title}`);

6.2 案例二:定时备份到云存储

// Backend Script
// #run=daily

const { exec } = require('child_process');
const dayjs = require('dayjs');

const backupDate = dayjs().format('YYYY-MM-DD');
const backupPath = `/backup/trilium-${backupDate}.db`;

// 使用 rclone 同步到云存储
exec(`rclone copy ${backupPath} remote:trilium-backup/`, (error, stdout, stderr) => {
    if (error) {
        api.log(`备份失败: ${error.message}`);
        return;
    }
    api.log(`备份成功: ${backupPath}`);
});

6.3 案例三:Telegram 机器人集成

# 外部 Python 脚本,通过 ETAPI 与 Trilium 交互
# 创建一个 Telegram 机器人,可以快速记录想法到 Trilium

import telebot
from trilium_py.client import ETAPI

# 配置
TELEGRAM_TOKEN = "YOUR_TELEGRAM_BOT_TOKEN"
TRILIUM_URL = "http://localhost:8080"
TRILIUM_TOKEN = "YOUR_ETAPI_TOKEN"
INBOX_NOTE_ID = "YOUR_INBOX_NOTE_ID"  # 收件箱笔记的 ID

bot = telebot.TeleBot(TELEGRAM_TOKEN)
ea = ETAPI(TRILIUM_URL, TRILIUM_TOKEN)

@bot.message_handler(func=lambda message: True)
def save_to_trilium(message):
    # 创建笔记
    from datetime import datetime
    title = f"📥 {datetime.now().strftime('%Y-%m-%d %H:%M')}"

    new_note = ea.create_note(
        parentNoteId=INBOX_NOTE_ID,
        title=title,
        type="text",
        content=message.text
    )

    # 添加标签
    ea.create_attribute(
        noteId=new_note['noteId'],
        type="label",
        name="source",
        value="telegram"
    )

    bot.reply_to(message, f"✅ 已保存到 Trilium: {title}")

bot.polling()

6.4 案例四:自动生成周报

// Backend Script
// #run=weekly (每周日执行)

const dayjs = require('dayjs');

// 计算本周范围
const weekStart = dayjs().startOf('week').format('YYYY-MM-DD');
const weekEnd = dayjs().endOf('week').format('YYYY-MM-DD');

// 搜索本周完成的任务
const completedTasks = api.searchForNotes(`
    #todo #status=done
    note.dateModified >= "${weekStart}"
`);

// 搜索本周创建的笔记
const createdNotes = api.searchForNotes(`
    note.dateCreated >= "${weekStart}"
`);

// 搜索本周读完的书
const finishedBooks = api.searchForNotes(`
    #book #status=finished
    #finishedDate >= "${weekStart}"
`);

// 生成周报
const report = `
# 📊 周报 (${weekStart} ~ ${weekEnd})

## ✅ 完成的任务 (${completedTasks.length})

${completedTasks.map(n => `- ${n.title}`).join('\n')}

## 📝 新建笔记 (${createdNotes.length})

${createdNotes.slice(0, 10).map(n => `- ${n.title}`).join('\n')}
${createdNotes.length > 10 ? `\n... 等共 ${createdNotes.length} 条` : ''}

## 📚 读完的书 (${finishedBooks.length})

${finishedBooks.map(n => `- ${n.title}`).join('\n')}

---
*自动生成于 ${dayjs().format('YYYY-MM-DD HH:mm')}*
`;

// 创建周报笔记
const weeklyRoot = api.searchForNote("#weeklyReportRoot");
if (weeklyRoot) {
    const reportNote = api.createNewNote({
        parentNoteId: weeklyRoot.noteId,
        title: `📊 周报 ${weekStart}`,
        type: "text",
        content: report
    });
    reportNote.setLabel("weeklyReport");
    reportNote.setLabel("date", weekStart);

    api.log(`周报已生成: ${weekStart}`);
}

七、本节小结

📝 核心要点回顾

  1. 脚本系统
    • Frontend Script:运行在浏览器,用于 UI 增强和快捷操作
    • Backend Script:运行在 Node.js,用于数据处理和自动化
    • 使用 #run= 标签设置自动执行时机
  2. ETAPI(REST API)
    • 允许外部程序与 Trilium 交互
    • 需要 ETAPI Token 进行认证
    • 可用 Python(trilium-py)或 Node.js 客户端
  3. AI/LLM 集成
    • 支持 OpenAI、Anthropic、Ollama 等提供商
    • 提供 AI 聊天、语义搜索、Agent 工具
    • 可通过 MCP 服务器让外部 AI 工具访问 Trilium
  4. 实用案例
    • 自动创建日记
    • 读书统计
    • Web Clipper 增强
    • Telegram 机器人
    • 自动周报

🎯 实践检查清单

完成本节学习后,请确认你已经:

🚀 下一节预告

下一节《数字花园实战》,我们将把前面学到的所有知识综合运用,构建完整的个人知识管理系统——日记系统、项目管理、读书笔记、个人 Wiki,让你的 Trilium 真正成为一座生长中的数字花园。


📚 参考资源

官方文档

客户端库

社区资源

回复