quantumflow-sdk 0.1.0__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (60) hide show
  1. api/__init__.py +1 -0
  2. api/auth.py +208 -0
  3. api/main.py +403 -0
  4. api/models.py +137 -0
  5. api/routes/__init__.py +1 -0
  6. api/routes/auth_routes.py +234 -0
  7. api/routes/teleport_routes.py +415 -0
  8. db/__init__.py +15 -0
  9. db/crud.py +319 -0
  10. db/database.py +93 -0
  11. db/models.py +197 -0
  12. quantumflow/__init__.py +47 -0
  13. quantumflow/algorithms/__init__.py +48 -0
  14. quantumflow/algorithms/compression/__init__.py +7 -0
  15. quantumflow/algorithms/compression/amplitude_amplification.py +189 -0
  16. quantumflow/algorithms/compression/qft_compression.py +133 -0
  17. quantumflow/algorithms/compression/token_compression.py +261 -0
  18. quantumflow/algorithms/cryptography/__init__.py +6 -0
  19. quantumflow/algorithms/cryptography/qkd.py +205 -0
  20. quantumflow/algorithms/cryptography/qrng.py +231 -0
  21. quantumflow/algorithms/machine_learning/__init__.py +7 -0
  22. quantumflow/algorithms/machine_learning/qnn.py +276 -0
  23. quantumflow/algorithms/machine_learning/qsvm.py +249 -0
  24. quantumflow/algorithms/machine_learning/vqe.py +229 -0
  25. quantumflow/algorithms/optimization/__init__.py +7 -0
  26. quantumflow/algorithms/optimization/grover.py +223 -0
  27. quantumflow/algorithms/optimization/qaoa.py +251 -0
  28. quantumflow/algorithms/optimization/quantum_annealing.py +237 -0
  29. quantumflow/algorithms/utility/__init__.py +6 -0
  30. quantumflow/algorithms/utility/circuit_optimizer.py +194 -0
  31. quantumflow/algorithms/utility/error_correction.py +330 -0
  32. quantumflow/api/__init__.py +1 -0
  33. quantumflow/api/routes/__init__.py +4 -0
  34. quantumflow/api/routes/billing_routes.py +520 -0
  35. quantumflow/backends/__init__.py +33 -0
  36. quantumflow/backends/base_backend.py +184 -0
  37. quantumflow/backends/braket_backend.py +345 -0
  38. quantumflow/backends/ibm_backend.py +112 -0
  39. quantumflow/backends/simulator_backend.py +86 -0
  40. quantumflow/billing/__init__.py +25 -0
  41. quantumflow/billing/models.py +126 -0
  42. quantumflow/billing/stripe_service.py +619 -0
  43. quantumflow/core/__init__.py +12 -0
  44. quantumflow/core/entanglement.py +164 -0
  45. quantumflow/core/memory.py +147 -0
  46. quantumflow/core/quantum_backprop.py +394 -0
  47. quantumflow/core/quantum_compressor.py +309 -0
  48. quantumflow/core/teleportation.py +386 -0
  49. quantumflow/integrations/__init__.py +107 -0
  50. quantumflow/integrations/autogen_tools.py +501 -0
  51. quantumflow/integrations/crewai_agents.py +425 -0
  52. quantumflow/integrations/crewai_tools.py +407 -0
  53. quantumflow/integrations/langchain_memory.py +385 -0
  54. quantumflow/integrations/langchain_tools.py +366 -0
  55. quantumflow/integrations/mcp_server.py +575 -0
  56. quantumflow_sdk-0.1.0.dist-info/METADATA +190 -0
  57. quantumflow_sdk-0.1.0.dist-info/RECORD +60 -0
  58. quantumflow_sdk-0.1.0.dist-info/WHEEL +5 -0
  59. quantumflow_sdk-0.1.0.dist-info/entry_points.txt +2 -0
  60. quantumflow_sdk-0.1.0.dist-info/top_level.txt +3 -0
