Spaces:
Sleeping
Sleeping
File size: 6,029 Bytes
be0477a | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 | import streamlit as st
import google.generativeai as genai
from PIL import Image
import os
class ForensicVLMOrchestrator:
def __init__(self, mode="api"):
self.mode = mode
# Configura a API do Google Gemini
try:
api_key = st.secrets.get("GOOGLE_API_KEY")
except Exception:
api_key = os.environ.get("GOOGLE_API_KEY")
if api_key:
genai.configure(api_key=api_key)
self.model = genai.GenerativeModel('gemini-2.5-flash')
def _determine_typology(self, prob_swin, prob_clip):
if prob_swin > prob_clip:
return "uma imagem totalmente criada por computador (não existe na vida real)"
else:
return "uma fotografia verdadeira onde o rosto foi alterado ou trocado"
def _crop_artifact_zone(self, img_rgb, bbox):
if not bbox:
return img_rgb
h, w = img_rgb.shape[:2]
x1, y1, x2, y2 = bbox
x1, y1 = max(0, x1), max(0, y1)
x2, y2 = min(w, x2), min(h, y2)
crop = img_rgb[y1:y2, x1:x2]
if crop.size == 0:
return img_rgb
return crop
def build_forensic_prompt(self, prob_final, prob_swin, prob_clip, zones_list):
tipo_fraude = self._determine_typology(prob_swin, prob_clip)
prompt = (
f"Gere um relatório pericial objetivo e acessível a um público leigo.\n"
f"Analise o recorte da imagem.\n\n"
f"--- DADOS DO SISTEMA ---\n"
f"Certeza de fraude: {prob_final * 100:.1f}%\n"
f"Tipo de fraude: {tipo_fraude}\n"
f"Zonas com anomalias detetadas: {zones_list}\n"
f"-----------------------\n\n"
f"REGRAS OBRIGATÓRIAS:\n"
f"1. Escreva exatamente 4 frases num único parágrafo, em Português de Portugal.\n"
f"2. PROIBIDO usar a primeira pessoa (eu, vejo, noto, acho). Use exclusivamente voz impessoal e formal.\n"
f"3. PROIBIDO usar calão ou jargão técnico (IA, algoritmo, síntese, CLIP, Swin, artefactos, píxeis).\n"
f"4. FRASE 1: Identifique as zonas afetadas ({zones_list}) e descreva os defeitos visuais presentes. Utilize conceitos reais de análise de imagem.\n"
f"5. FRASE 2: Indique que estas inconsistências visuais evidenciam tratar-se de {tipo_fraude}.\n"
f"6. FRASE 3: Descreva características globais da imagem que não são condizentes com uma fotografia genuína.\n"
f"7. FRASE 4: Conclua EXATAMENTE com: 'O sistema tem {prob_final * 100:.1f}% de certeza de que esta imagem é falsa.'\n"
)
return prompt
def build_real_prompt(self, prob_final):
"""Prompt para imagens classificadas como genuínas."""
certeza = (1.0 - prob_final) * 100
return (
f"Gere um relatório pericial objetivo e acessível a um público leigo.\n"
f"Analise o recorte da imagem.\n\n"
f"--- DADOS DO SISTEMA ---\n"
f"Certeza de autenticidade: {certeza:.1f}%\n"
f"-----------------------\n\n"
f"REGRAS OBRIGATÓRIAS:\n"
f"1. Escreva exatamente 3 frases num único parágrafo, em Português de Portugal.\n"
f"2. PROIBIDO usar a primeira pessoa. Use exclusivamente voz impessoal e formal.\n"
f"3. PROIBIDO usar jargão técnico (IA, algoritmo, CLIP, Swin, píxeis, artefactos).\n"
f"4. FRASE 1: Descreva características visuais que evidenciam autenticidade "
f"(ex: textura dérmica natural com imperfeições orgânicas, iluminação coerente, "
f"transições faciais fluidas, ausência de marcas de sobreposição).\n"
f"5. FRASE 2: Indique que não foram identificadas inconsistências visuais "
f"características de manipulação digital ou síntese artificial.\n"
f"6. FRASE 3: Conclua EXATAMENTE com: "
f"'O sistema tem {certeza:.1f}% de certeza de que esta imagem é genuína.'\n"
)
def generate_real_justification(self, img_rgb, prob_final):
"""Gera relatório de autenticidade para imagens classificadas como reais."""
if not hasattr(self, "model"):
return "Erro: Google API Key não configurada."
pil_img = Image.fromarray(img_rgb)
pil_img.thumbnail((512, 512), Image.Resampling.BICUBIC)
prompt = self.build_real_prompt(prob_final)
try:
response = self.model.generate_content(
[prompt, pil_img],
stream=True,
generation_config={"temperature": 0.1}
)
def stream_generator():
for chunk in response:
if chunk.text:
yield chunk.text
return stream_generator()
except Exception as e:
return f"Erro na chamada à API Gemini: {str(e)}"
def generate_justification(self, img_rgb, prob_final, prob_swin, prob_clip, zone_name, bbox):
crop_rgb = self._crop_artifact_zone(img_rgb, bbox)
prompt = self.build_forensic_prompt(prob_final, prob_swin, prob_clip, zone_name)
if not hasattr(self, 'model'):
return "Erro: Google API Key não configurada."
# Preparar imagem (Thumb para otimizar token/latência)
pil_img = Image.fromarray(crop_rgb)
pil_img.thumbnail((512, 512), Image.Resampling.BICUBIC)
try:
# Geração com streaming nativo do SDK do Gemini
response = self.model.generate_content(
[prompt, pil_img],
stream=True,
generation_config={"temperature": 0.1}
)
def stream_generator():
for chunk in response:
if chunk.text:
yield chunk.text
return stream_generator()
except Exception as e:
return f"Erro na chamada à API Gemini: {str(e)}" |