서비스 소개

SpeechBox API Service는 셀바스 AI의 음성인식·발음평가 엔진을 API로 제공합니다. 영어 학습 서비스에 필요한 음성 처리 기능을 REST 또는 WebSocket 인터페이스로 손쉽게 통합할 수 있습니다.

SR
발음 평가

지정 텍스트 기반 음성 인식과 발음 평가를 제공합니다. 전체·유창성·정확성·단어·음소 단위 점수와 억양 곡선 분석을 지원합니다.

sr/recognize →   sr/assess →   sr/intonation →

STT
자유 발화 STT

지정 텍스트 없이 자유 발화를 텍스트로 변환합니다. EPD(끝점 검출)와 중간 결과 스트리밍을 지원합니다.

stt/transcribe →

PHONICS
파닉스 분석

문장 또는 단어를 음소 단위로 파닉스 규칙에 따른 발음 패턴을 분석합니다.

phonics/analyze →

RFA
읽기 유창성 평가 (RFA)

STT 인식과 함께 읽기 유창성을 채점합니다. 속도·정확성·휴지 분석 결과를 제공합니다.

rfa/rfa →

API 안내

프로토콜 규격, 인증 방법, 오퍼레이션별 레퍼런스와 호출 샘플 코드를 안내합니다. 실제 호출 체험은 데모에서 확인할 수 있습니다.

REST https://{host}/api/v1/{service}/{operation}
WS wss://{host}/ws/v1

지원 프로토콜

모든 프로토콜은 동일한 JSON 메시지 스키마와 Service/Operation 카탈로그를 공유합니다. 하나의 세션은 하나의 Operation에 고정됩니다.

프로토콜엔드포인트용도
REST v1POST https://{host}/api/v1/{service}/{operation} 배치 처리 — 오디오 파일을 1회 업로드하여 결과 수신
WebSocket v1wss://{host}/ws/v1 배치 처리 + 실시간 스트리밍 — 마이크 입력 및 부분 결과 수신 가능

API 목록 및 지원 프로토콜

SpeechBox API Service에서 제공하는 API 목록입니다. API명을 클릭하면 상세 레퍼런스로 이동합니다.

API명설명프로토콜메서드인증
sr/recognize 지정한 텍스트를 기준으로 발화 음성을 인식하고 점수를 반환 REST WS POSTAPI Key
sr/recognize_long 긴 문단(paragraph) 단위 음성 인식 REST WS POSTAPI Key
sr/assess 참조 텍스트/참조 발음 대비 발음 평가 (전체·유창성·정확성·단어·음소 점수) REST WS POSTAPI Key
sr/intonation 발화 음성의 억양(피치 곡선) 분석 REST WS POSTAPI Key
stt/transcribe 자유 발화 음성을 텍스트로 변환 (순수 STT) REST WS POSTAPI Key
phonics/analyze 문장 또는 단어를 파닉스(Phonics) 분석 REST WS POSTAPI Key
rfa/rfa RFA — 읽기 유창성 평가 (STT + 유창성 채점) REST WS POSTAPI Key
ws-tickets 브라우저 WebSocket 접속용 1회성 티켓 발급 REST POSTAPI Key

API 레퍼런스

REST 공통 규격: POST /api/v1/{service}/{operation} — multipart/form-data(권장, 파트 request + audio) 또는 application/json(오디오 base64) 두 가지 방식을 지원합니다.

요청·응답 필드 표는 모두 JSON 기준입니다. 필드명의 .은 객체 안의 하위 필드를, []는 배열의 각 요소를 뜻합니다 (예: params.audio_format.sample_rate → {"params": {"audio_format": {"sample_rate": 16000}}}).
SR 발음평가

발음평가 (단문)

문장·단어 단위 인식입니다. 긴 문단은 발음평가 (장문)을 사용하세요.

REST 프로토콜

POST /api/v1/sr/recognize

요청 필드 JSON 기준

필드타입필수허용 값설명
user_sidstring필수사용자 식별자
params.textstring필수자유 문자열인식 기준이 되는 텍스트
params.resource_namestring필수배포 설정에 선언된 리소스에 한함 (대소문자 무관)인식 리소스. 인식 언어도 이 값으로 결정됩니다. 선언되지 않은 이름은 거부됩니다
params.audio_formatobject선택아래 audio_format.* 하위 필드object가 아닌 값(문자열 등)은 무시됩니다
params.audio_format.encodingstring선택raw PCM16LE로 해석되는 값
pcm
그 외 값은 검증하지 않고 컨테이너로 디코딩을 시도합니다 (wav · flac · ogg · mp3 등)
인코딩 힌트 (선택). 소문자·trim 후 비교하며, 미지정 시 컨테이너를 탐색한 뒤 raw PCM16LE로 간주합니다.
params.audio_format.sample_rateint선택양의 정수샘플링 레이트 (기본 16000, 권장 16000). 16kHz로 변환되어 처리됩니다.
params.audio_format.channelsint선택양의 정수채널 수 (기본 1, 권장 1). mono로 변환되어 처리됩니다
params.recognition_modestring선택no_epd — EPD 미사용 — 오디오 전체를 인식
use_epd — EPD로 발화 구간을 검출해 인식
use_epd_with_sil_append — EPD 사용 + 검출 구간 뒤에 묵음(SIL) 추가
끝점 검출 방식 (기본 use_epd_with_sil_append). 대소문자 무관
params.set_text_typestring선택LIST — 여러 문장 후보 중 1문장을 인식 (후보는 ;로 구분)
CHUNK — 1문장을 단어 단위로 분리 입력 (;로 구분)
CHUNK_SKIP — CHUNK + 단어 1개를 건너뛸 수 있는 형식
CHUNK_SERIAL — CHUNK + 어느 단어까지 발성했는지 확인
CHUNK_SERIAL_N_SKIP — CHUNK_SKIP과 CHUNK_SERIAL을 함께 적용
텍스트 매칭 방식 (기본 LIST). 대소문자 무관
params.configobject선택아래 config.* 하위 필드세부 옵션. 범위를 벗어나거나 타입이 맞지 않는 값은 거부되지 않고 무시되며, result.config_status에 -100(정상은 1)으로 보고됩니다
params.config.levelint선택0–4거절의 강도 (기본 1). 값이 클수록 거절 강도가 커집니다.
params.config.tm_limitint선택3–600한 번의 인식에서 처리할 수 있는 최대 음성 길이(초, 기본 30). 이 길이를 넘는 음성은 인식에 실패합니다.
params.config.pause_thint선택250–2500발화가 끝났다고 판정하기 위한 최소 묵음 길이(ms, 기본 500). 이 길이만큼 묵음이 이어지면 인식을 종료합니다.

호출 샘플

curl -X POST "https://{host}/api/v1/sr/recognize" \
  -H "Authorization: Bearer $API_KEY" \
  -F 'request={"user_sid":"user-2001","params":{"text":"Hello world","resource_name":"KONG_ALL",
       "audio_format":{"sample_rate":16000,"channels":1,"encoding":"pcm"}}};type=application/json' \
  -F "audio=@hello.wav"
import requests, json

resp = requests.post(
    "https://{host}/api/v1/sr/recognize",
    headers={"Authorization": f"Bearer {API_KEY}"},
    files={
        "request": (None, json.dumps({
            "user_sid": "user-2001",
            "params": {"text": "Hello world", "resource_name": "KONG_ALL"},
        }), "application/json"),
        "audio": ("hello.wav", open("hello.wav", "rb"), "audio/wav"),
    },
)
body = resp.json()
print(body)
const fs = require("fs");
const path = require("path");

const HOST = "https://{host}";

async function main() {
    const filePath = "./hello.wav";

    const fd = new FormData();

    fd.append(
        "request",
        new Blob(
            [
                JSON.stringify({
                    user_sid: "user-2001",
                    params: {
                        text: "Hello world",
                        resource_name: "KONG_ALL",
                    },
                }),
            ],
            { type: "application/json" }
        )
    );

    const file = new Blob([fs.readFileSync(filePath)]);
    fd.append("audio", file, path.basename(filePath));

    const res = await fetch(`${HOST}/api/v1/sr/recognize`, {
        method: "POST",
        headers: {
            Authorization: `Bearer ${API_KEY}`,
        },
        body: fd,
    });

    if (!res.ok) {
        console.error("HTTP Error:", res.status, await res.text());
        return;
    }

    const json = await res.json();
    console.log(json);
}

main();

응답 예시 (200)

{
  "session_id": "01HXXXXXXXXXXXXXXXXXXXXXXX",
  "result": {
    "result_type": "recognition",
    "text": "Hello world",
    "score": 95,
    "words": [
      { "text": "Hello", "score": 97, "start_ms": 0,   "end_ms": 500,
        "raw_data": { "phonemes": [
          { "str": "HH", "score": 95, "is_vowel": false, "start_ms": 0,   "end_ms": 80  },
          { "str": "AH", "score": 98, "is_vowel": true,  "start_ms": 80,  "end_ms": 300 },
          { "str": "L",  "score": 96, "is_vowel": false, "start_ms": 300, "end_ms": 500 }
        ]}},
      { "text": "world", "score": 93, "start_ms": 520, "end_ms": 990,
        "raw_data": { "phonemes": [
          { "str": "W",  "score": 90, "is_vowel": false, "start_ms": 520, "end_ms": 620 },
          { "str": "ER", "score": 95, "is_vowel": true,  "start_ms": 620, "end_ms": 990 }
        ]}}
    ]
  },
  "statistics": { "audio_duration": 1.5, "processing_time": 0.3 },
  "server_time": "2026-02-12T10:30:45Z"
}

응답 REST 응답 본문 — 필드는 결과 구조체를 참고하세요


WebSocket 프로토콜

WS wss://{host}/ws/v1

한 연결에서 아래 순서로 메시지를 주고받습니다. Text 프레임은 JSON 제어 메시지이고, Binary 프레임은 오디오입니다. 아래 요청·응답 필드는 모두 JSON 메시지 기준입니다. 연결 인증은 인증 (API Key)과 브라우저 인증을 참고하세요.

SR · 발음평가 (단문) 세션 흐름도
     Client                              Server
     ──────                              ──────
 ①  session.start           ─▶
                            ◀─  session.started       (session_id 발급)
 ②  command: start_audio    ─▶
                            ◀─  command.ack
 ③  [binary audio frame]    ─▶
                            ◀─  data_chunk.ack        (프레임마다 1회)
 ④  command: finalize_audio ─▶
                            ◀─  command.ack
                            ◀─  recognition.result    (최종 결과)
 ⑤  session.end             ─▶
                            ◀─  session.ended

 ※  session.heartbeat       ─▶   (① ~ ⑤ 사이, 30초 권장)
                            ◀─  session.heartbeat.ack
session.heartbeat — ① session.started를 받은 뒤부터 ⑤ session.end를 보내기 전까지 사이에 보냅니다. WebSocket 연결을 오래 유지하는 경우 세션이 만료되지 않도록 주기적으로 호출해 세션을 연장하는 데 사용합니다 (30초 주기 권장).

① session.start — 세션 시작

요청 Client → Server · Text 프레임 (JSON)

필드타입필수허용 값설명
typestring필수session.start메시지 종류
user_sidstring필수사용자 식별자
servicestring필수sr서비스
operationstring필수recognize오퍼레이션
paramsobject필수아래 params.* 하위 필드인식 파라미터. REST 요청의 params와 같습니다
params.textstring필수자유 문자열인식 기준이 되는 텍스트
params.resource_namestring필수배포 설정에 선언된 리소스에 한함 (대소문자 무관)인식 리소스. 인식 언어도 이 값으로 결정됩니다. 선언되지 않은 이름은 거부됩니다
params.audio_formatobject선택아래 audio_format.* 하위 필드object가 아닌 값(문자열 등)은 무시됩니다
params.audio_format.encodingstring선택raw PCM16LE로 해석되는 값
pcm
그 외 값은 검증하지 않고 컨테이너로 디코딩을 시도합니다 (wav · flac · ogg · mp3 등)
인코딩 힌트 (선택). 소문자·trim 후 비교하며, 미지정 시 컨테이너를 탐색한 뒤 raw PCM16LE로 간주합니다.
params.audio_format.sample_rateint선택양의 정수샘플링 레이트 (기본 16000, 권장 16000). 16kHz로 변환되어 처리됩니다.
params.audio_format.channelsint선택양의 정수채널 수 (기본 1, 권장 1). mono로 변환되어 처리됩니다
params.recognition_modestring선택no_epd — EPD 미사용 — 오디오 전체를 인식
use_epd — EPD로 발화 구간을 검출해 인식
use_epd_with_sil_append — EPD 사용 + 검출 구간 뒤에 묵음(SIL) 추가
끝점 검출 방식 (기본 use_epd_with_sil_append). 대소문자 무관
params.set_text_typestring선택LIST — 여러 문장 후보 중 1문장을 인식 (후보는 ;로 구분)
CHUNK — 1문장을 단어 단위로 분리 입력 (;로 구분)
CHUNK_SKIP — CHUNK + 단어 1개를 건너뛸 수 있는 형식
CHUNK_SERIAL — CHUNK + 어느 단어까지 발성했는지 확인
CHUNK_SERIAL_N_SKIP — CHUNK_SKIP과 CHUNK_SERIAL을 함께 적용
텍스트 매칭 방식 (기본 LIST). 대소문자 무관
params.configobject선택아래 config.* 하위 필드세부 옵션. 범위를 벗어나거나 타입이 맞지 않는 값은 거부되지 않고 무시되며, result.config_status에 -100(정상은 1)으로 보고됩니다
params.config.levelint선택0–4거절의 강도 (기본 1). 값이 클수록 거절 강도가 커집니다.
params.config.tm_limitint선택3–600한 번의 인식에서 처리할 수 있는 최대 음성 길이(초, 기본 30). 이 길이를 넘는 음성은 인식에 실패합니다.
params.config.pause_thint선택250–2500발화가 끝났다고 판정하기 위한 최소 묵음 길이(ms, 기본 500). 이 길이만큼 묵음이 이어지면 인식을 종료합니다.

응답 Server → Client · session.started

필드타입설명
typestring"session.started" 고정
session_idstring발급된 세션 ID. 이후 서버가 보내는 모든 메시지에 포함됩니다
subscription_uuidstring세션에 적용된 구독 UUID
subscription_plan_uidint구독 플랜 ID
subscription_statusstring구독 상태
server_timestring응답 서버 시각 (ISO 8601 UTC)
// 클라이언트 → 서버
{
  "type": "session.start",
  "user_sid": "user-2001",
  "service": "sr",
  "operation": "recognize",
  "params": {
    "text": "Hello world",
    "resource_name": "KONG_ALL",
    "audio_format": { "sample_rate": 16000, "channels": 1, "encoding": "pcm" }
  }
}

// 서버 → 클라이언트
{
  "type": "session.started",
  "session_id": "01HXXXXXXXXXXXXXXXXXXXXXXX",
  "subscription_uuid": "…",
  "subscription_plan_uid": 0,
  "subscription_status": "…",
  "server_time": "2026-02-12T10:30:45Z"
}
session.started를 받기 전에 command·Binary 프레임·session.heartbeat·session.end를 보내면 PROTOCOL_VIOLATION으로 연결이 종료됩니다. api_key 필드는 넣을 수 없으며(INVALID_MESSAGE), API Key는 연결 handshake에서만 전달합니다.

② command: start_audio — 오디오 수신 시작

요청 Client → Server · Text 프레임 (JSON)

필드타입필수허용 값설명
typestring필수command메시지 종류
commandstring필수start_audio커맨드 이름

응답 Server → Client · command.ack

필드타입설명
typestring"command.ack" 고정
session_idstring세션 ID
commandstring수락된 커맨드 이름
server_timestring응답 서버 시각 (ISO 8601 UTC)
server_processing_time_nsint서버 처리 소요 시간 (nanoseconds)
// 클라이언트 → 서버
{ "type": "command", "command": "start_audio" }

// 서버 → 클라이언트
{
  "type": "command.ack",
  "session_id": "01HXXXXXXXXXXXXXXXXXXXXXXX",
  "command": "start_audio",
  "server_time": "2026-02-12T10:30:45Z",
  "server_processing_time_ns": 85000
}

③ Binary 오디오 프레임 — 오디오 전송

요청 Client → Server · Binary 프레임

프레임내용설명
Binary오디오 바이트①의 params.audio_format 형식으로 해석합니다. JSON 래핑 없이 바이트 그대로 보냅니다

응답 Server → Client · data_chunk.ack (프레임마다 1회)

필드타입설명
typestring"data_chunk.ack" 고정
session_idstring세션 ID
bytesint이번 프레임의 수신 바이트 수
server_timestring응답 서버 시각 (ISO 8601 UTC)
server_processing_time_nsint서버 처리 소요 시간 (nanoseconds)
// 서버 → 클라이언트
{
  "type": "data_chunk.ack",
  "session_id": "01HXXXXXXXXXXXXXXXXXXXXXXX",
  "bytes": 48044,
  "server_time": "2026-02-12T10:30:45Z",
  "server_processing_time_ns": 412000
}
data_chunk.ack는 수신 확인일 뿐 인식 결과가 아닙니다. 인식은 ④ finalize_audio에서 실행됩니다.

④ command: finalize_audio — 수신 종료 · 인식 실행

요청 Client → Server · Text 프레임 (JSON)

필드타입필수허용 값설명
typestring필수command메시지 종류
commandstring필수finalize_audio커맨드 이름

응답 1 Server → Client · command.ack

필드타입설명
typestring"command.ack" 고정
session_idstring세션 ID
commandstring"finalize_audio" 고정
server_timestring응답 서버 시각 (ISO 8601 UTC)
server_processing_time_nsint서버 처리 소요 시간 (nanoseconds)

응답 2 Server → Client · recognition.result — 필드는 결과 구조체를 참고하세요

// 클라이언트 → 서버
{ "type": "command", "command": "finalize_audio" }

// 서버 → 클라이언트 (1) 커맨드 수락
{
  "type": "command.ack",
  "session_id": "01HXXXXXXXXXXXXXXXXXXXXXXX",
  "command": "finalize_audio",
  "server_time": "2026-02-12T10:30:46Z",
  "server_processing_time_ns": 310000000
}

// 서버 → 클라이언트 (2) 인식 결과
{
  "type": "recognition.result",
  "session_id": "01HXXXXXXXXXXXXXXXXXXXXXXX",
  "is_final": true,
  "result": {
    "result_type": "recognition",
    "text": "Hello world",
    "score": 95,
    "words": [ … ]
  },
  "statistics": { … },
  "server_time": "2026-02-12T10:30:46Z"
}
처리가 끝나면 command.ack와 recognition.result가 이 순서로 연달아 옵니다. 커맨드가 실패하면 두 메시지 대신 command.error가 오며, 세션은 유지됩니다.

⑤ session.end — 세션 종료

요청 Client → Server · Text 프레임 (JSON)

필드타입필수허용 값설명
typestring필수session.end메시지 종류
reasonstring선택자유 문자열종료 사유 (기본 completed). session.ended에 그대로 반환됩니다

응답 Server → Client · session.ended

필드타입설명
typestring"session.ended" 고정
session_idstring세션 ID
reasonstring요청의 reason 값
statistics.frames_receivedint세션 동안 수신한 Binary 프레임 수
statistics.audio_bytesint세션 동안 수신한 오디오 누적 바이트 수
server_timestring응답 서버 시각 (ISO 8601 UTC)
// 클라이언트 → 서버
{ "type": "session.end", "reason": "completed" }

// 서버 → 클라이언트
{
  "type": "session.ended",
  "session_id": "01HXXXXXXXXXXXXXXXXXXXXXXX",
  "reason": "completed",
  "statistics": { "frames_received": 1, "audio_bytes": 48044 },
  "server_time": "2026-02-12T10:30:47Z"
}
session.end는 finalize_audio를 대신 실행하지 않습니다. 결과가 필요하면 ④를 먼저 보내세요. 세션을 오래 유지할 때는 session.heartbeat를 주기적으로 보내 세션을 연장하세요 (30초 주기 권장).

오류 응답

서버는 상황에 따라 두 종류의 오류 메시지를 보냅니다. 오류 코드는 에러 코드를 참고하세요.

타입발생 시점세션
command.errorstart_audio · finalize_audio 등 커맨드 처리 실패유지
session.error세션 시작 실패, 메시지 순서 위반, 잘못된 메시지 형식, Binary 프레임 처리 실패대부분 종료
필드타입설명
typestring"command.error" 또는 "session.error"
session_idstring세션 ID (session.error는 세션이 만들어진 뒤에만 포함)
commandstring실패한 커맨드 이름 (command.error만 포함)
error.codestring오류 코드
error.messagestring오류 메시지
error.detailsobject부가 정보 (있을 때만 포함)
error.ap_request_idstring서버 로그 추적용 요청 ID. 문의 시 함께 전달하세요
server_timestring응답 서버 시각 (ISO 8601 UTC)
{
  "type": "command.error",
  "session_id": "01HXXXXXXXXXXXXXXXXXXXXXXX",
  "command": "finalize_audio",
  "error": { "code": "INVALID_MESSAGE", "message": "…", "ap_request_id": "…" },
  "server_time": "2026-02-12T10:30:46Z"
}

결과 구조체 REST · WebSocket 공용 · JSON 기준

아래 표는 REST 응답 본문과 WebSocket recognition.result 메시지에 공통으로 적용됩니다. REST는 응답 본문 최상위에, WebSocket은 결과 메시지 본문에 같은 필드가 담기며, WebSocket 메시지에는 type·is_final이 추가됩니다. REST 전용 표시가 있는 필드는 WebSocket 결과 메시지에 없습니다.

sr/recognize 결과

sr/recognize 응답 결과 구조입니다.

필드타입설명
session_idstring세션 ID
server_timestring응답 서버 시각 (ISO 8601 UTC)
statistics.actionstring실행된 엔진 액션명
statistics.sdkstringSDK명 (SelvySR)
statistics.runtimestring런타임 구현체 (sr2lib_runtime) — 런타임 계층의 값이 우선 적용되어 runtime_implementation과 동일한 값이 반환됩니다
statistics.runtime_implementationstring런타임 구현체 ID (sr2lib_runtime)
statistics.audio_sizeint사용자 음성 바이트 수
statistics.reference_audio_sizeint참조 음성 바이트 수 (없으면 0)
statistics.elapsed_nsint처리 소요 시간 (nanoseconds)
statistics.invoke_started_at_nsintinvoke 시작 타임스탬프 (nanoseconds)
statistics.invoke_completed_at_nsintinvoke 완료 타임스탬프 (nanoseconds)
statistics.recognition_modestring사용된 인식 모드
statistics.resource_namestring사용된 리소스명
errorobject오류 발생 시 포함 (정상 응답 시 부재) REST 전용 — WebSocket은 command.error·session.error 메시지로 전달됩니다
result.result_typestring"recognition" 고정
result.textstring인식된 텍스트 (최상위 후보)
result.scorefloat전체 인식 점수 (0–100)
result.confidencefloat인식 신뢰도 (엔진에 따라 제공, SelvySR 엔진에서는 부재)
result.words[]array어절 배열
result.words[].textstring어절 텍스트
result.words[].scorefloat어절 점수 (0–100)
result.words[].confidencefloat어절 신뢰도 (엔진에 따라 제공)
result.words[].start_msint시작 시각 (ms)
result.words[].end_msint종료 시각 (ms)
result.words[].raw_data.strstring어절 텍스트
result.words[].raw_data.scorefloat어절 점수 (0–100)
result.words[].raw_data.start_msintepd_start_ms 기준 시작점 (ms)
result.words[].raw_data.end_msintepd_start_ms 기준 끝점 (ms)
result.words[].raw_data.time_weightfloat문장 전체 시간 대비 해당 어절의 시간 비율
result.words[].raw_data.time_weighted_scorefloat시간 가중 어절 점수
result.words[].raw_data.stressScorefloat문장 내 강세 점수 (0–100)
result.words[].raw_data.phonemes[].strstringARPABET 기호
result.words[].raw_data.phonemes[].scorefloat음소 점수 (0–100)
result.words[].raw_data.phonemes[].start_msintepd_start_ms 기준 시작점 (ms)
result.words[].raw_data.phonemes[].end_msintepd_start_ms 기준 끝점 (ms)
result.words[].raw_data.phonemes[].phonme_idint음소 내부 ID
result.words[].raw_data.phonemes[].typeint음소 종류 비트마스크 — bit0(1) 자음, bit1(2) 모음. 0은 비음성 구간
result.words[].raw_data.phonemes[].is_vowelbool모음 여부
result.words[].raw_data.phonemes[].is_speechbool음성 구간 여부
result.alternatives[]arraycandidate_count > 1 시 추가 후보 배열
result.alternatives[].textstring후보 텍스트
result.alternatives[].scoreint후보 점수
result.alternatives[].confidencefloat후보 신뢰도 (엔진에 따라 제공)
result.alternatives[].raw_dataobject후보 엔진 원본
result.metadataobject엔진 부가 정보. SelvySR 엔진 정상 결과에서는 빈 object이며, 인식 거절 시 아래 status* 필드가 채워짐
result.metadata.statusstring인식 거절 시 "rejected" (정상 결과에서는 부재)
result.metadata.status_codestring거절 사유 코드명 (recognition_rejected · recognition_speech_failed 등)
result.metadata.status_code_valueint거절 사유 코드 숫자값
result.metadata.status_messagestring엔진 판정 메시지
result.raw_data.recog_modeintSet Text Type
result.raw_data.input_texts[]string[]인식 문장 후보 목록
result.raw_data.err_msgstring에러 메시지 (정상 시 빈 문자열)
result.raw_data.SnRfloat검출 음성구간의 신호 대 잡음비 (S/N Ratio)
result.raw_data.epd_detectedboolEPD 음성구간 검출 성공 여부
result.raw_data.speech_detectedbool음성 인식 성공 여부
result.raw_data.epd_start_msintEPD 검출 음성구간 시작점 (ms)
result.raw_data.epd_end_msintEPD 검출 음성구간 끝점 (ms)
result.raw_data.input_secondsfloat입력 음성 전체 길이 (초)
result.raw_data.process_secondsfloat처리 소요 시간 (초)
result.raw_data.xRTfloatReal-Time Factor — 처리시간 / 입력시간
result.raw_data.datetimestring결과 직렬화 시점 로컬 시각 (YYYY-MM-DD HH:MM:SS:mmm +hh:mm)
result.raw_data.input_info.langstring인식 모델 언어
result.raw_data.input_info.model_namestring인식 모델 이름
result.raw_data.input_info.recog_modeintSet Text Type
result.raw_data.input_info.input_textstring인식 문장 후보 리스트 원본 문자열
result.raw_data.input_info.recognition_timeint인식 시작 시각 (UTC timestamp)
result.raw_data.input_info.recognition_configobject인식에 사용된 설정값 (Config)
result.raw_data.results[]array인식 결과 후보 배열 — 점수 내림차순 정렬
result.raw_data.results[].strstring인식된 문장
result.raw_data.results[].scorefloat인식 점수 (0–100)
result.raw_data.results[].grade_percentageint학습자 백분위 위치 (100 = 상위 1%, 1 = 하위 1%)
result.raw_data.results[].start_msintepd_start_ms 기준 문장 시작점 (ms)
result.raw_data.results[].end_msintepd_start_ms 기준 문장 끝점 (ms)
result.raw_data.results[].index[]int[2][0] G2P 후보 리스트 위치, [1] 입력 문자열 위치
result.raw_data.results[].phoneme_stringstring음소 문자열 (발음 기호 시퀀스)
result.raw_data.results[].wpmfloat분당 단어 수
result.raw_data.results[].ppsfloat초당 음소 수
result.raw_data.results[].spsfloat초당 음절 수
result.raw_data.results[].confavgfloat단어별 인식 점수 단순 평균
result.raw_data.results[].conftimeavgfloat단어별 인식 점수 시간 가중 평균
result.raw_data.results[].meanfloat내부 통계 필드
result.raw_data.results[].varfloat내부 통계 필드
result.raw_data.results[].words[].strstring어절 텍스트
result.raw_data.results[].words[].scorefloat어절 점수 (0–100)
result.raw_data.results[].words[].start_msintepd_start_ms 기준 시작점 (ms)
result.raw_data.results[].words[].end_msintepd_start_ms 기준 끝점 (ms)
result.raw_data.results[].words[].time_weightfloat문장 전체 시간 대비 어절의 시간 비율
result.raw_data.results[].words[].time_weighted_scorefloat시간 가중 어절 점수
result.raw_data.results[].words[].stressScorefloat문장 내 강세 점수 (0–100)
result.raw_data.results[].words[].phonemes[].strstringARPABET 기호
result.raw_data.results[].words[].phonemes[].scorefloat음소 점수 (0–100)
result.raw_data.results[].words[].phonemes[].start_msintepd_start_ms 기준 시작점 (ms)
result.raw_data.results[].words[].phonemes[].end_msintepd_start_ms 기준 끝점 (ms)
result.raw_data.results[].words[].phonemes[].phonme_idint음소 내부 ID
result.raw_data.results[].words[].phonemes[].typeint음소 종류 비트마스크 — bit0(1) 자음, bit1(2) 모음. 0은 비음성 구간
result.raw_data.results[].words[].phonemes[].is_vowelbool모음 여부
result.raw_data.results[].words[].phonemes[].is_speechbool음성 구간 여부
result.raw_data.extra.api_namestring호출 API 이름
result.raw_data.extra.paramsstringAPI 호출 파라미터
result.raw_data.extra.returnsstringAPI 반환값
result.raw_data.extra.tagstring반환값 구분자
result.raw_data.extra.call_timeintAPI 호출 시각 (UTC timestamp)
result.raw_data.extra.return_timeintAPI 반환 시각 (UTC timestamp)
result.raw_data.extra.recogizedbool인식 요청에 대한 결과 여부
result.raw_data.extra.input_configobject입력 설정값 (Config)
result.raw_data.extra.input_textstring인식 문장 후보 리스트
result.raw_data.extra.loadedbool리소스 로딩 결과 여부
result.raw_data.extra.loaded_pathstring로딩된 리소스 경로
result.raw_data.extra.input_speech_lengthint입력 음성 데이터 길이 (sample 수)

발음평가 (장문)

문단 단위 인식입니다. 문장·단어 단위는 발음평가 (단문)을 사용하세요.

REST 프로토콜

POST /api/v1/sr/recognize_long

요청 필드 JSON 기준

필드타입필수허용 값설명
user_sidstring필수사용자 식별자
params.textstring필수자유 문자열인식 기준이 되는 텍스트
params.resource_namestring필수배포 설정에 선언된 리소스에 한함 (대소문자 무관)인식 리소스. 인식 언어도 이 값으로 결정됩니다. 선언되지 않은 이름은 거부됩니다
params.audio_formatobject선택아래 audio_format.* 하위 필드object가 아닌 값(문자열 등)은 무시됩니다
params.audio_format.encodingstring선택raw PCM16LE로 해석되는 값
pcm
그 외 값은 검증하지 않고 컨테이너로 디코딩을 시도합니다 (wav · flac · ogg · mp3 등)
인코딩 힌트 (선택). 소문자·trim 후 비교하며, 미지정 시 컨테이너를 탐색한 뒤 raw PCM16LE로 간주합니다.
params.audio_format.sample_rateint선택양의 정수샘플링 레이트 (기본 16000, 권장 16000). 16kHz로 변환되어 처리됩니다.
params.audio_format.channelsint선택양의 정수채널 수 (기본 1, 권장 1). mono로 변환되어 처리됩니다
params.configobject선택아래 config.* 하위 필드세부 옵션. 범위를 벗어나거나 타입이 맞지 않는 값은 거부되지 않고 무시되며, result.config_status에 -100(정상은 1)으로 보고됩니다
params.config.levelint선택0–4거절의 강도 (기본 1). 값이 클수록 거절 강도가 커집니다.
params.config.tm_limitint선택3–600한 번의 인식에서 처리할 수 있는 최대 음성 길이(초, 기본 30). 이 길이를 넘는 음성은 인식에 실패합니다.
params.config.pause_thint선택250–2500발화가 끝났다고 판정하기 위한 최소 묵음 길이(ms, 기본 500). 이 길이만큼 묵음이 이어지면 인식을 종료합니다.

호출 샘플

curl -X POST "https://{host}/api/v1/sr/recognize_long" \
  -H "Authorization: Bearer $API_KEY" \
  -F 'request={"user_sid":"user-2001","params":{"text":"This is my family. My father is a doctor. My mother is a teacher.",
       "resource_name":"KONG_ALL"}};type=application/json' \
  -F "audio=@paragraph.wav"
import requests, json

resp = requests.post(
    "https://{host}/api/v1/sr/recognize_long",
    headers={"Authorization": f"Bearer {API_KEY}"},
    files={
        "request": (None, json.dumps({
            "user_sid": "user-2001",
            "params": {
                "text": "This is my family. My father is a doctor. My mother is a teacher.",
                "resource_name": "KONG_ALL",
            },
        }), "application/json"),
        "audio": ("paragraph.wav", open("paragraph.wav", "rb"), "audio/wav"),
    },
)
result = resp.json()["result"]
print(result["text"], result["score"])
# 미발화 어절은 score·start_ms·end_ms 가 0 으로 내려옵니다.
for w in result["words"]:
    print(w["text"], w["score"], w["raw_data"]["is_spoken"])
const fs = require("fs");
const path = require("path");

const HOST = "https://{host}";

async function main() {
    const filePath = "./paragraph.wav";

    const fd = new FormData();

    fd.append(
        "request",
        new Blob(
            [
                JSON.stringify({
                    user_sid: "user-2001",
                    params: {
                        text: "This is my family. My father is a doctor. My mother is a teacher.",
                        resource_name: "KONG_ALL",
                    },
                }),
            ],
            { type: "application/json" }
        )
    );

    fd.append("audio", new Blob([fs.readFileSync(filePath)]), path.basename(filePath));

    const res = await fetch(`${HOST}/api/v1/sr/recognize_long`, {
        method: "POST",
        headers: { Authorization: `Bearer ${API_KEY}` },
        body: fd,
    });

    if (!res.ok) {
        console.error("HTTP Error:", res.status, await res.text());
        return;
    }

    const result = (await res.json()).result;
    console.log(result.text, result.score);
}

main();
set_text_type·recognition_mode는 sr/recognize 전용입니다 — sr/recognize_long에 전달해도 엔진에 반영되지 않습니다.

응답 REST 응답 본문 — 필드는 결과 구조체를 참고하세요


WebSocket 프로토콜

WS wss://{host}/ws/v1

한 연결에서 아래 순서로 메시지를 주고받습니다. Text 프레임은 JSON 제어 메시지이고, Binary 프레임은 오디오입니다. 아래 요청·응답 필드는 모두 JSON 메시지 기준입니다. 연결 인증은 인증 (API Key)과 브라우저 인증을 참고하세요.

SR · 발음평가 (장문) 세션 흐름도
     Client                              Server
     ──────                              ──────
 ①  session.start           ─▶
                            ◀─  session.started       (session_id 발급)
 ②  command: start_audio    ─▶
                            ◀─  command.ack
 ③  [binary audio frame]    ─▶
                            ◀─  data_chunk.ack        (프레임마다 1회)
 ④  command: finalize_audio ─▶
                            ◀─  command.ack
                            ◀─  recognition.result    (최종 결과)
 ⑤  session.end             ─▶
                            ◀─  session.ended

 ※  session.heartbeat       ─▶   (① ~ ⑤ 사이, 30초 권장)
                            ◀─  session.heartbeat.ack
session.heartbeat — ① session.started를 받은 뒤부터 ⑤ session.end를 보내기 전까지 사이에 보냅니다. WebSocket 연결을 오래 유지하는 경우 세션이 만료되지 않도록 주기적으로 호출해 세션을 연장하는 데 사용합니다 (30초 주기 권장).

① session.start — 세션 시작

요청 Client → Server · Text 프레임 (JSON)

필드타입필수허용 값설명
typestring필수session.start메시지 종류
user_sidstring필수사용자 식별자
servicestring필수sr서비스
operationstring필수recognize_long오퍼레이션
paramsobject필수아래 params.* 하위 필드요청 파라미터. REST 요청의 params와 같습니다
params.textstring필수자유 문자열인식 기준이 되는 텍스트
params.resource_namestring필수배포 설정에 선언된 리소스에 한함 (대소문자 무관)인식 리소스. 인식 언어도 이 값으로 결정됩니다. 선언되지 않은 이름은 거부됩니다
params.audio_formatobject선택아래 audio_format.* 하위 필드object가 아닌 값(문자열 등)은 무시됩니다
params.audio_format.encodingstring선택raw PCM16LE로 해석되는 값
pcm
그 외 값은 검증하지 않고 컨테이너로 디코딩을 시도합니다 (wav · flac · ogg · mp3 등)
인코딩 힌트 (선택). 소문자·trim 후 비교하며, 미지정 시 컨테이너를 탐색한 뒤 raw PCM16LE로 간주합니다.
params.audio_format.sample_rateint선택양의 정수샘플링 레이트 (기본 16000, 권장 16000). 16kHz로 변환되어 처리됩니다.
params.audio_format.channelsint선택양의 정수채널 수 (기본 1, 권장 1). mono로 변환되어 처리됩니다
params.configobject선택아래 config.* 하위 필드세부 옵션. 범위를 벗어나거나 타입이 맞지 않는 값은 거부되지 않고 무시되며, result.config_status에 -100(정상은 1)으로 보고됩니다
params.config.levelint선택0–4거절의 강도 (기본 1). 값이 클수록 거절 강도가 커집니다.
params.config.tm_limitint선택3–600한 번의 인식에서 처리할 수 있는 최대 음성 길이(초, 기본 30). 이 길이를 넘는 음성은 인식에 실패합니다.
params.config.pause_thint선택250–2500발화가 끝났다고 판정하기 위한 최소 묵음 길이(ms, 기본 500). 이 길이만큼 묵음이 이어지면 인식을 종료합니다.

응답 Server → Client · session.started

필드타입설명
typestring"session.started" 고정
session_idstring발급된 세션 ID. 이후 서버가 보내는 모든 메시지에 포함됩니다
subscription_uuidstring세션에 적용된 구독 UUID
subscription_plan_uidint구독 플랜 ID
subscription_statusstring구독 상태
server_timestring응답 서버 시각 (ISO 8601 UTC)
// 클라이언트 → 서버
{
  "type": "session.start",
  "user_sid": "user-2001",
  "service": "sr",
  "operation": "recognize_long",
  "params": {
    "text": "Once upon a time there lived a little girl. She loved to read books.",
    "resource_name": "KONG_ALL",
    "audio_format": { "sample_rate": 16000, "channels": 1, "encoding": "pcm" }
  }
}

// 서버 → 클라이언트
{
  "type": "session.started",
  "session_id": "01HXXXXXXXXXXXXXXXXXXXXXXX",
  "subscription_uuid": "…",
  "subscription_plan_uid": 0,
  "subscription_status": "…",
  "server_time": "2026-02-12T10:30:45Z"
}
session.started를 받기 전에 command·Binary 프레임·session.heartbeat·session.end를 보내면 PROTOCOL_VIOLATION으로 연결이 종료됩니다. api_key 필드는 넣을 수 없으며(INVALID_MESSAGE), API Key는 연결 handshake에서만 전달합니다.

② command: start_audio — 오디오 수신 시작

요청 Client → Server · Text 프레임 (JSON)

필드타입필수허용 값설명
typestring필수command메시지 종류
commandstring필수start_audio커맨드 이름

응답 Server → Client · command.ack

필드타입설명
typestring"command.ack" 고정
session_idstring세션 ID
commandstring수락된 커맨드 이름
server_timestring응답 서버 시각 (ISO 8601 UTC)
server_processing_time_nsint서버 처리 소요 시간 (nanoseconds)
// 클라이언트 → 서버
{ "type": "command", "command": "start_audio" }

// 서버 → 클라이언트
{
  "type": "command.ack",
  "session_id": "01HXXXXXXXXXXXXXXXXXXXXXXX",
  "command": "start_audio",
  "server_time": "2026-02-12T10:30:45Z",
  "server_processing_time_ns": 85000
}

③ Binary 오디오 프레임 — 오디오 전송

요청 Client → Server · Binary 프레임

프레임내용설명
Binary오디오 바이트①의 params.audio_format 형식으로 해석합니다. JSON 래핑 없이 바이트 그대로 보냅니다

응답 Server → Client · data_chunk.ack (프레임마다 1회)

필드타입설명
typestring"data_chunk.ack" 고정
session_idstring세션 ID
bytesint이번 프레임의 수신 바이트 수
server_timestring응답 서버 시각 (ISO 8601 UTC)
server_processing_time_nsint서버 처리 소요 시간 (nanoseconds)
// 서버 → 클라이언트
{
  "type": "data_chunk.ack",
  "session_id": "01HXXXXXXXXXXXXXXXXXXXXXXX",
  "bytes": 16000,
  "server_time": "2026-02-12T10:30:45Z",
  "server_processing_time_ns": 412000
}
data_chunk.ack는 수신 확인일 뿐 최종 결과가 아닙니다. 최종 결과는 ④ finalize_audio 이후에 옵니다.

④ command: finalize_audio — 수신 종료 · 인식 실행

요청 Client → Server · Text 프레임 (JSON)

필드타입필수허용 값설명
typestring필수command메시지 종류
commandstring필수finalize_audio커맨드 이름

응답 1 Server → Client · command.ack

필드타입설명
typestring"command.ack" 고정
session_idstring세션 ID
commandstring"finalize_audio" 고정
server_timestring응답 서버 시각 (ISO 8601 UTC)
server_processing_time_nsint서버 처리 소요 시간 (nanoseconds)

응답 2 Server → Client · recognition.result — 필드는 결과 구조체를 참고하세요

// 클라이언트 → 서버
{ "type": "command", "command": "finalize_audio" }

// 서버 → 클라이언트 (1) 커맨드 수락
{
  "type": "command.ack",
  "session_id": "01HXXXXXXXXXXXXXXXXXXXXXXX",
  "command": "finalize_audio",
  "server_time": "2026-02-12T10:30:46Z",
  "server_processing_time_ns": 310000000
}

// 서버 → 클라이언트 (2) 결과
{
  "type": "recognition.result",
  "session_id": "01HXXXXXXXXXXXXXXXXXXXXXXX",
  "is_final": true,
  "result": {
    "result_type": "recognition",
    "text": "Once upon a time there lived a little girl. She loved to read books.",
    "score": 88,
    "words": [ … ]
  },
  "statistics": { … },
  "server_time": "2026-02-12T10:30:46Z"
}
처리가 끝나면 command.ack와 recognition.result가 이 순서로 연달아 옵니다. 커맨드가 실패하면 두 메시지 대신 command.error가 오며, 세션은 유지됩니다.

⑤ session.end — 세션 종료

요청 Client → Server · Text 프레임 (JSON)

필드타입필수허용 값설명
typestring필수session.end메시지 종류
reasonstring선택자유 문자열종료 사유 (기본 completed). session.ended에 그대로 반환됩니다

응답 Server → Client · session.ended

필드타입설명
typestring"session.ended" 고정
session_idstring세션 ID
reasonstring요청의 reason 값
statistics.frames_receivedint세션 동안 수신한 Binary 프레임 수
statistics.audio_bytesint세션 동안 수신한 오디오 누적 바이트 수
server_timestring응답 서버 시각 (ISO 8601 UTC)
// 클라이언트 → 서버
{ "type": "session.end", "reason": "completed" }

// 서버 → 클라이언트
{
  "type": "session.ended",
  "session_id": "01HXXXXXXXXXXXXXXXXXXXXXXX",
  "reason": "completed",
  "statistics": { "frames_received": 1, "audio_bytes": 640044 },
  "server_time": "2026-02-12T10:30:47Z"
}
session.end는 finalize_audio를 대신 실행하지 않습니다. 결과가 필요하면 ④를 먼저 보내세요. 세션을 오래 유지할 때는 session.heartbeat를 주기적으로 보내 세션을 연장하세요 (30초 주기 권장).

오류 응답

서버는 상황에 따라 두 종류의 오류 메시지를 보냅니다. 오류 코드는 에러 코드를 참고하세요.

타입발생 시점세션
command.errorstart_audio · finalize_audio 등 커맨드 처리 실패유지
session.error세션 시작 실패, 메시지 순서 위반, 잘못된 메시지 형식, Binary 프레임 처리 실패대부분 종료
필드타입설명
typestring"command.error" 또는 "session.error"
session_idstring세션 ID (session.error는 세션이 만들어진 뒤에만 포함)
commandstring실패한 커맨드 이름 (command.error만 포함)
error.codestring오류 코드
error.messagestring오류 메시지
error.detailsobject부가 정보 (있을 때만 포함)
error.ap_request_idstring서버 로그 추적용 요청 ID. 문의 시 함께 전달하세요
server_timestring응답 서버 시각 (ISO 8601 UTC)
{
  "type": "command.error",
  "session_id": "01HXXXXXXXXXXXXXXXXXXXXXXX",
  "command": "finalize_audio",
  "error": { "code": "INVALID_MESSAGE", "message": "…", "ap_request_id": "…" },
  "server_time": "2026-02-12T10:30:46Z"
}

결과 구조체 REST · WebSocket 공용 · JSON 기준

아래 표는 REST 응답 본문과 WebSocket recognition.result 메시지에 공통으로 적용됩니다. REST는 응답 본문 최상위에, WebSocket은 결과 메시지 본문에 같은 필드가 담기며, WebSocket 메시지에는 type·is_final이 추가됩니다. REST 전용 표시가 있는 필드는 WebSocket 결과 메시지에 없습니다.

sr/recognize_long 결과

sr/recognize_long은 문단 단위 장문 인식 오퍼레이션입니다.

필드타입설명
session_idstring세션 ID
server_timestring응답 서버 시각 (ISO 8601 UTC)
errorobject오류 발생 시 포함 (정상 응답 시 부재). 이때 result·statistics는 부재 REST 전용 — WebSocket은 command.error·session.error 메시지로 전달됩니다
statistics.actionstring실행된 엔진 액션명
statistics.sdkstringSDK명 (SelvySR)
statistics.runtimestring런타임 구현체 (sr2lib_runtime) — 런타임 계층의 값이 우선 적용되어 runtime_implementation과 동일한 값이 반환됩니다
statistics.runtime_implementationstring런타임 구현체 ID (sr2lib_runtime)
statistics.audio_sizeint사용자 음성 바이트 수
statistics.reference_audio_sizeint참조 음성 바이트 수 (없으면 0)
statistics.elapsed_nsint처리 소요 시간 (nanoseconds)
statistics.invoke_started_at_nsintinvoke 시작 타임스탬프 (nanoseconds)
statistics.invoke_completed_at_nsintinvoke 완료 타임스탬프 (nanoseconds)
statistics.resource_namestring사용된 리소스명 (recognize_long은 recognition_mode를 포함하지 않음)
result.result_typestring"recognition" 고정
result.textstring인식된 전체 텍스트
result.scorefloat전체 인식 점수 (0–100)
result.metadataobject엔진 부가 정보 (없으면 빈 object)
result.words[]array어절 배열 (스크립트 순서)
result.words[].textstring어절 텍스트
result.words[].scorefloat어절 점수 (0–100, 미발화 시 0)
result.words[].start_msint시작 시각 (ms, 미발화 시 0)
result.words[].end_msint종료 시각 (ms, 미발화 시 0)
result.words[].raw_data.strstring어절 텍스트
result.words[].raw_data.scorefloat어절 점수 (0–100, 미발화 시 0)
result.words[].raw_data.start_msint시작 시각 (ms, 미발화 시 0)
result.words[].raw_data.end_msint종료 시각 (ms, 미발화 시 0)
result.words[].raw_data.is_spokenbool발화 여부
result.words[].raw_data.phonemes[]array음소 배열 (발화된 어절에만 포함)
result.words[].raw_data.phonemes[].strstringARPABET 기호 (유사 표기)
result.words[].raw_data.phonemes[].scorefloat음소 점수 (0–100)
result.words[].raw_data.phonemes[].start_msint음소 시작 시각 (ms)
result.words[].raw_data.phonemes[].end_msint음소 종료 시각 (ms)
result.words[].raw_data.phonemes[].is_vowelbool모음 여부
result.raw_data.strstring인식된 전체 텍스트 — 미발화 어절은 괄호로 감싸짐 (예: "hello (world)")
result.raw_data.scorefloat전체 인식 점수 (0–100) — 발화된 어절만의 평균 (미발화 어절은 분자·분모에서 제외, 전부 미발화 시 0)
result.raw_data.err_msgstring오류 메시지 (정상 시 빈 문자열)
result.raw_data.wpmfloat분당 단어 수
result.raw_data.words[]array어절 배열 (스크립트 순서, 미발화 어절 포함) — result.words[].raw_data와 동일 구조
result.raw_data.input_info.langstring인식 모델 언어
result.raw_data.input_info.model_namestring인식 모델 이름
result.raw_data.input_info.input_textstring인식 스크립트 문장
result.raw_data.input_info.recognition_configobject인식에 사용된 설정값 (Config)
result.raw_data.input_info.recognition_timeint인식 시작 시각 (UTC timestamp)
result.raw_data.extra.api_namestring호출 API 이름
result.raw_data.extra.paramsstringAPI 호출 파라미터
result.raw_data.extra.returnsstringAPI 반환값
result.raw_data.extra.tagstring반환값 구분자
result.raw_data.extra.call_timeintAPI 호출 시각 (UTC timestamp)
result.raw_data.extra.return_timeintAPI 반환 시각 (UTC timestamp)
result.raw_data.extra.input_configobject실제 엔진 호출 시 사용된 설정값

비교평가

REST 프로토콜

POST /api/v1/sr/assess

요청 필드 JSON 기준

참조 지정 방식 2가지 중 하나를 사용합니다.

필드타입필수허용 값설명
user_sidstring필수사용자 식별자
① 직접 음성 전달 방식 — reference_audio 멀티파트를 함께 전송
params.reference_textstring필수자유 문자열평가 기준 텍스트. ① 방식에서만 필수입니다
② 등록 ID 방식 — 사전 등록된 참조 음성 지정. 아래 중 하나 전송
아래 중
하나
params.reference_idstring택1자유 문자열등록된 참조 음성 ID. 가장 우선 적용됩니다
params.reference_resource_namestring택1자유 문자열사전 등록 리소스명
params.resource_keystring택1자유 문자열리소스 검색 키
params.resource_idstring택1자유 문자열리소스 ID
공통 선택 파라미터
params.enable_intonationbool선택true · false억양 곡선 포함 (기본 false). bool이 아닌 값은 무시됩니다
params.recognition_modestring선택no_epd — EPD 미사용 — 오디오 전체를 인식
use_epd — EPD로 발화 구간을 검출해 인식
use_epd_with_sil_append — EPD 사용 + 검출 구간 뒤에 묵음(SIL) 추가
기본 use_epd_with_sil_append. 대소문자 무관
params.set_text_typestring선택LIST — 여러 문장 후보 중 1문장을 인식 (후보는 ;로 구분)
CHUNK — 1문장을 단어 단위로 분리 입력 (;로 구분)
CHUNK_SKIP — CHUNK + 단어 1개를 건너뛸 수 있는 형식
CHUNK_SERIAL — CHUNK + 어느 단어까지 발성했는지 확인
CHUNK_SERIAL_N_SKIP — CHUNK_SKIP과 CHUNK_SERIAL을 함께 적용
기본 LIST. 대소문자 무관
params.resource_namestring필수배포 설정에 선언된 리소스에 한함 (대소문자 무관)인식 리소스. 인식 언어도 이 값으로 결정됩니다. 선언되지 않은 이름은 거부됩니다
params.audio_formatobject선택아래 audio_format.* 하위 필드object가 아닌 값(문자열 등)은 무시됩니다
params.audio_format.encodingstring선택raw PCM16LE로 해석되는 값
pcm
그 외 값은 검증하지 않고 컨테이너로 디코딩을 시도합니다 (wav · flac · ogg · mp3 등)
인코딩 힌트 (선택). 소문자·trim 후 비교하며, 미지정 시 컨테이너를 탐색한 뒤 raw PCM16LE로 간주합니다.
params.audio_format.sample_rateint선택양의 정수샘플링 레이트 (기본 16000, 권장 16000). 16kHz로 변환되어 처리됩니다.
params.audio_format.channelsint선택양의 정수채널 수 (기본 1, 권장 1). mono로 변환되어 처리됩니다
params.configobject선택아래 config.* 하위 필드세부 옵션. 범위를 벗어나거나 타입이 맞지 않는 값은 거부되지 않고 무시되며, result.config_status에 -100(정상은 1)으로 보고됩니다
params.config.levelint선택0–4거절의 강도 (기본 1). 값이 클수록 거절 강도가 커집니다.
params.config.tm_limitint선택3–600한 번의 인식에서 처리할 수 있는 최대 음성 길이(초, 기본 30). 이 길이를 넘는 음성은 인식에 실패합니다.
params.config.pause_thint선택250–2500발화가 끝났다고 판정하기 위한 최소 묵음 길이(ms, 기본 500). 이 길이만큼 묵음이 이어지면 인식을 종료합니다.
② 방식의 식별자 우선순위 — reference_id가 있으면 이 값이 사용되고, 없으면 reference_resource_name → resource_key → resource_id 순으로 처음 발견된 비어 있지 않은 값이 식별자로 사용됩니다. 네 필드 중 하나라도 채워져 있으면 등록 ID 방식으로 동작하며, 조회 실패 시 요청이 INVALID_REQUEST로 거부됩니다.

호출 샘플 — ① 참조 음성 직접 전달

curl -X POST "https://{host}/api/v1/sr/assess" \
  -H "Authorization: Bearer $API_KEY" \
  -F 'request={"user_sid":"user-2001","params":{"reference_text":"Hello world",
       "resource_name":"KONG_ALL"}};type=application/json' \
  -F "reference_audio=@native.wav" \
  -F "audio=@student.wav"
import requests, json

resp = requests.post(
    "https://{host}/api/v1/sr/assess",
    headers={"Authorization": f"Bearer {API_KEY}"},
    files={
        "request": (None, json.dumps({
            "user_sid": "user-2001",
            "params": {
                "reference_text": "Hello world",
                "resource_name": "KONG_ALL",
            },
        }), "application/json"),
        # 참조 음성과 사용자 음성을 각각 별도 파트로 전송
        "reference_audio": ("native.wav", open("native.wav", "rb"), "audio/wav"),
        "audio": ("student.wav", open("student.wav", "rb"), "audio/wav"),
    },
)
ass = resp.json()["result"]["ass_res"]
print(ass["overall"], ass["prosody_score"], ass["pronunciation_score"])

# ass_res.words[]는 점수만 제공하므로 어절 텍스트는 user_result에서 가져옵니다.
words = resp.json()["result"]["user_result"]["results"][0]["words"]
for w, sc in zip(words, ass["words"]):
    print(w["str"], sc["pronunciation"], sc["intonation"], sc["timing"], sc["loudness"])
const fs = require("fs");
const path = require("path");

const HOST = "https://{host}";

async function main() {
    const userPath = "./student.wav";
    const refPath  = "./native.wav";

    const fd = new FormData();

    fd.append(
        "request",
        new Blob(
            [
                JSON.stringify({
                    user_sid: "user-2001",
                    params: {
                        reference_text: "Hello world",
                        resource_name: "KONG_ALL",
                    },
                }),
            ],
            { type: "application/json" }
        )
    );

    // 참조 음성과 사용자 음성을 각각 별도 파트로 전송
    fd.append("reference_audio", new Blob([fs.readFileSync(refPath)]), path.basename(refPath));
    fd.append("audio", new Blob([fs.readFileSync(userPath)]), path.basename(userPath));

    const res = await fetch(`${HOST}/api/v1/sr/assess`, {
        method: "POST",
        headers: { Authorization: `Bearer ${API_KEY}` },
        body: fd,
    });

    if (!res.ok) {
        console.error("HTTP Error:", res.status, await res.text());
        return;
    }

    const ass = (await res.json()).result.ass_res;
    console.log(ass.overall, ass.prosody_score, ass.pronunciation_score);
}

main();

호출 샘플 — ② 서버에 등록된 참조 사용

# 참조 음성은 이미 서버에 등록되어 있으므로 reference_audio 파트를 보내지 않습니다.
curl -X POST "https://{host}/api/v1/sr/assess" \
  -H "Authorization: Bearer $API_KEY" \
  -F 'request={"user_sid":"user-2001","params":{"reference_id":"ref-001",
       "resource_name":"KONG_ALL"}};type=application/json' \
  -F "audio=@student.wav"
import requests, json

# reference_id 대신 reference_resource_name · resource_key · resource_id 중
# 하나를 보내도 됩니다 (reference_id 가 가장 우선 적용).
resp = requests.post(
    "https://{host}/api/v1/sr/assess",
    headers={"Authorization": f"Bearer {API_KEY}"},
    files={
        "request": (None, json.dumps({
            "user_sid": "user-2001",
            "params": {
                "reference_id": "ref-001",
                "resource_name": "KONG_ALL",
            },
        }), "application/json"),
        # 사용자 음성만 전송
        "audio": ("student.wav", open("student.wav", "rb"), "audio/wav"),
    },
)
ass = resp.json()["result"]["ass_res"]
print(ass["overall"], ass["prosody_score"], ass["pronunciation_score"])
const fs = require("fs");
const path = require("path");

const HOST = "https://{host}";

async function main() {
    const userPath = "./student.wav";

    const fd = new FormData();

    // reference_id 대신 reference_resource_name · resource_key · resource_id 중
    // 하나를 보내도 됩니다 (reference_id 가 가장 우선 적용).
    fd.append(
        "request",
        new Blob(
            [
                JSON.stringify({
                    user_sid: "user-2001",
                    params: {
                        reference_id: "ref-001",
                        resource_name: "KONG_ALL",
                    },
                }),
            ],
            { type: "application/json" }
        )
    );

    // 참조 음성은 서버에 등록되어 있어 사용자 음성만 전송합니다.
    fd.append("audio", new Blob([fs.readFileSync(userPath)]), path.basename(userPath));

    const res = await fetch(`${HOST}/api/v1/sr/assess`, {
        method: "POST",
        headers: { Authorization: `Bearer ${API_KEY}` },
        body: fd,
    });

    if (!res.ok) {
        console.error("HTTP Error:", res.status, await res.text());
        return;
    }

    const ass = (await res.json()).result.ass_res;
    console.log(ass.overall, ass.prosody_score, ass.pronunciation_score);
}

main();

응답 예시

종합 점수는 result.ass_res에, 어절·음소 상세는 result.user_result에 담깁니다. ass_res.words[]는 점수만 제공하며 어절 텍스트를 포함하지 않으므로, 어절 텍스트는 같은 순서의 user_result.results[0].words[]와 대응시켜 사용합니다.

{
  "session_id": "01HXXX…",
  "result": {
    "ass_res": {
      "overall": 87,
      "prosody_score": 82,
      "pronunciation_score": 88,
      "intonation_score": 85,
      "timing_score": 80,
      "loudness_score": 90,
      "err_msg": "",
      "words": [
        { "bSpoken": true, "bSmallLoudness": false,
          "pronunciation": 91, "intonation": 85, "timing": 80, "loudness": 90 }
      ]
    },
    "user_result": {
      "results": [
        { "str": "Hello world", "score": 88,
          "words": [
            { "str": "Hello", "score": 91,
              "phonemes": [ { "str": "HH", "score": 95 }, { "str": "AH", "score": 88 } ] }
          ]
        }
      ]
    },
    "ref_result": { "…": "user_result와 동일한 구조" }
  },
  "statistics": { … },
  "server_time": "2026-02-12T10:30:45Z"
}

응답 REST 응답 본문 — 필드는 결과 구조체를 참고하세요


WebSocket 프로토콜

WS wss://{host}/ws/v1

한 연결에서 아래 순서로 메시지를 주고받습니다. Text 프레임은 JSON 제어 메시지이고, Binary 프레임은 오디오입니다. 아래 요청·응답 필드는 모두 JSON 메시지 기준입니다. 연결 인증은 인증 (API Key)과 브라우저 인증을 참고하세요. 참조 지정 방식에 따라 흐름이 다르며, ② 등록 ID 방식은 ②·③ 단계를 건너뜁니다.

SR · 비교평가 세션 흐름도 — ① 직접 음성 전달 방식
     Client                                 Server
     ──────                                 ──────
 ①  session.start              ─▶   (params.mode: "instance")
                               ◀─  session.started
 ②  [binary reference audio]   ─▶
                               ◀─  data_chunk.ack       (프레임마다 1회)
 ③  command: prepare_reference ─▶
                               ◀─  ref.ok               (실패 시 ref.failed)
                               ◀─  command.ack
 ④  command: start_audio       ─▶
                               ◀─  command.ack
 ⑤  [binary user audio]        ─▶
                               ◀─  data_chunk.ack       (프레임마다 1회)
 ⑥  command: finalize_audio    ─▶
                               ◀─  command.ack
                               ◀─  assessment.result    (최종 결과)
 ⑦  session.end                ─▶
                               ◀─  session.ended

 ※  session.heartbeat          ─▶   (① ~ ⑦ 사이, 30초 권장)
                               ◀─  session.heartbeat.ack
SR · 비교평가 세션 흐름도 — ② 등록 ID 방식
     Client                                 Server
     ──────                                 ──────
 ①  session.start              ─▶   (params.reference_id 등)
                               ◀─  session.started
 ④  command: start_audio       ─▶
                               ◀─  command.ack
 ⑤  [binary user audio]        ─▶
                               ◀─  data_chunk.ack       (프레임마다 1회)
 ⑥  command: finalize_audio    ─▶
                               ◀─  command.ack
                               ◀─  assessment.result    (최종 결과)
 ⑦  session.end                ─▶
                               ◀─  session.ended

 ※  session.heartbeat          ─▶   (① ~ ⑦ 사이, 30초 권장)
                               ◀─  session.heartbeat.ack
session.heartbeat — ① session.started를 받은 뒤부터 ⑦ session.end를 보내기 전까지 사이에 보냅니다. WebSocket 연결을 오래 유지하는 경우 세션이 만료되지 않도록 주기적으로 호출해 세션을 연장하는 데 사용합니다 (30초 주기 권장).

① session.start — 세션 시작

요청 Client → Server · Text 프레임 (JSON)

필드타입필수허용 값설명
typestring필수session.start메시지 종류
user_sidstring필수사용자 식별자
servicestring필수sr서비스
operationstring필수assess오퍼레이션
paramsobject필수아래 params.* 하위 필드요청 파라미터. REST 요청의 params에 ① 방식용 params.mode가 추가됩니다
① 직접 음성 전달 방식 — 참조 음성을 Binary 프레임으로 전송 (아래 ②·③ 단계)
params.modestring필수instance① 방식 지정. 이 값이 있어야 prepare_reference 전에 받은 Binary 프레임을 참조 음성으로 누적합니다. WebSocket 전용 — REST는 reference_audio 파트로 구분하므로 필요 없습니다
params.reference_textstring필수자유 문자열평가 기준 텍스트. ① 방식에서만 필수입니다
② 등록 ID 방식 — 사전 등록된 참조 음성 지정. 아래 중 하나 전송
아래 중
하나
params.reference_idstring택1자유 문자열등록된 참조 음성 ID. 가장 우선 적용됩니다
params.reference_resource_namestring택1자유 문자열사전 등록 리소스명
params.resource_keystring택1자유 문자열리소스 검색 키
params.resource_idstring택1자유 문자열리소스 ID
공통 선택 파라미터
params.enable_intonationbool선택true · false억양 곡선 포함 (기본 false). bool이 아닌 값은 무시됩니다
params.recognition_modestring선택no_epd — EPD 미사용 — 오디오 전체를 인식
use_epd — EPD로 발화 구간을 검출해 인식
use_epd_with_sil_append — EPD 사용 + 검출 구간 뒤에 묵음(SIL) 추가
기본 use_epd_with_sil_append. 대소문자 무관
params.set_text_typestring선택LIST — 여러 문장 후보 중 1문장을 인식 (후보는 ;로 구분)
CHUNK — 1문장을 단어 단위로 분리 입력 (;로 구분)
CHUNK_SKIP — CHUNK + 단어 1개를 건너뛸 수 있는 형식
CHUNK_SERIAL — CHUNK + 어느 단어까지 발성했는지 확인
CHUNK_SERIAL_N_SKIP — CHUNK_SKIP과 CHUNK_SERIAL을 함께 적용
기본 LIST. 대소문자 무관
params.resource_namestring필수배포 설정에 선언된 리소스에 한함 (대소문자 무관)인식 리소스. 인식 언어도 이 값으로 결정됩니다. 선언되지 않은 이름은 거부됩니다
params.audio_formatobject선택아래 audio_format.* 하위 필드object가 아닌 값(문자열 등)은 무시됩니다
params.audio_format.encodingstring선택raw PCM16LE로 해석되는 값
pcm
그 외 값은 검증하지 않고 컨테이너로 디코딩을 시도합니다 (wav · flac · ogg · mp3 등)
인코딩 힌트 (선택). 소문자·trim 후 비교하며, 미지정 시 컨테이너를 탐색한 뒤 raw PCM16LE로 간주합니다.
params.audio_format.sample_rateint선택양의 정수샘플링 레이트 (기본 16000, 권장 16000). 16kHz로 변환되어 처리됩니다.
params.audio_format.channelsint선택양의 정수채널 수 (기본 1, 권장 1). mono로 변환되어 처리됩니다
params.configobject선택아래 config.* 하위 필드세부 옵션. 범위를 벗어나거나 타입이 맞지 않는 값은 거부되지 않고 무시되며, result.config_status에 -100(정상은 1)으로 보고됩니다
params.config.levelint선택0–4거절의 강도 (기본 1). 값이 클수록 거절 강도가 커집니다.
params.config.tm_limitint선택3–600한 번의 인식에서 처리할 수 있는 최대 음성 길이(초, 기본 30). 이 길이를 넘는 음성은 인식에 실패합니다.
params.config.pause_thint선택250–2500발화가 끝났다고 판정하기 위한 최소 묵음 길이(ms, 기본 500). 이 길이만큼 묵음이 이어지면 인식을 종료합니다.

응답 Server → Client · session.started

필드타입설명
typestring"session.started" 고정
session_idstring발급된 세션 ID. 이후 서버가 보내는 모든 메시지에 포함됩니다
subscription_uuidstring세션에 적용된 구독 UUID
subscription_plan_uidint구독 플랜 ID
subscription_statusstring구독 상태
server_timestring응답 서버 시각 (ISO 8601 UTC)
// 클라이언트 → 서버 — ① 직접 음성 전달 방식
{
  "type": "session.start",
  "user_sid": "user-2001",
  "service": "sr",
  "operation": "assess",
  "params": {
    "mode": "instance",
    "reference_text": "Hello world",
    "resource_name": "KONG_ALL",
    "audio_format": { "sample_rate": 16000, "channels": 1, "encoding": "pcm" }
  }
}

// 클라이언트 → 서버 — ② 등록 ID 방식
{
  "type": "session.start",
  "user_sid": "user-2001",
  "service": "sr",
  "operation": "assess",
  "params": {
    "reference_id": "ref-0001",
    "resource_name": "KONG_ALL",
    "audio_format": { "sample_rate": 16000, "channels": 1, "encoding": "pcm" }
  }
}

// 서버 → 클라이언트
{
  "type": "session.started",
  "session_id": "01HXXXXXXXXXXXXXXXXXXXXXXX",
  "subscription_uuid": "…",
  "subscription_plan_uid": 0,
  "subscription_status": "…",
  "server_time": "2026-02-12T10:30:45Z"
}
② 방식에서 참조 조회에 실패하면 session.started 대신 session.error가 오고 연결이 종료됩니다.
session.started를 받기 전에 command·Binary 프레임·session.heartbeat·session.end를 보내면 PROTOCOL_VIOLATION으로 연결이 종료됩니다. api_key 필드는 넣을 수 없으며(INVALID_MESSAGE), API Key는 연결 handshake에서만 전달합니다.

② Binary 오디오 프레임 — 참조 음성 전송 ① 방식만

요청 Client → Server · Binary 프레임

프레임내용설명
Binary참조 음성 바이트①의 params.audio_format 형식으로 해석합니다. JSON 래핑 없이 바이트 그대로 보냅니다

응답 Server → Client · data_chunk.ack (프레임마다 1회)

필드타입설명
typestring"data_chunk.ack" 고정
session_idstring세션 ID
bytesint이번 프레임의 수신 바이트 수
server_timestring응답 서버 시각 (ISO 8601 UTC)
server_processing_time_nsint서버 처리 소요 시간 (nanoseconds)
params.mode: "instance" 세션에서 ③ prepare_reference 전에 받은 Binary 프레임은 모두 참조 음성으로 누적됩니다. ③ 이후에 받은 프레임부터 사용자 음성이 됩니다.

③ command: prepare_reference — 참조 확정 ① 방식만

요청 Client → Server · Text 프레임 (JSON)

필드타입필수허용 값설명
typestring필수command메시지 종류
commandstring필수prepare_reference커맨드 이름

응답 1 Server → Client · ref.ok · ref.failed

필드타입설명
typestring"ref.ok" 또는 "ref.failed"
session_idstring세션 ID
modestring"instance"
reference.readybool참조 준비 성공 여부 (ref.ok는 true)
reference.audio_bytesint누적된 참조 음성 바이트 수 (16kHz mono PCM16LE 기준)
reference.textstring기준 텍스트 (params.reference_text가 있을 때만 포함)
messagestring처리 메시지. 실패 시 사유 (예: reference audio is required for sr/assess instance mode)
server_timestring응답 서버 시각 (ISO 8601 UTC)

응답 2 Server → Client · command.ack — 실패 시에는 command.error가 옵니다

필드타입설명
typestring"command.ack" 고정
session_idstring세션 ID
commandstring"prepare_reference" 고정
server_timestring응답 서버 시각 (ISO 8601 UTC)
server_processing_time_nsint서버 처리 소요 시간 (nanoseconds)
// 클라이언트 → 서버
{ "type": "command", "command": "prepare_reference" }

// 서버 → 클라이언트 (1) 참조 준비 결과
{
  "type": "ref.ok",
  "session_id": "01HXXXXXXXXXXXXXXXXXXXXXXX",
  "mode": "instance",
  "reference": { "ready": true, "audio_bytes": 48044, "text": "Hello world" },
  "message": "reference prepared",
  "server_time": "2026-02-12T10:30:45Z"
}

// 서버 → 클라이언트 (2) 커맨드 수락
{
  "type": "command.ack",
  "session_id": "01HXXXXXXXXXXXXXXXXXXXXXXX",
  "command": "prepare_reference",
  "server_time": "2026-02-12T10:30:45Z",
  "server_processing_time_ns": 90000
}
ref.ok·ref.failed가 command.ack·command.error보다 먼저 옵니다. params.reference_text가 없거나 참조 음성을 받지 못했으면 ref.failed 다음 command.error가 옵니다. 이 상태에서 ⑥ finalize_audio를 보내면 reference_not_ready로 거부되므로, 새 세션으로 다시 시작하세요. 이미 확정된 뒤 다시 보내면 ref.ok(message = reference already prepared)를 다시 보냅니다.

④ command: start_audio — 오디오 수신 시작

요청 Client → Server · Text 프레임 (JSON)

필드타입필수허용 값설명
typestring필수command메시지 종류
commandstring필수start_audio커맨드 이름

응답 Server → Client · command.ack

필드타입설명
typestring"command.ack" 고정
session_idstring세션 ID
commandstring수락된 커맨드 이름
server_timestring응답 서버 시각 (ISO 8601 UTC)
server_processing_time_nsint서버 처리 소요 시간 (nanoseconds)
// 클라이언트 → 서버
{ "type": "command", "command": "start_audio" }

// 서버 → 클라이언트
{
  "type": "command.ack",
  "session_id": "01HXXXXXXXXXXXXXXXXXXXXXXX",
  "command": "start_audio",
  "server_time": "2026-02-12T10:30:45Z",
  "server_processing_time_ns": 85000
}

⑤ Binary 오디오 프레임 — 사용자 음성 전송

요청 Client → Server · Binary 프레임

프레임내용설명
Binary오디오 바이트①의 params.audio_format 형식으로 해석합니다. JSON 래핑 없이 바이트 그대로 보냅니다

응답 Server → Client · data_chunk.ack (프레임마다 1회)

필드타입설명
typestring"data_chunk.ack" 고정
session_idstring세션 ID
bytesint이번 프레임의 수신 바이트 수
server_timestring응답 서버 시각 (ISO 8601 UTC)
server_processing_time_nsint서버 처리 소요 시간 (nanoseconds)
// 서버 → 클라이언트
{
  "type": "data_chunk.ack",
  "session_id": "01HXXXXXXXXXXXXXXXXXXXXXXX",
  "bytes": 16000,
  "server_time": "2026-02-12T10:30:45Z",
  "server_processing_time_ns": 412000
}
data_chunk.ack는 수신 확인일 뿐 최종 결과가 아닙니다. 최종 결과는 ⑥ finalize_audio 이후에 옵니다.

⑥ command: finalize_audio — 수신 종료 · 비교평가 실행

요청 Client → Server · Text 프레임 (JSON)

필드타입필수허용 값설명
typestring필수command메시지 종류
commandstring필수finalize_audio커맨드 이름

응답 1 Server → Client · command.ack

필드타입설명
typestring"command.ack" 고정
session_idstring세션 ID
commandstring"finalize_audio" 고정
server_timestring응답 서버 시각 (ISO 8601 UTC)
server_processing_time_nsint서버 처리 소요 시간 (nanoseconds)

응답 2 Server → Client · assessment.result — 필드는 결과 구조체를 참고하세요

// 클라이언트 → 서버
{ "type": "command", "command": "finalize_audio" }

// 서버 → 클라이언트 (1) 커맨드 수락
{
  "type": "command.ack",
  "session_id": "01HXXXXXXXXXXXXXXXXXXXXXXX",
  "command": "finalize_audio",
  "server_time": "2026-02-12T10:30:46Z",
  "server_processing_time_ns": 310000000
}

// 서버 → 클라이언트 (2) 결과
{
  "type": "assessment.result",
  "session_id": "01HXXXXXXXXXXXXXXXXXXXXXXX",
  "is_final": true,
  "result": {
    "ass_res": { … },
    "ref_result": { … },
    …
  },
  "statistics": { … },
  "server_time": "2026-02-12T10:30:46Z"
}
처리가 끝나면 command.ack와 assessment.result가 이 순서로 연달아 옵니다. 커맨드가 실패하면 두 메시지 대신 command.error가 오며, 세션은 유지됩니다.

⑦ session.end — 세션 종료

요청 Client → Server · Text 프레임 (JSON)

필드타입필수허용 값설명
typestring필수session.end메시지 종류
reasonstring선택자유 문자열종료 사유 (기본 completed). session.ended에 그대로 반환됩니다

응답 Server → Client · session.ended

필드타입설명
typestring"session.ended" 고정
session_idstring세션 ID
reasonstring요청의 reason 값
statistics.frames_receivedint세션 동안 수신한 Binary 프레임 수
statistics.audio_bytesint세션 동안 수신한 오디오 누적 바이트 수
server_timestring응답 서버 시각 (ISO 8601 UTC)
// 클라이언트 → 서버
{ "type": "session.end", "reason": "completed" }

// 서버 → 클라이언트
{
  "type": "session.ended",
  "session_id": "01HXXXXXXXXXXXXXXXXXXXXXXX",
  "reason": "completed",
  "statistics": { "frames_received": 2, "audio_bytes": 96088 },
  "server_time": "2026-02-12T10:30:47Z"
}
session.end는 finalize_audio를 대신 실행하지 않습니다. 결과가 필요하면 ⑥을 먼저 보내세요. 세션을 오래 유지할 때는 session.heartbeat를 주기적으로 보내 세션을 연장하세요 (30초 주기 권장).

오류 응답

서버는 상황에 따라 두 종류의 오류 메시지를 보냅니다. 오류 코드는 에러 코드를 참고하세요.

타입발생 시점세션
command.errorprepare_reference · start_audio · finalize_audio 등 커맨드 처리 실패 (예: 참조 미확정 상태의 finalize_audio)유지
session.error세션 시작 실패(② 방식의 참조 조회 실패 포함), 메시지 순서 위반, 잘못된 메시지 형식, Binary 프레임 처리 실패대부분 종료
필드타입설명
typestring"command.error" 또는 "session.error"
session_idstring세션 ID (session.error는 세션이 만들어진 뒤에만 포함)
commandstring실패한 커맨드 이름 (command.error만 포함)
error.codestring오류 코드
error.messagestring오류 메시지
error.detailsobject부가 정보 (있을 때만 포함)
error.ap_request_idstring서버 로그 추적용 요청 ID. 문의 시 함께 전달하세요
server_timestring응답 서버 시각 (ISO 8601 UTC)
{
  "type": "command.error",
  "session_id": "01HXXXXXXXXXXXXXXXXXXXXXXX",
  "command": "finalize_audio",
  "error": { "code": "INVALID_MESSAGE", "message": "…", "ap_request_id": "…" },
  "server_time": "2026-02-12T10:30:46Z"
}

결과 구조체 REST · WebSocket 공용 · JSON 기준

아래 표는 REST 응답 본문과 WebSocket assessment.result 메시지에 공통으로 적용됩니다. REST는 응답 본문 최상위에, WebSocket은 결과 메시지 본문에 같은 필드가 담기며, WebSocket 메시지에는 type·is_final이 추가됩니다. REST 전용 표시가 있는 필드는 WebSocket 결과 메시지에 없습니다.

sr/assess 결과

sr/assess 응답 결과 구조입니다. result.ass_res에 종합 점수, result.user_result에 어절·음소 상세가 담깁니다.

필드타입설명
session_idstring세션 ID
server_timestring응답 서버 시각 (ISO 8601 UTC)
errorobject오류 발생 시 포함 (정상 응답 시 부재). 이때 result·statistics는 부재 REST 전용 — WebSocket은 command.error·session.error 메시지로 전달됩니다
statistics.actionstring실행된 엔진 액션명
statistics.sdkstringSDK명 (SelvySR)
statistics.runtimestring런타임 구현체 (sr2lib_runtime) — 런타임 계층의 값이 우선 적용되어 runtime_implementation과 동일한 값이 반환됩니다
statistics.runtime_implementationstring런타임 구현체 ID (sr2lib_runtime)
statistics.audio_sizeint사용자 음성 바이트 수
statistics.reference_audio_sizeint참조 음성 바이트 수 (없으면 0)
statistics.elapsed_nsint처리 소요 시간 (nanoseconds)
statistics.invoke_started_at_nsintinvoke 시작 타임스탬프 (nanoseconds)
statistics.invoke_completed_at_nsintinvoke 완료 타임스탬프 (nanoseconds)
statistics.recognition_modestring사용자 음성 인식 모드
statistics.resource_namestring사용자 음성 인식에 사용된 리소스명
statistics.ref_recognition_modestring참조 음성 인식 모드 — 참조 음성을 직접 전달한 경우에만 포함
statistics.ref_resource_namestring참조 음성 인식에 사용된 리소스명 — 참조 음성을 직접 전달한 경우에만 포함
result.ass_resobject종합 평가 점수 객체
result.ass_res.overallint종합 점수 (0–100)
result.ass_res.prosody_scoreint운율 점수
result.ass_res.pronunciation_scoreint발음 점수
result.ass_res.timing_scoreint리듬 점수
result.ass_res.intonation_scoreint억양 점수
result.ass_res.loudness_scoreint크기 점수
result.ass_res.err_msgstring에러 메시지 (정상 시 빈 문자열)
result.ass_res.words[]array어절별 평가 점수
result.ass_res.words[].bSpokenbool발화 여부
result.ass_res.words[].bSmallLoudnessbool발성 크기 미달 여부
result.ass_res.words[].pronunciationint발음 점수
result.ass_res.words[].intonationint억양 점수
result.ass_res.words[].timingint리듬 점수
result.ass_res.words[].loudnessint크기 점수
result.ass_res.extraobject엔진 호출 부가 정보
result.ass_res.extra.api_namestring호출된 API 이름
result.ass_res.extra.call_timeintAPI 호출 시각 — UTC timestamp << 16 + ms 인코딩
result.ass_res.extra.paramsstringAPI 호출 파라미터 원문
result.ass_res.extra.return_timeintAPI 반환 시각 — UTC timestamp << 16 + ms 인코딩
result.ass_res.extra.returnsstringAPI 반환값 원문
result.ass_res.extra.tagstring반환값 구분 태그
result.user_result.recog_modeint(사용자 음성) Set Text Type
result.user_result.input_texts[]string[](사용자 음성) 인식 문장 후보 목록
result.user_result.err_msgstring(사용자 음성) 에러 메시지
result.user_result.SnRfloat(사용자 음성) 신호 대 잡음비
result.user_result.epd_detectedbool(사용자 음성) EPD 검출 성공 여부
result.user_result.speech_detectedbool(사용자 음성) 음성 인식 성공 여부
result.user_result.epd_start_msint(사용자 음성) EPD 시작점 (ms)
result.user_result.epd_end_msint(사용자 음성) EPD 끝점 (ms)
result.user_result.input_secondsfloat(사용자 음성) 입력 음성 길이 (초)
result.user_result.process_secondsfloat(사용자 음성) 처리 소요 시간 (초)
result.user_result.xRTfloat(사용자 음성) Real-Time Factor
result.user_result.datetimestring(사용자 음성) 결과 직렬화 시점 로컬 시각
result.user_result.input_info.langstring(사용자 음성) 인식 모델 언어
result.user_result.input_info.model_namestring(사용자 음성) 인식 모델 이름
result.user_result.input_info.recog_modeint(사용자 음성) Set Text Type
result.user_result.input_info.input_textstring(사용자 음성) 인식 문장 후보 리스트
result.user_result.input_info.recognition_timeint(사용자 음성) 인식 시작 시각 (UTC timestamp)
result.user_result.input_info.recognition_configobject(사용자 음성) 인식에 사용된 설정값
result.user_result.results[]array(사용자 음성) 인식 결과 후보 배열 — 점수 내림차순
result.user_result.results[].strstring인식된 문장
result.user_result.results[].scorefloat인식 점수 (0–100)
result.user_result.results[].grade_percentageint학습자 백분위 위치
result.user_result.results[].start_msintepd_start_ms 기준 시작점 (ms)
result.user_result.results[].end_msintepd_start_ms 기준 끝점 (ms)
result.user_result.results[].phoneme_stringstring음소 문자열
result.user_result.results[].wpmfloat분당 단어 수
result.user_result.results[].ppsfloat초당 음소 수
result.user_result.results[].spsfloat초당 음절 수
result.user_result.results[].confavgfloat단어별 인식 점수 단순 평균
result.user_result.results[].conftimeavgfloat단어별 인식 점수 시간 가중 평균
result.user_result.results[].words[].strstring어절 텍스트
result.user_result.results[].words[].scorefloat어절 점수 (0–100)
result.user_result.results[].words[].start_msintepd_start_ms 기준 시작점 (ms)
result.user_result.results[].words[].end_msintepd_start_ms 기준 끝점 (ms)
result.user_result.results[].words[].time_weightfloat어절의 시간 비율
result.user_result.results[].words[].time_weighted_scorefloat시간 가중 어절 점수
result.user_result.results[].words[].stressScorefloat강세 점수 (0–100)
result.user_result.results[].words[].phonemes[].strstringARPABET 기호
result.user_result.results[].words[].phonemes[].scorefloat음소 점수 (0–100)
result.user_result.results[].words[].phonemes[].start_msint시작점 (ms)
result.user_result.results[].words[].phonemes[].end_msint끝점 (ms)
result.user_result.results[].words[].phonemes[].phonme_idint음소 내부 ID
result.user_result.results[].words[].phonemes[].typeint음소 종류 비트마스크 — bit0(1) 자음, bit1(2) 모음. 0은 비음성 구간
result.user_result.results[].words[].phonemes[].is_vowelbool모음 여부
result.user_result.results[].words[].phonemes[].is_speechbool음성 구간 여부
result.user_result.extra.api_namestring(사용자 음성) 호출 API 이름
result.user_result.extra.call_timeint(사용자 음성) API 호출 시각 (UTC timestamp)
result.user_result.extra.return_timeint(사용자 음성) API 반환 시각 (UTC timestamp)
result.ref_resultobject참조(원어민) 음성 인식 결과 원본 — result.user_result와 완전히 동일한 구조(위 user_result.* 전체 필드가 그대로 제공됨)이며, 아래 두 contour 필드가 추가됩니다
result.ref_result.Intonationfloat[]참조 pitch draw contour (enable_intonation: true 시에만 포함)
result.ref_result.Loudnessfloat[]참조 energy draw contour (enable_intonation: true 시에만 포함)
result.Intonationfloat[]사용자 pitch contour (enable_intonation: true 시)
result.Loudnessfloat[]사용자 energy contour (enable_intonation: true 시)
result.metadataobject평가 거절 시에만 존재 — 정상 결과에서는 키 자체가 부재 (모델명은 포함되지 않음)
result.metadata.statusstring거절 시 "rejected"
result.metadata.status_codestring거절 사유 코드명 (recognition_speech_failed · user_recognition_speech_failed)
result.metadata.status_code_valueint거절 사유 코드 숫자값
result.metadata.status_messagestring엔진 에러 메시지

억양 분석

REST 프로토콜

POST /api/v1/sr/intonation

발화 음성의 피치(pitch) 곡선을 분석해 억양 데이터를 반환합니다. 결과는 result.Intonation(pitch)과 result.Loudness(energy) 두 개의 float[] 배열이며, 별도의 시간축 필드는 없습니다(등간격 샘플). intonation.result는 WebSocket 메시지의 type이며 REST 단발 응답 본문에는 type 필드가 없습니다.

요청 필드 JSON 기준

필드타입필수허용 값설명
user_sidstring필수사용자 식별자
params.recognition_modestring선택no_epd — EPD 미사용 — 오디오 전체를 인식
use_epd — EPD로 발화 구간을 검출해 인식
use_epd_with_sil_append — EPD 사용 + 검출 구간 뒤에 묵음(SIL) 추가
기본 use_epd_with_sil_append. 대소문자 무관
params.audio_formatobject선택아래 audio_format.* 하위 필드object가 아닌 값(문자열 등)은 무시됩니다
params.audio_format.encodingstring선택raw PCM16LE로 해석되는 값
pcm
그 외 값은 검증하지 않고 컨테이너로 디코딩을 시도합니다 (wav · flac · ogg · mp3 등)
인코딩 힌트 (선택). 소문자·trim 후 비교하며, 미지정 시 컨테이너를 탐색한 뒤 raw PCM16LE로 간주합니다.
params.audio_format.sample_rateint선택양의 정수샘플링 레이트 (기본 16000, 권장 16000). 16kHz로 변환되어 처리됩니다.
params.audio_format.channelsint선택양의 정수채널 수 (기본 1, 권장 1). mono로 변환되어 처리됩니다
params.configobject선택아래 config.* 하위 필드세부 옵션. 범위를 벗어나거나 타입이 맞지 않는 값은 거부되지 않고 무시되며, result.config_status에 -100(정상은 1)으로 보고됩니다
params.config.levelint선택0–4거절의 강도 (기본 1). 값이 클수록 거절 강도가 커집니다.
params.config.tm_limitint선택3–600한 번의 인식에서 처리할 수 있는 최대 음성 길이(초, 기본 30). 이 길이를 넘는 음성은 인식에 실패합니다.
params.config.pause_thint선택250–2500발화가 끝났다고 판정하기 위한 최소 묵음 길이(ms, 기본 500). 이 길이만큼 묵음이 이어지면 인식을 종료합니다.
억양 분석 전용 파라미터는 없으며, sr 공통 파라미터를 그대로 사용합니다. enable_intonation은 이 오퍼레이션에서 항상 활성이므로 전달할 필요가 없습니다.

호출 샘플

curl -X POST "https://{host}/api/v1/sr/intonation" \
  -H "Authorization: Bearer $API_KEY" \
  -F 'request={"user_sid":"user-2001","params":{}};type=application/json' \
  -F "audio=@speech.wav"
import requests, json

resp = requests.post(
    "https://{host}/api/v1/sr/intonation",
    headers={"Authorization": f"Bearer {API_KEY}"},
    files={
        "request": (None, json.dumps({"user_sid": "user-2001", "params": {}}),
                    "application/json"),
        "audio": ("speech.wav", open("speech.wav", "rb"), "audio/wav"),
    },
)
print(resp.json())
const fs = require("fs");
const path = require("path");

const HOST = "https://{host}";

async function main() {
    const filePath = "./speech.wav";

    const fd = new FormData();

    fd.append(
        "request",
        new Blob(
            [
                JSON.stringify({
                    user_sid: "user-2001",
                    params: {},
                }),
            ],
            { type: "application/json" }
        )
    );

    const file = new Blob([fs.readFileSync(filePath)]);
    fd.append("audio", file, path.basename(filePath));

    const res = await fetch(`${HOST}/api/v1/sr/intonation`, {
        method: "POST",
        headers: {
            Authorization: `Bearer ${API_KEY}`,
        },
        body: fd,
    });

    if (!res.ok) {
        console.error("HTTP Error:", res.status, await res.text());
        return;
    }

    const json = await res.json();
    console.log(json);
}

main();

응답 REST 응답 본문 — 필드는 결과 구조체를 참고하세요


WebSocket 프로토콜

WS wss://{host}/ws/v1

한 연결에서 아래 순서로 메시지를 주고받습니다. Text 프레임은 JSON 제어 메시지이고, Binary 프레임은 오디오입니다. 아래 요청·응답 필드는 모두 JSON 메시지 기준입니다. 연결 인증은 인증 (API Key)과 브라우저 인증을 참고하세요.

SR · 억양 분석 세션 흐름도
     Client                              Server
     ──────                              ──────
 ①  session.start           ─▶
                            ◀─  session.started       (session_id 발급)
 ②  command: start_audio    ─▶
                            ◀─  command.ack
 ③  [binary audio frame]    ─▶
                            ◀─  data_chunk.ack        (프레임마다 1회)
 ④  command: finalize_audio ─▶
                            ◀─  command.ack
                            ◀─  intonation.result     (최종 결과)
 ⑤  session.end             ─▶
                            ◀─  session.ended

 ※  session.heartbeat       ─▶   (① ~ ⑤ 사이, 30초 권장)
                            ◀─  session.heartbeat.ack
session.heartbeat — ① session.started를 받은 뒤부터 ⑤ session.end를 보내기 전까지 사이에 보냅니다. WebSocket 연결을 오래 유지하는 경우 세션이 만료되지 않도록 주기적으로 호출해 세션을 연장하는 데 사용합니다 (30초 주기 권장).

① session.start — 세션 시작

요청 Client → Server · Text 프레임 (JSON)

필드타입필수허용 값설명
typestring필수session.start메시지 종류
user_sidstring필수사용자 식별자
servicestring필수sr서비스
operationstring필수intonation오퍼레이션
paramsobject선택아래 params.* 하위 필드요청 파라미터. REST 요청의 params와 같습니다
params.recognition_modestring선택no_epd — EPD 미사용 — 오디오 전체를 인식
use_epd — EPD로 발화 구간을 검출해 인식
use_epd_with_sil_append — EPD 사용 + 검출 구간 뒤에 묵음(SIL) 추가
기본 use_epd_with_sil_append. 대소문자 무관
params.audio_formatobject선택아래 audio_format.* 하위 필드object가 아닌 값(문자열 등)은 무시됩니다
params.audio_format.encodingstring선택raw PCM16LE로 해석되는 값
pcm
그 외 값은 검증하지 않고 컨테이너로 디코딩을 시도합니다 (wav · flac · ogg · mp3 등)
인코딩 힌트 (선택). 소문자·trim 후 비교하며, 미지정 시 컨테이너를 탐색한 뒤 raw PCM16LE로 간주합니다.
params.audio_format.sample_rateint선택양의 정수샘플링 레이트 (기본 16000, 권장 16000). 16kHz로 변환되어 처리됩니다.
params.audio_format.channelsint선택양의 정수채널 수 (기본 1, 권장 1). mono로 변환되어 처리됩니다
params.configobject선택아래 config.* 하위 필드세부 옵션. 범위를 벗어나거나 타입이 맞지 않는 값은 거부되지 않고 무시되며, result.config_status에 -100(정상은 1)으로 보고됩니다
params.config.levelint선택0–4거절의 강도 (기본 1). 값이 클수록 거절 강도가 커집니다.
params.config.tm_limitint선택3–600한 번의 인식에서 처리할 수 있는 최대 음성 길이(초, 기본 30). 이 길이를 넘는 음성은 인식에 실패합니다.
params.config.pause_thint선택250–2500발화가 끝났다고 판정하기 위한 최소 묵음 길이(ms, 기본 500). 이 길이만큼 묵음이 이어지면 인식을 종료합니다.

응답 Server → Client · session.started

필드타입설명
typestring"session.started" 고정
session_idstring발급된 세션 ID. 이후 서버가 보내는 모든 메시지에 포함됩니다
subscription_uuidstring세션에 적용된 구독 UUID
subscription_plan_uidint구독 플랜 ID
subscription_statusstring구독 상태
server_timestring응답 서버 시각 (ISO 8601 UTC)
// 클라이언트 → 서버
{
  "type": "session.start",
  "user_sid": "user-2001",
  "service": "sr",
  "operation": "intonation",
  "params": {
    "recognition_mode": "use_epd_with_sil_append",
    "audio_format": { "sample_rate": 16000, "channels": 1, "encoding": "pcm" }
  }
}

// 서버 → 클라이언트
{
  "type": "session.started",
  "session_id": "01HXXXXXXXXXXXXXXXXXXXXXXX",
  "subscription_uuid": "…",
  "subscription_plan_uid": 0,
  "subscription_status": "…",
  "server_time": "2026-02-12T10:30:45Z"
}
session.started를 받기 전에 command·Binary 프레임·session.heartbeat·session.end를 보내면 PROTOCOL_VIOLATION으로 연결이 종료됩니다. api_key 필드는 넣을 수 없으며(INVALID_MESSAGE), API Key는 연결 handshake에서만 전달합니다.

② command: start_audio — 오디오 수신 시작

요청 Client → Server · Text 프레임 (JSON)

필드타입필수허용 값설명
typestring필수command메시지 종류
commandstring필수start_audio커맨드 이름

응답 Server → Client · command.ack

필드타입설명
typestring"command.ack" 고정
session_idstring세션 ID
commandstring수락된 커맨드 이름
server_timestring응답 서버 시각 (ISO 8601 UTC)
server_processing_time_nsint서버 처리 소요 시간 (nanoseconds)
// 클라이언트 → 서버
{ "type": "command", "command": "start_audio" }

// 서버 → 클라이언트
{
  "type": "command.ack",
  "session_id": "01HXXXXXXXXXXXXXXXXXXXXXXX",
  "command": "start_audio",
  "server_time": "2026-02-12T10:30:45Z",
  "server_processing_time_ns": 85000
}

③ Binary 오디오 프레임 — 오디오 전송

요청 Client → Server · Binary 프레임

프레임내용설명
Binary오디오 바이트①의 params.audio_format 형식으로 해석합니다. JSON 래핑 없이 바이트 그대로 보냅니다

응답 Server → Client · data_chunk.ack (프레임마다 1회)

필드타입설명
typestring"data_chunk.ack" 고정
session_idstring세션 ID
bytesint이번 프레임의 수신 바이트 수
server_timestring응답 서버 시각 (ISO 8601 UTC)
server_processing_time_nsint서버 처리 소요 시간 (nanoseconds)
// 서버 → 클라이언트
{
  "type": "data_chunk.ack",
  "session_id": "01HXXXXXXXXXXXXXXXXXXXXXXX",
  "bytes": 16000,
  "server_time": "2026-02-12T10:30:45Z",
  "server_processing_time_ns": 412000
}
data_chunk.ack는 수신 확인일 뿐 최종 결과가 아닙니다. 최종 결과는 ④ finalize_audio 이후에 옵니다.

④ command: finalize_audio — 수신 종료 · 억양 분석 실행

요청 Client → Server · Text 프레임 (JSON)

필드타입필수허용 값설명
typestring필수command메시지 종류
commandstring필수finalize_audio커맨드 이름

응답 1 Server → Client · command.ack

필드타입설명
typestring"command.ack" 고정
session_idstring세션 ID
commandstring"finalize_audio" 고정
server_timestring응답 서버 시각 (ISO 8601 UTC)
server_processing_time_nsint서버 처리 소요 시간 (nanoseconds)

응답 2 Server → Client · intonation.result — 필드는 결과 구조체를 참고하세요

// 클라이언트 → 서버
{ "type": "command", "command": "finalize_audio" }

// 서버 → 클라이언트 (1) 커맨드 수락
{
  "type": "command.ack",
  "session_id": "01HXXXXXXXXXXXXXXXXXXXXXXX",
  "command": "finalize_audio",
  "server_time": "2026-02-12T10:30:46Z",
  "server_processing_time_ns": 310000000
}

// 서버 → 클라이언트 (2) 결과
{
  "type": "intonation.result",
  "session_id": "01HXXXXXXXXXXXXXXXXXXXXXXX",
  "is_final": true,
  "result": {
    "Intonation": [ 0.0, 182.4, 185.1, … ],
    "Loudness":   [ 0.0, 0.42, 0.47, … ]
  },
  "statistics": { … },
  "server_time": "2026-02-12T10:30:46Z"
}
처리가 끝나면 command.ack와 intonation.result가 이 순서로 연달아 옵니다. 커맨드가 실패하면 두 메시지 대신 command.error가 오며, 세션은 유지됩니다.

⑤ session.end — 세션 종료

요청 Client → Server · Text 프레임 (JSON)

필드타입필수허용 값설명
typestring필수session.end메시지 종류
reasonstring선택자유 문자열종료 사유 (기본 completed). session.ended에 그대로 반환됩니다

응답 Server → Client · session.ended

필드타입설명
typestring"session.ended" 고정
session_idstring세션 ID
reasonstring요청의 reason 값
statistics.frames_receivedint세션 동안 수신한 Binary 프레임 수
statistics.audio_bytesint세션 동안 수신한 오디오 누적 바이트 수
server_timestring응답 서버 시각 (ISO 8601 UTC)
// 클라이언트 → 서버
{ "type": "session.end", "reason": "completed" }

// 서버 → 클라이언트
{
  "type": "session.ended",
  "session_id": "01HXXXXXXXXXXXXXXXXXXXXXXX",
  "reason": "completed",
  "statistics": { "frames_received": 1, "audio_bytes": 48044 },
  "server_time": "2026-02-12T10:30:47Z"
}
session.end는 finalize_audio를 대신 실행하지 않습니다. 결과가 필요하면 ④를 먼저 보내세요. 세션을 오래 유지할 때는 session.heartbeat를 주기적으로 보내 세션을 연장하세요 (30초 주기 권장).

오류 응답

서버는 상황에 따라 두 종류의 오류 메시지를 보냅니다. 오류 코드는 에러 코드를 참고하세요.

타입발생 시점세션
command.errorstart_audio · finalize_audio 등 커맨드 처리 실패유지
session.error세션 시작 실패, 메시지 순서 위반, 잘못된 메시지 형식, Binary 프레임 처리 실패대부분 종료
필드타입설명
typestring"command.error" 또는 "session.error"
session_idstring세션 ID (session.error는 세션이 만들어진 뒤에만 포함)
commandstring실패한 커맨드 이름 (command.error만 포함)
error.codestring오류 코드
error.messagestring오류 메시지
error.detailsobject부가 정보 (있을 때만 포함)
error.ap_request_idstring서버 로그 추적용 요청 ID. 문의 시 함께 전달하세요
server_timestring응답 서버 시각 (ISO 8601 UTC)
{
  "type": "command.error",
  "session_id": "01HXXXXXXXXXXXXXXXXXXXXXXX",
  "command": "finalize_audio",
  "error": { "code": "INVALID_MESSAGE", "message": "…", "ap_request_id": "…" },
  "server_time": "2026-02-12T10:30:46Z"
}

결과 구조체 REST · WebSocket 공용 · JSON 기준

아래 표는 REST 응답 본문과 WebSocket intonation.result 메시지에 공통으로 적용됩니다. REST는 응답 본문 최상위에, WebSocket은 결과 메시지 본문에 같은 필드가 담기며, WebSocket 메시지에는 type·is_final이 추가됩니다. REST 전용 표시가 있는 필드는 WebSocket 결과 메시지에 없습니다.

sr/intonation 결과

sr/intonation 응답 결과 구조입니다.

필드타입설명
session_idstring세션 ID
server_timestring응답 서버 시각 (ISO 8601 UTC)
errorobject오류 발생 시 포함 (정상 응답 시 부재). 이때 result·statistics는 부재 REST 전용 — WebSocket은 command.error·session.error 메시지로 전달됩니다
statistics.actionstring실행된 엔진 액션명
statistics.sdkstringSDK명 (SelvySR)
statistics.runtimestring런타임 구현체 (sr2lib_runtime) — 런타임 계층의 값이 우선 적용되어 runtime_implementation과 동일한 값이 반환됩니다
statistics.runtime_implementationstring런타임 구현체 ID (sr2lib_runtime)
statistics.audio_sizeint사용자 음성 바이트 수
statistics.reference_audio_sizeint참조 음성 바이트 수 (없으면 0)
statistics.elapsed_nsint처리 소요 시간 (nanoseconds)
statistics.invoke_started_at_nsintinvoke 시작 타임스탬프 (nanoseconds)
statistics.invoke_completed_at_nsintinvoke 완료 타임스탬프 (nanoseconds)
result.Intonationfloat[]pitch draw contour 값 배열
result.Loudnessfloat[]energy draw contour 값 배열
STT STT(자유 발화)

자유 발화

REST 프로토콜

POST /api/v1/stt/transcribe

요청 필드 JSON 기준

필드타입필수허용 값설명
user_sidstring필수사용자 식별자
params.resource_namestring필수배포 설정에 선언된 리소스에 한함선언되지 않은 이름은 거부됩니다
params.epdstring선택off — EPD 미사용
auto_stop — AUTO-STOP — 발화 종료 시 자동 정지, 중간 상세결과 없음
chunk — CHUNK — 구간 검출 시 중간 상세결과 제공
chunk_mid — CHUNK — 구간 검출과 무관하게 중간 상세결과를 계속 제공
bargein — BARGEIN — 끼어들기 감지 전용, 중간 상세결과 없음
auto_stop_mid — AUTO-STOP + 중간 상세결과 제공
끝점 검출 방식 (기본 auto_stop). 대소문자 무관. WebSocket 스트리밍에서 미지정 시 chunk_mid가 적용됩니다. 그 외 값은 400
params.async_modeint선택0 — 동기
1 — 비동기
기본 0이며, WebSocket 스트리밍은 미지정 시 1
params.async_mid_resultint선택0 — 비활성
1 — 활성
중간 결과 수신. 기본 0이며, WebSocket 스트리밍은 미지정 시 1. 0·1 외의 값은 거부됩니다
params.audio_formatobject선택아래 audio_format.* 하위 필드object가 아닌 값(문자열 등)은 무시됩니다
params.audio_format.encodingstring선택raw PCM16LE로 해석되는 값
pcm
그 외 값은 검증하지 않고 컨테이너로 디코딩을 시도합니다 (wav · flac · ogg · mp3 등)
인코딩 힌트 (선택). 소문자·trim 후 비교하며, 미지정 시 컨테이너를 탐색한 뒤 raw PCM16LE로 간주합니다.
params.audio_format.sample_rateint선택양의 정수샘플링 레이트 (기본 16000, 권장 16000). 16kHz로 변환되어 처리됩니다.
params.audio_format.channelsint선택양의 정수채널 수 (기본 1, 권장 1). mono로 변환되어 처리됩니다
params.configobject선택위 파라미터와 동일한 키 + 아래 config.* 하위 필드위 파라미터를 중첩 객체로 전달할 수 있습니다(동일 키 병합). 아래 필드는 config로만 지정합니다
params.config.epd_start_timeout_secint선택0 이상발화 시작 대기 타임아웃(초, 기본 0=미사용). epd_duration_timeout_sec와 함께 설정하거나 둘 다 0이어야 하며, 한쪽만 0보다 크면 400
params.config.epd_duration_timeout_secint선택0 이상발화 길이 타임아웃(초, 기본 0=미사용). 위와 동일한 쌍 제약
params.config.epd_margin_secfloat선택임의의 실수EPD 구간 마진(초, 기본 -1.0=미지정)
params.config.async_resultint선택0 — 비활성
1 — 활성
비동기 최종 결과 수신 (기본 0). WebSocket 스트리밍에서 미지정 시 1
인식 언어는 resource_name으로 선택하세요. model_id는 이 문서에서 안내하지 않습니다 — resource_name과 역할이 같기 때문입니다. 모델 선택은 resource_name 하나만 사용하세요. params 외에 멀티파트 audio 파트를 반드시 함께 전송해야 합니다.

응답은 recognition.result 형식이며, WebSocket 사용 시 recognition.partial 중간 결과를 함께 수신할 수 있습니다.

호출 샘플

curl -X POST "https://{host}/api/v1/stt/transcribe" \
  -H "Authorization: Bearer $API_KEY" \
  -F 'request={"user_sid":"user-2001","params":{"resource_name":"GeneralBase_16KModel","epd":"auto_stop"}};type=application/json' \
  -F "audio=@lecture.wav"
import requests, json

resp = requests.post(
    "https://{host}/api/v1/stt/transcribe",
    headers={"Authorization": f"Bearer {API_KEY}"},
    files={
        "request": (None, json.dumps({
            "user_sid": "user-2001",
            "params": {"resource_name": "GeneralBase_16KModel", "epd": "auto_stop"},
        }), "application/json"),
        "audio": ("lecture.wav", open("lecture.wav", "rb"), "audio/wav"),
    },
)
print(resp.json()["result"]["text"])
const fs = require("fs");
const path = require("path");

const HOST = "https://{host}";

async function main() {
    const filePath = "./speech.wav";

    const fd = new FormData();

    fd.append(
        "request",
        new Blob(
            [
                JSON.stringify({
                    user_sid: "user-2001",
                    params: {
                        resource_name: "EnglishBase_16KModel",
                        epd: "off",
                    },
                }),
            ],
            { type: "application/json" }
        )
    );

    fd.append("audio", new Blob([fs.readFileSync(filePath)]), path.basename(filePath));

    const res = await fetch(`${HOST}/api/v1/stt/transcribe`, {
        method: "POST",
        headers: { Authorization: `Bearer ${API_KEY}` },
        body: fd,
    });

    if (!res.ok) {
        console.error("HTTP Error:", res.status, await res.text());
        return;
    }

    const json = await res.json();
    console.log(json.result.text);
}

main();

응답 REST 응답 본문 — 필드는 결과 구조체를 참고하세요


WebSocket 프로토콜

WS wss://{host}/ws/v1

한 연결에서 아래 순서로 메시지를 주고받습니다. Text 프레임은 JSON 제어 메시지이고, Binary 프레임은 오디오입니다. 아래 요청·응답 필드는 모두 JSON 메시지 기준입니다. 연결 인증은 인증 (API Key)과 브라우저 인증을 참고하세요.

STT · 자유 발화 세션 흐름도
     Client                              Server
     ──────                              ──────
 ①  session.start           ─▶
                            ◀─  session.started       (session_id 발급)
 ②  command: start_audio    ─▶
                            ◀─  command.ack           (STT 스트리밍 시작)
 ③  [binary audio frame]    ─▶
                            ◀─  data_chunk.ack        (프레임마다 1회)
                            ◀─  recognition.partial … (중간 결과, 비동기)
 ④  command: finalize_audio ─▶
                            ◀─  command.ack           (처리 접수)
                            ◀─  recognition.partial … (마무리 중 변경 시)
                            ◀─  recognition.result    (최종 결과)
 ⑤  session.end             ─▶
                            ◀─  session.ended

 ※  session.heartbeat       ─▶   (① ~ ⑤ 사이, 30초 권장)
                            ◀─  session.heartbeat.ack
session.heartbeat — ① session.started를 받은 뒤부터 ⑤ session.end를 보내기 전까지 사이에 보냅니다. WebSocket 연결을 오래 유지하는 경우 세션이 만료되지 않도록 주기적으로 호출해 세션을 연장하는 데 사용합니다 (30초 주기 권장). 특히 finalize_audio 뒤 결과를 기다리는 동안에는 ack의 operation_async로 처리 진행 상태도 확인할 수 있습니다.

① session.start — 세션 시작

요청 Client → Server · Text 프레임 (JSON)

필드타입필수허용 값설명
typestring필수session.start메시지 종류
user_sidstring필수사용자 식별자
servicestring필수stt서비스
operationstring필수transcribe오퍼레이션
paramsobject필수아래 params.* 하위 필드요청 파라미터. REST 요청의 params와 같습니다
params.resource_namestring필수배포 설정에 선언된 리소스에 한함선언되지 않은 이름은 거부됩니다
params.epdstring선택off — EPD 미사용
auto_stop — AUTO-STOP — 발화 종료 시 자동 정지, 중간 상세결과 없음
chunk — CHUNK — 구간 검출 시 중간 상세결과 제공
chunk_mid — CHUNK — 구간 검출과 무관하게 중간 상세결과를 계속 제공
bargein — BARGEIN — 끼어들기 감지 전용, 중간 상세결과 없음
auto_stop_mid — AUTO-STOP + 중간 상세결과 제공
끝점 검출 방식 (기본 auto_stop). 대소문자 무관. WebSocket 스트리밍에서 미지정 시 chunk_mid가 적용됩니다. 그 외 값은 400
params.async_modeint선택0 — 동기
1 — 비동기
기본 0이며, WebSocket 스트리밍은 미지정 시 1
params.async_mid_resultint선택0 — 비활성
1 — 활성
중간 결과 수신. 기본 0이며, WebSocket 스트리밍은 미지정 시 1. 0·1 외의 값은 거부됩니다
params.audio_formatobject선택아래 audio_format.* 하위 필드object가 아닌 값(문자열 등)은 무시됩니다
params.audio_format.encodingstring선택raw PCM16LE로 해석되는 값
pcm
그 외 값은 검증하지 않고 컨테이너로 디코딩을 시도합니다 (wav · flac · ogg · mp3 등)
인코딩 힌트 (선택). 소문자·trim 후 비교하며, 미지정 시 컨테이너를 탐색한 뒤 raw PCM16LE로 간주합니다.
params.audio_format.sample_rateint선택양의 정수샘플링 레이트 (기본 16000, 권장 16000). 16kHz로 변환되어 처리됩니다.
params.audio_format.channelsint선택양의 정수채널 수 (기본 1, 권장 1). mono로 변환되어 처리됩니다
params.configobject선택위 파라미터와 동일한 키 + 아래 config.* 하위 필드위 파라미터를 중첩 객체로 전달할 수 있습니다(동일 키 병합). 아래 필드는 config로만 지정합니다
params.config.epd_start_timeout_secint선택0 이상발화 시작 대기 타임아웃(초, 기본 0=미사용). epd_duration_timeout_sec와 함께 설정하거나 둘 다 0이어야 하며, 한쪽만 0보다 크면 400
params.config.epd_duration_timeout_secint선택0 이상발화 길이 타임아웃(초, 기본 0=미사용). 위와 동일한 쌍 제약
params.config.epd_margin_secfloat선택임의의 실수EPD 구간 마진(초, 기본 -1.0=미지정)
params.config.async_resultint선택0 — 비활성
1 — 활성
비동기 최종 결과 수신 (기본 0). WebSocket 스트리밍에서 미지정 시 1

응답 Server → Client · session.started

필드타입설명
typestring"session.started" 고정
session_idstring발급된 세션 ID. 이후 서버가 보내는 모든 메시지에 포함됩니다
subscription_uuidstring세션에 적용된 구독 UUID
subscription_plan_uidint구독 플랜 ID
subscription_statusstring구독 상태
server_timestring응답 서버 시각 (ISO 8601 UTC)
// 클라이언트 → 서버
{
  "type": "session.start",
  "user_sid": "user-2001",
  "service": "stt",
  "operation": "transcribe",
  "params": {
    "resource_name": "EnglishBase_16KModel",
    "epd": "chunk_mid",
    "audio_format": { "sample_rate": 16000, "channels": 1, "encoding": "pcm" }
  }
}

// 서버 → 클라이언트
{
  "type": "session.started",
  "session_id": "01HXXXXXXXXXXXXXXXXXXXXXXX",
  "subscription_uuid": "…",
  "subscription_plan_uid": 0,
  "subscription_status": "…",
  "server_time": "2026-02-12T10:30:45Z"
}
session.started를 받기 전에 command·Binary 프레임·session.heartbeat·session.end를 보내면 PROTOCOL_VIOLATION으로 연결이 종료됩니다. api_key 필드는 넣을 수 없으며(INVALID_MESSAGE), API Key는 연결 handshake에서만 전달합니다.

② command: start_audio — 오디오 수신 시작

요청 Client → Server · Text 프레임 (JSON)

필드타입필수허용 값설명
typestring필수command메시지 종류
commandstring필수start_audio커맨드 이름

응답 Server → Client · command.ack

필드타입설명
typestring"command.ack" 고정
session_idstring세션 ID
commandstring수락된 커맨드 이름
server_timestring응답 서버 시각 (ISO 8601 UTC)
server_processing_time_nsint서버 처리 소요 시간 (nanoseconds)
// 클라이언트 → 서버
{ "type": "command", "command": "start_audio" }

// 서버 → 클라이언트
{
  "type": "command.ack",
  "session_id": "01HXXXXXXXXXXXXXXXXXXXXXXX",
  "command": "start_audio",
  "server_time": "2026-02-12T10:30:45Z",
  "server_processing_time_ns": 85000
}
start_audio부터 스트리밍 인식이 시작되며, 이후 보내는 오디오는 바로 인식됩니다.

③ Binary 오디오 프레임 — 오디오 전송 · 중간 결과 수신

요청 Client → Server · Binary 프레임

프레임내용설명
Binary오디오 바이트①의 params.audio_format 형식으로 해석합니다. JSON 래핑 없이 바이트 그대로 보냅니다

응답 Server → Client · data_chunk.ack (프레임마다 1회)

필드타입설명
typestring"data_chunk.ack" 고정
session_idstring세션 ID
bytesint이번 프레임의 수신 바이트 수
statistics.audio_sizeint지금까지 누적된 오디오 바이트 수 (16kHz mono PCM16LE 기준)
statistics.data_chunksint지금까지 처리한 프레임 수
statistics.streamingbooltrue 고정
statistics.streaming_end_detectedboolEPD가 발화 종료를 검출했는지 여부
statistics.audio_acceptedbool이 프레임이 인식에 반영됐는지 여부. EPD 종료 검출 뒤 프레임은 false
statistics.ignored_after_epdboolEPD 종료 검출 뒤라 버려진 프레임이면 true
statistics.runtimestring런타임 서비스 키
statistics.runtime_implementationstring런타임 구현체 ID
server_timestring응답 서버 시각 (ISO 8601 UTC)
server_processing_time_nsint서버 처리 소요 시간 (nanoseconds)
// 서버 → 클라이언트
{
  "type": "data_chunk.ack",
  "session_id": "01HXXXXXXXXXXXXXXXXXXXXXXX",
  "bytes": 16000,
  "statistics": {
    "audio_size": 16000, "data_chunks": 1, "streaming": true,
    "streaming_end_detected": false, "audio_accepted": true, "ignored_after_epd": false,
    "runtime": "…", "runtime_implementation": "…"
  },
  "server_time": "2026-02-12T10:30:45Z",
  "server_processing_time_ns": 412000
}

비동기 응답 Server → Client · recognition.partial

필드타입설명
typestring"recognition.partial" 고정
session_idstring세션 ID
is_finalboolfalse 고정
resultobjectSTT 엔진의 중간 결과 이벤트 원본
midstring현재까지의 중간 인식 텍스트 (엔진이 제공할 때만 포함)
mid_resultsarray중간 인식 결과 목록 (엔진이 제공할 때만 포함)
statistics.streamingbooltrue 고정
statistics.runtime_eventbooltrue 고정
statistics.runtime_msgstringSTT 엔진 이벤트 이름
statistics.runtime_phasestringSTT 엔진 처리 단계
statistics.runtime_sequence_numintSTT 엔진 이벤트 순번 (있을 때만 포함)
server_timestring응답 서버 시각 (ISO 8601 UTC)
// 서버 → 클라이언트 (오디오 수신 중 수시로)
{
  "type": "recognition.partial",
  "session_id": "01HXXXXXXXXXXXXXXXXXXXXXXX",
  "is_final": false,
  "result": { … },
  "mid": "Hello my name",
  "statistics": { "streaming": true, "runtime_event": true, "runtime_msg": "progress", "runtime_phase": "…" },
  "server_time": "2026-02-12T10:30:45Z"
}
data_chunk.ack는 수신 확인일 뿐 최종 결과가 아닙니다. 최종 결과는 ④ finalize_audio 이후에 옵니다.
recognition.partial은 중간 인식 결과(텍스트·EPD 상태 등)가 바뀔 때만 data_chunk.ack와 별개로 전송됩니다. params.async_mid_result를 0으로 두면 보내지 않습니다.
EPD가 발화 종료를 검출하면 그 프레임의 ack에 statistics.streaming_end_detected: true가 실립니다. 이후 프레임은 오류 없이 ack되지만 인식에는 반영되지 않으므로(audio_accepted: false), 오디오 전송을 멈추고 ④로 진행하세요.

④ command: finalize_audio — 수신 종료 · 최종 결과

요청 Client → Server · Text 프레임 (JSON)

필드타입필수허용 값설명
typestring필수command메시지 종류
commandstring필수finalize_audio커맨드 이름

응답 1 Server → Client · command.ack

필드타입설명
typestring"command.ack" 고정
session_idstring세션 ID
commandstring"finalize_audio" 고정
server_timestring응답 서버 시각 (ISO 8601 UTC)
server_processing_time_nsint서버 처리 소요 시간 (nanoseconds)

응답 2 Server → Client · recognition.result — 필드는 결과 구조체를 참고하세요

// 클라이언트 → 서버
{ "type": "command", "command": "finalize_audio" }

// 서버 → 클라이언트 (1) 처리 접수
{
  "type": "command.ack",
  "session_id": "01HXXXXXXXXXXXXXXXXXXXXXXX",
  "command": "finalize_audio",
  "server_time": "2026-02-12T10:30:46Z",
  "server_processing_time_ns": 120000
}

// 서버 → 클라이언트 (2) 최종 결과
{
  "type": "recognition.result",
  "session_id": "01HXXXXXXXXXXXXXXXXXXXXXXX",
  "is_final": true,
  "result": { "result_type": "recognition", "text": "Hello my name is Tom", … },
  "statistics": { … },
  "server_time": "2026-02-12T10:30:47Z"
}
WebSocket 스트리밍은 기본적으로 비동기(params.async_mode 미지정 시 1)로 마무리됩니다. command.ack는 처리 접수만 뜻하며, 마무리 중 중간 결과가 바뀌면 recognition.partial이 더 올 수 있고 마지막에 recognition.result가 한 번 옵니다. params.async_mode를 0으로 두면 처리를 마친 뒤 command.ack와 recognition.result를 연달아 보냅니다.
비동기 처리 중에는 session.heartbeat.ack의 operation_async로 진행 상태를 확인할 수 있습니다. operation_async.state는 queued → running → completed 순으로 바뀌며, 처리에 실패하면 별도 오류 메시지 없이 failed가 되고 operation_async.progress.error_code·error_message에 사유가 실립니다. 결과가 오지 않으면 heartbeat로 이 상태를 확인하세요.

⑤ session.end — 세션 종료

요청 Client → Server · Text 프레임 (JSON)

필드타입필수허용 값설명
typestring필수session.end메시지 종류
reasonstring선택자유 문자열종료 사유 (기본 completed). session.ended에 그대로 반환됩니다

응답 Server → Client · session.ended

필드타입설명
typestring"session.ended" 고정
session_idstring세션 ID
reasonstring요청의 reason 값
statistics.frames_receivedint세션 동안 수신한 Binary 프레임 수
statistics.audio_bytesint세션 동안 수신한 오디오 누적 바이트 수
server_timestring응답 서버 시각 (ISO 8601 UTC)
// 클라이언트 → 서버
{ "type": "session.end", "reason": "completed" }

// 서버 → 클라이언트
{
  "type": "session.ended",
  "session_id": "01HXXXXXXXXXXXXXXXXXXXXXXX",
  "reason": "completed",
  "statistics": { "frames_received": 12, "audio_bytes": 192000 },
  "server_time": "2026-02-12T10:30:47Z"
}
session.end는 finalize_audio를 대신 실행하지 않습니다. 결과가 필요하면 ④를 먼저 보내세요. 최종 결과를 받기 전에 보내면 진행 중인 처리가 취소됩니다. 세션을 오래 유지할 때는 session.heartbeat를 주기적으로 보내 세션을 연장하세요 (30초 주기 권장).

오류 응답

서버는 상황에 따라 두 종류의 오류 메시지를 보냅니다. 오류 코드는 에러 코드를 참고하세요.

타입발생 시점세션
command.errorstart_audio · finalize_audio 등 커맨드 처리 실패 (예: STT 스트리밍 시작 실패, 필수 입력 누락)유지
session.error세션 시작 실패, 메시지 순서 위반, 잘못된 메시지 형식, Binary 프레임 처리 실패대부분 종료
필드타입설명
typestring"command.error" 또는 "session.error"
session_idstring세션 ID (session.error는 세션이 만들어진 뒤에만 포함)
commandstring실패한 커맨드 이름 (command.error만 포함)
error.codestring오류 코드
error.messagestring오류 메시지
error.detailsobject부가 정보 (있을 때만 포함)
error.ap_request_idstring서버 로그 추적용 요청 ID. 문의 시 함께 전달하세요
server_timestring응답 서버 시각 (ISO 8601 UTC)
{
  "type": "command.error",
  "session_id": "01HXXXXXXXXXXXXXXXXXXXXXXX",
  "command": "finalize_audio",
  "error": { "code": "INVALID_MESSAGE", "message": "…", "ap_request_id": "…" },
  "server_time": "2026-02-12T10:30:46Z"
}

결과 구조체 REST · WebSocket 공용 · JSON 기준

아래 표는 REST 응답 본문과 WebSocket recognition.result 메시지에 공통으로 적용됩니다. REST는 응답 본문 최상위에, WebSocket은 결과 메시지 본문에 같은 필드가 담기며, WebSocket 메시지에는 type·is_final이 추가됩니다. REST 전용 표시가 있는 필드는 WebSocket 결과 메시지에 없습니다.

stt/transcribe 결과

stt/transcribe 응답 결과 구조입니다.

필드타입설명
session_idstring세션 ID
server_timestring응답 서버 시각 (ISO 8601 UTC)
statistics.audio_sizeint사용자 음성 바이트 수
statistics.data_chunksint수신한 오디오 청크 수
statistics.streamingbool스트리밍(WebSocket) 세션 여부
statistics.streaming_end_detectedbool스트리밍 중 EPD 종료 검출 여부
statistics.runtimestring런타임 서비스 키 (selvasai_lvcsr)
statistics.runtime_implementationstring런타임 구현체 ID (selvasai_lvcsr_runtime)
result.result_typestring결과 유형 ("recognition"). WebSocket 메시지의 type은 recognition.result
result.textstring인식된 전사 텍스트
result.scorefloat인식 신뢰도 점수
result.words[]array토큰 단위 어절 배열
result.words[].textstring어절 텍스트
result.words[].scorefloat어절 인식 신뢰도
result.words[].startint시작 시각 (ms)
result.words[].endint종료 시각 (ms)
result.words[].raw_dataobject토큰 원본 데이터
result.words[].raw_data.textstring토큰 텍스트
result.words[].raw_data.scorefloat토큰 인식 신뢰도
result.words[].raw_data.startint시작 시각 (ms)
result.words[].raw_data.endint종료 시각 (ms)
result.words[].raw_data.speakerint화자 ID (-1: 화자 미구분)
result.raw_dataobjectSDK 원본 전체 데이터 (엔진 passthrough)
result.raw_data.streamingbool스트리밍 세션 여부 — WebSocket 응답에만 포함
result.raw_data.phasestring스트리밍 단계 (예: end) — WebSocket 응답에만 포함
result.raw_data.openbool엔진 세션 유지 여부 — WebSocket 응답에만 포함
result.raw_data.sendobject중간 결과 전송 진단 정보 (send.mid.*) — WebSocket 응답에만 포함
result.raw_data.resultobjectWebSocket 응답에서는 아래 text·score·speakers·epd·timestamp·tokens[]·result_poll_attempts가 이 result.raw_data.result.* 아래에 한 단계 더 중첩됩니다. REST 단발 응답에서는 result.raw_data.* 직하에 위치합니다
result.raw_data.textstring인식 텍스트
result.raw_data.scorefloat인식 신뢰도
result.raw_data.speakersint화자 수
result.raw_data.transaction_idstring트랜잭션 ID
result.raw_data.result_poll_attemptsint결과 폴링 시도 횟수
result.raw_data.final_wait_mid_results[]array최종 결과 대기 중 수집된 중간 결과 목록 (스트리밍 + 중간결과 활성 시에만 포함)
result.raw_data.epdobject음성 구간 검출 정보
result.raw_data.epd.startint음성 시작 시각 (ms)
result.raw_data.epd.endint음성 종료 시각 (ms)
result.raw_data.timestampobject처리 시간 정보
result.raw_data.timestamp.startintEPD 시작 오프셋 (ms)
result.raw_data.timestamp.endintEPD 종료 오프셋 (ms)
result.raw_data.timestamp.start_timeobject처리 시작 시각 (year, month, day, hour, minute, second, millisecond)
result.raw_data.timestamp.end_timeobject처리 종료 시각 (year, month, day, hour, minute, second, millisecond)
result.raw_data.tokens[]array인식 토큰 원본 배열
result.raw_data.tokens[].textstring토큰 텍스트
result.raw_data.tokens[].scorefloat토큰 인식 신뢰도
result.raw_data.tokens[].startint시작 시각 (ms)
result.raw_data.tokens[].endint종료 시각 (ms)
result.raw_data.tokens[].speakerint화자 ID (-1: 화자 미구분)
result.metadataobject처리 부가 정보
result.metadata.speakersint화자 수
result.metadata.transaction_idstring트랜잭션 ID
result.metadata.epdobject음성 구간 검출 정보 (start, end)
result.metadata.timestampobject처리 시간 정보 (start, end, start_time, end_time)
result.metadata.streamingbool스트리밍 세션 여부 — WebSocket 응답에만 포함
result.metadata.phasestring스트리밍 단계 — WebSocket 응답에만 포함
result.metadata.openbool엔진 세션 유지 여부 — WebSocket 응답에만 포함
Phonics 파닉스

