segunda-feira, 3 de fevereiro de 2025

IA e Low-Code nas Organizações

A tecnologia disponível hoje em dia, em particular a Inteligência Artificial e soluções low-code (e no-code), empodera os usuários de uma forma geral (incluindo os do chamado "chão de fábrica"), tornando-os aptos a automatizar alguns fluxos de trabalho, analisar dados e tomar melhores decisões.

De um modo geral, os departamentos de TI não conseguem mais atender à totalidade das demandas corporativas, que crescem em número e complexidade. Precisam mudar seu foco para aspectos mais estratégicos das organizações e propiciar condições (dados e licenças de software) para que as soluções para o negócio também possam florescer nas pontas, pelas mãos do pessoal encarregado da execução.

sábado, 1 de fevereiro de 2025

O poder das LLMs na análise de inquéritos policiais

Introdução
O vídeo apresenta um programa escrito em Python que faz uso de LLMs, mediadas pela biblioteca litellm, para analisar uma coleção de inquéritos policiais em formato PDF.

Estratégias
Usamos o PyPDF para extrair textos dos PDFs. Preservamos a numeração das páginas para referenciar as respostas.
O texto extraído dos PDFs compõe o prompt, com as perguntas à LLM dirigidas à analise de cada caso.
A biblioteca litellm facilitou o desenvolvimento e abstraiu toda a complexidade das chamadas a APIs. Com ela, é fácil substituir um provedor de LLM por outro.

Privacidade
Provedores de LLMs, como a OpenAI, afirmam que não utilizam os dados de entrada e saída de suas APIs para treinamento. Também garantem que permanecem privados.

Avalie sempre os riscos
Prefira testar a ferramenta com processos não gravados de sigilo ou que serão elegíveis aos bancos públicos de sentenças.

Alucina?
LLMs ainda alucinam bastante.
O emprego da ferramenta no campo profissional deve ser avaliado caso a caso.

Restrições
Observe o número máximo de tokens de entrada e saída do modelo selecionado.
Faça sempre uma avaliação de custo-benefício.




 

segunda-feira, 2 de setembro de 2024

Por que proibir VPNs é um desafio para o STF?

É muito complicado para o STF proibir e fiscalizar o uso de VPNs para acessar o X. Por esse motivo, a primeira decisão de Alexandre de Moraes ordenava que a Apple e o Google retirassem de suas lojas de aplicativos ferramentas como Proton VPN, ExpressVPN, NordVPN, Surfshark, TOTALVPN, Atlas VPN e Bitdefender VPN, que poderiam ser facilmente empregadas para esse fim.

As VPNs são amplamente utilizadas por tribunais, ministérios públicos, polícias, empresas e pessoas físicas como meio de acesso a recursos corporativos ou redes privadas a partir de conexões menos seguras ou redes abertas, como as de aeroportos, hotéis e restaurantes. Recomendo que as utilizem quando se conectarem à Internet por meio de um Wi-Fi público. As VPNs criptografam o tráfego entre o usuário e o servidor VPN, ocultando o IP de origem. Nem mesmo o seu provedor de internet pode afirmar com certeza se você acessou ou não determinada plataforma; ele apenas saberá que você acessou uma VPN.

Ocorre que os serviços de VPN podem ou não coletar logs de uso (incluindo sites visitados) ou de conexão. Muitos provedores se limitam a registrar os dados da conexão necessários à tarifação, desconsiderando as atividades do usuário.

Não seria trivial ao STF emitir uma ordem genérica a essas empresas, a maioria sediada no exterior, obrigando-as a fornecer a relação de usuários que utilizaram VPNs para acessar o X. Tal medida, aliás, não alcançaria uma parte dos "infratores", já que não é difícil construir a própria VPN ou — por conta e risco — utilizar VPNs alternativas e menos colaborativas com as autoridades. Além disso, o emprego da técnica conhecida como Onion over VPN, que combina o uso de VPN com a rede Tor, pode adicionar uma camada extra de criptografia, escondendo a navegação até mesmo do provedor de VPN.

