Watch
1
0
Fork
You've already forked Seyyed_arc
0
forked from hesabix/arc
Seyyed_arc/hesabixAPI/app/core/settings.py
2026-08-18 17:20:26 +00:00

179 lines
7.6 KiB
Python
Executable file
Raw Permalink Blame History

This file contains invisible Unicode characters

This file contains invisible Unicode characters that are indistinguishable to humans but may be processed differently by a computer. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

from functools import lru_cache
from urllib.parse import quote_plus
from pydantic import BaseModel, Field
from pydantic_settings import BaseSettings, SettingsConfigDict
class Settings(BaseSettings):
model_config = SettingsConfigDict(env_file=".env", env_file_encoding="utf-8", extra="ignore")
app_name: str = "Hesabix API"
app_version: str = "0.1.0"
api_v1_prefix: str = "/api/v1"
environment: str = "development"
debug: bool = True
# Database
db_user: str = "hesabix"
db_password: str = "change_me"
db_host: str = "localhost"
db_port: int = 5432
db_name: str = "hesabix"
sqlalchemy_echo: bool = False
# DB Pooling — هر worker Uvicorn pool مستقل دارد.
# فرمول: (postgres_max_connections - overhead) / uvicorn_workers ≈ اتصال per worker
# با max_connections=300 و 24 worker → ~12 اتصال per worker (8+4)
# برای بار بالاتر از PgBouncer (transaction pooling) استفاده شود.
uvicorn_workers: int = 24
db_pool_size: int = 8
db_max_overflow: int = 4
db_pool_timeout: int = 30 # Timeout برای Pool (30 ثانیه)
db_pool_recycle: int = 1800 # Recycle اتصالات هر 30 دقیقه - بهینه برای جلوگیری از connection leak و بهبود performance
# Logging — پیش‌فرض پروداکشن: حداقل خروجی (از env با نام LOG_LEVEL هم خوانده می‌شود)
log_level: str = Field(
default="WARNING",
description="DEBUG | INFO | WARNING | ERROR | CRITICAL — برای دیباگ موقت LOG_LEVEL=DEBUG و ری‌استارت",
)
# Captcha / Security
captcha_length: int = 5
captcha_ttl_seconds: int = 180
captcha_secret: str = "change_me_captcha"
reset_password_ttl_seconds: int = 3600
# کلیدهای امنیتی اختصاصی (در production اجباری؛ در dev به captcha_secret برمی‌گردند)
api_key_pepper: str | None = None
otp_pepper: str | None = None
encryption_key: str | None = None
# Phone normalization
# Used as default region when parsing phone numbers without a country code
default_phone_region: str = "IR"
# لینک‌های وب (مثلاً ساخت /login?reset_token=... برای ادمین و قالب اعلان)
# اگر خالی باشد، در endpoint بازنشانی از header Origin (درخواست مرورگر) استفاده می‌شود
app_public_url: str = ""
# CORS — پذیرش هر Origin (API باز برای کلاینت‌های وب/موبایل/ابزارها)
# نکته: با allow_origins=["*"] در Starlette باید allow_credentials=False بماند (در app/main.py).
cors_allowed_origins: list[str] = ["*"]
# Telegram Bot
telegram_bot_token: str | None = None
telegram_bot_username: str | None = None # optional, used to build deep-links
telegram_webhook_secret: str | None = None
telegram_secret_header: str | None = None # optional header to validate Telegram webhook
telegram_proxy_enabled: bool | None = None
telegram_proxy_base_url: str | None = None
telegram_proxy_api_key: str | None = None
# Bale messenger (optional)
bale_bot_token: str | None = None
bale_bot_username: str | None = None # for deep-link to bot
bale_webhook_secret: str | None = None
# SMS (optional)
sms_provider_name: str | None = None # e.g., "twilio" or custom
sms_api_key: str | None = None
sms_sender: str | None = None
sms_provider_username: str | None = None # برای behinsms
sms_provider_password: str | None = None # برای behinsms
# سقف ارسال به هر شماره مقصد (مشترک بین همه worker؛ بدون Redis) — جلو ارسال از IPهای مختلف
sms_destination_rate_enabled: bool = True
sms_destination_rate_max_sends: int = 40 # حداکثر تعداد ارسال به همان شماره در پنجره
sms_destination_rate_window_minutes: int = 60 # طول پنجره (دقیقه)
# Share link / public card settings
share_link_code_length: int = 9
share_link_default_ttl_hours: int = 168 # 7 days
share_link_max_ttl_hours: int = 720 # 30 days
share_link_public_base_url: str = "https://app.hesabix.com/p"
share_link_secret: str = "change_me_share_link"
share_link_public_app_url: str = "https://app.hesabix.com/public"
wallet_webhook_secret: str | None = None
# Tax system (Moadian) integration
# پیش‌فرض روی حالت واقعی است؛ برای محیط‌های توسعه در env روی true ست شود
tax_system_force_simulation: bool = False
tax_system_timeout_seconds: int = 45
tax_system_sandbox_base_url: str = "https://sandboxrc.tax.gov.ir"
tax_system_production_base_url: str = "https://tp.tax.gov.ir"
tax_system_user_agent: str = "HesabixTaxClient/1.0"
tax_system_rate_limit_max_requests: int = 100 # حداکثر تعداد درخواست در window
tax_system_rate_limit_window_seconds: int = 3600 # بازه زمانی rate limit (ثانیه)
tax_system_inquire_max_workers: int = 5 # حداکثر تعداد thread برای parallel inquiries
tax_system_retry_max_attempts: int = 3 # حداکثر تعداد تلاش برای retry
tax_system_retry_initial_delay_seconds: float = 2.0 # تاخیر اولیه retry (ثانیه)
# Redis Cache
redis_enabled: bool = False
redis_host: str = "localhost"
redis_port: int = 6379
redis_db: int = 0
redis_password: str | None = None
# Softphone Media Edge
# api = workerهای عمومی (بدون media_hub زنده)
# media_edge = نود واحد Softphone (uvicorn --workers 1)
# auto = dev/تست تک‌process (اجازه عملیات media)
hesabix_process_role: str = "auto"
hesabix_media_edge_url: str = "http://127.0.0.1:8001"
hesabix_media_edge_token: str | None = None
# مانیتورینگ صف اعلان / پیامک (آستانه هشدار در پنل)
monitoring_outbox_due_retry_warn: int = 500
monitoring_outbox_sms_pending_warn: int = 50
# Pagination
max_page_size: int = 100 # حداکثر تعداد آیتم در هر صفحه
default_page_size: int = 20 # اندازه پیش‌فرض صفحه
# Query Timeout
query_timeout_seconds: int = 60 # Timeout برای query های طولانی (60 ثانیه)
# =========================
# Voice AI (STT/TTS/VAD)
# =========================
voice_enabled: bool = True
voice_sample_rate_hz: int = 16000
voice_frame_ms: int = 20
voice_vad_mode: int = 2
voice_vad_silence_ms: int = 650
voice_vad_min_speech_ms: int = 250
voice_vad_pre_roll_ms: int = 200
voice_vad_max_utterance_ms: int = 30_000
# STT (Whisper)
voice_stt_language: str = "fa"
voice_stt_model_size_or_path: str = "small"
voice_stt_device: str = "auto"
voice_stt_compute_type: str = "int8"
# TTS (متن‌باز)
# engine: "piper" | "coqui" (فقط Python<3.12) | "dummy"
voice_tts_engine: str = "dummy"
voice_tts_language: str = "fa"
voice_tts_model_name: str | None = None
voice_tts_model_path: str | None = None
# Piper (پیش‌فرض برای Python 3.12+)
voice_tts_piper_voice_fa: str = "fa_IR-ganji-medium"
voice_tts_piper_models_dir: str = "/var/lib/hesabix/voice-data/piper"
# Coqui (legacy؛ روی Python 3.12 در PyPI موجود نیست)
voice_tts_coqui_model_fa: str = "tts_models/fa/cv/vits/glow-tts"
voice_tts_output_sample_rate_hz: int = 16000
voice_tts_frame_ms: int = 20
# Data collection (اختیاری، برای بهبود کیفیت در آینده)
voice_data_collection_enabled: bool = False
voice_data_collection_dir: str = "/var/lib/hesabix/voice-data"
voice_max_concurrent_sessions_per_user: int = 2
voice_stt_max_seconds: int = 30
@property
def postgresql_dsn(self) -> str:
return (
f"postgresql+psycopg2://{self.db_user}:{quote_plus(self.db_password)}@{self.db_host}:{self.db_port}/{self.db_name}"
)
@lru_cache(maxsize=1)
def get_settings() -> Settings:
return Settings()