| |
| from typing import Any, Dict, List, Optional, Tuple |
| import os |
| from openai import OpenAI |
|
|
|
|
| def _build_client() -> OpenAI: |
| api_key = os.getenv("OPENAI_API_KEY") |
| if not api_key: |
| raise RuntimeError("OPENAI_API_KEY is not set.") |
| return OpenAI(api_key=api_key) |
|
|
|
|
| def explain_with_gpt4o( |
| n_qubits: int, |
| history: List[Dict[str, Any]], |
| state_ket: str, |
| probs_top: List[Tuple[str, float]], |
| shots: Optional[int] = None, |
| ) -> str: |
| """ |
| Generate a teaching-quality explanation using GPT-4o. |
| """ |
|
|
| ops = [] |
| for op in history: |
| if op.get("type") == "single": |
| ops.append(f"{op['gate']}(q{op['target']})") |
| elif op.get("type") == "cnot": |
| ops.append(f"CNOT(q{op['control']} → q{op['target']})") |
|
|
| prompt = f""" |
| You are an expert quantum computing instructor. |
| |
| Audience: |
| Undergraduate students learning quantum circuits. |
| |
| Rules: |
| - Do NOT repeat the prompt. |
| - Do NOT invent gates or probabilities. |
| - Use only the provided data. |
| |
| Provide the explanation using the following sections: |
| |
| ## Gate-by-gate explanation |
| Explain each operation intuitively. |
| |
| ## Interpretation of results |
| Explain superposition vs entanglement using the probabilities. |
| |
| ## Comparison to Bell states |
| Compare this state to |Φ+>, |Φ->, |Ψ+>, |Ψ->. |
| State clearly which one it matches (if any) and why. |
| |
| ## Behavior on real quantum hardware |
| Explain shot noise, readout error, decoherence, |
| and why forbidden states may appear with small probability. |
| |
| ## Debugging tips |
| Give exactly two concrete debugging tips. |
| |
| DATA: |
| Qubits: {n_qubits} |
| Circuit: {", ".join(ops)} |
| |
| Final state: |
| {state_ket} |
| |
| Top probabilities: |
| {probs_top} |
| |
| Shots: {shots} |
| |
| Answer: |
| """ |
|
|
| try: |
| client = _build_client() |
| response = client.chat.completions.create( |
| model="gpt-4o", |
| messages=[{"role": "user", "content": prompt}], |
| temperature=0.2, |
| max_tokens=800, |
| ) |
| except Exception as exc: |
| raise RuntimeError(f"OpenAI request failed ({type(exc).__name__}).") from exc |
|
|
| content = response.choices[0].message.content |
| if not content: |
| raise RuntimeError("OpenAI returned an empty explanation.") |
| return content.strip() |
|
|