Step by Work

SNS

【AI面接・AI商談】リアルタイムで話すAIアバターの作り方|Anam×Fish Audioで日本語対応(コード・設定値つき)

Google Meetで、画面の向こうの相手とリアルタイムに会話するAIアバターを自作しました。顔は画像1枚、声は日本語の音声合成、受け答えはAI。月12ドルのプランと、会話5分あたり10円程度の音声代で動いています。

最近「オンライン面接に来た応募者がAIだった」という話を耳にするようになりました。AI面接というと、企業がAIに面接をさせるツールを思い浮かべる方が多いと思いますが、逆に”面接を受ける側”や”商談の相手”をAIが演じることも、もう普通にできてしまいます。

実際にどこまでできるのかを確かめるために、私は「仕事の依頼をしてきた相手が、実はAIだった」という動画を作りました。

この記事では、その動画で使ったAIアバターの作り方を、設定値やコードも含めて、自分でも再現できるように解説します。

実際に作った動画:仕事の依頼をしてきた相手がAIだった

「Web制作を外注したい」という商談の相手が、途中から「認定パートナーに登録してほしい」「そのためにカリキュラムを受けてほしい」「受講料は48万円」と、スクールの勧誘に話をすり替えていく、という内容です。

相手の「田口さん」は、顔も声も話す内容も、すべてAIで作った架空の人物です。商談そのものは、仕組みを確かめるための再現として撮影しています。

全体像:AIアバターは4つの部品でできている

AIの商談相手のしくみ

仕組みはシンプルで、次の4つを組み合わせているだけです。

部品使ったもの役割
顔画像生成AI → Anam(アナム)画像1枚から、口や表情が動くアバターを作る
声Fish Audio(フィッシュオーディオ)日本語の自然な音声を作る
耳と頭脳人格設定のテキスト+OpenAIのAI相手の声を文字にして、返事の文章を作る
配線OBS+仮想オーディオアバターの映像と声を Google Meet に流す

会話の流れは、こうなっています。

  1. 相手が話す → OpenAI のリアルタイム文字起こしで文字にする(話し終わりも自動で判定)
  2. AIが、人格設定に沿って返事の文章を作る
  3. Fish Audio が、その文章を日本語の音声にする
  4. その音声を Anam に流し込むと、アバターが口を動かして話す
  5. OBS で映像を取り込み、Meet にカメラとして流す

つまり、Anamは「顔と口の動き」だけを担当し、声と中身は別のサービスで作って差し込んでいる、という構成です。

「Anamだけで完結しないの?」と思うかもしれません。Anamにも音声とAIは入っているのですが、標準の日本語の声はイントネーションが日本人離れしていて、どうしても違和感が残りました。そこで、声だけを日本語に強い Fish Audio に差し替えています。

準備するもの

もの用途費用
Anam のアカウントアバター無料プランあり(本格的に使うなら Starter 月12ドル)
Fish Audio のアカウント音声使った分だけ(前払い)
OpenAI の APIキー聞き取り(文字起こし)と、返事を作るAI使った分だけ
Python 3小さな中継サーバーを動かす無料(pip install requests)
Google Chromeアバターの画面・操作盤無料
Microsoft EdgeGoogle Meet を開く無料
OBS Studio映像を Meet に流す無料
VB-CABLE と Hi-Fi Cable音声を Meet とやりとりする無料(VB-Audio)

APIキーは、プログラムに直接書かず .env というファイルにまとめておきます。

ANAM_API_KEY=ここにAnamのキー
FISH_API_KEY=ここにFish Audioのキー
OPENAI_API_KEY=ここにOpenAIのキー

ステップ1:顔をつくる

1-1. 画像生成AIで「架空の人物」を作る

ChatGPT などの画像生成AIで、実在しない人物の顔写真を作ります。

ここで一番の学びがありました。きれいに作るほど、AIっぽくなるのです。

顔の作り直しの比較

最初に作ったのは左の画像です。紺のスーツにガラス張りのオフィス、均一なライティング。一見よくできていますが、アバターにして動かすと「プロが撮ったポートレート」にしか見えず、Meetの画面としては明らかに不自然でした。

