음성 메모 기능을 붙여야 했다. 사용자가 말로 녹음하면 그걸 텍스트로 바꿔서 저장하는 식이다. OpenAI Whisper API를 직접 붙일까 하다가, 이미 챗봇이랑 이미지 생성까지 Vercel AI SDK로 처리하고 있어서 음성도 같은 SDK로 되는지 찾아봤다.
ai 패키지에 experimental_transcribe라는 함수가 있다. 오디오를 넣으면 텍스트가 나온다. 이미지 뽑던 generateImage랑 결이 똑같아서, 새로 배울 게 거의 없었다.
기본 사용법
provider 패키지부터 설치한다. Whisper는 OpenAI라 @ai-sdk/openai를 쓴다.
npm install ai @ai-sdk/openai
라우트 핸들러에서 업로드된 파일을 받아 그대로 넘긴다.
// app/api/transcribe/route.ts
import { experimental_transcribe as transcribe } from 'ai';
import { openai } from '@ai-sdk/openai';
export async function POST(req: Request) {
const form = await req.formData();
const file = form.get('audio') as File;
const { text, segments, durationInSeconds } = await transcribe({
model: openai.transcription('whisper-1'),
audio: await file.arrayBuffer(),
});
return Response.json({ text, segments, durationInSeconds });
}
포인트는 openai.transcription(...)이다. 텍스트는 openai(...), 이미지는 .image(...), 음성은 .transcription(...)으로 모델을 고른다. audio에는 ArrayBuffer, Uint8Array, 파일 경로, URL 아무거나 넣어도 SDK가 알아서 처리한다.
반환값에서 챙길 것
text만 쓰기 아까운 게, segments가 같이 온다. 구간별로 시작·끝 시각과 문장이 들어있어서 자막이나 타임스탬프 UI를 만들 때 바로 쓴다.
for (const seg of segments) {
console.log(`[${seg.startSecond}s] ${seg.text}`);
}
durationInSeconds로 오디오 길이도 나오니까, 과금이나 사용량 제한 걸 때 참고하면 된다.
클라이언트에서 녹음 올리기
브라우저 MediaRecorder로 녹음한 Blob을 그대로 FormData에 실어 보내면 끝이다.
'use client';
async function upload(blob: Blob) {
const form = new FormData();
form.append('audio', blob, 'memo.webm');
const res = await fetch('/api/transcribe', { method: 'POST', body: form });
const { text } = await res.json();
return text;
}
webm이든 mp3든 Whisper가 알아서 받으니 포맷 변환을 따로 안 해도 됐다.
Whisper API를 직접 붙였으면 요청 형식이랑 응답 파싱을 새로 읽어야 했을 텐데, 이미지 뽑던 감각 그대로 음성까지 처리됐다. provider만 바꾸면 다른 STT 모델로 갈아타도 호출부는 그대로다. 아직 experimental_ 접두사가 붙어 있으니 시그니처가 바뀔 수 있다는 것만 염두에 두면 된다.