Browse Source

Merge pull request #266 from kalliope-project/fix_acapela

fix acapela TTS
Monf 7 years ago
parent
commit
51f5003e7b

+ 1 - 1
kalliope/core/TTS/TTSModule.py

@@ -47,7 +47,7 @@ class TTSModule(object):
 
         # set parameter from what we receive from the settings
         self.cache = kwargs.get('cache', False)
-        self.language = kwargs.get('language', None)
+        self.language = kwargs.get('language', "default")
         self.voice = kwargs.get('voice', "default")
         # the name of the TSS is the name of the Tss module that have instantiated TTSModule
         self.tts_caller_name = self.__class__.__name__

+ 5 - 1
kalliope/core/Utils/FileManager.py

@@ -1,6 +1,7 @@
 import logging
 import os
 
+import sys
 
 logging.basicConfig()
 logger = logging.getLogger("kalliope")
@@ -36,7 +37,10 @@ class FileManager:
         """
         try:
             with open(file_path, "wb") as file_open:
-                file_open.write(content.encode())
+                if sys.version_info[0] == 2:
+                    file_open.write(content)
+                else:
+                    file_open.write(content.encode())
                 file_open.close()
             return not FileManager.file_is_empty(file_path)
         except IOError as e:

+ 8 - 44
kalliope/tts/acapela/README.md

@@ -2,50 +2,14 @@
 
 This TTS is based on the [Acapela engine](http://www.acapela-group.com/)
 
-| Parameters | Required | Default | Choices                                                                            | Comment                                                                     |
-|------------|----------|---------|------------------------------------------------------------------------------------|-----------------------------------------------------------------------------|
-| language   | YES      |         | 34 languages (http://www.acapela-group.com/voices/repertoire/), example: "sonid15" | Language are corresponding to an id plz check the note beside to find yours |
-| voice      | YES      |         | multiple and depending of the language                                             | Check available names on the web site                                       |
-| cache      | No       | TRUE    | True / False                                                                       | True if you want to use the cache with this TTS                             |
-
+| Parameters | Required | Default | Choices                                                                   | Comment                                                                     |
+|------------|----------|---------|---------------------------------------------------------------------------|-----------------------------------------------------------------------------|
+| voice      | YES      |         | 34 languages (https://acapela-box.com/AcaBox/index.php), example: "manon" | Check available voices on the web site                                      |
+| spd        | NO       | 180     | Min: 120, Max: 240                                                        | Speech rate                                                                 |
+| vct        | NO       | 100     | Min: 85, Max: 115                                                         | Voice shaping                                                               |
+| cache      | No       | TRUE    | True / False                                                              | True if you want to use the cache with this TTS                             |
 
 #### Notes
 
-Corresponding languages to id :
-
-Arabic="sonid0"
-Catalan="sonid1"
-Czech="sonid2" 
-Danish="sonid3" 
-Dutch (Belgium)="sonid4" 
-Dutch (Netherlands)="sonid5" 
-English (AU)="sonid6" 
-English (India)="sonid7"
-English (Scottish)="sonid8"
-English (UK)="sonid9" 
-English (USA)="sonid10" 
-Faroese="sonid11"
-Finnish="sonid12"
-French (Belgium)="sonid13" 
-French (Canada) ="sonid14" 
-French (France)="sonid15"
-German="sonid16"
-Greek="sonid17" 
-Italian="sonid18"
-Japanese="sonid19"
-Korean="sonid20"
-Mandarin="sonid21"
-Norwegian="sonid22" 
-Polish="sonid23" 
-Portuguese (Brazil)="sonid24" 
-Portuguese (Portugal)="sonid25" 
-Russian="sonid26" 
-Sami (North)="sonid27"
-Spanish (Spain)="sonid28" 
-Spanish (US)="sonid29" 
-Swedish="sonid30" 
-Swedish (Finland) ="sonid31"
-Swedish (Gothenburg)  ="sonid32"
-Swedish (Scanian) ="sonid33" 
-Turkish ="sonid34"  
-                  
+The voice name is attached to a specific language.
+To test and get the name of a voice, please refer to [this website(https://acapela-box.com/AcaBox/index.php].

+ 66 - 36
kalliope/tts/acapela/acapela.py

@@ -1,13 +1,15 @@
-import requests
+import logging
 import re
+
+import requests
+
 from kalliope.core import FileManager
 from kalliope.core.TTS.TTSModule import TTSModule, FailToLoadSoundFile, MissingTTSParameter
-import logging
 
 logging.basicConfig()
 logger = logging.getLogger("kalliope")
 
-TTS_URL = "http://dmbx.acapela-group.com/DemoHTML5Form_V2_fr.php"
+TTS_URL = "https://acapela-box.com/AcaBox/dovaas.php"
 TTS_CONTENT_TYPE = "audio/mpeg"
 TTS_TIMEOUT_SEC = 30
 
@@ -17,7 +19,6 @@ class TCPTimeOutError(Exception):
     This error is raised when the TCP connection has been lost. Probably due to a low internet
     connection while trying to access the remote API.
     """
-
     pass
 
 