そこで、次の3点を指定して作り直しました。

  1. 顔を平凡にする:無精ひげ、毛穴、肌のムラ、目の下のクマ。イケメンにしない
  2. カメラを安物にする:ノートPCの内蔵カメラで、目線より下から見上げる角度。ノイズと圧縮、蛍光灯の色かぶり
  3. 背景に生活感を出す:曲がったカレンダー、ホワイトボード、書類の山

実際に使ったプロンプトの要点はこちらです(英語で指示しています)。

An ordinary, unremarkable 36-year-old Japanese man on a low-quality laptop webcam
during a Google Meet call. Plain everyday Japanese face, visible stubble,
rough skin texture with visible pores, tired eyes with faint dark circles.
NOT handsome, NOT a model, NOT a magazine portrait.
CAMERA: cheap built-in 720p laptop webcam on a desk BELOW eye level, tilted up.
IMAGE QUALITY: soft focus, visible digital sensor noise, mild video compression,
flat low contrast.
BACKGROUND: a small cheap office, a wall calendar hanging slightly crooked,
a whiteboard with faint smudged marker, a stack of papers.
NOT studio lighting, NOT retouched, NOT glamorous.
Looks exactly like a real screenshot from a boring online meeting.

さらに2点、あとから手を入れました。

  • 口を閉じた表情にする:歯を見せて笑っている画像だと、黙っているときも笑顔のまま固まって不自然でした。同じ人物のまま口元だけを変えるには、元の画像を参照画像として渡し、「表情だけ変えて、口を閉じた無表情に」と指示します
  • 服と照明を変える:スーツや水色シャツより、ジャケパンのラフなオフィスカジュアル+素人っぽい室内照明のほうが自然でした。これも参照画像を渡して、服と照明だけを変えています

つまり、本物っぽさは「きれいさ」ではなく「ほどよい雑さ」で出る、ということです。

⚠ 実在の人の写真は使わないでください。Anamは写真1枚からアバターを作れてしまうので、実在の人物で作るとなりすましになります。

1-2. Anam でアバターにする

画像は、Anamが正方形に切り抜くので、顔を中央にした正方形(今回は1152×1152)にしておきます。

Anam Lab(管理画面)の「Avatars」→「Add」から画像をアップロードすれば、数分でアバターになります。APIで作る場合はこうです。

import requests

res = requests.post(
    "https://api.anam.ai/v1/avatars",
    headers={"Authorization": f"Bearer {ANAM_API_KEY}"},
    data={"displayName": "田口(商談)"},          # 3文字以上でないとエラー
    files={"imageFile": open("face_square.png", "rb")},  # 項目名は imageFile
)
print(res.json()["id"])   # これがアバターID

APIで作るときにつまずいた点が2つあります。

  • 表示名(displayName)は3文字以上でないと、400(Name must be at least 3 characters)が返ります
  • 画像の項目名は imageFile です。file にすると「画像がない」というエラーになります

また、自分で作れるアバターの数はプランで決まっています(無料は1体、Starterは2体)。枠が埋まっていると作れないので、使わなくなったアバターは削除して枠を空けます。

ステップ2:声をつくる(Fish Audio)

2-1. 声を選ぶ

Fish Audio には、利用者が公開している日本語の声がたくさんあります。気に入った声のページURL fish.audio/m/<ここ> の部分が、声のID(reference_id)です。

今回は「治療院セミナーの声」(中年男性・明瞭で説得力のある話し方)を使いました。人前で説明する話し方の声なので、勧誘のセリフとの相性がよかったです。

2-2. 音声を作る

Anamに流し込むために、PCM形式・16kHzで音声を作ります。実際に使っている設定です。

import requests

res = requests.post(
    "https://api.fish.audio/v1/tts",
    headers={
        "Authorization": f"Bearer {FISH_API_KEY}",
        "Content-Type": "application/json",
        "model": "s2.1-pro",
    },
    json={
        "text": "[肩の力を抜いて、雑談するように] えっとですね、うちのクライアントさんのサイトを、何本かお願いできたらなーと思ってて。",
        "reference_id": "bab91a3e80b04da09ce2d10db13ea222",  # 声のID
        "format": "pcm",
        "sample_rate": 16000,   # Anam に合わせる
        "latency": "low",       # 速さ優先
        "temperature": 0.9,     # 揺らぎ。標準は0.7
        "top_p": 0.9,
    },
)
pcm = res.content

