Skip to Content
DocumentationGet Started

Frame Activity SDK 소개

Frame Activity SDK는 외부 임베드 콘텐츠에서 발생하는 학습 이벤트(예: 학습 시작, 답안 제출 등)를 IHFB SchoolPT 플랫폼에 전달하고, 학습 데이터의 저장 및 로드를 지원하는 JavaScript 라이브러리입니다.


설치 방법

설치 방법은 다음과 같습니다:


시작하기

<script type="module"> import { FrameActivitySdk } from './frame-activity-sdk.esm.js'; // SDK 인스턴스 생성 const frameActivitySdk = new FrameActivitySdk(); try { // 현재 모드 확인 const mode = await frameActivitySdk.getMode(); // 모드에 따른 시나리오 처리 if (mode === 'Edit') { // Edit 모드에서만 학습 활동 등록 await frameActivitySdk.registerActivities([ { activityId: '1', type: 'MULTIPLE_CHOICE', choices: [ { label: '서울', isCorrect: true }, { label: '부산', isCorrect: false }, { label: '대전', isCorrect: false }, ], }, { activityId: '2', type: 'SHORT_ANSWER', answer: '대한민국', }, { activityId: '3', type: 'INTERACTIVE', }, { activityId: '4', type: 'SPEAKING', speakingType: 'STT_ONLY', }, { activityId: '5', type: 'SPEAKING', speakingType: 'PHONICS', }, { activityId: '6', type: 'SPEAKING', speakingType: 'PRONUNCIATION', }, ]); } } catch (error) { console.error('초기화 실패:', error.message); } </script>

공통 사항

  • 모든 API는 비동기(async/await) 방식으로 동작합니다.
  • SDK는 각 메서드 호출 시 자동으로 초기화됩니다. 별도의 초기화 과정이 필요하지 않습니다.
  • 모든 API에서 다음과 같은 공통 에러가 발생할 수 있습니다:
    • SDK 초기화 관련 에러
    • 네트워크 통신 오류
    • serialize 관련 오류 (함수, undefined 등 JSON으로 serialize 할 수 없는 값 포함 시)

타입 정의

학습 활동 타입

interface Choice { label: string; isCorrect: boolean; } interface MultipleChoiceActivity { activityId: string; type: 'MULTIPLE_CHOICE'; choices: Choice[]; } interface ShortAnswerActivity { activityId: string; type: 'SHORT_ANSWER'; answer: string; } interface InteractiveActivity { activityId: string; type: 'INTERACTIVE'; } type SpeakingType = 'STT_ONLY' | 'PHONICS' | 'PRONUNCIATION'; interface SpeakingActivity { activityId: string; type: 'SPEAKING'; speakingType: SpeakingType; } type Activity = MultipleChoiceActivity | ShortAnswerActivity | InteractiveActivity | SpeakingActivity;

제출 데이터 타입

interface MultipleChoiceSubmitData { activityId: string; userSelectedIndexes: number[]; } interface ShortAnswerSubmitData { activityId: string; userAnswer: string; } interface InteractiveSubmitData { activityId: string; } interface SpeakingSubmitData { activityId: string; } type SubmitData = | MultipleChoiceSubmitData | ShortAnswerSubmitData | InteractiveSubmitData | SpeakingSubmitData;

저장 데이터 타입

type JsonPrimitive = string | number | boolean | null; type JsonArray = JsonValue[]; type JsonObject = { [key: string]: JsonValue }; type JsonValue = JsonPrimitive | JsonObject | JsonArray; interface SaveData extends JsonObject {}

API 상세 명세

getMode()

현재 SDK의 시나리오를 조회합니다.

매개변수: 없음

반환값:

  • Promise<'Study' | 'TeacherClassResult' | 'TeacherStudentResult' | 'StudentResult' | 'Edit'>

발생 가능한 에러:

  • "모드 조회 오류": 현재 모드를 조회하는 데 실패한 경우
  • "SDK 초기화 오류": SDK 연결 초기화에 실패한 경우

