🥕

VOICEVOXにTwitterを読み上げてもらう。「ついよみ」を開発しました。

2023/02/14に公開

ついよみ

ツイッターを読み上げるソフトウェアを開発しました。
音声合成ソフトにタイムラインの読み上げを行わせます。
https://booth.pm/ja/items/4503494

対応する音声合成ソフト

VOICEVOX以外にも、VOICEVOX APIを提供する以下の音声合成ソフトに対応しています

  • VOICEVOX
  • COEIROINK
  • LMROID
  • SHAREVOX
  • ITVOICE

使い方

  1. 音声合成ソフトを起動
  2. 本アプリを起動
  3. ブラウザ上で本アプリによるTwitterの使用を許可する。

本記事について

本記事では、ついよみの設計のポイントと得られた技術的な知見を記載します。

構成

全体の構成は大体こんな感じです。

音声を再生するまでの流れは以下の通り、

  1. TwitterにTweetを要求
  2. TwitterからTweetを取得
  3. VOICEVOXにTweetの文字列を送信
  4. VOICEVOXから音声を取得
  5. 取得した音声を再生

外的要素

Twitter API v2

https://developer.twitter.com/en/docs/twitter-api/tweets/timelines/api-reference/get-users-id-reverse-chronological

最新のツイートを25件取得するコード。プロフィール画像のURLも含めて取得する。

src-tauri/src/twitter_client.rs
    let token = "BEARER TOKEN",
    let user_id = "USER ID"
    let client = reqwest::Client::new();
    let auth_val = format!("Bearer {token}");

    let mut query = [
        ("expansions", "author_id"),
        ("user.fields", "profile_image_url"),
        ("tweet.fields", "created_at"),
        ("max_results", "25"),
    ]
    .to_vec();

    let url = format!("https://api.twitter.com/2/users/{user_id}/timelines/reverse_chronological");

    let timeline = client
        .get(url)
        .header(reqwest::header::AUTHORIZATION, auth_val)
        .query(&query)
        .send()
        .await
        .unwrap();

VOICEVOX API

https://github.com/VOICEVOX/voicevox_engine#api-ドキュメント

VOICEVOXは、内部のエンジン部がHTTPサーバとして動いており、HTTP経由で音声合成を実行することができる。ついよみは、このAPIを利用することで音声合成を行う。

  1. 音声合成を行うためのパラメータを生成
src-tauri/src/voicegen_client.rs
    let client = reqwest::Client::new();

    let url: String = "http://127.0.0.1:50021/audio_query".to_string();
    let audio_query = client
        .post(url)
        .query(&[
            ("text", text.as_str()),
            ("speaker", speaker.to_string().as_str()),
        ])
        .send()
        .await
        .unwrap()
        .text()
        .await
        .unwrap();
  1. 生成したパラメータを用いて音声を合成
src-tauri/src/voicegen_client.rs
    let audio_query = serde_json::to_string(&audio_query).unwrap();

    let url: String = "http://127.0.0.1:50021/synthesis".to_string();
    let data = client
        .post(url)
        .query(&[("speaker", speaker.to_string().as_str())])
        .body(audio_query)
        .send()
        .await
        .unwrap()
        .bytes()
        .await
        .unwrap();

詳細

外的要素がたくさんあり構成が複雑なので内部ロジックをもう少し詳細化。
図はDFDで表現。

主に以下の3つのロジックが平行に動作するように制御する必要がある。

  • ツイートを取得する部分
  • ツイートを音声に変換する部分
  • 音声を再生する部分

実装

  • React × Tauri

https://github.com/iwase22334/twradio

最後に

タイムラインを読み上げるソフトウェアを開発しました。内部的にはTwitter, VOICEVOX, スピーカーを適切に制御するコードになっています。

Discussion