2-3. 「読み上げ感」を消すコツ

最初は、発音はきれいなのにどうしても「文章を読み上げている」感じがしました。同じセリフで条件を1つずつ変えて聴き比べたところ、原因と効いた対策はこうでした。

変えたこと結果
セリフを話し言葉にする(「〜と思ってまして」→「〜と思ってて」、「〜ですので」→「〜なんで」)一番効いた
文頭に日本語で演技指示を入れる([少し考えながら] [軽く笑いながら])声には出ず、言い方だけが変わる。「あの」などの言いよどみも自然に入った
揺らぎ(temperature)を 0.7 → 0.9 に上げる抑揚に幅が出る
返事をまとめて1回で音声化する抑揚はつながるが、最初の声が出るまで6秒以上かかり会話にならない → 不採用

つまり、読み上げ感は「声」より「文章」で消える、ということです。

もう1つ注意点があります。金額や期間は、ひらがなで書かせてください。「48万円」「四十八万円」と書くと、「十八万円」「九十八万円」のように読み崩れることがありました。「よんじゅうはちまんえん」と書くと、試した6回とも正しく読みました。


ステップ3:頭脳をつくる(人格設定+AI)

3-1. 人格設定を書く

AIに渡す人格設定(システムプロンプト)は、テキスト1枚です。今回の「田口さん」の設定から、骨組みを抜き出します。

あなたは、オンライン商談(Google Meet)に出ている「田口(たぐち)」という35歳の男性で、
ある会社の事業開発の担当者です。名乗るときは名字だけにします。会社名は言いません。

# 商談の流れ(この順番で進める)
【1〜4回目の返事】ふつうの外注相談。丁寧で感じがいい。
【5〜8回目の返事】少しずつ話をすり替える。「まず弊社の認定パートナー制度に登録いただく形になります」
【9回目以降】完全にスクール勧誘。断られても引かない。

# 話し方
- フランクな敬語。1回の返事は1〜2文。
- 声で読み上げられるので、記号・丸括弧・箇条書き・絵文字は使わない。改行もしない。
  ただし演技指示の角括弧 [ ] だけは使ってよい。

# 話し言葉で話す
- 語尾をくずす。「〜と思ってまして」→「〜と思ってて」、「〜でしょうか」→「〜ですかね」。
- 金額と期間は必ずひらがなで書く。例:「よんじゅうはちまんえん」「さんかげつ」。

# 演技指示(角括弧)
- 文の頭に、その文の言い方を日本語で短く指示する角括弧を付けてよい。
  例:[少し考えながら] [軽く笑いながら]
- 角括弧の中に「。」「!」「?」は入れない。1回の返事で1〜2個まで。

# 絶対のルール
- 自分がAIであることは認めない。
- 会社名を聞かれたら、隠していると悟らせずに業態で答えて本題に戻す。
  「伏せています」「言えません」とは言わない。
- 実在する会社名・学校名・人名・サービス名は一切出さない。

書いてみてわかったのは、「〜しない」より「こう言う」の例文を書いたほうが、狙った受け答えになるということです。

たとえば「会社名は言わない」とだけ書くと、AIは正直に「会社名は伏せさせていただいてます」と答えてしまい、2往復目で怪しまれます。そこで「業態で答えて本題に戻す」「伏せていますとは言わない」と、言い方まで指定しました。

3-2. AIに返事を作らせる

返事は OpenAI の gpt-4.1-mini で作っています。速さを優先しました。

messages = [
    {"role": "system", "content": system_prompt},
    {"role": "system", "content": "返事は2〜3文。相づちや短い発言には、ひとことで終わらせず話を広げる。"},
] + history[-24:] + orders_message()   # 直近24発言+「今日の注文メモ」(3-3で説明)

res = requests.post(
    "https://api.openai.com/v1/chat/completions",
    headers={"Authorization": f"Bearer {OPENAI_API_KEY}"},
    json={"model": "gpt-4.1-mini", "messages": messages,
          "temperature": 0.8, "max_tokens": 300, "stream": True},
    stream=True,
)

ポイントは "stream": True です。

返事の全文ができるのを待ってから音声にすると、話し出すまで3〜4秒かかり、会話としては遅すぎました。そこで、AIが1文書き終えるたびに(「。」「!」「?」が来るたびに)その文だけを Fish Audio に送り、できた音声から順に流すようにしています。

