どくぴーの備忘録

真面目なことを書こうとするクソメガネのブログ。いつ投げ捨てられるのかは不明

Raspberry PiとBluetoothスピーカーとRuby + Sinatraで天の声APIを作ってみる

最近,研究室でRaspberry Piを借りてきたのでせっかくだから喋らせてみることにしました

なんかもうあった

nwpct1.hatenablog.com

カレーメシ先輩( id:nwpct1 )がラズパイ内で音声合成して喋らせていたのでコレを参考にしてみようと思ったのですが,docomo developer supportにはいっているHOYAサービスの音声合成APIを使ってRESTで殴って生成済み音声データを持って来て再生する仕組みにしておうちの中でPOSTすると喋らせてみることにします.

dev.smt.docomo.ne.jp

用意するもの

docomo developer supportに登録

dev.smt.docomo.ne.jp

にアクセスしてアカウントを取得します.取得したら,マイページからAPI利用申請・管理にアクセスしてアプリケーションを登録します.基本情報を入力し,『音声合成 【Powerd by HOYAサービス】』を選択してAPIキーを取得しましょう.

APIエンドポイントを作る

まずはGemfileの定義から.

source "https://rubygems.org"

gem 'sinatra'
gem 'sinatra-contrib'

ただ喋らせるだけなのでこれで十分です.DB用意したりして工夫する際は適宜追加しましょう.完了したら bundle install --path /vender/bundle でインストールします.

app.rb にエンドポイントを定義します.今回は適当に /api/v1/speech とします.ついでに /api/v1/speech/test にテスト用のエンドポイントも用意します.

#!/usr/bin/env ruby
# coding:utf-8
require 'sinatra'
require 'sinatra/json'
require 'json'

require './speech.rb'

# API

get '/api/v1/speech/test' do
  speech = Speech.new
  data = {result: speech.do_speech("これはテストです.音量などを確認してください.")}
  if data[:result] == 'success' then
    status 200
  else
    status 400
  end
  json data
end

post '/api/v1/speech', provides: :json do
  params = JSON.parse(request.body.read,  {:symbolize_names => true})
  text = params[:text]
  speech = Speech.new
  data = {result: speech.do_speech(text)}
  if data[:result] == 'success' then
    status 200
  else
    status 400
  end
  json data
end

実際に喋らせるSpeechクラスを実装します.do_speech メソッドだけですが.

require 'net/http'
require 'uri'

API_KEY = '(docomo developer supportで取得したAPIキー)'

class Speech
  def do_speech(text)

    endpoint = URI.parse('https://api.apigw.smt.docomo.ne.jp/voiceText/v1/textToSpeech')
    endpoint.query = 'APIKEY=' + API_KEY

    request_body = {
        'text'=>text,
        'speaker'=>'hikari'
    }

    res = Net::HTTP.post_form(endpoint, request_body)

    case res
      when Net::HTTPSuccess
        file_name = "voice.wav"
        File.binwrite(file_name, res.body)
        `aplay voice.wav` #Macに喋らせたいときはafplayにしましょう
        File.delete(file_name)
        return "success"
      else
        return res.body
    end
  end
end

ちなみに上のコメントにあるようにaplayをafplayにするとmacで喋れるようになります.この時点で,とりあえず bundle exec ruby app.rb -o 0.0.0.0 で起動して localhost:4567/api/v1/speech

{
    "text": "ほげほげ"
}

みたいなJSONをPOSTするとPCが喋ると思います.

Raspberry Pi側の環境構築

とりあえず頑張ってRaspberry Pirubyをインストールします.

qiita.com

Raspberry Piなのでインストールには凄い時間がかかりますが気長に待ちましょう.

完了したら

gem install bundler

でbundlerをインストールします.完了したらさっきのsinatraアプリケーションをgitなりでRaspberry Pi上に移動して bundle install --path /vender/bundle して, bundle exec ruby app.rb -o 0.0.0.0 で起動します.この時点で,Raspberry Piのイヤホンジャックにイヤホン等を繋いで '(Raspberry PiのIP):4567/api/v1/speech' に先程のJSONをPOSTすると喋るのですが,今回はBluetoothスピーカーに喋らせるので

apt-get install bluetooth bluez bluez-tools pulseaudio pulseaudio-module-bluetooth

でbluezとpulseaudioをインストールします.インストールしたら pulseaudio --start でpulseaudioを起動します.終了は pulseaudio -k です.

続いて,Bluetoothスピーカーの電源を入れ,bluetoothctlでペアリングを行います.

$ bluetoothctl -a
[bluetooth]# power on  //パワーオン
[bluetooth]# scan on   //スキャン開始
[NEW] Device A0:E9:xx:xx:xx:xx BT Speaker name  // Bluetoothスピーカーを見つける
[bluetooth]# connect A0:E9:xx:xx:xx:xx    
[bluetooth]# trust A0:E9:xx:xx:xx:xx
[bluetooth]# exit

ペアリングが完了したらデフォルトをそのスピーカーに設定して

$ pacmd set-default-sink bluez_sink.A0_E9_xx_xx_xx_xx

音量を設定します,

$ pactl set-sink-volume bluez_sink.A0_E9_xx_xx_xx_xx 60%
または
$ alsamixer

これで,Raspberry PiAPIを叩くとBluetoothスピーカーからおもむろに声が鳴り響くと思います.天井付近に設置すれば天の声っぽくなる…か?

サンプルコード

github.com