refactor: consolidate stimulus audio under AUDIO_PROMPT

Remove AUDIO_CLIP from the stimulus component catalog and use AUDIO_PROMPT for all question-side audio. Update integration, practice, and Postman docs accordingly.

Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
Yared Yemane 2026-06-05 03:34:01 -07:00
parent ab986a08f0
commit b5b9ef03b5
5 changed files with 15 additions and 15 deletions

View File

@ -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 ## 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` ### POST `/files/upload`

View File

@ -219,8 +219,7 @@ Load dynamically via **`GET /questions/component-catalog`**. Do not hardcode kin
| `QUESTION_TEXT` | Main prompt text | `string` | | `QUESTION_TEXT` | Main prompt text | `string` |
| `INSTRUCTION` | Instruction / directions | `string` | | `INSTRUCTION` | Instruction / directions | `string` |
| `PREP_TIME` | Preparation time (seconds) | `number` or `{ "seconds": N }` | | `PREP_TIME` | Preparation time (seconds) | `number` or `{ "seconds": N }` |
| `AUDIO_PROMPT` | Audio URL to play | `string` (HTTPS or MinIO presigned 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`) |
| `AUDIO_CLIP` | Embedded audio clip | `string` URL |
| `TEXT_PASSAGE` | Reading passage | `string` | | `TEXT_PASSAGE` | Reading passage | `string` |
| `IMAGE` | Image URL | `string` URL | | `IMAGE` | Image URL | `string` URL |
| `TABLE` | Reference table | `{ "columns": string[], "rows": string[][] }` | | `TABLE` | Reference table | `{ "columns": string[], "rows": string[][] }` |
@ -268,7 +267,6 @@ Load dynamically via **`GET /questions/component-catalog`**. Do not hardcode kin
"PREP_TIME", "PREP_TIME",
"INSTRUCTION", "INSTRUCTION",
"AUDIO_PROMPT", "AUDIO_PROMPT",
"AUDIO_CLIP",
"TEXT_PASSAGE", "TEXT_PASSAGE",
"IMAGE", "IMAGE",
"MATCHING_INPUTS", "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 ```json
{ {
"message": "Invalid dynamic_payload", "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_ATTACHMENT` | Stimulus | **Admin** when authoring question | `POST /files/upload` (`media_type=pdf`) |
| `PDF_UPLOAD` | Response | **Learner** at answer time | Learner app flow (separate) | | `PDF_UPLOAD` | Response | **Learner** at answer time | Learner app flow (separate) |
### IMAGE / AUDIO_CLIP (stimulus) ### IMAGE / AUDIO_PROMPT (stimulus)
```json ```json
{ "id": "illustration", "kind": "IMAGE", "value": "https://..." } { "id": "illustration", "kind": "IMAGE", "value": "https://..." }
``` ```
```json
{ "id": "prompt_audio", "kind": "AUDIO_PROMPT", "value": "https://..." }
```
--- ---
## 10. End-to-end admin workflows ## 10. End-to-end admin workflows
@ -1164,8 +1166,7 @@ const KIND_DEFAULT_LABELS: Record<string, string> = {
IMAGE: "Image", IMAGE: "Image",
TABLE: "Reference table", TABLE: "Reference table",
PDF_ATTACHMENT: "PDF document", PDF_ATTACHMENT: "PDF document",
AUDIO_CLIP: "Audio clip", AUDIO_PROMPT: "Audio",
AUDIO_PROMPT: "Audio prompt",
OPTION: "Answer choices", OPTION: "Answer choices",
SHORT_ANSWER: "Short answer", SHORT_ANSWER: "Short answer",
TEXT_INPUT: "Text input", TEXT_INPUT: "Text input",

View File

@ -65,7 +65,7 @@ If you create/update dynamic definitions:
## Step 0 (Optional): Upload Media ## 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 ### Endpoint

View File

@ -13,8 +13,8 @@ const (
StimulusQuestionText StimulusComponentKind = "QUESTION_TEXT" StimulusQuestionText StimulusComponentKind = "QUESTION_TEXT"
StimulusPrepTime StimulusComponentKind = "PREP_TIME" StimulusPrepTime StimulusComponentKind = "PREP_TIME"
StimulusInstruction StimulusComponentKind = "INSTRUCTION" StimulusInstruction StimulusComponentKind = "INSTRUCTION"
// StimulusAudioPrompt is the single stimulus-side audio kind (prompts, clips, listening passages).
StimulusAudioPrompt StimulusComponentKind = "AUDIO_PROMPT" StimulusAudioPrompt StimulusComponentKind = "AUDIO_PROMPT"
StimulusAudioClip StimulusComponentKind = "AUDIO_CLIP"
StimulusTextPassage StimulusComponentKind = "TEXT_PASSAGE" StimulusTextPassage StimulusComponentKind = "TEXT_PASSAGE"
StimulusImage StimulusComponentKind = "IMAGE" StimulusImage StimulusComponentKind = "IMAGE"
StimulusMatchingInputs StimulusComponentKind = "MATCHING_INPUTS" StimulusMatchingInputs StimulusComponentKind = "MATCHING_INPUTS"
@ -67,7 +67,6 @@ var (
StimulusPrepTime, StimulusPrepTime,
StimulusInstruction, StimulusInstruction,
StimulusAudioPrompt, StimulusAudioPrompt,
StimulusAudioClip,
StimulusTextPassage, StimulusTextPassage,
StimulusImage, StimulusImage,
StimulusMatchingInputs, StimulusMatchingInputs,

View File

@ -595,7 +595,7 @@
], ],
"body": { "body": {
"mode": "raw", "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": { "url": {
"raw": "{{base_url}}/api/v1/questions", "raw": "{{base_url}}/api/v1/questions",