Skip to content

Demo Application that uses SignalWire to call into a one leg conference and transcribe it.

signalwire/transcribe-app

Repository files navigation

SignalWire Live Transcription System

A Flask-based system for managing one-leg calls with SignalWire, featuring real-time transcription control (start/stop/summarize) through REST APIs. All SignalWire credentials are stored securely on the backend server.

Features

  • 🔐 JWT-based authentication
  • 📞 One-leg call architecture with infinite hold
  • 🎙️ Dynamic transcription control (start/stop/summarize)
  • 🔒 Secure credential management (backend only)
  • 🚀 Real-time updates via WebSocket
  • 📊 PostgreSQL for data persistence
  • 🔄 Redis for caching and pub/sub
  • 🐳 Docker containerization

Prerequisites

  • Docker and Docker Compose
  • SignalWire account with:
    • Space name
    • Project ID
    • API Token
    • Phone number for outbound calls

Quick Start

1. Clone the repository

git clone <repository-url>
cd signalwire-transcription

2. Configure environment variables

cp .env.example .env

Edit .env and add your SignalWire credentials:

SIGNALWIRE_SPACE=your-space-name
SIGNALWIRE_PROJECT_ID=your-project-id
SIGNALWIRE_API_TOKEN=your-api-token
SIGNALWIRE_FROM_NUMBER=+1234567890

Note: Docker Compose automatically loads variables from the .env file in the same directory. All services will have access to these environment variables.

3. Start the services

docker-compose up -d

This will start:

  • PostgreSQL database on port 5432
  • Redis on port 6379
  • Flask application on port 3000 (macOS-friendly, avoids port 5000 conflict with AirPlay)

4. Initialize the database

docker-compose exec app flask db init
docker-compose exec app flask db migrate -m "Initial migration"
docker-compose exec app flask db upgrade

API Documentation

Authentication

Register

POST /api/auth/register
Content-Type: application/json

{
    "email": "[email protected]",
    "password": "securepassword"
}

Login

POST /api/auth/login
Content-Type: application/json

{
    "email": "[email protected]",
    "password": "securepassword"
}

Response:

{
    "message": "Login successful",
    "user": {...},
    "access_token": "eyJhbGc...",
    "refresh_token": "eyJhbGc...",
    "expires_in": 3600
}

Call Management

All call endpoints require authentication via Bearer token.

Initiate a Call

POST /api/calls/initiate
Authorization: Bearer <token>
Content-Type: application/json

{
    "destination": "+14155551234",
    "destination_type": "phone",
    "auto_transcribe": false
}

Start Transcription

PUT /api/calls/{call_sid}/transcription
Authorization: Bearer <token>
Content-Type: application/json

{
    "action": "start"
}

Stop Transcription

PUT /api/calls/{call_sid}/transcription
Authorization: Bearer <token>
Content-Type: application/json

{
    "action": "stop"
}

Get Summary

PUT /api/calls/{call_sid}/transcription
Authorization: Bearer <token>
Content-Type: application/json

{
    "action": "summarize"
}

End Call

POST /api/calls/{call_sid}/end
Authorization: Bearer <token>

Get Call Details

GET /api/calls/{call_sid}
Authorization: Bearer <token>

List User's Calls

GET /api/calls?page=1&per_page=10
Authorization: Bearer <token>

Get Full Transcript

GET /api/calls/{call_sid}/transcript
Authorization: Bearer <token>

WebSocket Events

Connect to the WebSocket endpoint for real-time updates:

const socket = io('http://localhost:3000');

// Authenticate
socket.emit('authenticate', {
    token: 'your-jwt-token'
});

// Join a call room
socket.emit('join_call', {
    call_sid: 'call-sid-here',
    token: 'your-jwt-token'
});

// Listen for events
socket.on('transcription', (data) => {
    console.log('New transcription:', data);
});

socket.on('summary', (data) => {
    console.log('Summary received:', data);
});

socket.on('call_status', (data) => {
    console.log('Call status updated:', data);
});

Development

Running locally without Docker

  1. Install Python 3.11+
  2. Create a virtual environment:
python -m venv venv
source venv/bin/activate  # On Windows: venv\Scripts\activate
  1. Install dependencies:
pip install -r requirements.txt
  1. Set environment variables:
export FLASK_APP=app.main:app
export FLASK_ENV=development
  1. Run the application:
flask run

Running tests

docker-compose exec app pytest

Database migrations

Create a new migration:

docker-compose exec app flask db migrate -m "Description"

Apply migrations:

docker-compose exec app flask db upgrade

Project Structure

signalwire-transcription/
├── app/
│   ├── api/           # API endpoints
│   ├── models/        # Database models
│   ├── services/      # Business logic
│   ├── utils/         # Helper functions
│   └── main.py        # Application entry point
├── config/            # Configuration files
├── migrations/        # Database migrations
├── docker-compose.yml # Docker services
├── Dockerfile         # Container definition
├── requirements.txt   # Python dependencies
└── README.md         # This file

Security Considerations

  • SignalWire credentials are stored only in environment variables
  • Frontend never has access to SignalWire credentials
  • All API calls to SignalWire are made from the backend
  • JWT tokens expire after 1 hour (configurable)
  • CORS is configured for specific origins
  • Webhook endpoints validate SignalWire signatures (recommended)

Troubleshooting

Database connection issues

docker-compose logs postgres

Application errors

docker-compose logs app

Reset everything

docker-compose down -v
docker-compose up -d

Production Deployment

  1. Use a proper WSGI server (already configured with Gunicorn)
  2. Set up SSL/TLS certificates for HTTPS
  3. Configure a reverse proxy (Nginx/Apache)
  4. Use strong JWT secrets and database passwords
  5. Set up monitoring and logging
  6. Configure firewall rules for SignalWire webhooks

License

[Your License Here]

Support

For issues and questions, please open a GitHub issue.

About

Demo Application that uses SignalWire to call into a one leg conference and transcribe it.

Resources

Stars

Watchers

Forks

Releases

No releases published

Packages

No packages published