diff --git a/.DS_Store b/.DS_Store new file mode 100644 index 0000000..a2e5ec1 Binary files /dev/null and b/.DS_Store differ diff --git a/.github/.DS_Store b/.github/.DS_Store new file mode 100644 index 0000000..507b2ac Binary files /dev/null and b/.github/.DS_Store differ diff --git a/.github/workflows/cicd.yml b/.github/workflows/cicd.yml index bb3170e..eafd0f2 100644 --- a/.github/workflows/cicd.yml +++ b/.github/workflows/cicd.yml @@ -37,6 +37,7 @@ jobs: context: . file: ./Dockerfile push: true + no-cache: true tags: | ${{ env.IMAGE }}:latest ${{ env.IMAGE }}:${{ github.sha }} @@ -45,7 +46,6 @@ jobs: name: Deploy to Server needs: docker-build-push runs-on: ubuntu-latest - if: github.ref == 'refs/heads/main' steps: - name: Deploy via SSH @@ -62,4 +62,6 @@ jobs: -p 8000:8000 \ -e OPENAI_API_KEY=${{ secrets.OPENAI_API_KEY }} \ -e OPENAI_MODEL=${{ secrets.OPENAI_MODEL }} \ - ${{ env.IMAGE }}:latest \ No newline at end of file + ${{ env.IMAGE }}:latest + + docker image prune -af || true \ No newline at end of file diff --git a/Dockerfile b/Dockerfile index 7a7cca2..9ccf8df 100644 --- a/Dockerfile +++ b/Dockerfile @@ -6,4 +6,6 @@ COPY requirements.txt . RUN pip install --no-cache-dir -r requirements.txt COPY . . + +RUN python -m leftovers.domain.recommend.service.train CMD ["uvicorn", "main:app", "--host", "0.0.0.0", "--port", "8000"] diff --git a/leftovers/.DS_Store b/leftovers/.DS_Store new file mode 100644 index 0000000..f9ccfe9 Binary files /dev/null and b/leftovers/.DS_Store differ diff --git a/app/__init__.py b/leftovers/__init__.py similarity index 100% rename from app/__init__.py rename to leftovers/__init__.py diff --git a/app/core/config/config.py b/leftovers/core/config/config.py similarity index 100% rename from app/core/config/config.py rename to leftovers/core/config/config.py diff --git a/app/core/exception/global_error_handler.py b/leftovers/core/exception/global_error_handler.py similarity index 94% rename from app/core/exception/global_error_handler.py rename to leftovers/core/exception/global_error_handler.py index 037ca8f..2d4322a 100644 --- a/app/core/exception/global_error_handler.py +++ b/leftovers/core/exception/global_error_handler.py @@ -2,7 +2,7 @@ from fastapi.responses import JSONResponse from pydantic import ValidationError -from app.core.response.api_response import fail +from leftovers.core.response.api_response import fail # 공통 응답 포맷 생성기 def error_response(status: int, message: str, extra: dict = None): diff --git a/app/core/external/open_ai_client.py b/leftovers/core/external/open_ai_client.py similarity index 85% rename from app/core/external/open_ai_client.py rename to leftovers/core/external/open_ai_client.py index 1b248d8..71536b2 100644 --- a/app/core/external/open_ai_client.py +++ b/leftovers/core/external/open_ai_client.py @@ -1,5 +1,5 @@ from openai import OpenAI -from app.core.config.config import settings # 환경설정 로더 가져오기 +from leftovers.core.config.config import settings # 환경설정 로더 가져오기 _cfg = settings() # settings diff --git a/app/core/response/api_response.py b/leftovers/core/response/api_response.py similarity index 100% rename from app/core/response/api_response.py rename to leftovers/core/response/api_response.py diff --git a/app/domain/__init__.py b/leftovers/domain/__init__.py similarity index 100% rename from app/domain/__init__.py rename to leftovers/domain/__init__.py diff --git a/app/domain/recommend/__init__.py b/leftovers/domain/recommend/__init__.py similarity index 100% rename from app/domain/recommend/__init__.py rename to leftovers/domain/recommend/__init__.py diff --git a/app/domain/recommend/api/recommend_api.py b/leftovers/domain/recommend/api/recommend_api.py similarity index 78% rename from app/domain/recommend/api/recommend_api.py rename to leftovers/domain/recommend/api/recommend_api.py index df3cab3..1e3d82b 100644 --- a/app/domain/recommend/api/recommend_api.py +++ b/leftovers/domain/recommend/api/recommend_api.py @@ -1,8 +1,8 @@ from fastapi import APIRouter -from app.core.response.api_response import Envelope, ok, fail -from app.domain.recommend.schemas.recommend_request import RecommendReq -from app.domain.recommend.schemas.recommend_response import RecommendRes -from app.domain.recommend.service import evaluator, loader +from leftovers.core.response.api_response import Envelope, ok, fail +from leftovers.domain.recommend.schemas.recommend_request import RecommendReq +from leftovers.domain.recommend.schemas.recommend_response import RecommendRes +from leftovers.domain.recommend.service import evaluator, loader router = APIRouter(prefix="/menus") diff --git a/app/domain/recommend/data/foodData1.xlsx b/leftovers/domain/recommend/data/foodData1.xlsx similarity index 100% rename from app/domain/recommend/data/foodData1.xlsx rename to leftovers/domain/recommend/data/foodData1.xlsx diff --git a/app/domain/recommend/data/foodData2.xlsx b/leftovers/domain/recommend/data/foodData2.xlsx similarity index 100% rename from app/domain/recommend/data/foodData2.xlsx rename to leftovers/domain/recommend/data/foodData2.xlsx diff --git a/app/domain/recommend/schemas/recommend_request.py b/leftovers/domain/recommend/schemas/recommend_request.py similarity index 100% rename from app/domain/recommend/schemas/recommend_request.py rename to leftovers/domain/recommend/schemas/recommend_request.py diff --git a/app/domain/recommend/schemas/recommend_response.py b/leftovers/domain/recommend/schemas/recommend_response.py similarity index 100% rename from app/domain/recommend/schemas/recommend_response.py rename to leftovers/domain/recommend/schemas/recommend_response.py diff --git a/app/domain/recommend/service/__init__.py b/leftovers/domain/recommend/service/__init__.py similarity index 100% rename from app/domain/recommend/service/__init__.py rename to leftovers/domain/recommend/service/__init__.py diff --git a/app/domain/recommend/service/evaluator.py b/leftovers/domain/recommend/service/evaluator.py similarity index 91% rename from app/domain/recommend/service/evaluator.py rename to leftovers/domain/recommend/service/evaluator.py index 085230b..b580df9 100644 --- a/app/domain/recommend/service/evaluator.py +++ b/leftovers/domain/recommend/service/evaluator.py @@ -1,7 +1,7 @@ import numpy as np -from app.domain.recommend.service.scoring import compute_score -from app.domain.recommend.schemas.recommend_response import MatchItem -from app.domain.recommend.service import loader, matcher +from leftovers.domain.recommend.service.scoring import compute_score +from leftovers.domain.recommend.schemas.recommend_response import MatchItem +from leftovers.domain.recommend.service import loader, matcher # 음식 영양 성분을 딕셔너리에서 numpy 배열로 변환(ML 모델 입력은 항상 숫자여야 하므로) def to_feat(n: dict) -> np.ndarray: diff --git a/app/domain/recommend/service/food_kfda_loader.py b/leftovers/domain/recommend/service/food_kfda_loader.py similarity index 100% rename from app/domain/recommend/service/food_kfda_loader.py rename to leftovers/domain/recommend/service/food_kfda_loader.py diff --git a/app/domain/recommend/service/loader.py b/leftovers/domain/recommend/service/loader.py similarity index 85% rename from app/domain/recommend/service/loader.py rename to leftovers/domain/recommend/service/loader.py index 4774785..4fa7488 100644 --- a/app/domain/recommend/service/loader.py +++ b/leftovers/domain/recommend/service/loader.py @@ -1,10 +1,10 @@ from typing import List import joblib -from app.domain.recommend.service.food_kfda_loader import load_kfda_excels +from leftovers.domain.recommend.service.food_kfda_loader import load_kfda_excels -FOOD_FILES = ["app/domain/recommend/data/foodData1.xlsx", "app/domain/recommend/data/foodData2.xlsx"] -MODEL_DIR = "app/domain/recommend/model_store" +FOOD_FILES = ["leftovers/domain/recommend/data/foodData1.xlsx", "leftovers/domain/recommend/data/foodData2.xlsx"] +MODEL_DIR = "leftovers/domain/recommend/model_store" # 컨셉 CONCEPTS = {"diet", "keto", "low_sodium", "glycemic", "bulking"} diff --git a/app/domain/recommend/service/matcher.py b/leftovers/domain/recommend/service/matcher.py similarity index 93% rename from app/domain/recommend/service/matcher.py rename to leftovers/domain/recommend/service/matcher.py index 53a79ab..eef839c 100644 --- a/app/domain/recommend/service/matcher.py +++ b/leftovers/domain/recommend/service/matcher.py @@ -1,6 +1,6 @@ import numpy as np from sklearn.metrics.pairwise import cosine_similarity -from app.domain.recommend.service import loader +from leftovers.domain.recommend.service import loader # 메뉴 이름이 유사한 것 찾기 def match_top1(query: str): diff --git a/app/domain/recommend/service/scoring.py b/leftovers/domain/recommend/service/scoring.py similarity index 100% rename from app/domain/recommend/service/scoring.py rename to leftovers/domain/recommend/service/scoring.py diff --git a/app/domain/recommend/service/train.py b/leftovers/domain/recommend/service/train.py similarity index 91% rename from app/domain/recommend/service/train.py rename to leftovers/domain/recommend/service/train.py index 263a078..9bc2e13 100644 --- a/app/domain/recommend/service/train.py +++ b/leftovers/domain/recommend/service/train.py @@ -8,11 +8,11 @@ from sklearn.metrics import mean_absolute_error from sklearn.impute import SimpleImputer -from app.domain.recommend.service.food_kfda_loader import load_kfda_excels -from app.domain.recommend.service.scoring import fit_calibration, compute_score +from leftovers.domain.recommend.service.food_kfda_loader import load_kfda_excels +from leftovers.domain.recommend.service.scoring import fit_calibration, compute_score -FOOD_FILES = ["app/domain/recommend/data/foodData1.xlsx", "app/domain/recommend/data/foodData2.xlsx"] -MODEL_DIR = Path("app/domain/recommend/model_store") +FOOD_FILES = ["leftovers/domain/recommend/data/foodData1.xlsx", "leftovers/domain/recommend/data/foodData2.xlsx"] +MODEL_DIR = Path("leftovers/domain/recommend/model_store") MODEL_DIR.mkdir(parents=True, exist_ok=True) # 컨셉 diff --git a/app/domain/tip/api/tip_api.py b/leftovers/domain/tip/api/tip_api.py similarity index 89% rename from app/domain/tip/api/tip_api.py rename to leftovers/domain/tip/api/tip_api.py index c6411c6..36135f6 100644 --- a/app/domain/tip/api/tip_api.py +++ b/leftovers/domain/tip/api/tip_api.py @@ -1,10 +1,10 @@ from fastapi import APIRouter, HTTPException from typing import List -from app.core.response.api_response import Envelope, ok -from app.domain.tip.schemas.tip_request import TipRequest -from app.domain.tip.schemas.tip_response import TipItem -from app.domain.tip.service.prompt import chatForTip +from leftovers.core.response.api_response import Envelope, ok +from leftovers.domain.tip.schemas.tip_request import TipRequest +from leftovers.domain.tip.schemas.tip_response import TipItem +from leftovers.domain.tip.service.prompt import chatForTip import json from json import JSONDecodeError diff --git a/app/domain/tip/schemas/tip_request.py b/leftovers/domain/tip/schemas/tip_request.py similarity index 100% rename from app/domain/tip/schemas/tip_request.py rename to leftovers/domain/tip/schemas/tip_request.py diff --git a/app/domain/tip/schemas/tip_response.py b/leftovers/domain/tip/schemas/tip_response.py similarity index 100% rename from app/domain/tip/schemas/tip_response.py rename to leftovers/domain/tip/schemas/tip_response.py diff --git a/app/domain/tip/service/prompt.py b/leftovers/domain/tip/service/prompt.py similarity index 91% rename from app/domain/tip/service/prompt.py rename to leftovers/domain/tip/service/prompt.py index 97d011d..c25e348 100644 --- a/app/domain/tip/service/prompt.py +++ b/leftovers/domain/tip/service/prompt.py @@ -1,5 +1,5 @@ -from app.core.external.open_ai_client import client -from app.core.config.config import settings +from leftovers.core.external.open_ai_client import client +from leftovers.core.config.config import settings # OpenAI Responses API의 structured outputs 기능에서 쓰는 JSON Schema # TIp SCHEMA의 형태로 응답을 제공함 diff --git a/main.py b/main.py index fc65eb0..3cee34d 100644 --- a/main.py +++ b/main.py @@ -2,10 +2,10 @@ from pydantic import ValidationError from contextlib import asynccontextmanager -from app.domain.recommend.service import loader -from app.domain.tip.api import tip_api -from app.domain.recommend.api import recommend_api -from app.core.exception.global_error_handler import ( +from leftovers.domain.recommend.service import loader +from leftovers.domain.tip.api import tip_api +from leftovers.domain.recommend.api import recommend_api +from leftovers.core.exception.global_error_handler import ( validation_error_handler, http_exception_handler, global_exception_handler, @@ -17,7 +17,6 @@ async def lifespan(app: FastAPI): loop = asyncio.get_event_loop() await loop.run_in_executor(None, loader.load_all) - loader.load_all() print("모델/DB 로딩 완료") yield # 여기까지 오면 서버 실행