From 66c5ad44718894b617efbf8bddb52e346f14a521 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Cl=C3=A9mence=20Lesn=C3=A9?= Date: Wed, 9 Oct 2024 10:47:30 +0200 Subject: [PATCH] chore: Re-organise project structure --- Dockerfile | 4 +-- Makefile | 16 +++++----- {helpers => app/helpers}/__init__.py | 0 {helpers => app/helpers}/call_events.py | 22 +++++++------- {helpers => app/helpers}/call_llm.py | 18 +++++------ {helpers => app/helpers}/call_utils.py | 10 +++---- {helpers => app/helpers}/config.py | 2 +- .../helpers}/config_models/__init__.py | 0 .../helpers}/config_models/ai_search.py | 6 ++-- .../helpers}/config_models/ai_translation.py | 0 .../config_models/app_configuration.py | 0 .../helpers}/config_models/cache.py | 6 ++-- .../config_models/cognitive_service.py | 0 .../config_models/communication_services.py | 2 +- .../helpers}/config_models/conversation.py | 4 +-- .../helpers}/config_models/database.py | 10 +++---- {helpers => app/helpers}/config_models/llm.py | 2 +- .../helpers}/config_models/monitoring.py | 0 .../helpers}/config_models/prompts.py | 28 +++++++++--------- .../helpers}/config_models/queue.py | 8 ++--- .../helpers}/config_models/resources.py | 0 .../helpers}/config_models/root.py | 28 +++++++++--------- {helpers => app/helpers}/config_models/sms.py | 10 +++---- {helpers => app/helpers}/features.py | 12 ++++---- {helpers => app/helpers}/http.py | 0 {helpers => app/helpers}/identity.py | 2 +- {helpers => app/helpers}/llm_tools.py | 16 +++++----- {helpers => app/helpers}/llm_utils.py | 2 +- {helpers => app/helpers}/llm_worker.py | 16 +++++----- {helpers => app/helpers}/logging.py | 2 +- {helpers => app/helpers}/monitoring.py | 0 .../helpers}/pydantic_types/__init__.py | 0 .../helpers}/pydantic_types/phone_numbers.py | 0 app/helpers/resources.py | 19 ++++++++++++ {helpers => app/helpers}/translation.py | 6 ++-- main.py => app/main.py | 28 ++++++++++-------- {models => app/models}/__init__.py | 0 {models => app/models}/call.py | 23 +++++++------- {models => app/models}/claim.py | 0 {models => app/models}/error.py | 0 {models => app/models}/message.py | 6 ++-- {models => app/models}/next.py | 0 {models => app/models}/readiness.py | 0 {models => app/models}/reminder.py | 0 {models => app/models}/synthesis.py | 0 {models => app/models}/training.py | 0 {persistence => app/persistence}/__init__.py | 0 {persistence => app/persistence}/ai_search.py | 16 +++++----- .../persistence}/azure_queue_storage.py | 6 ++-- .../persistence}/communication_services.py | 12 ++++---- {persistence => app/persistence}/cosmos_db.py | 18 +++++------ {persistence => app/persistence}/icache.py | 4 +-- {persistence => app/persistence}/isearch.py | 8 ++--- {persistence => app/persistence}/isms.py | 6 ++-- {persistence => app/persistence}/istore.py | 8 ++--- {persistence => app/persistence}/memory.py | 8 ++--- {persistence => app/persistence}/redis.py | 8 ++--- {persistence => app/persistence}/sqlite.py | 14 ++++----- {persistence => app/persistence}/twilio.py | 12 ++++---- .../resources/public_website}/list.html.jinja | 0 .../public_website}/single.html.jinja | 0 .../public_website}/templates/base.html.jinja | 0 .../templates/call_me.html.jinja | 0 .../9b5ad71b2ce5302211f9c61530b329a4922fc6a4 | 0 .../resources}/tiktoken/README.md | 0 .../fb374d419588a4632f3f557e76b4b70aebbca790 | 0 {bicep => cicd/bicep}/app.bicep | 0 {bicep => cicd/bicep}/main.bicep | 0 helpers/resources.py | 22 -------------- {resources => public}/lexicon.xml | 0 {resources => public}/loading.wav | Bin {resources => public}/ready.wav | Bin pyproject.toml | 4 +-- tests/cache.py | 4 +-- tests/conftest.py | 10 +++---- tests/llm.py | 10 +++---- tests/local.py | 8 ++--- tests/search.py | 10 +++---- tests/store.py | 6 ++-- 79 files changed, 252 insertions(+), 250 deletions(-) rename {helpers => app/helpers}/__init__.py (100%) rename {helpers => app/helpers}/call_events.py (97%) rename {helpers => app/helpers}/call_llm.py (97%) rename {helpers => app/helpers}/call_utils.py (98%) rename {helpers => app/helpers}/config.py (95%) rename {helpers => app/helpers}/config_models/__init__.py (100%) rename {helpers => app/helpers}/config_models/ai_search.py (78%) rename {helpers => app/helpers}/config_models/ai_translation.py (100%) rename {helpers => app/helpers}/config_models/app_configuration.py (100%) rename {helpers => app/helpers}/config_models/cache.py (93%) rename {helpers => app/helpers}/config_models/cognitive_service.py (100%) rename {helpers => app/helpers}/config_models/communication_services.py (77%) rename {helpers => app/helpers}/config_models/conversation.py (98%) rename {helpers => app/helpers}/config_models/database.py (90%) rename {helpers => app/helpers}/config_models/llm.py (98%) rename {helpers => app/helpers}/config_models/monitoring.py (100%) rename {helpers => app/helpers}/config_models/prompts.py (97%) rename {helpers => app/helpers}/config_models/queue.py (73%) rename {helpers => app/helpers}/config_models/resources.py (100%) rename {helpers => app/helpers}/config_models/root.py (70%) rename {helpers => app/helpers}/config_models/sms.py (90%) rename {helpers => app/helpers}/features.py (90%) rename {helpers => app/helpers}/http.py (100%) rename {helpers => app/helpers}/identity.py (92%) rename {helpers => app/helpers}/llm_tools.py (98%) rename {helpers => app/helpers}/llm_utils.py (99%) rename {helpers => app/helpers}/llm_worker.py (97%) rename {helpers => app/helpers}/logging.py (84%) rename {helpers => app/helpers}/monitoring.py (100%) rename {helpers => app/helpers}/pydantic_types/__init__.py (100%) rename {helpers => app/helpers}/pydantic_types/phone_numbers.py (100%) create mode 100644 app/helpers/resources.py rename {helpers => app/helpers}/translation.py (94%) rename main.py => app/main.py (97%) rename {models => app/models}/__init__.py (100%) rename {models => app/models}/call.py (88%) rename {models => app/models}/claim.py (100%) rename {models => app/models}/error.py (100%) rename {models => app/models}/message.py (98%) rename {models => app/models}/next.py (100%) rename {models => app/models}/readiness.py (100%) rename {models => app/models}/reminder.py (100%) rename {models => app/models}/synthesis.py (100%) rename {models => app/models}/training.py (100%) rename {persistence => app/persistence}/__init__.py (100%) rename {persistence => app/persistence}/ai_search.py (94%) rename {persistence => app/persistence}/azure_queue_storage.py (97%) rename {persistence => app/persistence}/communication_services.py (88%) rename {persistence => app/persistence}/cosmos_db.py (96%) rename {persistence => app/persistence}/icache.py (87%) rename {persistence => app/persistence}/isearch.py (75%) rename {persistence => app/persistence}/isms.py (69%) rename {persistence => app/persistence}/istore.py (88%) rename {persistence => app/persistence}/memory.py (93%) rename {persistence => app/persistence}/redis.py (96%) rename {persistence => app/persistence}/sqlite.py (96%) rename {persistence => app/persistence}/twilio.py (90%) rename {public_website => app/resources/public_website}/list.html.jinja (100%) rename {public_website => app/resources/public_website}/single.html.jinja (100%) rename {public_website => app/resources/public_website}/templates/base.html.jinja (100%) rename {public_website => app/resources/public_website}/templates/call_me.html.jinja (100%) rename {resources => app/resources}/tiktoken/9b5ad71b2ce5302211f9c61530b329a4922fc6a4 (100%) rename {resources => app/resources}/tiktoken/README.md (100%) rename {resources => app/resources}/tiktoken/fb374d419588a4632f3f557e76b4b70aebbca790 (100%) rename {bicep => cicd/bicep}/app.bicep (100%) rename {bicep => cicd/bicep}/main.bicep (100%) delete mode 100644 helpers/resources.py rename {resources => public}/lexicon.xml (100%) rename {resources => public}/loading.wav (100%) rename {resources => public}/ready.wav (100%) diff --git a/Dockerfile b/Dockerfile index 7ca8f221..a03e0739 100644 --- a/Dockerfile +++ b/Dockerfile @@ -38,8 +38,8 @@ USER appuser COPY --from=build /venv /venv ENV PATH=/venv/bin:$PATH -COPY --chown=appuser:appuser . /app +COPY --chown=appuser:appuser /app /app/ WORKDIR /app -CMD ["bash", "-c", "gunicorn main:api --bind 0.0.0.0:8080 --proxy-protocol --workers 4 --worker-class uvicorn.workers.UvicornWorker"] +CMD ["bash", "-c", "gunicorn app.main:api --bind 0.0.0.0:8080 --proxy-protocol --workers 4 --worker-class uvicorn.workers.UvicornWorker"] diff --git a/Makefile b/Makefile index e95b5a19..6dd0a7d1 100644 --- a/Makefile +++ b/Makefile @@ -107,15 +107,15 @@ tunnel: devtunnel host $(tunnel_name) dev: - VERSION=$(version_full) PUBLIC_DOMAIN=$(tunnel_url) python3 -m gunicorn main:api \ + VERSION=$(version_full) PUBLIC_DOMAIN=$(tunnel_url) python3 -m gunicorn app.main:api \ --access-logfile - \ --bind 0.0.0.0:8080 \ --proxy-protocol \ --reload \ --reload-extra-file .env \ --reload-extra-file config.yaml \ - --workers 2 \ - --worker-class uvicorn.workers.UvicornWorker + --worker-class uvicorn.workers.UvicornWorker \ + --workers 2 build: $(docker) build \ @@ -145,11 +145,11 @@ deploy-bicep: 'openaiLocation=$(openai_location)' \ 'promptContentFilter=$(prompt_content_filter)' \ 'searchLocation=$(search_location)' \ - --template-file bicep/main.bicep \ + --template-file cicd/bicep/main.bicep \ --name $(name_sanitized) deploy-post: - @$(MAKE) copy-resources \ + @$(MAKE) copy-public \ name=$(blob_storage_public_name) @$(MAKE) twilio-register \ @@ -180,8 +180,8 @@ twilio-register: twilio phone-numbers:update $(twilio_phone_number) \ --sms-url $(endpoint)/twilio/sms -copy-resources: - @echo "📦 Copying resources to Azure storage account..." +copy-public: + @echo "📦 Copying public resources..." az storage blob upload-batch \ --account-name $(name_sanitized) \ --auth-mode login \ @@ -189,7 +189,7 @@ copy-resources: --no-progress \ --output none \ --overwrite \ - --source resources + --source public watch-call: @echo "👀 Watching status of $(phone_number)..." diff --git a/helpers/__init__.py b/app/helpers/__init__.py similarity index 100% rename from helpers/__init__.py rename to app/helpers/__init__.py diff --git a/helpers/call_events.py b/app/helpers/call_events.py similarity index 97% rename from helpers/call_events.py rename to app/helpers/call_events.py index 3bc1112e..5e603c5d 100644 --- a/helpers/call_events.py +++ b/app/helpers/call_events.py @@ -13,8 +13,8 @@ from azure.core.exceptions import ClientAuthenticationError, HttpResponseError from pydantic import ValidationError -from helpers.call_llm import load_llm_chat -from helpers.call_utils import ( +from app.helpers.call_llm import load_llm_chat +from app.helpers.call_utils import ( ContextEnum as CallContextEnum, handle_clear_queue, handle_hangup, @@ -23,13 +23,13 @@ handle_recognize_text, handle_transfer, ) -from helpers.config import CONFIG -from helpers.features import recording_enabled, voice_recognition_retry_max -from helpers.llm_worker import completion_sync -from helpers.logging import logger -from helpers.monitoring import CallAttributes, span_attribute, tracer -from models.call import CallStateModel -from models.message import ( +from app.helpers.config import CONFIG +from app.helpers.features import recording_enabled, voice_recognition_retry_max +from app.helpers.llm_worker import completion_sync +from app.helpers.logging import logger +from app.helpers.monitoring import CallAttributes, span_attribute, tracer +from app.models.call import CallStateModel +from app.models.message import ( ActionEnum as MessageActionEnum, MessageModel, PersonaEnum as MessagePersonaEnum, @@ -37,8 +37,8 @@ extract_message_style, remove_message_action, ) -from models.next import NextModel -from models.synthesis import SynthesisModel +from app.models.next import NextModel +from app.models.synthesis import SynthesisModel _sms = CONFIG.sms.instance() _db = CONFIG.database.instance() diff --git a/helpers/call_llm.py b/app/helpers/call_llm.py similarity index 97% rename from helpers/call_llm.py rename to app/helpers/call_llm.py index 66992826..7d52a2ae 100644 --- a/helpers/call_llm.py +++ b/app/helpers/call_llm.py @@ -5,24 +5,24 @@ from azure.communication.callautomation.aio import CallAutomationClient from openai import APIError -from helpers.call_utils import ( +from app.helpers.call_utils import ( handle_clear_queue, handle_media, handle_recognize_text, tts_sentence_split, ) -from helpers.config import CONFIG -from helpers.features import answer_hard_timeout_sec, answer_soft_timeout_sec -from helpers.llm_tools import LlmPlugins -from helpers.llm_worker import ( +from app.helpers.config import CONFIG +from app.helpers.features import answer_hard_timeout_sec, answer_soft_timeout_sec +from app.helpers.llm_tools import LlmPlugins +from app.helpers.llm_worker import ( MaximumTokensReachedError, SafetyCheckError, completion_stream, ) -from helpers.logging import logger -from helpers.monitoring import tracer -from models.call import CallStateModel -from models.message import ( +from app.helpers.logging import logger +from app.helpers.monitoring import tracer +from app.models.call import CallStateModel +from app.models.message import ( ActionEnum as MessageAction, MessageModel, PersonaEnum as MessagePersonaEnum, diff --git a/helpers/call_utils.py b/app/helpers/call_utils.py similarity index 98% rename from helpers/call_utils.py rename to app/helpers/call_utils.py index d1e5c49c..81cd22a8 100644 --- a/helpers/call_utils.py +++ b/app/helpers/call_utils.py @@ -17,11 +17,11 @@ ) from azure.core.exceptions import HttpResponseError, ResourceNotFoundError -from helpers.config import CONFIG -from helpers.features import phone_silence_timeout_sec -from helpers.logging import logger -from models.call import CallStateModel -from models.message import ( +from app.helpers.config import CONFIG +from app.helpers.features import phone_silence_timeout_sec +from app.helpers.logging import logger +from app.models.call import CallStateModel +from app.models.message import ( MessageModel, PersonaEnum as MessagePersonaEnum, StyleEnum as MessageStyleEnum, diff --git a/helpers/config.py b/app/helpers/config.py similarity index 95% rename from helpers/config.py rename to app/helpers/config.py index e8af6147..152974d4 100644 --- a/helpers/config.py +++ b/app/helpers/config.py @@ -4,7 +4,7 @@ from dotenv import find_dotenv from pydantic import ValidationError -from helpers.config_models.root import RootModel +from app.helpers.config_models.root import RootModel class ConfigNotFound(Exception): diff --git a/helpers/config_models/__init__.py b/app/helpers/config_models/__init__.py similarity index 100% rename from helpers/config_models/__init__.py rename to app/helpers/config_models/__init__.py diff --git a/helpers/config_models/ai_search.py b/app/helpers/config_models/ai_search.py similarity index 78% rename from helpers/config_models/ai_search.py rename to app/helpers/config_models/ai_search.py index 8eaca360..2ee9a6a8 100644 --- a/helpers/config_models/ai_search.py +++ b/app/helpers/config_models/ai_search.py @@ -2,7 +2,7 @@ from pydantic import BaseModel, Field -from persistence.isearch import ISearch +from app.persistence.isearch import ISearch class AiSearchModel(BaseModel, frozen=True): @@ -15,8 +15,8 @@ class AiSearchModel(BaseModel, frozen=True): @cache def instance(self) -> ISearch: - from helpers.config import CONFIG - from persistence.ai_search import ( + from app.helpers.config import CONFIG + from app.persistence.ai_search import ( AiSearchSearch, ) diff --git a/helpers/config_models/ai_translation.py b/app/helpers/config_models/ai_translation.py similarity index 100% rename from helpers/config_models/ai_translation.py rename to app/helpers/config_models/ai_translation.py diff --git a/helpers/config_models/app_configuration.py b/app/helpers/config_models/app_configuration.py similarity index 100% rename from helpers/config_models/app_configuration.py rename to app/helpers/config_models/app_configuration.py diff --git a/helpers/config_models/cache.py b/app/helpers/config_models/cache.py similarity index 93% rename from helpers/config_models/cache.py rename to app/helpers/config_models/cache.py index 4f615793..1928d093 100644 --- a/helpers/config_models/cache.py +++ b/app/helpers/config_models/cache.py @@ -3,7 +3,7 @@ from pydantic import BaseModel, Field, SecretStr, ValidationInfo, field_validator -from persistence.icache import ICache +from app.persistence.icache import ICache class ModeEnum(str, Enum): @@ -16,7 +16,7 @@ class MemoryModel(BaseModel, frozen=True): @cache def instance(self) -> ICache: - from persistence.memory import ( + from app.persistence.memory import ( MemoryCache, ) @@ -32,7 +32,7 @@ class RedisModel(BaseModel, frozen=True): @cache def instance(self) -> ICache: - from persistence.redis import ( + from app.persistence.redis import ( RedisCache, ) diff --git a/helpers/config_models/cognitive_service.py b/app/helpers/config_models/cognitive_service.py similarity index 100% rename from helpers/config_models/cognitive_service.py rename to app/helpers/config_models/cognitive_service.py diff --git a/helpers/config_models/communication_services.py b/app/helpers/config_models/communication_services.py similarity index 77% rename from helpers/config_models/communication_services.py rename to app/helpers/config_models/communication_services.py index 2298ea10..586074ab 100644 --- a/helpers/config_models/communication_services.py +++ b/app/helpers/config_models/communication_services.py @@ -1,6 +1,6 @@ from pydantic import BaseModel, SecretStr -from helpers.pydantic_types.phone_numbers import PhoneNumber +from app.helpers.pydantic_types.phone_numbers import PhoneNumber class CommunicationServicesModel(BaseModel): diff --git a/helpers/config_models/conversation.py b/app/helpers/config_models/conversation.py similarity index 98% rename from helpers/config_models/conversation.py rename to app/helpers/config_models/conversation.py index 6dbc2b77..233d6810 100644 --- a/helpers/config_models/conversation.py +++ b/app/helpers/config_models/conversation.py @@ -4,8 +4,8 @@ from pydantic import BaseModel, ConfigDict, EmailStr, Field, create_model from pydantic.fields import FieldInfo -from helpers.pydantic_types.phone_numbers import PhoneNumber -from models.claim import ClaimFieldModel, ClaimTypeEnum +from app.helpers.pydantic_types.phone_numbers import PhoneNumber +from app.models.claim import ClaimFieldModel, ClaimTypeEnum class LanguageEntryModel(BaseModel): diff --git a/helpers/config_models/database.py b/app/helpers/config_models/database.py similarity index 90% rename from helpers/config_models/database.py rename to app/helpers/config_models/database.py index 597004e2..0e5a84ba 100644 --- a/helpers/config_models/database.py +++ b/app/helpers/config_models/database.py @@ -3,7 +3,7 @@ from pydantic import BaseModel, ValidationInfo, field_validator -from persistence.istore import IStore +from app.persistence.istore import IStore class ModeEnum(str, Enum): @@ -18,8 +18,8 @@ class CosmosDbModel(BaseModel, frozen=True): @cache def instance(self) -> IStore: - from helpers.config import CONFIG - from persistence.cosmos_db import ( + from app.helpers.config import CONFIG + from app.persistence.cosmos_db import ( CosmosDbStore, ) @@ -41,8 +41,8 @@ def full_path(self) -> str: @cache def instance(self) -> IStore: - from helpers.config import CONFIG - from persistence.sqlite import ( + from app.helpers.config import CONFIG + from app.persistence.sqlite import ( SqliteStore, ) diff --git a/helpers/config_models/llm.py b/app/helpers/config_models/llm.py similarity index 98% rename from helpers/config_models/llm.py rename to app/helpers/config_models/llm.py index 598c37ed..e99426da 100644 --- a/helpers/config_models/llm.py +++ b/app/helpers/config_models/llm.py @@ -5,7 +5,7 @@ from openai import AsyncAzureOpenAI, AsyncOpenAI from pydantic import BaseModel, Field, SecretStr, ValidationInfo, field_validator -from helpers.identity import token +from app.helpers.identity import token class ModeEnum(str, Enum): diff --git a/helpers/config_models/monitoring.py b/app/helpers/config_models/monitoring.py similarity index 100% rename from helpers/config_models/monitoring.py rename to app/helpers/config_models/monitoring.py diff --git a/helpers/config_models/prompts.py b/app/helpers/config_models/prompts.py similarity index 97% rename from helpers/config_models/prompts.py rename to app/helpers/config_models/prompts.py index 9b4910c2..b7363d60 100644 --- a/helpers/config_models/prompts.py +++ b/app/helpers/config_models/prompts.py @@ -9,12 +9,12 @@ from openai.types.chat import ChatCompletionSystemMessageParam from pydantic import BaseModel, TypeAdapter -from models.call import CallStateModel -from models.message import MessageModel -from models.next import NextModel -from models.reminder import ReminderModel -from models.synthesis import SynthesisModel -from models.training import TrainingModel +from app.models.call import CallStateModel +from app.models.message import MessageModel +from app.models.next import NextModel +from app.models.reminder import ReminderModel +from app.models.synthesis import SynthesisModel +from app.models.training import TrainingModel class SoundModel(BaseModel): @@ -22,14 +22,14 @@ class SoundModel(BaseModel): ready_tpl: str = "{public_url}/ready.wav" def loading(self) -> str: - from helpers.config import CONFIG + from app.helpers.config import CONFIG return self.loading_tpl.format( public_url=CONFIG.resources.public_url, ) def ready(self) -> str: - from helpers.config import CONFIG + from app.helpers.config import CONFIG return self.ready_tpl.format( public_url=CONFIG.resources.public_url, @@ -319,7 +319,7 @@ class LlmModel(BaseModel): """ def default_system(self, call: CallStateModel) -> str: - from helpers.config import CONFIG + from app.helpers.config import CONFIG return self._format( self.default_system_tpl.format( @@ -336,7 +336,7 @@ def default_system(self, call: CallStateModel) -> str: def chat_system( self, call: CallStateModel, trainings: list[TrainingModel] ) -> list[ChatCompletionSystemMessageParam]: - from models.message import ( + from app.models.message import ( ActionEnum as MessageActionEnum, StyleEnum as MessageStyleEnum, ) @@ -485,7 +485,7 @@ def _messages( @cached_property def logger(self) -> Logger: - from helpers.logging import logger + from app.helpers.logging import logger return logger @@ -542,7 +542,7 @@ async def timeout_silence(self, call: CallStateModel) -> str: return await self._translate(self.timeout_silence_tpl, call) async def welcome_back(self, call: CallStateModel) -> str: - from helpers.features import callback_timeout_hour + from app.helpers.features import callback_timeout_hour return await self._translate( self.welcome_back_tpl, @@ -580,7 +580,7 @@ async def _translate(self, prompt_tpl: str, call: CallStateModel, **kwargs) -> s If the translation fails, the initial prompt is returned. """ - from helpers.translation import ( + from app.helpers.translation import ( translate_text, ) @@ -597,7 +597,7 @@ async def _translate(self, prompt_tpl: str, call: CallStateModel, **kwargs) -> s @cached_property def logger(self) -> Logger: - from helpers.logging import logger + from app.helpers.logging import logger return logger diff --git a/helpers/config_models/queue.py b/app/helpers/config_models/queue.py similarity index 73% rename from helpers/config_models/queue.py rename to app/helpers/config_models/queue.py index 778f6e6b..dcbd071a 100644 --- a/helpers/config_models/queue.py +++ b/app/helpers/config_models/queue.py @@ -12,7 +12,7 @@ class QueueModel(BaseModel, frozen=True): @cache def call(self): - from persistence.azure_queue_storage import AzureQueueStorage + from app.persistence.azure_queue_storage import AzureQueueStorage return AzureQueueStorage( account_url=self.account_url, @@ -21,7 +21,7 @@ def call(self): @cache def post(self): - from persistence.azure_queue_storage import AzureQueueStorage + from app.persistence.azure_queue_storage import AzureQueueStorage return AzureQueueStorage( account_url=self.account_url, @@ -30,7 +30,7 @@ def post(self): @cache def sms(self): - from persistence.azure_queue_storage import AzureQueueStorage + from app.persistence.azure_queue_storage import AzureQueueStorage return AzureQueueStorage( account_url=self.account_url, @@ -39,7 +39,7 @@ def sms(self): @cache def training(self): - from persistence.azure_queue_storage import AzureQueueStorage + from app.persistence.azure_queue_storage import AzureQueueStorage return AzureQueueStorage( account_url=self.account_url, diff --git a/helpers/config_models/resources.py b/app/helpers/config_models/resources.py similarity index 100% rename from helpers/config_models/resources.py rename to app/helpers/config_models/resources.py diff --git a/helpers/config_models/root.py b/app/helpers/config_models/root.py similarity index 70% rename from helpers/config_models/root.py rename to app/helpers/config_models/root.py index 8567453e..585017aa 100644 --- a/helpers/config_models/root.py +++ b/app/helpers/config_models/root.py @@ -5,20 +5,20 @@ SettingsConfigDict, ) -from helpers.config_models.ai_search import AiSearchModel -from helpers.config_models.ai_translation import AiTranslationModel -from helpers.config_models.app_configuration import AppConfigurationModel -from helpers.config_models.cache import CacheModel -from helpers.config_models.cognitive_service import CognitiveServiceModel -from helpers.config_models.communication_services import CommunicationServicesModel -from helpers.config_models.conversation import ConversationModel -from helpers.config_models.database import DatabaseModel -from helpers.config_models.llm import LlmModel -from helpers.config_models.monitoring import MonitoringModel -from helpers.config_models.prompts import PromptsModel -from helpers.config_models.queue import QueueModel -from helpers.config_models.resources import ResourcesModel -from helpers.config_models.sms import SmsModel +from app.helpers.config_models.ai_search import AiSearchModel +from app.helpers.config_models.ai_translation import AiTranslationModel +from app.helpers.config_models.app_configuration import AppConfigurationModel +from app.helpers.config_models.cache import CacheModel +from app.helpers.config_models.cognitive_service import CognitiveServiceModel +from app.helpers.config_models.communication_services import CommunicationServicesModel +from app.helpers.config_models.conversation import ConversationModel +from app.helpers.config_models.database import DatabaseModel +from app.helpers.config_models.llm import LlmModel +from app.helpers.config_models.monitoring import MonitoringModel +from app.helpers.config_models.prompts import PromptsModel +from app.helpers.config_models.queue import QueueModel +from app.helpers.config_models.resources import ResourcesModel +from app.helpers.config_models.sms import SmsModel class RootModel(BaseSettings): diff --git a/helpers/config_models/sms.py b/app/helpers/config_models/sms.py similarity index 90% rename from helpers/config_models/sms.py rename to app/helpers/config_models/sms.py index f82baff8..54b2207e 100644 --- a/helpers/config_models/sms.py +++ b/app/helpers/config_models/sms.py @@ -3,8 +3,8 @@ from pydantic import BaseModel, SecretStr, ValidationInfo, field_validator -from helpers.pydantic_types.phone_numbers import PhoneNumber -from persistence.isms import ISms +from app.helpers.pydantic_types.phone_numbers import PhoneNumber +from app.persistence.isms import ISms class ModeEnum(str, Enum): @@ -21,8 +21,8 @@ class CommunicationServiceModel(BaseModel, frozen=True): @cache def instance(self) -> ISms: - from helpers.config import CONFIG - from persistence.communication_services import ( + from app.helpers.config import CONFIG + from app.persistence.communication_services import ( CommunicationServicesSms, ) @@ -36,7 +36,7 @@ class TwilioModel(BaseModel, frozen=True): @cache def instance(self) -> ISms: - from persistence.twilio import ( + from app.persistence.twilio import ( TwilioSms, ) diff --git a/helpers/features.py b/app/helpers/features.py similarity index 90% rename from helpers/features.py rename to app/helpers/features.py index a0f21b25..5a312a5c 100644 --- a/helpers/features.py +++ b/app/helpers/features.py @@ -2,12 +2,12 @@ from azure.appconfiguration.aio import AzureAppConfigurationClient -from helpers.config import CONFIG -from helpers.config_models.cache import MemoryModel -from helpers.http import azure_transport -from helpers.identity import credential -from persistence.icache import ICache -from persistence.memory import MemoryCache +from app.helpers.config import CONFIG +from app.helpers.config_models.cache import MemoryModel +from app.helpers.http import azure_transport +from app.helpers.identity import credential +from app.persistence.icache import ICache +from app.persistence.memory import MemoryCache _cache: ICache = MemoryCache(MemoryModel(max_size=100)) _client: AzureAppConfigurationClient | None = None diff --git a/helpers/http.py b/app/helpers/http.py similarity index 100% rename from helpers/http.py rename to app/helpers/http.py diff --git a/helpers/identity.py b/app/helpers/identity.py similarity index 92% rename from helpers/identity.py rename to app/helpers/identity.py index 80893f77..eabf7778 100644 --- a/helpers/identity.py +++ b/app/helpers/identity.py @@ -2,7 +2,7 @@ from azure.identity.aio import DefaultAzureCredential, get_bearer_token_provider -from helpers.http import azure_transport +from app.helpers.http import azure_transport _client: DefaultAzureCredential | None = None diff --git a/helpers/llm_tools.py b/app/helpers/llm_tools.py similarity index 98% rename from helpers/llm_tools.py rename to app/helpers/llm_tools.py index 65d316c7..7449c64b 100644 --- a/helpers/llm_tools.py +++ b/app/helpers/llm_tools.py @@ -8,19 +8,19 @@ from openai.types.chat import ChatCompletionToolParam from pydantic import ValidationError -from helpers.call_utils import ContextEnum as CallContextEnum, handle_play_text -from helpers.config import CONFIG -from helpers.llm_utils import function_schema -from helpers.logging import logger -from models.call import CallStateModel -from models.message import ( +from app.helpers.call_utils import ContextEnum as CallContextEnum, handle_play_text +from app.helpers.config import CONFIG +from app.helpers.llm_utils import function_schema +from app.helpers.logging import logger +from app.models.call import CallStateModel +from app.models.message import ( ActionEnum as MessageActionEnum, MessageModel, PersonaEnum as MessagePersonaEnum, StyleEnum as MessageStyleEnum, ) -from models.reminder import ReminderModel -from models.training import TrainingModel +from app.models.reminder import ReminderModel +from app.models.training import TrainingModel _search = CONFIG.ai_search.instance() _sms = CONFIG.sms.instance() diff --git a/helpers/llm_utils.py b/app/helpers/llm_utils.py similarity index 99% rename from helpers/llm_utils.py rename to app/helpers/llm_utils.py index 542b9c33..be3471bc 100644 --- a/helpers/llm_utils.py +++ b/app/helpers/llm_utils.py @@ -15,7 +15,7 @@ from pydantic._internal._typing_extra import eval_type_lenient from pydantic.json_schema import JsonSchemaValue -from helpers.logging import logger +from app.helpers.logging import logger T = TypeVar("T") _jinja = Environment( diff --git a/helpers/llm_worker.py b/app/helpers/llm_worker.py similarity index 97% rename from helpers/llm_worker.py rename to app/helpers/llm_worker.py index bb594bc2..03ba698b 100644 --- a/helpers/llm_worker.py +++ b/app/helpers/llm_worker.py @@ -41,13 +41,15 @@ wait_random_exponential, ) -from helpers.config import CONFIG -from helpers.config_models.llm import AbstractPlatformModel as LlmAbstractPlatformModel -from helpers.features import slow_llm_for_chat -from helpers.logging import logger -from helpers.monitoring import tracer -from helpers.resources import resources_dir -from models.message import MessageModel +from app.helpers.config import CONFIG +from app.helpers.config_models.llm import ( + AbstractPlatformModel as LlmAbstractPlatformModel, +) +from app.helpers.features import slow_llm_for_chat +from app.helpers.logging import logger +from app.helpers.monitoring import tracer +from app.helpers.resources import resources_dir +from app.models.message import MessageModel environ["TRACELOOP_TRACE_CONTENT"] = str( True diff --git a/helpers/logging.py b/app/helpers/logging.py similarity index 84% rename from helpers/logging.py rename to app/helpers/logging.py index 1d1ca125..ad4cdd02 100644 --- a/helpers/logging.py +++ b/app/helpers/logging.py @@ -1,6 +1,6 @@ from logging import basicConfig, getLogger -from helpers.config import CONFIG +from app.helpers.config import CONFIG basicConfig(level=CONFIG.monitoring.logging.sys_level.value) logger = getLogger("call-center-ai") diff --git a/helpers/monitoring.py b/app/helpers/monitoring.py similarity index 100% rename from helpers/monitoring.py rename to app/helpers/monitoring.py diff --git a/helpers/pydantic_types/__init__.py b/app/helpers/pydantic_types/__init__.py similarity index 100% rename from helpers/pydantic_types/__init__.py rename to app/helpers/pydantic_types/__init__.py diff --git a/helpers/pydantic_types/phone_numbers.py b/app/helpers/pydantic_types/phone_numbers.py similarity index 100% rename from helpers/pydantic_types/phone_numbers.py rename to app/helpers/pydantic_types/phone_numbers.py diff --git a/app/helpers/resources.py b/app/helpers/resources.py new file mode 100644 index 00000000..58bc0dc4 --- /dev/null +++ b/app/helpers/resources.py @@ -0,0 +1,19 @@ +from functools import lru_cache +from os import getcwd +from os.path import abspath, join +from pathlib import Path + + +@lru_cache # Cache results in memory as resources are not expected to change +def resources_dir(folder: str) -> str: + """ + Get the absolute path to the resources folder. + """ + return join(_local_dir("resources"), folder) + + +def _local_dir(folder: str) -> str: + """ + Get the absolute path to a local folder. + """ + return str(Path(join(abspath(getcwd()), "app", folder)).resolve().absolute()) diff --git a/helpers/translation.py b/app/helpers/translation.py similarity index 94% rename from helpers/translation.py rename to app/helpers/translation.py index 10b11d89..d502113c 100644 --- a/helpers/translation.py +++ b/app/helpers/translation.py @@ -9,9 +9,9 @@ wait_random_exponential, ) -from helpers.config import CONFIG -from helpers.http import azure_transport -from helpers.logging import logger +from app.helpers.config import CONFIG +from app.helpers.http import azure_transport +from app.helpers.logging import logger logger.info("Using Translation %s", CONFIG.ai_translation.endpoint) diff --git a/main.py b/app/main.py similarity index 97% rename from main.py rename to app/main.py index b1b16a37..569af698 100644 --- a/main.py +++ b/app/main.py @@ -30,7 +30,7 @@ from starlette.exceptions import HTTPException as StarletteHTTPException from twilio.twiml.messaging_response import MessagingResponse -from helpers.call_events import ( +from app.helpers.call_events import ( on_call_connected, on_call_disconnected, on_end_call, @@ -45,17 +45,18 @@ on_transfer_completed, on_transfer_error, ) -from helpers.call_utils import ContextEnum as CallContextEnum -from helpers.config import CONFIG -from helpers.http import azure_transport -from helpers.logging import logger -from helpers.monitoring import CallAttributes, span_attribute, tracer -from helpers.pydantic_types.phone_numbers import PhoneNumber -from models.call import CallGetModel, CallInitiateModel, CallStateModel -from models.error import ErrorInnerModel, ErrorModel -from models.next import ActionEnum as NextActionEnum -from models.readiness import ReadinessCheckModel, ReadinessEnum, ReadinessModel -from persistence.azure_queue_storage import Message as AzureQueueStorageMessage +from app.helpers.call_utils import ContextEnum as CallContextEnum +from app.helpers.config import CONFIG +from app.helpers.http import azure_transport +from app.helpers.logging import logger +from app.helpers.monitoring import CallAttributes, span_attribute, tracer +from app.helpers.pydantic_types.phone_numbers import PhoneNumber +from app.helpers.resources import resources_dir +from app.models.call import CallGetModel, CallInitiateModel, CallStateModel +from app.models.error import ErrorInnerModel, ErrorModel +from app.models.next import ActionEnum as NextActionEnum +from app.models.readiness import ReadinessCheckModel, ReadinessEnum, ReadinessModel +from app.persistence.azure_queue_storage import Message as AzureQueueStorageMessage # First log logger.info( @@ -65,9 +66,10 @@ # Jinja configuration _jinja = Environment( + auto_reload=False, # Disable auto-reload for performance autoescape=True, enable_async=True, - loader=FileSystemLoader("public_website"), + loader=FileSystemLoader(resources_dir("public_website")), optimized=False, # Outsource optimization to html_minify ) # Jinja custom functions diff --git a/models/__init__.py b/app/models/__init__.py similarity index 100% rename from models/__init__.py rename to app/models/__init__.py diff --git a/models/call.py b/app/models/call.py similarity index 88% rename from models/call.py rename to app/models/call.py index 040731ee..3fe244f5 100644 --- a/models/call.py +++ b/app/models/call.py @@ -7,14 +7,17 @@ from pydantic import BaseModel, Field, ValidationInfo, computed_field, field_validator -from helpers.config_models.conversation import LanguageEntryModel, WorkflowInitiateModel -from helpers.monitoring import tracer -from helpers.pydantic_types.phone_numbers import PhoneNumber -from models.message import ActionEnum as MessageActionEnum, MessageModel -from models.next import NextModel -from models.reminder import ReminderModel -from models.synthesis import SynthesisModel -from models.training import TrainingModel +from app.helpers.config_models.conversation import ( + LanguageEntryModel, + WorkflowInitiateModel, +) +from app.helpers.monitoring import tracer +from app.helpers.pydantic_types.phone_numbers import PhoneNumber +from app.models.message import ActionEnum as MessageActionEnum, MessageModel +from app.models.next import NextModel +from app.models.reminder import ReminderModel +from app.models.synthesis import SynthesisModel +from app.models.training import TrainingModel class CallInitiateModel(WorkflowInitiateModel): @@ -89,7 +92,7 @@ class CallStateModel(CallGetModel, extra="ignore"): @computed_field @property def lang(self) -> LanguageEntryModel: # pyright: ignore - from helpers.config import CONFIG + from app.helpers.config import CONFIG lang = CONFIG.conversation.initiate.lang default = lang.default_lang @@ -114,7 +117,7 @@ async def trainings(self, cache_only: bool = True) -> list[TrainingModel]: Is using query expansion from last messages. Then, data is sorted by score. """ - from helpers.config import CONFIG + from app.helpers.config import CONFIG with tracer.start_as_current_span("call_trainings"): search = CONFIG.ai_search.instance() diff --git a/models/claim.py b/app/models/claim.py similarity index 100% rename from models/claim.py rename to app/models/claim.py diff --git a/models/error.py b/app/models/error.py similarity index 100% rename from models/error.py rename to app/models/error.py diff --git a/models/message.py b/app/models/message.py similarity index 98% rename from models/message.py rename to app/models/message.py index 56039833..e5605945 100644 --- a/models/message.py +++ b/app/models/message.py @@ -15,7 +15,7 @@ from openai.types.chat.chat_completion_chunk import ChoiceDeltaToolCall from pydantic import BaseModel, Field, field_validator -from helpers.monitoring import tracer +from app.helpers.monitoring import tracer _FUNC_NAME_SANITIZER_R = r"[^a-zA-Z0-9_-]" _MESSAGE_ACTION_R = r"(?:action=*([a-z_]*))? *(.*)" @@ -82,7 +82,7 @@ def __add__(self, other: ChoiceDeltaToolCall) -> "ToolModel": return self async def execute_function(self, plugins: object) -> None: - from helpers.logging import logger + from app.helpers.logging import logger json_str = self.function_arguments name = self.function_name @@ -145,7 +145,7 @@ async def execute_function(self, plugins: object) -> None: @staticmethod def _available_function_names() -> list[str]: - from helpers.llm_tools import ( + from app.helpers.llm_tools import ( LlmPlugins, ) diff --git a/models/next.py b/app/models/next.py similarity index 100% rename from models/next.py rename to app/models/next.py diff --git a/models/readiness.py b/app/models/readiness.py similarity index 100% rename from models/readiness.py rename to app/models/readiness.py diff --git a/models/reminder.py b/app/models/reminder.py similarity index 100% rename from models/reminder.py rename to app/models/reminder.py diff --git a/models/synthesis.py b/app/models/synthesis.py similarity index 100% rename from models/synthesis.py rename to app/models/synthesis.py diff --git a/models/training.py b/app/models/training.py similarity index 100% rename from models/training.py rename to app/models/training.py diff --git a/persistence/__init__.py b/app/persistence/__init__.py similarity index 100% rename from persistence/__init__.py rename to app/persistence/__init__.py diff --git a/persistence/ai_search.py b/app/persistence/ai_search.py similarity index 94% rename from persistence/ai_search.py rename to app/persistence/ai_search.py index ac9b6b02..83b6fb6a 100644 --- a/persistence/ai_search.py +++ b/app/persistence/ai_search.py @@ -22,14 +22,14 @@ wait_random_exponential, ) -from helpers.config_models.ai_search import AiSearchModel -from helpers.http import azure_transport -from helpers.identity import credential -from helpers.logging import logger -from models.readiness import ReadinessEnum -from models.training import TrainingModel -from persistence.icache import ICache -from persistence.isearch import ISearch +from app.helpers.config_models.ai_search import AiSearchModel +from app.helpers.http import azure_transport +from app.helpers.identity import credential +from app.helpers.logging import logger +from app.models.readiness import ReadinessEnum +from app.models.training import TrainingModel +from app.persistence.icache import ICache +from app.persistence.isearch import ISearch class AiSearchSearch(ISearch): diff --git a/persistence/azure_queue_storage.py b/app/persistence/azure_queue_storage.py similarity index 97% rename from persistence/azure_queue_storage.py rename to app/persistence/azure_queue_storage.py index 8d348ab7..4a6ec15c 100644 --- a/persistence/azure_queue_storage.py +++ b/app/persistence/azure_queue_storage.py @@ -14,9 +14,9 @@ wait_random_exponential, ) -from helpers.http import azure_transport -from helpers.identity import credential -from helpers.logging import logger +from app.helpers.http import azure_transport +from app.helpers.identity import credential +from app.helpers.logging import logger class Message(BaseModel): diff --git a/persistence/communication_services.py b/app/persistence/communication_services.py similarity index 88% rename from persistence/communication_services.py rename to app/persistence/communication_services.py index 37f6b9f7..c60d8d6a 100644 --- a/persistence/communication_services.py +++ b/app/persistence/communication_services.py @@ -2,12 +2,12 @@ from azure.communication.sms.aio import SmsClient from azure.core.exceptions import ClientAuthenticationError, HttpResponseError -from helpers.config_models.communication_services import CommunicationServicesModel -from helpers.http import azure_transport -from helpers.logging import logger -from helpers.pydantic_types.phone_numbers import PhoneNumber -from models.readiness import ReadinessEnum -from persistence.isms import ISms +from app.helpers.config_models.communication_services import CommunicationServicesModel +from app.helpers.http import azure_transport +from app.helpers.logging import logger +from app.helpers.pydantic_types.phone_numbers import PhoneNumber +from app.models.readiness import ReadinessEnum +from app.persistence.isms import ISms class CommunicationServicesSms(ISms): diff --git a/persistence/cosmos_db.py b/app/persistence/cosmos_db.py similarity index 96% rename from persistence/cosmos_db.py rename to app/persistence/cosmos_db.py index 3b910fff..c16f7909 100644 --- a/persistence/cosmos_db.py +++ b/app/persistence/cosmos_db.py @@ -8,15 +8,15 @@ from azure.cosmos.exceptions import CosmosHttpResponseError, CosmosResourceNotFoundError from pydantic import ValidationError -from helpers.config_models.database import CosmosDbModel -from helpers.features import callback_timeout_hour -from helpers.http import azure_transport -from helpers.identity import credential -from helpers.logging import logger -from models.call import CallStateModel -from models.readiness import ReadinessEnum -from persistence.icache import ICache -from persistence.istore import IStore +from app.helpers.config_models.database import CosmosDbModel +from app.helpers.features import callback_timeout_hour +from app.helpers.http import azure_transport +from app.helpers.identity import credential +from app.helpers.logging import logger +from app.models.call import CallStateModel +from app.models.readiness import ReadinessEnum +from app.persistence.icache import ICache +from app.persistence.istore import IStore class CosmosDbStore(IStore): diff --git a/persistence/icache.py b/app/persistence/icache.py similarity index 87% rename from persistence/icache.py rename to app/persistence/icache.py index 7a9ce550..fd975ea1 100644 --- a/persistence/icache.py +++ b/app/persistence/icache.py @@ -1,7 +1,7 @@ from abc import ABC, abstractmethod -from helpers.monitoring import tracer -from models.readiness import ReadinessEnum +from app.helpers.monitoring import tracer +from app.models.readiness import ReadinessEnum class ICache(ABC): diff --git a/persistence/isearch.py b/app/persistence/isearch.py similarity index 75% rename from persistence/isearch.py rename to app/persistence/isearch.py index fa308c9c..f354c2d6 100644 --- a/persistence/isearch.py +++ b/app/persistence/isearch.py @@ -1,9 +1,9 @@ from abc import ABC, abstractmethod -from helpers.monitoring import tracer -from models.readiness import ReadinessEnum -from models.training import TrainingModel -from persistence.icache import ICache +from app.helpers.monitoring import tracer +from app.models.readiness import ReadinessEnum +from app.models.training import TrainingModel +from app.persistence.icache import ICache class ISearch(ABC): diff --git a/persistence/isms.py b/app/persistence/isms.py similarity index 69% rename from persistence/isms.py rename to app/persistence/isms.py index 460ffb00..deeae092 100644 --- a/persistence/isms.py +++ b/app/persistence/isms.py @@ -1,8 +1,8 @@ from abc import ABC, abstractmethod -from helpers.monitoring import tracer -from helpers.pydantic_types.phone_numbers import PhoneNumber -from models.readiness import ReadinessEnum +from app.helpers.monitoring import tracer +from app.helpers.pydantic_types.phone_numbers import PhoneNumber +from app.models.readiness import ReadinessEnum class ISms(ABC): diff --git a/persistence/istore.py b/app/persistence/istore.py similarity index 88% rename from persistence/istore.py rename to app/persistence/istore.py index 1196adf0..1a42a85b 100644 --- a/persistence/istore.py +++ b/app/persistence/istore.py @@ -1,10 +1,10 @@ from abc import ABC, abstractmethod from uuid import UUID -from helpers.monitoring import tracer -from models.call import CallStateModel -from models.readiness import ReadinessEnum -from persistence.icache import ICache +from app.helpers.monitoring import tracer +from app.models.call import CallStateModel +from app.models.readiness import ReadinessEnum +from app.persistence.icache import ICache class IStore(ABC): diff --git a/persistence/memory.py b/app/persistence/memory.py similarity index 93% rename from persistence/memory.py rename to app/persistence/memory.py index 2e3ba72a..636347a7 100644 --- a/persistence/memory.py +++ b/app/persistence/memory.py @@ -2,10 +2,10 @@ from collections import OrderedDict from datetime import UTC, datetime, timedelta -from helpers.config_models.cache import MemoryModel -from helpers.logging import logger -from models.readiness import ReadinessEnum -from persistence.icache import ICache +from app.helpers.config_models.cache import MemoryModel +from app.helpers.logging import logger +from app.models.readiness import ReadinessEnum +from app.persistence.icache import ICache class MemoryCache(ICache): diff --git a/persistence/redis.py b/app/persistence/redis.py similarity index 96% rename from persistence/redis.py rename to app/persistence/redis.py index 62acf3b8..eeb4ceca 100644 --- a/persistence/redis.py +++ b/app/persistence/redis.py @@ -8,10 +8,10 @@ from redis.backoff import ExponentialBackoff from redis.exceptions import BusyLoadingError, ConnectionError, RedisError -from helpers.config_models.cache import RedisModel -from helpers.logging import logger -from models.readiness import ReadinessEnum -from persistence.icache import ICache +from app.helpers.config_models.cache import RedisModel +from app.helpers.logging import logger +from app.models.readiness import ReadinessEnum +from app.persistence.icache import ICache # Instrument redis RedisInstrumentor().instrument() diff --git a/persistence/sqlite.py b/app/persistence/sqlite.py similarity index 96% rename from persistence/sqlite.py rename to app/persistence/sqlite.py index be3f32d5..caa943b1 100644 --- a/persistence/sqlite.py +++ b/app/persistence/sqlite.py @@ -8,13 +8,13 @@ from opentelemetry.instrumentation.sqlite3 import SQLite3Instrumentor from pydantic import ValidationError -from helpers.config_models.database import SqliteModel -from helpers.features import callback_timeout_hour -from helpers.logging import logger -from models.call import CallStateModel -from models.readiness import ReadinessEnum -from persistence.icache import ICache -from persistence.istore import IStore +from app.helpers.config_models.database import SqliteModel +from app.helpers.features import callback_timeout_hour +from app.helpers.logging import logger +from app.models.call import CallStateModel +from app.models.readiness import ReadinessEnum +from app.persistence.icache import ICache +from app.persistence.istore import IStore # Instrument sqlite SQLite3Instrumentor().instrument() diff --git a/persistence/twilio.py b/app/persistence/twilio.py similarity index 90% rename from persistence/twilio.py rename to app/persistence/twilio.py index cb2b2acd..b5278b65 100644 --- a/persistence/twilio.py +++ b/app/persistence/twilio.py @@ -1,12 +1,12 @@ from twilio.base.exceptions import TwilioRestException from twilio.rest import Client -from helpers.config_models.sms import TwilioModel -from helpers.http import twilio_http -from helpers.logging import logger -from helpers.pydantic_types.phone_numbers import PhoneNumber -from models.readiness import ReadinessEnum -from persistence.isms import ISms +from app.helpers.config_models.sms import TwilioModel +from app.helpers.http import twilio_http +from app.helpers.logging import logger +from app.helpers.pydantic_types.phone_numbers import PhoneNumber +from app.models.readiness import ReadinessEnum +from app.persistence.isms import ISms class TwilioSms(ISms): diff --git a/public_website/list.html.jinja b/app/resources/public_website/list.html.jinja similarity index 100% rename from public_website/list.html.jinja rename to app/resources/public_website/list.html.jinja diff --git a/public_website/single.html.jinja b/app/resources/public_website/single.html.jinja similarity index 100% rename from public_website/single.html.jinja rename to app/resources/public_website/single.html.jinja diff --git a/public_website/templates/base.html.jinja b/app/resources/public_website/templates/base.html.jinja similarity index 100% rename from public_website/templates/base.html.jinja rename to app/resources/public_website/templates/base.html.jinja diff --git a/public_website/templates/call_me.html.jinja b/app/resources/public_website/templates/call_me.html.jinja similarity index 100% rename from public_website/templates/call_me.html.jinja rename to app/resources/public_website/templates/call_me.html.jinja diff --git a/resources/tiktoken/9b5ad71b2ce5302211f9c61530b329a4922fc6a4 b/app/resources/tiktoken/9b5ad71b2ce5302211f9c61530b329a4922fc6a4 similarity index 100% rename from resources/tiktoken/9b5ad71b2ce5302211f9c61530b329a4922fc6a4 rename to app/resources/tiktoken/9b5ad71b2ce5302211f9c61530b329a4922fc6a4 diff --git a/resources/tiktoken/README.md b/app/resources/tiktoken/README.md similarity index 100% rename from resources/tiktoken/README.md rename to app/resources/tiktoken/README.md diff --git a/resources/tiktoken/fb374d419588a4632f3f557e76b4b70aebbca790 b/app/resources/tiktoken/fb374d419588a4632f3f557e76b4b70aebbca790 similarity index 100% rename from resources/tiktoken/fb374d419588a4632f3f557e76b4b70aebbca790 rename to app/resources/tiktoken/fb374d419588a4632f3f557e76b4b70aebbca790 diff --git a/bicep/app.bicep b/cicd/bicep/app.bicep similarity index 100% rename from bicep/app.bicep rename to cicd/bicep/app.bicep diff --git a/bicep/main.bicep b/cicd/bicep/main.bicep similarity index 100% rename from bicep/main.bicep rename to cicd/bicep/main.bicep diff --git a/helpers/resources.py b/helpers/resources.py deleted file mode 100644 index 71f780bb..00000000 --- a/helpers/resources.py +++ /dev/null @@ -1,22 +0,0 @@ -import os -from functools import lru_cache -from os import path -from pathlib import Path - - -@lru_cache # Cache results in memory as resources are not expected to change -def resources_dir(folder: str) -> str: - """ - Get the absolute path to the resources folder. - """ - return str( - Path( - path.join( - os.path.abspath(os.getcwd()), - "resources", - folder, - ) - ) - .resolve() - .absolute() - ) diff --git a/resources/lexicon.xml b/public/lexicon.xml similarity index 100% rename from resources/lexicon.xml rename to public/lexicon.xml diff --git a/resources/loading.wav b/public/loading.wav similarity index 100% rename from resources/loading.wav rename to public/loading.wav diff --git a/resources/ready.wav b/public/ready.wav similarity index 100% rename from resources/ready.wav rename to public/ready.wav diff --git a/pyproject.toml b/pyproject.toml index 26c20f14..7f758b6a 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -65,9 +65,7 @@ dev = [ [tool.setuptools] py-modules = [ - "helpers", - "models", - "persistence", + "app", ] [tool.pip-tools] diff --git a/tests/cache.py b/tests/cache.py index 31f58137..a1acc686 100644 --- a/tests/cache.py +++ b/tests/cache.py @@ -1,8 +1,8 @@ import pytest from pytest_assume.plugin import assume -from helpers.config import CONFIG -from helpers.config_models.cache import ModeEnum as CacheModeEnum +from app.helpers.config import CONFIG +from app.helpers.config_models.cache import ModeEnum as CacheModeEnum @pytest.mark.parametrize( diff --git a/tests/conftest.py b/tests/conftest.py index bd7955e3..20421335 100644 --- a/tests/conftest.py +++ b/tests/conftest.py @@ -20,11 +20,11 @@ from langchain_openai import AzureChatOpenAI from pydantic import BaseModel, ValidationError -from helpers.call_utils import ContextEnum as CallContextEnum -from helpers.config import CONFIG -from helpers.logging import logger -from main import _str_to_contexts -from models.call import CallInitiateModel, CallStateModel +from app.helpers.call_utils import ContextEnum as CallContextEnum +from app.helpers.config import CONFIG +from app.helpers.logging import logger +from app.main import _str_to_contexts +from app.models.call import CallInitiateModel, CallStateModel class CallConnectionClientMock(CallConnectionClient): diff --git a/tests/llm.py b/tests/llm.py index 287e56ec..93d52925 100644 --- a/tests/llm.py +++ b/tests/llm.py @@ -17,7 +17,7 @@ from pydantic import TypeAdapter from pytest_assume.plugin import assume -from helpers.call_events import ( +from app.helpers.call_events import ( on_call_connected, on_call_disconnected, on_end_call, @@ -25,10 +25,10 @@ on_play_completed, on_speech_recognized, ) -from helpers.logging import logger -from models.call import CallStateModel -from models.reminder import ReminderModel -from models.training import TrainingModel +from app.helpers.logging import logger +from app.models.call import CallStateModel +from app.models.reminder import ReminderModel +from app.models.training import TrainingModel from tests.conftest import CallAutomationClientMock, with_conversations diff --git a/tests/local.py b/tests/local.py index 803de297..29c5502a 100644 --- a/tests/local.py +++ b/tests/local.py @@ -1,6 +1,6 @@ import asyncio -from helpers.call_events import ( +from app.helpers.call_events import ( on_call_connected, on_call_disconnected, on_end_call, @@ -8,9 +8,9 @@ on_play_completed, on_speech_recognized, ) -from helpers.config import CONFIG -from helpers.logging import logger -from models.call import CallInitiateModel, CallStateModel +from app.helpers.config import CONFIG +from app.helpers.logging import logger +from app.models.call import CallInitiateModel, CallStateModel from tests.conftest import CallAutomationClientMock diff --git a/tests/search.py b/tests/search.py index 86a253c6..1a39d96f 100644 --- a/tests/search.py +++ b/tests/search.py @@ -9,11 +9,11 @@ from pydantic import TypeAdapter from pytest_assume.plugin import assume -from helpers.config import CONFIG -from helpers.logging import logger -from models.call import CallStateModel -from models.message import MessageModel, PersonaEnum as MessagePersonaEnum -from models.training import TrainingModel +from app.helpers.config import CONFIG +from app.helpers.logging import logger +from app.models.call import CallStateModel +from app.models.message import MessageModel, PersonaEnum as MessagePersonaEnum +from app.models.training import TrainingModel from tests.conftest import with_conversations diff --git a/tests/store.py b/tests/store.py index 7ad5f853..c76f04db 100644 --- a/tests/store.py +++ b/tests/store.py @@ -1,9 +1,9 @@ import pytest from pytest_assume.plugin import assume -from helpers.config import CONFIG -from helpers.config_models.database import ModeEnum as DatabaseModeEnum -from models.call import CallStateModel +from app.helpers.config import CONFIG +from app.helpers.config_models.database import ModeEnum as DatabaseModeEnum +from app.models.call import CallStateModel @pytest.mark.parametrize(