@tiens.nguyen/gonext-local-worker 1.0.101 → 1.0.103

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.
@@ -1052,6 +1052,42 @@ async function correctOcrTextViaServer(extractedText, baseUrl) {
1052
1052
  return normalizeCorrection(corrected, extractedText);
1053
1053
  }
1054
1054
 
1055
+ /**
1056
+ * Call an Ollama host's native chat endpoint (POST {base}/api/chat) for text
1057
+ * correction/translation, e.g. base "https://ollama1.gomarsic.cc" model "qwen3:14b".
1058
+ * `think:false` suppresses reasoning models' <think> preamble so we get clean text.
1059
+ */
1060
+ async function correctOcrTextViaOllama(extractedText, base, model) {
1061
+ const systemPrompt =
1062
+ "You are a text correction assistant. Fix grammar and language errors in the " +
1063
+ "provided text while preserving the original meaning and language. " +
1064
+ "Return only the corrected text without any explanation.";
1065
+ const res = await fetch(`${base.replace(/\/+$/, "")}/api/chat`, {
1066
+ method: "POST",
1067
+ headers: { "Content-Type": "application/json" },
1068
+ body: JSON.stringify({
1069
+ model,
1070
+ stream: false,
1071
+ think: false,
1072
+ options: { temperature: 0 },
1073
+ messages: [
1074
+ { role: "system", content: systemPrompt },
1075
+ { role: "user", content: `Text:\n${extractedText}` },
1076
+ ],
1077
+ }),
1078
+ signal: AbortSignal.timeout(OCR_CORRECT_TIMEOUT_MS),
1079
+ });
1080
+ if (!res.ok) {
1081
+ throw new Error(`Ollama ${base} returned ${res.status}`);
1082
+ }
1083
+ const json = await res.json();
1084
+ let corrected = json?.message?.content?.trim() || "";
1085
+ // Safety net for reasoning models (qwen3) if `think:false` isn't honored:
1086
+ // drop any <think>…</think> preamble before normalizing.
1087
+ corrected = corrected.replace(/<think>[\s\S]*?<\/think>/gi, "").trim();
1088
+ return normalizeCorrection(corrected, extractedText);
1089
+ }
1090
+
1055
1091
  async function correctOcrText(extractedText, modelOverride = "") {
1056
1092
  if (OCR_SKIP_CORRECTION) {
1057
1093
  console.log("[gonext-worker] OCR correction skipped (GONEXT_OCR_SKIP_CORRECTION=1)");
@@ -1060,6 +1096,38 @@ async function correctOcrText(extractedText, modelOverride = "") {
1060
1096
 
1061
1097
  const override = modelOverride.trim();
1062
1098
 
1099
+ // Ollama-backed correction/translation, e.g. "ollama:qwen3:14b@@https://ollama1.gomarsic.cc".
1100
+ // The model may itself contain a colon (qwen3:14b), so only strip the leading
1101
+ // "ollama:" scheme and split the base off on the "@@" delimiter.
1102
+ if (override.toLowerCase().startsWith("ollama:")) {
1103
+ const rest = override.slice("ollama:".length);
1104
+ const at = rest.indexOf("@@");
1105
+ const model = (at >= 0 ? rest.slice(0, at) : rest).trim();
1106
+ const base = (at >= 0 ? rest.slice(at + 2) : "").trim().replace(/\/+$/, "");
1107
+ if (!model || !base) {
1108
+ console.warn(
1109
+ `[gonext-worker] OCR correction: malformed ollama override "${override}" (using raw OCR text)`
1110
+ );
1111
+ return extractedText;
1112
+ }
1113
+ console.log(`[gonext-worker] OCR correction via Ollama ${base} model=${model}`);
1114
+ console.log(`[gonext-worker] OCR correction input: ${extractedText.slice(0, 300)}`);
1115
+ try {
1116
+ const corrected = await correctOcrTextViaOllama(extractedText, base, model);
1117
+ console.log(`[gonext-worker] OCR correction output: ${corrected.slice(0, 300)}`);
1118
+ console.log(
1119
+ `[gonext-worker] OCR correction done: ${extractedText.length} → ${corrected.length} chars`
1120
+ );
1121
+ return corrected;
1122
+ } catch (e) {
1123
+ const msg = e instanceof Error ? e.message : String(e);
1124
+ console.warn(
1125
+ `[gonext-worker] OCR correction Ollama failed (using raw OCR text): ${msg.slice(0, 200)}`
1126
+ );
1127
+ return extractedText;
1128
+ }
1129
+ }
1130
+
1063
1131
  // If the override looks like a URL, call it as a running mlx_lm.server endpoint.
1064
1132
  // e.g. "http://127.0.0.1:8083/v1" or "http://127.0.0.1:8083"
1065
1133
  if (override.startsWith("http://") || override.startsWith("https://")) {
@@ -1685,7 +1753,12 @@ function logModelResponseToWorker(jobId, modelId, text) {
1685
1753
  async function checkOllamaTags(base) {
1686
1754
  const endpoint = `${base}/api/tags`;
1687
1755
  try {
1688
- const res = await fetch(endpoint, { method: "GET" });
1756
+ // Bounded so an unreachable/slow host fails fast (a hung fetch would exceed
1757
+ // the client's local-health wait and leave the status dot stuck "pending").
1758
+ const res = await fetch(endpoint, {
1759
+ method: "GET",
1760
+ signal: AbortSignal.timeout(4000),
1761
+ });
1689
1762
  if (!res.ok) return { online: false, endpoint, models: [] };
1690
1763
  const j = await res.json();
1691
1764
  const source = sourceLabelFromBase(base);
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@tiens.nguyen/gonext-local-worker",
3
- "version": "1.0.101",
3
+ "version": "1.0.103",
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",