@hzttt/multimodal-rag 0.1.1 → 0.1.2

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.
Files changed (4) hide show
  1. package/README.md +64 -15
  2. package/index.ts +44 -4
  3. package/package.json +1 -1
  4. package/src/setup.ts +86 -16
package/README.md CHANGED
@@ -30,7 +30,7 @@ ollama pull qwen3-embedding:latest
30
30
  ### 方式一:从 npm 安装(推荐)
31
31
 
32
32
  ```bash
33
- openclaw plugins install @hzttt/multimodal-rag
33
+ openclaw plugins install @hzttt/multimodal-rag@latest
34
34
  ```
35
35
 
36
36
  插件会自动安装到 `~/.openclaw/extensions/multimodal-rag/`,并自动安装所有运行时依赖。
@@ -64,11 +64,55 @@ openclaw multimodal-rag setup
64
64
  - **视觉模型**: `qwen3-vl:2b` (图像描述)
65
65
  - **嵌入模型**: `qwen3-embedding:latest` (向量生成)
66
66
  - **嵌入提供者**: `ollama` (本地)
67
- - **数据库路径**: `/home/lucy/.openclaw/multimodal-rag.lance`
67
+ - **数据库路径**: `~/.openclaw/multimodal-rag.lance`
68
68
  - **启动时索引**: `true` (自动索引已有文件)
69
69
 
70
70
  你只需要指定要监听的文件夹路径即可。
71
71
 
72
+ ### 非交互式配置(适合脚本/远程部署)
73
+
74
+ 通过命令行参数一次性完成配置,无需交互输入,适用于 SSH 远程部署、CI/CD 脚本等场景:
75
+
76
+ ```bash
77
+ # 最简用法:只指定监听路径(其他使用默认值)
78
+ openclaw multimodal-rag setup --non-interactive --watch ~/photos --watch ~/audio
79
+
80
+ # 简写形式
81
+ openclaw multimodal-rag setup -n -w ~/photos -w ~/audio
82
+
83
+ # 逗号分隔多个路径
84
+ openclaw multimodal-rag setup -n --watch ~/photos,~/mic-recordings,~/usb_data
85
+
86
+ # 自定义所有参数
87
+ openclaw multimodal-rag setup -n \
88
+ --watch ~/photos --watch ~/audio \
89
+ --ollama-url http://192.168.0.100:11434 \
90
+ --vision-model qwen3-vl:2b \
91
+ --embed-model qwen3-embedding:latest \
92
+ --db-path ~/.openclaw/my-rag.lance \
93
+ --no-index-on-start
94
+
95
+ # 使用 OpenAI 嵌入
96
+ openclaw multimodal-rag setup -n \
97
+ --watch ~/photos \
98
+ --embedding-provider openai \
99
+ --openai-api-key sk-xxx \
100
+ --openai-model text-embedding-3-small
101
+ ```
102
+
103
+ | 选项 | 简写 | 说明 | 默认值 |
104
+ | --- | --- | --- | --- |
105
+ | `--non-interactive` | `-n` | 启用非交互式模式 | - |
106
+ | `--watch <paths...>` | `-w` | 监听路径(可多次指定或逗号分隔) | 必填 |
107
+ | `--ollama-url <url>` | - | Ollama 服务地址 | `http://127.0.0.1:11434` |
108
+ | `--vision-model <model>` | - | 视觉模型 | `qwen3-vl:2b` |
109
+ | `--embed-model <model>` | - | 嵌入模型 | `qwen3-embedding:latest` |
110
+ | `--embedding-provider <p>` | - | 嵌入提供者: `ollama` / `openai` | `ollama` |
111
+ | `--openai-api-key <key>` | - | OpenAI API Key | - |
112
+ | `--openai-model <model>` | - | OpenAI 嵌入模型 | `text-embedding-3-small` |
113
+ | `--db-path <path>` | - | LanceDB 数据库路径 | `~/.openclaw/multimodal-rag.lance` |
114
+ | `--no-index-on-start` | - | 启动时不索引已有文件 | `false` |
115
+
72
116
  ### 手动配置
73
117
 
74
118
  如需自定义配置,编辑 `~/.openclaw/openclaw.json`:
@@ -100,18 +144,20 @@ openclaw multimodal-rag setup
100
144
 
101
145
  ### 配置项说明
102
146
 
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` | 启动时是否索引已有文件 |
147
+
148
+ | 配置项 | 类型 | 默认值 | 说明 |
149
+ | ------------------------ | -------- | ---------------------------------- | ---------------------------- |
150
+ | `watchPaths` | string[] | `[]` | 监听的文件夹路径(支持 `~` 展开) |
151
+ | `ollama.baseUrl` | string | `http://127.0.0.1:11434` | Ollama 服务地址 |
152
+ | `ollama.visionModel` | string | `qwen3-vl:2b` | 用于图像描述的视觉模型 |
153
+ | `ollama.embedModel` | string | `qwen3-embedding:latest` | 用于生成嵌入向量的模型 |
154
+ | `embedding.provider` | string | `ollama` | 嵌入提供者: `ollama` `openai` |
155
+ | `embedding.openaiApiKey` | string | - | OpenAI API Key(仅 openai 时需要) |
156
+ | `embedding.openaiModel` | string | `text-embedding-3-small` | OpenAI 嵌入模型 |
157
+ | `dbPath` | string | `~/.openclaw/multimodal-rag.lance` | LanceDB 数据库路径 |
158
+ | `watchDebounceMs` | number | `1000` | 文件监听去抖延迟(毫秒) |
159
+ | `indexExistingOnStart` | boolean | `true` | 启动时是否索引已有文件 |
160
+
115
161
 
116
162
  配置完成后,重启 OpenClaw Gateway 使配置生效。
117
163
 
@@ -155,6 +201,9 @@ Agent:[调用 media_stats] → 总计 120 个文件,图片 80,音频 40
155
201
  # 交互式配置
156
202
  openclaw multimodal-rag setup
157
203
 
204
+ # 非交互式配置
205
+ openclaw multimodal-rag setup -n --watch ~/photos --watch ~/audio
206
+
158
207
  # 手动索引文件或文件夹
159
208
  openclaw multimodal-rag index ~/Pictures/photo.jpg
160
209
 
@@ -205,4 +254,4 @@ openclaw plugins list | grep multimodal-rag
205
254
 
206
255
  ## 许可证
207
256
 
208
- MIT
257
+ MIT
package/index.ts CHANGED
@@ -15,7 +15,7 @@ import {
15
15
  createMediaListTool,
16
16
  createMediaStatsTool,
17
17
  } from "./src/tools.js";
18
- import { runSetup } from "./src/setup.js";
18
+ import { runSetup, runNonInteractiveSetup } from "./src/setup.js";
19
19
  import type { PluginConfig } from "./src/types.js";
20
20
 
21
21
  const multimodalRagPlugin = {
@@ -288,11 +288,51 @@ const multimodalRagPlugin = {
288
288
  });
289
289
 
290
290
  // openclaw multimodal-rag setup
291
+ // 支持交互式和非交互式两种模式:
292
+ // 交互式: openclaw multimodal-rag setup
293
+ // 非交互式: openclaw multimodal-rag setup -n --watch ~/photos --watch ~/audio
291
294
  rag
292
295
  .command("setup")
