[PYTHON] Authentification vocale et transcription avec Raspberry Pi 3 x Julius x Watson (Speech to Text)

Histoire

Récemment, je suis entré dans Ameft (NFL). Cependant, je ne comprends pas l'anglais. .. .. Même si vous ne comprenez pas la voix, pouvez-vous la déchiffrer d'une manière ou d'une autre en l'écrivant? En réfléchissant, j'ai lancé le défi de créer un texte vocal d'interviews de joueurs avec Raspberry Pi 3 × Julius × Watson (Speech to Text)

Chose que tu veux faire

img20170324_14192489.jpg

L'image ressemble à ceci Getting robots to listen: Using Watson’s Speech to Text service

environnement

supposition

Ce qui suit est supposé être prêt. Pour référence, indiquez le lien du site auquel j'ai fait référence

procédure

  1. Parlez à Raspberry Pi 3 en utilisant Julius (images ①②)
  2. Enregistrement vocal (image ③)
  3. Connectez-vous de Raspberry Pi3 à watson (Speech to Text) (Image ④)
  4. Texte de l'interview de you tube player avec Raspberry Pi 3 x watson (image ⑤)

■ Parlez à Raspberry Pi 3 en utilisant Julius

Julius semble avoir un fichier de lecture et un fichier de grammaire pour accélérer l'authentification. Après avoir essayé les deux, j'ai décidé d'utiliser le fichier de grammaire cette fois.

Veuillez consulter Raspberry Pi 3 x Julius (fichier de lecture et fichier de grammaire) pour les résultats de la vérification.

1.1 Vue d'ensemble du traitement de l'analyse vocale

Lorsque Julius est démarré en mode module (*), l'audio est renvoyé en XML. Si vous dites «Démarrer Watson», vous obtiendrez le code XML suivant.

<RECOGOUT>
  <SHYPO RANK="1" SCORE="-2903.453613" GRAM="0">
    <WHYPO WORD="Watson" CLASSID="Watson" PHONE="silB w a t o s o N silE" CM="0.791"/>
  </SHYPO>
</RECOGOUT>
<RECOGOUT>
  <SHYPO RANK="1" SCORE="-8478.763672" GRAM="0">
    <WHYPO WORD="Watson a commencé" CLASSID="Watson a commencé" PHONE="silB w a t o s o N k a i sh i silE" CM="1.000"/>
  </SHYPO>
</RECOGOUT>

Par conséquent, pour le mot parlé, analysez le XML et décrivez le processus à exécuter. (Ce n'est pas bon, mais c'est solide ...)

#Juger et traiter la voix
def decision_word(xml_list):
    watson = False
    for key, value in xml_list.items():
        if u"Tarte Razz" == key:
            print u"Oui. Qu'Est-ce que c'est?"
        if u"Watson" == key:
            print u"Bien reçu. préparer."
            watson = True
    return watson

1.2 Démarrez le serveur Julius et connectez-vous au serveur Julius du côté client

Modifié pour démarrer le serveur Julius dans le sous-processus

#Démarrer le serveur Julius
def invoke_julius():
    logging.debug("invoke_julius")
    # -Interdire la sortie du journal avec l'option nolog
    reccmd = ["/usr/local/bin/julius", "-C", "./julius-kits/grammar-kit-v4.1/hmm_mono.jconf", "-input", "mic", "-gram", "julius_watson","-nolog"]
    p = subprocess.Popen(reccmd, stdin=None, stdout=None, stderr=None)
    time.sleep(3.0)
    return p

#Serveur Julius
JULIUS_HOST = "localhost"
JULIUS_PORT = 10500

#Connectez-vous avec Julius
def create_socket():
    logging.debug("create_socket")
    # TCP/Connectez-vous à Julius avec IP
    sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
    sock.connect((JULIUS_HOST, JULIUS_PORT))
    sock_file = sock.makefile()

    return sock

1.3 Analyse vocale (analyse XML)

Comme mentionné ci-dessus, XML est renvoyé par Julius, alors récupérez les balises à </ RECOGOUT> et analysez-le. *. S'il y a une balise , une erreur se produira lors de l'analyse XML, donc un traitement autre que </ s> est inclus.

