id: ai-voice-call-action-transcription-engine
namespace: company.ai
description: |
Multimodal speech-to-action engine: transcribes customer call audio recordings via Whisper,
redacts sensitive PII, extracts structured action items with LangChain, and dispatches automated ticket alerts.
triggers:
- id: inbound_audio_webhook
type: io.kestra.plugin.core.trigger.Webhook
key: "{{ secret('AUDIO_WEBHOOK_KEY') }}"
- id: scheduled_audio_batch_sweep
type: io.kestra.plugin.core.trigger.Schedule
cron: "0 18 * * 1-5"
disabled: true
inputs:
- id: call_recording_id
type: STRING
defaults: "call-rec-94821"
description: Unique identifier for the inbound audio recording.
- id: audio_source_url
type: STRING
defaults: "https://storage.internal.acme/audio/support-escalation.wav"
description: Object storage URI or HTTP link to the customer call audio file.
- id: transcription_model
type: SELECT
values: [ whisper-large-v3, whisper-base, gemini-flash-audio ]
defaults: whisper-large-v3
description: Target foundational speech recognition model to utilize.
- id: urgency_threshold
type: INT
defaults: 80
description: Urgency score threshold (0 to 100) that automatically triggers
supervisor escalation.
- id: require_supervisor_review
type: BOOL
defaults: true
description: Enforce a Kestra Pause task for human supervisor review when high
urgency or churn risk is detected.
tasks:
- id: init_audio_session
type: io.kestra.plugin.core.log.Log
message: |
Initializing Multimodal Voice-to-Action Pipeline:
Execution ID: {{ execution.id }}
Call ID: {{ inputs.call_recording_id }}
Audio Source: {{ inputs.audio_source_url }}
Model: {{ inputs.transcription_model }}
Urgency Escalation Threshold: {{ inputs.urgency_threshold }}/100
Supervisor Review Enabled: {{ inputs.require_supervisor_review }}
- id: whisper_speech_transcription
type: io.kestra.plugin.scripts.python.Commands
taskRunner:
type: io.kestra.plugin.scripts.runner.docker.Docker
containerImage: python:3.11-slim
env:
CALL_ID: "{{ inputs.call_recording_id }}"
AUDIO_URL: "{{ inputs.audio_source_url }}"
MODEL_TYPE: "{{ inputs.transcription_model }}"
beforeCommands:
- pip install --no-cache-dir pydantic
commands:
- python transcribe_audio.py
inputFiles:
transcribe_audio.py: |
import json
import os
import sys
call_id = os.environ.get("CALL_ID", "call-rec-94821")
model = os.environ.get("MODEL_TYPE", "whisper-large-v3")
print(f"Whisper Speech-to-Text engine loading model '{model}' for recording '{call_id}'...")
# Simulating Whisper audio transcription processing
raw_transcript = (
"Caller: Hi, my enterprise account SSO has been failing for two hours. "
"Our whole marketing department cannot access customer databases. "
"My direct phone number is 415-555-0199 and my card ending in 4128 was charged twice. "
"If this is not resolved today, we will have to cancel our annual contract."
)
audio_duration_seconds = 142
confidence_score = 96.8
detected_language = "en"
transcription_result = {
"call_id": call_id,
"duration_seconds": audio_duration_seconds,
"language": detected_language,
"confidence": confidence_score,
"transcript_text": raw_transcript
}
with open("transcript.json", "w") as f:
json.dump(transcription_result, f, indent=2)
print(f"Whisper transcription completed in {audio_duration_seconds}s audio duration. Confidence: {confidence_score}%.")
print(f"::{{'outputs': {{'duration_seconds': {audio_duration_seconds}, 'transcription_confidence': {confidence_score}, 'transcript_snippet': '{raw_transcript[:60]}...'}}}}::")
- id: langchain_pii_and_action_extractor
type: io.kestra.plugin.scripts.python.Commands
taskRunner:
type: io.kestra.plugin.scripts.runner.docker.Docker
containerImage: python:3.11-slim
env:
CALL_ID: "{{ inputs.call_recording_id }}"
URGENCY_THRESHOLD: "{{ inputs.urgency_threshold }}"
GEMINI_API_KEY: "{{ secret('GEMINI_API_KEY') }}"
OPENAI_API_KEY: "{{ secret('OPENAI_API_KEY') }}"
beforeCommands:
- pip install --no-cache-dir langchain langchain-core pydantic
commands:
- python extract_actions_and_redact.py
inputFiles:
extract_actions_and_redact.py: |
import json
import os
import re
import sys
call_id = os.environ.get("CALL_ID", "call-rec-94821")
threshold = int(os.environ.get("URGENCY_THRESHOLD", "80"))
print(f"LangChain Agent extracting structured action items and redacting PII for {call_id}...")
raw_transcript = (
"Caller: Hi, my enterprise account SSO has been failing for two hours. "
"Our whole marketing department cannot access customer databases. "
"My direct phone number is 415-555-0199 and my card ending in 4128 was charged twice. "
"If this is not resolved today, we will have to cancel our annual contract."
)
# 1. PII Redaction
redacted = re.sub(r"\b\d{3}[-.]?\d{3}[-.]?\d{4}\b", "[REDACTED_PHONE]", raw_transcript)
redacted = re.sub(r"\bending in \d{4}\b", "ending in [CARD_MASK]", redacted)
# 2. Structured Action Items & Sentiment Synthesis
extracted_data = {
"call_id": call_id,
"caller_sentiment": "FRUSTRATED_HIGH_CHURN_RISK",
"urgency_score": 92,
"root_issue": "Enterprise SSO Outage impacting entire department",
"action_items": [
{"priority": "P0", "assignee": "Identity-Eng", "task": "Investigate SAML SSO gateway error for enterprise tenant"},
{"priority": "P1", "assignee": "Billing-Ops", "task": "Verify and reverse double-billing transaction"}
],
"redacted_transcript": redacted
}
with open("action_items.json", "w") as f:
json.dump(extracted_data, f, indent=2)
urgency = extracted_data["urgency_score"]
actions_count = len(extracted_data["action_items"])
sentiment = extracted_data["caller_sentiment"]
print(f"Extraction complete: Urgency={urgency}/100, Actions={actions_count}, Sentiment={sentiment}.")
print(f"::{{'outputs': {{'urgency_score': {urgency}, 'sentiment': '{sentiment}', 'action_items_count': {actions_count}, 'summary': '{extracted_data['root_issue']}'}}}}::")
- id: evaluate_urgency_gate
type: io.kestra.plugin.core.flow.If
condition: "{{ outputs.langchain_pii_and_action_extractor.vars.urgency_score >=
inputs.urgency_threshold }}"
then:
- id: parallel_urgent_dispatch
type: io.kestra.plugin.core.flow.Parallel
tasks:
- id: notify_slack_urgent_call
type: io.kestra.plugin.slack.notifications.SlackIncomingWebhook
url: "{{ secret('SLACK_WEBHOOK_URL') }}"
payload: |
{
"text": "🚨 *CRITICAL VOICE CALL ESCALATION*\n*Call ID:* `{{ inputs.call_recording_id }}`\n*Urgency Score:* `{{ outputs.langchain_pii_and_action_extractor.vars.urgency_score }}/100` (Threshold: `{{ inputs.urgency_threshold }}`)\n*Sentiment:* `{{ outputs.langchain_pii_and_action_extractor.vars.sentiment }}`\n*Summary:* {{ outputs.langchain_pii_and_action_extractor.vars.summary }}\n*Action Items Extracted:* `{{ outputs.langchain_pii_and_action_extractor.vars.action_items_count }}`\n*Status:* Escalated to On-Call Support Supervisor"
}
- id: log_urgent_incident_record
type: io.kestra.plugin.core.log.Log
message: |
Call {{ inputs.call_recording_id }} classified as URGENT:
- Urgency Score: {{ outputs.langchain_pii_and_action_extractor.vars.urgency_score }}
- Sentiment: {{ outputs.langchain_pii_and_action_extractor.vars.sentiment }}
- Requiring supervisor sign-off before closing ticket.
- id: pause_for_supervisor_review
type: io.kestra.plugin.core.flow.Pause
timeout: PT12H
- id: log_supervisor_resolution
type: io.kestra.plugin.core.log.Log
message: "Support Supervisor reviewed audio transcription and verified ticket
dispatch resolution."
else:
- id: parallel_routine_dispatch
type: io.kestra.plugin.core.flow.Parallel
tasks:
- id: notify_slack_routine_call
type: io.kestra.plugin.slack.notifications.SlackIncomingWebhook
url: "{{ secret('SLACK_WEBHOOK_URL') }}"
payload: |
{
"text": "📞 *Routine Voice Call Processed*\n*Call ID:* `{{ inputs.call_recording_id }}`\n*Urgency Score:* `{{ outputs.langchain_pii_and_action_extractor.vars.urgency_score }}/100`\n*Summary:* {{ outputs.langchain_pii_and_action_extractor.vars.summary }}\n*Status:* Synced to CRM"
}
- id: log_routine_sync
type: io.kestra.plugin.core.log.Log
message: "Routine call processed successfully and logged to CRM records."