feat : initial commit
This commit is contained in:
@@ -0,0 +1,4 @@
|
||||
# app/utils/__init__.py
|
||||
"""
|
||||
HealthSync Motivator Batch 유틸리티 패키지
|
||||
"""
|
||||
@@ -0,0 +1,72 @@
|
||||
# app/utils/claude_client.py
|
||||
"""
|
||||
HealthSync Motivator Batch Claude API 클라이언트
|
||||
"""
|
||||
import logging
|
||||
import asyncio
|
||||
import anthropic
|
||||
from app.config.settings import settings
|
||||
|
||||
logger = logging.getLogger(__name__)
|
||||
|
||||
class ClaudeClient:
|
||||
"""Claude API 호출 클라이언트"""
|
||||
|
||||
def __init__(self):
|
||||
self.api_key = settings.claude_api_key
|
||||
|
||||
# API 키 검증
|
||||
if not self.api_key or self.api_key == "" or self.api_key == "your_claude_api_key_here":
|
||||
raise ValueError("Claude API 키가 설정되지 않았습니다. .env 파일에 CLAUDE_API_KEY를 설정해주세요.")
|
||||
|
||||
# 동기 클라이언트 초기화
|
||||
self.client = anthropic.Anthropic(api_key=self.api_key)
|
||||
logger.info(f"✅ Claude API 클라이언트 초기화 완료")
|
||||
|
||||
async def call_claude_api(self, prompt: str) -> str:
|
||||
"""Claude API 호출 (비동기 래퍼)"""
|
||||
try:
|
||||
logger.info(f"🚀 Claude API 호출 시작 (모델: {settings.claude_model})")
|
||||
|
||||
# 동기 함수를 비동기로 실행
|
||||
def sync_call():
|
||||
return self.client.messages.create(
|
||||
model=settings.claude_model,
|
||||
max_tokens=settings.claude_max_tokens,
|
||||
temperature=settings.claude_temperature,
|
||||
messages=[
|
||||
{
|
||||
"role": "user",
|
||||
"content": prompt
|
||||
}
|
||||
]
|
||||
)
|
||||
|
||||
# 스레드 풀에서 동기 함수 실행
|
||||
message = await asyncio.get_event_loop().run_in_executor(None, sync_call)
|
||||
|
||||
logger.info("✅ Claude API 호출 성공")
|
||||
return message.content[0].text
|
||||
|
||||
except anthropic.AuthenticationError as e:
|
||||
logger.error("❌ Claude API 인증 실패 - API 키 확인 필요")
|
||||
raise Exception(f"Claude API 인증 실패: {str(e)}")
|
||||
|
||||
except anthropic.NotFoundError as e:
|
||||
logger.error("❌ Claude API 엔드포인트 또는 모델을 찾을 수 없음")
|
||||
raise Exception(f"Claude API 모델 또는 엔드포인트 오류: {str(e)}")
|
||||
|
||||
except anthropic.RateLimitError as e:
|
||||
logger.error("❌ Claude API 요청 한도 초과")
|
||||
raise Exception(f"Claude API 요청 한도 초과: {str(e)}")
|
||||
|
||||
except anthropic.APITimeoutError as e:
|
||||
logger.error("⏰ Claude API 타임아웃")
|
||||
raise Exception(f"Claude API 타임아웃: {str(e)}")
|
||||
|
||||
except Exception as e:
|
||||
logger.error(f"❌ Claude API 호출 중 예상치 못한 오류: {str(e)}")
|
||||
raise Exception(f"Claude API 호출 실패: {str(e)}")
|
||||
|
||||
# 전역 클라이언트 인스턴스
|
||||
claude_client = ClaudeClient()
|
||||
@@ -0,0 +1,86 @@
|
||||
# app/utils/database_utils.py
|
||||
"""
|
||||
HealthSync Motivator Batch 데이터베이스 유틸리티
|
||||
"""
|
||||
import databases
|
||||
import logging
|
||||
from typing import Dict, Any, List, Optional
|
||||
from app.config.settings import settings
|
||||
from app.repositories.queries import BaseQueries
|
||||
|
||||
logger = logging.getLogger(__name__)
|
||||
|
||||
|
||||
class SimpleDatabase:
|
||||
"""PostgreSQL 데이터베이스 연결 클래스"""
|
||||
|
||||
def __init__(self):
|
||||
self.database = databases.Database(settings.database_url)
|
||||
self._connected = False
|
||||
|
||||
async def connect(self):
|
||||
"""데이터베이스 연결"""
|
||||
if not self._connected:
|
||||
try:
|
||||
await self.database.connect()
|
||||
self._connected = True
|
||||
logger.info("데이터베이스 연결 성공")
|
||||
except Exception as e:
|
||||
logger.error(f"데이터베이스 연결 실패: {str(e)}")
|
||||
raise
|
||||
|
||||
async def disconnect(self):
|
||||
"""데이터베이스 연결 해제"""
|
||||
if self._connected:
|
||||
try:
|
||||
await self.database.disconnect()
|
||||
self._connected = False
|
||||
logger.info("데이터베이스 연결 해제")
|
||||
except Exception as e:
|
||||
logger.error(f"데이터베이스 연결 해제 실패: {str(e)}")
|
||||
|
||||
async def test_connection(self) -> bool:
|
||||
"""데이터베이스 연결 테스트"""
|
||||
try:
|
||||
if not self._connected:
|
||||
await self.connect()
|
||||
|
||||
result = await self.database.fetch_val(BaseQueries.CONNECTION_TEST)
|
||||
return result == 1
|
||||
except Exception as e:
|
||||
logger.error(f"데이터베이스 연결 테스트 실패: {str(e)}")
|
||||
return False
|
||||
|
||||
async def execute_query(self, query: str, values: Optional[Dict[str, Any]] = None) -> List[Dict[str, Any]]:
|
||||
"""쿼리 실행 (SELECT)"""
|
||||
try:
|
||||
if not self._connected:
|
||||
await self.connect()
|
||||
|
||||
rows = await self.database.fetch_all(query, values or {})
|
||||
return [dict(row) for row in rows]
|
||||
|
||||
except Exception as e:
|
||||
logger.error(f"쿼리 실행 실패: {str(e)}")
|
||||
logger.error(f"쿼리: {query}")
|
||||
logger.error(f"파라미터: {values}")
|
||||
raise Exception(f"쿼리 실행 실패: {str(e)}")
|
||||
|
||||
async def execute_insert(self, query: str, values: Optional[Dict[str, Any]] = None) -> int:
|
||||
"""INSERT 쿼리 실행"""
|
||||
try:
|
||||
if not self._connected:
|
||||
await self.connect()
|
||||
|
||||
result = await self.database.execute(query, values or {})
|
||||
return result
|
||||
|
||||
except Exception as e:
|
||||
logger.error(f"INSERT 실행 실패: {str(e)}")
|
||||
logger.error(f"쿼리: {query}")
|
||||
logger.error(f"파라미터: {values}")
|
||||
raise Exception(f"INSERT 실행 실패: {str(e)}")
|
||||
|
||||
|
||||
# 전역 데이터베이스 인스턴스
|
||||
db = SimpleDatabase()
|
||||
@@ -0,0 +1,37 @@
|
||||
# app/utils/logger.py
|
||||
"""
|
||||
HealthSync Motivator Batch 로깅 설정
|
||||
"""
|
||||
import logging
|
||||
import sys
|
||||
from datetime import datetime
|
||||
from app.config.settings import settings
|
||||
|
||||
|
||||
def setup_logger(name: str = "motivator_batch") -> logging.Logger:
|
||||
"""로거 설정"""
|
||||
logger = logging.getLogger(name)
|
||||
|
||||
# 이미 핸들러가 있으면 중복 추가 방지
|
||||
if logger.handlers:
|
||||
return logger
|
||||
|
||||
logger.setLevel(getattr(logging, settings.log_level.upper()))
|
||||
|
||||
# 콘솔 핸들러
|
||||
console_handler = logging.StreamHandler(sys.stdout)
|
||||
console_handler.setLevel(getattr(logging, settings.log_level.upper()))
|
||||
|
||||
# 포맷터
|
||||
formatter = logging.Formatter(
|
||||
'%(asctime)s - %(name)s - %(levelname)s - %(message)s',
|
||||
datefmt='%Y-%m-%d %H:%M:%S'
|
||||
)
|
||||
console_handler.setFormatter(formatter)
|
||||
|
||||
logger.addHandler(console_handler)
|
||||
return logger
|
||||
|
||||
|
||||
# 전역 로거
|
||||
batch_logger = setup_logger()
|
||||
Reference in New Issue
Block a user