import os from os import environ, path from datetime import timedelta import redis import ssl import tempfile from ipaddress import ip_address from common.utils.prompt_loader import load_prompt_templates basedir = path.abspath(path.dirname(__file__)) class Config(object): DEBUG = False DEVELOPMENT = False SECRET_KEY = environ.get('SECRET_KEY') COMPONENT_NAME = environ.get('COMPONENT_NAME') # Database Settings --------------------------------------------------------------------------- DB_HOST = environ.get('DB_HOST') DB_USER = environ.get('DB_USER') DB_PASS = environ.get('DB_PASS') DB_NAME = environ.get('DB_NAME') DB_PORT = environ.get('DB_PORT') SQLALCHEMY_DATABASE_URI = f'postgresql+pg8000://{DB_USER}:{DB_PASS}@{DB_HOST}:{DB_PORT}/{DB_NAME}' SQLALCHEMY_BINDS = {'public': SQLALCHEMY_DATABASE_URI} # Redis Settings ------------------------------------------------------------------------------ REDIS_URL = environ.get('REDIS_URL') REDIS_PORT = environ.get('REDIS_PORT', '6379') REDIS_USER = environ.get('REDIS_USER') REDIS_PASS = environ.get('REDIS_PASS') REDIS_CERT_DATA = environ.get('REDIS_CERT') # Determine if REDIS_URL is an IP; use it to control hostname checking REDIS_IS_IP = False try: ip_address(REDIS_URL) REDIS_IS_IP = True except Exception: REDIS_IS_IP = False REDIS_SSL_CHECK_HOSTNAME = not REDIS_IS_IP # Write CA once to a file, expose path REDIS_CA_CERT_PATH = None if REDIS_CERT_DATA: _tmp = tempfile.NamedTemporaryFile(mode='w', delete=False, suffix='.pem') _tmp.write(REDIS_CERT_DATA) _tmp.flush() _tmp.close() REDIS_CA_CERT_PATH = _tmp.name if not REDIS_CERT_DATA: # We are in a simple dev/test environment REDIS_BASE_URI = f'redis://{REDIS_URL}:{REDIS_PORT}' else: # We are in a scaleway environment, providing name, user and certificate REDIS_BASE_URI = f'rediss://{REDIS_USER}:{REDIS_PASS}@{REDIS_URL}:{REDIS_PORT}' # Central SSL options dict for reuse (Celery/Dogpile/etc.) REDIS_SSL_OPTIONS = None if REDIS_CERT_DATA and REDIS_CA_CERT_PATH: REDIS_SSL_OPTIONS = { 'ssl_cert_reqs': ssl.CERT_REQUIRED, 'ssl_ca_certs': REDIS_CA_CERT_PATH, 'ssl_check_hostname': REDIS_SSL_CHECK_HOSTNAME, } REDIS_PREFIXES = { 'celery_app': 'celery:app:', 'celery_chat': 'celery:chat:', 'session': 'session:', 'cache_workers': 'cache:workers:', 'pubsub_execution': 'pubsub:execution:', 'startup_ops': 'startup:ops:', } # Celery Redis settings CELERY_BROKER_URL = f'{REDIS_BASE_URI}/0' CELERY_RESULT_BACKEND = f'{REDIS_BASE_URI}/0' CELERY_BROKER_URL_CHAT = f'{REDIS_BASE_URI}/0' CELERY_RESULT_BACKEND_CHAT = f'{REDIS_BASE_URI}/0' # SSE PubSub settings SPECIALIST_EXEC_PUBSUB = f'{REDIS_BASE_URI}/0' # eveai_model cache Redis setting MODEL_CACHE_URL = f'{REDIS_BASE_URI}/0' # Session Settings with Redis ----------------------------------------------------------------- SESSION_TYPE = 'redis' SESSION_PERMANENT = True SESSION_USE_SIGNER = True PERMANENT_SESSION_LIFETIME = timedelta(minutes=60) SESSION_REFRESH_EACH_REQUEST = True # Configure SESSION_REDIS with SSL when cert is provided if REDIS_CERT_DATA and REDIS_CA_CERT_PATH: SESSION_REDIS = redis.Redis( host=REDIS_URL, port=int(REDIS_PORT or 6379), username=REDIS_USER, password=REDIS_PASS, ssl=True, ssl_cert_reqs=ssl.CERT_REQUIRED, ssl_ca_certs=REDIS_CA_CERT_PATH, ssl_check_hostname=REDIS_SSL_CHECK_HOSTNAME, ) else: SESSION_REDIS = redis.from_url(f'{REDIS_BASE_URI}/0') SESSION_KEY_PREFIX = f'session_{COMPONENT_NAME}:' SESSION_COOKIE_NAME = f'{COMPONENT_NAME}_session' SESSION_COOKIE_DOMAIN = None # Laat Flask dit automatisch bepalen SESSION_COOKIE_PATH = '/' SESSION_COOKIE_HTTPONLY = True SESSION_COOKIE_SECURE = False # True voor production met HTTPS SESSION_COOKIE_SAMESITE = 'Lax' REMEMBER_COOKIE_SAMESITE = 'strict' WTF_CSRF_ENABLED = True WTF_CSRF_TIME_LIMIT = None WTF_CSRF_SSL_STRICT = False # Set to True if using HTTPS # flask-security-too settings ----------------------------------------------------------------- # SECURITY_URL_PREFIX = '/admin' SECURITY_LOGIN_URL = '/admin/login' SECURITY_LOGOUT_URL = '/admin/logout' # SECURITY_REGISTER_URL = '/admin/register' # SECURITY_RESET_URL = '/admin/reset' # SECURITY_CHANGE_URL = '/admin/change' # SECURITY_POST_LOGIN_VIEW = '/admin/user/tenant_overview' # SECURITY_POST_LOGOUT_VIEW = '/admin' # SECURITY_POST_REGISTER_VIEW = '/admin/user/tenant_overview' # SECURITY_POST_RESET_VIEW = '/admin/login' # SECURITY_POST_CHANGE_VIEW = '/admin/login' # SECURITY_BLUEPRINT_NAME = 'security_bp' SECURITY_PASSWORD_SALT = environ.get('SECURITY_PASSWORD_SALT') SECURITY_CONFIRMABLE = True SECURITY_TRACKABLE = True SECURITY_PASSWORD_COMPLEXITY_CHECKER = 'zxcvbn' SECURITY_POST_LOGIN_VIEW = '/user/tenant_overview' SECURITY_RECOVERABLE = True SECURITY_EMAIL_SENDER = "eveai_super@flow-it.net" SECURITY_EMAIL_SUBJECT_PASSWORD_RESET = 'Reset Your Password' SECURITY_EMAIL_SUBJECT_PASSWORD_NOTICE = 'Your Password Has Been Reset' SECURITY_EMAIL_PLAINTEXT = False SECURITY_EMAIL_HTML = True SECURITY_SESSION_PROTECTION = 'basic' # of 'basic' als 'strong' problemen geeft SECURITY_REMEMBER_TOKEN_VALIDITY = timedelta(minutes=60) # Zelfde als session lifetime SECURITY_AUTO_LOGIN_AFTER_CONFIRM = True SECURITY_AUTO_LOGIN_AFTER_RESET = True # Ensure Flask-Security-Too is handling CSRF tokens when behind a proxy SECURITY_CSRF_PROTECT_MECHANISMS = ['session'] SECURITY_CSRF_COOKIE_NAME = 'XSRF-TOKEN' SECURITY_CSRF_HEADER = 'X-XSRF-TOKEN' WTF_CSRF_CHECK_DEFAULT = False # file upload settings ------------------------------------------------------------------------ MAX_CONTENT_LENGTH = 50 * 1024 * 1024 # supported languages ------------------------------------------------------------------------- SUPPORTED_LANGUAGE_DETAILS = { "English": { "iso 639-1": "en", "iso 639-2": "eng", "iso 639-3": "eng", "flag": "🇬🇧" }, "French": { "iso 639-1": "fr", "iso 639-2": "fre", # of 'fra' "iso 639-3": "fra", "flag": "🇫🇷" }, "German": { "iso 639-1": "de", "iso 639-2": "ger", # of 'deu' "iso 639-3": "deu", "flag": "🇩🇪" }, "Spanish": { "iso 639-1": "es", "iso 639-2": "spa", "iso 639-3": "spa", "flag": "🇪🇸" }, "Italian": { "iso 639-1": "it", "iso 639-2": "ita", "iso 639-3": "ita", "flag": "🇮🇹" }, "Portuguese": { "iso 639-1": "pt", "iso 639-2": "por", "iso 639-3": "por", "flag": "🇵🇹" }, "Dutch": { "iso 639-1": "nl", "iso 639-2": "dut", # of 'nld' "iso 639-3": "nld", "flag": "🇳🇱" }, "Russian": { "iso 639-1": "ru", "iso 639-2": "rus", "iso 639-3": "rus", "flag": "🇷🇺" }, "Chinese": { "iso 639-1": "zh", "iso 639-2": "chi", # of 'zho' "iso 639-3": "zho", "flag": "🇨🇳" }, "Japanese": { "iso 639-1": "ja", "iso 639-2": "jpn", "iso 639-3": "jpn", "flag": "🇯🇵" }, "Korean": { "iso 639-1": "ko", "iso 639-2": "kor", "iso 639-3": "kor", "flag": "🇰🇷" }, "Arabic": { "iso 639-1": "ar", "iso 639-2": "ara", "iso 639-3": "ara", "flag": "🇸🇦" }, "Hindi": { "iso 639-1": "hi", "iso 639-2": "hin", "iso 639-3": "hin", "flag": "🇮🇳" }, } # Afgeleide taalconstanten SUPPORTED_LANGUAGES = [lang_details["iso 639-1"] for lang_details in SUPPORTED_LANGUAGE_DETAILS.values()] SUPPORTED_LANGUAGES_FULL = list(SUPPORTED_LANGUAGE_DETAILS.keys()) SUPPORTED_LANGUAGE_ISO639_1_LOOKUP = {lang_details["iso 639-1"]: lang_name for lang_name, lang_details in SUPPORTED_LANGUAGE_DETAILS.items()} # supported currencies ------------------------------------------------------------------------ SUPPORTED_CURRENCIES = ['€', '$'] # supported LLMs & settings ------------------------------------------------------------------- # SUPPORTED_EMBEDDINGS = ['openai.text-embedding-3-small', 'openai.text-embedding-3-large', 'mistral.mistral-embed'] SUPPORTED_EMBEDDINGS = ['mistral.mistral-embed'] SUPPORTED_LLMS = ['mistral.mistral-large-latest', 'mistral.mistral-medium_latest', 'mistral.mistral-small-latest'] # Annotation text chunk length ANNOTATION_TEXT_CHUNK_LENGTH = 10000 # Environemnt Loaders OPENAI_API_KEY = environ.get('OPENAI_API_KEY') MISTRAL_API_KEY = environ.get('MISTRAL_API_KEY') # Celery settings (see above for Redis settings) ---------------------------------------------- CELERY_TASK_SERIALIZER = 'json' CELERY_RESULT_SERIALIZER = 'json' CELERY_ACCEPT_CONTENT = ['json'] CELERY_TIMEZONE = 'UTC' CELERY_ENABLE_UTC = True # JWT settings -------------------------------------------------------------------------------- JWT_SECRET_KEY = environ.get('JWT_SECRET_KEY') JWT_ACCESS_TOKEN_EXPIRES = timedelta(hours=1) # Set token expiry to 1 hour JWT_ACCESS_TOKEN_EXPIRES_DEPLOY = timedelta(hours=24) # Set long-lived token for deployment # API Encryption ------------------------------------------------------------------------------ API_ENCRYPTION_KEY = environ.get('API_ENCRYPTION_KEY') # Email settings for API key notifications PROMOTIONAL_IMAGE_URL = 'https://askeveai.com/wp-content/uploads/2024/07/Evie-Call-scaled.jpg' # Replace with your actual URL # Langsmith settings LANGCHAIN_TRACING_V2 = True LANGCHAIN_ENDPOINT = 'https://api.smith.langchain.com' LANGCHAIN_PROJECT = "eveai" TENANT_TYPES = ['Active', 'Demo', 'Inactive', 'Test'] # The maximum number of seconds allowed for audio compression (to save resources) MAX_COMPRESSION_DURATION = 60*10 # 10 minutes # The maximum number of seconds allowed for transcribing audio MAX_TRANSCRIPTION_DURATION = 60*10 # 10 minutes # Maximum CPU usage for a compression task COMPRESSION_CPU_LIMIT = 50 # Delay between compressing chunks in seconds COMPRESSION_PROCESS_DELAY = 1 # WordPress Integration Settings WORDPRESS_PROTOCOL = environ.get('WORDPRESS_PROTOCOL', 'http') WORDPRESS_HOST = environ.get('WORDPRESS_HOST', 'host.docker.internal') WORDPRESS_PORT = environ.get('WORDPRESS_PORT', '10003') WORDPRESS_BASE_URL = f"{WORDPRESS_PROTOCOL}://{WORDPRESS_HOST}:{WORDPRESS_PORT}" EXTERNAL_WORDPRESS_BASE_URL = 'localhost:10003' # Prometheus PUSH Gataway PUSH_GATEWAY_HOST = environ.get('PUSH_GATEWAY_HOST', 'pushgateway') PUSH_GATEWAY_PORT = environ.get('PUSH_GATEWAY_PORT', '9091') PUSH_GATEWAY_URL = f"{PUSH_GATEWAY_HOST}:{PUSH_GATEWAY_PORT}" # Scaleway parameters SW_EMAIL_ACCESS_KEY = environ.get('SW_EMAIL_ACCESS_KEY') SW_EMAIL_SECRET_KEY = environ.get('SW_EMAIL_SECRET_KEY') SW_EMAIL_SENDER = environ.get('SW_EMAIL_SENDER') SW_EMAIL_NAME = environ.get('SW_EMAIL_NAME') SW_PROJECT = environ.get('SW_PROJECT') # Entitlement Constants ENTITLEMENTS_MAX_PENDING_DAYS = 5 # Defines the maximum number of days a pending entitlement can be active # Content Directory for static content like the changelog, terms & conditions, privacy statement, ... CONTENT_DIR = '/app/content' class DevConfig(Config): DEVELOPMENT = True DEBUG = True FLASK_DEBUG = True EXPLAIN_TEMPLATE_LOADING = False # Define the nginx prefix used for the specific apps EVEAI_APP_LOCATION_PREFIX = '' EVEAI_CHAT_LOCATION_PREFIX = '/chat' CHAT_CLIENT_PREFIX = 'chat-client/chat/' # Define the static path STATIC_URL = 'https://evie-staging-static.askeveai.com' # PATH settings ffmpeg_path = '/usr/bin/ffmpeg' # OBJECT STORAGE OBJECT_STORAGE_TYPE = 'MINIO' OBJECT_STORAGE_TENANT_BASE = 'bucket' # MINIO MINIO_ENDPOINT = 'minio:9000' MINIO_ACCESS_KEY = 'minioadmin' MINIO_SECRET_KEY = 'minioadmin' MINIO_USE_HTTPS = False class StagingConfig(Config): DEVELOPMENT = False DEBUG = True FLASK_DEBUG = True EXPLAIN_TEMPLATE_LOADING = False # Define the nginx prefix used for the specific apps EVEAI_APP_LOCATION_PREFIX = '' EVEAI_CHAT_LOCATION_PREFIX = '' CHAT_CLIENT_PREFIX = '' # Define the static path STATIC_URL = 'https://evie-staging-static.askeveai.com' # PATH settings ffmpeg_path = '/usr/bin/ffmpeg' # OBJECT STORAGE OBJECT_STORAGE_TYPE = 'SCALEWAY' OBJECT_STORAGE_TENANT_BASE = 'folder' OBJECT_STORAGE_BUCKET_NAME = 'eveai-staging' # MINIO MINIO_ENDPOINT = environ.get('MINIO_ENDPOINT') MINIO_ACCESS_KEY = environ.get('MINIO_ACCESS_KEY') MINIO_SECRET_KEY = environ.get('MINIO_SECRET_KEY') MINIO_USE_HTTPS = True class ProdConfig(Config): DEVELOPMENT = False DEBUG = False FLASK_DEBUG = False EXPLAIN_TEMPLATE_LOADING = False # SESSION SETTINGS SESSION_COOKIE_SECURE = True WTF_CSRF_SSL_STRICT = True # Set to True if using HTTPS # Define the nginx prefix used for the specific apps EVEAI_APP_LOCATION_PREFIX = '' EVEAI_CHAT_LOCATION_PREFIX = '' # Define the static path STATIC_URL = 'https://evie-staging-static.askeveai.com' # PATH settings ffmpeg_path = '/usr/bin/ffmpeg' # MINIO MINIO_ENDPOINT = environ.get('MINIO_ENDPOINT') MINIO_ACCESS_KEY = environ.get('MINIO_ACCESS_KEY') MINIO_SECRET_KEY = environ.get('MINIO_SECRET_KEY') MINIO_USE_HTTPS = True def get_config(config_name='dev'): configs = { 'dev': DevConfig, 'staging': StagingConfig, 'prod': ProdConfig, 'default': DevConfig, } return configs.get(config_name)