feat : initial commit

This commit is contained in:
2025-06-20 05:51:38 +00:00
commit 00eae37abc
26 changed files with 924 additions and 0 deletions
+4
View File
@@ -0,0 +1,4 @@
# app/utils/__init__.py
"""
HealthSync Motivator Batch 유틸리티 패키지
"""
+72
View File
@@ -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()
+86
View File
@@ -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()
+37
View File
@@ -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()