#Extraire la balise spécifiée des données obtenues de julius
def extract_xml(tag_name, xml_in, xml_buff, line):
    xml = False
    final = False
    if line.startswith("<RECOGOUT>"):
        xml = True
        xml_buff = line
    elif line.startswith("</RECOGOUT>"):
        xml_buff += line 
        final = True
    else:
        if xml_in:
            xml_buff += escape(line) 
            xml = True
                
    return xml,xml_buff,final

# <s>Balises supprimées (correspondant car une erreur s'est produite lors de l'analyse XML)
def escape(line):
    str = line.replace("<s>",'')
    str = str.replace('</s>','')
    return str
    
#Analyser le XML des résultats de l'analyse Julius
def parse_recogout(xml_data):

    #Obtenez le mot du résultat de la reconnaissance
    #Enregistrer les résultats dans le dictionnaire
    word_list = []
    score_list = []
    xml_list = {} 
    for i in xml_data.findall(".//WHYPO"):
        word = i.get("WORD") 
        score = i.get("CM")
        if ("[s]" in word) == False:
            word_list.append(word)
            score_list.append(score)
    xml_list = dict(izip(word_list, score_list))
    return xml_list

1.4 Dans l'ensemble

C'est un peu long, mais le tout de 1.1 à 1.3 ressemble à ceci.

#Extraire la balise spécifiée des données obtenues de julius
def extract_xml(tag_name, xml_in, xml_buff, line):

    xml = False
    final = False
    if line.startswith("<RECOGOUT>"):
        xml = True
        xml_buff = line
    elif line.startswith("</RECOGOUT>"):
        xml_buff += line 
        final = True
    else:
        if xml_in:
            xml_buff += escape(line) 
            xml = True
                
    return xml,xml_buff,final

# <s>Balises supprimées (correspondant car une erreur s'est produite lors de l'analyse XML)
def escape(line):
    str = line.replace("<s>",'')
    str = str.replace('</s>','')

    return str
    
#Analyser le XML des résultats de l'analyse Julius
def parse_recogout(xml_data):

    #Obtenez le mot du résultat de la reconnaissance
    #Enregistrer les résultats dans le dictionnaire
    word_list = []
    score_list = []
    xml_list = {} 
    for i in xml_data.findall(".//WHYPO"):
        word = i.get("WORD") 
        score = i.get("CM")
        if ("[s]" in word) == False:
            word_list.append(word)
            score_list.append(score)
    xml_list = dict(izip(word_list, score_list))
    return xml_list

#Juger et traiter la voix
def decision_word(xml_list):
    watson = False
    for key, value in xml_list.items():
        if u"Tarte Razz" == key:
            print u"Oui. Qu'Est-ce que c'est?"
        if u"Watson" == key:
            print u"Bien reçu. préparer."
            watson = True
    return watson

#Serveur Julius
JULIUS_HOST = "localhost"
JULIUS_PORT = 10500

#Démarrer le serveur Julius
def invoke_julius():
    logging.debug("invoke_julius")
    # -Interdire la journalisation avec l'option nolog
    #Bientôt,-Exportez le journal dans un fichier avec l'option logfile, etc.
    reccmd = ["/usr/local/bin/julius", "-C", "./julius-kits/grammar-kit-v4.1/hmm_mono.jconf", "-input", "mic", "-gram", "julius_watson","-nolog"]
    p = subprocess.Popen(reccmd, stdin=None, stdout=None, stderr=None)
    time.sleep(3.0)
    return p

#déconnecter le serveur julius
def kill_process(julius):
    logging.debug("kill_process")
    julius.kill()
    time.sleep(3.0)

#Connectez-vous avec Julius
def create_socket():
    logging.debug("create_socket")
    # TCP/Connectez-vous à Julius avec IP
    sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
    sock.connect((JULIUS_HOST, JULIUS_PORT))
    sock_file = sock.makefile()

    return sock

#Connexion étroite avec Julius
def close_socket(sock):
    logging.debug("close_socket")
    sock.close()

