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
@@ -0,0 +1,520 @@
1
+ """
2
+ Billing API Routes - Stripe subscription and payment management.
3
+ """
4
+
5
+ from datetime import datetime
6
+ from typing import Optional
7
+ from fastapi import APIRouter, Depends, HTTPException, Header, Request
8
+ from pydantic import BaseModel
9
+
10
+ from api.auth import get_current_user
11
+ from db.models import User
12
+ from quantumflow.billing import (
13
+ StripeService,
14
+ SubscriptionTier,
15
+ TIER_PRICES,
16
+ TIER_LIMITS,
17
+ )
18
+
19
+ router = APIRouter(prefix="/billing", tags=["billing"])
20
+
21
+ # Initialize Stripe service (lazy init to handle missing keys gracefully)
22
+ _stripe_service: Optional[StripeService] = None
23
+
24
+
25
+ def get_stripe_service() -> StripeService:
26
+ """Get or create Stripe service instance."""
27
+ global _stripe_service
28
+ if _stripe_service is None:
29
+ _stripe_service = StripeService()
30
+ return _stripe_service
31
+
32
+
33
+ # ==================== Request/Response Models ====================
34
+
35
+
36
+ class CreateCustomerRequest(BaseModel):
37
+ """Request to create a Stripe customer."""
38
+ email: str
39
+ name: Optional[str] = None
40
+
41
+
42
+ class CreateSubscriptionRequest(BaseModel):
43
+ """Request to create a subscription."""
44
+ tier: SubscriptionTier
45
+ payment_method_id: Optional[str] = None
46
+ trial_days: int = 0
47
+
48
+
49
+ class UpdateSubscriptionRequest(BaseModel):
50
+ """Request to update subscription tier."""
51
+ tier: SubscriptionTier
52
+ prorate: bool = True
53
+
54
+
55
+ class CheckoutSessionRequest(BaseModel):
56
+ """Request to create checkout session."""
57
+ tier: SubscriptionTier
58
+ success_url: str
59
+ cancel_url: str
60
+
61
+
62
+ class BillingPortalRequest(BaseModel):
63
+ """Request for billing portal session."""
64
+ return_url: str
65
+
66
+
67
+ class SubscriptionResponse(BaseModel):
68
+ """Subscription details response."""
69
+ id: str
70
+ tier: str
71
+ status: str
72
+ current_period_start: datetime
73
+ current_period_end: datetime
74
+ cancel_at_period_end: bool
75
+ trial_end: Optional[datetime] = None
76
+
77
+
78
+ class PricingResponse(BaseModel):
79
+ """Pricing information response."""
80
+ tier: str
81
+ monthly_price: float
82
+ api_calls_included: int
83
+ overage_price_per_call: float
84
+ features: dict
85
+
86
+
87
+ class InvoiceResponse(BaseModel):
88
+ """Invoice response."""
89
+ id: str
90
+ amount_due: float
91
+ amount_paid: float
92
+ currency: str
93
+ status: str
94
+ invoice_pdf: Optional[str] = None
95
+ hosted_invoice_url: Optional[str] = None
96
+ period_start: Optional[datetime] = None
97
+ period_end: Optional[datetime] = None
98
+
99
+
100
+ class UsageSummaryResponse(BaseModel):
101
+ """Usage summary response."""
102
+ total_usage: int
103
+ period_start: Optional[datetime] = None
104
+ period_end: Optional[datetime] = None
105
+ tier: str
106
+ limit: int
107
+ remaining: int
108
+ overage: int
109
+
110
+
111
+ # ==================== Pricing Endpoints ====================
112
+
113
+
114
+ @router.get("/pricing", response_model=list[PricingResponse])
115
+ async def get_pricing():
116
+ """Get pricing information for all tiers."""
117
+ pricing = []
118
+ for tier in SubscriptionTier:
119
+ price_info = TIER_PRICES[tier]
120
+ tier_limits = TIER_LIMITS[tier]
121
+ pricing.append(PricingResponse(
122
+ tier=tier.value,
123
+ monthly_price=price_info.monthly_price_dollars,
124
+ api_calls_included=price_info.api_calls_included,
125
+ overage_price_per_call=price_info.overage_price_per_call,
126
+ features=tier_limits,
127
+ ))
128
+ return pricing
129
+
130
+
131
+ # ==================== Customer Endpoints ====================
132
+
133
+
134
+ @router.post("/customers")
135
+ async def create_customer(
136
+ request: CreateCustomerRequest,
137
+ current_user: User = Depends(get_current_user),
138
+ stripe: StripeService = Depends(get_stripe_service),
139
+ ):
140
+ """Create a Stripe customer for the current user."""
141
+ try:
142
+ customer = stripe.create_customer(
143
+ email=request.email,
144
+ name=request.name,
145
+ user_id=str(current_user.id),
146
+ metadata={"user_id": str(current_user.id)},
147
+ )
148
+ return {
149
+ "customer_id": customer.stripe_customer_id,
150
+ "email": customer.email,
151
+ "name": customer.name,
152
+ }
153
+ except Exception as e:
154
+ raise HTTPException(status_code=400, detail=str(e))
155
+
156
+
157
+ @router.get("/customers/me")
158
+ async def get_current_customer(
159
+ current_user: User = Depends(get_current_user),
160
+ stripe: StripeService = Depends(get_stripe_service),
161
+ ):
162
+ """Get current user's Stripe customer details."""
163
+ stripe_customer_id = getattr(current_user, 'stripe_customer_id', None)
164
+ if not stripe_customer_id:
165
+ raise HTTPException(status_code=404, detail="No billing account found")
166
+
167
+ customer = stripe.get_customer(stripe_customer_id)
168
+ if not customer:
169
+ raise HTTPException(status_code=404, detail="Customer not found")
170
+
171
+ return {
172
+ "customer_id": customer.stripe_customer_id,
173
+ "email": customer.email,
174
+ "name": customer.name,
175
+ "has_payment_method": customer.has_payment_method,
176
+ }
177
+
178
+
179
+ # ==================== Subscription Endpoints ====================
180
+
181
+
182
+ @router.post("/subscriptions", response_model=SubscriptionResponse)
183
+ async def create_subscription(
184
+ request: CreateSubscriptionRequest,
185
+ current_user: User = Depends(get_current_user),
186
+ stripe: StripeService = Depends(get_stripe_service),
187
+ ):
188
+ """Create a new subscription."""
189
+ stripe_customer_id = getattr(current_user, 'stripe_customer_id', None)
190
+ if not stripe_customer_id:
191
+ raise HTTPException(
192
+ status_code=400,
193
+ detail="Create a billing account first"
194
+ )
195
+
196
+ try:
197
+ subscription = stripe.create_subscription(
198
+ customer_id=stripe_customer_id,
199
+ tier=request.tier,
200
+ trial_days=request.trial_days,
201
+ payment_method_id=request.payment_method_id,
202
+ )
203
+ return SubscriptionResponse(
204
+ id=subscription.stripe_subscription_id,
205
+ tier=subscription.tier,
206
+ status=subscription.status.value,
207
+ current_period_start=subscription.current_period_start,
208
+ current_period_end=subscription.current_period_end,
209
+ cancel_at_period_end=subscription.cancel_at_period_end,
210
+ trial_end=subscription.trial_end,
211
+ )
212
+ except Exception as e:
213
+ raise HTTPException(status_code=400, detail=str(e))
214
+
215
+
216
+ @router.get("/subscriptions/current", response_model=SubscriptionResponse)
217
+ async def get_current_subscription(
218
+ current_user: User = Depends(get_current_user),
219
+ stripe: StripeService = Depends(get_stripe_service),
220
+ ):
221
+ """Get current user's active subscription."""
222
+ subscription_id = getattr(current_user, 'stripe_subscription_id', None)
223
+ if not subscription_id:
224
+ raise HTTPException(status_code=404, detail="No active subscription")
225
+
226
+ subscription = stripe.get_subscription(subscription_id)
227
+ if not subscription:
228
+ raise HTTPException(status_code=404, detail="Subscription not found")
229
+
230
+ return SubscriptionResponse(
231
+ id=subscription.stripe_subscription_id,
232
+ tier=subscription.tier,
233
+ status=subscription.status.value,
234
+ current_period_start=subscription.current_period_start,
235
+ current_period_end=subscription.current_period_end,
236
+ cancel_at_period_end=subscription.cancel_at_period_end,
237
+ trial_end=subscription.trial_end,
238
+ )
239
+
240
+
241
+ @router.patch("/subscriptions/current", response_model=SubscriptionResponse)
242
+ async def update_subscription(
243
+ request: UpdateSubscriptionRequest,
244
+ current_user: User = Depends(get_current_user),
245
+ stripe: StripeService = Depends(get_stripe_service),
246
+ ):
247
+ """Update subscription tier (upgrade/downgrade)."""
248
+ subscription_id = getattr(current_user, 'stripe_subscription_id', None)
249
+ if not subscription_id:
250
+ raise HTTPException(status_code=404, detail="No active subscription")
251
+
252
+ try:
253
+ subscription = stripe.update_subscription_tier(
254
+ stripe_subscription_id=subscription_id,
255
+ new_tier=request.tier,
256
+ prorate=request.prorate,
257
+ )
258
+ return SubscriptionResponse(
259
+ id=subscription.stripe_subscription_id,
260
+ tier=subscription.tier,
261
+ status=subscription.status.value,
262
+ current_period_start=subscription.current_period_start,
263
+ current_period_end=subscription.current_period_end,
264
+ cancel_at_period_end=subscription.cancel_at_period_end,
265
+ )
266
+ except Exception as e:
267
+ raise HTTPException(status_code=400, detail=str(e))
268
+
269
+
270
+ @router.delete("/subscriptions/current")
271
+ async def cancel_subscription(
272
+ at_period_end: bool = True,
273
+ current_user: User = Depends(get_current_user),
274
+ stripe: StripeService = Depends(get_stripe_service),
275
+ ):
276
+ """Cancel current subscription."""
277
+ subscription_id = getattr(current_user, 'stripe_subscription_id', None)
278
+ if not subscription_id:
279
+ raise HTTPException(status_code=404, detail="No active subscription")
280
+
281
+ try:
282
+ subscription = stripe.cancel_subscription(
283
+ stripe_subscription_id=subscription_id,
284
+ at_period_end=at_period_end,
285
+ )
286
+ return {
287
+ "message": "Subscription cancelled",
288
+ "cancel_at_period_end": subscription.cancel_at_period_end,
289
+ "current_period_end": subscription.current_period_end,
290
+ }
291
+ except Exception as e:
292
+ raise HTTPException(status_code=400, detail=str(e))
293
+
294
+
295
+ @router.post("/subscriptions/current/reactivate")
296
+ async def reactivate_subscription(
297
+ current_user: User = Depends(get_current_user),
298
+ stripe: StripeService = Depends(get_stripe_service),
299
+ ):
300
+ """Reactivate a cancelled subscription."""
301
+ subscription_id = getattr(current_user, 'stripe_subscription_id', None)
302
+ if not subscription_id:
303
+ raise HTTPException(status_code=404, detail="No subscription found")
304
+
305
+ try:
306
+ subscription = stripe.reactivate_subscription(subscription_id)
307
+ return {
308
+ "message": "Subscription reactivated",
309
+ "status": subscription.status.value,
310
+ }
311
+ except Exception as e:
312
+ raise HTTPException(status_code=400, detail=str(e))
313
+
314
+
315
+ # ==================== Usage Endpoints ====================
316
+
317
+
318
+ @router.get("/usage", response_model=UsageSummaryResponse)
319
+ async def get_usage_summary(
320
+ current_user: User = Depends(get_current_user),
321
+ stripe: StripeService = Depends(get_stripe_service),
322
+ ):
323
+ """Get usage summary for current billing period."""
324
+ subscription_item_id = getattr(current_user, 'stripe_subscription_item_id', None)
325
+ tier = getattr(current_user, 'tier', 'free')
326
+ tier_enum = SubscriptionTier(tier)
327
+ limit = TIER_LIMITS[tier_enum]["api_calls_monthly"]
328
+
329
+ if subscription_item_id:
330
+ summary = stripe.get_usage_summary(subscription_item_id)
331
+ total_usage = summary["total_usage"]
332
+ else:
333
+ # For free tier or no subscription, use internal tracking
334
+ total_usage = 0 # Would come from usage tracking
335
+ summary = {"period_start": None, "period_end": None}
336
+
337
+ return UsageSummaryResponse(
338
+ total_usage=total_usage,
339
+ period_start=summary.get("period_start"),
340
+ period_end=summary.get("period_end"),
341
+ tier=tier,
342
+ limit=limit,
343
+ remaining=max(0, limit - total_usage),
344
+ overage=max(0, total_usage - limit),
345
+ )
346
+
347
+
348
+ # ==================== Payment Methods ====================
349
+
350
+
351
+ @router.post("/payment-methods/setup")
352
+ async def create_setup_intent(
353
+ current_user: User = Depends(get_current_user),
354
+ stripe: StripeService = Depends(get_stripe_service),
355
+ ):
356
+ """Create a SetupIntent for adding a payment method."""
357
+ stripe_customer_id = getattr(current_user, 'stripe_customer_id', None)
358
+ if not stripe_customer_id:
359
+ raise HTTPException(status_code=400, detail="Create billing account first")
360
+
361
+ intent = stripe.create_setup_intent(stripe_customer_id)
362
+ return intent
363
+
364
+
365
+ @router.get("/payment-methods")
366
+ async def list_payment_methods(
367
+ current_user: User = Depends(get_current_user),
368
+ stripe: StripeService = Depends(get_stripe_service),
369
+ ):
370
+ """List saved payment methods."""
371
+ stripe_customer_id = getattr(current_user, 'stripe_customer_id', None)
372
+ if not stripe_customer_id:
373
+ return []
374
+
375
+ methods = stripe.list_payment_methods(stripe_customer_id)
376
+ return methods
377
+
378
+
379
+ # ==================== Invoices ====================
380
+
381
+
382
+ @router.get("/invoices", response_model=list[InvoiceResponse])
383
+ async def list_invoices(
384
+ limit: int = 10,
385
+ current_user: User = Depends(get_current_user),
386
+ stripe: StripeService = Depends(get_stripe_service),
387
+ ):
388
+ """List invoices for current user."""
389
+ stripe_customer_id = getattr(current_user, 'stripe_customer_id', None)
390
+ if not stripe_customer_id:
391
+ return []
392
+
393
+ invoices = stripe.list_invoices(stripe_customer_id, limit=limit)
394
+ return [
395
+ InvoiceResponse(
396
+ id=inv.stripe_invoice_id,
397
+ amount_due=inv.amount_due_dollars,
398
+ amount_paid=inv.amount_paid_dollars,
399
+ currency=inv.currency,
400
+ status=inv.status.value,
401
+ invoice_pdf=inv.invoice_pdf,
402
+ hosted_invoice_url=inv.hosted_invoice_url,
403
+ period_start=inv.period_start,
404
+ period_end=inv.period_end,
405
+ )
406
+ for inv in invoices
407
+ ]
408
+
409
+
410
+ @router.get("/invoices/upcoming", response_model=Optional[InvoiceResponse])
411
+ async def get_upcoming_invoice(
412
+ current_user: User = Depends(get_current_user),
413
+ stripe: StripeService = Depends(get_stripe_service),
414
+ ):
415
+ """Get upcoming invoice preview."""
416
+ stripe_customer_id = getattr(current_user, 'stripe_customer_id', None)
417
+ if not stripe_customer_id:
418
+ return None
419
+
420
+ invoice = stripe.get_upcoming_invoice(stripe_customer_id)
421
+ if not invoice:
422
+ return None
423
+
424
+ return InvoiceResponse(
425
+ id=invoice.stripe_invoice_id,
426
+ amount_due=invoice.amount_due_dollars,
427
+ amount_paid=invoice.amount_paid_dollars,
428
+ currency=invoice.currency,
429
+ status=invoice.status.value,
430
+ period_start=invoice.period_start,
431
+ period_end=invoice.period_end,
432
+ )
433
+
434
+
435
+ # ==================== Checkout & Portal ====================
436
+
437
+
438
+ @router.post("/checkout")
439
+ async def create_checkout_session(
440
+ request: CheckoutSessionRequest,
441
+ current_user: User = Depends(get_current_user),
442
+ stripe: StripeService = Depends(get_stripe_service),
443
+ ):
444
+ """Create a Stripe Checkout session."""
445
+ stripe_customer_id = getattr(current_user, 'stripe_customer_id', None)
446
+
447
+ # Auto-create customer if not exists
448
+ if not stripe_customer_id:
449
+ email = current_user.email
450
+ if not email:
451
+ raise HTTPException(status_code=400, detail="User email required")
452
+
453
+ customer = stripe.create_customer(
454
+ email=email,
455
+ name=current_user.name,
456
+ user_id=str(current_user.id),
457
+ metadata={"user_id": str(current_user.id)},
458
+ )
459
+ stripe_customer_id = customer.stripe_customer_id
460
+ # Note: In production, save stripe_customer_id to user record in database
461
+
462
+ try:
463
+ session = stripe.create_checkout_session(
464
+ customer_id=stripe_customer_id,
465
+ tier=request.tier,
466
+ success_url=request.success_url,
467
+ cancel_url=request.cancel_url,
468
+ )
469
+ return session
470
+ except Exception as e:
471
+ raise HTTPException(status_code=400, detail=str(e))
472
+
473
+
474
+ @router.post("/portal")
475
+ async def create_billing_portal(
476
+ request: BillingPortalRequest,
477
+ current_user: User = Depends(get_current_user),
478
+ stripe: StripeService = Depends(get_stripe_service),
479
+ ):
480
+ """Create a Stripe Billing Portal session."""
481
+ stripe_customer_id = getattr(current_user, 'stripe_customer_id', None)
482
+ if not stripe_customer_id:
483
+ raise HTTPException(status_code=400, detail="No billing account")
484
+
485
+ session = stripe.create_billing_portal_session(
486
+ customer_id=stripe_customer_id,
487
+ return_url=request.return_url,
488
+ )
489
+ return session
490
+
491
+
492
+ # ==================== Webhooks ====================
493
+
494
+
495
+ @router.post("/webhooks/stripe")
496
+ async def handle_stripe_webhook(
497
+ request: Request,
498
+ stripe_signature: str = Header(None, alias="Stripe-Signature"),
499
+ ):
500
+ """Handle Stripe webhook events."""
501
+ if not stripe_signature:
502
+ raise HTTPException(status_code=400, detail="Missing Stripe signature")
503
+
504
+ try:
505
+ stripe_service = get_stripe_service()
506
+ payload = await request.body()
507
+ event = stripe_service.construct_webhook_event(payload, stripe_signature)
508
+ result = stripe_service.handle_webhook_event(event)
509
+
510
+ # TODO: Update database based on result
511
+ # - subscription_created -> update user tier
512
+ # - subscription_deleted -> downgrade to free
513
+ # - payment_failed -> send notification
514
+
515
+ return {"received": True, "action": result.get("action")}
516
+
517
+ except ValueError as e:
518
+ raise HTTPException(status_code=400, detail=f"Invalid payload: {e}")
519
+ except Exception as e:
520
+ raise HTTPException(status_code=400, detail=f"Webhook error: {e}")
@@ -0,0 +1,33 @@
1
+ """QuantumFlow Backends - Quantum hardware and simulator backends."""
2
+
3
+ from quantumflow.backends.base_backend import (
4
+ QuantumBackend,
5
+ BackendType,
6
+ ExecutionResult,
7
+ get_backend,
8
+ )
9
+ from quantumflow.backends.simulator_backend import SimulatorBackend
10
+
11
+ # Lazy import for optional IBM backend
12
+ try:
13
+ from quantumflow.backends.ibm_backend import IBMBackend
14
+ except ImportError:
15
+ IBMBackend = None # type: ignore
16
+
17
+ # Lazy import for optional AWS Braket backend
18
+ try:
19
+ from quantumflow.backends.braket_backend import BraketBackend, BRAKET_DEVICES
20
+ except ImportError:
21
+ BraketBackend = None # type: ignore
22
+ BRAKET_DEVICES = {}
23
+
24
+ __all__ = [
25
+ "QuantumBackend",
26
+ "BackendType",
27
+ "ExecutionResult",
28
+ "get_backend",
29
+ "SimulatorBackend",
30
+ "IBMBackend",
31
+ "BraketBackend",
32
+ "BRAKET_DEVICES",
33
+ ]