@lzhzzzzwill/cofos 1.1.6 → 1.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/bin/cofos.js
CHANGED
|
@@ -162,7 +162,10 @@ function main() {
|
|
|
162
162
|
if (!existsSync(chatScript)) die(`Missing script: ${chatScript}`);
|
|
163
163
|
ensureDeps(py);
|
|
164
164
|
|
|
165
|
-
console.log(" Loading COFOS 9B + RAG backend from Hugging Face … first run may take a while
|
|
165
|
+
console.log(" Loading COFOS 9B + RAG backend from Hugging Face … first run may take a while");
|
|
166
|
+
if (pdfDir) console.log(" Local PDF RAG: enabled for this session");
|
|
167
|
+
else console.log(" Tip: add local papers with `cofos --pdf-dir ./new_pdfs`");
|
|
168
|
+
console.log("");
|
|
166
169
|
|
|
167
170
|
const backendEnv = {
|
|
168
171
|
...process.env,
|
|
@@ -188,8 +191,18 @@ function main() {
|
|
|
188
191
|
|
|
189
192
|
let buf = "", ready = false, generating = false, responseOpen = false, closed = false;
|
|
190
193
|
const inputQ = [];
|
|
191
|
-
const
|
|
192
|
-
|
|
194
|
+
const mainPrompt = C + " cofos " + R;
|
|
195
|
+
const contPrompt = G + " ... " + R;
|
|
196
|
+
const rl = createInterface({
|
|
197
|
+
input: process.stdin,
|
|
198
|
+
output: process.stdout,
|
|
199
|
+
terminal: true,
|
|
200
|
+
prompt: mainPrompt,
|
|
201
|
+
});
|
|
202
|
+
rl.on("line", (l) => {
|
|
203
|
+
if (!ready || generating) inputQ.push(l);
|
|
204
|
+
else if (!handle(l)) ask();
|
|
205
|
+
});
|
|
193
206
|
|
|
194
207
|
// Forward Python stderr (status / progress messages) to our stderr.
|
|
195
208
|
proc.stderr.on("data", (chunk) => { process.stderr.write(chunk); });
|
|
@@ -275,9 +288,12 @@ function main() {
|
|
|
275
288
|
ask();
|
|
276
289
|
}
|
|
277
290
|
|
|
278
|
-
function ask() {
|
|
291
|
+
function ask(prompt = mainPrompt) {
|
|
279
292
|
if (closed) return;
|
|
280
|
-
try {
|
|
293
|
+
try {
|
|
294
|
+
rl.setPrompt(prompt);
|
|
295
|
+
rl.prompt();
|
|
296
|
+
} catch (_) {}
|
|
281
297
|
}
|
|
282
298
|
|
|
283
299
|
/* ─── multi-line accumulator ─── */
|
|
@@ -287,8 +303,8 @@ function main() {
|
|
|
287
303
|
// Multi-line continuation: lines ending with "\"
|
|
288
304
|
if (input.endsWith("\\")) {
|
|
289
305
|
mlBuf.push(input.slice(0, -1));
|
|
290
|
-
|
|
291
|
-
return;
|
|
306
|
+
ask(contPrompt);
|
|
307
|
+
return true;
|
|
292
308
|
}
|
|
293
309
|
if (mlBuf.length > 0) {
|
|
294
310
|
mlBuf.push(input);
|
|
@@ -297,20 +313,20 @@ function main() {
|
|
|
297
313
|
}
|
|
298
314
|
|
|
299
315
|
input = input.trim();
|
|
300
|
-
if (!input)
|
|
316
|
+
if (!input) return false;
|
|
301
317
|
|
|
302
318
|
// Local-only commands (don't hit the backend).
|
|
303
|
-
if (/^\/(exit|quit)$/.test(input)) { proc.stdin.write("/exit\n"); proc.stdin.end(); return; }
|
|
319
|
+
if (/^\/(exit|quit)$/.test(input)) { proc.stdin.write("/exit\n"); proc.stdin.end(); return true; }
|
|
304
320
|
if (/^\/(help)$/.test(input)) {
|
|
305
|
-
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");
|
|
306
|
-
|
|
321
|
+
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 Add local papers to RAG:\n cofos --pdf-dir ./new_pdfs\n cofos --pdf-dir ./new_pdfs --rebuild-pdf-index\n\n Multi-line: end a line with \\ to continue.\n");
|
|
322
|
+
return false;
|
|
307
323
|
}
|
|
308
324
|
if (/^\/(clear)$/.test(input)) {
|
|
309
325
|
mlBuf = [];
|
|
310
326
|
responseOpen = false;
|
|
311
327
|
proc.stdin.write(input + "\n");
|
|
312
328
|
generating = true;
|
|
313
|
-
return;
|
|
329
|
+
return true;
|
|
314
330
|
}
|
|
315
331
|
if (/^\/(info)$/.test(input)) {
|
|
316
332
|
console.log(`\n COFOS CLI — v${pkg.version}`);
|
|
@@ -320,7 +336,7 @@ function main() {
|
|
|
320
336
|
console.log(` HF: ${backendEnv.HF_HOME}`);
|
|
321
337
|
console.log(" Engine: StudentAdapterInference + transformers + PyTorch");
|
|
322
338
|
console.log(" Hist: ~/.cofos_history.jsonl\n");
|
|
323
|
-
|
|
339
|
+
return false;
|
|
324
340
|
}
|
|
325
341
|
|
|
326
342
|
// Forward to backend. Echo a stable user turn so pasted/submitted questions remain visible in the transcript.
|
|
@@ -328,6 +344,7 @@ function main() {
|
|
|
328
344
|
responseOpen = false;
|
|
329
345
|
generating = true;
|
|
330
346
|
proc.stdin.write(input + "\n");
|
|
347
|
+
return true;
|
|
331
348
|
}
|
|
332
349
|
}
|
|
333
350
|
|
package/package.json
CHANGED
|
@@ -104,3 +104,16 @@ student_answer_refinement_user_prompt: 'Question: {question}
|
|
|
104
104
|
checklist, or explanation of how you rewrote it.
|
|
105
105
|
|
|
106
106
|
'
|
|
107
|
+
interaction:
|
|
108
|
+
greetings:
|
|
109
|
+
hi: Hello! What would you like to know about COFs or reactive oxygen species?
|
|
110
|
+
hello: Hello! What would you like to know about COFs or reactive oxygen species?
|
|
111
|
+
hey: Hello! What would you like to know about COFs or reactive oxygen species?
|
|
112
|
+
你好: 你好!你想了解 COF、光催化还是活性氧相关问题?
|
|
113
|
+
您好: 您好!你想了解 COF、光催化还是活性氧相关问题?
|
|
114
|
+
嗨: 你好!你想了解 COF、光催化还是活性氧相关问题?
|
|
115
|
+
在吗: 在的。你想了解哪方面的 COF 或活性氧问题?
|
|
116
|
+
thanks: You're welcome.
|
|
117
|
+
thank you: You're welcome.
|
|
118
|
+
谢谢: 不客气。
|
|
119
|
+
感谢: 不客气。
|
|
@@ -475,6 +475,7 @@ class StudentAdapterInference:
|
|
|
475
475
|
buffer = ""
|
|
476
476
|
started = False
|
|
477
477
|
in_think = False
|
|
478
|
+
awaiting_initial_answer = True
|
|
478
479
|
|
|
479
480
|
for chunk in chunks:
|
|
480
481
|
buffer += chunk
|
|
@@ -488,6 +489,16 @@ class StudentAdapterInference:
|
|
|
488
489
|
break
|
|
489
490
|
buffer = buffer[end + len("</think>") :]
|
|
490
491
|
in_think = False
|
|
492
|
+
awaiting_initial_answer = False
|
|
493
|
+
continue
|
|
494
|
+
|
|
495
|
+
# Some tokenizers suppress the opening <think> marker but still
|
|
496
|
+
# stream the reasoning text followed by </think>. At the start
|
|
497
|
+
# of an answer, drop everything before that closing marker too.
|
|
498
|
+
end_without_start = buffer.find("</think>")
|
|
499
|
+
if awaiting_initial_answer and end_without_start != -1:
|
|
500
|
+
buffer = buffer[end_without_start + len("</think>") :]
|
|
501
|
+
awaiting_initial_answer = False
|
|
491
502
|
continue
|
|
492
503
|
|
|
493
504
|
start = buffer.find("<think>")
|
package/scripts/chat.py
CHANGED
|
@@ -373,6 +373,14 @@ def ensure_runtime_data(project_root: Path, config: dict) -> None:
|
|
|
373
373
|
print("[chat] Runtime data ready.", file=sys.stderr, flush=True)
|
|
374
374
|
|
|
375
375
|
|
|
376
|
+
|
|
377
|
+
def _clean_history_content(role: str, content: str) -> str:
|
|
378
|
+
content = content.replace("COF-ROS-Reasoner", "COFOS")
|
|
379
|
+
if role == "assistant":
|
|
380
|
+
content = re.sub(r"(?is)<think>.*?</think>", "", content).strip()
|
|
381
|
+
content = re.sub(r"(?is)^.*?</think>", "", content).strip()
|
|
382
|
+
return content
|
|
383
|
+
|
|
376
384
|
def _load_history() -> list:
|
|
377
385
|
"""Load recent conversation turns from the persistent history file.
|
|
378
386
|
|
|
@@ -398,7 +406,9 @@ def _load_history() -> list:
|
|
|
398
406
|
and turn.get("role") in {"user", "assistant"}
|
|
399
407
|
and isinstance(turn.get("content"), str)
|
|
400
408
|
):
|
|
401
|
-
|
|
409
|
+
cleaned = _clean_history_content(turn["role"], turn["content"])
|
|
410
|
+
if cleaned:
|
|
411
|
+
turns.append({"role": turn["role"], "content": cleaned})
|
|
402
412
|
except OSError:
|
|
403
413
|
return []
|
|
404
414
|
|
|
@@ -463,14 +473,19 @@ def main() -> None:
|
|
|
463
473
|
import yaml
|
|
464
474
|
from inference.student_adapter_inference import StudentAdapterInference, StudentRAGContext
|
|
465
475
|
|
|
466
|
-
|
|
467
|
-
|
|
476
|
+
debug = os.environ.get("COFOS_DEBUG", "").lower() in {"1", "true", "yes", "on"}
|
|
477
|
+
log_level = logging.INFO if debug else logging.WARNING
|
|
478
|
+
logging.basicConfig(
|
|
479
|
+
level=log_level,
|
|
480
|
+
format="%(asctime)s - %(levelname)s - %(message)s",
|
|
481
|
+
force=True,
|
|
482
|
+
)
|
|
483
|
+
for noisy_logger in ("httpx", "httpcore", "huggingface_hub", "transformers"):
|
|
468
484
|
logging.getLogger(noisy_logger).setLevel(logging.WARNING)
|
|
469
485
|
|
|
470
486
|
config_path = default_config_path(runtime_root) if args.config == DEFAULT_CONFIG else resolve_project_path(runtime_root, args.config)
|
|
471
487
|
model_path = resolve_project_path(runtime_root, args.model_path)
|
|
472
488
|
|
|
473
|
-
debug = os.environ.get("COFOS_DEBUG", "").lower() in {"1", "true", "yes", "on"}
|
|
474
489
|
if debug:
|
|
475
490
|
print(f"[chat] Runtime root: {runtime_root}", file=sys.stderr, flush=True)
|
|
476
491
|
print(f"[chat] Cache root: {runtime_cache_root()}", file=sys.stderr, flush=True)
|