Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

SpeakerInfoの画像や音声のデータをURLで返すようにする? #1208

Open
Hiroshiba opened this issue May 2, 2024 · 8 comments · May be fixed by #1318
Open

SpeakerInfoの画像や音声のデータをURLで返すようにする? #1208

Hiroshiba opened this issue May 2, 2024 · 8 comments · May be fixed by #1318
Labels
機能向上 状態:実装 実装をおこなっている状態 状態:設計 設計をおこなっている状態 要議論 実行する前に議論が必要そうなもの

Comments

@Hiroshiba
Copy link
Member

Hiroshiba commented May 2, 2024

内容

エンジンのリソース情報を取得しようとすると結構な時間がかかることがわかっています。
VOICEVOXエディタは全キャラのリソース取得を起動時に行い、かつそれが必須な形であらゆるものがコーディングされていて、起動時間が10秒ほどかかる要因の1つとなっています。

時間がかかっているのは話者情報の取得API(/speaker_info/singer_info)です。
その中でもファイル取得やbase64エンコードに時間がかかっていることもわかっています(その他の関連リンク参照)。
これらの課題を一挙に解決できる方法の1つが、ファイル取得そのものを遅延させる方法です。

このissueでは画像や音声ファイルをbase64エンコードして/speaker_info等で返さず、何らかの方法でURLとして返すようにするかどうかを議論するissueです。

そもそもURL化するのが良いと思う理由

そっちのが一般的なことと、スケーラビリティが高いことと、エディタと親和性が高いためです。

  • そっちのが一般的
    • base64を返すのはあまり一般的じゃない 気がする
    • URLを返す他にも、IDを返してそのIDを元にリクエストしてもらう形式があるけど、後々のスケールのことも考えるとURLのがお得な気がする(↓参照)
  • スケーラビリティが高い
    • URLで返すなら、エンジンと関係ない場所にあるリソースを返すこともできる
    • 外部URLに立ち絵を置いておけば、立ち絵を後から自由に変更できるなど、柔軟な設計も可能にはなる
  • エディタと親和性が高い
    • そもそも画像や音声はblob化してsrcなどに指定してます
    • なのでURLだった場合はblob化しなければ自然と置き換えができる(はず)

実現方法

リソースファイルのURLは/static/speaker_infoAPIを作ってstaticでファイルを返せば良さそう。
ファイルパスはspeaker_info関数内で取ってきてるので、それをbase64エンコードするか、ファイルURLにするかの違いなだけなのでコード変更量は大きくなさそう。
エンジン自身のURLを取得するのはrequest.urlを取ってこればできるはず

互換性を考慮しつつファイルURLを返すように切り替える方法は、ワークアラウンド引数を追加する方法と、v2 APIを作る方法があると思います。

  • /speaker_info APIの引数に「URLで返すかどうか」情報をもたせるワークアラウンド
    • /speaker_info?workaround_resource_url=trueなどとすれば画像・音声をURLで返す
    • 型の変更がないのでエンジン・エディタともに変更が少なくて済む
    • engine_manifestは変えなくても良い・・・かも?
    • ワークアラウンドとしてるけど、正式な方法として提供しても良いかも(問題ないか結構検討したほうが良さそう)
  • /v2/speaker_info APIを作り、SpeakerInfoV2のようなモデルを返す
    • APIとモデルを作ること自体は簡単
    • APIが増えるのでengine_manifestを変える必要がある
    • エディタ側もマルチエンジンのこと考えるとそれなりの改修が必要
    • 他のv2 APIの拡張性も考え始めると検討事項が増えていく

個人的には議論の末引数指定を正式リリースできそうならそっちが良さそうに思いました。
できなそうなら、v2化するかワークアラウンドにするか諦めるかを考える感じかなと。

その他

関連リンク

@Hiroshiba Hiroshiba added 機能向上 要議論 実行する前に議論が必要そうなもの 状態:必要性議論 必要性を議論している状態 labels May 2, 2024
@y-chan
Copy link
Member

y-chan commented May 2, 2024

少し開発が止まっている感じはありますが、 ライブラリ管理APIのうちの/downloadable_libraryは、URLを返せる仕様になっているはずで、エディタ側でもそれをパースできるような仕様になっています。
これは、現状のエンジン・エディタが抱えているパフォーマンス問題に似た問題を抱えていたためなので、同様の仕様に変更することは、仕様の統一につながり、扱いやすさが向上すると思います。

