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.
- api/__init__.py +1 -0
- api/auth.py +208 -0
- api/main.py +403 -0
- api/models.py +137 -0
- api/routes/__init__.py +1 -0
- api/routes/auth_routes.py +234 -0
- api/routes/teleport_routes.py +415 -0
- db/__init__.py +15 -0
- db/crud.py +319 -0
- db/database.py +93 -0
- db/models.py +197 -0
- quantumflow/__init__.py +47 -0
- quantumflow/algorithms/__init__.py +48 -0
- quantumflow/algorithms/compression/__init__.py +7 -0
- quantumflow/algorithms/compression/amplitude_amplification.py +189 -0
- quantumflow/algorithms/compression/qft_compression.py +133 -0
- quantumflow/algorithms/compression/token_compression.py +261 -0
- quantumflow/algorithms/cryptography/__init__.py +6 -0
- quantumflow/algorithms/cryptography/qkd.py +205 -0
- quantumflow/algorithms/cryptography/qrng.py +231 -0
- quantumflow/algorithms/machine_learning/__init__.py +7 -0
- quantumflow/algorithms/machine_learning/qnn.py +276 -0
- quantumflow/algorithms/machine_learning/qsvm.py +249 -0
- quantumflow/algorithms/machine_learning/vqe.py +229 -0
- quantumflow/algorithms/optimization/__init__.py +7 -0
- quantumflow/algorithms/optimization/grover.py +223 -0
- quantumflow/algorithms/optimization/qaoa.py +251 -0
- quantumflow/algorithms/optimization/quantum_annealing.py +237 -0
- quantumflow/algorithms/utility/__init__.py +6 -0
- quantumflow/algorithms/utility/circuit_optimizer.py +194 -0
- quantumflow/algorithms/utility/error_correction.py +330 -0
- quantumflow/api/__init__.py +1 -0
- quantumflow/api/routes/__init__.py +4 -0
- quantumflow/api/routes/billing_routes.py +520 -0
- quantumflow/backends/__init__.py +33 -0
- quantumflow/backends/base_backend.py +184 -0
- quantumflow/backends/braket_backend.py +345 -0
- quantumflow/backends/ibm_backend.py +112 -0
- quantumflow/backends/simulator_backend.py +86 -0
- quantumflow/billing/__init__.py +25 -0
- quantumflow/billing/models.py +126 -0
- quantumflow/billing/stripe_service.py +619 -0
- quantumflow/core/__init__.py +12 -0
- quantumflow/core/entanglement.py +164 -0
- quantumflow/core/memory.py +147 -0
- quantumflow/core/quantum_backprop.py +394 -0
- quantumflow/core/quantum_compressor.py +309 -0
- quantumflow/core/teleportation.py +386 -0
- quantumflow/integrations/__init__.py +107 -0
- quantumflow/integrations/autogen_tools.py +501 -0
- quantumflow/integrations/crewai_agents.py +425 -0
- quantumflow/integrations/crewai_tools.py +407 -0
- quantumflow/integrations/langchain_memory.py +385 -0
- quantumflow/integrations/langchain_tools.py +366 -0
- quantumflow/integrations/mcp_server.py +575 -0
- quantumflow_sdk-0.1.0.dist-info/METADATA +190 -0
- quantumflow_sdk-0.1.0.dist-info/RECORD +60 -0
- quantumflow_sdk-0.1.0.dist-info/WHEEL +5 -0
- quantumflow_sdk-0.1.0.dist-info/entry_points.txt +2 -0
- quantumflow_sdk-0.1.0.dist-info/top_level.txt +3 -0
api/models.py
ADDED
|
@@ -0,0 +1,137 @@
|
|
|
1
|
+
"""
|
|
2
|
+
API Request/Response Models for QuantumFlow.
|
|
3
|
+
"""
|
|
4
|
+
|
|
5
|
+
from typing import Optional
|
|
6
|
+
from pydantic import BaseModel, Field
|
|
7
|
+
|
|
8
|
+
|
|
9
|
+
# === Compression Models ===
|
|
10
|
+
|
|
11
|
+
class CompressRequest(BaseModel):
|
|
12
|
+
"""Request to compress tokens."""
|
|
13
|
+
|
|
14
|
+
tokens: list[int] = Field(..., description="List of integer tokens to compress")
|
|
15
|
+
compression_level: float = Field(default=1.0, ge=0.0, le=1.0)
|
|
16
|
+
backend: str = Field(default="auto", description="Backend: auto, simulator, ibm")
|
|
17
|
+
execute: bool = Field(default=False, description="Execute on quantum backend")
|
|
18
|
+
shots: int = Field(default=1024, ge=1, le=10000)
|
|
19
|
+
|
|
20
|
+
|
|
21
|
+
class CompressResponse(BaseModel):
|
|
22
|
+
"""Response from token compression."""
|
|
23
|
+
|
|
24
|
+
input_tokens: int
|
|
25
|
+
output_qubits: int
|
|
26
|
+
tokens_saved: int
|
|
27
|
+
compression_ratio: float
|
|
28
|
+
compression_percent: float
|
|
29
|
+
fidelity: Optional[float] = None
|
|
30
|
+
execution_time_ms: Optional[float] = None
|
|
31
|
+
backend_used: str
|
|
32
|
+
|
|
33
|
+
|
|
34
|
+
# === Gradient Models ===
|
|
35
|
+
|
|
36
|
+
class GradientRequest(BaseModel):
|
|
37
|
+
"""Request to compute quantum gradient."""
|
|
38
|
+
|
|
39
|
+
input_state: list[float] = Field(..., description="Input state amplitudes")
|
|
40
|
+
target_state: list[float] = Field(..., description="Target state amplitudes")
|
|
41
|
+
weights: list[float] = Field(..., description="Current weight parameters")
|
|
42
|
+
backend: str = Field(default="auto")
|
|
43
|
+
shots: int = Field(default=1024, ge=1, le=10000)
|
|
44
|
+
|
|
45
|
+
|
|
46
|
+
class GradientResponse(BaseModel):
|
|
47
|
+
"""Response from quantum gradient computation."""
|
|
48
|
+
|
|
49
|
+
gradients: list[float]
|
|
50
|
+
bit_x: int
|
|
51
|
+
bit_z: int
|
|
52
|
+
gradient_direction: int
|
|
53
|
+
gradient_magnitude: float
|
|
54
|
+
classical_similarity: float
|
|
55
|
+
execution_time_ms: float
|
|
56
|
+
|
|
57
|
+
|
|
58
|
+
# === Backend Models ===
|
|
59
|
+
|
|
60
|
+
class BackendStatus(BaseModel):
|
|
61
|
+
"""Status of a quantum backend."""
|
|
62
|
+
|
|
63
|
+
name: str
|
|
64
|
+
status: str
|
|
65
|
+
is_simulator: bool
|
|
66
|
+
max_qubits: int
|
|
67
|
+
queue_position: Optional[int] = None
|
|
68
|
+
|
|
69
|
+
|
|
70
|
+
class BackendsResponse(BaseModel):
|
|
71
|
+
"""List of available backends."""
|
|
72
|
+
|
|
73
|
+
backends: list[BackendStatus]
|
|
74
|
+
|
|
75
|
+
|
|
76
|
+
# === Memory Models ===
|
|
77
|
+
|
|
78
|
+
class MemoryStoreRequest(BaseModel):
|
|
79
|
+
"""Request to store data in quantum memory."""
|
|
80
|
+
|
|
81
|
+
key: str = Field(..., min_length=1, max_length=256)
|
|
82
|
+
values: list[int]
|
|
83
|
+
compress: bool = Field(default=True)
|
|
84
|
+
|
|
85
|
+
|
|
86
|
+
class MemoryStoreResponse(BaseModel):
|
|
87
|
+
"""Response from memory store operation."""
|
|
88
|
+
|
|
89
|
+
key: str
|
|
90
|
+
stored_count: int
|
|
91
|
+
qubits_used: Optional[int] = None
|
|
92
|
+
compression_ratio: Optional[float] = None
|
|
93
|
+
|
|
94
|
+
|
|
95
|
+
class MemoryRetrieveResponse(BaseModel):
|
|
96
|
+
"""Response from memory retrieve operation."""
|
|
97
|
+
|
|
98
|
+
key: str
|
|
99
|
+
values: list[int]
|
|
100
|
+
|
|
101
|
+
|
|
102
|
+
class MemoryStatsResponse(BaseModel):
|
|
103
|
+
"""Quantum memory statistics."""
|
|
104
|
+
|
|
105
|
+
total_items: int
|
|
106
|
+
classical_size: int
|
|
107
|
+
quantum_size: int
|
|
108
|
+
compression_ratio: float
|
|
109
|
+
memory_saved_percent: float
|
|
110
|
+
|
|
111
|
+
|
|
112
|
+
# === Entanglement Models ===
|
|
113
|
+
|
|
114
|
+
class EntangleRequest(BaseModel):
|
|
115
|
+
"""Request to create entangled state."""
|
|
116
|
+
|
|
117
|
+
contexts: list[list[float]] = Field(..., min_length=2)
|
|
118
|
+
backend: str = Field(default="auto")
|
|
119
|
+
|
|
120
|
+
|
|
121
|
+
class EntangleResponse(BaseModel):
|
|
122
|
+
"""Response from entanglement creation."""
|
|
123
|
+
|
|
124
|
+
n_qubits: int
|
|
125
|
+
n_parties: int
|
|
126
|
+
entropy: float
|
|
127
|
+
is_maximally_entangled: bool
|
|
128
|
+
|
|
129
|
+
|
|
130
|
+
# === Health Models ===
|
|
131
|
+
|
|
132
|
+
class HealthResponse(BaseModel):
|
|
133
|
+
"""API health status."""
|
|
134
|
+
|
|
135
|
+
status: str
|
|
136
|
+
version: str
|
|
137
|
+
quantum_ready: bool
|
api/routes/__init__.py
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
"""API Routes Package."""
|
|
@@ -0,0 +1,234 @@
|
|
|
1
|
+
"""
|
|
2
|
+
Authentication Routes.
|
|
3
|
+
|
|
4
|
+
Endpoints for user registration, login, and API key management.
|
|
5
|
+
"""
|
|
6
|
+
|
|
7
|
+
from typing import Optional
|
|
8
|
+
from fastapi import APIRouter, Depends, HTTPException, status
|
|
9
|
+
from pydantic import BaseModel, EmailStr
|
|
10
|
+
from sqlalchemy.orm import Session
|
|
11
|
+
|
|
12
|
+
from api.auth import (
|
|
13
|
+
get_db_session,
|
|
14
|
+
get_current_user,
|
|
15
|
+
get_current_active_user,
|
|
16
|
+
create_access_token,
|
|
17
|
+
authenticate_user,
|
|
18
|
+
create_user,
|
|
19
|
+
create_api_key_for_user,
|
|
20
|
+
TokenResponse,
|
|
21
|
+
UserResponse,
|
|
22
|
+
APIKeyResponse,
|
|
23
|
+
ACCESS_TOKEN_EXPIRE_MINUTES,
|
|
24
|
+
)
|
|
25
|
+
from db import crud
|
|
26
|
+
from db.models import User
|
|
27
|
+
|
|
28
|
+
router = APIRouter(prefix="/auth", tags=["Authentication"])
|
|
29
|
+
|
|
30
|
+
|
|
31
|
+
# ============== Request Models ==============
|
|
32
|
+
|
|
33
|
+
class RegisterRequest(BaseModel):
|
|
34
|
+
"""User registration request."""
|
|
35
|
+
email: EmailStr
|
|
36
|
+
password: str
|
|
37
|
+
name: Optional[str] = None
|
|
38
|
+
|
|
39
|
+
|
|
40
|
+
class LoginRequest(BaseModel):
|
|
41
|
+
"""User login request."""
|
|
42
|
+
email: EmailStr
|
|
43
|
+
password: str
|
|
44
|
+
|
|
45
|
+
|
|
46
|
+
class CreateAPIKeyRequest(BaseModel):
|
|
47
|
+
"""Create API key request."""
|
|
48
|
+
name: str
|
|
49
|
+
scopes: Optional[list[str]] = None
|
|
50
|
+
|
|
51
|
+
|
|
52
|
+
class APIKeyCreatedResponse(BaseModel):
|
|
53
|
+
"""Response when API key is created (includes full key)."""
|
|
54
|
+
id: str
|
|
55
|
+
name: str
|
|
56
|
+
key: str # Only returned once!
|
|
57
|
+
prefix: str
|
|
58
|
+
message: str = "Save this key securely - it won't be shown again"
|
|
59
|
+
|
|
60
|
+
|
|
61
|
+
# ============== Routes ==============
|
|
62
|
+
|
|
63
|
+
@router.post("/register", response_model=UserResponse, status_code=status.HTTP_201_CREATED)
|
|
64
|
+
async def register(
|
|
65
|
+
request: RegisterRequest,
|
|
66
|
+
db: Session = Depends(get_db_session),
|
|
67
|
+
):
|
|
68
|
+
"""
|
|
69
|
+
Register a new user account.
|
|
70
|
+
"""
|
|
71
|
+
# Check if email exists
|
|
72
|
+
existing = crud.get_user_by_email(db, request.email)
|
|
73
|
+
if existing:
|
|
74
|
+
raise HTTPException(
|
|
75
|
+
status_code=status.HTTP_400_BAD_REQUEST,
|
|
76
|
+
detail="Email already registered",
|
|
77
|
+
)
|
|
78
|
+
|
|
79
|
+
# Create user
|
|
80
|
+
user = create_user(db, request.email, request.password, request.name)
|
|
81
|
+
|
|
82
|
+
return UserResponse(
|
|
83
|
+
id=str(user.id),
|
|
84
|
+
email=user.email,
|
|
85
|
+
name=user.name,
|
|
86
|
+
tier=user.tier,
|
|
87
|
+
is_active=user.is_active,
|
|
88
|
+
)
|
|
89
|
+
|
|
90
|
+
|
|
91
|
+
@router.post("/login", response_model=TokenResponse)
|
|
92
|
+
async def login(
|
|
93
|
+
request: LoginRequest,
|
|
94
|
+
db: Session = Depends(get_db_session),
|
|
95
|
+
):
|
|
96
|
+
"""
|
|
97
|
+
Login and get JWT access token.
|
|
98
|
+
"""
|
|
99
|
+
user = authenticate_user(db, request.email, request.password)
|
|
100
|
+
if not user:
|
|
101
|
+
raise HTTPException(
|
|
102
|
+
status_code=status.HTTP_401_UNAUTHORIZED,
|
|
103
|
+
detail="Invalid email or password",
|
|
104
|
+
)
|
|
105
|
+
|
|
106
|
+
if not user.is_active:
|
|
107
|
+
raise HTTPException(
|
|
108
|
+
status_code=status.HTTP_403_FORBIDDEN,
|
|
109
|
+
detail="Account is disabled",
|
|
110
|
+
)
|
|
111
|
+
|
|
112
|
+
# Update last login
|
|
113
|
+
crud.update_user_login(db, user)
|
|
114
|
+
|
|
115
|
+
# Create token
|
|
116
|
+
token = create_access_token(str(user.id))
|
|
117
|
+
|
|
118
|
+
return TokenResponse(
|
|
119
|
+
access_token=token,
|
|
120
|
+
expires_in=ACCESS_TOKEN_EXPIRE_MINUTES * 60,
|
|
121
|
+
)
|
|
122
|
+
|
|
123
|
+
|
|
124
|
+
@router.get("/me", response_model=UserResponse)
|
|
125
|
+
async def get_me(
|
|
126
|
+
current_user: User = Depends(get_current_active_user),
|
|
127
|
+
):
|
|
128
|
+
"""
|
|
129
|
+
Get current user profile.
|
|
130
|
+
"""
|
|
131
|
+
return UserResponse(
|
|
132
|
+
id=str(current_user.id),
|
|
133
|
+
email=current_user.email,
|
|
134
|
+
name=current_user.name,
|
|
135
|
+
tier=current_user.tier,
|
|
136
|
+
is_active=current_user.is_active,
|
|
137
|
+
)
|
|
138
|
+
|
|
139
|
+
|
|
140
|
+
@router.get("/usage")
|
|
141
|
+
async def get_usage(
|
|
142
|
+
current_user: User = Depends(get_current_active_user),
|
|
143
|
+
db: Session = Depends(get_db_session),
|
|
144
|
+
):
|
|
145
|
+
"""
|
|
146
|
+
Get current user's usage statistics.
|
|
147
|
+
"""
|
|
148
|
+
usage = crud.get_user_usage(db, current_user.id)
|
|
149
|
+
monthly = crud.get_monthly_usage(db, current_user.id)
|
|
150
|
+
|
|
151
|
+
return {
|
|
152
|
+
"user_id": str(current_user.id),
|
|
153
|
+
"tier": current_user.tier,
|
|
154
|
+
"monthly_quota": current_user.monthly_quota,
|
|
155
|
+
"monthly_used": monthly,
|
|
156
|
+
"monthly_remaining": max(0, current_user.monthly_quota - monthly),
|
|
157
|
+
"all_time": usage,
|
|
158
|
+
}
|
|
159
|
+
|
|
160
|
+
|
|
161
|
+
# ============== API Key Management ==============
|
|
162
|
+
|
|
163
|
+
@router.post("/keys", response_model=APIKeyCreatedResponse, status_code=status.HTTP_201_CREATED)
|
|
164
|
+
async def create_api_key(
|
|
165
|
+
request: CreateAPIKeyRequest,
|
|
166
|
+
current_user: User = Depends(get_current_active_user),
|
|
167
|
+
db: Session = Depends(get_db_session),
|
|
168
|
+
):
|
|
169
|
+
"""
|
|
170
|
+
Create a new API key.
|
|
171
|
+
|
|
172
|
+
The full key is only returned once - save it securely!
|
|
173
|
+
"""
|
|
174
|
+
key_record, raw_key = create_api_key_for_user(
|
|
175
|
+
db, current_user.id, request.name, request.scopes
|
|
176
|
+
)
|
|
177
|
+
|
|
178
|
+
return APIKeyCreatedResponse(
|
|
179
|
+
id=str(key_record.id),
|
|
180
|
+
name=key_record.name,
|
|
181
|
+
key=raw_key,
|
|
182
|
+
prefix=key_record.prefix,
|
|
183
|
+
)
|
|
184
|
+
|
|
185
|
+
|
|
186
|
+
@router.get("/keys", response_model=list[APIKeyResponse])
|
|
187
|
+
async def list_api_keys(
|
|
188
|
+
current_user: User = Depends(get_current_active_user),
|
|
189
|
+
db: Session = Depends(get_db_session),
|
|
190
|
+
):
|
|
191
|
+
"""
|
|
192
|
+
List all API keys for current user.
|
|
193
|
+
"""
|
|
194
|
+
keys = crud.get_user_api_keys(db, current_user.id)
|
|
195
|
+
|
|
196
|
+
return [
|
|
197
|
+
APIKeyResponse(
|
|
198
|
+
id=str(k.id),
|
|
199
|
+
name=k.name,
|
|
200
|
+
prefix=k.prefix,
|
|
201
|
+
created_at=k.created_at,
|
|
202
|
+
last_used=k.last_used,
|
|
203
|
+
is_active=k.is_active,
|
|
204
|
+
)
|
|
205
|
+
for k in keys
|
|
206
|
+
]
|
|
207
|
+
|
|
208
|
+
|
|
209
|
+
@router.delete("/keys/{key_id}")
|
|
210
|
+
async def revoke_api_key(
|
|
211
|
+
key_id: str,
|
|
212
|
+
current_user: User = Depends(get_current_active_user),
|
|
213
|
+
db: Session = Depends(get_db_session),
|
|
214
|
+
):
|
|
215
|
+
"""
|
|
216
|
+
Revoke an API key.
|
|
217
|
+
"""
|
|
218
|
+
from uuid import UUID
|
|
219
|
+
|
|
220
|
+
try:
|
|
221
|
+
uuid_key_id = UUID(key_id)
|
|
222
|
+
except ValueError:
|
|
223
|
+
raise HTTPException(status_code=400, detail="Invalid key ID")
|
|
224
|
+
|
|
225
|
+
# Verify key belongs to user
|
|
226
|
+
keys = crud.get_user_api_keys(db, current_user.id)
|
|
227
|
+
if not any(k.id == uuid_key_id for k in keys):
|
|
228
|
+
raise HTTPException(status_code=404, detail="API key not found")
|
|
229
|
+
|
|
230
|
+
success = crud.revoke_api_key(db, uuid_key_id)
|
|
231
|
+
if not success:
|
|
232
|
+
raise HTTPException(status_code=404, detail="API key not found")
|
|
233
|
+
|
|
234
|
+
return {"message": "API key revoked", "key_id": key_id}
|