@hzttt/multimodal-rag 0.1.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md ADDED
@@ -0,0 +1,208 @@
1
+ # Multimodal RAG Plugin
2
+
3
+ OpenClaw 多模态 RAG 插件 — 使用本地 AI 模型对图像和音频进行语义索引与时间感知搜索。
4
+
5
+ ## 功能特性
6
+
7
+ - **图像索引**:使用 Qwen3-VL 自动描述图像内容并生成嵌入向量
8
+ - **音频索引**:使用 Whisper 转录音频并生成嵌入向量
9
+ - **语义搜索**:基于向量相似度的语义检索,支持中英文
10
+ - **时间过滤**:按文件创建时间范围过滤搜索结果
11
+ - **自动监听**:实时监听文件夹变化,自动索引新增文件
12
+ - **向量存储**:使用 LanceDB 高效存储和检索
13
+ - **智能去重**:基于文件 SHA256 哈希去重
14
+
15
+ ## 前置条件
16
+
17
+ - [Ollama](https://ollama.ai) 已安装并运行
18
+ - 以下 Ollama 模型已拉取:
19
+ - `qwen3-vl:2b` (视觉模型,图像描述)
20
+ - `qwen3-embedding:latest` (嵌入模型,向量生成)
21
+
22
+ ```bash
23
+ # 安装模型
24
+ ollama pull qwen3-vl:2b
25
+ ollama pull qwen3-embedding:latest
26
+ ```
27
+
28
+ ## 安装
29
+
30
+ ### 方式一:从 npm 安装(推荐)
31
+
32
+ ```bash
33
+ openclaw plugins install @hzttt/multimodal-rag
34
+ ```
35
+
36
+ 插件会自动安装到 `~/.openclaw/extensions/multimodal-rag/`,并自动安装所有运行时依赖。
37
+
38
+ ### 方式二:从 GitHub 安装
39
+
40
+ ```bash
41
+ openclaw plugins install github:hzttt/multimodal-rag
42
+ ```
43
+
44
+ ### 方式三:从本地路径安装
45
+
46
+ ```bash
47
+ git clone https://github.com/hzttt/multimodal-rag.git
48
+ openclaw plugins install ./multimodal-rag
49
+ ```
50
+
51
+ ## 配置
52
+
53
+ ### 交互式配置(推荐)
54
+
55
+ 安装完成后,运行引导配置向导:
56
+
57
+ ```bash
58
+ openclaw multimodal-rag setup
59
+ ```
60
+
61
+ 向导将引导你配置**文件监听路径**,其他参数已使用推荐的默认值:
62
+
63
+ - **Ollama 地址**: `http://127.0.0.1:11434`
64
+ - **视觉模型**: `qwen3-vl:2b` (图像描述)
65
+ - **嵌入模型**: `qwen3-embedding:latest` (向量生成)
66
+ - **嵌入提供者**: `ollama` (本地)
67
+ - **数据库路径**: `/home/lucy/.openclaw/multimodal-rag.lance`
68
+ - **启动时索引**: `true` (自动索引已有文件)
69
+
70
+ 你只需要指定要监听的文件夹路径即可。
71
+
72
+ ### 手动配置
73
+
74
+ 如需自定义配置,编辑 `~/.openclaw/openclaw.json`:
75
+
76
+ ```json
77
+ {
78
+ "plugins": {
79
+ "entries": {
80
+ "multimodal-rag": {
81
+ "enabled": true,
82
+ "config": {
83
+ "watchPaths": ["~/mic-recordings", "/home/lucy/usb_data"],
84
+ "ollama": {
85
+ "baseUrl": "http://127.0.0.1:11434",
86
+ "visionModel": "qwen3-vl:2b",
87
+ "embedModel": "qwen3-embedding:latest"
88
+ },
89
+ "embedding": {
90
+ "provider": "ollama"
91
+ },
92
+ "dbPath": "/home/lucy/.openclaw/multimodal-rag.lance",
93
+ "indexExistingOnStart": true
94
+ }
95
+ }
96
+ }
97
+ }
98
+ }
99
+ ```
100
+
101
+ ### 配置项说明
102
+
103
+ | 配置项 | 类型 | 默认值 | 说明 |
104
+ |--------|------|--------|------|
105
+ | `watchPaths` | string[] | `[]` | 监听的文件夹路径(支持 `~` 展开) |
106
+ | `ollama.baseUrl` | string | `http://127.0.0.1:11434` | Ollama 服务地址 |
107
+ | `ollama.visionModel` | string | `qwen3-vl:2b` | 用于图像描述的视觉模型 |
108
+ | `ollama.embedModel` | string | `qwen3-embedding:latest` | 用于生成嵌入向量的模型 |
109
+ | `embedding.provider` | string | `ollama` | 嵌入提供者: `ollama` 或 `openai` |
110
+ | `embedding.openaiApiKey` | string | - | OpenAI API Key(仅 openai 时需要) |
111
+ | `embedding.openaiModel` | string | `text-embedding-3-small` | OpenAI 嵌入模型 |
112
+ | `dbPath` | string | `~/.openclaw/multimodal-rag.lance` | LanceDB 数据库路径 |
113
+ | `watchDebounceMs` | number | `1000` | 文件监听去抖延迟(毫秒) |
114
+ | `indexExistingOnStart` | boolean | `true` | 启动时是否索引已有文件 |
115
+
116
+ 配置完成后,重启 OpenClaw Gateway 使配置生效。
117
+
118
+ ## 使用方法
119
+
120
+ ### Agent 工具
121
+
122
+ 插件注册 4 个 Agent 工具,可以在对话中自然地调用:
123
+
124
+ #### `media_search` — 语义搜索
125
+
126
+ ```
127
+ 用户:上周我去东方明珠拍的照片在哪
128
+ Agent:[调用 media_search] → 找到 3 张匹配的照片 → 发送给用户
129
+ ```
130
+
131
+ #### `media_describe` — 获取媒体描述
132
+
133
+ ```
134
+ 用户:这个录音说了什么
135
+ Agent:[调用 media_describe(filePath)] → 返回音频转录内容
136
+ ```
137
+
138
+ #### `media_list` — 浏览媒体文件
139
+
140
+ ```
141
+ 用户:列出最近的照片
142
+ Agent:[调用 media_list(type="image")] → 返回最近索引的图片列表
143
+ ```
144
+
145
+ #### `media_stats` — 查看库统计
146
+
147
+ ```
148
+ 用户:我的媒体库有多少文件
149
+ Agent:[调用 media_stats] → 总计 120 个文件,图片 80,音频 40
150
+ ```
151
+
152
+ ### CLI 命令
153
+
154
+ ```bash
155
+ # 交互式配置
156
+ openclaw multimodal-rag setup
157
+
158
+ # 手动索引文件或文件夹
159
+ openclaw multimodal-rag index ~/Pictures/photo.jpg
160
+
161
+ # 语义搜索
162
+ openclaw multimodal-rag search "东方明珠"
163
+ openclaw multimodal-rag search "会议讨论" --type audio --after 2026-01-29
164
+
165
+ # 查看索引统计
166
+ openclaw multimodal-rag stats
167
+
168
+ # 列出已索引文件
169
+ openclaw multimodal-rag list --type image --limit 10
170
+
171
+ # 完整重新索引
172
+ openclaw multimodal-rag reindex --confirm
173
+
174
+ # 清空索引
175
+ openclaw multimodal-rag clear --confirm
176
+ ```
177
+
178
+ ## 故障排除
179
+
180
+ ### Ollama 连接失败
181
+
182
+ ```bash
183
+ # 确保 Ollama 已启动
184
+ ollama serve
185
+
186
+ # 检查连接
187
+ curl http://127.0.0.1:11434/api/tags
188
+ ```
189
+
190
+ ### 嵌入维度不匹配
191
+
192
+ 切换嵌入模型后需要重建索引:
193
+
194
+ ```bash
195
+ openclaw multimodal-rag reindex --confirm
196
+ ```
197
+
198
+ ### 文件监听不生效
199
+
200
+ 检查路径是否正确,以及插件是否已启用:
201
+
202
+ ```bash
203
+ openclaw plugins list | grep multimodal-rag
204
+ ```
205
+
206
+ ## 许可证
207
+
208
+ MIT
package/index.ts ADDED
@@ -0,0 +1,321 @@
1
+ /**
2
+ * OpenClaw Multimodal RAG Plugin
3
+ *
4
+ * 多模态 RAG 插件,支持图像和音频的语义索引与时间感知搜索。
5
+ */
6
+
7
+ import type { OpenClawPluginApi } from "openclaw/plugin-sdk";
8
+ import { MediaStorage } from "./src/storage.js";
9
+ import { createEmbeddingProvider } from "./src/embeddings.js";
10
+ import { createMediaProcessor } from "./src/processor.js";
11
+ import { MediaWatcher } from "./src/watcher.js";
12
+ import {
13
+ createMediaSearchTool,
14
+ createMediaDescribeTool,
15
+ createMediaListTool,
16
+ createMediaStatsTool,
17
+ } from "./src/tools.js";
18
+ import { runSetup } from "./src/setup.js";
19
+ import type { PluginConfig } from "./src/types.js";
20
+
21
+ const multimodalRagPlugin = {
22
+ id: "multimodal-rag",
23
+ name: "Multimodal RAG",
24
+ description:
25
+ "多模态 RAG 插件,支持图像和音频的语义索引与时间感知搜索",
26
+ kind: "rag" as const,
27
+
28
+ register(api: OpenClawPluginApi) {
29
+ // 解析配置(合并默认值)
30
+ const userConfig = (api.pluginConfig || {}) as Partial<PluginConfig>;
31
+
32
+ const cfg: PluginConfig = {
33
+ watchPaths: userConfig.watchPaths || [],
34
+ fileTypes: {
35
+ image: userConfig.fileTypes?.image || [".jpg", ".jpeg", ".png", ".webp", ".gif", ".heic"],
36
+ audio: userConfig.fileTypes?.audio || [".wav", ".mp3", ".m4a", ".ogg", ".flac", ".aac"],
37
+ },
38
+ ollama: {
39
+ baseUrl: userConfig.ollama?.baseUrl || "http://127.0.0.1:11434",
40
+ visionModel: userConfig.ollama?.visionModel || "qwen3-vl:2b",
41
+ embedModel: userConfig.ollama?.embedModel || "qwen3-embedding:latest",
42
+ },
43
+ embedding: {
44
+ provider: userConfig.embedding?.provider || "ollama",
45
+ openaiApiKey: userConfig.embedding?.openaiApiKey,
46
+ openaiModel: userConfig.embedding?.openaiModel || "text-embedding-3-small",
47
+ },
48
+ dbPath: userConfig.dbPath || "~/.openclaw/multimodal-rag.lance",
49
+ watchDebounceMs: userConfig.watchDebounceMs || 1000,
50
+ indexExistingOnStart: userConfig.indexExistingOnStart !== false,
51
+ };
52
+
53
+ // 解析数据库路径
54
+ const resolvedDbPath = api.resolvePath(cfg.dbPath);
55
+
56
+ // 创建嵌入提供者
57
+ const embeddings = createEmbeddingProvider({
58
+ provider: cfg.embedding.provider,
59
+ ollamaBaseUrl: cfg.ollama.baseUrl,
60
+ ollamaModel: cfg.ollama.embedModel,
61
+ openaiApiKey: cfg.embedding.openaiApiKey,
62
+ openaiModel: cfg.embedding.openaiModel,
63
+ });
64
+
65
+ const vectorDim = embeddings.getDimension();
66
+ api.logger.info?.(
67
+ `multimodal-rag: Using ${cfg.embedding.provider} embeddings (dim=${vectorDim})`,
68
+ );
69
+
70
+ // 创建存储
71
+ const storage = new MediaStorage(resolvedDbPath, vectorDim);
72
+
73
+ // 创建媒体处理器
74
+ const processor = createMediaProcessor({
75
+ ollamaBaseUrl: cfg.ollama.baseUrl,
76
+ visionModel: cfg.ollama.visionModel,
77
+ });
78
+
79
+ // 创建文件监听器
80
+ const watcher = new MediaWatcher(cfg, storage, embeddings, processor, api.logger);
81
+
82
+ // ========================================================================
83
+ // 注册工具
84
+ // ========================================================================
85
+
86
+ // 1. 统计工具 - 让 Agent 了解媒体库状态
87
+ api.registerTool(createMediaStatsTool(storage, watcher), {
88
+ name: "media_stats",
89
+ });
90
+
91
+ // 2. 搜索工具 - 主要的内容查找工具
92
+ api.registerTool(createMediaSearchTool(storage, embeddings), {
93
+ name: "media_search",
94
+ });
95
+
96
+ // 3. 列表工具 - 浏览和按时间过滤
97
+ api.registerTool(createMediaListTool(storage, cfg), {
98
+ name: "media_list",
99
+ });
100
+
101
+ // 4. 描述工具 - 查看单个文件详情
102
+ api.registerTool(createMediaDescribeTool(storage, processor, embeddings, watcher), {
103
+ name: "media_describe",
104
+ });
105
+
106
+ api.logger.info?.("multimodal-rag: Registered 4 agent tools");
107
+
108
+ // ========================================================================
109
+ // 注册 CLI 命令
110
+ // ========================================================================
111
+
112
+ api.registerCli(({ program }) => {
113
+ const rag = program
114
+ .command("multimodal-rag")
115
+ .description("Multimodal RAG plugin commands");
116
+
117
+ // openclaw multimodal-rag index <path>
118
+ rag
119
+ .command("index")
120
+ .description("手动索引指定路径的媒体文件")
121
+ .argument("<path>", "文件或文件夹路径")
122
+ .action(async (path: string) => {
123
+ try {
124
+ await watcher.indexPath(path);
125
+ console.log(`✓ 索引完成: ${path}`);
126
+ } catch (error) {
127
+ console.error(`✗ 索引失败: ${String(error)}`);
128
+ process.exit(1);
129
+ }
130
+ });
131
+
132
+ // openclaw multimodal-rag search <query>
133
+ rag
134
+ .command("search")
135
+ .description("搜索媒体文件")
136
+ .argument("<query>", "搜索查询")
137
+ .option("--type <type>", "媒体类型: image, audio, all", "all")
138
+ .option("--after <date>", "开始时间 (ISO 格式)")
139
+ .option("--before <date>", "结束时间 (ISO 格式)")
140
+ .option("--limit <n>", "返回数量", "5")
141
+ .action(async (query: string, opts: any) => {
142
+ try {
143
+ const vector = await embeddings.embed(query);
144
+ const afterTs = opts.after ? new Date(opts.after).getTime() : undefined;
145
+ const beforeTs = opts.before ? new Date(opts.before).getTime() : undefined;
146
+
147
+ const results = await storage.search(vector, {
148
+ type: opts.type,
149
+ after: afterTs,
150
+ before: beforeTs,
151
+ limit: Number.parseInt(opts.limit),
152
+ minScore: 0.3,
153
+ });
154
+
155
+ if (results.length === 0) {
156
+ console.log("未找到相关媒体文件");
157
+ return;
158
+ }
159
+
160
+ console.log(`找到 ${results.length} 个相关媒体文件:\n`);
161
+ for (const r of results) {
162
+ const date = new Date(r.entry.fileCreatedAt).toLocaleString("zh-CN");
163
+ const score = (r.score * 100).toFixed(0);
164
+ console.log(`[${r.entry.fileType}] ${r.entry.fileName} (${score}%)`);
165
+ console.log(` 路径: ${r.entry.filePath}`);
166
+ console.log(` 时间: ${date}`);
167
+ console.log(` 描述: ${r.entry.description.slice(0, 100)}...\n`);
168
+ }
169
+ } catch (error) {
170
+ console.error(`搜索失败: ${String(error)}`);
171
+ process.exit(1);
172
+ }
173
+ });
174
+
175
+ // openclaw multimodal-rag stats
176
+ rag
177
+ .command("stats")
178
+ .description("显示索引统计")
179
+ .action(async () => {
180
+ try {
181
+ // 使用 count() 统一查询逻辑(全量扫描 + 内存过滤)
182
+ const total = await storage.count();
183
+ const imageCount = await storage.count("image");
184
+ const audioCount = await storage.count("audio");
185
+
186
+ console.log("媒体库统计:");
187
+ console.log(` 总计: ${total} 个文件`);
188
+ console.log(` 图片: ${imageCount} 个`);
189
+ console.log(` 音频: ${audioCount} 个`);
190
+
191
+ // 数据完整性检查
192
+ if (total !== imageCount + audioCount) {
193
+ console.log(` 警告: 总数不匹配 (${total} ≠ ${imageCount} + ${audioCount})`);
194
+ }
195
+ } catch (error) {
196
+ console.error(`统计失败: ${String(error)}`);
197
+ process.exit(1);
198
+ }
199
+ });
200
+
201
+ // openclaw multimodal-rag list
202
+ rag
203
+ .command("list")
204
+ .description("列出已索引的媒体文件")
205
+ .option("--type <type>", "媒体类型: image, audio, all", "all")
206
+ .option("--after <date>", "开始时间 (ISO 格式)")
207
+ .option("--before <date>", "结束时间 (ISO 格式)")
208
+ .option("--limit <n>", "返回数量", "20")
209
+ .option("--offset <n>", "偏移量", "0")
210
+ .action(async (opts: any) => {
211
+ try {
212
+ const afterTs = opts.after ? new Date(opts.after).getTime() : undefined;
213
+ const beforeTs = opts.before ? new Date(opts.before).getTime() : undefined;
214
+
215
+ const { total, entries } = await storage.list({
216
+ type: opts.type,
217
+ after: afterTs,
218
+ before: beforeTs,
219
+ limit: Number.parseInt(opts.limit),
220
+ offset: Number.parseInt(opts.offset),
221
+ });
222
+
223
+ if (entries.length === 0) {
224
+ console.log("没有找到符合条件的媒体文件");
225
+ return;
226
+ }
227
+
228
+ console.log(`已索引 ${total} 个媒体文件:\n`);
229
+ for (let i = 0; i < entries.length; i++) {
230
+ const e = entries[i];
231
+ const date = new Date(e.fileCreatedAt).toLocaleString("zh-CN");
232
+ console.log(`${opts.offset + i + 1}. [${e.fileType}] ${e.fileName}`);
233
+ console.log(` 路径: ${e.filePath}`);
234
+ console.log(` 时间: ${date}`);
235
+ console.log(` 描述: ${e.description.slice(0, 80)}${e.description.length > 80 ? "..." : ""}\n`);
236
+ }
237
+
238
+ if (total > opts.offset + entries.length) {
239
+ console.log(`(显示 ${opts.offset + 1}-${opts.offset + entries.length},共 ${total} 个)`);
240
+ }
241
+ } catch (error) {
242
+ console.error(`列表失败: ${String(error)}`);
243
+ process.exit(1);
244
+ }
245
+ });
246
+
247
+ // openclaw multimodal-rag clear
248
+ rag
249
+ .command("clear")
250
+ .description("清空索引(谨慎使用)")
251
+ .option("--confirm", "确认清空")
252
+ .action(async (opts: any) => {
253
+ if (!opts.confirm) {
254
+ console.error("请使用 --confirm 确认清空操作");
255
+ process.exit(1);
256
+ }
257
+
258
+ try {
259
+ await storage.clear();
260
+ console.log("✓ 索引已清空");
261
+ } catch (error) {
262
+ console.error(`清空失败: ${String(error)}`);
263
+ process.exit(1);
264
+ }
265
+ });
266
+
267
+ // openclaw multimodal-rag reindex
268
+ rag
269
+ .command("reindex")
270
+ .description("完整重新索引(清空数据库并重新扫描所有文件)")
271
+ .option("--confirm", "确认重新索引")
272
+ .action(async (opts: any) => {
273
+ if (!opts.confirm) {
274
+ console.error("请使用 --confirm 确认重新索引操作");
275
+ console.error("警告: 此操作会清空现有索引并重新扫描所有文件");
276
+ process.exit(1);
277
+ }
278
+
279
+ try {
280
+ console.log("开始完整重新索引...");
281
+ await watcher.reindexAll();
282
+ console.log("✓ 重新索引完成");
283
+ console.log("提示: 使用 'openclaw multimodal-rag stats' 查看进度");
284
+ } catch (error) {
285
+ console.error(`重新索引失败: ${String(error)}`);
286
+ process.exit(1);
287
+ }
288
+ });
289
+
290
+ // openclaw multimodal-rag setup
291
+ rag
292
+ .command("setup")
293
+ .description("交互式引导配置插件")
294
+ .action(async () => {
295
+ await runSetup();
296
+ });
297
+ }, { commands: ["multimodal-rag"] });
298
+
299
+ // ========================================================================
300
+ // 注册服务(文件监听)
301
+ // ========================================================================
302
+
303
+ api.registerService({
304
+ id: "multimodal-rag-watcher",
305
+ start: async () => {
306
+ await watcher.start();
307
+ api.logger.info?.("multimodal-rag: File watcher started");
308
+ },
309
+ stop: async () => {
310
+ await watcher.stop();
311
+ api.logger.info?.("multimodal-rag: File watcher stopped");
312
+ },
313
+ });
314
+
315
+ api.logger.info?.(
316
+ `multimodal-rag: Plugin initialized (db: ${resolvedDbPath})`,
317
+ );
318
+ },
319
+ };
320
+
321
+ export default multimodalRagPlugin;
@@ -0,0 +1,114 @@
1
+ {
2
+ "id": "multimodal-rag",
3
+ "name": "Multimodal RAG",
4
+ "description": "多模态 RAG 插件,使用本地 AI 模型对图像和音频进行语义索引与时间感知搜索",
5
+ "version": "0.1.0",
6
+ "kind": "rag",
7
+ "configSchema": {
8
+ "type": "object",
9
+ "properties": {
10
+ "watchPaths": {
11
+ "type": "array",
12
+ "items": { "type": "string" },
13
+ "default": [],
14
+ "description": "监听的文件夹路径列表(支持 ~ 展开)"
15
+ },
16
+ "fileTypes": {
17
+ "type": "object",
18
+ "properties": {
19
+ "image": {
20
+ "type": "array",
21
+ "items": { "type": "string" },
22
+ "default": [".jpg", ".jpeg", ".png", ".webp", ".gif", ".heic"]
23
+ },
24
+ "audio": {
25
+ "type": "array",
26
+ "items": { "type": "string" },
27
+ "default": [".wav", ".mp3", ".m4a", ".ogg", ".flac", ".aac"]
28
+ }
29
+ },
30
+ "default": {}
31
+ },
32
+ "ollama": {
33
+ "type": "object",
34
+ "properties": {
35
+ "baseUrl": {
36
+ "type": "string",
37
+ "default": "http://127.0.0.1:11434"
38
+ },
39
+ "visionModel": {
40
+ "type": "string",
41
+ "default": "qwen3-vl:2b",
42
+ "description": "用于图像描述的视觉模型"
43
+ },
44
+ "embedModel": {
45
+ "type": "string",
46
+ "default": "qwen3-embedding:latest",
47
+ "description": "用于生成嵌入向量的模型"
48
+ }
49
+ },
50
+ "default": {}
51
+ },
52
+ "embedding": {
53
+ "type": "object",
54
+ "properties": {
55
+ "provider": {
56
+ "type": "string",
57
+ "enum": ["ollama", "openai"],
58
+ "default": "ollama"
59
+ },
60
+ "openaiApiKey": {
61
+ "type": "string",
62
+ "description": "OpenAI API Key(仅当 provider=openai 时需要)"
63
+ },
64
+ "openaiModel": {
65
+ "type": "string",
66
+ "default": "text-embedding-3-small"
67
+ }
68
+ },
69
+ "default": {}
70
+ },
71
+ "dbPath": {
72
+ "type": "string",
73
+ "default": "~/.openclaw/multimodal-rag.lance",
74
+ "description": "LanceDB 数据库路径"
75
+ },
76
+ "watchDebounceMs": {
77
+ "type": "number",
78
+ "default": 1000,
79
+ "description": "文件监听去抖延迟(毫秒)"
80
+ },
81
+ "indexExistingOnStart": {
82
+ "type": "boolean",
83
+ "default": true,
84
+ "description": "启动时是否索引现有文件"
85
+ }
86
+ }
87
+ },
88
+ "uiHints": {
89
+ "watchPaths": {
90
+ "label": "监听路径",
91
+ "placeholder": "~/mic-recordings"
92
+ },
93
+ "ollama.visionModel": {
94
+ "label": "视觉模型",
95
+ "placeholder": "qwen3-vl:2b"
96
+ },
97
+ "ollama.embedModel": {
98
+ "label": "嵌入模型",
99
+ "placeholder": "qwen3-embedding:latest"
100
+ },
101
+ "embedding.openaiApiKey": {
102
+ "label": "OpenAI API Key",
103
+ "sensitive": true
104
+ },
105
+ "dbPath": {
106
+ "label": "数据库路径",
107
+ "advanced": true
108
+ },
109
+ "watchDebounceMs": {
110
+ "label": "去抖延迟(毫秒)",
111
+ "advanced": true
112
+ }
113
+ }
114
+ }
package/package.json ADDED
@@ -0,0 +1,49 @@
1
+ {
2
+ "name": "@hzttt/multimodal-rag",
3
+ "version": "0.1.1",
4
+ "description": "OpenClaw plugin for multimodal RAG - semantic indexing and time-aware search for images and audio using local AI models",
5
+ "type": "module",
6
+ "repository": {
7
+ "type": "git",
8
+ "url": "https://github.com/hzttt/multimodal-rag.git"
9
+ },
10
+ "scripts": {
11
+ "build": "tsc",
12
+ "test": "node test/test-embedding.js"
13
+ },
14
+ "keywords": [
15
+ "openclaw",
16
+ "plugin",
17
+ "rag",
18
+ "multimodal",
19
+ "vision",
20
+ "embedding",
21
+ "lancedb",
22
+ "ollama",
23
+ "whisper"
24
+ ],
25
+ "author": "hzttt",
26
+ "license": "MIT",
27
+ "files": [
28
+ "index.ts",
29
+ "src/",
30
+ "openclaw.plugin.json",
31
+ "README.md"
32
+ ],
33
+ "dependencies": {
34
+ "@lancedb/lancedb": "^0.14.0",
35
+ "@sinclair/typebox": "^0.33.0",
36
+ "chokidar": "^4.0.0"
37
+ },
38
+ "peerDependencies": {
39
+ "openclaw": "*"
40
+ },
41
+ "openclaw": {
42
+ "extensions": [
43
+ "./index.ts"
44
+ ],
45
+ "install": {
46
+ "npmSpec": "@hzttt/multimodal-rag"
47
+ }
48
+ }
49
+ }