Skip to content

Analyzer

The analyzer module runs LLM-powered analysis on call transcriptions after a call ends. Two types of analyzers process every call: org analyzers (custom, user-defined) and system analyzers (platform-wide, hidden from users). Both use GPT-5 with a custom prompt to extract insights from the transcription.

Call ends → Transcription saved → analyze_call(call_id)
├─ Org Analyzers (assigned to the phone number)
│ For each: prompt + transcription → GPT-5 → save to call_analysis
└─ System Analyzers (run on every call)
For each: prompt + transcription → GPT-5 → save to system_call_analysis

Created and managed by the organization through the UI and API. Each analyzer has a custom prompt and is assigned to specific phone numbers via the phone_number_analyzer join table.

pub struct Analyzer {
pub id: Uuid,
pub name: String,
pub prompt: String, // LLM instruction for analysis
pub phone_ids: Vec<Uuid>, // Phone numbers this analyzer runs on
pub default: bool, // Auto-assign to new phone numbers
}

Example use cases: sentiment analysis, lead qualification, compliance checks, call summary generation.

Results are stored in the call_analysis table and visible in the call details UI.

Platform-level analyzers stored in the system_analyzer table. They run on every call automatically, regardless of phone number assignments. Organizations don’t see or manage these.

Results are stored in a separate system_call_analysis table.

analyze_call is the main entry point, called after a transcription is saved:

  1. Load the call record and its phone_number_id
  2. Find all org analyzers assigned to that phone number (phone_number_analyzer table)
  3. Run each org analyzer sequentially:
    • Load the analyzer’s prompt
    • Send prompt (system) + transcription (user) to GPT-5
    • Save result to call_analysis with call_id, analyzer_id, analysis_text
  4. Run all system analyzers (from system_analyzer table):
    • Same flow but results go to system_call_analysis with system_analyzer_id

All analysis goes through analyze_call_text:

pub async fn analyze_call_text(
prompt: String, // Analyzer instruction (system message)
transcription: String, // Call transcript (user message)
) -> Result<String, AppError>

Model: GPT-5 via aisdk OpenAI provider. Returns raw text output.

TableAnalyzer TypeKey Fields
call_analysisOrgcall_id, analyzer_id, analysis_text, created_at
system_call_analysisSystemcall_id, system_analyzer_id, analysis_text, created_at

All endpoints require an authenticated session and scope to the org.

RouteMethodDescription
/api/analyzersGETList all org analyzers (phone assignments not loaded)
/api/analyzers/{id}GETGet an analyzer with phone assignments
/api/analyzersPOSTCreate an analyzer with phone assignments
/api/analyzers/{id}PUTUpdate name, prompt, default flag, and phone assignments
/api/analyzers/{id}DELETEDelete an analyzer

Create and update accept AnalyzerData:

pub struct AnalyzerData {
pub name: String,
pub prompt: String,
pub phone_ids: Vec<Uuid>,
pub default: bool,
}

Phone assignment updates use a delete-all-then-reinsert strategy on phone_number_analyzer.

Analyzers are linked to phone numbers, not agents. When a call comes in on a phone number, all analyzers assigned to that number run on the transcription.

The default flag on an analyzer means it gets auto-assigned to newly purchased phone numbers (handled during the phone purchase flow in the twilio module).

src/mods/analyzer/
├── api/ # CRUD for org analyzers
├── components/ # UI: analyzer list, card, details, create form
├── types/ # Analyzer, AnalyzerData
├── utils/ # analyze_call, analyze_call_one_analyzer, analyze_call_system_analyzers, analyze_call_text
└── views/ # AnalyzerListView, AnalyzerDetailsView, CreateAnalyzerView
  • Call — analysis results are linked to calls and shown in call details
  • Phone — analyzers are assigned to phone numbers
  • Todos — todo extraction runs after analysis, also using the transcription