Pular para o conteúdo
🧠Inteligência em Código
📚 Tutoriais17 min de leitura

Processamento de Linguagem Natural (NLP) com Python

Guia completo de NLP com Python — tokenização, NER, classificação de texto, análise de sentimento usando spaCy e Hugging Face Transformers com exemplos práticos

#nlp#spacy#transformers#python#texto#ia

Processamento de Linguagem Natural (NLP) com Python

Processamento de Linguagem Natural (NLP, do inglês Natural Language Processing) é o campo da inteligência artificial dedicado a ensinar computadores a entender, interpretar e gerar linguagem humana. De assistentes virtuais a tradutores automáticos, de análise de sentimento em redes sociais a chatbots inteligentes — NLP está por toda parte.

Neste tutorial, vamos explorar as principais técnicas de NLP usando Python, com foco em duas bibliotecas poderosas: spaCy para processamento linguístico tradicional e Hugging Face Transformers para técnicas modernas baseadas em deep learning.


Pré-requisitos

Instalação

# spaCy e modelo para português
pip install spacy
python -m spacy download pt_core_news_lg

# Modelo em inglês (opcional)
python -m spacy download en_core_web_sm

# Hugging Face Transformers
pip install transformers torch sentencepiece

# Bibliotecas auxiliares
pip install nltk scikit-learn pandas matplotlib wordcloud

Estrutura do Projeto

nlp-python/
├── src/
│   ├── tokenization.py        # Tokenização e processamento básico
│   ├── ner.py                 # Reconhecimento de Entidades Nomeadas
│   ├── classification.py     # Classificação de texto
│   ├── sentiment.py           # Análise de sentimento
│   ├── similarity.py          # Similaridade semântica
│   └── transformers_nlp.py   # NLP com Transformers
├── data/                      # Dados de exemplo
├── output/                    # Resultados
└── requirements.txt

Parte 1: Fundamentos com spaCy

Introdução ao spaCy

O spaCy é uma biblioteca industrial de NLP — rápida, eficiente e projetada para produção. Vamos começar pelo básico:

"""Fundamentos de NLP com spaCy."""

import spacy

# Carregar modelo para português
nlp = spacy.load("pt_core_news_lg")

# Processar um texto
texto = """A inteligência artificial está transformando o Brasil. 
Empresas como a Petrobras e o Banco do Brasil investem milhões em 
soluções de machine learning. São Paulo lidera a adoção, com mais de 
500 startups de IA registradas na Faria Lima."""

doc = nlp(texto)

# O objeto doc contém toda a análise linguística
print(f"Número de tokens: {len(doc)}")
print(f"Número de sentenças: {len(list(doc.sents))}")
print(f"Número de entidades: {len(doc.ents)}")

Parte 2: Tokenização e Análise Morfológica

Tokenização

Tokenização é o processo de dividir texto em unidades menores (tokens). É o primeiro passo em qualquer pipeline de NLP:

"""Tokenização e análise morfológica detalhada."""

import spacy
from collections import Counter

nlp = spacy.load("pt_core_news_lg")


def tokenize_and_analyze(text: str) -> dict:
    """Tokeniza e analisa morfologicamente um texto."""
    doc = nlp(text)
    
    analysis = {
        "tokens": [],
        "pos_distribution": Counter(),
        "lemmas": [],
        "sentences": [],
    }
    
    for token in doc:
        token_info = {
            "text": token.text,
            "lemma": token.lemma_,       # Forma base
            "pos": token.pos_,            # Part-of-speech (universal)
            "tag": token.tag_,            # POS tag detalhada
            "dep": token.dep_,            # Dependência sintática
            "shape": token.shape_,        # Forma (Xxxxx, dd, etc.)
            "is_alpha": token.is_alpha,   # É alfanumérico?
            "is_stop": token.is_stop,     # É stop word?
            "is_punct": token.is_punct,   # É pontuação?
        }
        analysis["tokens"].append(token_info)
        analysis["pos_distribution"][token.pos_] += 1
        
        if not token.is_stop and not token.is_punct and token.is_alpha:
            analysis["lemmas"].append(token.lemma_.lower())
    
    # Sentenças
    for sent in doc.sents:
        analysis["sentences"].append(sent.text.strip())
    
    return analysis