#Traitement principal
def main():
    #Démarrer le serveur Julius
    julius = invoke_julius()
    #Connectez-vous à Julius
    sock = create_socket()

    julius_listening = True
    bufsize = 4096

    xml_buff = ""
    xml_in = False
    xml_final = False
    watson = False

    while julius_listening:            
        #Obtenez les résultats d'analyse de Julius
        data = cStringIO.StringIO(sock.recv(bufsize))
        #Obtenez une ligne du résultat de l'analyse
        line = data.readline()
        while line:
            #Seule la ligne affichant le résultat de l'analyse de la voix est extraite et traitée.
            #Extraire et traiter uniquement la balise RECOGOUT.
            xml_in, xml_buff, xml_final = extract_xml('RECOGOUT', xml_in, xml_buff, line)
            if xml_final:
                #Analyser mxl
                logging.debug(xml_buff)
                xml_data = fromstring(xml_buff)
                watson = decision_word( parse_recogout(xml_data))
                xml_final = False
                #Si le résultat est "Watson", accédez à l'authentification vocale
                if watson:
                    julius_listening = False #Julius a terminé
                    break
            #Obtenez une ligne du résultat de l'analyse
            line = data.readline()

    #Fermer la prise
    close_socket(sock)
    #Déconnecter julius
    kill_process(julius)← L'authentification vocale de watson "Speech to text" enregistre en utilisant un enregistrement, donc Julius se déconnecte (parce que le microphone entre en collision, ...)
    if watson:
        speechToText()← Si on vous dit "Watson", exécutez les processus ③ et ④

def initial_setting():
    #Paramètres du journal
    logging.basicConfig(filename='websocket_julius2.log', filemode='w', level=logging.DEBUG)
    logging.debug("initial_setting")
if __name__ == "__main__":
    try:
        #Processus d'initialisation
        initial_setting()
        #Traitement principal
        main()

    except Exception as e:
        print "error occurred", e, traceback.format_exc()
    finally:
        print "websocket_julius2...end"

■ Enregistrement vocal

Démarrez le processus d'enregistrement vocal (exécutez la commande arecord) en multi-thread. Envoyez des données binaires à watson chaque fois que vous enregistrez afin de pouvoir convertir l'audio en texte en temps réel. (*. L'échange de données vers watson sera décrit plus tard)

def opened(self):
    self.stream_audio_thread = threading.Thread(target=self.stream_audio)
    self.stream_audio_thread.start() 

#Démarrer le processus d'enregistrement
def stream_audio(self):
    # -Masquer le message avec l'option q
    reccmd = ["arecord", "-f", "S16_LE", "-r", "16000", "-t", "raw", "-q"]
    p = subprocess.Popen(reccmd,stdout=subprocess.PIPE)
    print 'Prêt. Veuillez exprimer'
    while self.listening:
        data = p.stdout.read(1024)
        try: 
            self.send(bytearray(data), binary=True)← Passer des données binaires à watson
        except ssl.SSLError: pass

■ Connectez-vous de Raspberry Pi3 à watson (Speech to Text)

Utilisez la version webSocket de Speech to Text pour convertir l'audio en texte en temps réel. Pour la parole en texte, veuillez également vous référer à J'ai essayé l'authentification vocale Watson (parole à texte).

Implémenté en référence à cette source d'exemple Getting robots to listen: Using Watson’s Speech to Text service

3.1 Se connecter à Watson (Speech to Text)

Connectez-vous à watson à l'aide de la bibliothèque pour watson (watson-developer-cloud-0.23.0)

class SpeechToTextClient(WebSocketClient):
    def __init__(self):
        ws_url = "wss://stream.watsonplatform.net/speech-to-text/api/v1/recognize"
        username = "XXXXXXX"
        password = "XXXXXXX"
        auth_string = "%s:%s" % (username, password)
        base64string = base64.encodestring(auth_string).replace("\n", "")

        self.listening = False
        try:
            WebSocketClient.__init__(self, ws_url,headers=[("Authorization", "Basic %s" % base64string)])
            self.connect()
        except: print "Failed to open WebSocket."

3.2 Connectez-vous à watson avec webSocket.

    # websocket(Lien)
    def opened(self):
        self.send('{"action":"start","content-type": "audio/l16;rate=16000","continuous":true,"inactivity_timeout":10,"interim_results":true}')

3.3 Authentification vocale Watson

Le résultat de l'exécution (données vocales) de la commande arecord exécutée dans le multi-thread décrit ci-dessus est envoyé à watson. C'est un peu long, mais ... 2. Enregistrement vocal-3. Quand j'ai mis en place la connexion de Raspberry Pi 3 à watson (Speech to Text), cela ressemble à ceci.

class SpeechToTextClient(WebSocketClient):
    def __init__(self):
        ws_url = "wss://stream.watsonplatform.net/speech-to-text/api/v1/recognize"
        username = "XXXXXXX"
        password = "XXXXXXX"
        auth_string = "%s:%s" % (username, password)
        base64string = base64.encodestring(auth_string).replace("\n", "")

        self.listening = False
        try:
            WebSocketClient.__init__(self, ws_url,headers=[("Authorization", "Basic %s" % base64string)])
            self.connect()
        except: print "Failed to open WebSocket."

    # websocket(Lien)
    def opened(self):
        self.send('{"action":"start","content-type": "audio/l16;rate=16000","continuous":true,"inactivity_timeout":10,"interim_results":true}')
        self.stream_audio_thread = threading.Thread(target=self.stream_audio)
        self.stream_audio_thread.start() 
        
    #Démarrer le processus d'enregistrement
    def stream_audio(self):
        while not self.listening:
            time.sleep(0.1)

        # -Masquer le message avec l'option q
        reccmd = ["arecord", "-f", "S16_LE", "-r", "16000", "-t", "raw", "-q"]
        p = subprocess.Popen(reccmd,stdout=subprocess.PIPE)
        print 'Prêt. Veuillez exprimer'
        while self.listening:
            data = p.stdout.read(1024)
            try: 
                self.send(bytearray(data), binary=True)
            except ssl.SSLError: pass

■ Texte de l'interview de You Tube Player avec Raspberry Pi 3 × watson

4.1 Implémentation de receive_message

Lors de la connexion avec webSocket, il semble que le résultat de l'analyse de watson puisse être reçu dans l'événement receive_message.

    # websockt(Recevoir un message)
    def received_message(self, message):
        print message 

4.2 Résultats de l'analyse Watson

Le résultat de l'analyse semble être renvoyé sous la forme d'un objet json.

Comme ça, j'ai pu convertir la voix en texte en temps réel.

キャプチャ.PNG

PostScript 2017/4/16 J'ai fait une vidéo comme celle-ci. https://youtu.be/IvWaHISF6nY

finalement

Impression que la voix ne peut pas être bien authentifiée lorsque vous parlez à plusieurs personnes ou lorsqu'il y a de la musique. Pourtant, je pensais que c'était tout simplement incroyable que la voix devienne un texte en temps réel. Je veux jouer de plus en plus avec l'authentification vocale.

Recommended Posts

Authentification vocale et transcription avec Raspberry Pi 3 x Julius x Watson (Speech to Text)
J'ai essayé l'authentification vocale Watson (Speech to Text)
Connectez-vous à Raspberry PI avec ssh sans mot de passe (authentification par clé)
Reconnaissance vocale en anglais avec python [speech to text]
Raspberry Pi 3 x Julius (fichier de lecture et fichier de grammaire)
Transcription vocale automatique avec l'API Google Cloud Speech
Convertir la voix en texte à l'aide du SDK Azure Speech
Connectez-vous à MySQL avec Python sur Raspberry Pi
IoT facile pour démarrer avec Raspeye et MESH
Visualisons la pièce avec tarte aux râpes, partie 1
Utilisez raspberryPi et Julius (reconnaissance vocale). ③ Création de dictionnaire
GPGPU avec Raspberry Pi
DigitalSignage avec Raspberry Pi
Introduction facile au piratage domestique avec Raspberry Pi et discord.py
Mettre à jour Raspberry Pi Python vers 3.7 ou version ultérieure avec pyenv
J'ai essayé les champignons Pepper x IBM Bluemix Text to Speech
Créez des jeux LCD (16x2) avec Raspberry Pi et Python
Connectez Raspberry Pi à Alibaba Cloud IoT Platform avec «Python»
Plantes Mutter avec Raspberry Pi
J'ai parlé à Raspberry Pi
Présentation de PyMySQL à Raspberry pi3
Parler avec Python [synthèse vocale]
J'ai essayé d'automatiser l'arrosage du pot avec Raspberry Pi
J'ai créé un serveur Web avec Razpai pour regarder des anime