@tiens.nguyen/gonext-local-worker 1.0.217 → 1.0.219

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.
@@ -1229,11 +1229,44 @@ function normalizeCorrection(raw, originalText) {
1229
1229
  * correction/translation, e.g. base "https://ollama1.gomarsic.cc" model "qwen3:14b".
1230
1230
  * `think:false` suppresses reasoning models' <think> preamble so we get clean text.
1231
1231
  */
1232
+ const OCR_CORRECT_SYSTEM_PROMPT =
1233
+ "You are a text correction assistant. Fix grammar and language errors in the " +
1234
+ "provided text while preserving the original meaning and language. " +
1235
+ "Return only the corrected text without any explanation.";
1236
+
1237
+ /**
1238
+ * Call an OpenAI-compatible chat endpoint (POST {base}/v1/chat/completions) for text
1239
+ * correction — e.g. an MLX `mlx_lm.server` (the agent model server) at
1240
+ * http://127.0.0.1:8080/v1 serving qwen3:14b. Strips any <think> preamble.
1241
+ */
1242
+ async function correctOcrTextViaOpenAI(extractedText, base, model) {
1243
+ const b = base.replace(/\/+$/, "");
1244
+ const url = /\/v1$/.test(b) ? `${b}/chat/completions` : `${b}/v1/chat/completions`;
1245
+ const res = await fetch(url, {
1246
+ method: "POST",
1247
+ headers: { "Content-Type": "application/json" },
1248
+ body: JSON.stringify({
1249
+ model,
1250
+ stream: false,
1251
+ temperature: 0,
1252
+ messages: [
1253
+ { role: "system", content: OCR_CORRECT_SYSTEM_PROMPT },
1254
+ { role: "user", content: `Text:\n${extractedText}` },
1255
+ ],
1256
+ }),
1257
+ signal: AbortSignal.timeout(OCR_CORRECT_TIMEOUT_MS),
1258
+ });
1259
+ if (!res.ok) {
1260
+ throw new Error(`MLX ${b} returned ${res.status}`);
1261
+ }
1262
+ const json = await res.json();
1263
+ let corrected = json?.choices?.[0]?.message?.content?.trim() || "";
1264
+ corrected = corrected.replace(/<think>[\s\S]*?<\/think>/gi, "").trim();
1265
+ return normalizeCorrection(corrected, extractedText);
1266
+ }
1267
+
1232
1268
  async function correctOcrTextViaOllama(extractedText, base, model) {
1233
- const systemPrompt =
1234
- "You are a text correction assistant. Fix grammar and language errors in the " +
1235
- "provided text while preserving the original meaning and language. " +
1236
- "Return only the corrected text without any explanation.";
1269
+ const systemPrompt = OCR_CORRECT_SYSTEM_PROMPT;
1237
1270
  const res = await fetch(`${base.replace(/\/+$/, "")}/api/chat`, {
1238
1271
  method: "POST",
1239
1272
  headers: { "Content-Type": "application/json" },
@@ -1260,24 +1293,27 @@ async function correctOcrTextViaOllama(extractedText, base, model) {
1260
1293
  return normalizeCorrection(corrected, extractedText);
1261
1294
  }
1262
1295
 
1263
- async function correctOcrText(extractedText) {
1296
+ async function correctOcrText(extractedText, correction) {
1264
1297
  if (OCR_SKIP_CORRECTION) {
1265
1298
  console.log("[gonext-worker] OCR correction skipped (GONEXT_OCR_SKIP_CORRECTION=1)");
1266
1299
  return extractedText;
1267
1300
  }
1268
1301
 
1269
- // OCR translation/correction is hardcoded to a managed Ollama service + model
1270
- // (the user-configurable chooser was removed). Any error falls back to raw text.
1302
+ // The API resolves the backend from the user's settings and bakes {backend,url,model}
1303
+ // into the job payload DEFAULT is "mlx" (the agent MLX model server, OpenAI /v1).
1304
+ // Absent (older jobs / no settings) → fall back to the legacy managed-Ollama default.
1305
+ const backend = correction?.backend === "mlx" ? "mlx" : "ollama";
1306
+ const url = (correction?.url || "").trim() || OCR_TRANSLATE_OLLAMA_URL;
1307
+ const model = (correction?.model || "").trim() || OCR_TRANSLATE_OLLAMA_MODEL;
1271
1308
  console.log(
1272
- `[gonext-worker] OCR correction via Ollama ${OCR_TRANSLATE_OLLAMA_URL} model=${OCR_TRANSLATE_OLLAMA_MODEL}`
1309
+ `[gonext-worker] OCR correction via ${backend} ${url} model=${model}`
1273
1310
  );
1274
1311
  console.log(`[gonext-worker] OCR correction input: ${extractedText.slice(0, 300)}`);
1275
1312
  try {
1276
- const corrected = await correctOcrTextViaOllama(
1277
- extractedText,
1278
- OCR_TRANSLATE_OLLAMA_URL,
1279
- OCR_TRANSLATE_OLLAMA_MODEL
1280
- );
1313
+ const corrected =
1314
+ backend === "mlx"
1315
+ ? await correctOcrTextViaOpenAI(extractedText, url, model)
1316
+ : await correctOcrTextViaOllama(extractedText, url, model);
1281
1317
  console.log(`[gonext-worker] OCR correction output: ${corrected.slice(0, 300)}`);
1282
1318
  console.log(
1283
1319
  `[gonext-worker] OCR correction done: ${extractedText.length} → ${corrected.length} chars`
@@ -1286,7 +1322,7 @@ async function correctOcrText(extractedText) {
1286
1322
  } catch (e) {
1287
1323
  const msg = e instanceof Error ? e.message : String(e);
1288
1324
  console.warn(
1289
- `[gonext-worker] OCR correction Ollama failed (using raw OCR text): ${msg.slice(0, 200)}`
1325
+ `[gonext-worker] OCR correction (${backend}) failed (using raw OCR text): ${msg.slice(0, 200)}`
1290
1326
  );
1291
1327
  return extractedText;
1292
1328
  }
@@ -1434,10 +1470,10 @@ async function runOcrJob(job) {
1434
1470
  } finally {
1435
1471
  await rm(tempDir, { recursive: true, force: true }).catch(() => {});
1436
1472
  }
1437
- // Post-process: correct grammar/language via the hardcoded managed Ollama
1438
- // service (qwen3:14b). Falls back to raw OCR text on any error so the job
1439
- // never fails here. (`payload.correctionModel` is no longer used.)
1440
- extractedText = await correctOcrText(extractedText);
1473
+ // Post-process: correct grammar/language via the backend the API resolved from the
1474
+ // user's settings (payload.correction = {backend,url,model}; default MLX = the agent
1475
+ // model server). Falls back to raw OCR text on any error so the job never fails here.
1476
+ extractedText = await correctOcrText(extractedText, payload.correction);
1441
1477
  const totalTimeSeconds = (Date.now() - start) / 1000;
1442
1478
  const doneRes = await workerFetch(`/api/worker/jobs/${jobId}`, {
1443
1479
  method: "PATCH",
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@tiens.nguyen/gonext-local-worker",
3
- "version": "1.0.217",
3
+ "version": "1.0.219",
4
4
  "description": "Polls GoNext cloud API for async local LLM jobs and runs them against Ollama/OpenAI-compatible servers on this Mac",
5
5
  "type": "module",
6
6
  "license": "MIT",