hgzero/rag/src/models/document.py
2025-10-29 05:54:08 +09:00

138 lines
6.2 KiB
Python

"""
관련자료 데이터 모델
"""
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="전체 청크 수")