Skip to content
This repository was archived by the owner on Jul 4, 2025. It is now read-only.
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -1,6 +1,9 @@
# Venv
venv

# Build artifacts
dist

# IDE Settings
.idea

Expand Down
21 changes: 11 additions & 10 deletions docs/source/conf.py
Original file line number Diff line number Diff line change
@@ -1,22 +1,23 @@
import os
import sys
sys.path.insert(0, os.path.abspath('../..'))

sys.path.insert(0, os.path.abspath("../.."))

# -- Project information -----------------------------------------------------
project = 'YandexGPT Python'
copyright = '2024, ALL SEE LLC'
author = 'ALL SEE LLC'
release = '0.2.3'
project = "YandexGPT Python"
copyright = "2024, ALL SEE LLC"
author = "ALL SEE LLC"
release = "0.2.5"

# -- General configuration ---------------------------------------------------
extensions = [
'sphinx.ext.duration',
'sphinx.ext.autodoc',
"sphinx.ext.duration",
"sphinx.ext.autodoc",
]

templates_path = ['_templates']
templates_path = ["_templates"]
exclude_patterns = []

# -- Options for HTML output -------------------------------------------------
html_theme = 'furo'
html_static_path = ['_static']
html_theme = "furo"
html_static_path = ["_static"]
914 changes: 914 additions & 0 deletions poetry.lock

Large diffs are not rendered by default.

29 changes: 29 additions & 0 deletions pyproject.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
[tool.poetry]
name = "yandex_gpt"
version = "0.2.5"
description = "A Python SDK for interacting with the YandexGPT API."
readme = "README.md"
license = "MIT"
authors = [
"ALL SEE LLC <info@allsee.team>",
"Anton Kudryavtsev <dartt0n@ya.ru>",
]
classifiers = [
"License :: OSI Approved :: MIT License",
"Operating System :: POSIX",
"Operating System :: MacOS :: MacOS X",
"Operating System :: Microsoft :: Windows",
"Programming Language :: Python :: 3",
]
homepage = "https://github.com/allseeteam/yandexgpt-python"

[tool.poetry.dependencies]
python = "^3.9"
aiohttp = "^3.7.2"
requests = "^2.31.0"
pyjwt = { extras = ["crypto"], version = "^2.10.0" }


[build-system]
requires = ["poetry-core"]
build-backend = "poetry.core.masonry.api"
4 changes: 0 additions & 4 deletions requirements.txt

This file was deleted.

25 changes: 0 additions & 25 deletions setup.py

This file was deleted.

21 changes: 9 additions & 12 deletions yandex_gpt/__init__.py
Original file line number Diff line number Diff line change
@@ -1,22 +1,19 @@
from .yandex_gpt import (
YandexGPTBase,
YandexGPT
)
from .yandex_gpt import YandexGPTBase, YandexGPT
from .config_manager import (
YandexGPTConfigManagerBase,
YandexGPTConfigManagerForAPIKey,
YandexGPTConfigManagerForIAMToken,
YandexGPTConfigManagerForIAMTokenWithBase64Key
YandexGPTConfigManagerForIAMTokenWithBase64Key,
)
from .thread import YandexGPTThread


__all__ = [
'YandexGPTBase',
'YandexGPT',
'YandexGPTConfigManagerBase',
'YandexGPTConfigManagerForAPIKey',
'YandexGPTConfigManagerForIAMToken',
'YandexGPTConfigManagerForIAMTokenWithBase64Key',
'YandexGPTThread'
"YandexGPTBase",
"YandexGPT",
"YandexGPTConfigManagerBase",
"YandexGPTConfigManagerForAPIKey",
"YandexGPTConfigManagerForIAMToken",
"YandexGPTConfigManagerForIAMTokenWithBase64Key",
"YandexGPTThread",
]
136 changes: 79 additions & 57 deletions yandex_gpt/config_manager.py
Original file line number Diff line number Diff line change
@@ -1,21 +1,14 @@
import base64
import os
import time
from typing import (
Optional,
List, Dict, Any
)
from typing import Optional, List, Dict, Any

import jwt
import requests


# List of available YaGPT models to use (May be needs to be moved to config file in the future)
available_models: List[str] = [
"yandexgpt",
"yandexgpt-lite",
"summarization"
]
available_models: List[str] = ["yandexgpt", "yandexgpt-lite", "summarization"]


