@startuml !theme mono title AI Service 내부 시퀀스 - 관련회의록연결 participant "RelationController" as Controller participant "RelationService" as Service participant "VectorService" as Vector participant "LLMClient" as LLM participant "RelationRepository" as Repo database "Azure OpenAI<>" as OpenAI database "Vector DB<>" as VectorDB database "PostgreSQL<>" as DB == 회의록 생성 완료 이벤트 수신 == note over Controller 내부 이벤트 또는 TranscriptFinalized 이벤트 수신 (meetingId, transcriptId) end note Controller -> Service: findRelatedTranscripts(meetingId, transcriptId) activate Service == 현재 회의록 정보 조회 == Service -> Repo: getTranscriptInfo(transcriptId) activate Repo Repo -> DB: 회의록 정보 조회 activate DB DB --> Repo: 회의록 정보 deactivate DB Repo --> Service: transcriptContent, meetingInfo deactivate Repo == 주제 및 키워드 추출 == Service -> Service: 키워드 추출 프롬프트 생성 note right 프롬프트: - 주요 주제 추출 (3-5개) - 핵심 키워드 추출 (10-15개) - 카테고리 분류 end note Service -> LLM: extractTopicsAndKeywords(transcriptContent) activate LLM LLM -> OpenAI: POST /chat/completions activate OpenAI note right 요청: - model: gpt-4o - temperature: 0.2 - response_format: json_object 응답 형식: { "topics": ["주제1", "주제2", "주제3"], "keywords": ["키워드1", "키워드2", ...], "category": "카테고리" } end note OpenAI --> LLM: 주제 및 키워드 deactivate OpenAI LLM --> Service: topics, keywords, category deactivate LLM == 벡터 임베딩 생성 == Service -> Service: 검색 쿼리 구성 note right 쿼리 텍스트: - 주요 주제 - 핵심 키워드 - 회의 요약 결합하여 검색용 텍스트 생성 end note Service -> Vector: generateQueryEmbedding(queryText) activate Vector Vector -> OpenAI: POST /embeddings activate OpenAI note right model: text-embedding-3-large input: {queryText} end note OpenAI --> Vector: 쿼리 임베딩 벡터 deactivate OpenAI Vector --> Service: queryEmbedding deactivate Vector == 벡터 유사도 검색 == Service -> Vector: searchSimilarTranscripts(queryEmbedding, meetingId, limit=20) activate Vector Vector -> VectorDB: 벡터 유사도 검색 activate VectorDB note right 검색 조건: - 코사인 유사도 기준 - 동일 폴더(프로젝트) 내 - 현재 회의록 제외 - 상위 20개 후보 조회 WHERE metadata.project_id = {projectId} AND vector_id != {currentTranscriptId} ORDER BY cosine_similarity DESC LIMIT 20 end note VectorDB --> Vector: 유사 회의록 목록 (벡터 유사도 점수 포함) deactivate VectorDB Vector --> Service: similarTranscripts (top 20) deactivate Vector == 관련도 점수 계산 및 필터링 == Service -> Service: 다중 기준으로 관련도 점수 재계산 note right 점수 계산 기준: 1. 벡터 유사도 (40%) - 코사인 유사도 점수 2. 키워드 일치도 (30%) - 공통 키워드 개수 - 가중치: 중요 키워드 우선 3. 참석자 중복도 (20%) - 동일 참석자 비율 4. 시간적 연관성 (10%) - 최근 회의 우선 - 분기별/월별 회의 패턴 최종 점수 = 가중 평균 end note loop 각 후보 회의록마다 Service -> Repo: getTranscriptDetails(candidateId) activate Repo Repo -> DB: 회의록 상세 정보 조회 activate DB DB --> Repo: 상세 정보 deactivate DB Repo --> Service: 참석자, 키워드, 날짜 deactivate Repo Service -> Service: 관련도 점수 계산 note right 관련도 = 벡터유사도 * 0.4 + 키워드일치도 * 0.3 + 참석자중복도 * 0.2 + 시간연관성 * 0.1 end note end Service -> Service: 필터링 및 정렬 note right 필터링 기준: - 관련도 70% 이상만 선택 - 관련도 점수순 정렬 - 상위 5개 선택 end note == 관련 회의록 저장 == loop 선택된 상위 5개 Service -> Repo: saveRelatedTranscript(transcriptId, relatedId, score, keywords) activate Repo Repo -> DB: 관련 회의록 연결 저장 activate DB note right 저장 데이터: - transcript_id - related_transcript_id - relevance_score - common_keywords (JSON) - created_at end note DB --> Repo: 저장 완료 deactivate DB Repo --> Service: 완료 deactivate Repo end == 응답 데이터 구성 == Service -> Service: 관련 회의록 정보 구성 note right 각 관련 회의록별 정보: - 제목 - 날짜 - 참석자 - 관련도 점수 (%) - 연관 키워드 - 링크 end note Service --> Controller: 관련 회의록 목록 (top 5) deactivate Service Controller -> Controller: 회의록 상단에 "관련 회의록" 섹션 추가 준비 note over Controller, DB 처리 시간: - 회의록 조회: 100-200ms - LLM 주제 추출: 2-3초 - 벡터 임베딩: 500ms-1초 - 벡터 검색: 500ms-1초 - 관련도 계산: 1-2초 (20개) - 저장 처리: 200-300ms 총 처리 시간: 약 5-8초 정책: - 관련도 70% 이상만 자동 연결 - 최대 5개까지 표시 - 동일 폴더(프로젝트) 내에서만 검색 end note @enduml