def print_token_table(text: str) -> None:
    """Imprime tabela detalhada de tokens."""
    doc = nlp(text)
    
    print(f"{'Token':<15} {'Lemma':<15} {'POS':<8} {'Dep':<10} {'Stop?':<6}")
    print("-" * 60)
    
    for token in doc:
        print(
            f"{token.text:<15} {token.lemma_:<15} {token.pos_:<8} "
            f"{token.dep_:<10} {str(token.is_stop):<6}"
        )


# Exemplo
text = "Os desenvolvedores brasileiros estão construindo aplicações incríveis de IA."
print_token_table(text)
analysis = tokenize_and_analyze(text)
print(f"\nDistribuição POS: {dict(analysis['pos_distribution'])}")
print(f"Lemmas (sem stops): {analysis['lemmas']}")

Análise de Stop Words e Frequência

def analyze_word_frequency(text: str, top_n: int = 20) -> dict:
    """Analisa frequência de palavras, removendo stop words."""
    doc = nlp(text)
    
    # Extrair tokens significativos (sem stop words, pontuação ou espaços)
    meaningful_tokens = [
        token.lemma_.lower()
        for token in doc
        if not token.is_stop
        and not token.is_punct
        and not token.is_space
        and token.is_alpha
        and len(token.text) > 2
    ]
    
    freq = Counter(meaningful_tokens)
    
    print(f"\nTop {top_n} palavras mais frequentes:")
    for word, count in freq.most_common(top_n):
        bar = "█" * count
        print(f"  {word:<20} {count:>4} {bar}")
    
    return {
        "total_tokens": len(doc),
        "unique_meaningful": len(set(meaningful_tokens)),
        "frequency": dict(freq.most_common(top_n)),
    }


def generate_wordcloud(text: str, output_path: str = "output/wordcloud.png") -> None:
    """Gera uma nuvem de palavras a partir de um texto."""
    from wordcloud import WordCloud
    import matplotlib.pyplot as plt
    from pathlib import Path
    
    doc = nlp(text)
    
    # Filtrar tokens
    words = " ".join([
        token.lemma_.lower()
        for token in doc
        if not token.is_stop and not token.is_punct
        and token.is_alpha and len(token.text) > 2
    ])
    
    wc = WordCloud(
        width=800,
        height=400,
        background_color="white",
        max_words=100,
        colormap="viridis",
    ).generate(words)
    
    Path(output_path).parent.mkdir(exist_ok=True)
    
    plt.figure(figsize=(16, 8))
    plt.imshow(wc, interpolation="bilinear")
    plt.axis("off")
    plt.tight_layout()
    plt.savefig(output_path, dpi=150, bbox_inches="tight")
    plt.close()
    
    print(f"Word cloud salva em: {output_path}")

Parte 3: Reconhecimento de Entidades Nomeadas (NER)

O Que É NER

NER (Named Entity Recognition) identifica e classifica entidades mencionadas no texto — pessoas, organizações, locais, datas, valores monetários, etc.

"""Reconhecimento de Entidades Nomeadas (NER)."""

import spacy
from collections import defaultdict

nlp = spacy.load("pt_core_news_lg")


def extract_entities(text: str) -> dict:
    """Extrai entidades nomeadas de um texto."""
    doc = nlp(text)
    
    entities = defaultdict(list)
    
    for ent in doc.ents:
        entities[ent.label_].append({
            "text": ent.text,
            "start": ent.start_char,
            "end": ent.end_char,
        })
    
    return dict(entities)


def print_entities(text: str) -> None:
    """Exibe entidades nomeadas de forma formatada."""
    doc = nlp(text)
    
    # Mapeamento de labels para português
    label_names = {
        "PER": "Pessoa",
        "ORG": "Organização",
        "LOC": "Local",
        "MISC": "Diversos",
        "DATE": "Data",
        "MONEY": "Dinheiro",
        "GPE": "Entidade Geopolítica",
        "EVENT": "Evento",
    }
    
    print("Entidades encontradas:")
    print("-" * 60)
    
    if not doc.ents:
        print("  Nenhuma entidade encontrada.")
        return
    
    for ent in doc.ents:
        label_pt = label_names.get(ent.label_, ent.label_)
        print(f"  [{label_pt}] {ent.text}")
    
    print(f"\nTotal: {len(doc.ents)} entidades")