293
- .description("交互式引导配置插件")
294
- .action(async () => {
295
- await runSetup();
296
+ .description("配置插件(支持交互式和非交互式模式)")
297
+ .option("-n, --non-interactive", "非交互式模式(需配合 --watch 使用)")
298
+ .option("-w, --watch <paths...>", "监听路径(可多次指定或逗号分隔)")
299
+ .option("--ollama-url <url>", "Ollama 服务地址", "http://127.0.0.1:11434")
300
+ .option("--vision-model <model>", "视觉模型名称", "qwen3-vl:2b")
301
+ .option("--embed-model <model>", "嵌入模型名称", "qwen3-embedding:latest")
302
+ .option("--embedding-provider <provider>", "嵌入提供者: ollama 或 openai", "ollama")
303
+ .option("--openai-api-key <key>", "OpenAI API Key(仅 openai 时需要)")
304
+ .option("--openai-model <model>", "OpenAI 嵌入模型")
305
+ .option("--db-path <path>", "LanceDB 数据库路径")
306
+ .option("--no-index-on-start", "启动时不索引已有文件")
307
+ .action(async (opts: {
308
+ nonInteractive?: boolean;
309
+ watch?: string[];
310
+ ollamaUrl?: string;
311
+ visionModel?: string;
312
+ embedModel?: string;
313
+ embeddingProvider?: string;
314
+ openaiApiKey?: string;
315
+ openaiModel?: string;
316
+ dbPath?: string;
317
+ noIndexOnStart?: boolean;
318
+ }) => {
319
+ if (opts.nonInteractive) {
320
+ // 非交互式模式:展开逗号分隔的路径
321
+ const watchPaths = (opts.watch || []).flatMap((p) => p.split(",").map((s) => s.trim()).filter(Boolean));
322
+ await runNonInteractiveSetup({
323
+ watch: watchPaths,
324
+ ollamaUrl: opts.ollamaUrl,
325
+ visionModel: opts.visionModel,
326
+ embedModel: opts.embedModel,
327
+ embeddingProvider: opts.embeddingProvider as "ollama" | "openai" | undefined,
328
+ openaiApiKey: opts.openaiApiKey,
329
+ openaiModel: opts.openaiModel,
330
+ dbPath: opts.dbPath,
331
+ noIndexOnStart: opts.noIndexOnStart,
332
+ });
333
+ } else {
334
+ await runSetup();
335
+ }
296
336
  });
297
337
  }, { commands: ["multimodal-rag"] });
298
338
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@hzttt/multimodal-rag",
3
- "version": "0.1.1",
3
+ "version": "0.1.2",
4
4
  "description": "OpenClaw plugin for multimodal RAG - semantic indexing and time-aware search for images and audio using local AI models",
5
5
  "type": "module",
