Spaces:
Sleeping
Sleeping
Deminiko
commited on
Commit
·
b86397a
1
Parent(s):
07a35f8
- .gitignore +3 -3
- agents/base_agent.py +12 -1
- app.py +263 -24
- config.py +22 -1
- orchestrators/orchestrator.py +13 -1
- orchestrators/quasar_orchestrator.py +13 -1
- tasks-project-state.json +67 -21
.gitignore
CHANGED
|
@@ -25,9 +25,9 @@ wheels/
|
|
| 25 |
venv/
|
| 26 |
ENV/
|
| 27 |
env/
|
| 28 |
-
|
| 29 |
-
# Environment Variables
|
| 30 |
-
.env
|
| 31 |
# .env.example IS committed as a template - do not exclude it
|
| 32 |
|
| 33 |
# Database and Logs
|
|
|
|
| 25 |
venv/
|
| 26 |
ENV/
|
| 27 |
env/
|
| 28 |
+
|
| 29 |
+
# Environment Variables # Actual secrets - never commit
|
| 30 |
+
.env
|
| 31 |
# .env.example IS committed as a template - do not exclude it
|
| 32 |
|
| 33 |
# Database and Logs
|
agents/base_agent.py
CHANGED
|
@@ -145,10 +145,21 @@ class LLMAgent(BaseAgent):
|
|
| 145 |
from config import config
|
| 146 |
from agents.llm_adapter import get_llm_adapter
|
| 147 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 148 |
self._adapter = get_llm_adapter(
|
| 149 |
provider=config.llm.provider,
|
| 150 |
model=config.llm.model,
|
| 151 |
-
api_key=
|
| 152 |
)
|
| 153 |
return self._adapter
|
| 154 |
|
|
|
|
| 145 |
from config import config
|
| 146 |
from agents.llm_adapter import get_llm_adapter
|
| 147 |
|
| 148 |
+
# Get API key dynamically (supports HF Spaces Secrets)
|
| 149 |
+
api_key = config.llm.get_api_key()
|
| 150 |
+
|
| 151 |
+
if not api_key:
|
| 152 |
+
raise ValueError(
|
| 153 |
+
"Missing API key! To use the Google AI API, provide api_key via:\n"
|
| 154 |
+
" 1. GOOGLE_API_KEY environment variable (HF Spaces Secrets)\n"
|
| 155 |
+
" 2. GENAI_API_KEY environment variable (fallback)\n"
|
| 156 |
+
" 3. Set in .env file (local development)"
|
| 157 |
+
)
|
| 158 |
+
|
| 159 |
self._adapter = get_llm_adapter(
|
| 160 |
provider=config.llm.provider,
|
| 161 |
model=config.llm.model,
|
| 162 |
+
api_key=api_key
|
| 163 |
)
|
| 164 |
return self._adapter
|
| 165 |
|
app.py
CHANGED
|
@@ -20,6 +20,13 @@ import requests
|
|
| 20 |
import time
|
| 21 |
from typing import Optional, List, Dict, Any
|
| 22 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 23 |
# Note: Gradio 6.0 doesn't support custom CSS in gr.Blocks()
|
| 24 |
# UI styles module available but not used in this version
|
| 25 |
|
|
@@ -221,6 +228,32 @@ def quick_build_circuit(template: str, num_qubits: int) -> str:
|
|
| 221 |
except Exception as e:
|
| 222 |
logger.error(f"Quick build error: {e}")
|
| 223 |
return f"# Error: {str(e)}"
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 224 |
# =============================================================================
|
| 225 |
# GRADIO INTERFACE
|
| 226 |
# =============================================================================
|
|
@@ -235,22 +268,137 @@ with gr.Blocks(title="QAgents - Quantum Circuit Assistant") as demo:
|
|
| 235 |
""")
|
| 236 |
|
| 237 |
with gr.Tabs():
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 238 |
# =================================================================
|
| 239 |
# TAB 1: CHAT INTERFACE
|
| 240 |
# =================================================================
|
| 241 |
with gr.TabItem("💬 Chat"):
|
| 242 |
-
gr.Markdown("### Chat with Quantum Circuit Agent")
|
| 243 |
-
gr.Markdown("
|
| 244 |
|
| 245 |
chatbot = gr.Chatbot(
|
| 246 |
value=[],
|
| 247 |
-
height=
|
| 248 |
label="Quantum Circuit Agent"
|
| 249 |
)
|
| 250 |
|
| 251 |
with gr.Row():
|
| 252 |
msg_input = gr.Textbox(
|
| 253 |
-
placeholder="
|
| 254 |
label="Your Message",
|
| 255 |
scale=4,
|
| 256 |
lines=1
|
|
@@ -262,6 +410,22 @@ with gr.Blocks(title="QAgents - Quantum Circuit Assistant") as demo:
|
|
| 262 |
help_btn = gr.Button("❓ Help", size="sm")
|
| 263 |
status_btn = gr.Button("📊 Status", size="sm")
|
| 264 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 265 |
# Chat handlers
|
| 266 |
def respond(message: str, chat_history: List):
|
| 267 |
if not message.strip():
|
|
@@ -284,11 +448,28 @@ with gr.Blocks(title="QAgents - Quantum Circuit Assistant") as demo:
|
|
| 284 |
chat_history.append({"role": "assistant", "content": status_text})
|
| 285 |
return chat_history
|
| 286 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 287 |
send_btn.click(respond, [msg_input, chatbot], [msg_input, chatbot])
|
| 288 |
msg_input.submit(respond, [msg_input, chatbot], [msg_input, chatbot])
|
| 289 |
clear_btn.click(lambda: [], outputs=[chatbot])
|
| 290 |
help_btn.click(show_help, [chatbot], [chatbot])
|
| 291 |
status_btn.click(show_status, [chatbot], [chatbot])
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 292 |
|
| 293 |
# =================================================================
|
| 294 |
# TAB 2: MCP ENDPOINTS HEALTH
|
|
@@ -364,29 +545,87 @@ with gr.Blocks(title="QAgents - Quantum Circuit Assistant") as demo:
|
|
| 364 |
build_btn.click(quick_build_circuit, [template_select, qubits_slider], [qasm_output])
|
| 365 |
|
| 366 |
# =================================================================
|
| 367 |
-
# TAB
|
| 368 |
# =================================================================
|
| 369 |
with gr.TabItem("ℹ️ About"):
|
| 370 |
gr.Markdown("""
|
| 371 |
-
|
| 372 |
-
|
| 373 |
-
|
| 374 |
-
|
| 375 |
-
|
| 376 |
-
|
| 377 |
-
|
| 378 |
-
|
| 379 |
-
|
| 380 |
-
|
| 381 |
-
|
| 382 |
-
|
| 383 |
-
|
| 384 |
-
|
| 385 |
-
|
| 386 |
-
|
| 387 |
-
|
| 388 |
-
|
| 389 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 390 |
""")
|
| 391 |
|
| 392 |
# Launch for HuggingFace Spaces
|
|
|
|
| 20 |
import time
|
| 21 |
from typing import Optional, List, Dict, Any
|
| 22 |
|
| 23 |
+
# Load environment variables from .env file (for local development)
|
| 24 |
+
try:
|
| 25 |
+
from dotenv import load_dotenv
|
| 26 |
+
load_dotenv()
|
| 27 |
+
except ImportError:
|
| 28 |
+
pass
|
| 29 |
+
|
| 30 |
# Note: Gradio 6.0 doesn't support custom CSS in gr.Blocks()
|
| 31 |
# UI styles module available but not used in this version
|
| 32 |
|
|
|
|
| 228 |
except Exception as e:
|
| 229 |
logger.error(f"Quick build error: {e}")
|
| 230 |
return f"# Error: {str(e)}"
|
| 231 |
+
# =============================================================================
|
| 232 |
+
# EXAMPLE QUESTIONS FOR UI
|
| 233 |
+
# =============================================================================
|
| 234 |
+
|
| 235 |
+
EXAMPLE_QUESTIONS = [
|
| 236 |
+
# Basic circuits
|
| 237 |
+
{"category": "🌟 Beginner", "question": "Create a Bell state circuit", "description": "Classic 2-qubit entanglement"},
|
| 238 |
+
{"category": "🌟 Beginner", "question": "Put a qubit in superposition", "description": "Single Hadamard gate"},
|
| 239 |
+
{"category": "🌟 Beginner", "question": "Create a simple NOT gate on qubit 0", "description": "X gate application"},
|
| 240 |
+
|
| 241 |
+
# Entanglement
|
| 242 |
+
{"category": "🔗 Entanglement", "question": "Generate a 3-qubit GHZ state", "description": "Greenberger-Horne-Zeilinger state"},
|
| 243 |
+
{"category": "🔗 Entanglement", "question": "Create a 4-qubit GHZ state with measurements", "description": "GHZ with classical bits"},
|
| 244 |
+
{"category": "🔗 Entanglement", "question": "Build a W state for 3 qubits", "description": "Another entangled state type"},
|
| 245 |
+
|
| 246 |
+
# Algorithms
|
| 247 |
+
{"category": "⚙️ Algorithms", "question": "Create a 4-qubit QFT circuit", "description": "Quantum Fourier Transform"},
|
| 248 |
+
{"category": "⚙️ Algorithms", "question": "Build a 2-qubit Grover search circuit", "description": "Quantum search algorithm"},
|
| 249 |
+
{"category": "⚙️ Algorithms", "question": "Generate a quantum teleportation circuit", "description": "State teleportation protocol"},
|
| 250 |
+
|
| 251 |
+
# Custom circuits
|
| 252 |
+
{"category": "🔧 Custom", "question": "Apply H gate to qubit 0, then CNOT from 0 to 1", "description": "Step-by-step gates"},
|
| 253 |
+
{"category": "🔧 Custom", "question": "Create a circuit with Rx(π/4) on qubit 0 and Ry(π/2) on qubit 1", "description": "Rotation gates"},
|
| 254 |
+
{"category": "🔧 Custom", "question": "Build a circuit that swaps qubit 0 and qubit 1", "description": "SWAP operation"},
|
| 255 |
+
]
|
| 256 |
+
|
| 257 |
# =============================================================================
|
| 258 |
# GRADIO INTERFACE
|
| 259 |
# =============================================================================
|
|
|
|
| 268 |
""")
|
| 269 |
|
| 270 |
with gr.Tabs():
|
| 271 |
+
# =================================================================
|
| 272 |
+
# TAB 0: GETTING STARTED (NEW)
|
| 273 |
+
# =================================================================
|
| 274 |
+
with gr.TabItem("🚀 Getting Started"):
|
| 275 |
+
gr.Markdown("""
|
| 276 |
+
## 👋 Welcome to QAgents!
|
| 277 |
+
|
| 278 |
+
QAgents is an AI-powered assistant that generates **quantum circuits** from natural language descriptions.
|
| 279 |
+
Just describe what you want, and the agent will produce valid **OpenQASM 2.0** code.
|
| 280 |
+
|
| 281 |
+
---
|
| 282 |
+
|
| 283 |
+
### 🎯 What Can I Ask?
|
| 284 |
+
|
| 285 |
+
| Category | What You Can Request | Example |
|
| 286 |
+
|----------|---------------------|---------|
|
| 287 |
+
| **Basic Gates** | Single qubit operations | *"Apply a Hadamard gate to qubit 0"* |
|
| 288 |
+
| **Entanglement** | Bell states, GHZ states | *"Create a Bell state"* |
|
| 289 |
+
| **Algorithms** | QFT, Grover, Teleportation | *"Build a 4-qubit QFT"* |
|
| 290 |
+
| **Custom Circuits** | Step-by-step gate sequences | *"Apply H to q0, then CNOT from q0 to q1"* |
|
| 291 |
+
| **Measurements** | Circuits with classical output | *"Create a GHZ state with measurements"* |
|
| 292 |
+
|
| 293 |
+
---
|
| 294 |
+
|
| 295 |
+
### 📝 How to Write Good Prompts
|
| 296 |
+
|
| 297 |
+
**✅ Be Specific:**
|
| 298 |
+
- ✅ *"Create a 3-qubit GHZ state"* → Clear qubit count
|
| 299 |
+
- ❌ *"Make something entangled"* → Too vague
|
| 300 |
+
|
| 301 |
+
**✅ Mention Qubit Numbers:**
|
| 302 |
+
- ✅ *"Apply CNOT from qubit 0 to qubit 1"* → Clear targets
|
| 303 |
+
- ❌ *"Do a CNOT"* → Which qubits?
|
| 304 |
+
|
| 305 |
+
**✅ Include Parameters for Rotation Gates:**
|
| 306 |
+
- ✅ *"Apply Rx(π/4) to qubit 0"* → Clear angle
|
| 307 |
+
- ❌ *"Rotate qubit 0"* → What angle?
|
| 308 |
+
|
| 309 |
+
---
|
| 310 |
+
|
| 311 |
+
### 🔧 Output Format
|
| 312 |
+
|
| 313 |
+
The agent returns **OpenQASM 2.0** code that can be:
|
| 314 |
+
- Copied and used in Qiskit, Cirq, or other quantum frameworks
|
| 315 |
+
- Simulated on IBM Quantum, Amazon Braket, or local simulators
|
| 316 |
+
- Validated and scored using the **Quick Build** or **MCP Health** tabs
|
| 317 |
+
|
| 318 |
+
---
|
| 319 |
+
|
| 320 |
+
### ⚡ Quick Tips
|
| 321 |
+
|
| 322 |
+
| Tip | Description |
|
| 323 |
+
|-----|-------------|
|
| 324 |
+
| 💬 Type `help` | Show available commands |
|
| 325 |
+
| 📊 Type `status` | Check MCP server connection |
|
| 326 |
+
| 🛠️ Use Quick Build | Generate circuits from templates without typing |
|
| 327 |
+
| 🔗 Check MCP Health | Verify backend tools are available |
|
| 328 |
+
|
| 329 |
+
---
|
| 330 |
+
|
| 331 |
+
### 🎮 Try These Examples
|
| 332 |
+
|
| 333 |
+
Click any example below to copy it, then paste in the **Chat** tab:
|
| 334 |
+
""")
|
| 335 |
+
|
| 336 |
+
# Display example questions in a nice format
|
| 337 |
+
with gr.Accordion("🌟 Beginner Examples", open=True):
|
| 338 |
+
gr.Markdown("""
|
| 339 |
+
| Example Prompt | What It Does |
|
| 340 |
+
|---------------|--------------|
|
| 341 |
+
| `Create a Bell state circuit` | Creates the classic 2-qubit entangled state |
|
| 342 |
+
| `Put a qubit in superposition` | Single Hadamard gate on qubit 0 |
|
| 343 |
+
| `Create a simple NOT gate on qubit 0` | Applies X gate to flip the qubit |
|
| 344 |
+
| `Apply Hadamard gates to qubits 0 and 1` | Parallel superposition |
|
| 345 |
+
""")
|
| 346 |
+
|
| 347 |
+
with gr.Accordion("🔗 Entanglement Examples", open=False):
|
| 348 |
+
gr.Markdown("""
|
| 349 |
+
| Example Prompt | What It Does |
|
| 350 |
+
|---------------|--------------|
|
| 351 |
+
| `Generate a 3-qubit GHZ state` | Creates a 3-qubit maximally entangled state |
|
| 352 |
+
| `Create a 4-qubit GHZ state with measurements` | GHZ state + measurement on all qubits |
|
| 353 |
+
| `Build a W state for 3 qubits` | Alternative entangled state with different properties |
|
| 354 |
+
| `Create an entangled pair of qubits` | Simple Bell state (synonym) |
|
| 355 |
+
""")
|
| 356 |
+
|
| 357 |
+
with gr.Accordion("⚙️ Algorithm Examples", open=False):
|
| 358 |
+
gr.Markdown("""
|
| 359 |
+
| Example Prompt | What It Does |
|
| 360 |
+
|---------------|--------------|
|
| 361 |
+
| `Create a 4-qubit QFT circuit` | Quantum Fourier Transform for 4 qubits |
|
| 362 |
+
| `Build a 2-qubit Grover search circuit` | Amplitude amplification algorithm |
|
| 363 |
+
| `Generate a quantum teleportation circuit` | 3-qubit state teleportation protocol |
|
| 364 |
+
| `Create an inverse QFT for 3 qubits` | Inverse Quantum Fourier Transform |
|
| 365 |
+
""")
|
| 366 |
+
|
| 367 |
+
with gr.Accordion("🔧 Custom Circuit Examples", open=False):
|
| 368 |
+
gr.Markdown("""
|
| 369 |
+
| Example Prompt | What It Does |
|
| 370 |
+
|---------------|--------------|
|
| 371 |
+
| `Apply H gate to qubit 0, then CNOT from 0 to 1` | Step-by-step gate application |
|
| 372 |
+
| `Create a circuit with Rx(π/4) on qubit 0` | Rotation around X-axis |
|
| 373 |
+
| `Build a circuit that swaps qubit 0 and qubit 1` | SWAP gate implementation |
|
| 374 |
+
| `Apply T gate to qubit 0 and S gate to qubit 1` | Phase gates |
|
| 375 |
+
| `Create a Toffoli gate on qubits 0, 1, 2` | Controlled-controlled-NOT |
|
| 376 |
+
""")
|
| 377 |
+
|
| 378 |
+
gr.Markdown("""
|
| 379 |
+
---
|
| 380 |
+
|
| 381 |
+
### 🚀 Ready to Start?
|
| 382 |
+
|
| 383 |
+
Head to the **💬 Chat** tab and try your first prompt!
|
| 384 |
+
""")
|
| 385 |
+
|
| 386 |
# =================================================================
|
| 387 |
# TAB 1: CHAT INTERFACE
|
| 388 |
# =================================================================
|
| 389 |
with gr.TabItem("💬 Chat"):
|
| 390 |
+
gr.Markdown("### 💬 Chat with Quantum Circuit Agent")
|
| 391 |
+
gr.Markdown("Describe the quantum circuit you want to create in plain English!")
|
| 392 |
|
| 393 |
chatbot = gr.Chatbot(
|
| 394 |
value=[],
|
| 395 |
+
height=350,
|
| 396 |
label="Quantum Circuit Agent"
|
| 397 |
)
|
| 398 |
|
| 399 |
with gr.Row():
|
| 400 |
msg_input = gr.Textbox(
|
| 401 |
+
placeholder="e.g., 'Create a Bell state' or 'Build a 3-qubit GHZ state'",
|
| 402 |
label="Your Message",
|
| 403 |
scale=4,
|
| 404 |
lines=1
|
|
|
|
| 410 |
help_btn = gr.Button("❓ Help", size="sm")
|
| 411 |
status_btn = gr.Button("📊 Status", size="sm")
|
| 412 |
|
| 413 |
+
# Example buttons section
|
| 414 |
+
gr.Markdown("---")
|
| 415 |
+
gr.Markdown("### ⚡ Quick Examples (click to use)")
|
| 416 |
+
|
| 417 |
+
with gr.Row():
|
| 418 |
+
ex1_btn = gr.Button("🔔 Bell State", size="sm")
|
| 419 |
+
ex2_btn = gr.Button("🌀 GHZ State (3q)", size="sm")
|
| 420 |
+
ex3_btn = gr.Button("📐 QFT (4q)", size="sm")
|
| 421 |
+
ex4_btn = gr.Button("🔍 Grover (2q)", size="sm")
|
| 422 |
+
|
| 423 |
+
with gr.Row():
|
| 424 |
+
ex5_btn = gr.Button("🌊 Superposition", size="sm")
|
| 425 |
+
ex6_btn = gr.Button("📡 Teleportation", size="sm")
|
| 426 |
+
ex7_btn = gr.Button("🔄 SWAP Gate", size="sm")
|
| 427 |
+
ex8_btn = gr.Button("🎛️ Custom CNOT", size="sm")
|
| 428 |
+
|
| 429 |
# Chat handlers
|
| 430 |
def respond(message: str, chat_history: List):
|
| 431 |
if not message.strip():
|
|
|
|
| 448 |
chat_history.append({"role": "assistant", "content": status_text})
|
| 449 |
return chat_history
|
| 450 |
|
| 451 |
+
# Example button handlers - each returns the example text and triggers the chat
|
| 452 |
+
def use_example(example_text: str, chat_history: List):
|
| 453 |
+
bot_response = chat_response(example_text, chat_history)
|
| 454 |
+
chat_history.append({"role": "user", "content": example_text})
|
| 455 |
+
chat_history.append({"role": "assistant", "content": bot_response})
|
| 456 |
+
return chat_history
|
| 457 |
+
|
| 458 |
send_btn.click(respond, [msg_input, chatbot], [msg_input, chatbot])
|
| 459 |
msg_input.submit(respond, [msg_input, chatbot], [msg_input, chatbot])
|
| 460 |
clear_btn.click(lambda: [], outputs=[chatbot])
|
| 461 |
help_btn.click(show_help, [chatbot], [chatbot])
|
| 462 |
status_btn.click(show_status, [chatbot], [chatbot])
|
| 463 |
+
|
| 464 |
+
# Wire up example buttons
|
| 465 |
+
ex1_btn.click(lambda h: use_example("Create a Bell state circuit", h), [chatbot], [chatbot])
|
| 466 |
+
ex2_btn.click(lambda h: use_example("Generate a 3-qubit GHZ state", h), [chatbot], [chatbot])
|
| 467 |
+
ex3_btn.click(lambda h: use_example("Create a 4-qubit QFT circuit", h), [chatbot], [chatbot])
|
| 468 |
+
ex4_btn.click(lambda h: use_example("Build a 2-qubit Grover search circuit", h), [chatbot], [chatbot])
|
| 469 |
+
ex5_btn.click(lambda h: use_example("Put 2 qubits in superposition", h), [chatbot], [chatbot])
|
| 470 |
+
ex6_btn.click(lambda h: use_example("Generate a quantum teleportation circuit", h), [chatbot], [chatbot])
|
| 471 |
+
ex7_btn.click(lambda h: use_example("Build a circuit that swaps qubit 0 and qubit 1", h), [chatbot], [chatbot])
|
| 472 |
+
ex8_btn.click(lambda h: use_example("Apply H gate to qubit 0, then CNOT from 0 to 1", h), [chatbot], [chatbot])
|
| 473 |
|
| 474 |
# =================================================================
|
| 475 |
# TAB 2: MCP ENDPOINTS HEALTH
|
|
|
|
| 545 |
build_btn.click(quick_build_circuit, [template_select, qubits_slider], [qasm_output])
|
| 546 |
|
| 547 |
# =================================================================
|
| 548 |
+
# TAB 5: ABOUT
|
| 549 |
# =================================================================
|
| 550 |
with gr.TabItem("ℹ️ About"):
|
| 551 |
gr.Markdown("""
|
| 552 |
+
## ℹ️ About QAgents
|
| 553 |
+
|
| 554 |
+
**QAgents** is a multi-agent system for quantum circuit generation using natural language.
|
| 555 |
+
|
| 556 |
+
---
|
| 557 |
+
|
| 558 |
+
### 🏗️ How it Works
|
| 559 |
+
|
| 560 |
+
```
|
| 561 |
+
┌─────────────────┐ ┌──────────────┐ ┌─────────────────────┐
|
| 562 |
+
│ Your Prompt │ ──► │ LLM Agent │ ──► │ OpenQASM 2.0 Code │
|
| 563 |
+
│ (Plain Text) │ │ (NAKED Mode) │ │ │
|
| 564 |
+
└─────────────────┘ └──────────────┘ └─────────────────────┘
|
| 565 |
+
│
|
| 566 |
+
▼
|
| 567 |
+
┌──────────────────┐
|
| 568 |
+
│ MCP Tools │
|
| 569 |
+
│ - Validate │
|
| 570 |
+
│ - Simulate │
|
| 571 |
+
│ - Score │
|
| 572 |
+
└──────────────────┘
|
| 573 |
+
```
|
| 574 |
+
|
| 575 |
+
1. **You describe** the quantum circuit you want in natural language
|
| 576 |
+
2. **NAKED mode** uses an LLM to generate valid OpenQASM 2.0 code directly
|
| 577 |
+
3. **MCP tools** can validate, simulate, and score your circuits
|
| 578 |
+
|
| 579 |
+
---
|
| 580 |
+
|
| 581 |
+
### 🎯 Capabilities
|
| 582 |
+
|
| 583 |
+
| Feature | Description |
|
| 584 |
+
|---------|-------------|
|
| 585 |
+
| **Circuit Generation** | Create circuits from descriptions |
|
| 586 |
+
| **Standard Gates** | H, X, Y, Z, S, T, Rx, Ry, Rz, CNOT, CZ, SWAP, Toffoli |
|
| 587 |
+
| **Templates** | Bell states, GHZ, QFT, Grover, Teleportation |
|
| 588 |
+
| **Output Format** | OpenQASM 2.0 (compatible with Qiskit, Cirq, etc.) |
|
| 589 |
+
| **Validation** | Syntax and semantic validation via MCP |
|
| 590 |
+
|
| 591 |
+
---
|
| 592 |
+
|
| 593 |
+
### 🔗 Architecture
|
| 594 |
+
|
| 595 |
+
| Component | Technology | Purpose |
|
| 596 |
+
|-----------|------------|---------|
|
| 597 |
+
| **Frontend** | Gradio 6.0 | This UI you're using |
|
| 598 |
+
| **Orchestrator** | QAgents-Workflows | Agent coordination |
|
| 599 |
+
| **LLM** | Gemini 2.5 Flash | Code generation |
|
| 600 |
+
| **Backend** | QuantumArchitect-MCP | Validation & simulation |
|
| 601 |
+
|
| 602 |
+
---
|
| 603 |
+
|
| 604 |
+
### 📖 Supported Quantum Operations
|
| 605 |
+
|
| 606 |
+
**Single-Qubit Gates:**
|
| 607 |
+
- `H` (Hadamard), `X`, `Y`, `Z` (Pauli gates)
|
| 608 |
+
- `S`, `T`, `Sdg`, `Tdg` (Phase gates)
|
| 609 |
+
- `Rx(θ)`, `Ry(θ)`, `Rz(θ)` (Rotation gates)
|
| 610 |
+
|
| 611 |
+
**Multi-Qubit Gates:**
|
| 612 |
+
- `CNOT/CX` (Controlled-NOT)
|
| 613 |
+
- `CZ` (Controlled-Z)
|
| 614 |
+
- `SWAP` (Swap two qubits)
|
| 615 |
+
- `CCX/Toffoli` (Controlled-Controlled-NOT)
|
| 616 |
+
|
| 617 |
+
---
|
| 618 |
+
|
| 619 |
+
### 📝 License
|
| 620 |
+
|
| 621 |
+
MIT License - Feel free to use and modify!
|
| 622 |
+
|
| 623 |
+
---
|
| 624 |
+
|
| 625 |
+
### 🔗 Links
|
| 626 |
+
|
| 627 |
+
- **QAgents-Workflows**: Frontend orchestration
|
| 628 |
+
- **QuantumArchitect-MCP**: Backend quantum tools
|
| 629 |
""")
|
| 630 |
|
| 631 |
# Launch for HuggingFace Spaces
|
config.py
CHANGED
|
@@ -13,6 +13,15 @@ from dataclasses import dataclass, field
|
|
| 13 |
from typing import Optional, List, Dict
|
| 14 |
import os
|
| 15 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 16 |
# Paths
|
| 17 |
PROJECT_ROOT = Path(__file__).parent
|
| 18 |
QUANTUM_MCP_ROOT = PROJECT_ROOT.parent / "QuantumArchitect-MCP"
|
|
@@ -162,7 +171,8 @@ class LLMConfig:
|
|
| 162 |
# Model identifier - reads from LLM_MODEL env var, falls back to "gemini-2.5-flash-lite"
|
| 163 |
model: str = field(default_factory=lambda: os.getenv("LLM_MODEL", "gemini-2.5-flash-lite"))
|
| 164 |
# API key - tries GOOGLE_API_KEY first (Gemini), then GENAI_API_KEY as fallback
|
| 165 |
-
|
|
|
|
| 166 |
temperature: float = 0.2
|
| 167 |
max_tokens: int = 2000
|
| 168 |
|
|
@@ -174,6 +184,17 @@ class LLMConfig:
|
|
| 174 |
enable_fallback: bool = True # Enable automatic model switching on rate limit
|
| 175 |
fallback_on_error: bool = True # Also fallback on API errors
|
| 176 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 177 |
@property
|
| 178 |
def model_string(self) -> str:
|
| 179 |
"""Get full model string for API calls."""
|
|
|
|
| 13 |
from typing import Optional, List, Dict
|
| 14 |
import os
|
| 15 |
|
| 16 |
+
# Load environment variables from .env file
|
| 17 |
+
try:
|
| 18 |
+
from dotenv import load_dotenv
|
| 19 |
+
load_dotenv()
|
| 20 |
+
except ImportError:
|
| 21 |
+
# If python-dotenv is not installed, continue without loading .env
|
| 22 |
+
# (it will use system environment variables only)
|
| 23 |
+
pass
|
| 24 |
+
|
| 25 |
# Paths
|
| 26 |
PROJECT_ROOT = Path(__file__).parent
|
| 27 |
QUANTUM_MCP_ROOT = PROJECT_ROOT.parent / "QuantumArchitect-MCP"
|
|
|
|
| 171 |
# Model identifier - reads from LLM_MODEL env var, falls back to "gemini-2.5-flash-lite"
|
| 172 |
model: str = field(default_factory=lambda: os.getenv("LLM_MODEL", "gemini-2.5-flash-lite"))
|
| 173 |
# API key - tries GOOGLE_API_KEY first (Gemini), then GENAI_API_KEY as fallback
|
| 174 |
+
# Use None as default and fetch dynamically to support HuggingFace Spaces
|
| 175 |
+
api_key: Optional[str] = None
|
| 176 |
temperature: float = 0.2
|
| 177 |
max_tokens: int = 2000
|
| 178 |
|
|
|
|
| 184 |
enable_fallback: bool = True # Enable automatic model switching on rate limit
|
| 185 |
fallback_on_error: bool = True # Also fallback on API errors
|
| 186 |
|
| 187 |
+
def __post_init__(self):
|
| 188 |
+
"""Initialize API key from environment if not set."""
|
| 189 |
+
if self.api_key is None:
|
| 190 |
+
# Try GOOGLE_API_KEY first, then GENAI_API_KEY
|
| 191 |
+
self.api_key = os.getenv("GOOGLE_API_KEY") or os.getenv("GENAI_API_KEY")
|
| 192 |
+
|
| 193 |
+
def get_api_key(self) -> Optional[str]:
|
| 194 |
+
"""Get current API key, checking environment on each call for HF Spaces."""
|
| 195 |
+
# Always check environment first to support dynamic Secrets in HF Spaces
|
| 196 |
+
return os.getenv("GOOGLE_API_KEY") or os.getenv("GENAI_API_KEY") or self.api_key
|
| 197 |
+
|
| 198 |
@property
|
| 199 |
def model_string(self) -> str:
|
| 200 |
"""Get full model string for API calls."""
|
orchestrators/orchestrator.py
CHANGED
|
@@ -379,9 +379,21 @@ class NakedOrchestrator(BaseOrchestrator):
|
|
| 379 |
if self._llm is None:
|
| 380 |
from agents.llm_adapter import get_llm_adapter
|
| 381 |
from config import config
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 382 |
self._llm = get_llm_adapter(
|
| 383 |
provider="gemini",
|
| 384 |
-
api_key=
|
| 385 |
enable_fallback=True
|
| 386 |
)
|
| 387 |
return self._llm
|
|
|
|
| 379 |
if self._llm is None:
|
| 380 |
from agents.llm_adapter import get_llm_adapter
|
| 381 |
from config import config
|
| 382 |
+
|
| 383 |
+
# Get API key dynamically (supports HF Spaces Secrets)
|
| 384 |
+
api_key = config.llm.get_api_key()
|
| 385 |
+
|
| 386 |
+
if not api_key:
|
| 387 |
+
raise ValueError(
|
| 388 |
+
"Missing API key! To use the Google AI API, provide api_key via:\n"
|
| 389 |
+
" 1. GOOGLE_API_KEY environment variable (HF Spaces Secrets)\n"
|
| 390 |
+
" 2. GENAI_API_KEY environment variable (fallback)\n"
|
| 391 |
+
" 3. Set in .env file (local development)"
|
| 392 |
+
)
|
| 393 |
+
|
| 394 |
self._llm = get_llm_adapter(
|
| 395 |
provider="gemini",
|
| 396 |
+
api_key=api_key,
|
| 397 |
enable_fallback=True
|
| 398 |
)
|
| 399 |
return self._llm
|
orchestrators/quasar_orchestrator.py
CHANGED
|
@@ -76,9 +76,21 @@ class QuasarOrchestrator:
|
|
| 76 |
if self._llm is None:
|
| 77 |
from agents.llm_adapter import get_llm_adapter
|
| 78 |
from config import config
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 79 |
self._llm = get_llm_adapter(
|
| 80 |
provider="gemini",
|
| 81 |
-
api_key=
|
| 82 |
enable_fallback=True
|
| 83 |
)
|
| 84 |
return self._llm
|
|
|
|
| 76 |
if self._llm is None:
|
| 77 |
from agents.llm_adapter import get_llm_adapter
|
| 78 |
from config import config
|
| 79 |
+
|
| 80 |
+
# Get API key dynamically (supports HF Spaces Secrets)
|
| 81 |
+
api_key = config.llm.get_api_key()
|
| 82 |
+
|
| 83 |
+
if not api_key:
|
| 84 |
+
raise ValueError(
|
| 85 |
+
"Missing API key! To use the Google AI API, provide api_key via:\n"
|
| 86 |
+
" 1. GOOGLE_API_KEY environment variable (HF Spaces Secrets)\n"
|
| 87 |
+
" 2. GENAI_API_KEY environment variable (fallback)\n"
|
| 88 |
+
" 3. Set in .env file (local development)"
|
| 89 |
+
)
|
| 90 |
+
|
| 91 |
self._llm = get_llm_adapter(
|
| 92 |
provider="gemini",
|
| 93 |
+
api_key=api_key,
|
| 94 |
enable_fallback=True
|
| 95 |
)
|
| 96 |
return self._llm
|
tasks-project-state.json
CHANGED
|
@@ -1,20 +1,22 @@
|
|
| 1 |
{
|
| 2 |
"project": "QAgents-Workflows",
|
| 3 |
-
"version": "0.9.
|
| 4 |
"description": "Multi-agent quantum circuit optimization system with chat UI and MCP integration",
|
| 5 |
"last_updated": "2025-11-30",
|
| 6 |
-
"status": "
|
| 7 |
-
"notes": "Fixed
|
| 8 |
|
| 9 |
"recent_changes": {
|
| 10 |
"2025-11-30": [
|
| 11 |
-
"Fixed
|
| 12 |
-
"
|
| 13 |
-
"
|
| 14 |
-
"Added
|
| 15 |
-
"
|
| 16 |
-
"
|
| 17 |
-
"
|
|
|
|
|
|
|
| 18 |
]
|
| 19 |
},
|
| 20 |
|
|
@@ -42,13 +44,34 @@
|
|
| 42 |
},
|
| 43 |
|
| 44 |
"app_features": {
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 45 |
"chat_tab": {
|
| 46 |
"description": "Interactive chat UI for quantum circuit generation",
|
| 47 |
"features": [
|
| 48 |
"Natural language circuit requests",
|
|
|
|
| 49 |
"Multiple orchestration modes (naked, quasar, hybrid, blackboard)",
|
| 50 |
-
"Difficulty level selection",
|
| 51 |
"Help and status commands"
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 52 |
]
|
| 53 |
},
|
| 54 |
"mcp_endpoints_tab": {
|
|
@@ -63,10 +86,42 @@
|
|
| 63 |
},
|
| 64 |
"quick_build_tab": {
|
| 65 |
"description": "Direct circuit template generation",
|
| 66 |
-
"templates": ["bell_state", "ghz_state", "qft", "grover", "
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 67 |
}
|
| 68 |
},
|
| 69 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 70 |
"mcp_endpoints": [
|
| 71 |
{"name": "create_circuit", "category": "Creation"},
|
| 72 |
{"name": "parse_qasm", "category": "Creation"},
|
|
@@ -84,15 +139,6 @@
|
|
| 84 |
{"name": "list_templates", "category": "Documentation"}
|
| 85 |
],
|
| 86 |
|
| 87 |
-
"comprehensive_test_results": {
|
| 88 |
-
"test_date": "2024-11-29",
|
| 89 |
-
"previous_results": {
|
| 90 |
-
"naked": {"success": "9/9 (100%)", "avg_time_ms": 3929},
|
| 91 |
-
"guided": {"success": "7/9 (78%)", "avg_time_ms": 23120},
|
| 92 |
-
"blackboard": {"success": "2/9 (22%)", "avg_time_ms": 13507}
|
| 93 |
-
}
|
| 94 |
-
},
|
| 95 |
-
|
| 96 |
"architectures": {
|
| 97 |
"naked": {
|
| 98 |
"description": "Direct LLM-to-QASM generation",
|
|
|
|
| 1 |
{
|
| 2 |
"project": "QAgents-Workflows",
|
| 3 |
+
"version": "0.9.3",
|
| 4 |
"description": "Multi-agent quantum circuit optimization system with chat UI and MCP integration",
|
| 5 |
"last_updated": "2025-11-30",
|
| 6 |
+
"status": "API_KEY_LOADING_FIXED",
|
| 7 |
+
"notes": "Fixed API key loading for HuggingFace Spaces. Now supports dynamic environment variable reading for Secrets. Added better error messages. Enhanced landing page with Getting Started tab, example questions, and clickable quick examples.",
|
| 8 |
|
| 9 |
"recent_changes": {
|
| 10 |
"2025-11-30": [
|
| 11 |
+
"Fixed API key loading issue - now dynamically reads from HF Space Secrets",
|
| 12 |
+
"Added get_api_key() method in LLMConfig for dynamic environment reading",
|
| 13 |
+
"Updated base_agent.py, orchestrator.py, quasar_orchestrator.py to use dynamic API key loading",
|
| 14 |
+
"Added clear error messages when API key is missing",
|
| 15 |
+
"Added new 'Getting Started' tab with comprehensive user guide",
|
| 16 |
+
"Added example questions organized by category (Beginner, Entanglement, Algorithms, Custom)",
|
| 17 |
+
"Added 8 clickable quick example buttons in Chat tab",
|
| 18 |
+
"Enhanced About tab with architecture diagram and detailed capabilities",
|
| 19 |
+
"Added prompt writing tips and output format documentation"
|
| 20 |
]
|
| 21 |
},
|
| 22 |
|
|
|
|
| 44 |
},
|
| 45 |
|
| 46 |
"app_features": {
|
| 47 |
+
"getting_started_tab": {
|
| 48 |
+
"description": "User onboarding and guide",
|
| 49 |
+
"features": [
|
| 50 |
+
"Welcome message and overview",
|
| 51 |
+
"Prompt categories table",
|
| 52 |
+
"How to write good prompts",
|
| 53 |
+
"Output format explanation",
|
| 54 |
+
"Quick tips",
|
| 55 |
+
"Collapsible example sections (Beginner, Entanglement, Algorithms, Custom)"
|
| 56 |
+
]
|
| 57 |
+
},
|
| 58 |
"chat_tab": {
|
| 59 |
"description": "Interactive chat UI for quantum circuit generation",
|
| 60 |
"features": [
|
| 61 |
"Natural language circuit requests",
|
| 62 |
+
"8 quick example buttons",
|
| 63 |
"Multiple orchestration modes (naked, quasar, hybrid, blackboard)",
|
|
|
|
| 64 |
"Help and status commands"
|
| 65 |
+
],
|
| 66 |
+
"quick_examples": [
|
| 67 |
+
"Bell State",
|
| 68 |
+
"GHZ State (3q)",
|
| 69 |
+
"QFT (4q)",
|
| 70 |
+
"Grover (2q)",
|
| 71 |
+
"Superposition",
|
| 72 |
+
"Teleportation",
|
| 73 |
+
"SWAP Gate",
|
| 74 |
+
"Custom CNOT"
|
| 75 |
]
|
| 76 |
},
|
| 77 |
"mcp_endpoints_tab": {
|
|
|
|
| 86 |
},
|
| 87 |
"quick_build_tab": {
|
| 88 |
"description": "Direct circuit template generation",
|
| 89 |
+
"templates": ["bell_state", "ghz_state", "qft", "grover", "superposition"]
|
| 90 |
+
},
|
| 91 |
+
"about_tab": {
|
| 92 |
+
"description": "Detailed system information",
|
| 93 |
+
"features": [
|
| 94 |
+
"Architecture diagram",
|
| 95 |
+
"Capabilities table",
|
| 96 |
+
"Supported quantum operations",
|
| 97 |
+
"Component stack details"
|
| 98 |
+
]
|
| 99 |
}
|
| 100 |
},
|
| 101 |
|
| 102 |
+
"example_questions": {
|
| 103 |
+
"beginner": [
|
| 104 |
+
"Create a Bell state circuit",
|
| 105 |
+
"Put a qubit in superposition",
|
| 106 |
+
"Create a simple NOT gate on qubit 0"
|
| 107 |
+
],
|
| 108 |
+
"entanglement": [
|
| 109 |
+
"Generate a 3-qubit GHZ state",
|
| 110 |
+
"Create a 4-qubit GHZ state with measurements",
|
| 111 |
+
"Build a W state for 3 qubits"
|
| 112 |
+
],
|
| 113 |
+
"algorithms": [
|
| 114 |
+
"Create a 4-qubit QFT circuit",
|
| 115 |
+
"Build a 2-qubit Grover search circuit",
|
| 116 |
+
"Generate a quantum teleportation circuit"
|
| 117 |
+
],
|
| 118 |
+
"custom": [
|
| 119 |
+
"Apply H gate to qubit 0, then CNOT from 0 to 1",
|
| 120 |
+
"Create a circuit with Rx(π/4) on qubit 0",
|
| 121 |
+
"Build a circuit that swaps qubit 0 and qubit 1"
|
| 122 |
+
]
|
| 123 |
+
},
|
| 124 |
+
|
| 125 |
"mcp_endpoints": [
|
| 126 |
{"name": "create_circuit", "category": "Creation"},
|
| 127 |
{"name": "parse_qasm", "category": "Creation"},
|
|
|
|
| 139 |
{"name": "list_templates", "category": "Documentation"}
|
| 140 |
],
|
| 141 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 142 |
"architectures": {
|
| 143 |
"naked": {
|
| 144 |
"description": "Direct LLM-to-QASM generation",
|