# Exemplo com texto rico em entidades
texto_noticias = """
O presidente Lula se reuniu com o CEO da Microsoft, Satya Nadella, 
em Brasília na última terça-feira. O encontro discutiu investimentos 
de R$ 5 bilhões em inteligência artificial no Brasil. A Petrobras e 
o Itaú também participaram das negociações. O acordo deve ser 
formalizado durante o Fórum Econômico Mundial em Davos, na Suíça, 
previsto para janeiro de 2027.
"""

print_entities(texto_noticias)
entities = extract_entities(texto_noticias)
print(f"\nEntidades por tipo: { {k: len(v) for k, v in entities.items()} }")

NER Customizado com Visualização

def visualize_entities_html(text: str, output_path: str = "output/entities.html") -> None:
    """Gera visualização HTML das entidades com displaCy."""
    from spacy import displacy
    from pathlib import Path
    
    doc = nlp(text)
    
    # Gerar HTML com displaCy
    html = displacy.render(doc, style="ent", page=True, options={
        "colors": {
            "PER": "#feca74",
            "ORG": "#7aecec",
            "LOC": "#ff9561",
            "MISC": "#c887fb",
        }
    })
    
    Path(output_path).parent.mkdir(exist_ok=True)
    Path(output_path).write_text(html)
    print(f"Visualização salva em: {output_path}")


def extract_relationships(text: str) -> list[dict]:
    """Extrai relações simples entre entidades baseado em proximidade."""
    doc = nlp(text)
    
    relationships = []
    entities = list(doc.ents)
    
    for i, ent1 in enumerate(entities):
        for ent2 in entities[i + 1:]:
            # Verificar se estão na mesma sentença
            sent1 = ent1.sent
            sent2 = ent2.sent
            
            if sent1 == sent2:
                # Extrair texto entre as entidades
                start = min(ent1.end_char, ent2.end_char)
                end = max(ent1.start_char, ent2.start_char)
                between = text[start:end].strip()
                
                if len(between) < 100:  # Proximidade razoável
                    relationships.append({
                        "entity1": {"text": ent1.text, "type": ent1.label_},
                        "entity2": {"text": ent2.text, "type": ent2.label_},
                        "context": between,
                        "sentence": sent1.text.strip(),
                    })
    
    return relationships

Parte 4: Classificação de Texto

Classificação com Scikit-learn

"""Classificação de texto com TF-IDF e scikit-learn."""

import numpy as np
import pandas as pd
from sklearn.feature_extraction.text import TfidfVectorizer
from sklearn.model_selection import train_test_split, cross_val_score
from sklearn.naive_bayes import MultinomialNB
from sklearn.linear_model import LogisticRegression
from sklearn.svm import LinearSVC
from sklearn.pipeline import Pipeline
from sklearn.metrics import classification_report, confusion_matrix
import spacy

nlp = spacy.load("pt_core_news_lg")


def preprocess_text(text: str) -> str:
    """Preprocessa texto para classificação."""
    doc = nlp(text.lower())
    tokens = [
        token.lemma_
        for token in doc
        if not token.is_stop
        and not token.is_punct
        and not token.is_space
        and token.is_alpha
        and len(token.text) > 2
    ]
    return " ".join(tokens)


