diff --git a/src/assistant/.env.example b/src/assistant/.env.example index 9a66582..9ddb24f 100644 --- a/src/assistant/.env.example +++ b/src/assistant/.env.example @@ -5,6 +5,12 @@ POSTGRES_USER=user POSTGRES_PASSWORD=Qwe123 POSTGRES_DB_NAME=api_db +PROXY_HOST=255.255.255.255 +PROXY_PORT=8888 +PROXY_USER=YOUR_USER +PROXY_PASSWORD=YOUR_PASSWORD +PROXY_ENABLE=False + NGINX_PORT=80 API_HOST=0.0.0.0 API_PORT=8000 diff --git a/src/assistant/lib/app/app.py b/src/assistant/lib/app/app.py index 4953002..c6183d7 100644 --- a/src/assistant/lib/app/app.py +++ b/src/assistant/lib/app/app.py @@ -58,6 +58,17 @@ class Application: logger.info("Initializing clients") + http_yandex_tts_client = clients.AsyncHttpClient( + base_url="yandex", # todo add yandex api url from settings + proxy_settings=settings.proxy, + ) + disposable_resources.append( + DisposableResource( + name="http_client yandex", + dispose_callback=http_yandex_tts_client.close(), + ) + ) + # Repositories logger.info("Initializing repositories") diff --git a/src/assistant/lib/app/settings.py b/src/assistant/lib/app/settings.py index 674ef87..72198a6 100644 --- a/src/assistant/lib/app/settings.py +++ b/src/assistant/lib/app/settings.py @@ -19,4 +19,6 @@ class Settings(pydantic_settings.BaseSettings): project: app_split_settings.ProjectSettings = pydantic.Field( default_factory=lambda: app_split_settings.ProjectSettings() ) + + proxy: app_split_settings.ProxySettings = pydantic.Field(default_factory=lambda: app_split_settings.ProxySettings()) voice: app_split_settings.VoiceSettings = pydantic.Field(default_factory=lambda: app_split_settings.VoiceSettings()) diff --git a/src/assistant/lib/app/split_settings/__init__.py b/src/assistant/lib/app/split_settings/__init__.py index 9fb0f0e..90343d5 100644 --- a/src/assistant/lib/app/split_settings/__init__.py +++ b/src/assistant/lib/app/split_settings/__init__.py @@ -4,8 +4,10 @@ from .logger import * from .openai import * from .postgres import * from .project import * +from .proxy import * from .voice import * + __all__ = [ "ApiSettings", "AppSettings", @@ -13,6 +15,7 @@ __all__ = [ "OpenaiSettings", "PostgresSettings", "ProjectSettings", + "ProxySettings", "VoiceSettings", "get_logging_config", ] diff --git a/src/assistant/lib/app/split_settings/proxy.py b/src/assistant/lib/app/split_settings/proxy.py new file mode 100644 index 0000000..336c748 --- /dev/null +++ b/src/assistant/lib/app/split_settings/proxy.py @@ -0,0 +1,43 @@ +import typing + +import pydantic +import pydantic_settings + +import lib.app.split_settings.utils as app_split_settings_utils + + +class ProxySettings(pydantic_settings.BaseSettings): + model_config = pydantic_settings.SettingsConfigDict( + env_file=app_split_settings_utils.ENV_PATH, + env_prefix="PROXY_", + env_file_encoding="utf-8", + extra="ignore", + ) + protocol: typing.Literal["http", "socks5"] = "http" + user: str | None = None + password: pydantic.SecretStr | None = None + host: str | None = None + port: int | None = None + enable: bool = False + + @property + def dsn(self) -> str: + if self.user and self.password: + password = self.password.get_secret_value() + return f"{self.protocol}://{self.user}:{password}@{self.host}:{self.port}" + return f"{self.protocol}://{self.host}:{self.port}" + + @pydantic.computed_field + @property + def dsn_as_safe_url(self) -> str: + if self.user and self.password: + return f"{self.protocol}://{self.user}:{self.password}@{self.host}:{self.port}" + return f"{self.protocol}://{self.host}:{self.port}" + + @pydantic.model_validator(mode="after") + def check_proxy(self): + if not self.enable: + return self + if self.host and self.port: + return self + raise ValueError("Proxy settings must be set if use_proxy is True") diff --git a/src/assistant/lib/clients/__init__.py b/src/assistant/lib/clients/__init__.py index 1fbe64c..0050424 100644 --- a/src/assistant/lib/clients/__init__.py +++ b/src/assistant/lib/clients/__init__.py @@ -1,3 +1,7 @@ +from .http_client import AsyncHttpClient from .postgres import AsyncPostgresClient -__all__ = ["AsyncPostgresClient"] +__all__ = [ + "AsyncHttpClient", + "AsyncPostgresClient", +] diff --git a/src/assistant/lib/clients/http_client.py b/src/assistant/lib/clients/http_client.py new file mode 100644 index 0000000..efc6a53 --- /dev/null +++ b/src/assistant/lib/clients/http_client.py @@ -0,0 +1,29 @@ +import typing + +import httpx + +import lib.app.split_settings as app_split_settings + + +class AsyncHttpClient(httpx.AsyncClient): + def __init__( + self, + proxy_settings: app_split_settings.ProxySettings, + base_url: str | None = None, + **client_params: typing.Any, + ) -> None: + self.base_url = base_url if base_url else "" + self.proxy_settings = proxy_settings + self.proxies = self.__get_proxies_from_settings() + self.client_params = client_params + + super().__init__(base_url=self.base_url, proxies=self.proxies, **client_params) + + def __get_proxies_from_settings(self) -> dict[str, str] | None: + if not self.proxy_settings.enable: + return None + proxies = {"all://": self.proxy_settings.dsn} + return proxies + + async def close(self) -> None: + await self.aclose()