Skip to main content

Python Utility Functions Library for Call Details Records ( CDRs ) from Brazilian Telecommunications Carriers

Project description

Ask DeepWiki

TeleUtils

Ferramentas utilitárias para processamento de registros de chamadas telefônicas (CDR) de operadoras brasileiras.


Visão Geral

O TeleUtils é uma biblioteca Python especializada em extração, transformação e análise de registros de chamadas telefônicas (CDR — Call Detail Records) provenientes de diferentes operadoras e tecnologias brasileiras. A biblioteca fornece um pipeline completo e eficiente para:

  1. Extração: Ler e padronizar arquivos CDR em múltiplos formatos
  2. Transformação: Normalizar dados, converter timestamps e enriquecer registros com indicadores
  3. Análise: Agregar dados e identificar padrões indicadores de atividade abusiva

A biblioteca é construída sobre Apache Spark para processamento escalável de grandes volumes de dados, integrada com Pandas e PyArrow para otimização de I/O.

Formatos Suportados

  • Ericsson — Sistemas de telecomunicações Ericsson
  • TIM VoLTE — Voice over LTE da TIM
  • TIM STIR — STIR/SHAKEN da TIM com autenticação
  • Vivo VoLTE — Voice over LTE da Vivo

Instalação

Com uv (recomendado)

uv pip install teleutils

Para ambiente de desenvolvimento:

git clone https://github.com/InovaFiscaliza/teleutils.git
cd teleutils
uv sync

Com pip

pip install teleutils

Dependências

  • pandas >= 2.3.3
  • pyarrow == 21.0.0
  • pyspark >= 3.5.5

Início Rápido

Exemplo completo cobrindo extração, transformação e análise:

from pyspark.sql import SparkSession
from teleutils.robocalls import (
    RoboCallsExtractor,
    RoboCallsTransformer,
    RoboCallsAnalyzer
)

# Inicializar sessão Spark
spark = SparkSession.builder \
    .appName("CDR Pipeline") \
    .getOrCreate()

# 1. EXTRAÇÃO: Ler CDR em formato CSV
extractor = RoboCallsExtractor(spark)
df_extracted = extractor.extract_cdr_tim_volte(
    source_file="data/tim_volte_cdr.csv",
    target_file="parquet/tim_volte_extracted"
)

# 2. TRANSFORMAÇÃO: Normalizar e padronizar
transformer = RoboCallsTransformer(
    spark,
    limiar_chamada_ofensora=6  # chamadas curtas <= 6 segundos
)
df_transformed = transformer.transform_cdr_tim_volte(
    source_file="parquet/tim_volte_extracted",
    target_file="parquet/tim_volte_transformed"
)

# 3. ANÁLISE: Agregar e identificar padrões
analyzer = RoboCallsAnalyzer(spark)
df_analyzed = analyzer.analyze(
    source_file="parquet/tim_volte_transformed",
    target_file="parquet/tim_volte_analyzed"
)

# Visualizar top 10 originadores mais agressivos
df_analyzed.show(10)

Referência da API

Módulo Responsabilidade Detalhes
preprocessing.number_format Normalização de números telefônicos brasileiros Ver detalhes
robocalls.extractors Extração de dados brutos em formato CDR Ver detalhes
robocalls.transformers Transformação e padronização dos dados Ver detalhes
robocalls.analyzers Análise agregada e detecção de padrões Ver detalhes

Detalhamento da API

Formatação de Números Telefônicos (preprocessing.number_format)

O módulo de formatação de números implementa a normalização de números telefônicos brasileiros de acordo com os padrões ANATEL (Agência Nacional de Telecomunicações) e o padrão internacional ITU-T E.164.

Funções Públicas:

