（個人開発）React+FastAPI+OSCを使って、VRChatでテキストチャット&翻訳機を作成してみた

![1.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/157463/7abafce3-24c3-a542-46f2-ca90661d8588.png)


# この記事の目的

この記事の目的は私が個人開発したKuretan　Avatar  Textというソフトウェアについての技術的説明および開発を通じで学んだことのまとめです。

Kuretan Avatar TextはVRChatというVRプラットフォームで利用できるテキストチャット&翻訳システムです。
[Kuretan Avatar Text \- Kuretan's lab \- BOOTH](https://kuretan.booth.pm/items/3962022)で無料ダウンロードできます。またフロントエンドに関しては[Kuretan's lab](https://kuretan-lab.com/)で公開しています。
以下の記事では主に外国語として英語を題材にしていますが、英語以外の言語でもどうようなことができます。

# 背景

## VRChatとは

VRChatはソーシャルVRプラットフォームの一つで、今話題になっているメタバースの一つです。

様々あるメタバースのプラットフォームの中でもVRChatは群を抜いて人気があります。
運営会社がアメリカの企業であり、利用者の多くはアメリカ人ですが日本人の中にも廃人熱心のファンがたくさんいます。

VRChatでは様々なことができます。お気に入りのかっこいい・可愛いアバターになったり、日常ではふれあることのないような人々と交流できます。
水族館や宇宙といった美しい風景も見ることができますし、FPSやホラーゲームといった様々なゲームも体験できます。語学学習もその一つです。

VRChatでは世界中の人々と交流することができます。その人々の中には日本語を勉強している外国人も多く含まれます。
日本語を勉強している外国人と英語を交えながら話すことは、英語の勉強にもなりますし楽しいものです。
そもそも私がVRChatを始めたきっかけは英語学習をするためです。

このようにいいことづくしのVRChatですが、私はVRChatに対して二つ不満を持っていました。
それはVRChatにテキストチャットのような任意の文字を表示する機能がないこと[^1]、および翻訳機能がないことです。
VRChatに類似したゲームでであるClusterにはデフォルトでテキストチャット機能が備わっています。

ネット上を調べてみたところ、英語のみに対応したVRChat用テキストチャットは無料のものから有料のものまで様々存在しています。
しかし、日本語に対応している使い勝手のよさそうなものは存在しませんでした。

## そもそもなぜテキストチャットが必要なのか

VRChatではほとんどの人がボイスチャットで会話をしています。一部には無言勢と呼ばれるボイスチャットを行わない人もいますが、
全体としての割合はそこまで高くありません。そのためテキストチャットの需要はそこまで大きないかもしれません。

しかし、VRChatを語学学習ツールとして見た場合テキストチャットは必須となります。
語学学習には文字が欠かせないからです。

例えば日本語を勉強している外国人に漢字を説明する場合、口頭で説明するのは困難です。
VRChatにはペンがあるため、ペンで空中に文字を書くことも一応可能です。
しかし、私は普段漢字を手書きすることがないため漢字を手書きするのは苦手です。
また日本語学習者が日頃教科書やアニメで見ている漢字と、我々が普段手書きする漢字の形は違います。
そのため外国人にとっても手書きの文字を読むことは簡単ではないでしょう。
また空中に文字をきれいに書くこと自体も簡単ではありません。
もしテキストチャットがあれば、直接漢字を見せることができるので非常に楽ですし、間違った漢字を教える心配もありません。

漢字の他にもスペルに関しても同様です。英語のスペリングの中には複雑なものも存在します。
また英語の発音に自信がなく、単語後聞き取ってもらえなくてもテキストチャットで入力できれば簡単に意思疎通ができます。

## なぜ翻訳機能が必要なのか

語学を勉強する上で翻訳は重要です。VRChatでは多くの英語話者がいるため、英語に関することを簡単に質問をすることができます。
しかしながら、翻訳は簡単なことではありません。VRChatプレーヤーの多くは翻訳者でもなければ語学教師でもありません。
幸いなことに近年のAIの発展にともない、機械翻訳が劇的に発展しています。
しかし、機械翻訳はしばしば空気を読めず的外れな翻訳をすることも少なくありません。
そこで機械翻訳と母語話者の両方を活用することが大切となります。
直接この言葉は英語でなんと言うのかを聞くよりも、機械翻訳の結果が合っているかどうかを尋ねた方が効率が良いです。
しかしながらVRヘッドセットを付けながら、いちいち翻訳サイトを利用するのは難しいです。

また語学の学習に関わらず、翻訳機能が使えればお互いに英語や日本語が不自由な場合でもコミュニケーションを取ることができます

# 技術的な話

## 概要

VRChatでは各プレイヤーがUnityを用いて作成したオリジナルのアバターを利用できます。
プレイヤーはUnity上でアバターにアニメーションやシェーダーを指定することができます。
これによりVRChat上でのアバターの見た目やアニメーションを自由に調整することができます。この機能を利用してテキストチャットを実装します。

VRChat上で文章を表示するためにはアバターに文字情報を送る必要があります。
VRChatはWebSocketやREST API,GraphQL等のプロトコルには対応していません。
VRChat が対応しているのはOSCのみです。OSCとはOpen Sound Controlの略で、電子楽器とリアルタイムで情報を共有するための通信プロトコルです。

OSCではintやfloatのほかにstringやBlobの送信が可能です。
これらのうちVRChatが対応しているのは、Int,BoolまたはFloatのstringのみとなっています。

つまり直接的には文字情報を送ることができないのです。[^2]
元々VRChat側の想定としては、簡単な数値のやり取り程度しか想定していないのが原因といえます。
そもそもテキストチャットにはWebSocketが使われるのが一般的です。
文字を直接送れない以上、アバターに文字上を送るためには一度数値に変更する必要があります。

VRChatではintは1バイトのみ対応しています。つまり256通りしか情報を持たないのです。
日本語で使用する文字数は明らかに256文字以上です。そこで二つのintの組み合わせで一文字を表現することにしました。


## 全体の概要図
![2.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/157463/f2fc4f7c-dc5f-364a-1f8c-c6618a898ec5.png)

KATは大きく分けて4つのパートからなります。一つ一つの技術的な背景を説明していきます。

## 1.アバター(Unity)に関して

アバターには文字を表示するための設定を行っていきます。VRChat のアバターはUnityのtext Mesh に対応していません。
そのため文字情報を文字として表示することはできません。そこでテクスチャとして、Charmapというフォントを画像データに変更したものを準備します。
このテクスチャを切り貼りすることで文字を表現しました。画像の切り貼りはシェーダーが行います。
しかしながらシェーダーに直接 OSC の情報を渡すことはできません。そのためアニメーションで OSC の情報を受け取り、それを変換してシェーダに渡します。

## 2.Charmap(C#)に関して

当初は使い慣れた Python を用いてCharmapを開発していましたが、他人に配布することを検討し計画を変更。
容易に綺麗なGUIを作れるC#の WPF での作製を決めました。

C #そのものは変わったことはありませんでしたが、作成するソフト自体があまり難しいものではなかったので簡単にできました。
またUnityもC#を使用しているため、Charmap用のソフトウェアを作成したことが役に立ちました。

### 3.バックエンド(Python)に関して

以上の工程でVRChat 側で準備することはできました。次に VRChatに送る情報を作成する必要性があります。
以下ではフロントエンドとバックエンドの二つの工程に分けて説明していきます。
当初はWebアプリとして完結させるつもりでしたが、OSC はUDP を使う関係上ブラウザのみで行うことは不可能です。
どうしてもローカルのサーバーが必要になります。

バックエンドの言語としてとしてPythonを採用しました。これは私が一番書き慣れた言語であり、
またアプリを作成する上で参考にしていたライブラリがPythonで書かれていたためでもあります。フレームワークとしてFastAPI を利用しました。

バックエンドの役割は以下の三つです
1.フロントエンドから送りたい文字情報を取得する
2.OSC の情報を VRChatに送る
3.フロントエンドおよびバックエンドで使用する各種データの保存

REST APIを通じてフロント側から文字を受け取ったら、その文字を整形します。
音声入力で得られた文章であるため、不適切な言葉が含まれている可能性があります。
その為 NG ワードでフィルターをかけます。 事前に作成した文字と数字の変換表に基づき文章を数字に変換し VRChatに送信します。

## フロントエンド

フロントエンドではフレームワークとしてReactを採用しました。

![3.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/157463/3f9ba620-948a-2a2b-7eef-54f45c330758.png)

VRChatでは多くのユーザーがVRヘッドセットを頭に付けているため、キーボードを使って文字を入力することは困難です。
ビジネスとしてではなくあくまで個人開発なので極力お金をかけたくありません。そこでWeb Speech APIを選択しました。
金銭的に余裕があるのであれば多くのAPIが選択可能ですが、無料・日本語対応・高品質となるとほかに手がありません。
音声認識を実装する時点では、Electron を使ったローカルアプリケーションも検討していましたが、
Web Speech API は Chromeのみに対応しています。そのためWebアプリケーションにすることにしました。

フロントエンドの仕事は以下の四つです。
1.Web Speech APIを用いて音声を認識し、文章に変換
2.必要なら文章を外部APIを用いて翻訳
3.処理済みのデータをバックエンドへ送信
4.バックエンドからAPIの情報等を入手

Web Speech API は複雑な設定なしに、簡単に利用することができます。
翻訳API については Google 翻訳と deepl 翻訳を使用しました。
今後可能であれば対応先を増やしていくつもりです。

# 作ってみた結果

試行錯誤の結果なんとか動くようにはなりました。
![3.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/157463/c240751a-1c4e-04d1-39aa-9cddd01bb5d5.png)

しかし、ここで一つ予期せぬ問題が発生しました。頻繁に文字化けが発生するのです。自分が送信した文章とアバターに表示している文章がずれてしまいます。
また自分から見たら正確に表示されていても、他人から見ると文字化けしていました。

色々と原因を検討した結果、原因はUDPにありました。

OSCでUDPを用いて通信を行っています。UDPは一般的にリアルタイム通信で頻繁に用いられるプロトコルです。
UDP はTCPと異なり、送信中に情報が失われても特に対応をしてくれません。その分TCPと比べれば高速ではありますが。

通信規格に関しては私ではどうしようもないので他の対応手段を考えました。

まず一番最初に考えたのは、チェックサムを用いて文字化けがあるかを自動的に判断し、必要に応じて再送するシステムです。
しかし、この方法は失敗でした。UDP により通信は一度だけ行われるわけではないからです。
UDP による通信は2度行われます。私の手元の端末から VRChatのサーバーへ一回、
そして VRChat のサーバーから各クライアントにもう一回送られます。
文字化けの判断は VRChatのサーバーに送る際にはできます。
しかし、VRChat のサーバーから各クライアントに送られた情報に関しては、
チェックのしようがありません。

最終的に採用した方法は、送信の間隔を力技で調整することです。様々な実験を試してみところ一度に送る文字数が10文字以下だとほぼ文字化しないことが分かりました。
おそらく同時に多くのOSCを送ると情報が落ちやすいのか、あるいは情報が多すぎてアバターの処理が追いついていない可能性もあります。
現在はまだ調整が完全には済むんでおらず、長文を送ると依然として文字化けが発生することがあります。
しかしながら短い文章においては問題なく送信ができています。

# 公開への準備

せっかく便利なものを作成したので一般に公開しようとしました。
それまでは私のローカル環境で動けばOKでしたが、一般配布するとなるとそうは行きません。
またユーザーの多くはプログラミングに詳しくないことが想定されますので、
PythonスクリプトをGithubに丸投げするだけでは誰にも利用されない可能性が高いです。
そこで細かな設定なしで簡単にインストールできる機能を作成しました。
具体的にはPythonスクリプトのexe化やUnity上での自動導入スクリプトの作成です。

公開はVRChat関連の商品が広く配布・販売されているBoothで行うようにしました。
Boothに公開されている人気商品はどれも説明が丁寧です。逆に人気のない商品は説明が不十分なものが多かったです。
そこでできるだけ分かりやすいい資料の作成に務めました。
![17.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/157463/fa8406a6-539c-8083-ecf1-d18a96e931ab.png)

例えばYouTubeのサムネイルのような商品紹介画像を作成しました。
正直言って、この工程がなりよりも厄介でした。プログラムと違い、明確なゴールが分かりずらいからです。

# 一般公開へ

ついに一般への公開ができました。
現在も日々より使いやすいように改良を重ねています。
現状ユーザーのほとんどが私の個人的な友人であるため、まだまだ宣伝不足です。
今後は宣伝をより一層がんばっていきたいです。

# 苦労した点・学んだこと

VRChat由来の原因不明なバグには何度も困り果てました。例をあげると最近はあまり遭遇しませんが、
開発当初はOSCを大量に利用するとアバターの挙動がおかしくなっていました。
当初は原因が全くわからず困り果てましたが、原因がVRChatとわかってからは休憩を取ってから作業するようにしたらうまく動くようになりました。

また扱う技術の幅広さにも苦労しましたが、逆に各言語の違いがよくわかりました。
私はこれまでまともに使ったことのある言語はPythonで、多少Bashや R 言語を触ったことがあるぐらいでした。
そのためJavaScript,Unity,C#の経験は全くありませんでした。

今回の開発を通じて、設計の大切さを学びました。いくらバグが出ないように集中してプログラムを噛んでいても元々の設計が悪いとどうしようもありません。
特に今回の個人開発では複数のソフトウェアを組み合わせることになるため、どの部分にどの機能を持たせるのか、それらの連携で悩みました。

個人で使うツールと他人が利用することが前提のツールの違いも痛感しました。
正直なところ一番苦労したのはコーディング以外のところです。
個人開発においてコーディングはごく一部の要素であると痛感しました。
特にドキュメントの作成には苦労しました。機能を追加すればするほど、
作成すべき資料が増えるので開発のやる気が低下しがちでした。


またライセンス関連の知識も習得しました。
オープンソース=出典を書けば自由に使ってOKぐらいの認識でしたが、今回の開発にあたり様々なことを勉強しました。
個人で使うだけならライセンスを気にする必要はありませんが、一般に公開するにはしっかりとライセンスを守る必要があります。
MIT,修正BSD,GPL等のライセンスの基本は理解できましたが、細かな事例に関しては悩むことも多いです。

# 個人開発の成果

最後の最後に言うのもなんなんですが、実はVRChatの公式でテキストチャット機能が公開されてしまいました。
KATを公開してから、公式テキストチャットの導入まで一か月程度しかありませんでした。
KATと違い、レスポンスも早く、面倒なインストールも不要です。

しかしながら公式が実装したのはあくまでテキストチャット機能です。
翻訳機能等はついていません。また公式のテキストチャットではキーボードに自分で手打ちを行う必要性があります。
また重要なことですが公式のテキストチャットは英語以外に対応していません。
正確に言うと英語で使用するアルファベット以外です。
そもそも VRChat はUIやドキュメントをはじめとして、英語以外の言語にまともに対応していません。
日本語ユーザーも多く、わざわざ日本サーバーを準備しているぐらいなので、
簡単な日本語の説明文ぐらい対応してもよいのではないでしょうか。

公式のテキストチャットが日本語に対応するまでは、KATを使う価値はありそうです。
またKATを公式のテキストチャットに対応させているので、フロントエンドや翻訳機能に関しては今後も活躍できそうです。

個人的にもKATはよく利用しています。語学学習にはもってこいです。
翻訳機能もあり便利です。Google 翻訳と DeepL 翻訳の二つに対応しているので、それらを見比べるのにも使っています。
最後にKAT作成にあたり読んだ本を紹介してこの記事を終わろうと思います。最後まで読んでいただきありがとうございました。

# 学習や業務に役立った本のまとめ・感想

[良いコード/悪いコードで学ぶ設計入門 ―保守しやすい 成長し続けるコードの書き方 \| 仙塲 大也 ](https://amzn.to/3edgG7b)

通称ミノ駆動本。非常に読みやすく、設計の重要さを学びました。これまでJavaは触ったことありませんでしたが、問題ありませんでした。

[Webを支える技術 ―― HTTP，URI，HTML，そしてREST WEB\+DB PRESS plus eBook : 山本 陽平: 本](https://amzn.to/3QgKnBr)

Webサービスの知識が全くなかったため、勉強のために購入しました。REST APIのRESTが何の略なのかが理解できました。

[テスト駆動開発 \| ＫｅｎｔＢｅｃｋ, 和田卓人](https://amzn.to/3CVfcZf)

KATを開発中に頻繁にバグに遭遇しました。その際にテスト駆動開発という手法をしりました。
まだ実際のプログラムにまでは落とし込めていないため、これから深読みしていきたいです。

[^1]: 実はVRChatが公式のテキストチャット機能を実装しました。KAT公開の一か月後です。
[^2]: [OSC Avatar Parameters](https://docs.vrchat.com/docs/osc-avatar-parameters)
VRChatは公式にテキストチャットを導入しました。このテキストチャットには直接stringで文字を送ることが可能ですが、対応しているのはアスキー文字のみです。