開発実績一覧へ
Web・業務システム開発IT・Webサービス

2Dバーチャルオフィス(近接音声・AI議事録)

アバターで近づくだけで会話が始まる。音声・ビデオ・画面共有・AI議事録を、ひとつの2Dオフィスで。

ノートPCに2Dバーチャルオフィスの画面が表示されている様子。アバターに在席・会議中の状態が表示され、近接音声・ビデオ通話・画面共有・AI議事録の4つの機能が並んでいる

Overview

プロジェクト概要

アバターでオフィスに「出社」し、ほかのメンバーに近づくと自動で音声がつながる、2Dバーチャルオフィスを開発しました。会議室に入れば、その場でビデオ通話と画面共有ができます。さらに、AIが会議を文字起こしして要約し、議事録にまとめます。対象は、リモート勤務・ハイブリッド勤務のスモールチーム(2〜20名)です。

同種のサービスでは、一定の距離で通話がオンとオフに切り替わる方式が使われています。本サービスでは、距離に応じて音量がなめらかに変わり、相手のいる方向から声が聞こえる方式に作り直しました。開発期間は約6か月で、要件定義から本番運用までの全工程を、当社のエンジニア1名で担当しました。本番リリース後は、導入150チーム・登録ユーザー約900名の規模で稼働しています。

※ お客様との守秘義務のため、お客様名・製品名は記載していません。掲載している画面とデータは、説明用に再構成したイメージです。

分類
受託開発。リアルタイムの音声・ビデオ通話とAI議事録を備えたWebサービスの開発
開発期間
約6か月
体制
エンジニア1名(要件定義から本番運用まで全工程)
規模
導入150チーム / 登録ユーザー約900名 / ピーク時の同時接続 約300
利用者
リモート勤務・ハイブリッド勤務のスモールチーム(2〜20名)
業種
IT・Webサービス
ロール
要件定義 / 技術選定 / アーキテクチャ設計 / DB設計 / バックエンド / リアルタイム基盤 / メディア(WebRTC) / フロントエンド / AI機能 / AWSインフラ / CI/CD / 監視 / 本番運用
技術
Ruby on Rails / AnyCable / LiveKit(WebRTC) / Phaser 3 / TypeScript / PostgreSQL / Redis / Claude API / Amazon Transcribe / AWS(ECS Fargate / EC2) / Terraform
自宅・コワーキングスペース・別の自宅で働く3人が、「今、少し話せますか?」「何が決まった?」と思いながら声をかけられずにいる様子

01 — 導入前の課題

同じチームなのに、隣に誰もいない

リモート勤務やハイブリッド勤務が広がり、チームは「同じ空間にいる感覚」を失いがちになりました。自宅やコワーキングスペースなど別々の場所で働いていると、「今、少し話せますか?」と気軽に声をかけにくくなります。少し話すだけのために会議のURLを発行し、ツールを行き来する必要があります。席を外している間に何が決まったのかも、つかみにくくなります。本サービスは、対象をスモールチームに絞り、こうした日々の不便を解消することをねらいました。

  • 雑談が減り、孤立感が生まれる
  • 少し話すために、会議のURLを発行する
  • 複数のツールを行き来する
  • 席を外した間の出来事をつかみにくい
2Dオフィスのマップ画面イメージ:アバター同士が近づいて会話しており、相手ごとの音量(100%、35%)と、在席・会議中・集中の状態が表示されている

02 — 近接音声

話しかけるボタンも、会議URLもいらない

オフィスのマップ上で、アバターを相手に近づけるだけで音声がつながり、離れると自然に切れます。音量は、相手との距離に応じてなめらかに変わります。画像の例では、近くにいる山田さんの声は100%、少し離れた鈴木さんの声は35%で聞こえています。相手のいる方向から声が聞こえるように、左右の定位も付けました。アバターには、在席・離席・会議中・集中といった状態が色で表示されます。アバターの位置は、1秒間に10〜15回、差分だけを配信し、受け取った側で補間してなめらかに描いています。

  • 近づくだけで音声がつながり、離れると切れる
  • 距離に応じて、音量がなめらかに変化
  • 相手のいる方向から声が聞こえる
  • 在席・会議中・集中などの状態を色で表示

