ML/
├── app/
│ ├── __init__.py # Flask 앱 및 환경변수 로드 초기화
│ ├── embed_books.py # 책 소개 텍스트 임베딩
│ ├── embed_user.py # 사용자 취향 데이터 임베딩
│ ├── generate_question.py # 도서별 GPT 기본 질문 생성
│ ├── main.py
│ └── recommend_books.py # 도서 추천 로직
├── .env
├── requirements.txt
├── README.md
└── .gitignore
pip install -r requirements.txtpython -m venv venv
source venv/bin/activate # Mac/Linux
venv\Scripts\activate # Windowscd app
python main.py기본적으로 http://localhost:5000에서 서버가 실행됩니다.
- 설명: 헬스체크(프로세스/라우팅 생존 확인)
- 응답(200):
{ "status": "ok" }-
설명: 책 제목으로 질문 1개 생성 (한국어, 단문)
-
헤더:
Content-Type: application/jsonx-api-key: <token>
-
요청(JSON):
{
"bookId": 1234,
"title": "소년이 온다"
}- 응답(200, JSON):
{
"bookId": 1234,
"blocked": false,
"question": "당신은 이 이야기 속 어떤 장면에서 가장 오래 머물렀을 것 같나요?",
"latencyMs": 820
}-
오류:
400{ "errorCode": "INVALID_REQUEST", "message": "요청이 올바르지 않습니다." }401{ "errorCode": "UNAUTHORIZED", "message": "부적절한 api key입니다. " }500{ "errorCode": "INTERNAL", "message": "서버 오류" }
-
설명: 유저 임베딩 벡터 생성/업서트 (읽은 책 임베딩 평균 저장)
-
경로 변수:
user_id: integer
-
응답:
- 200:
{ "message": "유저 벡터 생성 완료" } - 400:
{ "message": "벡터 생성 실패" }
- 200:
-
설명: 유저 벡터 기반 도서 추천 읽은 책 제외 → 임베딩 코사인 유사도 상위 N → 키워드는 OpenAI로 생성(실패/타임아웃 시 장르로 대체)
-
헤더:
Authorization: Bearer <token>Content-Type: application/json
-
쿼리 파라미터:
topK(int, 기본 10, 범위 1~100)
-
요청(JSON):
{ "userId": 42 }- 응답(200, JSON):
{
"userId": 42,
"generatedAt": "2025-08-19T03:05:00Z",
"items": [
{ "bookId": 101, "score": 0.873421, "keywords": ["세대 갈등", "기억"] },
{ "bookId": 87, "score": 0.851002, "keywords": ["자기회복"] }
]
}-
오류:
401{ "errorCode": "UNAUTHORIZED", "message": "인증이 필요합니다." }400{ "errorCode": "INVALID_REQUEST", "message": "요청 형식이 올바르지 않습니다." }404{ "errorCode": "USER_NOT_INDEXED", "message": "해당 사용자는 추천 인덱스에 존재하지 않습니다." }500{ "errorCode": "INTERNAL_ERROR", "message": "추천 생성 중 오류가 발생했습니다." }
-
질문 생성: OpenAI
gpt-4o-mini(모델 호출 타임아웃 2.2s), 응답에latencyMs포함 -
도서 임베딩: SentenceTransformers
BAAI/bge-m3→book.bert_embedding (longblob) -
유저 임베딩: 읽은 책 임베딩 평균 →
user_embedding(UPSERT) -
유사도:
cosine_similarity(scikit-learn) -
키워드 생성 폴백: OpenAI 실패/타임아웃 시 장르로 대체
-
인증:
/generate-question→x-api-key필요/api/books/recommend→Authorization: Bearer <token>필요