Jetsonでデュラブルストリームを介したローカルAIの提供
著者はNVIDIA Jetson Orin Nano SuperとKokoro-82Mモデルを使用してローカルテキスト読み上げアプリStreamTTSを構築し、従来のリクエスト・レスポンスではなくデュラブルストリーム(S2)を採用することで、共有可能でリアルタイム更新可能な音声生成を実現し、遅い推論、公平なスケジューリング、重複排除に対処しました。
ローカルAIがますます実用的になる中、著者はサードパーティのプロバイダに依存せずに独自のモデルをセルフホスティングし、ワークロードを独立して実行したいと考えました。NVIDIAのJetsonシリーズは良い出発点であり、著者はJetson Orin Nano Superキットを選択しました。これは1024のCUDAコアと32のテンソルコアを搭載し、67 TOPSの性能を持ち、Kokoro-82Mモデルを使用したテキスト読み上げアプリ「StreamTTS」を実行するのに十分です。
従来のアーキテクチャではリクエスト・レスポンスパターンが一般的ですが、推論は遅く、出力は段階的に生成されます。ブロッキングリクエストでは複数ユーザーが同時に送信すると待ち行列が発生します。著者は結果が共有可能であり、生成中にリアルタイムで聴けるリンクを即座に提供したいと考えました。そこで、デュラブルストリーム(durable streams)を中核アーキテクチャとして採用しました。デュラブルストリームは永続化されたレコードの順序付きシーケンスであり、読者はいつでも最初からリプレイしたり、最新の出力を追跡したりできます。
具体的な実装では、オープンソースのS2 Liteをローカルで実行し、ストリームストレージとして使用します。システムは複数の名前付きストリームを介して通信します。jobsストリームは推論要求を受け付け、pub/casts/ストリームは各生成タスクの音声出力を保存します。ワーカープロセスはjobsストリームからタスクを読み取り、Kokoroモデルを実行して音声を生成し、結果を対応する出力ストリームに追加します。フロントエンドのブラウザはWeb Audio APIを使用して文単位のMP3チャンクをデコードし、任意の位置からの再生やリアルタイム追跡をサポートします。
複数ユーザーへの公平性を確保するため、ワーカーは各ストリームの再生リード時間(lead)を追跡し、リードが最小のストリームに次の文を生成するよう優先順位を付けます。これにより全ユーザーがスムーズに体験できます。また、タスクIDはテキストと音声のSHA-256ハッシュから生成され、条件付き追加操作(match_seq_num=0)によって自動的に重複排除されます。同じ内容は一度だけ処理され、後続のリクエストは既存の結果を返します。
ワーカープロセスは持続的消費者パターンも実装しており、jobs/_cursorストリームに処理済みタスクのオフセットを記録します。クラッシュ後も再開可能で、再起動時に最後にコミットされたオフセットから処理を再開します。既に完了したタスクは出力ストリームのeosマーカーでスキップされます。この設計により、少なくとも1回の配信セマンティクスが保証され、試行境界マーカーで部分的な音声書き込みが処理されます。
最終的に、StreamTTSアプリはstreamtts.devでホストされ、著者のJetsonデバイス上で完全に動作しています。このアーキテクチャは、遅い推論、リプレイ可能性、および並行スケジューリングの問題をデュラブルストリームでエレガントに解決し、類似アプリケーションのための簡潔なリファレンスソリューションを提供します。