@lzhzzzzwill/cofos 1.0.0 → 1.0.2
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/README.md +104 -83
- package/bin/cofos.js +119 -41
- package/package.json +3 -2
- package/requirements.txt +8 -0
- package/runtime/config/config.yaml +313 -0
- package/runtime/config/prompt_templates.yaml +403 -0
- package/runtime/config/qwen3_5_config.md +46 -0
- package/runtime/src/data_processing/__init__.py +31 -0
- package/runtime/src/data_processing/clean_json_records.py +387 -0
- package/runtime/src/data_processing/parse_pdf_text.py +332 -0
- package/runtime/src/data_processing/parse_wos_xlsx.py +255 -0
- package/runtime/src/data_processing/schema_utils.py +56 -0
- package/runtime/src/data_processing/utils.py +74 -0
- package/runtime/src/inference/__init__.py +8 -0
- package/runtime/src/inference/query_router.py +33 -0
- package/runtime/src/inference/run_kg_grounded_inference.py +370 -0
- package/runtime/src/inference/student_adapter_inference.py +520 -0
- package/runtime/src/retrieval/__init__.py +10 -0
- package/runtime/src/retrieval/build_bm25_index.py +382 -0
- package/runtime/src/retrieval/build_faiss_index.py +328 -0
- package/runtime/src/retrieval/retrieve_evidence.py +859 -0
- package/runtime/src/retrieval/text_search.py +60 -0
- package/scripts/chat.py +479 -61
package/README.md
CHANGED
|
@@ -1,112 +1,133 @@
|
|
|
1
1
|
# COFOS CLI
|
|
2
2
|
|
|
3
|
-
|
|
3
|
+
COFOS CLI is a standalone Node.js command line wrapper around the COFOS Python runtime. It starts a persistent Python backend, loads the COFOS student model, prepares KG/BM25 runtime data when missing, and can ingest local PDFs as extra retrieval evidence.
|
|
4
4
|
|
|
5
5
|
```bash
|
|
6
|
-
npx cofos
|
|
6
|
+
npx @lzhzzzzwill/cofos
|
|
7
7
|
```
|
|
8
8
|
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
│
|
|
19
|
-
│
|
|
20
|
-
|
|
21
|
-
cofos > What is a MOF material?
|
|
22
|
-
[Model streams response...]
|
|
23
|
-
cofos > Tell me more about its applications.
|
|
9
|
+
## Runtime Model
|
|
10
|
+
|
|
11
|
+
The standalone npm package includes a minimal Python runtime under `runtime/`:
|
|
12
|
+
|
|
13
|
+
```text
|
|
14
|
+
fwdemo/
|
|
15
|
+
├── bin/cofos.js
|
|
16
|
+
├── scripts/chat.py
|
|
17
|
+
├── runtime/
|
|
18
|
+
│ ├── config/
|
|
19
|
+
│ └── src/
|
|
20
|
+
└── requirements.txt
|
|
24
21
|
```
|
|
25
22
|
|
|
26
|
-
|
|
23
|
+
The package does not include model weights or KG/BM25 data. Those are resolved lazily:
|
|
27
24
|
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
25
|
+
| Resource | Default | Local location |
|
|
26
|
+
|---|---|---|
|
|
27
|
+
| Student QA model | `Willlzh/COFOS` | Hugging Face cache |
|
|
28
|
+
| Runtime KG/BM25 | `Willlzh/COFOS_data/runtime` | `~/.cache/cofos/` |
|
|
29
|
+
| Local PDF chunks / manifest | user `--pdf-dir` | `~/.cache/cofos/data/processed/` |
|
|
30
|
+
| Conversation history | local file | `~/.cofos_history.jsonl` |
|
|
31
31
|
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
```
|
|
32
|
+
“Lazy” means the CLI checks local files first. It downloads or rebuilds only missing or changed resources.
|
|
33
|
+
|
|
34
|
+
## Quick Start
|
|
36
35
|
|
|
37
|
-
|
|
36
|
+
```bash
|
|
37
|
+
npx @lzhzzzzwill/cofos
|
|
38
|
+
```
|
|
38
39
|
|
|
39
|
-
|
|
40
|
+
Use local PDFs as additional BM25 evidence:
|
|
40
41
|
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
| `/exit` | 退出 |
|
|
45
|
-
| `/clear` | 清屏重新显示欢迎界面 |
|
|
46
|
-
| `/info` | 显示模型和版本信息 |
|
|
47
|
-
| `/model <id>` | 切换 Hugging Face 模型 |
|
|
42
|
+
```bash
|
|
43
|
+
npx @lzhzzzzwill/cofos --pdf-dir ./new_pdfs
|
|
44
|
+
```
|
|
48
45
|
|
|
49
|
-
|
|
46
|
+
Force PDF reparsing and BM25 rebuilding:
|
|
50
47
|
|
|
48
|
+
```bash
|
|
49
|
+
npx @lzhzzzzwill/cofos --pdf-dir ./new_pdfs --rebuild-pdf-index
|
|
51
50
|
```
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
└── scripts/
|
|
58
|
-
└── chat.py # Python 推理:加载模型、生成回复
|
|
51
|
+
|
|
52
|
+
Use a local merged model instead of Hugging Face:
|
|
53
|
+
|
|
54
|
+
```bash
|
|
55
|
+
npx @lzhzzzzwill/cofos --model /path/to/merged_model
|
|
59
56
|
```
|
|
60
57
|
|
|
61
|
-
|
|
58
|
+
Disable RAG for a session:
|
|
62
59
|
|
|
60
|
+
```bash
|
|
61
|
+
npx @lzhzzzzwill/cofos --no-rag
|
|
63
62
|
```
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
63
|
+
|
|
64
|
+
## Startup Behavior
|
|
65
|
+
|
|
66
|
+
On startup, the CLI does the following:
|
|
67
|
+
|
|
68
|
+
1. Finds Python and checks required Python packages.
|
|
69
|
+
2. Uses bundled `runtime/src` and `runtime/config`, so a full COFOS git checkout is not required.
|
|
70
|
+
3. Checks `~/.cache/cofos/` for KG/BM25 runtime data.
|
|
71
|
+
4. Downloads missing runtime files from `Willlzh/COFOS_data` only if needed.
|
|
72
|
+
5. If `--pdf-dir` is provided, scans PDF names, sizes, and mtimes.
|
|
73
|
+
6. Re-parses PDFs only when the folder contents changed or `--rebuild-pdf-index` is passed.
|
|
74
|
+
7. Merges ROS-related PDF chunks into BM25 retrieval.
|
|
75
|
+
8. Loads the model once and keeps the Python backend alive for the whole chat session.
|
|
76
|
+
|
|
77
|
+
PDF files are read locally and are not uploaded anywhere.
|
|
78
|
+
|
|
79
|
+
## Chat Commands
|
|
80
|
+
|
|
81
|
+
| Command | Description |
|
|
82
|
+
|---|---|
|
|
83
|
+
| `/help` | Show help |
|
|
84
|
+
| `/exit` | Quit |
|
|
85
|
+
| `/clear` | Clear conversation history for the session |
|
|
86
|
+
| `/save` | Report persisted history path |
|
|
87
|
+
| `/info` | Show model and RAG info |
|
|
88
|
+
| `/topk <n>` | Change retrieval top-k |
|
|
89
|
+
| `/rag off` | Disable RAG for this session |
|
|
90
|
+
| `/rag on` | Re-enable RAG for this session |
|
|
91
|
+
|
|
92
|
+
Multi-line questions are supported by ending a line with `\`.
|
|
93
|
+
|
|
94
|
+
## CLI Options
|
|
95
|
+
|
|
96
|
+
```bash
|
|
97
|
+
cofos \
|
|
98
|
+
--model Willlzh/COFOS \
|
|
99
|
+
--config config/config.yaml \
|
|
100
|
+
--pdf-dir ./new_pdfs \
|
|
101
|
+
--top-k 5
|
|
88
102
|
```
|
|
89
103
|
|
|
90
|
-
|
|
104
|
+
| Option | Description |
|
|
105
|
+
|---|---|
|
|
106
|
+
| `--model`, `--merged-model-path` | Hugging Face repo id or local merged model path |
|
|
107
|
+
| `--config` | Config path; defaults to bundled runtime config |
|
|
108
|
+
| `--pdf-dir` | Folder of PDFs to add as extra BM25 evidence |
|
|
109
|
+
| `--rebuild-pdf-index` | Force PDF parsing and BM25 rebuild |
|
|
110
|
+
| `--top-k` | Retrieval top-k |
|
|
111
|
+
| `--max-new-tokens` | Override generation length |
|
|
112
|
+
| `--no-rag` | Run without KG/BM25 retrieval |
|
|
91
113
|
|
|
92
|
-
|
|
93
|
-
|----|------|------|
|
|
94
|
-
| CLI 前端 | Node.js (ESM) | 终端 UI、子进程管理、管道通信 |
|
|
95
|
-
| 模型后端 | Python + transformers | 模型加载、token 生成、流式输出 |
|
|
96
|
-
| 模型 | SmolLM2-360M-Instruct (HF) | 对话推理 |
|
|
97
|
-
| 通信 | stdin/stdout 管道 | 进程间消息传递 |
|
|
98
|
-
| 分發 | npm | 包管理、全局命令、npx |
|
|
114
|
+
## Development
|
|
99
115
|
|
|
100
|
-
|
|
116
|
+
From this repository:
|
|
101
117
|
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
118
|
+
```bash
|
|
119
|
+
cd fwdemo
|
|
120
|
+
npm link
|
|
121
|
+
cofos --help
|
|
122
|
+
cofos --pdf-dir ../data/raw_pdfs
|
|
123
|
+
```
|
|
105
124
|
|
|
106
|
-
|
|
125
|
+
Before publishing:
|
|
107
126
|
|
|
108
127
|
```bash
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
npm run
|
|
128
|
+
node --check bin/cofos.js
|
|
129
|
+
python -m py_compile scripts/chat.py
|
|
130
|
+
npm pack --dry-run
|
|
112
131
|
```
|
|
132
|
+
|
|
133
|
+
`npm pack --dry-run` should include `runtime/config`, `runtime/src`, `bin`, `scripts`, and `requirements.txt`, but should not include `__pycache__` or `*.pyc` files.
|
package/bin/cofos.js
CHANGED
|
@@ -9,10 +9,15 @@ const __dirname = dirname(fileURLToPath(import.meta.url));
|
|
|
9
9
|
const root = resolve(__dirname, "..");
|
|
10
10
|
const chatScript = join(root, "scripts", "chat.py");
|
|
11
11
|
const reqFile = join(root, "requirements.txt");
|
|
12
|
+
const DEFAULT_MODEL = process.env.COFOS_MODEL || "Willlzh/COFOS";
|
|
13
|
+
const DEFAULT_CONFIG = process.env.COFOS_CONFIG || "config/config.yaml";
|
|
12
14
|
|
|
13
15
|
/* ─── ANSI ─── */
|
|
14
16
|
const R = "\x1b[0m", B = "\x1b[1m", D = "\x1b[2m";
|
|
15
|
-
const C = "\x1b[96m", W = "\x1b[97m", G = "\x1b[90m";
|
|
17
|
+
const C = "\x1b[96m", W = "\x1b[97m", G = "\x1b[90m", Y = "\x1b[93m";
|
|
18
|
+
|
|
19
|
+
/* ─── Protocol markers ─── */
|
|
20
|
+
const READY = "===READY===", RESPONSE = "===RESPONSE===", DONE = "===DONE===";
|
|
16
21
|
|
|
17
22
|
/* ─── 3D COFOS art ─── */
|
|
18
23
|
const C_ = [" ██████╗ ","██╔════╝ ","██║ ","██║ ","╚██████╗ "," ╚═════╝ "];
|
|
@@ -57,9 +62,9 @@ function render() {
|
|
|
57
62
|
l.push(emp(w));
|
|
58
63
|
l.push(sep(w));
|
|
59
64
|
l.push(emp(w));
|
|
60
|
-
l.push(cnt(W + B + "Welcome to COFOS CLI —
|
|
65
|
+
l.push(cnt(W + B + "Welcome to COFOS CLI — 9B + RAG chat (Willlzh/COFOS)" + R, w));
|
|
61
66
|
l.push(emp(w));
|
|
62
|
-
l.push(cnt(G + "Type
|
|
67
|
+
l.push(cnt(G + "Type /help · /exit · /topk 5 · /rag off · \\ for multiline" + R, w));
|
|
63
68
|
l.push(emp(w));
|
|
64
69
|
l.push(bot(w));
|
|
65
70
|
console.log(l.join("\n"));
|
|
@@ -72,7 +77,7 @@ function findPy() { return cmdExist("python3") ? "python3" : cmdExist("python")
|
|
|
72
77
|
|
|
73
78
|
function ensureDeps(py) {
|
|
74
79
|
console.log("[cofos] Checking Python dependencies …");
|
|
75
|
-
if (spawnSync(py, ["-c", "import transformers, torch; print('ok')"], { encoding: "utf-8", stdio: "pipe" }).status === 0) return;
|
|
80
|
+
if (spawnSync(py, ["-c", "import transformers, torch, yaml, huggingface_hub, requests, numpy, pdfplumber; import peft; import rank_bm25; print('ok')"], { encoding: "utf-8", stdio: "pipe" }).status === 0) return;
|
|
76
81
|
console.log("[cofos] Installing Python dependencies (first run, may take a while) …");
|
|
77
82
|
const r = spawnSync(py, ["-m", "pip", "install", "-r", reqFile], { encoding: "utf-8", stdio: "inherit" });
|
|
78
83
|
if (r.status !== 0) { console.error("[cofos] Failed to install Python dependencies."); process.exit(1); }
|
|
@@ -82,7 +87,21 @@ function ensureDeps(py) {
|
|
|
82
87
|
|
|
83
88
|
function main() {
|
|
84
89
|
if (process.argv.includes("-h") || process.argv.includes("--help")) {
|
|
85
|
-
console.log("\n COFOS CLI —
|
|
90
|
+
console.log("\n COFOS CLI — 9B + RAG chat (Willlzh/COFOS)\n");
|
|
91
|
+
console.log(" Usage: cofos [--model PATH] [--config PATH] [--pdf-dir DIR] [--top-k N] [--no-rag]\n");
|
|
92
|
+
console.log(" Commands in chat:");
|
|
93
|
+
console.log(" /help Show this help");
|
|
94
|
+
console.log(" /exit Quit");
|
|
95
|
+
console.log(" /clear Clear screen + conversation history");
|
|
96
|
+
console.log(" /save Persist conversation history");
|
|
97
|
+
console.log(" /info Show model and RAG info");
|
|
98
|
+
console.log(" /topk N Set retrieval top-k");
|
|
99
|
+
console.log(" /rag on|off Enable / disable RAG\n");
|
|
100
|
+
console.log(" Startup options:");
|
|
101
|
+
console.log(" --pdf-dir DIR Add PDFs from DIR as extra BM25 evidence");
|
|
102
|
+
console.log(" --rebuild-pdf-index Force reparsing PDFs and rebuilding BM25\n");
|
|
103
|
+
console.log(" Multi-line: end a line with \\ to continue on the next line.\n");
|
|
104
|
+
process.exit(0);
|
|
86
105
|
}
|
|
87
106
|
|
|
88
107
|
render();
|
|
@@ -92,42 +111,84 @@ function main() {
|
|
|
92
111
|
if (!existsSync(chatScript)) { console.error("[cofos] Missing script:", chatScript); process.exit(1); }
|
|
93
112
|
ensureDeps(py);
|
|
94
113
|
|
|
95
|
-
console.log(" Loading
|
|
114
|
+
console.log(" Loading COFOS 9B + RAG backend from Hugging Face … first run may take a while\n");
|
|
115
|
+
|
|
116
|
+
const cliArgs = process.argv.slice(2);
|
|
117
|
+
let modelPath = DEFAULT_MODEL;
|
|
118
|
+
let configPath = DEFAULT_CONFIG;
|
|
119
|
+
let topK = "5";
|
|
120
|
+
let pdfDir = null;
|
|
121
|
+
let rebuildPdfIndex = false;
|
|
122
|
+
const backendArgs = [chatScript];
|
|
123
|
+
for (let i = 0; i < cliArgs.length; i++) {
|
|
124
|
+
const arg = cliArgs[i];
|
|
125
|
+
if (arg === "--model" || arg === "--merged-model-path") {
|
|
126
|
+
modelPath = cliArgs[++i];
|
|
127
|
+
} else if (arg === "--config") {
|
|
128
|
+
configPath = cliArgs[++i];
|
|
129
|
+
} else if (arg === "--top-k") {
|
|
130
|
+
topK = cliArgs[++i];
|
|
131
|
+
} else if (arg === "--pdf-dir") {
|
|
132
|
+
pdfDir = cliArgs[++i];
|
|
133
|
+
} else if (arg === "--rebuild-pdf-index") {
|
|
134
|
+
rebuildPdfIndex = true;
|
|
135
|
+
} else if (arg === "--no-rag") {
|
|
136
|
+
backendArgs.push("--no-rag");
|
|
137
|
+
}
|
|
138
|
+
}
|
|
139
|
+
backendArgs.push("--merged-model-path", modelPath, "--config", configPath, "--top-k", topK);
|
|
140
|
+
if (pdfDir) backendArgs.push("--pdf-dir", pdfDir);
|
|
141
|
+
if (rebuildPdfIndex) backendArgs.push("--rebuild-pdf-index");
|
|
96
142
|
|
|
97
|
-
const proc = spawn(py,
|
|
143
|
+
const proc = spawn(py, backendArgs, { stdio: ["pipe", "pipe", "pipe"], encoding: "utf-8" });
|
|
98
144
|
|
|
99
145
|
let buf = "", ready = false, generating = false, closed = false;
|
|
100
146
|
const inputQ = [];
|
|
101
|
-
const rl = createInterface({ input: process.stdin });
|
|
147
|
+
const rl = createInterface({ input: process.stdin, terminal: true });
|
|
102
148
|
rl.on("line", (l) => { inputQ.push(l); });
|
|
103
149
|
|
|
150
|
+
// Forward Python stderr (status / progress messages) to our stderr.
|
|
151
|
+
proc.stderr.on("data", (chunk) => { process.stderr.write(chunk); });
|
|
152
|
+
|
|
104
153
|
proc.stdout.on("data", (chunk) => {
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
const i = buf.indexOf("===READY===");
|
|
109
|
-
if (i !== -1) {
|
|
110
|
-
ready = true;
|
|
111
|
-
buf = buf.slice(i + 10);
|
|
112
|
-
if (buf[0] === "\n") buf = buf.slice(1);
|
|
113
|
-
drain();
|
|
114
|
-
}
|
|
115
|
-
return;
|
|
116
|
-
}
|
|
117
|
-
if (!generating) return;
|
|
118
|
-
const i = buf.indexOf("\n===DONE===");
|
|
154
|
+
buf += chunk;
|
|
155
|
+
if (!ready) {
|
|
156
|
+
const i = buf.indexOf(READY);
|
|
119
157
|
if (i !== -1) {
|
|
120
|
-
|
|
121
|
-
buf = buf.slice(i +
|
|
158
|
+
ready = true;
|
|
159
|
+
buf = buf.slice(i + READY.length);
|
|
122
160
|
if (buf[0] === "\n") buf = buf.slice(1);
|
|
123
|
-
generating = false;
|
|
124
|
-
console.log("");
|
|
125
161
|
drain();
|
|
126
|
-
} else {
|
|
127
|
-
const k = 10;
|
|
128
|
-
if (buf.length > k) { process.stdout.write(buf.slice(0, -k)); buf = buf.slice(-k); }
|
|
129
162
|
}
|
|
130
|
-
|
|
163
|
+
return;
|
|
164
|
+
}
|
|
165
|
+
if (!generating) return;
|
|
166
|
+
|
|
167
|
+
// Scan for DONE marker — stream everything before it.
|
|
168
|
+
const di = buf.indexOf(DONE);
|
|
169
|
+
if (di !== -1) {
|
|
170
|
+
// Flush any pre-DONE content (cleaned of RESPONSE marker).
|
|
171
|
+
let pre = buf.slice(0, di);
|
|
172
|
+
const ri = pre.indexOf(RESPONSE);
|
|
173
|
+
if (ri !== -1) pre = pre.slice(ri + RESPONSE.length);
|
|
174
|
+
if (pre) process.stdout.write(pre);
|
|
175
|
+
buf = buf.slice(di + DONE.length);
|
|
176
|
+
if (buf[0] === "\n") buf = buf.slice(1);
|
|
177
|
+
generating = false;
|
|
178
|
+
console.log("");
|
|
179
|
+
drain();
|
|
180
|
+
} else {
|
|
181
|
+
// Stream buffered content, keeping only enough tail to catch a
|
|
182
|
+
// partial DONE marker.
|
|
183
|
+
const keep = DONE.length;
|
|
184
|
+
if (buf.length > keep) {
|
|
185
|
+
let out = buf.slice(0, -keep);
|
|
186
|
+
const ri = out.indexOf(RESPONSE);
|
|
187
|
+
if (ri !== -1) out = out.slice(ri + RESPONSE.length);
|
|
188
|
+
if (out) process.stdout.write(out);
|
|
189
|
+
buf = buf.slice(-keep);
|
|
190
|
+
}
|
|
191
|
+
}
|
|
131
192
|
});
|
|
132
193
|
|
|
133
194
|
proc.on("error", (e) => { console.error("[cofos] Python error:", e.message); process.exit(1); });
|
|
@@ -151,30 +212,47 @@ function main() {
|
|
|
151
212
|
try { rl.question(C + " cofos " + R, handle); } catch (_) {}
|
|
152
213
|
}
|
|
153
214
|
|
|
215
|
+
/* ─── multi-line accumulator ─── */
|
|
216
|
+
let mlBuf = [];
|
|
217
|
+
|
|
154
218
|
function handle(input) {
|
|
219
|
+
// Multi-line continuation: lines ending with "\"
|
|
220
|
+
if (input.endsWith("\\")) {
|
|
221
|
+
mlBuf.push(input.slice(0, -1));
|
|
222
|
+
try { rl.question(G + " ... " + R, handle); } catch (_) {}
|
|
223
|
+
return;
|
|
224
|
+
}
|
|
225
|
+
if (mlBuf.length > 0) {
|
|
226
|
+
mlBuf.push(input);
|
|
227
|
+
input = mlBuf.join("\n");
|
|
228
|
+
mlBuf = [];
|
|
229
|
+
}
|
|
230
|
+
|
|
155
231
|
input = input.trim();
|
|
156
232
|
if (!input) { ask(); return; }
|
|
157
233
|
|
|
234
|
+
// Local-only commands (don't hit the backend).
|
|
158
235
|
if (/^\/(exit|quit)$/.test(input)) { proc.stdin.write("/exit\n"); proc.stdin.end(); return; }
|
|
159
236
|
if (/^\/(help)$/.test(input)) {
|
|
160
|
-
console.log("\n Commands:\n /help
|
|
161
|
-
ask(); return;
|
|
162
|
-
}
|
|
163
|
-
if (/^\/(clear)$/.test(input)) { render(); console.log(""); ask(); return; }
|
|
164
|
-
if (/^\/(info)$/.test(input)) {
|
|
165
|
-
console.log("\n COFOS CLI — v1.0.0");
|
|
166
|
-
console.log(" Model: HuggingFaceTB/SmolLM2-360M-Instruct");
|
|
167
|
-
console.log(" Backend: transformers + PyTorch\n");
|
|
237
|
+
console.log("\n Commands:\n /help Show help\n /exit Quit\n /clear Clear conversation history\n /save Persist conversation history\n /info Model and RAG info\n /topk N Set retrieval top-k\n /rag on|off Enable/disable RAG\n\n Multi-line: end a line with \\ to continue.\n");
|
|
168
238
|
ask(); return;
|
|
169
239
|
}
|
|
170
|
-
if (/^\/
|
|
171
|
-
|
|
172
|
-
console.log("[cofos] Switching model to", m);
|
|
240
|
+
if (/^\/(clear)$/.test(input)) {
|
|
241
|
+
mlBuf = [];
|
|
173
242
|
proc.stdin.write(input + "\n");
|
|
174
243
|
generating = true;
|
|
175
244
|
return;
|
|
176
245
|
}
|
|
246
|
+
if (/^\/(info)$/.test(input)) {
|
|
247
|
+
console.log("\n COFOS CLI — v1.0.0");
|
|
248
|
+
console.log(" Model: Willlzh/COFOS (Hugging Face)");
|
|
249
|
+
console.log(" RAG: Willlzh/COFOS_data/runtime (KG + BM25) + optional --pdf-dir BM25 evidence");
|
|
250
|
+
console.log(" Engine: StudentAdapterInference + transformers + PyTorch");
|
|
251
|
+
console.log(" Hist: ~/.cofos_history.jsonl\n");
|
|
252
|
+
ask(); return;
|
|
253
|
+
}
|
|
177
254
|
|
|
255
|
+
// Forward to backend.
|
|
178
256
|
generating = true;
|
|
179
257
|
proc.stdin.write(input + "\n");
|
|
180
258
|
}
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@lzhzzzzwill/cofos",
|
|
3
|
-
"version": "1.0.
|
|
4
|
-
"description": "
|
|
3
|
+
"version": "1.0.2",
|
|
4
|
+
"description": "COFOS 9B + RAG chat CLI with optional local PDF ingestion.",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"bin": {
|
|
7
7
|
"cofos": "bin/cofos.js"
|
|
@@ -9,6 +9,7 @@
|
|
|
9
9
|
"files": [
|
|
10
10
|
"bin",
|
|
11
11
|
"scripts",
|
|
12
|
+
"runtime",
|
|
12
13
|
"requirements.txt"
|
|
13
14
|
],
|
|
14
15
|
"scripts": {
|