python-open-router 0.3.3__py3-none-any.whl → 0.4.1__py3-none-any.whl
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.
- python_open_router/__init__.py +18 -4
- python_open_router/models.py +143 -20
- python_open_router/open_router.py +157 -9
- {python_open_router-0.3.3.dist-info → python_open_router-0.4.1.dist-info}/METADATA +3 -3
- python_open_router-0.4.1.dist-info/RECORD +9 -0
- {python_open_router-0.3.3.dist-info → python_open_router-0.4.1.dist-info}/WHEEL +1 -1
- {python_open_router-0.3.3.dist-info → python_open_router-0.4.1.dist-info}/licenses/LICENSE.md +1 -1
- python_open_router-0.3.3.dist-info/RECORD +0 -9
python_open_router/__init__.py
CHANGED
|
@@ -6,34 +6,48 @@ from python_open_router.exceptions import (
|
|
|
6
6
|
OpenRouterError,
|
|
7
7
|
)
|
|
8
8
|
from python_open_router.models import (
|
|
9
|
-
|
|
10
|
-
|
|
9
|
+
DefaultParameters,
|
|
10
|
+
DeletedKeyResponse,
|
|
11
11
|
Key,
|
|
12
|
+
KeyCreateResponse,
|
|
12
13
|
KeyData,
|
|
13
14
|
KeyDataWrapper,
|
|
15
|
+
KeyResponseWrapper,
|
|
14
16
|
KeysDataWrapper,
|
|
15
17
|
Modality,
|
|
16
18
|
Model,
|
|
17
19
|
ModelArchitecture,
|
|
20
|
+
ModelLinks,
|
|
21
|
+
ModelResponseWrapper,
|
|
18
22
|
ModelsDataWrapper,
|
|
23
|
+
PerRequestLimits,
|
|
24
|
+
PublicPricing,
|
|
19
25
|
SupportedParameter,
|
|
26
|
+
TopProviderInfo,
|
|
20
27
|
)
|
|
21
28
|
from python_open_router.open_router import OpenRouterClient
|
|
22
29
|
|
|
23
30
|
__all__ = [
|
|
24
|
-
"
|
|
25
|
-
"
|
|
31
|
+
"DefaultParameters",
|
|
32
|
+
"DeletedKeyResponse",
|
|
26
33
|
"Key",
|
|
34
|
+
"KeyCreateResponse",
|
|
27
35
|
"KeyData",
|
|
28
36
|
"KeyDataWrapper",
|
|
37
|
+
"KeyResponseWrapper",
|
|
29
38
|
"KeysDataWrapper",
|
|
30
39
|
"Modality",
|
|
31
40
|
"Model",
|
|
32
41
|
"ModelArchitecture",
|
|
42
|
+
"ModelLinks",
|
|
43
|
+
"ModelResponseWrapper",
|
|
33
44
|
"ModelsDataWrapper",
|
|
34
45
|
"OpenRouterAuthenticationError",
|
|
35
46
|
"OpenRouterClient",
|
|
36
47
|
"OpenRouterConnectionError",
|
|
37
48
|
"OpenRouterError",
|
|
49
|
+
"PerRequestLimits",
|
|
50
|
+
"PublicPricing",
|
|
38
51
|
"SupportedParameter",
|
|
52
|
+
"TopProviderInfo",
|
|
39
53
|
]
|
python_open_router/models.py
CHANGED
|
@@ -24,10 +24,23 @@ class KeyData(DataClassORJSONMixin):
|
|
|
24
24
|
"""The OpenRouter key data."""
|
|
25
25
|
|
|
26
26
|
label: str
|
|
27
|
-
usage:
|
|
27
|
+
usage: float
|
|
28
28
|
is_provisioning_key: bool
|
|
29
|
-
limit_remaining:
|
|
29
|
+
limit_remaining: float | None
|
|
30
30
|
is_free_tier: bool
|
|
31
|
+
limit: float | None = None
|
|
32
|
+
limit_reset: str | None = None
|
|
33
|
+
usage_daily: float = 0.0
|
|
34
|
+
usage_weekly: float = 0.0
|
|
35
|
+
usage_monthly: float = 0.0
|
|
36
|
+
byok_usage: float = 0.0
|
|
37
|
+
byok_usage_daily: float = 0.0
|
|
38
|
+
byok_usage_weekly: float = 0.0
|
|
39
|
+
byok_usage_monthly: float = 0.0
|
|
40
|
+
include_byok_in_limit: bool = False
|
|
41
|
+
is_management_key: bool = False
|
|
42
|
+
creator_user_id: str | None = None
|
|
43
|
+
expires_at: str | None = None
|
|
31
44
|
|
|
32
45
|
|
|
33
46
|
@dataclass
|
|
@@ -38,10 +51,11 @@ class KeysDataWrapper(DataClassORJSONMixin):
|
|
|
38
51
|
|
|
39
52
|
|
|
40
53
|
@dataclass
|
|
41
|
-
class
|
|
42
|
-
"""
|
|
54
|
+
class KeyCreateResponse(DataClassORJSONMixin):
|
|
55
|
+
"""Response from creating a key."""
|
|
43
56
|
|
|
44
|
-
data:
|
|
57
|
+
data: Key
|
|
58
|
+
key: str
|
|
45
59
|
|
|
46
60
|
|
|
47
61
|
@dataclass
|
|
@@ -52,15 +66,44 @@ class Key(DataClassORJSONMixin):
|
|
|
52
66
|
name: str
|
|
53
67
|
label: str
|
|
54
68
|
disabled: bool
|
|
55
|
-
limit: float
|
|
69
|
+
limit: float | None = None
|
|
56
70
|
usage: float = 0.0
|
|
71
|
+
created_at: str = ""
|
|
72
|
+
updated_at: str | None = None
|
|
73
|
+
limit_remaining: float | None = None
|
|
74
|
+
limit_reset: str | None = None
|
|
75
|
+
workspace_id: str = ""
|
|
76
|
+
expires_at: str | None = None
|
|
77
|
+
usage_daily: float = 0.0
|
|
78
|
+
usage_weekly: float = 0.0
|
|
79
|
+
usage_monthly: float = 0.0
|
|
80
|
+
byok_usage: float = 0.0
|
|
81
|
+
byok_usage_daily: float = 0.0
|
|
82
|
+
byok_usage_weekly: float = 0.0
|
|
83
|
+
byok_usage_monthly: float = 0.0
|
|
84
|
+
include_byok_in_limit: bool = False
|
|
85
|
+
creator_user_id: str | None = None
|
|
57
86
|
|
|
58
87
|
|
|
59
|
-
@dataclass
|
|
60
|
-
class
|
|
61
|
-
"""
|
|
88
|
+
@dataclass
|
|
89
|
+
class KeyResponseWrapper(DataClassORJSONMixin):
|
|
90
|
+
"""Wrapper for single key response."""
|
|
91
|
+
|
|
92
|
+
data: Key
|
|
93
|
+
|
|
94
|
+
|
|
95
|
+
@dataclass
|
|
96
|
+
class DeletedKeyResponse(DataClassORJSONMixin):
|
|
97
|
+
"""Response after deleting a key."""
|
|
98
|
+
|
|
99
|
+
deleted: bool
|
|
62
100
|
|
|
63
|
-
|
|
101
|
+
|
|
102
|
+
@dataclass
|
|
103
|
+
class ModelResponseWrapper(DataClassORJSONMixin):
|
|
104
|
+
"""Wrapper for single OpenRouter model response."""
|
|
105
|
+
|
|
106
|
+
data: Model
|
|
64
107
|
|
|
65
108
|
|
|
66
109
|
@dataclass
|
|
@@ -75,25 +118,30 @@ class SupportedParameter(StrEnum):
|
|
|
75
118
|
|
|
76
119
|
TEMPERATURE = "temperature"
|
|
77
120
|
TOP_P = "top_p"
|
|
121
|
+
TOP_K = "top_k"
|
|
78
122
|
MAX_TOKENS = "max_tokens"
|
|
123
|
+
MAX_COMPLETION_TOKENS = "max_completion_tokens"
|
|
79
124
|
REASONING = "reasoning"
|
|
125
|
+
REASONING_EFFORT = "reasoning_effort"
|
|
80
126
|
INCLUDE_REASONING = "include_reasoning"
|
|
81
127
|
STOP = "stop"
|
|
82
|
-
TOK_K = "top_k"
|
|
83
128
|
SEED = "seed"
|
|
84
129
|
RESPONSE_FORMAT = "response_format"
|
|
130
|
+
STRUCTURED_OUTPUTS = "structured_outputs"
|
|
131
|
+
PREDICTION = "prediction"
|
|
85
132
|
TOOLS = "tools"
|
|
86
133
|
TOOL_CHOICE = "tool_choice"
|
|
134
|
+
PARALLEL_TOOL_CALLS = "parallel_tool_calls"
|
|
87
135
|
FREQUENCY_PENALTY = "frequency_penalty"
|
|
88
136
|
PRESENCE_PENALTY = "presence_penalty"
|
|
89
|
-
MIN_P = "min_p"
|
|
90
137
|
REPETITION_PENALTY = "repetition_penalty"
|
|
138
|
+
MIN_P = "min_p"
|
|
139
|
+
TOP_A = "top_a"
|
|
91
140
|
LOGPROBS = "logprobs"
|
|
92
141
|
LOGIT_BIAS = "logit_bias"
|
|
93
142
|
TOP_LOGPROBS = "top_logprobs"
|
|
94
|
-
STRUCTURED_OUTPUTS = "structured_outputs"
|
|
95
143
|
WEB_SEARCH_OPTIONS = "web_search_options"
|
|
96
|
-
|
|
144
|
+
VERBOSITY = "verbosity"
|
|
97
145
|
|
|
98
146
|
|
|
99
147
|
class Modality(StrEnum):
|
|
@@ -105,14 +153,77 @@ class Modality(StrEnum):
|
|
|
105
153
|
FILE = "file"
|
|
106
154
|
EMBEDDINGS = "embeddings"
|
|
107
155
|
VIDEO = "video"
|
|
156
|
+
RERANK = "rerank"
|
|
157
|
+
SPEECH = "speech"
|
|
158
|
+
TRANSCRIPTION = "transcription"
|
|
108
159
|
|
|
109
160
|
|
|
110
161
|
@dataclass(kw_only=True)
|
|
111
162
|
class ModelArchitecture(DataClassORJSONMixin):
|
|
112
|
-
"""Model data."""
|
|
163
|
+
"""Model architecture data."""
|
|
113
164
|
|
|
114
165
|
input_modalities: list[Modality]
|
|
115
166
|
output_modalities: list[Modality]
|
|
167
|
+
modality: str | None = None
|
|
168
|
+
instruct_type: str | None = None
|
|
169
|
+
tokenizer: str | None = None
|
|
170
|
+
|
|
171
|
+
|
|
172
|
+
@dataclass(kw_only=True)
|
|
173
|
+
class PublicPricing(DataClassORJSONMixin):
|
|
174
|
+
"""Model pricing data."""
|
|
175
|
+
|
|
176
|
+
completion: str
|
|
177
|
+
prompt: str
|
|
178
|
+
audio: str | None = None
|
|
179
|
+
audio_output: str | None = None
|
|
180
|
+
image: str | None = None
|
|
181
|
+
image_output: str | None = None
|
|
182
|
+
image_token: str | None = None
|
|
183
|
+
input_audio_cache: str | None = None
|
|
184
|
+
input_cache_read: str | None = None
|
|
185
|
+
input_cache_write: str | None = None
|
|
186
|
+
input_cache_write_1h: str | None = None
|
|
187
|
+
internal_reasoning: str | None = None
|
|
188
|
+
request: str | None = None
|
|
189
|
+
web_search: str | None = None
|
|
190
|
+
discount: float | None = None
|
|
191
|
+
|
|
192
|
+
|
|
193
|
+
@dataclass(kw_only=True)
|
|
194
|
+
class TopProviderInfo(DataClassORJSONMixin):
|
|
195
|
+
"""Top provider information."""
|
|
196
|
+
|
|
197
|
+
is_moderated: bool
|
|
198
|
+
context_length: int | None = None
|
|
199
|
+
max_completion_tokens: int | None = None
|
|
200
|
+
|
|
201
|
+
|
|
202
|
+
@dataclass(kw_only=True)
|
|
203
|
+
class DefaultParameters(DataClassORJSONMixin):
|
|
204
|
+
"""Default model parameters."""
|
|
205
|
+
|
|
206
|
+
temperature: float | None = None
|
|
207
|
+
top_p: float | None = None
|
|
208
|
+
top_k: int | None = None
|
|
209
|
+
frequency_penalty: float | None = None
|
|
210
|
+
presence_penalty: float | None = None
|
|
211
|
+
repetition_penalty: float | None = None
|
|
212
|
+
|
|
213
|
+
|
|
214
|
+
@dataclass(kw_only=True)
|
|
215
|
+
class PerRequestLimits(DataClassORJSONMixin):
|
|
216
|
+
"""Per-request limits."""
|
|
217
|
+
|
|
218
|
+
completion_tokens: float
|
|
219
|
+
prompt_tokens: float
|
|
220
|
+
|
|
221
|
+
|
|
222
|
+
@dataclass(kw_only=True)
|
|
223
|
+
class ModelLinks(DataClassORJSONMixin):
|
|
224
|
+
"""Model links."""
|
|
225
|
+
|
|
226
|
+
details: str
|
|
116
227
|
|
|
117
228
|
|
|
118
229
|
@dataclass(kw_only=True)
|
|
@@ -121,24 +232,34 @@ class Model(DataClassORJSONMixin):
|
|
|
121
232
|
|
|
122
233
|
id: str
|
|
123
234
|
canonical_slug: str
|
|
124
|
-
hugging_face_id: str | None
|
|
125
235
|
name: str
|
|
126
|
-
|
|
127
|
-
context_length: int
|
|
236
|
+
context_length: int | None
|
|
128
237
|
architecture: ModelArchitecture
|
|
129
238
|
supported_parameters: list[SupportedParameter]
|
|
239
|
+
pricing: PublicPricing
|
|
240
|
+
top_provider: TopProviderInfo
|
|
241
|
+
hugging_face_id: str | None = None
|
|
242
|
+
description: str | None = None
|
|
243
|
+
created: int | None = None
|
|
244
|
+
default_parameters: DefaultParameters | None = None
|
|
245
|
+
links: ModelLinks | None = None
|
|
246
|
+
per_request_limits: PerRequestLimits | None = None
|
|
247
|
+
supported_voices: list[str] | None = None
|
|
248
|
+
expiration_date: str | None = None
|
|
249
|
+
knowledge_cutoff: str | None = None
|
|
130
250
|
|
|
131
251
|
@classmethod
|
|
132
252
|
def __pre_deserialize__(cls, d: dict[str, Any]) -> dict[str, Any]:
|
|
133
253
|
"""Pre deserialize hook."""
|
|
134
254
|
parameters = d.get("supported_parameters", [])
|
|
255
|
+
supported = set(SupportedParameter)
|
|
256
|
+
d["supported_parameters"] = [p for p in parameters if p in supported]
|
|
135
257
|
for parameter in parameters:
|
|
136
|
-
if parameter not in
|
|
258
|
+
if parameter not in supported:
|
|
137
259
|
_LOGGER.warning(
|
|
138
260
|
"Unsupported parameter: %s. Please report at https://github.com/joostlek/python-open-router/issues.",
|
|
139
261
|
parameter,
|
|
140
262
|
)
|
|
141
|
-
parameters.remove(parameter)
|
|
142
263
|
return d
|
|
143
264
|
|
|
144
265
|
@classmethod
|
|
@@ -146,4 +267,6 @@ class Model(DataClassORJSONMixin):
|
|
|
146
267
|
"""Post deserialize hook."""
|
|
147
268
|
if obj.hugging_face_id == "":
|
|
148
269
|
obj.hugging_face_id = None
|
|
270
|
+
if obj.description == "":
|
|
271
|
+
obj.description = None
|
|
149
272
|
return obj
|
|
@@ -9,17 +9,24 @@ import socket
|
|
|
9
9
|
from typing import TYPE_CHECKING, Any
|
|
10
10
|
|
|
11
11
|
from aiohttp import ClientError, ClientResponseError, ClientSession
|
|
12
|
-
from aiohttp.hdrs import METH_GET, METH_POST
|
|
12
|
+
from aiohttp.hdrs import METH_DELETE, METH_GET, METH_PATCH, METH_POST
|
|
13
|
+
import orjson
|
|
13
14
|
from yarl import URL
|
|
14
15
|
|
|
15
|
-
from python_open_router.exceptions import
|
|
16
|
+
from python_open_router.exceptions import (
|
|
17
|
+
OpenRouterAuthenticationError,
|
|
18
|
+
OpenRouterConnectionError,
|
|
19
|
+
)
|
|
16
20
|
from python_open_router.models import (
|
|
17
|
-
|
|
21
|
+
DeletedKeyResponse,
|
|
18
22
|
Key,
|
|
23
|
+
KeyCreateResponse,
|
|
19
24
|
KeyData,
|
|
20
25
|
KeyDataWrapper,
|
|
26
|
+
KeyResponseWrapper,
|
|
21
27
|
KeysDataWrapper,
|
|
22
28
|
Model,
|
|
29
|
+
ModelResponseWrapper,
|
|
23
30
|
ModelsDataWrapper,
|
|
24
31
|
)
|
|
25
32
|
|
|
@@ -81,6 +88,10 @@ class OpenRouterClient:
|
|
|
81
88
|
msg = "Error occurred while communicating with the service"
|
|
82
89
|
raise OpenRouterConnectionError(msg) from exception
|
|
83
90
|
|
|
91
|
+
if response.status == 401:
|
|
92
|
+
msg = "Authentication failed"
|
|
93
|
+
raise OpenRouterAuthenticationError(msg)
|
|
94
|
+
|
|
84
95
|
if response.status >= 400:
|
|
85
96
|
content_type = response.headers.get("Content-Type", "")
|
|
86
97
|
text = await response.text()
|
|
@@ -97,25 +108,162 @@ class OpenRouterClient:
|
|
|
97
108
|
response = await self._request(METH_GET, "key")
|
|
98
109
|
return KeyDataWrapper.from_json(response).data
|
|
99
110
|
|
|
100
|
-
async def get_keys(
|
|
111
|
+
async def get_keys(
|
|
112
|
+
self,
|
|
113
|
+
*,
|
|
114
|
+
include_disabled: bool | None = None,
|
|
115
|
+
offset: int | None = None,
|
|
116
|
+
workspace_id: str | None = None,
|
|
117
|
+
) -> list[Key]:
|
|
101
118
|
"""Get all keys."""
|
|
102
|
-
|
|
119
|
+
params: dict[str, Any] = {}
|
|
120
|
+
if include_disabled is not None:
|
|
121
|
+
params["include_disabled"] = str(include_disabled).lower()
|
|
122
|
+
if offset is not None:
|
|
123
|
+
params["offset"] = str(offset)
|
|
124
|
+
if workspace_id is not None:
|
|
125
|
+
params["workspace_id"] = workspace_id
|
|
126
|
+
response = await self._request(METH_GET, "keys", params=params or None)
|
|
103
127
|
return KeysDataWrapper.from_json(response).data
|
|
104
128
|
|
|
105
|
-
async def create_key(
|
|
129
|
+
async def create_key(
|
|
130
|
+
self,
|
|
131
|
+
name: str,
|
|
132
|
+
limit: float | None = None,
|
|
133
|
+
*,
|
|
134
|
+
limit_reset: str | None = None,
|
|
135
|
+
workspace_id: str | None = None,
|
|
136
|
+
expires_at: str | None = None,
|
|
137
|
+
include_byok_in_limit: bool | None = None,
|
|
138
|
+
) -> Key:
|
|
106
139
|
"""Create a new key."""
|
|
107
140
|
data: dict[str, Any] = {"name": name}
|
|
108
141
|
if limit is not None:
|
|
109
142
|
data["limit"] = limit
|
|
143
|
+
if limit_reset is not None:
|
|
144
|
+
data["limit_reset"] = limit_reset
|
|
145
|
+
if workspace_id is not None:
|
|
146
|
+
data["workspace_id"] = workspace_id
|
|
147
|
+
if expires_at is not None:
|
|
148
|
+
data["expires_at"] = expires_at
|
|
149
|
+
if include_byok_in_limit is not None:
|
|
150
|
+
data["include_byok_in_limit"] = include_byok_in_limit
|
|
110
151
|
|
|
111
152
|
response = await self._request(METH_POST, "keys", data=data)
|
|
112
|
-
return
|
|
153
|
+
return KeyCreateResponse.from_json(response).data
|
|
154
|
+
|
|
155
|
+
async def get_key(self, key_hash: str) -> Key:
|
|
156
|
+
"""Get a single key by hash."""
|
|
157
|
+
response = await self._request(METH_GET, f"keys/{key_hash}")
|
|
158
|
+
return KeyResponseWrapper.from_json(response).data
|
|
159
|
+
|
|
160
|
+
async def update_key(
|
|
161
|
+
self,
|
|
162
|
+
key_hash: str,
|
|
163
|
+
*,
|
|
164
|
+
name: str | None = None,
|
|
165
|
+
disabled: bool | None = None,
|
|
166
|
+
limit: float | None = None,
|
|
167
|
+
limit_reset: str | None = None,
|
|
168
|
+
include_byok_in_limit: bool | None = None,
|
|
169
|
+
) -> Key:
|
|
170
|
+
"""Update an existing key."""
|
|
171
|
+
data: dict[str, Any] = {}
|
|
172
|
+
if name is not None:
|
|
173
|
+
data["name"] = name
|
|
174
|
+
if disabled is not None:
|
|
175
|
+
data["disabled"] = disabled
|
|
176
|
+
if limit is not None:
|
|
177
|
+
data["limit"] = limit
|
|
178
|
+
if limit_reset is not None:
|
|
179
|
+
data["limit_reset"] = limit_reset
|
|
180
|
+
if include_byok_in_limit is not None:
|
|
181
|
+
data["include_byok_in_limit"] = include_byok_in_limit
|
|
182
|
+
|
|
183
|
+
response = await self._request(METH_PATCH, f"keys/{key_hash}", data=data)
|
|
184
|
+
return KeyResponseWrapper.from_json(response).data
|
|
185
|
+
|
|
186
|
+
async def delete_key(self, key_hash: str) -> bool:
|
|
187
|
+
"""Delete a key by hash."""
|
|
188
|
+
response = await self._request(METH_DELETE, f"keys/{key_hash}")
|
|
189
|
+
return DeletedKeyResponse.from_json(response).deleted
|
|
190
|
+
|
|
191
|
+
async def get_model(self, author: str, slug: str) -> Model:
|
|
192
|
+
"""Get a single model by author and slug."""
|
|
193
|
+
response = await self._request(METH_GET, f"model/{author}/{slug}")
|
|
194
|
+
return ModelResponseWrapper.from_json(response).data
|
|
195
|
+
|
|
196
|
+
@staticmethod
|
|
197
|
+
def _filter_model_params(
|
|
198
|
+
kwargs: dict[str, Any],
|
|
199
|
+
*,
|
|
200
|
+
numeric_keys: frozenset[str] = frozenset(),
|
|
201
|
+
) -> dict[str, Any]:
|
|
202
|
+
"""Filter None values and convert numeric params to strings."""
|
|
203
|
+
params = {k: v for k, v in kwargs.items() if v is not None}
|
|
204
|
+
for key in numeric_keys:
|
|
205
|
+
if key in params:
|
|
206
|
+
params[key] = str(params[key])
|
|
207
|
+
return params
|
|
113
208
|
|
|
114
|
-
async def get_models(
|
|
209
|
+
async def get_models( # pylint: disable=too-many-locals
|
|
210
|
+
self,
|
|
211
|
+
*,
|
|
212
|
+
category: str | None = None,
|
|
213
|
+
supported_parameters: str | None = None,
|
|
214
|
+
output_modalities: str | None = None,
|
|
215
|
+
sort: str | None = None,
|
|
216
|
+
q: str | None = None,
|
|
217
|
+
input_modalities: str | None = None,
|
|
218
|
+
context: int | None = None,
|
|
219
|
+
min_price: float | None = None,
|
|
220
|
+
max_price: float | None = None,
|
|
221
|
+
arch: str | None = None,
|
|
222
|
+
model_authors: str | None = None,
|
|
223
|
+
providers: str | None = None,
|
|
224
|
+
distillable: str | None = None,
|
|
225
|
+
zdr: str | None = None,
|
|
226
|
+
region: str | None = None,
|
|
227
|
+
) -> list[Model]:
|
|
115
228
|
"""Get all available models."""
|
|
116
|
-
|
|
229
|
+
numeric = frozenset({"context", "min_price", "max_price"})
|
|
230
|
+
params = self._filter_model_params(
|
|
231
|
+
{
|
|
232
|
+
"category": category,
|
|
233
|
+
"supported_parameters": supported_parameters,
|
|
234
|
+
"output_modalities": output_modalities,
|
|
235
|
+
"sort": sort,
|
|
236
|
+
"q": q,
|
|
237
|
+
"input_modalities": input_modalities,
|
|
238
|
+
"context": context,
|
|
239
|
+
"min_price": min_price,
|
|
240
|
+
"max_price": max_price,
|
|
241
|
+
"arch": arch,
|
|
242
|
+
"model_authors": model_authors,
|
|
243
|
+
"providers": providers,
|
|
244
|
+
"distillable": distillable,
|
|
245
|
+
"zdr": zdr,
|
|
246
|
+
"region": region,
|
|
247
|
+
},
|
|
248
|
+
numeric_keys=numeric,
|
|
249
|
+
)
|
|
250
|
+
response = await self._request(METH_GET, "models", params=params or None)
|
|
117
251
|
return ModelsDataWrapper.from_json(response).data
|
|
118
252
|
|
|
253
|
+
async def count_models(
|
|
254
|
+
self,
|
|
255
|
+
*,
|
|
256
|
+
output_modalities: str | None = None,
|
|
257
|
+
) -> int:
|
|
258
|
+
"""Get total count of available models."""
|
|
259
|
+
params: dict[str, Any] = {}
|
|
260
|
+
if output_modalities is not None:
|
|
261
|
+
params["output_modalities"] = output_modalities
|
|
262
|
+
response = await self._request(METH_GET, "models/count", params=params or None)
|
|
263
|
+
result: dict[str, Any] = orjson.loads(response) # pylint: disable=no-member
|
|
264
|
+
count: int = result.get("data", {}).get("count", 0)
|
|
265
|
+
return count
|
|
266
|
+
|
|
119
267
|
async def close(self) -> None:
|
|
120
268
|
"""Close open client session."""
|
|
121
269
|
if self.session and self._close_session:
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: python_open_router
|
|
3
|
-
Version: 0.
|
|
3
|
+
Version: 0.4.1
|
|
4
4
|
Summary: Asynchronous Python client for Open Router.
|
|
5
5
|
License: MIT
|
|
6
6
|
License-File: LICENSE.md
|
|
@@ -121,7 +121,7 @@ check [the contributor's page][contributors].
|
|
|
121
121
|
|
|
122
122
|
MIT License
|
|
123
123
|
|
|
124
|
-
Copyright (c) 2025 Joost Lekkerkerker
|
|
124
|
+
Copyright (c) 2025-2026 Joost Lekkerkerker
|
|
125
125
|
|
|
126
126
|
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
127
127
|
of this software and associated documentation files (the "Software"), to deal
|
|
@@ -151,7 +151,7 @@ SOFTWARE.
|
|
|
151
151
|
[joostlek]: https://github.com/joostlek
|
|
152
152
|
[keepchangelog]: http://keepachangelog.com/en/1.0.0/
|
|
153
153
|
[license-shield]: https://img.shields.io/github/license/joostlek/python-open-router.svg
|
|
154
|
-
[maintenance-shield]: https://img.shields.io/maintenance/yes/
|
|
154
|
+
[maintenance-shield]: https://img.shields.io/maintenance/yes/2026.svg
|
|
155
155
|
[poetry-install]: https://python-poetry.org/docs/#installation
|
|
156
156
|
[poetry]: https://python-poetry.org
|
|
157
157
|
[pre-commit]: https://pre-commit.com/
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
python_open_router/__init__.py,sha256=9a8JXk66oCsPUc-XxgHBI29sVi6QbjlnUuCUxLDJUfo,1166
|
|
2
|
+
python_open_router/exceptions.py,sha256=68nskqNdXNMIK4iA1XOE1E5P5rbhAf27DDACkk-ZVwU,312
|
|
3
|
+
python_open_router/models.py,sha256=QYU81QGRUrrZL4ocTLBghT7R2xh3qge1F7s5IiG7atA,6973
|
|
4
|
+
python_open_router/open_router.py,sha256=JB_2fu1akGJ8niuP7FOlExWTV3ytDvmH_sXWKY5iO6I,9520
|
|
5
|
+
python_open_router/py.typed,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
6
|
+
python_open_router-0.4.1.dist-info/METADATA,sha256=SLP9hPBfCK5wTOi1_ogXl5qAilEP14-jQnQTajvtVEA,6060
|
|
7
|
+
python_open_router-0.4.1.dist-info/WHEEL,sha256=EGEvSphFYqXKs23-kQBeyNoJP1nrT8ZJKQoi5p5DYL8,88
|
|
8
|
+
python_open_router-0.4.1.dist-info/licenses/LICENSE.md,sha256=nVkEdxeRRC-wzKM8tgyAhQTR1hxiY2jftVwlTDKKQMQ,1082
|
|
9
|
+
python_open_router-0.4.1.dist-info/RECORD,,
|
|
@@ -1,9 +0,0 @@
|
|
|
1
|
-
python_open_router/__init__.py,sha256=UQt6SpcnmQkS2wiyjwA_Ggvvzu7Ucx8BOCyZLZ_F2uA,840
|
|
2
|
-
python_open_router/exceptions.py,sha256=68nskqNdXNMIK4iA1XOE1E5P5rbhAf27DDACkk-ZVwU,312
|
|
3
|
-
python_open_router/models.py,sha256=GHGwXr8DLYhf-jnmqNmqdQ4ISFRyYdWBd4WsQNlkDRY,3379
|
|
4
|
-
python_open_router/open_router.py,sha256=zq7aleWZfNFqbBb69Qp3_3jed95cwxtgGMlYFhDzYKw,4148
|
|
5
|
-
python_open_router/py.typed,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
6
|
-
python_open_router-0.3.3.dist-info/METADATA,sha256=jKLq5jP-h8fd4mHXqj0Q8GLXFeDNhL6GMGUo5c0nVHM,6055
|
|
7
|
-
python_open_router-0.3.3.dist-info/WHEEL,sha256=zp0Cn7JsFoX2ATtOhtaFYIiE2rmFAD4OcMhtUki8W3U,88
|
|
8
|
-
python_open_router-0.3.3.dist-info/licenses/LICENSE.md,sha256=Xbw7n2Ic30r4j8_MDNND4ss_sdoj9IGeIkEWc2Hsfs8,1077
|
|
9
|
-
python_open_router-0.3.3.dist-info/RECORD,,
|