音声の文字起こしと音声生成
AIモデルを使用して音声ファイルをテキストに文字起こしし、テキストから読み上げ音声を生成します。
AI Audio を使う理由
アプリケーションで音声を扱う必要があることがあります。要約したい会議の録音、検索したいボイスメモ、あるいは読み上げたい文章の回答などです。これをゼロから構築する場合、音声プロバイダーとの直接連携、APIキー管理、ファイルアップロード処理、フォーマット変換コードの実装が必要になります。
Squid AI Audio は、文字起こし(transcription)とテキスト読み上げ(text-to-speech)の両方を、単一のバックエンド呼び出しで提供します。
- TypeScript
- Python
// 音声ファイルをテキストに文字起こし
const text = await this.squid.ai().audio().transcribe(audioFile, {
modelName: 'whisper-1',
});
// テキストから音声を生成
const speechFile = await this.squid.ai().audio().createSpeech('Welcome to Squid', {
modelName: 'tts-1',
voice: 'nova',
});
# 音声ファイルをテキストに文字起こし
text = await self.squid.ai().audio().transcribe(
audio_bytes,
'recording.mp3',
'audio/mpeg',
options={'modelName': 'whisper-1'},
)
# テキストから音声を生成
speech_bytes = await self.squid.ai().audio().create_speech(
'Welcome to Squid',
{'modelName': 'tts-1', 'voice': 'nova'},
)
概要
Squid AI Audio は、OpenAI の Whisper(speech-to-text)および TTS(text-to-speech)モデルを単一の API の背後でラップします。バックエンドからメソッドを呼び出すだけで、Squid が認証、ファイルアップロード、フォーマット変換、レスポンスのデコードを処理します。
AI Audio を使うべきとき
| ユースケース | 推奨 |
|---|---|
| 話し言葉の音声を検索可能なテキストに変換する | transcribe() |
| 合成音声でテキストを読み上げる | createSpeech() |
| AI agent のチャット体験に音声入力を組み込む | AI chat widget で enable-transcription フラグを使用 |
| AI agent 用のカスタム音声 | voice options 付き agents を使用 |
仕組み
- バックエンドサービスから
this.squid.ai().audio().transcribe()または.createSpeech()を呼び出します - Squid バックエンドがリクエストを認証し、アプリケーション設定から OpenAI API key を参照して呼び出しを転送します
- 文字起こしでは、音声ファイルがモデルにストリーミングされ、文字起こし結果がテキストとして返ります
- 音声生成では、モデルがバイナリ音声を返し、Squid がそれを
Fileオブジェクト(TypeScript)またはbytes(Python)にラップします
クイックスタート
前提条件
squid initで初期化された Squid backend プロジェクト@squidcloud/backendパッケージ(TypeScript)またはsquidcloud-backendパッケージ(Python)- Squid Console で、アプリケーションの AI provider として OpenAI が設定済みであること
ステップ 1: 音声呼び出しをラップする executable を作成する
音声操作には Squid リソースに対する admin アクセスが必要なため、バックエンドで実行する必要があります。クライアントが安全に呼び出せるように、executable にラップしてください。
- TypeScript
- Python
import { executable, SquidFile, SquidService } from '@squidcloud/backend';
export class AudioService extends SquidService {
@executable()
async transcribeAudio(audio: SquidFile): Promise<string> {
this.assertIsAuthenticated();
// SquidFile には、クライアントからの元のファイル名と MIME type が含まれます。
// audio client が OpenAI にストリーミングできるよう、ネイティブの File に変換します。
const file = new File([audio.data], audio.originalName, { type: audio.mimetype });
return this.squid.ai().audio().transcribe(file, {
modelName: 'whisper-1',
});
}
}
from squidcloud_backend import SquidFile, SquidService, executable
class AudioService(SquidService):
@executable()
async def transcribe_audio(self, audio: SquidFile) -> str:
self.assert_is_authenticated()
# SquidFile は、ファイル bytes とメタデータを持つ TypedDict です。
return await self.squid.ai().audio().transcribe(
audio['data'],
audio['originalName'],
audio['mimetype'],
options={'modelName': 'whisper-1'},
)
ステップ 2: バックエンドをデプロイする、またはローカルで実行する
squid start
クラウドにデプロイする場合は、deploying your backend を参照してください。
ステップ 3: クライアントから executable を呼び出す
const fileInput = document.querySelector('input[type="file"]') as HTMLInputElement;
const audioFile = fileInput.files![0];
const transcript = await squid.executeFunction('transcribeAudio', audioFile);
console.log(transcript);
認証と設定
音声メソッドには、admin アクセスを持つ認証済みの Squid client が必要です。これは transcribe() と createSpeech() の両方に当てはまります。推奨パターンは 2 つあります。
- 呼び出しを executables にラップする。 これが標準パターンです。executable は admin context でバックエンド上で実行され、クライアントが基盤となる API key を見ることはありません。executables を参照してください。
- 特権を持つバックエンドサービスから呼び出す。 triggers、schedulers、webhooks などのバックエンド専用エントリポイントは、すでに backend privileges で実行されるため、そこから音声メソッドを直接呼び出せます。
未認証のブラウザクライアントからの呼び出しは UNAUTHORIZED エラーで拒否されます。
OpenAI は Squid app の external service として有効化されている必要があります。API key は Squid Console に保存され、audio client はリクエスト時にそれを参照します。
コアコンセプト
文字起こしモデル
Squid は 3 つの OpenAI 文字起こしモデルをサポートします。
| モデル | 注記 |
|---|---|
whisper-1 | デフォルト。最も広いレスポンス形式をサポートし、コストが低いです。 |
gpt-4o-transcribe | 高精度。JSON のみを返します。 |
gpt-4o-mini-transcribe | gpt-4o-transcribe より小さく安価。JSON のみを返します。 |
文字起こしオプション
AiAudioTranscribeOptions は modelName による discriminated union です。すべてのバリアントは、次の共通のベースフィールドを共有します。
| フィールド | 型 | 必須 | 説明 |
|---|---|---|---|
modelName | string | Yes | サポートされている文字起こしモデルのいずれか |
temperature | number | No | サンプリング温度 |
prompt | string | No | 文字起こしを誘導するための任意テキスト(例: 固有名詞) |
whisper-1 は追加で以下をサポートします。
| フィールド | 型 | 説明 |
|---|---|---|
responseFormat | string | 'json', 'text', 'srt', 'verbose_json', 'vtt' のいずれか。既定は 'json'。 |
gpt-4o-transcribe と gpt-4o-mini-transcribe は 'json' のみを返します。
このメソッドは、モデルの内部的なレスポンス形式に関わらず、常にプレーンな文字列を返します。
音声生成モデル
| モデル | 注記 |
|---|---|
tts-1 | 高速、低レイテンシー、忠実度はやや低め |
tts-1-hd | 高忠実度、低速 |
gpt-4o-mini-tts | 新しい GPT-4o ファミリーの TTS モデル |
音声生成オプション
AiAudioCreateSpeechOptions フィールド:
| フィールド | 型 | 必須 | 説明 |
|---|---|---|---|
modelName | string | Yes | サポートされている TTS モデルのいずれか |
voice | string | No | 'alloy', 'ash', 'ballad', 'coral', 'echo', 'fable', 'onyx', 'nova', 'sage', 'shimmer', 'verse' のいずれか。既定は 'alloy'。 |
responseFormat | string | No | 音声コンテナ形式。'mp3', 'opus', 'aac', 'flac', 'wav', 'pcm' のいずれか。既定は 'mp3'。 |
instructions | string | No | 話し方スタイルの自由形式ガイダンス(例: "speak slowly and clearly") |
speed | number | No | 再生速度の倍率。既定は 1.0。 |
戻り値の形
| メソッド | TypeScript の戻り値 | Python の戻り値 |
|---|---|---|
transcribe() | Promise<string> | str |
createSpeech() | Promise<File> | bytes |
TypeScript では、ファイルの MIME type と拡張子は responseFormat から推論されます。たとえば responseFormat: 'mp3' のリクエストでは、MIME type が audio/mpeg の audio.mp3 という名前のファイルが返ります。
コード例
クライアントがアップロードした音声を文字起こしする
- TypeScript
- Python
import { executable, SquidFile, SquidService } from '@squidcloud/backend';
export class AudioService extends SquidService {
@executable()
async transcribeRecording(audio: SquidFile, languageHint?: string): Promise<string> {
this.assertIsAuthenticated();
const file = new File([audio.data], audio.originalName, { type: audio.mimetype });
return this.squid.ai().audio().transcribe(file, {
modelName: 'whisper-1',
// prompt を使って、正しい綴りや用語へモデルをバイアスします。
prompt: languageHint,
});
}
}
from squidcloud_backend import SquidFile, SquidService, executable
class AudioService(SquidService):
@executable()
async def transcribe_recording(
self,
audio: SquidFile,
language_hint: str | None = None,
) -> str:
self.assert_is_authenticated()
return await self.squid.ai().audio().transcribe(
audio['data'],
audio['originalName'],
audio['mimetype'],
options={
'modelName': 'whisper-1',
# prompt を使って、正しい綴りへモデルをバイアスします。
'prompt': language_hint,
},
)
読み上げ音声を生成してクライアントに返す
この例では、テキストから MP3 ファイルを作成し、クライアントが再生できるよう base64 として返します。
- TypeScript
- Python
import { executable, SquidService } from '@squidcloud/backend';
export class SpeechService extends SquidService {
@executable()
async narrate(text: string): Promise<{ base64: string; mimeType: string }> {
this.assertIsAuthenticated();
const audioFile = await this.squid.ai().audio().createSpeech(text, {
modelName: 'tts-1-hd',
voice: 'nova',
responseFormat: 'mp3',
speed: 1.0,
});
// File を base64 に変換して、JSON 経由でクライアントに返せるようにします。
const buffer = Buffer.from(await audioFile.arrayBuffer());
return {
base64: buffer.toString('base64'),
mimeType: audioFile.type,
};
}
}
生成した音声を長期保存したい場合は、インラインで返すのではなく、結果を storage connector にアップロードしてください。
import base64
from squidcloud_backend import SquidService, executable
class SpeechService(SquidService):
@executable()
async def narrate(self, text: str) -> dict:
self.assert_is_authenticated()
audio_bytes = await self.squid.ai().audio().create_speech(
text,
{
'modelName': 'tts-1-hd',
'voice': 'nova',
'responseFormat': 'mp3',
'speed': 1.0,
},
)
# 音声を base64 として返し、JSON 経由でクライアントに返送できるようにします。
return {
'base64': base64.b64encode(audio_bytes).decode('ascii'),
'mimeType': 'audio/mpeg',
}
往復: 音声を生成してから、それを文字起こしで戻す
統合テストやサニティチェックに便利なパターンです。
- TypeScript
- Python
const speechFile = await this.squid.ai().audio().createSpeech('The quick brown fox jumps over the lazy dog.', {
modelName: 'tts-1',
});
const transcript = await this.squid.ai().audio().transcribe(speechFile, {
modelName: 'whisper-1',
});
console.log(transcript); // "The quick brown fox jumps over the lazy dog."
audio_bytes = await self.squid.ai().audio().create_speech(
'The quick brown fox jumps over the lazy dog.',
{'modelName': 'tts-1'},
)
transcript = await self.squid.ai().audio().transcribe(
audio_bytes,
'speech.mp3',
'audio/mpeg',
options={'modelName': 'whisper-1'},
)
print(transcript) # "The quick brown fox jumps over the lazy dog."
エラーハンドリング
よくあるエラー
| エラー | 原因 | 解決策 |
|---|---|---|
UNAUTHORIZED | 音声呼び出しが非 admin context(例: バックエンドなしのブラウザ)から発生した | 呼び出しを executable にラップするか、バックエンドコードから呼び出す |
Unsupported audio model | modelName がサポート一覧にない | 一覧にある文字起こしまたは TTS モデルのいずれかを使用する |
OpenAI external services are disabled | アプリケーションで OpenAI が有効化されていない | Squid Console で OpenAI を有効化し、API key を設定する |
| File too large | アップロードした音声が上流プロバイダーの制限を超えている | Whisper は 25 MB のアップロード制限があります。このサイズを超える音声は分割または圧縮してください。 |
呼び出し前に入力を検証する
OpenAI Whisper API は 25 MB を超えるファイルを拒否します。上流のエラーを待つのではなく、executable 内で大きすぎるアップロードを拒否してください。
- TypeScript
- Python
@executable()
async transcribeAudio(audio: SquidFile): Promise<string> {
this.assertIsAuthenticated();
const MAX_BYTES = 25 * 1024 * 1024;
if (audio.size > MAX_BYTES) {
throw new Error('Audio file exceeds 25 MB. Split or compress before transcribing.');
}
if (!audio.mimetype.startsWith('audio/')) {
throw new Error('Only audio files are accepted');
}
const file = new File([audio.data], audio.originalName, { type: audio.mimetype });
return this.squid.ai().audio().transcribe(file, { modelName: 'whisper-1' });
}
@executable()
async def transcribe_audio(self, audio: SquidFile) -> str:
self.assert_is_authenticated()
MAX_BYTES = 25 * 1024 * 1024
if audio['size'] > MAX_BYTES:
raise ValueError('Audio file exceeds 25 MB. Split or compress before transcribing.')
if not audio['mimetype'].startswith('audio/'):
raise ValueError('Only audio files are accepted')
return await self.squid.ai().audio().transcribe(
audio['data'],
audio['originalName'],
audio['mimetype'],
options={'modelName': 'whisper-1'},
)
ベストプラクティス
- 音声呼び出しは常に executables にラップしてください。 音声メソッドは admin アクセスを必要とします。ブラウザから直接公開すると API key の漏えいにつながり、認証もバイパスされます。
transcribe()を呼ぶ前に、ファイルサイズと MIME type を検証してください。上流プロバイダーにも制限があり、不正な入力を早期に弾くことでユーザーにより良いエラーメッセージを返せます。- 文字起こしでは
promptフィールドを使って、ドメイン用語、固有名詞、想定言語などを入力してください。精度改善のための最も安価な方法です。 - ストリーミングや低レイテンシー UX には
tts-1、レイテンシーより品質が重要な オフライン資産にはtts-1-hdを選んでください。 - 音声 executables に rate limiting を適用してください。音声生成と文字起こしはいずれも有償 API クォータを消費します。
- 生成した音声をキャッシュしてください。同じ入力テキストに対する text-to-speech は、同じ voice であれば常に同じ出力になるため、キャッシュによりクォータを節約できます。
参照
- Executables - 音声呼び出しをラップしてクライアントから呼べるようにする
- AI agent - 音声入力と音声出力を備えた AI agent を構築する
- AI chat widget - chat widget は
enable-transcriptionで音声入力を公開します - Rate and quota limiting - 音声 executables を悪用から保護する