사용 예시:

try { const mode = await frameActivitySdk.getMode(); switch (mode) { case 'Edit': // CMS에서 콘텐츠 등록 시 처리 break; case 'Study': // 수업 페이지에서 학습 진행 시 처리 break; case 'TeacherClassResult': // 선생님이 수업 화면에서 웹 저작물 컨텐츠의 결과를 조회 시 처리 break; case 'TeacherStudentResult': // 선생님이 수업 화면에서 학생 1명에 대한 웹저작물 컨텐츠의 결과를 조회 시 처리 break; case 'StudentResult': // 학생이 학습 화면에서 자신의 학습 결과를 조회 시 처리 break; } } catch (error) { console.error('모드 조회 실패:', error.message); }

registerActivities(activities: Activity[])

CMS에서 콘텐츠 등록 시 문제 정보를 등록합니다. Edit 모드에서만 사용해야 합니다.

매개변수:

  • activities: 등록할 학습 활동 배열

반환값:

  • Promise<void>

발생 가능한 에러:

  • "유효하지 않은 데이터 형식입니다.": 입력된 데이터가 배열이 아니거나 비어있는 경우
  • "중복된 activityId가 존재합니다.": 활동 데이터에 중복된 activityId가 있는 경우
  • "유효하지 않은 활동 데이터가 포함되어 있습니다.": 활동 데이터가 지원하는 타입의 형식에 맞지 않는 경우

사용 예시:

try { await frameActivitySdk.registerActivities([ { activityId: '1', type: 'MULTIPLE_CHOICE', choices: [ { label: '서울', isCorrect: true }, { label: '부산', isCorrect: false }, { label: '대전', isCorrect: false }, ], }, { activityId: '2', type: 'SHORT_ANSWER', answer: '대한민국', }, { activityId: '3', type: 'INTERACTIVE', }, { activityId: '4', type: 'SPEAKING', speakingType: 'STT_ONLY', }, { activityId: '5', type: 'SPEAKING', speakingType: 'PHONICS', }, { activityId: '6', type: 'SPEAKING', speakingType: 'PRONUNCIATION', }, ]); } catch (error) { console.error('활동 등록 실패:', error.message); }

submit(data: SubmitData[])

학습자의 답안을 제출합니다. Study 모드에서 사용됩니다.

매개변수:

  • data: 제출할 답안 데이터 배열

반환값:

  • Promise<void>

발생 가능한 에러:

  • "유효하지 않은 답안 데이터입니다.": 제출 데이터가 올바른 형식이 아닌 경우
    • 객관식: userSelectedIndexes가 숫자 배열이 아닌 경우
    • 주관식: userAnswer가 문자열이 아닌 경우
    • 말하기, 활동: 추가 데이터 없이 activityId만 제출
  • "존재하지 않는 activityId입니다.": 등록되지 않은 활동에 대한 답안 제출 시

사용 예시:

try { // 객관식 답안 제출 await frameActivitySdk.submit([ { activityId: '1', userSelectedIndexes: [0], // 첫 번째 선택지 선택 }, ]); // 주관식 답안 제출 await frameActivitySdk.submit([ { activityId: '2', userAnswer: '대한민국', }, ]); // 활동, 말하기 타입 제출 await frameActivitySdk.submit([ { activityId: '3', }, ]); } catch (error) { console.error('답안 제출 실패:', error.message); }

save(key: string, data: SaveData)

현재 학습 상태를 저장합니다. 저장되는 데이터는 LearningActivity 마다 독립적으로 관리됩니다.

매개변수:

  • key: 저장할 데이터의 키 (문자열)
  • data: 저장할 데이터 객체 (serialize 가능한 값)

반환값:

  • Promise<void>

발생 가능한 에러:

  • "유효하지 않은 저장 데이터입니다.": 저장 데이터가 serialize 가능한 형식이 아닌 경우
  • "직렬화할 수 없는 데이터가 포함되어 있습니다.": 데이터에 함수, undefined 등 JSON으로 serialize 할 수 없는 값이 포함된 경우

사용 예시:

try { await frameActivitySdk.save('user-progress', { currentStep: 3, progress: { answers: ['답안1', '답안2'], timestamp: new Date().toISOString(), }, }); } catch (error) { console.error('저장 실패:', error.message); }

load(key: string)

저장된 학습 상태를 불러옵니다.

매개변수:

  • key: 불러올 데이터의 키 (문자열, save 시 사용한 key와 동일한 값)

반환값:

  • Promise<JsonValue | null>

발생 가능한 에러:

  • "불러오기 오류": 저장된 데이터를 불러오는 데 실패한 경우
  • "유효하지 않은 키": 존재하지 않는 키로 데이터를 불러오려 할 경우

사용 예시:

try { const savedData = await frameActivitySdk.load('user-progress'); if (savedData) { // 저장된 데이터 처리 console.log('불러온 데이터:', savedData); } } catch (error) { console.error('불러오기 실패:', error.message); }

save/load에 활용되는 데이터 저장 및 접근 구조

데이터 저장 흐름

예시) 선생님 페이지에서의 save/load 활용

선생님이 수업 화면에서 학생 1명에 대한 웹저작물 컨텐츠의 결과를 조회할 때, 다음과 같은 시나리오로 save/load를 활용할 수 있습니다:

주의사항

⚠️ 중요 안내

  1. activityId는 문자열 형태의 고유 식별자로, 각 문제를 특정할 수 있는 유일한 값이어야 합니다.
  2. save()load()key는 문자열 형태이며 자유롭게 지정할 수 있습니다.
  3. save()를 통해 저장되는 데이터는 LearningActivity 마다 독립적으로 관리됩니다. 즉, 각 문제마다 개별적인 학습 상태가 유지됩니다.
  4. 각 모드는 다음과 같은 시나리오에서 사용됩니다:
    • Edit: CMS에서 콘텐츠를 등록할 때
    • Study: 수업 페이지에서 학습을 진행할 때
    • TeacherClassResult: 선생님이 수업 화면에서 웹 저작물 컨텐츠의 전체 결과를 조회할 때
    • TeacherStudentResult: 선생님이 수업 화면에서 학생 1명에 대한 웹저작물 컨텐츠의 결과를 조회할 때
    • StudentResult: 학생이 학습 화면에서 자신의 학습 결과를 조회할 때

save/load와 플랫폼 연동 관련 중요 안내

🚨 중요

save()load()를 통해 저장되는 데이터는 밀당 AIDT 플랫폼의 학습 데이터로 활용될 수 없습니다. 이는 웹 저작물 컨텐츠 내부에서만 사용되는 독립적인 저장소입니다.

  • save()/load() 데이터는 플랫폼의 학습 결과나 평가 데이터와 완전히 분리되어 있습니다.
  • 플랫폼에서는 이 데이터를 학습 이력이나 평가 결과로 활용할 수 없습니다.
  • 웹 저작물의 학습 결과를 플랫폼에 반영하려면 반드시 submit() API를 사용해야 합니다.

활용 가능한 용도:

  • 학습자의 현재 진행 상태 임시 저장
  • 게임 스코어나 설정값 저장
  • 사용자 인터페이스 상태 관리
  • 미완료된 답안의 임시 저장

예시:

// 학습 진행 상태 임시 저장 (플랫폼과 무관) await sdk.save('progress', { currentStep: 3 }); // 실제 학습 결과를 플랫폼에 제출 await sdk.submit([ { activityId: '1', userSelectedIndexes: [0], }, ]);

음성 파일 업로드

음성 파일을 업로드하고 다운로드 가능한 URL을 받습니다.

uploadFileWithBlob(params: UploadFileRequest)

매개변수:

  • params: UploadFileRequest 객체
    interface UploadFileRequest { blob: Blob; // 업로드할 파일 데이터 fileName: string; // 파일 이름 activityId?: string; // 연결할 활동 ID (선택사항) }

반환값:

  • Promise<UploadFileResponse>
    interface UploadFileResponse { url: string; // 다운로드 가능한 URL }

발생 가능한 에러:

  • "파일 업로드 오류": 파일 업로드 중 오류가 발생한 경우
  • "SDK 초기화 오류": SDK 연결 초기화에 실패한 경우

사용 예시:

try { const file = new Blob(['Hello, World!'], { type: 'audio/wav' }); const response = await frameActivitySdk.uploadFileWithBlob({ blob: file, fileName: 'audio.wav', activityId: '1', }); console.log('업로드된 파일 URL:', response.url); } catch (error) { console.error('파일 업로드 실패:', error.message); }

⚠️ 주의사항

  1. 아래 발화평가 기능을 사용하기 위해서는 반드시 음성 파일 업로드 기능을 사용해야 합니다.

발화평가

발화평가 기능을 통해 음성 인식(STT), 발음 평가, 파닉스 평가 등을 수행할 수 있습니다.

requestSpeechEvaluation(data: SpeechEvaluationRequestData)

발화평가를 요청합니다.

매개변수:

  • data: SpeechEvaluationRequestData 객체
    interface SpeechEvaluationRequestData { activityId: string; speakingType: 'STT_ONLY' | 'PHONICS' | 'PRONUNCIATION'; referenceText: string; // 발화평가 기준 텍스트 url: string; // 학생이 녹음한 오디오 URL }

반환값:

  • Promise<string>: 발화평가 요청 ID (sttId)

발생 가능한 에러:

  • "필수 파라미터가 누락되었습니다.": 필수 매개변수가 누락된 경우
  • "발화평가 요청 오류": 발화평가 요청 중 오류가 발생한 경우

사용 예시:

try { const sttId = await frameActivitySdk.requestSpeechEvaluation({ activityId: '1', speakingType: 'PRONUNCIATION', referenceText: 'Hello, how are you?', url: 'https://example.com/audio.mp3', }); console.log('발화평가 요청 ID:', sttId); } catch (error) { console.error('발화평가 요청 실패:', error.message); }

getSpeechEvaluationResult(sttId: string)

발화평가 결과를 조회합니다.

매개변수:

  • sttId: 발화평가 요청 시 받은 ID

반환값:

  • Promise<SpeechEvaluationResult>: 발화평가 결과는 speakingType에 따라 다음과 같은 구조를 가집니다:
  1. STT_ONLY (음성을 텍스트로 변환):
{ "sttId": "stt_001", "speakingType": "STT_ONLY", "status": "COMPLETED", "url": "https://example.com/audio.mp3", "sttResult": { "result": "안녕하세요", // 인식된 텍스트 "sttRecog": null } }
  1. PHONICS (파닉스 평가):
{ "sttId": "stt_002", "speakingType": "PHONICS", "status": "COMPLETED", "url": "https://example.com/audio.mp3", "sttResult": { "result": "cat", "sttRecog": null, "sttProneval": { "sentenceLevel": { "text": "cat", "startTimeInSec": 0.5, "endTimeInSec": 1.2, "intonation": { "data": [1, 2, 3], "length": 3, "max": 3, "min": 1 }, "proficiencyScore": [ { "name": "acoustic", "score": 85, "max": 100, "min": 0 } ] }, "wordLevel": [ { "text": "cat", "index": 0, "startTimeInSec": 0.5, "endTimeInSec": 1.2, "proficiencyScore": [ { "name": "acoustic", "score": 85, "max": 100, "min": 0 } ], "colorOfLetter": { "c": "GREEN", "a": "GREEN", "t": "ORANGE" } } ], "phoneLevel": [ [ { "text": "c", "ipa": "k", "startTimeInSec": 0.5, "endTimeInSec": 0.7, "score": 90, "windex": 0, "pindex": 0 } ] ], "phonicsComment": ["good"] } } }
  1. PRONUNCIATION (발음 평가):
{ "sttId": "stt_003", "speakingType": "PRONUNCIATION", "status": "COMPLETED", "url": "https://example.com/audio.mp3", "sttResult": { "result": "Hello, how are you?", "sttRecog": null, "sttProneval": { "alignment": { "sttAlignment": "hello how are you" }, "evaluationType": "pronunciation", "similarity": "0.85", "threshold": "0.7", "pronunciation": [ { "sentenceLevel": { "text": "Hello, how are you?", "startTimeInSec": 0.0, "endTimeInSec": 2.5, "intonation": { "data": [1, 2, 3, 2], "length": 4, "max": 3, "min": 1 }, "proficiencyScore": [ { "name": "EN_HOLISTIC", "score": 85, "max": 100, "min": 0 } ] }, "wordLevel": [ { "text": "hello", "index": 0, "startTimeInSec": 0.0, "endTimeInSec": 0.8, "proficiencyScore": [ { "name": "EN_SEGMENT", "score": 90, "max": 100, "min": 0 } ], "colorOfLetter": { "h": "GREEN", "e": "GREEN", "l": "GREEN", "l": "GREEN", "o": "GREEN" } } ] } ] } } }

주요 필드 설명:

  • status: 평가 상태 ('COMPLETED' 또는 'FAIL')
  • proficiencyScore: 각종 평가 점수
    • acoustic: 음향학적 점수
    • EN_HOLISTIC: 전반적인 영어 발음 점수
    • EN_SEGMENT: 개별 음소 발음 점수
    • EN_INTONATION: 억양 점수
    • EN_RATE: 발화 속도 점수
    • EN_PITCH: 음높이 점수
  • colorOfLetter: 각 글자별 발음 정확도
    • 'GREEN': 정확한 발음
    • 'ORANGE': 부분적으로 정확한 발음
    • 'RED': 부정확한 발음

발생 가능한 에러:

  • "유효하지 않은 sttId입니다.": 잘못된 sttId가 제공된 경우
  • "발화평가 결과 조회 오류": 결과 조회 중 오류가 발생한 경우

사용 예시:

try { const result = await frameActivitySdk.getSpeechEvaluationResult(sttId); if (result.status === 'COMPLETED') { switch (result.speakingType) { case 'STT_ONLY': console.log('인식된 텍스트:', result.sttResult?.result); break; case 'PHONICS': console.log('파닉스 평가 결과:', result.sttResult?.sttProneval); break; case 'PRONUNCIATION': console.log('발음 평가 결과:', result.sttResult?.sttProneval); break; } } else { console.log('평가 실패'); } } catch (error) { console.error('결과 조회 실패:', error.message); }

setHeight(height: number)

iframe의 높이를 픽셀 단위로 설정합니다. 기본값은 16:9 비율이며, height 값이 0일 경우 기본 비율(16:9)로 복구됩니다.

매개변수:

  • height: 높이 값 (픽셀 단위, 0 이상의 값)

반환값:

  • Promise<boolean>: 설정 성공 여부

발생 가능한 에러:

  • "높이는 0 이상의 값이여야 합니다.": 음수 값이 제공된 경우
  • "높이 설정 오류": 높이 설정 중 오류가 발생한 경우

사용 예시:

try { // 높이를 500px로 설정 await frameActivitySdk.setHeight(500); // 기본 16:9 비율로 복구 await frameActivitySdk.setHeight(0); } catch (error) { console.error('높이 설정 실패:', error.message); }

⚠️ 주의사항

  1. height 값은 0 이상의 값이어야 합니다.
  2. 전달하는 height 값이 0인 경우 기본 16:9 비율로 복구됩니다.
  3. iframe의 width는 100%로 고정되어 있어 width 값은 변경할 수 없습니다.
  4. 세로로 긴 컨텐츠의 경우 height 값을 증가시켜 컨텐츠가 잘리지 않도록 조정할 수 있습니다.

발화평가 시퀀스 다이어그램

Last updated on