Skip to content

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

9 Commits
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

bulk outbound calls with automatic transcription. places calls via Telnyx, plays a prompt, records the response, downloads the audio, and runs it through OpenAI Whisper. results stream to a TSV file as they complete.

cli-bulk-caller call numbers.txt

also works as a standalone transcriber for local audio files — no Telnyx needed.

python Flask license


how it works

numbers.txt
  → telnyx.Call.create() per number (thread pool, concurrent)
  → call answered → playback_start(audio_url) + record_start()
  → Telnyx fires webhook: call.recording.saved
  → download recording → OpenAI Whisper transcription
  → append result to TSV

a Flask server handles the Telnyx webhook lifecycle. the whole pipeline is event-driven — calls fan out, webhooks come back, transcriptions stream to disk. nothing is batched at the end.

what it does

  • concurrent outbound calls — reads E.164 numbers from a file, fans out via thread pool
  • automatic playback + recording — plays your audio prompt on answer, starts recording simultaneously
  • webhook-driven pipeline — Flask server reacts to Telnyx events (call.answered, call.hangup, call.recording.saved)
  • Whisper transcription — downloads recording, sends to whisper-1, writes result immediately
  • standalone file transcription — skip Telnyx entirely, transcribe local files or directories
  • exponential backoff — retries transcription up to 10 times with delay * 2^attempt
  • thread-safe incremental output — results written as they complete, not held in memory
  • multi-format output — TSV (default), CSV, or newline-delimited JSON

install

git clone https://github.com/yigitkonur/cli-bulk-caller.git
cd cli-bulk-caller
pip install .

this registers two CLI commands: cli-bulk-caller and tt (short alias).

configure

copy the example and fill it in:

cp .env.example .env
# required for call mode
TELNYX_API_KEY=your_telnyx_api_key
TELNYX_CONNECTION_ID=your_connection_id
TELNYX_FROM_NUMBER=+1234567890
AUDIO_URL=https://example.com/prompt.mp3

# required always
OPENAI_API_KEY=your_openai_api_key

# optional
WEBHOOK_HOST=0.0.0.0
WEBHOOK_PORT=5000
OUTPUT_FILE=results.tsv
MAX_WORKERS=5
RECORDING_FORMAT=mp3
RECORDING_CHANNELS=single
MAX_RETRIES=10
RETRY_DELAY=2.0

usage

place calls and transcribe

cli-bulk-caller call numbers.txt
cli-bulk-caller call numbers.txt --output calls.tsv --workers 10

numbers.txt is one E.164 phone number per line.

transcribe local files

cli-bulk-caller transcribe recording.mp3
cli-bulk-caller transcribe ./recordings/ --workers 3 --language en

supports .mp3, .wav, .m4a, .ogg, .flac, .webm, .mp4, .mpeg, .mpga.

run webhook server standalone

cli-bulk-caller server --port 5000 --host 0.0.0.0 --output results.tsv

validate config

cli-bulk-caller validate

prints a checklist of which required env vars are set.

CLI reference

call <numbers_file>

flag default description
--output / -o results.tsv output file path
--workers / -w 5 concurrent calls
--no-server skip starting the webhook server

transcribe <source>

flag default description
--output / -o transcriptions.tsv output file path
--workers / -w 3 concurrent transcriptions
--language / -l auto-detect BCP-47 language hint for Whisper (e.g. en, es, tr)

server

flag default description
--port / -p 5000 webhook server port
--host / -h 0.0.0.0 webhook server host
--output / -o results.tsv output file path

webhook endpoints

method path description
GET /health health check, returns active call count
POST /webhook main Telnyx event receiver
POST /webhook/call-recording-saved dedicated recording-saved handler
GET /webhook/health blueprint health check

the webhook server must be publicly reachable for Telnyx to deliver events. use ngrok, a reverse proxy, or deploy to a server with a public IP.

project structure

src/cli_bulk_caller/
  __init__.py              — package root
  __main__.py              — python -m support
  app.py                   — Flask app factory + orchestrator
  cli.py                   — Typer CLI (call, transcribe, server, validate)
  config.py                — settings dataclass, env loading, validation
  exceptions.py            — custom exception hierarchy
  models.py                — Call, TranscriptionResult, CallTranscriptionResult
  services/
    call_service.py        — Telnyx call lifecycle + thread pool fan-out
    transcription_service.py — Whisper interface, URL download, directory batch
    output_service.py      — thread-safe TSV/CSV/JSON writer
  utils/
    console.py             — Rich terminal UI
    logging.py             — logging config
  webhooks/
    handlers.py            — webhook dispatch + Flask blueprint

configuration reference

variable required default description
TELNYX_API_KEY call mode Telnyx API key
TELNYX_CONNECTION_ID call mode Telnyx connection/SIP trunk ID
TELNYX_FROM_NUMBER call mode caller ID (E.164)
OPENAI_API_KEY always OpenAI API key for Whisper
AUDIO_URL call mode URL of audio prompt played on answer
WEBHOOK_HOST no 0.0.0.0 Flask server host
WEBHOOK_PORT no 5000 Flask server port
OUTPUT_FILE no results.tsv output file path
MAX_WORKERS no 5 max concurrent calls/transcriptions
RECORDING_FORMAT no mp3 mp3 or wav
RECORDING_CHANNELS no single single or dual
MAX_RETRIES no 10 max Whisper retry attempts
RETRY_DELAY no 2.0 base delay (seconds) for exponential backoff

license

MIT

About

bulk outbound calls with automatic Whisper transcription via Telnyx

Topics

Resources

Stars

141 stars

Watchers

4 watching

Forks

Releases

Packages

Contributors

Languages