Spaces:
Sleeping
Sleeping
Refactor: Add robust download and detailed logging
Browse files
app.py
CHANGED
|
@@ -1,4 +1,3 @@
|
|
| 1 |
-
# app.py (Versi Final dengan Pemuatan Model yang Benar)
|
| 2 |
from flask import Flask, request, jsonify, send_from_directory
|
| 3 |
from transformers import AutoTokenizer, AutoModelForSequenceClassification
|
| 4 |
import torch
|
|
@@ -60,44 +59,50 @@ def load_all_models():
|
|
| 60 |
print("*" * 50)
|
| 61 |
print("Memuat semua model AI dari persistent storage...")
|
| 62 |
for model_name, model_path in MODEL_CONFIG.items():
|
|
|
|
| 63 |
if os.path.exists(model_path):
|
| 64 |
-
print(f" > Memuat {model_name} dari {model_path}...")
|
| 65 |
try:
|
|
|
|
| 66 |
tokenizer = AutoTokenizer.from_pretrained(model_path)
|
|
|
|
| 67 |
model = AutoModelForSequenceClassification.from_pretrained(model_path)
|
|
|
|
| 68 |
model.to(device)
|
| 69 |
model.eval()
|
| 70 |
models_cache[model_name] = (model, tokenizer)
|
| 71 |
-
print(f"
|
| 72 |
-
except Exception as e:
|
|
|
|
|
|
|
| 73 |
else:
|
| 74 |
-
print(f"
|
| 75 |
-
print("
|
|
|
|
| 76 |
print("*" * 50)
|
| 77 |
|
| 78 |
|
| 79 |
@app.route('/predict', methods=['POST'])
|
| 80 |
def predict():
|
| 81 |
-
print("\n[
|
| 82 |
try:
|
| 83 |
data = request.get_json()
|
| 84 |
url_input = data.get('url', '')
|
| 85 |
-
print(f"[
|
| 86 |
if not url_input or not url_input.strip(): return jsonify({"error": "URL tidak boleh kosong"}), 400
|
| 87 |
|
| 88 |
-
print("[
|
| 89 |
text_from_url, error_message = scrape_news_from_url(url_input)
|
| 90 |
if error_message: return jsonify({"error": error_message}), 400
|
| 91 |
-
print("[
|
| 92 |
|
| 93 |
cleaned_text = clean_text_for_prediction(text_from_url)
|
| 94 |
-
print("[
|
| 95 |
|
| 96 |
all_predictions = {}
|
| 97 |
individual_preds_list = []
|
| 98 |
|
| 99 |
for model_name, (model, tokenizer) in models_cache.items():
|
| 100 |
-
print(f"[
|
| 101 |
try:
|
| 102 |
inputs = tokenizer.encode_plus(cleaned_text, add_special_tokens=True, max_length=256, padding='max_length', truncation=True, return_attention_mask=True, return_tensors='pt')
|
| 103 |
input_ids = inputs['input_ids'].to(device)
|
|
@@ -109,21 +114,21 @@ def predict():
|
|
| 109 |
predicted_class = "Hoax" if predicted_class_idx.item() == 1 else "Fakta"
|
| 110 |
individual_preds_list.append(predicted_class_idx.item())
|
| 111 |
all_predictions[model_name] = {"prediction": predicted_class, "confidence": f"{confidence.item():.2%}"}
|
| 112 |
-
print(f"[
|
| 113 |
except Exception as e:
|
| 114 |
-
print(f"[ERROR] Prediksi dengan {model_name} gagal: {e}")
|
| 115 |
all_predictions[model_name] = {"prediction": "Error", "confidence": "N/A"}
|
| 116 |
|
| 117 |
if individual_preds_list:
|
| 118 |
-
print("[
|
| 119 |
ensemble_vote_result = mode(np.array(individual_preds_list))
|
| 120 |
final_prediction_idx = ensemble_vote_result.mode[0] if isinstance(ensemble_vote_result.mode, np.ndarray) else ensemble_vote_result.mode
|
| 121 |
final_prediction = "Hoax" if final_prediction_idx == 1 else "Fakta"
|
| 122 |
agreement = np.mean([p == final_prediction_idx for p in individual_preds_list])
|
| 123 |
all_predictions["Bagging (Ensemble)"] = {"prediction": final_prediction, "confidence": f"{agreement:.2%}"}
|
| 124 |
-
print("[
|
| 125 |
|
| 126 |
-
print("[
|
| 127 |
return jsonify(all_predictions)
|
| 128 |
except Exception as e:
|
| 129 |
print(f"[FATAL ERROR] Terjadi error tak terduga di rute /predict:")
|
|
@@ -133,8 +138,7 @@ def predict():
|
|
| 133 |
@app.route('/')
|
| 134 |
def serve_index(): return send_from_directory('frontend', 'index.html')
|
| 135 |
|
| 136 |
-
# ---
|
| 137 |
-
# Panggil fungsi load_all_models() di sini, di luar blok if __name__ == '__main__'
|
| 138 |
# Ini akan dieksekusi saat Gunicorn mengimpor file app.py
|
| 139 |
load_all_models()
|
| 140 |
|
|
|
|
|
|
|
| 1 |
from flask import Flask, request, jsonify, send_from_directory
|
| 2 |
from transformers import AutoTokenizer, AutoModelForSequenceClassification
|
| 3 |
import torch
|
|
|
|
| 59 |
print("*" * 50)
|
| 60 |
print("Memuat semua model AI dari persistent storage...")
|
| 61 |
for model_name, model_path in MODEL_CONFIG.items():
|
| 62 |
+
print(f"\n[LOAD] Mencoba memuat model: {model_name}")
|
| 63 |
if os.path.exists(model_path):
|
|
|
|
| 64 |
try:
|
| 65 |
+
print(f" [LOAD] Path ditemukan: {model_path}. Memuat tokenizer...")
|
| 66 |
tokenizer = AutoTokenizer.from_pretrained(model_path)
|
| 67 |
+
print(f" [LOAD] Tokenizer {model_name} dimuat. Memuat model...")
|
| 68 |
model = AutoModelForSequenceClassification.from_pretrained(model_path)
|
| 69 |
+
print(f" [LOAD] Model {model_name} dimuat. Memindahkan ke CPU dan set ke eval mode...")
|
| 70 |
model.to(device)
|
| 71 |
model.eval()
|
| 72 |
models_cache[model_name] = (model, tokenizer)
|
| 73 |
+
print(f" [SUCCESS] {model_name} berhasil dikonfigurasi.")
|
| 74 |
+
except Exception as e:
|
| 75 |
+
print(f" [ERROR] Gagal saat memuat model {model_name}: {e}")
|
| 76 |
+
traceback.print_exc()
|
| 77 |
else:
|
| 78 |
+
print(f" [WARNING] Direktori model untuk {model_name} tidak ditemukan di {model_path}")
|
| 79 |
+
print("\nProses pemuatan semua model selesai.")
|
| 80 |
+
print(f"Total model yang berhasil dimuat: {len(models_cache)}")
|
| 81 |
print("*" * 50)
|
| 82 |
|
| 83 |
|
| 84 |
@app.route('/predict', methods=['POST'])
|
| 85 |
def predict():
|
| 86 |
+
print("\n[PREDICT] Menerima permintaan di /predict")
|
| 87 |
try:
|
| 88 |
data = request.get_json()
|
| 89 |
url_input = data.get('url', '')
|
| 90 |
+
print(f"[PREDICT] URL yang diterima: {url_input}")
|
| 91 |
if not url_input or not url_input.strip(): return jsonify({"error": "URL tidak boleh kosong"}), 400
|
| 92 |
|
| 93 |
+
print("[PREDICT] Memulai proses scraping...")
|
| 94 |
text_from_url, error_message = scrape_news_from_url(url_input)
|
| 95 |
if error_message: return jsonify({"error": error_message}), 400
|
| 96 |
+
print("[PREDICT] Scraping berhasil.")
|
| 97 |
|
| 98 |
cleaned_text = clean_text_for_prediction(text_from_url)
|
| 99 |
+
print("[PREDICT] Teks berhasil dibersihkan.")
|
| 100 |
|
| 101 |
all_predictions = {}
|
| 102 |
individual_preds_list = []
|
| 103 |
|
| 104 |
for model_name, (model, tokenizer) in models_cache.items():
|
| 105 |
+
print(f" [PREDICT] Melakukan prediksi dengan {model_name}...")
|
| 106 |
try:
|
| 107 |
inputs = tokenizer.encode_plus(cleaned_text, add_special_tokens=True, max_length=256, padding='max_length', truncation=True, return_attention_mask=True, return_tensors='pt')
|
| 108 |
input_ids = inputs['input_ids'].to(device)
|
|
|
|
| 114 |
predicted_class = "Hoax" if predicted_class_idx.item() == 1 else "Fakta"
|
| 115 |
individual_preds_list.append(predicted_class_idx.item())
|
| 116 |
all_predictions[model_name] = {"prediction": predicted_class, "confidence": f"{confidence.item():.2%}"}
|
| 117 |
+
print(f" [PREDICT] Prediksi {model_name} berhasil: {predicted_class}")
|
| 118 |
except Exception as e:
|
| 119 |
+
print(f" [ERROR] Prediksi dengan {model_name} gagal: {e}")
|
| 120 |
all_predictions[model_name] = {"prediction": "Error", "confidence": "N/A"}
|
| 121 |
|
| 122 |
if individual_preds_list:
|
| 123 |
+
print("[PREDICT] Melakukan ensemble voting...")
|
| 124 |
ensemble_vote_result = mode(np.array(individual_preds_list))
|
| 125 |
final_prediction_idx = ensemble_vote_result.mode[0] if isinstance(ensemble_vote_result.mode, np.ndarray) else ensemble_vote_result.mode
|
| 126 |
final_prediction = "Hoax" if final_prediction_idx == 1 else "Fakta"
|
| 127 |
agreement = np.mean([p == final_prediction_idx for p in individual_preds_list])
|
| 128 |
all_predictions["Bagging (Ensemble)"] = {"prediction": final_prediction, "confidence": f"{agreement:.2%}"}
|
| 129 |
+
print("[PREDICT] Ensemble voting selesai.")
|
| 130 |
|
| 131 |
+
print("[PREDICT] Mengirimkan hasil ke frontend.")
|
| 132 |
return jsonify(all_predictions)
|
| 133 |
except Exception as e:
|
| 134 |
print(f"[FATAL ERROR] Terjadi error tak terduga di rute /predict:")
|
|
|
|
| 138 |
@app.route('/')
|
| 139 |
def serve_index(): return send_from_directory('frontend', 'index.html')
|
| 140 |
|
| 141 |
+
# --- Pemuatan Model Dipanggil di Sini ---
|
|
|
|
| 142 |
# Ini akan dieksekusi saat Gunicorn mengimpor file app.py
|
| 143 |
load_all_models()
|
| 144 |
|