o2o-castad-backend/config.py

405 lines
16 KiB
Python

from pathlib import Path
from pydantic import Field
from pydantic_settings import BaseSettings, SettingsConfigDict
PROJECT_DIR = Path(__file__).resolve().parent
# 미디어 파일 저장 디렉토리
MEDIA_ROOT = PROJECT_DIR / "media"
MEDIA_ROOT.mkdir(exist_ok=True)
_base_config = SettingsConfigDict(
env_file=PROJECT_DIR / ".env",
env_ignore_empty=True,
extra="ignore",
)
class ProjectSettings(BaseSettings):
PROJECT_NAME: str = Field(default="CastAD")
PROJECT_DOMAIN: str = Field(default="localhost:8000")
VERSION: str = Field(default="0.1.0")
DESCRIPTION: str = Field(default="FastAPI 기반 CastAD 프로젝트")
ADMIN_BASE_URL: str = Field(default="/admin")
DEBUG: bool = Field(default=True)
model_config = _base_config
class APIKeySettings(BaseSettings):
CHATGPT_API_KEY: str = Field(default="your-chatgpt-api-key") # 기본값 추가
SUNO_API_KEY: str = Field(default="your-suno-api-key") # Suno API 키
SUNO_CALLBACK_URL: str = Field(
default="https://example.com/api/suno/callback"
) # Suno 콜백 URL (필수)
CREATOMATE_API_KEY: str = Field(default="your-creatomate-api-key") # Creatomate API 키
model_config = _base_config
class CORSSettings(BaseSettings):
# CORS (Cross-Origin Resource Sharing) 설정
# 요청을 허용할 출처(Origin) 목록
# ["*"]: 모든 출처 허용 (개발 환경용, 프로덕션에서는 구체적인 도메인 지정 권장)
# 예: ["https://example.com", "https://app.example.com"]
CORS_ALLOW_ORIGINS: list[str] = ["*"]
# 자격 증명(쿠키, Authorization 헤더 등) 포함 요청 허용 여부
# True: 클라이언트가 credentials: 'include'로 요청 시 쿠키/인증 정보 전송 가능
# 주의: CORS_ALLOW_ORIGINS가 ["*"]일 때는 보안상 False 권장
CORS_ALLOW_CREDENTIALS: bool = True
# 허용할 HTTP 메서드 목록
# ["*"]: 모든 메서드 허용 (GET, POST, PUT, DELETE, PATCH, OPTIONS 등)
# 구체적 지정 예: ["GET", "POST", "PUT", "DELETE"]
CORS_ALLOW_METHODS: list[str] = ["*"]
# 클라이언트가 요청 시 사용할 수 있는 HTTP 헤더 목록
# ["*"]: 모든 헤더 허용
# 구체적 지정 예: ["Content-Type", "Authorization", "X-Custom-Header"]
CORS_ALLOW_HEADERS: list[str] = ["*"]
# 브라우저의 JavaScript에서 접근 가능한 응답 헤더 목록
# []: 기본 안전 헤더(Cache-Control, Content-Language, Content-Type,
# Expires, Last-Modified, Pragma)만 접근 가능
# 추가 노출 필요 시: ["X-Total-Count", "X-Request-Id", "X-Custom-Header"]
CORS_EXPOSE_HEADERS: list[str] = []
# Preflight 요청(OPTIONS) 결과를 캐시하는 시간(초)
# 600: 10분간 캐시 (이 시간 동안 동일 요청에 대해 preflight 생략)
# 0으로 설정 시 매번 preflight 요청 발생
CORS_MAX_AGE: int = 600
model_config = _base_config
class DatabaseSettings(BaseSettings):
# MySQL 연결 설정 (기본값: 테스트 계정 및 poc DB)
MYSQL_HOST: str = Field(default="localhost")
MYSQL_PORT: int = Field(default=3306)
MYSQL_USER: str = Field(default="test")
MYSQL_PASSWORD: str = Field(default="") # 환경변수에서 로드
MYSQL_DB: str = Field(default="poc")
# Redis 설정
REDIS_HOST: str = "localhost"
REDIS_PORT: int = 6379
model_config = _base_config
@property
def MYSQL_URL(self) -> str:
"""비동기 MySQL URL 생성 (asyncmy 드라이버 사용, SQLAlchemy 통합 최적화)"""
return f"mysql+asyncmy://{self.MYSQL_USER}:{self.MYSQL_PASSWORD}@{self.MYSQL_HOST}:{self.MYSQL_PORT}/{self.MYSQL_DB}"
def REDIS_URL(self, db: int = 0) -> str:
"""Redis URL 생성 (db 인수로 기본값 지원)"""
return f"redis://{self.REDIS_HOST}:{self.REDIS_PORT}/{db}"
class CrawlerSettings(BaseSettings):
NAVER_COOKIES: str = Field(default="")
model_config = _base_config
class AzureBlobSettings(BaseSettings):
"""Azure Blob Storage 설정"""
AZURE_BLOB_SAS_TOKEN: str = Field(
default="",
description="Azure Blob Storage SAS 토큰",
)
AZURE_BLOB_BASE_URL: str = Field(
default="https://ado2mediastoragepublic.blob.core.windows.net/ado2-media-public-access/ado2-media-original",
description="Azure Blob Storage 기본 URL",
)
model_config = _base_config
class CreatomateSettings(BaseSettings):
"""Creatomate 템플릿 설정"""
# 세로형 템플릿 (기본값)
TEMPLATE_ID_VERTICAL: str = Field(
default="e8c7b43f-de4b-4ba3-b8eb-5df688569193",
description="Creatomate 세로형 템플릿 ID",
)
TEMPLATE_DURATION_VERTICAL: float = Field(
default=90.0,
description="세로형 템플릿 기본 duration (초)",
)
# 가로형 템플릿
TEMPLATE_ID_HORIZONTAL: str = Field(
default="0f092a6a-f526-4ef0-9181-d4ad4426b9e7",
description="Creatomate 가로형 템플릿 ID",
)
TEMPLATE_DURATION_HORIZONTAL: float = Field(
default=30.0,
description="가로형 템플릿 기본 duration (초)",
)
model_config = _base_config
class PromptSettings(BaseSettings):
PROMPT_FOLDER_ROOT : str = Field(default="./app/utils/prompts")
MARKETING_PROMPT_NAME : str = Field(default="marketing_prompt")
SUMMARIZE_PROMPT_NAME : str = Field(default="summarize_prompt")
LYLIC_PROMPT_NAME : str = Field(default="lyric_prompt")
model_config = _base_config
class RecoverySettings(BaseSettings):
"""ChatGPT API 복구 및 타임아웃 설정"""
CHATGPT_TIMEOUT: float = Field(
default=600.0,
description="ChatGPT API 타임아웃 (초). OpenAI Python SDK 기본값: 600초 (10분)",
)
CHATGPT_MAX_RETRIES: int = Field(
default=1,
description="ChatGPT API 응답 실패 시 최대 재시도 횟수",
)
model_config = _base_config
class KakaoSettings(BaseSettings):
"""카카오 OAuth 설정"""
KAKAO_CLIENT_ID: str = Field(default="", description="카카오 REST API 키")
KAKAO_CLIENT_SECRET: str = Field(default="", description="카카오 Client Secret (선택)")
KAKAO_REDIRECT_URI: str = Field(
default="http://localhost:8000/api/v1/user/auth/kakao/callback",
description="카카오 로그인 후 리다이렉트 URI",
)
model_config = _base_config
class JWTSettings(BaseSettings):
"""JWT 토큰 설정"""
JWT_SECRET: str = Field(
default="your-super-secret-key-must-be-at-least-32-characters-long",
description="JWT 서명 비밀키 (최소 32자)",
)
JWT_ALGORITHM: str = Field(default="HS256", description="JWT 알고리즘")
JWT_ACCESS_TOKEN_EXPIRE_MINUTES: int = Field(
default=60, description="액세스 토큰 만료 시간 (분)"
)
JWT_REFRESH_TOKEN_EXPIRE_DAYS: int = Field(
default=7, description="리프레시 토큰 만료 시간 (일)"
)
model_config = _base_config
class LogSettings(BaseSettings):
"""
로깅 설정 클래스
애플리케이션의 로깅 동작을 제어하는 설정들을 관리합니다.
모든 설정은 .env 파일 또는 환경변수로 오버라이드 가능합니다.
사용 예시 (.env 파일):
LOG_LEVEL=INFO
LOG_CONSOLE_LEVEL=WARNING
LOG_FILE_LEVEL=DEBUG
LOG_DIR=/var/log/myapp
"""
# ============================================================
# 로그 디렉토리 설정
# ============================================================
# 로그 파일이 저장될 디렉토리 경로입니다.
# - 기본값: 프로젝트 루트의 logs 폴더
# - 운영 환경에서는 /www/log/uvicorn 또는 /var/log/app 등으로 설정 권장
# - 디렉토리가 존재하지 않으면 자동으로 생성됩니다.
# - .env 파일에서 LOG_DIR 환경변수로 오버라이드 가능
LOG_DIR: str = Field(
default="logs",
description="로그 파일 저장 디렉토리 (절대 경로 또는 상대 경로)",
)
# ============================================================
# 로그 출력 대상 설정
# ============================================================
# 콘솔 출력 활성화 여부
# - True: 터미널/콘솔에 로그 출력
# - False: 콘솔 출력 비활성화 (파일에만 기록)
LOG_CONSOLE_ENABLED: bool = Field(
default=True,
description="콘솔 로그 출력 활성화 여부",
)
# 파일 출력 활성화 여부
# - True: 로그 파일에 기록 (app.log, error.log)
# - False: 파일 출력 비활성화 (콘솔에만 출력)
LOG_FILE_ENABLED: bool = Field(
default=True,
description="파일 로그 출력 활성화 여부",
)
# ============================================================
# 로그 레벨 설정
# ============================================================
# 로그 레벨 우선순위 (낮음 → 높음):
# DEBUG < INFO < WARNING < ERROR < CRITICAL
#
# 설정된 레벨 이상의 로그만 출력됩니다.
# 예: INFO로 설정 시 DEBUG는 무시되고, INFO, WARNING, ERROR, CRITICAL만 출력
# ============================================================
# 기본 로그 레벨
# - 로거 자체의 최소 로그 레벨을 설정합니다.
# - 이 레벨보다 낮은 로그는 핸들러(콘솔/파일)로 전달되지 않습니다.
# - 가능한 값: DEBUG, INFO, WARNING, ERROR, CRITICAL
# - DEBUG: 개발 시 상세 디버깅 정보 (변수 값, 흐름 추적 등)
# - INFO: 일반적인 작업 진행 상황 (요청 시작/완료 등)
# - WARNING: 잠재적 문제 또는 주의가 필요한 상황
# - ERROR: 오류 발생, 하지만 애플리케이션은 계속 실행
# - CRITICAL: 심각한 오류, 애플리케이션 중단 가능성
LOG_LEVEL: str = Field(
default="DEBUG",
description="기본 로그 레벨",
)
# 콘솔 출력 로그 레벨
# - 터미널/콘솔에 출력되는 로그의 최소 레벨을 설정합니다.
# - 개발 환경: DEBUG 권장 (모든 로그 확인)
# - 운영 환경: INFO 또는 WARNING 권장 (중요한 정보만 출력)
# - LOG_LEVEL보다 낮게 설정해도 LOG_LEVEL이 우선 적용됩니다.
LOG_CONSOLE_LEVEL: str = Field(
default="DEBUG",
description="콘솔 출력 로그 레벨",
)
# 파일 출력 로그 레벨
# - 로그 파일에 기록되는 로그의 최소 레벨을 설정합니다.
# - 파일에는 더 상세한 로그를 남기고 싶을 때 DEBUG로 설정
# - 파일 저장 위치: logs/{날짜}_{모듈명}.log
# - 에러 로그는 별도로 logs/{날짜}_error.log에도 기록됩니다.
LOG_FILE_LEVEL: str = Field(
default="DEBUG",
description="파일 출력 로그 레벨",
)
# ============================================================
# 로그 파일 관리 설정
# ============================================================
# 로그 파일 최대 크기 (MB)
# - 파일이 이 크기를 초과하면 자동으로 새 파일로 롤오버됩니다.
# - 기존 파일은 .1, .2 등의 접미사가 붙어 백업됩니다.
# - 예: 15MB 설정 시, 파일이 15MB를 넘으면 새 파일 생성
LOG_MAX_SIZE_MB: int = Field(
default=15,
description="로그 파일 최대 크기 (MB)",
)
# 로그 파일 백업 개수
# - 롤오버 시 보관할 백업 파일의 최대 개수입니다.
# - 이 개수를 초과하면 가장 오래된 백업 파일이 삭제됩니다.
# - 예: 30 설정 시, 최대 30개의 백업 파일 유지
# - 디스크 용량 관리를 위해 적절한 값 설정 권장
LOG_BACKUP_COUNT: int = Field(
default=30,
description="로그 파일 백업 개수",
)
# ============================================================
# 로그 포맷 설정
# ============================================================
# 사용 가능한 포맷 변수:
# {asctime} - 로그 발생 시간 (LOG_DATE_FORMAT 형식)
# {levelname} - 로그 레벨 (DEBUG, INFO 등)
# {name} - 로거 이름 (home, song 등)
# {filename} - 소스 파일명
# {funcName} - 함수명
# {lineno} - 라인 번호
# {message} - 로그 메시지
# {module} - 모듈명
# {pathname} - 파일 전체 경로
#
# 포맷 예시:
# "[{asctime}] {levelname} {message}"
# 출력: [2024-01-14 15:30:00] INFO 서버 시작
# ============================================================
# 콘솔 로그 포맷
# - 터미널에 출력되는 로그의 형식을 지정합니다.
# - [{levelname}]은 로그 레벨을 대괄호로 감싸서 출력합니다.
LOG_CONSOLE_FORMAT: str = Field(
default="[{asctime}] [{levelname}] [{name}:{funcName}:{lineno}] {message}",
description="콘솔 로그 포맷",
)
# 파일 로그 포맷
# - 파일에 기록되는 로그의 형식을 지정합니다.
# - 파일에는 더 상세한 정보(filename 등)를 포함할 수 있습니다.
LOG_FILE_FORMAT: str = Field(
default="[{asctime}] [{levelname}] [{filename}:{name} -> {funcName}():{lineno}] {message}",
description="파일 로그 포맷",
)
# 날짜 포맷
# - {asctime}에 표시되는 시간의 형식을 지정합니다.
# - Python strftime 형식을 따릅니다.
# - 예시:
# "%Y-%m-%d %H:%M:%S" -> 2024-01-14 15:30:00
# "%Y/%m/%d %H:%M:%S.%f" -> 2024/01/14 15:30:00.123456
# "%d-%b-%Y %H:%M:%S" -> 14-Jan-2024 15:30:00
LOG_DATE_FORMAT: str = Field(
default="%Y-%m-%d %H:%M:%S",
description="로그 날짜 포맷",
)
model_config = _base_config
def get_log_dir(self) -> Path:
"""
로그 디렉토리 경로를 반환합니다.
우선순위:
1. .env의 LOG_DIR 설정값 (절대 경로인 경우)
2. /www/log/uvicorn 폴더가 존재하면 사용 (운영 서버)
3. 프로젝트 루트의 logs 폴더 (개발 환경 기본값)
Returns:
Path: 로그 디렉토리 경로 (존재하지 않으면 자동 생성)
"""
# 1. .env에서 설정한 경로가 절대 경로인 경우 우선 사용
log_dir_path = Path(self.LOG_DIR)
if log_dir_path.is_absolute():
log_dir_path.mkdir(parents=True, exist_ok=True)
return log_dir_path
# 2. 운영 서버 경로 확인 (/www/log/uvicorn)
production_log_dir = Path("/www/log/uvicorn")
if production_log_dir.exists():
return production_log_dir
# 3. 기본값: 프로젝트 루트의 logs 폴더
default_log_dir = PROJECT_DIR / self.LOG_DIR
default_log_dir.mkdir(parents=True, exist_ok=True)
return default_log_dir
prj_settings = ProjectSettings()
apikey_settings = APIKeySettings()
db_settings = DatabaseSettings()
cors_settings = CORSSettings()
crawler_settings = CrawlerSettings()
azure_blob_settings = AzureBlobSettings()
creatomate_settings = CreatomateSettings()
prompt_settings = PromptSettings()
log_settings = LogSettings()
kakao_settings = KakaoSettings()
jwt_settings = JWTSettings()
recovery_settings = RecoverySettings()