Skip to content

Commit

Permalink
quality: Use a more standard Pydantic way to parse config
Browse files Browse the repository at this point in the history
quality: Add some validation on the config values
  • Loading branch information
clemlesne committed Feb 21, 2024
1 parent 8f41488 commit 977a5bf
Show file tree
Hide file tree
Showing 15 changed files with 51 additions and 54 deletions.
4 changes: 2 additions & 2 deletions Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -65,7 +65,7 @@ tunnel:
devtunnel host $(tunnel_name)

dev:
VERSION=$(version_full) API_EVENTS_DOMAIN=$(tunnel_url) python3 -m uvicorn main:api \
VERSION=$(version_full) API__EVENTS_DOMAIN=$(tunnel_url) python3 -m uvicorn main:api \
--header x-version:$${VERSION} \
--no-server-header \
--port 8080 \
Expand All @@ -86,7 +86,7 @@ start:
@echo "🛠️ Deploying to localhost..."
$(docker) run \
--detach \
--env API_EVENTS_DOMAIN=$(tunnel_url) \
--env API__EVENTS_DOMAIN=$(tunnel_url) \
--env VERSION=$(version_full) \
--mount type=bind,source="$(CURDIR)/.env",target="/app/.env" \
--mount type=bind,source="$(CURDIR)/config.yaml",target="/app/config.yaml" \
Expand Down
9 changes: 4 additions & 5 deletions helpers/config_models/ai_search.py
Original file line number Diff line number Diff line change
@@ -1,11 +1,10 @@
from pydantic import SecretStr
from pydantic_settings import BaseSettings
from pydantic import SecretStr, BaseModel, Field


class AiSearchModel(BaseSettings):
class AiSearchModel(BaseModel):
access_key: SecretStr
endpoint: str
expansion_k: int = 5
expansion_k: int = Field(default=5, ge=1)
index: str
semantic_configuration: str
top_k: int = 15
top_k: int = Field(default=15, ge=1)
5 changes: 2 additions & 3 deletions helpers/config_models/ai_translation.py
Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@
from pydantic import SecretStr
from pydantic_settings import BaseSettings
from pydantic import SecretStr, BaseModel


class AiTranslationModel(BaseSettings):
class AiTranslationModel(BaseModel):
access_key: SecretStr
endpoint: str
4 changes: 2 additions & 2 deletions helpers/config_models/api.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
from pydantic_settings import BaseSettings
from pydantic import BaseModel


class ApiModel(BaseSettings, env_prefix="api_"):
class ApiModel(BaseModel):
events_domain: str
root_path: str = ""
13 changes: 6 additions & 7 deletions helpers/config_models/cache.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,5 @@
from enum import Enum
from pydantic import validator, SecretStr
from pydantic_settings import BaseSettings
from pydantic import validator, SecretStr, BaseModel, Field
from typing import Optional


Expand All @@ -9,19 +8,19 @@ class ModeEnum(str, Enum):
REDIS = "redis"


class MemoryModel(BaseSettings):
max_size: int = 100
class MemoryModel(BaseModel):
max_size: int = Field(default=100, ge=10)


class RedisModel(BaseSettings):
database: int = 0
class RedisModel(BaseModel):
database: int = Field(default=0, ge=0)
host: str
password: SecretStr
port: int = 6379
ssl: bool = True


class CacheModel(BaseSettings):
class CacheModel(BaseModel):
memory: Optional[MemoryModel] = None
mode: ModeEnum = ModeEnum.MEMORY
redis: Optional[RedisModel] = None
Expand Down
4 changes: 2 additions & 2 deletions helpers/config_models/cognitive_service.py
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
from pydantic_settings import BaseSettings
from pydantic import BaseModel


class CognitiveServiceModel(BaseSettings):
class CognitiveServiceModel(BaseModel):
endpoint: str
5 changes: 2 additions & 3 deletions helpers/config_models/communication_service.py
Original file line number Diff line number Diff line change
@@ -1,13 +1,12 @@
from pydantic import SecretStr
from pydantic import SecretStr, BaseModel
from pydantic_extra_types.phone_numbers import PhoneNumber
from pydantic_settings import BaseSettings


# E164 is standard accross all Microsoft services
PhoneNumber.phone_format = "E164"


class CommunicationServiceModel(BaseSettings):
class CommunicationServiceModel(BaseModel):
access_key: SecretStr
endpoint: str
phone_number: PhoneNumber
5 changes: 2 additions & 3 deletions helpers/config_models/content_safety.py
Original file line number Diff line number Diff line change
@@ -1,9 +1,8 @@
from typing import List
from pydantic import SecretStr, Field
from pydantic_settings import BaseSettings
from pydantic import SecretStr, Field, BaseModel


class ContentSafetyModel(BaseSettings):
class ContentSafetyModel(BaseModel):
access_key: SecretStr
blocklists: List[str]
category_hate_score: int = Field(default=0, ge=0, le=7)
Expand Down
9 changes: 4 additions & 5 deletions helpers/config_models/database.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,5 @@
from enum import Enum
from pydantic import validator, SecretStr, Field
from pydantic_settings import BaseSettings
from pydantic import validator, SecretStr, Field, BaseModel
from typing import Optional


Expand All @@ -9,14 +8,14 @@ class ModeEnum(str, Enum):
SQLITE = "sqlite"


class CosmosDbModel(BaseSettings):
class CosmosDbModel(BaseModel):
access_key: SecretStr
container: str
database: str
endpoint: str


class SqliteModel(BaseSettings):
class SqliteModel(BaseModel):
path: str = ".local"
schema_version: int = Field(default=3, frozen=True)
table: str = "calls"
Expand All @@ -30,7 +29,7 @@ def full_path(self) -> str:
return f"{self.path}-v{self.schema_version}.sqlite"