def create_sample_dataset() -> pd.DataFrame:
    """Cria dataset de exemplo para classificação de notícias."""
    data = {
        "text": [
            "O Flamengo venceu o Palmeiras por 3 a 1 no Maracanã",
            "Seleção brasileira convocada para as eliminatórias",
            "Novo técnico assume o comando do Corinthians",
            "Campeonato Brasileiro tem rodada decisiva neste fim de semana",
            "Jogador se lesiona e desfalca o time por três meses",
            "Ibovespa fecha em alta de 2% com otimismo global",
            "Banco Central mantém taxa Selic em 14,25%",
            "Inflação acumula 5,2% nos últimos 12 meses",
            "Dólar cai para R$ 5,10 com fluxo de capital estrangeiro",
            "PIB cresce 2,8% no terceiro trimestre de 2025",
            "Nova vacina contra dengue aprovada pela Anvisa",
            "Pesquisadores descobrem tratamento promissor para Alzheimer",
            "OMS alerta sobre nova variante do vírus da gripe",
            "Hospital Einstein inaugura centro de medicina de precisão",
            "Campanha de vacinação atinge 90% de cobertura no país",
            "SpaceX lança novo lote de satélites Starlink",
            "Apple apresenta novo chip M5 com IA integrada",
            "Google anuncia avanço em computação quântica",
            "Startup brasileira de IA recebe investimento de US$ 50 milhões",
            "5G chega a mais 100 cidades brasileiras em 2026",
        ],
        "category": [
            "esportes", "esportes", "esportes", "esportes", "esportes",
            "economia", "economia", "economia", "economia", "economia",
            "saude", "saude", "saude", "saude", "saude",
            "tecnologia", "tecnologia", "tecnologia", "tecnologia", "tecnologia",
        ],
    }
    return pd.DataFrame(data)


def train_text_classifier(df: pd.DataFrame) -> dict:
    """Treina e avalia classificadores de texto."""
    # Preprocessar textos
    df["processed"] = df["text"].apply(preprocess_text)
    
    X = df["processed"]
    y = df["category"]
    
    # Split
    X_train, X_test, y_train, y_test = train_test_split(
        X, y, test_size=0.3, random_state=42, stratify=y
    )
    
    # Definir pipelines de classificação
    classifiers = {
        "Naive Bayes": Pipeline([
            ("tfidf", TfidfVectorizer(max_features=5000, ngram_range=(1, 2))),
            ("clf", MultinomialNB(alpha=0.1)),
        ]),
        "Logistic Regression": Pipeline([
            ("tfidf", TfidfVectorizer(max_features=5000, ngram_range=(1, 2))),
            ("clf", LogisticRegression(max_iter=1000, C=1.0)),
        ]),
        "SVM": Pipeline([
            ("tfidf", TfidfVectorizer(max_features=5000, ngram_range=(1, 2))),
            ("clf", LinearSVC(max_iter=1000)),
        ]),
    }
    
    results = {}
    
    for name, pipeline in classifiers.items():
        # Treinar
        pipeline.fit(X_train, y_train)
        
        # Avaliar
        y_pred = pipeline.predict(X_test)
        
        # Validação cruzada
        cv_scores = cross_val_score(pipeline, X, y, cv=3, scoring="accuracy")
        
        results[name] = {
            "accuracy": float(np.mean(y_pred == y_test)),
            "cv_accuracy": float(cv_scores.mean()),
            "cv_std": float(cv_scores.std()),
            "report": classification_report(y_test, y_pred, output_dict=True),
        }
        
        print(f"\n{'='*50}")
        print(f"Classificador: {name}")
        print(f"Acurácia: {results[name]['accuracy']:.2%}")
        print(f"CV Acurácia: {results[name]['cv_accuracy']:.2%} "
              f"(±{results[name]['cv_std']:.2%})")
        print(classification_report(y_test, y_pred))
    
    return results


def predict_category(pipeline, text: str) -> dict:
    """Classifica um novo texto."""
    processed = preprocess_text(text)
    prediction = pipeline.predict([processed])[0]
    
    # Probabilidades (se disponível)
    probabilities = {}
    if hasattr(pipeline.named_steps["clf"], "predict_proba"):
        probs = pipeline.predict_proba([processed])[0]
        classes = pipeline.classes_
        probabilities = {cls: float(prob) for cls, prob in zip(classes, probs)}
    
    return {
        "text": text,
        "predicted_category": prediction,
        "probabilities": probabilities,
    }

Parte 5: Análise de Sentimento

Análise Básica com spaCy

"""Análise de sentimento com múltiplas abordagens."""

import spacy

nlp = spacy.load("pt_core_news_lg")


