CoolFace
Apppublic

BugZoid/text-humanizer

sourceHugging Faceupdated 2y agoView on Hugging Face
5likes
app.py286 linesDownload Raw Back to root
1import streamlit as st2from transformers import T5ForConditionalGeneration, T5Tokenizer3import torch4from torch.utils.data import Dataset, DataLoader5import json6import os7from datetime import datetime8import tempfile9 10# Custom dataset for fine-tuning11class TextHumanizerDataset(Dataset):12    def __init__(self, data, tokenizer, max_length=512):13        self.data = data14        self.tokenizer = tokenizer15        self.max_length = max_length16 17    def __len__(self):18        return len(self.data)19 20    def __getitem__(self, idx):21        item = self.data[idx]22        input_encoding = self.tokenizer(23            f"reescreva em português natural, mantendo todas as informações: {item['input_text']}",24            max_length=self.max_length,25            padding='max_length',26            truncation=True,27            return_tensors='pt'28        )29        30        target_encoding = self.tokenizer(31            item['output_text'],32            max_length=self.max_length,33            padding='max_length',34            truncation=True,35            return_tensors='pt'36        )37 38        return {39            'input_ids': input_encoding['input_ids'].squeeze(),40            'attention_mask': input_encoding['attention_mask'].squeeze(),41            'labels': target_encoding['input_ids'].squeeze()42        }43 44def get_storage_path():45    """Retorna o caminho correto para armazenamento no Hugging Face Spaces"""46    if os.environ.get('SPACE_ID'):  # Verifica se está rodando no Spaces47        return '/data'  # Diretório persistente no Spaces48    else:49        # Fallback para desenvolvimento local50        temp_dir = tempfile.gettempdir()51        feedback_dir = os.path.join(temp_dir, 'feedback_data')52        os.makedirs(feedback_dir, exist_ok=True)53        return feedback_dir54 55def save_feedback(input_text, output_text, rating):56    """Salva o feedback do usuário para futuro treinamento"""57    feedback_data = {58        'input_text': input_text,59        'output_text': output_text,60        'rating': rating,61        'timestamp': datetime.now().isoformat()62    }63    64    storage_path = get_storage_path()65    feedback_file = os.path.join(storage_path, 'feedback.json')66    67    try:68        # Cria arquivo se não existir69        if not os.path.exists(feedback_file):70            with open(feedback_file, 'w') as f:71                f.write('')72        73        # Append do novo feedback74        with open(feedback_file, 'a') as f:75            f.write(json.dumps(feedback_data) + '\n')76            77        return True78    except Exception as e:79        st.error(f"Erro ao salvar feedback: {str(e)}")80        return False81 82def fine_tune_model():83    """Realiza fine-tuning do modelo com dados de feedback positivo"""84    storage_path = get_storage_path()85    feedback_file = os.path.join(storage_path, 'feedback.json')86    87    if not os.path.exists(feedback_file):88        return89    90    try:91        # Carrega dados de feedback92        positive_examples = []93        with open(feedback_file, 'r') as f:94            for line in f:95                if line.strip():  # Ignora linhas vazias96                    feedback = json.loads(line)97                    if feedback['rating'] >= 4:  # Usa apenas feedback positivo98                        positive_examples.append({99                            'input_text': feedback['input_text'],100                            'output_text': feedback['output_text']101                        })102        103        if not positive_examples:104            return105        106        # Cria dataset e dataloader107        dataset = TextHumanizerDataset(positive_examples, st.session_state.tokenizer)108        dataloader = DataLoader(dataset, batch_size=4, shuffle=True)109        110        # Configura otimizador111        optimizer = torch.optim.AdamW(st.session_state.model.parameters(), lr=1e-5)112        113        # Fine-tuning114        st.session_state.model.train()115        for batch in dataloader:116            optimizer.zero_grad()117            outputs = st.session_state.model(118                input_ids=batch['input_ids'],119                attention_mask=batch['attention_mask'],120                labels=batch['labels']121            )122            loss = outputs.loss123            loss.backward()124            optimizer.step()125        126        st.session_state.model.eval()127        return True128    129    except Exception as e:130        st.error(f"Erro durante o fine-tuning: {str(e)}")131        return False132 133def clean_generated_text(text):134    """Remove comandos e limpa o texto gerado"""135    text = text.strip()136 137    # Lista de prefixos de comando para remover138    prefixes = [139        "reescreva o seguinte texto",140        "reescreva este texto",141        "reescreva o texto",142        "traduza",143        "humanize:",144        "humanizar:",145        "em português",146        "de forma mais natural"147    ]148 149    # Remove os prefixos de comando150    text_lower = text.lower()151    for prefix in prefixes:152        if text_lower.startswith(prefix):153            text = text[len(prefix):].strip()154            text_lower = text.lower()155    156    # Capitaliza a primeira letra157    if text:158        text = text[0].upper() + text[1:]159    160    return text161 162def humanize_text(text):163    """Humaniza o texto mantendo coerência e tamanho"""164    prompt = f"reescreva em português natural, mantendo todas as informações: {text}"165    166    # Tokenização com padding167    inputs = st.session_state.tokenizer(168        prompt,169        return_tensors="pt",170        max_length=512,  # Reduzido para evitar problemas de memória171        padding=True,172        truncation=True173    )174 175    # Parâmetros mais conservadores para geração176    try:177        outputs = st.session_state.model.generate(178            inputs.input_ids,179            max_length=512,  # Reduzido para maior estabilidade180            min_length=int(len(text.split()) * 0.8),  # Garante pelo menos 80% do tamanho original181            do_sample=False,  # Desativa amostragem para maior estabilidade182            num_beams=2,      # Reduzido para evitar problemas de memória183            repetition_penalty=1.1,  # Reduzido para evitar instabilidades184            length_penalty=1.0,      # Valor neutro185            early_stopping=True,     # Ativa early stopping186            no_repeat_ngram_size=2   # Evita repetições de bigramas187        )188        189        result = st.session_state.tokenizer.decode(outputs[0], skip_special_tokens=True)190        result = clean_generated_text(result)191        192        # Garante tamanho mínimo de forma mais suave193        if len(result.split()) < len(text.split()):194            missing_words = len(text.split()) - len(result.split())195            original_words = text.split()[-missing_words:]196            result = result + " " + " ".join(original_words)197        198        return result199        200    except Exception as e:201        st.error(f"Erro durante a geração: {str(e)}")202        # Fallback: retorna o texto original em caso de erro203        return text204 205# Initialize session state206if 'model_loaded' not in st.session_state:207    st.session_state.tokenizer = T5Tokenizer.from_pretrained("t5-base")208    st.session_state.model = T5ForConditionalGeneration.from_pretrained("t5-base")209    st.session_state.model_loaded = True210 211# UI Components212st.set_page_config(page_title="Advanced Text Humanizer", page_icon="🤖")213 214st.title("🤖 → 🧑 Humanizador de Texto Avançado")215st.markdown("""216Este aplicativo transforma textos robotizados em linguagem mais natural e humana, 217mantendo todas as informações originais e incluindo sistema de feedback para melhoria contínua.218""")219 220# Input area221input_text = st.text_area(222    "Cole seu texto de robô aqui:",223    height=150,224    help="Cole seu texto aqui para transformá-lo em uma versão mais natural e humana."225)226 227# Process button and results228if st.button("Humanizar", type="primary"):229    if not input_text:230        st.warning("⚠️ Por favor, cole um texto primeiro!")231    else:232        with st.spinner("Processando o texto..."):233            try:234                final_text = humanize_text(input_text)235                236                # Display results237                st.success("✨ Texto humanizado:")238                col1, col2 = st.columns(2)239                240                with col1:241                    st.text("Original:")242                    st.info(input_text)243                    st.write(f"Palavras: {len(input_text.split())}")244                245                with col2:246                    st.text("Resultado:")247                    st.info(final_text)248                    st.write(f"Palavras: {len(final_text.split())}")249                250                # Feedback section251                st.markdown("### Feedback")252                rating = st.slider(253                    "Como você avalia a qualidade do texto humanizado?",254                    min_value=1,255                    max_value=5,256                    value=3,257                    help="1 = Muito ruim, 5 = Excelente"258                )259                260                if st.button("Enviar Feedback"):261                    if save_feedback(input_text, final_text, rating):262                        st.success("Feedback salvo com sucesso! Obrigado pela contribuição.")263                        264                        # Trigger fine-tuning if we have enough positive feedback265                        if rating >= 4:266                            with st.spinner("Atualizando modelo com seu feedback..."):267                                if fine_tune_model():268                                    st.success("Modelo atualizado com sucesso!")269                                else:270                                    st.warning("Não foi possível atualizar o modelo neste momento.")271                    else:272                        st.error("Não foi possível salvar o feedback. Tente novamente mais tarde.")273                274            except Exception as e:275                st.error(f"❌ Erro no processamento: {str(e)}")276 277# Footer278st.markdown("---")279st.markdown(280    """281    <div style='text-align: center'>282        <small>Desenvolvido com ❤️ usando Streamlit e Transformers</small>283    </div>284    """,285    unsafe_allow_html=True286)