import gradio as gr from transformers import pipeline import re import torch import timm from PIL import Image import numpy as np import base64 from io import BytesIO try: eva02_model = timm.create_model('hf_hub:SmilingWolf/wd-eva02-large-tagger-v3', pretrained=True) eva02_model.eval() import requests tags_response = requests.get('https://huggingface.co/SmilingWolf/wd-eva02-large-tagger-v3/resolve/main/selected_tags.csv') tags_lines = tags_response.text.strip().split('\n') eva02_tags = [line.split(',')[1] for line in tags_lines[1:]] print(f"Modelo EVA02 carregado com {len(eva02_tags)} tags") except Exception as e: print(f"Erro ao carregar EVA02: {e}") eva02_model = None eva02_tags = [] content_model = pipeline("image-classification", model="facebook/convnext-base-224") nsfw_model = pipeline("image-classification", model="Falconsai/nsfw_image_detection") def decode_base64_image(base64_string): if ',' in base64_string: base64_string = base64_string.split(',')[1] try: image_data = base64.b64decode(base64_string) image = Image.open(BytesIO(image_data)) return image except Exception as e: print(f"Erro ao decodificar base64: {e}") return None def analyze_with_eva02(image): if eva02_model is None: return [], [] image_tensor = torch.from_numpy(np.array(image)).permute(2, 0, 1).float() / 255.0 image_tensor = torch.nn.functional.interpolate( image_tensor.unsqueeze(0), size=(448, 448), mode='bilinear', align_corners=False ) with torch.no_grad(): features = eva02_model(image_tensor) probs = torch.sigmoid(features[0]) detected_tags = [] tag_scores = [] for i, (tag, prob) in enumerate(zip(eva02_tags, probs)): if prob > 0.5: detected_tags.append(tag) tag_scores.append(float(prob)) return detected_tags, tag_scores def analyze_image(image_input, base64_input=None): image = None if base64_input and isinstance(base64_input, str) and base64_input.strip(): image = decode_base64_image(base64_input) if image is None: return { "content": "unknown", "adult_content": False, "violence": False, "sensitive_content": False, "content_description": "Erro ao processar imagem base64." } elif image_input is not None: image = image_input else: return { "content": "unknown", "adult_content": False, "violence": False, "sensitive_content": False, "content_description": "Nenhuma imagem fornecida." } if isinstance(image, np.ndarray): image = Image.fromarray(image) if eva02_model is not None: eva02_tags_detected, eva02_scores = analyze_with_eva02(image) combined_labels = " ".join(eva02_tags_detected).lower() print(f"EVA02 detectou: {eva02_tags_detected}") else: content_preds = content_model(image) top_content = max(content_preds, key=lambda x: x["score"]) nsfw_preds = nsfw_model(image) top_nsfw = max(nsfw_preds, key=lambda x: x["score"]) all_labels = [] for pred in content_preds: all_labels.append(pred["label"].lower()) for pred in nsfw_preds: all_labels.append(pred["label"].lower()) combined_labels = " ".join(all_labels) human_keywords = [ "1boy", "1girl", "2boys", "2girls", "multiple boys", "multiple girls", "human", "person", "people", "man", "woman", "child", "baby", "boy", "girl", "face", "portrait", "selfie", "crowd", "family", "couple", "teenager", "male", "female", "adult", "teen", "kid", "toddler", "infant" ] dog_keywords = [ "1dog", "2dogs", "multiple dogs", "dog", "puppy", "retriever", "labrador", "golden", "beagle", "bulldog", "poodle", "german shepherd", "chihuahua", "terrier", "hound", "mastiff", "canine", "pet", "animal", "malamute", "malemute", "alaskan", "doggy", "doggie", "pup", "husky", "border collie", "dachshund", "boxer", "rottweiler", "siberian husky", "australian shepherd" ] human_count = sum(1 for keyword in human_keywords if keyword in combined_labels) dog_count = sum(1 for keyword in dog_keywords if keyword in combined_labels) if dog_count > 0 and human_count > 0: if dog_count >= human_count: is_dog = True is_human = False else: is_dog = False is_human = True elif dog_count > 0: is_dog = True is_human = False elif human_count > 0: is_dog = False is_human = True else: is_dog = False is_human = False violence_keywords = [ "blood", "wound", "injury", "hurt", "pain", "fight", "violence", "weapon", "knife", "gun", "attack", "aggression", "conflict", "battle", "war", "bloody", "injured", "wounded", "bleeding", "scar", "bruise", "cut" ] suffering_keywords = [ "sad", "crying", "tears", "depressed", "miserable", "suffering", "pain", "distress", "anguish", "grief", "mourning", "funeral", "death", "dead", "dying", "illness", "sick", "injured", "abandoned", "neglected", "crying", "tears", "sad", "depressed", "miserable", "grief", "mourning" ] abuse_keywords = [ "abuse", "mistreatment", "cruelty", "torture", "beaten", "chained", "caged", "starving", "malnourished", "neglected", "abandoned", "chained", "caged", "starving", "malnourished", "abused", "mistreated" ] death_keywords = [ "death", "dead", "dying", "corpse", "carcass", "deceased", "lifeless", "motionless", "still", "rigid", "pale", "cold", "skull", "bones", "grave", "tombstone", "funeral", "coffin", "burial" ] suspicious_keywords = [ "unconscious", "motionless", "lifeless", "rigid", "cold", "pale", "injured", "wounded", "bleeding", "hurt", "pain", "distress", "abandoned", "neglected", "starving", "malnourished", "chained", "caged" ] normal_dog_behavior = [ "sleeping", "resting", "lying", "sitting", "playing", "running", "walking", "happy", "excited", "alert", "awake", "active", "energetic", "playful" ] if eva02_model is not None: adult_keywords = ["nsfw", "explicit", "nude", "naked", "sexual", "adult", "mature"] adult_content = any(keyword in combined_labels for keyword in adult_keywords) else: adult_content = top_nsfw["label"].lower() == "nsfw" violence = any(keyword in combined_labels for keyword in violence_keywords) suffering = any(keyword in combined_labels for keyword in suffering_keywords) abuse = any(keyword in combined_labels for keyword in abuse_keywords) death = any(keyword in combined_labels for keyword in death_keywords) has_suspicious_behavior = any(keyword in combined_labels for keyword in suspicious_keywords) has_normal_behavior = any(keyword in combined_labels for keyword in normal_dog_behavior) has_death_indicators = any(keyword in combined_labels for keyword in death_keywords) if is_dog: suspicious_animal = has_death_indicators or (has_suspicious_behavior and not has_normal_behavior) dead_dog = has_death_indicators else: suspicious_animal = has_suspicious_behavior dead_dog = False sensitive = adult_content or violence or suffering or abuse or death or suspicious_animal or dead_dog if is_human: content_type = "human" elif is_dog: content_type = "dog" else: content_type = "unknown" description_parts = [] if content_type == "human": description_parts.append("Imagem contendo pessoa(s)") elif content_type == "dog": description_parts.append("Imagem contendo cão/cachorro") else: description_parts.append(f"Imagem contendo {label}") if adult_content: description_parts.append("com conteúdo adulto") if violence: description_parts.append("com violência") if suffering: description_parts.append("mostrando sofrimento") if abuse: description_parts.append("com maus tratos") if death: description_parts.append("mostrando morte") if suspicious_animal: description_parts.append("com características suspeitas") if dead_dog: description_parts.append("morto") if sensitive: description_parts.append("- CONTEÚDO SENSÍVEL") else: description_parts.append("- conteúdo seguro") description = " ".join(description_parts) + "." detected_human_tags = [tag for tag in human_keywords if tag in combined_labels] detected_dog_tags = [tag for tag in dog_keywords if tag in combined_labels] detected_suspicious = [tag for tag in suspicious_keywords if tag in combined_labels] detected_normal = [tag for tag in normal_dog_behavior if tag in combined_labels] detected_death = [tag for tag in death_keywords if tag in combined_labels] debug_info = f" [Debug: Human({human_count}): {detected_human_tags}, Dog({dog_count}): {detected_dog_tags}, Suspicious: {detected_suspicious}, Normal: {detected_normal}, Death: {detected_death}]" return { "content": content_type, "adult_content": adult_content, "violence": violence, "sensitive_content": sensitive, "content_description": description + debug_info } demo = gr.Interface( fn=analyze_image, inputs=[ gr.Image(type="pil", label="Upload de Imagem ou Cole Base64"), gr.Textbox(label="Ou Cole String Base64 Aqui", lines=3, placeholder="data:image/jpeg;base64,/9j/4AAQ...") ], outputs="json", title="Dog / Human Safety Detector", description="Envie uma imagem ou cole uma string base64 para análise de moderação" ) if __name__ == "__main__": demo.launch()