markpdfdown 0.1.7 → 0.1.8
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/dist/main/index.js +182 -69
- package/dist/preload/index.js +0 -1
- package/dist/renderer/assets/{index-C9Uc3AS4.js → index-iEK8qT5k.js} +5345 -4775
- package/dist/renderer/assets/index-yTU2skrN.css +327 -0
- package/dist/renderer/index.html +2 -2
- package/package.json +16 -3
- package/dist/renderer/assets/index-CbMlWqbh.css +0 -327
package/dist/main/index.js
CHANGED
|
@@ -516,6 +516,69 @@ class ImagePathUtil {
|
|
|
516
516
|
this.uploadsDir = null;
|
|
517
517
|
}
|
|
518
518
|
}
|
|
519
|
+
class FileWaitUtil {
|
|
520
|
+
static MAX_ATTEMPTS = 5;
|
|
521
|
+
static DELAY_MS = 1e3;
|
|
522
|
+
/**
|
|
523
|
+
* Wait for a file to become available and non-empty.
|
|
524
|
+
*
|
|
525
|
+
* @param filePath - Full path to the file
|
|
526
|
+
* @param uploadsDir - Base uploads directory for diagnostic logging
|
|
527
|
+
* @param taskId - Task ID for diagnostic logging
|
|
528
|
+
* @param filename - Original filename for error messages
|
|
529
|
+
* @param label - Log label (e.g., 'PDFSplitter', 'ImageSplitter')
|
|
530
|
+
* @throws Error if the file is not found after all retries
|
|
531
|
+
*/
|
|
532
|
+
static async waitForFile(filePath, uploadsDir, taskId, filename, label) {
|
|
533
|
+
for (let attempt = 1; attempt <= this.MAX_ATTEMPTS; attempt++) {
|
|
534
|
+
try {
|
|
535
|
+
await promises.access(filePath);
|
|
536
|
+
const stats = await promises.stat(filePath);
|
|
537
|
+
if (stats.size > 0) {
|
|
538
|
+
if (attempt > 1) {
|
|
539
|
+
console.log(
|
|
540
|
+
`[${label}] File became available on attempt ${attempt}: ${filePath}`
|
|
541
|
+
);
|
|
542
|
+
}
|
|
543
|
+
return;
|
|
544
|
+
}
|
|
545
|
+
console.warn(
|
|
546
|
+
`[${label}] File exists but is empty (attempt ${attempt}/${this.MAX_ATTEMPTS}): ${filePath}`
|
|
547
|
+
);
|
|
548
|
+
} catch {
|
|
549
|
+
console.warn(
|
|
550
|
+
`[${label}] File not accessible (attempt ${attempt}/${this.MAX_ATTEMPTS}): ${filePath}`
|
|
551
|
+
);
|
|
552
|
+
}
|
|
553
|
+
if (attempt < this.MAX_ATTEMPTS) {
|
|
554
|
+
await new Promise((resolve) => setTimeout(resolve, this.DELAY_MS));
|
|
555
|
+
}
|
|
556
|
+
}
|
|
557
|
+
await this.logDiagnostics(uploadsDir, taskId, filename, label);
|
|
558
|
+
throw new Error(
|
|
559
|
+
`${label === "PDFSplitter" ? "PDF" : "Image"} file not found: ${filename}. The file may have been moved or deleted.`
|
|
560
|
+
);
|
|
561
|
+
}
|
|
562
|
+
/**
|
|
563
|
+
* Log diagnostic information about the task directory contents.
|
|
564
|
+
*/
|
|
565
|
+
static async logDiagnostics(uploadsDir, taskId, filename, label) {
|
|
566
|
+
const taskDir = path.join(uploadsDir, taskId);
|
|
567
|
+
try {
|
|
568
|
+
const dirExists = await promises.stat(taskDir).then(() => true).catch(() => false);
|
|
569
|
+
if (dirExists) {
|
|
570
|
+
const files = await promises.readdir(taskDir);
|
|
571
|
+
console.error(
|
|
572
|
+
`[${label}] Task directory exists but target file not found. Dir: ${taskDir}, Files in dir: [${files.join(", ")}], Expected: ${filename}`
|
|
573
|
+
);
|
|
574
|
+
} else {
|
|
575
|
+
console.error(`[${label}] Task directory does not exist: ${taskDir}`);
|
|
576
|
+
}
|
|
577
|
+
} catch (diagError) {
|
|
578
|
+
console.error(`[${label}] Diagnostic check failed:`, diagError);
|
|
579
|
+
}
|
|
580
|
+
}
|
|
581
|
+
}
|
|
519
582
|
class PageRangeParser {
|
|
520
583
|
/**
|
|
521
584
|
* Regular expression for validating page range format.
|
|
@@ -684,6 +747,7 @@ class PDFSplitter {
|
|
|
684
747
|
const taskId = task.id;
|
|
685
748
|
const filename = task.filename;
|
|
686
749
|
const sourcePath = path.join(this.uploadsDir, taskId, filename);
|
|
750
|
+
await FileWaitUtil.waitForFile(sourcePath, this.uploadsDir, taskId, filename, "PDFSplitter");
|
|
687
751
|
try {
|
|
688
752
|
const totalPages = await this.getPDFPageCountWithRetry(sourcePath);
|
|
689
753
|
const pageNumbers = PageRangeParser.parse(task.page_range, totalPages);
|
|
@@ -855,8 +919,8 @@ class ImageSplitter {
|
|
|
855
919
|
const taskId = task.id;
|
|
856
920
|
const filename = task.filename;
|
|
857
921
|
const sourcePath = path.join(this.uploadsDir, taskId, filename);
|
|
922
|
+
await FileWaitUtil.waitForFile(sourcePath, this.uploadsDir, taskId, filename, "ImageSplitter");
|
|
858
923
|
try {
|
|
859
|
-
await promises.access(sourcePath);
|
|
860
924
|
const ext = path.extname(filename).toLowerCase();
|
|
861
925
|
if (!ext) {
|
|
862
926
|
throw new Error(`Image file has no extension: ${filename}`);
|
|
@@ -1119,6 +1183,22 @@ const findAll$2 = async () => {
|
|
|
1119
1183
|
orderBy: [{ createdAt: "desc" }]
|
|
1120
1184
|
});
|
|
1121
1185
|
};
|
|
1186
|
+
const findAllIncludeDisabled = async () => {
|
|
1187
|
+
return await prisma.provider.findMany({
|
|
1188
|
+
select: {
|
|
1189
|
+
id: true,
|
|
1190
|
+
name: true,
|
|
1191
|
+
type: true,
|
|
1192
|
+
api_key: true,
|
|
1193
|
+
base_url: true,
|
|
1194
|
+
suffix: true,
|
|
1195
|
+
status: true,
|
|
1196
|
+
createdAt: true,
|
|
1197
|
+
updatedAt: true
|
|
1198
|
+
},
|
|
1199
|
+
orderBy: [{ createdAt: "desc" }]
|
|
1200
|
+
});
|
|
1201
|
+
};
|
|
1122
1202
|
const findById$1 = async (id) => {
|
|
1123
1203
|
return await prisma.provider.findUnique({
|
|
1124
1204
|
where: { id },
|
|
@@ -1169,6 +1249,7 @@ const updateStatus = async (id, status) => {
|
|
|
1169
1249
|
};
|
|
1170
1250
|
const providerRepository = {
|
|
1171
1251
|
findAll: findAll$2,
|
|
1252
|
+
findAllIncludeDisabled,
|
|
1172
1253
|
findById: findById$1,
|
|
1173
1254
|
create: create$2,
|
|
1174
1255
|
update: update$1,
|
|
@@ -1411,25 +1492,31 @@ class ConverterWorker extends WorkerBase {
|
|
|
1411
1492
|
/**
|
|
1412
1493
|
* Claim a PENDING page for processing using optimistic locking.
|
|
1413
1494
|
*
|
|
1414
|
-
*
|
|
1415
|
-
*
|
|
1416
|
-
*
|
|
1417
|
-
* - page.status = PENDING
|
|
1418
|
-
* - page.worker_id = null
|
|
1495
|
+
* Strategy: First find tasks in valid states (PROCESSING/COMPLETED),
|
|
1496
|
+
* then find PENDING pages only within those tasks. This avoids the problem
|
|
1497
|
+
* where orphaned PENDING pages from terminal tasks exhaust claim attempts.
|
|
1419
1498
|
*
|
|
1420
1499
|
* Order: retry_count ASC, page ASC (prioritize fresh pages)
|
|
1421
1500
|
*/
|
|
1422
1501
|
async claimPage() {
|
|
1423
1502
|
const maxAttempts = 5;
|
|
1424
|
-
const
|
|
1503
|
+
const activeTasks = await prisma.task.findMany({
|
|
1504
|
+
where: {
|
|
1505
|
+
status: { in: [TaskStatus.PROCESSING, TaskStatus.COMPLETED] }
|
|
1506
|
+
},
|
|
1507
|
+
select: { id: true }
|
|
1508
|
+
});
|
|
1509
|
+
if (activeTasks.length === 0) {
|
|
1510
|
+
return null;
|
|
1511
|
+
}
|
|
1512
|
+
const activeTaskIds = activeTasks.map((t) => t.id);
|
|
1425
1513
|
for (let attempt = 0; attempt < maxAttempts; attempt++) {
|
|
1426
1514
|
try {
|
|
1427
1515
|
const candidate = await prisma.taskDetail.findFirst({
|
|
1428
1516
|
where: {
|
|
1429
1517
|
status: PageStatus.PENDING,
|
|
1430
1518
|
worker_id: null,
|
|
1431
|
-
|
|
1432
|
-
...checkedTaskIds.length > 0 && { task: { notIn: checkedTaskIds } }
|
|
1519
|
+
task: { in: activeTaskIds }
|
|
1433
1520
|
},
|
|
1434
1521
|
orderBy: [
|
|
1435
1522
|
{ retry_count: "asc" },
|
|
@@ -1439,14 +1526,6 @@ class ConverterWorker extends WorkerBase {
|
|
|
1439
1526
|
if (!candidate) {
|
|
1440
1527
|
return null;
|
|
1441
1528
|
}
|
|
1442
|
-
const task = await prisma.task.findUnique({
|
|
1443
|
-
where: { id: candidate.task },
|
|
1444
|
-
select: { status: true }
|
|
1445
|
-
});
|
|
1446
|
-
if (!task || task.status !== TaskStatus.PROCESSING && task.status !== TaskStatus.COMPLETED) {
|
|
1447
|
-
checkedTaskIds.push(candidate.task);
|
|
1448
|
-
continue;
|
|
1449
|
-
}
|
|
1450
1529
|
const result = await prisma.taskDetail.updateMany({
|
|
1451
1530
|
where: {
|
|
1452
1531
|
id: candidate.id,
|
|
@@ -2303,11 +2382,43 @@ class WorkerOrchestrator {
|
|
|
2303
2382
|
if (orphanedMergingTasks.count > 0) {
|
|
2304
2383
|
console.log(`[WorkerOrchestrator] Reset ${orphanedMergingTasks.count} orphaned MERGING tasks to READY_TO_MERGE`);
|
|
2305
2384
|
}
|
|
2385
|
+
const terminalTaskStatuses = [
|
|
2386
|
+
TaskStatus.CREATED,
|
|
2387
|
+
TaskStatus.FAILED,
|
|
2388
|
+
TaskStatus.CANCELLED,
|
|
2389
|
+
TaskStatus.COMPLETED,
|
|
2390
|
+
TaskStatus.PARTIAL_FAILED
|
|
2391
|
+
];
|
|
2392
|
+
const terminalTasks = await prisma.task.findMany({
|
|
2393
|
+
where: {
|
|
2394
|
+
status: { in: terminalTaskStatuses }
|
|
2395
|
+
},
|
|
2396
|
+
select: { id: true }
|
|
2397
|
+
});
|
|
2398
|
+
let orphanedPendingPages = 0;
|
|
2399
|
+
if (terminalTasks.length > 0) {
|
|
2400
|
+
const terminalTaskIds = terminalTasks.map((t) => t.id);
|
|
2401
|
+
const result2 = await prisma.taskDetail.updateMany({
|
|
2402
|
+
where: {
|
|
2403
|
+
task: { in: terminalTaskIds },
|
|
2404
|
+
status: PageStatus.PENDING
|
|
2405
|
+
},
|
|
2406
|
+
data: {
|
|
2407
|
+
status: PageStatus.FAILED,
|
|
2408
|
+
error: "Orphaned: parent task no longer active"
|
|
2409
|
+
}
|
|
2410
|
+
});
|
|
2411
|
+
orphanedPendingPages = result2.count;
|
|
2412
|
+
if (orphanedPendingPages > 0) {
|
|
2413
|
+
console.log(`[WorkerOrchestrator] Marked ${orphanedPendingPages} orphaned PENDING pages as FAILED (parent task in terminal state)`);
|
|
2414
|
+
}
|
|
2415
|
+
}
|
|
2306
2416
|
const result = {
|
|
2307
2417
|
orphanedPages: orphanedPages.count,
|
|
2308
2418
|
orphanedSplittingTasks: orphanedSplittingTasks.count,
|
|
2309
2419
|
orphanedMergingTasks: orphanedMergingTasks.count,
|
|
2310
|
-
|
|
2420
|
+
orphanedPendingPages,
|
|
2421
|
+
total: orphanedPages.count + orphanedSplittingTasks.count + orphanedMergingTasks.count + orphanedPendingPages
|
|
2311
2422
|
};
|
|
2312
2423
|
if (result.total === 0) {
|
|
2313
2424
|
console.log("[WorkerOrchestrator] No orphaned work found");
|
|
@@ -2321,6 +2432,7 @@ class WorkerOrchestrator {
|
|
|
2321
2432
|
orphanedPages: 0,
|
|
2322
2433
|
orphanedSplittingTasks: 0,
|
|
2323
2434
|
orphanedMergingTasks: 0,
|
|
2435
|
+
orphanedPendingPages: 0,
|
|
2324
2436
|
total: 0
|
|
2325
2437
|
};
|
|
2326
2438
|
}
|
|
@@ -2367,7 +2479,6 @@ const IPC_CHANNELS = {
|
|
|
2367
2479
|
DOWNLOAD_MARKDOWN: "file:downloadMarkdown",
|
|
2368
2480
|
SELECT_DIALOG: "file:selectDialog",
|
|
2369
2481
|
UPLOAD: "file:upload",
|
|
2370
|
-
UPLOAD_MULTIPLE: "file:uploadMultiple",
|
|
2371
2482
|
UPLOAD_FILE_CONTENT: "file:uploadFileContent"
|
|
2372
2483
|
},
|
|
2373
2484
|
// Completion (LLM) channels
|
|
@@ -2379,7 +2490,7 @@ const IPC_CHANNELS = {
|
|
|
2379
2490
|
function registerProviderHandlers() {
|
|
2380
2491
|
ipcMain.handle(IPC_CHANNELS.PROVIDER.GET_ALL, async () => {
|
|
2381
2492
|
try {
|
|
2382
|
-
const providers = await providerRepository.
|
|
2493
|
+
const providers = await providerRepository.findAllIncludeDisabled();
|
|
2383
2494
|
return { success: true, data: providers };
|
|
2384
2495
|
} catch (error) {
|
|
2385
2496
|
console.error("[IPC] provider:getAll error:", error);
|
|
@@ -2597,7 +2708,7 @@ const findById = async (id) => {
|
|
|
2597
2708
|
const create = async (task) => {
|
|
2598
2709
|
return await prisma.task.create({
|
|
2599
2710
|
data: {
|
|
2600
|
-
id: v4(),
|
|
2711
|
+
id: task?.id || v4(),
|
|
2601
2712
|
filename: task?.filename || "",
|
|
2602
2713
|
type: task?.type || "",
|
|
2603
2714
|
page_range: task?.page_range || "",
|
|
@@ -2605,8 +2716,8 @@ const create = async (task) => {
|
|
|
2605
2716
|
provider: task?.provider || 0,
|
|
2606
2717
|
model: task?.model || "",
|
|
2607
2718
|
model_name: task?.model_name || "",
|
|
2608
|
-
progress: 0,
|
|
2609
|
-
status: 0
|
|
2719
|
+
progress: task?.progress ?? 0,
|
|
2720
|
+
status: task?.status ?? 0
|
|
2610
2721
|
}
|
|
2611
2722
|
});
|
|
2612
2723
|
};
|
|
@@ -3132,6 +3243,7 @@ function registerFileHandlers() {
|
|
|
3132
3243
|
return { success: false, error: "Task ID and file path are required" };
|
|
3133
3244
|
}
|
|
3134
3245
|
if (!fs.existsSync(filePath)) {
|
|
3246
|
+
console.error(`[IPC] file:upload - Source file does not exist: ${filePath}`);
|
|
3135
3247
|
return { success: false, error: "File does not exist" };
|
|
3136
3248
|
}
|
|
3137
3249
|
const baseUploadDir = fileLogic.getUploadDir();
|
|
@@ -3139,10 +3251,26 @@ function registerFileHandlers() {
|
|
|
3139
3251
|
if (!fs.existsSync(uploadDir)) {
|
|
3140
3252
|
fs.mkdirSync(uploadDir, { recursive: true });
|
|
3141
3253
|
}
|
|
3254
|
+
try {
|
|
3255
|
+
fs.accessSync(uploadDir, fs.constants.W_OK);
|
|
3256
|
+
} catch {
|
|
3257
|
+
console.error(`[IPC] file:upload - Upload directory is not writable: ${uploadDir}`);
|
|
3258
|
+
return { success: false, error: `Upload directory is not writable: ${uploadDir}` };
|
|
3259
|
+
}
|
|
3142
3260
|
const fileName = path.basename(filePath);
|
|
3143
3261
|
const destPath = path.join(uploadDir, fileName);
|
|
3262
|
+
console.log(`[IPC] file:upload - Copying file: ${filePath} -> ${destPath}`);
|
|
3144
3263
|
fs.copyFileSync(filePath, destPath);
|
|
3264
|
+
if (!fs.existsSync(destPath)) {
|
|
3265
|
+
console.error(`[IPC] file:upload - File copy verification failed, destination not found: ${destPath}`);
|
|
3266
|
+
return { success: false, error: "File copy failed: destination file not found after copy" };
|
|
3267
|
+
}
|
|
3145
3268
|
const stats = fs.statSync(destPath);
|
|
3269
|
+
if (stats.size === 0) {
|
|
3270
|
+
console.error(`[IPC] file:upload - Copied file is empty: ${destPath}`);
|
|
3271
|
+
return { success: false, error: "File copy failed: destination file is empty" };
|
|
3272
|
+
}
|
|
3273
|
+
console.log(`[IPC] file:upload - File copied successfully: ${destPath} (${stats.size} bytes)`);
|
|
3146
3274
|
const fileInfo = {
|
|
3147
3275
|
originalName: fileName,
|
|
3148
3276
|
savedName: fileName,
|
|
@@ -3157,45 +3285,6 @@ function registerFileHandlers() {
|
|
|
3157
3285
|
}
|
|
3158
3286
|
}
|
|
3159
3287
|
);
|
|
3160
|
-
ipcMain.handle(
|
|
3161
|
-
IPC_CHANNELS.FILE.UPLOAD_MULTIPLE,
|
|
3162
|
-
async (_, taskId, filePaths) => {
|
|
3163
|
-
try {
|
|
3164
|
-
if (!taskId || !Array.isArray(filePaths) || filePaths.length === 0) {
|
|
3165
|
-
return { success: false, error: "Task ID and file path list are required" };
|
|
3166
|
-
}
|
|
3167
|
-
const uploadResults = [];
|
|
3168
|
-
for (const filePath of filePaths) {
|
|
3169
|
-
if (!fs.existsSync(filePath)) {
|
|
3170
|
-
continue;
|
|
3171
|
-
}
|
|
3172
|
-
const baseUploadDir = fileLogic.getUploadDir();
|
|
3173
|
-
const uploadDir = path.join(baseUploadDir, taskId);
|
|
3174
|
-
if (!fs.existsSync(uploadDir)) {
|
|
3175
|
-
fs.mkdirSync(uploadDir, { recursive: true });
|
|
3176
|
-
}
|
|
3177
|
-
const fileName = path.basename(filePath);
|
|
3178
|
-
const destPath = path.join(uploadDir, fileName);
|
|
3179
|
-
fs.copyFileSync(filePath, destPath);
|
|
3180
|
-
const stats = fs.statSync(destPath);
|
|
3181
|
-
uploadResults.push({
|
|
3182
|
-
originalName: fileName,
|
|
3183
|
-
savedName: fileName,
|
|
3184
|
-
path: destPath,
|
|
3185
|
-
size: stats.size,
|
|
3186
|
-
taskId
|
|
3187
|
-
});
|
|
3188
|
-
}
|
|
3189
|
-
return {
|
|
3190
|
-
success: true,
|
|
3191
|
-
data: { message: "Files uploaded successfully", files: uploadResults }
|
|
3192
|
-
};
|
|
3193
|
-
} catch (error) {
|
|
3194
|
-
console.error("[IPC] file:uploadMultiple error:", error);
|
|
3195
|
-
return { success: false, error: error.message };
|
|
3196
|
-
}
|
|
3197
|
-
}
|
|
3198
|
-
);
|
|
3199
3288
|
ipcMain.handle(
|
|
3200
3289
|
IPC_CHANNELS.FILE.UPLOAD_FILE_CONTENT,
|
|
3201
3290
|
async (_, taskId, fileName, fileBuffer) => {
|
|
@@ -3208,13 +3297,30 @@ function registerFileHandlers() {
|
|
|
3208
3297
|
if (!fs.existsSync(uploadDir)) {
|
|
3209
3298
|
fs.mkdirSync(uploadDir, { recursive: true });
|
|
3210
3299
|
}
|
|
3211
|
-
|
|
3300
|
+
try {
|
|
3301
|
+
fs.accessSync(uploadDir, fs.constants.W_OK);
|
|
3302
|
+
} catch {
|
|
3303
|
+
console.error(`[IPC] file:uploadFileContent - Upload directory is not writable: ${uploadDir}`);
|
|
3304
|
+
return { success: false, error: `Upload directory is not writable: ${uploadDir}` };
|
|
3305
|
+
}
|
|
3306
|
+
const safeName = path.basename(fileName);
|
|
3307
|
+
const destPath = path.join(uploadDir, safeName);
|
|
3212
3308
|
const buffer = Buffer.from(fileBuffer);
|
|
3309
|
+
console.log(`[IPC] file:uploadFileContent - Writing file: ${destPath} (${buffer.length} bytes)`);
|
|
3213
3310
|
fs.writeFileSync(destPath, buffer);
|
|
3311
|
+
if (!fs.existsSync(destPath)) {
|
|
3312
|
+
console.error(`[IPC] file:uploadFileContent - File write verification failed, not found: ${destPath}`);
|
|
3313
|
+
return { success: false, error: "File write failed: file not found after write" };
|
|
3314
|
+
}
|
|
3214
3315
|
const stats = fs.statSync(destPath);
|
|
3316
|
+
if (stats.size === 0) {
|
|
3317
|
+
console.error(`[IPC] file:uploadFileContent - Written file is empty: ${destPath}`);
|
|
3318
|
+
return { success: false, error: "File write failed: file is empty" };
|
|
3319
|
+
}
|
|
3320
|
+
console.log(`[IPC] file:uploadFileContent - File written successfully: ${destPath} (${stats.size} bytes)`);
|
|
3215
3321
|
const fileInfo = {
|
|
3216
|
-
originalName:
|
|
3217
|
-
savedName:
|
|
3322
|
+
originalName: safeName,
|
|
3323
|
+
savedName: safeName,
|
|
3218
3324
|
path: destPath,
|
|
3219
3325
|
size: stats.size,
|
|
3220
3326
|
taskId
|
|
@@ -3234,7 +3340,10 @@ function registerCompletionHandlers() {
|
|
|
3234
3340
|
async (_, providerId, modelId, url) => {
|
|
3235
3341
|
try {
|
|
3236
3342
|
if (!providerId || !modelId || !url) {
|
|
3237
|
-
return {
|
|
3343
|
+
return {
|
|
3344
|
+
success: false,
|
|
3345
|
+
error: "providerId, modelId, and url are required"
|
|
3346
|
+
};
|
|
3238
3347
|
}
|
|
3239
3348
|
const result = await modelLogic.completion(providerId, {
|
|
3240
3349
|
model: modelId,
|
|
@@ -3266,11 +3375,15 @@ function registerCompletionHandlers() {
|
|
|
3266
3375
|
async (_, providerId, modelId) => {
|
|
3267
3376
|
try {
|
|
3268
3377
|
if (!providerId || !modelId) {
|
|
3269
|
-
return {
|
|
3378
|
+
return {
|
|
3379
|
+
success: false,
|
|
3380
|
+
error: "providerId and modelId are required"
|
|
3381
|
+
};
|
|
3270
3382
|
}
|
|
3271
|
-
const testImageBase64 = "
|
|
3383
|
+
const testImageBase64 = "iVBORw0KGgoAAAANSUhEUgAAACAAAAAgCAYAAABzenr0AAAG1klEQVR4Aa3Be2zV5R3H8ff3OaftaUsvdpRCKZbBQIZQASuKGKwEhsMgzogo7BKijBimW8zmskEGREb8g8Ql2yJmAttw0+F0iTMYYYAZYx0KXloBHUFs15ZyaYGW0kLp89nvOYfDuo6LLr5eRi+ScoGHgTlABZBHHwK8wAsEeIEHvMALBHiBF3iEFwjavagRbARbW5ZjHVxgXCBpEvACUM5VCPACLxDgBR7wAi8Q4AVe4AEvIcALvKgDHhyS66qJxIhImgRsAYr5FAww4yIzUowkI2L8hxlGxAgKBQ88vmTZ9qdXrWgwSbnAXqCcz0iAFwjwAi/wgBdI4AEv8AIPSMIDXuBFHXB9HHgIKOcytu78kN/9aRcfHTxCT49n5LAS7rtrArOmVWBmOAMvcEZS64kOPmlooV+/BEOHFOPMSBMGEhhBueDhOHA/l9B9voeFT2zgN3+sprdd7x1iwyv/YMrNI3jxlwsZNKAAZ7Cntp4fPfUK23Z+iPciGFJaxPcWzWDBvCk4c3gDh4EEBl7MiS1fvvxnQBZ9LF76Amtf3ElQmJ/NnVVjGF5eTNORU3R391DX2Mqrm9/nwdkTeePNvcz81s85cOgoEhe1tXey+c0PqNn3L2bfOYFYzIGBYSQZ18SBPPrYsmM/zz7/V4LJlcN5dd1iigpzCY62tDP/sbX8Zcd+DnxylHu/vYbdNXWcO3eeWMwx756J3DJhOI1HTrLuhb/RfOwUr2+t4cc/3cjqFfNAICNiIOXFlkfo4xvfXUfD4RMUFuSw4+UfUFyUR1puThZz7rqRTdtqaT7WRn1jK+fP95CVGefP6xfz/UVfobKinKpbr2P+vbewaVstx1tP825tPTOnjmVgSSGBGRHD0cfefzZR/c7HBIu/WUVJ/3z6yk5k8Myq+fS29LGZzLj9egwwAweU9M9j/dMLMDMk8exvt+MMnIEBzsBJ/JfXt39A2rx7JnI5N4//IpUV5QSJrAweXTCVNAPMwAGVFeXcfstIgje212IIZ+AMHOCISFy0p7aeYGBxPqNHDOJK7p5+A8GUm0dQkJdNbwY4AwfMmn4DwfHW0zQdPoEDnIEZxBFgIIEZ1DW2EIy5bjBX88NHZjByWAlVk0ZyOc5g3Ogy0hqaWhlSWgQCDOICTICBBC2tHQSlJQVcTWZmnLmzKrma0pIC0trazuCMFEEcgQxMgEHX2W6C3JwsPi8Z8RgXSTguMIgTCGRggng8RnC+x/N56TrbTVp2IgMzcKTEJTADBDLI75cgaGvvpLe6Rx7H5eTgEglyJlTQ8dY7mDPypk4hf1oVvuMM5xqbQALnyCwdhOuXS9ByooO0/tf0wwEyQOCISKQISvrnEzQfbUPiouzRoyj9yRMMeHQhx9c+T9Hcr0EsRveRoxxbsx7f2UnLhj9w9uAhTu+o5tSmzaTVNbaQVjaoEGdggDOII8BAAjMoLysiOFh/jEACI2JG9+FmztU3kF0xmsyywWQNvZYvfH0uzU89jbzIGFBMxuBS8qbejjkjbf+BwwQFedmU9M8ncAZe4EREgECCkcMGEjQ2n+DkqTMEAiwe4/ivf4/O9zD4ySX4ri58ZxdBYvQoOt7eg2Un6Ni1G4s5LCuLtD219QRjRw2mN2fgEEikCMaNHkIgwe6aOhAgsESC4kULKJg5HcvIQN5jmRkEZw8eIrdyPEHxogVYZiZpPd6z671DBDfdMJS+HCJJIqlybDnxmCOofudjJJI6a/bRsmEjiKRjv/gVXfsPcGzNOvKqbqOnrZ1zdQ107vuI3t7b28Cptk6C2276En3FRURgBhLk5iQYP+Za3n7/E3a8dYBAgrLVKwkEmKBs9ZP0NXjlEvrasmMfQSzmqJo0kr4cEoFEimDa5C8T/H3PQbrOdhNIpAhERHwqr22tJbj1xuEUFebSlxMRiUAiaeYdYwnOdJ5j17uHQCRJpAhERFzRiVNnqN5zkOC+uyZwKXFEu8zyTAIDyZg4bhh3Tx/HkeNtjBo+CAEmwEACM0AgAxNgXFJ+vwRfvWMMTc0nmTd7IpfQHgdqkCbLwAQYGMbLzzxCkgECGSAwAwnMAIEMTIDxP2Ixx2vrv8MV1DjESwQCEZEIJFIEIiKSJJIkUgQiIv4fG53gOYk6AoGISAQSKQIREUkSSRIpAhERn0UdsDa2ctWK7qVLlu0CHjAjk8DAiJgRmJFiYESMJDOSzEgxMCLG1XQAs83s4xiRlatWNCxdsmw7MM2MQgIDI2JGYEaKgRExksxIMTAiRpIZl1MHzDazaiJGL11nlAt6yOB+oAIjz4iYEZiRYmBEjCQzUgyMiJFkRlo7UAO8BDxnZh1c8G9YG8EnbnLcrgAAAABJRU5ErkJggg==";
|
|
3272
3384
|
const result = await modelLogic.completion(providerId, {
|
|
3273
3385
|
model: modelId,
|
|
3386
|
+
maxTokens: 8,
|
|
3274
3387
|
messages: [
|
|
3275
3388
|
{
|
|
3276
3389
|
role: "user",
|
|
@@ -3283,7 +3396,7 @@ function registerCompletionHandlers() {
|
|
|
3283
3396
|
},
|
|
3284
3397
|
{
|
|
3285
3398
|
type: "text",
|
|
3286
|
-
text: "
|
|
3399
|
+
text: "Please identify the largest letter in the image."
|
|
3287
3400
|
}
|
|
3288
3401
|
]
|
|
3289
3402
|
}
|
package/dist/preload/index.js
CHANGED
|
@@ -37,7 +37,6 @@ electron.contextBridge.exposeInMainWorld("api", {
|
|
|
37
37
|
file: {
|
|
38
38
|
selectDialog: () => electron.ipcRenderer.invoke("file:selectDialog"),
|
|
39
39
|
upload: (taskId, filePath) => electron.ipcRenderer.invoke("file:upload", taskId, filePath),
|
|
40
|
-
uploadMultiple: (taskId, filePaths) => electron.ipcRenderer.invoke("file:uploadMultiple", taskId, filePaths),
|
|
41
40
|
uploadFileContent: (taskId, fileName, fileBuffer) => electron.ipcRenderer.invoke("file:uploadFileContent", taskId, fileName, fileBuffer),
|
|
42
41
|
getImagePath: (taskId, page) => electron.ipcRenderer.invoke("file:getImagePath", taskId, page),
|
|
43
42
|
downloadMarkdown: (taskId) => electron.ipcRenderer.invoke("file:downloadMarkdown", taskId)
|