@bedolla/enrivision 0.1.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/LICENSE +619 -0
- package/README.md +214 -0
- package/dist/client/EnriProxyClient.d.ts +323 -0
- package/dist/client/EnriProxyClient.d.ts.map +1 -0
- package/dist/client/EnriProxyClient.js +348 -0
- package/dist/client/EnriProxyClient.js.map +1 -0
- package/dist/index.d.ts +10 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +90 -0
- package/dist/index.js.map +1 -0
- package/dist/package-info.d.ts +8 -0
- package/dist/package-info.d.ts.map +1 -0
- package/dist/package-info.js +28 -0
- package/dist/package-info.js.map +1 -0
- package/dist/server/EnriVisionServer.d.ts +63 -0
- package/dist/server/EnriVisionServer.d.ts.map +1 -0
- package/dist/server/EnriVisionServer.js +246 -0
- package/dist/server/EnriVisionServer.js.map +1 -0
- package/dist/shared/tar.d.ts +108 -0
- package/dist/shared/tar.d.ts.map +1 -0
- package/dist/shared/tar.js +346 -0
- package/dist/shared/tar.js.map +1 -0
- package/dist/shared/validation.d.ts +61 -0
- package/dist/shared/validation.d.ts.map +1 -0
- package/dist/shared/validation.js +107 -0
- package/dist/shared/validation.js.map +1 -0
- package/dist/tools/AnalyzeMediaTool.d.ts +302 -0
- package/dist/tools/AnalyzeMediaTool.d.ts.map +1 -0
- package/dist/tools/AnalyzeMediaTool.js +509 -0
- package/dist/tools/AnalyzeMediaTool.js.map +1 -0
- package/package.json +58 -0
|
@@ -0,0 +1,509 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* ANALYZE MEDIA TOOL
|
|
3
|
+
*
|
|
4
|
+
* Implements the `analyze_media` MCP tool:
|
|
5
|
+
* - Validates local file path
|
|
6
|
+
* - Streams the file to EnriProxy via resumable uploads
|
|
7
|
+
* - Triggers server-side analysis and returns text-only results
|
|
8
|
+
*
|
|
9
|
+
* @module tools/AnalyzeMediaTool
|
|
10
|
+
*/
|
|
11
|
+
import { existsSync } from "node:fs";
|
|
12
|
+
import { stat, open } from "node:fs/promises";
|
|
13
|
+
import { basename, extname, isAbsolute } from "node:path";
|
|
14
|
+
import { randomUUID } from "node:crypto";
|
|
15
|
+
import { lookup as mimeLookup } from "mime-types";
|
|
16
|
+
import { EnriProxyHttpError } from "../client/EnriProxyClient.js";
|
|
17
|
+
import { assertHttpUrl, assertNonEmptyString, assertObject, optionalBoolean, optionalInt, optionalNumber, optionalString } from "../shared/validation.js";
|
|
18
|
+
import { computeTarSizeBytes, TarStream } from "../shared/tar.js";
|
|
19
|
+
/**
|
|
20
|
+
* Content type for EnriVision media-set archives (tar, no compression).
|
|
21
|
+
*/
|
|
22
|
+
const ENRIVISION_MEDIA_SET_TAR_CONTENT_TYPE = "application/vnd.enrivision.media-set+tar";
|
|
23
|
+
/**
|
|
24
|
+
* Fixed manifest entry name inside EnriVision media-set tar archives.
|
|
25
|
+
*/
|
|
26
|
+
const ENRIVISION_MEDIA_SET_TAR_MANIFEST_NAME = "manifest.json";
|
|
27
|
+
/**
|
|
28
|
+
* MCP tool that uploads and analyzes local media.
|
|
29
|
+
*/
|
|
30
|
+
export class AnalyzeMediaTool {
|
|
31
|
+
/**
|
|
32
|
+
* Tool dependencies.
|
|
33
|
+
*/
|
|
34
|
+
deps;
|
|
35
|
+
/**
|
|
36
|
+
* Creates a new {@link AnalyzeMediaTool}.
|
|
37
|
+
*
|
|
38
|
+
* @param deps - Tool dependencies
|
|
39
|
+
*/
|
|
40
|
+
constructor(deps) {
|
|
41
|
+
this.deps = deps;
|
|
42
|
+
}
|
|
43
|
+
/**
|
|
44
|
+
* Validates raw MCP tool arguments.
|
|
45
|
+
*
|
|
46
|
+
* @param raw - Raw tool arguments
|
|
47
|
+
* @returns Validated parameters
|
|
48
|
+
*/
|
|
49
|
+
parseParams(raw) {
|
|
50
|
+
const obj = assertObject(raw, "arguments");
|
|
51
|
+
const pathRaw = typeof obj["path"] === "string" ? obj["path"].trim() : "";
|
|
52
|
+
const path = pathRaw ? pathRaw : undefined;
|
|
53
|
+
if (path && !isAbsolute(path)) {
|
|
54
|
+
throw new Error("path must be an absolute file path.");
|
|
55
|
+
}
|
|
56
|
+
const pathsRaw = obj["paths"];
|
|
57
|
+
let paths;
|
|
58
|
+
if (typeof pathsRaw !== "undefined") {
|
|
59
|
+
if (!Array.isArray(pathsRaw)) {
|
|
60
|
+
throw new Error("paths must be an array of absolute file paths.");
|
|
61
|
+
}
|
|
62
|
+
const out = [];
|
|
63
|
+
for (const item of pathsRaw) {
|
|
64
|
+
if (typeof item !== "string" || !item.trim()) {
|
|
65
|
+
continue;
|
|
66
|
+
}
|
|
67
|
+
const p = item.trim();
|
|
68
|
+
if (!isAbsolute(p)) {
|
|
69
|
+
throw new Error("paths must contain only absolute file paths.");
|
|
70
|
+
}
|
|
71
|
+
out.push(p);
|
|
72
|
+
}
|
|
73
|
+
if (out.length > 0) {
|
|
74
|
+
paths = out;
|
|
75
|
+
}
|
|
76
|
+
}
|
|
77
|
+
if (!path && (!paths || paths.length === 0)) {
|
|
78
|
+
throw new Error("Provide either 'path' or 'paths'.");
|
|
79
|
+
}
|
|
80
|
+
const context = optionalString(obj["context"]);
|
|
81
|
+
const question = optionalString(obj["question"]);
|
|
82
|
+
const language = optionalString(obj["language"]);
|
|
83
|
+
const maxFrames = optionalInt(obj["max_frames"]);
|
|
84
|
+
const transcribe = optionalBoolean(obj["transcribe"]);
|
|
85
|
+
const transcriptionLanguage = optionalString(obj["transcription_language"]);
|
|
86
|
+
const analysisModeRaw = optionalString(obj["analysis_mode"]);
|
|
87
|
+
const analysisMode = analysisModeRaw === "auto" || analysisModeRaw === "single" || analysisModeRaw === "multipass"
|
|
88
|
+
? analysisModeRaw
|
|
89
|
+
: analysisModeRaw
|
|
90
|
+
? (() => {
|
|
91
|
+
throw new Error("analysis_mode must be one of: auto|single|multipass.");
|
|
92
|
+
})()
|
|
93
|
+
: undefined;
|
|
94
|
+
const videoRaw = obj["video"];
|
|
95
|
+
let video;
|
|
96
|
+
if (typeof videoRaw !== "undefined") {
|
|
97
|
+
const v = assertObject(videoRaw, "video");
|
|
98
|
+
video = {
|
|
99
|
+
clipStartSeconds: optionalNumber(v["clip_start_seconds"]),
|
|
100
|
+
clipDurationSeconds: optionalNumber(v["clip_duration_seconds"]),
|
|
101
|
+
segmentSeconds: optionalNumber(v["segment_seconds"]),
|
|
102
|
+
maxSegments: optionalInt(v["max_segments"]),
|
|
103
|
+
maxFramesPerSegment: optionalInt(v["max_frames_per_segment"])
|
|
104
|
+
};
|
|
105
|
+
}
|
|
106
|
+
const documentRaw = obj["document"];
|
|
107
|
+
let document;
|
|
108
|
+
if (typeof documentRaw !== "undefined") {
|
|
109
|
+
const d = assertObject(documentRaw, "document");
|
|
110
|
+
document = {
|
|
111
|
+
maxPagesTotal: optionalInt(d["max_pages_total"]),
|
|
112
|
+
pagesPerBatch: optionalInt(d["pages_per_batch"]),
|
|
113
|
+
maxImagesPerBatch: optionalInt(d["max_images_per_batch"]),
|
|
114
|
+
scannedTextThresholdChars: optionalInt(d["scanned_text_threshold_chars"])
|
|
115
|
+
};
|
|
116
|
+
}
|
|
117
|
+
const audioRaw = obj["audio"];
|
|
118
|
+
let audio;
|
|
119
|
+
if (typeof audioRaw !== "undefined") {
|
|
120
|
+
const a = assertObject(audioRaw, "audio");
|
|
121
|
+
audio = {
|
|
122
|
+
timestamps: optionalBoolean(a["timestamps"]),
|
|
123
|
+
segmentSeconds: optionalNumber(a["segment_seconds"]),
|
|
124
|
+
maxSegments: optionalInt(a["max_segments"])
|
|
125
|
+
};
|
|
126
|
+
}
|
|
127
|
+
const imagesRaw = obj["images"];
|
|
128
|
+
let images;
|
|
129
|
+
if (typeof imagesRaw !== "undefined") {
|
|
130
|
+
const img = assertObject(imagesRaw, "images");
|
|
131
|
+
images = {
|
|
132
|
+
maxImagesTotal: optionalInt(img["max_images_total"]),
|
|
133
|
+
imagesPerBatch: optionalInt(img["images_per_batch"]),
|
|
134
|
+
maxDimension: optionalInt(img["max_dimension"])
|
|
135
|
+
};
|
|
136
|
+
}
|
|
137
|
+
return {
|
|
138
|
+
path,
|
|
139
|
+
paths,
|
|
140
|
+
context,
|
|
141
|
+
question,
|
|
142
|
+
language,
|
|
143
|
+
maxFrames,
|
|
144
|
+
transcribe,
|
|
145
|
+
transcriptionLanguage,
|
|
146
|
+
analysisMode,
|
|
147
|
+
video,
|
|
148
|
+
document,
|
|
149
|
+
audio,
|
|
150
|
+
images
|
|
151
|
+
};
|
|
152
|
+
}
|
|
153
|
+
/**
|
|
154
|
+
* Executes the tool.
|
|
155
|
+
*
|
|
156
|
+
* @param params - Validated parameters
|
|
157
|
+
* @returns Tool result
|
|
158
|
+
*/
|
|
159
|
+
async execute(params) {
|
|
160
|
+
const serverUrl = assertHttpUrl(this.deps.defaultServerUrl, "ENRIPROXY_URL");
|
|
161
|
+
const apiKey = assertNonEmptyString(this.deps.defaultApiKey, "ENRIPROXY_API_KEY");
|
|
162
|
+
const timeoutMs = this.deps.defaultTimeoutMs;
|
|
163
|
+
const clientTraceId = `enrivision_${randomUUID()}`;
|
|
164
|
+
const client = this.deps.createClient(serverUrl, apiKey, timeoutMs);
|
|
165
|
+
const resolvedPaths = Array.isArray(params.paths) && params.paths.length > 0
|
|
166
|
+
? [...params.paths]
|
|
167
|
+
: typeof params.path === "string" && params.path.trim()
|
|
168
|
+
? [params.path.trim()]
|
|
169
|
+
: [];
|
|
170
|
+
if (resolvedPaths.length === 0) {
|
|
171
|
+
throw new Error("Provide either 'path' or 'paths'.");
|
|
172
|
+
}
|
|
173
|
+
let uploadId;
|
|
174
|
+
if (resolvedPaths.length > 1) {
|
|
175
|
+
uploadId = await this.uploadImageSetAsMediaSetTar(client, resolvedPaths, timeoutMs, clientTraceId);
|
|
176
|
+
}
|
|
177
|
+
else {
|
|
178
|
+
const singlePath = resolvedPaths[0];
|
|
179
|
+
const fileSize = await this.assertReadableFile(singlePath);
|
|
180
|
+
const filename = basename(singlePath);
|
|
181
|
+
const contentType = this.detectMimeType(singlePath);
|
|
182
|
+
const session = await client.createUploadSession({
|
|
183
|
+
filename,
|
|
184
|
+
sizeBytes: fileSize,
|
|
185
|
+
contentType,
|
|
186
|
+
clientTraceId
|
|
187
|
+
});
|
|
188
|
+
const finalOffset = await this.uploadFileResumable(client, singlePath, fileSize, session, timeoutMs);
|
|
189
|
+
if (finalOffset !== fileSize) {
|
|
190
|
+
throw new Error(`Upload incomplete: sent ${finalOffset} of ${fileSize} bytes.`);
|
|
191
|
+
}
|
|
192
|
+
uploadId = session.upload_id;
|
|
193
|
+
}
|
|
194
|
+
const defaultLanguageRaw = typeof process.env["ENRIVISION_DEFAULT_LANGUAGE"] === "string"
|
|
195
|
+
? process.env["ENRIVISION_DEFAULT_LANGUAGE"].trim()
|
|
196
|
+
: "";
|
|
197
|
+
const language = typeof params.language === "string" && params.language.trim()
|
|
198
|
+
? params.language.trim()
|
|
199
|
+
: defaultLanguageRaw
|
|
200
|
+
? defaultLanguageRaw
|
|
201
|
+
: undefined;
|
|
202
|
+
const analysis = await client.analyze({
|
|
203
|
+
uploadId,
|
|
204
|
+
context: params.context,
|
|
205
|
+
question: params.question,
|
|
206
|
+
language,
|
|
207
|
+
maxFrames: params.maxFrames,
|
|
208
|
+
transcribe: params.transcribe,
|
|
209
|
+
transcriptionLanguage: params.transcriptionLanguage,
|
|
210
|
+
analysisMode: params.analysisMode,
|
|
211
|
+
video: params.video,
|
|
212
|
+
document: params.document,
|
|
213
|
+
audio: params.audio,
|
|
214
|
+
images: params.images
|
|
215
|
+
});
|
|
216
|
+
const extraction = this.stripInternalExtractionFields(analysis.extraction);
|
|
217
|
+
return {
|
|
218
|
+
analysis: analysis.analysis,
|
|
219
|
+
media_type: analysis.media_type,
|
|
220
|
+
extraction
|
|
221
|
+
};
|
|
222
|
+
}
|
|
223
|
+
/**
|
|
224
|
+
* Removes internal identifiers (upload ids, routing-only values, etc.) from the
|
|
225
|
+
* extraction payload before returning it to the model.
|
|
226
|
+
*
|
|
227
|
+
* @param extraction - Raw extraction object returned by EnriProxy
|
|
228
|
+
* @returns Sanitized extraction object
|
|
229
|
+
*/
|
|
230
|
+
stripInternalExtractionFields(extraction) {
|
|
231
|
+
const stripped = this.stripInternalFields(extraction);
|
|
232
|
+
return this.asPlainObject(stripped);
|
|
233
|
+
}
|
|
234
|
+
/**
|
|
235
|
+
* Recursively strips internal fields from an unknown value.
|
|
236
|
+
*
|
|
237
|
+
* @param value - Unknown value to sanitize
|
|
238
|
+
* @returns Sanitized value
|
|
239
|
+
*/
|
|
240
|
+
stripInternalFields(value) {
|
|
241
|
+
if (Array.isArray(value)) {
|
|
242
|
+
return value.map((item) => this.stripInternalFields(item));
|
|
243
|
+
}
|
|
244
|
+
if (!value || typeof value !== "object") {
|
|
245
|
+
return value;
|
|
246
|
+
}
|
|
247
|
+
const record = value;
|
|
248
|
+
const next = {};
|
|
249
|
+
for (const [key, child] of Object.entries(record)) {
|
|
250
|
+
if (key === "upload_id" || key === "uploadId") {
|
|
251
|
+
continue;
|
|
252
|
+
}
|
|
253
|
+
if (key === "detected_media_type") {
|
|
254
|
+
continue;
|
|
255
|
+
}
|
|
256
|
+
if (key === "analysis_mode_requested" || key === "analysis_mode_used") {
|
|
257
|
+
continue;
|
|
258
|
+
}
|
|
259
|
+
if (key === "multipass") {
|
|
260
|
+
continue;
|
|
261
|
+
}
|
|
262
|
+
if (key === "model") {
|
|
263
|
+
continue;
|
|
264
|
+
}
|
|
265
|
+
next[key] = this.stripInternalFields(child);
|
|
266
|
+
}
|
|
267
|
+
return next;
|
|
268
|
+
}
|
|
269
|
+
/**
|
|
270
|
+
* Ensures the sanitized extraction value is a plain JSON object.
|
|
271
|
+
*
|
|
272
|
+
* @param value - Sanitized value
|
|
273
|
+
* @returns Plain object
|
|
274
|
+
*/
|
|
275
|
+
asPlainObject(value) {
|
|
276
|
+
if (value && typeof value === "object" && !Array.isArray(value)) {
|
|
277
|
+
return value;
|
|
278
|
+
}
|
|
279
|
+
return {};
|
|
280
|
+
}
|
|
281
|
+
/**
|
|
282
|
+
* Validates that a path exists and is a readable file.
|
|
283
|
+
*
|
|
284
|
+
* @param filePath - Local filesystem path
|
|
285
|
+
* @returns File size in bytes
|
|
286
|
+
*/
|
|
287
|
+
async assertReadableFile(filePath) {
|
|
288
|
+
if (!existsSync(filePath)) {
|
|
289
|
+
throw new Error(`File not found: ${filePath}`);
|
|
290
|
+
}
|
|
291
|
+
const st = await stat(filePath);
|
|
292
|
+
if (!st.isFile()) {
|
|
293
|
+
throw new Error(`Not a file: ${filePath}`);
|
|
294
|
+
}
|
|
295
|
+
// Ensure the file is readable.
|
|
296
|
+
const handle = await open(filePath, "r");
|
|
297
|
+
try {
|
|
298
|
+
return st.size;
|
|
299
|
+
}
|
|
300
|
+
finally {
|
|
301
|
+
await handle.close();
|
|
302
|
+
}
|
|
303
|
+
}
|
|
304
|
+
/**
|
|
305
|
+
* Detects MIME type using file extension.
|
|
306
|
+
*
|
|
307
|
+
* @param filePath - File path
|
|
308
|
+
* @returns MIME type string
|
|
309
|
+
*/
|
|
310
|
+
detectMimeType(filePath) {
|
|
311
|
+
const detected = mimeLookup(filePath);
|
|
312
|
+
if (typeof detected === "string" && detected.trim()) {
|
|
313
|
+
return detected.trim();
|
|
314
|
+
}
|
|
315
|
+
return "application/octet-stream";
|
|
316
|
+
}
|
|
317
|
+
/**
|
|
318
|
+
* Uploads multiple local images as a single EnriVision media-set tar archive.
|
|
319
|
+
*
|
|
320
|
+
* @remarks
|
|
321
|
+
* This avoids creating many concurrent resumable upload sessions (which are
|
|
322
|
+
* capped per API key) and enables server-side batching + reduce for large
|
|
323
|
+
* screenshot sets.
|
|
324
|
+
*
|
|
325
|
+
* @param client - EnriProxy client
|
|
326
|
+
* @param filePaths - Absolute image file paths
|
|
327
|
+
* @param timeoutMs - Request timeout per HTTP request
|
|
328
|
+
* @param clientTraceId - Client trace id for correlation
|
|
329
|
+
* @returns Upload id for the created tar session
|
|
330
|
+
*/
|
|
331
|
+
async uploadImageSetAsMediaSetTar(client, filePaths, timeoutMs, clientTraceId) {
|
|
332
|
+
if (filePaths.length < 2) {
|
|
333
|
+
throw new Error("uploadImageSetAsMediaSetTar requires at least 2 file paths.");
|
|
334
|
+
}
|
|
335
|
+
const files = [];
|
|
336
|
+
for (let i = 0; i < filePaths.length; i += 1) {
|
|
337
|
+
const p = filePaths[i];
|
|
338
|
+
const sizeBytes = await this.assertReadableFile(p);
|
|
339
|
+
const filename = basename(p);
|
|
340
|
+
const contentType = this.detectMimeType(p);
|
|
341
|
+
if (!contentType.toLowerCase().startsWith("image/")) {
|
|
342
|
+
throw new Error(`paths must contain only image files. Not an image: ${p} (${contentType})`);
|
|
343
|
+
}
|
|
344
|
+
const extRaw = extname(filename).toLowerCase();
|
|
345
|
+
const ext = extRaw && /^[a-z0-9.]+$/.test(extRaw) ? extRaw : ".img";
|
|
346
|
+
const entryName = `${String(i + 1).padStart(6, "0")}${ext}`;
|
|
347
|
+
files.push({
|
|
348
|
+
index: i + 1,
|
|
349
|
+
path: p,
|
|
350
|
+
filename,
|
|
351
|
+
sizeBytes,
|
|
352
|
+
contentType,
|
|
353
|
+
entryName
|
|
354
|
+
});
|
|
355
|
+
}
|
|
356
|
+
const manifest = {
|
|
357
|
+
type: "enrivision_media_set",
|
|
358
|
+
version: 1,
|
|
359
|
+
media_type: "image_set",
|
|
360
|
+
items: files.map((f) => ({
|
|
361
|
+
index: f.index,
|
|
362
|
+
name: f.entryName,
|
|
363
|
+
filename: f.filename,
|
|
364
|
+
content_type: f.contentType,
|
|
365
|
+
size_bytes: f.sizeBytes
|
|
366
|
+
}))
|
|
367
|
+
};
|
|
368
|
+
const manifestBuffer = Buffer.from(JSON.stringify(manifest), "utf8");
|
|
369
|
+
const nowSeconds = Math.floor(Date.now() / 1000);
|
|
370
|
+
const entries = [
|
|
371
|
+
{
|
|
372
|
+
name: ENRIVISION_MEDIA_SET_TAR_MANIFEST_NAME,
|
|
373
|
+
source: { type: "buffer", buffer: manifestBuffer },
|
|
374
|
+
mtimeSeconds: nowSeconds
|
|
375
|
+
},
|
|
376
|
+
...files.map((f) => ({
|
|
377
|
+
name: f.entryName,
|
|
378
|
+
source: { type: "file", path: f.path, sizeBytes: f.sizeBytes },
|
|
379
|
+
mtimeSeconds: nowSeconds
|
|
380
|
+
}))
|
|
381
|
+
];
|
|
382
|
+
const tarSizeBytes = computeTarSizeBytes(entries);
|
|
383
|
+
const tar = new TarStream(entries);
|
|
384
|
+
if (tar.getSizeBytes() !== tarSizeBytes) {
|
|
385
|
+
throw new Error("Internal error: tar size mismatch.");
|
|
386
|
+
}
|
|
387
|
+
const session = await client.createUploadSession({
|
|
388
|
+
filename: "enrivision-image-set.tar",
|
|
389
|
+
sizeBytes: tarSizeBytes,
|
|
390
|
+
contentType: ENRIVISION_MEDIA_SET_TAR_CONTENT_TYPE,
|
|
391
|
+
clientTraceId
|
|
392
|
+
});
|
|
393
|
+
const chunkSize = Math.max(1, Math.floor(session.chunk_size_bytes));
|
|
394
|
+
let offset = await client.getUploadOffset(session.upload_id);
|
|
395
|
+
if (offset < 0 || offset > tarSizeBytes) {
|
|
396
|
+
throw new Error(`Invalid server offset for tar upload: ${offset}`);
|
|
397
|
+
}
|
|
398
|
+
while (offset < tarSizeBytes) {
|
|
399
|
+
let madeProgress = false;
|
|
400
|
+
for await (const chunk of tar.iterateChunks(offset, chunkSize)) {
|
|
401
|
+
if (chunk.length === 0) {
|
|
402
|
+
continue;
|
|
403
|
+
}
|
|
404
|
+
const expectedOffset = offset;
|
|
405
|
+
const nextOffset = await this.uploadChunkWithRetry(client, session.upload_id, expectedOffset, chunk, timeoutMs);
|
|
406
|
+
offset = nextOffset;
|
|
407
|
+
madeProgress = true;
|
|
408
|
+
const progress = Math.floor((offset / tarSizeBytes) * 100);
|
|
409
|
+
console.error(`enrivision: upload ${progress}% (${offset}/${tarSizeBytes} bytes)`);
|
|
410
|
+
// Offset resync: restart generation from the server-provided offset.
|
|
411
|
+
if (offset !== expectedOffset + chunk.length) {
|
|
412
|
+
break;
|
|
413
|
+
}
|
|
414
|
+
if (offset >= tarSizeBytes) {
|
|
415
|
+
break;
|
|
416
|
+
}
|
|
417
|
+
}
|
|
418
|
+
if (!madeProgress) {
|
|
419
|
+
throw new Error("Upload stalled: no progress while sending tar chunks.");
|
|
420
|
+
}
|
|
421
|
+
}
|
|
422
|
+
if (offset !== tarSizeBytes) {
|
|
423
|
+
throw new Error(`Upload incomplete: sent ${offset} of ${tarSizeBytes} bytes.`);
|
|
424
|
+
}
|
|
425
|
+
return session.upload_id;
|
|
426
|
+
}
|
|
427
|
+
/**
|
|
428
|
+
* Uploads a file to EnriProxy in resumable chunks.
|
|
429
|
+
*
|
|
430
|
+
* @param client - EnriProxy client
|
|
431
|
+
* @param filePath - Local file path
|
|
432
|
+
* @param fileSize - Total file size in bytes
|
|
433
|
+
* @param session - Server-created session
|
|
434
|
+
* @param timeoutMs - Request timeout in milliseconds
|
|
435
|
+
* @returns Final offset
|
|
436
|
+
*/
|
|
437
|
+
async uploadFileResumable(client, filePath, fileSize, session, timeoutMs) {
|
|
438
|
+
const chunkSize = Math.max(1, Math.floor(session.chunk_size_bytes));
|
|
439
|
+
const handle = await open(filePath, "r");
|
|
440
|
+
try {
|
|
441
|
+
let offset = await client.getUploadOffset(session.upload_id);
|
|
442
|
+
while (offset < fileSize) {
|
|
443
|
+
const remaining = fileSize - offset;
|
|
444
|
+
const nextSize = Math.min(chunkSize, remaining);
|
|
445
|
+
const buffer = Buffer.allocUnsafe(nextSize);
|
|
446
|
+
const read = await handle.read(buffer, 0, nextSize, offset);
|
|
447
|
+
if (read.bytesRead <= 0) {
|
|
448
|
+
break;
|
|
449
|
+
}
|
|
450
|
+
const chunk = read.bytesRead === buffer.length ? buffer : buffer.subarray(0, read.bytesRead);
|
|
451
|
+
offset = await this.uploadChunkWithRetry(client, session.upload_id, offset, chunk, timeoutMs);
|
|
452
|
+
const progress = Math.floor((offset / fileSize) * 100);
|
|
453
|
+
console.error(`enrivision: upload ${progress}% (${offset}/${fileSize} bytes)`);
|
|
454
|
+
}
|
|
455
|
+
return offset;
|
|
456
|
+
}
|
|
457
|
+
finally {
|
|
458
|
+
await handle.close();
|
|
459
|
+
}
|
|
460
|
+
}
|
|
461
|
+
/**
|
|
462
|
+
* Uploads a single chunk with retry and offset resync.
|
|
463
|
+
*
|
|
464
|
+
* @param client - EnriProxy client
|
|
465
|
+
* @param uploadId - Upload id
|
|
466
|
+
* @param offset - Expected offset
|
|
467
|
+
* @param chunk - Chunk bytes
|
|
468
|
+
* @param timeoutMs - Timeout in ms
|
|
469
|
+
* @returns New offset
|
|
470
|
+
*/
|
|
471
|
+
async uploadChunkWithRetry(client, uploadId, offset, chunk, timeoutMs) {
|
|
472
|
+
const maxAttempts = 5;
|
|
473
|
+
for (let attempt = 1; attempt <= maxAttempts; attempt += 1) {
|
|
474
|
+
try {
|
|
475
|
+
return await client.appendUploadChunk({ uploadId, offset, chunk, timeoutMs });
|
|
476
|
+
}
|
|
477
|
+
catch (error) {
|
|
478
|
+
const message = error instanceof Error ? error.message : String(error);
|
|
479
|
+
if (error instanceof EnriProxyHttpError) {
|
|
480
|
+
// Offset mismatch: resync and let the caller re-read at the correct offset.
|
|
481
|
+
if (error.status === 409) {
|
|
482
|
+
const actual = await client.getUploadOffset(uploadId);
|
|
483
|
+
if (actual !== offset) {
|
|
484
|
+
console.error(`enrivision: offset resync (${offset} -> ${actual})`);
|
|
485
|
+
return actual;
|
|
486
|
+
}
|
|
487
|
+
}
|
|
488
|
+
// Do not retry on client errors (except 409 which is handled above).
|
|
489
|
+
if (error.status === 400 ||
|
|
490
|
+
error.status === 401 ||
|
|
491
|
+
error.status === 403 ||
|
|
492
|
+
error.status === 404 ||
|
|
493
|
+
error.status === 410 ||
|
|
494
|
+
error.status === 413) {
|
|
495
|
+
throw error;
|
|
496
|
+
}
|
|
497
|
+
}
|
|
498
|
+
if (attempt === maxAttempts) {
|
|
499
|
+
throw error;
|
|
500
|
+
}
|
|
501
|
+
const backoffMs = Math.min(1000 * Math.pow(2, attempt - 1), 10000);
|
|
502
|
+
console.error(`enrivision: retry ${attempt}/${maxAttempts} after ${backoffMs}ms (${message})`);
|
|
503
|
+
await new Promise((resolve) => setTimeout(resolve, backoffMs));
|
|
504
|
+
}
|
|
505
|
+
}
|
|
506
|
+
throw new Error("Upload failed after retries.");
|
|
507
|
+
}
|
|
508
|
+
}
|
|
509
|
+
//# sourceMappingURL=AnalyzeMediaTool.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"AnalyzeMediaTool.js","sourceRoot":"","sources":["../../src/tools/AnalyzeMediaTool.ts"],"names":[],"mappings":"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"}
|
package/package.json
ADDED
|
@@ -0,0 +1,58 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@bedolla/enrivision",
|
|
3
|
+
"version": "0.1.0",
|
|
4
|
+
"description": "MCP server that uploads local media to EnriProxy and returns server-side analysis (resumable uploads).",
|
|
5
|
+
"keywords": [
|
|
6
|
+
"mcp",
|
|
7
|
+
"model-context-protocol",
|
|
8
|
+
"enrivision",
|
|
9
|
+
"enriproxy",
|
|
10
|
+
"vision",
|
|
11
|
+
"video",
|
|
12
|
+
"audio",
|
|
13
|
+
"image",
|
|
14
|
+
"document"
|
|
15
|
+
],
|
|
16
|
+
"repository": {
|
|
17
|
+
"type": "git",
|
|
18
|
+
"url": "git+https://github.com/Bedolla/EnriVision.git"
|
|
19
|
+
},
|
|
20
|
+
"bugs": {
|
|
21
|
+
"url": "https://github.com/Bedolla/EnriVision/issues"
|
|
22
|
+
},
|
|
23
|
+
"homepage": "https://github.com/Bedolla/EnriVision#readme",
|
|
24
|
+
"license": "AGPL-3.0-only",
|
|
25
|
+
"author": "Pipochas",
|
|
26
|
+
"type": "module",
|
|
27
|
+
"main": "dist/index.js",
|
|
28
|
+
"bin": {
|
|
29
|
+
"enrivision": "dist/index.js"
|
|
30
|
+
},
|
|
31
|
+
"publishConfig": {
|
|
32
|
+
"access": "public"
|
|
33
|
+
},
|
|
34
|
+
"files": [
|
|
35
|
+
"dist",
|
|
36
|
+
"README.md",
|
|
37
|
+
"LICENSE"
|
|
38
|
+
],
|
|
39
|
+
"scripts": {
|
|
40
|
+
"typecheck": "tsc -p tsconfig.json --noEmit",
|
|
41
|
+
"build": "tsc -p tsconfig.json",
|
|
42
|
+
"prepack": "npm run build",
|
|
43
|
+
"start": "node dist/index.js",
|
|
44
|
+
"test": "vitest run"
|
|
45
|
+
},
|
|
46
|
+
"dependencies": {
|
|
47
|
+
"@modelcontextprotocol/sdk": "1.25.1",
|
|
48
|
+
"mime-types": "3.0.2"
|
|
49
|
+
},
|
|
50
|
+
"devDependencies": {
|
|
51
|
+
"@types/node": "25.0.3",
|
|
52
|
+
"typescript": "5.9.3",
|
|
53
|
+
"vitest": "4.0.16"
|
|
54
|
+
},
|
|
55
|
+
"engines": {
|
|
56
|
+
"node": ">=22"
|
|
57
|
+
}
|
|
58
|
+
}
|