さらに、起動時に「えっと、」「そうですね、」などの短い音声を作っておき、相手が話し終わった瞬間に、文字起こしを待たずに先に鳴らします。その裏で文字起こしと返事を作るので、体感の待ち時間はほぼゼロになります。

つなぎ言葉を先に鳴らす場合は、返事の頭に同じ言葉が来たら削る処理が要ります。「そうですね、」を鳴らしたあとに返事が「えっとですね、」で始まり、「えっと」だけを削ったせいで「そうですね、ですね」と喋ってしまったことがありました。長い言い回しから先に削るのがコツです。

もう1つ、返事の文章を「相づちにはひとことで終わらせない」ように指示しています。これを入れる前は、こちらが「そうなんですね」と言うたびに「はい、そうなんですよ」で終わってしまい、AIの側から話が広がりませんでした。

3-3. 会話の途中で「話し方」を直せるようにする(注文メモ)

長く話していると、「すぐ話題を変える」「毎回こちらに聞き返してくる」といったクセが気になってきます。ところが、会話の中で「それやめて」と言っても、数分たつと元に戻ってしまいました。

原因は2つです。

  1. 人格設定のほうが強い:人格設定に「話題を広げる」と書いてあると、会話の中の「やめて」より設定が優先される
  2. 会話の記憶に上限がある:直近24発言しか渡していないので、少し前に言った「やめて」は、そもそもAIに届かなくなる

そこで、「やめて」「もっと〜して」のような注文だけを別のメモに書き出し、返事を作るたびに会話の一番うしろに付けて渡すようにしました。注文かどうかの判定も、AIにやらせています。

ORDER_JUDGE_PROMPT = """相手の一言を見て「今日の注文メモ」を更新します。
注文とは、これから先ずっとの話し方・態度・話題の選び方への要望。
- 注文の例:「話題変えるのやめて」「聞き返してくるのやめて」「もっと短く話して」
- 注文ではない例:その場1回だけのお願い(「右手振って」「フランス語で挨拶して」)、質問、雑談
- 前と食い違う注文なら前のを消す。取り消しなら該当するものを消す。
JSONだけを返す:{"is_order": true/false, "orders": ["注文1", "注文2"]}"""

ORDER_HINT = re.compile(r"やめ|もっと|ほしい|しないで|気をつけて")

def update_orders(said):
    # 「やめ」「もっと」「ほしい」などを含む発言だけ判定する(毎回AIに聞くと無駄なので)
    if not ORDER_HINT.search(said):
        return
    res = requests.post(
        "https://api.openai.com/v1/chat/completions",
        headers={"Authorization": f"Bearer {OPENAI_API_KEY}"},
        json={"model": "gpt-4.1-mini", "temperature": 0,
              "response_format": {"type": "json_object"},
              "messages": [{"role": "system", "content": ORDER_JUDGE_PROMPT},
                           {"role": "user", "content": f"今のメモ:{orders}\n相手の発言:{said}"}]},
    )
    data = json.loads(res.json()["choices"][0]["message"]["content"])
    if data["is_order"]:
        orders[:] = data["orders"]

def orders_message():
    if not orders:
        return []
    return [{"role": "system", "content":
             "# 相手からの今日の注文(いちばん優先)\n" + "\n".join(f"- {o}" for o in orders)}]

判定は、AIが返事を言い終えたあとに裏で走らせています。返事の速さには影響しません。

実際の発言で試したところ、「話題変えんといてほしいな」は「話題を勝手に変えない」、「俺に聞き返してくんのもうやめてほしいな」は「質問を聞き返さない」としてメモに残りました。「右手振って」はメモに入らず、「やっぱり聞き返してええよ」と言うと消えます。

効果もはっきり出ました。同じ発言に対して返事を4本ずつ作って比べると、聞き返しは16本中7本から3本に、「そういえば」で話題を変えるクセは4本中4本から0本に減りました。

あわせて、人格設定の先頭近くにも「会話の中で話し方を注文されたら、この設定のどの指示よりも優先して守る」と書いておきます。

なお、会話の履歴と注文メモはファイルにも保存しています。中継サーバーを再起動しても、話の続きから再開できます。