Função Parâmetros Retorno Descrição
normalize_number(subscriber_number, national_destination_code="") subscriber_number (str/int): Número a normalizar
national_destination_code (str): Código de área (opcional)
(str, bool): Número normalizado e flag de validade Normaliza um número telefônico brasileiro
normalize_number_pair(number_a, number_b, national_destination_code="") number_a (str/int): Primeiro número
number_b (str/int): Segundo número
national_destination_code (str): Código de área (opcional)
(str, bool, str, bool): Ambos normalizados com flags Normaliza par de números com inferência contextual de área

Exemplo de Uso:

from teleutils.preprocessing import normalize_number, normalize_number_pair

# Normalizar número individual
numero_formatado, eh_valido = normalize_number("(11) 99999-9999")
print(f"Número: {numero_formatado}, Válido: {eh_valido}")
# Saída: Número: 11999999999, Válido: True

# Normalizar número local com código de área
numero_fmt, valido = normalize_number("88888888", "11")
print(f"Número com DDD: {numero_fmt}")
# Saída: Número com DDD: 1188888888

# Normalizar par de números (origem e destino)
a_fmt, a_ok, b_fmt, b_ok = normalize_number_pair("11999999999", "88888888")
print(f"A: {a_fmt} ({a_ok}), B: {b_fmt} ({b_ok})")
# Saída: A: 11999999999 (True), B: 1188888888 (True)

Extração de CDR (robocalls.extractors)

O módulo de extração fornece ferramentas para ler e padronizar arquivos CDR em múltiplos formatos de operadoras brasileiras. A extração é baseada em esquemas configuráveis que definem delimitador, índices de coluna e nomes finais.

Classes Públicas:

Classe Responsabilidade
RoboCallsExtractor(spark) Extrai dados brutos de arquivos CDR em diferentes formatos
CDRSchema(name, delimiter, has_header, column_indices, column_names, job_description) Define esquema de mapeamento de colunas para um formato CDR específico

Métodos Públicos de RoboCallsExtractor:

Método Parâmetros Retorno Descrição
extract_cdr_ericsson(source_file, target_file) source_file (str): Caminho CSV
target_file (str): Diretório parquet saída
DataFrame Extrai CDR formato Ericsson
extract_cdr_tim_volte(source_file, target_file) source_file (str): Caminho CSV
target_file (str): Diretório parquet saída
DataFrame Extrai CDR formato TIM VoLTE
extract_cdr_tim_stir(source_file, target_file) source_file (str): Caminho CSV
target_file (str): Diretório parquet saída
DataFrame Extrai CDR formato TIM STIR
extract_cdr_vivo_volte(source_file, target_file) source_file (str): Caminho CSV
target_file (str): Diretório parquet saída
DataFrame Extrai CDR formato Vivo VoLTE

Exemplo de Uso:

from pyspark.sql import SparkSession
from teleutils.robocalls import RoboCallsExtractor

spark = SparkSession.builder.appName("Extract CDR").getOrCreate()
extractor = RoboCallsExtractor(spark)

# Extrair CDR TIM VoLTE
df = extractor.extract_cdr_tim_volte(
    source_file="raw_data/cdr_tim_volte.csv",
    target_file="processed/tim_volte_extracted"
)

# Explorar dados extraídos
print(df.printSchema())
print(df.count())  # Total de registros
df.show(5)

Transformação de Dados (robocalls.transformers)

O módulo de transformação padroniza dados CDR brutos, normalizando números telefônicos, parseando timestamps, e enriquecendo registros com indicadores binários de padrão de abuso (chamadas curtas, caixa postal, autenticação).

Classes Públicas:

Classe Responsabilidade
RoboCallsTransformer(spark, limiar_chamada_ofensora=6) Transforma CDR brutos para formato padronizado e enriquecido

Métodos Públicos de RoboCallsTransformer:

Método Parâmetros Retorno Descrição
transform_cdr_ericsson(source_file, target_file) source_file (str): Parquet extraído
target_file (str): Diretório parquet saída
DataFrame Transforma CDR Ericsson
transform_cdr_tim_volte(source_file, target_file) source_file (str): Parquet extraído
target_file (str): Diretório parquet saída
DataFrame Transforma CDR TIM VoLTE
transform_cdr_tim_stir(source_file, target_file) source_file (str): Parquet extraído
target_file (str): Diretório parquet saída
DataFrame Transforma CDR TIM STIR
transform_cdr_vivo_volte(source_file, target_file) source_file (str): Parquet extraído
target_file (str): Diretório parquet saída
DataFrame Transforma CDR Vivo VoLTE

Schema de Saída da Transformação:

Todos os transformadores retornam um DataFrame com as seguintes colunas padronizadas:

Coluna Tipo Descrição Valores
referencia string Identificador único da chamada no CDR Variável conforme fonte
tipo_de_chamada string Classificação da chamada TER, FORv, 3, 4, 82, etc.
data_hora timestamp Data e hora exata da chamada ISO 8601 format
numero_de_a_formatado string Número originador padronizado Formato CN+PREFIXO+MCDU ou como informado
numero_de_b_formatado string Número destinatário padronizado Formato CN+PREFIXO+MCDU ou como informado
hora_da_chamada string Hora cheia (sem minutos/segundos) Formato YYYYMMDDHH
duracao_da_chamada integer Duração total da chamada Segundos (0 se null)
chamada_curta integer Flag indicador de duração curta 0 = duração > limiar, 1 = duração ≤ limiar
chamada_caixa_postal integer Flag indicador de encaminhamento ao correio de voz 0 = não encaminhado, 1 = encaminhado
chamada_autenticada integer Status da autenticação STIR/SHAKEN -1 = falhou, 0 = não verificada, 1 = bem-sucedida

Exemplo de Uso:

from pyspark.sql import SparkSession
from teleutils.robocalls import RoboCallsTransformer

spark = SparkSession.builder.appName("Transform CDR").getOrCreate()
transformer = RoboCallsTransformer(
    spark,
    limiar_chamada_ofensora=6  # Classificar como curta se duração <= 6s
)

# Transformar CDR TIM VoLTE
df_transformed = transformer.transform_cdr_tim_volte(
    source_file="processed/tim_volte_extracted",
    target_file="processed/tim_volte_transformed"
)

# Explorar dados transformados
df_transformed.printSchema()
print(f"Total de registros: {df_transformed.count()}")

# Filtrar chamadas curtas
chamadas_curtas = df_transformed.filter("chamada_curta == 1")
print(f"Chamadas curtas: {chamadas_curtas.count()}")

# Mostrar amostra
df_transformed.show(5)

Análise de Padrões (robocalls.analyzers)

O módulo de análise agrupa recursos CDR por número originador e hora da chamada, computando métricas que indicam atividade abusiva (robocalls, campanhas agressivas de telemarketing).

Classes Públicas:

Classe Responsabilidade
RoboCallsAnalyzer(spark) Analisa CDR transformados e identifica padrões abusivos

Métodos Públicos de RoboCallsAnalyzer:

Método Parâmetros Retorno Descrição
analyze(source_file, target_file="") source_file (str): Parquet transformado
target_file (str): Diretório parquet saída
DataFrame Agrupa por (numero_de_a_formatado, hora_da_chamada) e calcula métricas

Schema de Saída da Análise:

Coluna Tipo Descrição
numero_de_a_formatado string Número originador (agregação)
hora_da_chamada string Hora cheia em formato YYYYMMDDHH (agregação)
total_chamadas long Contagem total de chamadas no grupo
total_chamadas_curtas long Contagem de chamadas com duração ≤ limiar
total_chamadas_caixa_postal long Contagem de chamadas encaminhadas ao correio de voz
total_chamadas_autenticadas long Contagem de chamadas com autenticação bem-sucedida (score = 1)

Exemplo de Uso:

from pyspark.sql import SparkSession
from teleutils.robocalls import RoboCallsAnalyzer

spark = SparkSession.builder.appName("Analyze CDR").getOrCreate()
analyzer = RoboCallsAnalyzer(spark)

