日常のひとりごとをマイクで拾って自動ツイートしてみた

とある記事にこう書かれていました。

> [『Twitterで本当に「つぶやける」仕組みをつくってみたら、世界が少しだけ変わった』](https://liginc.co.jp/257428)

> いまTwitterを見ているんですけど、このつぶやきって実際は「本当のつぶやき」じゃないですよね？
なのに、つぶやき、つぶやきって……

> 俺の知っている人たち、みんな文章をつくって投稿してるんですよね。
やっぱり本当のつぶやきじゃないですよね？

「確かにそうだ！」と非常に感心しました。
なのでこの記事を参考に、**ひとりごとをマイクで拾って自動ツイート**するシステムを開発してみました。

---

## できたもの
こんな感じにひとりごとが自動ツイートされます
<blockquote class="twitter-tweet"><p lang="ja" dir="ltr">とりあえずこれで完成 かなー</p>&mdash; ジョーのリアルなつぶやき (@RealTweet_Joe) <a href="https://twitter.com/RealTweet_Joe/status/1165290740798222336?ref_src=twsrc%5Etfw">August 24, 2019</a></blockquote>

<blockquote class="twitter-tweet"><p lang="ja" dir="ltr">あーこれすごいいいな</p>&mdash; ジョーのリアルなつぶやき (@RealTweet_Joe) <a href="https://twitter.com/RealTweet_Joe/status/1165310631982985216?ref_src=twsrc%5Etfw">August 24, 2019</a></blockquote>

---

## システム概要
![ECynArTUUAArFTy.jpeg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/253818/f2dac80a-2670-3ab0-ba27-d69a66ff0962.jpeg)

具体的には、
1. Google Chrome + [Web Speech API](https://w3c.github.io/speech-api/speechapi.html)
2. Ruby on Rails
3. Twitter API
をそれぞれ使っています。

---

## Web Speech APIの実装方法
下記記事を参考に実装しましたが、非常に簡単でした！
[Webページでブラウザの音声認識機能を使おう](https://qiita.com/hmmrjn/items/4b77a86030ed0071f548)

最低限の機能を試すには下記でokです。

```html
<script>
  SpeechRecognition = webkitSpeechRecognition || SpeechRecognition;
  const recognition = new SpeechRecognition();

  recognition.onresult = (event) => {
    alert(event.results[0][0].transcript);
  }

  recognition.start();
</script>
```

---

私の場合は「Webサイト表示時にマイクonしたい」「マイクが勝手に切れたら再度onしたい」「start/stopボタンが欲しい」「テキスト化の状況を見たい」という条件があったので下記のようにしました。

```html
<button id="switch-btn">stop</button>
<div id="result-div"></div>

<script>
  const switchBtn = document.querySelector('#switch-btn');
  const resultDiv = document.querySelector('#result-div');

  SpeechRecognition = webkitSpeechRecognition || SpeechRecognition;
  let recognition = new SpeechRecognition();

  recognition.lang = 'ja-JP';
  recognition.interimResults = true;
  recognition.continuous = true;

  let finalTranscript = ''; // 確定した(黒の)認識結果

  recognition.onresult = (event) => {
    resultDiv.innerHTML = '';

    let interimTranscript = ''; // 暫定(灰色)の認識結果
    for (let i = event.resultIndex; i < event.results.length; i++) {
      let transcript = event.results[i][0].transcript;
      if (event.results[i].isFinal) {
        finalTranscript += transcript;
        resultDiv.innerHTML = finalTranscript;
        finalTranscript = '';
      } else {
        interimTranscript = transcript;
        resultDiv.innerHTML = '<i style="color:#ddd;">' + interimTranscript + '</i>';
      }
    }
  }

  let recordActive = true;
  recognition.start();

  switchBtn.onclick = () => {
    if (!recordActive) {
      recognition.start();
      switchBtn.innerHTML = 'stop';
      resultDiv.innerHTML = '';
      recordActive = true;
    } else {
      recognition.stop();
      switchBtn.innerHTML = 'start';
      recordActive = false;
    }
  }

  function checkNotAutoFinished() {
    if (recordActive) {
      recognition.start();
      resultDiv.innerHTML = '';
    }
  }
  setInterval('checkNotAutoFinished()', 60000); // stopボタンが押されていなければ、1分ごとにリスタート
</script>
```

---

## Twitter APIの実装方法
**jQueryによるAjax通信**を用いました。
具体的にはhttps://developer.twitter.com/ でAPI登録後、上記コードの中で

```js
$.ajax({url: '/home/update', type: "GET", data:{text:finalTranscript}});
```

とし、対応するコントローラーでは

---

```rb
class HomeController < ApplicationController
  before_action :set_twitter_client

  def update
    text = params.require(:text)
    begin
      @twitter.update(text)
    rescue => e
      error = e
    end
    render plain: error || "Twitter.update"
  end

  helper_method :update

  private

  def set_twitter_client
    @twitter = Twitter::REST::Client.new do |config|
      config.consumer_key        = "APIから取得"
      config.consumer_secret     = "同上"
      config.access_token        = "同上"
      config.access_token_secret = "同上"
    end
  end
end
```
とする事で実装可能です。

---

## 使い方
あとはWebサイトを開いたままにして作業していれば、自動でツイートが行われます。

<blockquote class="twitter-tweet"><p lang="ja" dir="ltr">なんかできそう</p>&mdash; ジョーのリアルなつぶやき (@RealTweet_Joe) <a href="https://twitter.com/RealTweet_Joe/status/1165297054609858561?ref_src=twsrc%5Etfw">August 24, 2019</a></blockquote>

<blockquote class="twitter-tweet"><p lang="ja" dir="ltr">理科1700年に聞かせんのやりたい</p>&mdash; ジョーのリアルなつぶやき (@RealTweet_Joe) <a href="https://twitter.com/RealTweet_Joe/status/1165290843256680449?ref_src=twsrc%5Etfw">August 24, 2019</a></blockquote>

<blockquote class="twitter-tweet"><p lang="ja" dir="ltr">ほっともっと</p>&mdash; ジョーのリアルなつぶやき (@RealTweet_Joe) <a href="https://twitter.com/RealTweet_Joe/status/1165481249244372993?ref_src=twsrc%5Etfw">August 25, 2019</a></blockquote>

<blockquote class="twitter-tweet"><p lang="ja" dir="ltr">米どころ</p>&mdash; ジョーのリアルなつぶやき (@RealTweet_Joe) <a href="https://twitter.com/RealTweet_Joe/status/1165499679326576640?ref_src=twsrc%5Etfw">August 25, 2019</a></blockquote>
<br>
…**精度はそれなり**でした。