일반 STT
일반 STT API는 음성 파일을 텍스트로 변환할 수 있는 API입니다. 일반 STT API의 경우, HTTP 기반의 REST API로 구현되어 있습니다.
지원 포맷
일반 STT API는 음성 파일 포맷 mp4, m4a, mp3, amr, flac, wav 을 지원하고 있습니다.
인증 토큰 발급
일반 STT API는 인증 가이드를 통해 토큰을 발급받은 뒤 사용하실 수 있습니다.
API 목록
Method | URL | Description |
---|---|---|
POST | /v1/transcribe | 파일 전사 요청 |
GET | /v1/transcribe/{TRANSCRIBE_ID} | 파일 전사 결과 조회 |
1) [POST] /v1/transcribe
저장된 음성 파일에 대해 전사를 요청하는 API입니다.
HTTP 요청
POST https://openapi.vito.ai/v1/transcribe
요청 헤더
Authorization: bearer {YOUR_JWT_TOKEN}
- scheme: bearer
- bearerFormat: JWT
요청 바디 (Request body)
content-type: multipart/form-data
Field | Type | Required |
---|---|---|
config | RequestConfig | required |
file | Binary | required |
RequestConfig
Name | Desc | Type | Required | Value | Default |
---|---|---|---|---|---|
model_name | 음성인식 모델 | string | optional | sommers, whisper | sommers |
language | 음성인식 언어, whisper 사용할 때만 적용 | string | optional | ko | |
use_diarization | 화자 분리 사용 여부 | boolean | optional | false | |
diarization.spk_count | 화자수, use_diarization 이 true일 때만 적용 | integer | optional | 0 이상의 정수 | 0 (화자수 예측) |
use_itn | 영어/숫자/단위 변환 여부 | boolean | optional | true | |
use_disfluency_filter | 간투어 필터 사용 여부 | boolean | optional | true | |
use_profanity_filter | 비속어 필터 사용 여부 | boolean | optional | false | |
use_paragraph_splitter | 문단 나누기 사용 여부 | boolean | optional | true | |
paragraph_splitter.max | 문단의 최대 문자 길이, use_paragraph_splitter 이 true일 때만 적용 | integer | optional | 1 이상의 정수 | 50 |
domain | 음성파일의 종류 (도메인) | string | optional | GENERAL, CALL | GENERAL |
use_word_timestamp | 단어별 Timestamp 사용 여부 | boolean | optional | false | |
keywords | 키워드 부스팅용 단어 리스트 | array | optional |
일반 STT API의 경우 아래와 같은 제약 사항이 있습니다.
- POST API 동시처리 제한: 10개, POST API로 요청한 뒤 처리가 완료되기 전까지의 요청 개수를 의미하며, API 처리에 대한 완료는 아래 GET API를 통해 확인 가능합니다.
- 최대 인식파일 크기: 2GB, 최대 인식가능 시간: 4시간.
샘플 코드 1
- cURL
- Python
- Java
curl -X "POST" \
"https://openapi.vito.ai/v1/transcribe" \
-H "accept: application/json" \
-H "Authorization: Bearer ${YOUR_JWT_TOKEN}" \
-H "Content-Type: multipart/form-data" \
-F "file=@sample.wav" \
-F 'config={}'
import json
import requests
config = {}
resp = requests.post(
'https://openapi.vito.ai/v1/transcribe',
headers={'Authorization': 'bearer '+'{YOUR_JWT_TOKEN}'},
data={'config': json.dumps(config)},
files={'file': open('sample.wav', 'rb')}
)
resp.raise_for_status()
print(resp.json())
package ai.vito.openapi.batch;
import java.io.DataOutputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.InputStream;
import java.net.HttpURLConnection;
import java.net.URL;
import java.net.URLConnection;
import java.util.Scanner;
public class PostTranscribeSample {
public static void main(String[] args) throws Exception {
URL url = new URL("https://openapi.vito.ai/v1/transcribe");
HttpURLConnection httpConn = (HttpURLConnection) url.openConnection();
httpConn.setRequestMethod("POST");
httpConn.setRequestProperty("accept", "application/json");
httpConn.setRequestProperty("Authorization", "Bearer "+ "{YOUR_JWT_TOKEN}");
httpConn.setRequestProperty("Content-Type", "multipart/form-data;boundary=authsample");
httpConn.setDoOutput(true);
File file = new File("sample.wav");
DataOutputStream outputStream;
outputStream = new DataOutputStream(httpConn.getOutputStream());
outputStream.writeBytes("--authsample\r\n");
outputStream.writeBytes("Content-Disposition: form-data; name=\"file\";filename=\"" + file.getName() +"\"\r\n");
outputStream.writeBytes("Content-Type: " + URLConnection.guessContentTypeFromName(file.getName()) + "\r\n");
outputStream.writeBytes("Content-Transfer-Encoding: binary" + "\r\n");
outputStream.writeBytes("\r\n");
FileInputStream in =new FileInputStream(file);
byte[] buffer = new byte[(int)file.length()];
int bytesRead = -1;
while ((bytesRead = in.read(buffer)) != -1) {
outputStream.write(buffer,0,bytesRead);
outputStream.writeBytes("\r\n");
outputStream.writeBytes("--authsample\r\n");
}
outputStream.writeBytes("\r\n");
outputStream.writeBytes("--authsample\r\n");
outputStream.writeBytes("Content-Disposition: form-data; name=\"config\"\r\n");
outputStream.writeBytes("Content-Type: application/json\r\n");
outputStream.writeBytes("\r\n");
outputStream.writeBytes("{}")
outputStream.writeBytes("\r\n");
outputStream.writeBytes("--authsample\r\n");
outputStream.flush();
outputStream.close();
InputStream responseStream = httpConn.getResponseCode() / 100 == 2
? httpConn.getInputStream()
: httpConn.getErrorStream();
Scanner s = new Scanner(responseStream).useDelimiter("\\A");
String response = s.hasNext() ? s.next() : "";
s.close();
System.out.println(response);
}
}
샘플 코드 2
- cURL
- Python
- Java
curl -X "POST" \
"https://openapi.vito.ai/v1/transcribe" \
-H "accept: application/json" \
-H "Authorization: Bearer ${YOUR_JWT_TOKEN}" \
-H "Content-Type: multipart/form-data" \
-F "file=@sample.wav" \
-F 'config={
"use_diarization": true,
"diarization": {
"spk_count": 2
},
"use_itn": false,
"use_disfluency_filter": false,
"use_profanity_filter": false,
"use_paragraph_splitter": true,
"paragraph_splitter": {
"max": 50
}
}'
import json
import requests
config = {
"use_diarization": True,
"diarization": {
"spk_count": 2
},
"use_itn": False,
"use_disfluency_filter": False,
"use_profanity_filter": False,
"use_paragraph_splitter": True,
"paragraph_splitter": {
"max": 50
}
}
resp = requests.post(
'https://openapi.vito.ai/v1/transcribe',
headers={'Authorization': 'bearer '+'{YOUR_JWT_TOKEN}'},
data={'config': json.dumps(config)},
files={'file': open('sample.wav', 'rb')}
)
resp.raise_for_status()
print(resp.json())
package ai.vito.openapi.batch;
import java.io.DataOutputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.InputStream;
import java.net.HttpURLConnection;
import java.net.URL;
import java.net.URLConnection;
import java.util.Scanner;
public class PostTranscribeSample {
public static void main(String[] args) throws Exception {
URL url = new URL("https://openapi.vito.ai/v1/transcribe");
HttpURLConnection httpConn = (HttpURLConnection) url.openConnection();
httpConn.setRequestMethod("POST");
httpConn.setRequestProperty("accept", "application/json");
httpConn.setRequestProperty("Authorization", "Bearer "+ "{YOUR_JWT_TOKEN}");
httpConn.setRequestProperty("Content-Type", "multipart/form-data;boundary=authsample");
httpConn.setDoOutput(true);
File file = new File("sample.wav");
DataOutputStream outputStream;
outputStream = new DataOutputStream(httpConn.getOutputStream());
outputStream.writeBytes("--authsample\r\n");
outputStream.writeBytes("Content-Disposition: form-data; name=\"file\";filename=\"" + file.getName() +"\"\r\n");
outputStream.writeBytes("Content-Type: " + URLConnection.guessContentTypeFromName(file.getName()) + "\r\n");
outputStream.writeBytes("Content-Transfer-Encoding: binary" + "\r\n");
outputStream.writeBytes("\r\n");
FileInputStream in =new FileInputStream(file);
byte[] buffer = new byte[(int)file.length()];
int bytesRead = -1;
while ((bytesRead = in.read(buffer)) != -1) {
outputStream.write(buffer,0,bytesRead);
outputStream.writeBytes("\r\n");
outputStream.writeBytes("--authsample\r\n");
}
outputStream.writeBytes("\r\n");
outputStream.writeBytes("--authsample\r\n");
outputStream.writeBytes("Content-Disposition: form-data; name=\"config\"\r\n");
outputStream.writeBytes("Content-Type: application/json\r\n");
outputStream.writeBytes("\r\n");
outputStream.writeBytes(
"{\n" +
" \"use_diarization\": true,\n" +
" \"diarization\": {\"spk_count\": 2},\n" +
" \"use_itn\": false,\n" +
" \"use_disfluency_filter\": false,\n" +
" \"use_profanity_filter\": false,\n" +
" \"use_paragraph_splitter\": true,\n" +
" \"paragraph_splitter\": {\"max\": 50}\n" +
"}"
)
outputStream.writeBytes("\r\n");
outputStream.writeBytes("--authsample\r\n");
outputStream.flush();
outputStream.close();
InputStream responseStream = httpConn.getResponseCode() / 100 == 2
? httpConn.getInputStream()
: httpConn.getErrorStream();
Scanner s = new Scanner(responseStream).useDelimiter("\\A");
String response = s.hasNext() ? s.next() : "";
s.close();
System.out.println(response);
}
}
응답 바디 (Response Body)
응답이 성공한 경우 HTTP Status 200과 함께 아래와 같은 응답을 내려줍니다.
{
"id": "{TRANSCRIBE_ID}"
}
오류 코드
HTTP Status | Code | Notes |
---|---|---|
400 | H0001 | 잘못된 파라미터 요청 |
400 | H0010 | 지원하지 않는 파일 포맷 |
401 | H0002 | 유효하지 않은 토큰 |
413 | H0005 | 파일 사이즈 초과 |
413 | H0006 | 파일 길이 초과 |
429 | A0001 | 사용량 초과 |
429 | A0002 | 동시 처리 제한 초과 |
500 | E500 | 서버 오류 |
아래는 응답이 실패한 경우 가운데 하나의 예시입니다.
{
"code": "H0001",
"msg": "unexpected end of JSON input"
}
2) [GET] /v1/transcribe/{TRANSCRIBE_ID}
- 음성 파일의 전사 결과를 조회하는 API입니다. 전사 요청 API에서 응답받은
TRANSCRIBE_ID
를 사용하여 전사 결과를 조회할 수 있습니다.
HTTP 요청
GET https://openapi.vito.ai/v1/transcribe/{TRANSCRIBE_ID}
요청 헤더
Authorization: bearer {YOUR_JWT_TOKEN}
- scheme: bearer
- bearerFormat: JWT
샘플 코드
- cURL
- Python
- Java
curl -X "GET" \
"https://openapi.vito.ai/v1/transcribe/${TRANSCRIBE_ID}" \
-H "accept: application/json" \
-H "Authorization: Bearer ${YOUR_JWT_TOKEN}"
import requests
resp = requests.get(
'https://openapi.vito.ai/v1/transcribe/'+'{TRANSCRIBE_ID}',
headers={'Authorization': 'bearer '+'{YOUR_JWT_TOKEN}'},
)
resp.raise_for_status()
print(resp.json())
package ai.vito.openapi.batch;
import java.io.InputStream;
import java.net.HttpURLConnection;
import java.net.URL;
import java.util.Scanner;
public class GetTranscribeSample {
public static void main(String[] args) throws Exception {
URL url = new URL("https://openapi.vito.ai/v1/transcribe/"+"{TRANSCRIBE_ID}");
HttpURLConnection httpConn = (HttpURLConnection) url.openConnection();
httpConn.setRequestMethod("GET");
httpConn.setRequestProperty("accept", "application/json");
httpConn.setRequestProperty("Authorization", "Bearer {YOUR_JWT_TOKEN}");
InputStream responseStream = httpConn.getResponseCode() / 100 == 2
? httpConn.getInputStream()
: httpConn.getErrorStream();
Scanner s = new Scanner(responseStream).useDelimiter("\\A");
String response = s.hasNext() ? s.next() : "";
s.close();
System.out.println(response);
}
}
응답 바디 (Response Body)
응답이 성공한 경우 HTTP Status 200과 함께 아래와 같은 응답을 내려줍니다.
Name | Desc | Type | Value |
---|---|---|---|
id | transcribe id | string | |
status | 전사 결과 상태 | string | transcribing , completed , failed |
results.utterances | 발화 정보 | array | |
results.utterances.start_at | 발화 시작 시각 (ms) | integer | |
results.utterances.duration | 발화 duration (ms) | integer | |
results.utterances.msg | 발화 텍스트 | string | |
results.utterances.spk | 화자/채널 ID | integer |
일반 STT API의 경우, 긴 음성 파일도 지원하기 위하여 Polling 방식으로 구현되어 있습니다. 전사 요청 API에서 응답받은 {TRANSCRIBE_ID}의 상태 값이 transcribing
인 경우, 최종 상태(completed
또는 failed
)가 될 때까지 주기적으로 조회하여 변환 결과를 확인할 수 있습니다. 권장하는 Polling 주기는 5초입니다.
(Polling 주기가 너무 짧을 경우 HTTP Status 429로 요청 제한 초과 응답이 내려갈 수 있습니다.)
status: transcribing
{
"id": "{TRANSCRIBE_ID}",
"status": "transcribing"
}
status: completed
{
"id": "{TRANSCRIBE_ID}",
"status": "completed",
"results": {
"utterances": [
{
"start_at": 4737,
"duration": 2360,
"msg": "안녕하세요.",
"spk": 0
},
{
"start_at": 8197,
"duration": 3280,
"msg": "네, 안녕하세요? 반갑습니다.",
"spk": 1
}
]
}
}
status: failed
응답은 성공했지만 전사가 실패한 경우 아래와 같은 응답을 내려줍니다.
{
"id": "{TRANSCRIBE_ID}",
"status": "failed",
"error": {
"code": "{ERROR_CODE}",
"message": "{MESSAGE}"
}
}
위와 같은 경우가 지속적으로 발생할 경우, 문의해주시기 바랍니다.
오류 코드
HttpStatus | Code | Notes |
---|---|---|
400 | H0001 | 잘못된 파라미터 요청 |
401 | H0002 | 유효하지 않은 토큰 |
403 | H0003 | 권한 없음 |
404 | H0004 | 전사 결과 없음 |
410 | H0007 | 전사 결과 만료됨 |
429 | A0003 | 요청 제한 초과 |
500 | E500 | 서버 오류 |
아래는 응답이 실패한 경우 가운데 하나의 예시입니다.
{
"code": "H0004",
"msg": "not found"
}