@lzhzzzzwill/cofos 1.1.13 → 1.1.15
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/bin/cofos.js +46 -41
- package/package.json +1 -1
package/bin/cofos.js
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
2
|
import { spawn, spawnSync } from "node:child_process";
|
|
3
|
-
import { createInterface,
|
|
3
|
+
import { clearLine, createInterface, cursorTo } from "node:readline";
|
|
4
4
|
import { existsSync, readFileSync } from "node:fs";
|
|
5
5
|
import { dirname, join, resolve } from "node:path";
|
|
6
6
|
import { fileURLToPath } from "node:url";
|
|
@@ -45,37 +45,43 @@ function row(left, right, lw, rw) { return "│ " + cell(left, lw) + " │ " + c
|
|
|
45
45
|
function full(t, w) { return "│ " + cell(t, w - 2) + " │"; }
|
|
46
46
|
function empty(w) { return full("", w); }
|
|
47
47
|
|
|
48
|
-
function
|
|
48
|
+
function logoLines(width) {
|
|
49
|
+
if (width >= ART_W) return ART.map((line) => C + B + line + R);
|
|
50
|
+
return [C + B + "COFOS" + R];
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
function render({ modelPath, cacheDir, pdfDir }) {
|
|
49
54
|
console.clear();
|
|
50
55
|
const w = fw();
|
|
51
56
|
const minSplit = 96;
|
|
52
57
|
const cwd = process.cwd();
|
|
53
|
-
const rag = "RAG: KG + BM25 +
|
|
54
|
-
const leftTitle = C + B + "COFOS" + R;
|
|
58
|
+
const rag = pdfDir ? "RAG: KG + BM25 + local PDFs" : "RAG: KG + BM25";
|
|
55
59
|
const left = [
|
|
56
|
-
|
|
57
|
-
G + "9B scientific RAG CLI" + R,
|
|
60
|
+
...logoLines(Math.floor((w - 5) * 0.48)),
|
|
58
61
|
"",
|
|
59
|
-
|
|
62
|
+
G + "Scientific RAG CLI" + R,
|
|
63
|
+
W + "Model" + R + " " + modelPath,
|
|
60
64
|
W + "Params" + R + " 9B",
|
|
61
|
-
W + "Path" + R + "
|
|
65
|
+
W + "Path" + R + " " + cwd,
|
|
66
|
+
W + "Cache" + R + " " + cacheDir,
|
|
62
67
|
];
|
|
63
68
|
const right = [
|
|
64
69
|
W + B + "What COFOS Does" + R,
|
|
65
|
-
"
|
|
70
|
+
"COFOS answers scientific questions about covalent organic frameworks,",
|
|
71
|
+
"photocatalysis, reactive oxygen species, and oxygen-reduction products.",
|
|
66
72
|
rag,
|
|
67
73
|
"",
|
|
68
74
|
W + B + "Suggested Commands" + R,
|
|
69
|
-
"/help
|
|
70
|
-
"/topk 5
|
|
71
|
-
"/rag off
|
|
72
|
-
"cofos --pdf-dir ./new_pdfs
|
|
75
|
+
"/help show commands and PDF-RAG usage",
|
|
76
|
+
"/topk 5 change retrieval depth",
|
|
77
|
+
"/rag off answer without retrieval",
|
|
78
|
+
"cofos --pdf-dir ./new_pdfs add local papers",
|
|
73
79
|
];
|
|
74
80
|
|
|
75
81
|
const lines = [top(w)];
|
|
76
82
|
if (w >= minSplit) {
|
|
77
83
|
const inner = w - 5;
|
|
78
|
-
const lw = Math.max(
|
|
84
|
+
const lw = Math.max(46, Math.floor(inner * 0.48));
|
|
79
85
|
const rw = inner - lw;
|
|
80
86
|
const n = Math.max(left.length, right.length);
|
|
81
87
|
for (let i = 0; i < n; i++) lines.push(row(left[i] || "", right[i] || "", lw, rw));
|
|
@@ -84,8 +90,6 @@ function render() {
|
|
|
84
90
|
lines.push(sep(w));
|
|
85
91
|
for (const item of right) lines.push(full(item, w));
|
|
86
92
|
}
|
|
87
|
-
lines.push(empty(w));
|
|
88
|
-
lines.push(full(G + "Type / for commands · /exit · /topk 5 · /rag off · \\ for multiline" + R, w));
|
|
89
93
|
lines.push(bot(w));
|
|
90
94
|
console.log(lines.join("\n"));
|
|
91
95
|
}
|
|
@@ -110,7 +114,7 @@ function slashMatches(line) {
|
|
|
110
114
|
function slashCompletions(line) {
|
|
111
115
|
if (!line.startsWith("/")) return [[], line];
|
|
112
116
|
const hits = slashMatches(line).map(({ cmd }) => cmd);
|
|
113
|
-
return [hits
|
|
117
|
+
return [hits, line];
|
|
114
118
|
}
|
|
115
119
|
|
|
116
120
|
function slashHint(line = "/") {
|
|
@@ -205,7 +209,7 @@ function main() {
|
|
|
205
209
|
if (pdfDir) backendArgs.push("--pdf-dir", pdfDir);
|
|
206
210
|
if (rebuildPdfIndex) backendArgs.push("--rebuild-pdf-index");
|
|
207
211
|
|
|
208
|
-
render();
|
|
212
|
+
render({ modelPath, cacheDir, pdfDir });
|
|
209
213
|
|
|
210
214
|
const py = findPy();
|
|
211
215
|
if (!py) die("Python not found. Install Python 3.9+ and re-run.");
|
|
@@ -250,32 +254,33 @@ function main() {
|
|
|
250
254
|
prompt: mainPrompt,
|
|
251
255
|
completer: slashCompletions,
|
|
252
256
|
});
|
|
253
|
-
let lastSlashHint = "";
|
|
254
257
|
rl.on("line", (l) => {
|
|
255
|
-
lastSlashHint = "";
|
|
256
258
|
if (!ready || generating) inputQ.push(l);
|
|
257
259
|
else if (!handle(l)) ask();
|
|
258
260
|
});
|
|
259
|
-
|
|
260
|
-
|
|
261
|
-
|
|
262
|
-
|
|
263
|
-
|
|
264
|
-
|
|
265
|
-
|
|
266
|
-
|
|
267
|
-
|
|
268
|
-
|
|
269
|
-
|
|
270
|
-
|
|
271
|
-
|
|
272
|
-
|
|
273
|
-
}
|
|
274
|
-
});
|
|
261
|
+
|
|
262
|
+
function preserveInputWrite(stream, chunk) {
|
|
263
|
+
const data = String(chunk);
|
|
264
|
+
if (!rl.terminal || closed) {
|
|
265
|
+
stream.write(data);
|
|
266
|
+
return;
|
|
267
|
+
}
|
|
268
|
+
const activeInput = !generating;
|
|
269
|
+
if (activeInput) {
|
|
270
|
+
clearLine(rl.output, 0);
|
|
271
|
+
cursorTo(rl.output, 0);
|
|
272
|
+
}
|
|
273
|
+
stream.write(data);
|
|
274
|
+
if (activeInput) rl.prompt(true);
|
|
275
275
|
}
|
|
276
276
|
|
|
277
|
-
//
|
|
278
|
-
|
|
277
|
+
// Let users type while the Python backend is still loading. Submitted lines
|
|
278
|
+
// are queued until READY, while status logs are written above and the input
|
|
279
|
+
// line is restored afterward.
|
|
280
|
+
ask();
|
|
281
|
+
|
|
282
|
+
// Forward Python stderr (status / progress messages) without destroying the input line.
|
|
283
|
+
proc.stderr.on("data", (chunk) => { preserveInputWrite(process.stderr, chunk); });
|
|
279
284
|
|
|
280
285
|
proc.stdout.on("data", (chunk) => {
|
|
281
286
|
buf += chunk;
|
|
@@ -310,19 +315,19 @@ function main() {
|
|
|
310
315
|
const di = buf.indexOf(DONE);
|
|
311
316
|
if (di !== -1) {
|
|
312
317
|
const pre = buf.slice(0, di);
|
|
313
|
-
if (pre) process.stdout
|
|
318
|
+
if (pre) preserveInputWrite(process.stdout, pre);
|
|
314
319
|
buf = buf.slice(di + DONE.length);
|
|
315
320
|
if (buf[0] === "\n") buf = buf.slice(1);
|
|
316
321
|
generating = false;
|
|
317
322
|
responseOpen = false;
|
|
318
|
-
|
|
323
|
+
preserveInputWrite(process.stdout, "\n");
|
|
319
324
|
drain();
|
|
320
325
|
} else {
|
|
321
326
|
// Stream buffered content, keeping enough tail to catch a partial DONE marker.
|
|
322
327
|
const keep = DONE.length - 1;
|
|
323
328
|
if (buf.length > keep) {
|
|
324
329
|
const out = buf.slice(0, -keep);
|
|
325
|
-
if (out) process.stdout
|
|
330
|
+
if (out) preserveInputWrite(process.stdout, out);
|
|
326
331
|
buf = buf.slice(-keep);
|
|
327
332
|
}
|
|
328
333
|
}
|