Sistema de Análise de Sentimento de Tweets em Tempo Real com .NET

No mundo hiperconectado de hoje, a capacidade de entender a opinião pública em tempo real não é um luxo, mas uma necessidade estratégica. Milhares de mensagens são postadas a cada segundo, e saber se seus clientes ou o público em geral estão se sentindo positivos, negativos ou neutros sobre sua marca ou produto é uma mina de ouro de dados.

É aqui que entra o Sistema de Análise de Sentimento de Texto em Tempo Real com .NET.

Este não é um projeto C# comum de CRUD (Create, Read, Update, Delete). Ele nos desafia a mergulhar em uma arquitetura de alta relevância no mercado: a combinação de Inteligência Artificial (IA) com comunicação em tempo real. Usaremos o poder do ecossistema .NET para construir uma solução full-stack, onde o C# será a linguagem unificadora, desde o modelo de Machine Learning até a interface de usuário.

O objetivo é transformar um fluxo constante de dados brutos de texto em informações acionáveis, exibindo a classificação do sentimento em um dashboard dinâmico e instantâneo. Este projeto não apenas aprimora suas habilidades em C# e ASP.NET Core, mas também o insere no campo da Data Science e Web Sockets (via SignalR), qualificações altamente procuradas por empresas modernas.


Estrutura e Arquitetura do Projeto

O sistema será composto por três camadas principais que se comunicam de forma eficiente, todas construídas no ecra .NET:

CamadaComponenteFunçãoTecnologias Chave
Backend & MLAPI de EntradaRecebe os dados de texto para análise.ASP.NET Core Minimal APIs
Serviço de AnáliseCarrega o modelo e executa a previsão do sentimento para o texto.ML.NET (Classificação de Texto)
Tempo RealHub de NotificaçãoCanal de comunicação bidirecional aberto que envia atualizações instantâneas.ASP.NET Core SignalR (Hubs)
Serviço de BroadcastDistribui o resultado da análise (texto + sentimento) para o Hub.IHubContext<T> do SignalR
FrontendDashboardInterface que exibe a lista de textos e suas classificações dinamicamente.Blazor WebAssembly ou Blazor Server
Cliente de Tempo RealConecta-se ao Hub e atualiza a interface assim que um novo dado é recebido.SignalR Client (nativo no Blazor)

1. Configuração do Projeto e ML.NET

A espinha dorsal do projeto começa com o backend ASP.NET Core e a integração do Machine Learning.

A. Instalação de Pacotes NuGet

Instale os seguintes pacotes no seu projeto ASP.NET Core Web API:

Bash
dotnet add package Microsoft.ML
dotnet add package Microsoft.ML.FastTree

B. Definição do Modelo de Dados

As classes abaixo definem a estrutura de dados para comunicação com o ML.NET e o restante da aplicação.

C#
using Microsoft.ML.Data;

// 1. Classe de Entrada (O que o modelo irá receber)
public class SentimentData
{
    // O texto do "tweet" que queremos classificar.
    [LoadColumn(0)]
    public string TweetText { get; set; }

    // O rótulo (Label) usado APENAS para treinamento. 
    [LoadColumn(1), ColumnName("Label")]
    public bool Sentiment { get; set; }
}

// 2. Classe de Saída (O que o modelo irá retornar)
public class SentimentPrediction
{
    // O valor do sentimento previsto (true = positivo, false = negativo)
    [ColumnName("PredictedLabel")]
    public bool Prediction { get; set; }

    // A probabilidade da previsão (confiança do modelo)
    public float Probability { get; set; }

    // A pontuação bruta (score)
    public float Score { get; set; }
}

C. Criação do Serviço de Treinamento e Previsão

A classe SentimentAnalysisService encapsula a lógica do ML.NET.

C#
using Microsoft.ML;
using Microsoft.ML.Data;

public class SentimentAnalysisService
{
    private readonly MLContext _mlContext;
    private ITransformer _model;

    public SentimentAnalysisService()
    {
        _mlContext = new MLContext(seed: 0);
        // O modelo deve ser carregado ou treinado ao iniciar
        LoadOrCreateTrainedModel();
    }