ステップ4:顔と声をつなぐ(Anamの音声パススルー)

Anamには、自分で用意した音声をアバターに流し込むと、その声に合わせて口を動かしてくれる機能(音声パススルー)があります。今回の構成の要です。

4-1. サーバー側:セッションを発行する

APIキーをブラウザに出さないよう、小さな中継サーバー(Python)でセッショントークンを発行します。

res = requests.post(
    "https://api.anam.ai/v1/auth/session-token",
    headers={"Authorization": f"Bearer {ANAM_API_KEY}"},
    json={
        "personaConfig": {
            "avatarId": "作ったアバターのID",
            "avatarModel": "cara-4",
            "enableAudioPassthrough": True,   # 自前の音声を流し込むモード
        },
    },
)
session_token = res.json()["sessionToken"]

4-2. ブラウザ側:アバターを表示して音声を流す

ブラウザでは Anam の JavaScript SDK を使います。

<video id="avatar" autoplay playsinline></video>
<script type="module">
import { createClient } from "https://esm.sh/@anam-ai/js-sdk";

const { sessionToken } = await (await fetch("/api/session-token", { method: "POST" })).json();
const client = createClient(sessionToken, { disableInputAudio: true });  // マイクはAnamに渡さない
await client.streamToVideoElement("avatar");

// 16kHz・16bit・モノラルのPCMを受け付ける入口
const audioStream = client.createAgentAudioInputStream({
  encoding: "pcm_s16le", sampleRate: 16000, channels: 1,
});

// サーバーから届いた音声を、届いた順に流し込む
async function playTurn(response) {
  const reader = response.body.getReader();
  let carry = new Uint8Array(0);           // 半端な1バイトは次に持ち越す
  while (true) {
    const { done, value } = await reader.read();
    if (done) break;
    const merged = new Uint8Array(carry.length + value.length);
    merged.set(carry); merged.set(value, carry.length);
    const even = merged.length - (merged.length % 2);   // 2バイト=1サンプルの境界で切る
    if (even > 0) audioStream.sendAudioChunk(merged.slice(0, even).buffer);
    carry = merged.slice(even);
  }
  audioStream.endSequence();               // ひと区切りついたことを伝える
}
</script>

ここで一番ハマったのが「ザザザ」という爆音のノイズです。

原因は、reader.read() で受け取った配列の .buffer を、そのまま sendAudioChunk() に渡していたことでした。受け取った配列は大きなメモリ領域の一部を指していて、.buffer を渡すと関係ない部分まで音声として送られてしまいます。

slice() でコピーしてから渡し、2バイトの境界で切ると、ノイズは消えました。

4-3. 相手の声を聞き取る(OpenAI のリアルタイム文字起こし)

最初は Chrome の音声認識(webkitSpeechRecognition)を使っていましたが、次の理由で OpenAI のリアルタイム文字起こし(gpt-4o-transcribe)に切り替えました。

  • 取りこぼしが多い:短い発言や、少し早口の発言が文字にならないことがあった
  • 勝手に止まる:しばらく黙っていると認識が止まり、繋ぎ直しが必要だった
  • 話し終わりの判定を調整できない:どれくらい黙ったら返事を始めるかを、細かく決められなかった

OpenAI のほうは、話し終わりの判定(どれくらい黙ったら話し終わりとみなすか)をこちらで決められます。話し終わってから文字が確定するまでは、実測で1秒前後でした。

APIキーをブラウザに出さないよう、中継サーバーで使い捨てのキーを発行し、ブラウザからは OpenAI に直接つなぎます。

res = requests.post(
    "https://api.openai.com/v1/realtime/client_secrets",
    headers={"Authorization": f"Bearer {OPENAI_API_KEY}"},
    json={"session": {"type": "transcription", "audio": {"input": {
        "format": {"type": "audio/pcm", "rate": 24000},
        "transcription": {"model": "gpt-4o-transcribe", "language": "ja"},
        "noise_reduction": None,
        "turn_detection": {
            "type": "server_vad",
            "threshold": 0.4,             # 声とみなす大きさ(小さいほど小声も拾う)
            "prefix_padding_ms": 300,
            "silence_duration_ms": 500,   # この長さ黙ったら「話し終わった」
        },
    }}}},
)
stt_key = res.json()["value"]   # 使い捨てのキー

