Solucionado (ver solução)

Importante

Você está vendo a versão anterior da nova experiência da Alura que estamos preparando para você. Em breve, ela ganha uma identidade visual novinha totalmente pensada em potencializar seus estudos!

Solucionado
(ver solução)
1
resposta

[Projeto] Faça como eu fiz: lidar com exceções e IA | Python: Inteligência Artificial Aplicada

# ===== 1. TRATAMENTO DE EXCEÇÕES =====
def processar_dados_com_excecoes():
    try:
        # Diferentes tipos de erro
        valor = int("abc")  # ValueError
        resultado = 10 / 0  # ZeroDivisionError
        numero = "texto" + 5  # TypeError
    except ValueError as e:
        print(f"Erro de valor: insira um número válido. Detalhes: {e}")
    except ZeroDivisionError:
        print("Erro: divisão por zero não permitida")
    except TypeError:
        print("Erro de tipo: verifique os tipos de dados")
    except Exception as e:
        print(f"Erro inesperado: {e}")
    finally:
        print("Processamento finalizado\n")

processar_dados_com_excecoes()

# ===== 2. FILTRAGEM E MANIPULAÇÃO DE DADOS =====
# Criar DataFrame com resenhas
resenhas_data = {
    'id': [1, 2, 3, 4, 5],
    'texto': [
        'Produto excelente, muito bom',
        'Péssimo, não recomendo',
        'Ótima qualidade',
        'Decepcionante, falhas graves',
        'Maravilhoso, superou expectativas'
    ],
    'sentimento': [1, -1, 1, -1, 1]
}

df = pd.DataFrame(resenhas_data)

# Filtrar resenhas negativas
resenhas_negativas = df[df['sentimento'] == -1]['texto']
texto_unificado = ' | '.join(resenhas_negativas)
print(f"Resenhas negativas unificadas:\n{texto_unificado}\n")

# ===== 3. INTEGRAÇÃO COM LLM =====
client = Anthropic()

def analisar_resenhas_com_llm(texto_resenhas):
    try:
        prompt = f"""Analise as seguintes resenhas negativas e identifique APENAS UMA palavra para cada categoria solicitada.

Resenhas: {texto_resenhas}

Responda no formato: CATEGORIA1 CATEGORIA2 CATEGORIA3
Categorias: Principal_Problema Emoção_Predominante Recomendação_Ação
Limite: uma palavra por categoria."""
        
        message = client.messages.create(
            model="claude-3-5-sonnet-20241022",
            max_tokens=100,
            messages=[
                {"role": "user", "content": prompt}
            ]
        )
        return message.content[0].text
    except Exception as e:
        print(f"Erro ao conectar com LLM: {e}")
        return None

# Análise de resenhas
resposta = analisar_resenhas_com_llm(texto_unificado)
if resposta:
    categorias = resposta.strip().split()
    print(f"Análise LLM: {resposta}")
    print(f"Categorias extraídas: {categorias}\n")

# ===== 4. PROCESSAMENTO EM LOTE =====
def processar_resenhas_em_lote(dataframe, tamanho_lote=2):
    try:
        resultados = []
        for i in range(0, len(dataframe), tamanho_lote):
            lote = dataframe.iloc[i:i+tamanho_lote]
            texto_lote = ' | '.join(lote['texto'].values)
            
            try:
                analise = analisar_resenhas_com_llm(texto_lote)
                resultados.append({
                    'lote': i//tamanho_lote + 1,
                    'quantidade': len(lote),
                    'analise': analise
                })
            except Exception as e:
                print(f"Erro no lote {i//tamanho_lote + 1}: {e}")
        
        return pd.DataFrame(resultados)
    finally:
        print("Processamento em lote concluído")

# Executar processamento
df_resultados = processar_resenhas_em_lote(df)
print("Resultados do processamento em lote:")
print(df_resultados)

# ===== 5. EXTRAÇÃO E CONVERSÃO JSON =====
import json

