@startuml !theme mono title AI Service 내부 시퀀스 - 실시간Todo추출 participant "SuggestionController" as Controller participant "RealtimeTodoService" as Service participant "LLMClient" as LLM participant "SuggestionRepository" as Repo participant "TranscriptRepository" as TranscriptRepo database "Azure OpenAI<>" as OpenAI database "PostgreSQL<>" as DB == 실시간 액션아이템 추출 요청 == note over Controller TranscriptService로부터 호출 또는 API 직접 호출: POST /api/ai/suggestions/action-item Body: { "meetingId": "{meetingId}", "transcriptText": "최근 대화 내용" } end note Controller -> Service: extractRealtimeActionItems(meetingId, transcriptText) activate Service == 회의 맥락 및 참석자 정보 조회 == Service -> TranscriptRepo: getMeetingContext(meetingId) activate TranscriptRepo TranscriptRepo -> DB: SELECT meeting_info, participants, roles\nFROM meeting_context activate DB DB --> TranscriptRepo: 회의 및 참석자 정보 deactivate DB TranscriptRepo --> Service: meetingContext deactivate TranscriptRepo Service -> Repo: getPreviousActionItems(meetingId) activate Repo Repo -> DB: SELECT content FROM ai_suggestions\nWHERE meeting_id = {meetingId}\nAND suggestion_type = 'ACTION_ITEM'\nAND status IN ('PENDING', 'APPLIED') activate DB DB --> Repo: 이미 추출된 액션아이템 deactivate DB Repo --> Service: previousActionItems deactivate Repo == LLM 기반 액션아이템 패턴 감지 == Service -> Service: 액션아이템 추출 프롬프트 생성 note right 시스템 프롬프트: - 역할: 액션아이템 추출 전문가 - 목표: 실시간으로 Todo 발생 감지 액션아이템 패턴 예시: - "제가 ~하겠습니다" - "~까지 완료하겠습니다" - "~을 담당하겠습니다" - "~을 해보겠습니다" - "~를 처리하겠습니다" - "[이름]님, ~해주시겠어요?" - "~하기로 했습니다" (결정 + 액션) 사용자 프롬프트: - 회의 참석자: {participants} - 이미 추출된 Todo: {previousActionItems} - 현재 대화 내용: {transcriptText} 지시사항: - 위 패턴이 포함된 문장 찾기 - Todo 내용 명확화 - 담당자 식별 (발언자 또는 지정된 사람) - 마감일 추출 (명시적 또는 추정) - 우선순위 판단 - 신뢰도 점수 계산 응답 형식: { "actionItems": [ { "content": "할 일 내용", "assignee": "담당자 이름", "dueDate": "YYYY-MM-DD" or null, "priority": "HIGH|MEDIUM|LOW", "confidence": 0.0-1.0, "extractedFrom": "원문 발췌", "relatedDecision": "관련 결정사항 ID" } ] } end note Service -> LLM: detectActionItemPatterns(prompt) activate LLM LLM -> OpenAI: POST /chat/completions activate OpenAI note right 요청 파라미터: - model: gpt-4o - temperature: 0.2 (정확한 추출 위해 낮은 값) - response_format: json_object - max_tokens: 1500 end note OpenAI -> OpenAI: 대화 텍스트 분석 note right 처리 단계: 1. 문장별로 액션아이템 패턴 검사 2. "하겠습니다" 등 키워드 탐지 3. 할 일 내용 추출 및 명확화 - 동사로 시작하도록 정리 - 구체적인 작업으로 변환 4. 담당자 식별 - 발언자 자신이 하는 경우 - 다른 사람을 지정한 경우 5. 마감일 추출 - 명시적: "내일까지", "이번 주 금요일" - 암묵적: "빨리", "다음 회의 전" - 없으면 null 6. 우선순위 판단 - HIGH: 긴급, 중요, 블로커 - MEDIUM: 중요하지만 여유 있음 - LOW: 추가 작업, 선택적 7. 신뢰도 계산 - 명확한 약속: 0.9-1.0 - 추정 약속: 0.7-0.9 - 암묵적 합의: 0.5-0.7 end note OpenAI --> LLM: 액션아이템 후보 목록 (JSON) deactivate OpenAI LLM --> Service: actionItemSuggestions deactivate LLM == 제안 검증 및 필터링 == Service -> Service: 액션아이템 검증 note right 검증 기준: - 신뢰도 70% 이상만 선택 - 중복 제거 * 이미 추출된 것과 비교 * 유사도 90% 이상이면 제외 - 담당자 검증 * 참석자 목록에 있는지 확인 * 없으면 "미지정"으로 표시 - 내용 명확성 검증 * 동사가 있는지 * 구체적인 작업인지 - 마감일 형식 검증 - 우선순위별 정렬 end note loop 각 제안마다 Service -> Service: 제안 메타데이터 보강 note right 추가 정보: - 생성 시각 - 회의 진행 시점 (분) - 원문 위치 (라인 번호) - 상태: PENDING - 관련 결정사항 참조 - 관련 논의 섹션 참조 end note end == 제안 저장 == loop 각 검증된 제안마다 Service -> Repo: saveSuggestion(meetingId, actionItem) activate Repo Repo -> DB: INSERT INTO ai_suggestions activate DB note right 저장 데이터: - meeting_id - suggestion_type: 'ACTION_ITEM' - content: 할 일 내용 - assignee: 담당자 - due_date: 마감일 - priority: HIGH/MEDIUM/LOW - confidence_score: 0.0-1.0 - extracted_from: 원문 - related_decision_id: 관련 결정 - status: PENDING - created_at end note DB --> Repo: suggestionId deactivate DB Repo --> Service: suggestionId deactivate Repo end == 응답 구성 == Service -> Service: 응답 데이터 구성 note right 프론트엔드 전달 형식: { "suggestions": [ { "id": "suggestion-uuid", "content": "할 일 내용", "assignee": "김철수", "dueDate": "2025-02-01", "priority": "HIGH", "confidence": 0.85, "extractedFrom": "원문 발췌", "relatedDecision": "decision-uuid", "canApply": true } ], "totalCount": 제안 개수, "displayHint": "오른쪽 탭 '액션아이템' 섹션" } end note Service --> Controller: 액션아이템 제안 생성 완료 deactivate Service Controller --> Controller: 200 OK 응답 반환 note right 프론트엔드 처리: - 오른쪽 "추천" 탭의 "액션아이템" 섹션 표시 - "적용" 버튼 활성화 - 담당자별로 그룹화 표시 - 우선순위별 색상 코딩 - 마감일 표시 (없으면 "미정") - 신뢰도 표시 (%) end note == 사용자가 제안 적용 시 == note over Controller 사용자가 "적용" 버튼 클릭 시: PUT /api/ai/suggestions/{suggestionId}/apply Body: { "assignee": "김철수" (수정 가능), "dueDate": "2025-02-01" (수정 가능) } end note Controller -> Service: applySuggestion(suggestionId, updateData) activate Service Service -> Repo: updateSuggestionStatus(suggestionId, "APPLIED") activate Repo Repo -> DB: UPDATE ai_suggestions\nSET status = 'APPLIED',\napplied_at = NOW(),\nassignee = {updateData.assignee},\ndue_date = {updateData.dueDate} activate DB DB --> Repo: 업데이트 완료 deactivate DB Repo --> Service: 완료 deactivate Repo Service -> Service: Meeting Service에 Todo 생성 요청 note right POST /meetings/{meetingId}/todos Body: { "content": "할 일 내용", "assignee": "담당자", "dueDate": "마감일", "priority": "우선순위", "relatedSection": "관련 회의록 섹션" } Meeting Service에서: - Todo 생성 - TodoCreated 이벤트 발행 - 담당자에게 알림 발송 end note Service --> Controller: 적용 완료 deactivate Service Controller --> Controller: 200 OK note over Controller, DB 처리 시간: - 맥락 조회: 100-200ms - LLM 패턴 감지: 1-2초 - 검증 및 필터링: 100-200ms - 저장 처리: 200-300ms 총 처리 시간: 약 2-3초 제안 정책: - 신뢰도 70% 이상만 제안 - 명확한 액션 표현 우선 - 중복 제거 (유사도 90% 기준) - 실시간으로 계속 감지 - 최대 20개까지 누적 표시 - 적용된 것은 회색 처리 차이점 (회의 종료 후 Todo 추출과): - 실시간: 5초마다 즉시 추출 - 종료 후: 전체 회의록 기반 종합 추출 - 실시간은 "후보"로 제시 - 종료 후는 "확정" 추출 후 자동 생성 end note @enduml