def simple_sentiment_lexicon(text: str) -> dict:
    """Análise de sentimento básica usando léxico."""
    # Léxico simplificado de sentimento para português
    positive_words = {
        "bom", "ótimo", "excelente", "maravilhoso", "incrível", "fantástico",
        "adorar", "amar", "gostar", "feliz", "alegre", "satisfeito",
        "melhor", "sucesso", "positivo", "crescer", "ganhar", "lucro",
        "inovar", "avançar", "conquistar", "realizar", "impressionante",
        "eficiente", "revolucionário", "promissor", "benefício", "oportunidade",
    }
    
    negative_words = {
        "ruim", "péssimo", "horrível", "terrível", "mau", "pior",
        "odiar", "detestar", "triste", "infeliz", "frustrado", "decepcionado",
        "fracasso", "negativo", "perder", "prejuízo", "crise", "problema",
        "difícil", "complicado", "preocupante", "risco", "ameaça", "queda",
        "falhar", "errar", "cancelar", "destruir", "piorar", "reclamar",
    }
    
    doc = nlp(text.lower())
    
    pos_count = 0
    neg_count = 0
    pos_found = []
    neg_found = []
    
    for token in doc:
        lemma = token.lemma_.lower()
        if lemma in positive_words:
            pos_count += 1
            pos_found.append(token.text)
        elif lemma in negative_words:
            neg_count += 1
            neg_found.append(token.text)
    
    total = pos_count + neg_count
    if total == 0:
        sentiment = "neutral"
        score = 0.0
    elif pos_count > neg_count:
        sentiment = "positive"
        score = pos_count / total
    else:
        sentiment = "negative"
        score = -neg_count / total
    
    return {
        "sentiment": sentiment,
        "score": round(score, 4),
        "positive_words": pos_found,
        "negative_words": neg_found,
        "positive_count": pos_count,
        "negative_count": neg_count,
    }

Análise de Sentimento com Transformers

"""Análise de sentimento avançada com Hugging Face Transformers."""

from transformers import pipeline as hf_pipeline


class SentimentAnalyzer:
    """Analisador de sentimento usando modelos Transformer."""

    def __init__(self, model_name: str = "nlptown/bert-base-multilingual-uncased-sentiment"):
        """
        Inicializa o analisador.
        
        Modelos recomendados para português:
        - nlptown/bert-base-multilingual-uncased-sentiment (multilíngue, 1-5 estrelas)
        - cardiffnlp/twitter-xlm-roberta-base-sentiment (multilíngue, pos/neg/neu)
        - lxyuan/distilbert-base-multilingual-cased-sentiments-student (multilíngue)
        """
        self.classifier = hf_pipeline(
            "sentiment-analysis",
            model=model_name,
            top_k=None,
        )
        self.model_name = model_name

    def analyze(self, text: str) -> dict:
        """Analisa o sentimento de um texto."""
        result = self.classifier(text[:512])  # Limitar tamanho
        
        scores = {r["label"]: r["score"] for r in result[0]}
        
        # Determinar sentimento dominante
        top_label = max(scores, key=scores.get)
        top_score = scores[top_label]
        
        return {
            "text": text[:100] + ("..." if len(text) > 100 else ""),
            "sentiment": top_label,
            "confidence": round(top_score, 4),
            "all_scores": {k: round(v, 4) for k, v in scores.items()},
        }

    def analyze_batch(self, texts: list[str]) -> list[dict]:
        """Analisa sentimento de múltiplos textos."""
        return [self.analyze(text) for text in texts]

    def analyze_aspects(self, text: str, aspects: list[str]) -> dict:
        """Análise de sentimento por aspecto."""
        results = {}
        
        for aspect in aspects:
            # Extrair sentenças que mencionam o aspecto
            doc = nlp(text.lower())
            relevant_sents = [
                sent.text
                for sent in doc.sents
                if aspect.lower() in sent.text.lower()
            ]
            
            if relevant_sents:
                combined = " ".join(relevant_sents)
                analysis = self.analyze(combined)
                results[aspect] = analysis
            else:
                results[aspect] = {"sentiment": "not_mentioned", "confidence": 0.0}
        
        return results