class YandexGPTConfigManagerBase:
Expand All @@ -37,12 +30,13 @@ class YandexGPTConfigManagerBase:
The API key for authorization. More details on getting an API key can be found here:
https://yandex.cloud/ru/docs/iam/operations/api-key/create
"""

def __init__(
self,
model_type: Optional[str] = None,
catalog_id: Optional[str] = None,
iam_token: Optional[str] = None,
api_key: Optional[str] = None,
self,
model_type: Optional[str] = None,
catalog_id: Optional[str] = None,
iam_token: Optional[str] = None,
api_key: Optional[str] = None,
) -> None:
"""
Initializes a new instance of the YandexGPTConfigManagerBase class.
Expand Down Expand Up @@ -127,7 +121,9 @@ def completion_request_model_type_uri_field(self) -> str:

# Checking if model_type is in available_models
if self.model_type not in available_models:
raise ValueError(f"Model type {self.model_type} is not supported. Supported values: {available_models}")
raise ValueError(
f"Model type {self.model_type} is not supported. Supported values: {available_models}"
)

# Checking if model_type and catalog_id are set and returning the model type URI field string
if self.model_type and self.catalog_id:
Expand All @@ -153,11 +149,12 @@ class YandexGPTConfigManagerForAPIKey(YandexGPTConfigManagerBase):
The API key for authorization. More details on obtaining an API key can be found here:
https://yandex.cloud/ru/docs/iam/operations/api-key/create
"""

def __init__(
self,
model_type: Optional[str] = None,
catalog_id: Optional[str] = None,
api_key: Optional[str] = None,
self,
model_type: Optional[str] = None,
catalog_id: Optional[str] = None,
api_key: Optional[str] = None,
) -> None:
"""
Initializes a new instance of the YandexGPTConfigManagerForAPIKey class.
Expand All @@ -172,11 +169,7 @@ def __init__(
API key for authorization.
"""
# Setting model type, catalog ID and API key from the constructor
super().__init__(
model_type=model_type,
catalog_id=catalog_id,
api_key=api_key
)
super().__init__(model_type=model_type, catalog_id=catalog_id, api_key=api_key)

# Setting model type, catalog ID and API key from the environment variables if they are set
self._set_config_from_env_vars()
Expand Down Expand Up @@ -235,11 +228,12 @@ class YandexGPTConfigManagerForIAMToken(YandexGPTConfigManagerBase):
The IAM token for authorization. Details on obtaining an IAM token can be found here:
https://yandex.cloud/ru/docs/iam/operations/iam-token/create-for-sa
"""

def __init__(
self,
model_type: Optional[str] = None,
catalog_id: Optional[str] = None,
iam_token: Optional[str] = None,
self,
model_type: Optional[str] = None,
catalog_id: Optional[str] = None,
iam_token: Optional[str] = None,
) -> None:
"""
Initializes a new instance of the YandexGPTConfigManagerForIAMToken class.
Expand All @@ -255,9 +249,7 @@ def __init__(
"""
# Setting model type, catalog ID and IAM token from the constructor
super().__init__(
model_type=model_type,
catalog_id=catalog_id,
iam_token=iam_token
model_type=model_type, catalog_id=catalog_id, iam_token=iam_token
)

# Setting model type, catalog ID and IAM token using one of options
Expand Down Expand Up @@ -295,15 +287,31 @@ def _set_iam_from_env_config_and_private_key(self) -> None:
Generates and sets IAM token from environment variables if not provided.
"""
# Getting environment variables
iam_url: str = os.getenv("YANDEX_GPT_IAM_URL", "https://iam.api.cloud.yandex.net/iam/v1/tokens")
service_account_id: Optional[str] = os.getenv("YANDEX_GPT_SERVICE_ACCOUNT_ID", None)
service_account_key_id: Optional[str] = os.getenv("YANDEX_GPT_SERVICE_ACCOUNT_KEY_ID", None)
iam_url: str = os.getenv(
"YANDEX_GPT_IAM_URL", "https://iam.api.cloud.yandex.net/iam/v1/tokens"
)
service_account_id: Optional[str] = os.getenv(
"YANDEX_GPT_SERVICE_ACCOUNT_ID", None
)
service_account_key_id: Optional[str] = os.getenv(
"YANDEX_GPT_SERVICE_ACCOUNT_KEY_ID", None
)
catalog_id: Optional[str] = os.getenv("YANDEX_GPT_CATALOG_ID", None)
private_key: Optional[str] = os.getenv("YANDEX_GPT_PRIVATE_KEY", None)

# Checking environment variables
if not all([iam_url, service_account_id, service_account_key_id, catalog_id, private_key]):
raise ValueError("One or more environment variables for IAM token generation are missing.")
if not all(
[
iam_url,
service_account_id,
service_account_key_id,
catalog_id,
private_key,
]
):
raise ValueError(
"One or more environment variables for IAM token generation are missing."
)

# Generating JWT token
jwt_token: str = self._generate_jwt_token(
Expand All @@ -318,10 +326,10 @@ def _set_iam_from_env_config_and_private_key(self) -> None:

@staticmethod
def _generate_jwt_token(
service_account_id: str,
private_key: str,
key_id: str,
url: str = "https://iam.api.cloud.yandex.net/iam/v1/tokens",
service_account_id: str,
private_key: str,
key_id: str,
url: str = "https://iam.api.cloud.yandex.net/iam/v1/tokens",
) -> str:
"""
Generates and swaps a JWT token to an IAM token.
Expand Down Expand Up @@ -351,16 +359,13 @@ def _generate_jwt_token(
"exp": now + 360,
}
encoded_token: str = jwt.encode(
payload,
private_key,
algorithm="PS256",
headers={"kid": key_id}
payload, private_key, algorithm="PS256", headers={"kid": key_id}
)
return encoded_token

@staticmethod
def _swap_jwt_to_iam(
jwt_token: str, url: str = "https://iam.api.cloud.yandex.net/iam/v1/tokens"
jwt_token: str, url: str = "https://iam.api.cloud.yandex.net/iam/v1/tokens"
) -> str:
"""
Swaps a JWT token for an IAM token by making a POST request to the Yandex IAM service.
Expand All @@ -385,17 +390,15 @@ def _swap_jwt_to_iam(
headers: Dict[str, str] = {"Content-Type": "application/json"}
data: Dict[str, str] = {"jwt": jwt_token}
# Swapping JWT token to IAM
response: requests.Response = requests.post(
url,
headers=headers,
json=data
)
response: requests.Response = requests.post(url, headers=headers, json=data)
if response.status_code == 200:
# If succeeded to get IAM token return it
return response.json()["iamToken"]
else:
# If failed to get IAM token raise an exception
raise Exception(f"Failed to get IAM token. Status code: {response.status_code}\n{response.text}")
raise Exception(
f"Failed to get IAM token. Status code: {response.status_code}\n{response.text}"
)

def _check_config(self) -> None:
"""
Expand Down Expand Up @@ -428,6 +431,7 @@ class YandexGPTConfigManagerForIAMTokenWithBase64Key(YandexGPTConfigManagerForIA

Inherits attributes from YandexGPTConfigManagerForIAMToken.
"""

def _set_iam_from_env_config_and_private_key(self) -> None:
"""
Overrides the base method to generate and set the IAM token using a base64-encoded private key from
Expand All @@ -439,15 +443,33 @@ def _set_iam_from_env_config_and_private_key(self) -> None:
If any required environment variables are missing.
"""
# Getting environment variables
iam_url: str = os.getenv("YANDEX_GPT_IAM_URL", "https://iam.api.cloud.yandex.net/iam/v1/tokens")
service_account_id: Optional[str] = os.getenv("YANDEX_GPT_SERVICE_ACCOUNT_ID", None)
service_account_key_id: Optional[str] = os.getenv("YANDEX_GPT_SERVICE_ACCOUNT_KEY_ID", None)
iam_url: str = os.getenv(
"YANDEX_GPT_IAM_URL", "https://iam.api.cloud.yandex.net/iam/v1/tokens"
)
service_account_id: Optional[str] = os.getenv(
"YANDEX_GPT_SERVICE_ACCOUNT_ID", None
)
service_account_key_id: Optional[str] = os.getenv(
"YANDEX_GPT_SERVICE_ACCOUNT_KEY_ID", None
)
catalog_id: Optional[str] = os.getenv("YANDEX_GPT_CATALOG_ID", None)
private_key_base64: Optional[str] = os.getenv("YANDEX_GPT_PRIVATE_KEY_BASE64", None)
private_key_base64: Optional[str] = os.getenv(
"YANDEX_GPT_PRIVATE_KEY_BASE64", None
)

# Checking environment variables
if not all([iam_url, service_account_id, service_account_key_id, catalog_id, private_key_base64]):
raise ValueError("One or more environment variables for IAM token generation are missing.")
if not all(
[
iam_url,
service_account_id,
service_account_key_id,
catalog_id,
private_key_base64,
]
):
raise ValueError(
"One or more environment variables for IAM token generation are missing."
)

# Decoding private key
private_key_bytes: bytes = base64.b64decode(private_key_base64)
Expand Down
Loading