๋ฆฌํด์ ๋ก(ReturnZero) ๊ฐ์
๋ฆฌํด์ ๋ก๋ ํ๊ตญ์ด ์์ฑ์ธ์(STT) ๋ถ์ผ์์ ์ฐ์ํ ์ฑ๋ฅ์ ๋ณด์ด๋ ์๋น์ค๋ก, ๋ค์ํ ๋ฒค์น๋งํฌ์์ ๊ทธ ์ฑ๋ฅ์ ์ ์ฆํ๊ณ ์๋ค. ํนํ ํ๊ตญ์ด ์ธ์ด๋ชจ๋ธ์ ๋ค๋ถ์ผ ์ฌ๊ณ ๋ ฅ์ ์ธก์ ํ๋ โ๋ก์งKor(LogicKor)โ ๋ฆฌ๋๋ณด๋์์ ๊ฒฝ๋ํ๋ ๊ฑฐ๋์ธ์ด๋ชจ๋ธ(sLLM) ์ค 1์๋ฅผ ๋ฌ์ฑํ๋ค.
ํ๊ตญ์ด STT ์ฑ๋ฅ ๋น๊ต
๋ค์์ ํ๊ตญ์ด STT ์ฑ๋ฅ์ ๋น๊ตํ ๋ฒค์น๋งํฌ๋ก, ๋ฆฌํด์ ๋ก์ ์ฐ์ํ ์ฑ๋ฅ์ ํ์ธํ ์ ์๋ค.
| API \ ๋ฐ์ดํฐ์ | Avg. CER(%) | ์ฃผ์ ์์ญ๋ณ ํ์ | ํ์ | ์๋ด | ์ ์์ง ์ ํ๋ง | ํ๊ตญ์ด ๊ฐ์ | KsponSpeech eval clean | KsponSpeech eval other |
|---|---|---|---|---|---|---|---|---|
| OpenAI Whisper | 11.39 | 10.49 | 10.16 | 7.51 | 17.27 | 10.89 | 12.06 | 11.34 |
| Google api v2 | 11.50 | N/A1 | 11.62 | 8.37 | 14.11 | 11.48 | 11.82 | 11.59 |
| ETRI | 10.19 | 9.95 | 10.56 | 8.36 | 15.46 | 9.89 | 9.99 | 7.15 |
| Naver ClovaSpeech | 9.52 | 7.88 | 8.53 | 5.89 | 9.09 | 13.71 | 10.66 | 10.86 |
| ๋ฆฌํด์ ๋ก | 6.18 | 6.78 | 7.27 | 3.56 | 4.66 | 7.76 | 6.61 | 6.64 |
| ๋ฆฌํด์ ๋ก Whisper2 | 6.59 | 6.84 | 8.33 | 4.1 | 4.26 | 7.11 | 7.78 | 7.73 |
| STT OpenAPI๋ ๋ค์์ ๋ ๊ฐ์ง ํํ๋ฅผ ์ ๊ณตํ๋ค: |
- ์ผ๋ฐ STT: ์์ฑ ํ์ผ์ ํ ์คํธ๋ก ๋ณํ
- ์คํธ๋ฆฌ๋ฐ STT: ์ค์๊ฐ์ผ๋ก ์์ฑ์ธ์ ์ฒ๋ฆฌ
์ฐธ๊ณ ์ฌํญ
- ๋ฌด๋ฃ ์ฌ์ฉ๋: ๊ธฐ๋ณธ 10์๊ฐ์ ๋ฌด๋ฃ ์ ๊ณต
- ๋ณด๊ด ์ฃผ๊ธฐ: ๊ฐ์ธ์ ๋ณด๋ฅผ ์ํด ๋ณํ๋ ๋ฐ์ดํฐ๋ 3์ผ ๋์๋ง ๊ธฐ๋กํ๋ฉฐ, 3์ผ์ด ์ง๋๋ฉด ์ญ์ ํจ
- Web, App ํ๊ฒฝ์์ ์ฌ์ฉํ๋ ๊ฒ๋ณด๋ค, ์๋ฒ๋ฅผ ํตํด์ ์ฐ๋ํ๋ ๋ฐฉ์์ ๊ถ์ฅ
์ธ์ฆ ๊ฐ์ด๋
API๋ฅผ ์ฌ์ฉํ๊ธฐ ์ํด์๋ ์ ํ๋ฆฌ์ผ์ด์ ๋ฑ๋ก์ด ํ์ํ๋ค. ์๋ ์ ์ฐจ๋ฅผ ๋ฐ๋ฅด๋ฉด ๋๋ค.
- RTZR ๋๋ฒจ๋กํผ์ค ์ฌ์ดํธ ํ์๊ฐ์
- ์ฝ์์ ์ ์ฅ
- API ์ฐ๋์ ํ์ํ SECRET(client_id, client_secret) ์ ๋ณด ๋ฐ๊ธ
์ ํ๋ฆฌ์ผ์ด์ ๋ฑ๋ก์ด ์๋ฃ๋๋ฉด, ๋ฐ๊ธ๋ฐ์ Secret ์ ๋ณด์ ์ธ์ฆ ๊ณผ์ ์ ํตํด Token์ ๋ฐ๊ธ๋ฐ์ ์ ์๋ค.
API ๋ชฉ๋ก
| Method | URL | Description |
|---|---|---|
| POST | /v1/authenticate | ์ธ์ฆ ํ ํฐ ์์ฒญ |
์ธ์ฆ ํ ํฐ ์์ฒญ ์ํ ์ฝ๋
import requests
resp = requests.post(
'https://openapi.vito.ai/v1/authenticate',
data={'client_id': '{YOUR_CLIENT_ID}',
'client_secret': '{YOUR_CLIENT_SECRET}'}
)
resp.raise_for_status()
print(resp.json())์๋ต ๋ฐ๋ (Response Body)
์ฑ๊ณต ์, HTTP Status 200๊ณผ ํจ๊ป ์๋์ ๊ฐ์ ์๋ต์ด ๋ฐํ๋๋ค.
{
"access_token": "{YOUR_JWT_TOKEN}",
"expire_at": 1690377931
}CAUTION
token์ ๋ง๋ฃ ๊ธฐ๊ฐ์ 6์๊ฐ์ด๋ฏ๋ก /v1/authenticate๋ฅผ ํตํด ์ฃผ๊ธฐ์ ์ผ๋ก ํ ํฐ์ ๊ฐฑ์ ํด์ผ ํ๋ค.
์ค๋ฅ ์ฝ๋์ ๋ํ ์์ธํ ๋ด์ฉ์ RTZR STT ๋ฌธ์๋ฅผ ์ฐธ๊ณ ํ๋ค.
์ผ๋ฐ STT
์ผ๋ฐ STT API๋ ์์ฑ ํ์ผ์ ํ ์คํธ๋ก ๋ณํํ ์ ์๋ ๊ธฐ๋ฅ์ ์ ๊ณตํ๋ค. HTTP ๊ธฐ๋ฐ์ REST API3๋ก ๊ตฌํ๋์ด ์์ผ๋ฉฐ, ๋ค์ํ ์์ฑ ํ์ผ ํฌ๋งท์ ์ง์ํ๋ค.
์ง์ ํฌ๋งท
- mp4, m4a, mp3, amr, flac, wav
API ๋ชฉ๋ก
| Method | URL | Description |
|---|---|---|
| POST | /v1/transcribe | ํ์ผ ์ ์ฌ ์์ฒญ |
| GET | /v1/transcribe/{TRANSCRIBE_ID} | ํ์ผ ์ ์ฌ ๊ฒฐ๊ณผ ์กฐํ |
1) [POST]/v1/transcribe
์ ์ฅ๋ ์์ฑ ํ์ผ์ ๋ํด ์ ์ฌ๋ฅผ ์์ฒญํ๋ค.
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 |
CAUTION
์ผ๋ฐ STT API์ ๊ฒฝ์ฐ ์๋์ ๊ฐ์ ์ ์ฝ ์ฌํญ์ด ์๋ค.
- POST API์ ๋์์ฒ๋ฆฌ ์ ํ: 10๊ฐ, POST API๋ก ์์ฒญํ ๋ค ์ฒ๋ฆฌ๊ฐ ์๋ฃ๋๊ธฐ ์ ๊น์ง์ ์์ฒญ ๊ฐ์๋ฅผ ์๋ฏธํ๋ฉฐ, ์๋ฃ ์ฌ๋ถ๋ GET API๋ฅผ ํตํด ํ์ธ ๊ฐ๋ฅํ๋ค.
- ์ต๋ ์ธ์ํ์ผ ํฌ๊ธฐ: 2GB, ์ต๋ ์ธ์๊ฐ๋ฅ ์๊ฐ: 4์๊ฐ.
์ํ ์ฝ๋
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())๋ค์ํ ์ต์ ์ ์ค์ ํ ์์:
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())์๋ต ๋ฐ๋ (Response Body)
์ฑ๊ณต ์, HTTP Status 200๊ณผ ํจ๊ป ์๋์ ๊ฐ์ ์๋ต์ด ๋ฐํ๋๋ค.
{
"id": "{TRANSCRIBE_ID}"
}์๋ต์ด ์คํจํ ๊ฒฝ์ฐ ์ค๋ฅ ์ฝ๋๋ RTZR STT ๋ฌธ์๋ฅผ ์ฐธ๊ณ ํ๋ค.
2) [GET]/v1/transcribe/{TRANSCRIBE_ID}
์ ์ฌ ์์ฒญ ์ ๋ฐ๊ธ๋ฐ์ TRANSCRIBE_ID๋ฅผ ์ฌ์ฉํ์ฌ ์ ์ฌ ๊ฒฐ๊ณผ๋ฅผ ์กฐํํ๋ค.
HTTP ์์ฒญ
GET https://openapi.vito.ai/v1/transcribe/{TRANSCRIBE_ID}์์ฒญ ํค๋
Authorization: bearer {YOUR_JWT_TOKEN}- scheme: bearer
- bearerFormat: JWT
์ํ ์ฝ๋
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())์๋ต ๋ฐ๋ (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 |
TIP
์ผ๋ฐ STT API๋ ๊ธด ์์ฑ ํ์ผ๋ ์ง์ํ๊ธฐ ์ํด Polling ๋ฐฉ์์ ์ฌ์ฉํ๋ค. status ๊ฐ์ด transcribing์ธ ๊ฒฝ์ฐ, ์ต์ข ์ํ(completed ๋๋ failed)๊ฐ ๋ ๋๊น์ง ์ฃผ๊ธฐ์ ์ผ๋ก ์กฐํํ์ฌ ๊ฒฐ๊ณผ๋ฅผ ํ์ธํด์ผ ํ๋ค. ๊ถ์ฅ Pooling ์ฃผ๊ธฐ๋ 5์ด๋ค.
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
}
]
}
}์๋ต์ด ์คํจํ ๊ฒฝ์ฐ ์ค๋ฅ ์ฝ๋๋ RTZR STT ๋ฌธ์๋ฅผ ์ฐธ๊ณ ํ์.
์ฌ์ฉ์๊ธ
์๊ธ
- ์ํ๋ณ ์๊ธ์ ๋ค์๊ณผ ๊ฐ๋ค:
- ์ผ๋ฐ STT: 1์๊ฐ๋น 1,000์
- ์คํธ๋ฆฌ๋ฐ STT: 1์๊ฐ 1,000์
- ์๊ธ์ ์ฌ์ฉ๋์ ๋ฐ๋ผ ๋งค์ ์ฒญ๊ตฌ๋๋ฉฐ, ๋ถ๊ฐ์ธ ๋ณ๋
- ์ฌ์ฉ๋์ 1์ด ๋จ์๋ก ์ง๊ณํ ๋ค ์๊ฐ ๋จ์๋ก ํ์ฐํ๋ค(ex. 900์ด = 15๋ถ = 0.25์๊ฐ์ผ๋ก ์ง๊ณ)
- ์ผ๋ฐ STT์ ๊ฒฝ์ฐ ์์ฑ ํ์ผ ๊ธธ์ด๋ฅผ ๊ธฐ์ค์ผ๋ก ์ฌ์ฉ๋์ด ์ง๊ณ๋จ.
- ๋ค์ค ์ฑ๋ ์ต์ ์ ์ฌ์ฉํ ๊ฒฝ์ฐ ๊ฐ ์ฑ๋๋ณ ์์ฑ ํ์ผ ๊ธธ์ด์ ํฉ์ด ์ง๊ณ๋จ
- ์คํธ๋ฆฌ๋ฐ STT์ ๊ฒฝ์ฐ, ์ค์๊ฐ ์คํธ๋ฆผ์ ๊ธธ์ด๋ฅผ ๊ธฐ์ค์ผ๋ก ์ฌ์ฉ๋์ด ์ง๊ณ๋จ
- ์ผ๋ฐ STT์ ๊ฒฝ์ฐ ์์ฑ ํ์ผ ๊ธธ์ด๋ฅผ ๊ธฐ์ค์ผ๋ก ์ฌ์ฉ๋์ด ์ง๊ณ๋จ.
๋ค๋ฅธ STT ์๋น์ค์ ์๊ธ์ ๋ค์์ ์ฐธ๊ณ ํ์.
ํ๋
- ๋ชจ๋ ์ ์ ๋ ๊ฐ์ ์ฆ์ basic ํ๋์ผ๋ก ์์ํจ
๋ฌด๋ฃ ์ฌ์ฉ๋
- ๋ฌด๋ฃ ์ฌ์ฉ๋: ๋ชจ๋ ์ ์ ์๊ฒ ๊ฐ์
์ฆ์ ๊ธฐ๋ณธ 10์๊ฐ์ ๋ฌด๋ฃ ์ ๊ณตํจ
- ์ผ๋ฐ STT์ ์คํธ๋ฆฌ๋ฐ STT ๊ตฌ๋ถ ์์ด API ์ฌ์ฉ ์๊ฐ์ ํฉ์ฐ์ผ๋ก 10์๊ฐ์ ์ ๊ณต
- ๋ฌด๋ฃ ์ฌ์ฉ๋์ ๋ํด์๋ ๋ณ๋์ ์๊ธ์ด ์ฒญ๊ตฌ๋์ง ์์
Footnotes
-
Google์ ์์ฑ์ธ์ ํ์ผ ํฌ๊ธฐ์ ์ ํ์ผ๋ก ์๋ต โฉ
-
OpenAI์์ ๊ณต๊ฐํ Whisper ์คํ์์ค ๋ชจ๋ธ์ ๋ฆฌํด์ ๋ก์ ๋ฐ์ดํฐ๋ฅผ ํ์ธํ๋(fine-tuning)ํ ๋ชจ๋ธ โฉ
-
Representational State Transfer API, ์์์ ์ด๋ฆ์ผ๋ก ๊ตฌ๋ถํ์ฌ ํด๋น ์์์ ์ํ๋ฅผ ์ฃผ๊ณ ๋ฐ๋ ๋ชจ๋ ๊ฒ์ ์๋ฏธ โฉ