ユースケース

LLM と avacast で作る、英会話の練習相手

音声認識で聞き取り、LLM が返事を考え、avacast が話す。3 つの部品を組み合わせて、ブラウザで英語の会話練習ができる画面を作ります。


全体の構成

利用者の声はブラウザの音声認識で文字にし、サーバーに送ります。サーバーは LLM に返事を作らせ、その文章を avacast の speak に渡します。映像と音声は WebRTC でブラウザに届きます。

  • ブラウザ: 音声認識 (Web Speech API) と、avacast の SDK での映像の表示
  • サーバー: 会話の履歴を持って LLM を呼び、返事を avacast へ渡す
  • avacast: 渡された英文を音声と口の動きにして、映像として配信する

avacast に含まれるのは、渡された文章を話す部分です。返事を考える LLM と音声認識は、使い慣れたものを組み合わせます。

英語の声でセッションを作る

セッションはサーバーで API キーを使って作ります。voice.language を en にすると英語で話します。voice.speed は 0.8〜1.2 で、学習者向けに少しゆっくりにしておくと聞き取りやすくなります。

サーバー (セッションの作成)

const res = await fetch('https://api.avacast.jp/v1/sessions', {
  method: 'POST',
  headers: {
    Authorization: `Bearer ${process.env.AVACAST_API_KEY}`,
    'Content-Type': 'application/json',
  },
  body: JSON.stringify({
    avatar_id: 'avt_xxxxxxxx',
    voice: { language: 'en', speed: 0.9 },
  }),
});
const { session_id, client_token, webrtc } = await res.json();
// ブラウザへは session_id・client_token・webrtc を返す (API キーは返さない)

ブラウザでは、受け取った値を SDK に渡して映像を表示します。

ブラウザ (映像の表示)

import { AvacastSession } from 'avacast';

const session = new AvacastSession(client_token, {
  signalingUrl: webrtc.signaling_url,
  iceServers: webrtc.ice_servers,
});
session.attach(document.getElementById('avatar'));
await session.start();

ブラウザで英語を聞き取る

音声認識はブラウザの SpeechRecognition を使います。lang を en-US にして、聞き取った英文をサーバーへ送ります。利用者が話し始めたら session.interrupt() を呼ぶと、アバターが話している途中の返事を止められます。

ブラウザ (音声認識)

const Recognition = window.SpeechRecognition || window.webkitSpeechRecognition;
const rec = new Recognition();
rec.lang = 'en-US';

rec.onspeechstart = () => session.interrupt();
rec.onresult = async (e) => {
  const userText = e.results[0][0].transcript;
  await fetch('/api/reply', {
    method: 'POST',
    headers: { 'Content-Type': 'application/json' },
    body: JSON.stringify({ sessionId: session_id, userText }),
  });
};

talkButton.addEventListener('click', () => rec.start());

SpeechRecognition が使えないブラウザでは、録音した音声をサーバー側の音声認識サービスに送る形に置き換えます。後ろの流れは変わりません。

LLM の返事をそのまま話させる

サーバーは LLM で返事を作り、その文章を POST /v1/sessions/:id/speak に渡します。下の llm.reply は、お使いの LLM の SDK に置き換えてください。

サーバー (/api/reply)

export async function POST(req: Request) {
  const { sessionId, userText } = await req.json();
  // そのセッションがログイン中の利用者のものかを、ここで確かめる
  const reply = await llm.reply(userText);

  await fetch(`https://api.avacast.jp/v1/sessions/${sessionId}/speak`, {
    method: 'POST',
    headers: {
      Authorization: `Bearer ${process.env.AVACAST_API_KEY}`,
      'Content-Type': 'application/json',
    },
    body: JSON.stringify({ text: reply }),
  });
  return Response.json({ reply });
}
  • 1 回に渡せる文章は 1,000 文字までです。
  • 前の返事を話し終わるのを待たずに speak を呼べます。順番に話します (1 セッションあたり 20 件まで)。
  • ブラウザが接続する前に呼ぶと 409 session_not_connected になります。映像が届いた合図は SDK の session.ready です。

レベルに合わせた話し方

言い回しの難しさや、間違いを指摘するかどうかは、LLM への指示で変えられます。avacast 側の設定は変えずに済みます。

LLM への指示の例

const system = [
  'You are a friendly English conversation partner for a Japanese learner (CEFR A2).',
  'Use short sentences and common words. Ask one question at a time.',
  'If the learner makes a grammar mistake, say the correct sentence once, then continue.',
  'Keep each reply to one or two sentences.',
].join('\n');

返事を 1〜2 文に収めるよう指示しておくと、話し終わるまでの待ち時間が短くなり、会話のテンポが保てます。

料金の目安

課金はセッションを開いていた時間 (接続時間) です。無料プランは月 30 分まで、1 セッション最長 5 分です。1 回 15 分の練習を想定するなら、1 セッション最長 15 分の Starter (¥1,980/月・月 200 分込み) から使えます。

月 30 分まで無料

カード登録なしで始められます。

API キーを発行

ブログ一覧へ