Ryzenth 2.0.5__py3-none-any.whl → 2.0.6__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.
- Ryzenth/__init__.py +2 -1
- Ryzenth/__version__.py +1 -1
- Ryzenth/_base_client.py +66 -0
- Ryzenth/_client.py +38 -46
- Ryzenth/_shared.py +2 -0
- Ryzenth/tl/__init__.py +3 -0
- Ryzenth/tl/logger_service.py +66 -0
- {ryzenth-2.0.5.dist-info → ryzenth-2.0.6.dist-info}/METADATA +13 -2
- {ryzenth-2.0.5.dist-info → ryzenth-2.0.6.dist-info}/RECORD +12 -9
- {ryzenth-2.0.5.dist-info → ryzenth-2.0.6.dist-info}/WHEEL +0 -0
- {ryzenth-2.0.5.dist-info → ryzenth-2.0.6.dist-info}/licenses/LICENSE +0 -0
- {ryzenth-2.0.5.dist-info → ryzenth-2.0.6.dist-info}/top_level.txt +0 -0
Ryzenth/__init__.py
CHANGED
@@ -19,7 +19,8 @@
|
|
19
19
|
|
20
20
|
from . import *
|
21
21
|
from .__version__ import __version__
|
22
|
-
from .
|
22
|
+
from ._base_client import ApiKeyFrom, FromConvertDot, UrHellFrom
|
23
|
+
from ._client import RyzenthApiClient
|
23
24
|
|
24
25
|
__all__ = [
|
25
26
|
"ApiKeyFrom",
|
Ryzenth/__version__.py
CHANGED
Ryzenth/_base_client.py
ADDED
@@ -0,0 +1,66 @@
|
|
1
|
+
#!/usr/bin/env python
|
2
|
+
# -*- coding: utf-8 -*-
|
3
|
+
# Copyright 2019-2025 (c) Randy W @xtdevs, @xtsea
|
4
|
+
#
|
5
|
+
# from : https://github.com/TeamKillerX
|
6
|
+
# Channel : @RendyProjects
|
7
|
+
# This program is free software: you can redistribute it and/or modify
|
8
|
+
# it under the terms of the GNU Affero General Public License as published by
|
9
|
+
# the Free Software Foundation, either version 3 of the License, or
|
10
|
+
# (at your option) any later version.
|
11
|
+
#
|
12
|
+
# This program is distributed in the hope that it will be useful,
|
13
|
+
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
14
|
+
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
15
|
+
# GNU Affero General Public License for more details.
|
16
|
+
#
|
17
|
+
# You should have received a copy of the GNU Affero General Public License
|
18
|
+
# along with this program. If not, see <https://www.gnu.org/licenses/>.
|
19
|
+
|
20
|
+
import base64
|
21
|
+
from os import environ
|
22
|
+
|
23
|
+
from box import Box
|
24
|
+
|
25
|
+
from ._asynchisded import RyzenthXAsync
|
26
|
+
from ._shared import UNKNOWN_TEST
|
27
|
+
from ._synchisded import RyzenthXSync
|
28
|
+
from .helper import Decorators
|
29
|
+
|
30
|
+
|
31
|
+
class ApiKeyFrom:
|
32
|
+
def __init__(self, api_key: str = None, is_ok=False):
|
33
|
+
if api_key == Ellipsis:
|
34
|
+
is_ok = True
|
35
|
+
api_key = None
|
36
|
+
|
37
|
+
if not api_key:
|
38
|
+
api_key = environ.get("RYZENTH_API_KEY")
|
39
|
+
|
40
|
+
if not api_key:
|
41
|
+
error404_bytes = UNKNOWN_TEST.encode("ascii")
|
42
|
+
string_bytes = base64.b64decode(error404_bytes)
|
43
|
+
api_key = string_bytes.decode("ascii") if is_ok else None
|
44
|
+
|
45
|
+
|
46
|
+
self.api_key = api_key
|
47
|
+
self.aio = RyzenthXAsync(api_key)
|
48
|
+
self._sync = RyzenthXSync(api_key)
|
49
|
+
|
50
|
+
def something(self):
|
51
|
+
pass
|
52
|
+
|
53
|
+
class UrHellFrom:
|
54
|
+
def __init__(self, name: str, only_author=False):
|
55
|
+
self.decorators = Decorators(ApiKeyFrom)
|
56
|
+
self.ai = self.decorators.send_ai(name=name, only_author=only_author)
|
57
|
+
|
58
|
+
def something(self):
|
59
|
+
pass
|
60
|
+
|
61
|
+
class FromConvertDot:
|
62
|
+
def __init__(self, obj):
|
63
|
+
self.obj = obj
|
64
|
+
|
65
|
+
def to_dot(self):
|
66
|
+
return Box(self.obj if self.obj is not None else {})
|
Ryzenth/_client.py
CHANGED
@@ -19,58 +19,22 @@
|
|
19
19
|
|
20
20
|
import asyncio
|
21
21
|
import json
|
22
|
-
import
|
22
|
+
import logging
|
23
23
|
import random
|
24
24
|
import time
|
25
25
|
import typing as t
|
26
|
-
from os import
|
26
|
+
from os import getenv
|
27
27
|
|
28
28
|
import aiohttp
|
29
29
|
import httpx
|
30
|
-
from box import Box
|
31
30
|
|
32
31
|
from .__version__ import get_user_agent
|
33
|
-
from ._asynchisded import RyzenthXAsync
|
34
32
|
from ._errors import ForbiddenError, InternalError, ToolNotFoundError, WhatFuckError
|
35
33
|
from ._shared import TOOL_DOMAIN_MAP
|
36
|
-
from .
|
37
|
-
from .
|
34
|
+
from .helper import AutoRetry
|
35
|
+
from .tl import LoggerService
|
38
36
|
|
39
37
|
|
40
|
-
class ApiKeyFrom:
|
41
|
-
def __init__(self, api_key: str = None, is_ok=False):
|
42
|
-
if api_key is Ellipsis:
|
43
|
-
is_ok = True
|
44
|
-
api_key = None
|
45
|
-
|
46
|
-
if not api_key:
|
47
|
-
api_key = environ.get("RYZENTH_API_KEY")
|
48
|
-
|
49
|
-
if not api_key:
|
50
|
-
api_key = "akeno_UKQEQMt991kh2Ehh7JqJYKapx8CCyeC" if is_ok else None
|
51
|
-
|
52
|
-
self.api_key = api_key
|
53
|
-
self.aio = RyzenthXAsync(api_key)
|
54
|
-
self._sync = RyzenthXSync(api_key)
|
55
|
-
|
56
|
-
def something(self):
|
57
|
-
pass
|
58
|
-
|
59
|
-
class UrHellFrom:
|
60
|
-
def __init__(self, name: str, only_author=False):
|
61
|
-
self.decorators = Decorators(ApiKeyFrom)
|
62
|
-
self.ai = self.decorators.send_ai(name=name, only_author=only_author)
|
63
|
-
|
64
|
-
def something(self):
|
65
|
-
pass
|
66
|
-
|
67
|
-
class FromConvertDot:
|
68
|
-
def __init__(self, obj):
|
69
|
-
self.obj = obj
|
70
|
-
|
71
|
-
def to_dot(self):
|
72
|
-
return Box(self.obj if self.obj is not None else {})
|
73
|
-
|
74
38
|
class RyzenthApiClient:
|
75
39
|
def __init__(
|
76
40
|
self,
|
@@ -79,7 +43,9 @@ class RyzenthApiClient:
|
|
79
43
|
api_key: dict[str, list[dict]],
|
80
44
|
rate_limit: int = 5,
|
81
45
|
use_default_headers: bool = False,
|
82
|
-
use_httpx: bool = False
|
46
|
+
use_httpx: bool = False,
|
47
|
+
settings: dict = None,
|
48
|
+
logger: t.Optional[LoggerService] = None
|
83
49
|
) -> None:
|
84
50
|
if not isinstance(api_key, dict) or not api_key:
|
85
51
|
raise WhatFuckError("API Key must be a non-empty dict of tool_name → list of headers")
|
@@ -92,6 +58,9 @@ class RyzenthApiClient:
|
|
92
58
|
self._request_counter = 0
|
93
59
|
self._last_reset = time.monotonic()
|
94
60
|
self._use_httpx = use_httpx
|
61
|
+
self._settings = settings or {}
|
62
|
+
self._logger = logger
|
63
|
+
self._init_logging()
|
95
64
|
|
96
65
|
self._tools: dict[str, str] = {
|
97
66
|
name: TOOL_DOMAIN_MAP.get(name)
|
@@ -103,6 +72,21 @@ class RyzenthApiClient:
|
|
103
72
|
aiohttp.ClientSession()
|
104
73
|
)
|
105
74
|
|
75
|
+
def _init_logging(self):
|
76
|
+
log_level = "WARNING"
|
77
|
+
disable_httpx_log = False
|
78
|
+
|
79
|
+
for entry in self._settings.get("logging", []):
|
80
|
+
if "level" in entry:
|
81
|
+
log_level = entry["level"].upper()
|
82
|
+
if "httpx_log" in entry:
|
83
|
+
disable_httpx_log = not entry["httpx_log"]
|
84
|
+
|
85
|
+
logging.basicConfig(level=getattr(logging, log_level, logging.WARNING))
|
86
|
+
if disable_httpx_log:
|
87
|
+
logging.getLogger("httpx").setLevel(logging.CRITICAL)
|
88
|
+
logging.getLogger("httpcore").setLevel(logging.CRITICAL)
|
89
|
+
|
106
90
|
def get_base_url(self, tool: str) -> str:
|
107
91
|
check_ok = self._tools.get(tool, None)
|
108
92
|
if check_ok is None:
|
@@ -186,12 +170,16 @@ class RyzenthApiClient:
|
|
186
170
|
resp = await self._session.get(url, params=params, headers=headers)
|
187
171
|
await self._status_resp_error(resp, status_httpx=True)
|
188
172
|
resp.raise_for_status()
|
189
|
-
|
173
|
+
data = resp.content if use_image_content else resp.json()
|
190
174
|
else:
|
191
175
|
async with self._session.get(url, params=params, headers=headers) as resp:
|
192
176
|
await self._status_resp_error(resp, status_httpx=False)
|
193
177
|
resp.raise_for_status()
|
194
|
-
|
178
|
+
data = await resp.read() if use_image_content else await resp.json()
|
179
|
+
|
180
|
+
if self._logger:
|
181
|
+
await self._logger.log(f"[GET {tool}] ✅ Success: {url}")
|
182
|
+
return data
|
195
183
|
|
196
184
|
@AutoRetry(max_retries=3, delay=1.5)
|
197
185
|
async def post(
|
@@ -211,12 +199,16 @@ class RyzenthApiClient:
|
|
211
199
|
resp = await self._session.post(url, data=data, json=json, headers=headers)
|
212
200
|
await self._status_resp_error(resp, status_httpx=True)
|
213
201
|
resp.raise_for_status()
|
214
|
-
|
202
|
+
data = resp.content if use_image_content else resp.json()
|
215
203
|
else:
|
216
204
|
async with self._session.post(url, data=data, json=json, headers=headers) as resp:
|
217
205
|
await self._status_resp_error(resp, status_httpx=False)
|
218
206
|
resp.raise_for_status()
|
219
|
-
|
207
|
+
data = await resp.read() if use_image_content else await resp.json()
|
208
|
+
|
209
|
+
if self._logger:
|
210
|
+
await self._logger.log(f"[POST {tool}] ✅ Success: {url}")
|
211
|
+
return data
|
220
212
|
|
221
213
|
async def close(self):
|
222
|
-
await self._session.close()
|
214
|
+
return await self._session.aclose() if self._use_httpx else await self._session.close()
|
Ryzenth/_shared.py
CHANGED
Ryzenth/tl/__init__.py
ADDED
@@ -0,0 +1,66 @@
|
|
1
|
+
#!/usr/bin/env python
|
2
|
+
# -*- coding: utf-8 -*-
|
3
|
+
# Copyright 2019-2025 (c) Randy W @xtdevs, @xtsea
|
4
|
+
#
|
5
|
+
# from : https://github.com/TeamKillerX
|
6
|
+
# Channel : @RendyProjects
|
7
|
+
# This program is free software: you can redistribute it and/or modify
|
8
|
+
# it under the terms of the GNU Affero General Public License as published by
|
9
|
+
# the Free Software Foundation, either version 3 of the License, or
|
10
|
+
# (at your option) any later version.
|
11
|
+
#
|
12
|
+
# This program is distributed in the hope that it will be useful,
|
13
|
+
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
14
|
+
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
15
|
+
# GNU Affero General Public License for more details.
|
16
|
+
#
|
17
|
+
# You should have received a copy of the GNU Affero General Public License
|
18
|
+
# along with this program. If not, see <https://www.gnu.org/licenses/>.
|
19
|
+
|
20
|
+
import logging
|
21
|
+
from datetime import datetime as dt
|
22
|
+
|
23
|
+
import httpx
|
24
|
+
|
25
|
+
from .._errors import ForbiddenError, InternalError
|
26
|
+
|
27
|
+
|
28
|
+
class LoggerService:
|
29
|
+
def __init__(self, config: dict):
|
30
|
+
self.config = config
|
31
|
+
|
32
|
+
async def log(self, message: str):
|
33
|
+
timestamp = dt.now().strftime("%Y-%m-%d %H:%M:%S")
|
34
|
+
full_message = f"[{timestamp}] {message}"
|
35
|
+
|
36
|
+
if self.config.get("telegram", {}).get("enabled"):
|
37
|
+
try:
|
38
|
+
await self._send_telegram(full_message)
|
39
|
+
except Exception as e:
|
40
|
+
logging.info(f"[Logger] Telegram log failed: {e}")
|
41
|
+
|
42
|
+
if self.config.get("database", {}).get("enabled"):
|
43
|
+
try:
|
44
|
+
await self.config["database"]["save_func"](full_message)
|
45
|
+
except Exception as e:
|
46
|
+
logging.info(f"[Logger] DB log failed: {e}")
|
47
|
+
|
48
|
+
async def _send_telegram(self, text: str):
|
49
|
+
token = self.config["telegram"]["token"]
|
50
|
+
chat_id = self.config["telegram"]["chat_id"]
|
51
|
+
url = f"https://api.telegram.org/bot{token}/sendMessage"
|
52
|
+
|
53
|
+
try:
|
54
|
+
async with httpx.AsyncClient() as client:
|
55
|
+
resp = await client.post(url, data={"chat_id": chat_id, "text": text})
|
56
|
+
if resp.status_code == 200:
|
57
|
+
logging.info("[Logger] Telegram log success")
|
58
|
+
elif resp.status_code == 403:
|
59
|
+
raise ForbiddenError("Access Forbidden: You may be blocked or banned.")
|
60
|
+
elif resp.status_code == 401:
|
61
|
+
raise ForbiddenError("Access Forbidden: Required bot token or invalid params.")
|
62
|
+
elif resp.status_code == 500:
|
63
|
+
raise InternalError("Error requests status code 500")
|
64
|
+
except Exception as e:
|
65
|
+
logging.info(f"[Logger] httpx failed: {e}")
|
66
|
+
raise e
|
@@ -1,6 +1,6 @@
|
|
1
1
|
Metadata-Version: 2.4
|
2
2
|
Name: Ryzenth
|
3
|
-
Version: 2.0.
|
3
|
+
Version: 2.0.6
|
4
4
|
Summary: Ryzenth Python Wrapper For Perfomance
|
5
5
|
Author: TeamKillerX
|
6
6
|
License: MIT
|
@@ -63,7 +63,17 @@ Dynamic: summary
|
|
63
63
|
<a href="https://github.com/TeamKillerX/Ryzenth/workflows/"><img src="https://github.com/TeamKillerX/Ryzenth/actions/workflows/sync-tests.yml/badge.svg" alt="API Tests"/></a>
|
64
64
|
</div>
|
65
65
|
|
66
|
-
|
66
|
+
---
|
67
|
+
|
68
|
+

|
69
|
+
|
70
|
+
---
|
71
|
+
|
72
|
+
**Ryzenth** is a flexible Multi-API SDK with built-in support for API key management and database integration.
|
73
|
+
|
74
|
+
It supports both **synchronous and asynchronous** workflows out of the box, making it ideal for modern use cases such as AI APIs, Telegram bots, REST services, and automation tools.
|
75
|
+
|
76
|
+
With native integration for `httpx`, `aiohttp`, advanced logging (including optional Telegram alerts), and support for database storage like MongoDB, Ryzenth is designed for developers who need a lightweight, scalable, and customizable API client.
|
67
77
|
|
68
78
|
> Note: Ryzenth API V1 (**javascript**) is still alive and supported, but Ryzenth is the next generation.
|
69
79
|
|
@@ -73,6 +83,7 @@ Dynamic: summary
|
|
73
83
|
- Built-in API Key management
|
74
84
|
- Support for modern AI endpoints (image generation, search, text, and more)
|
75
85
|
- Designed for speed with `httpx`
|
86
|
+
- Etc
|
76
87
|
|
77
88
|
## Installation
|
78
89
|
|
@@ -1,9 +1,10 @@
|
|
1
|
-
Ryzenth/__init__.py,sha256=
|
2
|
-
Ryzenth/__version__.py,sha256=
|
1
|
+
Ryzenth/__init__.py,sha256=tUSSKb2xEQGDZFg1g-9PsSuWAPvuUBG9cAXyIHyBmMg,1066
|
2
|
+
Ryzenth/__version__.py,sha256=_TA3rYUCdqJrMGE_VClpMOuFcVFr0KLvvOY2ER_Ic98,223
|
3
3
|
Ryzenth/_asynchisded.py,sha256=5ZjrXZzMSZw3T6kQ3eg-owgH1Y2dmGWJy9AOQqcoFUQ,5051
|
4
|
-
Ryzenth/
|
4
|
+
Ryzenth/_base_client.py,sha256=9oVkoYduSILsk38T2_jvT0frsl2B7ISD2YsR4BJ3Rfk,2032
|
5
|
+
Ryzenth/_client.py,sha256=hbt3U5szOrBuJkszY6jTmAoxHs89_mEfRZHvFXOnVWk,8028
|
5
6
|
Ryzenth/_errors.py,sha256=bOqi0_DElcmRrBqyDim6K248Ys-JQRSOvd32sJGW3aw,1812
|
6
|
-
Ryzenth/_shared.py,sha256=
|
7
|
+
Ryzenth/_shared.py,sha256=GfKOf7SPmtS5xJS9Sd5t846atH_1Ox9oCjhpqO4PXMA,2018
|
7
8
|
Ryzenth/_synchisded.py,sha256=Ns0F4iA4kWUg2j5u0Tyqj2E1mXIMs29IoQZCYW5G1Gw,4922
|
8
9
|
Ryzenth/helper/__init__.py,sha256=ZditYtDnZOtTJ_odPgWH0Nrj-qQJ868zjy41_DzK_ns,1473
|
9
10
|
Ryzenth/helper/_decorators.py,sha256=8uKdcseA7Cbq5sy2twgujZhbwqjaLwX13BT70diNRFs,2782
|
@@ -20,9 +21,11 @@ Ryzenth/tests/test_deepseek.py,sha256=_KbYr-haKBt5Xc-YULBL9Ic5OM02SX17hvQWWjYpNA
|
|
20
21
|
Ryzenth/tests/test_moderator.py,sha256=wc9A_0gx3LobMD7CDS-h2eTNPNYxeJk_rqtd2QTt428,291
|
21
22
|
Ryzenth/tests/test_send.py,sha256=yPQV3XRsPKBo4eSsz5kc2R6BEuru0zmMexYshX0Ac3s,573
|
22
23
|
Ryzenth/tests/test_send_downloader.py,sha256=23Lkq6bkh5SVDZ2hRH1Q3nlqpl-dqqGMSznDkmgDbhc,1318
|
24
|
+
Ryzenth/tl/__init__.py,sha256=SDoC1aFqHf682PasjkCIWzBdqvOJQ-Wn7ybDOxhHmMo,71
|
25
|
+
Ryzenth/tl/logger_service.py,sha256=23Mdi9obe-aF9SWBwgbRlk3hgQJdK9JYfg1iOsaUAW0,2651
|
23
26
|
Ryzenth/types/__init__.py,sha256=2q3Oy7wCtgHa1cVY1JVN6cJht7uEAva3yFijSiJxYdI,1392
|
24
|
-
ryzenth-2.0.
|
25
|
-
ryzenth-2.0.
|
26
|
-
ryzenth-2.0.
|
27
|
-
ryzenth-2.0.
|
28
|
-
ryzenth-2.0.
|
27
|
+
ryzenth-2.0.6.dist-info/licenses/LICENSE,sha256=C73aiGSgoCAVNzvAHs-TROaf5vV8yCj9nqpGrmfNHHo,1068
|
28
|
+
ryzenth-2.0.6.dist-info/METADATA,sha256=rJu9rxGBq-7Ds5maFxs5rYugNOQGin7BVx7vZiiRkUI,5250
|
29
|
+
ryzenth-2.0.6.dist-info/WHEEL,sha256=_zCd3N1l69ArxyTb8rzEoP9TpbYXkqRFSNOD5OuxnTs,91
|
30
|
+
ryzenth-2.0.6.dist-info/top_level.txt,sha256=0vIhjOjoQuCxLeZO0of8VCx2jsri-bLHV28nh8wWDnc,8
|
31
|
+
ryzenth-2.0.6.dist-info/RECORD,,
|
File without changes
|
File without changes
|
File without changes
|