Spaces:
Runtime error
Runtime error
| """ | |
| llm.py — the LLM slot (Task 2 wiring point). | |
| This is where the Qwen2.5-3B-Instruct GGUF model lives. The module is written | |
| now so the rest of the pipeline has a clean, lazy single point of integration. | |
| Until the model is wired in, `is_available()` returns False and the pipeline | |
| falls back to the heuristic parser in `spec.interpret_query`. | |
| """ | |
| from __future__ import annotations | |
| import os | |
| import logging | |
| from typing import Optional | |
| from .spec import QuantumSpec, interpret_query, parse_dsl | |
| log = logging.getLogger(__name__) | |
| # ── Configuration ──────────────────────────────────────────────────────────── | |
| MODEL_REPO = os.environ.get( | |
| "QAC_L_MODEL_REPO", | |
| "YOUR_USERNAME/qwen3b-quantum-compiler", # Replace with your repo | |
| ) | |
| MODEL_FILE = os.environ.get( | |
| "QAC_L_MODEL_FILE", | |
| "qwen3b_quantum.gguf", | |
| ) | |
| N_CTX = int(os.environ.get("QAC_L_N_CTX", "4096")) | |
| N_THREADS = int(os.environ.get("QAC_L_N_THREADS", "2")) | |
| _LLM = None | |
| _LOAD_ATTEMPTED = False | |
| # ── Loading ────────────────────────────────────────────────────────────────── | |
| def _load(): | |
| """Lazy-load the GGUF model. Returns the llama-cpp instance or None.""" | |
| global _LLM, _LOAD_ATTEMPTED | |
| if _LOAD_ATTEMPTED: | |
| return _LLM | |
| _LOAD_ATTEMPTED = True | |
| try: | |
| from huggingface_hub import hf_hub_download | |
| from llama_cpp import Llama | |
| path = hf_hub_download(repo_id=MODEL_REPO, filename=MODEL_FILE) | |
| log.info("Loading LLM %s/%s (ctx=%d, threads=%d)", | |
| MODEL_REPO, MODEL_FILE, N_CTX, N_THREADS) | |
| _LLM = Llama( | |
| model_path=path, | |
| n_ctx=N_CTX, | |
| n_threads=N_THREADS, | |
| verbose=False, | |
| ) | |
| log.info("LLM loaded.") | |
| except Exception as exc: | |
| log.warning("LLM unavailable, falling back to heuristic parser: %s", exc) | |
| _LLM = None | |
| return _LLM | |
| def is_available() -> bool: | |
| """True iff the GGUF model can be loaded in this environment.""" | |
| return _load() is not None | |
| # ── Generation ─────────────────────────────────────────────────────────────── | |
| _COMPILE_SYS = ( | |
| "You are a quantum compiler. Translate the user's natural-language request " | |
| "into exactly one strict DSL line. Valid formats:\n" | |
| " [ACTION: RANDOM] [QUBITS: n] # n in 1..5\n" | |
| " [ACTION: VQE] [DISTANCE: r] # r in 0.5..2.5 (Å)\n" | |
| " [ACTION: BELL] [PAIRS: k] # k in 1..4\n" | |
| " [ACTION: GROVER] [ITEMS: m] # m in 2..16\n" | |
| " [ACTION: QAOA] [NODES: v] [DEPTH: p]# v in 2..8, p in 1..3\n" | |
| "Output ONLY the DSL line, nothing else." | |
| ) | |
| _REPORT_SYS = ( | |
| "You are a senior quantum physicist. Given raw measurement counts and " | |
| "computed statistics, explain the result in clear, scientifically accurate " | |
| "English. Treat probabilities below 5% as expected quantum noise. Be concise." | |
| ) | |
| def _chat(llm, system: str, user: str, *, max_tokens: int, temperature: float) -> str: | |
| resp = llm.create_chat_completion( | |
| messages=[{"role": "system", "content": system}, | |
| {"role": "user", "content": user}], | |
| max_tokens=max_tokens, | |
| temperature=temperature, | |
| ) | |
| return resp["choices"][0]["message"]["content"].strip() | |
| # ── Public API ─────────────────────────────────────────────────────────────── | |
| def compile_query(query: str) -> Optional[QuantumSpec]: | |
| """English → QuantumSpec via the LLM, or heuristic fallback.""" | |
| llm = _load() | |
| if llm is not None: | |
| raw = _chat(llm, _COMPILE_SYS, query, max_tokens=64, temperature=0.1) | |
| spec = parse_dsl(raw) | |
| if spec is not None: | |
| return spec | |
| log.warning("LLM produced unparseable DSL (%r); trying heuristic.", raw) | |
| return interpret_query(query) | |
| def explain_results(query: str, receipt_text: str, receipt_data: dict) -> str: | |
| """Results → natural-language explanation via the LLM or template fallback.""" | |
| llm = _load() | |
| if llm is None: | |
| return _template_explanation(query, receipt_data) | |
| user = f"Original query: {query}\n\nReceipt:\n{receipt_text}" | |
| return _chat(llm, _REPORT_SYS, user, max_tokens=256, temperature=0.7) | |
| def _template_explanation(query: str, data: dict) -> str: | |
| """Plain-English summary derived from statistics — no LLM needed.""" | |
| action = data.get("action", "?") | |
| s = data.get("statistics", {}) | |
| if action == "RANDOM": | |
| return (f"Measured {data['qubits']} qubits in superposition across " | |
| f"{data['shots']} shots. The distribution had " | |
| f"{s.get('entropy_bits', 0):.2f} bits of entropy " | |
| f"(max {s.get('max_entropy_bits', 0):.2f}), i.e. " | |
| f"{s.get('uniformity', 0):.0%} uniform — these are genuinely " | |
| f"random bits from quantum measurement.") | |
| if action == "BELL": | |
| return (f"Created {s.get('entangled_pairs', 1)} Bell pair(s). " | |
| f"{s.get('correlation', 0):.2%} of shots produced perfectly " | |
| f"correlated outcomes between paired qubits " | |
| f"(ideal: 100%), confirming entanglement.") | |
| if action == "GROVER": | |
| return (f"Grover search found the marked state |{s.get('target_state')}⟩ " | |
| f"with {s.get('success_probability', 0):.0%} probability after " | |
| f"{data['extra'].get('iterations', '?')} iterations — a " | |
| f"quadratic speedup over the {s.get('classical_baseline', 0):.0%} " | |
| f"classical baseline.") | |
| if action == "QAOA": | |
| return (f"QAOA (p={s.get('depth_p', 1)}) found a MaxCut of " | |
| f"{s.get('best_cut', 0)}/{s.get('max_possible_cut', 0)} on the " | |
| f"ring graph, approximation ratio " | |
| f"{s.get('approximation_ratio', 0):.2f}.") | |
| if action == "VQE": | |
| return (f"VQE converged to a ground-state energy of " | |
| f"{s.get('vqe_converged_energy_ha', 0)} Ha for H₂ at " | |
| f"{data['extra'].get('bond_distance_angstrom', '?')} Å " | |
| f"(analytical reference {s.get('analytical_energy_ha', 0)} Ha).") | |
| return "No explanation available for this action." |