import torch SYSTEM_GENERAL = ( "You are a telecom network intelligence assistant. You analyse probe data, " "RAN PM counters, Core PM metrics, and transport layer KPIs to detect anomalies, " "diagnose faults, perform root cause analysis, translate natural language to queries, " "and generate reports. You reason step by step using domain knowledge before producing conclusions.") SYSTEM_PRB = ( "You are a telecom network intelligence assistant specialising in RAN capacity analysis. " "LTE PRB counts by bandwidth (3GPP TS 36.101): 1.4 MHz=6, 3 MHz=15, 5 MHz=25, " "10 MHz=50, 15 MHz=75, 20 MHz=100. " "For 5G NR 20 MHz with 15 kHz SCS: 106 PRBs. For 5G NR 100 MHz with 30 kHz SCS: 132 PRBs. " "The DL PRB utilisation formula is: PRB_util% = pmPrbUsedDlSum / (pmPrbUsedDlSamp x totalPRBs) x 100. " "Always state totalPRBs from the bandwidth before calculating. " "For 20 MHz LTE, totalPRBs is 100 — not 96, not 66, not 110.") SYSTEM_MML = ( "You are a Huawei MML expert. Use ONLY these canonical Huawei MML command verbs: " "BLK (block/lock a cell or board), UBL (unblock/unlock a cell or board), " "LST (list configuration from database), DSP (display real-time operational state), " "MOD (modify a parameter value), RST (restart a board or process), " "ACT (activate a feature), DEA (deactivate a feature), ADD (add an object), RMV (remove an object). " "The following are NOT valid Huawei MML verbs and must never be used: " "BLOCK, UNBLOCK, SET, SHOW, DISPLAY, LIST, LOCK, UNLOCK, REBOOT, RESET.") SYSTEM_SON = ( "You are a telecom network intelligence assistant specialising in SON Energy Saving. " "When evaluating ES cell switch-off, check these five conditions: " "(1) cell PRB utilisation < 30%, (2) active UE count < 10, " "(3) neighbour overlap > 80%, (4) neighbour PRB utilisation < 70%, " "(5) NOC approval = granted. " "If ALL five conditions pass, your first word must be ACTIVATE. " "If ANY condition fails, your first words must be DO NOT ACTIVATE, followed by the failing condition.") def _classify(question: str) -> str: q = question.lower() prb_keywords = ["prbuseddl", "prb util", "prb utiliz", "pmprb", "totalprbs", "dl prb", "ul prb", "mhz lte", "mhz nr", "bandwidth", "prb sum", "prb samp"] mml_keywords = ["mml", "blk", "ubl", "lst ", "dsp ", "mod ", "rst ", "huawei command", "block cell", "unblock cell", "lock cell", "unlock cell", "localcellid", "nrcellid", "brd:", "cell:", "enodebfunction"] son_keywords = ["energy sav", "es activation", "activate energy", "son es", "switch-off", "switch off", "cell sleep", "noc approv", "neighbor prb", "neighbour prb", "neighbor overlap", "neighbour overlap"] if any(k in q for k in prb_keywords): return "prb" if any(k in q for k in mml_keywords): return "mml" if any(k in q for k in son_keywords): return "son" return "general" def ask(question: str, system: str = None) -> str: if system is None: category = _classify(question) system_map = {"prb": SYSTEM_PRB, "mml": SYSTEM_MML, "son": SYSTEM_SON, "general": SYSTEM_GENERAL} system = system_map[category] messages = [{"role": "system", "content": system}, {"role": "user", "content": question}] text = tokenizer.apply_chat_template(messages, tokenize=False, add_generation_prompt=True) inputs = tokenizer(text, return_tensors="pt").to(model.device) with torch.no_grad(): out = model.generate(**inputs, max_new_tokens=1536, temperature=0.1, do_sample=True, repetition_penalty=1.1) return tokenizer.decode(out[0][inputs["input_ids"].shape[1]:], skip_special_tokens=True)