Spaces:
Runtime error
Runtime error
| import os | |
| import sys | |
| import random | |
| import shutil | |
| import socket | |
| import requests | |
| import threading | |
| import pandas as pd | |
| import matplotlib.pyplot as plt | |
| import seaborn as sns | |
| from functools import partial | |
| from http.server import SimpleHTTPRequestHandler, HTTPServer | |
| from datasets import load_dataset | |
| from sklearn.metrics import classification_report, accuracy_score, confusion_matrix, roc_curve, auc | |
| # --- KONFIGURACJA --- | |
| API_URL = "http://127.0.0.1:8000" # Adres Twojego backendu FastAPI | |
| TEST_GUILD_ID = "eval_test_guild" # Testowa gildia | |
| SAMPLE_SIZE = 30 # Liczba pr贸bek na klas臋 (30 FAKE + 30 REAL = 60 test贸w) | |
| TEMP_DIR = "temp_eval_images" # Katalog tymczasowy na zdj臋cia | |
| # --------------------- | |
| def setup_test_guild(): | |
| """Wysy艂a 偶膮danie konfiguracji gildii testowej na backendzie.""" | |
| print(f"[*] Konfigurowanie testowej gildii '{TEST_GUILD_ID}' na backendzie...") | |
| setup_payload = { | |
| "active_text_model": "none", | |
| "active_image_model": "capcheck/ai-image-detection", # Model do przetestowania | |
| "log_channel_id": None, | |
| "multi_model_workflow": False | |
| } | |
| try: | |
| r = requests.post(f"{API_URL}/guilds/{TEST_GUILD_ID}/setup", json=setup_payload) | |
| if r.status_code == 200: | |
| print("[+] Testowa gildia skonfigurowana pomy艣lnie.") | |
| else: | |
| print(f"[-] B艂膮d konfiguracji gildii: {r.status_code} - {r.text}") | |
| sys.exit(1) | |
| except Exception as e: | |
| print(f"[-] Brak po艂膮czenia z FastAPI pod adresem {API_URL}. B艂膮d: {e}") | |
| sys.exit(1) | |
| def prepare_dataset(sample_size): | |
| """Pobiera zbi贸r CIFAKE z Hugging Face i tworzy zbalansowany zbi贸r testowy.""" | |
| print("[*] Pobieranie zbioru yanbax/CIFAKE_autotrain_compatible...") | |
| try: | |
| ds = load_dataset( | |
| "yanbax/CIFAKE_autotrain_compatible", | |
| split="train", | |
| revision="refs/convert/parquet" | |
| ) | |
| except Exception as e: | |
| print(f"[-] Nie uda艂o si臋 pobra膰 zbioru z Hugging Face: {e}") | |
| sys.exit(1) | |
| # Pobieramy nazwy klas z metadanych zbioru | |
| label_names = ds.features['label'].names | |
| print(f"[+] Wykryte klasy w zbiorze: {label_names}") | |
| # Znajdujemy indeks klasy oznaczaj膮cej sztuczny obraz (fake) | |
| fake_label_idx = next(i for i, name in enumerate(label_names) if "fake" in name.lower()) | |
| real_images = [] | |
| fake_images = [] | |
| print("[*] Filtrowanie i przygotowywanie pr贸bek obraz贸w...") | |
| for item in ds: | |
| if item['label'] == fake_label_idx: | |
| fake_images.append(item['image']) | |
| else: | |
| real_images.append(item['image']) | |
| # Przerywamy zbieranie pr贸bek, kiedy mamy ich wystarczaj膮co du偶o do losowania | |
| if len(real_images) >= sample_size * 2 and len(fake_images) >= sample_size * 2: | |
| break | |
| # Losowanie pr贸bek | |
| random.seed(42) | |
| real_selected = random.sample(real_images, min(sample_size, len(real_images))) | |
| fake_selected = random.sample(fake_images, min(sample_size, len(fake_images))) | |
| test_set = [] | |
| for img in real_selected: | |
| test_set.append({"image": img, "is_fake_ground_truth": False}) | |
| for img in fake_selected: | |
| test_set.append({"image": img, "is_fake_ground_truth": True}) | |
| random.shuffle(test_set) | |
| return test_set | |
| def find_free_port(): | |
| """Wyszukuje wolny port w systemie operacyjnym.""" | |
| s = socket.socket(socket.AF_INET, socket.SOCK_STREAM) | |
| s.bind(("", 0)) | |
| port = s.getsockname()[1] | |
| s.close() | |
| return port | |
| def run_evaluation(test_set, host, port): | |
| """Przeprowadza testy wysy艂aj膮c 偶膮dania do FastAPI.""" | |
| raw_results = [] | |
| total = len(test_set) | |
| print(f"[*] Rozpoczynanie wysy艂ki {total} 偶膮da艅 do FastAPI...") | |
| for i, item in enumerate(test_set): | |
| # Generujemy lokalny URL prowadz膮cy do naszego tymczasowego serwera HTTP | |
| image_url = f"http://{host}:{port}/{item['local_filename']}" | |
| payload = { | |
| "guild_id": TEST_GUILD_ID, | |
| "user_id": f"eval_user_img_{i}", # Obej艣cie limitera | |
| "image_url": image_url, | |
| "content_type": "image" | |
| } | |
| try: | |
| r = requests.post(f"{API_URL}/analyze", json=payload) | |
| if r.status_code == 200: | |
| data = r.json() | |
| is_deepfake_pred = data["is_deepfake"] | |
| confidence = data["confidence"] | |
| analysis_time = data["analysis_time"] | |
| used_model = data["used_model"] | |
| raw_results.append({ | |
| "id": i, | |
| "ground_truth": item["is_fake_ground_truth"], | |
| "predicted": is_deepfake_pred, | |
| "confidence": confidence, | |
| "analysis_time": analysis_time, | |
| "used_model": used_model, | |
| "status": "SUCCESS" | |
| }) | |
| print(f"[{i+1}/{total}] OK | GT: {item['is_fake_ground_truth']} | PRED: {is_deepfake_pred} | Conf: {confidence:.2f}") | |
| else: | |
| print(f"[{i+1}/{total}] B艂膮d API ({r.status_code}): {r.text}") | |
| raw_results.append({"id": i, "status": f"API_ERROR_{r.status_code}", "ground_truth": item["is_fake_ground_truth"]}) | |
| except Exception as e: | |
| print(f"[{i+1}/{total}] B艂膮d po艂膮czenia: {e}") | |
| raw_results.append({"id": i, "status": "CONNECTION_ERROR", "ground_truth": item["is_fake_ground_truth"]}) | |
| return raw_results | |
| def process_and_save_results(raw_results): | |
| """Wylicza metryki, zapisuje raporty oraz generuje wykresy.""" | |
| df_all = pd.DataFrame(raw_results) | |
| df_all.to_csv("image_evaluation_raw_results.csv", index=False, encoding="utf-8") | |
| print("[+] Zapisano surowe wyniki do: image_evaluation_raw_results.csv") | |
| df_success = df_all[df_all["status"] == "SUCCESS"].copy() | |
| if df_success.empty: | |
| print("[-] Brak pomy艣lnych wynik贸w analizy. Wykresy i raporty nie zostan膮 wygenerowane.") | |
| return | |
| y_true = df_success["ground_truth"].astype(bool).tolist() | |
| y_pred = df_success["predicted"].astype(bool).tolist() | |
| y_prob_fake = [] | |
| for _, row in df_success.iterrows(): | |
| conf = row["confidence"] | |
| pred = row["predicted"] | |
| y_prob_fake.append(conf if pred else 1.0 - conf) | |
| acc = accuracy_score(y_true, y_pred) | |
| report = classification_report(y_true, y_pred, target_names=["REAL_IMAGE", "AI_GENERATED"]) | |
| avg_time = df_success["analysis_time"].mean() | |
| report_filename = "image_evaluation_summary_report.txt" | |
| with open(report_filename, "w", encoding="utf-8") as f: | |
| f.write("==================================================\n") | |
| f.write(" RAPORT JAKO艢CI DETEKCJI OBRAZ脫W (DEEPFAKE) \n") | |
| f.write("==================================================\n") | |
| f.write(f"Zanalizowano pomy艣lnie pr贸bki: {len(df_success)} / {len(df_all)}\n") | |
| f.write(f"Og贸lna dok艂adno艣膰 (Accuracy): {acc:.2%}\n") | |
| f.write(f"艢redni czas analizy: {avg_time:.3f} sekundy\n\n") | |
| f.write("Szczeg贸艂owe metryki klasyfikacji:\n") | |
| f.write(report) | |
| f.write("==================================================\n") | |
| print(f"[+] Zapisano tekstowy raport ko艅cowy do: {report_filename}") | |
| print("\n" + "="*50 + "\n" + f"DOK艁ADNO艢膯 SYSTEMU (OBRAZY): {acc:.2%}" + "\n" + "="*50) | |
| print(report) | |
| # Wykres: Confusion Matrix | |
| cm = confusion_matrix(y_true, y_pred) | |
| plt.figure(figsize=(6, 5)) | |
| sns.heatmap( | |
| cm, annot=True, fmt="d", cmap="Oranges", | |
| xticklabels=["REAL_IMAGE", "AI_GENERATED"], | |
| yticklabels=["REAL_IMAGE", "AI_GENERATED"] | |
| ) | |
| plt.title("Macierz Pomy艂ek (Image Confusion Matrix)") | |
| plt.ylabel("Warto艣膰 Rzeczywista") | |
| plt.xlabel("Warto艣膰 Przewidziana") | |
| plt.tight_layout() | |
| plt.savefig("image_confusion_matrix.png") | |
| print("[+] Wygenerowano wykres: image_confusion_matrix.png") | |
| plt.close() | |
| # Wykres: Krzywa ROC | |
| fpr, tpr, _ = roc_curve(y_true, y_prob_fake) | |
| roc_auc = auc(fpr, tpr) | |
| plt.figure(figsize=(6, 5)) | |
| plt.plot(fpr, tpr, color="orangered", lw=2, label=f"Krzywa ROC (AUC = {roc_auc:.2f})") | |
| plt.plot([0, 1], [0, 1], color="navy", lw=2, linestyle="--") | |
| plt.xlim([0.0, 1.0]) | |
| plt.ylim([0.0, 1.05]) | |
| plt.xlabel("False Positive Rate (1 - Specyficzno艣膰)") | |
| plt.ylabel("True Positive Rate (Czu艂o艣膰)") | |
| plt.title("Krzywa ROC (Detekcja Obrazu)") | |
| plt.legend(loc="lower right") | |
| plt.tight_layout() | |
| plt.savefig("image_roc_curve.png") | |
| print("[+] Wygenerowano wykres: image_roc_curve.png") | |
| plt.close() | |
| if __name__ == "__main__": | |
| setup_test_guild() | |
| test_set = prepare_dataset(SAMPLE_SIZE) | |
| # Przygotowujemy tymczasowy folder i zapisujemy do niego obrazy | |
| if os.path.exists(TEMP_DIR): | |
| shutil.rmtree(TEMP_DIR) | |
| os.makedirs(TEMP_DIR, exist_ok=True) | |
| print("[*] Zapisywanie obraz贸w do katalogu tymczasowego...") | |
| for idx, item in enumerate(test_set): | |
| filename = f"img_{idx}.jpg" | |
| item["image"].save(os.path.join(TEMP_DIR, filename)) | |
| item["local_filename"] = filename | |
| # Uruchamiamy lokalny serwer HTTP w tle na losowym wolnym porcie | |
| host = "127.0.0.1" | |
| port = find_free_port() | |
| handler_factory = partial(SimpleHTTPRequestHandler, directory=TEMP_DIR) | |
| server = HTTPServer((host, port), handler_factory) | |
| server_thread = threading.Thread(target=server.serve_forever) | |
| server_thread.daemon = True | |
| server_thread.start() | |
| print(f"[+] Uruchomiono asynchroniczny lokalny serwer HTTP na http://{host}:{port}/") | |
| # Wykonujemy testy | |
| raw_results = run_evaluation(test_set, host, port) | |
| # Wy艂膮czamy serwer i sprz膮tamy folder | |
| print("[*] Zatrzymywanie lokalnego serwera i czyszczenie plik贸w tymczasowych...") | |
| server.shutdown() | |
| server.server_close() | |
| shutil.rmtree(TEMP_DIR) | |
| # Analizujemy i zapisujemy wyniki | |
| process_and_save_results(raw_results) |