qubrid 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.
@@ -0,0 +1,26 @@
1
+ name: tests
2
+
3
+ on:
4
+ push:
5
+ branches: [main]
6
+ pull_request:
7
+
8
+ jobs:
9
+ test:
10
+ runs-on: ubuntu-latest
11
+ strategy:
12
+ matrix:
13
+ python-version: ["3.9", "3.11", "3.12"]
14
+ steps:
15
+ - uses: actions/checkout@v4
16
+ - uses: actions/setup-python@v5
17
+ with:
18
+ python-version: ${{ matrix.python-version }}
19
+ - name: Install
20
+ run: pip install -e ".[dev]"
21
+ - name: Lint
22
+ run: ruff check src tests examples
23
+ - name: Format check
24
+ run: ruff format --check src tests examples
25
+ - name: Tests
26
+ run: python -m pytest tests/ -q
@@ -0,0 +1,9 @@
1
+ __pycache__/
2
+ *.egg-info/
3
+ dist/
4
+ build/
5
+ .venv/
6
+ .pytest_cache/
7
+ .ruff_cache/
8
+ qubrid-docs/
9
+ qubrid-examples/
qubrid-0.1.0/AGENTS.md ADDED
@@ -0,0 +1,27 @@
1
+ # AGENTS.md
2
+
3
+ First-party Python SDK for Qubrid AI inference (`qubrid` on PyPI). Standalone: `httpx` + `pydantic` only — never add an `openai` dependency.
4
+
5
+ ## Commands
6
+
7
+ - Install (editable + dev): `pip install -e ".[dev]"`
8
+ - Tests: `python -m pytest tests/ -q` (27 tests, `respx`-mocked HTTP — no network/key needed)
9
+ - Lint: `ruff check src tests` · Format: `ruff format src tests`
10
+ - `Optional[...]` is deliberate (py39 runtime compat for pydantic); `UP006/7/35/45` are silenced in `pyproject.toml` — do not "modernize" to `X | None`.
11
+
12
+ ## Architecture
13
+
14
+ - `src/qubrid/client.py` — `QubridClient` / `AsyncQubridClient` (env `QUBRID_API_KEY`, `base_url` + `legacy_base_url`, `timeout`, `max_retries`). Owns one `httpx` client; resources are thin wrappers over it.
15
+ - `src/qubrid/_http.py` — retry-with-backoff on 429/5xx (honors `Retry-After`), error mapping, SSE `data:` parsing. Sync/async parity lives here.
16
+ - `src/qubrid/_types.py` — pydantic models mirroring `QubridAI-Inc/docs` `api-reference/*/openapi.json`. Model IDs are plain `str` (catalog churns).
17
+ - Resources: `chat.py` (`POST /chat/completions`, streaming + not), `vision_ocr.py` (same path, docs-example defaults), `audio.py` (TTS on `/v1`, STT multipart auto-routed to legacy `/api/v1/qubridai`), `extra.py` (embeddings/images/video).
18
+ - `src/qubrid/exceptions.py` — `QubridError` + typed subclasses carrying `status_code/code/type/param/request_id/body`.
19
+
20
+ ## Gotchas (verified vs docs repo + examples repo, 2026-09-08)
21
+
22
+ - Two live prefixes: canonical `https://platform.qubrid.com/v1`, legacy `.../api/v1/qubridai` for STT **only**. Do not mix field names across them.
23
+ - Embeddings has **no** Qubrid OpenAPI spec — `embeddings.create` is an explicitly experimental OpenAI-compatible passthrough (user-approved). Flag shape changes.
24
+ - Image-edits has no OpenAPI file (quickstarts only): local files → multipart, remote URLs → JSON `images:[...]`. Video accepts both `url` and `video_url` (`resolved_url`).
25
+ - No REST API exists for RAG / fine-tuning / GPU provisioning / models listing (UI-only) — do not invent endpoints; raise/flag instead.
26
+ - `api-reference/endpoint/` (`/plants`) is a Mintlify template placeholder, not real.
27
+ - OCR default `tencent/HunyuanOCR` (live-verified 2026-09-08; examples' `Hunyuan/Hunyuan-OCR-1B` 404s `model_not_found`).
@@ -0,0 +1,26 @@
1
+ # Changelog
2
+
3
+ All notable changes to the `qubrid` package. Format follows [Keep a Changelog](https://keepachangelog.com/en/1.0.0/).
4
+
5
+ ## [0.1.0] — 2026-09-08
6
+
7
+ ### Added
8
+ - Initial standalone SDK (`httpx` + `pydantic`, no `openai` dependency).
9
+ - `QubridClient` / `AsyncQubridClient` with `QUBRID_API_KEY` env fallback, `base_url` + `legacy_base_url` overrides, configurable timeout/retries.
10
+ - `chat.completions.create` (streaming SSE generator + non-streaming), live-verified vs `api-reference/chat/openapi.json`.
11
+ - `vision.analyze`, `ocr.extract` thin wrappers over `/chat/completions`, live-verified (OCR default corrected to `tencent/HunyuanOCR` — examples' `Hunyuan/Hunyuan-OCR-1B` 404s).
12
+ - `audio.transcriptions.create` (STT multipart, auto-routed to legacy `/api/v1/qubridai/audio/transcribe`), live-verified.
13
+ - `audio.speech.create` (TTS `POST /audio/generations`), `images.generate` / `images.edit`, `videos.generate` (accepts both `url` and `video_url`), `embeddings.create` — retained per-spec but **not working live** (see Fixed/Unverified below).
14
+ - Typed errors (`AuthenticationError`, `RateLimitError`, `InvalidRequestError`, … with `code`/`request_id`/`body`), retry-with-backoff on 429/5xx.
15
+ - Mocked test suite (`respx`), README quickstart + per-category examples.
16
+
17
+ ### Live-verification findings (2026-09-08 smoke test, ~$0.0005 spend)
18
+ - Fixed: OCR default `Hunyuan/Hunyuan-OCR-1B` → `tencent/HunyuanOCR` (former is 404 `model_not_found` live; latter verified 200 with usage 1699/17).
19
+ - Unverified: TTS returns `400 content_policy_violation` on all tested inputs including the docs' own example sentence; `images/generations` returns `405 Method Not Allowed` despite exact spec match (`images.edit`, `videos.generate` deliberately untested, same family); `POST /v1/embeddings` is 404 with empty body (endpoint doesn't exist).
20
+
21
+ ### Final verification (2026-09-08, v0.1.0 polish)
22
+ - Live-verified end-to-end against the real Qubrid API: chat (streaming + non-streaming), vision, OCR (corrected default `tencent/HunyuanOCR`), STT.
23
+ - Confirmed non-functional: embeddings (endpoint doesn't exist, 404 with empty body); images/video generation (`405 Method Not Allowed` despite exact OpenAPI spec match — likely account/region routing issue on Qubrid's side; siblings untested by decision); TTS (reachable, request shape accepted, but safety filter rejected all tested inputs including Qubrid's own documented example sentence).
24
+ - Clean-room install verified: fresh venv, non-editable `pip install`, import + live quickstart call succeeded from outside the source tree.
25
+ - Total live-testing spend across the full verification effort: ~$0.0006.
26
+ - Docs-only fixes: streaming example guards against `None` deltas; README notes Windows console unicode quirk (`PYTHONIOENCODING=utf-8`). No core SDK logic changed.
qubrid-0.1.0/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 Qubrid AI Community SDK
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.
qubrid-0.1.0/PKG-INFO ADDED
@@ -0,0 +1,190 @@
1
+ Metadata-Version: 2.5
2
+ Name: qubrid
3
+ Version: 0.1.0
4
+ Summary: First-party Python SDK for Qubrid AI GPU-accelerated inference (chat, vision, OCR, TTS, STT, images, video, embeddings)
5
+ Project-URL: Homepage, https://platform.qubrid.com
6
+ Project-URL: Documentation, https://github.com/QubridAI-Inc/docs
7
+ Project-URL: Repository, https://github.com/QubridAI-Inc/qubrid-examples
8
+ Project-URL: Changelog, https://github.com/Abhi-shek26/python-sdk-buildup/blob/main/CHANGELOG.md
9
+ Author-email: Qubrid AI Community SDK <support@qubrid.com>
10
+ License: MIT
11
+ License-File: LICENSE
12
+ Keywords: ai,chat,inference,llm,qubrid,sdk,stt,tts,vision
13
+ Classifier: Development Status :: 4 - Beta
14
+ Classifier: Intended Audience :: Developers
15
+ Classifier: License :: OSI Approved :: MIT License
16
+ Classifier: Programming Language :: Python :: 3
17
+ Classifier: Programming Language :: Python :: 3.9
18
+ Classifier: Programming Language :: Python :: 3.10
19
+ Classifier: Programming Language :: Python :: 3.11
20
+ Classifier: Programming Language :: Python :: 3.12
21
+ Classifier: Topic :: Scientific/Engineering :: Artificial Intelligence
22
+ Requires-Python: >=3.9
23
+ Requires-Dist: httpx<1,>=0.27
24
+ Requires-Dist: pydantic>=2.0
25
+ Provides-Extra: dev
26
+ Requires-Dist: mypy>=1.0; extra == 'dev'
27
+ Requires-Dist: pytest-asyncio>=0.23; extra == 'dev'
28
+ Requires-Dist: pytest>=8; extra == 'dev'
29
+ Requires-Dist: respx>=0.22; extra == 'dev'
30
+ Requires-Dist: ruff>=0.4; extra == 'dev'
31
+ Description-Content-Type: text/markdown
32
+
33
+ # Qubrid Python SDK — `qubrid`
34
+
35
+ First-party, standalone Python client for [Qubrid AI](https://platform.qubrid.com) GPU-accelerated inference. No `openai` dependency (`httpx` + `pydantic` only).
36
+
37
+ **Docs truth:** endpoint shapes verified against [`QubridAI-Inc/docs`](https://github.com/QubridAI-Inc/docs) (`api-reference/*/openapi.json`) and runnable payloads in [`QubridAI-Inc/qubrid-examples`](https://github.com/QubridAI-Inc/qubrid-examples).
38
+
39
+ | Resource | Endpoint | Base |
40
+ |---|---|---|
41
+ | `client.chat.completions` | `POST /chat/completions` (OpenAI-compatible, `stream` supported) | `…/v1` |
42
+ | `client.vision` | same `POST /chat/completions` (image_url parts) | `…/v1` |
43
+ | `client.ocr` | same `POST /chat/completions` (default `tencent/HunyuanOCR`, live-verified) | `…/v1` |
44
+ | `client.audio.speech` (TTS) | `POST /audio/generations` `{model,text,voice,language_type}` | `…/v1` |
45
+ | `client.audio.transcriptions` (STT) | `POST /audio/transcribe` multipart `{file,model}` | `…/api/v1/qubridai` (legacy — auto-routed) |
46
+ | `client.images` | `POST /images/generations`, `POST /images/edits` | `…/v1` |
47
+ | `client.videos` | `POST /videos/generations` | `…/v1` |
48
+ | `client.embeddings` | `POST /embeddings` — ⚠️ **EXPERIMENTAL**, no Qubrid OpenAPI spec | `…/v1` |
49
+
50
+ **Not in the SDK (no documented REST API — UI-only):** RAG (beta upload + Chat UI), no-code Fine-Tuning studio, GPU Instances/Clusters/Bare-Metal provisioning, models listing (`GET /models`). Model IDs are plain `str` (catalog of 100+ changes often — never an enum).
51
+
52
+ ## Live verification status (smoke-tested 2026-09-08)
53
+
54
+ Confirmed working end-to-end: chat (+ streaming), vision, OCR (default `tencent/HunyuanOCR`), STT.
55
+
56
+ - **TTS — unverified:** endpoint reachable, shape accepted, but the safety filter rejected every tested input (`400 content_policy_violation`), including the docs' own example sentence.
57
+ - **Images / video — currently unroutable:** `POST /v1/images/generations` returns `405 Method Not Allowed` despite matching the OpenAPI spec exactly; `images.edit` / `videos.generate` untested (same family, deliberately not probed). Code retained per-spec; treat as unstable.
58
+ - **Embeddings — doesn't exist:** `POST /v1/embeddings` returns 404 with an empty body. The method is kept as an experimental stub only.
59
+
60
+ ## Install
61
+
62
+ ```bash
63
+ pip install qubrid
64
+ # or from source:
65
+ pip install -e ".[dev]"
66
+ ```
67
+
68
+ Requires Python 3.9+, `QUBRID_API_KEY` from https://platform.qubrid.com/api-keys:
69
+
70
+ ```bash
71
+ export QUBRID_API_KEY="qb_..."
72
+ ```
73
+
74
+ ## Quickstart
75
+
76
+ ```python
77
+ from qubrid import QubridClient
78
+
79
+ client = QubridClient() # reads QUBRID_API_KEY
80
+
81
+ resp = client.chat.completions.create(
82
+ model="openai/gpt-oss-120b",
83
+ messages=[{"role": "user", "content": "Summarize this ticket into next steps."}],
84
+ max_tokens=4096,
85
+ temperature=0.7,
86
+ )
87
+ print(resp.content)
88
+ print(resp.usage.total_tokens)
89
+
90
+ # Streaming
91
+ for chunk in client.chat.completions.create(
92
+ model="deepseek-ai/DeepSeek-V3.2",
93
+ messages=[{"role": "user", "content": "Write a haiku about GPUs."}],
94
+ stream=True,
95
+ ):
96
+ print(chunk.delta, end="", flush=True)
97
+
98
+ # Async
99
+ import asyncio
100
+ from qubrid import AsyncQubridClient
101
+
102
+ async def main():
103
+ async with AsyncQubridClient() as c:
104
+ r = await c.chat.completions.create(
105
+ model="openai/gpt-oss-120b", messages=[{"role": "user", "content": "Hi"}])
106
+ print(r.content)
107
+
108
+ asyncio.run(main())
109
+ ```
110
+
111
+ ## One example per category
112
+
113
+ ```python
114
+ # Vision (Qwen/Qwen3-VL-Plus + image_url parts)
115
+ v = client.vision.analyze(
116
+ prompt="What is in this image?",
117
+ image_urls="https://cdn.britannica.com/61/93061-050-99147DCE/Statue-of-Liberty-Island-New-York-Bay.jpg",
118
+ )
119
+ print(v.content)
120
+
121
+ # OCR (default tencent/HunyuanOCR — live-verified; examples' Hunyuan/Hunyuan-OCR-1B 404s)
122
+ o = client.ocr.extract(image_urls="https://example.com/receipt.jpg")
123
+ print(o.content)
124
+
125
+ # TTS → hosted mp3 URL
126
+ s = client.audio.speech.create(text="Today is a wonderful day to build something people love!",
127
+ voice="Cherry", language_type="Auto")
128
+ print(s.url)
129
+
130
+ # STT (multipart upload, auto-routed to legacy prefix)
131
+ t = client.audio.transcriptions.create(model="openai/whisper-large-v3", file="clip.wav")
132
+ print(t.text)
133
+
134
+ # Images
135
+ img = client.images.generate(model="p-image", prompt="a lighthouse at dusk",
136
+ aspect_ratio="16:9", output_format="webp")
137
+ print(img.data[0].url)
138
+ edit = client.images.edit(model="p-image-edit", prompt="add a red flag",
139
+ image="https://example.com/in.png")
140
+
141
+ # Video (only documented model: p-video, ≤10s)
142
+ vid = client.videos.generate(model="p-video", prompt="ocean waves", duration=5)
143
+ print(vid.url)
144
+
145
+ # Embeddings — EXPERIMENTAL passthrough (no Qubrid spec; may change)
146
+ e = client.embeddings.create(model="BAAI/bge-large-en-v1.5", input="hello world")
147
+ print(e.data[0].embedding[:4])
148
+ ```
149
+
150
+ More in [`examples/`](examples/).
151
+
152
+ ## Configuration
153
+
154
+ ```python
155
+ QubridClient(
156
+ api_key="qb_...", # or QUBRID_API_KEY env
157
+ base_url="https://platform.qubrid.com/v1", # override canonical
158
+ legacy_base_url="https://platform.qubrid.com/api/v1/qubridai", # STT only
159
+ timeout=60.0, # seconds; per-call `timeout=` also supported
160
+ max_retries=2, # retry-with-backoff on 429/5xx
161
+ )
162
+ ```
163
+
164
+ ## Errors
165
+
166
+ ```python
167
+ from qubrid import QubridError, AuthenticationError, RateLimitError
168
+
169
+ try:
170
+ client.chat.completions.create(model="m", messages=[])
171
+ except AuthenticationError:
172
+ ... # bad/missing key (401)
173
+ except RateLimitError as e:
174
+ print(e.status_code, e.code, e.request_id, e.body)
175
+ except QubridError as e:
176
+ ... # base class: InvalidRequestError, NotFoundError,
177
+ # PermissionDeniedError, QuotaExceededError, ServerError, APIConnectionError
178
+ ```
179
+
180
+ ## Docs & flags
181
+
182
+ - STT lives on the legacy prefix — the client handles it; only override `legacy_base_url` for staging/mocks.
183
+ - Live-verified 2026-09-08: runnable examples' `Hunyuan/Hunyuan-OCR-1B` returns 404 `model_not_found`; the working id is `tencent/HunyuanOCR` (the SDK default).
184
+ - Video quickstart JS reads `data[0].video_url` while the spec says `url` — both accepted (`VideoData.resolved_url`).
185
+ - Image-edit has no OpenAPI file (quickstarts only); local files → multipart, remote URLs → JSON `images:[...]`.
186
+ - Anything under `api-reference/endpoint/` (`/plants`) is a Mintlify template placeholder, not a real API.
187
+
188
+ ## Known environment quirks
189
+
190
+ - **Garbled unicode on Windows terminals:** model output containing emoji, accented characters, or other non-ASCII text may render as `�` in default Windows consoles (e.g. `cmd.exe` / PowerShell with a legacy code page). This is a console-encoding artifact, not an SDK bug — the returned strings are correct. If affected, run with `PYTHONIOENCODING=utf-8` or use a UTF-8-capable terminal (e.g. Windows Terminal).
qubrid-0.1.0/README.md ADDED
@@ -0,0 +1,158 @@
1
+ # Qubrid Python SDK — `qubrid`
2
+
3
+ First-party, standalone Python client for [Qubrid AI](https://platform.qubrid.com) GPU-accelerated inference. No `openai` dependency (`httpx` + `pydantic` only).
4
+
5
+ **Docs truth:** endpoint shapes verified against [`QubridAI-Inc/docs`](https://github.com/QubridAI-Inc/docs) (`api-reference/*/openapi.json`) and runnable payloads in [`QubridAI-Inc/qubrid-examples`](https://github.com/QubridAI-Inc/qubrid-examples).
6
+
7
+ | Resource | Endpoint | Base |
8
+ |---|---|---|
9
+ | `client.chat.completions` | `POST /chat/completions` (OpenAI-compatible, `stream` supported) | `…/v1` |
10
+ | `client.vision` | same `POST /chat/completions` (image_url parts) | `…/v1` |
11
+ | `client.ocr` | same `POST /chat/completions` (default `tencent/HunyuanOCR`, live-verified) | `…/v1` |
12
+ | `client.audio.speech` (TTS) | `POST /audio/generations` `{model,text,voice,language_type}` | `…/v1` |
13
+ | `client.audio.transcriptions` (STT) | `POST /audio/transcribe` multipart `{file,model}` | `…/api/v1/qubridai` (legacy — auto-routed) |
14
+ | `client.images` | `POST /images/generations`, `POST /images/edits` | `…/v1` |
15
+ | `client.videos` | `POST /videos/generations` | `…/v1` |
16
+ | `client.embeddings` | `POST /embeddings` — ⚠️ **EXPERIMENTAL**, no Qubrid OpenAPI spec | `…/v1` |
17
+
18
+ **Not in the SDK (no documented REST API — UI-only):** RAG (beta upload + Chat UI), no-code Fine-Tuning studio, GPU Instances/Clusters/Bare-Metal provisioning, models listing (`GET /models`). Model IDs are plain `str` (catalog of 100+ changes often — never an enum).
19
+
20
+ ## Live verification status (smoke-tested 2026-09-08)
21
+
22
+ Confirmed working end-to-end: chat (+ streaming), vision, OCR (default `tencent/HunyuanOCR`), STT.
23
+
24
+ - **TTS — unverified:** endpoint reachable, shape accepted, but the safety filter rejected every tested input (`400 content_policy_violation`), including the docs' own example sentence.
25
+ - **Images / video — currently unroutable:** `POST /v1/images/generations` returns `405 Method Not Allowed` despite matching the OpenAPI spec exactly; `images.edit` / `videos.generate` untested (same family, deliberately not probed). Code retained per-spec; treat as unstable.
26
+ - **Embeddings — doesn't exist:** `POST /v1/embeddings` returns 404 with an empty body. The method is kept as an experimental stub only.
27
+
28
+ ## Install
29
+
30
+ ```bash
31
+ pip install qubrid
32
+ # or from source:
33
+ pip install -e ".[dev]"
34
+ ```
35
+
36
+ Requires Python 3.9+, `QUBRID_API_KEY` from https://platform.qubrid.com/api-keys:
37
+
38
+ ```bash
39
+ export QUBRID_API_KEY="qb_..."
40
+ ```
41
+
42
+ ## Quickstart
43
+
44
+ ```python
45
+ from qubrid import QubridClient
46
+
47
+ client = QubridClient() # reads QUBRID_API_KEY
48
+
49
+ resp = client.chat.completions.create(
50
+ model="openai/gpt-oss-120b",
51
+ messages=[{"role": "user", "content": "Summarize this ticket into next steps."}],
52
+ max_tokens=4096,
53
+ temperature=0.7,
54
+ )
55
+ print(resp.content)
56
+ print(resp.usage.total_tokens)
57
+
58
+ # Streaming
59
+ for chunk in client.chat.completions.create(
60
+ model="deepseek-ai/DeepSeek-V3.2",
61
+ messages=[{"role": "user", "content": "Write a haiku about GPUs."}],
62
+ stream=True,
63
+ ):
64
+ print(chunk.delta, end="", flush=True)
65
+
66
+ # Async
67
+ import asyncio
68
+ from qubrid import AsyncQubridClient
69
+
70
+ async def main():
71
+ async with AsyncQubridClient() as c:
72
+ r = await c.chat.completions.create(
73
+ model="openai/gpt-oss-120b", messages=[{"role": "user", "content": "Hi"}])
74
+ print(r.content)
75
+
76
+ asyncio.run(main())
77
+ ```
78
+
79
+ ## One example per category
80
+
81
+ ```python
82
+ # Vision (Qwen/Qwen3-VL-Plus + image_url parts)
83
+ v = client.vision.analyze(
84
+ prompt="What is in this image?",
85
+ image_urls="https://cdn.britannica.com/61/93061-050-99147DCE/Statue-of-Liberty-Island-New-York-Bay.jpg",
86
+ )
87
+ print(v.content)
88
+
89
+ # OCR (default tencent/HunyuanOCR — live-verified; examples' Hunyuan/Hunyuan-OCR-1B 404s)
90
+ o = client.ocr.extract(image_urls="https://example.com/receipt.jpg")
91
+ print(o.content)
92
+
93
+ # TTS → hosted mp3 URL
94
+ s = client.audio.speech.create(text="Today is a wonderful day to build something people love!",
95
+ voice="Cherry", language_type="Auto")
96
+ print(s.url)
97
+
98
+ # STT (multipart upload, auto-routed to legacy prefix)
99
+ t = client.audio.transcriptions.create(model="openai/whisper-large-v3", file="clip.wav")
100
+ print(t.text)
101
+
102
+ # Images
103
+ img = client.images.generate(model="p-image", prompt="a lighthouse at dusk",
104
+ aspect_ratio="16:9", output_format="webp")
105
+ print(img.data[0].url)
106
+ edit = client.images.edit(model="p-image-edit", prompt="add a red flag",
107
+ image="https://example.com/in.png")
108
+
109
+ # Video (only documented model: p-video, ≤10s)
110
+ vid = client.videos.generate(model="p-video", prompt="ocean waves", duration=5)
111
+ print(vid.url)
112
+
113
+ # Embeddings — EXPERIMENTAL passthrough (no Qubrid spec; may change)
114
+ e = client.embeddings.create(model="BAAI/bge-large-en-v1.5", input="hello world")
115
+ print(e.data[0].embedding[:4])
116
+ ```
117
+
118
+ More in [`examples/`](examples/).
119
+
120
+ ## Configuration
121
+
122
+ ```python
123
+ QubridClient(
124
+ api_key="qb_...", # or QUBRID_API_KEY env
125
+ base_url="https://platform.qubrid.com/v1", # override canonical
126
+ legacy_base_url="https://platform.qubrid.com/api/v1/qubridai", # STT only
127
+ timeout=60.0, # seconds; per-call `timeout=` also supported
128
+ max_retries=2, # retry-with-backoff on 429/5xx
129
+ )
130
+ ```
131
+
132
+ ## Errors
133
+
134
+ ```python
135
+ from qubrid import QubridError, AuthenticationError, RateLimitError
136
+
137
+ try:
138
+ client.chat.completions.create(model="m", messages=[])
139
+ except AuthenticationError:
140
+ ... # bad/missing key (401)
141
+ except RateLimitError as e:
142
+ print(e.status_code, e.code, e.request_id, e.body)
143
+ except QubridError as e:
144
+ ... # base class: InvalidRequestError, NotFoundError,
145
+ # PermissionDeniedError, QuotaExceededError, ServerError, APIConnectionError
146
+ ```
147
+
148
+ ## Docs & flags
149
+
150
+ - STT lives on the legacy prefix — the client handles it; only override `legacy_base_url` for staging/mocks.
151
+ - Live-verified 2026-09-08: runnable examples' `Hunyuan/Hunyuan-OCR-1B` returns 404 `model_not_found`; the working id is `tencent/HunyuanOCR` (the SDK default).
152
+ - Video quickstart JS reads `data[0].video_url` while the spec says `url` — both accepted (`VideoData.resolved_url`).
153
+ - Image-edit has no OpenAPI file (quickstarts only); local files → multipart, remote URLs → JSON `images:[...]`.
154
+ - Anything under `api-reference/endpoint/` (`/plants`) is a Mintlify template placeholder, not a real API.
155
+
156
+ ## Known environment quirks
157
+
158
+ - **Garbled unicode on Windows terminals:** model output containing emoji, accented characters, or other non-ASCII text may render as `�` in default Windows consoles (e.g. `cmd.exe` / PowerShell with a legacy code page). This is a console-encoding artifact, not an SDK bug — the returned strings are correct. If affected, run with `PYTHONIOENCODING=utf-8` or use a UTF-8-capable terminal (e.g. Windows Terminal).
@@ -0,0 +1,19 @@
1
+ """TTS + STT examples."""
2
+
3
+ from qubrid import QubridClient
4
+
5
+ client = QubridClient()
6
+
7
+ speech = client.audio.speech.create(
8
+ model="qwen3-tts-flash",
9
+ text="Today is a wonderful day to build something people love!",
10
+ voice="Cherry",
11
+ language_type="Auto",
12
+ )
13
+ print(speech.url)
14
+
15
+ transcript = client.audio.transcriptions.create(
16
+ model="openai/whisper-large-v3",
17
+ file="clip.wav", # local path, file object, or (filename, bytes) tuple
18
+ )
19
+ print(transcript.text)
@@ -0,0 +1,27 @@
1
+ """Images, video, embeddings (experimental) examples."""
2
+
3
+ from qubrid import QubridClient
4
+
5
+ client = QubridClient()
6
+
7
+ img = client.images.generate(
8
+ model="p-image",
9
+ prompt="a lighthouse at dusk",
10
+ aspect_ratio="16:9",
11
+ output_format="webp",
12
+ )
13
+ print(img.data[0].url)
14
+
15
+ edit = client.images.edit(
16
+ model="p-image-edit",
17
+ prompt="add a red flag",
18
+ image="https://example.com/in.png", # remote URL → JSON; local path → multipart
19
+ )
20
+ print(edit.data[0].url)
21
+
22
+ vid = client.videos.generate(model="p-video", prompt="ocean waves at sunset", duration=5)
23
+ print(vid.url)
24
+
25
+ # EXPERIMENTAL: no Qubrid OpenAPI spec for embeddings; OpenAI-compatible passthrough.
26
+ emb = client.embeddings.create(model="BAAI/bge-large-en-v1.5", input="hello world")
27
+ print(emb.data[0].embedding[:4])
@@ -0,0 +1,27 @@
1
+ """Qubrid SDK quickstart — chat (non-streaming + streaming)."""
2
+
3
+ from qubrid import QubridClient
4
+
5
+ client = QubridClient() # QUBRID_API_KEY
6
+
7
+ resp = client.chat.completions.create(
8
+ model="openai/gpt-oss-120b",
9
+ messages=[
10
+ {"role": "user", "content": "Summarize this support ticket into bullet-point next steps."}
11
+ ],
12
+ max_tokens=4096,
13
+ temperature=0.7,
14
+ top_p=1,
15
+ )
16
+ print(resp.content)
17
+
18
+ for chunk in client.chat.completions.create(
19
+ model="openai/gpt-oss-120b",
20
+ messages=[{"role": "user", "content": "Write a haiku about GPUs."}],
21
+ stream=True,
22
+ ):
23
+ # Some SSE events carry no text (e.g. role-only first chunk) — skip them
24
+ # so the output doesn't contain literal "None"s.
25
+ if chunk.delta:
26
+ print(chunk.delta, end="", flush=True)
27
+ print()
@@ -0,0 +1,18 @@
1
+ """Vision + OCR examples (docs-example payloads)."""
2
+
3
+ from qubrid import QubridClient
4
+
5
+ client = QubridClient()
6
+
7
+ vision = client.vision.analyze(
8
+ model="Qwen/Qwen3-VL-Plus",
9
+ prompt="What is in this image? Describe the main elements.",
10
+ image_urls="https://cdn.britannica.com/61/93061-050-99147DCE/Statue-of-Liberty-Island-New-York-Bay.jpg",
11
+ )
12
+ print(vision.content)
13
+
14
+ ocr = client.ocr.extract(
15
+ image_urls="https://example.com/receipt.jpg", # replace with a real image URL
16
+ # model="tencent/HunyuanOCR", # default (live-verified)
17
+ )
18
+ print(ocr.content)
@@ -0,0 +1,64 @@
1
+ [build-system]
2
+ requires = ["hatchling"]
3
+ build-backend = "hatchling.build"
4
+
5
+ [project]
6
+ name = "qubrid"
7
+ version = "0.1.0"
8
+ description = "First-party Python SDK for Qubrid AI GPU-accelerated inference (chat, vision, OCR, TTS, STT, images, video, embeddings)"
9
+ readme = "README.md"
10
+ requires-python = ">=3.9"
11
+ license = { text = "MIT" }
12
+ authors = [{ name = "Qubrid AI Community SDK", email = "support@qubrid.com" }]
13
+ keywords = ["qubrid", "ai", "llm", "inference", "sdk", "chat", "vision", "tts", "stt"]
14
+ classifiers = [
15
+ "Development Status :: 4 - Beta",
16
+ "Intended Audience :: Developers",
17
+ "License :: OSI Approved :: MIT License",
18
+ "Programming Language :: Python :: 3",
19
+ "Programming Language :: Python :: 3.9",
20
+ "Programming Language :: Python :: 3.10",
21
+ "Programming Language :: Python :: 3.11",
22
+ "Programming Language :: Python :: 3.12",
23
+ "Topic :: Scientific/Engineering :: Artificial Intelligence",
24
+ ]
25
+ dependencies = [
26
+ "httpx>=0.27,<1",
27
+ "pydantic>=2.0",
28
+ ]
29
+
30
+ [project.urls]
31
+ Homepage = "https://platform.qubrid.com"
32
+ Documentation = "https://github.com/QubridAI-Inc/docs"
33
+ Repository = "https://github.com/QubridAI-Inc/qubrid-examples"
34
+ Changelog = "https://github.com/Abhi-shek26/python-sdk-buildup/blob/main/CHANGELOG.md"
35
+
36
+ [project.optional-dependencies]
37
+ dev = [
38
+ "pytest>=8",
39
+ "pytest-asyncio>=0.23",
40
+ "respx>=0.22",
41
+ "mypy>=1.0",
42
+ "ruff>=0.4",
43
+ ]
44
+
45
+ [tool.hatch.build.targets.wheel]
46
+ packages = ["src/qubrid"]
47
+
48
+ [tool.pytest.ini_options]
49
+ testpaths = ["tests"]
50
+ asyncio_mode = "auto"
51
+
52
+ [tool.ruff]
53
+ target-version = "py39"
54
+ line-length = 100
55
+
56
+ [tool.ruff.lint]
57
+ # Optional[...] kept deliberately: `X | None` breaks at runtime on Python 3.9
58
+ # for pydantic-evaluated annotations, so silence pyupgrade rewrites.
59
+ ignore = ["UP006", "UP007", "UP035", "UP045", "PYI034"]
60
+
61
+ [tool.mypy]
62
+ python_version = "3.9"
63
+ strict = false
64
+ ignore_missing_imports = true