화면 테마
학습 상태와 결과 조회
개통 전
결과 조회 API(learning-results, learning-runs)는 아직 테스트 환경에 열리지 않았습니다. 아래는 확정된 응답 명세이며 개통 일정은 별도로 안내합니다. 지금 테스트 환경에서는 학습 진입·학습이력 조회·활동 CSV를 확인할 수 있습니다.
활동 하나는 RA·WR·SP 중 한 유형입니다. 하나의 학습 차시를 조회하면 그 유형의 결과 객체 하나를 반환합니다. 별도의 하위 활동 목록이나 하위 활동 ID를 거쳐 결과를 다시 조회하는 단계는 없습니다. IBTRA·IBTW·IBTS는 각각 RA·WR·SP와 같은 결과 구조를 사용하며, studyInfo.studyType은 요청한 IBT 코드를 그대로 반환합니다.
아발론 서버가 조회 전용 Bearer key로 호출합니다. 학생 ID와 학습 진입 때 보낸 6개 값(studyType·level·layer·unitCd·regYear·season) 으로 조회합니다. 플랭 활동 ID는 보내지 않으며, 사전에 플랭의 차시 ID를 받을 필요도 없습니다.
http
GET /integrations/v1/learning-results?memIdx=001234567&studyType=WR&level=MA&layer=RED&unitCd=1®Year=2026&season=3
Authorization: Bearer <PARTNER_SERVER_KEY>| query | 필수 | 의미 |
|---|---|---|
memIdx | 필수 | 아발론 학생 ID. 선행 0 보존 |
studyType | 필수 | 학습 유형 코드 |
level | 필수 | 레벨 코드 |
layer | 필수 | 레이어 코드 |
unitCd | 필수 | 아발론 단원 코드. 진입 때 보낸 문자열 그대로 |
regYear | 필수 | 기수 연도 |
season | 필수 | 기수 시즌(1~4) |
attempt | 선택 | 다시 해보기 회차(1부터). 없으면 마지막으로 완료된 회차 |
6개 값은 학습 진입 때와 같은 규칙으로 하나의 활동을 가리킵니다. 같은 단원이라도 regYear·season이 다르면 다른 활동입니다. 6개 값에 해당하는 활동이 없으면 404 CONTAINER_NOT_FOUND, 활동은 있지만 그 학생의 학습 기록(또는 지정한 회차)이 없으면 404 LEARNING_RUN_NOT_FOUND입니다. 다른 활동이나 다른 회차의 결과로 대체하지 않습니다. 귀속 월(regYm)은 조회 조건이 아니며, 저장된 값을 studyInfo로 반환합니다.
학생이 완료 화면에서 다시 해보기를 하면 같은 활동의 새 회차가 생기고, 결과도 회차마다 따로 계산·보관됩니다.
attempt를 생략하면 마지막으로 완료된 회차의 결과를 반환합니다. 다시 해보기로 새 회차가 진행 중이어도, 이미 받은 완료("1100") 결과가 학습 중으로 바뀌지 않습니다. 아직 완료된 회차가 없으면 진행 중인 회차를 반환합니다.- 응답의
attemptNumber·attemptCount로 이 결과의 회차와 지금까지의 회차 수(진행 중 회차 포함)를 알 수 있습니다.attemptNumber가attemptCount보다 작으면 새 회차가 진행 중입니다. - 모든 회차의 결과를 보관하려면
attemptCount까지attempt로 회차별 조회합니다. 마지막 결과만 필요하면 기본 조회만 쓰면 됩니다.
응답에서 data.learningRunId를 얻은 뒤에는 GET /integrations/v1/learning-runs/:learningRunId로 같은 결과를 조회할 수도 있습니다. 회차마다 별도 수행 기록과 ID를 가집니다. 학생 실행 창의 권한으로 조회용 서버 API를 호출할 수 없습니다.
응답 구조
| 위치 | 필드 | 의미 |
|---|---|---|
| 최상위 | success, regDate, data | regDate는 응답 생성 시각 |
data | studyInfo | 학습 시작 시 저장한 studyType, memIdx, level, layer, unitCd, regYear, season, regYm |
data | attemptNumber, attemptCount | 이 결과의 회차와 지금까지의 회차 수(진행 중 포함). 다시 해보기가 없으면 둘 다 1 |
data | studyStatus | 문자열 "0": 학습 전, "500": 학습 중, "1100": 학습 완료 |
data | 유형별 결과 필드 | accuracy, fluency, sentences, originalEssay, rubrics 등 해당 유형의 결과 필드를 같은 깊이에 배치. totalScore는 RA에만 제공 |
data | studyDate | 마지막 학생 학습 시각. 분석·교사 수정 시각과 구분 |
data.results[], data.activities[], data.result처럼 결과를 다시 감싸는 계층은 추가하지 않습니다. regDate·studyDate는 YYYY-MM-DD HH:mm:ss 형식의 한국시간이며, 학습 전 studyDate는 null입니다.
수행 기록과 결과 상태 필드
| 필드 | 위치 | 필요한 이유 |
|---|---|---|
learningRunId | 결과 응답의 data | 학생·활동·회차에 해당하는 수행 기록의 ID. ID 방식의 후속 조회에 사용 |
resultStatus | 결과 응답의 data | 학습 완료와 분석 준비 상태 구분 |
resultRevision | 결과 응답의 data | 재분석·교사 수정에 따른 결과 변경 구분 |
unavailableReason | 결과 응답의 data | 결과 미준비·실패·공개 제한 사유. 정상 준비 시 null |
이 필드는 수행 기록과 결과의 준비 상태·변경 여부를 식별합니다. 활동은 6개 값으로 식별하며 플랭 활동 ID는 진입·결과 조회에 사용하지 않습니다.
| resultStatus | 의미 |
|---|---|
not_started | 결과 생성 전 |
processing | 분석 진행 중 |
ready | 결과 준비 완료 |
failed | 분석 실패 |
withheld | 시험 등 결과 공개 제한 |
제출은 완료됐지만 분석 중인 WR 응답 예시입니다. 실제 점수 예시가 아니라 응답 구조 예시입니다.
json
{
"success": true,
"regDate": "2026-09-14 10:20:05",
"data": {
"studyInfo": {
"studyType": "WR",
"memIdx": "001234567",
"level": "MA",
"layer": "RED",
"unitCd": "1",
"regYear": "2026",
"season": "3",
"regYm": "202609"
},
"attemptNumber": 1,
"attemptCount": 1,
"studyStatus": "1100",
"learningRunId": "example-run-id",
"resultStatus": "processing",
"resultRevision": 1,
"unavailableReason": "analysis_in_progress",
"topic": null,
"originalEssay": null,
"correctedEssay": null,
"mission": null,
"grammarCorrections": null,
"rubrics": null,
"comment": null,
"studyDate": "2026-09-14 10:20:00"
}
}분석 전·진행 중·실패·공개 제한 상태에서도 studyInfo와 studyStatus는 반환하고, 답안·음원·점수 등 유형별 결과 필드는 null로 반환하는 안입니다. ready일 때는 해당 유형의 결과를 채웁니다. 확인된 빈 목록은 []이며, 미준비를 빈 목록이나 0점으로 표현하지 않습니다. SP 음성 평가 연동 전에는 ready 상태에서도 FLUENCY/PRONUNCIATION의 score/strengths/improvements를 모두 JSON null로 반환합니다. 이 두 축의 미지원만으로 결과 준비를 지연하거나 실패 처리하지 않습니다. 아발론의 전체 종합 코멘트는 필수 제공 항목이므로 ready 상태에서는 comment가 비어 있지 않은 문자열로 반환됩니다.
RA의 전체 녹음 이력 반환도 위 공개·준비 상태를 따릅니다. 결과 본문을 제공하는 상태에서는 실패한 과거 시도를 삭제하거나 순번을 바꾸지 않고, 측정값이 없는 필드는 null로 표시합니다. 전체 집계는 현재 RAV3의 최고점 선택·집계 방식을 따릅니다. 개별 시도의 미측정값을 다른 시도의 점수로 채우지는 않습니다.
분석 중에는 일정 간격으로 재조회하고 실패·공개 제한을 무한 대기와 구분합니다. 재조회 간격·상한과 최종 오류 코드 명세는 플랭이 정해 안내합니다. HTTP 호출 성공 여부인 success와 학습/분석 성공 여부는 별개입니다.
유형별 응답 필드
아래 결과 필드는 모두 data 바로 아래에 있습니다. 필드 이름과 배열·객체 구조에는 확정된 연동 정책을 반영했습니다.
| 유형 | 결과 필드 |
|---|---|
| RA | totalScore, accuracy, fluency, sentences[], comment, studyDate |
| WR | topic, originalEssay, correctedEssay, mission[], grammarCorrections[], rubrics, comment, studyDate |
| SP | topic, recordings[], mission[], grammarCorrections[], rubrics, comment, studyDate |
| 하위 객체 | 응답 필드 |
|---|---|
| accuracy | score, stars, goodCount, normalCount, badCount, totalWords, goodRatio, normalRatio, badRatio |
| fluency | score, stars, wpm, wpmStars, wpmComment, hesitationAvgSec, hesitationStars, hesitationComment |
| sentences[] | sentenceIndex, totalAttempt, originalText, nativeAudioUrl, attempts[] |
| sentences[].attempts[] | attemptIndex, accuracyScore, accuracyStars, fluencyScore, fluencyStars, studentAudioUrl, tokens[] |
| sentences[].attempts[].tokens[] | tokenIndex, startIndex, endIndex, word, status |
| recordings[] | audioIndex, audioUrl, sttTranscript |
| mission[] | title, basis, isPassed |
| grammarCorrections[] | 틀린 문장만 포함. correctYn="N", originalSentence, wrongToken, correctedToken, correctedSentence, feedback |
| rubrics | 평가축 코드를 키로 갖는 객체. 각 값은 score, strengths[], improvements[] |
WR·SP 점수 제공 범위
WR·SP 및 대응 IBTW·IBTS는 개별 루브릭의 점수·강점·개선점을 제공합니다. 기존에 없는 종합 점수를 새로 계산하지 않으며, totalScore는 응답에서 제외합니다. 결과 준비 상태와 관계없이 키 자체를 생략하고 null로도 반환하지 않습니다.
전체 종합 코멘트 comment는 계속 제공합니다. RA의 totalScore와 기존 RAV3 집계 기준도 유지합니다.
RA 전체 시도와 평가 구간
RA의 sentences[]는 문장/콘텐츠별 한 항목이며 각 항목의 attempts[]에 모든 저장 녹음 시도를 담습니다. 문장은 sentenceIndex, 시도는 attemptIndex 오름차순으로 반환합니다. totalAttempt는 최초 녹음을 포함한 해당 문장의 전체 저장 시도 수이며 결과 본문을 반환할 때 attempts.length와 같습니다. 다른 회차의 시도는 합치지 않습니다.
| 필드 | JSON 타입 | 기준 |
|---|---|---|
| sentenceIndex | 정수 | 콘텐츠 순서, 1부터 시작 |
| totalAttempt | 정수 | 해당 콘텐츠의 전체 저장 녹음 시도 수 |
| originalText | 문자열 | 모든 시도의 하이라이트 위치가 가리키는 기준 원문 |
| attempts[].attemptIndex | 정수 | 해당 콘텐츠 안의 녹음 순서, 1부터 시작 |
| attempts[].tokens[].tokenIndex | 정수 | 해당 시도의 tokens 배열 순서, 1부터 시작하며 시도마다 다시 시작 |
| attempts[].tokens[].startIndex | 정수 | originalText의 UTF-16 문자 위치, 0부터 시작·시작 포함 |
| attempts[].tokens[].endIndex | 정수 | originalText의 UTF-16 문자 위치, 끝 제외 |
originalText.slice(startIndex, endIndex) === word가 성립하도록 전달합니다. endIndex는 마지막 문자의 다음 위치입니다. 토큰은 원문 순서로 반환하며 tokenIndex는 문자 위치·점수·시간을 의미하지 않습니다. (sentenceIndex, attemptIndex, tokenIndex)로 응답 안의 평가 구간을 구분합니다. originalText를 임의로 trim하거나 공백·줄바꿈을 바꾼 뒤 인덱스를 적용하면 안 됩니다.
아래는 응답의 sentences 부분을 발췌한 설명용 예시입니다. 음원 주소와 점수는 예시 값입니다.
json
{
"sentences": [
{
"sentenceIndex": 1,
"totalAttempt": 2,
"originalText": "What now?",
"nativeAudioUrl": "https://media.example/ra-native.mp3",
"attempts": [
{
"attemptIndex": 1,
"accuracyScore": 86,
"accuracyStars": 3,
"fluencyScore": 90,
"fluencyStars": 3,
"studentAudioUrl": "https://media.example/ra-attempt-1.webm",
"tokens": [
{
"tokenIndex": 1,
"startIndex": 0,
"endIndex": 4,
"word": "What",
"status": "good"
},
{
"tokenIndex": 2,
"startIndex": 5,
"endIndex": 9,
"word": "now?",
"status": "good"
}
]
},
{
"attemptIndex": 2,
"accuracyScore": 80,
"accuracyStars": 3,
"fluencyScore": 70,
"fluencyStars": 2,
"studentAudioUrl": "https://media.example/ra-attempt-2.webm",
"tokens": [
{
"tokenIndex": 1,
"startIndex": 0,
"endIndex": 4,
"word": "What",
"status": "good"
},
{
"tokenIndex": 2,
"startIndex": 5,
"endIndex": 9,
"word": "now?",
"status": "bad"
}
]
}
]
}
]
}각 시도의 점수·별점·학생 음원·tokens는 해당 시도의 결과이며, nativeAudioUrl과 originalText는 콘텐츠 공통 정보입니다. 실패한 시도도 attemptIndex를 유지하고, 알 수 없는 측정값은 null로 반환합니다. 분석되지 않아 토큰을 알 수 없으면 tokens는 null이며, 비어 있음이 확인된 목록만 []입니다. 녹음이 없는 내부 초기 placeholder는 시도로 세거나 빈 객체로 반환하지 않습니다.
전체 점수·통계는 현재 RAV3와 동일하게 콘텐츠별 최고점 시도를 선택해 집계합니다. 최고점은 해당 시도의 종합 점수를 기준으로 정하며 동점이면 기존 선택을 유지합니다. 정확성·유창성·속도·머뭇거림·평가 구간 통계는 같은 선택 결과를 사용하고, 종합 코멘트도 이 집계를 근거로 생성합니다. 모든 시도 이력을 평균한 점수가 아닙니다.
tokens[].word는 평가 구간이며, to be?처럼 여러 단어가 합쳐진 문자열일 수 있습니다. 병합된 구간의 점수에 따른 status를 전달합니다. accuracy의 goodCount·normalCount·badCount는 판정별 평가 구간 수이며 totalWords는 세 count의 합입니다. totalWords는 공백으로 구분한 개별 단어 수를 의미하지 않습니다. 전체 시도의 토큰을 모두 합친 수와 최고점 시도 기준의 전체 집계는 다를 수 있습니다.
RA 소수값의 문자열 표현
아래 다섯 필드는 값이 있을 때 소수점 한 자리의 JSON 문자열로 반환합니다. 값이 0이나 정수여도 "0.0", "100.0"처럼 같은 타입·자릿수를 유지합니다. 소수 구분자는 마침표이며 단위·%·천 단위 쉼표를 붙이지 않습니다.
| 필드 | 타입 | 예시 |
|---|---|---|
| accuracy.goodRatio | 문자열 또는 null | "91.2" |
| accuracy.normalRatio | 문자열 또는 null | "7.5" |
| accuracy.badRatio | 문자열 또는 null | "1.3" |
| fluency.wpm | 문자열 또는 null | "119.4" |
| fluency.hesitationAvgSec | 문자열 또는 null | "8.4" |
비율은 각 count / totalWords × 100을 소수점 한 자리로 반올림해 문자열화합니다. 각 비율을 독립 반올림하므로 합계가 정확히 100.0이 아닐 수 있습니다. totalWords가 0이면 세 비율은 null입니다. 속도·머뭇거림은 기존 RAV3 집계값을 한 자리 문자열로 표현하며 집계 산식은 바꾸지 않습니다. 미준비·미지원 값은 JSON null로 반환하고 "null", 빈 문자열, "0.0"으로 대체하지 않습니다. 이 다섯 필드 이외의 점수·별점·횟수·인덱스는 숫자 타입을 유지합니다.
WR·SP 루브릭
WR의 루브릭 키는 TOPIC_RELEVANCE, ORGANIZATION, SUPPORT, VOCABULARY, GRAMMAR에 실제 아발론 평가 기준을 매핑합니다. SP는 FLUENCY, PRONUNCIATION, VOCABULARY, TOPIC_RELEVANCE, GRAMMAR이며 발음·음성 유창성은 1차 평가에서 제외하며 지원 여부·평가 방식은 추후 결정합니다. 연동 전에는 FLUENCY/PRONUNCIATION 객체를 유지하고 각 객체의 score/strengths/improvements를 모두 JSON null로 반환합니다. RA의 기존 음성 평가 결과는 계속 제공합니다. 자세한 범위는 학습 결과 제공 범위를 참고하세요. 임의로 기존 점수 이름을 바꾸어 채우지 않습니다.
SP 응답에는 round 필드를 포함하지 않습니다. 단원은 studyInfo.unitCd, 다시 해보기 회차는 attemptNumber로 표현합니다.
미션은 제목 title, 판정 근거 basis, 통과 여부 isPassed만 제공합니다. achievementRate는 응답에 포함하지 않습니다. 실제 수행 개수는 basis에 보존합니다. 루브릭의 강점·개선점이 생성되지 않은 경우 해당 필드는 null이며, 확인된 빈 목록만 []로 반환합니다.