mirror of
https://github.com/hwanny1128/HGZero.git
synced 2025-12-06 10:16:24 +00:00
AI 제안사항 추출 기능 개선 및 API 경로 수정
- ClaudeService에 analyze_suggestions 메서드 추가 - 개선된 제안사항 추출 프롬프트 생성 (구체적이고 실행 가능한 제안사항) - API 경로 수정: /api/v1/ai/suggestions → /api/ai/suggestions - 프론트엔드 HTML API 경로 업데이트 (v1 제거) - RealtimeSuggestionsResponse 모델 export 추가 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
parent
5c32362278
commit
9c2d8dc9b2
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
@ -1,8 +1,10 @@
|
|||||||
"""API v1 Router"""
|
"""API v1 Router"""
|
||||||
from fastapi import APIRouter
|
from fastapi import APIRouter
|
||||||
from .transcripts import router as transcripts_router
|
from .transcripts import router as transcripts_router
|
||||||
|
from .suggestions import router as suggestions_router
|
||||||
|
|
||||||
router = APIRouter()
|
router = APIRouter()
|
||||||
|
|
||||||
# 라우터 등록
|
# 라우터 등록
|
||||||
router.include_router(transcripts_router, prefix="/transcripts", tags=["Transcripts"])
|
router.include_router(transcripts_router, prefix="/transcripts", tags=["Transcripts"])
|
||||||
|
router.include_router(suggestions_router, prefix="/ai/suggestions", tags=["AI Suggestions"])
|
||||||
|
|||||||
Binary file not shown.
Binary file not shown.
Binary file not shown.
@ -6,6 +6,10 @@ from .transcript import (
|
|||||||
ParticipantMinutes,
|
ParticipantMinutes,
|
||||||
ExtractedTodo
|
ExtractedTodo
|
||||||
)
|
)
|
||||||
|
from .response import (
|
||||||
|
SimpleSuggestion,
|
||||||
|
RealtimeSuggestionsResponse
|
||||||
|
)
|
||||||
|
|
||||||
__all__ = [
|
__all__ = [
|
||||||
"ConsolidateRequest",
|
"ConsolidateRequest",
|
||||||
@ -13,4 +17,6 @@ __all__ = [
|
|||||||
"AgendaSummary",
|
"AgendaSummary",
|
||||||
"ParticipantMinutes",
|
"ParticipantMinutes",
|
||||||
"ExtractedTodo",
|
"ExtractedTodo",
|
||||||
|
"SimpleSuggestion",
|
||||||
|
"RealtimeSuggestionsResponse",
|
||||||
]
|
]
|
||||||
|
|||||||
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
72
ai-python/app/prompts/suggestions_prompt.py
Normal file
72
ai-python/app/prompts/suggestions_prompt.py
Normal file
@ -0,0 +1,72 @@
|
|||||||
|
"""AI 제안사항 추출 프롬프트"""
|
||||||
|
|
||||||
|
|
||||||
|
def get_suggestions_prompt(transcript_text: str) -> tuple[str, str]:
|
||||||
|
"""
|
||||||
|
회의 텍스트에서 AI 제안사항을 추출하는 프롬프트 생성
|
||||||
|
|
||||||
|
Returns:
|
||||||
|
(system_prompt, user_prompt) 튜플
|
||||||
|
"""
|
||||||
|
|
||||||
|
system_prompt = """당신은 회의 내용 분석 전문가입니다.
|
||||||
|
회의 텍스트를 분석하여 실행 가능한 제안사항을 추출해주세요."""
|
||||||
|
|
||||||
|
user_prompt = f"""다음 회의 내용을 분석하여 **구체적이고 실행 가능한 제안사항**을 추출해주세요.
|
||||||
|
|
||||||
|
# 회의 내용
|
||||||
|
{transcript_text}
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
# 제안사항 추출 기준
|
||||||
|
1. **실행 가능성**: 바로 실행할 수 있는 구체적인 액션 아이템
|
||||||
|
2. **명확성**: 누가, 무엇을, 언제까지 해야 하는지 명확한 내용
|
||||||
|
3. **중요도**: 회의 목표 달성에 중요한 사항
|
||||||
|
4. **완결성**: 하나의 제안사항이 독립적으로 완결된 내용
|
||||||
|
|
||||||
|
# 제안사항 유형 예시
|
||||||
|
- **후속 작업**: "시장 조사 보고서를 다음 주까지 작성하여 공유"
|
||||||
|
- **의사결정 필요**: "예산안 3안 중 최종안을 이번 주 금요일까지 결정"
|
||||||
|
- **리스크 대응**: "법률 검토를 위해 법무팀과 사전 협의 필요"
|
||||||
|
- **일정 조율**: "다음 회의를 3월 15일로 확정하고 참석자에게 공지"
|
||||||
|
- **자료 준비**: "경쟁사 분석 자료를 회의 전까지 준비"
|
||||||
|
- **검토 요청**: "초안에 대한 팀원들의 피드백 수집 필요"
|
||||||
|
- **승인 필요**: "최종 기획안을 경영진에게 보고하여 승인 받기"
|
||||||
|
|
||||||
|
# 제안사항 작성 가이드
|
||||||
|
- **구체적으로**: "검토 필요" (X) → "법무팀과 계약서 조항 검토 미팅 잡기" (O)
|
||||||
|
- **명확하게**: "나중에 하기" (X) → "다음 주 화요일까지 완료" (O)
|
||||||
|
- **실행 가능하게**: "잘 되길 바람" (X) → "주간 진행상황 공유 미팅 설정" (O)
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
# 출력 형식
|
||||||
|
반드시 아래 JSON 형식으로만 응답하세요:
|
||||||
|
|
||||||
|
```json
|
||||||
|
{{
|
||||||
|
"suggestions": [
|
||||||
|
{{
|
||||||
|
"content": "제안사항 내용 (구체적이고 실행 가능하게, 50자 이상 작성)",
|
||||||
|
"confidence": 0.85 (이 제안사항의 중요도/확실성, 0.7-1.0 사이)
|
||||||
|
}},
|
||||||
|
{{
|
||||||
|
"content": "또 다른 제안사항",
|
||||||
|
"confidence": 0.92
|
||||||
|
}}
|
||||||
|
]
|
||||||
|
}}
|
||||||
|
```
|
||||||
|
|
||||||
|
# 중요 규칙
|
||||||
|
1. **회의 내용에 명시된 사항만** 추출 (추측하지 않기)
|
||||||
|
2. **최소 3개, 최대 7개**의 제안사항 추출
|
||||||
|
3. 중요도가 높은 순서로 정렬
|
||||||
|
4. confidence는 **0.7 이상**만 포함
|
||||||
|
5. 각 제안사항은 **50자 이상** 구체적으로 작성
|
||||||
|
6. JSON만 출력 (```json이나 다른 텍스트 포함 금지)
|
||||||
|
|
||||||
|
이제 위 회의 내용에서 제안사항을 JSON 형식으로 추출해주세요."""
|
||||||
|
|
||||||
|
return system_prompt, user_prompt
|
||||||
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
@ -85,6 +85,55 @@ class ClaudeService:
|
|||||||
logger.error(f"Claude API 호출 실패: {e}")
|
logger.error(f"Claude API 호출 실패: {e}")
|
||||||
raise
|
raise
|
||||||
|
|
||||||
|
async def analyze_suggestions(self, transcript_text: str):
|
||||||
|
"""
|
||||||
|
회의 텍스트에서 AI 제안사항 추출
|
||||||
|
|
||||||
|
Args:
|
||||||
|
transcript_text: 회의 텍스트
|
||||||
|
|
||||||
|
Returns:
|
||||||
|
RealtimeSuggestionsResponse 객체
|
||||||
|
"""
|
||||||
|
from app.models import RealtimeSuggestionsResponse, SimpleSuggestion
|
||||||
|
from app.prompts.suggestions_prompt import get_suggestions_prompt
|
||||||
|
from datetime import datetime
|
||||||
|
import uuid
|
||||||
|
|
||||||
|
try:
|
||||||
|
# 프롬프트 생성
|
||||||
|
system_prompt, user_prompt = get_suggestions_prompt(transcript_text)
|
||||||
|
|
||||||
|
# Claude API 호출
|
||||||
|
result = await self.generate_completion(
|
||||||
|
prompt=user_prompt,
|
||||||
|
system_prompt=system_prompt
|
||||||
|
)
|
||||||
|
|
||||||
|
# 응답 파싱
|
||||||
|
suggestions_data = result.get("suggestions", [])
|
||||||
|
|
||||||
|
# SimpleSuggestion 객체로 변환
|
||||||
|
suggestions = [
|
||||||
|
SimpleSuggestion(
|
||||||
|
id=str(uuid.uuid4()),
|
||||||
|
content=s["content"],
|
||||||
|
timestamp=datetime.now().strftime("%H:%M:%S"),
|
||||||
|
confidence=s.get("confidence", 0.85)
|
||||||
|
)
|
||||||
|
for s in suggestions_data
|
||||||
|
if s.get("confidence", 0) >= 0.7 # 신뢰도 0.7 이상만
|
||||||
|
]
|
||||||
|
|
||||||
|
logger.info(f"AI 제안사항 {len(suggestions)}개 추출 완료")
|
||||||
|
|
||||||
|
return RealtimeSuggestionsResponse(suggestions=suggestions)
|
||||||
|
|
||||||
|
except Exception as e:
|
||||||
|
logger.error(f"제안사항 분석 실패: {e}", exc_info=True)
|
||||||
|
# 빈 응답 반환
|
||||||
|
return RealtimeSuggestionsResponse(suggestions=[])
|
||||||
|
|
||||||
|
|
||||||
# 싱글톤 인스턴스
|
# 싱글톤 인스턴스
|
||||||
claude_service = ClaudeService()
|
claude_service = ClaudeService()
|
||||||
|
|||||||
@ -179,7 +179,7 @@
|
|||||||
<div class="info-box">
|
<div class="info-box">
|
||||||
<h3>📋 테스트 정보</h3>
|
<h3>📋 테스트 정보</h3>
|
||||||
<p><strong>STT Service:</strong> <code>ws://localhost:8084/ws/audio</code></p>
|
<p><strong>STT Service:</strong> <code>ws://localhost:8084/ws/audio</code></p>
|
||||||
<p><strong>AI Service:</strong> <code>http://localhost:8086/api/v1/ai/suggestions</code></p>
|
<p><strong>AI Service:</strong> <code>http://localhost:8086/api/ai/suggestions</code></p>
|
||||||
<p><strong>Meeting ID:</strong> <code id="meetingId">test-meeting-001</code></p>
|
<p><strong>Meeting ID:</strong> <code id="meetingId">test-meeting-001</code></p>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
@ -345,7 +345,7 @@
|
|||||||
|
|
||||||
// AI SSE 연결
|
// AI SSE 연결
|
||||||
function connectAIEventSource() {
|
function connectAIEventSource() {
|
||||||
const sseUrl = `http://localhost:8086/api/v1/ai/suggestions/meetings/${meetingId}/stream`;
|
const sseUrl = `http://localhost:8086/api/ai/suggestions/meetings/${meetingId}/stream`;
|
||||||
addLog('AI SSE 연결 시도...', 'info');
|
addLog('AI SSE 연결 시도...', 'info');
|
||||||
|
|
||||||
aiEventSource = new EventSource(sseUrl);
|
aiEventSource = new EventSource(sseUrl);
|
||||||
|
|||||||
@ -467,7 +467,7 @@
|
|||||||
|
|
||||||
// AI 제안사항 SSE 연결
|
// AI 제안사항 SSE 연결
|
||||||
function connectAISuggestions() {
|
function connectAISuggestions() {
|
||||||
const sseUrl = `${aiServiceUrl}/api/v1/ai/suggestions/meetings/${meetingId}/stream`;
|
const sseUrl = `${aiServiceUrl}/api/ai/suggestions/meetings/${meetingId}/stream`;
|
||||||
addLog('AI 제안사항 SSE 연결 시도: ' + sseUrl, 'info');
|
addLog('AI 제안사항 SSE 연결 시도: ' + sseUrl, 'info');
|
||||||
|
|
||||||
eventSource = new EventSource(sseUrl);
|
eventSource = new EventSource(sseUrl);
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user