Spaces:
Sleeping
Sleeping
| import streamlit as st | |
| import torch | |
| from transformers import AutoTokenizer, AutoModelForSequenceClassification | |
| from urllib.parse import urlparse | |
| import pandas as pd | |
| import io | |
| # --- CONFIGURAÇÕES --- | |
| # ⚠️ TROQUE PELO SEU USUÁRIO/MODELO NO HUGGING FACE | |
| MODEL_ID = "asilvamaia/ident_br" | |
| # Configuração da Página | |
| st.set_page_config(page_title="Validador de Domínios .BR", page_icon="🇧🇷") | |
| # --- FUNÇÃO DE LIMPEZA (V11) --- | |
| def limpar_entrada(texto: str) -> str: | |
| texto = str(texto).strip().lower() | |
| if not texto: return "" | |
| if "@" in texto: return texto # Mantém e-mail para rejeição | |
| if "http" not in texto and "://" not in texto: | |
| texto_temp = "http://" + texto | |
| else: | |
| texto_temp = texto | |
| try: | |
| parsed = urlparse(texto_temp) | |
| dominio_limpo = parsed.netloc if parsed.netloc else texto | |
| if ":" in dominio_limpo: # Remove porta | |
| dominio_limpo = dominio_limpo.split(':')[0] | |
| if dominio_limpo.startswith("www."): # Remove www | |
| dominio_limpo = dominio_limpo[4:] | |
| return dominio_limpo | |
| except: | |
| return texto | |
| # --- CARREGAMENTO DO MODELO (COM CACHE) --- | |
| # O cache impede que o modelo seja recarregado a cada clique, deixando o app rápido | |
| def load_model(): | |
| try: | |
| tokenizer = AutoTokenizer.from_pretrained(MODEL_ID) | |
| model = AutoModelForSequenceClassification.from_pretrained(MODEL_ID) | |
| # No Space gratuito usamos CPU | |
| model.to("cpu") | |
| model.eval() | |
| return tokenizer, model | |
| except Exception as e: | |
| st.error(f"Erro ao carregar o modelo: {e}") | |
| return None, None | |
| tokenizer, model = load_model() | |
| # --- INTERFACE --- | |
| st.title("🇧🇷 Validador de Domínios .BR com IA") | |
| st.write("Faça upload de uma lista suja (.txt) e a IA extrairá apenas os domínios .br válidos.") | |
| uploaded_file = st.file_uploader("Escolha um arquivo .txt", type="txt") | |
| if uploaded_file is not None and tokenizer is not None: | |
| # Lê o arquivo | |
| stringio = io.StringIO(uploaded_file.getvalue().decode("utf-8")) | |
| linhas = stringio.readlines() | |
| st.info(f"Arquivo carregado com {len(linhas)} linhas. Processando...") | |
| if st.button("Iniciar Limpeza"): | |
| validos = [] | |
| rejeitados = [] | |
| # Barra de progresso | |
| progress_bar = st.progress(0) | |
| # Processamento (Batch size 1 para simplicidade visual ou aumentar se precisar) | |
| # Como é CPU, vamos processar linha a linha para atualizar a barra | |
| for i, linha in enumerate(linhas): | |
| original = linha.strip() | |
| limpo = limpar_entrada(original) | |
| if not limpo: continue | |
| # Inferência | |
| inputs = tokenizer(limpo, return_tensors="pt", truncation=True, max_length=128) | |
| with torch.no_grad(): | |
| outputs = model(**inputs) | |
| pred = torch.argmax(outputs.logits, dim=1).item() | |
| # Regras de Validação | |
| if pred == 1 and "." in limpo and "@" not in limpo: | |
| validos.append(limpo) | |
| else: | |
| rejeitados.append(original) | |
| # Atualiza barra a cada 10 itens para não travar a UI | |
| if i % 10 == 0: | |
| progress_bar.progress((i + 1) / len(linhas)) | |
| progress_bar.progress(100) | |
| # --- RESULTADOS --- | |
| st.success("Processamento Concluído!") | |
| col1, col2 = st.columns(2) | |
| with col1: | |
| st.metric("✅ Aprovados", len(validos)) | |
| with col2: | |
| st.metric("🔴 Rejeitados", len(rejeitados)) | |
| # --- DOWNLOAD --- | |
| # Remove duplicatas | |
| validos_unicos = sorted(list(set(validos))) | |
| res_text = "\n".join(validos_unicos) | |
| st.download_button( | |
| label="⬇️ Baixar Lista Limpa (.txt)", | |
| data=res_text, | |
| file_name="dominios_limpos.txt", | |
| mime="text/plain" | |
| ) | |
| # Opcional: Mostrar amostra | |
| with st.expander("Ver amostra dos aprovados"): | |
| st.write(validos_unicos[:20]) |