Hermes 操作 Trilium 传图指南
本文档记录 Hermes Agent 通过 ETAPI 向 Trilium 笔记添加图片的完整流程,包括搜图、上传和引用。
一、ETAPI 附件接口
Trilium v0.63+ 的 ETAPI 附件接口接受 JSON body(不是 multipart 表单)。
创建附件
POST /etapi/attachments
Content-Type: application/json
Authorization: <ETAPI_TOKEN>
{
"ownerId": "<目标 NoteId>",
"role": "image",
"mime": "image/jpeg",
"title": "描述性标题",
"content": "<base64 编码的图片数据>",
"position": 100
}
| 参数 | 说明 |
|---|---|
| ownerId | 目标笔记的 noteId |
| role | "image" 或 "file" |
| mime | MIME 类型(image/jpeg, image/png 等) |
| title | 显示标题 |
| content | 图片的 base64 编码字符串(可选,也可后续上传) |
| position | 排序位置(整数) |
返回 201 及附件对象,包含 attachmentId。
读取/写入附件内容
GET /etapi/attachments/{attachmentId}/content # 读取原始内容
PUT /etapi/attachments/{attachmentId}/content # 写入原始内容(binary body)
引用附件
在笔记 HTML 中使用以下路径引用:
api/attachments/{attachmentId}/image/{filename}
例如:api/attachments/YGMH54cTFaj4/image/beatles.jpg
二、Python 上传脚本
import urllib.request, json, base64
def upload_image_to_trilium(token, note_id, image_path, title, position=0):
"""Upload an image to a Trilium note via ETAPI."""
with open(image_path, 'rb') as f:
b64 = base64.b64encode(f.read()).decode('ascii')
# Determine MIME from extension
ext = image_path.rsplit('.', 1)[-1].lower()
mime_map = {'jpg': 'image/jpeg', 'jpeg': 'image/jpeg',
'png': 'image/png', 'gif': 'image/gif',
'webp': 'image/webp'}
mime = mime_map.get(ext, 'image/jpeg')
payload = json.dumps({
"ownerId": note_id,
"role": "image",
"mime": mime,
"title": title,
"content": b64,
"position": position
}).encode()
req = urllib.request.Request(
'https://trilium.atibm.com/etapi/attachments',
data=payload,
headers={
'Authorization': token,
'Content-Type': 'application/json'
}
)
resp = urllib.request.urlopen(req)
data = json.loads(resp.read())
return data['attachmentId'] # 返回 attachmentId 用于引用
三、Hermes 搜图途径
Hermes 没有 web_search 工具,但有以下搜图方式:
方法 A:PinchTab + DuckDuckGo 图片搜索
- 用 PinchTab 打开 DuckDuckGo 图片搜索
- 导航:
https://duckduckgo.com/?q={关键词}&iax=images&ia=images - 用
pinchtab_get_text或pinchtab_snapshot提取结果 - 用
pinchtab_click打开图片页 - 右键/检查获取图片 URL,用 curl 下载
方法 B:Wikimedia Commons API
- 搜索图片:
https://commons.wikimedia.org/w/api.php?action=query&list=search&srsearch={关键词}&srlimit=5&format=json&srnamespace=6 - 获取下载 URL:
https://commons.wikimedia.org/w/api.php?action=query&titles={文件名}&prop=imageinfo&iiprop=url&format=json - 用 curl 下载:
curl -sL -o output.jpg '{image_url}'
注意:Google 图片搜索有反爬验证(CAPTCHA),不可用。直接 curl 请求搜索引擎也被拦截。
四、完整工作流示例
- 搜图 — 用 PinchTab 开 DuckDuckGo 搜图,或 Wikimedia API 查找 CC 协议图片
- 下载 — 用 curl 下载到
/tmp/ - 上传 — 用 Python 脚本 base64 编码后 POST 到 ETAPI
- 引用 — 在笔记 HTML 中插入
<img src="api/attachments/{attachmentId}/image/{filename}"> - 更新 — 用 PUT /etapi/notes/{noteId}/content 写入更新后的 HTML
注意:PUT 更新内容时用 Content-Type: text/plain,不是 application/json。
五、常见问题
Q: 上传返回 500 "role must be given"
确认用的是 JSON body(非 multipart/form-data),且 ownerId 是已有笔记的 ID。
Q: 图片上传后笔记不显示
确认 attachmentId 拼写正确,且 role="image"。
Q: 笔记内容更新后返回 "Router not found"
确认用的是 PUT /etapi/notes/{noteId}/content,且 Content-Type 为 text/plain。