feat : initial commit
HealthSync Intelligence CI / build-and-push (push) Has been cancelled

This commit is contained in:
hyerimmy
2025-06-20 05:28:30 +00:00
commit 910bd902b1
72 changed files with 6758 additions and 0 deletions
View File
+36
View File
@@ -0,0 +1,36 @@
"""
HealthSync AI 기본 데이터 모델
"""
from pydantic import BaseModel, Field
from datetime import datetime
from typing import Optional, Generic, TypeVar, List
from enum import Enum
# Generic 타입 정의
T = TypeVar('T')
class BaseResponse(BaseModel, Generic[T]):
"""기본 응답 모델"""
success: bool = Field(default=True, description="요청 성공 여부")
message: str = Field(default="", description="응답 메시지")
data: Optional[T] = Field(default=None, description="응답 데이터")
timestamp: datetime = Field(default_factory=datetime.now, description="응답 시간")
class Config:
json_encoders = {
datetime: lambda v: v.isoformat()
}
class ErrorResponse(BaseModel):
"""에러 응답 모델"""
success: bool = Field(default=False, description="요청 성공 여부")
error_code: str = Field(..., description="에러 코드")
message: str = Field(..., description="에러 메시지")
details: Optional[dict] = Field(default=None, description="에러 상세 정보")
timestamp: datetime = Field(default_factory=datetime.now, description="에러 발생 시간")
class Config:
json_encoders = {
datetime: lambda v: v.isoformat()
}
+28
View File
@@ -0,0 +1,28 @@
# app/models/chat_message.py
"""
HealthSync AI 채팅 메시지 모델
"""
from pydantic import BaseModel, Field
from datetime import datetime
from typing import Optional
from enum import Enum
class MessageType(str, Enum):
"""메시지 타입"""
CONSULTATION = "consultation" # 상담
CELEBRATION = "celebration" # 축하
ENCOURAGEMENT = "encouragement" # 독려
class ChatMessage(BaseModel):
"""채팅 메시지 모델"""
message_id: Optional[int] = Field(None, description="메시지 ID")
member_serial_number: int = Field(..., description="회원 일련번호")
message_type: str = Field(..., max_length=20, description="메시지 타입")
message_content: Optional[str] = Field(None, description="메시지 내용")
response_content: Optional[str] = Field(None, description="AI 응답 내용")
created_at: datetime = Field(default_factory=datetime.now, description="생성일시")
class Config:
json_encoders = {
datetime: lambda v: v.isoformat()
}
+56
View File
@@ -0,0 +1,56 @@
"""
HealthSync AI 공통 모델 (Common Service)
"""
from pydantic import BaseModel, Field
from datetime import datetime
from typing import Optional, Dict, Any, List
from enum import Enum
class EventType(str, Enum):
"""이벤트 타입"""
USER_REGISTERED = "user_registered"
HEALTH_DATA_SYNCED = "health_data_synced"
GOAL_SETUP = "goal_setup"
MISSION_COMPLETED = "mission_completed"
AI_ANALYSIS_COMPLETED = "ai_analysis_completed"
NOTIFICATION_SENT = "notification_sent"
class EventStore(BaseModel):
"""이벤트 저장소"""
event_id: int = Field(..., description="이벤트 ID")
aggregate_id: str = Field(..., max_length=36, description="집계 ID")
event_type: str = Field(..., max_length=100, description="이벤트 타입")
event_data: Optional[str] = Field(None, description="이벤트 데이터")
member_serial_number: Optional[int] = Field(None, description="회원 일련번호")
service_name: Optional[str] = Field(None, max_length=50, description="서비스명")
created_at: datetime = Field(default_factory=datetime.now, description="생성일시")
class SystemConfig(BaseModel):
"""시스템 설정"""
config_id: int = Field(..., description="설정 ID")
config_key: str = Field(..., max_length=200, description="설정 키")
config_value: Optional[str] = Field(None, description="설정 값")
description: Optional[str] = Field(None, max_length=500, description="설명")
created_at: datetime = Field(default_factory=datetime.now, description="생성일시")
class APIResponse(BaseModel):
"""표준 API 응답"""
success: bool = Field(True, description="성공 여부")
message: str = Field(..., description="응답 메시지")
data: Optional[Dict[str, Any]] = Field(None, description="응답 데이터")
timestamp: datetime = Field(default_factory=datetime.now, description="응답 시각")
class Config:
json_encoders = {
datetime: lambda v: v.isoformat()
}
class PaginatedResponse(BaseModel):
"""페이지네이션 응답"""
items: List[Any] = Field(..., description="아이템 목록")
total: int = Field(..., description="전체 수")
page: int = Field(..., description="현재 페이지")
size: int = Field(..., description="페이지 크기")
pages: int = Field(..., description="전체 페이지 수")
has_next: bool = Field(..., description="다음 페이지 존재 여부")
has_prev: bool = Field(..., description="이전 페이지 존재 여부")
+113
View File
@@ -0,0 +1,113 @@
"""
HealthSync AI 목표 관리 관련 모델 (Goal Service)
"""
from pydantic import BaseModel, Field
from datetime import datetime, date
from typing import Optional, List, Dict, Any
from enum import Enum
class MissionStatus(str, Enum):
"""미션 상태"""
ACTIVE = "active"
COMPLETED = "completed"
PAUSED = "paused"
CANCELLED = "cancelled"
class GoalType(str, Enum):
"""목표 타입"""
DAILY = "daily"
WEEKLY = "weekly"
MONTHLY = "monthly"
class DifficultyLevel(str, Enum):
"""난이도 레벨"""
BEGINNER = "beginner"
INTERMEDIATE = "intermediate"
ADVANCED = "advanced"
class MissionCategory(str, Enum):
"""미션 카테고리"""
EXERCISE = "exercise"
NUTRITION = "nutrition"
MENTAL_HEALTH = "mental_health"
HYDRATION = "hydration"
SLEEP = "sleep"
STRESS_MANAGEMENT = "stress_management"
class UserMissionGoal(BaseModel):
"""사용자 미션 목표"""
mission_id: int = Field(..., description="미션 ID")
member_serial_number: int = Field(..., description="회원 일련번호")
performance_date: date = Field(..., description="수행 날짜")
mission_name: str = Field(..., max_length=100, description="미션명")
mission_description: Optional[str] = Field(None, max_length=200, description="미션 설명")
daily_target_count: int = Field(..., description="일일 목표 횟수")
is_active: bool = Field(True, description="활성 상태")
created_at: datetime = Field(default_factory=datetime.now, description="생성일시")
class MissionCompletionHistory(BaseModel):
"""미션 완료 이력"""
completion_id: int = Field(..., description="완료 ID")
mission_id: int = Field(..., description="미션 ID")
member_serial_number: int = Field(..., description="회원 일련번호")
completion_date: date = Field(..., description="완료 날짜")
daily_target_count: int = Field(..., description="일일 목표 횟수")
daily_completed_count: int = Field(..., description="일일 완료 횟수")
created_at: datetime = Field(default_factory=datetime.now, description="생성일시")
class MissionSelectionRequest(BaseModel):
"""미션 선택 요청"""
user_id: int = Field(..., description="사용자 ID")
selected_mission_ids: List[str] = Field(..., description="선택된 미션 ID 목록")
class GoalSetupResponse(BaseModel):
"""목표 설정 응답"""
goal_id: str = Field(..., description="목표 ID")
selected_missions: List[Dict[str, Any]] = Field(..., description="선택된 미션 목록")
message: str = Field(..., description="응답 메시지")
setup_completed_at: datetime = Field(..., description="설정 완료 일시")
class ActiveMissionsResponse(BaseModel):
"""활성 미션 응답"""
daily_missions: List[Dict[str, Any]] = Field(..., description="일일 미션 목록")
total_missions: int = Field(..., description="전체 미션 수")
today_completed_count: int = Field(..., description="오늘 완료 수")
completion_rate: float = Field(..., description="완료율")
class MissionCompleteRequest(BaseModel):
"""미션 완료 요청"""
user_id: int = Field(..., description="사용자 ID")
completed: bool = Field(..., description="완료 여부")
completed_at: datetime = Field(..., description="완료 일시")
notes: Optional[str] = Field(None, description="메모")
class MissionCompleteResponse(BaseModel):
"""미션 완료 응답"""
message: str = Field(..., description="응답 메시지")
status: str = Field(..., description="상태")
achievement_message: str = Field(..., description="성취 메시지")
new_streak_days: int = Field(..., description="새로운 연속 달성 일수")
total_completed_count: int = Field(..., description="전체 완료 수")
earned_points: int = Field(..., description="획득 포인트")
class MissionHistoryResponse(BaseModel):
"""미션 이력 응답"""
total_achievement_rate: float = Field(..., description="전체 달성률")
period_achievement_rate: float = Field(..., description="기간 달성률")
best_streak: int = Field(..., description="최고 연속 달성")
mission_stats: List[Dict[str, Any]] = Field(..., description="미션별 통계")
chart_data: Optional[Dict[str, Any]] = Field(None, description="차트 데이터")
period: Dict[str, str] = Field(..., description="조회 기간")
insights: List[str] = Field(..., description="인사이트")
class MissionResetRequest(BaseModel):
"""미션 재설정 요청"""
user_id: int = Field(..., description="사용자 ID")
reason: str = Field(..., description="재설정 사유")
current_mission_ids: List[str] = Field(..., description="현재 미션 ID 목록")
class MissionResetResponse(BaseModel):
"""미션 재설정 응답"""
message: str = Field(..., description="응답 메시지")
new_recommendations: List[Dict[str, Any]] = Field(..., description="새로운 추천 미션")
reset_completed_at: datetime = Field(..., description="재설정 완료 일시")
+134
View File
@@ -0,0 +1,134 @@
"""
HealthSync AI 건강 관련 모델 (Health Service)
"""
from pydantic import BaseModel, Field
from datetime import datetime, date
from typing import Optional, List, Dict, Any
from enum import Enum
from decimal import Decimal
class RiskLevel(str, Enum):
"""위험도 레벨"""
LOW = "low"
MEDIUM = "medium"
HIGH = "high"
CRITICAL = "critical"
class RangeStatus(str, Enum):
"""정상치 범위 상태"""
NORMAL = "normal"
WARNING = "warning"
DANGER = "danger"
class UploadStatus(str, Enum):
"""업로드 상태"""
PENDING = "pending"
SUCCESS = "success"
FAILED = "failed"
class HealthCheckupRaw(BaseModel):
"""건강검진 원천 데이터"""
raw_id: int = Field(..., description="원본 ID")
reference_year: int = Field(..., description="기준 년도")
birth_date: date = Field(..., description="생년월일")
name: str = Field(..., max_length=50, description="이름")
region_code: Optional[int] = Field(None, description="지역 코드")
gender_code: Optional[int] = Field(None, description="성별 코드")
age: Optional[int] = Field(None, description="나이")
height: Optional[int] = Field(None, description="신장(cm)")
weight: Optional[int] = Field(None, description="체중(kg)")
waist_circumference: Optional[int] = Field(None, description="허리둘레(cm)")
visual_acuity_left: Optional[Decimal] = Field(None, description="좌측 시력")
visual_acuity_right: Optional[Decimal] = Field(None, description="우측 시력")
hearing_left: Optional[int] = Field(None, description="좌측 청력")
hearing_right: Optional[int] = Field(None, description="우측 청력")
systolic_bp: Optional[int] = Field(None, description="수축기 혈압")
diastolic_bp: Optional[int] = Field(None, description="이완기 혈압")
fasting_glucose: Optional[int] = Field(None, description="공복혈당")
total_cholesterol: Optional[int] = Field(None, description="총 콜레스테롤")
triglyceride: Optional[int] = Field(None, description="중성지방")
hdl_cholesterol: Optional[int] = Field(None, description="HDL 콜레스테롤")
ldl_cholesterol: Optional[int] = Field(None, description="LDL 콜레스테롤")
hemoglobin: Optional[Decimal] = Field(None, description="혈색소")
urine_protein: Optional[int] = Field(None, description="요단백")
serum_creatinine: Optional[Decimal] = Field(None, description="혈청크레아티닌")
ast: Optional[int] = Field(None, description="AST")
alt: Optional[int] = Field(None, description="ALT")
gamma_gtp: Optional[int] = Field(None, description="감마지티피")
smoking_status: Optional[int] = Field(None, description="흡연 상태")
drinking_status: Optional[int] = Field(None, description="음주 상태")
created_at: datetime = Field(default_factory=datetime.now, description="생성일시")
class HealthCheckup(BaseModel):
"""처리된 건강검진 데이터"""
checkup_id: int = Field(..., description="건강검진 ID")
member_serial_number: int = Field(..., description="회원 일련번호")
raw_id: int = Field(..., description="원본 데이터 ID")
reference_year: int = Field(..., description="기준 년도")
age: Optional[int] = Field(None, description="나이")
height: Optional[int] = Field(None, description="신장(cm)")
weight: Optional[int] = Field(None, description="체중(kg)")
bmi: Optional[Decimal] = Field(None, description="BMI")
waist_circumference: Optional[int] = Field(None, description="허리둘레(cm)")
visual_acuity_left: Optional[Decimal] = Field(None, description="좌측 시력")
visual_acuity_right: Optional[Decimal] = Field(None, description="우측 시력")
hearing_left: Optional[int] = Field(None, description="좌측 청력")
hearing_right: Optional[int] = Field(None, description="우측 청력")
systolic_bp: Optional[int] = Field(None, description="수축기 혈압")
diastolic_bp: Optional[int] = Field(None, description="이완기 혈압")
fasting_glucose: Optional[int] = Field(None, description="공복혈당")
total_cholesterol: Optional[int] = Field(None, description="총 콜레스테롤")
triglyceride: Optional[int] = Field(None, description="중성지방")
hdl_cholesterol: Optional[int] = Field(None, description="HDL 콜레스테롤")
ldl_cholesterol: Optional[int] = Field(None, description="LDL 콜레스테롤")
hemoglobin: Optional[Decimal] = Field(None, description="혈색소")
urine_protein: Optional[int] = Field(None, description="요단백")
serum_creatinine: Optional[Decimal] = Field(None, description="혈청크레아티닌")
ast: Optional[int] = Field(None, description="AST")
alt: Optional[int] = Field(None, description="ALT")
gamma_gtp: Optional[int] = Field(None, description="감마지티피")
smoking_status: Optional[int] = Field(None, description="흡연 상태")
drinking_status: Optional[int] = Field(None, description="음주 상태")
processed_at: Optional[datetime] = Field(None, description="처리일시")
created_at: datetime = Field(default_factory=datetime.now, description="생성일시")
class HealthNormalRange(BaseModel):
"""건강 정상치 기준"""
range_id: int = Field(..., description="범위 ID")
health_item_code: Optional[str] = Field(None, max_length=25, description="건강항목 코드")
health_item_name: Optional[str] = Field(None, max_length=30, description="건강항목명")
gender_code: Optional[int] = Field(None, description="성별 코드 (0:공통, 1:남성, 2:여성)")
unit: Optional[str] = Field(None, max_length=10, description="단위")
normal_range: Optional[str] = Field(None, max_length=15, description="정상 범위")
warning_range: Optional[str] = Field(None, max_length=15, description="주의 범위")
danger_range: Optional[str] = Field(None, max_length=15, description="위험 범위")
note: Optional[str] = Field(None, max_length=50, description="비고")
created_at: datetime = Field(default_factory=datetime.now, description="생성일시")
class HealthSyncResponse(BaseModel):
"""건강검진 연동 응답"""
sync_status: str = Field(..., description="동기화 상태")
message: str = Field(..., description="응답 메시지")
is_ready_for_analysis: bool = Field(..., description="분석 준비 여부")
synced_at: datetime = Field(..., description="동기화 일시")
class HealthHistoryResponse(BaseModel):
"""건강검진 이력 응답"""
user_info: Dict[str, Any] = Field(..., description="사용자 정보")
checkup_records: List[Dict[str, Any]] = Field(..., description="건강검진 기록")
chart_data: Optional[Dict[str, Any]] = Field(None, description="차트 데이터")
normal_range_reference: Optional[Dict[str, Any]] = Field(None, description="정상치 기준")
class CheckupFileRequest(BaseModel):
"""건강검진 파일 업로드 요청"""
user_id: int = Field(..., description="사용자 ID")
file_name: str = Field(..., description="파일명")
file_type: str = Field(..., description="파일 형식")
file_content: str = Field(..., description="파일 내용")
class FileUploadResponse(BaseModel):
"""파일 업로드 응답"""
file_id: str = Field(..., description="파일 ID")
upload_url: str = Field(..., description="업로드 URL")
status: str = Field(..., description="업로드 상태")
message: str = Field(..., description="응답 메시지")
+142
View File
@@ -0,0 +1,142 @@
"""
HealthSync AI 지능형 서비스 관련 모델 (Intelligence Service)
"""
from pydantic import BaseModel, Field
from datetime import datetime
from typing import Optional, List, Dict, Any
from enum import Enum
class MessageRole(str, Enum):
"""메시지 역할"""
USER = "user"
ASSISTANT = "assistant"
SYSTEM = "system"
class MessageType(str, Enum):
"""메시지 타입"""
QUESTION = "question"
ANSWER = "answer"
NOTIFICATION = "notification"
CELEBRATION = "celebration"
ENCOURAGEMENT = "encouragement"
class SenderType(str, Enum):
"""발신자 타입"""
USER = "user"
AI = "ai"
SYSTEM = "system"
class NotificationType(str, Enum):
"""알림 타입"""
DAILY_ENCOURAGEMENT = "daily_encouragement"
WEEKLY_SUMMARY = "weekly_summary"
MILESTONE_CELEBRATION = "milestone_celebration"
HEALTH_REMINDER = "health_reminder"
MISSION_REMINDER = "mission_reminder"
class EncouragementLevel(str, Enum):
"""격려 레벨"""
LOW = "low"
MEDIUM = "medium"
HIGH = "high"
INTENSIVE = "intensive"
class ChatMessage(BaseModel):
"""채팅 메시지"""
message_id: int = Field(..., description="메시지 ID")
member_serial_number: int = Field(..., description="회원 일련번호")
message_type: str = Field(..., max_length=20, description="메시지 타입")
message_content: Optional[str] = Field(None, description="메시지 내용")
response_content: Optional[str] = Field(None, description="응답 내용")
created_at: datetime = Field(default_factory=datetime.now, description="생성일시")
class HealthDiagnosisResponse(BaseModel):
"""건강 진단 응답"""
three_sentence_summary: List[str] = Field(..., description="3줄 요약")
health_score: int = Field(..., description="건강 점수")
risk_level: str = Field(..., description="위험 레벨")
occupation_considerations: str = Field(..., description="직업별 고려사항")
analysis_timestamp: datetime = Field(..., description="분석 시각")
confidence_score: float = Field(..., description="신뢰도 점수")
class RecommendedMission(BaseModel):
"""추천 미션"""
mission_id: str = Field(..., description="미션 ID")
title: str = Field(..., description="미션 제목")
description: str = Field(..., description="미션 설명")
category: str = Field(..., description="미션 카테고리")
difficulty: str = Field(..., description="난이도")
health_benefit: str = Field(..., description="건강상 이점")
occupation_relevance: str = Field(..., description="직업 연관성")
estimated_time_minutes: int = Field(..., description="예상 소요 시간(분)")
class MissionRecommendationResponse(BaseModel):
"""미션 추천 응답"""
missions: List[RecommendedMission] = Field(..., description="추천 미션 목록")
recommendation_reason: str = Field(..., description="추천 사유")
total_recommended: int = Field(..., description="전체 추천 수")
class ChatRequest(BaseModel):
"""채팅 요청"""
message: str = Field(..., min_length=1, max_length=500, description="메시지 내용")
session_id: str = Field(..., description="세션 ID")
context: Optional[str] = Field(None, description="컨텍스트")
user_id: int = Field(..., description="사용자 ID")
class ChatResponse(BaseModel):
"""채팅 응답"""
response: str = Field(..., description="AI 응답")
session_id: str = Field(..., description="세션 ID")
timestamp: datetime = Field(..., description="응답 시각")
suggested_questions: List[str] = Field(..., description="추천 질문")
response_type: str = Field(..., description="응답 타입")
class ChatHistoryResponse(BaseModel):
"""채팅 이력 응답"""
session_id: str = Field(..., description="세션 ID")
messages: List[Dict[str, Any]] = Field(..., description="메시지 목록")
total_message_count: int = Field(..., description="전체 메시지 수")
cache_expiration: Optional[str] = Field(None, description="캐시 만료 시간")
class CelebrationRequest(BaseModel):
"""축하 메시지 요청"""
user_id: int = Field(..., description="사용자 ID")
mission_id: str = Field(..., description="미션 ID")
achievement_type: str = Field(..., description="성취 타입")
consecutive_days: int = Field(..., description="연속 달성 일수")
total_achievements: int = Field(..., description="전체 성취 수")
class CelebrationResponse(BaseModel):
"""축하 메시지 응답"""
congrats_message: str = Field(..., description="축하 메시지")
achievement_badge: str = Field(..., description="성취 배지")
health_benefit: str = Field(..., description="건강상 이점")
next_milestone: str = Field(..., description="다음 마일스톤")
encouragement_level: str = Field(..., description="격려 레벨")
visual_effect: str = Field(..., description="시각 효과")
class EncouragementRequest(BaseModel):
"""독려 메시지 요청"""
user_id: int = Field(..., description="사용자 ID")
missions_status: List[Dict[str, Any]] = Field(..., description="미션 상태 목록")
class EncouragementResponse(BaseModel):
"""독려 메시지 응답"""
message: str = Field(..., description="독려 메시지")
motivation_type: str = Field(..., description="동기부여 타입")
timing: str = Field(..., description="타이밍")
personalized_tip: str = Field(..., description="개인화된 팁")
priority: str = Field(..., description="우선순위")
class BatchNotificationRequest(BaseModel):
"""배치 알림 요청"""
trigger_time: datetime = Field(..., description="트리거 시간")
target_users: List[str] = Field(..., description="대상 사용자 목록")
notification_type: str = Field(..., description="알림 타입")
class BatchNotificationResponse(BaseModel):
"""배치 알림 응답"""
processed_count: int = Field(..., description="처리된 수")
success_count: int = Field(..., description="성공 수")
failed_count: int = Field(..., description="실패 수")
next_scheduled_time: Optional[datetime] = Field(None, description="다음 예약 시간")
+59
View File
@@ -0,0 +1,59 @@
"""
HealthSync AI 사용자 관련 모델 (User Service)
"""
from pydantic import BaseModel, Field
from datetime import datetime, date
from typing import Optional
from enum import Enum
class UserStatus(str, Enum):
"""사용자 상태"""
ACTIVE = "active"
INACTIVE = "inactive"
SUSPENDED = "suspended"
class OccupationType(BaseModel):
"""직업 유형 모델"""
occupation_code: str = Field(..., max_length=20, description="직업 코드")
occupation_name: str = Field(..., max_length=100, description="직업명")
category: Optional[str] = Field(None, max_length=50, description="직업 카테고리")
class User(BaseModel):
"""사용자 기본 모델"""
member_serial_number: int = Field(..., description="회원 일련번호")
google_id: str = Field(..., max_length=255, description="구글 ID")
name: str = Field(..., max_length=100, description="사용자 이름")
birth_date: date = Field(..., description="생년월일")
occupation: Optional[str] = Field(None, max_length=50, description="직업")
created_at: datetime = Field(default_factory=datetime.now, description="생성일시")
updated_at: datetime = Field(default_factory=datetime.now, description="수정일시")
last_login_at: Optional[datetime] = Field(None, description="마지막 로그인")
class UserRegistrationRequest(BaseModel):
"""사용자 등록 요청"""
name: str = Field(..., min_length=1, max_length=100, description="사용자 이름")
birth_date: date = Field(..., description="생년월일")
occupation: Optional[str] = Field(None, max_length=50, description="직업")
class UserRegistrationResponse(BaseModel):
"""사용자 등록 응답"""
user_id: int = Field(..., description="사용자 ID")
message: str = Field(..., description="등록 결과 메시지")
status: str = Field(..., description="등록 상태")
class UserProfileResponse(BaseModel):
"""사용자 프로필 응답"""
user_id: int = Field(..., description="사용자 ID")
name: str = Field(..., description="사용자 이름")
age: int = Field(..., description="나이")
occupation: Optional[str] = Field(None, description="직업")
registered_at: datetime = Field(..., description="등록일시")
last_login_at: Optional[datetime] = Field(None, description="마지막 로그인")
class LoginResponse(BaseModel):
"""로그인 응답"""
access_token: str = Field(..., description="액세스 토큰")
refresh_token: str = Field(..., description="리프레시 토큰")
is_new_user: bool = Field(..., description="신규 사용자 여부")
user_id: int = Field(..., description="사용자 ID")
expires_in: int = Field(..., description="토큰 만료 시간(초)")