quantlix 0.1.0__tar.gz

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 (44) hide show
  1. quantlix-0.1.0/LICENSE +21 -0
  2. quantlix-0.1.0/PKG-INFO +107 -0
  3. quantlix-0.1.0/README.md +68 -0
  4. quantlix-0.1.0/api/__init__.py +1 -0
  5. quantlix-0.1.0/api/auth.py +81 -0
  6. quantlix-0.1.0/api/config.py +61 -0
  7. quantlix-0.1.0/api/db.py +38 -0
  8. quantlix-0.1.0/api/disposable_domains.py +499 -0
  9. quantlix-0.1.0/api/email.py +202 -0
  10. quantlix-0.1.0/api/main.py +83 -0
  11. quantlix-0.1.0/api/models.py +142 -0
  12. quantlix-0.1.0/api/queue.py +23 -0
  13. quantlix-0.1.0/api/rate_limit.py +178 -0
  14. quantlix-0.1.0/api/routes/__init__.py +1 -0
  15. quantlix-0.1.0/api/routes/auth.py +477 -0
  16. quantlix-0.1.0/api/routes/billing.py +234 -0
  17. quantlix-0.1.0/api/routes/deploy.py +34 -0
  18. quantlix-0.1.0/api/routes/health.py +20 -0
  19. quantlix-0.1.0/api/routes/jobs.py +43 -0
  20. quantlix-0.1.0/api/routes/run.py +76 -0
  21. quantlix-0.1.0/api/routes/status.py +63 -0
  22. quantlix-0.1.0/api/routes/usage.py +143 -0
  23. quantlix-0.1.0/api/schemas.py +252 -0
  24. quantlix-0.1.0/api/usage_service.py +82 -0
  25. quantlix-0.1.0/cli/__init__.py +1 -0
  26. quantlix-0.1.0/cli/main.py +367 -0
  27. quantlix-0.1.0/orchestrator/__init__.py +1 -0
  28. quantlix-0.1.0/orchestrator/config.py +28 -0
  29. quantlix-0.1.0/orchestrator/inference_client.py +38 -0
  30. quantlix-0.1.0/orchestrator/k8s.py +124 -0
  31. quantlix-0.1.0/orchestrator/main.py +43 -0
  32. quantlix-0.1.0/orchestrator/worker.py +192 -0
  33. quantlix-0.1.0/pyproject.toml +55 -0
  34. quantlix-0.1.0/quantlix.egg-info/PKG-INFO +107 -0
  35. quantlix-0.1.0/quantlix.egg-info/SOURCES.txt +42 -0
  36. quantlix-0.1.0/quantlix.egg-info/dependency_links.txt +1 -0
  37. quantlix-0.1.0/quantlix.egg-info/entry_points.txt +2 -0
  38. quantlix-0.1.0/quantlix.egg-info/requires.txt +20 -0
  39. quantlix-0.1.0/quantlix.egg-info/top_level.txt +4 -0
  40. quantlix-0.1.0/sdk/__init__.py +1 -0
  41. quantlix-0.1.0/sdk/python/__init__.py +24 -0
  42. quantlix-0.1.0/sdk/quantlix/__init__.py +21 -0
  43. quantlix-0.1.0/sdk/quantlix/client.py +311 -0
  44. quantlix-0.1.0/setup.cfg +4 -0