    // Método para simular o carregamento/criação de um modelo
    private void LoadOrCreateTrainedModel()
    {
        // **IMPORTANTE: Em um projeto real, você deve carregar um modelo pré-treinado (.zip) aqui**
        // Ex: _model = _mlContext.Model.Load("sentimentModel.zip", out var modelSchema);

        // Para este exemplo, treinamos um modelo MINIMAL com dados de amostra.
        var sampleData = new List<SentimentData>
        {
            new SentimentData { TweetText = "Amei o novo produto, super recomendo!", Sentiment = true },
            new SentimentData { TweetText = "Que horror, tive uma experiência terrível.", Sentiment = false },
            new SentimentData { TweetText = "É ok, nada demais.", Sentiment = true },
            new SentimentData { TweetText = "O serviço de suporte foi incrível!", Sentiment = true }
        };

        IDataView trainingDataView = _mlContext.Data.LoadFromEnumerable(sampleData);

        // Define o pipeline de treinamento (FeaturizeText + SdcaLogisticRegression)
        var pipeline = _mlContext.Transforms.Text.FeaturizeText(
            outputColumnName: "Features", 
            inputColumnName: nameof(SentimentData.TweetText))
            .Append(_mlContext.BinaryClassification.Trainers.SdcaLogisticRegression(
                labelColumnName: "Label", 
                featureColumnName: "Features"));

        // Treina o modelo
        _model = pipeline.Fit(trainingDataView);
        
        // **Em produção, você salvaria este modelo:** // _mlContext.Model.Save(_model, trainingDataView.Schema, "sentimentModel.zip");
    }

    /// <summary>
    /// Classifica o sentimento de um texto.
    /// </summary>
    /// <param name="text">O texto a ser analisado.</param>
    /// <returns>A previsão de sentimento.</returns>
    public SentimentPrediction PredictSentiment(string text)
    {
        // Cria um motor de previsão a partir do modelo
        var predictionEngine = _mlContext.Model.CreatePredictionEngine<SentimentData, SentimentPrediction>(_model);

        var sampleData = new SentimentData { TweetText = text };
        
        // Faz a previsão
        return predictionEngine.Predict(sampleData);
    }
}

2. Implementação da API, SignalR e Comunicação em Tempo Real

A mágica do tempo real acontece no arquivo Program.cs. Usamos a Injeção de Dependência para fornecer o serviço de ML.NET e o IHubContext do SignalR para broadcast.

C#
using Microsoft.AspNetCore.SignalR;

var builder = WebApplication.CreateBuilder(args);

// Adicionar Injeção de Dependência do nosso serviço ML.NET
builder.Services.AddSingleton<SentimentAnalysisService>();

// Adicionar SignalR (para a próxima etapa de tempo real)
builder.Services.AddSignalR();

// Adicionar CORS (necessário para o Blazor Frontend rodando em outra porta/domínio)
builder.Services.AddCors(options =>
{
    options.AddPolicy("CorsPolicy", policy =>
    {
        policy.AllowAnyHeader()
              .AllowAnyMethod()
              // Ajuste para a URL do seu Blazor Frontend, permitindo SignalR (AllowCredentials)
              .WithOrigins("http://localhost:5000", "http://localhost:5001") 
              .AllowCredentials(); 
    });
});

var app = builder.Build();

app.UseCors("CorsPolicy");

// Mapeamento do SignalR Hub
app.MapHub<SentimentHub>("/sentimentHub");

// --- Minimal API Endpoint para Análise ---
app.MapPost("/api/analyze", async (string tweetText, 
                                   SentimentAnalysisService service, 
                                   IHubContext<SentimentHub> hubContext) =>
{
    if (string.IsNullOrWhiteSpace(tweetText))
    {
        return Results.BadRequest("O texto não pode estar vazio.");
    }

    // 1. Realiza a previsão do sentimento
    var prediction = service.PredictSentiment(tweetText);

    // 2. Formata o resultado para envio (JSON)
    var result = new 
    {
        Text = tweetText,
        // Converte o booleano de previsão para uma string amigável
        Sentiment = prediction.Prediction ? "Positivo" : "Negativo", 
        Confidence = Math.Round(prediction.Probability, 4)
    };

    // 3. Comunica o resultado em TEMPO REAL para TODOS os clientes via SignalR
    // O SendAsync usa o método 'ReceiveSentimentUpdate' que será consumido no frontend Blazor.
    await hubContext.Clients.All.SendAsync("ReceiveSentimentUpdate", result);

    // Retorna o resultado da API (para quem a chamou)
    return Results.Ok(result);
});

app.Run();

// --- Classe do SignalR Hub ---
// Esta classe é apenas o identificador para o SignalR. 
// A lógica de envio (broadcast) é feita via IHubContext no endpoint da API.
public class SentimentHub : Hub
{
}

Testando o Backend: API e Tempo Real

Você validou a integração do ML.NET e configurou o SignalR. O próximo passo crucial é testar se o fluxo completo está funcionando antes de construir o frontend.

