CIの結果を音声合成で喋らせたいということがあったので実現方法を共有します。
音声合成ソフトはいろいろあるけど、今回はWeb APIで使えるVoiceTextを使いました。
そして、昔作ったVoiceText4Jを引っ張り出してきました。
まずはシンプルにこのVoiceText4JをSpring Boot経由で呼ぶだけのsyaberuというアプリを作りました。

ローカルでSyaberuを実行
こちらから最新のjarファイルをダウンロードしてください。
java -jar syaberu-0.0.1*.jar
API Keyをこちらから取得してください。
API_KEY=...
curl http://localhost:8080 -H "X-Api-Key: ${API_KEY}" -d text=こんにちは
speakerパラメータで話者を変えることもできます。
curl http://localhost:8080 -H "X-Api-Key: ${API_KEY}" -d text=こんにちは -d speaker=haruka
curl http://localhost:8080 -H "X-Api-Key: ${API_KEY}" -d text=こんにちは -d speaker=hikari
インターネット経由でローカルのSyaberuを実行
ローカルで音声合成を鳴らすのは簡単にできました。しかし、任意のCIサーバーからビルド結果を鳴らすにはインターネットを経由してSyaberuにリクエストを送る必要があります。
このSyaberuをクラウドにデプロイしても意味がありません。音声が鳴るのはスピーカーがついている端末上で、かつ聞こえないと意味がないです。
なので、ローカルで起動しているSyaberuにインターネット経由でFirewallを超えてアクセスしてもらう必要があります。
まず思いつくのはngrokを使う方法です。Syaberuの隣にngrokサーバーを立てて、ngrokが払い出すport/hostnameを経由してlocalhost:8080にアクセスさせることは可能です。
無料プランだとngrokのport/hostnameがrestartするたびに変わるのでCIに設定するには都合が悪いです。そこで、同じような仕組みを作りました。
ここで役に立つのが双方向プロトコルであるRSocketです。RSocketはSpring Boot 2.2から簡単に利用できるようになっています。興味のある人はこちらの資料を見てください。
RSocketを使って、SyaberuのProxy Serverを作成し、これをクラウド上におき、CIからはクラウド上のProxyサーバーにアクセスしてもらいます。Syaberuは起動時にProxyとRSocketでつなぎに行きます。ProxyはHTTPでリクエストをもらったらボディをそのままRSocketでつながっているSyaberuに送信し、このリクエストをSyaberuはVoiceTextに送ることで音声合成を鳴らすことができます。
図に示すと次のようになります。

ソースはこちら。
Syaberu RSocket Proxyをローカルで実行
こちらから最新のjarファイルをダウンロードしてください。
java -jar syaberu-rsocket-proxy-0.0.1*.jar
Syaberuの起動時にsyaberu.proxy-uriにRSocket ProxyのURLを指定します。syaberu.proxy-subscription-idはチャネル名みたいなものです。
java -jar syaberu-0.0.1*.jar --syaberu.proxy-uri=http://localhost:8082/rsocket --syaberu.proxy-subscription-id=test
これで次のようにProxy経由でSyaberuにリクエストを送れます。
curl http://localhost:8082/proxy/test -H "X-Api-Key: ${API_KEY}" -d text=こんにちは
Syaberu RSocket ProxyをCloud Foundryで実行
Syaberu RSocket ProxyをCloud Foundryにデプロイする場合はcf pushするだけです。
cf push syaberu-rsocket-proxy -p syaberu-rsocket-proxy-0.0.1*.jar
Syaberu RSocket ProxyはトランスポートレイヤにWebSocketを使っているため、Pivotal Web Servicesを使う場合は8443ポートを経由してアクセスする必要があります。
お試し用としてhttps://syaberu-rsocket-proxy.cfapps.io:8443にデプロイしてあるので、以下のように使えます。syaberu.proxy-subscription-idは被らないようにした方が良いです。
java -jar syaberu-0.0.1*.jar --syaberu.proxy-uri=https://syaberu-rsocket-proxy.cfapps.io:8443/rsocket --syaberu.proxy-subscription-id=test
CIからは次のようにアクセスすれば良いです。
curl https://syaberu-rsocket-proxy.cfapps.io:8443/proxy/test -H "X-Api-Key: ${API_KEY}" -d text=こんにちは
Concourseからビルド結果を喋らせる
Concourseから鳴らしたい場合、はtaskでcurlを叩けば十分なのですが、putで鳴らしたい場合は、以前Line Notifyに通知したのと同じような方法で実現できます。
サンプルパイプラインを貼っておきます。
resource_types:
- name: http-api
type: docker-image
source:
repository: aequitas/http-api-resource
resources:
- name: syaberu
type: http-api
source:
uri: https://syaberu-rsocket-proxy.cfapps.io:8443/proxy/((syaberu_subscription_id))
method: POST
headers:
X-Api-Key: ((voicetext_api_token))
form_data:
text: "{text}"
speaker: "{speaker}"
emotion: "{emotion}"
jobs:
- name: hello
plan:
- task: say-hello
config:
platform: linux
image_resource:
type: docker-image
source:
repository: alpine
run:
path: sh
args:
- -c
- |
echo "Hello"
# わざと失敗させたいとき
# exit 1
on_success:
put: syaberu
params:
speaker: hikari
text: タスクが成功しました
emotion: happiness
on_failure:
put: syaberu
params:
speaker: hikari
text: タスクが失敗しました
emotion: sadness