studio-workers 0.0.1__tar.gz → 1.4.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.
- studio_workers-1.4.0/LICENSE +141 -0
- studio_workers-1.4.0/PKG-INFO +86 -0
- studio_workers-1.4.0/README.md +56 -0
- studio_workers-1.4.0/README.pypi.md +46 -0
- studio_workers-1.4.0/pyproject.toml +104 -0
- studio_workers-1.4.0/studio_workers/__init__.py +3 -0
- studio_workers-1.4.0/studio_workers/adapters/__init__.py +3 -0
- studio_workers-1.4.0/studio_workers/cli.py +108 -0
- studio_workers-1.4.0/studio_workers/constants.py +1 -0
- studio_workers-1.4.0/studio_workers/contracts/__init__.py +82 -0
- studio_workers-1.4.0/studio_workers/contracts/downloaded_file.py +72 -0
- studio_workers-1.4.0/studio_workers/contracts/group_expansion.py +246 -0
- studio_workers-1.4.0/studio_workers/contracts/job_claim.py +49 -0
- studio_workers-1.4.0/studio_workers/contracts/log_schema.py +71 -0
- studio_workers-1.4.0/studio_workers/contracts/redaction.py +250 -0
- studio_workers-1.4.0/studio_workers/contracts/schema_projection.py +84 -0
- studio_workers-1.4.0/studio_workers/contracts/step_result.py +26 -0
- studio_workers-1.4.0/studio_workers/contracts/version.py +6 -0
- studio_workers-1.4.0/studio_workers/contracts/webhook_completion.py +185 -0
- studio_workers-1.4.0/studio_workers/contracts/workspace_paths.py +45 -0
- studio_workers-1.4.0/studio_workers/engines/__init__.py +3 -0
- studio_workers-1.4.0/studio_workers/engines/audio/__init__.py +3 -0
- studio_workers-1.4.0/studio_workers/engines/audio/handler.py +408 -0
- studio_workers-1.4.0/studio_workers/engines/audio/settings.py +41 -0
- studio_workers-1.4.0/studio_workers/engines/comfyui/__init__.py +13 -0
- studio_workers-1.4.0/studio_workers/engines/comfyui/client.py +260 -0
- studio_workers-1.4.0/studio_workers/engines/comfyui/handler.py +578 -0
- studio_workers-1.4.0/studio_workers/engines/comfyui/presets/fooocus_styles.json +741 -0
- studio_workers-1.4.0/studio_workers/engines/comfyui/presets/fooocus_styles_compact.json +129 -0
- studio_workers-1.4.0/studio_workers/engines/comfyui/server.py +197 -0
- studio_workers-1.4.0/studio_workers/engines/comfyui/settings.py +38 -0
- studio_workers-1.4.0/studio_workers/engines/comfyui/templates.py +390 -0
- studio_workers-1.4.0/studio_workers/engines/comfyui/workflows/comfyui_imgedit.json +144 -0
- studio_workers-1.4.0/studio_workers/engines/comfyui/workflows/comfyui_txt2img.json +162 -0
- studio_workers-1.4.0/studio_workers/engines/comfyui/workflows/comfyui_txt2img_flux2.json +108 -0
- studio_workers-1.4.0/studio_workers/engines/comfyui/workflows/comfyui_txt2img_flux2_9b.json +150 -0
- studio_workers-1.4.0/studio_workers/engines/comfyui/workflows/comfyui_txt2img_fp8.json +104 -0
- studio_workers-1.4.0/studio_workers/engines/comfyui/workflows/comfyui_txt2img_gguf.json +103 -0
- studio_workers-1.4.0/studio_workers/engines/general/__init__.py +1 -0
- studio_workers-1.4.0/studio_workers/engines/general/executor.py +1804 -0
- studio_workers-1.4.0/studio_workers/engines/general/handler.py +300 -0
- studio_workers-1.4.0/studio_workers/engines/transfer/__init__.py +3 -0
- studio_workers-1.4.0/studio_workers/engines/transfer/handler.py +827 -0
- studio_workers-1.4.0/studio_workers/engines/video/__init__.py +72 -0
- studio_workers-1.4.0/studio_workers/engines/video/common.py +443 -0
- studio_workers-1.4.0/studio_workers/engines/video/create_video.py +709 -0
- studio_workers-1.4.0/studio_workers/engines/video/fonts/ComicNeue-Bold.ttf +0 -0
- studio_workers-1.4.0/studio_workers/engines/video/fonts/ComicNeue-Regular.ttf +0 -0
- studio_workers-1.4.0/studio_workers/engines/video/fonts/FrederickatheGreat-Regular.ttf +0 -0
- studio_workers-1.4.0/studio_workers/engines/video/fonts/LibreBaskerville-Regular.ttf +0 -0
- studio_workers-1.4.0/studio_workers/engines/video/fonts/Lobster-Regular.ttf +0 -0
- studio_workers-1.4.0/studio_workers/engines/video/fonts/LuckiestGuy-Regular.ttf +0 -0
- studio_workers-1.4.0/studio_workers/engines/video/fonts/NanumPenScript-Regular.ttf +0 -0
- studio_workers-1.4.0/studio_workers/engines/video/fonts/NotoSansKR-Bold.ttf +0 -0
- studio_workers-1.4.0/studio_workers/engines/video/fonts/NotoSansKR-Regular.ttf +0 -0
- studio_workers-1.4.0/studio_workers/engines/video/fonts/NotoSansSC-Regular.ttf +0 -0
- studio_workers-1.4.0/studio_workers/engines/video/fonts/NotoSansTC-Regular.ttf +0 -0
- studio_workers-1.4.0/studio_workers/engines/video/fonts/Nunito-Regular.ttf +0 -0
- studio_workers-1.4.0/studio_workers/engines/video/fonts/Oswald-Bold.ttf +0 -0
- studio_workers-1.4.0/studio_workers/engines/video/fonts/Oswald-Regular.ttf +0 -0
- studio_workers-1.4.0/studio_workers/engines/video/fonts/Pacifico-Regular.ttf +0 -0
- studio_workers-1.4.0/studio_workers/engines/video/fonts/PermanentMarker-Regular.ttf +0 -0
- studio_workers-1.4.0/studio_workers/engines/video/fonts/Roboto-Regular.ttf +0 -0
- studio_workers-1.4.0/studio_workers/engines/video/fonts/Shrikhand-Regular.ttf +0 -0
- studio_workers-1.4.0/studio_workers/engines/video/fonts/licenses/Comic_Neue-OFL.txt +93 -0
- studio_workers-1.4.0/studio_workers/engines/video/fonts/licenses/Fredericka_the_Great-OFL.txt +94 -0
- studio_workers-1.4.0/studio_workers/engines/video/fonts/licenses/Libre_Baskerville-OFL.txt +94 -0
- studio_workers-1.4.0/studio_workers/engines/video/fonts/licenses/Lobster-OFL.txt +93 -0
- studio_workers-1.4.0/studio_workers/engines/video/fonts/licenses/LuckiestGuy-OFL.txt +94 -0
- studio_workers-1.4.0/studio_workers/engines/video/fonts/licenses/Nanum_Pen_Script-OFL.txt +97 -0
- studio_workers-1.4.0/studio_workers/engines/video/fonts/licenses/Noto_Sans_KR-OFL.txt +93 -0
- studio_workers-1.4.0/studio_workers/engines/video/fonts/licenses/Noto_Sans_SC-OFL.txt +93 -0
- studio_workers-1.4.0/studio_workers/engines/video/fonts/licenses/Noto_Sans_TC-OFL.txt +93 -0
- studio_workers-1.4.0/studio_workers/engines/video/fonts/licenses/Nunito-OFL.txt +93 -0
- studio_workers-1.4.0/studio_workers/engines/video/fonts/licenses/Oswald-OFL.txt +93 -0
- studio_workers-1.4.0/studio_workers/engines/video/fonts/licenses/Pacifico-OFL.txt +93 -0
- studio_workers-1.4.0/studio_workers/engines/video/fonts/licenses/Permanent_Marker-LICENSE.txt +202 -0
- studio_workers-1.4.0/studio_workers/engines/video/fonts/licenses/Roboto-LICENSE.txt +202 -0
- studio_workers-1.4.0/studio_workers/engines/video/fonts/licenses/Shrikhand-OFL.txt +93 -0
- studio_workers-1.4.0/studio_workers/engines/video/handler.py +1048 -0
- studio_workers-1.4.0/studio_workers/engines/video/merge_video_audio.py +525 -0
- studio_workers-1.4.0/studio_workers/engines/video/normalize.py +751 -0
- studio_workers-1.4.0/studio_workers/engines/video/settings.py +41 -0
- studio_workers-1.4.0/studio_workers/engines/video/subtitle_utils.py +923 -0
- studio_workers-1.4.0/studio_workers/engines/video/utils.py +428 -0
- studio_workers-1.4.0/studio_workers/env_files.py +17 -0
- studio_workers-1.4.0/studio_workers/settings.py +147 -0
- studio_workers-1.4.0/studio_workers/utils/__init__.py +29 -0
- studio_workers-1.4.0/studio_workers/utils/cf_access.py +17 -0
- studio_workers-1.4.0/studio_workers/utils/credential_client.py +176 -0
- studio_workers-1.4.0/studio_workers/utils/dead_letter.py +91 -0
- studio_workers-1.4.0/studio_workers/utils/error_codes.py +33 -0
- studio_workers-1.4.0/studio_workers/utils/file_upload_client.py +331 -0
- studio_workers-1.4.0/studio_workers/utils/http_job_client.py +251 -0
- studio_workers-1.4.0/studio_workers/utils/logging_config.py +463 -0
- studio_workers-1.4.0/studio_workers/utils/redaction.py +26 -0
- studio_workers-1.4.0/studio_workers/utils/result_publisher.py +128 -0
- studio_workers-1.4.0/studio_workers/utils/security.py +253 -0
- studio_workers-1.4.0/studio_workers/utils/storage.py +117 -0
- studio_workers-1.4.0/studio_workers/utils/worker_base.py +519 -0
- studio_workers-1.4.0/studio_workers/worker.py +166 -0
- studio_workers-1.4.0/studio_workers/worker_types.py +390 -0
- studio_workers-1.4.0/studio_workers.egg-info/PKG-INFO +86 -0
- studio_workers-1.4.0/studio_workers.egg-info/SOURCES.txt +107 -0
- studio_workers-1.4.0/studio_workers.egg-info/entry_points.txt +2 -0
- studio_workers-1.4.0/studio_workers.egg-info/requires.txt +33 -0
- studio_workers-1.4.0/studio_workers.egg-info/top_level.txt +1 -0
- studio_workers-0.0.1/PKG-INFO +0 -17
- studio_workers-0.0.1/README.md +0 -8
- studio_workers-0.0.1/pyproject.toml +0 -19
- studio_workers-0.0.1/studio_workers.egg-info/PKG-INFO +0 -17
- studio_workers-0.0.1/studio_workers.egg-info/SOURCES.txt +0 -6
- studio_workers-0.0.1/studio_workers.egg-info/top_level.txt +0 -1
- {studio_workers-0.0.1 → studio_workers-1.4.0}/setup.cfg +0 -0
- {studio_workers-0.0.1 → studio_workers-1.4.0}/studio_workers.egg-info/dependency_links.txt +0 -0
|
@@ -0,0 +1,141 @@
|
|
|
1
|
+
Studio Use License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2025-2026 Kawika Ohumukini. All rights reserved.
|
|
4
|
+
|
|
5
|
+
This license governs the use of the Studio software platform ("Software"),
|
|
6
|
+
including its API, frontend, worker, and documentation components.
|
|
7
|
+
|
|
8
|
+
This is not an open-source license. The source code is publicly available
|
|
9
|
+
for transparency and community contribution, but commercial use is subject
|
|
10
|
+
to the terms below.
|
|
11
|
+
|
|
12
|
+
|
|
13
|
+
1. PERMITTED USE
|
|
14
|
+
|
|
15
|
+
You may:
|
|
16
|
+
|
|
17
|
+
(a) Deploy and operate the Software for your own business purposes.
|
|
18
|
+
|
|
19
|
+
(b) Operate a hosted instance of the Software and charge customers for
|
|
20
|
+
access to it (SaaS model). There is no limit on the number of
|
|
21
|
+
customers or organizations on your instance.
|
|
22
|
+
|
|
23
|
+
(c) Provide consulting, installation, deployment, configuration, training,
|
|
24
|
+
and support services related to the Software.
|
|
25
|
+
|
|
26
|
+
(d) Deploy the Software for individual clients as part of bespoke service
|
|
27
|
+
engagements (one instance per client engagement).
|
|
28
|
+
|
|
29
|
+
(e) Provide the Software source code to your clients so they may deploy
|
|
30
|
+
and operate their own instance.
|
|
31
|
+
|
|
32
|
+
(f) Create, sell, and distribute your own workflow configurations,
|
|
33
|
+
templates, and automations. These are your intellectual property.
|
|
34
|
+
|
|
35
|
+
(g) Sell any output produced by the Software (images, video, text, data,
|
|
36
|
+
or any other generated content).
|
|
37
|
+
|
|
38
|
+
(h) Modify the Software for your own use.
|
|
39
|
+
|
|
40
|
+
(i) Contribute to this project.
|
|
41
|
+
|
|
42
|
+
|
|
43
|
+
2. RESTRICTIONS
|
|
44
|
+
|
|
45
|
+
You may not:
|
|
46
|
+
|
|
47
|
+
(a) Offer automated or self-service provisioning of Software instances
|
|
48
|
+
to third parties. You may not build a platform, tool, or service
|
|
49
|
+
whose primary function is deploying, hosting, or managing Software
|
|
50
|
+
instances on behalf of others.
|
|
51
|
+
|
|
52
|
+
(b) Distribute or sell pre-configured images, containers, deployment
|
|
53
|
+
packages, automation, or infrastructure templates that contain or
|
|
54
|
+
install the Software for third-party use.
|
|
55
|
+
|
|
56
|
+
Installing the Software on a client's own infrastructure using the
|
|
57
|
+
official Studio Console, as part of a service engagement, is
|
|
58
|
+
permitted and is not distribution under this section.
|
|
59
|
+
|
|
60
|
+
(c) Fork or rebrand the Software for resale or distribution as a
|
|
61
|
+
competing workflow automation platform or service.
|
|
62
|
+
|
|
63
|
+
(d) Redistribute, sublicense, or sell copies of the Software source
|
|
64
|
+
code as a standalone product or component.
|
|
65
|
+
|
|
66
|
+
(e) Remove or alter any copyright, trademark, or license notices
|
|
67
|
+
included in the Software.
|
|
68
|
+
|
|
69
|
+
The distinction this license draws is between OPERATING and DISTRIBUTING.
|
|
70
|
+
You may build a business that runs on Studio. You may not build a business
|
|
71
|
+
that distributes Studio.
|
|
72
|
+
|
|
73
|
+
For avoidance of doubt: operating a single Studio deployment as a
|
|
74
|
+
multi-tenant service for customers is permitted. Offering Studio
|
|
75
|
+
deployment, provisioning, or instance creation as a service to third
|
|
76
|
+
parties is not.
|
|
77
|
+
|
|
78
|
+
|
|
79
|
+
3. MARKETPLACE PACKAGES
|
|
80
|
+
|
|
81
|
+
The Studio Marketplace (the studio-community and studio-plus repositories)
|
|
82
|
+
provides optional provider packages, services, and templates under separate
|
|
83
|
+
terms. Marketplace packages:
|
|
84
|
+
|
|
85
|
+
(a) Are licensed separately from this Software under their own terms.
|
|
86
|
+
|
|
87
|
+
(b) May not be redistributed, sideloaded, bundled, or transferred to
|
|
88
|
+
third-party deployments. Each deploying party must obtain marketplace
|
|
89
|
+
packages directly from the official marketplace.
|
|
90
|
+
|
|
91
|
+
(c) Are subject to the Studio Marketplace Package License, which governs
|
|
92
|
+
access, usage, and distribution.
|
|
93
|
+
|
|
94
|
+
For clarity: workflow configurations that reference marketplace packages
|
|
95
|
+
may be freely shared or sold. The marketplace packages themselves may not.
|
|
96
|
+
|
|
97
|
+
Forking the public catalog repository to propose a contribution is
|
|
98
|
+
permitted. Publishing or distributing packages from such a fork is not.
|
|
99
|
+
|
|
100
|
+
|
|
101
|
+
4. USER-CREATED CONTENT
|
|
102
|
+
|
|
103
|
+
Workflow configurations, templates, automations, field mappings, and other
|
|
104
|
+
user-created content (typically JSON or similar configuration files) are the
|
|
105
|
+
intellectual property of their creators. This license makes no claim on
|
|
106
|
+
user-created content.
|
|
107
|
+
|
|
108
|
+
|
|
109
|
+
5. TRADEMARKS
|
|
110
|
+
|
|
111
|
+
"Studio," "Self-Host Studio," "Self-Host Hub," and associated logos and
|
|
112
|
+
marks are trademarks of the copyright holder. Use of these trademarks is
|
|
113
|
+
subject to applicable trademark law. You may use these names to truthfully
|
|
114
|
+
describe your relationship with the Software (e.g., "built on Self-Host
|
|
115
|
+
Studio," "powered by Studio"). You may not use the trademarks in a way
|
|
116
|
+
that implies endorsement, affiliation, or origin without prior written
|
|
117
|
+
consent. Nothing in this license grants the right to use these names or
|
|
118
|
+
marks as part of a product name, company name, or primary branding.
|
|
119
|
+
|
|
120
|
+
|
|
121
|
+
6. CONTRIBUTIONS
|
|
122
|
+
|
|
123
|
+
Contributions to this project are assigned to the copyright holder and
|
|
124
|
+
their successors and assigns. By submitting a contribution, you agree to
|
|
125
|
+
this assignment and represent that you have the right to make the
|
|
126
|
+
contribution.
|
|
127
|
+
|
|
128
|
+
|
|
129
|
+
7. NO WARRANTY
|
|
130
|
+
|
|
131
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
|
|
132
|
+
OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
133
|
+
FITNESS FOR A PARTICULAR PURPOSE, AND NONINFRINGEMENT.
|
|
134
|
+
|
|
135
|
+
IN NO EVENT SHALL THE AUTHORS, COPYRIGHT HOLDERS, OR CONTRIBUTORS BE LIABLE
|
|
136
|
+
FOR ANY CLAIM, DAMAGES, OR OTHER LIABILITY, WHETHER IN AN ACTION OF
|
|
137
|
+
CONTRACT, TORT, OR OTHERWISE, ARISING FROM, OUT OF, OR IN CONNECTION WITH
|
|
138
|
+
THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
|
139
|
+
|
|
140
|
+
Operators are solely responsible for compliance with applicable laws and
|
|
141
|
+
third-party service terms. See LEGAL.md for detailed operator obligations.
|
|
@@ -0,0 +1,86 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: studio-workers
|
|
3
|
+
Version: 1.4.0
|
|
4
|
+
Summary: Studio workflow job workers
|
|
5
|
+
Author: Kawika Ohumukini
|
|
6
|
+
License-Expression: LicenseRef-Studio-Use-License
|
|
7
|
+
Requires-Python: >=3.12
|
|
8
|
+
Description-Content-Type: text/markdown
|
|
9
|
+
License-File: LICENSE
|
|
10
|
+
Requires-Dist: httpx>=0.28.1
|
|
11
|
+
Requires-Dist: psutil>=5.9.0
|
|
12
|
+
Requires-Dist: jsonpath-ng>=1.6.0
|
|
13
|
+
Requires-Dist: Pillow>=10.0.0
|
|
14
|
+
Requires-Dist: rich>=13.0.0
|
|
15
|
+
Requires-Dist: mutagen>=1.47.0
|
|
16
|
+
Requires-Dist: pydantic>=2.0.0
|
|
17
|
+
Requires-Dist: pydantic-settings>=2.0.0
|
|
18
|
+
Provides-Extra: audio
|
|
19
|
+
Requires-Dist: chatterbox-tts; extra == "audio"
|
|
20
|
+
Requires-Dist: torch; extra == "audio"
|
|
21
|
+
Requires-Dist: soundfile; extra == "audio"
|
|
22
|
+
Requires-Dist: setuptools<81,>=78.1.1; extra == "audio"
|
|
23
|
+
Provides-Extra: comfyui
|
|
24
|
+
Requires-Dist: websocket-client>=1.6.0; extra == "comfyui"
|
|
25
|
+
Provides-Extra: video
|
|
26
|
+
Requires-Dist: openai-whisper>=20231117; extra == "video"
|
|
27
|
+
Requires-Dist: faster-whisper>=1.0.0; extra == "video"
|
|
28
|
+
Provides-Extra: test
|
|
29
|
+
Requires-Dist: pytest>=8.0.0; extra == "test"
|
|
30
|
+
Requires-Dist: pytest-asyncio>=0.23.0; extra == "test"
|
|
31
|
+
Requires-Dist: pytest-cov>=4.1.0; extra == "test"
|
|
32
|
+
Requires-Dist: pytest-httpx>=0.30.0; extra == "test"
|
|
33
|
+
Requires-Dist: pytest-xdist>=3.0.0; extra == "test"
|
|
34
|
+
Requires-Dist: respx>=0.21.0; extra == "test"
|
|
35
|
+
Requires-Dist: freezegun>=1.2.0; extra == "test"
|
|
36
|
+
Requires-Dist: pyright>=1.1.405; extra == "test"
|
|
37
|
+
Requires-Dist: flake8>=7.1.1; extra == "test"
|
|
38
|
+
Requires-Dist: python-dotenv>=1.2.2; extra == "test"
|
|
39
|
+
Dynamic: license-file
|
|
40
|
+
|
|
41
|
+
# studio-workers
|
|
42
|
+
|
|
43
|
+
Native (no-Docker) workers for [SelfHostHub Studio](https://www.skool.com/selfhosthub). Run any Studio worker engine directly on the host, pointed at your Studio API. This is the supported path for GPU work on Apple Silicon, where Docker cannot reach the Mac GPU, and for installing workers on demand inside a single GPU pod.
|
|
44
|
+
|
|
45
|
+
## Install
|
|
46
|
+
|
|
47
|
+
Pick the extra for the engine you want to run:
|
|
48
|
+
|
|
49
|
+
```bash
|
|
50
|
+
pip install "studio-workers[audio]" # TTS (Chatterbox, torch)
|
|
51
|
+
pip install "studio-workers[video]" # transcription and video (whisper)
|
|
52
|
+
pip install "studio-workers[comfyui]" # ComfyUI bridge
|
|
53
|
+
pip install "studio-workers" # general + transfer (CPU only)
|
|
54
|
+
```
|
|
55
|
+
|
|
56
|
+
The `[audio]` extra currently requires Python 3.12: its Chatterbox dependency chain does not yet resolve on 3.13 (the install fails with an `llvmlite` build error). The other extras run on 3.12+.
|
|
57
|
+
|
|
58
|
+
## Version pinning
|
|
59
|
+
|
|
60
|
+
Install the `studio-workers` version that matches your Studio release; the release notes name it. The API checks the worker version at registration and refuses a mismatch.
|
|
61
|
+
|
|
62
|
+
## Check the install
|
|
63
|
+
|
|
64
|
+
```bash
|
|
65
|
+
studio-workers doctor --engine audio
|
|
66
|
+
```
|
|
67
|
+
|
|
68
|
+
`doctor` fails loudly when a GPU host would silently run on CPU: it asserts torch sees MPS on Apple Silicon and CUDA when an NVIDIA driver is present.
|
|
69
|
+
|
|
70
|
+
## Run
|
|
71
|
+
|
|
72
|
+
```bash
|
|
73
|
+
SHS_API_BASE_URL=https://your-studio-api \
|
|
74
|
+
SHS_PUBLIC_BASE_URL=https://your-studio \
|
|
75
|
+
SHS_WORKER_SHARED_SECRET=... \
|
|
76
|
+
SHS_WORKSPACE_ROOT=/path/to/workspace \
|
|
77
|
+
studio-workers run --type audio
|
|
78
|
+
```
|
|
79
|
+
|
|
80
|
+
(`python -m studio_workers.worker` with `SHS_WORKER_TYPE` set still works; `run` is the same loop.)
|
|
81
|
+
|
|
82
|
+
The worker polls the API for jobs over HTTP; no inbound port is required. See your Studio instance's worker access documentation for the sanctioned connection paths.
|
|
83
|
+
|
|
84
|
+
## Third-party software
|
|
85
|
+
|
|
86
|
+
Installing an engine extra pulls third-party packages (torch, Chatterbox TTS, whisper, ComfyUI dependencies) from their own upstreams under their own licenses; model weights download on first run.
|
|
@@ -0,0 +1,56 @@
|
|
|
1
|
+
# Studio Worker
|
|
2
|
+
|
|
3
|
+
> **Community & support:** [SelfHostHub Community](https://www.skool.com/selfhosthub) · [Innovators (Plus)](https://www.skool.com/selfhostinnovators)
|
|
4
|
+
|
|
5
|
+
HTTP polling-based background job processor for Studio.
|
|
6
|
+
|
|
7
|
+
## Overview
|
|
8
|
+
|
|
9
|
+
Handles async tasks: image generation, video processing, webhook delivery.
|
|
10
|
+
|
|
11
|
+
## Local Development (Mac)
|
|
12
|
+
|
|
13
|
+
### Prerequisites
|
|
14
|
+
|
|
15
|
+
```bash
|
|
16
|
+
# ffmpeg with libass (required for subtitle burn)
|
|
17
|
+
# The default Homebrew bottle does NOT include libass.
|
|
18
|
+
brew tap homebrew-ffmpeg/ffmpeg
|
|
19
|
+
brew install homebrew-ffmpeg/ffmpeg/ffmpeg
|
|
20
|
+
|
|
21
|
+
# Verify the ass filter is available
|
|
22
|
+
ffmpeg -filters 2>&1 | grep -w ass
|
|
23
|
+
```
|
|
24
|
+
|
|
25
|
+
If you previously installed the default `ffmpeg` formula, replace it:
|
|
26
|
+
|
|
27
|
+
```bash
|
|
28
|
+
brew uninstall ffmpeg
|
|
29
|
+
brew install homebrew-ffmpeg/ffmpeg/ffmpeg
|
|
30
|
+
```
|
|
31
|
+
|
|
32
|
+
### Video Worker
|
|
33
|
+
|
|
34
|
+
```bash
|
|
35
|
+
make video-local-setup # Creates venv, installs deps, fonts
|
|
36
|
+
make video-run-local # Starts worker (polls API at localhost:8000)
|
|
37
|
+
```
|
|
38
|
+
|
|
39
|
+
**Apple Silicon GPU (MPS)**: Whisper transcription runs on the MPS GPU automatically. A monkey-patch handles Whisper's DTW alignment step which calls `.double()` (float64) - unsupported on MPS - by moving that tensor to CPU before conversion. Inference stays on GPU.
|
|
40
|
+
|
|
41
|
+
### Audio Worker
|
|
42
|
+
|
|
43
|
+
```bash
|
|
44
|
+
make audio-local-setup # Creates venv, installs Chatterbox TTS
|
|
45
|
+
make audio-run-local # Starts worker (MPS/CPU)
|
|
46
|
+
```
|
|
47
|
+
|
|
48
|
+
## Documentation
|
|
49
|
+
|
|
50
|
+
See [docs/](../docs/) in the monorepo for full documentation.
|
|
51
|
+
|
|
52
|
+
## License
|
|
53
|
+
|
|
54
|
+
Studio Use License - See [LICENSE](LICENSE)
|
|
55
|
+
|
|
56
|
+
For operator responsibilities and legal notices, see [LEGAL.md](LEGAL.md).
|
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
# studio-workers
|
|
2
|
+
|
|
3
|
+
Native (no-Docker) workers for [SelfHostHub Studio](https://www.skool.com/selfhosthub). Run any Studio worker engine directly on the host, pointed at your Studio API. This is the supported path for GPU work on Apple Silicon, where Docker cannot reach the Mac GPU, and for installing workers on demand inside a single GPU pod.
|
|
4
|
+
|
|
5
|
+
## Install
|
|
6
|
+
|
|
7
|
+
Pick the extra for the engine you want to run:
|
|
8
|
+
|
|
9
|
+
```bash
|
|
10
|
+
pip install "studio-workers[audio]" # TTS (Chatterbox, torch)
|
|
11
|
+
pip install "studio-workers[video]" # transcription and video (whisper)
|
|
12
|
+
pip install "studio-workers[comfyui]" # ComfyUI bridge
|
|
13
|
+
pip install "studio-workers" # general + transfer (CPU only)
|
|
14
|
+
```
|
|
15
|
+
|
|
16
|
+
The `[audio]` extra currently requires Python 3.12: its Chatterbox dependency chain does not yet resolve on 3.13 (the install fails with an `llvmlite` build error). The other extras run on 3.12+.
|
|
17
|
+
|
|
18
|
+
## Version pinning
|
|
19
|
+
|
|
20
|
+
Install the `studio-workers` version that matches your Studio release; the release notes name it. The API checks the worker version at registration and refuses a mismatch.
|
|
21
|
+
|
|
22
|
+
## Check the install
|
|
23
|
+
|
|
24
|
+
```bash
|
|
25
|
+
studio-workers doctor --engine audio
|
|
26
|
+
```
|
|
27
|
+
|
|
28
|
+
`doctor` fails loudly when a GPU host would silently run on CPU: it asserts torch sees MPS on Apple Silicon and CUDA when an NVIDIA driver is present.
|
|
29
|
+
|
|
30
|
+
## Run
|
|
31
|
+
|
|
32
|
+
```bash
|
|
33
|
+
SHS_API_BASE_URL=https://your-studio-api \
|
|
34
|
+
SHS_PUBLIC_BASE_URL=https://your-studio \
|
|
35
|
+
SHS_WORKER_SHARED_SECRET=... \
|
|
36
|
+
SHS_WORKSPACE_ROOT=/path/to/workspace \
|
|
37
|
+
studio-workers run --type audio
|
|
38
|
+
```
|
|
39
|
+
|
|
40
|
+
(`python -m studio_workers.worker` with `SHS_WORKER_TYPE` set still works; `run` is the same loop.)
|
|
41
|
+
|
|
42
|
+
The worker polls the API for jobs over HTTP; no inbound port is required. See your Studio instance's worker access documentation for the sanctioned connection paths.
|
|
43
|
+
|
|
44
|
+
## Third-party software
|
|
45
|
+
|
|
46
|
+
Installing an engine extra pulls third-party packages (torch, Chatterbox TTS, whisper, ComfyUI dependencies) from their own upstreams under their own licenses; model weights download on first run.
|
|
@@ -0,0 +1,104 @@
|
|
|
1
|
+
[build-system]
|
|
2
|
+
requires = ["setuptools>=77"]
|
|
3
|
+
build-backend = "setuptools.build_meta"
|
|
4
|
+
|
|
5
|
+
[project]
|
|
6
|
+
name = "studio-workers"
|
|
7
|
+
dynamic = ["version"]
|
|
8
|
+
description = "Studio workflow job workers"
|
|
9
|
+
readme = "README.pypi.md"
|
|
10
|
+
requires-python = ">=3.12"
|
|
11
|
+
license = "LicenseRef-Studio-Use-License"
|
|
12
|
+
license-files = ["LICENSE"]
|
|
13
|
+
authors = [
|
|
14
|
+
{name = "Kawika Ohumukini"}
|
|
15
|
+
]
|
|
16
|
+
dependencies = [
|
|
17
|
+
"httpx>=0.28.1",
|
|
18
|
+
"psutil>=5.9.0",
|
|
19
|
+
"jsonpath-ng>=1.6.0",
|
|
20
|
+
"Pillow>=10.0.0",
|
|
21
|
+
"rich>=13.0.0",
|
|
22
|
+
"mutagen>=1.47.0",
|
|
23
|
+
"pydantic>=2.0.0",
|
|
24
|
+
"pydantic-settings>=2.0.0",
|
|
25
|
+
]
|
|
26
|
+
|
|
27
|
+
[project.scripts]
|
|
28
|
+
studio-workers = "studio_workers.cli:main"
|
|
29
|
+
|
|
30
|
+
[project.optional-dependencies]
|
|
31
|
+
audio = [
|
|
32
|
+
"chatterbox-tts",
|
|
33
|
+
"torch",
|
|
34
|
+
"soundfile",
|
|
35
|
+
# resemble-perth needs pkg_resources (gone in setuptools 82, warns in 81); uv venvs ship
|
|
36
|
+
# no setuptools at all, so the extra must provide a CVE-fixed one itself.
|
|
37
|
+
"setuptools>=78.1.1,<81",
|
|
38
|
+
]
|
|
39
|
+
comfyui = [
|
|
40
|
+
"websocket-client>=1.6.0",
|
|
41
|
+
]
|
|
42
|
+
video = [
|
|
43
|
+
"openai-whisper>=20231117",
|
|
44
|
+
"faster-whisper>=1.0.0",
|
|
45
|
+
]
|
|
46
|
+
test = [
|
|
47
|
+
"pytest>=8.0.0",
|
|
48
|
+
"pytest-asyncio>=0.23.0",
|
|
49
|
+
"pytest-cov>=4.1.0",
|
|
50
|
+
"pytest-httpx>=0.30.0",
|
|
51
|
+
"pytest-xdist>=3.0.0",
|
|
52
|
+
"respx>=0.21.0",
|
|
53
|
+
"freezegun>=1.2.0",
|
|
54
|
+
"pyright>=1.1.405",
|
|
55
|
+
"flake8>=7.1.1",
|
|
56
|
+
"python-dotenv>=1.2.2", # test-time only: conftest.py pre-loads envs/.env.test before shared.settings imports
|
|
57
|
+
]
|
|
58
|
+
|
|
59
|
+
[tool.setuptools.dynamic]
|
|
60
|
+
version = {attr = "studio_workers.contracts.version.WORKERS_VERSION"}
|
|
61
|
+
|
|
62
|
+
[tool.pytest.ini_options]
|
|
63
|
+
testpaths = ["tests"]
|
|
64
|
+
python_files = ["test_*.py"]
|
|
65
|
+
python_functions = ["test_*"]
|
|
66
|
+
asyncio_mode = "auto"
|
|
67
|
+
asyncio_default_fixture_loop_scope = "function"
|
|
68
|
+
addopts = [
|
|
69
|
+
"-v",
|
|
70
|
+
"--tb=short",
|
|
71
|
+
"--strict-markers",
|
|
72
|
+
]
|
|
73
|
+
markers = [
|
|
74
|
+
"unit: Unit tests (no external dependencies)",
|
|
75
|
+
"integration: Integration tests (may need mocked services)",
|
|
76
|
+
"slow: Tests that take significant time",
|
|
77
|
+
]
|
|
78
|
+
|
|
79
|
+
[tool.coverage.run]
|
|
80
|
+
source = ["studio_workers"]
|
|
81
|
+
branch = true
|
|
82
|
+
omit = [
|
|
83
|
+
"*/tests/*",
|
|
84
|
+
"*/.venv/*",
|
|
85
|
+
# Shared contracts package: gated by api/tests/unit/contracts, not the workers suite.
|
|
86
|
+
"studio_workers/contracts/*",
|
|
87
|
+
]
|
|
88
|
+
|
|
89
|
+
[tool.coverage.report]
|
|
90
|
+
exclude_lines = [
|
|
91
|
+
"pragma: no cover",
|
|
92
|
+
"if TYPE_CHECKING:",
|
|
93
|
+
"if __name__ == .__main__.:",
|
|
94
|
+
"raise NotImplementedError",
|
|
95
|
+
]
|
|
96
|
+
show_missing = true
|
|
97
|
+
|
|
98
|
+
[tool.setuptools.packages.find]
|
|
99
|
+
include = ["studio_workers*"]
|
|
100
|
+
exclude = ["tests*", "docker*", "typestubs*"]
|
|
101
|
+
|
|
102
|
+
[tool.setuptools.package-data]
|
|
103
|
+
"studio_workers.engines.comfyui" = ["presets/*.json", "workflows/*.json"]
|
|
104
|
+
"studio_workers.engines.video" = ["fonts/*", "fonts/licenses/*"]
|
|
@@ -0,0 +1,108 @@
|
|
|
1
|
+
# workers/studio_workers/cli.py
|
|
2
|
+
|
|
3
|
+
"""studio-workers console entrypoint: `doctor` (environment check) and `run` (start a worker)."""
|
|
4
|
+
|
|
5
|
+
import argparse
|
|
6
|
+
import platform
|
|
7
|
+
import shutil
|
|
8
|
+
import sys
|
|
9
|
+
|
|
10
|
+
from studio_workers.contracts.version import WORKERS_VERSION
|
|
11
|
+
|
|
12
|
+
# Engines whose inference runs torch locally; the others need no GPU here
|
|
13
|
+
# (comfyui proxies to an external ComfyUI server, general/transfer are CPU).
|
|
14
|
+
TORCH_ENGINES = {"audio", "video"}
|
|
15
|
+
|
|
16
|
+
|
|
17
|
+
def _expected_accelerator() -> str | None:
|
|
18
|
+
"""The accelerator this host should expose: mps on Apple Silicon, cuda when
|
|
19
|
+
an NVIDIA driver is present, else None (CPU is legitimate)."""
|
|
20
|
+
if sys.platform == "darwin" and platform.machine() == "arm64":
|
|
21
|
+
return "mps"
|
|
22
|
+
if sys.platform.startswith("linux") and shutil.which("nvidia-smi"):
|
|
23
|
+
return "cuda"
|
|
24
|
+
return None
|
|
25
|
+
|
|
26
|
+
|
|
27
|
+
def _torch_device() -> tuple[str | None, str | None]:
|
|
28
|
+
"""(device, torch version); device None when torch is not installed."""
|
|
29
|
+
try:
|
|
30
|
+
import torch
|
|
31
|
+
except ImportError:
|
|
32
|
+
return None, None
|
|
33
|
+
if torch.cuda.is_available():
|
|
34
|
+
return "cuda", torch.__version__
|
|
35
|
+
if hasattr(torch.backends, "mps") and torch.backends.mps.is_available():
|
|
36
|
+
return "mps", torch.__version__
|
|
37
|
+
return "cpu", torch.__version__
|
|
38
|
+
|
|
39
|
+
|
|
40
|
+
def doctor(engine: str | None) -> int:
|
|
41
|
+
"""Report the environment and fail loudly when a GPU host would silently run on CPU."""
|
|
42
|
+
print(f"studio-workers {WORKERS_VERSION}")
|
|
43
|
+
print(f"python {platform.python_version()} on {sys.platform}/{platform.machine()}")
|
|
44
|
+
|
|
45
|
+
expected = _expected_accelerator()
|
|
46
|
+
device, torch_version = _torch_device()
|
|
47
|
+
|
|
48
|
+
if device is None:
|
|
49
|
+
if engine in TORCH_ENGINES:
|
|
50
|
+
print(
|
|
51
|
+
f"ERROR: torch is not installed but the {engine} engine needs it. "
|
|
52
|
+
f'Install the engine extra: pip install "studio-workers[{engine}]=={WORKERS_VERSION}"'
|
|
53
|
+
)
|
|
54
|
+
return 1
|
|
55
|
+
print("torch: not installed (not required for this engine)")
|
|
56
|
+
return 0
|
|
57
|
+
|
|
58
|
+
print(f"torch {torch_version}, device={device}")
|
|
59
|
+
if expected and device == "cpu":
|
|
60
|
+
hint = (
|
|
61
|
+
"Docker cannot reach the Mac GPU; run natively (this install) with an MPS-enabled torch wheel."
|
|
62
|
+
if expected == "mps"
|
|
63
|
+
else "Reinstall torch from the matching CUDA index (https://download.pytorch.org/whl/) for your driver."
|
|
64
|
+
)
|
|
65
|
+
print(
|
|
66
|
+
f"ERROR: this host exposes {expected} but torch only sees the CPU; "
|
|
67
|
+
f"generation would run uselessly slow instead of failing. {hint}"
|
|
68
|
+
)
|
|
69
|
+
return 1
|
|
70
|
+
return 0
|
|
71
|
+
|
|
72
|
+
|
|
73
|
+
def run(worker_type: str | None) -> int:
|
|
74
|
+
"""Start the worker loop; --type overrides SHS_WORKER_TYPE."""
|
|
75
|
+
import os
|
|
76
|
+
|
|
77
|
+
if worker_type:
|
|
78
|
+
os.environ["SHS_WORKER_TYPE"] = worker_type
|
|
79
|
+
|
|
80
|
+
from studio_workers import worker
|
|
81
|
+
|
|
82
|
+
worker.main()
|
|
83
|
+
return 0
|
|
84
|
+
|
|
85
|
+
|
|
86
|
+
def main(argv: list[str] | None = None) -> int:
|
|
87
|
+
parser = argparse.ArgumentParser(prog="studio-workers")
|
|
88
|
+
parser.add_argument("--version", action="version", version=WORKERS_VERSION)
|
|
89
|
+
sub = parser.add_subparsers(dest="command", required=True)
|
|
90
|
+
|
|
91
|
+
p_doctor = sub.add_parser("doctor", help="check this host can run a worker")
|
|
92
|
+
p_doctor.add_argument(
|
|
93
|
+
"--engine",
|
|
94
|
+
choices=["general", "transfer", "video", "audio", "comfyui"],
|
|
95
|
+
help="engine you intend to run; makes torch mandatory for audio/video",
|
|
96
|
+
)
|
|
97
|
+
|
|
98
|
+
p_run = sub.add_parser("run", help="start a worker (same loop as python -m studio_workers.worker)")
|
|
99
|
+
p_run.add_argument("--type", dest="worker_type", help="worker type; overrides SHS_WORKER_TYPE")
|
|
100
|
+
|
|
101
|
+
args = parser.parse_args(argv)
|
|
102
|
+
if args.command == "doctor":
|
|
103
|
+
return doctor(args.engine)
|
|
104
|
+
return run(args.worker_type)
|
|
105
|
+
|
|
106
|
+
|
|
107
|
+
if __name__ == "__main__":
|
|
108
|
+
sys.exit(main())
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
# workers/studio_workers/constants.py
|
|
@@ -0,0 +1,82 @@
|
|
|
1
|
+
# workers/studio_workers/contracts/__init__.py
|
|
2
|
+
|
|
3
|
+
"""
|
|
4
|
+
Shared contract types between API and workers.
|
|
5
|
+
|
|
6
|
+
Pydantic models define canonical payload shapes for cross-component
|
|
7
|
+
communication. Log schema defines canonical JSON log field names.
|
|
8
|
+
Both sides import from here - one source of truth.
|
|
9
|
+
|
|
10
|
+
Python 3.11 compatible (workers use 3.11, API uses 3.12).
|
|
11
|
+
"""
|
|
12
|
+
|
|
13
|
+
from studio_workers.contracts.log_schema import (
|
|
14
|
+
FIELD_CORRELATION_ID,
|
|
15
|
+
FIELD_EXCEPTION,
|
|
16
|
+
FIELD_EXTRA,
|
|
17
|
+
FIELD_HOST,
|
|
18
|
+
FIELD_LEVEL,
|
|
19
|
+
FIELD_LOGGER,
|
|
20
|
+
FIELD_MESSAGE,
|
|
21
|
+
FIELD_SERVICE,
|
|
22
|
+
FIELD_TIMESTAMP,
|
|
23
|
+
VERBOSITY_FULL,
|
|
24
|
+
VERBOSITY_MINIMAL,
|
|
25
|
+
VERBOSITY_STANDARD,
|
|
26
|
+
format_timestamp,
|
|
27
|
+
get_log_verbosity,
|
|
28
|
+
)
|
|
29
|
+
from studio_workers.contracts.redaction import (
|
|
30
|
+
PII_KEYS,
|
|
31
|
+
REDACTED_PLACEHOLDER,
|
|
32
|
+
SENSITIVE_KEYS,
|
|
33
|
+
is_pii_key,
|
|
34
|
+
is_sensitive_key,
|
|
35
|
+
redact_sensitive_data,
|
|
36
|
+
redact_url,
|
|
37
|
+
)
|
|
38
|
+
|
|
39
|
+
__all__ = [
|
|
40
|
+
"DownloadedFileContract",
|
|
41
|
+
"JobClaimContract",
|
|
42
|
+
"StepResultContract",
|
|
43
|
+
"FIELD_TIMESTAMP",
|
|
44
|
+
"FIELD_LEVEL",
|
|
45
|
+
"FIELD_SERVICE",
|
|
46
|
+
"FIELD_MESSAGE",
|
|
47
|
+
"FIELD_HOST",
|
|
48
|
+
"FIELD_LOGGER",
|
|
49
|
+
"FIELD_CORRELATION_ID",
|
|
50
|
+
"FIELD_EXCEPTION",
|
|
51
|
+
"FIELD_EXTRA",
|
|
52
|
+
"VERBOSITY_MINIMAL",
|
|
53
|
+
"VERBOSITY_STANDARD",
|
|
54
|
+
"VERBOSITY_FULL",
|
|
55
|
+
"get_log_verbosity",
|
|
56
|
+
"format_timestamp",
|
|
57
|
+
"SENSITIVE_KEYS",
|
|
58
|
+
"PII_KEYS",
|
|
59
|
+
"REDACTED_PLACEHOLDER",
|
|
60
|
+
"is_sensitive_key",
|
|
61
|
+
"is_pii_key",
|
|
62
|
+
"redact_sensitive_data",
|
|
63
|
+
"redact_url",
|
|
64
|
+
]
|
|
65
|
+
|
|
66
|
+
|
|
67
|
+
def __getattr__(name: str):
|
|
68
|
+
"""Lazy-import pydantic-dependent contracts to avoid pulling in pydantic
|
|
69
|
+
for lightweight consumers (e.g., workers that only need log_schema)."""
|
|
70
|
+
if name == "DownloadedFileContract":
|
|
71
|
+
from studio_workers.contracts.downloaded_file import DownloadedFileContract
|
|
72
|
+
|
|
73
|
+
return DownloadedFileContract
|
|
74
|
+
if name == "JobClaimContract":
|
|
75
|
+
from studio_workers.contracts.job_claim import JobClaimContract
|
|
76
|
+
|
|
77
|
+
return JobClaimContract
|
|
78
|
+
if name == "StepResultContract":
|
|
79
|
+
from studio_workers.contracts.step_result import StepResultContract
|
|
80
|
+
|
|
81
|
+
return StepResultContract
|
|
82
|
+
raise AttributeError(f"module 'contracts' has no attribute {name!r}")
|