mirror of
https://github.com/Monadical-SAS/reflector.git
synced 2026-03-29 10:26:46 +00:00
* Increase max connections * Classify hard and transient hatchet errors * Fan out partial success * Force reprocessing of error transcripts * Stop retrying on 402 payment required * Avoid httpx/hatchet timeout race * Add retry wrapper to get_response for for transient errors * Add retry backoff * Return falsy results so get_response won't retry on empty string * Skip error status in on_workflow_failure when transcript already ended * Fix precommit issues * Fail step on first fan-out failure instead of skipping
204 lines
6.8 KiB
Python
204 lines
6.8 KiB
Python
from pydantic.types import PositiveInt
|
|
from pydantic_settings import BaseSettings, SettingsConfigDict
|
|
|
|
from reflector.schemas.platform import DAILY_PLATFORM, Platform
|
|
from reflector.utils.string import NonEmptyString
|
|
|
|
|
|
class Settings(BaseSettings):
|
|
model_config = SettingsConfigDict(
|
|
env_file=".env",
|
|
env_file_encoding="utf-8",
|
|
extra="ignore",
|
|
)
|
|
|
|
ROOT_PATH: str = "/"
|
|
|
|
# WebRTC port range for ICE candidates (e.g. "50000-50100").
|
|
# When set, monkey-patches aioice to bind UDP sockets within this range,
|
|
# allowing Docker port mapping instead of network_mode: host.
|
|
WEBRTC_PORT_RANGE: str | None = None
|
|
# Host IP or hostname to advertise in ICE candidates instead of the
|
|
# container's internal IP. Use "host.docker.internal" in Docker with
|
|
# extra_hosts, or a specific LAN IP. Resolved at connection time.
|
|
WEBRTC_HOST: str | None = None
|
|
|
|
# CORS
|
|
UI_BASE_URL: str = "http://localhost:3000"
|
|
CORS_ORIGIN: str = "*"
|
|
CORS_ALLOW_CREDENTIALS: bool = False
|
|
|
|
# Database
|
|
DATABASE_URL: str = (
|
|
"postgresql+asyncpg://reflector:reflector@localhost:5432/reflector"
|
|
)
|
|
|
|
# local data directory
|
|
DATA_DIR: str = "./data"
|
|
|
|
# Audio Chunking
|
|
# backends: silero, frames
|
|
AUDIO_CHUNKER_BACKEND: str = "frames"
|
|
|
|
# HuggingFace token for gated models (pyannote diarization in --cpu mode)
|
|
HF_TOKEN: str | None = None
|
|
|
|
# Audio Transcription
|
|
# backends:
|
|
# - whisper: in-process model loading (no HTTP, runs in same process)
|
|
# - modal: HTTP API client (works with Modal.com OR self-hosted gpu/self_hosted/)
|
|
TRANSCRIPT_BACKEND: str = "whisper"
|
|
|
|
# Whisper model sizes for local transcription
|
|
# Options: "tiny", "base", "small", "medium", "large-v2"
|
|
WHISPER_CHUNK_MODEL: str = "tiny"
|
|
WHISPER_FILE_MODEL: str = "tiny"
|
|
TRANSCRIPT_URL: str | None = None
|
|
TRANSCRIPT_TIMEOUT: int = 90
|
|
TRANSCRIPT_FILE_TIMEOUT: int = (
|
|
540 # Below Hatchet TIMEOUT_HEAVY (600) to avoid timeout race
|
|
)
|
|
|
|
# Audio Transcription: modal backend
|
|
TRANSCRIPT_MODAL_API_KEY: str | None = None
|
|
|
|
# Audio transcription storage
|
|
TRANSCRIPT_STORAGE_BACKEND: str | None = None
|
|
|
|
# Storage configuration for AWS
|
|
TRANSCRIPT_STORAGE_AWS_BUCKET_NAME: str = "reflector-bucket"
|
|
TRANSCRIPT_STORAGE_AWS_REGION: str = "us-east-1"
|
|
TRANSCRIPT_STORAGE_AWS_ACCESS_KEY_ID: str | None = None
|
|
TRANSCRIPT_STORAGE_AWS_SECRET_ACCESS_KEY: str | None = None
|
|
TRANSCRIPT_STORAGE_AWS_ENDPOINT_URL: str | None = None
|
|
|
|
# Platform-specific recording storage (follows {PREFIX}_STORAGE_AWS_{CREDENTIAL} pattern)
|
|
# Whereby storage configuration
|
|
WHEREBY_STORAGE_AWS_BUCKET_NAME: str | None = None
|
|
WHEREBY_STORAGE_AWS_REGION: str | None = None
|
|
WHEREBY_STORAGE_AWS_ACCESS_KEY_ID: str | None = None
|
|
WHEREBY_STORAGE_AWS_SECRET_ACCESS_KEY: str | None = None
|
|
|
|
# Daily.co storage configuration
|
|
DAILYCO_STORAGE_AWS_BUCKET_NAME: str | None = None
|
|
DAILYCO_STORAGE_AWS_REGION: str | None = None
|
|
DAILYCO_STORAGE_AWS_ROLE_ARN: str | None = None
|
|
# Worker credentials for reading/deleting from Daily's recording bucket
|
|
DAILYCO_STORAGE_AWS_ACCESS_KEY_ID: str | None = None
|
|
DAILYCO_STORAGE_AWS_SECRET_ACCESS_KEY: str | None = None
|
|
|
|
# Translate into the target language
|
|
TRANSLATION_BACKEND: str = "passthrough"
|
|
TRANSLATE_URL: str | None = None
|
|
TRANSLATE_TIMEOUT: int = 90
|
|
|
|
# Translation: modal backend
|
|
TRANSLATE_MODAL_API_KEY: str | None = None
|
|
|
|
# LLM
|
|
LLM_MODEL: str = "microsoft/phi-4"
|
|
LLM_URL: str | None = None
|
|
LLM_API_KEY: str | None = None
|
|
LLM_CONTEXT_WINDOW: int = 16000
|
|
LLM_REQUEST_TIMEOUT: float = 300.0 # HTTP request timeout for LLM calls (seconds)
|
|
|
|
LLM_PARSE_MAX_RETRIES: int = (
|
|
3 # Max retries for JSON/validation errors (total attempts = retries + 1)
|
|
)
|
|
LLM_STRUCTURED_RESPONSE_TIMEOUT: int = (
|
|
300 # Timeout in seconds for structured responses (5 minutes)
|
|
)
|
|
|
|
# Diarization
|
|
# backends: modal — HTTP API client, pyannote — in-process pyannote.audio
|
|
DIARIZATION_ENABLED: bool = True
|
|
DIARIZATION_BACKEND: str = "modal"
|
|
DIARIZATION_URL: str | None = None
|
|
DIARIZATION_FILE_TIMEOUT: int = 600
|
|
|
|
# Diarization: modal backend
|
|
DIARIZATION_MODAL_API_KEY: str | None = None
|
|
|
|
# Audio Padding
|
|
# backends:
|
|
# - pyav: in-process PyAV padding (no HTTP, runs in same process)
|
|
# - modal: HTTP API client (works with Modal.com OR self-hosted gpu/self_hosted/)
|
|
PADDING_BACKEND: str = "pyav"
|
|
PADDING_URL: str | None = None
|
|
PADDING_MODAL_API_KEY: str | None = None
|
|
|
|
# Sentry
|
|
SENTRY_DSN: str | None = None
|
|
|
|
# User authentication (none, jwt, password)
|
|
AUTH_BACKEND: str = "none"
|
|
|
|
# User authentication using JWT
|
|
AUTH_JWT_ALGORITHM: str = "RS256"
|
|
AUTH_JWT_PUBLIC_KEY: str | None = "authentik.monadical.com_public.pem"
|
|
AUTH_JWT_AUDIENCE: str | None = None
|
|
|
|
# User authentication using password (selfhosted)
|
|
ADMIN_EMAIL: str | None = None
|
|
ADMIN_PASSWORD_HASH: str | None = None
|
|
|
|
PUBLIC_MODE: bool = False
|
|
PUBLIC_DATA_RETENTION_DAYS: PositiveInt = 7
|
|
|
|
# Min transcript length to generate topic + summary
|
|
MIN_TRANSCRIPT_LENGTH: int = 750
|
|
|
|
# Celery
|
|
CELERY_BROKER_URL: str = "redis://localhost:6379/1"
|
|
CELERY_RESULT_BACKEND: str = "redis://localhost:6379/1"
|
|
|
|
# Redis
|
|
REDIS_HOST: str = "localhost"
|
|
REDIS_PORT: int = 6379
|
|
REDIS_CACHE_DB: int = 2
|
|
|
|
# Secret key
|
|
SECRET_KEY: str = "changeme-f02f86fd8b3e4fd892c6043e5a298e21"
|
|
|
|
# Current hosting/domain
|
|
BASE_URL: str = "http://localhost:1250"
|
|
|
|
# Profiling
|
|
PROFILING: bool = False
|
|
|
|
# Healthcheck
|
|
HEALTHCHECK_URL: str | None = None
|
|
|
|
# Whereby integration
|
|
WHEREBY_API_URL: str = "https://api.whereby.dev/v1"
|
|
WHEREBY_API_KEY: NonEmptyString | None = None
|
|
WHEREBY_WEBHOOK_SECRET: str | None = None
|
|
AWS_PROCESS_RECORDING_QUEUE_URL: str | None = None
|
|
SQS_POLLING_TIMEOUT_SECONDS: int = 60
|
|
CELERY_BEAT_POLL_INTERVAL: int = (
|
|
0 # 0 = use individual defaults; set e.g. 300 for 5-min polling
|
|
)
|
|
|
|
# Daily.co integration
|
|
DAILY_API_KEY: str | None = None
|
|
DAILY_WEBHOOK_SECRET: str | None = None
|
|
DAILY_SUBDOMAIN: str | None = None
|
|
DAILY_WEBHOOK_UUID: str | None = (
|
|
None # Webhook UUID for this environment. Not used by production code
|
|
)
|
|
# Platform Configuration
|
|
DEFAULT_VIDEO_PLATFORM: Platform = DAILY_PLATFORM
|
|
|
|
# Zulip integration
|
|
ZULIP_REALM: str | None = None
|
|
ZULIP_API_KEY: str | None = None
|
|
ZULIP_BOT_EMAIL: str | None = None
|
|
|
|
# Hatchet workflow orchestration (always enabled for multitrack processing)
|
|
HATCHET_CLIENT_TOKEN: str | None = None
|
|
HATCHET_CLIENT_TLS_STRATEGY: str = "none" # none, tls, mtls
|
|
HATCHET_DEBUG: bool = False
|
|
|
|
|
|
settings = Settings()
|