class DatabaseModel(BaseSettings):
class DatabaseModel(BaseModel):
cosmos_db: Optional[CosmosDbModel] = None
mode: ModeEnum = ModeEnum.SQLITE
sqlite: Optional[SqliteModel] = None
Expand Down
6 changes: 3 additions & 3 deletions helpers/config_models/monitoring.py
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
from enum import Enum
from pydantic_settings import BaseSettings
from pydantic import BaseModel


class LoggingLevelEnum(str, Enum):
Expand All @@ -12,12 +12,12 @@ class LoggingLevelEnum(str, Enum):
WARNING = "WARNING"


class LoggingMonitoringModel(BaseSettings):
class LoggingMonitoringModel(BaseModel):
app_level: LoggingLevelEnum = LoggingLevelEnum.INFO
sys_level: LoggingLevelEnum = LoggingLevelEnum.WARNING


class MonitoringModel(BaseSettings):
class MonitoringModel(BaseModel):
logging: LoggingMonitoringModel = (
LoggingMonitoringModel()
) # Object is fully defined by default
5 changes: 2 additions & 3 deletions helpers/config_models/openai.py
Original file line number Diff line number Diff line change
@@ -1,9 +1,8 @@
from pydantic import SecretStr
from pydantic_settings import BaseSettings
from pydantic import SecretStr, BaseModel
from typing import Optional


class OpenAiModel(BaseSettings):
class OpenAiModel(BaseModel):
api_key: Optional[SecretStr] = None
endpoint: str
gpt_deployment: str
Expand Down
13 changes: 5 additions & 8 deletions helpers/config_models/prompts.py
Original file line number Diff line number Diff line change
Expand Up @@ -7,13 +7,12 @@
from models.next import ActionEnum as NextActionEnum
from models.reminder import ReminderModel
from models.training import TrainingModel
from pydantic import computed_field, TypeAdapter
from pydantic_settings import BaseSettings
from pydantic import TypeAdapter, BaseModel
from textwrap import dedent
from typing import List, Optional


class SoundModel(BaseSettings):
class SoundModel(BaseModel):
loading_tpl: str = "{public_url}/loading.wav"
ready_tpl: str = "{public_url}/ready.wav"

Expand All @@ -32,7 +31,7 @@ def ready(self) -> str:
)


class LlmModel(BaseSettings):
class LlmModel(BaseModel):
"""
Introduce to Assistant who they are, what they do.
Expand Down Expand Up @@ -391,15 +390,14 @@ def _return(
self._logger.debug(f"LLM prompt: {res}")
return res

@computed_field
@cached_property
def _logger(self) -> Logger:
from helpers.logging import build_logger

return build_logger(__name__)


class TtsModel(BaseSettings, env_prefix="prompts_tts_"):
class TtsModel(BaseModel):
tts_lang: str = "en-US"
calltransfer_failure_tpl: str = (
"It seems I can't connect you with an agent at the moment, but the next available agent will call you back as soon as possible."
Expand Down Expand Up @@ -521,15 +519,14 @@ async def _translate(self, prompt_tpl: str, call: CallModel, **kwargs) -> str:
pass
return translation or initial

@computed_field
@cached_property
def _logger(self) -> Logger:
from helpers.logging import build_logger

return build_logger(__name__)


class PromptsModel(BaseSettings, env_prefix="prompts_"):
class PromptsModel(BaseModel):
llm: LlmModel = LlmModel() # Object is fully defined by default
sounds: SoundModel = SoundModel() # Object is fully defined by default
tts: TtsModel = TtsModel() # Object is fully defined by default
4 changes: 2 additions & 2 deletions helpers/config_models/resources.py
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
from pydantic_settings import BaseSettings
from pydantic import BaseModel


class ResourcesModel(BaseSettings):
class ResourcesModel(BaseModel):
public_url: str
11 changes: 9 additions & 2 deletions helpers/config_models/root.py
Original file line number Diff line number Diff line change
Expand Up @@ -12,10 +12,17 @@
from helpers.config_models.resources import ResourcesModel
from helpers.config_models.workflow import WorkflowModel
from pydantic import Field
from pydantic_settings import BaseSettings
from pydantic_settings import BaseSettings, SettingsConfigDict


class RootModel(BaseSettings, env_prefix=""):
class RootModel(BaseSettings):
# Pydantic settings
model_config = SettingsConfigDict(
env_ignore_empty=True,
env_nested_delimiter="__",
env_prefix="",
)

# Immutable fields
version: str = Field(frozen=True)
# Editable fields
Expand Down
8 changes: 4 additions & 4 deletions helpers/config_models/workflow.py
Original file line number Diff line number Diff line change
@@ -1,14 +1,14 @@
from functools import cached_property
from pydantic import BaseModel
from pydantic_extra_types.phone_numbers import PhoneNumber
from pydantic_settings import BaseSettings
from typing import List


# E164 is standard accross all Microsoft services
PhoneNumber.phone_format = "E164"


class LanguageEntryModel(BaseSettings):
class LanguageEntryModel(BaseModel):
"""
Language entry, containing the standard short code, an human name and the Azure Text-to-Speech voice name.
Expand All @@ -27,7 +27,7 @@ def __str__(self): # Pretty print for logs
return self.short_code


class LanguageModel(BaseSettings):
class LanguageModel(BaseModel):
"""
Manage language for the workflow.
"""
Expand Down Expand Up @@ -68,7 +68,7 @@ def default_lang(self) -> LanguageEntryModel:
)


class WorkflowModel(BaseSettings, env_prefix="workflow_"):
class WorkflowModel(BaseModel):
agent_phone_number: PhoneNumber
bot_company: str
bot_name: str
Expand Down

0 comments on commit 977a5bf

Please sign in to comment.