use crate::device::shared::{AiOptions, RecordOptions, TranscribeOptions};
use crate::{format_number, AsrVendor, FlowState, NumberFormat, Region, VoiceServer};
use cal_jambonz::dial::TranscribeDial;
use cal_jambonz::listen::Listen;
use cal_jambonz::recognizer::Recognizer;
use cal_jambonz::vendors::amazon::{AWSRecognizer, AwsAsrLanguage};
use cal_jambonz::vendors::deepgram::DeepgramRecognizer;
use cal_jambonz::vendors::google::{
GoogleInteractionType, GoogleRecognizer, GoogleRecognizerLanguage, GoogleSpeechModel,
};
use cal_jambonz::vendors::ibm::IbmRecognizer;
use cal_jambonz::vendors::microsoft::MSRecognizer;
use cal_jambonz::vendors::nvidia::NvidiaRecognizer;
use cal_jambonz::vendors::soniox::SonioxRecognizer;
use cal_jambonz::verbs;
use rand::prelude::SliceRandom;
use rand::rng;
use std::collections::HashMap;
use std::sync::Arc;
pub fn get_transcribe(transcribe_opts: TranscribeOptions) -> Option<TranscribeDial> {
if transcribe_opts.enabled {
match transcribe_opts.language {
AsrVendor::Deepgram => {
let transcribe = TranscribeDial {
transcription_hook: "transcribe".to_string(),
recognizer: Recognizer::Deepgram(DeepgramRecognizer {
language: None,
separate_recognition_per_channel: Some(true),
hints: None,
vad: None,
interim: None,
alt_languages: None,
asr_dtmf_termination_digit: None,
asr_timeout: None,
deepgram_options: None,
}),
};
Some(transcribe)
}
AsrVendor::Google => {
let transcribe = TranscribeDial {
transcription_hook: "transcribe".to_string(),
recognizer: Recognizer::Google(GoogleRecognizer {
language: Some(GoogleRecognizerLanguage::EnglishUnitedKingdom),
interaction_type: Some(GoogleInteractionType::PhoneCall),
model: Some(GoogleSpeechModel::PhoneCall),
separate_recognition_per_channel: Some(true),
enhanced_model: Some(true),
vad: None,
interim: None,
alt_languages: None,
asr_dtmf_termination_digit: None,
asr_timeout: None,
diarization: None,
diarization_min_speakers: None,
diarization_max_speakers: None,
hints: None,
hints_boost: None,
naics_code: None,
punctuation: None,
single_utterance: None,
}),
};
Some(transcribe)
}
AsrVendor::Aws => {
let transcribe = TranscribeDial {
transcription_hook: "transcribe".to_string(),
recognizer: Recognizer::Aws(AWSRecognizer {
language: Some(AwsAsrLanguage::EnglishBritish),
separate_recognition_per_channel: Some(true),
identify_channels: Some(true),
vad: None,
interim: None,
alt_languages: None,
asr_dtmf_termination_digit: None,
asr_timeout: None,
filter_method: None,
vocabulary_name: None,
vocabulary_filter_name: None,
}),
};
Some(transcribe)
}
AsrVendor::Ibm => {
let transcribe = TranscribeDial {
transcription_hook: "transcribe".to_string(),
recognizer: Recognizer::Ibm(IbmRecognizer {
vad: None,
interim: None,
language: None,
alt_languages: None,
asr_dtmf_termination_digit: None,
asr_timeout: None,
separate_recognition_per_channel: Some(true),
ibm_options: None,
}),
};
Some(transcribe)
}
AsrVendor::Microsoft => {
let transcribe = TranscribeDial {
transcription_hook: "transcribe".to_string(),
recognizer: Recognizer::Microsoft(MSRecognizer {
vad: None,
interim: None,
language: None,
alt_languages: None,
asr_dtmf_termination_digit: None,
asr_timeout: None,
separate_recognition_per_channel: None,
azure_service_endpoint: None,
azure_options: None,
hints: None,
initial_speech_timeout_ms: None,
profanity_filter: None,
profanity_option: None,
output_format: None,
request_snr: None,
}),
};
Some(transcribe)
}
AsrVendor::Nuance => {
let transcribe = TranscribeDial {
transcription_hook: "transcribe".to_string(),
recognizer: Recognizer::Microsoft(MSRecognizer {
vad: None,
interim: None,
language: None,
alt_languages: None,
asr_dtmf_termination_digit: None,
asr_timeout: None,
separate_recognition_per_channel: None,
azure_service_endpoint: None,
azure_options: None,
hints: None,
initial_speech_timeout_ms: None,
profanity_filter: None,
profanity_option: None,
output_format: None,
request_snr: None,
}),
};
Some(transcribe)
}
AsrVendor::Nvidia => {
let transcribe = TranscribeDial {
transcription_hook: "transcribe".to_string(),
recognizer: Recognizer::Nvidia(NvidiaRecognizer {
vad: None,
interim: None,
language: None,
alt_languages: None,
asr_dtmf_termination_digit: None,
asr_timeout: None,
separate_recognition_per_channel: None,
hints: None,
hints_boost: None,
nvidia_options: None,
}),
};
Some(transcribe)
}
AsrVendor::Soniox => {
let transcribe = TranscribeDial {
transcription_hook: "transcribe".to_string(),
recognizer: Recognizer::Soniox(SonioxRecognizer {
vad: None,
interim: None,
language: None,
alt_languages: None,
asr_dtmf_termination_digit: None,
asr_timeout: None,
separate_recognition_per_channel: None,
hints: None,
soniox_options: None,
}),
};
Some(transcribe)
}
}
} else {
None
}
}
pub fn get_caller_id(format: &NumberFormat, state: &FlowState) -> String {
let caller_id = match state.data.get("from") {
Some(dt) => dt.value.clone(),
None => state.initial_request.to.clone(),
};
format_number(
caller_id.as_str(),
state.account.country_code(),
&format.clone(),
)
}
pub fn get_called_id(format: &NumberFormat, state: &FlowState) -> String {
let called_id = match state.data.get("to") {
Some(dt) => dt.value.clone(),
None => state.initial_request.to.clone(),
};
format_number(
called_id.as_str(),
state.account.country_code(),
&format.clone(),
)
}
pub fn get_proxy(
proxies: Vec<String>,
state: &FlowState,
regions: Vec<Arc<Region>>,
) -> Option<VoiceServer> {
let mut proxies = proxies.clone();
proxies.shuffle(&mut rng());
for proxy in &proxies {
if let Some(vs) = state.region.voice_servers.iter().find(|vs| vs.id == *proxy) {
return Some(vs.clone());
}
}
for region in ®ions {
for proxy in &proxies {
if let Some(vs) = region.voice_servers.iter().find(|vs| vs.id == *proxy) {
return Some(vs.clone());
}
}
}
None
}
pub fn get_listen(
record_options: &RecordOptions,
ai_options: AiOptions,
state: &FlowState,
) -> Option<Listen> {
match record_options.enabled {
true => {
let mut meta: HashMap<String, String> = HashMap::new();
meta.insert("type".to_string(), "session:record".to_string());
meta.insert("account_id".to_string(), state.account.id.clone());
meta.insert(
"retention".to_string(),
record_options.retention.to_string(),
);
meta.insert("ai_summary".to_string(), ai_options.summary.to_string());
meta.insert(
"ai_transcribe".to_string(),
ai_options.transcribe.to_string(),
);
let transcribe: Option<verbs::transcribe::Transcribe> = match ai_options.recognizer {
Some(recognizer) => Some(verbs::transcribe::Transcribe {
transcription_hook: format!("{}/transcribe", state.base_url),
recognizer,
}),
None => None,
};
let listen = Listen::new(
format!("{}/record", state.base_url),
format!("{}/record-complete", state.base_url),
)
.mix_type(Some(record_options.mix_type.clone()))
.transcribe(transcribe)
.metadata(Some(meta))
.clone();
Some(listen)
}
false => None,
}
}