# Exemplo de uso
def demo_sentiment():
    """Demonstração de análise de sentimento."""
    analyzer = SentimentAnalyzer()
    
    reviews = [
        "Produto excelente! Qualidade incrível e entrega super rápida. Recomendo muito!",
        "Péssima experiência. O produto veio com defeito e o atendimento foi horrível.",
        "O produto é razoável. Nada excepcional, mas cumpre o que promete.",
        "Amei tudo! A embalagem linda, produto funciona perfeitamente. Nota 10!",
        "Decepcionante. Paguei caro e a qualidade é muito abaixo do esperado.",
    ]
    
    print("Análise de Sentimento de Reviews")
    print("=" * 60)
    
    for review in reviews:
        result = analyzer.analyze(review)
        emoji = {"positive": "😊", "negative": "😞", "neutral": "😐"}.get(
            result["sentiment"].lower()[:3], "🤔"
        )
        print(f"\n{emoji} [{result['sentiment']}] (confiança: {result['confidence']:.2%})")
        print(f"   \"{result['text']}\"")

Parte 6: Similaridade Semântica

Similaridade com spaCy

"""Similaridade semântica entre textos."""

import spacy
import numpy as np

nlp = spacy.load("pt_core_news_lg")


def compute_similarity(text1: str, text2: str) -> float:
    """Calcula similaridade semântica entre dois textos usando spaCy."""
    doc1 = nlp(text1)
    doc2 = nlp(text2)
    return doc1.similarity(doc2)


def find_most_similar(query: str, documents: list[str], top_k: int = 3) -> list[dict]:
    """Encontra os documentos mais similares a uma query."""
    query_doc = nlp(query)
    
    similarities = []
    for i, doc_text in enumerate(documents):
        doc = nlp(doc_text)
        sim = query_doc.similarity(doc)
        similarities.append({
            "index": i,
            "text": doc_text[:100] + ("..." if len(doc_text) > 100 else ""),
            "similarity": round(sim, 4),
        })
    
    similarities.sort(key=lambda x: x["similarity"], reverse=True)
    return similarities[:top_k]


def cluster_texts_by_similarity(texts: list[str], threshold: float = 0.8) -> list[list[int]]:
    """Agrupa textos similares baseado em um limiar de similaridade."""
    n = len(texts)
    docs = [nlp(text) for text in texts]
    
    # Calcular matriz de similaridade
    similarity_matrix = np.zeros((n, n))
    for i in range(n):
        for j in range(i, n):
            sim = docs[i].similarity(docs[j])
            similarity_matrix[i][j] = sim
            similarity_matrix[j][i] = sim
    
    # Clustering simples baseado em limiar
    visited = set()
    clusters = []
    
    for i in range(n):
        if i in visited:
            continue
        cluster = [i]
        visited.add(i)
        
        for j in range(i + 1, n):
            if j not in visited and similarity_matrix[i][j] >= threshold:
                cluster.append(j)
                visited.add(j)
        
        clusters.append(cluster)
    
    return clusters


# Demonstração
def demo_similarity():
    """Demonstração de similaridade semântica."""
    documents = [
        "Python é uma linguagem de programação versátil e popular",
        "Java é muito utilizado em aplicações empresariais",
        "O gato dormiu no sofá durante toda a tarde",
        "A linguagem Python é amplamente adotada por desenvolvedores",
        "Cães e gatos são os animais de estimação mais comuns",
        "JavaScript domina o desenvolvimento web front-end",
    ]
    
    query = "Qual a melhor linguagem de programação?"
    
    print(f"Query: \"{query}\"")
    print("\nDocumentos mais similares:")
    
    results = find_most_similar(query, documents, top_k=3)
    for r in results:
        print(f"  [{r['similarity']:.4f}] {r['text']}")
    
    print("\nClusters de similaridade (threshold=0.7):")
    clusters = cluster_texts_by_similarity(documents, threshold=0.7)
    for i, cluster in enumerate(clusters):
        print(f"  Cluster {i + 1}:")
        for idx in cluster:
            print(f"    - {documents[idx][:60]}...")

Parte 7: NLP Moderno com Transformers

Classificação Zero-Shot

