File size: 4,010 Bytes
54b590a
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
# 檔名:recommend_api.py
# 功能:
#   - 提供 /recommend API
#   - 內部呼叫 recommender.run_recommend_model() 來產生 clothe.json
#   - 自動把每次收到的 request 存成 json 檔,放在 saved_requests/
#   - 自動把每次回傳的 clothe_json 存成 json 檔,放在 saved_clothes/
#   - ✅ 自動判斷身形,印出身形,並把結果塞進 report 給推薦系統用

from fastapi import FastAPI
from pydantic import BaseModel
from typing import Optional, Dict, Any

from pathlib import Path
import json
import time

from recommender import run_recommend_model, ClotheJSON
from body_type_classifier import classify_male_body_type, classify_female_body_type

app = FastAPI(title="Recommendation Service")

BASE_DIR = Path(__file__).resolve().parent

LOG_REQ_DIR = BASE_DIR / "saved_requests"
LOG_REQ_DIR.mkdir(exist_ok=True)

LOG_RES_DIR = BASE_DIR / "saved_clothes"
LOG_RES_DIR.mkdir(exist_ok=True)


class WeatherInfo(BaseModel):
    condition: str
    temperature: float
    humidity: Optional[float] = None


class RecommendRequest(BaseModel):
    user_id: Optional[str] = None
    report: dict
    weather: WeatherInfo


DEFAULT_GENDER = "male"


def extract_gender(report: Dict[str, Any]) -> Optional[str]:
    gender = (
        report.get("gender") or
        report.get("sex") or
        report.get("Gender") or
        report.get("user_gender")
    )

    if isinstance(gender, str):
        g = gender.lower()
        if g in ("male", "m", "boy", "man", "男", "男性"):
            return "male"
        if g in ("female", "f", "girl", "woman", "女", "女性"):
            return "female"

    if DEFAULT_GENDER is not None:
        print(f"[BodyType] report 中沒有 gender 欄位,暫時使用 DEFAULT_GENDER={DEFAULT_GENDER}")
        return DEFAULT_GENDER

    return None


def extract_body_measurements(report: Dict[str, Any]) -> Optional[Dict[str, float]]:
    bm = report.get("body_measurements")
    if isinstance(bm, dict):
        return bm
    return None


def attach_body_type(report: Dict[str, Any]) -> None:
    body_measurements = extract_body_measurements(report)
    gender = extract_gender(report)

    if not body_measurements or not gender:
        print(
            f"[BodyType] 無法判斷:缺少 body_measurements 或 gender,"
            f"gender={gender}, has_body={bool(body_measurements)}"
        )
        return

    try:
        if gender == "male":
            body_type = classify_male_body_type(body_measurements)
        else:
            body_type = classify_female_body_type(body_measurements)

        print(f"[BodyType] gender={gender} → body_type={body_type}")

        report["body_type"] = body_type
        report["body_gender"] = gender

    except Exception as e:
        print(f"[BodyType] 判斷身形時發生錯誤: {e}")


@app.post("/recommend", response_model=ClotheJSON)
def recommend(req: RecommendRequest) -> ClotheJSON:
    weather_dict = req.weather.dict()

    timestamp = int(time.time())
    user_part = req.user_id if req.user_id else "anonymous"
    base_name = f"{user_part}_{timestamp}"

    report_dict: Dict[str, Any] = dict(req.report)

    attach_body_type(report_dict)

    req_path = LOG_REQ_DIR / f"request_{base_name}.json"
    with req_path.open("w", encoding="utf-8") as f:
        json.dump(
            {
                "user_id": req.user_id,
                "report": report_dict,
                "weather": weather_dict,
            },
            f,
            ensure_ascii=False,
            indent=2,
        )

    clothe_json = run_recommend_model(report_dict, weather_dict)

    res_path = LOG_RES_DIR / f"clothe_{base_name}.json"
    with res_path.open("w", encoding="utf-8") as f:
        json.dump(
            clothe_json,
            f,
            ensure_ascii=False,
            indent=2,
        )

    return clothe_json