@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.
- package/README.md +64 -15
- package/index.ts +44 -4
- package/package.json +1 -1
- 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
|
-
- **数据库路径**:
|
|
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
|
-
|
|
|
106
|
-
| `
|
|
107
|
-
| `ollama.
|
|
108
|
-
| `ollama.
|
|
109
|
-
| `
|
|
110
|
-
| `embedding.
|
|
111
|
-
| `embedding.
|
|
112
|
-
| `
|
|
113
|
-
| `
|
|
114
|
-
| `
|
|
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
|
-
.
|
|
295
|
-
|
|
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
package/src/setup.ts
CHANGED
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
/**
|
|
2
|
-
*
|
|
2
|
+
* 引导配置(交互式 & 非交互式)
|
|
3
3
|
*
|
|
4
|
-
*
|
|
5
|
-
*
|
|
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
|
-
|
|
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
|
|