Skip to main content

A Python library for Asterisk Gateway Interface (AGI) applications

Project description

BasicAGI

A Python library for creating Asterisk Gateway Interface (AGI) applications.

PyPI version Python versions License: MIT

What is AGI?

The Asterisk Gateway Interface (AGI) is a powerful interface that allows external programs to control call flow in Asterisk PBX. AGI scripts can be written in any language and provide a way to add custom logic to your dialplan.

Features

  • Simple and intuitive API - Easy-to-use Python interface for AGI commands
  • Comprehensive command support - Covers all major AGI commands and functions
  • Robust variable handling - Access to all AGI environment variables
  • Audio and media control - Stream files, play prompts, and control media
  • Database operations - Read/write to Asterisk database
  • Call control - Answer, hangup, transfer, and redirect calls
  • TTS and speech - Text-to-speech and digit/number speaking functions
  • Debug support - Built-in debugging capabilities
  • Production ready - Used in real-world VoIP applications

Installation

Install BasicAGI using pip:

pip install basicagi

Quick Start

Here's a simple AGI script that answers a call, plays a welcome message, and hangs up:

#!/usr/bin/env python3

from basicagi import BasicAGI

def main():
    # Create AGI instance
    agi = BasicAGI()

    # Answer the call
    agi.answer()

    # Play welcome message
    agi.stream_file("welcome")

    # Say the caller ID
    caller_id = agi.get_agi_var("callerid")
    if caller_id:
        agi.say_digits(caller_id)

    # Hang up
    agi.hangup()

if __name__ == "__main__":
    main()

Usage Examples

Basic Call Handling

from basicagi import BasicAGI

agi = BasicAGI()

# Answer the call
agi.answer()

# Get caller information
caller_id = agi.get_agi_var("callerid")
channel = agi.get_agi_var("channel")

# Set caller ID
agi.set_callerid("1234567890", "My Company")

# Play audio file with digit interruption
digit = agi.stream_file("menu", "123456789*0#")

# Process user input
if digit == "1":
    agi.stream_file("option1")
elif digit == "2":
    agi.stream_file("option2")
else:
    agi.stream_file("invalid")

agi.hangup()

Interactive Voice Response (IVR)

from basicagi import BasicAGI

def handle_ivr():
    agi = BasicAGI()
    agi.answer()

    while True:
        # Play main menu
        digit = agi.get_option("main-menu", "123456789*0#", 5000)

        if digit == "1":
            # Sales department
            agi.stream_file("connecting-sales")
            agi.exec("Dial", "PJSIP/sales@internal")
            break
        elif digit == "2":
            # Support department
            agi.stream_file("connecting-support")
            agi.exec("Dial", "PJSIP/support@internal")
            break
        elif digit == "0":
            # Operator
            agi.stream_file("connecting-operator")
            agi.exec("Dial", "PJSIP/operator@internal")
            break
        else:
            # Invalid option
            agi.stream_file("invalid-option")
            continue

    agi.hangup()

if __name__ == "__main__":
    handle_ivr()

Database Operations

from basicagi import BasicAGI

agi = BasicAGI()
agi.answer()

# Store caller information
caller_id = agi.get_agi_var("callerid")
agi.database_put("callers", caller_id, "last_call_time", str(time.time()))

# Retrieve stored data
last_call = agi.database_get("callers", f"{caller_id}/last_call_time")
if last_call:
    agi.verbose(f"Caller {caller_id} last called at {last_call}")

# Set CDR variables
agi.set_cdr_variable("custom_field", "important_call")

agi.hangup()

Text-to-Speech and Number Handling

from basicagi import BasicAGI
import time

agi = BasicAGI()
agi.answer()

# Say current time
current_time = int(time.time())
agi.say_datetime(current_time, "", "ABdY 'digits/at' IMp")

# Say a number
agi.say_number(12345)

# Spell out text
agi.say_alpha("HELLO")

# Say individual digits
agi.say_digits("567890")

agi.hangup()

AGI Environment Variables

Access Asterisk environment variables easily:

from basicagi import BasicAGI

agi = BasicAGI()

# Get specific variable
caller_id = agi.get_agi_var("callerid")
channel = agi.get_agi_var("channel")
extension = agi.get_agi_var("extension")

# Get all available variables
all_vars = agi.get_all_agi_vars()
for key, value in all_vars.items():
    agi.verbose(f"{key}: {value}")

# Get list of all variable keys
var_keys = agi.get_agi_var_keys()

Debugging

Enable debugging by setting the AGI_DEBUG environment variable:

export AGI_DEBUG=true
python your_agi_script.py

Or in your Asterisk dialplan:

exten => 123,1,Set(AGI_DEBUG=true)
same => n,AGI(your_script.py)

Asterisk Integration

Using in Dialplan

Add your AGI script to your Asterisk dialplan:

[incoming]
exten => _X.,1,AGI(your_script.py)
same => n,Hangup()

File Permissions

Make sure your AGI script is executable:

chmod +x /var/lib/asterisk/agi-bin/your_script.py

AGI Directory

Place your scripts in the Asterisk AGI directory (typically /var/lib/asterisk/agi-bin/)

API Reference

Core Methods

  • answer() - Answer the channel
  • hangup(channel=None) - Hang up the channel
  • exec(application, *args) - Execute an Asterisk application