"""NLP avançado com Hugging Face Transformers."""

from transformers import pipeline as hf_pipeline


class ZeroShotClassifier:
    """Classificação zero-shot — classifica sem treinamento prévio."""

    def __init__(self):
        self.classifier = hf_pipeline(
            "zero-shot-classification",
            model="facebook/bart-large-mnli",
        )

    def classify(self, text: str, labels: list[str]) -> dict:
        """Classifica um texto nas categorias fornecidas."""
        result = self.classifier(text, candidate_labels=labels, multi_label=False)
        
        return {
            "text": text[:100],
            "labels": result["labels"],
            "scores": [round(s, 4) for s in result["scores"]],
            "best_label": result["labels"][0],
            "best_score": round(result["scores"][0], 4),
        }


def demo_zero_shot():
    """Demonstração de classificação zero-shot."""
    classifier = ZeroShotClassifier()
    
    texts = [
        "O novo smartphone da Samsung tem uma câmera de 200 megapixels",
        "Governo anuncia programa de habitação para famílias de baixa renda",
        "Receita de bolo de chocolate com cobertura de brigadeiro",
    ]
    
    categories = ["tecnologia", "política", "culinária", "esportes", "ciência"]
    
    for text in texts:
        result = classifier.classify(text, categories)
        print(f"\nTexto: \"{result['text']}\"")
        print(f"Categoria: {result['best_label']} ({result['best_score']:.2%})")

Geração de Texto

class TextGenerator:
    """Geração de texto com modelos Transformer."""

    def __init__(self, model_name: str = "gpt2"):
        self.generator = hf_pipeline(
            "text-generation",
            model=model_name,
        )

    def generate(
        self,
        prompt: str,
        max_length: int = 200,
        temperature: float = 0.7,
        num_sequences: int = 1,
    ) -> list[str]:
        """Gera texto a partir de um prompt."""
        results = self.generator(
            prompt,
            max_length=max_length,
            temperature=temperature,
            num_return_sequences=num_sequences,
            do_sample=True,
            top_p=0.95,
            pad_token_id=50256,
        )
        
        return [r["generated_text"] for r in results]

Sumarização Automática

class TextSummarizer:
    """Sumarização automática de textos longos."""

    def __init__(self, model_name: str = "facebook/bart-large-cnn"):
        self.summarizer = hf_pipeline("summarization", model=model_name)

    def summarize(
        self,
        text: str,
        max_length: int = 150,
        min_length: int = 30,
    ) -> str:
        """Gera um resumo do texto."""
        result = self.summarizer(
            text,
            max_length=max_length,
            min_length=min_length,
            do_sample=False,
        )
        return result[0]["summary_text"]

    def summarize_long_text(
        self,
        text: str,
        chunk_size: int = 1000,
        max_summary_length: int = 150,
    ) -> str:
        """Sumariza textos longos dividindo em chunks."""
        # Dividir em chunks
        words = text.split()
        chunks = []
        current_chunk = []
        current_size = 0
        
        for word in words:
            current_chunk.append(word)
            current_size += len(word) + 1
            
            if current_size >= chunk_size:
                chunks.append(" ".join(current_chunk))
                current_chunk = []
                current_size = 0
        
        if current_chunk:
            chunks.append(" ".join(current_chunk))
        
        # Sumarizar cada chunk
        summaries = []
        for chunk in chunks:
            if len(chunk.split()) > 20:  # Mínimo de palavras
                summary = self.summarize(chunk, max_length=max_summary_length)
                summaries.append(summary)
        
        # Se os resumos ainda forem longos, sumarizar novamente
        combined = " ".join(summaries)
        if len(combined.split()) > max_summary_length:
            return self.summarize(combined, max_length=max_summary_length)
        
        return combined

Question Answering

class QuestionAnswerer:
    """Responde perguntas baseado em contexto."""

    def __init__(self, model_name: str = "deepset/roberta-base-squad2"):
        self.qa = hf_pipeline("question-answering", model=model_name)

    def answer(self, question: str, context: str) -> dict:
        """Responde uma pergunta dado um contexto."""
        result = self.qa(question=question, context=context)
        
        return {
            "question": question,
            "answer": result["answer"],
            "confidence": round(result["score"], 4),
            "start": result["start"],
            "end": result["end"],
        }


