Xor

<<< Назад

Об "обделённых" пользователях Win-систем -- с точки зрения кэширования winTTS сообщений

Из коробки winTTS не кэширует голосовые сообщения, чем, как я думаю, выбивается из мейнстрима Мажордомо. Предлагается решение, устраняющее эту несправедливость.
ps. Устарело, всё внедрено Сергеем в штатный функционал

Небольшая правка нескольких файлов позволяет создавать пользователям winTTS кэш голосовых сообщений, позволяющий так же как и обладателям Яндекса, Гугла и RHVoice, например, слать аудиофайлы на терминалы и т.п.

При установке на Вин-систему для работы с winTTS устанавливаются два файла c:\_majordomo\htdocs\rc\sapi.js и c:\_majordomo\htdocs\rc\sapi_cached.js.
Первый из которых "тупо" проговаривает все фразы, а второй - более сложный -- кэширует новый файл в '/cms/cached/voice/sapi_md5($message).mp3 и повторяющиеся фразы проговаривает уже из кэша.

Обидно, что в windows_tts.class.php, отвечающем за winTTS-говорилку, жёстко прописана ссылка только на файл sapi.js:

 safe_exec('cscript ' . DOC_ROOT . '/rc/sapi.js ' . $message, 1, $level);

Я сначала просто переименовывал sapi_cached.js в sapi.js и winTTS начинала кэшировать файлы.
Спустя какое-то время стали приходить всякие дурацкие мысли насчет того, как улучшить то, что и так работает:
скрипт на js сам считал md5($message), мучительно и на трех страницах эмулируя пхпшную функцию. Заставил считать это в windows_tts.class.php и передавать в скрипт параметром.

Вот измененный файл sapi.js:

if (WScript.Arguments.length == 0) {
    WScript.Quit();
 }
var fnMD5 = '';
if (WScript.Arguments.Named.Exists("md5"))
  fnMD5 = WScript.Arguments.Named("md5"); 
  var text = new Array();
for (var i=0; i<WScript.Arguments.Unnamed.Count; i++)
    text.push(WScript.Arguments.Unnamed(i));
 var fso = new ActiveXObject("Scripting.FileSystemObject"); 
 var scriptPath = fso.GetFile(WScript.ScriptFullName).ParentFolder;
 strWavFileName = scriptPath+'/../cms/cached/voice/sapi_'+fnMD5+'.wav';
 strMp3FileName = scriptPath+'/../cms/cached/voice/sapi_'+fnMD5+'.mp3';
 var wShell = WScript.CreateObject("Wscript.Shell");
   if (!fso.FileExists(strMp3FileName)) {//no cached file
    var sv = WScript.CreateObject("SAPI.SpVoice");
    var oFilestream = WScript.CreateObject("SAPI.SpFileStream");
      sv.WaitUntilDone(-1);    // Don't be loud
     //save to wav
    oFilestream.Open(strWavFileName, 3, false);
    sv.AudioOutputStream = oFilestream;
    sv.speak(text.join(' '),0);
    oFilestream.close();
    //convert wav to mp3
    var strCommand = scriptPath+"/lame.exe -V0 "+strWavFileName+" "+strMp3FileName;
    wShell.run(strCommand, 0, true); //WaitUntilDone
    //delete wav
    if(fso.FileExists(strWavFileName)){
     fso.DeleteFile(strWavFileName,true);
    }
   } 
//play mp3 
var strCommand = scriptPath+"/madplay.exe \"" + strMp3FileName+"\"";
wShell.run(strCommand, 0, true);

А вот изменения в windows_tts.class.php:

function processSubscription($event, &$details)
{
    $this->getConfig();

    if ($event == 'SAY' && !$this->config['DISABLED'] && (!$details['ignoreVoice']))
    {
         $level = $details['level'];
         $message = $details['message'];
         $mmd5 = md5($message); //добавили сюда расчет md5 сообщения
         if ($level >= (int)getGlobal('minMsgLevel') && IsWindowsOS())
         {
                //safe_exec('cscript ' . DOC_ROOT . '/rc/sapi.js ' . $message, 1, $level); //закомментим то, что было
                safe_exec('cscript ' . DOC_ROOT . '/rc/sapi.js /md5:' .$mmd5.' ' . $message, 1, $level); //добавим вызов нашего скрипта с новым параметром md5
                $details['ignoreVoice'] = 1;
         }
    }
}

У меня это работает уже месяц. Полёт нормальный.
Если народу понравится, буду оформлять пулл реквест.

ps. Устарело, всё внедрено Сергеем в штатный функционал

Обсуждение (6) (6)

Смотрите так же:
16.09.2018 Перезагрузка Мажордомо в Win-системах

Москва, Россия

На форуме: xor