Audio & Media

  • stream_file(audio_file, escape_digits="", offset=None) - Stream an audio file
  • get_option(audio_file, escape_digits="", timeout=0) - Stream file and wait for digit
  • control_stream_file(...) - Stream file with control (FF/RW/pause)
  • set_music(on_off, music_class="") - Enable/disable music on hold

Speech & TTS

  • say_alpha(string, escape_digits="") - Say character string
  • say_digits(number, escape_digits="") - Say digits one by one
  • say_number(number, escape_digits="", gender="") - Say number
  • say_date(date, escape_digits="") - Say date
  • say_time(time, escape_digits="") - Say time
  • say_datetime(time, escape_digits="", format="", timezone="") - Say date and time

Variables & Data

  • get_variable(name) - Get channel variable
  • set_variable(name, value="") - Set channel variable
  • get_agi_var(keyname) - Get AGI environment variable
  • get_all_agi_vars() - Get all AGI variables
  • set_cdr_variable(name, value="") - Set CDR variable

Database Operations

  • database_get(family, key) - Get value from Asterisk database
  • database_put(family, key, value) - Put value into Asterisk database
  • database_del(family, key) - Delete key from database
  • database_deltree(family, key=None) - Delete database tree

Call Control

  • set_callerid(number, name=None) - Set caller ID
  • set_context(context) - Set context for continuation
  • set_extension(extension) - Set extension for continuation
  • set_priority(priority) - Set priority for continuation
  • channel_status(channel=None) - Get channel status

User Input

  • get_data(audio_file, timeout=None, max_digits=None) - Get data from user
  • wait_for_digit(timeout=-1) - Wait for digit press
  • receive_char(timeout=0) - Receive character from channel
  • receive_text(timeout=0) - Receive text from channel

Development

Setup Development Environment

# Create virtual environment
uv venv .venv

# Install package in development mode with dependencies
source .venv/bin/activate && uv pip install -e .

# Install test and development dependencies
source .venv/bin/activate && uv pip install pytest pytest-cov ruff

Code Quality and Pre-commit Checks

Before submitting any changes, ensure your code passes all quality checks:

# Sort imports with ruff
source .venv/bin/activate && ruff check --select I --fix basicagi tests examples

# Format code with ruff
source .venv/bin/activate && ruff format basicagi tests examples

# Run linter with ruff
source .venv/bin/activate && ruff check basicagi tests examples

# Fix linting issues automatically
source .venv/bin/activate && ruff check --fix basicagi tests examples

# Run tests
source .venv/bin/activate && python -m pytest tests/

# Run tests with coverage
source .venv/bin/activate && python -m pytest tests/ --cov=basicagi --cov-report=html

Git Pre-commit Hook (Recommended)

Automate code quality checks with a Git pre-commit hook:

# Install the Git pre-commit hook
./git-hooks-setup.sh

The Git pre-commit hook will automatically run before each commit and will:

  • Sort imports with ruff
  • Format code with ruff
  • Run linting with ruff
  • Run tests if test files are modified

To bypass the hook for a specific commit: git commit --no-verify

Manual Pre-commit Workflow

If not using pre-commit hooks, run these commands before committing:

  1. Sort imports: ruff check --select I --fix basicagi tests examples
  2. Format code: ruff format basicagi tests examples
  3. Check linting: ruff check basicagi tests examples
  4. Run tests: python -m pytest tests/

This ensures consistent code style and catches issues early.

Contributing

Contributions are welcome! Please feel free to submit a Pull Request.

License

This project is licensed under the MIT License - see the LICENSE file for details.

Related Projects

  • Asterisk - The open source PBX
  • pyst2 - Python library for Asterisk

Support

For bug reports and feature requests, please use the GitHub Issues page.

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

basicagi-1.0.1.tar.gz (15.2 kB view details)

Uploaded Source

Built Distribution

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

basicagi-1.0.1-py3-none-any.whl (9.7 kB view details)

Uploaded Python 3

File details

Details for the file basicagi-1.0.1.tar.gz.

File metadata

  • Download URL: basicagi-1.0.1.tar.gz
  • Upload date:
  • Size: 15.2 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/6.1.0 CPython/3.13.7

File hashes

Hashes for basicagi-1.0.1.tar.gz
Algorithm Hash digest
SHA256 a9cdedf9a5e40c9b6371b83bb09109976855f92841e0f16ac60246755751b9cd
MD5 b2e836e6ebdd9bf8f919698b12c490c5
BLAKE2b-256 ab6318fa708f93c453a846d4163e199e06e5e22aa3ff7a4e160fb79a015cdafb

See more details on using hashes here.

File details

Details for the file basicagi-1.0.1-py3-none-any.whl.

File metadata

  • Download URL: basicagi-1.0.1-py3-none-any.whl
  • Upload date:
  • Size: 9.7 kB
  • Tags: Python 3
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/6.1.0 CPython/3.13.7

File hashes

Hashes for basicagi-1.0.1-py3-none-any.whl
Algorithm Hash digest
SHA256 5326cd25a665f8bdfbb2ca82d2c1a83d4772495bc20e752d063469b834dbc0d5
MD5 03a845edb42c5f0a87d9fb780e703a2d
BLAKE2b-256 1037c1d813499e066d30eafb2802c8ba6a6018cc16e559226e4f7080b793da0a

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