khazri-2 / synapse_controller.py
Yusiko's picture
Upload 9 files
b399ea6 verified
Raw
History Blame Contribute Delete
3.95 kB
import re
import time
import torch
class SynapseController:
def __init__(self, model, tokenizer):
self.model = model
self.tokenizer = tokenizer
self.device = next(model.parameters()).device
self.eot_id = tokenizer.convert_tokens_to_ids("<|eot|>")
def _prompt(self, question):
return f"<|user|>\n{question}\n<|assistant|>\n"
def _clean(self, text):
text = str(text)
if "<|eot|>" in text:
text = text.split("<|eot|>")[0]
if "<|final|>" in text:
text = text.split("<|final|>")[-1]
return text.strip()
def _model(self, question, max_new_tokens=140):
inputs = self.tokenizer(self._prompt(question), return_tensors="pt").to(self.device)
input_len = inputs["input_ids"].shape[-1]
start = time.time()
with torch.no_grad():
out = self.model.generate(
**inputs,
max_new_tokens=max_new_tokens,
min_new_tokens=4,
do_sample=False,
pad_token_id=self.tokenizer.pad_token_id,
eos_token_id=self.eot_id,
repetition_penalty=1.12,
no_repeat_ngram_size=4,
)
raw = self.tokenizer.decode(out[0][input_len:], skip_special_tokens=False).strip()
return self._clean(raw), raw, round(time.time() - start, 3)
def _nsr(self, question):
q = str(question).strip()
m = re.search(r"Calculate:\s*(-?\d+)\s*([\+\-\*])\s*(-?\d+)", q)
if m:
a, op, b = int(m.group(1)), m.group(2), int(m.group(3))
val = a + b if op == "+" else a - b if op == "-" else a * b
return True, f"Final answer: {val}", f"{a} {op} {b} = {val}"
m = re.search(r"A shop has\s+(\d+)\s+boxes\. Each box has\s+(\d+)\s+pencils\.\s+(\d+)\s+pencils are lost", q)
if m:
boxes, items, lost = int(m.group(1)), int(m.group(2)), int(m.group(3))
val = boxes * items - lost
return True, f"Final answer: {val}", f"{boxes} * {items} - {lost} = {val}"
return False, "", ""
def _uqm(self, question):
q = str(question).lower()
risky = ["private password", "hidden bank pin", "silently think", "lost private letter", "unpublished diary", "unknown person"]
if any(x in q for x in risky):
return True, "I do not have sufficient information.", "Insufficient evidence or unknowable/private information."
return False, "", ""
def _tms(self, question):
q = str(question)
if "Context:" not in q or "Question:" not in q:
return False, "", ""
context = q.split("Context:", 1)[1].split("Question:", 1)[0].strip()
patterns = [
r"called\s+([A-Z][A-Za-z0-9\-]+(?:\s+[A-Z][A-Za-z0-9\-]+)*)",
r"named\s+([A-Z][A-Za-z0-9\-]+(?:\s+[A-Z][A-Za-z0-9\-]+)*)",
r"in\s+([A-Z][A-Za-z0-9\-]+)\s+in\s+\d{4}",
r"code name\s+([A-Z][A-Za-z0-9\-]+(?:\-[A-Z][A-Za-z0-9\-]+)*)",
]
for pat in patterns:
m = re.search(pat, context)
if m:
ans = m.group(1).strip()
return True, ans, f"Extracted from context: {ans}"
return False, "", ""
def generate(self, question, return_trace=True, **kwargs):
for route_name, fn in [("UQM_ABSTAIN", self._uqm), ("NSR_CALCULATOR", self._nsr), ("TMS_CONTEXT", self._tms)]:
ok, ans, trace = fn(question)
if ok:
result = {"answer": ans, "route": route_name, "trace": trace}
return result if return_trace else ans
ans, raw, latency = self._model(question, max_new_tokens=kwargs.get("max_new_tokens", 140))
result = {"answer": ans, "route": "MODEL_FALLBACK", "trace": "Used pure model fallback.", "raw_answer": raw, "latency_sec": latency}
return result if return_trace else ans