@@ -29,11 +30,18 @@ class Acapela(TTSModule):
         if self.voice is None:
             raise MissingTTSParameter("voice parameter is required by the Acapela TTS")
 
+        # speech rate
+        self.spd = kwargs.get('spd', 180)
+        # VOICE SHAPING
+        self.vct = kwargs.get('vct', 100)
+
+        self.words = None
+
     def say(self, words):
         """
         :param words: The sentence to say
         """
-
+        self.words = words
         self.generate_and_play(words, self._generate_audio_file)
 
     def _generate_audio_file(self):
@@ -46,56 +54,78 @@ class Acapela(TTSModule):
         # Prepare payload
         payload = self.get_payload()
 
-        try:
-            # Get the mp3 URL from the page
-            url = Acapela.get_audio_link(TTS_URL, payload)
+        cookie = Acapela._get_cookie()
 
-            # getting the mp3
-            r = requests.get(url, params=payload, stream=True, timeout=TTS_TIMEOUT_SEC)
-            content_type = r.headers['Content-Type']
+        # Get the mp3 URL from the page
+        mp3_url = Acapela.get_audio_link(TTS_URL, payload, cookie)
 
-            logger.debug("Acapela : Trying to get url: %s response code: %s and content-type: %s",
-                         r.url,
-                         r.status_code,
-                         content_type)
-            # Verify the response status code and the response content type
-            if r.status_code != requests.codes.ok or content_type != TTS_CONTENT_TYPE:
-                raise FailToLoadSoundFile("Acapela : Fail while trying to remotely access the audio file")
+        # getting the mp3
+        headers = {
+            "Cookie": "%s" % cookie
+        }
+        r = requests.get(mp3_url, headers=headers, stream=True, timeout=TTS_TIMEOUT_SEC)
+        content_type = r.headers['Content-Type']
 
-            # OK we get the audio we can write the sound file
-            FileManager.write_in_file(self.file_path, r.content)
+        logger.debug("Acapela : Trying to get url: %s response code: %s and content-type: %s",
+                     r.url,
+                     r.status_code,
+                     content_type)
+        # Verify the response status code and the response content type
+        if r.status_code != requests.codes.ok or content_type != TTS_CONTENT_TYPE:
+            raise FailToLoadSoundFile("Acapela : Fail while trying to remotely access the audio file")
 
-        except:
-            raise TCPTimeOutError("TCP timeout, the connection to the remote API has been lost")
+        # OK we get the audio we can write the sound file
+        FileManager.write_in_file(self.file_path, r.content)
 
     def get_payload(self):
         """
-        Generic method used load the payload used to acces the remote api
-
+        Generic method used load the payload used to access the remote api
         :return: Payload to use to access the remote api
         """
-
         return {
-            "MyLanguages": self.language,
-            "MySelectedVoice": self.voice,
-            "MyTextForTTS": self.words,
-            "t": "1",
-            "agreeterms": "on",
-            "SendToVaaS": ""
+            "text": "%s" % self.words,
+            "voice": "%s22k" % self.voice,
+            "spd": "%s" % self.spd,
+            "vct": "%s" % self.vct,
+            "codecMP3": "1",
+            "format": "WAV 22kHz",
+            "listen": 1
         }
 
     @staticmethod
-    def get_audio_link(url, payload, timeout_expected=TTS_TIMEOUT_SEC):
+    def get_audio_link(url, payload, cookie, timeout_expected=TTS_TIMEOUT_SEC):
         """
         Return the audio link
 
         :param url: the url to access
-        :param payload: the payload to use to acces the remote api
+        :param payload: the payload to use to access the remote api
         :param timeout_expected: timeout before the post request is cancel
+        :param cookie: cookie used for authentication
         :return: the audio link
         :rtype: String
         """
+        headers = {
+            "Cookie": "%s" % cookie
+        }
+
+        r = requests.post(url, data=payload, headers=headers, timeout=timeout_expected)
+        data = r.json()
+        return data["snd_url"]
+
+    @staticmethod
+    def _get_cookie():
+        """
+        Get a cookie that is used to authenticate post request
+        :return: the str cookie
+        """
+        returned_cookie = ""
+        index_url = "https://acapela-box.com/AcaBox/index.php"
+        r = requests.get(index_url)
+
+        regex = "(acabox=\w+)"
+        cookie_match = re.match(regex, r.headers["Set-Cookie"])
+
+        if cookie_match:
+            returned_cookie = cookie_match.group(1)
 
-        r = requests.post(url, payload, timeout=timeout_expected)
-        data = r.content
-        return re.search("(?P<url>https?://[^\s]+).mp3", data).group(0)
+        return returned_cookie

+ 6 - 6
kalliope/tts/pico2wave/README.md

@@ -12,9 +12,9 @@ This TTS is based on the SVOX picoTTS engine
 
 Supported languages : 
 
-Anglais en-US
-Anglais en-GB
-Français fr-FR
-Espagnol es-ES
-Allemand de-DE
-Italien it-IT
+- English en-US
+- English en-GB
+- French fr-FR
+- Spanish es-ES
+- German de-DE
+- Italian it-IT