def extrair_json_resenhas(dataframe):
    try:
        lista_json = []
        for idx, row in dataframe.iterrows():
            json_obj = {
                "id": int(row['id']),
                "texto": str(row['texto']),
                "sentimento": int(row['sentimento'])
            }
            lista_json.append(json_obj)
        
        # Converter para dicionários Python
        dicts_python = json.loads(json.dumps(lista_json))
        return dicts_python
    except json.JSONDecodeError as e:
        print(f"Erro ao processar JSON: {e}")
        return []
    finally:
        print("Extração JSON finalizada")

resenhas_dict = extrair_json_resenhas(df)
print(f"\nResenhas como dicionários:\n{resenhas_dict[0]}")
::

Resumo da implementação:

  1. Exceções: Tratamento de ValueError, ZeroDivisionError, TypeError com blocos específicos
  2. Finally: Garante execução de limpeza
  3. Pandas: Filtro por sentimento negativo e extração de coluna
  4. Join: Unifica resenhas com delimitador ' | '
  5. LLM: API Anthropic com prompt estruturado
  6. Split: Converte resposta em lista
  7. Processamento em lote: Função que agrupa e analisa dados
  8. JSON: Conversão entre formatos

1 resposta
solução!

Olá, Estudante. Como vai?

Excelente trabalho de implementação! O seu código cobre de forma muito completa o fluxo de tratamento de exceções, manipulação de strings e dados com Pandas, além de integrar com sucesso uma API de LLM aplicando boas práticas de engenharia de prompt e processamento em lote (batch processing).

Para agregar ainda mais valor ao seu projeto e consolidar o aprendizado deste capítulo, trago alguns pontos de atenção técnica e sugestões de melhorias:

1. Comportamento do Bloco try-except no Item 1

No seu primeiro bloco de código, você listou três operações que geram exceções (ValueError, ZeroDivisionError e TypeError).

  • Ponto de Atenção: Do jeito que o código está escrito, assim que a linha valor = int("abc") é executada, ela dispara o ValueError imediatamente. O interpretador Python interrompe a execução do bloco try naquele exato momento e pula direto para o except ValueError. Isso significa que as linhas com a divisão por zero e a concatenação de texto nunca chegam a ser executadas.

Se o seu objetivo for testar e capturar todas elas na mesma execução, o ideal seria isolar cada operação em seu próprio bloco try-except ou dentro de um laço de repetição.

2. Otimização no Processamento em Lote (Item 4)

Na função processar_resenhas_em_lote, você adicionou uma estrutura robusta para capturar falhas. Contudo, na chamada da API dentro do laço:

try:
    analise = analisar_resenhas_com_llm(texto_lote)
    resultados.append({...})
except Exception as e:
    print(f"Erro no lote {i//tamanho_lote + 1}: {e}")
  • Dica de Resiliência: Como a função analisar_resenhas_com_llm já possui um bloco try-except interno que captura qualquer exceção e retorna None, o bloco except do lote nunca será acionado em caso de erro na API. Para tratar o erro no lote de forma eficaz, você pode verificar o retorno da função:
analise = analisar_resenhas_com_llm(texto_lote)
if analise is not None:
    resultados.append({
        'lote': i//tamanho_lote + 1,
        'quantidade': len(lote),
        'analise': analise
    })
else:
    print(f"Erro no lote {i//tamanho_lote + 1}: API retornou None")

3. Simplificação na Extração de JSON (Item 5)

Na conversão final, você utilizou a estratégia de transformar a lista em uma string JSON e depois fazer o load de volta para dicionários Python:

dicts_python = json.loads(json.dumps(lista_json))

O Pandas já possui um método nativo extremamente otimizado que faz exatamente essa conversão para dicionários e listas de forma direta, sem a necessidade de iterar manualmente com o for e sem importar a biblioteca json. Você pode reduzir todo esse bloco para apenas uma linha:

dicts_python = dataframe[['id', 'texto', 'sentimento']].to_dict(orient='records')

O parâmetro orient='records' gera exatamente uma lista de dicionários onde cada linha do DataFrame se transforma em um objeto.

Parabéns pela dedicação e pela estrutura limpa do resumo da sua atividade. Continue explorando as integrações com LLMs e o tratamento de falhas, pois esse é um diferencial crítico em sistemas de produção!

Espero que possa ter lhe ajudado!