開発中の課題と解決

近接音声を自然にする(最も難しかった点)

課題
一定の距離でオンとオフが切り替わる方式では、会話が不自然でした。利用者どうしを直接つなぐ構成は、同時に話す人が増えると破綻しました。エコーやハウリング、モバイルでの音声の制約も壁になりました。
解決
音声をSFU(LiveKit)経由に寄せ、音声を受け取る相手は近くにいる人だけに絞って、通信量を抑えました。距離から音量を決める減衰のカーブは、実際に動かしながら調整しています。ある距離までは最大の音量、そこから先はなめらかに無音へ近づく形にしたことが、会話の自然さの決め手になりました。本番稼働後の音声の片道の遅延は200ms未満、音声の接続の確立は1.5秒未満です。
会議室の画面イメージ:マップ上の会議室、参加者のビデオ、共有中の資料、AI議事録(要約・決定事項・対応事項・次回の予定)が1つの画面に表示されている

03 — 会議室とAI議事録

そのまま会議室へ。共有も議事録も、ここで完結

マップ上の会議室に入ると、その場でビデオ通話と画面共有が使えるようになります。外部の会議ツールへ移る必要はありません。会議室の中にいる人どうしは、距離に関係なく最大の音量で聞こえ、部屋を出ると自動で退出します。会議の音声はAmazon Transcribeで文字にし、Claude APIで要約して、要約・決定事項・対応事項・次回の予定をまとめた議事録にします。できあがった議事録は、チームのチャットへ自動で投稿されます。

  • 会議室に入るだけで、ビデオ通話と画面共有を開始
  • 外部の会議ツールやURLの発行が不要
  • AIが会議を文字起こしし、要約して議事録に
  • 議事録をチームのチャットへ自動で投稿

開発中の課題と解決

WebRTC・メディアの安定化

課題
UDPを使うメディアの配信は、Fargateと相性が悪く、NAT越えやポートの開放でつまずきました。
解決
LiveKitはEC2に分けて構築してUDPを確保し、TURNを併用しました。アプリの層(Fargate)とメディアの層(EC2)で役割を分け、Terraformで同じ構成を再現できるようにしています。本番稼働後の月次の稼働率は99.9%です。
不在中の要点の画面イメージ:10:00〜10:40の不在中の出来事が3件の要点にまとめられている。150チーム導入、約900ユーザー、月次稼働率99.9%の表示

04 — 不在中の要点

40分離れていても、40分を読み返さなくていい

席を外していた人には、不在だった間のチャットと議事録から、AIが「不在中の要点」を作って示します。画像の例では、10:00〜10:40の40分間の出来事が、「デザイン案はB案で進行」「山田さんが資料を更新」「15:00に再確認予定」の3件にまとめられています。席に戻ったとき、流れたチャットをさかのぼって読む必要がありません。AIの処理は重いため、ジョブとして裏側で実行しています。頻度の高いヘルプ応答と、要約・議事録とで、Claudeのモデルを使い分けました。

  • 不在中のチャットと議事録から、要点だけを整理
  • 何があったかを、数十秒で把握
  • 用途に応じてClaudeのモデルを使い分け
  • 重いAI処理は、ジョブとして裏側で実行

開発中の課題と解決

高頻度の位置同期をさばく

課題
RailsとActionCableだけでは、多数の接続への高頻度の配信で並行性が足りませんでした。位置をデータベースに書くと、すぐに逼迫しました。
解決
WebSocketの処理をAnyCable(Go)に任せ、Rubyでの開発のしやすさは保ちました。位置などの一時的な状態はRedisで持ち、差分を10〜15Hzで送って受け取った側で補間することで、送る量を減らしています。再接続のときは、スナップショットから復元します。本番稼働後、ピーク時の同時接続は約300、体感の移動の遅延は150ms未満です。