6
6
  "repository": {
package/src/setup.ts CHANGED
@@ -1,8 +1,8 @@
1
1
  /**
2
- * 交互式引导配置
2
+ * 引导配置(交互式 & 非交互式)
3
3
  *
4
- * 运行 `openclaw multimodal-rag setup` 时调用,
5
- * 引导用户完成必要配置并写入 openclaw 配置文件。
4
+ * 交互式: `openclaw multimodal-rag setup`
5
+ * 非交互式: `openclaw multimodal-rag setup --watch ~/photos,~/audio --non-interactive`
6
6
  */
7
7
 
8
8
  import * as readline from "node:readline/promises";
@@ -31,6 +31,19 @@ type PluginConfigPartial = {
31
31
  indexExistingOnStart?: boolean;
32
32
  };
33
33
 
34
+ /** 非交互式 setup 的选项 */
35
+ export type NonInteractiveSetupOpts = {
36
+ watch: string[];
37
+ ollamaUrl?: string;
38
+ visionModel?: string;
39
+ embedModel?: string;
40
+ embeddingProvider?: "ollama" | "openai";
41
+ openaiApiKey?: string;
42
+ openaiModel?: string;
43
+ dbPath?: string;
44
+ noIndexOnStart?: boolean;
45
+ };
46
+
34
47
  function loadOpenClawConfig(): Record<string, unknown> {
35
48
  if (!fs.existsSync(CONFIG_FILE)) {
36
49
  return {};
@@ -54,6 +67,75 @@ function getExistingPluginConfig(config: Record<string, unknown>): PluginConfigP
54
67
  return (entry?.config as PluginConfigPartial) || {};
55
68
  }
56
69
 
70
+ /**
71
+ * 将插件配置写入 openclaw.json
72
+ */
73
+ function writePluginConfig(pluginConfig: PluginConfigPartial): void {
74
+ const config = loadOpenClawConfig();
75
+ const plugins = (config.plugins || {}) as Record<string, unknown>;
76
+ const entries = (plugins.entries || {}) as Record<string, unknown>;
77
+ const pluginEntry = (entries["multimodal-rag"] || {}) as Record<string, unknown>;
78
+
79
+ pluginEntry.enabled = true;
80
+ pluginEntry.config = pluginConfig;
81
+
82
+ entries["multimodal-rag"] = pluginEntry;
83
+ plugins.entries = entries;
84
+ config.plugins = plugins;
85
+
86
+ saveOpenClawConfig(config);
87
+ }
88
+
89
+ /**
90
+ * 非交互式配置
91
+ *
92
+ * 适用于脚本自动化、SSH 远程部署等场景。
93
+ * 所有参数通过命令行选项传入,不读取 stdin。
94
+ *
95
+ * 用法:
96
+ * openclaw multimodal-rag setup --non-interactive --watch ~/photos,~/audio
97
+ * openclaw multimodal-rag setup -n -w ~/photos -w ~/audio --ollama-url http://host:11434
98
+ */
99
+ export async function runNonInteractiveSetup(opts: NonInteractiveSetupOpts): Promise<void> {
100
+ if (opts.watch.length === 0) {
101
+ console.error("✗ 非交互式模式必须通过 --watch 指定至少一个监听路径");
102
+ console.error(" 示例: openclaw multimodal-rag setup --non-interactive --watch ~/photos");
103
+ process.exit(1);
104
+ }
105
+
106
+ const existing = getExistingPluginConfig(loadOpenClawConfig());
107
+
108
+ const pluginConfig: PluginConfigPartial = {
109
+ watchPaths: opts.watch,
110
+ ollama: {
111
+ baseUrl: opts.ollamaUrl || existing.ollama?.baseUrl || "http://127.0.0.1:11434",
112
+ visionModel: opts.visionModel || existing.ollama?.visionModel || "qwen3-vl:2b",
113
+ embedModel: opts.embedModel || existing.ollama?.embedModel || "qwen3-embedding:latest",
114
+ },
115
+ embedding: {
116
+ provider: opts.embeddingProvider || existing.embedding?.provider || "ollama",
117
+ ...(opts.openaiApiKey && { openaiApiKey: opts.openaiApiKey }),
118
+ ...(opts.openaiModel && { openaiModel: opts.openaiModel }),
119
+ },
120
+ dbPath: opts.dbPath || existing.dbPath || "~/.openclaw/multimodal-rag.lance",
121
+ indexExistingOnStart: opts.noIndexOnStart ? false : (existing.indexExistingOnStart !== false),
122
+ };
123
+
124
+ writePluginConfig(pluginConfig);
125
+
126
+ console.log("✓ 配置已保存到 ~/.openclaw/openclaw.json\n");
127
+ console.log("配置摘要:");
128
+ console.log(` 监听路径: ${pluginConfig.watchPaths!.join(", ")}`);
129
+ console.log(` Ollama 地址: ${pluginConfig.ollama!.baseUrl}`);
130
+ console.log(` 视觉模型: ${pluginConfig.ollama!.visionModel}`);
131
+ console.log(` 嵌入模型: ${pluginConfig.ollama!.embedModel}`);
132
+ console.log(` 嵌入提供者: ${pluginConfig.embedding!.provider}`);
133
+ console.log(` 数据库路径: ${pluginConfig.dbPath}`);
134
+ console.log(` 启动时索引: ${pluginConfig.indexExistingOnStart ? "是" : "否"}`);
135
+ console.log();
136
+ console.log("提示: 重启 OpenClaw Gateway 以加载新配置");
137
+ }
138
+
57
139
  async function checkOllamaHealth(baseUrl: string): Promise<boolean> {
58
140
  try {
59
141
  const res = await fetch(`${baseUrl}/api/tags`, { signal: AbortSignal.timeout(5000) });
@@ -148,19 +230,7 @@ export async function runSetup(): Promise<void> {
148
230
  // ================================================================
149
231
  console.log("\n── 保存配置 ──\n");
150
232
 
151
- // 深合并到 openclaw 配置
152
- const plugins = (config.plugins || {}) as Record<string, unknown>;
153
- const entries = (plugins.entries || {}) as Record<string, unknown>;
154
- const pluginEntry = (entries["multimodal-rag"] || {}) as Record<string, unknown>;
155
-
156
- pluginEntry.enabled = true;
157
- pluginEntry.config = pluginConfig;
158
-
159
- entries["multimodal-rag"] = pluginEntry;
160
- plugins.entries = entries;
161
- config.plugins = plugins;
162
-
163
- saveOpenClawConfig(config);
233
+ writePluginConfig(pluginConfig);
164
234
 
165
235
  console.log("✓ 配置已保存到 ~/.openclaw/openclaw.json\n");
166
236