juturna 1.0.2__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.
- juturna-1.0.2/LICENSE +21 -0
- juturna-1.0.2/PKG-INFO +172 -0
- juturna-1.0.2/README.md +131 -0
- juturna-1.0.2/juturna/__init__.py +24 -0
- juturna-1.0.2/juturna/__main__.py +30 -0
- juturna-1.0.2/juturna/cli/_cli_utils.py +23 -0
- juturna-1.0.2/juturna/cli/commands/__init__.py +35 -0
- juturna-1.0.2/juturna/cli/commands/_common_pipe_parser.py +27 -0
- juturna-1.0.2/juturna/cli/commands/_create_tools.py +74 -0
- juturna-1.0.2/juturna/cli/commands/_juturna_config_creator.py +521 -0
- juturna-1.0.2/juturna/cli/commands/_juturna_service.py +102 -0
- juturna-1.0.2/juturna/cli/commands/_node_stub.py +94 -0
- juturna-1.0.2/juturna/cli/commands/_validation_tools.py +112 -0
- juturna-1.0.2/juturna/cli/commands/basic_config.template +3 -0
- juturna-1.0.2/juturna/cli/commands/basic_node.template +65 -0
- juturna-1.0.2/juturna/cli/commands/create.py +40 -0
- juturna-1.0.2/juturna/cli/commands/launch.py +90 -0
- juturna-1.0.2/juturna/cli/commands/serve.py +83 -0
- juturna-1.0.2/juturna/cli/commands/stub.py +55 -0
- juturna-1.0.2/juturna/cli/commands/validate.py +252 -0
- juturna-1.0.2/juturna/components/__init__.py +12 -0
- juturna-1.0.2/juturna/components/_buffer.py +80 -0
- juturna-1.0.2/juturna/components/_component_builder.py +129 -0
- juturna-1.0.2/juturna/components/_mapper.py +197 -0
- juturna-1.0.2/juturna/components/_message.py +190 -0
- juturna-1.0.2/juturna/components/_node.py +427 -0
- juturna-1.0.2/juturna/components/_pipeline.py +232 -0
- juturna-1.0.2/juturna/components/_pipeline_manager.py +173 -0
- juturna-1.0.2/juturna/components/_resource_broker.py +17 -0
- juturna-1.0.2/juturna/components/_synchronisers.py +11 -0
- juturna-1.0.2/juturna/hub/__init__.py +10 -0
- juturna-1.0.2/juturna/hub/__main__.py +72 -0
- juturna-1.0.2/juturna/hub/_gh_utils.py +70 -0
- juturna-1.0.2/juturna/hub/_utils.py +193 -0
- juturna-1.0.2/juturna/meta/__init__.py +20 -0
- juturna-1.0.2/juturna/meta/_constants.py +28 -0
- juturna-1.0.2/juturna/names/__init__.py +10 -0
- juturna-1.0.2/juturna/names/_component_status.py +23 -0
- juturna-1.0.2/juturna/names/_pipeline_status.py +9 -0
- juturna-1.0.2/juturna/names/_service_status.py +13 -0
- juturna-1.0.2/juturna/nodes/__init__.py +8 -0
- juturna-1.0.2/juturna/nodes/sink/__init__.py +10 -0
- juturna-1.0.2/juturna/nodes/sink/_notifier_http/config.toml +6 -0
- juturna-1.0.2/juturna/nodes/sink/_notifier_http/notifier_http.py +83 -0
- juturna-1.0.2/juturna/nodes/sink/_notifier_udp/README.md +8 -0
- juturna-1.0.2/juturna/nodes/sink/_notifier_udp/config.toml +10 -0
- juturna-1.0.2/juturna/nodes/sink/_notifier_udp/notifier_udp.py +121 -0
- juturna-1.0.2/juturna/nodes/sink/_notifier_udp/requirements.txt +0 -0
- juturna-1.0.2/juturna/nodes/sink/_notifier_websocket/config.toml +4 -0
- juturna-1.0.2/juturna/nodes/sink/_notifier_websocket/notifier_websocket.py +59 -0
- juturna-1.0.2/juturna/nodes/sink/_videostream_ffmpeg/config.toml +12 -0
- juturna-1.0.2/juturna/nodes/sink/_videostream_ffmpeg/ffmpeg_launcher_h264.sh.template +18 -0
- juturna-1.0.2/juturna/nodes/sink/_videostream_ffmpeg/ffmpeg_launcher_vp8-dump.sh.template +14 -0
- juturna-1.0.2/juturna/nodes/sink/_videostream_ffmpeg/ffmpeg_launcher_vp8.sh.template +22 -0
- juturna-1.0.2/juturna/nodes/sink/_videostream_ffmpeg/videostream_ffmpeg.py +113 -0
- juturna-1.0.2/juturna/nodes/source/__init__.py +10 -0
- juturna-1.0.2/juturna/nodes/source/_audio_file/audio_file.py +162 -0
- juturna-1.0.2/juturna/nodes/source/_audio_file/config.toml +6 -0
- juturna-1.0.2/juturna/nodes/source/_audio_rtp/audio_rtp.py +367 -0
- juturna-1.0.2/juturna/nodes/source/_audio_rtp/config.toml +11 -0
- juturna-1.0.2/juturna/nodes/source/_audio_rtp/ffmpeg_launcher.sh.template +9 -0
- juturna-1.0.2/juturna/nodes/source/_audio_rtp/remote_source.sdp.template +9 -0
- juturna-1.0.2/juturna/nodes/source/_json_http/README.md +11 -0
- juturna-1.0.2/juturna/nodes/source/_json_http/config.toml +5 -0
- juturna-1.0.2/juturna/nodes/source/_json_http/json_http.py +212 -0
- juturna-1.0.2/juturna/nodes/source/_json_http/requirements.txt +0 -0
- juturna-1.0.2/juturna/nodes/source/_json_websocket/README.md +14 -0
- juturna-1.0.2/juturna/nodes/source/_json_websocket/config.toml +5 -0
- juturna-1.0.2/juturna/nodes/source/_json_websocket/json_websocket.py +107 -0
- juturna-1.0.2/juturna/nodes/source/_json_websocket/requirements.txt +0 -0
- juturna-1.0.2/juturna/nodes/source/_video_file/README.md +8 -0
- juturna-1.0.2/juturna/nodes/source/_video_file/config.toml +6 -0
- juturna-1.0.2/juturna/nodes/source/_video_file/ffmpeg_launcher.sh.template +10 -0
- juturna-1.0.2/juturna/nodes/source/_video_file/requirements.txt +0 -0
- juturna-1.0.2/juturna/nodes/source/_video_file/video_file.py +131 -0
- juturna-1.0.2/juturna/nodes/source/_video_rtp/config.toml +9 -0
- juturna-1.0.2/juturna/nodes/source/_video_rtp/ffmpeg_launcher.sh.template +8 -0
- juturna-1.0.2/juturna/nodes/source/_video_rtp/remote_source.sdp.template +9 -0
- juturna-1.0.2/juturna/nodes/source/_video_rtp/video_rtp.py +168 -0
- juturna-1.0.2/juturna/payloads/__init__.py +22 -0
- juturna-1.0.2/juturna/payloads/_generics.py +29 -0
- juturna-1.0.2/juturna/payloads/_payloads.py +108 -0
- juturna-1.0.2/juturna/utils/__init__.py +6 -0
- juturna-1.0.2/juturna/utils/jt_utils/__init__.py +3 -0
- juturna-1.0.2/juturna/utils/jt_utils/_get_env_var.py +31 -0
- juturna-1.0.2/juturna/utils/log_utils/__init__.py +12 -0
- juturna-1.0.2/juturna/utils/log_utils/_formatters.py +72 -0
- juturna-1.0.2/juturna/utils/log_utils/_log_helper.py +62 -0
- juturna-1.0.2/juturna/utils/net_utils/__init__.py +10 -0
- juturna-1.0.2/juturna/utils/net_utils/_port_scanner.py +22 -0
- juturna-1.0.2/juturna/utils/net_utils/_rtp_client.py +96 -0
- juturna-1.0.2/juturna/utils/net_utils/_rtp_datagram.py +61 -0
- juturna-1.0.2/juturna/utils/proc_utils/__init__.py +6 -0
- juturna-1.0.2/juturna/utils/proc_utils/_trx_utils.py +64 -0
- juturna-1.0.2/pyproject.toml +88 -0
juturna-1.0.2/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2025 Antonio Bevilacqua
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
juturna-1.0.2/PKG-INFO
ADDED
|
@@ -0,0 +1,172 @@
|
|
|
1
|
+
Metadata-Version: 2.3
|
|
2
|
+
Name: juturna
|
|
3
|
+
Version: 1.0.2
|
|
4
|
+
Summary: Juturna core library
|
|
5
|
+
License: MIT
|
|
6
|
+
Author: Antonio Bevilacqua
|
|
7
|
+
Author-email: b3by.in.th3.sky@gmail.com
|
|
8
|
+
Maintainer: Antonio Bevilacqua
|
|
9
|
+
Maintainer-email: b3by.in.th3.sky@gmail.com
|
|
10
|
+
Requires-Python: >=3.12
|
|
11
|
+
Classifier: License :: OSI Approved :: MIT License
|
|
12
|
+
Classifier: Programming Language :: Python
|
|
13
|
+
Classifier: Programming Language :: Python :: 3
|
|
14
|
+
Provides-Extra: dev
|
|
15
|
+
Provides-Extra: httpwrapper
|
|
16
|
+
Provides-Extra: pipebuilder
|
|
17
|
+
Requires-Dist: av (>=14.2.0,<15.0.0)
|
|
18
|
+
Requires-Dist: fastapi-cli[httpwrapper] (>=0.0.7,<0.0.8) ; extra == "httpwrapper"
|
|
19
|
+
Requires-Dist: fastapi[httpwrapper] (>=0.115.12,<0.116.0) ; extra == "httpwrapper"
|
|
20
|
+
Requires-Dist: furo[dev] (>=2025.9.25,<2026.0.0) ; extra == "dev"
|
|
21
|
+
Requires-Dist: numpy (==2.2.3)
|
|
22
|
+
Requires-Dist: prompt_toolkit[pipebuilder] (>=3.0.52,<4.0.0) ; extra == "pipebuilder"
|
|
23
|
+
Requires-Dist: pytest[dev] (>=8.3.5,<9.0.0) ; extra == "dev"
|
|
24
|
+
Requires-Dist: requests (==2.32.3)
|
|
25
|
+
Requires-Dist: rich[pipebuilder] (>=13.8.1,<14.0.0) ; extra == "pipebuilder"
|
|
26
|
+
Requires-Dist: sphinx-autoapi[dev] (>=3.6.0,<4.0.0) ; extra == "dev"
|
|
27
|
+
Requires-Dist: sphinx-autobuild[dev] (>=2024.10.3,<2025.0.0) ; extra == "dev"
|
|
28
|
+
Requires-Dist: sphinx-design[dev] (>=0.6.1,<0.7.0) ; extra == "dev"
|
|
29
|
+
Requires-Dist: sphinx-new-tab-link[dev] (>=0.8.0,<0.9.0) ; extra == "dev"
|
|
30
|
+
Requires-Dist: sphinx[dev] (>=8.2.3,<9.0.0) ; extra == "dev"
|
|
31
|
+
Requires-Dist: sphinxcontrib-apidoc[dev] (>=0.5.0,<0.6.0) ; extra == "dev"
|
|
32
|
+
Requires-Dist: sphinxcontrib-napoleon[dev] (>=0.7,<0.8) ; extra == "dev"
|
|
33
|
+
Requires-Dist: websockets (>=15.0.1,<16.0.0)
|
|
34
|
+
Project-URL: Changelog, https://github.com/meetecho/juturna/blob/main/CHANGELOG.md
|
|
35
|
+
Project-URL: Documentation, https://meetecho.github.io/juturna/index.html
|
|
36
|
+
Project-URL: Homepage, https://github.com/meetecho/juturna
|
|
37
|
+
Project-URL: Issues, https://github.com/meetecho/juturna/issues
|
|
38
|
+
Project-URL: Repository, https://github.com/meetecho/juturna
|
|
39
|
+
Description-Content-Type: text/markdown
|
|
40
|
+
|
|
41
|
+
# Juturna – Real-time AI Pipeline Framework
|
|
42
|
+
<p align="center"><img src="https://raw.githubusercontent.com/meetecho/juturna/main/docs/source/_static/img/logo_dark_alt.svg" width="30%">
|
|
43
|
+
<br>
|
|
44
|
+
<img src="https://img.shields.io/github/license/meetecho/juturna?style=for-the-badge"> <img src="https://img.shields.io/github/stars/meetecho/juturna?style=for-the-badge"> <img src="https://img.shields.io/github/forks/meetecho/juturna?style=for-the-badge"> <img src="https://img.shields.io/github/issues/meetecho/juturna?style=for-the-badge">
|
|
45
|
+
</p>
|
|
46
|
+
|
|
47
|
+
## :seedling: Important to know
|
|
48
|
+
Juturna is actively evolving with exciting new features and improvements being
|
|
49
|
+
added regularly. We're using semantic versioning to clearly communicate any
|
|
50
|
+
breaking changes between releases, so you can upgrade with confidence. Juturna
|
|
51
|
+
is perfect for experimentation and prototyping today, and we're working toward
|
|
52
|
+
production-ready stability with each release. So, if you plan to deploy it in
|
|
53
|
+
production, make sure you are comfortable managing potential updates and
|
|
54
|
+
adjustments.
|
|
55
|
+
|
|
56
|
+
## At a glance
|
|
57
|
+
|
|
58
|
+
**Juturna** is a data pipeline library written in Python. It is particularly
|
|
59
|
+
useful for fast prototyping multimedia, **real-time** data applications, as
|
|
60
|
+
well as exploring and testing AI models, in a modular and flexible fashion.
|
|
61
|
+
|
|
62
|
+
Among its many features, there are a few keypoints to highligh about Juturna:
|
|
63
|
+
|
|
64
|
+
* :zap: **Real-Time Streaming:** continuouusly process audio, video and
|
|
65
|
+
arbitrary data streams
|
|
66
|
+
* :electric_plug: **Modularity:** create your own nodes and share them through
|
|
67
|
+
the Juturna hub
|
|
68
|
+
* :link: **Composable workloads:** design pipelines to solve complex tasks in
|
|
69
|
+
minutes
|
|
70
|
+
* 🚀 **Parallelism & Batching:** parallel, non-blocking execution for high
|
|
71
|
+
throughput
|
|
72
|
+
* 📊 **Observability:** built-in logging and metrics support
|
|
73
|
+
|
|
74
|
+
[documentation](https://meetecho.github.io/juturna/index.html) | [contribute](https://github.com/meetecho/juturna/blob/main/CONTRIBUTING.md) | [meetecho](https://www.meetecho.com/en/)
|
|
75
|
+
|
|
76
|
+
## Overview
|
|
77
|
+
|
|
78
|
+
A **pipeline** can simply be defined as a collection of **nodes**.
|
|
79
|
+
|
|
80
|
+
Each **node** acquires a piece of data from its parents and, after performing a
|
|
81
|
+
single task, provide its output to its children. In this sense, a Juturna
|
|
82
|
+
pipeline is nothing else but a DAG, where root nodes have an in-degree of 0
|
|
83
|
+
(this is not technically the case, but we’ll skip it for now), and every other
|
|
84
|
+
node has an in-degree of 1 or more.
|
|
85
|
+
|
|
86
|
+
An example of one of our pipelines, currently in use for live audio
|
|
87
|
+
transcription and summarisation is shown here.
|
|
88
|
+
|
|
89
|
+
<p align="center"><img src="https://raw.githubusercontent.com/meetecho/juturna/main/assets/img/pipeline_example.png"></p>
|
|
90
|
+
|
|
91
|
+
Whilst Juturna ships with a number of built-in nodes (mainly source and sink
|
|
92
|
+
nodes), you can implement your own nodes with ease, and share them so others
|
|
93
|
+
can use them too.
|
|
94
|
+
|
|
95
|
+
To know more about the Juturna internals, please refer to the full
|
|
96
|
+
documentation.
|
|
97
|
+
|
|
98
|
+
## Installation
|
|
99
|
+
|
|
100
|
+
The following dependencies are required to use Juturna:
|
|
101
|
+
|
|
102
|
+
- ``python >= 3.12``
|
|
103
|
+
- system libraries ``libsm6``, ``libext6``, ``ffmpeg``
|
|
104
|
+
|
|
105
|
+
:information_source: Current Python building version is 3.12. The library still
|
|
106
|
+
has to be tested on Python 3.13 and later with GIL disabled.
|
|
107
|
+
|
|
108
|
+
|
|
109
|
+
Juturna is currently available as a opensource codebase, but not yet published
|
|
110
|
+
on PyPi. To install it on your system, first clone the repository, then use
|
|
111
|
+
pip to install it (assuming you are working in a virtual environment):
|
|
112
|
+
|
|
113
|
+
```
|
|
114
|
+
(venv) $ git clone https://github.com/meetecho/juturna
|
|
115
|
+
(venv) $ pip install ./juturna
|
|
116
|
+
```
|
|
117
|
+
|
|
118
|
+
In case you want to include all the development dependencies in the
|
|
119
|
+
installation, specify the ``dev`` group:
|
|
120
|
+
|
|
121
|
+
```
|
|
122
|
+
(venv) $ pip install "./juturna[dev]"
|
|
123
|
+
```
|
|
124
|
+
|
|
125
|
+
To include the Juturna HTTP wrapper, include the ``httpwrapper``:
|
|
126
|
+
|
|
127
|
+
```
|
|
128
|
+
(venv) $ pip install "./juturna[httpwrapper]"
|
|
129
|
+
```
|
|
130
|
+
|
|
131
|
+
Alternatively, you can manually install the required dependencies, and just
|
|
132
|
+
import the juturna module from within the repository folder:
|
|
133
|
+
|
|
134
|
+
```
|
|
135
|
+
(venv) $ pip install av ffmpeg-python opencv-python numpy requests websockets
|
|
136
|
+
(venv) $ python
|
|
137
|
+
>>> import juturna as jt
|
|
138
|
+
```
|
|
139
|
+
|
|
140
|
+
### Dockerfile
|
|
141
|
+
|
|
142
|
+
In the Juturna repository you will find a Dockerfile that can be used to create
|
|
143
|
+
a base Juturna image. To build it, symply navigate within the repo folder and
|
|
144
|
+
run:
|
|
145
|
+
|
|
146
|
+
```
|
|
147
|
+
$ docker build -t juturna:latest .
|
|
148
|
+
```
|
|
149
|
+
|
|
150
|
+
## Contributing
|
|
151
|
+
|
|
152
|
+
Please read [`CONTRIBUTING.md`](https://github.com/meetecho/juturna/blob/main/CONTRIBUTING.md) for:
|
|
153
|
+
|
|
154
|
+
* Branching & PR workflow
|
|
155
|
+
* Code style & linting
|
|
156
|
+
* Issue triage (TBD)
|
|
157
|
+
* Issue & PR templates and a Code of Conduct are provided (TBD)
|
|
158
|
+
* Signing CRA
|
|
159
|
+
|
|
160
|
+
## Changelog
|
|
161
|
+
|
|
162
|
+
All notable changes are documented in [`CHANGELOG.md`](https://github.com/meetecho/juturna/blob/main/CHANGELOG.md)
|
|
163
|
+
following [Semantic Versioning](https://semver.org).
|
|
164
|
+
|
|
165
|
+
## External Docs & Support
|
|
166
|
+
|
|
167
|
+
Coming soon!
|
|
168
|
+
|
|
169
|
+
## License
|
|
170
|
+
|
|
171
|
+
Distributed under the **MIT License**. See [LICENSE](https://github.com/meetecho/juturna/blob/main/LICENSE) for details.
|
|
172
|
+
|
juturna-1.0.2/README.md
ADDED
|
@@ -0,0 +1,131 @@
|
|
|
1
|
+
# Juturna – Real-time AI Pipeline Framework
|
|
2
|
+
<p align="center"><img src="https://raw.githubusercontent.com/meetecho/juturna/main/docs/source/_static/img/logo_dark_alt.svg" width="30%">
|
|
3
|
+
<br>
|
|
4
|
+
<img src="https://img.shields.io/github/license/meetecho/juturna?style=for-the-badge"> <img src="https://img.shields.io/github/stars/meetecho/juturna?style=for-the-badge"> <img src="https://img.shields.io/github/forks/meetecho/juturna?style=for-the-badge"> <img src="https://img.shields.io/github/issues/meetecho/juturna?style=for-the-badge">
|
|
5
|
+
</p>
|
|
6
|
+
|
|
7
|
+
## :seedling: Important to know
|
|
8
|
+
Juturna is actively evolving with exciting new features and improvements being
|
|
9
|
+
added regularly. We're using semantic versioning to clearly communicate any
|
|
10
|
+
breaking changes between releases, so you can upgrade with confidence. Juturna
|
|
11
|
+
is perfect for experimentation and prototyping today, and we're working toward
|
|
12
|
+
production-ready stability with each release. So, if you plan to deploy it in
|
|
13
|
+
production, make sure you are comfortable managing potential updates and
|
|
14
|
+
adjustments.
|
|
15
|
+
|
|
16
|
+
## At a glance
|
|
17
|
+
|
|
18
|
+
**Juturna** is a data pipeline library written in Python. It is particularly
|
|
19
|
+
useful for fast prototyping multimedia, **real-time** data applications, as
|
|
20
|
+
well as exploring and testing AI models, in a modular and flexible fashion.
|
|
21
|
+
|
|
22
|
+
Among its many features, there are a few keypoints to highligh about Juturna:
|
|
23
|
+
|
|
24
|
+
* :zap: **Real-Time Streaming:** continuouusly process audio, video and
|
|
25
|
+
arbitrary data streams
|
|
26
|
+
* :electric_plug: **Modularity:** create your own nodes and share them through
|
|
27
|
+
the Juturna hub
|
|
28
|
+
* :link: **Composable workloads:** design pipelines to solve complex tasks in
|
|
29
|
+
minutes
|
|
30
|
+
* 🚀 **Parallelism & Batching:** parallel, non-blocking execution for high
|
|
31
|
+
throughput
|
|
32
|
+
* 📊 **Observability:** built-in logging and metrics support
|
|
33
|
+
|
|
34
|
+
[documentation](https://meetecho.github.io/juturna/index.html) | [contribute](https://github.com/meetecho/juturna/blob/main/CONTRIBUTING.md) | [meetecho](https://www.meetecho.com/en/)
|
|
35
|
+
|
|
36
|
+
## Overview
|
|
37
|
+
|
|
38
|
+
A **pipeline** can simply be defined as a collection of **nodes**.
|
|
39
|
+
|
|
40
|
+
Each **node** acquires a piece of data from its parents and, after performing a
|
|
41
|
+
single task, provide its output to its children. In this sense, a Juturna
|
|
42
|
+
pipeline is nothing else but a DAG, where root nodes have an in-degree of 0
|
|
43
|
+
(this is not technically the case, but we’ll skip it for now), and every other
|
|
44
|
+
node has an in-degree of 1 or more.
|
|
45
|
+
|
|
46
|
+
An example of one of our pipelines, currently in use for live audio
|
|
47
|
+
transcription and summarisation is shown here.
|
|
48
|
+
|
|
49
|
+
<p align="center"><img src="https://raw.githubusercontent.com/meetecho/juturna/main/assets/img/pipeline_example.png"></p>
|
|
50
|
+
|
|
51
|
+
Whilst Juturna ships with a number of built-in nodes (mainly source and sink
|
|
52
|
+
nodes), you can implement your own nodes with ease, and share them so others
|
|
53
|
+
can use them too.
|
|
54
|
+
|
|
55
|
+
To know more about the Juturna internals, please refer to the full
|
|
56
|
+
documentation.
|
|
57
|
+
|
|
58
|
+
## Installation
|
|
59
|
+
|
|
60
|
+
The following dependencies are required to use Juturna:
|
|
61
|
+
|
|
62
|
+
- ``python >= 3.12``
|
|
63
|
+
- system libraries ``libsm6``, ``libext6``, ``ffmpeg``
|
|
64
|
+
|
|
65
|
+
:information_source: Current Python building version is 3.12. The library still
|
|
66
|
+
has to be tested on Python 3.13 and later with GIL disabled.
|
|
67
|
+
|
|
68
|
+
|
|
69
|
+
Juturna is currently available as a opensource codebase, but not yet published
|
|
70
|
+
on PyPi. To install it on your system, first clone the repository, then use
|
|
71
|
+
pip to install it (assuming you are working in a virtual environment):
|
|
72
|
+
|
|
73
|
+
```
|
|
74
|
+
(venv) $ git clone https://github.com/meetecho/juturna
|
|
75
|
+
(venv) $ pip install ./juturna
|
|
76
|
+
```
|
|
77
|
+
|
|
78
|
+
In case you want to include all the development dependencies in the
|
|
79
|
+
installation, specify the ``dev`` group:
|
|
80
|
+
|
|
81
|
+
```
|
|
82
|
+
(venv) $ pip install "./juturna[dev]"
|
|
83
|
+
```
|
|
84
|
+
|
|
85
|
+
To include the Juturna HTTP wrapper, include the ``httpwrapper``:
|
|
86
|
+
|
|
87
|
+
```
|
|
88
|
+
(venv) $ pip install "./juturna[httpwrapper]"
|
|
89
|
+
```
|
|
90
|
+
|
|
91
|
+
Alternatively, you can manually install the required dependencies, and just
|
|
92
|
+
import the juturna module from within the repository folder:
|
|
93
|
+
|
|
94
|
+
```
|
|
95
|
+
(venv) $ pip install av ffmpeg-python opencv-python numpy requests websockets
|
|
96
|
+
(venv) $ python
|
|
97
|
+
>>> import juturna as jt
|
|
98
|
+
```
|
|
99
|
+
|
|
100
|
+
### Dockerfile
|
|
101
|
+
|
|
102
|
+
In the Juturna repository you will find a Dockerfile that can be used to create
|
|
103
|
+
a base Juturna image. To build it, symply navigate within the repo folder and
|
|
104
|
+
run:
|
|
105
|
+
|
|
106
|
+
```
|
|
107
|
+
$ docker build -t juturna:latest .
|
|
108
|
+
```
|
|
109
|
+
|
|
110
|
+
## Contributing
|
|
111
|
+
|
|
112
|
+
Please read [`CONTRIBUTING.md`](https://github.com/meetecho/juturna/blob/main/CONTRIBUTING.md) for:
|
|
113
|
+
|
|
114
|
+
* Branching & PR workflow
|
|
115
|
+
* Code style & linting
|
|
116
|
+
* Issue triage (TBD)
|
|
117
|
+
* Issue & PR templates and a Code of Conduct are provided (TBD)
|
|
118
|
+
* Signing CRA
|
|
119
|
+
|
|
120
|
+
## Changelog
|
|
121
|
+
|
|
122
|
+
All notable changes are documented in [`CHANGELOG.md`](https://github.com/meetecho/juturna/blob/main/CHANGELOG.md)
|
|
123
|
+
following [Semantic Versioning](https://semver.org).
|
|
124
|
+
|
|
125
|
+
## External Docs & Support
|
|
126
|
+
|
|
127
|
+
Coming soon!
|
|
128
|
+
|
|
129
|
+
## License
|
|
130
|
+
|
|
131
|
+
Distributed under the **MIT License**. See [LICENSE](https://github.com/meetecho/juturna/blob/main/LICENSE) for details.
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
import juturna.names as names
|
|
2
|
+
import juturna.components as components
|
|
3
|
+
import juturna.nodes as nodes
|
|
4
|
+
import juturna.utils as utils
|
|
5
|
+
import juturna.hub as hub
|
|
6
|
+
import juturna.meta as meta
|
|
7
|
+
import juturna.payloads as payloads
|
|
8
|
+
|
|
9
|
+
import juturna.utils.log_utils as log
|
|
10
|
+
|
|
11
|
+
|
|
12
|
+
__app_name__ = 'juturna'
|
|
13
|
+
__version__ = '0.1.0'
|
|
14
|
+
|
|
15
|
+
__all__ = [
|
|
16
|
+
'names',
|
|
17
|
+
'components',
|
|
18
|
+
'nodes',
|
|
19
|
+
'utils',
|
|
20
|
+
'log',
|
|
21
|
+
'meta',
|
|
22
|
+
'hub',
|
|
23
|
+
'payloads'
|
|
24
|
+
]
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
import argparse
|
|
2
|
+
import sys
|
|
3
|
+
|
|
4
|
+
|
|
5
|
+
from juturna.cli import commands
|
|
6
|
+
|
|
7
|
+
|
|
8
|
+
parser = argparse.ArgumentParser(
|
|
9
|
+
prog='juturna',
|
|
10
|
+
description=(
|
|
11
|
+
'Collection of simple CLI utilities to manage pipeline configuration '
|
|
12
|
+
'files and pipeline lifecycles.'
|
|
13
|
+
))
|
|
14
|
+
|
|
15
|
+
subparsers = parser.add_subparsers(
|
|
16
|
+
dest='command',
|
|
17
|
+
description='List of commands included in the juturna CLI')
|
|
18
|
+
|
|
19
|
+
commands.register_all(subparsers)
|
|
20
|
+
_ret = 0
|
|
21
|
+
|
|
22
|
+
args = parser.parse_args()
|
|
23
|
+
|
|
24
|
+
if command := args.command:
|
|
25
|
+
delattr(args, 'command')
|
|
26
|
+
_ret = commands.command(command)(args)
|
|
27
|
+
else:
|
|
28
|
+
parser.print_help()
|
|
29
|
+
|
|
30
|
+
sys.exit(_ret)
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
import argparse
|
|
2
|
+
import pathlib
|
|
3
|
+
|
|
4
|
+
|
|
5
|
+
|
|
6
|
+
def _is_file_ok(file_path: str) -> str:
|
|
7
|
+
if not pathlib.Path(file_path).exists():
|
|
8
|
+
raise argparse.ArgumentTypeError(f'{file_path} does not exists')
|
|
9
|
+
|
|
10
|
+
if not pathlib.Path(file_path).is_file():
|
|
11
|
+
raise argparse.ArgumentTypeError(f'{file_path} is not a file')
|
|
12
|
+
|
|
13
|
+
return file_path
|
|
14
|
+
|
|
15
|
+
|
|
16
|
+
def _is_dir_ok(dir_path: str) -> str:
|
|
17
|
+
if not pathlib.Path(dir_path).exists():
|
|
18
|
+
raise argparse.ArgumentTypeError(f'{dir_path} does not exists')
|
|
19
|
+
|
|
20
|
+
if not pathlib.Path(dir_path).is_dir():
|
|
21
|
+
raise argparse.ArgumentTypeError(f'{dir_path} is not a file')
|
|
22
|
+
|
|
23
|
+
return dir_path
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
"""
|
|
2
|
+
CLI registry
|
|
3
|
+
|
|
4
|
+
Commands are registered based on whether their required modules are installed. A
|
|
5
|
+
command for which its module fails to be imported will not be registered, so it
|
|
6
|
+
will not be available in the command line.
|
|
7
|
+
"""
|
|
8
|
+
|
|
9
|
+
import importlib
|
|
10
|
+
|
|
11
|
+
|
|
12
|
+
_MODULES = {
|
|
13
|
+
cmd: None for cmd in ['launch', 'validate', 'serve', 'create', 'stub']
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
|
|
17
|
+
def _safe_reg(module_name: str, subparsers):
|
|
18
|
+
try:
|
|
19
|
+
_MODULES[module_name] = importlib.import_module(
|
|
20
|
+
f'juturna.cli.commands.{module_name}'
|
|
21
|
+
)
|
|
22
|
+
_MODULES[module_name].setup_parser(subparsers)
|
|
23
|
+
except ModuleNotFoundError:
|
|
24
|
+
...
|
|
25
|
+
|
|
26
|
+
|
|
27
|
+
def register_all(subparsers):
|
|
28
|
+
"""Register subparsers for all modules"""
|
|
29
|
+
for module in _MODULES:
|
|
30
|
+
_safe_reg(module, subparsers)
|
|
31
|
+
|
|
32
|
+
|
|
33
|
+
def command(cmd_name: str):
|
|
34
|
+
"""Return command caller function"""
|
|
35
|
+
return _MODULES[cmd_name]._execute
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
import argparse
|
|
2
|
+
|
|
3
|
+
from juturna.cli import _cli_utils
|
|
4
|
+
|
|
5
|
+
|
|
6
|
+
def common_parser():
|
|
7
|
+
parser = argparse.ArgumentParser(add_help=False)
|
|
8
|
+
|
|
9
|
+
parser.add_argument(
|
|
10
|
+
'--log-level',
|
|
11
|
+
'-l',
|
|
12
|
+
type=str,
|
|
13
|
+
default='DEBUG',
|
|
14
|
+
choices=['NOTSET', 'DEBUG', 'INFO', 'WARNING', 'ERROR'],
|
|
15
|
+
help='set log level during pipeline execution'
|
|
16
|
+
)
|
|
17
|
+
|
|
18
|
+
parser.add_argument(
|
|
19
|
+
'--config',
|
|
20
|
+
'-c',
|
|
21
|
+
required=True,
|
|
22
|
+
metavar='FILE',
|
|
23
|
+
type=_cli_utils._is_file_ok,
|
|
24
|
+
help='pipeline json configuration file',
|
|
25
|
+
)
|
|
26
|
+
|
|
27
|
+
return parser
|
|
@@ -0,0 +1,74 @@
|
|
|
1
|
+
import pathlib
|
|
2
|
+
import tomllib
|
|
3
|
+
|
|
4
|
+
|
|
5
|
+
_TYPE_MAP = {
|
|
6
|
+
bool: 'boolean',
|
|
7
|
+
int: 'integer',
|
|
8
|
+
float: 'float',
|
|
9
|
+
str: 'string',
|
|
10
|
+
dict: 'dictionary',
|
|
11
|
+
list: 'list',
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
|
|
15
|
+
def discover_nodes(node_folder: str) -> dict:
|
|
16
|
+
node_registry = dict()
|
|
17
|
+
|
|
18
|
+
folder = pathlib.Path(node_folder)
|
|
19
|
+
|
|
20
|
+
if not folder.exists():
|
|
21
|
+
raise FileNotFoundError(f'node folder {node_folder} does not exist')
|
|
22
|
+
|
|
23
|
+
for node_type_dir in folder.iterdir():
|
|
24
|
+
if not node_type_dir.is_dir():
|
|
25
|
+
continue
|
|
26
|
+
|
|
27
|
+
nodes = discover_node_marks(str(node_type_dir))
|
|
28
|
+
|
|
29
|
+
if nodes:
|
|
30
|
+
node_registry[node_type_dir.name] = nodes
|
|
31
|
+
|
|
32
|
+
return node_registry
|
|
33
|
+
|
|
34
|
+
|
|
35
|
+
def discover_node_marks(node_folder: str) -> dict:
|
|
36
|
+
folder = pathlib.Path(node_folder)
|
|
37
|
+
registry = dict()
|
|
38
|
+
|
|
39
|
+
marks = folder.glob('_*')
|
|
40
|
+
|
|
41
|
+
for mark_dir in filter(lambda d: d.is_dir(), marks):
|
|
42
|
+
mark = mark_dir.name[1:]
|
|
43
|
+
config_path = mark_dir / 'config.toml'
|
|
44
|
+
|
|
45
|
+
if not config_path.exists():
|
|
46
|
+
continue
|
|
47
|
+
|
|
48
|
+
with open(config_path, 'rb') as f:
|
|
49
|
+
config = tomllib.load(f)
|
|
50
|
+
arguments = config.get('arguments', {})
|
|
51
|
+
|
|
52
|
+
registry[mark] = {
|
|
53
|
+
'arguments': {
|
|
54
|
+
arg_name: {
|
|
55
|
+
'default': arg_value,
|
|
56
|
+
'type': _TYPE_MAP.get(type(arg_value)),
|
|
57
|
+
}
|
|
58
|
+
for arg_name, arg_value in arguments.items()
|
|
59
|
+
}
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
return registry
|
|
63
|
+
|
|
64
|
+
|
|
65
|
+
def get_types(nodes: dict) -> list[str]:
|
|
66
|
+
return sorted(nodes.keys())
|
|
67
|
+
|
|
68
|
+
|
|
69
|
+
def get_marks(nodes: dict, node_type: str) -> list[str]:
|
|
70
|
+
return sorted(nodes.get(node_type, {}).keys())
|
|
71
|
+
|
|
72
|
+
|
|
73
|
+
def get_config(nodes: dict, node_type: str, node_mark: str) -> dict | None:
|
|
74
|
+
return nodes.get(node_type, {}).get(node_mark)
|