Scope

担当範囲

当社はエンジニア1名の体制で、要件定義から本番運用まで、すべての工程を担当しました。お客様とは要件と優先度をすり合わせながら、体験の中心となる部分から段階的に作りました。

工程担当
要件と優先度のすり合わせお客様と当社
要件定義、技術選定当社
アーキテクチャ設計、DB設計当社
バックエンド(認証、チーム、課金、データの保存)当社
リアルタイム基盤(位置の同期、在席状況、チャット)当社
メディア(WebRTCによる音声・ビデオ・画面共有)当社
フロントエンド(2Dオフィスの描画、管理・設定画面)当社
AI機能(議事録、要約、不在中の要点)当社
AWSインフラ、CI/CD、監視当社
本番運用当社

1名ですべての層を担当したため、「体験の中心を最短で成立させる」という判断と、リアルタイム通信・メディアという難しい部分の作り込みが、最も大きなテーマになりました。

Architecture

使用技術・システム構成

記録の中心
Ruby on Rails 8 / PostgreSQL(Amazon RDS)。認証、チーム、課金、データの保存。会議の参加トークンもここで発行
リアルタイム層
AnyCable(Go) / Redis(Amazon ElastiCache)。在席状況、位置、チャット、通話の接続手続き。位置は差分を10〜15Hzで配信
メディア層
LiveKit(SFU)。音声、ビデオ、画面共有。ブラウザとはWebRTCで接続
音声の処理
Web Audio。距離に応じた音量の調整、左右の定位
フロントエンド
TypeScript / Phaser 3(2Dオフィスの描画) / Hotwire・Tailwind CSS(管理・設定画面) / Vite
AI・音声認識
Claude API(議事録、要約、ヘルプ応答) / Amazon Transcribe(会議の音声の文字起こし)
認証・課金
Devise / Pundit / Stripe(サブスクリプション)
非同期処理
Sidekiq。重い処理をジョブとして実行
実行基盤
AWS ECS Fargate(アプリ) / EC2(LiveKit) / ALB / S3 / CloudFront / SES
開発・運用
Docker / Terraform / GitHub Actions / Sentry

主な技術の選定理由

Railsを記録の中心に

Railsが得意な認証、課金、データの保存に集中させました。苦手な高頻度の配信とメディアの配信は、専用の層に任せています。

AnyCable(Go)

RailsとActionCableだけでは、多数の接続への高頻度の配信で並行性が足りませんでした。WebSocketの処理をGo製のサーバーに任せ、チャネルの処理はRubyのまま保ちました。

LiveKit(SFU)

利用者どうしを直接つなぐ構成は、同時に話す人が増えると破綻しました。SFUを経由させ、接続の数が人数の2乗に比例して増える問題を避けています。

LiveKitをEC2に置く

UDPを使うメディアはFargateと相性が悪かったため、EC2に分けて構築し、UDPを確保しました。

位置をRedisで扱う

位置をデータベースに書くとすぐに逼迫したため、位置などの一時的な状態はRedisとメモリで扱いました。

Claudeのモデルの使い分け

頻度の高いヘルプ応答には軽量なモデル、要約と議事録には高性能なモデルを使い、コストと品質の両方を保ちました。

Process

開発の進め方

  1. 1

    「まず、同じ空間にいる感覚を最短で成立させる」という方針で、フェーズを分けて進めました。約6か月の中で、近接音声の作り込みに最も時間を使っています。

  2. 2

    Phase 0(基盤):土台となる基盤を作りました。

  3. 3

    Phase 1(MVPコア):近接音声、会議、在席状況。近接音声を最優先で作り込みました。

  4. 4

    Phase 2(AI差別化):AIによる議事録、要約などの機能を加えました。

  5. 5

    Phase 3(拡張・本番化):機能の拡張と、本番運用への移行を行いました。本番リリースの後は、スモールチーム向けに段階的に展開しています。

  6. 6

    インフラはTerraformでコードにし、同じ環境を再現できるようにしました。CI/CDにはGitHub Actionsを使っています。

