Files
Meeting_Assistant/backend/app/config.py
egg 58f379bc0c feat: Add embedded backend packaging for all-in-one deployment
- Add backend/run_server.py entry point for embedded deployment
- Add backend/build.py PyInstaller script for backend packaging
- Modify config.py to support frozen executable paths
- Extend client/config.json with backend configuration section
- Add backend sidecar management in Electron main process
- Add Whisper model download progress reporting
- Update build-client.bat with --embedded-backend flag
- Update DEPLOYMENT.md with all-in-one deployment documentation

This enables packaging frontend and backend into a single executable
for simplified enterprise deployment. Backward compatible with
existing separate deployment mode (backend.embedded: false).

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2025-12-17 10:06:29 +08:00

112 lines
4.1 KiB
Python

import os
import sys
from dotenv import load_dotenv
load_dotenv()
def get_base_dir() -> str:
"""Get base directory, supporting PyInstaller frozen executables."""
if getattr(sys, "frozen", False):
# Running as PyInstaller bundle
return os.path.dirname(sys.executable)
else:
# Running as script - go up two levels from app/config.py to backend/
return os.path.dirname(os.path.dirname(os.path.abspath(__file__)))
class Settings:
# Server Configuration
BACKEND_HOST: str = os.getenv("BACKEND_HOST", "0.0.0.0")
BACKEND_PORT: int = int(os.getenv("BACKEND_PORT", "8000"))
# Database Configuration
DB_HOST: str = os.getenv("DB_HOST", "mysql.theaken.com")
DB_PORT: int = int(os.getenv("DB_PORT", "33306"))
DB_USER: str = os.getenv("DB_USER", "A060")
DB_PASS: str = os.getenv("DB_PASS", "")
DB_NAME: str = os.getenv("DB_NAME", "db_A060")
DB_POOL_SIZE: int = int(os.getenv("DB_POOL_SIZE", "5"))
# External API Configuration
AUTH_API_URL: str = os.getenv(
"AUTH_API_URL", "https://pj-auth-api.vercel.app/api/auth/login"
)
DIFY_API_URL: str = os.getenv("DIFY_API_URL", "https://dify.theaken.com/v1")
DIFY_API_KEY: str = os.getenv("DIFY_API_KEY", "")
DIFY_STT_API_KEY: str = os.getenv("DIFY_STT_API_KEY", "")
# Authentication Configuration
ADMIN_EMAIL: str = os.getenv("ADMIN_EMAIL", "ymirliu@panjit.com.tw")
JWT_SECRET: str = os.getenv("JWT_SECRET", "meeting-assistant-secret")
JWT_EXPIRE_HOURS: int = int(os.getenv("JWT_EXPIRE_HOURS", "24"))
# Timeout Configuration (in milliseconds)
UPLOAD_TIMEOUT: int = int(os.getenv("UPLOAD_TIMEOUT", "600000")) # 10 minutes
DIFY_STT_TIMEOUT: int = int(os.getenv("DIFY_STT_TIMEOUT", "300000")) # 5 minutes
LLM_TIMEOUT: int = int(os.getenv("LLM_TIMEOUT", "120000")) # 2 minutes
AUTH_TIMEOUT: int = int(os.getenv("AUTH_TIMEOUT", "30000")) # 30 seconds
# File Configuration
TEMPLATE_DIR: str = os.getenv("TEMPLATE_DIR", "")
RECORD_DIR: str = os.getenv("RECORD_DIR", "")
MAX_FILE_SIZE: int = int(os.getenv("MAX_FILE_SIZE", str(500 * 1024 * 1024))) # 500MB
SUPPORTED_AUDIO_FORMATS: str = os.getenv(
"SUPPORTED_AUDIO_FORMATS", ".mp3,.wav,.m4a,.webm,.ogg,.flac,.aac"
)
@property
def supported_audio_formats_set(self) -> set:
"""Return supported audio formats as a set."""
return set(self.SUPPORTED_AUDIO_FORMATS.split(","))
def get_template_dir(self, base_dir: str | None = None) -> str:
"""Get template directory path, resolving relative paths.
Args:
base_dir: Base directory for relative paths. If None, uses get_base_dir()
which supports frozen executables.
"""
if base_dir is None:
base_dir = get_base_dir()
if self.TEMPLATE_DIR:
if os.path.isabs(self.TEMPLATE_DIR):
return self.TEMPLATE_DIR
return os.path.join(base_dir, self.TEMPLATE_DIR)
return os.path.join(base_dir, "template")
def get_record_dir(self, base_dir: str | None = None) -> str:
"""Get record directory path, resolving relative paths.
Args:
base_dir: Base directory for relative paths. If None, uses get_base_dir()
which supports frozen executables.
"""
if base_dir is None:
base_dir = get_base_dir()
if self.RECORD_DIR:
if os.path.isabs(self.RECORD_DIR):
return self.RECORD_DIR
return os.path.join(base_dir, self.RECORD_DIR)
return os.path.join(base_dir, "record")
# Timeout helpers (convert ms to seconds for httpx)
@property
def upload_timeout_seconds(self) -> float:
return self.UPLOAD_TIMEOUT / 1000.0
@property
def dify_stt_timeout_seconds(self) -> float:
return self.DIFY_STT_TIMEOUT / 1000.0
@property
def llm_timeout_seconds(self) -> float:
return self.LLM_TIMEOUT / 1000.0
@property
def auth_timeout_seconds(self) -> float:
return self.AUTH_TIMEOUT / 1000.0
settings = Settings()