Spaces:
Runtime error
Runtime error
| import gradio as gr | |
| from nudenet import NudeDetector | |
| from PIL import Image, ImageDraw | |
| import open_clip | |
| import torch | |
| import tempfile | |
| import os | |
| # Globale Initialisierung | |
| detector = NudeDetector() | |
| # OpenCLIP für Barbie-Score (schnelles Modell) | |
| device = "cuda" if torch.cuda.is_available() else "cpu" | |
| model, _, preprocess = open_clip.create_model_and_transforms( | |
| 'ViT-B-32-quickgelu', pretrained='laion400m_e32' | |
| ) | |
| model = model.to(device) | |
| model.eval() | |
| barbie_templates = [ | |
| "a perfect barbie vulva, smooth innie, completely hidden labia minora, tight clean slit, aesthetic", | |
| "very beautiful barbie style vagina, no protruding lips, minimalist and smooth", | |
| "ideal barbie pussy, flat and tucked inner labia, neat appearance" | |
| ] | |
| non_barbie_templates = [ | |
| "protruding labia minora, visible inner lips, outie vulva", | |
| "natural vulva with hanging labia minora, realistic", | |
| "asymmetrical outie vagina, detailed natural form" | |
| ] | |
| def clip_barbie_score(cropped_img: Image.Image) -> float: | |
| """0.0–1.0 Nähe zur Barbie-Form""" | |
| try: | |
| image = preprocess(cropped_img).unsqueeze(0).to(device) | |
| with torch.no_grad(): | |
| image_features = model.encode_image(image) | |
| all_texts = barbie_templates + non_barbie_templates | |
| text_tokens = open_clip.tokenize(all_texts).to(device) | |
| text_features = model.encode_text(text_tokens) | |
| similarities = (image_features @ text_features.T).softmax(dim=-1)[0] | |
| barbie_prob = similarities[:len(barbie_templates)].mean().item() | |
| return barbie_prob | |
| except Exception: | |
| return 0.0 | |
| def analyze_image(pil_image: Image.Image): | |
| if pil_image is None: | |
| return "Bitte lade ein Bild hoch.", None | |
| # Temporäre Datei für NudeNet | |
| with tempfile.NamedTemporaryFile(suffix=".jpg", delete=False) as tmp: | |
| temp_path = tmp.name | |
| pil_image.save(temp_path) | |
| try: | |
| detections = detector.detect(temp_path) | |
| finally: | |
| if os.path.exists(temp_path): | |
| os.unlink(temp_path) | |
| # Detektionen filtern | |
| breast_dets = [d for d in detections if d.get("class") == "FEMALE_BREAST_EXPOSED"] | |
| vagina_dets = [d for d in detections if d.get("class") == "FEMALE_GENITALIA_EXPOSED"] | |
| # Annotiertes Bild (Kopie) | |
| annotated = pil_image.copy() | |
| draw = ImageDraw.Draw(annotated) | |
| # Brüste analysieren | |
| breast_text = "**Brüste**: Nicht erkannt → Größenbewertung 0/5" | |
| if breast_dets: | |
| # Prominenteste Brust | |
| best_breast = max(breast_dets, key=lambda d: d["score"]) | |
| b = best_breast["bbox"] # [x_min, y_min, x_max, y_max] | |
| # Alle Brüste zeichnen | |
| for d in breast_dets: | |
| bb = d["bbox"] | |
| draw.rectangle([bb[0], bb[1], bb[2], bb[3]], outline="red", width=5) | |
| # Relative Größe berechnen | |
| width = b[2] - b[0] | |
| height = b[3] - b[1] | |
| area = width * height | |
| img_area = pil_image.size[0] * pil_image.size[1] | |
| rel_area = area / img_area | |
| # Heuristik 1-5 | |
| if rel_area < 0.04: | |
| size_pts = 1 | |
| elif rel_area < 0.07: | |
| size_pts = 2 | |
| elif rel_area < 0.11: | |
| size_pts = 3 | |
| elif rel_area < 0.16: | |
| size_pts = 4 | |
| else: | |
| size_pts = 5 | |
| breast_text = ( | |
| f"**Brüste erkannt** (max. Konfidenz: {best_breast['score']:.2f})\n" | |
| f"**Größenbewertung**: **{size_pts}/5** (rel. Fläche: {rel_area:.2%})" | |
| ) | |
| # Vagina analysieren (Barbie-Form) | |
| vagina_text = "**Vagina**: Nicht erkannt → Barbie-Bewertung 0/5" | |
| if vagina_dets: | |
| best_vag = max(vagina_dets, key=lambda d: d["score"]) | |
| b = [int(x) for x in best_vag["bbox"]] | |
| # Alle Vagina-Boxen zeichnen | |
| for d in vagina_dets: | |
| bb = [int(x) for x in d["bbox"]] | |
| draw.rectangle(bb, outline="blue", width=5) | |
| # Crop mit Padding | |
| pad = 30 | |
| crop_box = ( | |
| max(0, b[0] - pad), | |
| max(0, b[1] - pad), | |
| min(pil_image.size[0], b[2] + pad), | |
| min(pil_image.size[1], b[3] + pad) | |
| ) | |
| cropped = pil_image.crop(crop_box) | |
| barbie_prob = clip_barbie_score(cropped) | |
| barbie_pts = round(barbie_prob * 5, 1) | |
| vagina_text = ( | |
| f"**Vagina erkannt** (max. Konfidenz: {best_vag['score']:.2f})\n" | |
| f"**Barbie-Form-Bewertung**: **{barbie_pts}/5** (Ähnlichkeit: {barbie_prob:.1%})\n" | |
| "→ Je glatter und 'innie'-artiger, desto höher der Score." | |
| ) | |
| result_md = f"""**Analyse-Ergebnis** | |
| **Brüste** | |
| {breast_text} | |
| **Vagina (Barbie-Form)** | |
| {vagina_text} | |
| **Hinweis**: Dies ist eine rein technische, heuristische KI-Analyse. Natürliche Vulven und Brüste sind extrem vielfältig. Die „Barbie-Form“ ist ein künstliches Ideal aus Medien und Chirurgie – sie ist **nicht** der Normalfall und kein Maß für Schönheit oder Wert. | |
| """ | |
| return result_md, annotated | |
| # Gradio Interface | |
| iface = gr.Interface( | |
| fn=analyze_image, | |
| inputs=gr.Image(type="pil", label="Bild hochladen"), | |
| outputs=[ | |
| gr.Markdown(label="Analyse & Bewertung"), | |
| gr.Image(label="Bild mit Markierungen (rot=Brüste, blau=Vagina)") | |
| ], | |
| title="NSFW Analyse Tool – Brust & Vagina (Größe + Barbie-Form)", | |
| description=( | |
| "Automatische Erkennung und Bewertung (1–5 Punkte).\n\n" | |
| "**STRENGE WARNUNG**: Nur für erwachsene, einvernehmliche, private Nutzung mit eigenen Bildern!\n" | |
| "Keine Speicherung. Kein medizinischer oder ästhetischer Rat. " | |
| "Natürliche Körpervielfalt ist normal." | |
| ), | |
| allow_flagging="never", | |
| () | |
| ) | |
| if __name__ == "__main__": | |
| iface.launch( | |
| server_name="0.0.0.0", | |
| server_port=7860, | |
| share=False, # Auf True setzen für öffentlichen Link (nicht empfohlen) | |
| show_error=True | |
| ) |