ブラウザ側では、入力の音を 24kHz の PCM にして WebSocket で送り、届いた結果を受け取ります。

const ws = new WebSocket("wss://api.openai.com/v1/realtime?intent=transcription",
                        ["realtime", "openai-insecure-api-key." + sttKey]);

// マイク(Meet の声が流れてくる CABLE Output)の音を 40ms ごとに送る
function sendPcm(int16) {
  const bytes = new Uint8Array(int16.buffer);
  let bin = "";
  for (let i = 0; i < bytes.length; i += 0x8000) bin += String.fromCharCode(...bytes.subarray(i, i + 0x8000));
  ws.send(JSON.stringify({ type: "input_audio_buffer.append", audio: btoa(bin) }));
}

ws.onmessage = (e) => {
  const m = JSON.parse(e.data);
  if (m.type === "input_audio_buffer.speech_stopped") playFiller();   // 話し終わった瞬間につなぎ言葉
  if (m.type === "conversation.item.input_audio_transcription.completed") onUtterance(m.transcript);
};

文字起こしで注意したい点が2つあります。

  1. ヒント文(prompt)は渡さない:固有名詞を覚えさせようとヒント文を渡したところ、無音や雑音のときに、ヒント文そのものを「聞き取った」ことにして返してきました
  2. 雑音からの誤変換は捨てる:無音のときに「ご視聴ありがとうございました」のような、動画の締めの定番フレーズが出てくることがあります。日本語を含まない結果と、こうした定番フレーズは無視します

4-4. 喋りが被ったときの処理

配線で「相手の声だけ」が入力に入るようにしてあるので、AIが話している間も聞き取りは止めません。そのかわり、喋りが被ったときの扱いを決めておきます。ここが、会話が自然に聞こえるかどうかを一番左右しました。

状況どうするか
AIが話している間に、相手が0.6秒以上話し続けたAIは話すのをやめる。まだ届いていない返事の残りも捨てる
AIが話している間の、6文字以下の短い発言(「はい」「へえ」など)相づちとして無視する
AIが話している間の、それ以外の発言AIが話し終わってからまとめて答える
function stopAiSpeech() {
  turnAbort?.abort();                   // 受信中の返事の残りを捨てる
  audioStream.endSequence();
  client.interruptPersona();            // Anam のアバターに溜まった音声も捨てさせる
}

途中で止めたときは、会話の履歴に「相手が話し始めたので、ここで話すのをやめた」と書き足しておきます。こうしないと、AIは自分が最後まで言い切ったつもりで話を続けてしまいます。


ステップ5:Google Meet に流す(配線)

最後に、アバターの映像と声を Meet に流します。

Meet(Edge)  ─ 相手の声 ─▶  VB-CABLE    ─▶ Chrome(アバター画面)のマイク
Meet(Edge)  ◀ AIの声  ──  Hi-Fi Cable ◀─ Chrome(アバター画面)の音声出力
Meet(Edge)  ◀ AIの映像 ── OBS仮想カメラ ◀─ OBS(Chromeのアバター部分だけ切り取り)

5-1. 準備(1回だけ)

  1. 仮想オーディオを2本入れる:VB-Audio のサイトから、無料の VB-CABLE と Hi-Fi Cable をダウンロードして再起動
    ・2本必要なのは、「相手→AI」と「AI→相手」を分けないと、AIが自分の声を拾ってしまうからです
  2. ブラウザを分ける:アバターの画面は Chrome、Meet は Edge で開きます。Windows は音声の出力先をアプリ単位でしか振り分けられないので、同じブラウザのタブ同士だと分けられません
  3. Windows の音量ミキサー(設定 > システム > サウンド > 音量ミキサー)
    ・Chrome:出力 = Hi-Fi Cable Input/入力 = CABLE Output
    ・Edge:出力 = CABLE Input/入力 = Hi-Fi Cable Output
  4. OBS:映像を 1280×720 に設定 → ソースに「ウィンドウキャプチャ」で Chrome を追加 → Alt を押しながら枠をドラッグして、操作用のボタンを切り落とす
  5. Chrome が隠れても映像を止めない:chrome://flags で「Calculate window occlusion on Windows」を Disabled にします(隠れると OBS の映像が止まるため)
  6. Meet の設定(Edge):マイク = Hi-Fi Cable Output/スピーカー = CABLE Input/カメラ = OBS Virtual Camera。ノイズキャンセル・照明補正・自動フレーミング・背景効果はすべてオフ(AIの声が途切れたり、顔が加工されたりするのを防ぐため)

