airia 0.1.6__tar.gz → 0.1.34__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.
- airia-0.1.34/PKG-INFO +221 -0
- airia-0.1.34/README.md +191 -0
- airia-0.1.34/airia/client/_request_handler/__init__.py +4 -0
- airia-0.1.34/airia/client/_request_handler/async_request_handler.py +293 -0
- airia-0.1.34/airia/client/_request_handler/base_request_handler.py +104 -0
- airia-0.1.34/airia/client/_request_handler/sync_request_handler.py +272 -0
- airia-0.1.34/airia/client/async_client.py +194 -0
- airia-0.1.34/airia/client/attachments/__init__.py +4 -0
- airia-0.1.34/airia/client/attachments/async_attachments.py +52 -0
- airia-0.1.34/airia/client/attachments/base_attachments.py +54 -0
- airia-0.1.34/airia/client/attachments/sync_attachments.py +52 -0
- airia-0.1.34/airia/client/base_client.py +87 -0
- airia-0.1.34/airia/client/conversations/__init__.py +4 -0
- airia-0.1.34/airia/client/conversations/async_conversations.py +187 -0
- airia-0.1.34/airia/client/conversations/base_conversations.py +135 -0
- airia-0.1.34/airia/client/conversations/sync_conversations.py +182 -0
- airia-0.1.34/airia/client/data_vector_search/__init__.py +4 -0
- airia-0.1.34/airia/client/data_vector_search/async_data_vector_search.py +91 -0
- airia-0.1.34/airia/client/data_vector_search/base_data_vector_search.py +54 -0
- airia-0.1.34/airia/client/data_vector_search/sync_data_vector_search.py +85 -0
- airia-0.1.34/airia/client/deployments/__init__.py +11 -0
- airia-0.1.34/airia/client/deployments/async_deployments.py +139 -0
- airia-0.1.34/airia/client/deployments/base_deployments.py +115 -0
- airia-0.1.34/airia/client/deployments/sync_deployments.py +139 -0
- airia-0.1.34/airia/client/library/__init__.py +5 -0
- airia-0.1.34/airia/client/library/async_library.py +100 -0
- airia-0.1.34/airia/client/library/base_library.py +110 -0
- airia-0.1.34/airia/client/library/sync_library.py +100 -0
- airia-0.1.34/airia/client/models/__init__.py +4 -0
- airia-0.1.34/airia/client/models/async_models.py +156 -0
- airia-0.1.34/airia/client/models/base_models.py +102 -0
- airia-0.1.34/airia/client/models/sync_models.py +154 -0
- airia-0.1.34/airia/client/pipeline_execution/__init__.py +4 -0
- airia-0.1.34/airia/client/pipeline_execution/async_pipeline_execution.py +551 -0
- airia-0.1.34/airia/client/pipeline_execution/base_pipeline_execution.py +266 -0
- airia-0.1.34/airia/client/pipeline_execution/sync_pipeline_execution.py +558 -0
- airia-0.1.34/airia/client/pipeline_import/__init__.py +4 -0
- airia-0.1.34/airia/client/pipeline_import/async_pipeline_import.py +147 -0
- airia-0.1.34/airia/client/pipeline_import/base_pipeline_import.py +95 -0
- airia-0.1.34/airia/client/pipeline_import/sync_pipeline_import.py +143 -0
- airia-0.1.34/airia/client/pipelines_config/__init__.py +4 -0
- airia-0.1.34/airia/client/pipelines_config/async_pipelines_config.py +270 -0
- airia-0.1.34/airia/client/pipelines_config/base_pipelines_config.py +177 -0
- airia-0.1.34/airia/client/pipelines_config/sync_pipelines_config.py +270 -0
- airia-0.1.34/airia/client/project/__init__.py +4 -0
- airia-0.1.34/airia/client/project/async_project.py +148 -0
- airia-0.1.34/airia/client/project/base_project.py +97 -0
- airia-0.1.34/airia/client/project/sync_project.py +148 -0
- airia-0.1.34/airia/client/store/__init__.py +4 -0
- airia-0.1.34/airia/client/store/async_store.py +392 -0
- airia-0.1.34/airia/client/store/base_store.py +253 -0
- airia-0.1.34/airia/client/store/sync_store.py +367 -0
- airia-0.1.34/airia/client/sync_client.py +194 -0
- airia-0.1.34/airia/client/tools/__init__.py +4 -0
- airia-0.1.34/airia/client/tools/async_tools.py +259 -0
- airia-0.1.34/airia/client/tools/base_tools.py +153 -0
- airia-0.1.34/airia/client/tools/sync_tools.py +245 -0
- airia-0.1.34/airia/constants.py +20 -0
- {airia-0.1.6 → airia-0.1.34}/airia/exceptions.py +12 -11
- {airia-0.1.6 → airia-0.1.34}/airia/logs.py +10 -32
- airia-0.1.34/airia/types/__init__.py +11 -0
- airia-0.1.34/airia/types/_request_data.py +38 -0
- airia-0.1.34/airia/types/_structured_output.py +182 -0
- airia-0.1.34/airia/types/api/__init__.py +4 -0
- airia-0.1.34/airia/types/api/attachments/__init__.py +3 -0
- airia-0.1.34/airia/types/api/attachments/upload_file.py +17 -0
- airia-0.1.34/airia/types/api/conversations/__init__.py +13 -0
- airia-0.1.34/airia/types/api/conversations/_conversations.py +115 -0
- airia-0.1.34/airia/types/api/data_vector_search/__init__.py +3 -0
- airia-0.1.34/airia/types/api/data_vector_search/get_file_chunks.py +45 -0
- airia-0.1.34/airia/types/api/deployments/__init__.py +26 -0
- airia-0.1.34/airia/types/api/deployments/get_deployment.py +106 -0
- airia-0.1.34/airia/types/api/deployments/get_deployments.py +224 -0
- airia-0.1.34/airia/types/api/library/__init__.py +11 -0
- airia-0.1.34/airia/types/api/library/_library_models.py +218 -0
- airia-0.1.34/airia/types/api/models/__init__.py +13 -0
- airia-0.1.34/airia/types/api/models/list_models.py +129 -0
- airia-0.1.34/airia/types/api/pipeline_execution/__init__.py +31 -0
- airia-0.1.34/airia/types/api/pipeline_execution/_pipeline_execution.py +183 -0
- airia-0.1.34/airia/types/api/pipeline_execution/get_pipeline_execution.py +83 -0
- airia-0.1.34/airia/types/api/pipeline_import/__init__.py +11 -0
- airia-0.1.34/airia/types/api/pipeline_import/create_agent_from_pipeline_definition.py +108 -0
- airia-0.1.34/airia/types/api/pipelines_config/__init__.py +93 -0
- airia-0.1.34/airia/types/api/pipelines_config/export_pipeline_definition.py +1531 -0
- airia-0.1.34/airia/types/api/pipelines_config/get_pipeline_config.py +554 -0
- airia-0.1.34/airia/types/api/pipelines_config/get_pipelines_config.py +381 -0
- airia-0.1.34/airia/types/api/project/__init__.py +3 -0
- airia-0.1.34/airia/types/api/project/get_projects.py +91 -0
- airia-0.1.34/airia/types/api/store/__init__.py +19 -0
- airia-0.1.34/airia/types/api/store/get_file.py +145 -0
- airia-0.1.34/airia/types/api/store/get_files.py +21 -0
- airia-0.1.34/airia/types/api/tools/__init__.py +7 -0
- airia-0.1.34/airia/types/api/tools/_tools.py +245 -0
- {airia-0.1.6/airia/types → airia-0.1.34/airia/types/sse}/__init__.py +12 -18
- airia-0.1.34/airia/types/sse/sse_messages.py +767 -0
- {airia-0.1.6 → airia-0.1.34}/airia/utils/sse_parser.py +41 -8
- airia-0.1.34/airia.egg-info/PKG-INFO +221 -0
- airia-0.1.34/airia.egg-info/SOURCES.txt +105 -0
- {airia-0.1.6 → airia-0.1.34}/pyproject.toml +10 -2
- airia-0.1.6/PKG-INFO +0 -535
- airia-0.1.6/README.md +0 -505
- airia-0.1.6/airia/client/async_client.py +0 -582
- airia-0.1.6/airia/client/base_client.py +0 -218
- airia-0.1.6/airia/client/sync_client.py +0 -564
- airia-0.1.6/airia/types/api/get_pipeline_config.py +0 -65
- airia-0.1.6/airia/types/api/pipeline_execution.py +0 -33
- airia-0.1.6/airia/types/request_data.py +0 -10
- airia-0.1.6/airia/types/sse_messages.py +0 -269
- airia-0.1.6/airia.egg-info/PKG-INFO +0 -535
- airia-0.1.6/airia.egg-info/SOURCES.txt +0 -27
- airia-0.1.6/tests/test_anthropic_gateway.py +0 -93
- airia-0.1.6/tests/test_execute_pipeline.py +0 -241
- airia-0.1.6/tests/test_get_active_pipelines_ids.py +0 -191
- airia-0.1.6/tests/test_get_pipeline_config.py +0 -394
- airia-0.1.6/tests/test_openai_gateway.py +0 -103
- {airia-0.1.6 → airia-0.1.34}/LICENSE +0 -0
- {airia-0.1.6 → airia-0.1.34}/airia/__init__.py +0 -0
- {airia-0.1.6 → airia-0.1.34}/airia/client/__init__.py +0 -0
- /airia-0.1.6/airia/types/api_version.py → /airia-0.1.34/airia/types/_api_version.py +0 -0
- {airia-0.1.6 → airia-0.1.34}/airia.egg-info/dependency_links.txt +0 -0
- {airia-0.1.6 → airia-0.1.34}/airia.egg-info/requires.txt +0 -0
- {airia-0.1.6 → airia-0.1.34}/airia.egg-info/top_level.txt +0 -0
- {airia-0.1.6 → airia-0.1.34}/setup.cfg +0 -0
airia-0.1.34/PKG-INFO
ADDED
|
@@ -0,0 +1,221 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: airia
|
|
3
|
+
Version: 0.1.34
|
|
4
|
+
Summary: Python SDK for Airia API
|
|
5
|
+
Author-email: Airia LLC <support@airia.com>
|
|
6
|
+
License: MIT
|
|
7
|
+
Classifier: Programming Language :: Python :: 3
|
|
8
|
+
Classifier: Programming Language :: Python :: 3.9
|
|
9
|
+
Classifier: Programming Language :: Python :: 3.10
|
|
10
|
+
Classifier: Programming Language :: Python :: 3.11
|
|
11
|
+
Classifier: Programming Language :: Python :: 3.12
|
|
12
|
+
Classifier: Programming Language :: Python :: 3.13
|
|
13
|
+
Classifier: License :: OSI Approved :: MIT License
|
|
14
|
+
Classifier: Operating System :: OS Independent
|
|
15
|
+
Requires-Python: >=3.9
|
|
16
|
+
Description-Content-Type: text/markdown
|
|
17
|
+
License-File: LICENSE
|
|
18
|
+
Requires-Dist: requests>=2.32.3
|
|
19
|
+
Requires-Dist: aiohttp>=3.11.14
|
|
20
|
+
Requires-Dist: loguru>=0.7.3
|
|
21
|
+
Requires-Dist: pydantic>=2.11.0
|
|
22
|
+
Provides-Extra: anthropic
|
|
23
|
+
Requires-Dist: anthropic>=0.49.0; extra == "anthropic"
|
|
24
|
+
Provides-Extra: openai
|
|
25
|
+
Requires-Dist: openai>=1.74.0; extra == "openai"
|
|
26
|
+
Provides-Extra: all
|
|
27
|
+
Requires-Dist: anthropic>=0.49.0; extra == "all"
|
|
28
|
+
Requires-Dist: openai>=1.74.0; extra == "all"
|
|
29
|
+
Dynamic: license-file
|
|
30
|
+
|
|
31
|
+
# Airia Python API Library
|
|
32
|
+
|
|
33
|
+
[](https://badge.fury.io/py/airia)
|
|
34
|
+
[](https://pypi.org/project/airia/)
|
|
35
|
+
[](https://pypi.org/project/airia/)
|
|
36
|
+
|
|
37
|
+
The Airia Python library provides a clean and intuitive interface to interact with Airia API. The library offers both synchronous and asynchronous clients for maximum flexibility in your applications.
|
|
38
|
+
|
|
39
|
+
## Features
|
|
40
|
+
|
|
41
|
+
- **Dual Client Support**: Choose between synchronous (`AiriaClient`) and asynchronous (`AiriaAsyncClient`) implementations
|
|
42
|
+
- **Pipeline Execution**: Easily run AI pipelines with customizable parameters
|
|
43
|
+
- **Gateway Support**: Seamlessly integrate with OpenAI and Anthropic services through Airia gateways
|
|
44
|
+
- **Error Handling**: Comprehensive error handling with custom exceptions
|
|
45
|
+
- **Logging**: Built-in configurable logging with correlation ID support for request tracing
|
|
46
|
+
- **Flexible Authentication**: Support for both API keys and bearer tokens with flexible configuration
|
|
47
|
+
|
|
48
|
+
## Documentation and Quick Start Guides
|
|
49
|
+
|
|
50
|
+
Full documentation and quick start guides are available [here](https://airiallc.github.io/airia-python).
|
|
51
|
+
|
|
52
|
+
You can also run the documentation page locally with `mkdocs`:
|
|
53
|
+
|
|
54
|
+
1. [Install development dependencies](#install-with-development-dependencies)
|
|
55
|
+
2. Run `mkdocs serve` to start the local server
|
|
56
|
+
|
|
57
|
+
## Installation
|
|
58
|
+
|
|
59
|
+
You can install the package using pip or uv:
|
|
60
|
+
|
|
61
|
+
<table>
|
|
62
|
+
<tr>
|
|
63
|
+
<th>pip</th>
|
|
64
|
+
<th>uv</th>
|
|
65
|
+
</tr>
|
|
66
|
+
<tr>
|
|
67
|
+
<td>
|
|
68
|
+
|
|
69
|
+
```bash
|
|
70
|
+
pip install airia
|
|
71
|
+
```
|
|
72
|
+
|
|
73
|
+
</td>
|
|
74
|
+
<td>
|
|
75
|
+
|
|
76
|
+
```bash
|
|
77
|
+
uv add airia
|
|
78
|
+
```
|
|
79
|
+
|
|
80
|
+
</td>
|
|
81
|
+
</tr>
|
|
82
|
+
</table>
|
|
83
|
+
|
|
84
|
+
### Install with optional dependencies
|
|
85
|
+
|
|
86
|
+
The package supports optional dependencies for gateway functionality:
|
|
87
|
+
|
|
88
|
+
<table>
|
|
89
|
+
<tr>
|
|
90
|
+
<th>OpenAI Gateway</th>
|
|
91
|
+
<th>Anthropic Gateway</th>
|
|
92
|
+
<th>All Gateways</th>
|
|
93
|
+
</tr>
|
|
94
|
+
<tr>
|
|
95
|
+
<td>
|
|
96
|
+
|
|
97
|
+
```bash
|
|
98
|
+
pip install "airia[openai]"
|
|
99
|
+
```
|
|
100
|
+
|
|
101
|
+
</td>
|
|
102
|
+
<td>
|
|
103
|
+
|
|
104
|
+
```bash
|
|
105
|
+
pip install "airia[anthropic]"
|
|
106
|
+
```
|
|
107
|
+
|
|
108
|
+
</td>
|
|
109
|
+
<td>
|
|
110
|
+
|
|
111
|
+
```bash
|
|
112
|
+
pip install "airia[all]"
|
|
113
|
+
```
|
|
114
|
+
|
|
115
|
+
</td>
|
|
116
|
+
</tr>
|
|
117
|
+
</table>
|
|
118
|
+
|
|
119
|
+
### Install with development dependencies
|
|
120
|
+
|
|
121
|
+
Clone the repository:
|
|
122
|
+
|
|
123
|
+
```bash
|
|
124
|
+
git clone https://github.com/AiriaLLC/airia-python.git
|
|
125
|
+
cd airia-python
|
|
126
|
+
```
|
|
127
|
+
|
|
128
|
+
Then, run one of the following commands:
|
|
129
|
+
|
|
130
|
+
<table>
|
|
131
|
+
<tr>
|
|
132
|
+
<th>pip</th>
|
|
133
|
+
<th>uv</th>
|
|
134
|
+
</tr>
|
|
135
|
+
<tr>
|
|
136
|
+
<td>
|
|
137
|
+
|
|
138
|
+
```bash
|
|
139
|
+
pip install dependency-groups
|
|
140
|
+
dev=$(python -m dependency_groups dev)
|
|
141
|
+
pip install -e .
|
|
142
|
+
pip install $dev
|
|
143
|
+
```
|
|
144
|
+
|
|
145
|
+
</td>
|
|
146
|
+
<td>
|
|
147
|
+
|
|
148
|
+
```bash
|
|
149
|
+
uv sync --frozen --group dev
|
|
150
|
+
```
|
|
151
|
+
|
|
152
|
+
</td>
|
|
153
|
+
</tr>
|
|
154
|
+
</table>
|
|
155
|
+
|
|
156
|
+
## Building from Source
|
|
157
|
+
|
|
158
|
+
First make sure you have already cloned the repository, then run one of the following commands:
|
|
159
|
+
|
|
160
|
+
<table>
|
|
161
|
+
<tr>
|
|
162
|
+
<th>pip</th>
|
|
163
|
+
<th>uv</th>
|
|
164
|
+
</tr>
|
|
165
|
+
<tr>
|
|
166
|
+
<td>
|
|
167
|
+
|
|
168
|
+
```bash
|
|
169
|
+
pip install build
|
|
170
|
+
python -m build
|
|
171
|
+
```
|
|
172
|
+
|
|
173
|
+
</td>
|
|
174
|
+
<td>
|
|
175
|
+
|
|
176
|
+
```bash
|
|
177
|
+
uv build
|
|
178
|
+
```
|
|
179
|
+
|
|
180
|
+
</td>
|
|
181
|
+
</tr>
|
|
182
|
+
</table>
|
|
183
|
+
|
|
184
|
+
This will create both wheel and source distribution in the `dist/` directory.
|
|
185
|
+
|
|
186
|
+
## Requirements
|
|
187
|
+
|
|
188
|
+
- Python 3.9 or higher
|
|
189
|
+
- Core dependencies:
|
|
190
|
+
- requests
|
|
191
|
+
- aiohttp
|
|
192
|
+
- loguru
|
|
193
|
+
- pydantic
|
|
194
|
+
|
|
195
|
+
- Optional dependencies:
|
|
196
|
+
- OpenAI gateway: `openai>=1.74.0`
|
|
197
|
+
- Anthropic gateway: `anthropic>=0.49.0`
|
|
198
|
+
|
|
199
|
+
## Development
|
|
200
|
+
|
|
201
|
+
To run tests (make sure you have development dependencies installed):
|
|
202
|
+
|
|
203
|
+
```bash
|
|
204
|
+
pytest
|
|
205
|
+
```
|
|
206
|
+
|
|
207
|
+
For testing gateway functionality, install the optional dependencies:
|
|
208
|
+
|
|
209
|
+
```bash
|
|
210
|
+
# For OpenAI gateway tests
|
|
211
|
+
pip install -e .[openai]
|
|
212
|
+
pytest tests/test_openai_gateway.py
|
|
213
|
+
|
|
214
|
+
# For Anthropic gateway tests
|
|
215
|
+
pip install -e .[anthropic]
|
|
216
|
+
pytest tests/test_anthropic_gateway.py
|
|
217
|
+
|
|
218
|
+
# For all tests
|
|
219
|
+
pip install -e .[all]
|
|
220
|
+
pytest
|
|
221
|
+
```
|
airia-0.1.34/README.md
ADDED
|
@@ -0,0 +1,191 @@
|
|
|
1
|
+
# Airia Python API Library
|
|
2
|
+
|
|
3
|
+
[](https://badge.fury.io/py/airia)
|
|
4
|
+
[](https://pypi.org/project/airia/)
|
|
5
|
+
[](https://pypi.org/project/airia/)
|
|
6
|
+
|
|
7
|
+
The Airia Python library provides a clean and intuitive interface to interact with Airia API. The library offers both synchronous and asynchronous clients for maximum flexibility in your applications.
|
|
8
|
+
|
|
9
|
+
## Features
|
|
10
|
+
|
|
11
|
+
- **Dual Client Support**: Choose between synchronous (`AiriaClient`) and asynchronous (`AiriaAsyncClient`) implementations
|
|
12
|
+
- **Pipeline Execution**: Easily run AI pipelines with customizable parameters
|
|
13
|
+
- **Gateway Support**: Seamlessly integrate with OpenAI and Anthropic services through Airia gateways
|
|
14
|
+
- **Error Handling**: Comprehensive error handling with custom exceptions
|
|
15
|
+
- **Logging**: Built-in configurable logging with correlation ID support for request tracing
|
|
16
|
+
- **Flexible Authentication**: Support for both API keys and bearer tokens with flexible configuration
|
|
17
|
+
|
|
18
|
+
## Documentation and Quick Start Guides
|
|
19
|
+
|
|
20
|
+
Full documentation and quick start guides are available [here](https://airiallc.github.io/airia-python).
|
|
21
|
+
|
|
22
|
+
You can also run the documentation page locally with `mkdocs`:
|
|
23
|
+
|
|
24
|
+
1. [Install development dependencies](#install-with-development-dependencies)
|
|
25
|
+
2. Run `mkdocs serve` to start the local server
|
|
26
|
+
|
|
27
|
+
## Installation
|
|
28
|
+
|
|
29
|
+
You can install the package using pip or uv:
|
|
30
|
+
|
|
31
|
+
<table>
|
|
32
|
+
<tr>
|
|
33
|
+
<th>pip</th>
|
|
34
|
+
<th>uv</th>
|
|
35
|
+
</tr>
|
|
36
|
+
<tr>
|
|
37
|
+
<td>
|
|
38
|
+
|
|
39
|
+
```bash
|
|
40
|
+
pip install airia
|
|
41
|
+
```
|
|
42
|
+
|
|
43
|
+
</td>
|
|
44
|
+
<td>
|
|
45
|
+
|
|
46
|
+
```bash
|
|
47
|
+
uv add airia
|
|
48
|
+
```
|
|
49
|
+
|
|
50
|
+
</td>
|
|
51
|
+
</tr>
|
|
52
|
+
</table>
|
|
53
|
+
|
|
54
|
+
### Install with optional dependencies
|
|
55
|
+
|
|
56
|
+
The package supports optional dependencies for gateway functionality:
|
|
57
|
+
|
|
58
|
+
<table>
|
|
59
|
+
<tr>
|
|
60
|
+
<th>OpenAI Gateway</th>
|
|
61
|
+
<th>Anthropic Gateway</th>
|
|
62
|
+
<th>All Gateways</th>
|
|
63
|
+
</tr>
|
|
64
|
+
<tr>
|
|
65
|
+
<td>
|
|
66
|
+
|
|
67
|
+
```bash
|
|
68
|
+
pip install "airia[openai]"
|
|
69
|
+
```
|
|
70
|
+
|
|
71
|
+
</td>
|
|
72
|
+
<td>
|
|
73
|
+
|
|
74
|
+
```bash
|
|
75
|
+
pip install "airia[anthropic]"
|
|
76
|
+
```
|
|
77
|
+
|
|
78
|
+
</td>
|
|
79
|
+
<td>
|
|
80
|
+
|
|
81
|
+
```bash
|
|
82
|
+
pip install "airia[all]"
|
|
83
|
+
```
|
|
84
|
+
|
|
85
|
+
</td>
|
|
86
|
+
</tr>
|
|
87
|
+
</table>
|
|
88
|
+
|
|
89
|
+
### Install with development dependencies
|
|
90
|
+
|
|
91
|
+
Clone the repository:
|
|
92
|
+
|
|
93
|
+
```bash
|
|
94
|
+
git clone https://github.com/AiriaLLC/airia-python.git
|
|
95
|
+
cd airia-python
|
|
96
|
+
```
|
|
97
|
+
|
|
98
|
+
Then, run one of the following commands:
|
|
99
|
+
|
|
100
|
+
<table>
|
|
101
|
+
<tr>
|
|
102
|
+
<th>pip</th>
|
|
103
|
+
<th>uv</th>
|
|
104
|
+
</tr>
|
|
105
|
+
<tr>
|
|
106
|
+
<td>
|
|
107
|
+
|
|
108
|
+
```bash
|
|
109
|
+
pip install dependency-groups
|
|
110
|
+
dev=$(python -m dependency_groups dev)
|
|
111
|
+
pip install -e .
|
|
112
|
+
pip install $dev
|
|
113
|
+
```
|
|
114
|
+
|
|
115
|
+
</td>
|
|
116
|
+
<td>
|
|
117
|
+
|
|
118
|
+
```bash
|
|
119
|
+
uv sync --frozen --group dev
|
|
120
|
+
```
|
|
121
|
+
|
|
122
|
+
</td>
|
|
123
|
+
</tr>
|
|
124
|
+
</table>
|
|
125
|
+
|
|
126
|
+
## Building from Source
|
|
127
|
+
|
|
128
|
+
First make sure you have already cloned the repository, then run one of the following commands:
|
|
129
|
+
|
|
130
|
+
<table>
|
|
131
|
+
<tr>
|
|
132
|
+
<th>pip</th>
|
|
133
|
+
<th>uv</th>
|
|
134
|
+
</tr>
|
|
135
|
+
<tr>
|
|
136
|
+
<td>
|
|
137
|
+
|
|
138
|
+
```bash
|
|
139
|
+
pip install build
|
|
140
|
+
python -m build
|
|
141
|
+
```
|
|
142
|
+
|
|
143
|
+
</td>
|
|
144
|
+
<td>
|
|
145
|
+
|
|
146
|
+
```bash
|
|
147
|
+
uv build
|
|
148
|
+
```
|
|
149
|
+
|
|
150
|
+
</td>
|
|
151
|
+
</tr>
|
|
152
|
+
</table>
|
|
153
|
+
|
|
154
|
+
This will create both wheel and source distribution in the `dist/` directory.
|
|
155
|
+
|
|
156
|
+
## Requirements
|
|
157
|
+
|
|
158
|
+
- Python 3.9 or higher
|
|
159
|
+
- Core dependencies:
|
|
160
|
+
- requests
|
|
161
|
+
- aiohttp
|
|
162
|
+
- loguru
|
|
163
|
+
- pydantic
|
|
164
|
+
|
|
165
|
+
- Optional dependencies:
|
|
166
|
+
- OpenAI gateway: `openai>=1.74.0`
|
|
167
|
+
- Anthropic gateway: `anthropic>=0.49.0`
|
|
168
|
+
|
|
169
|
+
## Development
|
|
170
|
+
|
|
171
|
+
To run tests (make sure you have development dependencies installed):
|
|
172
|
+
|
|
173
|
+
```bash
|
|
174
|
+
pytest
|
|
175
|
+
```
|
|
176
|
+
|
|
177
|
+
For testing gateway functionality, install the optional dependencies:
|
|
178
|
+
|
|
179
|
+
```bash
|
|
180
|
+
# For OpenAI gateway tests
|
|
181
|
+
pip install -e .[openai]
|
|
182
|
+
pytest tests/test_openai_gateway.py
|
|
183
|
+
|
|
184
|
+
# For Anthropic gateway tests
|
|
185
|
+
pip install -e .[anthropic]
|
|
186
|
+
pytest tests/test_anthropic_gateway.py
|
|
187
|
+
|
|
188
|
+
# For all tests
|
|
189
|
+
pip install -e .[all]
|
|
190
|
+
pytest
|
|
191
|
+
```
|
|
@@ -0,0 +1,293 @@
|
|
|
1
|
+
import asyncio
|
|
2
|
+
import weakref
|
|
3
|
+
from typing import Any, AsyncIterator, Dict, Optional
|
|
4
|
+
|
|
5
|
+
import aiohttp
|
|
6
|
+
import loguru
|
|
7
|
+
|
|
8
|
+
from ...exceptions import AiriaAPIError
|
|
9
|
+
from ...types._request_data import RequestData
|
|
10
|
+
from ...utils.sse_parser import async_parse_sse_stream_chunked
|
|
11
|
+
from .base_request_handler import BaseRequestHandler
|
|
12
|
+
|
|
13
|
+
|
|
14
|
+
class AsyncRequestHandler(BaseRequestHandler):
|
|
15
|
+
def __init__(
|
|
16
|
+
self,
|
|
17
|
+
logger: "loguru.Logger",
|
|
18
|
+
timeout: float,
|
|
19
|
+
base_url: str,
|
|
20
|
+
api_key: Optional[str] = None,
|
|
21
|
+
bearer_token: Optional[str] = None,
|
|
22
|
+
log_requests: bool = False,
|
|
23
|
+
):
|
|
24
|
+
self.session = aiohttp.ClientSession()
|
|
25
|
+
|
|
26
|
+
self._finalizer = weakref.finalize(self, self._cleanup_session, self.session)
|
|
27
|
+
|
|
28
|
+
super().__init__(
|
|
29
|
+
logger=logger,
|
|
30
|
+
timeout=timeout,
|
|
31
|
+
api_key=api_key,
|
|
32
|
+
base_url=base_url,
|
|
33
|
+
bearer_token=bearer_token,
|
|
34
|
+
log_requests=log_requests,
|
|
35
|
+
)
|
|
36
|
+
|
|
37
|
+
@staticmethod
|
|
38
|
+
def _cleanup_session(session: aiohttp.ClientSession):
|
|
39
|
+
"""Static method to clean up session - called by finalizer"""
|
|
40
|
+
if session and not session.closed:
|
|
41
|
+
# Create a new event loop if none exists
|
|
42
|
+
try:
|
|
43
|
+
loop = asyncio.get_event_loop()
|
|
44
|
+
if loop.is_closed():
|
|
45
|
+
raise RuntimeError("Event loop is closed")
|
|
46
|
+
except RuntimeError:
|
|
47
|
+
loop = asyncio.new_event_loop()
|
|
48
|
+
asyncio.set_event_loop(loop)
|
|
49
|
+
|
|
50
|
+
# Close the session
|
|
51
|
+
if not loop.is_running():
|
|
52
|
+
loop.run_until_complete(session.close())
|
|
53
|
+
else:
|
|
54
|
+
# If loop is running, schedule the close operation
|
|
55
|
+
asyncio.create_task(session.close())
|
|
56
|
+
|
|
57
|
+
async def close(self):
|
|
58
|
+
"""
|
|
59
|
+
Closes the aiohttp session to free up system resources.
|
|
60
|
+
|
|
61
|
+
This method should be called when the RequestHandler is no longer needed to ensure
|
|
62
|
+
proper cleanup of the underlying session and its resources.
|
|
63
|
+
"""
|
|
64
|
+
if self.session and not self.session.closed:
|
|
65
|
+
await self.session.close()
|
|
66
|
+
|
|
67
|
+
def _handle_exception(
|
|
68
|
+
self,
|
|
69
|
+
e: aiohttp.ClientResponseError,
|
|
70
|
+
detailed_error: str,
|
|
71
|
+
url: str,
|
|
72
|
+
correlation_id: str,
|
|
73
|
+
):
|
|
74
|
+
# Log the error response if enabled
|
|
75
|
+
if self.log_requests:
|
|
76
|
+
self.logger.error(
|
|
77
|
+
f"API Error: {e.status} {e.message}\n"
|
|
78
|
+
f"Detailed Error Message: {detailed_error}\n"
|
|
79
|
+
f"URL: {url}\n"
|
|
80
|
+
f"Correlation ID: {correlation_id}"
|
|
81
|
+
)
|
|
82
|
+
|
|
83
|
+
# Extract error details from response
|
|
84
|
+
error_message = e.message
|
|
85
|
+
|
|
86
|
+
# Make sure sensitive auth information is not included in error messages
|
|
87
|
+
sanitized_message = error_message
|
|
88
|
+
if self.api_key and self.api_key in sanitized_message:
|
|
89
|
+
sanitized_message = sanitized_message.replace(self.api_key, "[REDACTED]")
|
|
90
|
+
if self.bearer_token and self.bearer_token in sanitized_message:
|
|
91
|
+
sanitized_message = sanitized_message.replace(
|
|
92
|
+
self.bearer_token, "[REDACTED]"
|
|
93
|
+
)
|
|
94
|
+
|
|
95
|
+
# Raise custom exception with status code and sanitized message
|
|
96
|
+
raise AiriaAPIError(
|
|
97
|
+
status_code=e.status,
|
|
98
|
+
message=sanitized_message,
|
|
99
|
+
detailed_message=detailed_error,
|
|
100
|
+
) from e
|
|
101
|
+
|
|
102
|
+
async def make_request(
|
|
103
|
+
self, method: str, request_data: RequestData, return_json: bool = True
|
|
104
|
+
) -> Optional[Dict[str, Any]]:
|
|
105
|
+
"""
|
|
106
|
+
Makes an asynchronous HTTP request to the Airia API.
|
|
107
|
+
|
|
108
|
+
Args:
|
|
109
|
+
method (str): The HTTP method (e.g., 'GET', 'POST')
|
|
110
|
+
request_data: A dictionary containing the following request information:
|
|
111
|
+
- url: The endpoint URL for the request
|
|
112
|
+
- headers: HTTP headers to include in the request
|
|
113
|
+
- payload: The JSON payload/body for the request
|
|
114
|
+
- params: Optional query parameters to append to the URL
|
|
115
|
+
- files: Optional file data to be uploaded in the request body
|
|
116
|
+
- correlation_id: Unique identifier for request tracing
|
|
117
|
+
return_json (bool): Whether to return the response as JSON. Default is True.
|
|
118
|
+
|
|
119
|
+
Returns:
|
|
120
|
+
resp ([Dict[str, Any]): The JSON response from the API as a dictionary.
|
|
121
|
+
|
|
122
|
+
Raises:
|
|
123
|
+
AiriaAPIError: If the API returns an error response, with details about the error
|
|
124
|
+
aiohttp.ClientResponseError: For HTTP-related errors
|
|
125
|
+
|
|
126
|
+
Note:
|
|
127
|
+
This is an internal method used by other client methods to make API requests.
|
|
128
|
+
It handles logging, error handling, and API key redaction in error messages.
|
|
129
|
+
"""
|
|
130
|
+
try:
|
|
131
|
+
# Make the request
|
|
132
|
+
async with self.session.request(
|
|
133
|
+
method=method,
|
|
134
|
+
url=request_data.url,
|
|
135
|
+
json=request_data.payload,
|
|
136
|
+
params=request_data.params,
|
|
137
|
+
headers=request_data.headers,
|
|
138
|
+
timeout=self.timeout,
|
|
139
|
+
) as response:
|
|
140
|
+
# Log the response if enabled
|
|
141
|
+
if self.log_requests:
|
|
142
|
+
self.logger.info(
|
|
143
|
+
f"API Response: {response.status} {response.reason}\n"
|
|
144
|
+
f"URL: {request_data.url}\n"
|
|
145
|
+
f"Correlation ID: {request_data.correlation_id}"
|
|
146
|
+
)
|
|
147
|
+
|
|
148
|
+
# Check for HTTP errors
|
|
149
|
+
if not response.ok:
|
|
150
|
+
response_text = await response.text()
|
|
151
|
+
response.raise_for_status()
|
|
152
|
+
|
|
153
|
+
# Return the response as a dictionary
|
|
154
|
+
if return_json:
|
|
155
|
+
return await response.json()
|
|
156
|
+
|
|
157
|
+
except aiohttp.ClientResponseError as e:
|
|
158
|
+
self._handle_exception(
|
|
159
|
+
e, response_text, request_data.url, request_data.correlation_id
|
|
160
|
+
)
|
|
161
|
+
|
|
162
|
+
async def make_request_stream(
|
|
163
|
+
self, method: str, request_data: RequestData
|
|
164
|
+
) -> AsyncIterator[str]:
|
|
165
|
+
"""
|
|
166
|
+
Makes an asynchronous HTTP request to the Airia API.
|
|
167
|
+
|
|
168
|
+
Args:
|
|
169
|
+
method (str): The HTTP method (e.g., 'GET', 'POST')
|
|
170
|
+
request_data: A dictionary containing the following request information:
|
|
171
|
+
- url: The endpoint URL for the request
|
|
172
|
+
- headers: HTTP headers to include in the request
|
|
173
|
+
- payload: The JSON payload/body for the request
|
|
174
|
+
- params: Optional query parameters to append to the URL
|
|
175
|
+
- files: Optional file data to be uploaded in the request body
|
|
176
|
+
- correlation_id: Unique identifier for request tracing
|
|
177
|
+
|
|
178
|
+
Yields:
|
|
179
|
+
resp AsyncIterator[str]]: yields chunks of the response as they are received.
|
|
180
|
+
|
|
181
|
+
Raises:
|
|
182
|
+
AiriaAPIError: If the API returns an error response, with details about the error
|
|
183
|
+
aiohttp.ClientResponseError: For HTTP-related errors
|
|
184
|
+
|
|
185
|
+
Note:
|
|
186
|
+
This is an internal method used by other client methods to make API requests.
|
|
187
|
+
It handles logging, error handling, and API key redaction in error messages.
|
|
188
|
+
"""
|
|
189
|
+
try:
|
|
190
|
+
# Make the request
|
|
191
|
+
async with self.session.request(
|
|
192
|
+
method=method,
|
|
193
|
+
url=request_data.url,
|
|
194
|
+
json=request_data.payload,
|
|
195
|
+
params=request_data.params,
|
|
196
|
+
headers=request_data.headers,
|
|
197
|
+
timeout=self.timeout,
|
|
198
|
+
chunked=True,
|
|
199
|
+
) as response:
|
|
200
|
+
# Log the response if enabled
|
|
201
|
+
if self.log_requests:
|
|
202
|
+
self.logger.info(
|
|
203
|
+
f"API Response: {response.status} {response.reason}\n"
|
|
204
|
+
f"URL: {request_data.url}\n"
|
|
205
|
+
f"Correlation ID: {request_data.correlation_id}"
|
|
206
|
+
)
|
|
207
|
+
|
|
208
|
+
# Check for HTTP errors
|
|
209
|
+
if not response.ok:
|
|
210
|
+
response_text = await response.text()
|
|
211
|
+
response.raise_for_status()
|
|
212
|
+
|
|
213
|
+
# Yields the response content as a stream if streaming
|
|
214
|
+
async for message in async_parse_sse_stream_chunked(
|
|
215
|
+
response.content.iter_any()
|
|
216
|
+
):
|
|
217
|
+
yield message
|
|
218
|
+
|
|
219
|
+
except aiohttp.ClientResponseError as e:
|
|
220
|
+
self._handle_exception(
|
|
221
|
+
e, response_text, request_data.url, request_data.correlation_id
|
|
222
|
+
)
|
|
223
|
+
|
|
224
|
+
async def make_request_multipart(
|
|
225
|
+
self, method: str, request_data: RequestData, return_json: bool = True
|
|
226
|
+
) -> Optional[Dict[str, Any]]:
|
|
227
|
+
"""
|
|
228
|
+
Makes an asynchronous HTTP request with multipart form data to the Airia API.
|
|
229
|
+
|
|
230
|
+
Args:
|
|
231
|
+
method (str): The HTTP method (e.g., 'POST')
|
|
232
|
+
request_data: A dictionary containing the following request information:
|
|
233
|
+
- url: The endpoint URL for the request
|
|
234
|
+
- headers: HTTP headers to include in the request
|
|
235
|
+
- payload: The form data payload including file content
|
|
236
|
+
- params: Optional query parameters to append to the URL
|
|
237
|
+
- files: Optional file data to be uploaded in the request body
|
|
238
|
+
- correlation_id: Unique identifier for request tracing
|
|
239
|
+
return_json (bool): Whether to return the response as JSON. Default is True.
|
|
240
|
+
|
|
241
|
+
Returns:
|
|
242
|
+
resp (Optional[Dict[str, Any]]): The JSON response from the API as a dictionary.
|
|
243
|
+
|
|
244
|
+
Raises:
|
|
245
|
+
AiriaAPIError: If the API returns an error response, with details about the error
|
|
246
|
+
aiohttp.ClientResponseError: For HTTP-related errors
|
|
247
|
+
|
|
248
|
+
Note:
|
|
249
|
+
This is an internal method used by file upload methods to make multipart requests.
|
|
250
|
+
It handles multipart form data encoding, logging, and error handling.
|
|
251
|
+
"""
|
|
252
|
+
try:
|
|
253
|
+
# Prepare multipart form data
|
|
254
|
+
data = aiohttp.FormData()
|
|
255
|
+
|
|
256
|
+
# Add form fields
|
|
257
|
+
for key, value in request_data.payload.items():
|
|
258
|
+
data.add_field(key, str(value))
|
|
259
|
+
|
|
260
|
+
# Add files
|
|
261
|
+
for key, value in request_data.files.items():
|
|
262
|
+
data.add_field(key, value[1], filename=value[0], content_type=value[2])
|
|
263
|
+
|
|
264
|
+
# Make the request
|
|
265
|
+
async with self.session.request(
|
|
266
|
+
method=method,
|
|
267
|
+
url=request_data.url,
|
|
268
|
+
data=data,
|
|
269
|
+
params=request_data.params,
|
|
270
|
+
headers=request_data.headers,
|
|
271
|
+
timeout=self.timeout,
|
|
272
|
+
) as response:
|
|
273
|
+
# Log the response if enabled
|
|
274
|
+
if self.log_requests:
|
|
275
|
+
self.logger.info(
|
|
276
|
+
f"API Response: {response.status} {response.reason}\n"
|
|
277
|
+
f"URL: {request_data.url}\n"
|
|
278
|
+
f"Correlation ID: {request_data.correlation_id}"
|
|
279
|
+
)
|
|
280
|
+
|
|
281
|
+
# Check for HTTP errors
|
|
282
|
+
if not response.ok:
|
|
283
|
+
response_text = await response.text()
|
|
284
|
+
response.raise_for_status()
|
|
285
|
+
|
|
286
|
+
# Return the response as a dictionary
|
|
287
|
+
if return_json:
|
|
288
|
+
return await response.json()
|
|
289
|
+
|
|
290
|
+
except aiohttp.ClientResponseError as e:
|
|
291
|
+
self._handle_exception(
|
|
292
|
+
e, response_text, request_data.url, request_data.correlation_id
|
|
293
|
+
)
|