cortexgrid-infer 0.3.7__tar.gz → 0.3.8__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.
- {cortexgrid_infer-0.3.7 → cortexgrid_infer-0.3.8}/PKG-INFO +23 -24
- {cortexgrid_infer-0.3.7 → cortexgrid_infer-0.3.8}/README.md +21 -22
- {cortexgrid_infer-0.3.7 → cortexgrid_infer-0.3.8}/cortexgrid_infer/__init__.py +2 -4
- {cortexgrid_infer-0.3.7 → cortexgrid_infer-0.3.8}/cortexgrid_infer/core.py +5 -10
- {cortexgrid_infer-0.3.7 → cortexgrid_infer-0.3.8}/cortexgrid_infer/importers/base.py +0 -4
- {cortexgrid_infer-0.3.7 → cortexgrid_infer-0.3.8}/cortexgrid_infer/protocols/completion.py +1 -10
- {cortexgrid_infer-0.3.7 → cortexgrid_infer-0.3.8}/cortexgrid_infer/protocols/imaging.py +0 -10
- {cortexgrid_infer-0.3.7 → cortexgrid_infer-0.3.8}/cortexgrid_infer/protocols/meshing.py +0 -10
- {cortexgrid_infer-0.3.7 → cortexgrid_infer-0.3.8}/cortexgrid_infer/protocols/rewriting.py +0 -9
- {cortexgrid_infer-0.3.7 → cortexgrid_infer-0.3.8}/cortexgrid_infer/registry.py +5 -13
- {cortexgrid_infer-0.3.7 → cortexgrid_infer-0.3.8}/cortexgrid_infer/serve_apps/anthropic.py +2 -2
- {cortexgrid_infer-0.3.7 → cortexgrid_infer-0.3.8}/cortexgrid_infer/serve_apps/base.py +5 -7
- {cortexgrid_infer-0.3.7 → cortexgrid_infer-0.3.8}/cortexgrid_infer/serve_apps/gemini/text2image.py +3 -2
- {cortexgrid_infer-0.3.7 → cortexgrid_infer-0.3.8}/cortexgrid_infer/serve_apps/gemini/text2text.py +3 -2
- {cortexgrid_infer-0.3.7 → cortexgrid_infer-0.3.8}/cortexgrid_infer/serve_apps/image2mesh.py +2 -2
- {cortexgrid_infer-0.3.7 → cortexgrid_infer-0.3.8}/cortexgrid_infer/serve_apps/text2image.py +2 -2
- {cortexgrid_infer-0.3.7 → cortexgrid_infer-0.3.8}/cortexgrid_infer/serve_apps/text2text.py +2 -2
- {cortexgrid_infer-0.3.7 → cortexgrid_infer-0.3.8}/cortexgrid_infer/serve_apps/text_rewriter.py +2 -2
- {cortexgrid_infer-0.3.7 → cortexgrid_infer-0.3.8}/pyproject.toml +2 -2
- {cortexgrid_infer-0.3.7 → cortexgrid_infer-0.3.8}/.gitignore +0 -0
- {cortexgrid_infer-0.3.7 → cortexgrid_infer-0.3.8}/LICENSE +0 -0
- {cortexgrid_infer-0.3.7 → cortexgrid_infer-0.3.8}/cortexgrid_infer/compiling.py +0 -0
- {cortexgrid_infer-0.3.7 → cortexgrid_infer-0.3.8}/cortexgrid_infer/device.py +0 -0
- {cortexgrid_infer-0.3.7 → cortexgrid_infer-0.3.8}/cortexgrid_infer/importers/__init__.py +0 -0
- {cortexgrid_infer-0.3.7 → cortexgrid_infer-0.3.8}/cortexgrid_infer/importers/huggingface.py +0 -0
- {cortexgrid_infer-0.3.7 → cortexgrid_infer-0.3.8}/cortexgrid_infer/protocols/__init__.py +0 -0
- {cortexgrid_infer-0.3.7 → cortexgrid_infer-0.3.8}/cortexgrid_infer/py.typed +0 -0
- {cortexgrid_infer-0.3.7 → cortexgrid_infer-0.3.8}/cortexgrid_infer/serve_apps/__init__.py +0 -0
- {cortexgrid_infer-0.3.7 → cortexgrid_infer-0.3.8}/cortexgrid_infer/serve_apps/gemini/__init__.py +0 -0
- {cortexgrid_infer-0.3.7 → cortexgrid_infer-0.3.8}/cortexgrid_infer/serve_apps/gemini/base.py +0 -0
- {cortexgrid_infer-0.3.7 → cortexgrid_infer-0.3.8}/cortexgrid_infer/serve_apps/streamed_completion.py +0 -0
- {cortexgrid_infer-0.3.7 → cortexgrid_infer-0.3.8}/cortexgrid_infer/utils.py +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.5
|
|
2
2
|
Name: cortexgrid-infer
|
|
3
|
-
Version: 0.3.
|
|
3
|
+
Version: 0.3.8
|
|
4
4
|
Summary: Serve apps per task (text-to-text, text-to-image, image-to-mesh) and importers per source (HuggingFace) for running models on cortexgrid
|
|
5
5
|
Project-URL: Homepage, https://github.com/robodatalab/cortexgrid-infer
|
|
6
6
|
Project-URL: Repository, https://github.com/robodatalab/cortexgrid-infer
|
|
@@ -9,7 +9,7 @@ License-File: LICENSE
|
|
|
9
9
|
Requires-Python: <3.12,>=3.11
|
|
10
10
|
Requires-Dist: accelerate>=0.33
|
|
11
11
|
Requires-Dist: anthropic>=0.40.0
|
|
12
|
-
Requires-Dist: cortexgrid>=0.3.
|
|
12
|
+
Requires-Dist: cortexgrid>=0.3.16
|
|
13
13
|
Requires-Dist: diffusers>=0.38
|
|
14
14
|
Requires-Dist: fastapi>=0.133
|
|
15
15
|
Requires-Dist: google-genai>=1.0
|
|
@@ -85,11 +85,12 @@ need:
|
|
|
85
85
|
| `.serve_app` | the class cortexgrid bundles and runs on the cluster |
|
|
86
86
|
| `.requirements()` | what one replica needs to be placed and to run |
|
|
87
87
|
| `.config()` | settings the serve app reads at construction, if it needs any |
|
|
88
|
-
| `.client(url)` | a client that speaks the deployed app's routes |
|
|
89
88
|
| `.source` | *(importers only)* a callable that downloads the weights and returns the directory |
|
|
90
89
|
|
|
91
90
|
One with weights goes through `cortexgrid.import_model`, one without through
|
|
92
|
-
`cortexgrid.register_model`.
|
|
91
|
+
`cortexgrid.register_model`. Once deployed, the `cortexgrid.Deployment` hands back
|
|
92
|
+
the client that speaks the app's routes: `deployment.client()` once the app serves,
|
|
93
|
+
or `deployment.client_async()` at once, with `await model.is_ready()` to ask.
|
|
93
94
|
|
|
94
95
|
## Quick start
|
|
95
96
|
|
|
@@ -117,13 +118,11 @@ cortexgrid.remote(
|
|
|
117
118
|
import_weights, imp, imp.requirements(), num_gpus=0, num_cpus=2
|
|
118
119
|
).result()
|
|
119
120
|
|
|
120
|
-
# 2. Deploy
|
|
121
|
-
deployment = cortexgrid.deploy_model(
|
|
122
|
-
imp.family, imp.suffix, cortexgrid.IMPORTED, wait=True, timeout=1800
|
|
123
|
-
)
|
|
121
|
+
# 2. Deploy.
|
|
122
|
+
deployment = cortexgrid.deploy_model(imp.family, imp.suffix, cortexgrid.IMPORTED, timeout=1800)
|
|
124
123
|
|
|
125
|
-
# 3. Inference.
|
|
126
|
-
model =
|
|
124
|
+
# 3. Inference — the client blocks until the Ray Serve app is running.
|
|
125
|
+
model = deployment.client()
|
|
127
126
|
|
|
128
127
|
async def run():
|
|
129
128
|
result = await mg.generate(model, "a red bicycle on a beach at sunrise")
|
|
@@ -281,8 +280,7 @@ it is the floor; only quantizing the weights or running fewer forwards moves it.
|
|
|
281
280
|
`complete` streams `CompletionChunk`s (`.content`, `.thinking`, `.tool_calls`, `.finish_reason`):
|
|
282
281
|
|
|
283
282
|
```python
|
|
284
|
-
|
|
285
|
-
model = imp.client(deployment.url)
|
|
283
|
+
model = deployment.client()
|
|
286
284
|
messages = [{"role": "user", "content": "Explain RAG in one sentence."}]
|
|
287
285
|
|
|
288
286
|
async for chunk in mg.complete(model, messages, max_new_tokens=512, temperature=0.7):
|
|
@@ -323,7 +321,7 @@ a re-deploy rather than a re-registration.
|
|
|
323
321
|
|
|
324
322
|
A replica asks for no hardware at all, so it is placed on any node, CPU-only
|
|
325
323
|
included. From there it deploys and streams exactly like a cluster-served model:
|
|
326
|
-
`
|
|
324
|
+
`deployment.client()` returns the same `ServedCompletingModel`. Anthropic
|
|
327
325
|
reports tool calls as structured blocks rather than as generated text, so the
|
|
328
326
|
serve app re-encodes them into the text form the client parses.
|
|
329
327
|
|
|
@@ -346,7 +344,7 @@ cortexgrid.register_model(
|
|
|
346
344
|
|
|
347
345
|
Everything said above for Anthropic holds: `config` carries the model name and
|
|
348
346
|
the name of the secret (`api_key_secret="..."` to use another), both editable on
|
|
349
|
-
the model card; a replica needs no hardware; and `
|
|
347
|
+
the model card; a replica needs no hardware; and `deployment.client()`
|
|
350
348
|
is a `ServedCompletingModel`, with Gemini's function calls re-encoded into the
|
|
351
349
|
text form the client parses.
|
|
352
350
|
|
|
@@ -356,7 +354,8 @@ client is a `ServedGeneratingModel`:
|
|
|
356
354
|
```python
|
|
357
355
|
entry = mg.Hosted("gemini-2.5-flash-image", mg.GeminiText2Image)
|
|
358
356
|
...
|
|
359
|
-
|
|
357
|
+
model = deployment.client()
|
|
358
|
+
picture = await mg.generate(model, "a fox in the snow", size=2048)
|
|
360
359
|
```
|
|
361
360
|
|
|
362
361
|
It takes a prompt only, and makes a square picture. `size` picks Gemini's size
|
|
@@ -368,28 +367,28 @@ diffusion settings with no Gemini counterpart, and come back as `None`.
|
|
|
368
367
|
| | |
|
|
369
368
|
|---|---|
|
|
370
369
|
| `HuggingFaceImporter(hf_id, serve_app, token=None, ignore_patterns=None)` | Importer for a model on the HuggingFace Hub, run by `serve_app`. |
|
|
371
|
-
| `Importer` | Base of the importers: identity, scratch directory, `source`, and `requirements()`
|
|
370
|
+
| `Importer` | Base of the importers: identity, scratch directory, `source`, and `requirements()` taken from the serve app. A new source implements `download(local_dir)` and `weights()`. |
|
|
372
371
|
| `Hosted(model_id, serve_app, **settings)` | Entry for a model hosted elsewhere; no weights. `settings` are the serve app's `config` arguments. |
|
|
373
|
-
| `ModelEntry` | Base of both: `model_id`, `family`, `suffix`, `serve_app`, `requirements()`, `config()
|
|
372
|
+
| `ModelEntry` | Base of both: `model_id`, `family`, `suffix`, `serve_app`, `requirements()`, `config()`. |
|
|
374
373
|
| `Text2Text`, `Text2Image`, `TextRewriter`, `Image2Mesh` | Serve apps that run weights (`LocalModel`s). |
|
|
375
374
|
| `AnthropicText2Text` | Serve app that forwards to the Anthropic API (a `HostedModel`). |
|
|
376
375
|
| `GeminiText2Text`, `GeminiText2Image` | Serve apps that forward to the Gemini API (`HostedModel`s sharing the `GeminiModel` base). |
|
|
377
|
-
| `LocalModel` | Base of the serve apps that run weights: `ignore_patterns()`, `bytes_per_param`, `min_vram_gb`, `requirements(weights)`, `config()` (the model card's defaults, `compile: "false"` among them), `client(
|
|
378
|
-
| `HostedModel` | Base of the serve apps that forward: `config(model_id, **settings)`, `requirements()`, `client(
|
|
376
|
+
| `LocalModel` | Base of the serve apps that run weights: `ignore_patterns()`, `bytes_per_param`, `min_vram_gb`, `requirements(weights)`, `config()` (the model card's defaults, `compile: "false"` among them), `client(deployment)`. |
|
|
377
|
+
| `HostedModel` | Base of the serve apps that forward: `config(model_id, **settings)`, `requirements()`, `client(deployment)`. |
|
|
379
378
|
| `Weights(params=None, file_bytes=0)` | What an importer reads about the weights, handed to the serve app to size a replica. |
|
|
380
379
|
| `complete(model, messages, tools=None, max_new_tokens=2048, temperature=0.7, **kw)` | Async stream of `CompletionChunk` for a `CompletingModel`. |
|
|
381
380
|
| `generate(model, prompt, *, image=None, **kw) -> GeneratedImage` | One image from a `GeneratingModel`. |
|
|
382
|
-
| `ServedCompletingModel(
|
|
383
|
-
| `ServedGeneratingModel(
|
|
384
|
-
| `ServedMeshingModel(
|
|
381
|
+
| `ServedCompletingModel(key, url)` | Client for any deployed completion app. |
|
|
382
|
+
| `ServedGeneratingModel(key, url)` | Client for any deployed text-to-image app. |
|
|
383
|
+
| `ServedMeshingModel(key, url)` | Client for any deployed image-to-mesh app. |
|
|
385
384
|
| `split_model_id(model_id) -> (family, suffix)` | The registry identity an importer derives. |
|
|
386
385
|
| `detect_device()` | The torch device a serve app should load onto. |
|
|
387
386
|
| `compiling.Mode.GRAPHED` / `compiling.Mode.FUSED` | The two modes a serve app chooses between. See [Compilation](#compilation). |
|
|
388
387
|
| `compiling.supported(device)` / `compile_module(module, device, mode)` / `compile_pipeline(pipe, device, mode)` | Whether to compile here, and what a serve app calls to do it. |
|
|
389
388
|
| `ModelDeployFailed` | Re-exported from cortexgrid; subclasses `RuntimeError`. |
|
|
390
389
|
|
|
391
|
-
Types: `
|
|
392
|
-
`CompletionChunk`, `GeneratedImage`, `GeneratedMesh`, `ToolCall`, `Message`, `Tool`,
|
|
390
|
+
Types: `CompletingModel`, `GeneratingModel`, `MeshingModel`, `RewritingModel` (each
|
|
391
|
+
a `cortexgrid.DeploymentClient`), `CompletionChunk`, `GeneratedImage`, `GeneratedMesh`, `ToolCall`, `Message`, `Tool`,
|
|
393
392
|
`ToolSpec`.
|
|
394
393
|
|
|
395
394
|
Extending it:
|
|
@@ -57,11 +57,12 @@ need:
|
|
|
57
57
|
| `.serve_app` | the class cortexgrid bundles and runs on the cluster |
|
|
58
58
|
| `.requirements()` | what one replica needs to be placed and to run |
|
|
59
59
|
| `.config()` | settings the serve app reads at construction, if it needs any |
|
|
60
|
-
| `.client(url)` | a client that speaks the deployed app's routes |
|
|
61
60
|
| `.source` | *(importers only)* a callable that downloads the weights and returns the directory |
|
|
62
61
|
|
|
63
62
|
One with weights goes through `cortexgrid.import_model`, one without through
|
|
64
|
-
`cortexgrid.register_model`.
|
|
63
|
+
`cortexgrid.register_model`. Once deployed, the `cortexgrid.Deployment` hands back
|
|
64
|
+
the client that speaks the app's routes: `deployment.client()` once the app serves,
|
|
65
|
+
or `deployment.client_async()` at once, with `await model.is_ready()` to ask.
|
|
65
66
|
|
|
66
67
|
## Quick start
|
|
67
68
|
|
|
@@ -89,13 +90,11 @@ cortexgrid.remote(
|
|
|
89
90
|
import_weights, imp, imp.requirements(), num_gpus=0, num_cpus=2
|
|
90
91
|
).result()
|
|
91
92
|
|
|
92
|
-
# 2. Deploy
|
|
93
|
-
deployment = cortexgrid.deploy_model(
|
|
94
|
-
imp.family, imp.suffix, cortexgrid.IMPORTED, wait=True, timeout=1800
|
|
95
|
-
)
|
|
93
|
+
# 2. Deploy.
|
|
94
|
+
deployment = cortexgrid.deploy_model(imp.family, imp.suffix, cortexgrid.IMPORTED, timeout=1800)
|
|
96
95
|
|
|
97
|
-
# 3. Inference.
|
|
98
|
-
model =
|
|
96
|
+
# 3. Inference — the client blocks until the Ray Serve app is running.
|
|
97
|
+
model = deployment.client()
|
|
99
98
|
|
|
100
99
|
async def run():
|
|
101
100
|
result = await mg.generate(model, "a red bicycle on a beach at sunrise")
|
|
@@ -253,8 +252,7 @@ it is the floor; only quantizing the weights or running fewer forwards moves it.
|
|
|
253
252
|
`complete` streams `CompletionChunk`s (`.content`, `.thinking`, `.tool_calls`, `.finish_reason`):
|
|
254
253
|
|
|
255
254
|
```python
|
|
256
|
-
|
|
257
|
-
model = imp.client(deployment.url)
|
|
255
|
+
model = deployment.client()
|
|
258
256
|
messages = [{"role": "user", "content": "Explain RAG in one sentence."}]
|
|
259
257
|
|
|
260
258
|
async for chunk in mg.complete(model, messages, max_new_tokens=512, temperature=0.7):
|
|
@@ -295,7 +293,7 @@ a re-deploy rather than a re-registration.
|
|
|
295
293
|
|
|
296
294
|
A replica asks for no hardware at all, so it is placed on any node, CPU-only
|
|
297
295
|
included. From there it deploys and streams exactly like a cluster-served model:
|
|
298
|
-
`
|
|
296
|
+
`deployment.client()` returns the same `ServedCompletingModel`. Anthropic
|
|
299
297
|
reports tool calls as structured blocks rather than as generated text, so the
|
|
300
298
|
serve app re-encodes them into the text form the client parses.
|
|
301
299
|
|
|
@@ -318,7 +316,7 @@ cortexgrid.register_model(
|
|
|
318
316
|
|
|
319
317
|
Everything said above for Anthropic holds: `config` carries the model name and
|
|
320
318
|
the name of the secret (`api_key_secret="..."` to use another), both editable on
|
|
321
|
-
the model card; a replica needs no hardware; and `
|
|
319
|
+
the model card; a replica needs no hardware; and `deployment.client()`
|
|
322
320
|
is a `ServedCompletingModel`, with Gemini's function calls re-encoded into the
|
|
323
321
|
text form the client parses.
|
|
324
322
|
|
|
@@ -328,7 +326,8 @@ client is a `ServedGeneratingModel`:
|
|
|
328
326
|
```python
|
|
329
327
|
entry = mg.Hosted("gemini-2.5-flash-image", mg.GeminiText2Image)
|
|
330
328
|
...
|
|
331
|
-
|
|
329
|
+
model = deployment.client()
|
|
330
|
+
picture = await mg.generate(model, "a fox in the snow", size=2048)
|
|
332
331
|
```
|
|
333
332
|
|
|
334
333
|
It takes a prompt only, and makes a square picture. `size` picks Gemini's size
|
|
@@ -340,28 +339,28 @@ diffusion settings with no Gemini counterpart, and come back as `None`.
|
|
|
340
339
|
| | |
|
|
341
340
|
|---|---|
|
|
342
341
|
| `HuggingFaceImporter(hf_id, serve_app, token=None, ignore_patterns=None)` | Importer for a model on the HuggingFace Hub, run by `serve_app`. |
|
|
343
|
-
| `Importer` | Base of the importers: identity, scratch directory, `source`, and `requirements()`
|
|
342
|
+
| `Importer` | Base of the importers: identity, scratch directory, `source`, and `requirements()` taken from the serve app. A new source implements `download(local_dir)` and `weights()`. |
|
|
344
343
|
| `Hosted(model_id, serve_app, **settings)` | Entry for a model hosted elsewhere; no weights. `settings` are the serve app's `config` arguments. |
|
|
345
|
-
| `ModelEntry` | Base of both: `model_id`, `family`, `suffix`, `serve_app`, `requirements()`, `config()
|
|
344
|
+
| `ModelEntry` | Base of both: `model_id`, `family`, `suffix`, `serve_app`, `requirements()`, `config()`. |
|
|
346
345
|
| `Text2Text`, `Text2Image`, `TextRewriter`, `Image2Mesh` | Serve apps that run weights (`LocalModel`s). |
|
|
347
346
|
| `AnthropicText2Text` | Serve app that forwards to the Anthropic API (a `HostedModel`). |
|
|
348
347
|
| `GeminiText2Text`, `GeminiText2Image` | Serve apps that forward to the Gemini API (`HostedModel`s sharing the `GeminiModel` base). |
|
|
349
|
-
| `LocalModel` | Base of the serve apps that run weights: `ignore_patterns()`, `bytes_per_param`, `min_vram_gb`, `requirements(weights)`, `config()` (the model card's defaults, `compile: "false"` among them), `client(
|
|
350
|
-
| `HostedModel` | Base of the serve apps that forward: `config(model_id, **settings)`, `requirements()`, `client(
|
|
348
|
+
| `LocalModel` | Base of the serve apps that run weights: `ignore_patterns()`, `bytes_per_param`, `min_vram_gb`, `requirements(weights)`, `config()` (the model card's defaults, `compile: "false"` among them), `client(deployment)`. |
|
|
349
|
+
| `HostedModel` | Base of the serve apps that forward: `config(model_id, **settings)`, `requirements()`, `client(deployment)`. |
|
|
351
350
|
| `Weights(params=None, file_bytes=0)` | What an importer reads about the weights, handed to the serve app to size a replica. |
|
|
352
351
|
| `complete(model, messages, tools=None, max_new_tokens=2048, temperature=0.7, **kw)` | Async stream of `CompletionChunk` for a `CompletingModel`. |
|
|
353
352
|
| `generate(model, prompt, *, image=None, **kw) -> GeneratedImage` | One image from a `GeneratingModel`. |
|
|
354
|
-
| `ServedCompletingModel(
|
|
355
|
-
| `ServedGeneratingModel(
|
|
356
|
-
| `ServedMeshingModel(
|
|
353
|
+
| `ServedCompletingModel(key, url)` | Client for any deployed completion app. |
|
|
354
|
+
| `ServedGeneratingModel(key, url)` | Client for any deployed text-to-image app. |
|
|
355
|
+
| `ServedMeshingModel(key, url)` | Client for any deployed image-to-mesh app. |
|
|
357
356
|
| `split_model_id(model_id) -> (family, suffix)` | The registry identity an importer derives. |
|
|
358
357
|
| `detect_device()` | The torch device a serve app should load onto. |
|
|
359
358
|
| `compiling.Mode.GRAPHED` / `compiling.Mode.FUSED` | The two modes a serve app chooses between. See [Compilation](#compilation). |
|
|
360
359
|
| `compiling.supported(device)` / `compile_module(module, device, mode)` / `compile_pipeline(pipe, device, mode)` | Whether to compile here, and what a serve app calls to do it. |
|
|
361
360
|
| `ModelDeployFailed` | Re-exported from cortexgrid; subclasses `RuntimeError`. |
|
|
362
361
|
|
|
363
|
-
Types: `
|
|
364
|
-
`CompletionChunk`, `GeneratedImage`, `GeneratedMesh`, `ToolCall`, `Message`, `Tool`,
|
|
362
|
+
Types: `CompletingModel`, `GeneratingModel`, `MeshingModel`, `RewritingModel` (each
|
|
363
|
+
a `cortexgrid.DeploymentClient`), `CompletionChunk`, `GeneratedImage`, `GeneratedMesh`, `ToolCall`, `Message`, `Tool`,
|
|
365
364
|
`ToolSpec`.
|
|
366
365
|
|
|
367
366
|
Extending it:
|
|
@@ -18,8 +18,8 @@ nothing else, split along the two things a model is:
|
|
|
18
18
|
family=imp.family, suffix=imp.suffix,
|
|
19
19
|
requirements=imp.requirements(),
|
|
20
20
|
)
|
|
21
|
-
deployment = cortexgrid.deploy_model(imp.family, imp.suffix, cortexgrid.IMPORTED
|
|
22
|
-
model =
|
|
21
|
+
deployment = cortexgrid.deploy_model(imp.family, imp.suffix, cortexgrid.IMPORTED)
|
|
22
|
+
model = deployment.client()
|
|
23
23
|
|
|
24
24
|
A model hosted elsewhere has no weights and so no importer: its serve app
|
|
25
25
|
forwards to it, and a `Hosted` entry registers it.
|
|
@@ -31,7 +31,6 @@ from cortexgrid import ModelDeployFailed
|
|
|
31
31
|
|
|
32
32
|
from cortexgrid_infer.core import (
|
|
33
33
|
CompletionChunk,
|
|
34
|
-
DeployedModel,
|
|
35
34
|
CompletingModel,
|
|
36
35
|
GeneratedImage,
|
|
37
36
|
GeneratedMesh,
|
|
@@ -71,7 +70,6 @@ from cortexgrid_infer.importers import HuggingFaceImporter, Importer
|
|
|
71
70
|
|
|
72
71
|
__all__ = [
|
|
73
72
|
"CompletionChunk",
|
|
74
|
-
"DeployedModel",
|
|
75
73
|
"CompletingModel",
|
|
76
74
|
"GeneratedImage",
|
|
77
75
|
"GeneratedMesh",
|
|
@@ -8,6 +8,7 @@ from functools import partial
|
|
|
8
8
|
from collections.abc import AsyncIterator
|
|
9
9
|
from typing import Any, Callable, Sequence
|
|
10
10
|
|
|
11
|
+
import cortexgrid
|
|
11
12
|
import numpy as np
|
|
12
13
|
|
|
13
14
|
|
|
@@ -64,13 +65,7 @@ ToolSpec = dict[str, Any]
|
|
|
64
65
|
Tool = Callable[..., Any] | ToolSpec
|
|
65
66
|
|
|
66
67
|
|
|
67
|
-
class
|
|
68
|
-
@property
|
|
69
|
-
@abc.abstractmethod
|
|
70
|
-
def name(self) -> str: ...
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
class CompletingModel(DeployedModel):
|
|
68
|
+
class CompletingModel(cortexgrid.DeploymentClient, abc.ABC):
|
|
74
69
|
@abc.abstractmethod
|
|
75
70
|
def complete(
|
|
76
71
|
self,
|
|
@@ -93,7 +88,7 @@ class GeneratedImage:
|
|
|
93
88
|
params: dict[str, Any] = field(default_factory=dict)
|
|
94
89
|
|
|
95
90
|
|
|
96
|
-
class GeneratingModel(
|
|
91
|
+
class GeneratingModel(cortexgrid.DeploymentClient, abc.ABC):
|
|
97
92
|
"""A deployed image model. Unlike completion, generation is a single
|
|
98
93
|
request/response (no token streaming), so `generate` returns one result."""
|
|
99
94
|
|
|
@@ -124,14 +119,14 @@ class GeneratedMesh:
|
|
|
124
119
|
params: dict[str, Any] = field(default_factory=dict)
|
|
125
120
|
|
|
126
121
|
|
|
127
|
-
class MeshingModel(
|
|
122
|
+
class MeshingModel(cortexgrid.DeploymentClient, abc.ABC):
|
|
128
123
|
"""A deployed model that makes a mesh of the object in one picture."""
|
|
129
124
|
|
|
130
125
|
@abc.abstractmethod
|
|
131
126
|
async def mesh(self, image: bytes, **kwargs: Any) -> GeneratedMesh: ...
|
|
132
127
|
|
|
133
128
|
|
|
134
|
-
class RewritingModel(
|
|
129
|
+
class RewritingModel(cortexgrid.DeploymentClient, abc.ABC):
|
|
135
130
|
"""A deployed model that rewrites one text into another - corrects,
|
|
136
131
|
paraphrases, summarises or translates it. Like generation, a single
|
|
137
132
|
request/response."""
|
|
@@ -29,7 +29,6 @@ from typing import Self
|
|
|
29
29
|
|
|
30
30
|
import cortexgrid
|
|
31
31
|
|
|
32
|
-
from cortexgrid_infer.core import DeployedModel
|
|
33
32
|
from cortexgrid_infer.registry import ModelEntry, split_model_id
|
|
34
33
|
from cortexgrid_infer.serve_apps.base import LocalModel, Weights
|
|
35
34
|
|
|
@@ -97,6 +96,3 @@ class Importer(ModelEntry):
|
|
|
97
96
|
|
|
98
97
|
def config(self) -> dict[str, str]:
|
|
99
98
|
return self.serve_app.config()
|
|
100
|
-
|
|
101
|
-
def client(self, url: str) -> DeployedModel:
|
|
102
|
-
return self.serve_app.client(url, self.model_id)
|
|
@@ -13,7 +13,6 @@ back as `CompletionChunk`s and reassembles the tool calls.
|
|
|
13
13
|
from __future__ import annotations
|
|
14
14
|
|
|
15
15
|
from collections.abc import AsyncIterator
|
|
16
|
-
from dataclasses import dataclass
|
|
17
16
|
import json
|
|
18
17
|
from typing import Any, Sequence
|
|
19
18
|
|
|
@@ -22,19 +21,11 @@ import httpx
|
|
|
22
21
|
from cortexgrid_infer.core import CompletingModel, CompletionChunk, Message, Tool
|
|
23
22
|
from cortexgrid_infer.utils import build_tool_map, normalize_tools
|
|
24
23
|
|
|
25
|
-
@dataclass
|
|
26
24
|
class ServedCompletingModel(CompletingModel):
|
|
27
25
|
"""Client for a completion app cortexgrid has deployed at `url`.
|
|
28
26
|
|
|
29
27
|
Provider-agnostic: every completion serve app speaks the protocol above, so
|
|
30
|
-
which model is behind it only shows up in `
|
|
31
|
-
|
|
32
|
-
url: str
|
|
33
|
-
model_id: str
|
|
34
|
-
|
|
35
|
-
@property
|
|
36
|
-
def name(self) -> str:
|
|
37
|
-
return self.model_id
|
|
28
|
+
which model is behind it only shows up in its deployment's `key`."""
|
|
38
29
|
|
|
39
30
|
async def loglikelihoods(
|
|
40
31
|
self, messages: list[Message], continuations: list[str]
|
|
@@ -15,7 +15,6 @@ task whoever made it.
|
|
|
15
15
|
from __future__ import annotations
|
|
16
16
|
|
|
17
17
|
import base64
|
|
18
|
-
from dataclasses import dataclass
|
|
19
18
|
from typing import Any
|
|
20
19
|
|
|
21
20
|
import httpx
|
|
@@ -23,17 +22,9 @@ import httpx
|
|
|
23
22
|
from cortexgrid_infer.core import GeneratedImage, GeneratingModel
|
|
24
23
|
|
|
25
24
|
|
|
26
|
-
@dataclass
|
|
27
25
|
class ServedGeneratingModel(GeneratingModel):
|
|
28
26
|
"""The client of any text-to-image serve app deployed at `url`."""
|
|
29
27
|
|
|
30
|
-
url: str
|
|
31
|
-
model_id: str
|
|
32
|
-
|
|
33
|
-
@property
|
|
34
|
-
def name(self) -> str:
|
|
35
|
-
return self.model_id
|
|
36
|
-
|
|
37
28
|
async def generate(
|
|
38
29
|
self,
|
|
39
30
|
prompt: str,
|
|
@@ -69,6 +60,5 @@ class ServedGeneratingModel(GeneratingModel):
|
|
|
69
60
|
"guidance": data.get("guidance", guidance),
|
|
70
61
|
"seed": data.get("seed", seed),
|
|
71
62
|
"duration_s": data.get("duration_s"),
|
|
72
|
-
"model_id": self.model_id,
|
|
73
63
|
},
|
|
74
64
|
)
|
|
@@ -15,7 +15,6 @@ Every such app speaks it through
|
|
|
15
15
|
from __future__ import annotations
|
|
16
16
|
|
|
17
17
|
import base64
|
|
18
|
-
from dataclasses import dataclass
|
|
19
18
|
from typing import Any
|
|
20
19
|
|
|
21
20
|
import httpx
|
|
@@ -41,17 +40,9 @@ def decode(data: str, kind: tuple[str, int]) -> np.ndarray:
|
|
|
41
40
|
return np.frombuffer(base64.b64decode(data), dtype=dtype).reshape(-1, columns)
|
|
42
41
|
|
|
43
42
|
|
|
44
|
-
@dataclass
|
|
45
43
|
class ServedMeshingModel(MeshingModel):
|
|
46
44
|
"""The client of any image-to-mesh serve app deployed at `url`."""
|
|
47
45
|
|
|
48
|
-
url: str
|
|
49
|
-
model_id: str
|
|
50
|
-
|
|
51
|
-
@property
|
|
52
|
-
def name(self) -> str:
|
|
53
|
-
return self.model_id
|
|
54
|
-
|
|
55
46
|
async def mesh(self, image: bytes, **options: Any) -> GeneratedMesh:
|
|
56
47
|
body: dict[str, Any] = {"image": base64.b64encode(image).decode("ascii"), **options}
|
|
57
48
|
# Meshing takes seconds; no client-side timeout.
|
|
@@ -67,6 +58,5 @@ class ServedMeshingModel(MeshingModel):
|
|
|
67
58
|
params={
|
|
68
59
|
**data.get("params", {}),
|
|
69
60
|
"duration_s": data.get("duration_s"),
|
|
70
|
-
"model_id": self.model_id,
|
|
71
61
|
},
|
|
72
62
|
)
|
|
@@ -15,7 +15,6 @@ every model of the task whoever made it.
|
|
|
15
15
|
|
|
16
16
|
from __future__ import annotations
|
|
17
17
|
|
|
18
|
-
from dataclasses import dataclass
|
|
19
18
|
from typing import Any
|
|
20
19
|
|
|
21
20
|
import httpx
|
|
@@ -23,17 +22,9 @@ import httpx
|
|
|
23
22
|
from cortexgrid_infer.core import RewritingModel
|
|
24
23
|
|
|
25
24
|
|
|
26
|
-
@dataclass
|
|
27
25
|
class ServedRewritingModel(RewritingModel):
|
|
28
26
|
"""The client of any rewriting serve app deployed at `url`."""
|
|
29
27
|
|
|
30
|
-
url: str
|
|
31
|
-
model_id: str
|
|
32
|
-
|
|
33
|
-
@property
|
|
34
|
-
def name(self) -> str:
|
|
35
|
-
return self.model_id
|
|
36
|
-
|
|
37
28
|
async def rewrite(
|
|
38
29
|
self, text: str, max_new_tokens: int = 512, **generation_options: Any
|
|
39
30
|
) -> str:
|
|
@@ -5,9 +5,9 @@ cortexgrid stores whatever weights it is handed under whatever key it is given,
|
|
|
5
5
|
and serves them with whatever class it was told to bundle. It deliberately knows
|
|
6
6
|
nothing about where a model came from or what shape it is. A `ModelEntry`
|
|
7
7
|
supplies exactly that missing knowledge - the registry identity, the serve app,
|
|
8
|
-
the hardware it needs, its config
|
|
9
|
-
|
|
10
|
-
|
|
8
|
+
the hardware it needs, and its config - and drives no lifecycle of its own:
|
|
9
|
+
importing, deploying and deleting stay the caller's calls against the cortexgrid
|
|
10
|
+
SDK, and a deployment's client is the deployment's `client()`.
|
|
11
11
|
|
|
12
12
|
A model with weights is an importer's (`cortexgrid_infer.importers`) and goes
|
|
13
13
|
through `import_model`. A model hosted elsewhere is a `Hosted` entry and goes
|
|
@@ -27,7 +27,6 @@ import abc
|
|
|
27
27
|
|
|
28
28
|
import cortexgrid
|
|
29
29
|
|
|
30
|
-
from cortexgrid_infer.core import DeployedModel
|
|
31
30
|
from cortexgrid_infer.serve_apps.base import HostedModel
|
|
32
31
|
|
|
33
32
|
|
|
@@ -49,8 +48,8 @@ def split_model_id(model_id: str) -> tuple[str, str]:
|
|
|
49
48
|
class ModelEntry(abc.ABC):
|
|
50
49
|
"""One model as the registry files it and cortexgrid serves it."""
|
|
51
50
|
|
|
52
|
-
# The id the model is known by where it came from; the registry key
|
|
53
|
-
#
|
|
51
|
+
# The id the model is known by where it came from; the registry key derives
|
|
52
|
+
# from it.
|
|
54
53
|
model_id: str
|
|
55
54
|
|
|
56
55
|
# The class cortexgrid bundles and instantiates on the cluster.
|
|
@@ -72,10 +71,6 @@ class ModelEntry(abc.ABC):
|
|
|
72
71
|
bundled code already knows everything it needs."""
|
|
73
72
|
return {}
|
|
74
73
|
|
|
75
|
-
@abc.abstractmethod
|
|
76
|
-
def client(self, url: str) -> DeployedModel:
|
|
77
|
-
"""Return a client for this model's serve app, deployed at `url`."""
|
|
78
|
-
|
|
79
74
|
|
|
80
75
|
class Hosted(ModelEntry):
|
|
81
76
|
"""A model hosted elsewhere, served by a `HostedModel` app that forwards to it.
|
|
@@ -97,6 +92,3 @@ class Hosted(ModelEntry):
|
|
|
97
92
|
|
|
98
93
|
def config(self) -> dict[str, str]:
|
|
99
94
|
return dict(self._config)
|
|
100
|
-
|
|
101
|
-
def client(self, url: str) -> DeployedModel:
|
|
102
|
-
return self.serve_app.client(url, self.model_id)
|
|
@@ -129,8 +129,8 @@ class AnthropicText2Text(HostedModel):
|
|
|
129
129
|
return {MODEL_PARAM: model_id, API_KEY_SECRET_PARAM: api_key_secret}
|
|
130
130
|
|
|
131
131
|
@classmethod
|
|
132
|
-
def client(cls,
|
|
133
|
-
return ServedCompletingModel(
|
|
132
|
+
def client(cls, deployment: cortexgrid.Deployment[ServedCompletingModel]) -> ServedCompletingModel:
|
|
133
|
+
return ServedCompletingModel(key=deployment.key, url=deployment.url)
|
|
134
134
|
|
|
135
135
|
def __init__(self, deployment: cortexgrid.DeploymentKey) -> None:
|
|
136
136
|
config = cortexgrid.model_config(deployment)
|
|
@@ -20,12 +20,10 @@ in step with it.
|
|
|
20
20
|
from __future__ import annotations
|
|
21
21
|
|
|
22
22
|
from dataclasses import dataclass
|
|
23
|
-
from typing import ClassVar
|
|
23
|
+
from typing import Any, ClassVar
|
|
24
24
|
|
|
25
25
|
import cortexgrid
|
|
26
26
|
|
|
27
|
-
from cortexgrid_infer.core import DeployedModel
|
|
28
|
-
|
|
29
27
|
_GIB = float(1 << 30)
|
|
30
28
|
|
|
31
29
|
ENABLE_THINKING_PARAM = "enable_thinking"
|
|
@@ -107,8 +105,8 @@ class LocalModel:
|
|
|
107
105
|
return {COMPILE_PARAM: "false"}
|
|
108
106
|
|
|
109
107
|
@classmethod
|
|
110
|
-
def client(cls,
|
|
111
|
-
"""A client for this app
|
|
108
|
+
def client(cls, deployment: cortexgrid.Deployment[Any]) -> cortexgrid.DeploymentClient:
|
|
109
|
+
"""A client for this app's `deployment`."""
|
|
112
110
|
raise NotImplementedError
|
|
113
111
|
|
|
114
112
|
|
|
@@ -128,6 +126,6 @@ class HostedModel:
|
|
|
128
126
|
return cortexgrid.ModelRequirements()
|
|
129
127
|
|
|
130
128
|
@classmethod
|
|
131
|
-
def client(cls,
|
|
132
|
-
"""A client for this app
|
|
129
|
+
def client(cls, deployment: cortexgrid.Deployment[Any]) -> cortexgrid.DeploymentClient:
|
|
130
|
+
"""A client for this app's `deployment`."""
|
|
133
131
|
raise NotImplementedError
|
{cortexgrid_infer-0.3.7 → cortexgrid_infer-0.3.8}/cortexgrid_infer/serve_apps/gemini/text2image.py
RENAMED
|
@@ -13,6 +13,7 @@ import io
|
|
|
13
13
|
import time
|
|
14
14
|
from typing import Any
|
|
15
15
|
|
|
16
|
+
import cortexgrid
|
|
16
17
|
from cortexgrid import serve
|
|
17
18
|
from fastapi import FastAPI, HTTPException
|
|
18
19
|
from google.genai import types
|
|
@@ -63,8 +64,8 @@ def no_image_reason(response: types.GenerateContentResponse) -> str:
|
|
|
63
64
|
@serve.ingress(_app)
|
|
64
65
|
class GeminiText2Image(GeminiModel):
|
|
65
66
|
@classmethod
|
|
66
|
-
def client(cls,
|
|
67
|
-
return ServedGeneratingModel(
|
|
67
|
+
def client(cls, deployment: cortexgrid.Deployment[ServedGeneratingModel]) -> ServedGeneratingModel:
|
|
68
|
+
return ServedGeneratingModel(key=deployment.key, url=deployment.url)
|
|
68
69
|
|
|
69
70
|
@_app.post("/generate")
|
|
70
71
|
async def generate(self, body: dict[str, Any]) -> dict[str, Any]:
|
{cortexgrid_infer-0.3.7 → cortexgrid_infer-0.3.8}/cortexgrid_infer/serve_apps/gemini/text2text.py
RENAMED
|
@@ -11,6 +11,7 @@ import base64
|
|
|
11
11
|
from collections.abc import AsyncIterator
|
|
12
12
|
from typing import Any
|
|
13
13
|
|
|
14
|
+
import cortexgrid
|
|
14
15
|
from cortexgrid import serve
|
|
15
16
|
from fastapi import FastAPI, HTTPException, status
|
|
16
17
|
from fastapi.responses import StreamingResponse
|
|
@@ -124,8 +125,8 @@ class GeminiText2Text(GeminiModel):
|
|
|
124
125
|
}
|
|
125
126
|
|
|
126
127
|
@classmethod
|
|
127
|
-
def client(cls,
|
|
128
|
-
return ServedCompletingModel(
|
|
128
|
+
def client(cls, deployment: cortexgrid.Deployment[ServedCompletingModel]) -> ServedCompletingModel:
|
|
129
|
+
return ServedCompletingModel(key=deployment.key, url=deployment.url)
|
|
129
130
|
|
|
130
131
|
@_app.post("/complete")
|
|
131
132
|
async def complete(self, body: dict[str, Any]) -> StreamingResponse:
|
|
@@ -51,8 +51,8 @@ class Image2Mesh(LocalModel):
|
|
|
51
51
|
show - querying the model over a whole 3D grid usually does."""
|
|
52
52
|
|
|
53
53
|
@classmethod
|
|
54
|
-
def client(cls,
|
|
55
|
-
return ServedMeshingModel(
|
|
54
|
+
def client(cls, deployment: cortexgrid.Deployment[ServedMeshingModel]) -> ServedMeshingModel:
|
|
55
|
+
return ServedMeshingModel(key=deployment.key, url=deployment.url)
|
|
56
56
|
|
|
57
57
|
def __init__(self, deployment: cortexgrid.DeploymentKey) -> None:
|
|
58
58
|
self.device = detect_device()
|
|
@@ -81,8 +81,8 @@ class Text2Image(LocalModel):
|
|
|
81
81
|
return _DEFAULT_IGNORE + [p.strip() for p in extra.split(",") if p.strip()]
|
|
82
82
|
|
|
83
83
|
@classmethod
|
|
84
|
-
def client(cls,
|
|
85
|
-
return ServedGeneratingModel(
|
|
84
|
+
def client(cls, deployment: cortexgrid.Deployment[ServedGeneratingModel]) -> ServedGeneratingModel:
|
|
85
|
+
return ServedGeneratingModel(key=deployment.key, url=deployment.url)
|
|
86
86
|
|
|
87
87
|
def __init__(self, deployment: cortexgrid.DeploymentKey) -> None:
|
|
88
88
|
path = cortexgrid.load_model(deployment.family, deployment.suffix, deployment.run_name)
|
|
@@ -123,8 +123,8 @@ class Text2Text(LocalModel):
|
|
|
123
123
|
return {**super().config(), ENABLE_THINKING_PARAM: "true"}
|
|
124
124
|
|
|
125
125
|
@classmethod
|
|
126
|
-
def client(cls,
|
|
127
|
-
return ServedCompletingModel(
|
|
126
|
+
def client(cls, deployment: cortexgrid.Deployment[ServedCompletingModel]) -> ServedCompletingModel:
|
|
127
|
+
return ServedCompletingModel(key=deployment.key, url=deployment.url)
|
|
128
128
|
|
|
129
129
|
def __init__(self, deployment: cortexgrid.DeploymentKey) -> None:
|
|
130
130
|
path = cortexgrid.load_model(
|
{cortexgrid_infer-0.3.7 → cortexgrid_infer-0.3.8}/cortexgrid_infer/serve_apps/text_rewriter.py
RENAMED
|
@@ -47,8 +47,8 @@ def _bucket(length: int) -> int:
|
|
|
47
47
|
@serve.ingress(_app)
|
|
48
48
|
class TextRewriter(LocalModel):
|
|
49
49
|
@classmethod
|
|
50
|
-
def client(cls,
|
|
51
|
-
return ServedRewritingModel(
|
|
50
|
+
def client(cls, deployment: cortexgrid.Deployment[ServedRewritingModel]) -> ServedRewritingModel:
|
|
51
|
+
return ServedRewritingModel(key=deployment.key, url=deployment.url)
|
|
52
52
|
|
|
53
53
|
def __init__(self, deployment: cortexgrid.DeploymentKey) -> None:
|
|
54
54
|
path = cortexgrid.load_model(deployment.family, deployment.suffix, deployment.run_name)
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
[project]
|
|
2
2
|
name = "cortexgrid-infer"
|
|
3
|
-
version = "0.3.
|
|
3
|
+
version = "0.3.8"
|
|
4
4
|
description = "Serve apps per task (text-to-text, text-to-image, image-to-mesh) and importers per source (HuggingFace) for running models on cortexgrid"
|
|
5
5
|
readme = "README.md"
|
|
6
6
|
license = "Apache-2.0"
|
|
@@ -17,7 +17,7 @@ dependencies = [
|
|
|
17
17
|
# redundant PUT - which is why this library has no reuse guard of its own.
|
|
18
18
|
# 0.3.12: DeploymentKey - a serve-app is constructed with its deployment's
|
|
19
19
|
# key and reads that deployment's config with model_config(key).
|
|
20
|
-
"cortexgrid>=0.3.
|
|
20
|
+
"cortexgrid>=0.3.16",
|
|
21
21
|
"torch>=2.0.0",
|
|
22
22
|
# 4.47: CompileConfig, which the completion serve app hands to `generate`
|
|
23
23
|
# alongside a static cache so transformers compiles the decode step itself.
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{cortexgrid_infer-0.3.7 → cortexgrid_infer-0.3.8}/cortexgrid_infer/serve_apps/gemini/__init__.py
RENAMED
|
File without changes
|
{cortexgrid_infer-0.3.7 → cortexgrid_infer-0.3.8}/cortexgrid_infer/serve_apps/gemini/base.py
RENAMED
|
File without changes
|
{cortexgrid_infer-0.3.7 → cortexgrid_infer-0.3.8}/cortexgrid_infer/serve_apps/streamed_completion.py
RENAMED
|
File without changes
|
|
File without changes
|