def demo_qa():
    """Demonstração de Question Answering."""
    qa = QuestionAnswerer()
    
    context = """
    Python foi criado por Guido van Rossum e lançado pela primeira vez em 1991. 
    É uma linguagem de programação de alto nível, interpretada e de propósito geral. 
    Python enfatiza a legibilidade do código com sua notável indentação significativa. 
    A linguagem é mantida pela Python Software Foundation e sua versão atual é 3.12.
    Python é amplamente usado em ciência de dados, inteligência artificial, 
    desenvolvimento web e automação.
    """
    
    questions = [
        "Quem criou Python?",
        "Quando Python foi lançado?",
        "Qual a versão atual do Python?",
        "Para que Python é usado?",
    ]
    
    print("Question Answering")
    print("=" * 60)
    
    for q in questions:
        result = qa.answer(q, context)
        print(f"\nQ: {result['question']}")
        print(f"A: {result['answer']} (confiança: {result['confidence']:.2%})")

Parte 8: Pipeline NLP Completo

"""Pipeline NLP completo que combina todas as técnicas."""

import spacy
from dataclasses import dataclass


@dataclass
class NLPAnalysis:
    """Resultado completo da análise NLP."""

    text: str
    language: str
    word_count: int
    sentence_count: int
    entities: dict
    sentiment: dict
    keywords: list[str]
    summary: str | None


class NLPPipeline:
    """Pipeline completo de análise de texto."""

    def __init__(self):
        self.nlp = spacy.load("pt_core_news_lg")

    def analyze(self, text: str) -> NLPAnalysis:
        """Executa análise NLP completa em um texto."""
        doc = self.nlp(text)
        
        # Contagens básicas
        sentences = list(doc.sents)
        word_count = len([t for t in doc if t.is_alpha])
        
        # Entidades
        entities = {}
        for ent in doc.ents:
            if ent.label_ not in entities:
                entities[ent.label_] = []
            entities[ent.label_].append(ent.text)
        
        # Keywords (lemmas mais frequentes)
        from collections import Counter
        lemmas = [
            t.lemma_.lower() for t in doc
            if not t.is_stop and t.is_alpha and len(t.text) > 2
        ]
        keywords = [word for word, _ in Counter(lemmas).most_common(10)]
        
        # Sentimento simples
        sentiment = simple_sentiment_lexicon(text)
        
        return NLPAnalysis(
            text=text[:200] + "..." if len(text) > 200 else text,
            language="pt",
            word_count=word_count,
            sentence_count=len(sentences),
            entities=entities,
            sentiment=sentiment,
            keywords=keywords,
            summary=None,
        )

Conclusão

Neste tutorial, percorremos o universo do NLP com Python:

  1. Tokenização e análise morfológica com spaCy — a base de todo processamento de texto.
  2. NER — identificação automática de pessoas, organizações, locais e mais.
  3. Classificação de texto — categorização automática usando TF-IDF e ML clássico.
  4. Análise de sentimento — tanto com léxico quanto com Transformers.
  5. Similaridade semântica — encontrar textos com significado similar.
  6. NLP moderno com Transformers — zero-shot classification, QA, sumarização.
  7. Pipeline completo — combinando tudo em uma análise unificada.

O NLP é um dos campos mais dinâmicos da IA, com novos modelos e técnicas surgindo constantemente. As bases que construímos aqui preparam você para qualquer desafio nessa área.


Próximos Passos

  • Treinar modelos NER customizados com spaCy para domínios específicos.
  • Explorar modelos multilíngues para tradução automática.
  • Implementar chatbots com compreensão de linguagem natural.
  • Fine-tuning de modelos Transformer para tarefas específicas em português.
  • Explorar modelos de linguagem grandes (LLMs) como GPT e Claude para NLP avançado.
  • Construir sistemas RAG (Retrieval Augmented Generation) para QA sobre documentos próprios.

Acompanhe o Inteligência em Código para mais tutoriais sobre NLP, IA e Python.