""" 관련자료 데이터 모델 """ from typing import Optional, List, Dict, Any from datetime import datetime from pydantic import BaseModel, Field from uuid import UUID class DocumentMetadata(BaseModel): """문서 메타데이터""" folder: Optional[str] = Field(None, description="폴더명") business_domain: Optional[str] = Field(None, description="업무 도메인") additional_fields: Optional[Dict[str, Any]] = Field(None, description="추가 필드") class Document(BaseModel): """문서 모델""" document_id: str = Field(..., description="문서 ID") document_type: str = Field(..., description="문서 타입 (meeting_minutes, org_document 등)") business_domain: Optional[str] = Field(None, description="업무 도메인") title: str = Field(..., description="문서 제목") content: str = Field(..., description="문서 전체 내용") summary: str = Field(..., description="문서 요약 (3-5 문장)") keywords: List[str] = Field(default_factory=list, description="키워드 목록") created_date: Optional[str] = Field(None, description="생성일시") participants: List[str] = Field(default_factory=list, description="참석자 목록 (회의록의 경우)") metadata: Optional[DocumentMetadata] = Field(None, description="메타데이터") embedding: Optional[List[float]] = Field(None, description="임베딩 벡터 (1536차원)") class Config: json_schema_extra = { "example": { "document_id": "고객-MM-001", "document_type": "meeting_minutes", "business_domain": "고객서비스", "title": "상담 품질 향상 워크샵 1차", "content": "회의 일시: 2025-10-02...", "summary": "고객 만족도 지표 검토와 VOC 트렌드 분석을 논의...", "keywords": ["CSAT", "고객응대", "챗봇"], "participants": ["김민준", "이미준"] } } class DocumentChunk(BaseModel): """문서 청크 (Azure AI Search 인덱싱용)""" id: str = Field(..., description="청크 ID (document_id_chunk_N)") document_id: str = Field(..., description="원본 문서 ID") document_type: str = Field(..., description="문서 타입") title: str = Field(..., description="문서 제목") folder: Optional[str] = Field(None, description="폴더명") created_date: Optional[str] = Field(None, description="생성일시") participants: List[str] = Field(default_factory=list, description="참석자 목록") keywords: List[str] = Field(default_factory=list, description="키워드 목록") agenda_id: Optional[str] = Field(None, description="안건 ID (회의록의 경우)") agenda_title: Optional[str] = Field(None, description="안건 제목") chunk_index: int = Field(..., description="청크 인덱스") content: str = Field(..., description="청크 내용") content_vector: List[float] = Field(..., description="내용 임베딩 벡터") token_count: int = Field(..., description="토큰 수") class DocumentSearchRequest(BaseModel): """문서 검색 요청""" query: str = Field(..., min_length=1, description="검색 쿼리") top_k: int = Field(3, ge=1, le=10, description="반환할 최대 결과 수") relevance_threshold: float = Field(0.70, ge=0.0, le=1.0, description="최소 관련도 임계값") folder: Optional[str] = Field(None, description="폴더 필터 (같은 폴더 우선)") document_type: Optional[str] = Field(None, description="문서 타입 필터") business_domain: Optional[str] = Field(None, description="업무 도메인 필터") semantic_ranking: bool = Field(True, description="Semantic Ranking 사용 여부") class Config: json_schema_extra = { "example": { "query": "고객 만족도 개선 방안", "top_k": 3, "relevance_threshold": 0.70, "folder": "고객서비스팀", "semantic_ranking": True } } class DocumentSearchResult(BaseModel): """문서 검색 결과""" document_id: str title: str document_type: str created_date: Optional[str] relevance_score: float = Field(..., ge=0.0, le=1.0) relevance_level: str = Field(..., description="HIGH (>90%), MEDIUM (70-90%), LOW (<70%)") content_excerpt: str = Field(..., description="관련 내용 발췌") folder: Optional[str] = None class RelatedMeetingRequest(BaseModel): """관련 회의록 검색 요청""" meeting_id: str = Field(..., description="현재 회의 ID") top_k: int = Field(3, ge=1, le=5, description="반환할 최대 결과 수") relevance_threshold: float = Field(0.70, ge=0.0, le=1.0, description="최소 관련도 임계값") class RelatedMeeting(BaseModel): """관련 회의록""" meeting_id: str title: str meeting_date: Optional[str] relevance_score: float = Field(..., ge=0.0, le=1.0) relevance_level: str = Field(..., description="HIGH, MEDIUM, LOW") similar_content_summary: Optional[str] = Field(None, description="유사 내용 요약 (3문장)") url: str = Field(..., description="회의록 URL") class DocumentSummarizeRequest(BaseModel): """문서 요약 요청""" document_id: str = Field(..., description="문서 ID") current_meeting_id: Optional[str] = Field(None, description="현재 회의 ID (비교용)") summary_type: str = Field("similar_content", description="요약 타입 (similar_content, full)") class DocumentSummary(BaseModel): """문서 요약""" document_id: str summary: str = Field(..., description="요약 내용") generated_by: str = Field("claude-3-5-sonnet", description="생성 모델") tokens_used: int = Field(..., description="사용된 토큰 수") cached: bool = Field(False, description="캐시 여부") class DocumentStats(BaseModel): """문서 통계""" total_documents: int = Field(..., description="전체 문서 수") by_type: Dict[str, int] = Field(..., description="타입별 문서 수") by_domain: Dict[str, int] = Field(..., description="도메인별 문서 수") total_chunks: int = Field(..., description="전체 청크 수")