AI活用

OpenAI文字起こしAPIの使い方|JavaScriptで音声ファイルをテキスト化する

OpenAIのTranscriptions APIをNode.jsから呼び、音声を日本語テキストへ変換する最小コード、話者分離、長時間音声、再現テストを解説します。

この記事の目次
  1. 結論:ファイルAPIとRealtimeを用途で分ける
  2. Node.jsプロジェクトを準備する
  3. 音声ファイルを文字起こしする
  4. 日本語の結果を整形する
  5. 話者分離を使う
  6. 長い音声を分割する
  7. 日本語音声の再現テスト
  8. プライバシーと運用の注意
  9. まとめ

OpenAIの文字起こしAPIは、Node.jsから音声ファイルを送信し、テキストを受け取れます。公式SDKの audio.transcriptions.create() へファイルとモデルを渡すのが最小構成です。

会議やインタビューで使う場合は、文字起こしだけでなく、録音同意、話者、タイムスタンプ、固有名詞、長時間ファイル、保存方針まで設計します。

この記事では、ファイル文字起こしの最小コード、日本語の整形、話者分離、長い音声の分割、期待値と差分を残す再現テストを解説します。

情報確認日:2026年7月17日(日本時間)

結論:ファイルAPIとRealtimeを用途で分ける

方式 向く用途 特徴
Transcriptions API 録音済みファイル、議事録、字幕 ファイル単位で実装しやすい
Realtime transcription 通話中の字幕、ライブ入力 音声streamとイベント処理が必要

最初は録音済みの短いファイルでTranscriptions APIを試し、認証、形式、モデル、出力を確認します。

スポンサーリンク

Node.jsプロジェクトを準備する

mkdir openai-transcription-sample
cd openai-transcription-sample
npm init -y
npm pkg set type=module
npm pkg set scripts.start="node transcribe.mjs"
npm install openai
export OPENAI_API_KEY="your_api_key_here"
node_modules/
audio/
transcripts/
.env
.env.*
!.env.example

音声には個人情報が含まれやすいため、サンプル音声や文字起こし結果をGitへ含めるかは用途に合わせて決めます。APIキーはブラウザへ置かず、サーバー側の環境変数から読み取ります。

音声ファイルを文字起こしする

transcribe.mjsを作ります。

import fs from "node:fs";
import OpenAI from "openai";

if (!process.env.OPENAI_API_KEY) {
  throw new Error("OPENAI_API_KEY is not set");
}

const filePath = process.argv[2];
if (!filePath || !fs.existsSync(filePath)) {
  throw new Error("Usage: npm start -- path/to/audio.mp3");
}

const client = new OpenAI();
const model =
  process.env.OPENAI_TRANSCRIBE_MODEL || "gpt-4o-transcribe";

const transcription = await client.audio.transcriptions.create({
  file: fs.createReadStream(filePath),
  model,
  language: "ja",
});

console.log(transcription.text);
npm start -- audio/sample.mp3

API Referenceで案内される対応形式にはflac、mp3、mp4、mpeg、mpga、m4a、ogg、wav、webmがあります。制限やモデル対応は更新されるため、大きなファイルを送る前に現行ガイドを確認してください。

日本語の結果を整形する

文字起こしと、議事録用の整形・要約は分けます。まず原文に近いtranscriptを保存し、別処理で句読点、改行、用語置換、要約を行います。

function normalizeJapanese(text) {
  return text
    .normalize("NFKC")
    .replace(/[ \t]+/g, " ")
    .replace(/\s*\n\s*/g, "\n")
    .trim();
}

console.log(normalizeJapanese(transcription.text));

固有名詞を機械置換する場合は、元のtranscriptを残し、置換一覧と理由を記録します。要約だけを保存すると、後から誤変換を確認できません。

話者分離を使う

複数話者を区別したい場合は、確認時点で gpt-4o-transcribe-diarize が話者分離用モデルとしてAPI Referenceに掲載されています。通常のtext応答ではなく、話者と区間を持つ出力を処理します。

自動話者ラベルを実名とみなさず、Speaker 0、Speaker 1と時刻を確認してから、人が氏名を対応付けます。似た声、重なり、雑音で誤る可能性があります。

確認 理由
話者の切替時刻 発話の重なりで境界がずれる
氏名の割当 モデルのラベルは本人確認ではない
短い相づち 別話者へ誤割当されやすい
重要発言 決定事項は音声を聞き直す

長い音声を分割する

長時間音声は、単純に同じ秒数で切ると単語や文の途中で分かれます。無音区間を候補にし、少し重複させて分割し、開始時刻をメタデータとして持ちます。

音声
├─ chunk-001 00:00:00〜00:10:05
├─ chunk-002 00:09:55〜00:20:02
└─ chunk-003 00:19:52〜00:28:40

重複10秒を照合し、同じ文を1回だけ残す。
  1. 無音検出で分割候補を作る
  2. 各chunkへ元音声の開始時刻を付ける
  3. 前後を数秒重ねる
  4. 並列数とrate limitを守って送信する
  5. 重複部分を文字列と時刻で照合する
  6. 結合後に重要箇所を音声と突き合わせる

日本語音声の再現テスト

次の文を自分の声で録音し、audio/fixture-ja.wavとして保存します。第三者の音声は同意なく使わないでください。

本日の会議では、公開日を7月24日に変更しました。
担当は佐藤さんで、確認期限は7月21日です。
項目 記録
期待値 上記2文。日付、氏名、担当関係が必須
入力 fixture-ja.wav、1話者、静かな室内
モデル OPENAI_TRANSCRIBE_MODELの値
実行結果 制作時はAPIキー未使用のため未取得。実行者が保存
合格 24日、佐藤、21日が正しく、意味が変わらない

compare.mjsで正規化後の差を確認します。

import fs from "node:fs";

const expected = fs.readFileSync("expected.txt", "utf8");
const actual = fs.readFileSync("actual.txt", "utf8");

const normalize = (text) =>
  text.normalize("NFKC").replace(/[\s、。,.]/g, "");

console.log({
  exactAfterNormalize:
    normalize(expected) === normalize(actual),
  requiredTerms: ["24日", "佐藤", "21日"].map((term) => ({
    term,
    found: actual.includes(term),
  })),
});

完全一致だけでなく、日付、氏名、否定、数量など、業務上重要な語を個別に採点します。モデル変更時に同じ音声で再実行します。

プライバシーと運用の注意

  • 録音対象者へ目的、保存、共有範囲を説明する
  • アップロード前に不要な個人情報を除く
  • 音声、原文、整形版、要約の保存期間を分ける
  • APIのデータ利用・保持設定を現行文書で確認する
  • 重要な決定事項は音声と人が照合する
  • 誤変換の訂正履歴を残す

会議全体の録音から要約・確認までの運用はAI議事録の作り方も参考になります。

まとめ

OpenAI文字起こしAPIは、公式SDKの audio.transcriptions.create() へ音声fileとmodelを渡して利用します。まず短い日本語fixtureで、固有名詞・日付・否定を含む期待値と差分を記録します。

長い音声は無音区間と重複を使って分割し、話者分離や要約を別工程にしてください。録音同意、権限、保存、訂正も実装の一部です。

スポンサーリンク