-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Merge pull request #4 from LlmKira/dev
feat(novelai-python): Add user subscription endpoint
- Loading branch information
Showing
12 changed files
with
248 additions
and
16 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,41 @@ | ||
# -*- coding: utf-8 -*- | ||
# @Time : 2024/2/7 上午10:16 | ||
# @Author : sudoskys | ||
# @File : subscription.py | ||
# @Software: PyCharm | ||
import asyncio | ||
import os | ||
|
||
from dotenv import load_dotenv | ||
from loguru import logger | ||
from pydantic import SecretStr | ||
|
||
from novelai_python import APIError, SubscriptionResp | ||
from novelai_python import Subscription, JwtCredential | ||
|
||
load_dotenv() | ||
|
||
enhance = "year 2023,dynamic angle, best quality, amazing quality, very aesthetic, absurdres" | ||
token = None | ||
jwt = os.getenv("NOVELAI_JWT") or token | ||
|
||
|
||
async def main(): | ||
globe_s = JwtCredential(jwt_token=SecretStr(jwt)) | ||
try: | ||
_res = await Subscription().request( | ||
session=globe_s | ||
) | ||
except APIError as e: | ||
logger.exception(e) | ||
print(e.response) | ||
return | ||
|
||
_res: SubscriptionResp | ||
print(_res) | ||
print(_res.is_active) | ||
print(_res.anlas_left) | ||
|
||
|
||
loop = asyncio.get_event_loop() | ||
loop.run_until_complete(main()) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,6 +1,6 @@ | ||
[project] | ||
name = "novelai-python" | ||
version = "0.1.7" | ||
version = "0.1.8" | ||
description = "Novelai Python Binding With Pydantic" | ||
authors = [ | ||
{ name = "sudoskys", email = "[email protected]" }, | ||
|
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,5 @@ | ||
# -*- coding: utf-8 -*- | ||
# @Time : 2024/2/7 上午9:57 | ||
# @Author : sudoskys | ||
# @File : __init__.py.py | ||
# @Software: PyCharm |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,52 @@ | ||
# -*- coding: utf-8 -*- | ||
# @Time : 2024/2/7 上午9:57 | ||
# @Author : sudoskys | ||
# @File : subscription.py | ||
# @Software: PyCharm | ||
from typing import Optional, Dict, Any, List | ||
|
||
from pydantic import BaseModel, Field | ||
|
||
|
||
class TrainingSteps(BaseModel): | ||
fixedTrainingStepsLeft: int | ||
purchasedTrainingSteps: int | ||
|
||
|
||
class ImageGenerationLimit(BaseModel): | ||
resolution: int | ||
maxPrompts: int | ||
|
||
|
||
class Perks(BaseModel): | ||
maxPriorityActions: int | ||
startPriority: int | ||
moduleTrainingSteps: int | ||
unlimitedMaxPriority: bool | ||
voiceGeneration: bool | ||
imageGeneration: bool | ||
unlimitedImageGeneration: bool | ||
unlimitedImageGenerationLimits: List[ImageGenerationLimit] | ||
contextTokens: int | ||
|
||
|
||
class SubscriptionResp(BaseModel): | ||
tier: int = Field(..., description="Subscription tier") | ||
active: bool = Field(..., description="Subscription status") | ||
expiresAt: int = Field(..., description="Subscription expiration time") | ||
perks: Perks = Field(..., description="Subscription perks") | ||
paymentProcessorData: Optional[Dict[Any, Any]] | ||
trainingStepsLeft: TrainingSteps = Field(..., description="Training steps left") | ||
accountType: int = Field(..., description="Account type") | ||
|
||
@property | ||
def is_active(self): | ||
return self.active | ||
|
||
@property | ||
def anlas_left(self): | ||
return self.trainingStepsLeft.fixedTrainingStepsLeft | ||
|
||
@property | ||
def is_unlimited_image_generation(self): | ||
return self.perks.unlimitedImageGeneration |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,7 @@ | ||
# -*- coding: utf-8 -*- | ||
# @Time : 2024/2/7 上午10:03 | ||
# @Author : sudoskys | ||
# @File : __init__.py.py | ||
# @Software: PyCharm | ||
|
||
from .subscription import * # noqa: F403 |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,81 @@ | ||
# -*- coding: utf-8 -*- | ||
# @Time : 2024/2/7 上午10:04 | ||
# @Author : sudoskys | ||
# @File : subscription.py.py | ||
# @Software: PyCharm | ||
from typing import Optional, Union | ||
|
||
import httpx | ||
from curl_cffi.requests import AsyncSession | ||
from loguru import logger | ||
from pydantic import BaseModel, PrivateAttr | ||
|
||
from ... import APIError, AuthError | ||
from ..._response.user.subscription import SubscriptionResp | ||
from ...credential import JwtCredential | ||
from ...utils import try_jsonfy | ||
|
||
|
||
class Subscription(BaseModel): | ||
_endpoint: Optional[str] = PrivateAttr("https://api.novelai.net") | ||
|
||
@property | ||
def base_url(self): | ||
return f"{self.endpoint.strip('/')}/user/subscription" | ||
|
||
@property | ||
def endpoint(self): | ||
return self._endpoint | ||
|
||
@endpoint.setter | ||
def endpoint(self, value): | ||
self._endpoint = value | ||
|
||
async def request(self, | ||
session: Union[AsyncSession, JwtCredential], | ||
) -> SubscriptionResp: | ||
""" | ||
Request to get user subscription information | ||
:param session: | ||
:return: | ||
""" | ||
if isinstance(session, JwtCredential): | ||
session = session.session | ||
request_data = {} | ||
logger.debug("Subscription") | ||
try: | ||
assert hasattr(session, "get"), "session must have get method." | ||
response = await session.get( | ||
self.base_url, | ||
) | ||
if "application/json" not in response.headers.get('Content-Type'): | ||
logger.error(f"Unexpected content type: {response.headers.get('Content-Type')}") | ||
try: | ||
_msg = response.json() | ||
except Exception: | ||
raise APIError( | ||
message=f"Unexpected content type: {response.headers.get('Content-Type')}", | ||
request=request_data, | ||
status_code=response.status_code, | ||
response=try_jsonfy(response.content) | ||
) | ||
status_code = _msg.get("statusCode", response.status_code) | ||
message = _msg.get("message", "Unknown error") | ||
if status_code in [400, 401, 402]: | ||
# 400 : validation error | ||
# 401 : unauthorized | ||
# 402 : payment required | ||
# 409 : conflict | ||
raise AuthError(message, request=request_data, status_code=status_code, response=_msg) | ||
if status_code in [500]: | ||
# An unknown error occured. | ||
raise APIError(message, request=request_data, status_code=status_code, response=_msg) | ||
raise APIError(message, request=request_data, status_code=status_code, response=_msg) | ||
return SubscriptionResp.model_validate(response.json()) | ||
except httpx.HTTPError as exc: | ||
raise RuntimeError(f"An HTTP error occurred: {exc}") | ||
except APIError as e: | ||
raise e | ||
except Exception as e: | ||
logger.opt(exception=e).exception("An Unexpected error occurred") | ||
raise e |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters