Twilioの音声をMicrosoftのBing Speech APIを使ってテキスト化する方法

マインドテックの冨です。

先日、Twilioのハッカソンに行ってきました。電話を使ったアプリケーションを作ろうとすると、音声をテキスト化したいニーズが出てきます。実際、Twilioにはテキスト化の機能もあるのですが、現状では日本語は対象外なんですよね。(あとテキスト化のお値段がちょっと高いw)

そんなわけでテキスト化するためには(自力で実装するのでなければ)外部のAPIを呼び出す必要があります。Google Speech APIを利用する方法は昔、高橋さんがガッツリ書いておられるので、ここではBing Speech APIを利用する方法をご紹介しましょう。サンプルはpython2.7で動作確認をしていますが、もちろん他の言語でも問題ないと思います。

ドキュメントと関連リンク

Bing Speech APIとは
https://azure.microsoft.com/ja-jp/services/cognitive-services/speech/

ドキュメント
https://www.microsoft.com/cognitive-services/en-us/speech-api/documentation/overview

Speech APIではテキスト化する音声認識と、テキストを音声データに変換する機能がありますが、ここでは前者を使います。
Microsoft Congitive Serviceのアカウントは取得しておいてください。
https://www.microsoft.com/cognitive-services/en-us/

APIキーの取得

Cognitive Service の管理画面で"Bing Speech"のサービスの箇所から"key 1″をShow/Copyしておいてください。API呼び出しの際に必要になります。

認証~APIアクセストークンの取得

APIの呼び出しの際には認証が必要になります。詳細はドキュメントを参照いただくとして(笑)キーを送って認証トークンを取得します。トークンは10分間有効。
リクエストヘッダー"Ocp-Apim-Subscription-Key"にAPIキーを指定します。

Pythonでこんな感じに書きました。requestsを使ってます。

import requests
import urllib

def authorize():

    url = "https://api.cognitive.microsoft.com/sts/v1.0/issueToken"

    headers = {
        "Content-type": "application/x-www-form-urlencoded",
        "Ocp-Apim-Subscription-Key": "取得したAPIキー"
    }

    response = requests.post(url, headers=headers)

    if response.ok:
        _body = response.text
        return _body
    else:
        response.raise_for_status()

音声変換

先に取得したアクセストークンは、API呼び出しの際にヘッダーに付与します。

"Authorization": "Bearer " + token

認証の場合と同様に、指定されたエンドポイントにPOSTでデータを投げます。

import requests
import urllib

def speech_to_text( raw_data, token, lang="ja-JP", samplerate=8000, scenarios="ulm"):
    data = raw_data
    params = {
        "version": "3.0",
        "requestid": "b2c95ede-97eb-4c88-81e4-80f32d6aee54",
        "appid": "D4D52672-91D7-4C74-8AD8-42B1D98141A5",
        "format": "json",
        "locale": lang,
        "device.os": "Windows",
        "scenarios": scenarios,
        "instanceid": "565D69FF-E928-4B7E-87DA-9A750B96D9E3" # from Sample Bot Framework
    }
    
    url = "https://speech.platform.bing.com/recognize?" + urllib.urlencode(params)
    headers = {"Content-type": "audio/wav; samplerate={0}".format(samplerate),
               "Authorization": "Bearer " + token }
    
    response = requests.post(url, data=data, headers=headers)
    
    if response.ok:
        result = response.json()["results"][0]
        return result["lexical"]
    else:
        raise response.raise_for_status()

“version","appid"などは指定された固定値。
“requestid","instanceid"は本当はGUIDを作成しなければいけないようですが、サンプルの文字列で動いたのでそのまま使っています(笑)きちんとしたい人は適当に直してください。
“senario"もulm, websearch などの指定が出来るようですが、違いがよく分かりませんでした。スミマセン。

端末でのテスト

これらを呼び出して実際にテキスト化してみます。適当に声を録音したwavファイルを作成します。(サンプリングレートは8000にしています。)

infile = open("sample.wav", 'r')
raw = infile.read()
txt =  speech_to_text( raw , token, lang="ja-JP", samplerate=8000, scenarios="ulm")
print "text : " + txt

これで

$ python test.py
text : こんにちは

こんな感じで表示されば、呼び出しはうまくいっています。

Twilioの録音音声を上記の例の"sample.wav"に相当するデータとして引き渡しできればOKです。

サーバー側のアプリ

続いて、TwiMLを返し、録音音声を取得して先のSpeech APIを呼び出すWebアプリを作成します。電話口で話した言葉をおうむ返しに読み返してくれます。

ここではpythonのBottleフレームワークを利用して、先に作成した関数も組み込んでみます。

# coding: utf-8
import sys
import os
import bottle
import requests
import urllib
import json
import commands
from bottle import route, run, post, Response, request, static_file
from twilio import twiml
from twilio.rest import TwilioRestClient

reload(sys)
sys.setdefaultencoding('utf-8')

app = bottle.default_app()
twilio_client = TwilioRestClient('TwilioのACCOUNT SID' , 'TwilioのAUTH TOKEN')

TWILIO_NUMBER = os.environ.get('(TWILIO_NUMBER)', '(Twilioで購入した電話番号)')
NGROK_BASE_URL = os.environ.get('NGROK_BASE_URL', '')

@route('/')
def index():
    """Returns standard text response to show app is working."""
    return Response("Bottle app up and running!")

@post('/twiml')
def twiml_response():
    response = twiml.Response()
    
    response.say("何か話してキーを押してください。",language="ja-jp",voice="woman")
    response.record(action="http://(サーバーのアドレス)/handlerecording",method="GET", maxLength="20", finishOnKey="0123456789*#")
    return Response(str(response))

@route('/handlerecording')
def handlerecording():

    recording_url = request.query.get('RecordingUrl')
    voice = urllib.urlopen(recording_url).read()

    ## Authorize for Bing Speech API
    token = authorize()
    txt =  speech_to_text( voice , token, lang="ja-JP", samplerate=8000, scenarios="ulm")
    
    # respond TwiML
    response = twiml.Response()
    response.say(txt,language="ja-jp",voice="woman")

    return Response(str(response))

def authorize():

    url = "https://api.cognitive.microsoft.com/sts/v1.0/issueToken"
    headers = {
        "Content-type": "application/x-www-form-urlencoded",
        "Ocp-Apim-Subscription-Key": "(API key)"
    }
    response = requests.post(url, headers=headers)
    
    if response.ok:
        _body = response.text
        return _body
    else:
        response.raise_for_status()

def speech_to_text( raw_data, token, lang="ja-JP", samplerate=8000, scenarios="ulm"):
    data = raw_data
    params = {
        "version": "3.0",
        "requestid": "b2c95ede-97eb-4c88-81e4-80f32d6aee54",
        "appid": "D4D52672-91D7-4C74-8AD8-42B1D98141A5",
        "format": "json",
        "locale": lang,
        "device.os": "Windows",
        "scenarios": scenarios,
        "instanceid": "565D69FF-E928-4B7E-87DA-9A750B96D9E3" # from Sample Bot Framework
        }

    url = "https://speech.platform.bing.com/recognize?" + urllib.urlencode(params)
    headers = {"Content-type": "audio/wav; samplerate={0}".format(samplerate),
            "Authorization": "Bearer " + token }
        
    response = requests.post(url, data=data, headers=headers)

    if response.ok:
        result = response.json()["results"][0]
        return result["lexical"]
    else:
        raise response.raise_for_status()
        
if __name__ == '__main__':
    run(host='(サーバーのアドレス)', port=80, debug=False, reloader=True)

(Twilioサーバー側の録音音声を削除する機能を入れてませんので、必要に応じて追加してみてください。)

TwiML取得URLの設定

Twilioコンソールで購入した電話番号の、TwiML取得URLを設定します。
電話番号>アクティブな電話番号>音声通話の"A CALL COMES IN"の欄を、上記のBottleアプリが動いているサーバーを指定します。

 

ここまでで作業は終了です。購入した電話番号に電話をかけて、ガイダンスに従って何かを話、任意のボタンを押すと、裏では”Bing Speech API"を呼び出してテキスト化し、それをTwiMLのSay動詞で読み上げを行います。上記のサンプルでお分かりの通り、Twilioの録音音声をそのまま読み込んで、Speech APIに渡せばテキスト化されてきます。特に変換は必要ありませんでした。

取得したテキストは何らかの処理に使えると思いますので、工夫してアプリを作ってみてください。(自分は同じMicrosoftのLUIS(language Understanding Intelligent Service)に送って意味解析をさせる事をやってみました。これについては改めて書こうと思います。)

ではでは。

技術・開発

Posted by tomi