diff --git a/chat_savant/elevenlabs.py b/chat_savant/elevenlabs.py new file mode 100644 index 0000000..e69de29 diff --git a/chat_savant/settings.py b/chat_savant/settings.py new file mode 100644 index 0000000..665333a --- /dev/null +++ b/chat_savant/settings.py @@ -0,0 +1,29 @@ +from pydantic import BaseSettings, Field, SecretStr + + +class SavantSettings(BaseSettings): + """Savant Application Settings. + + All environment varaibles supplied should be prefixed with "SAVANT_". + """ + + eleven_labs_api_key: SecretStr = Field( + default="", description="An optional Eleven Labs API key for text to speech." + ) + llm_model_name: str = Field( + default="eachadea_vicuna-7b-1.1", description="The large language model name used in API requests." + ) + openai_api_key: SecretStr = Field( + default="EMPTY", description="An OPEN_API_KEY or an empty value if using FastChat replacement server" + ) + openai_api_base: str = Field( + default="http://localhost:8000/v1", + description="The base url to an OpenAI API compliant endpoint. \ + Defaulted to FastChat replacement server defaults.", + ) + + class Config: + env_prefix = "SAVANT_" + + +savant_settings = SavantSettings() diff --git a/pyproject.toml b/pyproject.toml index bdcd7ea..9f863f7 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -22,6 +22,7 @@ savant-cli = "chat_savant.cli:main" [project.optional-dependencies] whisper = ["openai-whisper"] +elevenlabs = ["elevenlabs", "mpv"] [tool.setuptools] packages = ["chat_savant"] @@ -29,3 +30,10 @@ packages = ["chat_savant"] [tool.setuptools.dynamic] version = {attr = "chat_savant.__version__"} dependencies = {file = ["requirements.txt"]} + +[tool.black] +line-length = 120 +skip-string-normalization = true + +[tool.ruff] +line-length = 120 diff --git a/requirements.in b/requirements.in index e69de29..ad519bb 100644 --- a/requirements.in +++ b/requirements.in @@ -0,0 +1 @@ +pydantic>=1.6.2,<2.0.0 diff --git a/requirements.txt b/requirements.txt index ea51277..d91d0a3 100644 --- a/requirements.txt +++ b/requirements.txt @@ -1,6 +1,10 @@ # -# This file is autogenerated by pip-compile with Python 3.11 +# This file is autogenerated by pip-compile with Python 3.10 # by the following command: # -# pip-compile --output-file=requirements.txt requirements.in +# pip-compile requirements.in # +pydantic==1.10.8 + # via -r requirements.in +typing-extensions==4.6.2 + # via pydantic diff --git a/tests/unit/test_settings.py b/tests/unit/test_settings.py new file mode 100644 index 0000000..eb2d2bf --- /dev/null +++ b/tests/unit/test_settings.py @@ -0,0 +1,32 @@ +import os +from unittest.mock import patch + +from pydantic.types import SecretStr + +from chat_savant.settings import SavantSettings + +SETTING_DEFAULTS = { + "OPENAI_API_KEY": "EMPTY", + "OPENAI_API_BASE": "http://localhost:8000/v1", + "LLM_MODEL_NAME": "eachadea_vicuna-7b-1.1", + "ELEVEN_LABS_API_KEY": "", +} + + +def test_setting_defaults(): + """Regression test for settings schema.""" + with patch.dict(os.environ, {}, clear=True): + savant_settings = SavantSettings() + assert len(savant_settings.dict()) == len(SETTING_DEFAULTS) + for k, v in SETTING_DEFAULTS.items(): + _setting_value = getattr(savant_settings, k.lower()) + unmasked_setting = ( + _setting_value.get_secret_value() if isinstance(_setting_value, SecretStr) else _setting_value + ) + unmasked_setting == v + + +def test_with_envvar_prefix(): + with patch.dict(os.environ, {"SAVANT_ELEVEN_LABS_API_KEY": "thisisnotreal"}, clear=True): + savant_settings = SavantSettings() + assert savant_settings.eleven_labs_api_key.get_secret_value() == "thisisnotreal"