api/__init__.py ADDED
@@ -0,0 +1 @@
1
+ """QuantumFlow API Package."""
api/auth.py ADDED
@@ -0,0 +1,208 @@
1
+ """
2
+ Authentication for QuantumFlow API.
3
+
4
+ Supports:
5
+ - API Key authentication
6
+ - JWT tokens for user sessions
7
+ - Database-backed user management
8
+ """
9
+
10
+ import os
11
+ from datetime import datetime, timedelta
12
+ from typing import Optional
13
+ from uuid import UUID
14
+
15
+ from fastapi import HTTPException, Security, status, Depends
16
+ from fastapi.security import APIKeyHeader, HTTPBearer
17
+ from jose import JWTError, jwt
18
+ from pydantic import BaseModel
19
+ from sqlalchemy.orm import Session
20
+
21
+ from db.database import get_db
22
+ from db import crud
23
+ from db.models import User, APIKey as APIKeyModel
24
+
25
+
26
+ # Configuration
27
+ API_KEY_HEADER = APIKeyHeader(name="X-API-Key", auto_error=False)
28
+ BEARER_SCHEME = HTTPBearer(auto_error=False)
29
+
30
+ SECRET_KEY = os.getenv("JWT_SECRET", "dev-secret-key-change-in-production")
31
+ ALGORITHM = "HS256"
32
+ ACCESS_TOKEN_EXPIRE_MINUTES = 60 * 24 # 24 hours
33
+
34
+
35
+ class TokenData(BaseModel):
36
+ """JWT token payload."""
37
+ user_id: str
38
+ exp: Optional[datetime] = None
39
+
40
+
41
+ class TokenResponse(BaseModel):
42
+ """Token response model."""
43
+ access_token: str
44
+ token_type: str = "bearer"
45
+ expires_in: int
46
+
47
+
48
+ class UserResponse(BaseModel):
49
+ """User response model."""
50
+ id: str
51
+ email: str
52
+ name: Optional[str]
53
+ tier: str
54
+ is_active: bool
55
+
56
+ class Config:
57
+ from_attributes = True
58
+
59
+
60
+ class APIKeyResponse(BaseModel):
61
+ """API key response (without full key)."""
62
+ id: str
63
+ name: str
64
+ prefix: str
65
+ created_at: datetime
66
+ last_used: Optional[datetime]
67
+ is_active: bool
68
+
69
+ class Config:
70
+ from_attributes = True
71
+
72
+
73
+ # ============== JWT Functions ==============
74
+
75
+ def create_access_token(user_id: str, expires_delta: Optional[timedelta] = None) -> str:
76
+ """Create a JWT access token."""
77
+ expire = datetime.utcnow() + (expires_delta or timedelta(minutes=ACCESS_TOKEN_EXPIRE_MINUTES))
78
+ to_encode = {"sub": user_id, "exp": expire}
79
+ return jwt.encode(to_encode, SECRET_KEY, algorithm=ALGORITHM)
80
+
81
+
82
+ def verify_token(token: str) -> Optional[TokenData]:
83
+ """Verify and decode a JWT token."""
84
+ try:
85
+ payload = jwt.decode(token, SECRET_KEY, algorithms=[ALGORITHM])
86
+ user_id: str = payload.get("sub")
87
+ if user_id is None:
88
+ return None
89
+ return TokenData(user_id=user_id, exp=payload.get("exp"))
90
+ except JWTError:
91
+ return None
92
+
93
+
94
+ # ============== Auth Dependencies ==============
95
+
96
+ def get_db_session():
97
+ """Get database session."""
98
+ db = next(get_db())
99
+ try:
100
+ yield db
101
+ finally:
102
+ db.close()
103
+
104
+
105
+ async def get_current_user(
106
+ api_key: Optional[str] = Security(API_KEY_HEADER),
107
+ bearer: Optional[object] = Security(BEARER_SCHEME),
108
+ db: Session = Depends(get_db_session),
109
+ ) -> User:
110
+ """
111
+ Get the current authenticated user.
112
+
113
+ Supports both API Key and Bearer token authentication.
114
+ Returns the User object from database.
115
+ """
116
+ # Try API Key first
117
+ if api_key:
118
+ key_record = crud.get_api_key(db, api_key)
119
+ if key_record:
120
+ crud.update_api_key_usage(db, key_record)
121
+ user = crud.get_user(db, key_record.user_id)
122
+ if user and user.is_active:
123
+ return user
124
+
125
+ # Try Bearer token
126
+ if bearer and hasattr(bearer, 'credentials'):
127
+ token_data = verify_token(bearer.credentials)
128
+ if token_data:
129
+ try:
130
+ user_id = UUID(token_data.user_id)
131
+ user = crud.get_user(db, user_id)
132
+ if user and user.is_active:
133
+ return user
134
+ except ValueError:
135
+ pass
136
+
137
+ # Fallback: Allow dev key in development
138
+ if api_key == "qf_dev_key_123" and os.getenv("ENV", "development") == "development":
139
+ # Create or get dev user
140
+ dev_user = crud.get_user_by_email(db, "dev@quantumflow.local")
141
+ if not dev_user:
142
+ dev_user = crud.create_user(db, "dev@quantumflow.local", "devpassword", "Dev User")
143
+ return dev_user
144
+
145
+ raise HTTPException(
146
+ status_code=status.HTTP_401_UNAUTHORIZED,
147
+ detail="Invalid or missing authentication",
148
+ headers={"WWW-Authenticate": "Bearer"},
149
+ )
150
+
151
+
152
+ async def get_optional_user(
153
+ api_key: Optional[str] = Security(API_KEY_HEADER),
154
+ bearer: Optional[object] = Security(BEARER_SCHEME),
155
+ db: Session = Depends(get_db_session),
156
+ ) -> Optional[User]:
157
+ """Get user if authenticated, None otherwise."""
158
+ try:
159
+ return await get_current_user(api_key, bearer, db)
160
+ except HTTPException:
161
+ return None
162
+
163
+
164
+ async def get_current_active_user(
165
+ current_user: User = Depends(get_current_user),
166
+ ) -> User:
167
+ """Ensure user is active."""
168
+ if not current_user.is_active:
169
+ raise HTTPException(
170
+ status_code=status.HTTP_403_FORBIDDEN,
171
+ detail="User account is disabled",
172
+ )
173
+ return current_user
174
+
175
+
176
+ async def check_user_quota(
177
+ current_user: User = Depends(get_current_active_user),
178
+ db: Session = Depends(get_db_session),
179
+ ) -> User:
180
+ """Check if user is within their usage quota."""
181
+ if not crud.check_quota(db, current_user):
182
+ raise HTTPException(
183
+ status_code=status.HTTP_429_TOO_MANY_REQUESTS,
184
+ detail="Monthly API quota exceeded. Please upgrade your plan.",
185
+ )
186
+ return current_user
187
+
188
+
189
+ # ============== Helper Functions ==============
190
+
191
+ def authenticate_user(db: Session, email: str, password: str) -> Optional[User]:
192
+ """Authenticate user by email and password."""
193
+ return crud.authenticate_user(db, email, password)
194
+
195
+
196
+ def create_user(db: Session, email: str, password: str, name: Optional[str] = None) -> User:
197
+ """Create a new user."""
198
+ return crud.create_user(db, email, password, name)
199
+
200
+
201
+ def create_api_key_for_user(
202
+ db: Session,
203
+ user_id: UUID,
204
+ name: str,
205
+ scopes: Optional[list[str]] = None,
206
+ ) -> tuple[APIKeyModel, str]:
207
+ """Create API key for user. Returns (key_record, raw_key)."""
208
+ return crud.create_api_key(db, user_id, name, scopes)
api/main.py ADDED
@@ -0,0 +1,403 @@
1
+ """
2
+ QuantumFlow API - FastAPI Application.
3
+
4
+ Endpoints:
5
+ - POST /v1/compress - Token compression (Paper 1)
6
+ - POST /v1/gradient - Quantum backprop (Paper 2)
7
+ - GET /v1/backends - Available quantum backends
8
+ - POST /v1/memory/* - Quantum memory operations
9
+ - POST /v1/entangle - Create entangled states
10
+ - /auth/* - Authentication and API key management
11
+ """
12
+
13
+ import os
14
+ import sys
15
+ import time
16
+ from contextlib import asynccontextmanager
17
+ from typing import Optional
18
+
19
+ from fastapi import FastAPI, HTTPException, Depends, Request, status
20
+ from fastapi.middleware.cors import CORSMiddleware
21
+ import numpy as np
22
+
23
+ # Add src to path for imports
24
+ sys.path.insert(0, os.path.dirname(os.path.dirname(os.path.abspath(__file__))))
25
+
26
+ from api.models import (
27
+ CompressRequest, CompressResponse,
28
+ GradientRequest, GradientResponse,
29
+ BackendStatus, BackendsResponse,
30
+ MemoryStoreRequest, MemoryStoreResponse,
31
+ MemoryRetrieveResponse, MemoryStatsResponse,
32
+ EntangleRequest, EntangleResponse,
33
+ HealthResponse,
34
+ )
35
+ from api.auth import get_current_user, get_optional_user, get_db_session
36
+ from api.routes.auth_routes import router as auth_router
37
+ from api.routes.teleport_routes import router as teleport_router
38
+
39
+ # Import billing routes (optional - only if Stripe is configured)
40
+ try:
41
+ from quantumflow.api.routes.billing_routes import router as billing_router
42
+ BILLING_ENABLED = True
43
+ except ImportError:
44
+ BILLING_ENABLED = False
45
+ billing_router = None
46
+
47
+ from quantumflow.core.quantum_compressor import QuantumCompressor
48
+ from quantumflow.core.quantum_backprop import QuantumBackprop
49
+ from quantumflow.core.entanglement import Entangler
50
+ from quantumflow.core.memory import QuantumMemory
51
+ from quantumflow.backends.base_backend import BackendType
52
+
53
+ from db.database import init_db
54
+ from db.models import User
55
+ from db import crud
56
+
57
+
58
+ # Global instances (initialized on startup)
59
+ _compressor: Optional[QuantumCompressor] = None
60
+ _backprop: Optional[QuantumBackprop] = None
61
+ _entangler: Optional[Entangler] = None
62
+ _memory: Optional[QuantumMemory] = None
63
+ _db_initialized: bool = False
64
+
65
+
66
+ @asynccontextmanager
67
+ async def lifespan(app: FastAPI):
68
+ """Initialize quantum components and database on startup."""
69
+ global _compressor, _backprop, _entangler, _memory, _db_initialized
70
+
71
+ # Initialize quantum components
72
+ _compressor = QuantumCompressor(backend="simulator")
73
+ _backprop = QuantumBackprop(backend="simulator")
74
+ _entangler = Entangler(backend="simulator")
75
+ _memory = QuantumMemory(backend="simulator")
76
+
77
+ # Initialize database
78
+ try:
79
+ init_db()
80
+ _db_initialized = True
81
+ print("Database initialized successfully")
82
+ except Exception as e:
83
+ print(f"Database initialization failed: {e}")
84
+ print("Running without database - some features will be limited")
85
+ _db_initialized = False
86
+
87
+ yield
88
+
89
+ # Cleanup
90
+ _compressor = None
91
+ _backprop = None
92
+ _entangler = None
93
+ _memory = None
94
+
95
+
96
+ # Create FastAPI app
97
+ app = FastAPI(
98
+ title="QuantumFlow API",
99
+ description="Quantum-optimized AI agent workflow platform",
100
+ version="0.1.0",
101
+ lifespan=lifespan,
102
+ )
103
+
104
+ # CORS middleware
105
+ app.add_middleware(
106
+ CORSMiddleware,
107
+ allow_origins=["*"], # Configure for production
108
+ allow_credentials=True,
109
+ allow_methods=["*"],
110
+ allow_headers=["*"],
111
+ )
112
+
113
+ # Include auth routes
114
+ app.include_router(auth_router)
115
+
116
+ # Include teleportation & secure messaging routes
117
+ app.include_router(teleport_router)
118
+
119
+ # Include billing routes if available
120
+ if BILLING_ENABLED and billing_router:
121
+ app.include_router(billing_router)
122
+
123
+
124
+ # === Health Endpoints ===
125
+
126
+ @app.get("/health", response_model=HealthResponse, tags=["Health"])
127
+ async def health_check():
128
+ """Check API health status."""
129
+ return HealthResponse(
130
+ status="healthy",
131
+ version="0.1.0",
132
+ quantum_ready=_compressor is not None,
133
+ )
134
+
135
+
136
+ @app.get("/", tags=["Health"])
137
+ async def root():
138
+ """API root endpoint."""
139
+ return {
140
+ "name": "QuantumFlow API",
141
+ "version": "0.1.0",
142
+ "docs": "/docs",
143
+ "database": "connected" if _db_initialized else "not connected",
144
+ }
145
+
146
+
147
+ # === Compression Endpoints (Paper 1) ===
148
+
149
+ @app.post("/v1/compress", response_model=CompressResponse, tags=["Compression"])
150
+ async def compress_tokens(
151
+ request: CompressRequest,
152
+ http_request: Request,
153
+ user: Optional[User] = Depends(get_optional_user),
154
+ ):
155
+ """
156
+ Compress tokens using quantum amplitude encoding.
157
+
158
+ Achieves 53% token reduction via quantum superposition.
159
+ """
160
+ if not _compressor:
161
+ raise HTTPException(status_code=503, detail="Quantum compressor not initialized")
162
+
163
+ start_time = time.perf_counter()
164
+
165
+ try:
166
+ if request.execute:
167
+ result = _compressor.compress_and_execute(
168
+ tokens=request.tokens,
169
+ compression_level=request.compression_level,
170
+ shots=request.shots,
171
+ )
172
+ fidelity = result.execution_result.fidelity if result.execution_result else None
173
+ else:
174
+ result = _compressor.compress(
175
+ tokens=request.tokens,
176
+ compression_level=request.compression_level,
177
+ )
178
+ fidelity = None
179
+
180
+ execution_time = (time.perf_counter() - start_time) * 1000
181
+
182
+ # Track usage if user is authenticated and db is available
183
+ if user and _db_initialized:
184
+ try:
185
+ db = next(get_db_session())
186
+ crud.create_usage_record(
187
+ db,
188
+ user_id=user.id,
189
+ endpoint="/v1/compress",
190
+ method="POST",
191
+ tokens_input=len(request.tokens),
192
+ tokens_output=result.n_qubits,
193
+ qubits_used=result.n_qubits,
194
+ execution_time_ms=execution_time,
195
+ ip_address=http_request.client.host if http_request.client else None,
196
+ )
197
+ except Exception:
198
+ pass # Don't fail request if usage tracking fails
199
+
200
+ return CompressResponse(
201
+ input_tokens=result.input_token_count,
202
+ output_qubits=result.n_qubits,
203
+ tokens_saved=result.tokens_saved,
204
+ compression_ratio=result.compression_ratio,
205
+ compression_percent=result.compression_percentage,
206
+ fidelity=fidelity,
207
+ execution_time_ms=execution_time,
208
+ backend_used=request.backend,
209
+ )
210
+
211
+ except Exception as e:
212
+ raise HTTPException(status_code=400, detail=str(e))
213
+
214
+
215
+ # === Gradient Endpoints (Paper 2) ===
216
+
217
+ @app.post("/v1/gradient", response_model=GradientResponse, tags=["Backpropagation"])
218
+ async def compute_gradient(
219
+ request: GradientRequest,
220
+ user: Optional[User] = Depends(get_optional_user),
221
+ ):
222
+ """
223
+ Compute gradient using quantum teleportation protocol.
224
+
225
+ Achieves 97.78% similarity with classical gradients.
226
+ """
227
+ if not _backprop:
228
+ raise HTTPException(status_code=503, detail="Quantum backprop not initialized")
229
+
230
+ start_time = time.perf_counter()
231
+
232
+ try:
233
+ result = _backprop.compute_gradient(
234
+ input_state=np.array(request.input_state),
235
+ target_state=np.array(request.target_state),
236
+ weights=np.array(request.weights),
237
+ shots=request.shots,
238
+ )
239
+
240
+ execution_time = (time.perf_counter() - start_time) * 1000
241
+
242
+ return GradientResponse(
243
+ gradients=result.gradients.tolist(),
244
+ bit_x=result.bit_x,
245
+ bit_z=result.bit_z,
246
+ gradient_direction=result.gradient_direction,
247
+ gradient_magnitude=result.gradient_magnitude,
248
+ classical_similarity=abs(result.similarity),
249
+ execution_time_ms=execution_time,
250
+ )
251
+
252
+ except Exception as e:
253
+ raise HTTPException(status_code=400, detail=str(e))
254
+
255
+
256
+ # === Backend Endpoints ===
257
+
258
+ @app.get("/v1/backends", response_model=BackendsResponse, tags=["Backends"])
259
+ async def list_backends():
260
+ """List available quantum backends."""
261
+ backends = [
262
+ BackendStatus(
263
+ name="simulator",
264
+ status="online",
265
+ is_simulator=True,
266
+ max_qubits=30,
267
+ ),
268
+ BackendStatus(
269
+ name="ibm",
270
+ status="available",
271
+ is_simulator=False,
272
+ max_qubits=156,
273
+ queue_position=None,
274
+ ),
275
+ # AWS Braket backends
276
+ BackendStatus(
277
+ name="aws_sv1",
278
+ status="available",
279
+ is_simulator=True,
280
+ max_qubits=34,
281
+ ),
282
+ BackendStatus(
283
+ name="aws_ionq",
284
+ status="available",
285
+ is_simulator=False,
286
+ max_qubits=25,
287
+ ),
288
+ BackendStatus(
289
+ name="aws_rigetti",
290
+ status="available",
291
+ is_simulator=False,
292
+ max_qubits=80,
293
+ ),
294
+ ]
295
+ return BackendsResponse(backends=backends)
296
+
297
+
298
+ # === Memory Endpoints ===
299
+
300
+ @app.post("/v1/memory/store", response_model=MemoryStoreResponse, tags=["Memory"])
301
+ async def memory_store(
302
+ request: MemoryStoreRequest,
303
+ user: Optional[User] = Depends(get_optional_user),
304
+ ):
305
+ """Store data in quantum memory."""
306
+ if not _memory:
307
+ raise HTTPException(status_code=503, detail="Quantum memory not initialized")
308
+
309
+ try:
310
+ slot = _memory.store(request.key, request.values, compress=request.compress)
311
+
312
+ return MemoryStoreResponse(
313
+ key=request.key,
314
+ stored_count=len(request.values),
315
+ qubits_used=slot.compressed.n_qubits if slot.compressed else None,
316
+ compression_ratio=slot.compressed.compression_ratio if slot.compressed else None,
317
+ )
318
+
319
+ except Exception as e:
320
+ raise HTTPException(status_code=400, detail=str(e))
321
+
322
+
323
+ @app.get("/v1/memory/{key}", response_model=MemoryRetrieveResponse, tags=["Memory"])
324
+ async def memory_retrieve(
325
+ key: str,
326
+ user: Optional[User] = Depends(get_optional_user),
327
+ ):
328
+ """Retrieve data from quantum memory."""
329
+ if not _memory:
330
+ raise HTTPException(status_code=503, detail="Quantum memory not initialized")
331
+
332
+ try:
333
+ values = _memory.retrieve(key)
334
+ return MemoryRetrieveResponse(key=key, values=values)
335
+ except KeyError:
336
+ raise HTTPException(status_code=404, detail=f"Key '{key}' not found")
337
+
338
+
339
+ @app.delete("/v1/memory/{key}", tags=["Memory"])
340
+ async def memory_delete(
341
+ key: str,
342
+ user: Optional[User] = Depends(get_optional_user),
343
+ ):
344
+ """Delete data from quantum memory."""
345
+ if not _memory:
346
+ raise HTTPException(status_code=503, detail="Quantum memory not initialized")
347
+
348
+ if _memory.delete(key):
349
+ return {"deleted": True, "key": key}
350
+ raise HTTPException(status_code=404, detail=f"Key '{key}' not found")
351
+
352
+
353
+ @app.get("/v1/memory", response_model=MemoryStatsResponse, tags=["Memory"])
354
+ async def memory_stats(user: Optional[User] = Depends(get_optional_user)):
355
+ """Get quantum memory statistics."""
356
+ if not _memory:
357
+ raise HTTPException(status_code=503, detail="Quantum memory not initialized")
358
+
359
+ stats = _memory.get_stats()
360
+ return MemoryStatsResponse(
361
+ total_items=stats.total_items,
362
+ classical_size=stats.classical_size,
363
+ quantum_size=stats.quantum_size,
364
+ compression_ratio=stats.compression_ratio,
365
+ memory_saved_percent=stats.memory_saved_percent,
366
+ )
367
+
368
+
369
+ # === Entanglement Endpoints ===
370
+
371
+ @app.post("/v1/entangle", response_model=EntangleResponse, tags=["Entanglement"])
372
+ async def create_entanglement(
373
+ request: EntangleRequest,
374
+ user: Optional[User] = Depends(get_optional_user),
375
+ ):
376
+ """Create entangled state from multiple contexts."""
377
+ if not _entangler:
378
+ raise HTTPException(status_code=503, detail="Entangler not initialized")
379
+
380
+ try:
381
+ if len(request.contexts) == 2:
382
+ state = _entangler.entangle_contexts(
383
+ request.contexts[0],
384
+ request.contexts[1],
385
+ )
386
+ else:
387
+ state = _entangler.create_ghz_state(len(request.contexts))
388
+
389
+ return EntangleResponse(
390
+ n_qubits=state.n_qubits,
391
+ n_parties=state.n_parties,
392
+ entropy=state.entropy,
393
+ is_maximally_entangled=state.is_maximally_entangled,
394
+ )
395
+
396
+ except Exception as e:
397
+ raise HTTPException(status_code=400, detail=str(e))
398
+
399
+
400
+ # Run with: uvicorn api.main:app --reload
401
+ if __name__ == "__main__":
402
+ import uvicorn
403
+ uvicorn.run(app, host="0.0.0.0", port=8000)