Na minha opinião, a primeira decisão monocrática sobre a suspensão do X, que, incidentalmente, inviabilizaria o uso de VPN em dispositivos móveis, revela as dificuldades operacionais aqui apontadas. Essa medida não se sustentaria sem comprometer gravemente a Segurança da Informação de um modo geral e, provavelmente por isso, já foi reconsiderada nesse aspecto.

segunda-feira, 22 de julho de 2024

Degravação de Conversas Exportadas do WhatsApp com Python e Whisper

Na semana passada, precisei instruir um processo criminal com uma conversa de WhatsApp que continha mensagens de texto, de áudio e de vídeo.

Para proceder à transcrição, observando a integridade dos arquivos e a sequência cronológica das mensagens, recorremos ao Python e à Inteligência Artificial, usando o Whisper, que é um modelo de fala de código aberto.

O script encontra os arquivos de áudio (opus) e vídeo (mp4) na pasta da conversa de WhatsApp exportada. Na sequência, lê o arquivo do chat, linha a linha. Quando acha referência às mídias, chama o método do Whisper para fazer a transcrição e a incorpora no texto.

Como de costume, compartilhei o código no GitHub, no repositório [transcreve_zap](https://github.com/jespimentel/transcreve_zap), para que possa ser reusado e aprimorado.

Também deixei uma demonstração de seu funcionamento no YouTube:[Degravação do WhatsApp com Python]( https://www.youtube.com/watch?v=M1hxhwUWl0M).

Fico à disposição para conversarmos sobre as estratégias usadas nesse programa.

sábado, 8 de junho de 2024

Usando o difflib do Python para configurar reuniões virtuais

Introdução

O difflib é um módulo da biblioteca padrão do Python que permite comparar sequências, tais como arquivos, listas, strings e outros dados. Ele é especialmente útil para identificar e destacar diferenças entre essas sequências.

Neste post, focaremos na função get_close_matches(). Vale a pena, porém, conhecer outras funções contidas no módulo. 

Estrutura da função

difflib.get_close_matches(word, possibilities, n=3, cutoff=0.6)

A função get_close_matches retorna uma lista das melhores correspondências entre uma sequência de caracteres (geralmente palavras) e uma lista de possibilidades. As n respostas mais prováveis são retornadas em ordem decrescente de semelhança. O parâmetro n deve ser maior que 0, sendo 3 o valor padrão.

O ponto de corte (cutoff) é um valor float do intervalo [0, 1], com padrão em 0.6. Pontuações inferiores ao ponto de corte são ignoradas.

Um caso de uso

Durante a última campanha para Procurador-Geral, precisávamos criar reuniões virtuais no MS Teams com um número variado de colegas, às vezes ultrapassando a centena.

Possuíamos uma planilha Excel que relacionava nomes de colegas a seus respectivos e-mails funcionais. Era um documento oficial, de acesso permitido a qualquer membro da Instituição.

Então, listávamos num arquivo texto os nomes aproximados de quem, deveria ser convidado para as reuniões de campanha (às vezes incompletos ou mesmo com algum erro de grafia) e incumbíamos o Python de nos entregar os e-mails correspondentes aos nomes da lista oficial que mais se assemelhassem  aos fornecidos. O acerto chegava próximo dos 100%! 

O script relacionava os e-mails em arquivo texto, de forma que bastava colá-los no campo próprio do MS Teams para que a reunião já estivesse configurada.

O código

import pandas as pd
import difflib

df = pd.read_excel('emails_dos_membros_2024_01.xlsx')
df['Nome'] = df['Nome'].str.lower()
df['E-mail'] = df['E-mail'].str.lower()

# Relação de nomes para a reunião
arq = open("emails.txt", "r")
nomes_para_a_reuniao = ['antonio carlos']

# Itera sobre cada linha do arquivo
for linha in arq:
# Adiciona a linha à lista
nomes_para_a_reuniao.append(linha.rstrip("\n").lower())

# Fecha o arquivo
arq.close()

# Imprime a lista
print(f'Total de nomes: {len(nomes_para_a_reuniao)}')
relacao_oficial = df['Nome'].to_list()

lista_correspondencia = []

for nome in nomes_para_a_reuniao:
correspondencia = difflib.get_close_matches(nome, relacao_oficial, 1, 0.3)
try:
nome_encontrado = correspondencia[0]
lista_correspondencia.append(nome_encontrado)
print(nome, ">>>", nome_encontrado.strip())
except:
print(f'\nPulamos {nome}!!!\n')

print(f"Nomes encontrados: {len(lista_correspondencia)}")
e_mails = []

for index, row in df.iterrows():
for nome in lista_correspondencia:
if row['Nome']==nome:
e_mails.append(row['E-mail'])

# Saída
nome_arquivo = "saida.txt"

with open(nome_arquivo, 'w') as arquivo:
for e_mail in e_mails:
arquivo.write(e_mail + '\n')


Explicação do código

Primeiro, o código importa as bibliotecas necessárias (pandas para manipulação de dados e difflib para comparação de strings). Em seguida, carrega um arquivo Excel contendo nomes e e-mails, converte os valores das colunas 'Nome' e 'E-mail' para letras minúsculas para garantir a consistência nas comparações, e exibe uma amostra dos dados.

Depois, abre um arquivo de texto contendo nomes adicionais e adiciona esses nomes a uma lista preexistente, convertendo cada nome para minúsculas. Em seguida, imprime o total de nomes nessa lista combinada.

Para cada nome na lista combinada, o código usa difflib.get_close_matches para encontrar a correspondência mais próxima na lista de nomes do DataFrame (lista oficial), com um índice de similaridade mínimo. Se encontrar uma correspondência, adiciona o nome correspondente a uma nova lista e imprime a correspondência. Se não encontrar, imprime uma mensagem indicando que o nome foi pulado, para que se possa fazer a inclusão manual. Após isso, imprime o total de nomes encontrados.

Em seguida, o código percorre cada linha do DataFrame, verificando se o nome na linha corresponde a algum nome na lista de correspondência. Se houver correspondência, adiciona o e-mail correspondente a uma lista de e-mails.

Finalmente, o código escreve os e-mails encontrados em um arquivo de texto, um por linha.

Em conclusão: o código compara listas de nomes (lista oficial e lista fornecida), encontra as correspondências e extrai os e-mails associados.

quinta-feira, 28 de março de 2024

Consulta com Python à API pública do DataJud (Base de Dados do Poder Judiciário) do CNJ

O Conselho Nacional de Justiça - CNJ disponibiliza uma API pública que fornece os metadados e movimentações dos processos judiciais não gravados de sigilo. A documentação da ferramenta está disponível aqui.

A API permite pesquisas pelo número de processo ou por classe processual e órgão julgador. A resposta pode conter até 10.000 registros por página.

Cada tribunal tem seu "endpoint" específico. Na documentação da API encontramos a URL do TJSP e a chave pública para a consulta. Usando o Python, criamos uma solicitação POST para obter os dados sobre ANPPs.

Sabendo que a API utiliza o Elasticsearch - uma linguagem de consulta que permite recuperar informações segundo determinados critérios de pesquisa - restringimos a requisição à classe 12729 (que corresponde à "Execução de Medidas Alternativas"). Com o método response.json(), convertemos a resposta da API (em JSON) em dicionário Python, facilitando a criação do dataframe.
Mais à frente, utilizamos a busca pela string "Acordo de Não Persecução Penal" na coluna "assuntos" para restringir o dataframe ao que, de fato, nos interessava (dados sobre os ANPPs).

O código também converteu todos os horários para o fuso de São Paulo.

A partir desse ponto, foi possível agrupar as informações por períodos de tempo e horários, para as devidas análises e plotagens.
Descobrimos, assim, que; - 23,31% dos ajuizamentos de ANPP ocorrem fora do horário de expediente.
- De agosto de 2023 para cá houve uma sensível queda do número de ANPPs ajuizados no Estado de São Paulo, o que talvez se explique em razão da nova regulamentação do ANPP que foi estabelecida no âmbito do MPSP.

O notebook com o código usado na análise pode ser acessado a partir do meu GitHub. Experimente rodá-lo no Colab.

Uma vez que a coluna "movimentos" do dataframe pode conter o Cód: 12735, relativo à extinção da punibilidade pelo cumprimento do ANPP, pode ser interessante, num projeto futuro, verificar qual a porcentagem de acordos cumpridos e o tempo médio para que isso ocorra.