파닉스 분석

REST 프로토콜

POST /api/v1/phonics/analyze

요청 필드 JSON 기준

필드타입필수허용 값설명
user_sidstring필수사용자 식별자
params.phonics_typestring필수word — 단어 단위 분석
sentence — 문장 단위 분석
분석 단위. 대소문자 무관. 미지정 시 phonics_type is required 오류, 그 외 값은 400
params.phonics_idint택1임의의 정수파닉스 콘텐츠 ID (phonics_text와 정확히 하나만 전송 — 둘 다 있거나 둘 다 없으면 오류)
params.phonics_textstring택1영문자·공백·ASCII 구두점
영문자 1자 이상 필수, 숫자 불가
분석 대상 텍스트 (phonics_id와 택1). 구두점은 단어 경계로 정규화됩니다
params.resource_namestring필수배포 설정에 선언된 Phonics 전용 리소스에 한함일반 STT 모델을 지정하면 실패합니다
params.audio_formatobject선택아래 audio_format.* 하위 필드object가 아닌 값(문자열 등)은 무시됩니다
params.audio_format.encodingstring선택raw PCM16LE로 해석되는 값
pcm
그 외 값은 검증하지 않고 컨테이너로 디코딩을 시도합니다 (wav · flac · ogg · mp3 등)
인코딩 힌트 (선택). 소문자·trim 후 비교하며, 미지정 시 컨테이너를 탐색한 뒤 raw PCM16LE로 간주합니다.
params.audio_format.sample_rateint선택양의 정수샘플링 레이트 (기본 16000, 권장 16000). 16kHz로 변환되어 처리됩니다.
params.audio_format.channelsint선택양의 정수채널 수 (기본 1, 권장 1). mono로 변환되어 처리됩니다
params.epdstring선택off — EPD 미사용
auto_stop — AUTO-STOP — 발화 종료 시 자동 정지, 중간 상세결과 없음
chunk — CHUNK — 구간 검출 시 중간 상세결과 제공
chunk_mid — CHUNK — 구간 검출과 무관하게 중간 상세결과를 계속 제공
bargein — BARGEIN — 끼어들기 감지 전용, 중간 상세결과 없음
auto_stop_mid — AUTO-STOP + 중간 상세결과 제공
끝점 검출 방식 (기본 auto_stop). 대소문자 무관. 그 외 값은 400
params.configobject선택위 파라미터와 동일한 키 (phonics_type·epd 포함) + 아래 config.* 하위 필드위 파라미터를 중첩 객체로 전달할 수 있습니다(동일 키 병합). async_* 계열은 전달해도 phonics가 항상 동기 처리되어 효과가 없습니다
params.config.epd_start_timeout_secint선택0 이상발화 시작 대기 타임아웃(초, 기본 0=미사용). epd_duration_timeout_sec와 함께 설정하거나 둘 다 0이어야 하며, 한쪽만 0보다 크면 400
params.config.epd_duration_timeout_secint선택0 이상발화 길이 타임아웃(초, 기본 0=미사용). 위와 동일한 쌍 제약
params.config.epd_margin_secfloat선택임의의 실수EPD 구간 마진(초, 기본 -1.0=미지정)
params.config.async_resultint선택0 — 비활성
1 — 활성
비동기 최종 결과 수신 (기본 0). WebSocket 스트리밍에서 미지정 시 1
model_id는 이 문서에서 안내하지 않습니다 — resource_name과 역할이 같기 때문입니다. 모델 선택은 resource_name 하나만 사용하세요. async_mode·async_mid_result도 전달은 가능하지만 phonics는 항상 동기 처리되어 효과가 없습니다. 결과 타입 phonics.result는 WebSocket 메시지의 type이며, REST 단발 응답 본문에는 type·result_type 필드가 없습니다.

호출 샘플

curl -X POST "https://{host}/api/v1/phonics/analyze" \
  -H "Authorization: Bearer $API_KEY" \
  -F 'request={"user_sid":"user-2001","params":{"phonics_type":"word","phonics_text":"about",
       "resource_name":"Phonics_16KModel"}};type=application/json' \
  -F "audio=@phonics.wav"
import requests, json

resp = requests.post(
    "https://{host}/api/v1/phonics/analyze",
    headers={"Authorization": f"Bearer {API_KEY}"},
    files={
        "request": (None, json.dumps({
            "user_sid": "user-2001",
            "params": {
                "phonics_type": "word",
                "phonics_text": "about",
                "resource_name": "Phonics_16KModel",
            },
        }), "application/json"),
        "audio": ("phonics.wav", open("phonics.wav", "rb"), "audio/wav"),
    },
)
result = resp.json()["result"]
print(result["phonics_type"], result["score"])
const fs = require("fs");
const path = require("path");

const HOST = "https://{host}";

async function main() {
    const filePath = "./phonics.wav";

    const fd = new FormData();

    fd.append(
        "request",
        new Blob(
            [
                JSON.stringify({
                    user_sid: "user-2001",
                    params: {
                        phonics_type: "word",
                        phonics_text: "about",
                        resource_name: "Phonics_16KModel",
                    },
                }),
            ],
            { type: "application/json" }
        )
    );

    fd.append("audio", new Blob([fs.readFileSync(filePath)]), path.basename(filePath));

    const res = await fetch(`${HOST}/api/v1/phonics/analyze`, {
        method: "POST",
        headers: { Authorization: `Bearer ${API_KEY}` },
        body: fd,
    });

    if (!res.ok) {
        console.error("HTTP Error:", res.status, await res.text());
        return;
    }

    const json = await res.json();
    console.log(json.result.phonics_type, json.result.score);
}

main();

응답 REST 응답 본문 — 필드는 결과 구조체를 참고하세요


WebSocket 프로토콜

WS wss://{host}/ws/v1

한 연결에서 아래 순서로 메시지를 주고받습니다. Text 프레임은 JSON 제어 메시지이고, Binary 프레임은 오디오입니다. 아래 요청·응답 필드는 모두 JSON 메시지 기준입니다. 연결 인증은 인증 (API Key)과 브라우저 인증을 참고하세요.

Phonics · 파닉스 분석 세션 흐름도
     Client                              Server
     ──────                              ──────
 ①  session.start           ─▶
                            ◀─  session.started       (session_id 발급)
 ②  command: start_audio    ─▶
                            ◀─  command.ack
 ③  [binary audio frame]    ─▶
                            ◀─  data_chunk.ack        (프레임마다 1회)
 ④  command: finalize_audio ─▶
                            ◀─  command.ack
                            ◀─  phonics.result        (최종 결과)
 ⑤  session.end             ─▶
                            ◀─  session.ended

 ※  session.heartbeat       ─▶   (① ~ ⑤ 사이, 30초 권장)
                            ◀─  session.heartbeat.ack
session.heartbeat — ① session.started를 받은 뒤부터 ⑤ session.end를 보내기 전까지 사이에 보냅니다. WebSocket 연결을 오래 유지하는 경우 세션이 만료되지 않도록 주기적으로 호출해 세션을 연장하는 데 사용합니다 (30초 주기 권장).

① session.start — 세션 시작

요청 Client → Server · Text 프레임 (JSON)

필드타입필수허용 값설명
typestring필수session.start메시지 종류
user_sidstring필수사용자 식별자
servicestring필수phonics서비스
operationstring필수analyze오퍼레이션
paramsobject필수아래 params.* 하위 필드요청 파라미터. REST 요청의 params와 같습니다
params.phonics_typestring필수word — 단어 단위 분석
sentence — 문장 단위 분석
분석 단위. 대소문자 무관. 미지정 시 phonics_type is required 오류, 그 외 값은 400
params.phonics_idint택1임의의 정수파닉스 콘텐츠 ID (phonics_text와 정확히 하나만 전송 — 둘 다 있거나 둘 다 없으면 오류)
params.phonics_textstring택1영문자·공백·ASCII 구두점
영문자 1자 이상 필수, 숫자 불가
분석 대상 텍스트 (phonics_id와 택1). 구두점은 단어 경계로 정규화됩니다
params.resource_namestring필수배포 설정에 선언된 Phonics 전용 리소스에 한함일반 STT 모델을 지정하면 실패합니다
params.audio_formatobject선택아래 audio_format.* 하위 필드object가 아닌 값(문자열 등)은 무시됩니다
params.audio_format.encodingstring선택raw PCM16LE로 해석되는 값
pcm
그 외 값은 검증하지 않고 컨테이너로 디코딩을 시도합니다 (wav · flac · ogg · mp3 등)
인코딩 힌트 (선택). 소문자·trim 후 비교하며, 미지정 시 컨테이너를 탐색한 뒤 raw PCM16LE로 간주합니다.
params.audio_format.sample_rateint선택양의 정수샘플링 레이트 (기본 16000, 권장 16000). 16kHz로 변환되어 처리됩니다.
params.audio_format.channelsint선택양의 정수채널 수 (기본 1, 권장 1). mono로 변환되어 처리됩니다
params.epdstring선택off — EPD 미사용
auto_stop — AUTO-STOP — 발화 종료 시 자동 정지, 중간 상세결과 없음
chunk — CHUNK — 구간 검출 시 중간 상세결과 제공
chunk_mid — CHUNK — 구간 검출과 무관하게 중간 상세결과를 계속 제공
bargein — BARGEIN — 끼어들기 감지 전용, 중간 상세결과 없음
auto_stop_mid — AUTO-STOP + 중간 상세결과 제공
끝점 검출 방식 (기본 auto_stop). 대소문자 무관. 그 외 값은 400
params.configobject선택위 파라미터와 동일한 키 (phonics_type·epd 포함) + 아래 config.* 하위 필드위 파라미터를 중첩 객체로 전달할 수 있습니다(동일 키 병합). async_* 계열은 전달해도 phonics가 항상 동기 처리되어 효과가 없습니다
params.config.epd_start_timeout_secint선택0 이상발화 시작 대기 타임아웃(초, 기본 0=미사용). epd_duration_timeout_sec와 함께 설정하거나 둘 다 0이어야 하며, 한쪽만 0보다 크면 400
params.config.epd_duration_timeout_secint선택0 이상발화 길이 타임아웃(초, 기본 0=미사용). 위와 동일한 쌍 제약
params.config.epd_margin_secfloat선택임의의 실수EPD 구간 마진(초, 기본 -1.0=미지정)
params.config.async_resultint선택0 — 비활성
1 — 활성
비동기 최종 결과 수신 (기본 0). WebSocket 스트리밍에서 미지정 시 1

응답 Server → Client · session.started

필드타입설명
typestring"session.started" 고정
session_idstring발급된 세션 ID. 이후 서버가 보내는 모든 메시지에 포함됩니다
subscription_uuidstring세션에 적용된 구독 UUID
subscription_plan_uidint구독 플랜 ID
subscription_statusstring구독 상태
server_timestring응답 서버 시각 (ISO 8601 UTC)
// 클라이언트 → 서버
{
  "type": "session.start",
  "user_sid": "user-2001",
  "service": "phonics",
  "operation": "analyze",
  "params": {
    "phonics_type": "word",
    "phonics_text": "cat",
    "resource_name": "…",
    "audio_format": { "sample_rate": 16000, "channels": 1, "encoding": "pcm" }
  }
}

// 서버 → 클라이언트
{
  "type": "session.started",
  "session_id": "01HXXXXXXXXXXXXXXXXXXXXXXX",
  "subscription_uuid": "…",
  "subscription_plan_uid": 0,
  "subscription_status": "…",
  "server_time": "2026-02-12T10:30:45Z"
}
session.started를 받기 전에 command·Binary 프레임·session.heartbeat·session.end를 보내면 PROTOCOL_VIOLATION으로 연결이 종료됩니다. api_key 필드는 넣을 수 없으며(INVALID_MESSAGE), API Key는 연결 handshake에서만 전달합니다.

② command: start_audio — 오디오 수신 시작

요청 Client → Server · Text 프레임 (JSON)

필드타입필수허용 값설명
typestring필수command메시지 종류
commandstring필수start_audio커맨드 이름

응답 Server → Client · command.ack

필드타입설명
typestring"command.ack" 고정
session_idstring세션 ID
commandstring수락된 커맨드 이름
server_timestring응답 서버 시각 (ISO 8601 UTC)
server_processing_time_nsint서버 처리 소요 시간 (nanoseconds)
// 클라이언트 → 서버
{ "type": "command", "command": "start_audio" }

// 서버 → 클라이언트
{
  "type": "command.ack",
  "session_id": "01HXXXXXXXXXXXXXXXXXXXXXXX",
  "command": "start_audio",
  "server_time": "2026-02-12T10:30:45Z",
  "server_processing_time_ns": 85000
}

③ Binary 오디오 프레임 — 오디오 전송

요청 Client → Server · Binary 프레임

프레임내용설명
Binary오디오 바이트①의 params.audio_format 형식으로 해석합니다. JSON 래핑 없이 바이트 그대로 보냅니다

응답 Server → Client · data_chunk.ack (프레임마다 1회)

필드타입설명
typestring"data_chunk.ack" 고정
session_idstring세션 ID
bytesint이번 프레임의 수신 바이트 수
server_timestring응답 서버 시각 (ISO 8601 UTC)
server_processing_time_nsint서버 처리 소요 시간 (nanoseconds)
// 서버 → 클라이언트
{
  "type": "data_chunk.ack",
  "session_id": "01HXXXXXXXXXXXXXXXXXXXXXXX",
  "bytes": 16000,
  "server_time": "2026-02-12T10:30:45Z",
  "server_processing_time_ns": 412000
}
data_chunk.ack는 수신 확인일 뿐 최종 결과가 아닙니다. 최종 결과는 ④ finalize_audio 이후에 옵니다.

④ command: finalize_audio — 수신 종료 · 파닉스 분석 실행

요청 Client → Server · Text 프레임 (JSON)

필드타입필수허용 값설명
typestring필수command메시지 종류
commandstring필수finalize_audio커맨드 이름

응답 1 Server → Client · command.ack

필드타입설명
typestring"command.ack" 고정
session_idstring세션 ID
commandstring"finalize_audio" 고정
server_timestring응답 서버 시각 (ISO 8601 UTC)
server_processing_time_nsint서버 처리 소요 시간 (nanoseconds)

응답 2 Server → Client · phonics.result — 필드는 결과 구조체를 참고하세요

// 클라이언트 → 서버
{ "type": "command", "command": "finalize_audio" }

// 서버 → 클라이언트 (1) 커맨드 수락
{
  "type": "command.ack",
  "session_id": "01HXXXXXXXXXXXXXXXXXXXXXXX",
  "command": "finalize_audio",
  "server_time": "2026-02-12T10:30:46Z",
  "server_processing_time_ns": 310000000
}

// 서버 → 클라이언트 (2) 결과
{
  "type": "phonics.result",
  "session_id": "01HXXXXXXXXXXXXXXXXXXXXXXX",
  "is_final": true,
  "result": {
    "phonics_type": "word",
    "text": "cat",
    "score": 87,
    "phonics_count": 3,
    …
  },
  "statistics": { … },
  "server_time": "2026-02-12T10:30:46Z"
}
처리가 끝나면 command.ack와 phonics.result가 이 순서로 연달아 옵니다. 커맨드가 실패하면 두 메시지 대신 command.error가 오며, 세션은 유지됩니다.
Phonics는 스트리밍 인식을 하지 않으며 recognition.partial을 보내지 않습니다. async_* 값과 관계없이 항상 동기로 처리됩니다.

⑤ session.end — 세션 종료

요청 Client → Server · Text 프레임 (JSON)

필드타입필수허용 값설명
typestring필수session.end메시지 종류
reasonstring선택자유 문자열종료 사유 (기본 completed). session.ended에 그대로 반환됩니다

응답 Server → Client · session.ended

필드타입설명
typestring"session.ended" 고정
session_idstring세션 ID
reasonstring요청의 reason 값
statistics.frames_receivedint세션 동안 수신한 Binary 프레임 수
statistics.audio_bytesint세션 동안 수신한 오디오 누적 바이트 수
server_timestring응답 서버 시각 (ISO 8601 UTC)
// 클라이언트 → 서버
{ "type": "session.end", "reason": "completed" }

// 서버 → 클라이언트
{
  "type": "session.ended",
  "session_id": "01HXXXXXXXXXXXXXXXXXXXXXXX",
  "reason": "completed",
  "statistics": { "frames_received": 1, "audio_bytes": 32044 },
  "server_time": "2026-02-12T10:30:47Z"
}
session.end는 finalize_audio를 대신 실행하지 않습니다. 결과가 필요하면 ④를 먼저 보내세요. 세션을 오래 유지할 때는 session.heartbeat를 주기적으로 보내 세션을 연장하세요 (30초 주기 권장).

오류 응답

서버는 상황에 따라 두 종류의 오류 메시지를 보냅니다. 오류 코드는 에러 코드를 참고하세요.

타입발생 시점세션
command.errorstart_audio · finalize_audio 등 커맨드 처리 실패 (예: phonics_id·phonics_text 누락)유지
session.error세션 시작 실패, 메시지 순서 위반, 잘못된 메시지 형식, Binary 프레임 처리 실패대부분 종료
필드타입설명
typestring"command.error" 또는 "session.error"
session_idstring세션 ID (session.error는 세션이 만들어진 뒤에만 포함)
commandstring실패한 커맨드 이름 (command.error만 포함)
error.codestring오류 코드
error.messagestring오류 메시지
error.detailsobject부가 정보 (있을 때만 포함)
error.ap_request_idstring서버 로그 추적용 요청 ID. 문의 시 함께 전달하세요
server_timestring응답 서버 시각 (ISO 8601 UTC)
{
  "type": "command.error",
  "session_id": "01HXXXXXXXXXXXXXXXXXXXXXXX",
  "command": "finalize_audio",
  "error": { "code": "INVALID_MESSAGE", "message": "…", "ap_request_id": "…" },
  "server_time": "2026-02-12T10:30:46Z"
}

결과 구조체 REST · WebSocket 공용 · JSON 기준

아래 표는 REST 응답 본문과 WebSocket phonics.result 메시지에 공통으로 적용됩니다. REST는 응답 본문 최상위에, WebSocket은 결과 메시지 본문에 같은 필드가 담기며, WebSocket 메시지에는 type·is_final이 추가됩니다. REST 전용 표시가 있는 필드는 WebSocket 결과 메시지에 없습니다.

phonics/analyze 결과

phonics/analyze 응답 결과 구조입니다. phonics_type에 따라 sentence / word 두 가지 형태로 반환됩니다.

sentence 모드

필드타입설명
session_idstring세션 ID
server_timestring응답 서버 시각 (ISO 8601 UTC)
errorobject오류 발생 시 포함 (정상 응답 시 부재). 이때 result·statistics는 부재 REST 전용 — WebSocket은 command.error·session.error 메시지로 전달됩니다
statistics.audio_sizeint사용자 음성 바이트 수
statistics.data_chunksint수신한 오디오 청크 수
statistics.streamingbool스트리밍 채널 사용 여부 (phonics는 항상 false)
statistics.streaming_end_detectedbool스트리밍 EPD 종료 검출 여부 (phonics는 항상 false)
statistics.runtimestring런타임 서비스 키 (selvasai_lvcsr)
statistics.runtime_implementationstring런타임 구현체 ID (selvasai_lvcsr_runtime)
result.phonics_typestring"sentence"
result.textstringARPABET 기호 인식 텍스트
result.scorefloat인식 확률값 (0–1) — 발음 점수가 아닌 SDK 인식 신뢰도
result.phonics_countintphonics 배열 크기
result.transaction_idstring트랜잭션 ID
result.epdobject음성 구간 검출 정보
result.epd.startint음성 시작 시각 (ms)
result.epd.endint음성 종료 시각 (ms)
result.tokens[]array인식 토큰 배열
result.tokens[].textstring토큰 텍스트 (ARPABET 기호)
result.tokens[].scorefloat토큰 인식 신뢰도
result.tokens[].startint시작 시각 (ms)
result.tokens[].endint종료 시각 (ms)
result.tokens[].speakerint화자 ID
result.phonics[]array단어별 Phonics 결과
result.phonics[].scorefloatCorrectness 비율 (Match / Total, 0–1) — sentence 모드에서는 SDK가 값을 채우지 않아 0.0으로 반환됨
result.phonics[].json_rawstringSDK 원본 JSON 문자열
result.phonics[].jsonobjectSDK 원본 파싱 결과
result.phonics[].json.textstring단어 표기
result.phonics[].json.uidstring단어 고유 식별자
result.phonics[].json.arpabetstringARPABET 기호
result.phonics[].json.ipastringIPA 기호
result.phonics[].json.phones[]array음소 배열
result.phonics[].json.phones[].textstring음소에 해당하는 철자
result.phonics[].json.phones[].arpabetstringARPABET 기호
result.phonics[].json.phones[].ipastringIPA 기호
result.phonics[].json.phones[].ipa#intIPA 기호 코드값
result.phonics[].json.phones[].scorefloat발음 점수 (0–100)
result.phonics[].json.phones[].soundlikeobject실제 들린 음소 정보
result.phonics[].json.phones[].soundlike.arpabetstring실제 들린 ARPABET 기호
result.phonics[].json.phones[].soundlike.ipastring실제 들린 IPA 기호
result.phonics[].json.phones[].soundlike.scorefloat유사도 점수
result.phonics[].json.phones[].DF[]array변별적 자질 진단
result.phonics[].json.phones[].DF[].textstring자질 이름
result.phonics[].json.phones[].DF[].definedstring목표값 ("+" / "-")
result.phonics[].json.phones[].DF[].detectedbool실제 발화 검출 여부
result.phonics[].json.evals[]array음절-음소 매핑 평가 배열
result.phonics[].json.evals[].textstring철자
result.phonics[].json.evals[].arpabetstringARPABET 기호
result.phonics[].json.evals[].ipastringIPA 기호
result.phonics[].json.evals[].scorefloat발음 점수 (0–100)
result.phonics[].json.evals[].pStint음소 시작 인덱스 — 문장 전체 기준이며 해당 단어의 phones[] 지역 인덱스가 아님
result.phonics[].json.evals[].pEdint음소 종료 인덱스 (exclusive, 문장 전체 기준)
result.phonics[].json.syllables[]array음절 배열
result.phonics[].json.syllables[].textstring음절 철자
result.phonics[].json.syllables[].arpabetstring음절 ARPABET 기호
result.phonics[].json.syllables[].ipastring음절 IPA 기호
result.phonics[].json.syllables[].scorefloat음절 발음 점수
result.phonics[].json.syllables[].eStintevals[] 시작 인덱스 — 문장 전체 기준
result.phonics[].json.syllables[].eEdintevals[] 종료 인덱스 (exclusive, 문장 전체 기준)

word 모드

필드타입설명
session_idstring세션 ID
server_timestring응답 서버 시각 (ISO 8601 UTC)
errorobject오류 발생 시 포함 (정상 응답 시 부재). 이때 result·statistics는 부재 REST 전용 — WebSocket은 command.error·session.error 메시지로 전달됩니다
statistics.audio_sizeint사용자 음성 바이트 수
statistics.data_chunksint수신한 오디오 청크 수
statistics.streamingbool스트리밍 채널 사용 여부 (phonics는 항상 false)
statistics.streaming_end_detectedbool스트리밍 EPD 종료 검출 여부 (phonics는 항상 false)
statistics.runtimestring런타임 서비스 키 (selvasai_lvcsr)
statistics.runtime_implementationstring런타임 구현체 ID (selvasai_lvcsr_runtime)
result.phonics_typestring"word"
result.textstringARPABET 기호 인식 텍스트
result.scorefloat인식 신뢰도 점수
result.correctness_scorefloat발음 정확도 점수 (0–100)
result.transaction_idstring트랜잭션 ID
result.epdobject음성 구간 검출 정보
result.epd.startint음성 시작 시각 (ms)
result.epd.endint음성 종료 시각 (ms)
result.json_rawstringSDK 원본 JSON 문자열
result.jsonobjectSDK 원본 파싱 결과
result.json.textstring단어 표기
result.json.uidstring단어 고유 식별자
result.json.arpabetstringARPABET 기호
result.json.ipastringIPA 기호
result.json.phones[]array음소 배열
result.json.phones[].textstring음소에 해당하는 철자
result.json.phones[].arpabetstringARPABET 기호
result.json.phones[].ipastringIPA 기호
result.json.phones[].ipa#intIPA 기호 코드값
result.json.phones[].scorefloat발음 점수 (0–100)
result.json.phones[].soundlikeobject실제 들린 음소 정보
result.json.phones[].soundlike.arpabetstring실제 들린 ARPABET 기호
result.json.phones[].soundlike.ipastring실제 들린 IPA 기호
result.json.phones[].soundlike.scorefloat유사도 점수
result.json.phones[].DF[]array변별적 자질 진단
result.json.phones[].DF[].textstring자질 이름
result.json.phones[].DF[].definedstring목표값 ("+" / "-")
result.json.phones[].DF[].detectedbool실제 발화 검출 여부
result.json.evals[]array음절-음소 매핑 평가 배열
result.json.evals[].textstring철자
result.json.evals[].arpabetstringARPABET 기호
result.json.evals[].ipastringIPA 기호
result.json.evals[].scorefloat발음 점수 (0–100)
result.json.evals[].pStintphones[] 시작 인덱스
result.json.evals[].pEdintphones[] 종료 인덱스 (exclusive)
result.json.syllables[]array음절 배열
result.json.syllables[].textstring음절 철자
result.json.syllables[].arpabetstring음절 ARPABET 기호
result.json.syllables[].ipastring음절 IPA 기호
result.json.syllables[].scorefloat음절 발음 점수
result.json.syllables[].eStintevals[] 시작 인덱스
result.json.syllables[].eEdintevals[] 종료 인덱스 (exclusive)
result.tokens[]array인식 토큰 배열
result.tokens[].textstring토큰 텍스트
result.tokens[].scorefloat토큰 인식 신뢰도
result.tokens[].startint시작 시각 (ms)
result.tokens[].endint종료 시각 (ms)
result.tokens[].speakerint화자 ID
RFA 읽기 유창성

