VOC_Monitor/app/models/statistics.py

115 lines
4.6 KiB
Python

"""
VOC 통계 분석 데이터 모델
통계 보고서 생성 및 분석 옵션을 정의하는 Pydantic 모델입니다.
데이터 유효성 검증, 기간 제한, 날짜 형식 검증 등을 수행합니다.
주요 모델:
- StatisticsReport: 통계 보고서 데이터
- StatisticsOptions: 분석 옵션
작성자: KH.Choi
최종 수정: 2026-02-18
버전: 1.1 (Pydantic v2 호환성 수정)
"""
import re
from datetime import datetime, timedelta
from typing import Optional, List, Dict, Any
from pydantic import BaseModel, Field, field_validator, model_validator
class StatisticsReport(BaseModel):
"""
VOC 통계 분석 보고서 데이터 모델
통계 분석 결과를 담는 데이터 모델입니다.
기간별, 부서별, 상태별 통계와 키워드 분석 결과를 포함합니다.
"""
period_start: str = Field(..., description="분석 기간 시작일 (YYYY-MM-DD)")
period_end: str = Field(..., description="분석 기간 종료일 (YYYY-MM-DD)")
total_count: int = Field(0, description="총 VOC 건수", ge=0)
by_department: Dict[str, int] = Field(default_factory=dict, description="부서별 통계")
by_status: Dict[str, int] = Field(default_factory=dict, description="상태별 통계")
by_date: Dict[str, int] = Field(default_factory=dict, description="날짜별 통계")
top_keywords: List[tuple] = Field(default_factory=list, description="빈출 키워드 TOP 10")
charts: Dict[str, str] = Field(default_factory=dict, description="차트 이미지 경로")
generated_at: Optional[str] = Field(None, description="보고서 생성 시각")
@field_validator('period_start', 'period_end')
@classmethod
def validate_date_format(cls, v):
"""날짜 형식 검증 (YYYY-MM-DD)"""
pattern = r'^\d{4}-\d{2}-\d{2}$'
if not re.match(pattern, v):
raise ValueError(f"유효하지 않은 날짜 형식: {v} (YYYY-MM-DD 필요)")
try:
datetime.strptime(v, "%Y-%m-%d")
except ValueError as e:
raise ValueError(f"유효하지 않은 날짜: {v}")
return v
@model_validator(mode='after')
def validate_period(self):
"""기간 유효성 검증"""
start = self.period_start
end = self.period_end
if start and end:
start_date = datetime.strptime(start, "%Y-%m-%d")
end_date = datetime.strptime(end, "%Y-%m-%d")
if start_date > end_date:
raise ValueError("시작일이 종료일보다 늦을 수 없습니다.")
if (end_date - start_date).days > 365:
raise ValueError("분석 기간은 최대 1년까지만 가능합니다.")
return self
class StatisticsOptions(BaseModel):
"""
통계 분석 옵션 모델
"""
period_start: str = Field(..., description="분석 기간 시작일 (YYYY-MM-DD)")
period_end: str = Field(..., description="분석 기간 종료일 (YYYY-MM-DD)")
include_department: bool = Field(True, description="부서별 통계 포함 여부")
include_status: bool = Field(True, description="상태별 통계 포함 여부")
include_keywords: bool = Field(True, description="키워드 분석 포함 여부")
include_charts: bool = Field(True, description="차트 생성 여부")
output_format: str = Field("excel", pattern="^(excel|pdf|both)$", description="출력 형식")
output_path: Optional[str] = Field(None, description="저장 경로")
@field_validator('period_start', 'period_end')
@classmethod
def validate_date_format(cls, v):
"""날짜 형식 검증 (YYYY-MM-DD)"""
pattern = r'^\d{4}-\d{2}-\d{2}$'
if not re.match(pattern, v):
raise ValueError(f"유효하지 않은 날짜 형식: {v} (YYYY-MM-DD 필요)")
try:
datetime.strptime(v, "%Y-%m-%d")
except ValueError as e:
raise ValueError(f"유효하지 않은 날짜: {v}")
return v
@model_validator(mode='after')
def validate_period(self):
"""기간 유효성 검증"""
start = self.period_start
end = self.period_end
if start and end:
start_date = datetime.strptime(start, "%Y-%m-%d")
end_date = datetime.strptime(end, "%Y-%m-%d")
if start_date > end_date:
raise ValueError("시작일이 종료일보다 늦을 수 없습니다.")
if (end_date - start_date).days > 365:
raise ValueError("분석 기간은 최대 1년까지만 가능합니다.")
return self