Cloudflare Workers AI 使ってみた「音声認識編」
CloudflareのAI APIでWhisperモデルを使った音声認識アプリの構築
こんにちは、ikechan こといけがわです。
Cloudflare Workers AIの新しいモデルを試す連載、今回は音声認識モデル Whisper を使ってみました。WhisperはOpenAIが開発した高精度な音声認識モデルで、多言語対応の音声からテキストへの変換(Speech-to-Text)を実現します。
今回はmacOSのターミナルからリアルタイムで音声を録音し、Whisperモデルでテキスト変換する実験的なアプリケーションを構築してみました。
前提条件
この記事を進めるにあたり、以下の準備が必要です。
-
Cloudflare アカウント
Workers AI の利用に必須。Whisperモデルが有効になっているか確認してください。 -
Node.js / Bun 開発環境
今回はHonoフレームワークとBunを使用してサーバーを構築します。 -
macOS 環境
sox
(Sound eXchange)ツールを使用するので、Homebrewでインストールが必要です。
実装手順
1. 環境のセットアップ
まず、Honoプロジェクトを作成し、必要なパッケージをインストールします。
bun create hono@latest voice-recognition-app
cd voice-recognition-app
bun add sox # 音声録音用のパッケージ
macOSでは以下のコマンドで録音に必要なツールをインストールします。
brew install sox
2. APIリクエスト用のユーティリティ
まず、Cloudflare Workers AIへのリクエストを処理するコードを実装します。usecase.ts
ファイルを作成しましょう。
import { config } from "./constant";
import type {
ApiRequestParams,
AudioTranscriptionResult,
} from "./types";
export const makeApiRequest = async ({
endpoint,
data,
contentType,
}: ApiRequestParams): Promise<Response> => {
console.log("url", `${config.url}${endpoint}`);
const response = await fetch(`${config.url}${endpoint}`, {
method: "POST",
headers: {
Authorization: `Bearer ${config.key}`,
"Content-Type": contentType,
},
body: data,
});
if (!response.ok) {
const errorText = await response.text();
throw new Error(
`API Error: ${response.status} ${response.statusText} - ${errorText}`
);
}
return response;
};
// 音声認識用の関数
export const transcribeAudio = async (audioData: Uint8Array): Promise<any> => {
try {
console.log("Whisperモデルにリクエスト送信中...");
console.log(`送信データサイズ: ${audioData.length} バイト`);
const response = await makeApiRequest({
endpoint: "/@cf/openai/whisper",
data: audioData,
contentType: "audio/wav",
});
console.log("APIステータスコード:", response.status);
return response.json();
} catch (error) {
console.error("API呼び出しエラー:", error);
throw error;
}
};
3. 設定ファイルの作成
constant.ts
ファイルにCloudflare APIの設定を記述します。
export const config = {
url: "https://api.cloudflare.com/client/v4/accounts/あなたのアカウントID/ai/run",
key: "あなたのAPIキー"
};
4. 音声録音とWhisperモデルの実行
record.ts
ファイルに、ターミナルからの音声録音とWhisperモデルでの認識を行うコードを実装します。
import { transcribeAudio } from "./usecase";
import fs from "fs";
import path from "path";
import { spawn } from "child_process";
// 録音用の一時ファイルパス
const TEMP_WAV_FILE = path.join(process.cwd(), "temp_recording.wav");
// macOSでの録音処理(soxを使用)
async function recordAudioWithSox(durationSeconds: number): Promise<Uint8Array> {
console.log(`マイクから録音を開始します (${durationSeconds}秒間)...`);
// 既存の録音ファイルを削除
if (fs.existsSync(TEMP_WAV_FILE)) {
fs.unlinkSync(TEMP_WAV_FILE);
}
// soxのrecコマンドで録音を実行
return new Promise((resolve, reject) => {
const rec = spawn("rec", [
"-q", // 静かモード
TEMP_WAV_FILE, // 出力ファイル
"rate", "16k", // サンプルレート16kHz
"channels", "1", // モノラル
"trim", "0", `${durationSeconds}` // 録音時間
]);
rec.on("close", (code) => {
if (code !== 0) {
reject(new Error(`録音プロセスが異常終了しました (code: ${code})`));
return;
}
try {
// 録音ファイルを読み込み
const audioData = fs.readFileSync(TEMP_WAV_FILE);
resolve(new Uint8Array(audioData));
} catch (error) {
reject(error);
}
});
rec.stderr.on("data", (data) => {
console.error(`録音エラー: ${data}`);
});
});
}
// メイン処理
async function main() {
console.log("Cloudflare Whisper音声認識ツール");
console.log("================================");
console.log(
"マイクから音声を録音し、Whisperモデルを使って文字起こしを行います。"
);
while (true) {
try {
// 5秒間録音
const audioData = await recordAudioWithSox(5);
console.log("録音完了! 文字起こし処理中...");
// Whisperモデルで文字起こし
const response = await transcribeAudio(audioData);
console.log("\n--- 文字起こし結果 ---");
if (response && response.result && response.result.text) {
console.log(response.result.text);
if (response.result.word_count) {
console.log(`単語数: ${response.result.word_count}`);
}
} else {
console.log("結果が取得できませんでした。");
}
} catch (error) {
console.error("エラーが発生しました:", error);
}
console.log(
"\n続けるには Enter キーを押してください。終了するには Ctrl+C を押してください。"
);
await new Promise((resolve) => {
process.stdin.once("data", () => resolve(null));
});
}
}
// スクリプトが直接実行された場合のみ実行
if (require.main === module) {
main().catch(console.error);
}
export { recordAudioWithSox, transcribeAudio };
5. APIエンドポイントの実装
WebサーバーAPIからWhisperモデルを利用できるように、index.ts
ファイルにエンドポイントを追加します。
import { Hono } from "hono";
import { transcribeAudio } from "./usecase";
const app = new Hono();
// 音声認識エンドポイント
app.post("/transcribe", async (c) => {
try {
const audioBuffer = await c.req.arrayBuffer();
if (!audioBuffer || audioBuffer.byteLength === 0) {
return c.json({ success: false, error: "Audio data is required" }, 400);
}
const audioData = new Uint8Array(audioBuffer);
const result = await transcribeAudio(audioData);
return c.json({ success: true, result });
} catch (error) {
return c.json(
{
success: false,
error: error instanceof Error ? error.message : "Unknown error occurred"
},
400
);
}
});
Bun.serve({
fetch: app.fetch,
port: 8080
});
export default app;
動作確認
1. ターミナルからの音声認識
ターミナルからCLIモードでWhisperモデルを使って音声認識を行う場合は、以下のコマンドを実行します。
bun run record.ts
これを実行すると、5秒間の録音が始まり、録音終了後にWhisperモデルによる認識結果が表示されます。
2. APIを使った音声認識
サーバーを起動して、WebAPIとして音声認識を提供する場合は以下のコマンドを実行します。
bun run index.ts
その後、別のターミナルから以下のようにcurlコマンドで音声ファイルを送信することでAPIを利用できます。
curl -X POST http://localhost:8080/transcribe \
--data-binary @path/to/your/audiofile.wav \
-H "Content-Type: audio/wav"
実行結果
実際に「おはようございます」と言ってみた時の認識結果です:
マイクから録音を開始します (5秒間)...
録音完了! 文字起こし処理中...
Whisperモデルにリクエスト送信中...
送信データサイズ: 320080 バイト
APIステータスコード: 200
--- 文字起こし結果 ---
おはようございます
単語数: 4
一度録音した後、Enterキーを押すとまた録音が始まるので、様々な言葉で試してみることができます。日本語だけでなく、英語や他の言語でも認識可能です。
まとめ
今回はCloudflare Workers AIのWhisperモデルを使って、MacOSターミナルからリアルタイムで音声認識を行うアプリケーションを実装しました。
Whisperモデルは多言語対応の高精度な音声認識を提供し、APIを通じて簡単に利用できるため、様々な音声処理アプリケーションに組み込むことができます。
Cloudflare Workers AIは、このようなAI機能をサーバーレス環境で簡単に利用できる強力なツールであり、様々なシーンで活用できます。今後も他のモデルを試していきたいと思います。
お知らせ
toraco株式会社では、エンジニア向けコミュニティを 2024年11月1日 より開始しました。
Discord サーバーでは、
- もくもく会・作業ラジオ・雑談部屋
- オフラインイベントの案内
- 副業や案件の紹介
- フロントエンド・生成AI技術の情報共有
など、さまざまな活動を行っています!
ぜひ、こちらからご参加ください。
Discussion