diff --git a/docs/DYNAMIC_PRACTICE_CREATION_LMS_GUIDE.md b/docs/DYNAMIC_PRACTICE_CREATION_LMS_GUIDE.md index df0b82f..8254a35 100644 --- a/docs/DYNAMIC_PRACTICE_CREATION_LMS_GUIDE.md +++ b/docs/DYNAMIC_PRACTICE_CREATION_LMS_GUIDE.md @@ -221,7 +221,7 @@ Use these to confirm the parent exists and to display titles in the admin UI. ## 8. Step 1 — (Optional) Upload media -Required when the definition uses `IMAGE`, `AUDIO_CLIP`, `AUDIO_PROMPT`, or `PDF_ATTACHMENT` stimulus slots. +Required when the definition uses `IMAGE`, `AUDIO_PROMPT`, or `PDF_ATTACHMENT` stimulus slots. ### POST `/files/upload` diff --git a/docs/DYNAMIC_QUESTION_TYPE_BUILDER_ADMIN_INTEGRATION.md b/docs/DYNAMIC_QUESTION_TYPE_BUILDER_ADMIN_INTEGRATION.md index a2c6a06..eb87790 100644 --- a/docs/DYNAMIC_QUESTION_TYPE_BUILDER_ADMIN_INTEGRATION.md +++ b/docs/DYNAMIC_QUESTION_TYPE_BUILDER_ADMIN_INTEGRATION.md @@ -219,8 +219,7 @@ Load dynamically via **`GET /questions/component-catalog`**. Do not hardcode kin | `QUESTION_TEXT` | Main prompt text | `string` | | `INSTRUCTION` | Instruction / directions | `string` | | `PREP_TIME` | Preparation time (seconds) | `number` or `{ "seconds": N }` | -| `AUDIO_PROMPT` | Audio URL to play | `string` (HTTPS or MinIO presigned URL) | -| `AUDIO_CLIP` | Embedded audio clip | `string` URL | +| `AUDIO_PROMPT` | Stimulus audio (prompt, clip, or listening passage) | `string` URL (HTTPS or MinIO presigned URL from `POST /files/upload` with `media_type=audio`) | | `TEXT_PASSAGE` | Reading passage | `string` | | `IMAGE` | Image URL | `string` URL | | `TABLE` | Reference table | `{ "columns": string[], "rows": string[][] }` | @@ -268,7 +267,6 @@ Load dynamically via **`GET /questions/component-catalog`**. Do not hardcode kin "PREP_TIME", "INSTRUCTION", "AUDIO_PROMPT", - "AUDIO_CLIP", "TEXT_PASSAGE", "IMAGE", "MATCHING_INPUTS", @@ -664,7 +662,7 @@ Use before filling `IMAGE`, `AUDIO_*`, or `PDF_ATTACHMENT` stimulus values. } ``` -**Admin usage:** Put `data.url` into `dynamic_payload.stimulus[].value` for `IMAGE` / `AUDIO_CLIP` / `PDF_ATTACHMENT`. Optionally store `minio://{object_key}` and resolve later. +**Admin usage:** Put `data.url` into `dynamic_payload.stimulus[].value` for `IMAGE` / `AUDIO_PROMPT` / `PDF_ATTACHMENT`. Optionally store `minio://{object_key}` and resolve later. --- @@ -805,7 +803,7 @@ Use when the UI stored `minio://` references instead of long presigned URLs. ```json { "message": "Invalid dynamic_payload", - "error": "dynamic_payload.stimulus[1]: kind \"AUDIO_CLIP\" is not allowed by selected definition" + "error": "dynamic_payload.stimulus[1]: kind \"TABLE\" is not allowed by selected definition" } ``` @@ -1035,12 +1033,16 @@ Server does not yet enforce `config.max_rows` / `max_columns`; mirror in UI. | `PDF_ATTACHMENT` | Stimulus | **Admin** when authoring question | `POST /files/upload` (`media_type=pdf`) | | `PDF_UPLOAD` | Response | **Learner** at answer time | Learner app flow (separate) | -### IMAGE / AUDIO_CLIP (stimulus) +### IMAGE / AUDIO_PROMPT (stimulus) ```json { "id": "illustration", "kind": "IMAGE", "value": "https://..." } ``` +```json +{ "id": "prompt_audio", "kind": "AUDIO_PROMPT", "value": "https://..." } +``` + --- ## 10. End-to-end admin workflows @@ -1164,8 +1166,7 @@ const KIND_DEFAULT_LABELS: Record = { IMAGE: "Image", TABLE: "Reference table", PDF_ATTACHMENT: "PDF document", - AUDIO_CLIP: "Audio clip", - AUDIO_PROMPT: "Audio prompt", + AUDIO_PROMPT: "Audio", OPTION: "Answer choices", SHORT_ANSWER: "Short answer", TEXT_INPUT: "Text input", diff --git a/docs/PRACTICE_CREATION_API_GUIDE.md b/docs/PRACTICE_CREATION_API_GUIDE.md index b4a9283..87762cb 100644 --- a/docs/PRACTICE_CREATION_API_GUIDE.md +++ b/docs/PRACTICE_CREATION_API_GUIDE.md @@ -65,7 +65,7 @@ If you create/update dynamic definitions: ## Step 0 (Optional): Upload Media -Use this when question content references audio/image/PDF URLs (e.g. dynamic `IMAGE`, `AUDIO_CLIP`, or `PDF_ATTACHMENT` stimulus). +Use this when question content references audio/image/PDF URLs (e.g. dynamic `IMAGE`, `AUDIO_PROMPT`, or `PDF_ATTACHMENT` stimulus). ### Endpoint diff --git a/internal/domain/question_type_builder.go b/internal/domain/question_type_builder.go index 635ea80..7c76231 100644 --- a/internal/domain/question_type_builder.go +++ b/internal/domain/question_type_builder.go @@ -13,9 +13,9 @@ const ( StimulusQuestionText StimulusComponentKind = "QUESTION_TEXT" StimulusPrepTime StimulusComponentKind = "PREP_TIME" StimulusInstruction StimulusComponentKind = "INSTRUCTION" - StimulusAudioPrompt StimulusComponentKind = "AUDIO_PROMPT" - StimulusAudioClip StimulusComponentKind = "AUDIO_CLIP" - StimulusTextPassage StimulusComponentKind = "TEXT_PASSAGE" + // StimulusAudioPrompt is the single stimulus-side audio kind (prompts, clips, listening passages). + StimulusAudioPrompt StimulusComponentKind = "AUDIO_PROMPT" + StimulusTextPassage StimulusComponentKind = "TEXT_PASSAGE" StimulusImage StimulusComponentKind = "IMAGE" StimulusMatchingInputs StimulusComponentKind = "MATCHING_INPUTS" StimulusSelectMissingWords StimulusComponentKind = "SELECT_MISSING_WORDS" @@ -67,7 +67,6 @@ var ( StimulusPrepTime, StimulusInstruction, StimulusAudioPrompt, - StimulusAudioClip, StimulusTextPassage, StimulusImage, StimulusMatchingInputs, diff --git a/postman/Dynamic-Question-Type-Builder.postman_collection.json b/postman/Dynamic-Question-Type-Builder.postman_collection.json index 1201e1e..ef44a87 100644 --- a/postman/Dynamic-Question-Type-Builder.postman_collection.json +++ b/postman/Dynamic-Question-Type-Builder.postman_collection.json @@ -595,7 +595,7 @@ ], "body": { "mode": "raw", - "raw": "{\n \"question_text\": \"Should fail because AUDIO_CLIP is not allowed by selected definition\",\n \"question_type\": \"DYNAMIC\",\n \"question_type_definition_id\": {{dynamic_definition_id}},\n \"dynamic_payload\": {\n \"stimulus\": [\n {\n \"id\": \"audio1\",\n \"kind\": \"AUDIO_CLIP\",\n \"value\": \"https://cdn.example.com/audio/not-allowed.mp3\"\n }\n ],\n \"response\": [\n {\n \"id\": \"choices\",\n \"kind\": \"OPTION\",\n \"value\": {\n \"options\": [\n {\"id\": \"a\", \"text\": \"A\", \"is_correct\": true},\n {\"id\": \"b\", \"text\": \"B\", \"is_correct\": false}\n ]\n }\n }\n ]\n }\n}" + "raw": "{\n \"question_type\": \"DYNAMIC\",\n \"question_type_definition_id\": {{dynamic_definition_id}},\n \"dynamic_payload\": {\n \"stimulus\": [\n {\n \"id\": \"data_table\",\n \"kind\": \"TABLE\",\n \"value\": {\n \"columns\": [\"A\"],\n \"rows\": [[\"1\"]]\n }\n }\n ],\n \"response\": [\n {\n \"id\": \"choices\",\n \"kind\": \"OPTION\",\n \"value\": {\n \"options\": [\n {\"id\": \"a\", \"text\": \"A\", \"is_correct\": true},\n {\"id\": \"b\", \"text\": \"B\", \"is_correct\": false}\n ]\n }\n }\n ]\n }\n}" }, "url": { "raw": "{{base_url}}/api/v1/questions",