Implementação Prática de Correspondência Multimodal para Conteúdo de Vídeos
Este sistema automatiza a verificação de consistência entre thumbnailss e títulos de vídeos curtos, utilizando o modelo CLIP-GmP-ViT-L-14. A solução opera localmente, preservando privacidade dos dados e oferecendo processamento eficiente sem depandência de serviços externos.
Para configurar o ambiente, execute os seguintes comandos no terminal:
pip install torch torchvision transformers pillow streamlit
Em seguida, crie um script Python com a seguinte estrutura:
import streamlit as st
import torch
from PIL import Image
from transformers import CLIPProcessor, CLIPModel
import warnings
warnings.filterwarnings("ignore")
st.set_page_config(page_title="Ferramenta de Correspondência Multimodal", layout="wide")
st.title("CLIP-GmP-ViT-L-14 - Correspondência Imagem-Texto")
st.markdown("Envie uma imagem e insira múltiplas descrições textuais (separadas por vírgulas). A ferramenta calculará e classificará a correspondência entre cada descrição e a imagem.")
@st.cache_resource
def carregar_modelo_multimodal():
identificador_modelo = "openai/clip-vit-large-patch14"
try:
modelo = CLIPModel.from_pretrained(identificador_modelo)
processador = CLIPProcessor.from_pretrained(identificador_modelo)
return modelo, processador
except Exception as erro:
st.error(f"Falha ao carregar modelo: {erro}")
return None, None
modelo, processador = carregar_modelo_multimodal()
if modelo is None or processador is None:
st.stop()
coluna_esquerda, coluna_direita = st.columns([1, 2])
with coluna_esquerda:
st.subheader("📷 Envio de Imagem")
arquivo_imagem = st.file_uploader("Selecione uma imagem para análise", type=["jpg", "jpeg", "png"])
if arquivo_imagem:
img = Image.open(arquivo_imagem).convert("RGB")
st.image(img, caption="Imagem carregada", width=300)
st.success("Imagem processada com sucesso!")
else:
st.info("Aguardando upload da imagem...")
img = None
with coluna_direita:
st.subheader("📝 Descrições Textuais")
exemplos_descricoes = "cachorro brincando no parque, gato dormindo no sofá, carro vermelho na rua, prato de comida deliciosa"
descricoes_input = st.text_area(
"Insira descrições separadas por vírgulas",
value=exemplos_descricoes,
height=100,
help="Exemplo: praia ensolarada, rua movimentada, floresta tranquila"
)
if descricoes_input:
lista_descricoes = [t.strip() for t in descricoes_input.split(",") if t.strip()]
else:
lista_descricoes = []
st.subheader("🚀 Resultados da Análise")
if st.button("Iniciar Análise", type="primary") and img and lista_descricoes:
with st.spinner("Processando similaridade..."):
try:
entradas = processador(text=lista_descricoes, images=img, return_tensors="pt", padding=True)
with torch.no_grad():
saidas = modelo(**entradas)
pontuacoes_imagem = saidas.logits_per_image
probabilidades = pontuacoes_imagem.softmax(dim=1).squeeze().tolist()
resultados = list(zip(lista_descricoes, probabilidades))
resultados.sort(key=lambda x: x[1], reverse=True)
st.markdown("### 📊 Classificação por Correspondência (ordem decrescente)")
for descricao, confianca in resultados:
st.write(f"**{descricao}**")
st.progress(confianca, text=f"{confianca * 100:.2f}%")
st.write("")
except Exception as erro:
st.error(f"Erro durante processamento: {erro}")
elif st.button("Iniciar Análise"):
if not img:
st.warning("Por favor, envie uma imagem primeiro.")
elif not lista_descricoes:
st.warning("Insira pelo menos uma descrição textual.")
# Script para análise em lote
import os
from PIL import Image
from transformers import CLIPProcessor, CLIPModel
import torch
print("Carregando modelo CLIP...")
modelo = CLIPModel.from_pretrained("openai/clip-vit-large-patch14")
processador = CLIPProcessor.from_pretrained("openai/clip-vit-large-patch14")
print("Modelo carregado com sucesso!")
palavras_positivas = ["tutorial", "comida", "esportes", "musica", "pet"]
palavras_alerta = ["chocante", "você não vai acreditar", "ganhe dinheiro rápido", "emergência", "clickbait"]
diretorio_thumbnails = "./thumbnails_videos"
arquivos_imagem = [f for f in os.listdir(diretorio_thumbnails) if f.endswith(('.jpg', '.png', '.jpeg'))]
if not arquivos_imagem:
print("Nenhuma imagem encontrada no diretório.")
exit()
for img_file in arquivos_imagem:
print(f"\n=== Analisando thumbnail: {img_file} ===")
caminho_imagem = os.path.join(diretorio_thumbnails, img_file)
try:
imagem = Image.open(caminho_imagem).convert("RGB")
except Exception as erro:
print(f" Erro: não foi possível abrir {img_file}: {erro}")
continue
todas_palavras = palavras_positivas + palavras_alerta
entradas = processador(text=todas_palavras, images=imagem, return_tensors="pt", padding=True)
with torch.no_grad():
saidas = modelo(**entradas)
pontuacoes = saidas.logits_per_image.softmax(dim=1).squeeze().tolist()
resultados = list(zip(todas_palavras, pontuacoes))
top_3 = sorted(resultados, key=lambda x: x[1], reverse=True)[:3]
print(" Top 3 palavras-chave:")
for kw, score in top_3:
print(f" - '{kw}': {score * 100:.1f}%")
palavra_top, pontuacao_top = top_3[0]
limiar_alerta = 0.3
if palavra_top in palavras_alerta and pontuacao_top > limiar_alerta:
print(f" ⚠️ [Alerta] Thumbnail pode ser clickbait! Palavra '{palavra_top}' (confiança {pontuacao_top * 100:.1f}%) está na lista de alerta.")
elif palavra_top in palavras_positivas:
print(f" ✅ Correspondência alta com '{palavra_top}', conteúdo consistente.")
else:
print(f" ℹ️ Análise concluída, sem regras ativadas.")
print("\nProcessamento em lote finalizado!")