HealthSync_Motivator/app/services/motivation_service.py
2025-06-20 05:51:38 +00:00

165 lines
6.8 KiB
Python

# app/services/motivation_service.py
"""
HealthSync Motivator Batch 독려 메시지 생성 서비스
"""
import asyncio
from typing import Dict, Any, List
from datetime import datetime
from app.utils.database_utils import db
from app.utils.claude_client import claude_client
from app.utils.logger import batch_logger
from app.config.prompts import get_encouragement_prompt
from app.repositories.queries import UserQueries, GoalQueries, ChatQueries
from app.models.chat_message import MessageType
class MotivationService:
"""독려 메시지 생성 비즈니스 로직 서비스"""
def __init__(self):
self.logger = batch_logger
async def process_all_users(self) -> Dict[str, int]:
"""모든 활성 사용자에 대해 독려 메시지 처리"""
try:
self.logger.info("🚀 독려 메시지 배치 처리 시작")
# 1. 활성 사용자 목록 조회
active_users = await db.execute_query(UserQueries.GET_ACTIVE_USERS)
self.logger.info(f"📊 활성 사용자 수: {len(active_users)}")
# 처리 결과 카운터
results = {
"total_users": len(active_users),
"processed_users": 0,
"sent_messages": 0,
"skipped_users": 0,
"failed_users": 0
}
# 2. 각 사용자별 독려 메시지 처리
for user in active_users:
try:
user_id = user["member_serial_number"]
self.logger.info(f"👤 사용자 처리 시작: {user['name']} (ID: {user_id})")
# 사용자별 독려 메시지 처리
message_sent = await self._process_user_encouragement(user)
results["processed_users"] += 1
if message_sent:
results["sent_messages"] += 1
else:
results["skipped_users"] += 1
except Exception as e:
self.logger.error(f"❌ 사용자 처리 실패 - user_id: {user.get('member_serial_number')}, error: {str(e)}")
results["failed_users"] += 1
self.logger.info(f"✅ 독려 메시지 배치 처리 완료: {results}")
return results
except Exception as e:
self.logger.error(f"❌ 배치 처리 전체 실패: {str(e)}")
raise Exception(f"배치 처리 실패: {str(e)}")
async def _process_user_encouragement(self, user: Dict[str, Any]) -> bool:
"""개별 사용자 독려 메시지 처리"""
try:
user_id = user["member_serial_number"]
user_name = user["name"]
occupation = user.get("occupation", "정보 없음")
# # 1. 오늘 이미 독려 메시지를 받았는지 확인
# today_encouragement = await db.execute_query(
# ChatQueries.CHECK_TODAY_ENCOURAGEMENT,
# {"user_id": user_id}
# )
#
# if today_encouragement and today_encouragement[0]["count"] > 0:
# self.logger.info(f"⏭️ 이미 독려 메시지 발송됨 - user: {user_name}")
# return False
# 2. 미완료 미션 조회
incomplete_missions = await db.execute_query(
GoalQueries.GET_INCOMPLETE_MISSIONS,
{"user_id": user_id}
)
if not incomplete_missions:
self.logger.info(f"✅ 미완료 미션 없음 - user: {user_name}")
return False
# 3. 독려 메시지 생성
encouragement_message = await self._generate_encouragement_message(
occupation, incomplete_missions
)
# 4. 채팅 DB에 저장
await self._save_encouragement_message(user_id, encouragement_message)
self.logger.info(f"💌 독려 메시지 발송 완료 - user: {user_name}, "
f"미완료 미션: {len(incomplete_missions)}")
return True
except Exception as e:
self.logger.error(f"❌ 사용자 독려 메시지 처리 실패 - user_id: {user_id}, error: {str(e)}")
raise Exception(f"사용자 독려 메시지 처리 실패: {str(e)}")
async def _generate_encouragement_message(self, occupation: str, incomplete_missions: List[Dict[str, Any]]) -> str:
"""Claude API를 통한 독려 메시지 생성"""
try:
# 미완료 미션 목록 문자열 생성
mission_list = []
for mission in incomplete_missions:
mission_list.append(f"- {mission['mission_name']} (목표: {mission['daily_target_count']}회)")
missions_text = "\n".join(mission_list)
# 프롬프트 생성
prompt_template = get_encouragement_prompt()
formatted_prompt = prompt_template.format(
occupation=occupation,
incomplete_missions=missions_text
)
# Claude API 호출
claude_response = await claude_client.call_claude_api(formatted_prompt)
# 응답 정제 (앞뒤 공백 제거, 따옴표 제거)
encouragement_message = claude_response.strip().strip('"').strip("'")
self.logger.info(f"💭 독려 메시지 생성 완료 - 길이: {len(encouragement_message)}")
return encouragement_message
except Exception as e:
self.logger.error(f"❌ 독려 메시지 생성 실패: {str(e)}")
raise Exception(f"독려 메시지 생성 실패: {str(e)}")
async def _save_encouragement_message(self, user_id: int, message: str) -> None:
"""독려 메시지를 채팅 DB에 저장 (수정된 메서드)"""
try:
# ChatMessage 모델에 맞춰 데이터 구성
message_data = {
"member_serial_number": user_id,
"message_type": MessageType.ENCOURAGEMENT.value, # "encouragement"
"message_content": None, # 사용자 입력이 없으므로 None
"response_content": message, # AI가 생성한 독려 메시지
"created_at": datetime.now()
}
await db.execute_insert(
ChatQueries.INSERT_ENCOURAGEMENT_MESSAGE,
message_data
)
self.logger.info(f"💾 독려 메시지 DB 저장 완료 - user_id: {user_id}, "
f"message_type: {MessageType.ENCOURAGEMENT.value}")
except Exception as e:
self.logger.error(f"❌ 독려 메시지 DB 저장 실패 - user_id: {user_id}, error: {str(e)}")
raise Exception(f"독려 메시지 DB 저장 실패: {str(e)}")
# 전역 서비스 인스턴스
motivation_service = MotivationService()