mirror of
https://github.com/hwanny1128/HGZero.git
synced 2025-12-06 07:56:24 +00:00
✅ 구현 완료 - AI Python Service (FastAPI, Claude API, 8087 포트) - POST /api/v1/transcripts/consolidate - 참석자별 회의록 → AI 통합 분석 - 키워드/안건별 요약/Todo 추출 - Meeting Service AI 통합 - EndMeetingService (@Primary) - AIServiceClient (RestTemplate, 30초 timeout) - AI 분석 결과 저장 (meeting_analysis, todos) - 회의 상태 COMPLETED 처리 - DTO 구조 (간소화) - ConsolidateRequest/Response - MeetingEndDTO - Todo 제목만 포함 (담당자/마감일 제거) 📝 기술스택 - Python: FastAPI, anthropic 0.71.0, psycopg2 - Java: Spring Boot, RestTemplate - Claude: claude-3-5-sonnet-20241022 🔧 주요 이슈 해결 - 포트 충돌: 8086(feature/stt-ai) → 8087(feat/meeting-ai) - Bean 충돌: @Primary 추가 - YAML 문법: ai.service.url 구조 수정 - anthropic 라이브러리 업그레이드 📚 테스트 가이드 및 스크립트 작성 - claude/MEETING-AI-TEST-GUIDE.md - test-meeting-ai.sh 🤖 Generated with Claude Code Co-Authored-By: Claude <noreply@anthropic.com>
91 lines
2.8 KiB
Python
91 lines
2.8 KiB
Python
"""Claude API Service"""
|
|
import anthropic
|
|
import json
|
|
import logging
|
|
from typing import Dict, Any
|
|
from app.config import get_settings
|
|
|
|
logger = logging.getLogger(__name__)
|
|
settings = get_settings()
|
|
|
|
|
|
class ClaudeService:
|
|
"""Claude API 호출 서비스"""
|
|
|
|
def __init__(self):
|
|
self.client = anthropic.Anthropic(api_key=settings.claude_api_key)
|
|
self.model = settings.claude_model
|
|
self.max_tokens = settings.claude_max_tokens
|
|
self.temperature = settings.claude_temperature
|
|
|
|
async def generate_completion(
|
|
self,
|
|
prompt: str,
|
|
system_prompt: str = None
|
|
) -> Dict[str, Any]:
|
|
"""
|
|
Claude API 호출하여 응답 생성
|
|
|
|
Args:
|
|
prompt: 사용자 프롬프트
|
|
system_prompt: 시스템 프롬프트 (선택)
|
|
|
|
Returns:
|
|
Claude API 응답 (JSON 파싱)
|
|
"""
|
|
try:
|
|
# 메시지 구성
|
|
messages = [
|
|
{
|
|
"role": "user",
|
|
"content": prompt
|
|
}
|
|
]
|
|
|
|
# API 호출
|
|
logger.info(f"Claude API 호출 시작 - Model: {self.model}")
|
|
|
|
if system_prompt:
|
|
response = self.client.messages.create(
|
|
model=self.model,
|
|
max_tokens=self.max_tokens,
|
|
temperature=self.temperature,
|
|
system=system_prompt,
|
|
messages=messages
|
|
)
|
|
else:
|
|
response = self.client.messages.create(
|
|
model=self.model,
|
|
max_tokens=self.max_tokens,
|
|
temperature=self.temperature,
|
|
messages=messages
|
|
)
|
|
|
|
# 응답 텍스트 추출
|
|
response_text = response.content[0].text
|
|
logger.info(f"Claude API 응답 수신 완료 - Tokens: {response.usage.input_tokens + response.usage.output_tokens}")
|
|
|
|
# JSON 파싱
|
|
# ```json ... ``` 블록 제거
|
|
if "```json" in response_text:
|
|
response_text = response_text.split("```json")[1].split("```")[0].strip()
|
|
elif "```" in response_text:
|
|
response_text = response_text.split("```")[1].split("```")[0].strip()
|
|
|
|
result = json.loads(response_text)
|
|
|
|
return result
|
|
|
|
except json.JSONDecodeError as e:
|
|
logger.error(f"JSON 파싱 실패: {e}")
|
|
logger.error(f"응답 텍스트: {response_text[:500]}...")
|
|
raise ValueError(f"Claude API 응답을 JSON으로 파싱할 수 없습니다: {str(e)}")
|
|
|
|
except Exception as e:
|
|
logger.error(f"Claude API 호출 실패: {e}")
|
|
raise
|
|
|
|
|
|
# 싱글톤 인스턴스
|
|
claude_service = ClaudeService()
|