quantlix-0.1.0/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2025 Quantlix
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
@@ -0,0 +1,107 @@
1
+ Metadata-Version: 2.4
2
+ Name: quantlix
3
+ Version: 0.1.0
4
+ Summary: Quantlix — AI-focused GPU inference platform
5
+ Author: Quantlix
6
+ License: MIT
7
+ Project-URL: Homepage, https://quantlix.ai
8
+ Project-URL: Repository, https://github.com/quantlix/cloud
9
+ Project-URL: Documentation, https://github.com/quantlix/cloud#readme
10
+ Keywords: ai,inference,gpu,ml,deployment
11
+ Classifier: Development Status :: 4 - Beta
12
+ Classifier: Intended Audience :: Developers
13
+ Classifier: License :: OSI Approved :: MIT License
14
+ Classifier: Programming Language :: Python :: 3
15
+ Classifier: Programming Language :: Python :: 3.12
16
+ Requires-Python: >=3.12
17
+ Description-Content-Type: text/markdown
18
+ License-File: LICENSE
19
+ Requires-Dist: typer[all]>=0.9.0
20
+ Requires-Dist: python-dotenv>=1.0.0
21
+ Requires-Dist: httpx>=0.26.0
22
+ Requires-Dist: rich>=13.0.0
23
+ Provides-Extra: full
24
+ Requires-Dist: fastapi>=0.109.0; extra == "full"
25
+ Requires-Dist: uvicorn[standard]>=0.27.0; extra == "full"
26
+ Requires-Dist: sqlalchemy[asyncio]>=2.0.0; extra == "full"
27
+ Requires-Dist: asyncpg>=0.29.0; extra == "full"
28
+ Requires-Dist: greenlet>=3.0.0; extra == "full"
29
+ Requires-Dist: psycopg[binary]>=3.0.0; extra == "full"
30
+ Requires-Dist: redis>=5.0.0; extra == "full"
31
+ Requires-Dist: minio>=7.2.0; extra == "full"
32
+ Requires-Dist: python-jose[cryptography]>=3.3.0; extra == "full"
33
+ Requires-Dist: bcrypt>=4.0.0; extra == "full"
34
+ Requires-Dist: pydantic-settings>=2.1.0; extra == "full"
35
+ Requires-Dist: prometheus-client>=0.19.0; extra == "full"
36
+ Requires-Dist: aiosmtplib>=3.0.0; extra == "full"
37
+ Requires-Dist: stripe>=8.0.0; extra == "full"
38
+ Dynamic: license-file
39
+
40
+ # Quantlix
41
+
42
+ Deploy AI models in seconds. A simple inference platform with REST API, usage-based billing, and Kubernetes orchestration.
43
+
44
+ ## Features
45
+
46
+ - **REST API** — Deploy models, run inference, check status
47
+ - **Usage-based billing** — Free, Starter (€9/mo), Pro (€19/mo) tiers with Stripe
48
+ - **Queue & orchestration** — Redis queue, K8s job scheduling
49
+ - **Customer portal** — Next.js dashboard, usage graphs, real-time logs
50
+ - **CLI** — `quantlix deploy`, `quantlix run` for local dev
51
+
52
+ ## Quick start
53
+
54
+ ```bash
55
+ # 1. Clone and start services
56
+ git clone https://github.com/quantlix/cloud
57
+ cd cloud
58
+ cp .env.example .env
59
+ docker compose up -d
60
+
61
+ # 2. Create account (or use dev seed)
62
+ pip install -e .
63
+ quantlix signup --email you@example.com --password YourSecurePassword123!
64
+ # Verify email, then:
65
+ quantlix login --email you@example.com --password YourSecurePassword123!
66
+
67
+ # 3. Deploy and run
68
+ quantlix deploy qx-example
69
+ quantlix run <deployment_id> -i '{"prompt": "Hello!"}'
70
+ ```
71
+
72
+ See [docs/CLI_GUIDE.md](docs/CLI_GUIDE.md) for detailed setup.
73
+
74
+ ## Architecture
75
+
76
+ ```
77
+ ┌─────────────┐ ┌─────────┐ ┌──────────────┐
78
+ │ Portal │────▶│ API │────▶│ PostgreSQL │
79
+ │ (Next.js) │ │(FastAPI)│ │ Redis │
80
+ └─────────────┘ └────┬────┘ └──────────────┘
81
+
82
+
83
+ ┌──────────────┐
84
+ │ Orchestrator │────▶ Kubernetes / Inference
85
+ │ (Worker) │
86
+ └──────────────┘
87
+ ```
88
+
89
+ ## Project structure
90
+
91
+ | Directory | Description |
92
+ |-----------|-------------|
93
+ | `api/` | FastAPI backend (auth, deploy, run, billing, usage) |
94
+ | `portal/` | Next.js customer dashboard |
95
+ | `orchestrator/` | Redis queue worker, K8s job runner |
96
+ | `inference/` | Mock inference service (replace with your model server) |
97
+ | `sdk/` | Python client library |
98
+ | `cli/` | `quantlix` CLI |
99
+ | `infra/` | Terraform (Hetzner), Kubernetes manifests |
100
+
101
+ ## Production
102
+
103
+ See [docs/GO_LIVE.md](docs/GO_LIVE.md) for the full deployment checklist: Stripe, SMTP, DNS, SSL, secrets.
104
+
105
+ ## License
106
+
107
+ MIT — see [LICENSE](LICENSE).
@@ -0,0 +1,68 @@
1
+ # Quantlix
2
+
3
+ Deploy AI models in seconds. A simple inference platform with REST API, usage-based billing, and Kubernetes orchestration.
4
+
5
+ ## Features
6
+
7
+ - **REST API** — Deploy models, run inference, check status
8
+ - **Usage-based billing** — Free, Starter (€9/mo), Pro (€19/mo) tiers with Stripe
9
+ - **Queue & orchestration** — Redis queue, K8s job scheduling
10
+ - **Customer portal** — Next.js dashboard, usage graphs, real-time logs
11
+ - **CLI** — `quantlix deploy`, `quantlix run` for local dev
12
+
13
+ ## Quick start
14
+
15
+ ```bash
16
+ # 1. Clone and start services
17
+ git clone https://github.com/quantlix/cloud
18
+ cd cloud
19
+ cp .env.example .env
20
+ docker compose up -d
21
+
22
+ # 2. Create account (or use dev seed)
23
+ pip install -e .
24
+ quantlix signup --email you@example.com --password YourSecurePassword123!
25
+ # Verify email, then:
26
+ quantlix login --email you@example.com --password YourSecurePassword123!
27
+
28
+ # 3. Deploy and run
29
+ quantlix deploy qx-example
30
+ quantlix run <deployment_id> -i '{"prompt": "Hello!"}'
31
+ ```
32
+
33
+ See [docs/CLI_GUIDE.md](docs/CLI_GUIDE.md) for detailed setup.
34
+
35
+ ## Architecture
36
+
37
+ ```
38
+ ┌─────────────┐ ┌─────────┐ ┌──────────────┐
39
+ │ Portal │────▶│ API │────▶│ PostgreSQL │
40
+ │ (Next.js) │ │(FastAPI)│ │ Redis │
41
+ └─────────────┘ └────┬────┘ └──────────────┘
42
+
43
+
44
+ ┌──────────────┐
45
+ │ Orchestrator │────▶ Kubernetes / Inference
46
+ │ (Worker) │
47
+ └──────────────┘
48
+ ```
49
+
50
+ ## Project structure
51
+
52
+ | Directory | Description |
53
+ |-----------|-------------|
54
+ | `api/` | FastAPI backend (auth, deploy, run, billing, usage) |
55
+ | `portal/` | Next.js customer dashboard |
56
+ | `orchestrator/` | Redis queue worker, K8s job runner |
57
+ | `inference/` | Mock inference service (replace with your model server) |
58
+ | `sdk/` | Python client library |
59
+ | `cli/` | `quantlix` CLI |
60
+ | `infra/` | Terraform (Hetzner), Kubernetes manifests |
61
+
62
+ ## Production
63
+
64
+ See [docs/GO_LIVE.md](docs/GO_LIVE.md) for the full deployment checklist: Stripe, SMTP, DNS, SSL, secrets.
65
+
66
+ ## License
67
+
68
+ MIT — see [LICENSE](LICENSE).
@@ -0,0 +1 @@
1
+ """Quantlix API."""
@@ -0,0 +1,81 @@
1
+ """API key and password authentication."""
2
+ import hashlib
3
+ from typing import Annotated
4
+
5
+ import bcrypt
6
+ from fastapi import Depends, HTTPException, status
7
+ from fastapi.security import APIKeyHeader
8
+ from sqlalchemy import select
9
+ from sqlalchemy.ext.asyncio import AsyncSession
10
+
11
+ from api.db import get_db
12
+ from api.models import APIKey, User
13
+
14
+
15
+ api_key_header = APIKeyHeader(name="X-API-Key", auto_error=False)
16
+
17
+
18
+ def hash_password(password: str) -> str:
19
+ """Hash password with bcrypt."""
20
+ return bcrypt.hashpw(password.encode(), bcrypt.gensalt()).decode()
21
+
22
+
23
+ def verify_password(plain: str, hashed: str) -> bool:
24
+ """Verify password against hash."""
25
+ return bcrypt.checkpw(plain.encode(), hashed.encode())
26
+
27
+
28
+ def hash_api_key(key: str) -> str:
29
+ """Hash API key for storage (never store plain)."""
30
+ return hashlib.sha256(key.encode()).hexdigest()
31
+
32
+
33
+ async def get_user_from_api_key(
34
+ api_key: Annotated[str | None, Depends(api_key_header)],
35
+ db: Annotated[AsyncSession, Depends(get_db)],
36
+ ) -> User:
37
+ """Resolve API key to user. Raises 401 if invalid or missing."""
38
+ if not api_key or not api_key.strip():
39
+ raise HTTPException(
40
+ status_code=status.HTTP_401_UNAUTHORIZED,
41
+ detail="Missing API key. Provide X-API-Key header.",
42
+ )
43
+ key_hash = hash_api_key(api_key.strip())
44
+ result = await db.execute(
45
+ select(APIKey).where(APIKey.key_hash == key_hash)
46
+ )
47
+ api_key_row = result.scalar_one_or_none()
48
+ if not api_key_row:
49
+ raise HTTPException(
50
+ status_code=status.HTTP_401_UNAUTHORIZED,
51
+ detail="Invalid API key.",
52
+ )
53
+ result = await db.execute(select(User).where(User.id == api_key_row.user_id))
54
+ user = result.scalar_one()
55
+ return user
56
+
57
+
58
+ async def get_current_api_key(
59
+ api_key: Annotated[str | None, Depends(api_key_header)],
60
+ db: Annotated[AsyncSession, Depends(get_db)],
61
+ ) -> APIKey:
62
+ """Resolve API key header to APIKey row. Raises 401 if invalid. For rotate/revoke flows."""
63
+ if not api_key or not api_key.strip():
64
+ raise HTTPException(
65
+ status_code=status.HTTP_401_UNAUTHORIZED,
66
+ detail="Missing API key. Provide X-API-Key header.",
67
+ )
68
+ key_hash = hash_api_key(api_key.strip())
69
+ result = await db.execute(select(APIKey).where(APIKey.key_hash == key_hash))
70
+ api_key_row = result.scalar_one_or_none()
71
+ if not api_key_row:
72
+ raise HTTPException(
73
+ status_code=status.HTTP_401_UNAUTHORIZED,
74
+ detail="Invalid API key.",
75
+ )
76
+ return api_key_row
77
+
78
+
79
+ # Type aliases for route dependencies
80
+ CurrentUser = Annotated[User, Depends(get_user_from_api_key)]
81
+ CurrentAPIKey = Annotated[APIKey, Depends(get_current_api_key)]
@@ -0,0 +1,61 @@
1
+ """Application configuration."""
2
+ from pydantic import ConfigDict
3
+ from pydantic_settings import BaseSettings
4
+
5
+
6
+ class Settings(BaseSettings):
7
+ model_config = ConfigDict(
8
+ extra="ignore",
9
+ env_file=".env",
10
+ env_file_encoding="utf-8",
11
+ )
12
+
13
+ postgres_host: str = "localhost"
14
+ postgres_port: int = 5432
15
+ postgres_user: str = "cloud"
16
+ postgres_password: str = "cloud_secret"
17
+ postgres_db: str = "cloud"
18
+ redis_url: str = "redis://localhost:6379/0"
19
+ minio_endpoint: str = "localhost:9000"
20
+ minio_access_key: str = "minioadmin"
21
+ minio_secret_key: str = "minioadmin"
22
+ minio_bucket: str = "models"
23
+ jwt_secret: str = "dev-secret-change-me"
24
+
25
+ # Email (Sweego). Set to False to disable all email until domain is verified.
26
+ # Use SWEEGO_API_KEY for HTTP API (recommended in K8s; avoids SMTP port blocking).
27
+ # Otherwise use SMTP with smtp_user/smtp_password.
28
+ email_enabled: bool = True
29
+ sweego_api_key: str = "" # When set, use Sweego HTTP API instead of SMTP
30
+ sweego_auth_type: str = "api_token" # "api_token" (Api-Token), "api_key" (Api-Key), or "bearer" (Authorization: Bearer)
31
+ smtp_host: str = "smtp.sweego.io"
32
+ smtp_port: int = 587
33
+ smtp_user: str = ""
34
+ smtp_password: str = ""
35
+ smtp_from_email: str = "support@quantlix.ai"
36
+ smtp_from_name: str = "Quantlix"
37
+ app_base_url: str = "https://api.quantlix.ai" # For verification links
38
+ portal_base_url: str = "https://app.quantlix.ai" # For Stripe redirects
39
+ dev_return_verification_link: bool = False # If True, include verification link in signup response (for local testing)
40
+
41
+ # Usage limits (0 = unlimited)
42
+ usage_limit_tokens_per_month: int = 0
43
+ usage_limit_compute_seconds_per_month: float = 0.0
44
+
45
+ # CORS (comma-separated extra origins, e.g. for Vercel: https://quantlix.vercel.app)
46
+ cors_origins: str = ""
47
+
48
+ # Stripe
49
+ stripe_secret_key: str = ""
50
+ stripe_webhook_secret: str = ""
51
+ stripe_price_id_starter: str = "" # Price ID for Starter €9/mo
52
+ stripe_price_id_pro: str = "" # Price ID for Pro plan (e.g. price_xxx)
53
+
54
+ @property
55
+ def database_url(self) -> str:
56
+ return (
57
+ f"postgresql+asyncpg://{self.postgres_user}:{self.postgres_password}"
58
+ f"@{self.postgres_host}:{self.postgres_port}/{self.postgres_db}"
59
+ )
60
+
61
+ settings = Settings()
@@ -0,0 +1,38 @@
1
+ """Database setup and session management."""
2
+ from collections.abc import AsyncGenerator
3
+
4
+ from sqlalchemy.ext.asyncio import AsyncSession, async_sessionmaker, create_async_engine
5
+ from sqlalchemy.orm import DeclarativeBase
6
+
7
+ from api.config import settings
8
+
9
+
10
+ class Base(DeclarativeBase):
11
+ """SQLAlchemy declarative base."""
12
+
13
+
14
+ engine = create_async_engine(
15
+ settings.database_url,
16
+ echo=False,
17
+ )
18
+
19
+ async_session_maker = async_sessionmaker(
20
+ engine,
21
+ class_=AsyncSession,
22
+ expire_on_commit=False,
23
+ autocommit=False,
24
+ autoflush=False,
25
+ )
26
+
27
+
28
+ async def get_db() -> AsyncGenerator[AsyncSession, None]:
29
+ """Dependency for async DB session."""
30
+ async with async_session_maker() as session:
31
+ try:
32
+ yield session
33
+ await session.commit()
34
+ except Exception:
35
+ await session.rollback()
36
+ raise
37
+ finally:
38
+ await session.close()