Node.js と Claude API を使って音声起動の AI アシスタントを構築する

Dev.to / 2026/4/16

💬 オピニオンDeveloper Stack & InfrastructureTools & Practical Usage

要点

  • ブラウザ側の Web Speech API と Node.js/Express のバックエンドを組み合わせて、音声起動の AI アシスタントを構築する手順を解説する。
  • SimplyLouie の開発者 API(平価で月額 $10 として掲載)を使って Claude による音声の解釈と、文脈を踏まえた応答の生成を行う。
  • 会話の文脈(コンテキスト)はインメモリの履歴で管理し、永続化とスケーラビリティのために Redis にアップグレードできる旨を記載している。
  • 実装は段階的に示され、フロントエンドで音声入力を取得して文字起こしした後、その内容をバックエンドに送って AI 処理を行うところから始まる。
  • 全体として、手軽に利用できる Web コンポーネントと API コンポーネントを用いた、低コストで文脈対応の音声エージェントのための実用的な参照アーキテクチャを提供する。

Node.js と Claude API で音声起動型 AI アシスタントを作る

面白いものを作りたくなりました。つまり、実際に文脈を理解し、会話の中であなたが先に話した内容を覚えていて、動かすのにかかる費用が月にコーヒー 1 杯未満の音声アシスタントです。

こちらは、SimplyLouie 経由で Claude API にアクセスし、Web Speech API + Node.js を使って作った手順です。

スタック

  • フロントエンド:バニラ JS + Web Speech API(Chrome/Edge に組み込み — ライブラリ不要)
  • バックエンド:Node.js Express
  • AI:SimplyLouie の開発者 API 経由の Claude(毎月定額 $10)
  • ストレージ:メモリ上の会話履歴(Redis にアップグレード可能)

手順 1:フロントエンド — 音声入力をキャプチャする

<!DOCTYPE html>
<html>
<head>
  <title>Voice AI</title>
</head>
<body>
  <button id="startBtn"> 押して話す</button>
  <div id="transcript"></div>
  <div id="response"></div>

  <script>
    const btn = document.getElementById('startBtn');
    const transcriptEl = document.getElementById('transcript');
    const responseEl = document.getElementById('response');

    const recognition = new webkitSpeechRecognition();
    recognition.continuous = false;
    recognition.interimResults = false;
    recognition.lang = 'en-US';

    btn.addEventListener('mousedown', () => recognition.start());
    btn.addEventListener('mouseup', () => recognition.stop());

    recognition.onresult = async (event) => {
      const transcript = event.results[0][0].transcript;
      transcriptEl.textContent = `あなたはこう言いました: ${transcript}`;

      const reply = await fetch('/api/chat', {
        method: 'POST',
        headers: { 'Content-Type': 'application/json' },
        body: JSON.stringify({ message: transcript })
      }).then(r => r.json());

      responseEl.textContent = `AI: ${reply.response}`;

      // 応答を読み上げる
      const utterance = new SpeechSynthesisUtterance(reply.response);
      window.speechSynthesis.speak(utterance);
    };
  </script>
</body>
</html>

手順 2:バックエンド — 会話のコンテキストを扱う

const express = require('express');
const app = express();
app.use(express.json());

// シンプルなインメモリの会話ストア(セッションをキーにする)
const conversations = new Map();

app.post('/api/chat', async (req, res) => {
  const sessionId = req.headers['x-session-id'] || 'default';
  const { message } = req.body;

  // 会話履歴を取得するか新しく作成する
  if (!conversations.has(sessionId)) {
    conversations.set(sessionId, []);
  }
  const history = conversations.get(sessionId);

  // ユーザーのメッセージを追加
  history.push({ role: 'user', content: message });

  // コンテキストの制限内に収めるため、直近の10往復分を保持
  const recentHistory = history.slice(-20);

  try {
    const response = await fetch('https://simplylouie.com/api/chat', {
      method: 'POST',
      headers: {
        'Content-Type': 'application/json',
        'Authorization': `Bearer ${process.env.LOUIE_API_KEY}`
      },
      body: JSON.stringify({
        messages: recentHistory,
        system: 'あなたは有能な音声アシスタントです。返答は簡潔にしてください。読み上げられるため、可能な限り2文以内に収めてください。'
      })
    });

    const data = await response.json();
    const aiReply = data.response || data.content;

    // アシスタントの応答を保存する
    history.push({ role: 'assistant', content: aiReply });

    res.json({ response: aiReply });
  } catch (err) {
    res.status(500).json({ error: 'AI unavailable' });
  }
});

app.listen(3000, () => console.log('Voice AI running on :3000'));

ステップ3:会話を覚えるためのセッショントラッキングを追加する

フロントエンドは一貫したセッションIDを送る必要があります:

// フロントエンドに追加 — ページ読み込みごとに1回生成
const sessionId = Math.random().toString(36).substr(2, 9);

// fetch呼び出しを更新:
const reply = await fetch('/api/chat', {
  method: 'POST',
  headers: {
    'Content-Type': 'application/json',
    'x-session-id': sessionId  // <-- これを追加
  },
  body: JSON.stringify({ message: transcript })
}).then(r => r.json());

これで、セッション中にあなたが以前話した内容を覚えています。

できること

一度動き始めると:

You: "What's the capital of France?"
AI: "Paris."

You: "What's the population there?"
AI: "Paris has about 2.1 million people in the city proper."

2つ目の質問がうまく機能していることに注目してください。「there」は会話履歴のおかげでパリを指していると理解します。

コスト計算

私はこれを、音声インタラクション約200回で1週間動かしました:

  • Claude API(SimplyLouie経由):$10/月の定額(開発者ティア)
  • ホスティング(Railway):$5/月
  • Web Speech API:free(ブラウザ内蔵)
  • 合計:$15/月

比較すると、OpenAIのWhisperで音声→テキスト化+GPT-4 APIでこの仕組みを作る場合、同じ量だと月$40〜60になります。

任意:ウェイクワード検出を追加する

常に聞きっぱなしにしたい場合(Alexaのように):

// 認識を継続的に再起動
recognition.onend = () => {
  if (isListening) recognition.start();
};

recognition.onresult = async (event) => {
  const transcript = event.results[0][0].transcript.toLowerCase();

  // ウェイクワードが検出された場合のみ応答
  if (!transcript.includes('hey louie')) return;

  const actualMessage = transcript.replace('hey louie', '').trim();
  // ... ハンドラの残り
};

let isListening = true;
recognition.start();

始める

これを動かす開発者API: simplylouie.com/developers

$10/月の定額。トークン課金による想定外の請求はありません。APIを叩けば、それが動きます。

このプロジェクトの完全なリポジトリはコメント欄にあります — そこで質問してもらっても大丈夫です。