fastsdk 0.2.32__tar.gz → 0.3.1__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.
- {fastsdk-0.2.32 → fastsdk-0.3.1}/PKG-INFO +138 -80
- fastsdk-0.3.1/README.md +165 -0
- fastsdk-0.3.1/fastsdk/__init__.py +27 -0
- fastsdk-0.3.1/fastsdk/api.py +132 -0
- fastsdk-0.3.1/fastsdk/cli.py +343 -0
- fastsdk-0.3.1/fastsdk/fastClient.py +113 -0
- fastsdk-0.3.1/fastsdk/fastSDK.py +313 -0
- fastsdk-0.3.1/fastsdk/fastStub.py +46 -0
- fastsdk-0.3.1/fastsdk/sdk_factory/__init__.py +11 -0
- {fastsdk-0.2.32 → fastsdk-0.3.1}/fastsdk/sdk_factory/sdk_factory.py +12 -12
- fastsdk-0.3.1/fastsdk/service_interaction/__init__.py +9 -0
- fastsdk-0.3.1/fastsdk/service_interaction/api_job_manager.py +63 -0
- fastsdk-0.3.1/fastsdk/service_interaction/api_seex.py +115 -0
- fastsdk-0.3.1/fastsdk/service_interaction/async_bridge.py +47 -0
- fastsdk-0.3.1/fastsdk/service_interaction/job_runtime.py +264 -0
- fastsdk-0.3.1/fastsdk/service_interaction/job_tasks.py +192 -0
- fastsdk-0.3.1/fastsdk/service_interaction/pipeline_planner.py +58 -0
- fastsdk-0.3.1/fastsdk/service_interaction/provider_factory.py +111 -0
- fastsdk-0.3.1/fastsdk/service_interaction/provider_stack_registry.py +76 -0
- fastsdk-0.3.1/fastsdk/service_interaction/request/api_client.py +369 -0
- {fastsdk-0.2.32 → fastsdk-0.3.1}/fastsdk/service_interaction/request/api_client_replicate.py +8 -2
- {fastsdk-0.2.32 → fastsdk-0.3.1}/fastsdk/service_interaction/request/api_client_runpod.py +1 -2
- {fastsdk-0.2.32 → fastsdk-0.3.1}/fastsdk/service_interaction/request/api_client_socaity.py +14 -39
- {fastsdk-0.2.32 → fastsdk-0.3.1}/fastsdk/service_interaction/response/response_parser.py +26 -10
- fastsdk-0.3.1/fastsdk/service_interaction/response/response_schemas.py +30 -0
- fastsdk-0.3.1/fastsdk/service_interaction/response/sse_assembly.py +109 -0
- fastsdk-0.3.1/fastsdk/service_interaction/response/stream_session.py +194 -0
- fastsdk-0.3.1/fastsdk/service_specification_loader/replicate_loader.py +127 -0
- {fastsdk-0.2.32 → fastsdk-0.3.1}/fastsdk/service_specification_loader/runpod_open_api_loader.py +3 -3
- {fastsdk-0.2.32 → fastsdk-0.3.1}/fastsdk/service_specification_loader/spec_loader.py +2 -33
- {fastsdk-0.2.32 → fastsdk-0.3.1}/fastsdk.egg-info/PKG-INFO +138 -80
- {fastsdk-0.2.32 → fastsdk-0.3.1}/fastsdk.egg-info/SOURCES.txt +19 -2
- fastsdk-0.3.1/fastsdk.egg-info/entry_points.txt +2 -0
- {fastsdk-0.2.32 → fastsdk-0.3.1}/fastsdk.egg-info/requires.txt +4 -0
- {fastsdk-0.2.32 → fastsdk-0.3.1}/pyproject.toml +15 -3
- fastsdk-0.3.1/test/test_apipod_debug_test_services.py +427 -0
- fastsdk-0.3.1/test/test_apipod_registry_service_management_example.py +161 -0
- fastsdk-0.3.1/test/test_client_factory.py +27 -0
- fastsdk-0.3.1/test/test_client_factory_manual.py +117 -0
- {fastsdk-0.2.32 → fastsdk-0.3.1}/test/test_client_from_fastapi.py +14 -18
- {fastsdk-0.2.32 → fastsdk-0.3.1}/test/test_client_from_runpod_serverless.py +12 -16
- fastsdk-0.3.1/test/test_localhost_services.py +42 -0
- {fastsdk-0.2.32 → fastsdk-0.3.1}/test/test_manual_sdk.py +14 -14
- fastsdk-0.3.1/test/test_replicate.py +83 -0
- fastsdk-0.2.32/README.md +0 -110
- fastsdk-0.2.32/fastsdk/__init__.py +0 -14
- fastsdk-0.2.32/fastsdk/fastClient.py +0 -76
- fastsdk-0.2.32/fastsdk/fastSDK.py +0 -373
- fastsdk-0.2.32/fastsdk/sdk_factory/__init__.py +0 -9
- fastsdk-0.2.32/fastsdk/service_interaction/__init__.py +0 -16
- fastsdk-0.2.32/fastsdk/service_interaction/api_job_manager.py +0 -384
- fastsdk-0.2.32/fastsdk/service_interaction/api_seex.py +0 -210
- fastsdk-0.2.32/fastsdk/service_interaction/request/api_client.py +0 -200
- fastsdk-0.2.32/fastsdk/service_interaction/response/response_parser_strategies.py +0 -188
- fastsdk-0.2.32/fastsdk/service_interaction/response/response_schemas.py +0 -141
- fastsdk-0.2.32/test/test_client_factory.py +0 -119
- {fastsdk-0.2.32 → fastsdk-0.3.1}/LICENSE +0 -0
- {fastsdk-0.2.32 → fastsdk-0.3.1}/fastsdk/sdk_factory/sdk_template.j2 +0 -0
- {fastsdk-0.2.32 → fastsdk-0.3.1}/fastsdk/service_interaction/request/__init__.py +0 -0
- {fastsdk-0.2.32 → fastsdk-0.3.1}/fastsdk/service_interaction/request/file_handler.py +0 -0
- {fastsdk-0.2.32 → fastsdk-0.3.1}/fastsdk/service_interaction/response/api_job_status.py +0 -0
- {fastsdk-0.2.32 → fastsdk-0.3.1}/fastsdk.egg-info/dependency_links.txt +0 -0
- {fastsdk-0.2.32 → fastsdk-0.3.1}/fastsdk.egg-info/top_level.txt +0 -0
- {fastsdk-0.2.32 → fastsdk-0.3.1}/setup.cfg +0 -0
- {fastsdk-0.2.32 → fastsdk-0.3.1}/test/test_httpx_api.py +0 -0
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: fastsdk
|
|
3
|
-
Version: 0.
|
|
4
|
-
Summary:
|
|
3
|
+
Version: 0.3.1
|
|
4
|
+
Summary: Turn any AI/web service (OpenAPI, Replicate, RunPod, APIPod) into a native-feeling Python client.
|
|
5
5
|
Author: SocAIty
|
|
6
6
|
License: GNU GENERAL PUBLIC LICENSE
|
|
7
7
|
Version 3, 29 June 2007
|
|
@@ -692,117 +692,175 @@ Requires-Dist: singleton_decorator==1.0.0
|
|
|
692
692
|
Requires-Dist: jinja2>=3.1.6
|
|
693
693
|
Requires-Dist: fastcloud>=0.0.14
|
|
694
694
|
Requires-Dist: apipod-registry>=0.0.2
|
|
695
|
+
Requires-Dist: socaity-schemas>=0.0.1
|
|
695
696
|
Provides-Extra: dev
|
|
696
697
|
Requires-Dist: pytest; extra == "dev"
|
|
698
|
+
Provides-Extra: replicate
|
|
699
|
+
Requires-Dist: replicate; extra == "replicate"
|
|
697
700
|
Dynamic: license-file
|
|
698
701
|
|
|
702
|
+
<p align="center">
|
|
703
|
+
<img src="docs/assets/banner.png" alt="fastSDK. Any service. One typed client." width="100%" />
|
|
704
|
+
</p>
|
|
699
705
|
|
|
700
|
-
<h1 align="center" style="margin-top:-25px">fastSDK</h1>
|
|
701
706
|
<p align="center">
|
|
702
|
-
<
|
|
707
|
+
<a href="https://pypi.org/project/fastsdk/"><img src="https://img.shields.io/pypi/v/fastsdk?labelColor=000000&color=76B900" alt="PyPI version"></a>
|
|
708
|
+
<a href="https://pypi.org/project/fastsdk/"><img src="https://img.shields.io/pypi/pyversions/fastsdk?labelColor=000000&color=76B900" alt="Python versions"></a>
|
|
709
|
+
<a href="https://github.com/SocAIty/fastSDK"><img src="https://img.shields.io/badge/github-SocAIty%2FfastSDK-76B900?labelColor=000000" alt="GitHub"></a>
|
|
710
|
+
<a href="LICENSE"><img src="https://img.shields.io/badge/license-GPLv3-76B900?labelColor=000000" alt="License"></a>
|
|
703
711
|
</p>
|
|
704
|
-
<h3 align="center" style="margin-top:-10px">
|
|
712
|
+
<h3 align="center" style="margin-top:-10px">Call any AI / web service like a native Python function</h3>
|
|
705
713
|
|
|
714
|
+
fastSDK turns any hosted service — OpenAPI/FastAPI, [APIPod](https://github.com/SocAIty/APIPod), [RunPod](https://www.runpod.io), [Replicate](https://replicate.com), [Cog](https://github.com/replicate/cog) — into a Python client that feels like a local library: typed methods, file upload/download, async job handling and parallel execution included.
|
|
706
715
|
|
|
716
|
+
Point it at a service. Call it like a function. That's the whole idea.
|
|
707
717
|
|
|
708
|
-
|
|
709
|
-
|
|
710
|
-
FastSDK creates a full functioning client for any openapi service.
|
|
718
|
+
```python
|
|
719
|
+
import fastsdk
|
|
711
720
|
|
|
712
|
-
|
|
721
|
+
client = fastsdk.connect("http://localhost:8009")
|
|
722
|
+
job = client.submit_job("/text2voice", text="hello world")
|
|
723
|
+
audio = job.get_result()
|
|
724
|
+
audio.save("hello.mp3")
|
|
725
|
+
```
|
|
713
726
|
|
|
714
|
-
|
|
715
|
-
In a first approach you would just use the [requests](https://pypi.org/project/requests/) library and send the requests to the server. However, while you do so,
|
|
716
|
-
your cpu is idle waiting for the request to finish. Over time your requirements get bigger, suddenly you do not only have one endpoint but multiples.
|
|
717
|
-
You will do different requests in parallel, you need to transfer files, and you struggle to do so in a structured, performant way.
|
|
718
|
-
Suddenly you end up in a threading, asyncio and complexity hell with many inconsistencies. You realize that you cannot transfer your 1GB video via an simple web request to your beautiful API.
|
|
719
|
-
All these problems are solved with the fastSDK.
|
|
720
|
-
Simple API calls, file uploads, job handling, and cloud storage providers are just a few features of the fastSDK.
|
|
727
|
+
## Why fastSDK?
|
|
721
728
|
|
|
722
|
-
|
|
723
|
-
|
|
729
|
+
Calling a web service from Python sounds trivial until you actually do it in production:
|
|
730
|
+
you wait synchronously on long-running ML jobs, you hand-write request code for every endpoint, you fight with file uploads (try sending a 1 GB video through `requests`), you poll job status loops, and you reinvent threading to run requests in parallel.
|
|
724
731
|
|
|
725
|
-
|
|
732
|
+
fastSDK solves exactly that, and nothing else:
|
|
733
|
+
|
|
734
|
+
- **One call = one job.** Every call returns a job object immediately. Get the result when you need it, run hundreds of jobs in parallel meanwhile.
|
|
735
|
+
- **Files just work.** Images, audio, video are handled by [media-toolkit](https://github.com/SocAIty/media-toolkit) — local paths, URLs, bytes or numpy arrays in; media objects out. Large files are uploaded via cloud storage (S3, Azure) when configured.
|
|
736
|
+
- **Job-based providers are normalized.** Replicate, RunPod serverless, APIPod and Socaity all expose "submit, then poll" APIs with different wire formats. fastSDK handles submission, polling, progress and cancellation uniformly.
|
|
737
|
+
- **Codegen when you want it, not when you don't.** Use `connect()` for instant access, or `generate_stub()` to get a typed `.py` client with one method per endpoint - autocomplete and docstrings included.
|
|
738
|
+
|
|
739
|
+
## Installation
|
|
726
740
|
|
|
727
|
-
Out of the box works with following services:
|
|
728
|
-
- Services created with [APIPod](https://github.com/SocAIty/APIPod) which return a job object.
|
|
729
|
-
- [Runpod](https://github.com/runpod/runpod-python) services
|
|
730
|
-
- [Cog](https://github.com/replicate/cog) services
|
|
731
|
-
- OpenAPI 3.0 / RestAPIs
|
|
732
|
-
- [fastAPI](https://github.com/tiangolo/fastapi)
|
|
733
|
-
- [Flask](https://flask.palletsprojects.com/en/2.0.x/)
|
|
734
|
-
|
|
735
|
-
Can be used together with
|
|
736
|
-
- [Socaity.ai](https://www.socaity.ai) services
|
|
737
|
-
- [Replicate.ai](https://www.replicate.com) services
|
|
738
|
-
|
|
739
|
-
### Features:
|
|
740
|
-
- Easy file upload, download thanks to [media-toolkit](https://github.com/SocAIty/media-toolkit).
|
|
741
|
-
- Support for cloud storage providers like [Azure Blob Storage](https://azure.microsoft.com/de-de/products/storage/blobs/?msockid=015b54a7ada76c452812402bac8c6dde) and [Amazon S3](https://aws.amazon.com/es/s3/).
|
|
742
|
-
- Async and Threaded job support. Execute multiple requests and heavy preprocessing tasks in parallel and with high speed.
|
|
743
|
-
- Massively parallel job and request execution.
|
|
744
|
-
- Working with services that create "Jobs". The SDK will wait for the job to finish and return the result.
|
|
745
|
-
- Support for [APIPod](https://github.com/SocAIty/APIPod) and [runpod (serverless)](https://www.runpod.io/serverless-gpu) endpoints.
|
|
746
|
-
- Retrieving the job status, progres and print status updates.
|
|
747
|
-
- Streaming of files
|
|
748
|
-
- Automatic serialization of data types
|
|
749
|
-
|
|
750
|
-
# Installation
|
|
751
|
-
|
|
752
|
-
To install from PyPI:
|
|
753
|
-
This version includes all features needed to conveniently wrap your API into an SDK.
|
|
754
741
|
```bash
|
|
755
|
-
pip install fastsdk
|
|
742
|
+
pip install fastsdk # core
|
|
743
|
+
pip install fastsdk[replicate] # + Replicate model support
|
|
744
|
+
```
|
|
745
|
+
|
|
746
|
+
## Get started
|
|
747
|
+
|
|
748
|
+
### Option A: connect — use a service right now
|
|
749
|
+
|
|
750
|
+
No files, no codegen. Works with a URL, an `openapi.json` path, or a Replicate model reference.
|
|
751
|
+
|
|
752
|
+
```python
|
|
753
|
+
import fastsdk
|
|
754
|
+
|
|
755
|
+
client = fastsdk.connect("http://localhost:8009")
|
|
756
|
+
job = client.submit_job("/text2voice", text="hello world")
|
|
757
|
+
result = job.get_result()
|
|
756
758
|
```
|
|
757
759
|
|
|
758
|
-
|
|
760
|
+
### Option B: generate_stub — typed clients for real projects
|
|
759
761
|
|
|
760
|
-
|
|
761
|
-
You can use an example openapi.json from our face2face service located in this repos under [/test/test_files/face2face.json](/test/test_files/face2face.json)
|
|
762
|
+
Generates a `.py` file with one typed method per endpoint. This is your SDK.
|
|
762
763
|
|
|
763
764
|
```python
|
|
764
|
-
|
|
765
|
-
|
|
765
|
+
import fastsdk
|
|
766
|
+
|
|
767
|
+
stub = fastsdk.generate_stub("http://localhost:8009", save_path="clients/")
|
|
768
|
+
print(stub.path, stub.class_name)
|
|
766
769
|
|
|
767
|
-
#
|
|
768
|
-
|
|
769
|
-
|
|
770
|
-
|
|
770
|
+
# use it immediately ...
|
|
771
|
+
client = stub.client()
|
|
772
|
+
job = client.text2voice(text="hello world")
|
|
773
|
+
|
|
774
|
+
# ... or import it in your next run like any other module
|
|
775
|
+
# from clients.speechcraft import speechcraft
|
|
776
|
+
# client = speechcraft()
|
|
771
777
|
```
|
|
772
778
|
|
|
773
|
-
|
|
774
|
-
|
|
775
|
-
|
|
779
|
+
Re-running `generate_stub` is safe: the file is overwritten and the service registration is updated, not duplicated.
|
|
780
|
+
|
|
781
|
+
### Replicate models
|
|
782
|
+
|
|
783
|
+
Official models (called via `/v1/models/{owner}/{name}/predictions`) and community models (called via `/v1/predictions` with a version) are resolved automatically — you just name the model:
|
|
784
|
+
|
|
776
785
|
```python
|
|
777
|
-
|
|
778
|
-
|
|
779
|
-
|
|
786
|
+
import fastsdk # requires: pip install fastsdk[replicate] and REPLICATE_API_KEY
|
|
787
|
+
|
|
788
|
+
stub = fastsdk.generate_stub("replicate:black-forest-labs/flux-schnell", save_path="clients/")
|
|
789
|
+
flux = stub.client()
|
|
790
|
+
job = flux(prompt="a t-rex on a skateboard")
|
|
791
|
+
image = job.get_result()
|
|
780
792
|
```
|
|
781
|
-
|
|
782
|
-
|
|
793
|
+
|
|
794
|
+
### Working with jobs
|
|
783
795
|
|
|
784
796
|
```python
|
|
785
|
-
|
|
786
|
-
|
|
787
|
-
|
|
788
|
-
|
|
797
|
+
job = client.swap_img_to_img(source_img="face1.jpg", target_img="face2.jpg")
|
|
798
|
+
job.get_result() # block until done and return the result
|
|
799
|
+
job.cancel() # cancel locally and remotely (provider permitting)
|
|
800
|
+
|
|
801
|
+
# run many jobs in parallel - this is where fastSDK shines
|
|
802
|
+
jobs = [client.text2voice(text=t) for t in hundred_texts]
|
|
803
|
+
results = fastsdk.gather_results(jobs)
|
|
804
|
+
```
|
|
805
|
+
|
|
806
|
+
### API keys
|
|
807
|
+
|
|
808
|
+
Pass `api_key=...` to `connect()`, `generate_stub()` or the client constructor — or set environment variables: `REPLICATE_API_KEY`, `RUNPOD_API_KEY`, `SOCAITY_API_KEY`, or `<SERVICE_ID>_API_KEY` for your own services.
|
|
809
|
+
|
|
810
|
+
## The four concepts
|
|
811
|
+
|
|
812
|
+
| Concept | What it is |
|
|
813
|
+
|---|---|
|
|
814
|
+
| **Service definition** | The parsed, normalized description of a service: endpoints, parameters, address, provider type. Get one with `fastsdk.inspect_service(source)` — it has no side effects. |
|
|
815
|
+
| **Registry** | An in-process directory of service definitions, shared by all clients. `register_service()` adds to it; generated stubs look their service up in it by ID. |
|
|
816
|
+
| **Client** | The runtime object you call (`FastClient`). It submits jobs to the service. `connect()` gives you a generic one instantly. |
|
|
817
|
+
| **Stub** | A generated `.py` file containing a client subclass with one typed method per endpoint. Made by `generate_stub()`; it's plain code — read it, version it, ship it. |
|
|
818
|
+
|
|
819
|
+
## CLI
|
|
820
|
+
|
|
821
|
+
Everything above also works from the terminal — same verbs, same behavior:
|
|
822
|
+
|
|
823
|
+
```bash
|
|
824
|
+
# What can this service do?
|
|
825
|
+
fastsdk inspect http://localhost:8009
|
|
826
|
+
|
|
827
|
+
# Generate a typed client stub
|
|
828
|
+
fastsdk generate http://localhost:8009 -o clients/ --name SpeechCraft
|
|
829
|
+
fastsdk generate replicate:black-forest-labs/flux-schnell --api-key r8_...
|
|
830
|
+
|
|
831
|
+
# Call an endpoint without writing any code (curl for AI services)
|
|
832
|
+
fastsdk call http://localhost:8009 /text2voice --text "hello world" -o hello.mp3
|
|
833
|
+
|
|
834
|
+
# Keep services around by name (persisted in ~/.fastsdk/registry)
|
|
835
|
+
fastsdk registry add http://localhost:8009 --name speechcraft
|
|
836
|
+
fastsdk registry list
|
|
837
|
+
fastsdk call speechcraft /text2voice --text "hi again"
|
|
838
|
+
```
|
|
789
839
|
|
|
790
|
-
|
|
791
|
-
In settings.py the default environment variables are set.
|
|
840
|
+
## Service compatibility
|
|
792
841
|
|
|
793
|
-
|
|
842
|
+
Works out of the box with:
|
|
843
|
+
- [APIPod](https://github.com/SocAIty/APIPod) services (job-based, the natural counterpart to fastSDK)
|
|
844
|
+
- [Replicate](https://replicate.com) models (official and community)
|
|
845
|
+
- [RunPod serverless](https://www.runpod.io/serverless-gpu) endpoints
|
|
846
|
+
- [Cog](https://github.com/replicate/cog) services
|
|
847
|
+
- Any OpenAPI 3.0 service ([FastAPI](https://github.com/tiangolo/fastapi), [Flask](https://flask.palletsprojects.com/), ...)
|
|
848
|
+
- [Socaity.ai](https://www.socaity.ai) services
|
|
849
|
+
|
|
850
|
+
## fastSDK + APIPod
|
|
794
851
|
|
|
795
852
|
<img src="https://github.com/SocAIty/APIPod/blob/main/docs/fastsdk_to_apipod.png?raw=true" width="50%" />
|
|
796
853
|
|
|
797
|
-
[APIPod](https://github.com/SocAIty/APIPod)
|
|
798
|
-
|
|
799
|
-
Create your service now.
|
|
854
|
+
[APIPod](https://github.com/SocAIty/APIPod) builds and deploys the services; fastSDK consumes them. Two beating hearts :two_hearts: for service ↔ client interaction.
|
|
855
|
+
|
|
800
856
|
|
|
801
|
-
|
|
857
|
+
## Contribute
|
|
802
858
|
|
|
803
|
-
We at
|
|
804
|
-
|
|
805
|
-
fastSDK is licensed
|
|
859
|
+
We at SocAIty want to provide the best tools to bring generative AI to the cloud.
|
|
860
|
+
Report bugs, ideas and feature requests in the issues section.
|
|
861
|
+
fastSDK is MIT-licensed and free to use. Leave a star to support us!
|
|
806
862
|
|
|
807
|
-
|
|
808
|
-
|
|
863
|
+
---
|
|
864
|
+
<p align="center">
|
|
865
|
+
Made with ❤️ by <a href="https://www.socaity.ai?utm_source=github&utm_content=fastsdk-20-29-06-2026">SocAIty</a>
|
|
866
|
+
</p>
|
fastsdk-0.3.1/README.md
ADDED
|
@@ -0,0 +1,165 @@
|
|
|
1
|
+
<p align="center">
|
|
2
|
+
<img src="docs/assets/banner.png" alt="fastSDK. Any service. One typed client." width="100%" />
|
|
3
|
+
</p>
|
|
4
|
+
|
|
5
|
+
<p align="center">
|
|
6
|
+
<a href="https://pypi.org/project/fastsdk/"><img src="https://img.shields.io/pypi/v/fastsdk?labelColor=000000&color=76B900" alt="PyPI version"></a>
|
|
7
|
+
<a href="https://pypi.org/project/fastsdk/"><img src="https://img.shields.io/pypi/pyversions/fastsdk?labelColor=000000&color=76B900" alt="Python versions"></a>
|
|
8
|
+
<a href="https://github.com/SocAIty/fastSDK"><img src="https://img.shields.io/badge/github-SocAIty%2FfastSDK-76B900?labelColor=000000" alt="GitHub"></a>
|
|
9
|
+
<a href="LICENSE"><img src="https://img.shields.io/badge/license-GPLv3-76B900?labelColor=000000" alt="License"></a>
|
|
10
|
+
</p>
|
|
11
|
+
<h3 align="center" style="margin-top:-10px">Call any AI / web service like a native Python function</h3>
|
|
12
|
+
|
|
13
|
+
fastSDK turns any hosted service — OpenAPI/FastAPI, [APIPod](https://github.com/SocAIty/APIPod), [RunPod](https://www.runpod.io), [Replicate](https://replicate.com), [Cog](https://github.com/replicate/cog) — into a Python client that feels like a local library: typed methods, file upload/download, async job handling and parallel execution included.
|
|
14
|
+
|
|
15
|
+
Point it at a service. Call it like a function. That's the whole idea.
|
|
16
|
+
|
|
17
|
+
```python
|
|
18
|
+
import fastsdk
|
|
19
|
+
|
|
20
|
+
client = fastsdk.connect("http://localhost:8009")
|
|
21
|
+
job = client.submit_job("/text2voice", text="hello world")
|
|
22
|
+
audio = job.get_result()
|
|
23
|
+
audio.save("hello.mp3")
|
|
24
|
+
```
|
|
25
|
+
|
|
26
|
+
## Why fastSDK?
|
|
27
|
+
|
|
28
|
+
Calling a web service from Python sounds trivial until you actually do it in production:
|
|
29
|
+
you wait synchronously on long-running ML jobs, you hand-write request code for every endpoint, you fight with file uploads (try sending a 1 GB video through `requests`), you poll job status loops, and you reinvent threading to run requests in parallel.
|
|
30
|
+
|
|
31
|
+
fastSDK solves exactly that, and nothing else:
|
|
32
|
+
|
|
33
|
+
- **One call = one job.** Every call returns a job object immediately. Get the result when you need it, run hundreds of jobs in parallel meanwhile.
|
|
34
|
+
- **Files just work.** Images, audio, video are handled by [media-toolkit](https://github.com/SocAIty/media-toolkit) — local paths, URLs, bytes or numpy arrays in; media objects out. Large files are uploaded via cloud storage (S3, Azure) when configured.
|
|
35
|
+
- **Job-based providers are normalized.** Replicate, RunPod serverless, APIPod and Socaity all expose "submit, then poll" APIs with different wire formats. fastSDK handles submission, polling, progress and cancellation uniformly.
|
|
36
|
+
- **Codegen when you want it, not when you don't.** Use `connect()` for instant access, or `generate_stub()` to get a typed `.py` client with one method per endpoint - autocomplete and docstrings included.
|
|
37
|
+
|
|
38
|
+
## Installation
|
|
39
|
+
|
|
40
|
+
```bash
|
|
41
|
+
pip install fastsdk # core
|
|
42
|
+
pip install fastsdk[replicate] # + Replicate model support
|
|
43
|
+
```
|
|
44
|
+
|
|
45
|
+
## Get started
|
|
46
|
+
|
|
47
|
+
### Option A: connect — use a service right now
|
|
48
|
+
|
|
49
|
+
No files, no codegen. Works with a URL, an `openapi.json` path, or a Replicate model reference.
|
|
50
|
+
|
|
51
|
+
```python
|
|
52
|
+
import fastsdk
|
|
53
|
+
|
|
54
|
+
client = fastsdk.connect("http://localhost:8009")
|
|
55
|
+
job = client.submit_job("/text2voice", text="hello world")
|
|
56
|
+
result = job.get_result()
|
|
57
|
+
```
|
|
58
|
+
|
|
59
|
+
### Option B: generate_stub — typed clients for real projects
|
|
60
|
+
|
|
61
|
+
Generates a `.py` file with one typed method per endpoint. This is your SDK.
|
|
62
|
+
|
|
63
|
+
```python
|
|
64
|
+
import fastsdk
|
|
65
|
+
|
|
66
|
+
stub = fastsdk.generate_stub("http://localhost:8009", save_path="clients/")
|
|
67
|
+
print(stub.path, stub.class_name)
|
|
68
|
+
|
|
69
|
+
# use it immediately ...
|
|
70
|
+
client = stub.client()
|
|
71
|
+
job = client.text2voice(text="hello world")
|
|
72
|
+
|
|
73
|
+
# ... or import it in your next run like any other module
|
|
74
|
+
# from clients.speechcraft import speechcraft
|
|
75
|
+
# client = speechcraft()
|
|
76
|
+
```
|
|
77
|
+
|
|
78
|
+
Re-running `generate_stub` is safe: the file is overwritten and the service registration is updated, not duplicated.
|
|
79
|
+
|
|
80
|
+
### Replicate models
|
|
81
|
+
|
|
82
|
+
Official models (called via `/v1/models/{owner}/{name}/predictions`) and community models (called via `/v1/predictions` with a version) are resolved automatically — you just name the model:
|
|
83
|
+
|
|
84
|
+
```python
|
|
85
|
+
import fastsdk # requires: pip install fastsdk[replicate] and REPLICATE_API_KEY
|
|
86
|
+
|
|
87
|
+
stub = fastsdk.generate_stub("replicate:black-forest-labs/flux-schnell", save_path="clients/")
|
|
88
|
+
flux = stub.client()
|
|
89
|
+
job = flux(prompt="a t-rex on a skateboard")
|
|
90
|
+
image = job.get_result()
|
|
91
|
+
```
|
|
92
|
+
|
|
93
|
+
### Working with jobs
|
|
94
|
+
|
|
95
|
+
```python
|
|
96
|
+
job = client.swap_img_to_img(source_img="face1.jpg", target_img="face2.jpg")
|
|
97
|
+
job.get_result() # block until done and return the result
|
|
98
|
+
job.cancel() # cancel locally and remotely (provider permitting)
|
|
99
|
+
|
|
100
|
+
# run many jobs in parallel - this is where fastSDK shines
|
|
101
|
+
jobs = [client.text2voice(text=t) for t in hundred_texts]
|
|
102
|
+
results = fastsdk.gather_results(jobs)
|
|
103
|
+
```
|
|
104
|
+
|
|
105
|
+
### API keys
|
|
106
|
+
|
|
107
|
+
Pass `api_key=...` to `connect()`, `generate_stub()` or the client constructor — or set environment variables: `REPLICATE_API_KEY`, `RUNPOD_API_KEY`, `SOCAITY_API_KEY`, or `<SERVICE_ID>_API_KEY` for your own services.
|
|
108
|
+
|
|
109
|
+
## The four concepts
|
|
110
|
+
|
|
111
|
+
| Concept | What it is |
|
|
112
|
+
|---|---|
|
|
113
|
+
| **Service definition** | The parsed, normalized description of a service: endpoints, parameters, address, provider type. Get one with `fastsdk.inspect_service(source)` — it has no side effects. |
|
|
114
|
+
| **Registry** | An in-process directory of service definitions, shared by all clients. `register_service()` adds to it; generated stubs look their service up in it by ID. |
|
|
115
|
+
| **Client** | The runtime object you call (`FastClient`). It submits jobs to the service. `connect()` gives you a generic one instantly. |
|
|
116
|
+
| **Stub** | A generated `.py` file containing a client subclass with one typed method per endpoint. Made by `generate_stub()`; it's plain code — read it, version it, ship it. |
|
|
117
|
+
|
|
118
|
+
## CLI
|
|
119
|
+
|
|
120
|
+
Everything above also works from the terminal — same verbs, same behavior:
|
|
121
|
+
|
|
122
|
+
```bash
|
|
123
|
+
# What can this service do?
|
|
124
|
+
fastsdk inspect http://localhost:8009
|
|
125
|
+
|
|
126
|
+
# Generate a typed client stub
|
|
127
|
+
fastsdk generate http://localhost:8009 -o clients/ --name SpeechCraft
|
|
128
|
+
fastsdk generate replicate:black-forest-labs/flux-schnell --api-key r8_...
|
|
129
|
+
|
|
130
|
+
# Call an endpoint without writing any code (curl for AI services)
|
|
131
|
+
fastsdk call http://localhost:8009 /text2voice --text "hello world" -o hello.mp3
|
|
132
|
+
|
|
133
|
+
# Keep services around by name (persisted in ~/.fastsdk/registry)
|
|
134
|
+
fastsdk registry add http://localhost:8009 --name speechcraft
|
|
135
|
+
fastsdk registry list
|
|
136
|
+
fastsdk call speechcraft /text2voice --text "hi again"
|
|
137
|
+
```
|
|
138
|
+
|
|
139
|
+
## Service compatibility
|
|
140
|
+
|
|
141
|
+
Works out of the box with:
|
|
142
|
+
- [APIPod](https://github.com/SocAIty/APIPod) services (job-based, the natural counterpart to fastSDK)
|
|
143
|
+
- [Replicate](https://replicate.com) models (official and community)
|
|
144
|
+
- [RunPod serverless](https://www.runpod.io/serverless-gpu) endpoints
|
|
145
|
+
- [Cog](https://github.com/replicate/cog) services
|
|
146
|
+
- Any OpenAPI 3.0 service ([FastAPI](https://github.com/tiangolo/fastapi), [Flask](https://flask.palletsprojects.com/), ...)
|
|
147
|
+
- [Socaity.ai](https://www.socaity.ai) services
|
|
148
|
+
|
|
149
|
+
## fastSDK + APIPod
|
|
150
|
+
|
|
151
|
+
<img src="https://github.com/SocAIty/APIPod/blob/main/docs/fastsdk_to_apipod.png?raw=true" width="50%" />
|
|
152
|
+
|
|
153
|
+
[APIPod](https://github.com/SocAIty/APIPod) builds and deploys the services; fastSDK consumes them. Two beating hearts :two_hearts: for service ↔ client interaction.
|
|
154
|
+
|
|
155
|
+
|
|
156
|
+
## Contribute
|
|
157
|
+
|
|
158
|
+
We at SocAIty want to provide the best tools to bring generative AI to the cloud.
|
|
159
|
+
Report bugs, ideas and feature requests in the issues section.
|
|
160
|
+
fastSDK is MIT-licensed and free to use. Leave a star to support us!
|
|
161
|
+
|
|
162
|
+
---
|
|
163
|
+
<p align="center">
|
|
164
|
+
Made with ❤️ by <a href="https://www.socaity.ai?utm_source=github&utm_content=fastsdk-20-29-06-2026">SocAIty</a>
|
|
165
|
+
</p>
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
from .fastStub import FastStub
|
|
2
|
+
from media_toolkit import MediaFile, ImageFile, VideoFile, AudioFile
|
|
3
|
+
from meseex import gather_results, gather_results_async
|
|
4
|
+
|
|
5
|
+
from .api import (
|
|
6
|
+
connect,
|
|
7
|
+
inspect_service,
|
|
8
|
+
generate_stub,
|
|
9
|
+
register_service,
|
|
10
|
+
get_service,
|
|
11
|
+
list_services,
|
|
12
|
+
remove_service,
|
|
13
|
+
) # create_sdk is a deprecated alias of generate_stub
|
|
14
|
+
from .service_interaction.api_seex import APISeex
|
|
15
|
+
from .fastClient import FastClient
|
|
16
|
+
from .fastSDK import FastSDK
|
|
17
|
+
|
|
18
|
+
|
|
19
|
+
__all__ = [
|
|
20
|
+
# primary API
|
|
21
|
+
'connect', 'inspect_service', 'generate_stub', 'register_service',
|
|
22
|
+
'get_service', 'list_services', 'remove_service',
|
|
23
|
+
# classes
|
|
24
|
+
'FastStub', 'FastClient', 'APISeex', 'FastSDK',
|
|
25
|
+
# re-exports
|
|
26
|
+
'MediaFile', 'ImageFile', 'VideoFile', 'AudioFile', 'gather_results', 'gather_results_async'
|
|
27
|
+
]
|
|
@@ -0,0 +1,132 @@
|
|
|
1
|
+
"""
|
|
2
|
+
The public, module-level API of fastsdk.
|
|
3
|
+
|
|
4
|
+
These functions wrap the FastSDK singleton so users never have to deal with it directly:
|
|
5
|
+
|
|
6
|
+
import fastsdk
|
|
7
|
+
|
|
8
|
+
client = fastsdk.connect("http://localhost:8009") # use a service right now
|
|
9
|
+
stub = fastsdk.generate_stub("http://localhost:8009") # generate a client stub file
|
|
10
|
+
sd = fastsdk.inspect_service("replicate:owner/name") # look at a service without side effects
|
|
11
|
+
sd = fastsdk.register_service("./openapi.json") # add a service to the registry
|
|
12
|
+
"""
|
|
13
|
+
from pathlib import Path
|
|
14
|
+
from typing import Any, Dict, List, Optional, Union, TYPE_CHECKING
|
|
15
|
+
|
|
16
|
+
from socaity_schemas.service_definitions import ServiceDefinition
|
|
17
|
+
|
|
18
|
+
from fastsdk.fastSDK import FastSDK
|
|
19
|
+
|
|
20
|
+
if TYPE_CHECKING:
|
|
21
|
+
from fastsdk.fastClient import FastClient
|
|
22
|
+
from fastsdk.fastStub import FastStub
|
|
23
|
+
|
|
24
|
+
|
|
25
|
+
def connect(
|
|
26
|
+
source: Union[str, Path, Dict[str, Any], ServiceDefinition],
|
|
27
|
+
api_key: Optional[str] = None,
|
|
28
|
+
**kwargs
|
|
29
|
+
) -> 'FastClient':
|
|
30
|
+
"""
|
|
31
|
+
Connect to a service and get a ready-to-use client - no code generation, no files.
|
|
32
|
+
|
|
33
|
+
Args:
|
|
34
|
+
source: Service URL ("http://localhost:8009"), openapi.json path/dict, ServiceDefinition,
|
|
35
|
+
Replicate model reference ("replicate:owner/name") or a registered service ID/name.
|
|
36
|
+
api_key: Optional API key. Falls back to environment variables.
|
|
37
|
+
**kwargs: Additional service loading arguments (see inspect_service).
|
|
38
|
+
|
|
39
|
+
Returns:
|
|
40
|
+
FastClient. Call endpoints generically via client.submit_job("/endpoint", **params).
|
|
41
|
+
|
|
42
|
+
Example:
|
|
43
|
+
client = fastsdk.connect("http://localhost:8009")
|
|
44
|
+
job = client.submit_job("/text2voice", text="hello world")
|
|
45
|
+
audio = job.get_result()
|
|
46
|
+
"""
|
|
47
|
+
return FastSDK().connect(source, api_key=api_key, **kwargs)
|
|
48
|
+
|
|
49
|
+
|
|
50
|
+
def inspect_service(
|
|
51
|
+
source: Union[str, Path, Dict[str, Any], ServiceDefinition],
|
|
52
|
+
api_key: Optional[str] = None,
|
|
53
|
+
**kwargs
|
|
54
|
+
) -> ServiceDefinition:
|
|
55
|
+
"""
|
|
56
|
+
Load and parse a service into a ServiceDefinition without registering it anywhere.
|
|
57
|
+
Pure function: no side effects on the registry.
|
|
58
|
+
|
|
59
|
+
Args:
|
|
60
|
+
source: Service URL, openapi.json path/dict, Replicate model reference or ServiceDefinition.
|
|
61
|
+
api_key: Required for RunPod and Replicate sources.
|
|
62
|
+
**kwargs: Overrides such as service_name, service_id, service_address, specification, ...
|
|
63
|
+
|
|
64
|
+
Returns:
|
|
65
|
+
ServiceDefinition with endpoints, parameters and the resolved service address.
|
|
66
|
+
"""
|
|
67
|
+
return FastSDK.inspect_service(source, api_key=api_key, **kwargs)
|
|
68
|
+
|
|
69
|
+
|
|
70
|
+
def generate_stub(
|
|
71
|
+
source: Union[str, Path, Dict[str, Any], ServiceDefinition],
|
|
72
|
+
save_path: Optional[str] = None,
|
|
73
|
+
class_name: Optional[str] = None,
|
|
74
|
+
template: Optional[str] = None,
|
|
75
|
+
**kwargs
|
|
76
|
+
) -> 'FastStub':
|
|
77
|
+
"""
|
|
78
|
+
Generate a Python client stub file (.py) for a service. The generated class has one typed
|
|
79
|
+
method per endpoint. The service is also registered in the registry, so the stub can be
|
|
80
|
+
used immediately in the same process.
|
|
81
|
+
|
|
82
|
+
Args:
|
|
83
|
+
source: Service URL, openapi.json path/dict, ServiceDefinition, Replicate model
|
|
84
|
+
reference or a registered service ID/name.
|
|
85
|
+
save_path: File or directory path for the generated .py file. Defaults to the current directory.
|
|
86
|
+
class_name: Name of the generated class. Defaults to the (normalized) service name.
|
|
87
|
+
template: Optional custom Jinja2 template path.
|
|
88
|
+
**kwargs: Additional service loading arguments (e.g. api_key, service_name).
|
|
89
|
+
|
|
90
|
+
Returns:
|
|
91
|
+
GeneratedStub with .path, .class_name, .service_definition and .client().
|
|
92
|
+
|
|
93
|
+
Example:
|
|
94
|
+
stub = fastsdk.generate_stub("http://localhost:8009", save_path="clients/")
|
|
95
|
+
client = stub.client() # use it right away
|
|
96
|
+
# or in the next run:
|
|
97
|
+
# from clients.speechcraft import SpeechCraft
|
|
98
|
+
"""
|
|
99
|
+
return FastSDK().generate_stub(source, save_path=save_path, class_name=class_name, template=template, **kwargs)
|
|
100
|
+
|
|
101
|
+
|
|
102
|
+
def register_service(
|
|
103
|
+
source: Union[str, Path, Dict[str, Any], ServiceDefinition],
|
|
104
|
+
**kwargs
|
|
105
|
+
) -> ServiceDefinition:
|
|
106
|
+
"""
|
|
107
|
+
Load a service and add it to the registry. Idempotent: re-registering a service with the
|
|
108
|
+
same ID replaces the previous entry.
|
|
109
|
+
|
|
110
|
+
Args:
|
|
111
|
+
source: Service URL, openapi.json path/dict, Replicate model reference or ServiceDefinition.
|
|
112
|
+
**kwargs: Overrides such as service_name, service_id, service_address, api_key, ...
|
|
113
|
+
|
|
114
|
+
Returns:
|
|
115
|
+
The registered ServiceDefinition.
|
|
116
|
+
"""
|
|
117
|
+
return FastSDK().register_service(source, **kwargs)
|
|
118
|
+
|
|
119
|
+
|
|
120
|
+
def get_service(service_id_or_name: str) -> Optional[ServiceDefinition]:
|
|
121
|
+
"""Get a registered service by ID or name. Returns None if not found."""
|
|
122
|
+
return FastSDK().get_service(service_id_or_name)
|
|
123
|
+
|
|
124
|
+
|
|
125
|
+
def list_services() -> List[ServiceDefinition]:
|
|
126
|
+
"""List all services currently in the registry."""
|
|
127
|
+
return FastSDK().service_registry.list_services()
|
|
128
|
+
|
|
129
|
+
|
|
130
|
+
def remove_service(service_id_or_name: str) -> bool:
|
|
131
|
+
"""Remove a service from the registry. Returns True if it was removed."""
|
|
132
|
+
return FastSDK().service_registry.remove_service(service_id_or_name)
|