# Analisar padrões
df_analyzed = analyzer.analyze(
    source_file="processed/tim_volte_transformed",
    target_file="analyzed/tim_volte_analyzed"
)

# Top 10 originadores mais agressivos (mais chamadas curtas)
df_analyzed.show(10)

# Filtrar padrões com alta concentração de chamadas curtas
padroes_suspeitos = df_analyzed.filter("total_chamadas_curtas >= 50")
print(f"Padrões suspeitos identificados: {padroes_suspeitos.count()}")

# Estatísticas por hora
df_analyzed.groupBy("hora_da_chamada") \
    .agg({"total_chamadas_curtas": "sum"}) \
    .sort("hora_da_chamada") \
    .show(24)

Contribuição

Configuração do Ambiente de Desenvolvimento

  1. Clone o repositório:

    git clone https://github.com/InovaFiscaliza/teleutils.git
    cd teleutils
    
  2. Sincronize dependências com uv:

    uv sync
    
  3. Ative o ambiente virtual:

    source .venv/bin/activate
    
  4. Instale hooks de pré-commit:

    pre-commit install
    

Padrões de Desenvolvimento

  • Commits: Siga Conventional Commits com gitmoji
    • Exemplos: ✨ feat: adicionar novo formato de CDR, 🐛 fix: corrigir parsing de datas
  • Código: Respeite linting com ruff e formatação com black
  • Testes: Escreva testes para novas funcionalidades
  • Documentação: Mantenha docstrings em Google Style e atualize este README quando necessário

Executando Testes

# Executar todos os testes
pytest tests/

# Com cobertura
pytest --cov=teleutils tests/

# Testes específicos
pytest tests/robocalls/

Licença

TeleUtils é licenciado sob GNU General Public License v3.0. Veja o arquivo LICENSE para mais detalhes.


Referências


Desenvolvido por: InovaFiscaliza Última atualização: Março 2026

Project details


Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

teleutils-0.1.0.tar.gz (19.2 kB view details)

Uploaded Source

Built Distribution

If you're not sure about the file name format, learn more about wheel file names.

teleutils-0.1.0-py3-none-any.whl (23.6 kB view details)

Uploaded Python 3

File details

Details for the file teleutils-0.1.0.tar.gz.

File metadata

  • Download URL: teleutils-0.1.0.tar.gz
  • Upload date:
  • Size: 19.2 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? No
  • Uploaded via: uv/0.9.2

File hashes

Hashes for teleutils-0.1.0.tar.gz
Algorithm Hash digest
SHA256 9791b7beba22b59e6857ed5e7f5d0fa65ffa9f2b66b9d9c5bd979990a76810ba
MD5 ac2494daf508a8d5590e7fe6a340b957
BLAKE2b-256 a02a00408b9b9371c1bc175f5fac1d42749557bab9cde25e026f5ca4da671fbd

See more details on using hashes here.

File details

Details for the file teleutils-0.1.0-py3-none-any.whl.

File metadata

  • Download URL: teleutils-0.1.0-py3-none-any.whl
  • Upload date:
  • Size: 23.6 kB
  • Tags: Python 3
  • Uploaded using Trusted Publishing? No
  • Uploaded via: uv/0.9.2

File hashes

Hashes for teleutils-0.1.0-py3-none-any.whl
Algorithm Hash digest
SHA256 21c45d45609a3b64de7febc1aa34e57fdf8b71bf8179ffa54325ffc9e1baa889
MD5 eeb681659229e124319e04bb0a88f08e
BLAKE2b-256 d923989f33c4e5378280bc2327a049017ff794626bff00380b869fb074ab7b6a

See more details on using hashes here.

Supported by

AWS Cloud computing and Security Sponsor Datadog Monitoring Depot Continuous Integration Fastly CDN Google Download Analytics Pingdom Monitoring Sentry Error logging StatusPage Status page