1. Teste da API com uma Ferramenta HTTP (Postman/Insomnia)

Use um cliente HTTP para simular um novo dado de texto chegando ao sistema.

Detalhes da Requisição:

  • Método: POST

  • URL: https://localhost:[PORTA]/api/analyze

  • Parâmetro de Consulta (Query Param): Adicione tweetText com um texto de teste.

    • Exemplo: https://localhost:[PORTA]/api/analyze?tweetText=Este é um teste incrível!

Resposta Esperada (Status 200 OK):

Seu backend deve retornar um JSON formatado, confirmando a classificação.

JSON
{
  "text": "Este é um teste incrível!",
  "sentiment": "Positivo",
  "confidence": 0.9854
}

2. Teste da Comunicação em Tempo Real (SignalR CLI)

O SignalR precisa de um cliente persistente. A ferramenta de linha de comando oficial da Microsoft é a forma mais simples de validar o broadcast.

Pré-requisito: Instale a ferramenta global SignalR CLI:

Bash
dotnet tool install -g Microsoft.AspNetCore.SignalR.Client.Cli

Passos:

  1. Inicie a Escuta do Cliente SignalR:

    Abra seu terminal e execute:

    Bash
    dotnet signalr listen --urls "https://localhost:[PORTA]/sentimentHub" --hubpath "sentimentHub"
    

    O terminal agora está esperando mensagens e deve mostrar Connected to 'https://localhost:[PORTA]/sentimentHub'.

  2. Dispare o Evento da API:

    Com o terminal escutando, use o Postman (ou outro cliente HTTP) para enviar uma nova requisição POST para o endpoint /api/analyze.

  3. Analise a Saída do Terminal:

    Imediatamente após a API retornar o Status 200 OK no Postman, você deve ver uma saída no terminal do SignalR:

    [INVOCATION] Target: ReceiveSentimentUpdate, Arguments: [{"text":"O dia está perfeito!","sentiment":"Positivo","confidence":0.75}]
    

Se o JSON aparecer no terminal do SignalR, o broadcast em tempo real está perfeitamente configurado e a arquitetura está pronta para o frontend!


Próximos Passos: O Frontend com Blazor

Com o backend totalmente validado — o ML.NET classificando e o SignalR transmitindo instantaneamente — o foco agora é construir o Dashboard Dinâmico que consumirá esse fluxo de dados em tempo real.

O Blazor é a escolha ideal, pois permite que você continue a usar C# e .NET para todo o desenvolvimento frontend, eliminando a necessidade de JavaScript complexo para o cliente SignalR.

Escolha do Modelo de Hospedagem

Antes de começar, você precisa escolher como o Blazor será hospedado:

ModeloOnde o App RodaComunicaçãoCenário Ideal
Blazor ServerServidorUtiliza uma conexão SignalR persistente para sincronizar o DOM (renderização no servidor).Ótimo para latência baixa, inicialização rápida e para manter a lógica sensível no servidor.
Blazor WebAssembly (WASM)Navegador (Cliente)O runtime .NET é baixado e roda no cliente. Comunica-se com o backend via APIs (HTTP) ou SignalR (WebSockets).Perfeito para escalabilidade (offload de processamento para o cliente) e suporte a offline.

Para este projeto, onde a funcionalidade principal é a comunicação em tempo real via SignalR, ambos os modelos funcionam perfeitamente. O Blazor Server já usa o SignalR para toda a comunicação UI, mas o Blazor WASM usa a mesma biblioteca Microsoft.AspNetCore.SignalR.Client para se conectar ao seu SentimentHub.

Implementação do Cliente SignalR no Blazor

A lógica de conexão será a mesma, independentemente do modelo de hospedagem Blazor que você escolher (WASM ou Server). Você usará a classe HubConnectionBuilder.

1. Classe de Modelo de Dados no Frontend

Crie a mesma estrutura de dados (ou uma versão simplificada) que você usou para enviar o resultado da API.

C#
// Localizada no seu projeto Blazor (Componente ou Models)
public class SentimentResult
{
    public string Text { get; set; }
    public string Sentiment { get; set; } // "Positivo" ou "Negativo"
    public float Confidence { get; set; }
}

2. Lógica do Componente Blazor (Exemplo: SentimentDashboard.razor)

Este componente será responsável por conectar-se ao Hub e receber as atualizações em tempo real.

C#
@page "/sentiment-dashboard"
@using Microsoft.AspNetCore.SignalR.Client
@implements IAsyncDisposable
@inject NavigationManager NavigationManager // Para obter a URL base