읽기 유창성 평가

REST 프로토콜

POST /api/v1/rfa/rfa

기준 문장을 읽은 사용자 발화를 음성 인식하여 제시문장의 완독률을 분석한 후 SR을 통해 발음 유창성을 평가하는 복합 오퍼레이션입니다.

요청 필드 JSON 기준

필드타입필수허용 값설명
user_sidstring필수사용자 식별자
params.reference_textstring필수자유 문자열 (비어 있지 않아야 함)기준 문장. 비어 있으면 요청이 거부됩니다
params.resource_namestring필수배포 설정에 선언된 리소스에 한함평가 엔진 리소스. 인식 언어도 이 값으로 결정됩니다
params.stt_resource_namestring선택배포 설정에 선언된 리소스에 한함음성 인식 모델 요청별 override
params.configobject선택아래 config.* 하위 필드음성 인식 세부 옵션 override
params.config.epdstring선택off — EPD 미사용 (RFA 기본값)
auto_stop — AUTO-STOP — 발화 종료 시 자동 정지
chunk — CHUNK — 구간 검출 시 중간 상세결과 제공
chunk_mid — CHUNK — 중간 상세결과를 계속 제공
bargein — BARGEIN — 끼어들기 감지 전용
RFA 기본값은 off(EPD 미사용)이라 발화 전체를 평가합니다. RFA는 auto_stop_mid를 지원하지 않으며, 해석할 수 없는 값은 거부되지 않고 그대로 전달됩니다
params.config.epd_start_timeout_secint선택0 이상발화 시작 대기 타임아웃(초, 기본 0=미사용). epd_duration_timeout_sec와 함께 설정하거나 둘 다 0이어야 하며, 한쪽만 0보다 크면 400
params.config.epd_duration_timeout_secint선택0 이상발화 길이 타임아웃(초, 기본 0=미사용). 위와 동일한 쌍 제약
params.config.epd_margin_secfloat선택임의의 실수EPD 구간 마진(초, 기본 -1.0=미지정)
params.audio_formatobject선택아래 audio_format.* 하위 필드16kHz mono로 디코딩됩니다. object가 아닌 값은 무시됩니다
params.audio_format.encodingstring선택raw PCM16LE로 해석되는 값
pcm
그 외 값은 검증하지 않고 컨테이너로 디코딩을 시도합니다 (wav · flac · ogg · mp3 등)
인코딩 힌트 (선택). 소문자·trim 후 비교하며, 미지정 시 컨테이너를 탐색한 뒤 raw PCM16LE로 간주합니다.
params.audio_format.sample_rateint선택양의 정수샘플링 레이트 (기본 16000, 권장 16000). 16kHz로 변환되어 처리됩니다.
params.audio_format.channelsint선택양의 정수채널 수 (기본 1, 권장 1). mono로 변환되어 처리됩니다

응답 (REST batch)

공통 필드에 더해 recognition(음성 인식 결과 이벤트 전체)과 events[] 배열이 항상 포함됩니다. recognition은 이벤트 봉투이므로 인식 텍스트는 recognition.result.text로 접근합니다.

{
  "session_id": "01H…",
  "recognition": {
    "type": "recognition.result",
    "session_id": "01H…",
    "is_final": true,
    "result": { "result_type": "recognition", "text": "…", "score": 95, "words": [ … ] },
    "statistics": { … },
    "server_time": "2026-06-24T00:00:00Z"
  },
  "result":      { "accuracy": 82.5, "completeness": 91.0, "total_type_counts": { … }, … },
  "statistics":  { … },
  "events": [
    { "type": "session.started" }, { "type": "command.ack" },
    { "type": "recognition.result", "is_final": true },
    { "type": "rfa.result",         "is_final": true },
    { "type": "session.ended" }
  ],
  "server_time": "2026-06-24T00:00:00Z"
}

호출 샘플

curl -X POST "https://{host}/api/v1/rfa/rfa" \
  -H "Authorization: Bearer $API_KEY" \
  -F 'request={"user_sid":"user-2001","params":{
       "reference_text":"Honeybees are small insects that play a huge role in nature.",
       "resource_name":"KONG_ALL"}};type=application/json' \
  -F "audio=@reading.wav"
import requests, json

resp = requests.post(
    "https://{host}/api/v1/rfa/rfa",
    headers={"Authorization": f"Bearer {API_KEY}"},
    files={
        "request": (None, json.dumps({
            "user_sid": "user-2001",
            "params": {
                "reference_text": "Honeybees are small insects that play a huge role in nature.",
                "resource_name": "KONG_ALL",
                # 필요 시 음성 인식 모델 override:
                # "stt_resource_name": "…", "config": {"epd": 0},
            },
        }), "application/json"),
        "audio": ("reading.wav", open("reading.wav", "rb"), "audio/wav"),
    },
)
body = resp.json()
# recognition은 이벤트 봉투이므로 한 단계 더 들어갑니다.
print("인식:", body["recognition"]["result"]["text"])
print("RFA:", body["result"]["accuracy"], body["result"]["completeness"])
const fs = require("fs");
const path = require("path");

const HOST = "https://{host}";

async function main() {
    const filePath = "./reading.wav";

    const fd = new FormData();

    fd.append(
        "request",
        new Blob(
            [
                JSON.stringify({
                    user_sid: "user-2001",
                    params: {
                        reference_text: "Honeybees are small insects that play a huge role in nature.",
                        resource_name: "KONG_ALL",
                    },
                }),
            ],
            { type: "application/json" }
        )
    );

    fd.append("audio", new Blob([fs.readFileSync(filePath)]), path.basename(filePath));

    const res = await fetch(`${HOST}/api/v1/rfa/rfa`, {
        method: "POST",
        headers: { Authorization: `Bearer ${API_KEY}` },
        body: fd,
    });

    if (!res.ok) {
        console.error("HTTP Error:", res.status, await res.text());
        return;
    }

    const json = await res.json();
    console.log(json.result);
}

main();

응답 REST 응답 본문 — 필드는 결과 구조체를 참고하세요


WebSocket 프로토콜

WS wss://{host}/ws/v1

한 연결에서 아래 순서로 메시지를 주고받습니다. Text 프레임은 JSON 제어 메시지이고, Binary 프레임은 오디오입니다. 아래 요청·응답 필드는 모두 JSON 메시지 기준입니다. 연결 인증은 인증 (API Key)과 브라우저 인증을 참고하세요.

RFA · 읽기 유창성 평가 세션 흐름도
     Client                              Server
     ──────                              ──────
 ①  session.start           ─▶
                            ◀─  session.started       (session_id 발급)
 ②  command: start_audio    ─▶
                            ◀─  command.ack           (RFA 스트리밍 시작)
 ③  [binary audio frame]    ─▶
                            ◀─  data_chunk.ack        (프레임마다 1회)
                            ◀─  recognition.partial … (RFA 중간 결과, 비동기)
 ④  command: finalize_audio ─▶
                            ◀─  command.ack           (처리 접수)
                            ◀─  recognition.result    (최종 인식 결과)
                            ◀─  rfa.result            (RFA 평가 결과)
 ⑤  session.end             ─▶
                            ◀─  session.ended

 ※  session.heartbeat       ─▶   (① ~ ⑤ 사이, 30초 권장)
                            ◀─  session.heartbeat.ack
session.heartbeat — ① session.started를 받은 뒤부터 ⑤ session.end를 보내기 전까지 사이에 보냅니다. WebSocket 연결을 오래 유지하는 경우 세션이 만료되지 않도록 주기적으로 호출해 세션을 연장하는 데 사용합니다 (30초 주기 권장). 특히 finalize_audio 뒤 결과를 기다리는 동안에는 ack의 operation_async로 처리 진행 상태도 확인할 수 있습니다.

① session.start — 세션 시작

요청 Client → Server · Text 프레임 (JSON)

필드타입필수허용 값설명
typestring필수session.start메시지 종류
user_sidstring필수사용자 식별자
servicestring필수rfa서비스
operationstring필수rfa오퍼레이션
paramsobject필수아래 params.* 하위 필드요청 파라미터. REST 요청의 params와 같습니다
params.reference_textstring필수자유 문자열 (비어 있지 않아야 함)기준 문장. 비어 있으면 요청이 거부됩니다
params.resource_namestring필수배포 설정에 선언된 리소스에 한함평가 엔진 리소스. 인식 언어도 이 값으로 결정됩니다
params.stt_resource_namestring선택배포 설정에 선언된 리소스에 한함음성 인식 모델 요청별 override
params.configobject선택아래 config.* 하위 필드음성 인식 세부 옵션 override
params.config.epdstring선택off — EPD 미사용 (RFA 기본값)
auto_stop — AUTO-STOP — 발화 종료 시 자동 정지
chunk — CHUNK — 구간 검출 시 중간 상세결과 제공
chunk_mid — CHUNK — 중간 상세결과를 계속 제공
bargein — BARGEIN — 끼어들기 감지 전용
WebSocket에서는 chunk_mid 사용을 권장합니다. RFA는 auto_stop_mid를 지원하지 않으며, 해석할 수 없는 값은 거부되지 않고 그대로 전달됩니다
params.config.epd_start_timeout_secint선택0 이상발화 시작 대기 타임아웃(초, 기본 0=미사용). epd_duration_timeout_sec와 함께 설정하거나 둘 다 0이어야 하며, 한쪽만 0보다 크면 400
params.config.epd_duration_timeout_secint선택0 이상발화 길이 타임아웃(초, 기본 0=미사용). 위와 동일한 쌍 제약
params.config.epd_margin_secfloat선택임의의 실수EPD 구간 마진(초, 기본 -1.0=미지정)
params.config.async_mid_resultint선택0 — 비활성
1 — 활성
중간 인식 결과(recognition.partial) 전송 여부 (기본 1). WebSocket 전용
params.audio_formatobject선택아래 audio_format.* 하위 필드16kHz mono로 디코딩됩니다. object가 아닌 값은 무시됩니다
params.audio_format.encodingstring선택raw PCM16LE로 해석되는 값
pcm
그 외 값은 검증하지 않고 컨테이너로 디코딩을 시도합니다 (wav · flac · ogg · mp3 등)
인코딩 힌트 (선택). 소문자·trim 후 비교하며, 미지정 시 컨테이너를 탐색한 뒤 raw PCM16LE로 간주합니다.
params.audio_format.sample_rateint선택양의 정수샘플링 레이트 (기본 16000, 권장 16000). 16kHz로 변환되어 처리됩니다.
params.audio_format.channelsint선택양의 정수채널 수 (기본 1, 권장 1). mono로 변환되어 처리됩니다

응답 Server → Client · session.started

필드타입설명
typestring"session.started" 고정
session_idstring발급된 세션 ID. 이후 서버가 보내는 모든 메시지에 포함됩니다
subscription_uuidstring세션에 적용된 구독 UUID
subscription_plan_uidint구독 플랜 ID
subscription_statusstring구독 상태
server_timestring응답 서버 시각 (ISO 8601 UTC)
// 클라이언트 → 서버
{
  "type": "session.start",
  "user_sid": "user-2001",
  "service": "rfa",
  "operation": "rfa",
  "params": {
    "reference_text": "Honeybees are small insects that play a huge role in nature.",
    "resource_name": "KONG_ALL",
    "audio_format": { "sample_rate": 16000, "channels": 1, "encoding": "pcm" }
  }
}

// 서버 → 클라이언트
{
  "type": "session.started",
  "session_id": "01HXXXXXXXXXXXXXXXXXXXXXXX",
  "subscription_uuid": "…",
  "subscription_plan_uid": 0,
  "subscription_status": "…",
  "server_time": "2026-02-12T10:30:45Z"
}
session.started를 받기 전에 command·Binary 프레임·session.heartbeat·session.end를 보내면 PROTOCOL_VIOLATION으로 연결이 종료됩니다. api_key 필드는 넣을 수 없으며(INVALID_MESSAGE), API Key는 연결 handshake에서만 전달합니다.

② command: start_audio — 오디오 수신 시작

요청 Client → Server · Text 프레임 (JSON)

필드타입필수허용 값설명
typestring필수command메시지 종류
commandstring필수start_audio커맨드 이름

응답 Server → Client · command.ack

필드타입설명
typestring"command.ack" 고정
session_idstring세션 ID
commandstring수락된 커맨드 이름
server_timestring응답 서버 시각 (ISO 8601 UTC)
server_processing_time_nsint서버 처리 소요 시간 (nanoseconds)
// 클라이언트 → 서버
{ "type": "command", "command": "start_audio" }

// 서버 → 클라이언트
{
  "type": "command.ack",
  "session_id": "01HXXXXXXXXXXXXXXXXXXXXXXX",
  "command": "start_audio",
  "server_time": "2026-02-12T10:30:45Z",
  "server_processing_time_ns": 85000
}
start_audio부터 스트리밍 인식이 시작되며, 이후 보내는 오디오는 바로 인식됩니다.

③ Binary 오디오 프레임 — 오디오 전송 · 중간 결과 수신

요청 Client → Server · Binary 프레임

프레임내용설명
Binary오디오 바이트①의 params.audio_format 형식으로 해석합니다. JSON 래핑 없이 바이트 그대로 보냅니다

응답 Server → Client · data_chunk.ack (프레임마다 1회)

필드타입설명
typestring"data_chunk.ack" 고정
session_idstring세션 ID
bytesint이번 프레임의 수신 바이트 수
server_timestring응답 서버 시각 (ISO 8601 UTC)
server_processing_time_nsint서버 처리 소요 시간 (nanoseconds)
// 서버 → 클라이언트
{
  "type": "data_chunk.ack",
  "session_id": "01HXXXXXXXXXXXXXXXXXXXXXXX",
  "bytes": 16000,
  "server_time": "2026-02-12T10:30:45Z",
  "server_processing_time_ns": 412000
}

비동기 응답 Server → Client · recognition.partial

필드타입설명
typestring"recognition.partial" 고정
session_idstring세션 ID
is_finalboolfalse 고정
resultobject인식 엔진의 중간 결과 이벤트 원본
midstring현재까지의 중간 인식 텍스트 (엔진이 제공할 때만 포함)
mid_resultsarray중간 인식 결과 목록 (엔진이 제공할 때만 포함)
statistics.streamingbooltrue 고정
statistics.runtime_eventbooltrue 고정
statistics.runtime_msgstring인식 엔진 이벤트 이름
statistics.runtime_phasestring인식 엔진 처리 단계
statistics.runtime_sequence_numint인식 엔진 이벤트 순번 (있을 때만 포함)
server_timestring응답 서버 시각 (ISO 8601 UTC)
// 서버 → 클라이언트 (오디오 수신 중 수시로)
{
  "type": "recognition.partial",
  "session_id": "01HXXXXXXXXXXXXXXXXXXXXXXX",
  "is_final": false,
  "result": { … },
  "mid": "Honeybees are small insects",
  "statistics": { "streaming": true, "runtime_event": true, "runtime_msg": "…", "runtime_phase": "…" },
  "server_time": "2026-02-12T10:30:45Z"
}
data_chunk.ack는 수신 확인일 뿐 최종 결과가 아닙니다. 최종 결과는 ④ finalize_audio 이후에 옵니다.
recognition.partial은 중간 인식 텍스트가 바뀔 때마다 data_chunk.ack와 별개로 비동기 전송됩니다. 발생 빈도는 params.config.epd 설정과 인식 엔진에 따라 다르며, params.config.async_mid_result를 0으로 두면 보내지 않습니다. 평가 결과가 아닌 진행 표시용입니다.

④ command: finalize_audio — 수신 종료 · 평가 실행

요청 Client → Server · Text 프레임 (JSON)

필드타입필수허용 값설명
typestring필수command메시지 종류
commandstring필수finalize_audio커맨드 이름

응답 1 Server → Client · command.ack — 처리 접수를 뜻합니다

필드타입설명
typestring"command.ack" 고정
session_idstring세션 ID
commandstring"finalize_audio" 고정
server_timestring응답 서버 시각 (ISO 8601 UTC)
server_processing_time_nsint서버 처리 소요 시간 (nanoseconds)

응답 2 Server → Client · recognition.result

필드타입설명
typestring"recognition.result" 고정
session_idstring세션 ID
is_finalbooltrue 고정
resultobject최종 인식 결과. 인식 텍스트는 result.text입니다
statisticsobject인식 처리 통계
server_timestring응답 서버 시각 (ISO 8601 UTC)

응답 3 Server → Client · rfa.result — 필드는 결과 구조체를 참고하세요

// 클라이언트 → 서버
{ "type": "command", "command": "finalize_audio" }

// 서버 → 클라이언트 (1) 처리 접수
{
  "type": "command.ack",
  "session_id": "01HXXXXXXXXXXXXXXXXXXXXXXX",
  "command": "finalize_audio",
  "server_time": "2026-02-12T10:30:46Z",
  "server_processing_time_ns": 95000
}

// 서버 → 클라이언트 (2) 최종 인식 결과
{
  "type": "recognition.result",
  "session_id": "01HXXXXXXXXXXXXXXXXXXXXXXX",
  "is_final": true,
  "result": { "result_type": "recognition", "text": "Honeybees are small insects that play a huge role in nature.", … },
  "statistics": { … },
  "server_time": "2026-02-12T10:30:47Z"
}

// 서버 → 클라이언트 (3) RFA 평가 결과
{
  "type": "rfa.result",
  "session_id": "01HXXXXXXXXXXXXXXXXXXXXXXX",
  "is_final": true,
  "result": { "accuracy": 82.5, "completeness": 91.0, "total_type_counts": { … }, … },
  "statistics": { … },
  "server_time": "2026-02-12T10:30:48Z"
}
RFA는 finalize_audio를 비동기로 처리합니다. command.ack는 처리 접수만 뜻하며, 음성 인식이 끝나면 recognition.result, 이어서 평가가 끝나면 rfa.result가 차례로 옵니다. rfa.result를 받은 뒤 ⑤로 진행하세요.
처리 중에 보낸 session.heartbeat의 ack에는 진행 상태 operation_async가 함께 실립니다.
접수 뒤 인식·평가 단계에서 실패하면 결과 대신 session.error가 옵니다. 이때도 ⑤로 세션을 종료하세요.

⑤ session.end — 세션 종료

요청 Client → Server · Text 프레임 (JSON)

필드타입필수허용 값설명
typestring필수session.end메시지 종류
reasonstring선택자유 문자열종료 사유 (기본 completed). session.ended에 그대로 반환됩니다

응답 Server → Client · session.ended

필드타입설명
typestring"session.ended" 고정
session_idstring세션 ID
reasonstring요청의 reason 값
statistics.frames_receivedint세션 동안 수신한 Binary 프레임 수
statistics.audio_bytesint세션 동안 수신한 오디오 누적 바이트 수
server_timestring응답 서버 시각 (ISO 8601 UTC)
// 클라이언트 → 서버
{ "type": "session.end", "reason": "completed" }

// 서버 → 클라이언트
{
  "type": "session.ended",
  "session_id": "01HXXXXXXXXXXXXXXXXXXXXXXX",
  "reason": "completed",
  "statistics": { "frames_received": 12, "audio_bytes": 192000 },
  "server_time": "2026-02-12T10:30:47Z"
}
session.end는 finalize_audio를 대신 실행하지 않습니다. 결과가 필요하면 ④를 먼저 보내세요. rfa.result를 받기 전에 보내면 진행 중인 평가가 취소됩니다. 세션을 오래 유지할 때는 session.heartbeat를 주기적으로 보내 세션을 연장하세요 (30초 주기 권장).

오류 응답

서버는 상황에 따라 두 종류의 오류 메시지를 보냅니다. 오류 코드는 에러 코드를 참고하세요.

타입발생 시점세션
command.errorstart_audio · finalize_audio 등 커맨드 처리 실패 (예: start_audio의 스트리밍 인식 시작 실패)유지
session.error세션 시작 실패, 메시지 순서 위반, 잘못된 메시지 형식, Binary 프레임 처리 실패, finalize_audio 접수 뒤 인식·평가 실패대부분 종료
필드타입설명
typestring"command.error" 또는 "session.error"
session_idstring세션 ID (session.error는 세션이 만들어진 뒤에만 포함)
commandstring실패한 커맨드 이름 (command.error만 포함)
error.codestring오류 코드
error.messagestring오류 메시지
error.detailsobject부가 정보 (있을 때만 포함)
error.ap_request_idstring서버 로그 추적용 요청 ID. 문의 시 함께 전달하세요
server_timestring응답 서버 시각 (ISO 8601 UTC)
{
  "type": "command.error",
  "session_id": "01HXXXXXXXXXXXXXXXXXXXXXXX",
  "command": "finalize_audio",
  "error": { "code": "INVALID_MESSAGE", "message": "…", "ap_request_id": "…" },
  "server_time": "2026-02-12T10:30:46Z"
}

결과 구조체 REST · WebSocket 공용 · JSON 기준

아래 표는 REST 응답 본문과 WebSocket rfa.result 메시지에 공통으로 적용됩니다. REST는 응답 본문 최상위에, WebSocket은 rfa.result 메시지 본문에 같은 필드가 담깁니다. REST 전용으로 표시한 recognition·events[]는 REST batch 응답에만 있으며, WebSocket에서는 같은 내용이 recognition.result 등 개별 메시지로 따로 옵니다.

rfa/rfa 결과

공통 필드는 session_id · server_time · statistics · result(RFA 평가 결과)이며, REST batch 응답에는 recognition(음성 인식 결과) · events[]가 추가됩니다.

