@huanlin/dsh-plugin-mineru 0.2.0

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,87 @@
1
+ # dsh-mineru
2
+
3
+ DSH 插件:向模型暴露 [MinerU](https://github.com/opendatalab/MinerU) 文档解析工具。MinerU 可将 PDF、图片、DOCX、PPTX、XLSX 等文件转换为结构化的 Markdown / JSON。
4
+
5
+ ## 安装
6
+
7
+ ```sh
8
+ # 从 git 安装(推荐):
9
+ dsh plugin --profile <profile> add github:huanlinoto/dsh-plugin-mineru
10
+
11
+ # 从本地 checkout 开发安装:
12
+ dsh plugin --profile <profile> add link:D:\Projects\deepseek-harness\dsh-mineru
13
+ ```
14
+
15
+ pnpm ≥10 从 git 安装时,需在 profile 的 `pnpm-workspace.yaml` 中允许构建:
16
+
17
+ ```yaml
18
+ allowBuilds:
19
+ '@huanlin/dsh-plugin-mineru': true
20
+ ```
21
+
22
+ ## 配置
23
+
24
+ 在 DSH GUI 设置页或 `cordis.patch.yml` 中配置:
25
+
26
+ | 字段 | 类型 | 默认值 | 说明 |
27
+ |------|------|--------|------|
28
+ | `baseURL` | string | *(必填)* | MinerU API 地址,如 `http://your-mineru-host:18000` |
29
+ | `apiKeyEnv` | credential-ref | `MINERU_API_KEY` | API key 的环境变量名 / 凭据引用。测试实例无需鉴权。 |
30
+ | `defaultBackend` | enum | `pipeline` | `pipeline` / `vlm-engine` / `hybrid-engine` / `vlm-http-client` / `hybrid-http-client` |
31
+ | `defaultParseMethod` | enum | `auto` | `auto` / `txt` / `ocr` |
32
+ | `defaultLang` | string | `ch` | pipeline 后端的语言代码 |
33
+ | `pollIntervalMs` | number | `2000` | 异步状态轮询间隔 |
34
+ | `pollTimeoutMs` | number | `600000` | `mineru_parse_document` 最大轮询时长(10 分钟) |
35
+ | `requestTimeoutMs` | number | `60000` | 单次 HTTP 请求超时 |
36
+ | `maxMdOutputChars` | number | `200000` | 内联返回给模型的 markdown 字符上限;超出时完整内容存到临时文件 |
37
+
38
+ ## 工具
39
+
40
+ ### `mineru_parse_document`(推荐)
41
+
42
+ 解析本地文档并返回提取出的 markdown。内部自动完成:提交文件 → 轮询至完成 → 返回 markdown。大多数解析任务用这个即可。
43
+
44
+ ### `mineru_submit_parse_job`
45
+
46
+ 异步提交解析任务,立即返回 `task_id`。适合大文档或并行批量提交。
47
+
48
+ ### `mineru_get_parse_status`
49
+
50
+ 轮询异步任务状态,返回 `pending` / `processing` / `completed` / `failed`。
51
+
52
+ ### `mineru_get_parse_result`
53
+
54
+ 获取已完成任务的结果。内联返回 markdown(过大则截断),并将完整结构化 JSON 存到 `raw_result_path`。
55
+
56
+ ### `mineru_health`
57
+
58
+ 检查服务器健康状态、版本、队列深度与并发容量。
59
+
60
+ ## 开发
61
+
62
+ ```sh
63
+ pnpm install # 安装开发依赖(schemastery、typescript、vitest)
64
+ pnpm run typecheck # tsc --noEmit 类型检查
65
+ pnpm test # vitest run 单元测试
66
+ pnpm run build # tsdown 构建 → lib/
67
+ ```
68
+
69
+ ## 目录结构
70
+
71
+ ```
72
+ dsh-mineru/
73
+ ├── src/
74
+ │ ├── index.ts # 入口:name、inject、Config(Schemastery)、apply
75
+ │ ├── client.ts # MinerUClient(基于 fetch 的 HTTP 客户端 + 类型)
76
+ │ ├── tools.ts # 5 个 defineTool 定义 + 辅助函数 + registerTools
77
+ │ └── types.d.ts # @deepseek-ai/dsh-tools + cordis 的环境类型声明
78
+ ├── tests/
79
+ │ └── tools.spec.ts # 单元测试(mock fetch,无需真实服务器)
80
+ ├── cordis.patch.yml # bundle 层:插入 dsh-mineru 插件行
81
+ ├── package.json # dsh.bundle.patch 声明 + peerDeps
82
+ └── tsconfig.json # NodeNext、ES2022、strict
83
+ ```
84
+
85
+ ## 测试 API
86
+
87
+ 请自己部署 MinerU 实例。`cordis.patch.yml` 默认指向 `http://localhost:18000`,请在 DSH GUI 中覆盖 `baseURL` 改为你的 MinerU 服务器地址。
@@ -0,0 +1,10 @@
1
+ # dsh-mineru bundle layer: inserts the dsh-mineru plugin row.
2
+ # Loaded by `dsh plugin --profile <name> add @huanlin/dsh-plugin-mineru`.
3
+ # The `name` is the package entry; Loader resolves it from profile node_modules.
4
+ # baseURL is configured at runtime via the DSH GUI settings page (MinerU section);
5
+ # the value below is the first-boot seed only.
6
+ - insert:
7
+ - id: dsh-mineru
8
+ name: '@huanlin/dsh-plugin-mineru'
9
+ config:
10
+ baseURL: 'http://localhost:18000'
package/lib/client.js ADDED
@@ -0,0 +1,419 @@
1
+ import { useCallback, useEffect, useState } from "react";
2
+ import { jsx, jsxs } from "react/jsx-runtime";
3
+ //#region \0dsh-css:D:\Projects\deepseek-harness\dsh-mineru\src\client\SettingsPage.module.css.mjs
4
+ const css = ".ljbh0j_section {\n display: flex;\n flex-direction: column;\n gap: 12px;\n max-width: 720px;\n color: var(--dsw-alias-label-primary);\n}\n\n.ljbh0j_title {\n margin: 0;\n font-size: 16px;\n line-height: 24px;\n font-weight: 500;\n color: var(--dsw-alias-label-primary);\n}\n\n.ljbh0j_intro {\n margin: 0;\n font-size: 14px;\n line-height: 22px;\n color: var(--dsw-alias-label-tertiary);\n}\n\n.ljbh0j_error {\n margin: 0;\n padding: 8px 12px;\n border: 1px solid var(--dsw-alias-state-error-primary);\n border-radius: 8px;\n background: var(--dsw-alias-interactive-bg-hover-danger);\n font-size: 12px;\n line-height: 18px;\n color: var(--dsw-alias-state-error-primary);\n display: flex;\n align-items: center;\n justify-content: space-between;\n gap: 8px;\n}\n\n.ljbh0j_errorDismiss {\n flex: none;\n border: none;\n background: transparent;\n color: inherit;\n font-size: 16px;\n line-height: 1;\n cursor: pointer;\n padding: 0 4px;\n}\n\n.ljbh0j_loading {\n font-size: 14px;\n line-height: 22px;\n color: var(--dsw-alias-label-tertiary);\n}\n\n.ljbh0j_editor {\n border: 1px solid var(--dsw-alias-border-l2);\n border-radius: 12px;\n padding: 14px 16px;\n display: flex;\n flex-direction: column;\n gap: 14px;\n background: var(--dsw-alias-bg-module-platform);\n}\n\n.ljbh0j_row {\n display: flex;\n gap: 12px;\n}\n\n.ljbh0j_row > .ljbh0j_field {\n flex: 1;\n}\n\n.ljbh0j_field {\n display: flex;\n flex-direction: column;\n gap: 4px;\n}\n\n.ljbh0j_fieldLabel {\n font-size: 12px;\n line-height: 18px;\n color: var(--dsw-alias-label-tertiary);\n}\n\n.ljbh0j_input,\n.ljbh0j_select {\n height: 32px;\n border: 1px solid var(--dsw-alias-border-l2);\n border-radius: 8px;\n padding: 0 10px;\n font-size: 14px;\n line-height: 20px;\n color: var(--dsw-alias-label-primary);\n background: var(--dsw-alias-bg-layer-1);\n outline: none;\n}\n\n.ljbh0j_input:focus,\n.ljbh0j_select:focus {\n border-color: var(--dsw-alias-state-focus-primary);\n}\n\n.ljbh0j_select {\n appearance: none;\n cursor: pointer;\n}\n\n.ljbh0j_actions {\n display: flex;\n align-items: center;\n gap: 10px;\n flex-wrap: wrap;\n}\n\n.ljbh0j_primaryButton {\n height: 36px;\n border: none;\n border-radius: 18px;\n padding: 0 18px;\n font-size: 14px;\n font-weight: 500;\n color: var(--dsw-alias-text-on-primary);\n background: var(--dsw-alias-interactive-bg-primary);\n cursor: pointer;\n}\n\n.ljbh0j_primaryButton:disabled {\n opacity: 0.5;\n cursor: not-allowed;\n}\n\n.ljbh0j_secondaryButton {\n height: 36px;\n border: 1px solid var(--dsw-alias-border-l2);\n border-radius: 18px;\n padding: 0 18px;\n font-size: 14px;\n color: var(--dsw-alias-label-primary);\n background: var(--dsw-alias-bg-layer-1);\n cursor: pointer;\n}\n\n.ljbh0j_secondaryButton:disabled {\n opacity: 0.5;\n cursor: not-allowed;\n}\n\n.ljbh0j_testOk {\n font-size: 12px;\n line-height: 18px;\n color: var(--dsw-alias-state-success-primary);\n}\n\n.ljbh0j_testWarn {\n font-size: 12px;\n line-height: 18px;\n color: var(--dsw-alias-state-warning-primary);\n}\n\n.ljbh0j_testErr {\n font-size: 12px;\n line-height: 18px;\n color: var(--dsw-alias-state-error-primary);\n}\n";
5
+ const classMap = {
6
+ "section": "ljbh0j_section",
7
+ "title": "ljbh0j_title",
8
+ "intro": "ljbh0j_intro",
9
+ "error": "ljbh0j_error",
10
+ "errorDismiss": "ljbh0j_errorDismiss",
11
+ "loading": "ljbh0j_loading",
12
+ "editor": "ljbh0j_editor",
13
+ "row": "ljbh0j_row",
14
+ "field": "ljbh0j_field",
15
+ "fieldLabel": "ljbh0j_fieldLabel",
16
+ "input": "ljbh0j_input",
17
+ "select": "ljbh0j_select",
18
+ "actions": "ljbh0j_actions",
19
+ "primaryButton": "ljbh0j_primaryButton",
20
+ "secondaryButton": "ljbh0j_secondaryButton",
21
+ "testOk": "ljbh0j_testOk",
22
+ "testWarn": "ljbh0j_testWarn",
23
+ "testErr": "ljbh0j_testErr"
24
+ };
25
+ const tagId = "@huanlin/dsh-plugin-mineru/SettingsPage.module.css";
26
+ if (typeof document !== "undefined" && document.querySelector("style[data-plugin-css=" + JSON.stringify(tagId) + "]") === null) {
27
+ const tag = document.createElement("style");
28
+ tag.dataset.plugin = "@huanlin/dsh-plugin-mineru";
29
+ tag.dataset.pluginCss = tagId;
30
+ tag.textContent = css;
31
+ document.head.appendChild(tag);
32
+ } else if (typeof document !== "undefined") {
33
+ const existing = document.querySelector("style[data-plugin-css=" + JSON.stringify(tagId) + "]");
34
+ if (existing) existing.textContent = css;
35
+ }
36
+ //#endregion
37
+ //#region src/client/SettingsPage.tsx
38
+ const BACKENDS = [
39
+ "pipeline",
40
+ "vlm-engine",
41
+ "hybrid-engine",
42
+ "vlm-http-client",
43
+ "hybrid-http-client"
44
+ ];
45
+ const PARSE_METHODS = [
46
+ "auto",
47
+ "txt",
48
+ "ocr"
49
+ ];
50
+ async function callRpc(rpc, endpoint, payload) {
51
+ return rpc.call("/mineru-api", endpoint, payload);
52
+ }
53
+ function SettingsPage({ rpc, t }) {
54
+ const [config, setConfig] = useState(null);
55
+ const [draft, setDraft] = useState(null);
56
+ const [loading, setLoading] = useState(true);
57
+ const [saving, setSaving] = useState(false);
58
+ const [saved, setSaved] = useState(false);
59
+ const [error, setError] = useState(void 0);
60
+ const [testStatus, setTestStatus] = useState("idle");
61
+ const [testMessage, setTestMessage] = useState(void 0);
62
+ const refresh = useCallback(async () => {
63
+ setLoading(true);
64
+ setError(void 0);
65
+ try {
66
+ const result = await callRpc(rpc, "mineru/config.get", {});
67
+ if (result.ok) {
68
+ setConfig(result.value.config);
69
+ setDraft(result.value.config);
70
+ } else setError(result.error.message);
71
+ } catch (err) {
72
+ setError(err instanceof Error ? err.message : String(err));
73
+ } finally {
74
+ setLoading(false);
75
+ }
76
+ }, [rpc]);
77
+ useEffect(() => {
78
+ refresh();
79
+ }, [refresh]);
80
+ const save = useCallback(async () => {
81
+ if (draft === null) return;
82
+ setSaving(true);
83
+ setError(void 0);
84
+ setSaved(false);
85
+ try {
86
+ const result = await callRpc(rpc, "mineru/config.set", { config: draft });
87
+ if (result.ok) {
88
+ setConfig(result.value.config);
89
+ setDraft(result.value.config);
90
+ setSaved(true);
91
+ setTimeout(() => setSaved(false), 2e3);
92
+ } else setError(result.error.message);
93
+ } catch (err) {
94
+ setError(err instanceof Error ? err.message : String(err));
95
+ } finally {
96
+ setSaving(false);
97
+ }
98
+ }, [draft, rpc]);
99
+ const testConnection = useCallback(async () => {
100
+ if (draft === null) return;
101
+ setTestStatus("testing");
102
+ setTestMessage(void 0);
103
+ try {
104
+ const result = await callRpc(rpc, "mineru/health", {});
105
+ if (result.ok && result.value.status === "healthy") {
106
+ setTestStatus("healthy");
107
+ const v = result.value.version ? ` v${result.value.version}` : "";
108
+ const q = result.value.queued_tasks !== void 0 ? ` (${result.value.queued_tasks} queued)` : "";
109
+ setTestMessage(`${t("test.healthy")}${v}${q}`);
110
+ } else if (result.ok) {
111
+ setTestStatus("unhealthy");
112
+ setTestMessage(t("test.unhealthy"));
113
+ } else {
114
+ setTestStatus("error");
115
+ setTestMessage(result.error.message);
116
+ }
117
+ } catch (err) {
118
+ setTestStatus("error");
119
+ setTestMessage(err instanceof Error ? err.message : String(err));
120
+ }
121
+ }, [
122
+ draft,
123
+ rpc,
124
+ t
125
+ ]);
126
+ const patch = (p) => {
127
+ setDraft((prev) => prev === null ? prev : {
128
+ ...prev,
129
+ ...p
130
+ });
131
+ };
132
+ if (loading || draft === null) return /* @__PURE__ */ jsxs("section", {
133
+ className: classMap.section,
134
+ children: [/* @__PURE__ */ jsx("h2", {
135
+ className: classMap.title,
136
+ children: t("page.title")
137
+ }), /* @__PURE__ */ jsx("div", {
138
+ className: classMap.loading,
139
+ children: "…"
140
+ })]
141
+ });
142
+ const dirty = JSON.stringify(draft) !== JSON.stringify(config);
143
+ return /* @__PURE__ */ jsxs("section", {
144
+ className: classMap.section,
145
+ children: [
146
+ /* @__PURE__ */ jsx("h2", {
147
+ className: classMap.title,
148
+ children: t("page.title")
149
+ }),
150
+ /* @__PURE__ */ jsx("p", {
151
+ className: classMap.intro,
152
+ children: t("page.intro")
153
+ }),
154
+ error !== void 0 && /* @__PURE__ */ jsxs("div", {
155
+ className: classMap.error,
156
+ children: [error, /* @__PURE__ */ jsx("button", {
157
+ type: "button",
158
+ className: classMap.errorDismiss,
159
+ onClick: () => setError(void 0),
160
+ children: "×"
161
+ })]
162
+ }),
163
+ /* @__PURE__ */ jsxs("div", {
164
+ className: classMap.editor,
165
+ children: [
166
+ /* @__PURE__ */ jsxs("label", {
167
+ className: classMap.field,
168
+ children: [/* @__PURE__ */ jsx("span", {
169
+ className: classMap.fieldLabel,
170
+ children: t("field.baseURL")
171
+ }), /* @__PURE__ */ jsx("input", {
172
+ className: classMap.input,
173
+ value: draft.baseURL,
174
+ placeholder: t("field.baseURL.placeholder"),
175
+ onChange: (e) => patch({ baseURL: e.target.value })
176
+ })]
177
+ }),
178
+ /* @__PURE__ */ jsxs("label", {
179
+ className: classMap.field,
180
+ children: [/* @__PURE__ */ jsx("span", {
181
+ className: classMap.fieldLabel,
182
+ children: t("field.apiKeyEnv")
183
+ }), /* @__PURE__ */ jsx("input", {
184
+ className: classMap.input,
185
+ value: draft.apiKeyEnv,
186
+ placeholder: t("field.apiKeyEnv.placeholder"),
187
+ onChange: (e) => patch({ apiKeyEnv: e.target.value })
188
+ })]
189
+ }),
190
+ /* @__PURE__ */ jsxs("div", {
191
+ className: classMap.row,
192
+ children: [/* @__PURE__ */ jsxs("label", {
193
+ className: classMap.field,
194
+ children: [/* @__PURE__ */ jsx("span", {
195
+ className: classMap.fieldLabel,
196
+ children: t("field.defaultBackend")
197
+ }), /* @__PURE__ */ jsx("select", {
198
+ className: classMap.select,
199
+ value: draft.defaultBackend,
200
+ onChange: (e) => patch({ defaultBackend: e.target.value }),
201
+ children: BACKENDS.map((b) => /* @__PURE__ */ jsx("option", {
202
+ value: b,
203
+ children: t(`backend.${b}`)
204
+ }, b))
205
+ })]
206
+ }), /* @__PURE__ */ jsxs("label", {
207
+ className: classMap.field,
208
+ children: [/* @__PURE__ */ jsx("span", {
209
+ className: classMap.fieldLabel,
210
+ children: t("field.defaultParseMethod")
211
+ }), /* @__PURE__ */ jsx("select", {
212
+ className: classMap.select,
213
+ value: draft.defaultParseMethod,
214
+ onChange: (e) => patch({ defaultParseMethod: e.target.value }),
215
+ children: PARSE_METHODS.map((m) => /* @__PURE__ */ jsx("option", {
216
+ value: m,
217
+ children: t(`parse.${m}`)
218
+ }, m))
219
+ })]
220
+ })]
221
+ }),
222
+ /* @__PURE__ */ jsxs("div", {
223
+ className: classMap.row,
224
+ children: [/* @__PURE__ */ jsxs("label", {
225
+ className: classMap.field,
226
+ children: [/* @__PURE__ */ jsx("span", {
227
+ className: classMap.fieldLabel,
228
+ children: t("field.defaultLang")
229
+ }), /* @__PURE__ */ jsx("input", {
230
+ className: classMap.input,
231
+ value: draft.defaultLang,
232
+ onChange: (e) => patch({ defaultLang: e.target.value })
233
+ })]
234
+ }), /* @__PURE__ */ jsxs("label", {
235
+ className: classMap.field,
236
+ children: [/* @__PURE__ */ jsx("span", {
237
+ className: classMap.fieldLabel,
238
+ children: t("field.pollIntervalMs")
239
+ }), /* @__PURE__ */ jsx("input", {
240
+ type: "number",
241
+ className: classMap.input,
242
+ value: draft.pollIntervalMs,
243
+ onChange: (e) => patch({ pollIntervalMs: Number(e.target.value) })
244
+ })]
245
+ })]
246
+ }),
247
+ /* @__PURE__ */ jsxs("div", {
248
+ className: classMap.row,
249
+ children: [/* @__PURE__ */ jsxs("label", {
250
+ className: classMap.field,
251
+ children: [/* @__PURE__ */ jsx("span", {
252
+ className: classMap.fieldLabel,
253
+ children: t("field.pollTimeoutMs")
254
+ }), /* @__PURE__ */ jsx("input", {
255
+ type: "number",
256
+ className: classMap.input,
257
+ value: draft.pollTimeoutMs,
258
+ onChange: (e) => patch({ pollTimeoutMs: Number(e.target.value) })
259
+ })]
260
+ }), /* @__PURE__ */ jsxs("label", {
261
+ className: classMap.field,
262
+ children: [/* @__PURE__ */ jsx("span", {
263
+ className: classMap.fieldLabel,
264
+ children: t("field.requestTimeoutMs")
265
+ }), /* @__PURE__ */ jsx("input", {
266
+ type: "number",
267
+ className: classMap.input,
268
+ value: draft.requestTimeoutMs,
269
+ onChange: (e) => patch({ requestTimeoutMs: Number(e.target.value) })
270
+ })]
271
+ })]
272
+ }),
273
+ /* @__PURE__ */ jsxs("label", {
274
+ className: classMap.field,
275
+ children: [/* @__PURE__ */ jsx("span", {
276
+ className: classMap.fieldLabel,
277
+ children: t("field.maxMdOutputChars")
278
+ }), /* @__PURE__ */ jsx("input", {
279
+ type: "number",
280
+ className: classMap.input,
281
+ value: draft.maxMdOutputChars,
282
+ onChange: (e) => patch({ maxMdOutputChars: Number(e.target.value) })
283
+ })]
284
+ })
285
+ ]
286
+ }),
287
+ /* @__PURE__ */ jsxs("div", {
288
+ className: classMap.actions,
289
+ children: [
290
+ /* @__PURE__ */ jsx("button", {
291
+ type: "button",
292
+ className: classMap.primaryButton,
293
+ onClick: () => void save(),
294
+ disabled: !dirty || saving,
295
+ children: saving ? "…" : saved ? t("action.saved") : t("action.save")
296
+ }),
297
+ /* @__PURE__ */ jsx("button", {
298
+ type: "button",
299
+ className: classMap.secondaryButton,
300
+ onClick: () => void testConnection(),
301
+ disabled: testStatus === "testing",
302
+ children: testStatus === "testing" ? t("action.testing") : t("action.test")
303
+ }),
304
+ testStatus === "healthy" && testMessage !== void 0 && /* @__PURE__ */ jsx("span", {
305
+ className: classMap.testOk,
306
+ children: testMessage
307
+ }),
308
+ testStatus === "unhealthy" && testMessage !== void 0 && /* @__PURE__ */ jsx("span", {
309
+ className: classMap.testWarn,
310
+ children: testMessage
311
+ }),
312
+ testStatus === "error" && testMessage !== void 0 && /* @__PURE__ */ jsxs("span", {
313
+ className: classMap.testErr,
314
+ children: [
315
+ t("test.error"),
316
+ ": ",
317
+ testMessage
318
+ ]
319
+ })
320
+ ]
321
+ })
322
+ ]
323
+ });
324
+ }
325
+ //#endregion
326
+ //#region src/client/locales.ts
327
+ const NS = "dsh-mineru";
328
+ const en = {
329
+ "nav": "MinerU",
330
+ "page.title": "MinerU Configuration",
331
+ "page.intro": "Configure the MinerU document parsing server. Changes apply immediately to all mineru_* tools.",
332
+ "field.baseURL": "API Base URL",
333
+ "field.baseURL.placeholder": "http://your-mineru-host:18000",
334
+ "field.apiKeyEnv": "API Key Env Var",
335
+ "field.apiKeyEnv.placeholder": "MINERU_API_KEY",
336
+ "field.defaultBackend": "Default Backend",
337
+ "field.defaultParseMethod": "Default Parse Method",
338
+ "field.defaultLang": "Default Language",
339
+ "field.pollIntervalMs": "Poll Interval (ms)",
340
+ "field.pollTimeoutMs": "Poll Timeout (ms)",
341
+ "field.requestTimeoutMs": "Request Timeout (ms)",
342
+ "field.maxMdOutputChars": "Max Markdown Output Chars",
343
+ "action.save": "Save",
344
+ "action.saved": "Saved",
345
+ "action.test": "Test Connection",
346
+ "action.testing": "Testing…",
347
+ "test.healthy": "Healthy",
348
+ "test.unhealthy": "Unhealthy",
349
+ "test.error": "Connection failed",
350
+ "backend.pipeline": "pipeline (no VLM, multi-language)",
351
+ "backend.vlm-engine": "vlm-engine (VLM only)",
352
+ "backend.hybrid-engine": "hybrid-engine (VLM + pipeline)",
353
+ "backend.vlm-http-client": "vlm-http-client",
354
+ "backend.hybrid-http-client": "hybrid-http-client",
355
+ "parse.auto": "auto",
356
+ "parse.txt": "txt (text only, no OCR)",
357
+ "parse.ocr": "ocr (force OCR)"
358
+ };
359
+ const zh = {
360
+ "nav": "MinerU",
361
+ "page.title": "MinerU 配置",
362
+ "page.intro": "配置 MinerU 文档解析服务器。修改后立即对所有 mineru_* 工具生效。",
363
+ "field.baseURL": "API 地址",
364
+ "field.baseURL.placeholder": "http://your-mineru-host:18000",
365
+ "field.apiKeyEnv": "API Key 环境变量",
366
+ "field.apiKeyEnv.placeholder": "MINERU_API_KEY",
367
+ "field.defaultBackend": "默认后端",
368
+ "field.defaultParseMethod": "默认解析方式",
369
+ "field.defaultLang": "默认语言",
370
+ "field.pollIntervalMs": "轮询间隔 (ms)",
371
+ "field.pollTimeoutMs": "轮询超时 (ms)",
372
+ "field.requestTimeoutMs": "请求超时 (ms)",
373
+ "field.maxMdOutputChars": "Markdown 输出字符上限",
374
+ "action.save": "保存",
375
+ "action.saved": "已保存",
376
+ "action.test": "测试连接",
377
+ "action.testing": "测试中…",
378
+ "test.healthy": "健康",
379
+ "test.unhealthy": "异常",
380
+ "test.error": "连接失败",
381
+ "backend.pipeline": "pipeline(无 VLM,多语言)",
382
+ "backend.vlm-engine": "vlm-engine(仅 VLM)",
383
+ "backend.hybrid-engine": "hybrid-engine(VLM + pipeline)",
384
+ "backend.vlm-http-client": "vlm-http-client",
385
+ "backend.hybrid-http-client": "hybrid-http-client",
386
+ "parse.auto": "auto",
387
+ "parse.txt": "txt(仅文本,不 OCR)",
388
+ "parse.ocr": "ocr(强制 OCR)"
389
+ };
390
+ //#endregion
391
+ //#region src/client/index.ts
392
+ const inject = [
393
+ "slots",
394
+ "locale",
395
+ "connection"
396
+ ];
397
+ function apply(ctx) {
398
+ ctx.effect(() => ctx.locale.register(NS, {
399
+ zh,
400
+ en
401
+ }), "dsh-mineru: dictionaries");
402
+ const connection = ctx.connection;
403
+ const t = ctx.locale.bind(NS);
404
+ const settingsInjected = () => ({
405
+ rpc: connection.rpc,
406
+ t
407
+ });
408
+ ctx.slots.inject("settings.section", () => ctx.slots.register({
409
+ name: "settings.section",
410
+ id: "dsh-mineru",
411
+ order: 40,
412
+ label: () => t("nav"),
413
+ inject: settingsInjected
414
+ }, SettingsPage));
415
+ }
416
+ //#endregion
417
+ export { apply, inject };
418
+
419
+ //# sourceMappingURL=client.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"client.js","names":["css"],"sources":["../src/client/SettingsPage.tsx","../src/client/locales.ts","../src/client/index.ts"],"sourcesContent":["import { useCallback, useEffect, useState } from 'react'\nimport type { PropsRuntime } from '@deepseek-ai/dsh-client-ui-slots'\nimport type { PropsLocale } from '@deepseek-ai/dsh-client-ui-slots'\nimport type { ClientConnectionRpc, RpcResult } from '@deepseek-ai/dsh-client-connection/client'\nimport type { MineruRuntimeConfig } from '../rpc.js'\nimport type { MineruKey } from './locales.js'\nimport css from './SettingsPage.module.css'\n\nexport interface MineruSettingsInjected {\n readonly rpc: ClientConnectionRpc\n readonly t: (key: string) => string\n}\n\ntype SettingsPageProps = PropsRuntime<'settings.section'> & PropsLocale<'dsh-mineru'> & MineruSettingsInjected\n\ntype ConfigGetResult = RpcResult<{ readonly config: MineruRuntimeConfig }>\ntype ConfigSetResult = RpcResult<{ readonly config: MineruRuntimeConfig }>\ntype HealthResult = RpcResult<{ readonly status: string; readonly version?: string; readonly queued_tasks?: number; readonly processing_tasks?: number }>\n\nconst BACKENDS = ['pipeline', 'vlm-engine', 'hybrid-engine', 'vlm-http-client', 'hybrid-http-client'] as const\nconst PARSE_METHODS = ['auto', 'txt', 'ocr'] as const\n\nasync function callRpc<T>(rpc: ClientConnectionRpc, endpoint: string, payload: unknown): Promise<T> {\n return rpc.call('/mineru-api', endpoint, payload) as Promise<T>\n}\n\nexport function SettingsPage({ rpc, t }: SettingsPageProps) {\n const [config, setConfig] = useState<MineruRuntimeConfig | null>(null)\n const [draft, setDraft] = useState<MineruRuntimeConfig | null>(null)\n const [loading, setLoading] = useState(true)\n const [saving, setSaving] = useState(false)\n const [saved, setSaved] = useState(false)\n const [error, setError] = useState<string | undefined>(undefined)\n const [testStatus, setTestStatus] = useState<'idle' | 'testing' | 'healthy' | 'unhealthy' | 'error'>('idle')\n const [testMessage, setTestMessage] = useState<string | undefined>(undefined)\n\n const refresh = useCallback(async () => {\n setLoading(true)\n setError(undefined)\n try {\n const result = await callRpc<ConfigGetResult>(rpc, 'mineru/config.get', {})\n if (result.ok) {\n setConfig(result.value.config)\n setDraft(result.value.config)\n } else {\n setError(result.error.message)\n }\n } catch (err) {\n setError(err instanceof Error ? err.message : String(err))\n } finally {\n setLoading(false)\n }\n }, [rpc])\n\n useEffect(() => { void refresh() }, [refresh])\n\n const save = useCallback(async () => {\n if (draft === null) return\n setSaving(true)\n setError(undefined)\n setSaved(false)\n try {\n const result = await callRpc<ConfigSetResult>(rpc, 'mineru/config.set', { config: draft })\n if (result.ok) {\n setConfig(result.value.config)\n setDraft(result.value.config)\n setSaved(true)\n setTimeout(() => setSaved(false), 2000)\n } else {\n setError(result.error.message)\n }\n } catch (err) {\n setError(err instanceof Error ? err.message : String(err))\n } finally {\n setSaving(false)\n }\n }, [draft, rpc])\n\n const testConnection = useCallback(async () => {\n if (draft === null) return\n setTestStatus('testing')\n setTestMessage(undefined)\n try {\n const result = await callRpc<HealthResult>(rpc, 'mineru/health', {})\n if (result.ok && result.value.status === 'healthy') {\n setTestStatus('healthy')\n const v = result.value.version ? ` v${result.value.version}` : ''\n const q = result.value.queued_tasks !== undefined ? ` (${result.value.queued_tasks} queued)` : ''\n setTestMessage(`${t('test.healthy')}${v}${q}`)\n } else if (result.ok) {\n setTestStatus('unhealthy')\n setTestMessage(t('test.unhealthy'))\n } else {\n setTestStatus('error')\n setTestMessage(result.error.message)\n }\n } catch (err) {\n setTestStatus('error')\n setTestMessage(err instanceof Error ? err.message : String(err))\n }\n }, [draft, rpc, t])\n\n const patch = (p: Partial<MineruRuntimeConfig>): void => {\n setDraft(prev => prev === null ? prev : { ...prev, ...p })\n }\n\n if (loading || draft === null) {\n return (\n <section className={css.section}>\n <h2 className={css.title}>{t('page.title')}</h2>\n <div className={css.loading}>…</div>\n </section>\n )\n }\n\n const dirty = JSON.stringify(draft) !== JSON.stringify(config)\n\n return (\n <section className={css.section}>\n <h2 className={css.title}>{t('page.title')}</h2>\n <p className={css.intro}>{t('page.intro')}</p>\n\n {error !== undefined && (\n <div className={css.error}>\n {error}\n <button type=\"button\" className={css.errorDismiss} onClick={() => setError(undefined)}>×</button>\n </div>\n )}\n\n <div className={css.editor}>\n <label className={css.field}>\n <span className={css.fieldLabel}>{t('field.baseURL')}</span>\n <input\n className={css.input}\n value={draft.baseURL}\n placeholder={t('field.baseURL.placeholder')}\n onChange={e => patch({ baseURL: e.target.value })}\n />\n </label>\n\n <label className={css.field}>\n <span className={css.fieldLabel}>{t('field.apiKeyEnv')}</span>\n <input\n className={css.input}\n value={draft.apiKeyEnv}\n placeholder={t('field.apiKeyEnv.placeholder')}\n onChange={e => patch({ apiKeyEnv: e.target.value })}\n />\n </label>\n\n <div className={css.row}>\n <label className={css.field}>\n <span className={css.fieldLabel}>{t('field.defaultBackend')}</span>\n <select\n className={css.select}\n value={draft.defaultBackend}\n onChange={e => patch({ defaultBackend: e.target.value })}\n >\n {BACKENDS.map(b => (\n <option key={b} value={b}>{t(`backend.${b}` as MineruKey)}</option>\n ))}\n </select>\n </label>\n\n <label className={css.field}>\n <span className={css.fieldLabel}>{t('field.defaultParseMethod')}</span>\n <select\n className={css.select}\n value={draft.defaultParseMethod}\n onChange={e => patch({ defaultParseMethod: e.target.value })}\n >\n {PARSE_METHODS.map(m => (\n <option key={m} value={m}>{t(`parse.${m}` as MineruKey)}</option>\n ))}\n </select>\n </label>\n </div>\n\n <div className={css.row}>\n <label className={css.field}>\n <span className={css.fieldLabel}>{t('field.defaultLang')}</span>\n <input\n className={css.input}\n value={draft.defaultLang}\n onChange={e => patch({ defaultLang: e.target.value })}\n />\n </label>\n\n <label className={css.field}>\n <span className={css.fieldLabel}>{t('field.pollIntervalMs')}</span>\n <input\n type=\"number\"\n className={css.input}\n value={draft.pollIntervalMs}\n onChange={e => patch({ pollIntervalMs: Number(e.target.value) })}\n />\n </label>\n </div>\n\n <div className={css.row}>\n <label className={css.field}>\n <span className={css.fieldLabel}>{t('field.pollTimeoutMs')}</span>\n <input\n type=\"number\"\n className={css.input}\n value={draft.pollTimeoutMs}\n onChange={e => patch({ pollTimeoutMs: Number(e.target.value) })}\n />\n </label>\n\n <label className={css.field}>\n <span className={css.fieldLabel}>{t('field.requestTimeoutMs')}</span>\n <input\n type=\"number\"\n className={css.input}\n value={draft.requestTimeoutMs}\n onChange={e => patch({ requestTimeoutMs: Number(e.target.value) })}\n />\n </label>\n </div>\n\n <label className={css.field}>\n <span className={css.fieldLabel}>{t('field.maxMdOutputChars')}</span>\n <input\n type=\"number\"\n className={css.input}\n value={draft.maxMdOutputChars}\n onChange={e => patch({ maxMdOutputChars: Number(e.target.value) })}\n />\n </label>\n </div>\n\n <div className={css.actions}>\n <button\n type=\"button\"\n className={css.primaryButton}\n onClick={() => void save()}\n disabled={!dirty || saving}\n >\n {saving ? '…' : saved ? t('action.saved') : t('action.save')}\n </button>\n <button\n type=\"button\"\n className={css.secondaryButton}\n onClick={() => void testConnection()}\n disabled={testStatus === 'testing'}\n >\n {testStatus === 'testing' ? t('action.testing') : t('action.test')}\n </button>\n {testStatus === 'healthy' && testMessage !== undefined && (\n <span className={css.testOk}>{testMessage}</span>\n )}\n {testStatus === 'unhealthy' && testMessage !== undefined && (\n <span className={css.testWarn}>{testMessage}</span>\n )}\n {testStatus === 'error' && testMessage !== undefined && (\n <span className={css.testErr}>{t('test.error')}: {testMessage}</span>\n )}\n </div>\n </section>\n )\n}\n","export type MineruKey =\n | 'nav'\n | 'page.title'\n | 'page.intro'\n | 'field.baseURL'\n | 'field.baseURL.placeholder'\n | 'field.apiKeyEnv'\n | 'field.apiKeyEnv.placeholder'\n | 'field.defaultBackend'\n | 'field.defaultParseMethod'\n | 'field.defaultLang'\n | 'field.pollIntervalMs'\n | 'field.pollTimeoutMs'\n | 'field.requestTimeoutMs'\n | 'field.maxMdOutputChars'\n | 'action.save'\n | 'action.saved'\n | 'action.test'\n | 'action.testing'\n | 'test.healthy'\n | 'test.unhealthy'\n | 'test.error'\n | 'backend.pipeline'\n | 'backend.vlm-engine'\n | 'backend.hybrid-engine'\n | 'backend.vlm-http-client'\n | 'backend.hybrid-http-client'\n | 'parse.auto'\n | 'parse.txt'\n | 'parse.ocr'\n\nexport const NS = 'dsh-mineru'\n\nexport const en: Record<MineruKey, string> = {\n 'nav': 'MinerU',\n 'page.title': 'MinerU Configuration',\n 'page.intro': 'Configure the MinerU document parsing server. Changes apply immediately to all mineru_* tools.',\n 'field.baseURL': 'API Base URL',\n 'field.baseURL.placeholder': 'http://your-mineru-host:18000',\n 'field.apiKeyEnv': 'API Key Env Var',\n 'field.apiKeyEnv.placeholder': 'MINERU_API_KEY',\n 'field.defaultBackend': 'Default Backend',\n 'field.defaultParseMethod': 'Default Parse Method',\n 'field.defaultLang': 'Default Language',\n 'field.pollIntervalMs': 'Poll Interval (ms)',\n 'field.pollTimeoutMs': 'Poll Timeout (ms)',\n 'field.requestTimeoutMs': 'Request Timeout (ms)',\n 'field.maxMdOutputChars': 'Max Markdown Output Chars',\n 'action.save': 'Save',\n 'action.saved': 'Saved',\n 'action.test': 'Test Connection',\n 'action.testing': 'Testing…',\n 'test.healthy': 'Healthy',\n 'test.unhealthy': 'Unhealthy',\n 'test.error': 'Connection failed',\n 'backend.pipeline': 'pipeline (no VLM, multi-language)',\n 'backend.vlm-engine': 'vlm-engine (VLM only)',\n 'backend.hybrid-engine': 'hybrid-engine (VLM + pipeline)',\n 'backend.vlm-http-client': 'vlm-http-client',\n 'backend.hybrid-http-client': 'hybrid-http-client',\n 'parse.auto': 'auto',\n 'parse.txt': 'txt (text only, no OCR)',\n 'parse.ocr': 'ocr (force OCR)',\n}\n\nexport const zh: Record<MineruKey, string> = {\n 'nav': 'MinerU',\n 'page.title': 'MinerU 配置',\n 'page.intro': '配置 MinerU 文档解析服务器。修改后立即对所有 mineru_* 工具生效。',\n 'field.baseURL': 'API 地址',\n 'field.baseURL.placeholder': 'http://your-mineru-host:18000',\n 'field.apiKeyEnv': 'API Key 环境变量',\n 'field.apiKeyEnv.placeholder': 'MINERU_API_KEY',\n 'field.defaultBackend': '默认后端',\n 'field.defaultParseMethod': '默认解析方式',\n 'field.defaultLang': '默认语言',\n 'field.pollIntervalMs': '轮询间隔 (ms)',\n 'field.pollTimeoutMs': '轮询超时 (ms)',\n 'field.requestTimeoutMs': '请求超时 (ms)',\n 'field.maxMdOutputChars': 'Markdown 输出字符上限',\n 'action.save': '保存',\n 'action.saved': '已保存',\n 'action.test': '测试连接',\n 'action.testing': '测试中…',\n 'test.healthy': '健康',\n 'test.unhealthy': '异常',\n 'test.error': '连接失败',\n 'backend.pipeline': 'pipeline(无 VLM,多语言)',\n 'backend.vlm-engine': 'vlm-engine(仅 VLM)',\n 'backend.hybrid-engine': 'hybrid-engine(VLM + pipeline)',\n 'backend.vlm-http-client': 'vlm-http-client',\n 'backend.hybrid-http-client': 'hybrid-http-client',\n 'parse.auto': 'auto',\n 'parse.txt': 'txt(仅文本,不 OCR)',\n 'parse.ocr': 'ocr(强制 OCR)',\n}\n","import type { ClientContext } from '@deepseek-ai/dsh-client-runtime/client'\nimport type { ConnectionHandle } from '@deepseek-ai/dsh-client-connection/client'\nimport type {} from '@deepseek-ai/dsh-client-connection/client'\nimport type {} from '@deepseek-ai/dsh-client-ui-settings/client'\nimport type {} from '@deepseek-ai/dsh-client-locale/client'\nimport { SettingsPage, type MineruSettingsInjected } from './SettingsPage.js'\nimport { en, NS, zh, type MineruKey } from './locales.js'\n\ndeclare module '@deepseek-ai/dsh-client-ui-slots' {\n interface LocaleNamespaceMap {\n 'dsh-mineru': MineruKey\n }\n}\n\nexport const inject = ['slots', 'locale', 'connection']\n\nexport function apply(ctx: ClientContext): void {\n ctx.effect(() => ctx.locale.register(NS, { zh, en }), 'dsh-mineru: dictionaries')\n\n const connection = ctx.connection as unknown as ConnectionHandle\n const t = ctx.locale.bind(NS) as (key: string) => string\n\n const settingsInjected = (): MineruSettingsInjected => ({\n rpc: connection.rpc,\n t,\n })\n\n ctx.slots.inject('settings.section', () => ctx.slots.register({\n name: 'settings.section',\n id: 'dsh-mineru',\n order: 40,\n label: () => t('nav'),\n inject: settingsInjected,\n }, SettingsPage))\n}\n"],"mappings":"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"}