エンジン側では、クエリ引数を使えるようにするとよいのかなと思いました。
URLモードかbase64文字列モードを切り替えられるオプショナルクエリにしてしまうことは別に破壊的変更ではないので、workaroundはなくても良いかなと思いました。
また、v2 apiは統一してすべてのAPIで作ったほうが扱いがしやすいと思うので、現状作るべきではないと思いました。

@sabonerune
Copy link
Contributor

sabonerune commented May 2, 2024

あとはキャッシュ周り?
軽く動作を確認したところ
datelast-modifiedetag:が付与されCache-Controlヘッダは付与されませんでした。
そのためブラウザは自動的にキャッシュの有効期限を推定して有効と判断した間はリクエストをせずにキャッシュを使い回します。
そのためエンジンの更新をしても表示が変わらないという不具合を起こす可能性があります。

@Hiroshiba
Copy link
Member Author

Hiroshiba commented May 4, 2024

@y-chan なるほどです!

クエリパラメータの場合、なんか落とし穴があるきがするんですよね・・・。
エディタ側からマルチエンジンとして引数がない既存エンジンにリクエストを投げる・・・ときは問題ないはずですが・・・。

既存エンジンにはない場合があるということをユーザーが知らない、とか・・・?
まあそれはAPI追加でも同じだし、大丈夫かな。。。

@Hiroshiba
Copy link
Member Author

@sabonerune キャッシュなるほどです!考慮ありがとうございます!!

仕様はどこにも書いてなかったのですが、コードを追っていくとたぶんファイルサイズとファイル作成日からetag作る感じでした。
https://github.com/encode/starlette/blob/9f16bf5c25e126200701f6e04330864f4a91a898/starlette/responses.py#L317-L318

StaticFilesのコードはここ
https://github.com/encode/starlette/blob/9f16bf5c25e126200701f6e04330864f4a91a898/starlette/staticfiles.py#L185-L187

将来ファイル作成日を消す変更を行った上、ファイルサイズが偶然被ったらキャッシュがバグになりますが、まあ、普通にしてたら大丈夫かな〜。

@Hiroshiba Hiroshiba changed the title 画像や音声のデータをURLで返すようにする? SpeakerInfoの画像や音声のデータをURLで返すようにする? May 4, 2024
@sabonerune
Copy link
Contributor

@Hiroshiba datelast-modifiedからブラウザは勝手にキャッシュの有効期限を推測して有効期限の間はサーバーにリクエストを送らずにキャッシュを利用してしまいます。サーバーにリクエストを送らないためetagの照合も行われません。

@Hiroshiba
Copy link
Member Author

@sabonerune お~~~~なるほどです!! 確かにキャッシュが入ってきそうですね!!!

うーん、no-cacheを付けるか、etag見てもらうようにするか、あるいは気づかなかったことにするかって感じですねぇ。
立ち絵を更新してそれを告知することもある以上、何もしないのはイマイチかも。

@sabonerune
Copy link
Contributor

@Hiroshiba あとはリソースが更新されたらURLを毎回変更するとかでしょうか?
この場合は逆にキャッシュの有効期限を極端に長くしてしまっても構わないというのがメリットで、リソース管理かコードが面倒になるのがデメリットですね…

@Hiroshiba
Copy link
Member Author

@sabonerune 調べたらキャッシュを不要にしたりするのをキャッシュバスティングだとか言うというのを見つけました。
FastAPIやStarletteでそういう機能は公式で提供されてなさそうですね・・・。

一応サードパーティで作られてる方はいらっしゃいました。
https://github.com/tmkontra/fastapi-static-digest
まあたぶん起動時にハッシュ化するので(普通それで問題ない)起動が遅くなってしまうのですが・・・。

頑張る価値はある気はちょっとしますねぇ。
事前にファイル名をコンパイルする形が手っ取り早い気がしました。
例えば話者ごとのリソースファイルへのパスをjsonで管理するようにして、ビルド時にファイル名をmd5ハッシュ等に置き換えてjsonも置き換え、あとはそのURLを/speaker_infosで案内、とかが現実的でしょうか。

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
機能向上 状態:実装 実装をおこなっている状態 状態:設計 設計をおこなっている状態 要議論 実行する前に議論が必要そうなもの
Projects
None yet
Development

Successfully merging a pull request may close this issue.

4 participants