Files
daily-news-app/app/core/config.py
donald db0f0bbfe7 Initial commit: Daily News App
企業內部新聞彙整與分析系統
- 自動新聞抓取 (Digitimes, 經濟日報, 工商時報)
- AI 智慧摘要 (OpenAI/Claude/Ollama)
- 群組管理與訂閱通知
- 已清理 Python 快取檔案

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

Co-Authored-By: Claude <noreply@anthropic.com>
2025-12-03 23:53:24 +08:00

138 lines
4.3 KiB
Python
Raw Blame History

This file contains ambiguous Unicode characters

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.

"""
應用程式設定模組
使用 Pydantic Settings 管理環境變數
"""
from functools import lru_cache
from typing import Literal
from pydantic import Field
from pydantic_settings import BaseSettings, SettingsConfigDict
class Settings(BaseSettings):
"""應用程式設定"""
model_config = SettingsConfigDict(
env_file=".env",
env_file_encoding="utf-8",
case_sensitive=False
)
# 應用程式
app_name: str = "每日報導APP"
app_env: Literal["development", "staging", "production"] = "development"
debug: bool = Field(
default=False, # 預設為 False更安全
description="除錯模式,僅開發環境使用"
)
secret_key: str = Field(
default="change-me-in-production",
description="應用程式密鑰,生產環境必須透過環境變數設定"
)
# 資料庫
db_host: str = "localhost"
db_port: int = 3306
db_name: str = "daily_news_app"
db_user: str = "root"
db_password: str = ""
@property
def database_url(self) -> str:
if self.db_host == "sqlite":
return f"sqlite:///{self.db_name}.db"
return f"mysql+pymysql://{self.db_user}:{self.db_password}@{self.db_host}:{self.db_port}/{self.db_name}?charset=utf8mb4"
@property
def async_database_url(self) -> str:
if self.db_host == "sqlite":
return f"sqlite+aiosqlite:///{self.db_name}.db"
return f"mysql+aiomysql://{self.db_user}:{self.db_password}@{self.db_host}:{self.db_port}/{self.db_name}?charset=utf8mb4"
# JWT
jwt_secret_key: str = Field(
default="change-me",
description="JWT 簽章密鑰,生產環境必須透過環境變數設定"
)
jwt_algorithm: str = "HS256"
jwt_access_token_expire_minutes: int = Field(
default=480, # 開發環境預設值
description="JWT Token 過期時間(分鐘),建議生產環境設為 60-120 分鐘"
)
# LDAP
ldap_server: str = ""
ldap_port: int = 389
ldap_base_dn: str = ""
ldap_bind_dn: str = ""
ldap_bind_password: str = ""
# LLM
llm_provider: Literal["gemini", "openai", "ollama"] = "gemini"
gemini_api_key: str = ""
gemini_model: str = "gemini-1.5-pro"
openai_api_key: str = ""
openai_model: str = "gpt-4o"
ollama_endpoint: str = "http://localhost:11434"
ollama_model: str = "llama3"
# SMTP
smtp_host: str = ""
smtp_port: int = 587
smtp_username: str = ""
smtp_password: str = ""
smtp_from_email: str = ""
smtp_from_name: str = "每日報導系統"
# 爬蟲
crawl_schedule_time: str = "08:00"
crawl_request_delay: int = 3
crawl_max_retries: int = 3
# Digitimes
digitimes_username: str = ""
digitimes_password: str = ""
# 資料保留
data_retention_days: int = 60
# PDF
pdf_logo_path: str = ""
pdf_header_text: str = ""
pdf_footer_text: str = "本報告僅供內部參考使用"
# CORS 設定
cors_origins: list[str] = Field(
default=["http://localhost:3000", "http://localhost:8000"],
description="允許的 CORS 來源列表,生產環境必須明確指定,不能使用 *"
)
# 管理員預設密碼
admin_password: str = Field(
default="admin123",
description="管理員預設密碼"
)
def validate_secrets():
"""驗證生產環境的密鑰設定"""
if settings.app_env == "production":
if settings.secret_key == "change-me-in-production":
raise ValueError("生產環境必須設定 SECRET_KEY 環境變數")
if settings.jwt_secret_key == "change-me":
raise ValueError("生產環境必須設定 JWT_SECRET_KEY 環境變數")
if len(settings.secret_key) < 32:
raise ValueError("SECRET_KEY 長度必須至少 32 字元")
if len(settings.jwt_secret_key) < 32:
raise ValueError("JWT_SECRET_KEY 長度必須至少 32 字元")
if settings.jwt_access_token_expire_minutes > 120:
import warnings
warnings.warn("生產環境 JWT Token 過期時間建議不超過 120 分鐘")
@lru_cache
def get_settings() -> Settings:
"""取得設定實例(快取)"""
return Settings()
settings = get_settings()