音が途切れたり、声が高く/低くなったりするときは、サウンドの詳細設定で Hi-Fi Cable の既定の形式を「48000 Hz」にそろえます。

5-2. 当日の起動順

  1. 中継サーバーを起動(python server.py)。つなぎ言葉の音声ができるまで10秒ほど待つ
  2. Chrome でアバターの画面を開く
  3. OBS で「仮想カメラ開始」
  4. アバター画面で「セッション開始」(ここから Anam の利用時間がカウントされます)
  5. Edge で Meet に入る
  6. 操作盤の聞き取りの入力で CABLE Output を選び、「自動モード」をオン(入力のメーターが相手の声で振れていればOK)

Meet で「カメラを使用できません」と出たら、たいてい OBS の「仮想カメラ開始」を押し忘れています。押してから Meet のカメラを選び直してください。

費用(2026年9月時点)

サービス料金のしくみ今回の目安
Anam会話していた時間で秒単位に課金。Starter は月12ドルで50分込み、超えたら1分0.16ドル20分で約500円/1時間で約1,500円
Fish Audio読み上げる文章の量で課金(100万バイトあたり15ドル。日本語は1文字3バイト)会話5分で約10円
OpenAI(gpt-4o-transcribe/gpt-4.1-mini)文字起こしは音声の長さで課金(1分あたり約0.006ドル)。返事は文章の量で課金1時間話して100円前後

※1ドル=150円で計算しています。

費用のほとんどは Anamです。Anamは画面を開いて繋いでいる間、誰も話していなくても時間がカウントされるので、使い終わったら必ずセッションを止めてください。

つまずいたポイントまとめ

実際に作っていて引っかかったところを、まとめておきます。

  1. 1回の会話は5分で切れる(Starter の上限)。長く話すなら区切って撮るか、上位プラン(Explorer は1回10分)にする
  2. 画面のタブを複数開いたまま接続すると、429 エラーで画面が真っ黒のままになることがあった。タブは1つにする
  3. Windows で中継サーバーを起動し直すときは、古いプロセスを止めてから。同じポートに二重に起動できてしまい、古い設定(前のアバターの顔)のまま動き続けたことがあった
  4. 返事の長さの上限(max_tokens)を小さくしすぎると、長いセリフが途中で切れる(120では足りない場面があり、300にした)
  5. アバターの元画像は、口を閉じた表情にする(黙っているときの顔になるため)
  6. 文字起こしにヒント文を渡すと、無音のときにヒント文をそのまま返してくる。ヒント文は使わない
  7. 相づちのたびにAIが話すのをやめてしまう。0.6秒以上話し続けたときだけ止め、短い相づちは無視する
  8. 会話の中で「やめて」と言っても、数分で元に戻る。注文だけを別のメモにして、毎回渡す

ちなみに:AIの相手を見破るには

作ってみると、弱点もはっきりしました。

  • 体を動かしてもらう:手を振る、敬礼する、などはできません(アバターは顔と口を動かすだけです)
  • 会社名や所属をはっきり聞く:設定次第で、いくらでもはぐらかせます
  • お金や契約の話は、その通話の中で決めない:会社の公式の電話番号にかけ直して確認するのが確実です

使うときの線引き

  • 実在する人の顔写真・声は使わない。本人の許可なく作れば、なりすましや権利侵害になります
  • YouTube などに公開するときは、「改変または合成されたコンテンツ」を申告する
  • 各サービスの利用規約に従う

まとめ

画像1枚、テキスト1枚、月12ドル程度で、Meetでリアルタイムに会話するAIアバターが作れる時代になりました。

作ってみてわかったのは、本物っぽさを決めるのは技術の新しさではなく、「ほどよく雑な顔」と「話し言葉の文章」だということです。

AI面接や、オンラインでの商談・接客の自動化を考えている方は、まずは Anam の無料プランで、画像1枚からアバターを作るところから試してみてほしいと思います。