<h2>Análise de Sentimento em Tempo Real</h2>

@if (hubConnection is null)
{
    <p><em>Conectando-se ao SignalR Hub...</em></p>
}
else
{
    <p>Conexão estabelecida. Recebendo dados instantaneamente.</p>
}

<div class="sentiment-feed">
    @foreach (var result in recentResults)
    {
        <div class="@(result.Sentiment == "Positivo" ? "alert-success" : "alert-danger")">
            <strong>@result.Sentiment</strong> (@(result.Confidence.ToString("P0"))): @result.Text
        </div>
    }
</div>

@code {
    private HubConnection? hubConnection;
    private List<SentimentResult> recentResults = new();
    
    // Define o número máximo de resultados a serem exibidos no painel
    private const int MaxResults = 10; 

    protected override async Task OnInitializedAsync()
    {
        // Constrói a URL do Hub: usa a URL base do seu app + o endpoint do Hub.
        var hubUrl = NavigationManager.ToAbsoluteUri("/sentimentHub");
        
        hubConnection = new HubConnectionBuilder()
            .WithUrl(hubUrl)
            .WithAutomaticReconnect() // Garante reconexão automática se a conexão cair
            .Build();

        // 1. Define o Método Receptor
        // Este nome ('ReceiveSentimentUpdate') deve ser EXATAMENTE o mesmo usado no .SendAsync() da sua Minimal API.
        hubConnection.On<SentimentResult>("ReceiveSentimentUpdate", (result) =>
        {
            // 2. Adiciona o novo resultado
            recentResults.Insert(0, result);
            
            // 3. Limita o número de resultados para não sobrecarregar o painel
            if (recentResults.Count > MaxResults)
            {
                recentResults.RemoveAt(MaxResults);
            }
            
            // 4. Notifica o Blazor para re-renderizar a UI (necessário em alguns contextos)
            StateHasChanged(); 
        });

        // 5. Inicia a conexão
        await hubConnection.StartAsync();
    }
    
    // Implementação para garantir que a conexão SignalR seja fechada ao sair
    public async ValueTask DisposeAsync()
    {
        if (hubConnection is not null)
        {
            await hubConnection.DisposeAsync();
        }
    }
}

Ao implementar este código no Blazor, seu frontend estará escutando ativamente o servidor. Cada vez que uma requisição POST for enviada para /api/analyze no backend, o SignalR fará o broadcast, e o método ReceiveSentimentUpdate será invocado no seu Blazor para atualizar o dashboard instantaneamente.

Com o frontend pronto, você terá concluído o ciclo ML.NET API SignalR Blazor e terá um sistema de análise de sentimento em tempo real totalmente funcional!


Conclusão

Com a integração das três camadas — ML.NET, ASP.NET Core SignalR, e Blazor — você concluiu a construção de um sistema de análise de sentimento em tempo real de altíssimo valor.

Este projeto representa muito mais do que a simples combinação de bibliotecas. Ele demonstra sua capacidade de:

  1. Orquestrar Arquiteturas Modernas: Você foi além do desenvolvimento web tradicional, criando um sistema distribuído que lida com processamento intensivo (Machine Learning) e comunicação de baixa latência (WebSockets).

  2. Unificar a Stack com .NET: Você usou C# em toda a arquitetura, do backend de processamento de dados (ML.NET) ao frontend dinâmico (Blazor), otimizando a produtividade e a manutenção do código.

  3. Transformar Dados em Ação: O fluxo é instantâneo: cada dado de texto bruto é transformado em um insight acionável (Positivo ou Negativo) e exibido no dashboard, permitindo que a sua equipe tome decisões estratégicas no momento exato em que a opinião pública se forma.

O sistema construído é uma fundação robusta. A partir daqui, as possibilidades de expansão são vastas: você pode integrar modelos de Machine Learning mais complexos, conectar a API a serviços de streaming de dados reais (como Kafka ou Azure Event Hubs), ou adicionar visualizações de dados avançadas para monitorar a tendência de sentimento ao longo do tempo.

Parabéns por dominar esta poderosa arquitetura! Este é o tipo de projeto que realmente impulsiona a inovação e o seu portfólio no mercado.



Comentários

Postagens mais visitadas deste blog

Laços de Repetição em Python: Conceitos e Exemplos Práticos

Manipulação de Arquivos no C#: Como Ler, Escrever e Trabalhar com Arquivos de Forma Simples

Como Instalar o Xamarin com C#: Passo a Passo Completo