Update app.py
Browse files
app.py
CHANGED
|
@@ -187,9 +187,10 @@ def get_unified_recommendations_api(
|
|
| 187 |
|
| 188 |
|
| 189 |
# JALUR 2 & 3: Pengguna Baru (dengan atau tanpa probe)
|
| 190 |
-
elif preferred_categories
|
| 191 |
-
# Ini adalah jalur
|
| 192 |
-
|
|
|
|
| 193 |
|
| 194 |
# 1. Validasi Kategori
|
| 195 |
valid_categories = [cat for cat in preferred_categories if cat in df_wisata.columns and cat in list_kategori_wisata_valid_passed]
|
|
@@ -210,17 +211,32 @@ def get_unified_recommendations_api(
|
|
| 210 |
else:
|
| 211 |
candidate_wisata_df['google_rating_norm'] = 0.0
|
| 212 |
|
| 213 |
-
# 4.
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 214 |
valid_probe_user_ids_int = []
|
|
|
|
| 215 |
for raw_id in probe_user_raw_ids:
|
| 216 |
try:
|
| 217 |
valid_probe_user_ids_int.append(user_encoder_passed.transform([raw_id])[0])
|
| 218 |
except ValueError:
|
| 219 |
-
|
| 220 |
-
|
| 221 |
-
|
|
|
|
|
|
|
| 222 |
if not valid_probe_user_ids_int:
|
| 223 |
-
print("Warning: Tidak ada probe user ID yang valid. NCF appeal score akan 0.")
|
| 224 |
candidate_wisata_df['avg_ncf_appeal_score'] = 0.0
|
| 225 |
else:
|
| 226 |
avg_ncf_appeal_scores = []
|
|
@@ -251,26 +267,25 @@ def get_unified_recommendations_api(
|
|
| 251 |
|
| 252 |
candidate_wisata_df['avg_ncf_appeal_score'] = avg_ncf_appeal_scores
|
| 253 |
|
| 254 |
-
#
|
| 255 |
candidate_wisata_df['final_score %'] = (
|
| 256 |
(weight_google_rating_new * candidate_wisata_df['google_rating_norm'].fillna(0) +
|
| 257 |
weight_ncf_appeal_new * candidate_wisata_df['avg_ncf_appeal_score']) * 100
|
| 258 |
)
|
| 259 |
ranked_wisata = candidate_wisata_df.sort_values(by='final_score %', ascending=False).head(n)
|
| 260 |
|
| 261 |
-
#
|
| 262 |
display_cols = ['ID Tempat', 'Nama Wisata', 'final_score %']
|
| 263 |
-
return ranked_wisata[display_cols].to_dict(orient='records')
|
| 264 |
-
|
| 265 |
else:
|
| 266 |
-
|
| 267 |
-
|
| 268 |
|
| 269 |
# --- 5. Definisikan Request Body dengan Pydantic ---
|
| 270 |
class RecommendationRequest(BaseModel):
|
| 271 |
-
user_id: Optional[str] = Field(None, description="ID unik pengguna yang sudah
|
| 272 |
-
preferred_categories: Optional[List[str]] = Field(None, description="
|
| 273 |
-
probe_user_ids: Optional[List[str]] = Field(None, description="(Opsional) Daftar ID pengguna 'probe' untuk NCF hybrid.")
|
| 274 |
n: int = Field(10, gt=0, le=50, description="Jumlah rekomendasi yang diinginkan.")
|
| 275 |
|
| 276 |
class Config:
|
|
@@ -314,10 +329,6 @@ async def get_recommendations(request: RecommendationRequest):
|
|
| 314 |
recommendations = get_unified_recommendations_api(
|
| 315 |
raw_user_id=request.user_id,
|
| 316 |
preferred_categories=request.preferred_categories,
|
| 317 |
-
|
| 318 |
-
# Teruskan probe_user_ids ke fungsi utama
|
| 319 |
-
probe_user_raw_ids=request.probe_user_ids,
|
| 320 |
-
|
| 321 |
n=request.n
|
| 322 |
)
|
| 323 |
|
|
|
|
| 187 |
|
| 188 |
|
| 189 |
# JALUR 2 & 3: Pengguna Baru (dengan atau tanpa probe)
|
| 190 |
+
elif preferred_categories:
|
| 191 |
+
# Ini adalah jalur untuk pengguna baru dengan metode hybrid NCF probing.
|
| 192 |
+
# Probe users akan dipilih secara otomatis dan acak di server.
|
| 193 |
+
print(f"Membuat rekomendasi untuk pengguna baru dengan preferensi: {preferred_categories} (NCF probe otomatis)")
|
| 194 |
|
| 195 |
# 1. Validasi Kategori
|
| 196 |
valid_categories = [cat for cat in preferred_categories if cat in df_wisata.columns and cat in list_kategori_wisata_valid_passed]
|
|
|
|
| 211 |
else:
|
| 212 |
candidate_wisata_df['google_rating_norm'] = 0.0
|
| 213 |
|
| 214 |
+
# 4. Pilih Probe Users Secara Acak di Server (LOGIKA BARU)
|
| 215 |
+
all_known_users = list(user_encoder_passed.classes_)
|
| 216 |
+
if not all_known_users:
|
| 217 |
+
print("Warning: Tidak ada data pengguna di dalam sistem untuk melakukan probing. Rekomendasi tidak dapat dibuat.")
|
| 218 |
+
# Opsi: Jatuh ke metode fallback yang lebih sederhana (non-NCF) atau kembalikan kosong.
|
| 219 |
+
# Mengembalikan kosong lebih aman jika NCF adalah inti dari logika ini.
|
| 220 |
+
return []
|
| 221 |
+
|
| 222 |
+
num_to_sample = min(NUM_SAMPLES_FOR_PROBE, len(all_known_users))
|
| 223 |
+
probe_user_raw_ids = random.sample(all_known_users, num_to_sample)
|
| 224 |
+
print(f"Server memilih {len(probe_user_raw_ids)} probe users secara acak.")
|
| 225 |
+
|
| 226 |
+
# 5. Ubah Probe User IDs ke Format Integer (yang sebelumnya adalah Validasi)
|
| 227 |
valid_probe_user_ids_int = []
|
| 228 |
+
# Loop ini tetap diperlukan untuk mengubah ID string acak menjadi integer untuk model
|
| 229 |
for raw_id in probe_user_raw_ids:
|
| 230 |
try:
|
| 231 |
valid_probe_user_ids_int.append(user_encoder_passed.transform([raw_id])[0])
|
| 232 |
except ValueError:
|
| 233 |
+
# Secara teori ini jarang terjadi jika `all_known_users` berasal dari sumber yang sama,
|
| 234 |
+
# tapi ini adalah pengaman yang baik.
|
| 235 |
+
print(f"Warning: Probe user ID '{raw_id}' yang dipilih secara acak tidak dikenal encoder.")
|
| 236 |
+
|
| 237 |
+
# 6. Hitung Skor NCF untuk Setiap Kandidat Wisata
|
| 238 |
if not valid_probe_user_ids_int:
|
| 239 |
+
print("Warning: Tidak ada probe user ID yang valid setelah proses encoding. NCF appeal score akan 0.")
|
| 240 |
candidate_wisata_df['avg_ncf_appeal_score'] = 0.0
|
| 241 |
else:
|
| 242 |
avg_ncf_appeal_scores = []
|
|
|
|
| 267 |
|
| 268 |
candidate_wisata_df['avg_ncf_appeal_score'] = avg_ncf_appeal_scores
|
| 269 |
|
| 270 |
+
# 7. Hitung Skor Akhir dan Lakukan Ranking
|
| 271 |
candidate_wisata_df['final_score %'] = (
|
| 272 |
(weight_google_rating_new * candidate_wisata_df['google_rating_norm'].fillna(0) +
|
| 273 |
weight_ncf_appeal_new * candidate_wisata_df['avg_ncf_appeal_score']) * 100
|
| 274 |
)
|
| 275 |
ranked_wisata = candidate_wisata_df.sort_values(by='final_score %', ascending=False).head(n)
|
| 276 |
|
| 277 |
+
# 8. Kembalikan Hasil dalam Format yang Diinginkan
|
| 278 |
display_cols = ['ID Tempat', 'Nama Wisata', 'final_score %']
|
| 279 |
+
return ranked_wisata[[col for col in display_cols if col in ranked_wisata.columns]].to_dict(orient='records')
|
| 280 |
+
|
| 281 |
else:
|
| 282 |
+
# Jika tidak ada input yang valid
|
| 283 |
+
return []
|
| 284 |
|
| 285 |
# --- 5. Definisikan Request Body dengan Pydantic ---
|
| 286 |
class RecommendationRequest(BaseModel):
|
| 287 |
+
user_id: Optional[str] = Field(None, description="ID unik pengguna yang sudah terdaftar.")
|
| 288 |
+
preferred_categories: Optional[List[str]] = Field(None, description="Daftar kategori yang disukai pengguna baru.")
|
|
|
|
| 289 |
n: int = Field(10, gt=0, le=50, description="Jumlah rekomendasi yang diinginkan.")
|
| 290 |
|
| 291 |
class Config:
|
|
|
|
| 329 |
recommendations = get_unified_recommendations_api(
|
| 330 |
raw_user_id=request.user_id,
|
| 331 |
preferred_categories=request.preferred_categories,
|
|
|
|
|
|
|
|
|
|
|
|
|
| 332 |
n=request.n
|
| 333 |
)
|
| 334 |
|