Files
agc_2-X/extras/vdc_AWS_polly_TTS.php
T
mattf 854cfb1277 Added more debug output to the agi-AGENT_route.agi script
Added FHG(file-http-get) message playback option to download file from website to the VD_amd.agi
Added example script for AWS Polly TTS generation of audio prompts
Updated documentation

git-svn-id: svn://192.168.202.10@3594 3d104415-ff17-0410-8863-d5cf3c621b8a
2022-04-21 19:05:31 +00:00

238 lines
8.0 KiB
PHP

<?php
# vdc_AWS_polly_TTS.php
#
# Copyright (C) 2022 Matt Florell <vicidial@gmail.com> LICENSE: AGPLv2
#
# This script is designed to send a request to Amazon's AWS Polly Text-to-Speech
# service and receive back a PCM audio file(8k, 16bit, mono). Then add a WAV
# file header to it so it can be played natively in Asterisk.
#
# !!! THE AWS PHP SDK IS REQUIRED!!! You can download it here:
# http://docs.aws.amazon.com/aws-sdk-php/v3/download/aws.zip
# (the above zip file contains over 3,000 files, make sure you have space)
# (unzip it inside a new 'polly' directory in the 'agc' web directory)
#
# !!! IMPORTANT !!! You must customize this script to your needs, and you must
# populate the credentials and region for your AWS account
#
# !!! IMPORTANT !!! This script assumes that the directory exists and is writable:
# agc/polly/generated
#
### Example URL to use in a SCRIPT tab Iframe:
# http://127.0.0.1/agc/vdc_AWS_polly_TTS.php?user=--A--user--B--&pass=--A--pass--B--&counter=--A--lead_id--B--&message=message+goes+here
#
# CHANGELOG:
# 220410-2127 - First build of script
#
$version = '2.14-1';
$build = '220410-2127';
$api_script = 'AWS_polly';
$startMS = microtime();
require_once("dbconnect_mysqli.php");
require_once("functions.php");
$query_string = getenv("QUERY_STRING");
if (isset($_GET["user"])) {$user=$_GET["user"];}
elseif (isset($_POST["user"])) {$user=$_POST["user"];}
if (isset($_GET["pass"])) {$pass=$_GET["pass"];}
elseif (isset($_POST["pass"])) {$pass=$_POST["pass"];}
if (isset($_GET["message"])) {$message=$_GET["message"];}
elseif (isset($_POST["message"])) {$message=$_POST["message"];}
if (isset($_GET["counter"])) {$counter=$_GET["counter"];}
elseif (isset($_POST["counter"])) {$counter=$_POST["counter"];}
if (isset($_GET["force"])) {$force=$_GET["force"];}
elseif (isset($_POST["force"])) {$force=$_POST["force"];}
if (isset($_GET["voice"])) {$voice=$_GET["voice"];}
elseif (isset($_POST["voice"])) {$voice=$_POST["voice"];}
if (isset($_GET["DB"])) {$DB=$_GET["DB"];}
elseif (isset($_POST["DB"])) {$DB=$_POST["DB"];}
$DB=preg_replace("/[^0-9a-zA-Z]/","",$DB);
$user=preg_replace("/\'|\"|\\\\|;| /","",$user);
$pass=preg_replace("/\'|\"|\\\\|;| /","",$pass);
#############################################
##### START SYSTEM_SETTINGS LOOKUP #####
$stmt = "SELECT use_non_latin,allow_sipsak_messages,enable_languages,language_method,meetme_enter_login_filename,meetme_enter_leave3way_filename,agent_debug_logging,allow_web_debug FROM system_settings;";
$rslt=mysql_to_mysqli($stmt, $link);
#if ($DB) {echo "$stmt\n";}
$qm_conf_ct = mysqli_num_rows($rslt);
if ($qm_conf_ct > 0)
{
$row=mysqli_fetch_row($rslt);
$non_latin = $row[0];
$allow_sipsak_messages = $row[1];
$SSenable_languages = $row[2];
$SSlanguage_method = $row[3];
$meetme_enter_login_filename = $row[4];
$meetme_enter_leave3way_filename = $row[5];
$SSagent_debug_logging = $row[6];
$SSallow_web_debug = $row[7];
}
if ($SSallow_web_debug < 1) {$DB=0;}
##### END SETTINGS LOOKUP #####
###########################################
header ("Content-type: text/html; charset=utf-8");
header ("Cache-Control: no-cache, must-revalidate"); // HTTP/1.1
header ("Pragma: no-cache"); // HTTP/1.0
$txt = '.txt';
$StarTtime = date("U");
$NOW_DATE = date("Y-m-d");
$NOW_TIME = date("Y-m-d H:i:s");
$CIDdate = date("mdHis");
$ENTRYdate = date("YmdHis");
$MT[0]='';
$message = preg_replace("/\'|\\\\|;/","",$message);
$counter = preg_replace("/[^0-9]/","",$counter);
$force = preg_replace("/[^0-9]/","",$force);
$voice = preg_replace("/[^-_0-9a-zA-Z]/","",$voice);
if ($non_latin < 1)
{
$user=preg_replace("/[^-_0-9a-zA-Z]/","",$user);
$pass=preg_replace("/[^-_0-9a-zA-Z]/","",$pass);
}
else
{
$user = preg_replace('/[^-_0-9\p{L}]/u','',$user);
$pass = preg_replace('/[^-\.\+\/\=_0-9\p{L}]/u','',$pass);
}
# check user auth
$auth=0;
$auth_message = user_authorization($user,$pass,'',0,0,0,0,'AWS_polly');
if ($auth_message == 'GOOD')
{$auth=1;}
if ( (strlen($user)<2) or (strlen($pass)<2) or ($auth==0) )
{
echo _QXZ("Invalid Username/Password:")." |$user|$pass|$auth|$authlive|$auth_message|\n";
exit;
}
if (strlen($message) < 1)
{
echo "ERROR: invalid message: |$message|\n";
}
else
{
if (strlen($message) < 10)
{$message = '<speak>this is a test of the AWS Polly text to speech service. Number test, <say-as interpret-as="characters">1234567890</say-as>. Currency test, 987654321 dollars and 98 cents. Done.</speak>';}
if (strlen($voice) < 1) {$voice = 'Matthew';}
require_once './polly/aws-autoloader.php';
$awsAccessKeyId = 'XXXXXXXXXXXXXXXXXXXX';
$awsSecretKey = 'YYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYY';
$credentials = new \Aws\Credentials\Credentials($awsAccessKeyId, $awsSecretKey);
$client = new \Aws\Polly\PollyClient([
'version' => '2016-06-10',
'credentials' => $credentials,
'region' => 'us-east-1',
]);
$result = $client->synthesizeSpeech([
'Engine' => 'neural',
'OutputFormat' => 'pcm',
'SampleRate' => '8000',
'Text' => $message,
'TextType' => 'ssml',
'VoiceId' => $voice,
]);
$resultData = $result->get('AudioStream')->getContents();
# $resultData = file_get_contents('polly.raw');
//Output file
$temp_filename = "./polly/generated/".$counter."_TTS.wav";
$fp = fopen($temp_filename, 'wb');
$pcm_size = strlen($resultData);
$size = 36 + $pcm_size;
$chunk_size = 16;
$audio_format = 1;
$channels = 1; //mono
$sample_rate = 8000; //Hz #From the AWS Polly documentation: Valid values for pcm are "8000" and "16000" The default value is "16000".
$bits_per_sample = 16;
$block_align = $channels * $bits_per_sample / 8;
$byte_rate = $sample_rate * $channels * $bits_per_sample / 8;
//RIFF chunk descriptor
fwrite($fp, 'RIFF');
fwrite($fp,pack('I', $size));
fwrite($fp, 'WAVE');
//fmt sub-chunk
fwrite($fp, 'fmt ');
fwrite($fp,pack('I', $chunk_size));
fwrite($fp,pack('v', $audio_format));
fwrite($fp,pack('v', $channels));
fwrite($fp,pack('I', $sample_rate));
fwrite($fp,pack('I', $byte_rate));
fwrite($fp,pack('v', $block_align));
fwrite($fp,pack('v', $bits_per_sample));
//data sub-chunk
fwrite($fp, 'data');
fwrite($fp,pack('i', $pcm_size));
fwrite($fp, $resultData);
fclose($fp);
$endMS = microtime();
$startMSary = explode(" ",$startMS);
$endMSary = explode(" ",$endMS);
$runS = ($endMSary[0] - $startMSary[0]);
$runM = ($endMSary[1] - $startMSary[1]);
$TOTALrun = ($runS + $runM);
echo "SUCCESS|".$counter."_TTS.wav|\n";
# Log request to vicidial_api_log
$stmt="INSERT INTO vicidial_api_log set user='polly',agent_user='$user',function='aws_polly',value='TTS',result=\"GOOD\",result_reason='$counter ".$counter."_TTS.wav bytes: $size voice: $voice',source='AWS',data='$message',api_date=NOW(),api_script='$api_script',run_time='$TOTALrun',webserver='',api_url='';";
$rslt=mysql_to_mysqli($stmt, $link);
$ALaffected_rows = mysqli_affected_rows($link);
if ($DB > 0) {echo "LOG: $ALaffected_rows|$stmt|\n";}
# example export of mp3 audio data
# header('Content-Transfer-Encoding: binary');
# header('Content-Type: audio/wave, audio/wav, audio/x-wav, audio/x-pn-wav');
# header('Content-Type: audio/mpeg, audio/x-mpeg, audio/x-mpeg-3, audio/mpeg3');
# header('Content-length: ' . strlen($resultData));
# header('Content-Disposition: attachment; filename="pollyTTS.wav"');
# header('X-Pad: avoid browser bug');
# header('Cache-Control: no-cache');
# echo $resultData;
# output as MP3 to listen
# $size = strlen($resultData); // File size
# $length = $size; // Content length
# $start = 0; // Start byte
# $end = $size - 1; // End byte
# header('Content-Transfer-Encoding:chunked');
# header("Content-Type: audio/mpeg");
# header("Accept-Ranges: 0-$length");
# header("Content-Range: bytes $start-$end/$size");
# header("Content-Length: $length");
# echo $resultData;
# output as MP3 to download
# header('Content-length: ' . strlen($resultData));
# header('Content-Disposition: attachment; filename="polly-text-to-speech.mp3"');
# header('X-Pad: avoid browser bug');
# header('Cache-Control: no-cache');
# echo $resultData;
}
exit;
?>