필드타입설명
session_idstring세션 ID
server_timestring응답 서버 시각 (ISO 8601)
typestring메시지 타입 — "rfa.result" WebSocket 메시지와 REST batch events[] 항목에만 포함, REST 응답 최상위에는 없음
is_finalbool최종 결과 여부 WebSocket 메시지와 REST batch events[] 항목에만 포함, REST 응답 최상위에는 없음
statistics.actionstring실행된 액션명 (예: serverproc::reading_fluency_assessment)
statistics.runtime_actionstring런타임에 전달된 액션명 (action과 동일한 값)
statistics.sdkstringSDK명 (예: SelvySR)
statistics.runtimestring런타임 구현체 (예: sr2lib_runtime)
statistics.data_chunksint수신한 오디오 청크 수
statistics.elapsed_nsint처리 소요 시간 (nanoseconds)
statistics.invoke_started_at_nsintinvoke 시작 타임스탬프 (nanoseconds)
statistics.invoke_completed_at_nsintinvoke 완료 타임스탬프 (nanoseconds)
statistics.recognition_alignment_sourcestring인식 정렬 소스 — word_timestamps (단어 타임스탬프 사용) 또는 text_fallback (텍스트 기반 대체 정렬)
statistics.recognized_info_countint인식 정보 수
statistics.reference_audio_bytesint참조 음성 바이트 수
statistics.resource_namestring사용된 리소스명
statistics.rfa_runtimestringRFA 런타임 서비스 키
statistics.rfa_runtime_implementationstringRFA 런타임 구현체 ID
statistics.stt_resource_namestring음성 인식 리소스명
statistics.stt_model_idint요청에서 음성 인식 모델 ID를 override한 경우에만 포함
statistics.stt_runtimestring음성 인식 런타임 서비스 키
statistics.stt_runtime_implementationstring음성 인식 런타임 구현체 ID
statistics.user_audio_bytesint사용자 음성 바이트 수
errorobject실패 시 오류 객체 (code · message · details). 이때 events[]에 session.error 이벤트도 포함됨 REST 전용 — WebSocket은 command.error·session.error 메시지로 전달됩니다
recognitionobject마지막 recognition.result 이벤트 전체 — type · session_id · is_final · result · statistics · server_time을 그대로 포함 (result 단축 참조가 아님) REST 전용
recognition.resultobject음성 인식 결과 객체 — 자유 발화 결과의 result와 동일한 구조. 인식 텍스트는 recognition.result.text REST 전용
result.accuracyfloat전체 정확도 (0–100)
result.attempt_ratefloat전체 발화 시도율 (0–100)
result.completenessfloat전체 완성도 (0–100)
result.total_mapping_scorefloat전체 매핑 점수 (0–100)
result.total_mapping_distanceint전체 편집 거리 합산
result.total_type_countsobject매핑 유형별 단어 수. 희소 맵이므로 해당 유형이 하나도 없으면 키 자체가 부재합니다 (값 0이 아님)
result.total_type_counts.Matchint정확히 인식된 단어 수
result.total_type_counts.Subint대체(오독) 단어 수
result.total_type_counts.Delint삭제(미발화) 단어 수
result.total_type_counts.Insint삽입(스크립트에 없는 발화) 단어 수
result.total_type_counts.Split-Subint분할 대체 — 스크립트 1단어가 여러 단어로 발화된 수
result.total_type_counts.Merge-Subint병합 대체 — 스크립트 여러 단어가 1단어로 발화된 수
result.total_type_counts.Split-Matchint분할 일치 — 스크립트 1단어가 여러 단어로 정확히 발화된 수
result.total_type_counts.Merge-Matchint병합 일치 — 스크립트 여러 단어가 1단어로 정확히 발화된 수
result.total_type_counts.Complexint복합 매핑 단어 수
result.recog_successbool인식 성공 여부
result.error_messagestring오류 메시지 (정상 시 빈 문자열)
result.fluency_metrics_via_recog_words.wpmfloat(인식 단어 기준) 분당 단어 수
result.fluency_metrics_via_recog_words.ppsfloat(인식 단어 기준) 초당 음소 수
result.fluency_metrics_via_recog_words.spsfloat(인식 단어 기준) 초당 음절 수
result.fluency_metrics_via_recog_words.inter_words_latencyint(인식 단어 기준) 단어 간 누적/평균 지연 (ms)
result.fluency_metrics_via_mapping_groups.wpmfloat(매핑 그룹 기준) 분당 단어 수
result.fluency_metrics_via_mapping_groups.ppsfloat(매핑 그룹 기준) 초당 음소 수
result.fluency_metrics_via_mapping_groups.spsfloat(매핑 그룹 기준) 초당 음절 수
result.fluency_metrics_via_mapping_groups.inter_words_latencyint(매핑 그룹 기준) 단어 간 누적/평균 지연 (ms)
result.extraobject엔진 메타 정보. rfa/rfa에서는 채워지지 않습니다 — 키는 존재하지만 문자열은 빈 값, 시각 값은 의미 없는 값이므로 사용하지 마세요
result.extra.api_namestring호출 API 이름 (미사용, 빈 문자열)
result.extra.paramsstringAPI 호출 파라미터 (미사용, 빈 문자열)
result.extra.call_timeintAPI 호출 시각 — UTC timestamp << 16 + ms 인코딩 (미사용)
result.extra.return_timeintAPI 반환 시각 — UTC timestamp << 16 + ms 인코딩 (미사용)
result.full_mapping_groups[]array전체 단어 정렬 결과 배열 (스크립트 단어 순)
result.full_mapping_groups[].typestring매핑 유형 — Match (정확) · Sub (대체) · Del (미발화) · Ins (삽입) · Split-Sub (1→N 분할) · Merge-Sub (N→1 병합)
result.full_mapping_groups[].script_stringstring스크립트 단어 (정규화된 형태). Ins 유형은 빈 문자열
result.full_mapping_groups[].script_textstring스크립트 원문 (구두점 포함). Ins 유형은 빈 문자열
result.full_mapping_groups[].recognized_stringstring인식된 단어 (Del 유형은 빈 문자열). Split-Sub는 공백으로 구분된 복수 단어
result.full_mapping_groups[].is_spokenbool발화 여부
result.full_mapping_groups[].start_msint단어 시작 시각 (ms, Del 등 미발화 시 -1)
result.full_mapping_groups[].end_msint단어 종료 시각 (ms, Del 등 미발화 시 -1)
result.full_mapping_groups[].mapping_scorefloat단어 매핑 점수 (0–100)
result.full_mapping_groups[].mapping_distanceint단어 편집 거리
result.full_mapping_groups[].fluency_metrics.wpmfloat분당 단어 수
result.full_mapping_groups[].fluency_metrics.ppsfloat초당 음소 수
result.full_mapping_groups[].fluency_metrics.spsfloat초당 음절 수
result.full_mapping_groups[].fluency_metrics.inter_words_latencyint이전 단어와의 지연 (ms)
result.full_mapping_groups[].fluency_metrics.stress_score.stressScorefloat전체 강세 점수 (Del 등 미발화 그룹에도 항상 포함)
result.full_mapping_groups[].fluency_metrics.stress_score.stressNScorefloat강세 정규화 점수
result.full_mapping_groups[].fluency_metrics.stress_score.durationScorefloat음절 지속 시간 점수
result.full_mapping_groups[].fluency_metrics.stress_score.durationNScorefloat지속 시간 정규화 점수
result.full_mapping_groups[].fluency_metrics.stress_score.energyScorefloat에너지(음량) 점수
result.full_mapping_groups[].fluency_metrics.stress_score.energyNScorefloat에너지 정규화 점수
result.full_mapping_groups[].fluency_metrics.stress_score.pitchScorefloat피치 점수
result.full_mapping_groups[].fluency_metrics.stress_score.pitchNScorefloat피치 정규화 점수
result.full_mapping_groups[].fluency_metrics.stress_score.pitchVariationScorefloat피치 변화 점수
result.full_mapping_groups[].fluency_metrics.stress_score.pitchVariationNScorefloat피치 변화 정규화 점수
result.full_mapping_groups[].recognized_tokens[]array인식 토큰 상세 배열 (Del 유형은 빈 배열)
result.full_mapping_groups[].recognized_tokens[].indexint토큰 인덱스
result.full_mapping_groups[].recognized_tokens[].strstring인식된 단어 텍스트
result.full_mapping_groups[].recognized_tokens[].scorefloat발음 점수 (0–100)
result.full_mapping_groups[].recognized_tokens[].is_spokenbool발화 여부
result.full_mapping_groups[].recognized_tokens[].start_msint단어 시작 시각 (ms)
result.full_mapping_groups[].recognized_tokens[].end_msint단어 종료 시각 (ms)
result.full_mapping_groups[].recognized_tokens[].syllables_countint음절 수
result.full_mapping_groups[].recognized_tokens[].phonemes[].strstringARPABET 기호 (유사 표기)
result.full_mapping_groups[].recognized_tokens[].phonemes[].scorefloat음소 점수 (0–100)
result.full_mapping_groups[].recognized_tokens[].phonemes[].start_msint음소 시작 시각 (ms)
result.full_mapping_groups[].recognized_tokens[].phonemes[].end_msint음소 종료 시각 (ms)
result.full_mapping_groups[].recognized_tokens[].phonemes[].phoneme_idint음소 내부 ID
result.full_mapping_groups[].recognized_tokens[].phonemes[].phoneme_typeint음소 유형
result.full_mapping_groups[].recognized_tokens[].phonemes[].is_vowelbool모음 여부
result.full_mapping_groups[].recognized_tokens[].phonemes[].is_speechbool음성 구간 여부
result.full_mapping_groups[].script_tokens[]array스크립트 토큰 배열 (Ins 유형은 빈 배열)
result.full_mapping_groups[].script_tokens[].indexint스크립트 토큰 인덱스
result.full_mapping_groups[].script_tokens[].sentence_indexint문장 인덱스
result.full_mapping_groups[].script_tokens[].keywordstring키워드 (정규화된 형태)
result.full_mapping_groups[].script_tokens[].textstring원문 텍스트 (구두점 포함)
result.full_mapping_groups[].script_tokens[].text_lengthint텍스트 길이 (문자 수)
result.full_mapping_groups[].script_tokens[].text_positionint전체 스크립트 내 문자 위치
result.full_mapping_groups[].script_tokens[].pronunciation_strings[]array발음 문자열 배열 (엔진 내부 음소 표기)
result.sentences[]array문장별 분석 결과
result.sentences[].idint문장 ID (0부터 시작)
result.sentences[].accuracyfloat문장 정확도 (0–100)
result.sentences[].attempt_ratefloat문장 발화 시도율 (0–100)
result.sentences[].completenessfloat문장 완성도 (0–100)
result.sentences[].mapping_scorefloat문장 매핑 점수 (0–100)
result.sentences[].mapping_distanceint문장 편집 거리 합산
result.sentences[].type_counts.Matchint정확히 인식된 단어 수
result.sentences[].type_counts.Subint대체(오독) 단어 수
result.sentences[].type_counts.Delint삭제(미발화) 단어 수
result.sentences[].type_counts.Insint삽입(스크립트에 없는 발화) 단어 수
result.sentences[].type_counts.Split-Subint분할 대체 단어 수
result.sentences[].type_counts.Merge-Subint병합 대체 단어 수 (해당 매핑이 없으면 키 자체가 부재)
result.sentences[].fluency_metrics.wpmfloat분당 단어 수
result.sentences[].fluency_metrics.ppsfloat초당 음소 수
result.sentences[].fluency_metrics.spsfloat초당 음절 수
result.sentences[].fluency_metrics.inter_words_latencyint단어 간 누적/평균 지연 (ms)
result.sentences[].mapping_groups[]array문장 내 단어 정렬 결과 — result.full_mapping_groups[]와 동일 구조
events[]array이벤트 배열 — rfa/rfa REST batch 응답에는 항상 포함됩니다. 순서: session.started → command.ack → recognition.result → rfa.result → session.ended REST 전용
events[].typestring이벤트 타입 — session.started / command.ack / recognition.result / rfa.result / session.ended / session.error(실패 시) REST 전용
events[].session_idstring세션 ID REST 전용
events[].server_timestring서버 시각 (ISO 8601) REST 전용
events[].subscription_plan_uidint구독 플랜 ID (session.started 타입) REST 전용
events[].subscription_statusstring구독 상태 (session.started 타입) REST 전용
events[].subscription_uuidstring구독 UUID (session.started 타입) REST 전용
events[].commandstring명령 이름 (command.ack 타입) REST 전용
events[].is_finalbool최종 결과 여부 (recognition.result / rfa.result 타입) REST 전용
events[].resultobject결과 객체 (recognition.result / rfa.result 타입) REST 전용
events[].statisticsobject처리 통계 (recognition.result / rfa.result 타입) REST 전용
events[].reasonstring종료 이유 (session.ended 타입, REST batch에서는 completed) REST 전용
events[].errorobject오류 객체 (session.error 타입) — code · message · details REST 전용
events[].statistics.frames_receivedint수신 프레임 수 (session.ended 타입) — WebSocket 전용이며 REST batch에서는 항상 0 REST 전용
events[].statistics.audio_bytesint수신 오디오 바이트 수 (session.ended 타입) — WebSocket 전용이며 REST batch에서는 항상 0 REST 전용
PROTOCOL 프로토콜

REST v1 프로토콜

단일 HTTP 요청으로 오디오 전체를 업로드하고 결과를 받는 배치 방식입니다. 가장 간단하며 서버 간 연동에 적합합니다.

POST /api/v1/{service}/{operation}

요청 방식 2가지

방식Content-Type구성
Multipart (권장)multipart/form-data JSON 파라미터(request 파트) + 오디오 바이너리(audio 파트)를 분리 전송. reference_audio 파트 추가 가능 (선택)
JSONapplication/json 오디오를 base64로 인코딩하여 JSON 본문(audio.data)에 포함

공통 최상위 필드

필드필수설명
user_sid필수계정 범위 사용자 식별자
params선택오퍼레이션별 파라미터 (각 레퍼런스 참고)
audio선택사용자 발화 음성. JSON 모드는 {"encoding":"base64","data":"…"} 객체 또는 base64 문자열
reference_audio선택참조 음성 (assess instance 모드)
client_info선택{id} — id 외의 키는 무시됨

service/operation은 URL 경로로 지정하므로 본문에서 생략합니다.

WebSocket v1 프로토콜

마이크 실시간 처리를 위한 양방향 스트리밍 프로토콜입니다. Text 프레임은 JSON 제어 메시지, Binary 프레임은 raw 오디오입니다.

WS wss://{host}/ws/v1

메시지 타입

방향분류타입설명
클라이언트 → 서버 세션 session.start · session.end 세션 시작 / 종료
오디오 command (start_audio · data_chunk · finalize_audio) · Binary 오디오 프레임 수신 시작 / 청크 전달 / 수신 종료·처리 시작
연결 유지 session.heartbeat 30초 주기 권장, 120초 무응답 시 타임아웃
서버 → 클라이언트 세션 session.started · session.ended · session.error · session.heartbeat.ack 세션 수립 / 종료 / 오류 / heartbeat 응답
커맨드 응답 command.ack · command.error · data_chunk.ack 커맨드 수락 / 커맨드 거부 (세션 유지, error.details.state에 현재 상태 정수값 포함) / 오디오 프레임 수신 확인
인식 결과 recognition.partial · recognition.result · assessment.result · intonation.result · phonics.result · rfa.result 부분 결과 (옵션 활성 시) / 최종 인식·평가·억양·파닉스·RFA 결과
기타 filesave.result · ref.ok · ref.failed 파일 저장 결과 / 참조 처리 성공·실패

상세 세션 흐름은 WebSocket 세션 흐름을 참고하세요.

GUIDE 공통 가이드

인증 (API Key)

모든 API는 콘솔에서 발급받은 계정 단위 API Key로 인증합니다. 프로토콜별 전달 방식은 다음과 같습니다.

프로토콜전달 방식비고
RESTAuthorization: Bearer <api-key> 헤더 body의 api_key 필드는 사용 금지
WebSocketAuthorization 헤더 또는 Cookie: ap_ws_ticket 브라우저는 ws-tickets로 티켓 발급 후 접속
사용자 식별은 계정 범위의 user_sid만 제출합니다. 계정은 API Key로 결정되며, 요청에 account_uid·user_uid를 넣어도 무시됩니다. Key가 없거나 만료되면 UNAUTHENTICATED(401), Key 소유 계정과 무관한 user_sid는 IDENTITY_MISMATCH(403)가 반환됩니다.

브라우저 인증

POST /api/v1/ws-tickets

브라우저는 WebSocket handshake에 Authorization 헤더를 넣을 수 없으므로, 사전에 1회성 티켓을 발급받아 Cookie로 ap_ws_ticket를 추가 후 접속합니다.

POST /api/v1/ws-tickets
Authorization: Bearer <api-key>
Content-Type: application/json

{ "purpose": "session.start", "user_sid": "user-2001" }

── 201 Created ──
Set-Cookie: ap_ws_ticket=…; Path=/ws/v1; Max-Age=30; HttpOnly; SameSite=Strict; Secure

{
  "expires_in": 30,
  "purpose": "session.start"
}

Secure 속성·쿠키명·TTL은 운영 환경에 따라 달라질 수 있습니다.

호출 샘플

# 티켓 발급 — Set-Cookie 를 cookie.txt 에 저장
curl -X POST "https://{host}/api/v1/ws-tickets" \
  -H "Authorization: Bearer $API_KEY" \
  -H "Content-Type: application/json" \
  -c cookie.txt \
  -d '{"purpose":"session.start","user_sid":"user-2001"}'

# 응답: {"expires_in":30,"purpose":"session.start"}
# 이후 30초 안에 cookie.txt 의 쿠키를 실어 wss://{host}/ws/v1 로 연결
import requests

# Session 을 쓰면 Set-Cookie 가 자동으로 보관됩니다
session = requests.Session()
resp = session.post(
  "https://{host}/api/v1/ws-tickets",
  headers={"Authorization": f"Bearer {API_KEY}"},
  json={"purpose": "session.start", "user_sid": "user-2001"},
)
print(resp.json())   # {"expires_in": 30, "purpose": "session.start"}

# 30초 안에 같은 쿠키로 WebSocket 연결 (websocket-client 예시)
cookie = "; ".join(f"{c.name}={c.value}" for c in session.cookies)
# ws = websocket.create_connection(
#     "wss://{host}/ws/v1", header=[f"Cookie: {cookie}"])
// 티켓 발급 (쿠키는 자동 저장) → 30초 안에 WS 연결
await fetch("https://{host}/api/v1/ws-tickets", {
  method: "POST",
  credentials: "include",   // Set-Cookie 수신에 필수
  headers: { Authorization: `Bearer ${API_KEY}`, "Content-Type": "application/json" },
  body: JSON.stringify({ purpose: "session.start", user_sid: "user-2001" }),
});
const ws = new WebSocket("wss://{host}/ws/v1");  // 쿠키로 인증됨

티켓 TTL(Time To Live, 유효시간) 기본 30초이며 1회만 사용할 수 있습니다.

WebSocket 세션 흐름

WS wss://{host}/ws/v1

Text 프레임 = JSON 제어 메시지, Binary 프레임 = raw 오디오(16Khz PCM, Little Endian 권장)입니다.

세션 흐름

Client                                Server
──────                                ──────
session.start          ─▶
                     ◀─  session.started        (session_id 발급)
command: start_audio   ─▶
                     ◀─  command.ack            (IDLE → RECEIVING)
[binary audio frames]  ─▶
                     ◀─  data_chunk.ack …       (수신 확인, 인식 결과 아님)
                     ◀─  recognition.partial …  (부분 결과 옵션 활성 시)
command: finalize_audio ─▶
                     ◀─  command.ack            (RECEIVING → PROCESSING)
                     ◀─  recognition.result / assessment.result …
session.end            ─▶
                     ◀─  session.ended

session.start 예시

{
  "type": "session.start",
  "user_sid": "user-2001",
  "service": "sr",
  "operation": "recognize",
  "params": {
  "text": "Hello world",
  "resource_name": "KONG_ALL",
  "audio_format": { "sample_rate": 16000, "channels": 1, "encoding": "pcm" }
  },
  "client_info": { "id": "client-001" }
}

session.started 페이로드

{
  "type": "session.started",
  "session_id": "01HXXXXXXXXXXXXXXXXXXXXXXX",
  "subscription_uuid": "…",
  "subscription_plan_uid": 0,
  "subscription_status": "…",
  "server_time": "2026-02-12T10:30:45Z"
}

command.ack와 session.heartbeat.ack에는 server_processing_time_ns가 함께 포함됩니다.

주의 — session.started 수신 전에 command/binary를 보내면 PROTOCOL_VIOLATION으로 연결이 종료됩니다. session.end는 finalize_audio를 자동 실행하지 않으므로 결과가 필요하면 종료 전에 반드시 finalize 하세요.

session.heartbeat

WebSocket 연결을 오래 유지하는 동안 세션을 연장하는 keep-alive 메시지입니다. 장시간 연결을 유지할 때는 주기적으로 호출해 세션을 연장해야 하며, 수신하면 세션이 연장되고 session.heartbeat.ack로 응답합니다. 세션 타임아웃이 120초이므로 30초 주기를 권장합니다.

전송 구간 — 반드시 session.started를 받은 뒤부터 session.end를 보내기 전까지 사이에 보내야 합니다. 이 구간 안에서는 start_audio·Binary 프레임·finalize_audio 등 다른 메시지와 순서 제약 없이 언제든 보낼 수 있으며, finalize_audio 뒤 결과를 기다리는 동안에도 보낼 수 있습니다.
필드타입필수허용 값설명
typestring필수session.heartbeat이 메시지의 유일한 필드입니다

요청 / 응답 예시

// 클라이언트 → 서버
{ "type": "session.heartbeat" }

// 서버 → 클라이언트
{
  "type": "session.heartbeat.ack",
  "session_id": "01HXXXXXXXXXXXXXXXXXXXXXXX",
  "server_time": "2026-02-12T10:30:45Z",
  "server_processing_time_ns": 128000
}

비동기 오퍼레이션이 진행 중이면 ack에 operation_async 객체가 함께 포함됩니다 (진행 상태가 없으면 키 자체가 생략됩니다).

구간 밖에서 보낸 경우 — session.start 응답을 기다리는 중에 보내면 session.heartbeat before session.started로 거부되고, 세션이 시작되지 않은 상태에서 보내면 SESSION_NOT_STARTED가 반환됩니다.

오디오 형식 · 요청 제한

AudioFormat 객체

필드타입허용 값설명
sample_rateint양의 정수 (기본 16000)샘플링 레이트. 16kHz로 변환되어 처리됩니다 (권장 16000).
channelsint양의 정수 (기본 1)채널 수. mono로 변환되어 처리됩니다 (권장 1)
encodingstringraw PCM: pcm
컨테이너: wav · flac · ogg · opus 등
인코딩 힌트 (선택). 미지정 시 raw PCM16LE로 간주

수신한 오디오는 자동으로 16kHz mono PCM으로 변환되어 처리됩니다. 브라우저 마이크 입력은 PCM16LE 바이너리 프레임으로 전송하는 것을 권장합니다.

raw PCM은 16-bit little endian으로 고정 해석됩니다. mp3 등 일부 컨테이너 형식은 지원되지 않을 수 있으므로 WAV 또는 raw PCM 사용을 권장합니다.

요청 제한

오디오 길이

서비스권장최대
SR 단문
sr/recognize
1분 이내2분
SR 장문
sr/recognize_long
3분 이내10분
RFA
rfa/rfa
3분 이내10분
STT
stt/transcribe
3분 이내10분
Phonics
phonics/analyze
3분 이내10분

그 외 제한

항목구분값비고
요청 본문 크기REST≤ 8 MB초과 시 413 PAYLOAD_TOO_LARGE
타임아웃REST 비동기 결과 대기90초초과 시 504 TIMEOUT. 본문 업로드 시간이 아닌 결과 대기 시간
WebSocket 세션120초무응답 시 세션 종료
heartbeat 권장 주기30초
동시 세션사용자당1초과 시 429 CONNECTION_LIMIT_EXCEEDED

에러 코드

실패 시 모든 프로토콜이 공통 에러 객체 error와 server_time을 포함한 JSON을 반환합니다.

{
  "error": {
    "code": "UNSUPPORTED_MEDIA_TYPE",
    "message": "Unsupported audio format",
    "details": { "reason": "decode_failed" },
    "ap_request_id": "01HXXXXXXXXXXXXXXXXXXXXXXX"
  },
  "server_time": "2026-02-12T10:30:45Z"
}

details는 값이 없으면 키 자체가 생략되며, ap_request_id도 상관관계 ID가 없으면 생략됩니다. 실제로 사용되는 details 키는 reason · command · state · wait_ms · issued_session_id · saw_recognition_result 등입니다. 응답 헤더 X-AP-Request-Id로도 동일한 요청 ID를 확인할 수 있습니다.

codeHttp Response의미
INVALID_REQUEST / INVALID_MESSAGE400잘못된 요청 형식, 필수 파라미터 누락 (user_sid 등). 같은 원인이지만 REST는 INVALID_REQUEST, WebSocket은 INVALID_MESSAGE로 전달됩니다
INVALID_JSON / INVALID_MULTIPART400JSON 파싱 실패 / 멀티파트 구성 오류
UNSUPPORTED_MEDIA_TYPE400디코딩할 수 없는 오디오 형식
UNSUPPORTED_MESSAGE_TYPE400지원하지 않는 메시지 타입
INVALID_OPERATION / UNSUPPORTED_OPERATION / OPERATION_NOT_ALLOWED_FOR_PROTOCOL400존재하지 않는 서비스·오퍼레이션, 해당 프로토콜에서 허용되지 않는 오퍼레이션
COMMAND_NOT_ALLOWED / UNSUPPORTED_COMMAND400현재 세션 상태에서 허용되지 않는 command / 모듈이 지원하지 않는 command
SESSION_NOT_OPENED / SESSION_NOT_STARTED / SESSION_ALREADY_STARTED / SESSION_ID_MISMATCH400세션 순서·식별자 오류
PROTOCOL_VIOLATION—프레임 순서·세션 상태 위반 — WebSocket · TCP 전용(session.error로 전달되고 연결이 종료됨, HTTP 상태 없음)
UNAUTHENTICATED401API Key 누락·형식 오류·폐기·만료
IDENTITY_MISMATCH403user_sid 또는 세션 소유자 불일치
DUPLICATE_USER403동일 사용자 중복 세션
ADMISSION_FAILED403 · 429구독·쿼터 거절. 사유는 error.details.reason에 담김 (QUOTA_EXCEEDED · CP_UNAVAILABLE 등). 쿼터 초과는 429
SESSION_NOT_FOUND404세션 없음 또는 만료
PAYLOAD_TOO_LARGE413요청 본문 최대 크기(8MB) 초과
CONNECTION_LIMIT_EXCEEDED429동시 접속·세션 한도 초과
INTERNAL_ERROR500서버 내부 오류
RUNTIME_SERVICE_INTERNAL_ERROR500AI 엔진(런타임) 내부 오류
OPERATION_FAILED500오퍼레이션 결과 미수신 (RFA 인식·평가 결과 누락 등)
PROTOCOL_TRANSPORT_EXPIRED / ABORTED409 · 500전송 계층 만료 / 처리 중단. 세션 승인·개시 중에 연결이 끊긴 경우는 409, 그 외에는 500
AUTHENTICATION_UNAVAILABLE / OPEN_SESSION_FAILED503인증 서버 연결 실패 / 세션 개시 실패
RUNTIME_SERVICE_NOT_FOUND / RUNTIME_SERVICE_DISABLED / RUNTIME_SERVICE_BUSY_TIMEOUT503런타임 미등록 · 비활성 · 혼잡
TIMEOUT504REST 비동기 결과 대기 시간 초과 (RFA 등). details.reason은 REST_UNARY_ASYNC_TIMEOUT이며 details.wait_ms와 함께 부분 events[]가 반환됩니다