Quality & Security

品質・セキュリティ・運用

認証・権限

ログインはDevise、権限はPunditで制御します。

会議への参加

会議の参加トークンはサーバー側で発行し、LiveKitへ渡します。

切断への備え

位置などの一時的な状態は、切断・再接続のときにスナップショットから復元します。

通信の確保

LiveKitをEC2に分けてUDPを確保し、TURNを併用してNAT越えに対応します。

インフラの再現性と監視

Terraformでインフラをコードにし、同じ構成を再現できます。CI/CDにGitHub Actions、監視にSentryを使っています。

稼働

本番リリースの後、段階的に展開し、月次の稼働率99.9%で安定して稼働しました。

Results

成果

近づくだけで自然に話せる近接音声と、AIによる議事録の自動作成を備えた2Dバーチャルオフィスを、エンジニア1名で要件定義から本番運用まで担当し、150チーム・約900名の規模で安定して稼働させました。

  • 会議の議事録の作成を自動化しました。手作業で約15分/会議かかっていたものが、ほぼ0分になりました(約90%削減)。
  • 近づくだけで話せるため、会議を設定しない気軽な会話が日常のものになりました。
  • 通話、会議、画面共有がオフィスの中で完結し、外部の会議のURLを発行する必要がなくなりました。
  • AIによる要約で、不在中に何があったかを数十秒でつかめるようになりました。
  • 稼働の実績:導入150チーム、登録ユーザー約900名、ピーク時の同時接続 約300、月次の稼働率99.9%。
  • 品質の実績:体感の移動の遅延150ms未満、音声の片道の遅延200ms未満、音声の接続の確立1.5秒未満、会議の最大ストリーム数は1室あたり約30。

FAQ

技術面のよくあるご質問

Q. 近接音声は、ほかのサービスと何が違いますか?
一定の距離でオンとオフが切り替わる方式ではなく、相手との距離から音量を連続的に決め、左右に定位させています。ある距離までは最大の音量で、そこから先はなめらかに無音へ近づきます。
Q. 人数が増えても通話は保てますか?
全員がSFU(LiveKit)へ音声を送り、各利用者は近くにいる相手の音声だけを受け取ります。利用者どうしを直接つなぐ構成で起きる、接続の数が急に増える問題を避けています。
Q. なぜ構成を3層に分けたのですか?
性能の要件が異なる処理を1つにまとめないためです。Railsは認証・課金・データの保存に集中させ、高頻度の配信はAnyCable、メディアの配信はLiveKitに任せています。
Q. アバターの位置はどう同期していますか?
10〜15Hzで差分だけを配信し、受け取った側で補間して描いています。位置はデータベースに書かず、Redisとメモリで扱います。切断したときは、スナップショットの再送で復元します。
Q. AIの議事録はどのように作られますか?
会議の音声をAmazon Transcribeで文字にし、Claude APIで要約して議事録にまとめ、チームのチャットへ自動で投稿します。重い処理はSidekiqのジョブとして実行しています。
Q. なぜLiveKitだけEC2で動かしているのですか?
UDPを使うメディアはFargateと相性が悪かったためです。LiveKitはEC2に分けてUDPを確保し、TURNを併用してNAT越えに対応しています。

Tech Stack

Ruby on RailsAnyCableLiveKit(WebRTC)Phaser 3TypeScriptPostgreSQLRedisClaude APIAmazon TranscribeAWS(ECS Fargate / EC2)Terraform

Contact

まだ要件が固まっていなくても大丈夫です。

業務内容や課題を整理しながら、実現方法・開発範囲・進め方をご提案します。 まずはお気軽にご相談ください。