10 KiB
Audio Practice (Speaking Practice) — Admin Panel Integration Guide
Overview
The Yimaru backend fully supports audio/speaking practices. This guide covers the steps needed to integrate the feature into the admin panel frontend.
Backend Status (✅ Already Complete)
| Layer | File | What It Does |
|---|---|---|
| Domain | internal/domain/questions.go |
QuestionTypeAudio = "AUDIO" constant, VoicePrompt, SampleAnswerVoicePrompt, AudioCorrectAnswerText fields |
| Handler | internal/web_server/handlers/questions.go |
CreateQuestion accepts question_type: "AUDIO" with audio-specific fields |
| Handler | internal/web_server/handlers/file_handler.go |
UploadAudio (general audio upload) and SubmitAudioAnswer (learner recording) |
| Migration | db/migrations/000022_audio_questions.up.sql |
AUDIO type constraint + question_audio_answers table |
| Migration | db/migrations/000028_user_audio_responses.up.sql |
user_audio_responses table for learner recordings |
| SQL | db/query/question_audio_answers.sql |
CRUD for correct answer text per audio question |
| SQL | db/query/user_audio_responses.sql |
CRUD for learner audio submissions |
| Routes | internal/web_server/routes.go |
POST /files/audio, POST /questions/audio-answer |
Admin Panel Frontend Steps
Step 1: Add "AUDIO" Option to the Question Type Selector
When creating/editing a question, the admin should be able to select AUDIO as a question type alongside MCQ, TRUE_FALSE, and SHORT_ANSWER.
Step 2: Build the AUDIO Question Form
When question_type = "AUDIO" is selected, render these fields:
| Field | API Field | Type | Required | Description |
|---|---|---|---|---|
| Question Text | question_text |
string |
✅ | The prompt/instruction text shown to the learner |
| Voice Prompt | voice_prompt |
string (URL) |
Optional | Audio file URL — the question read aloud or a listening prompt |
| Sample Answer Voice | sample_answer_voice_prompt |
string (URL) |
Optional | Audio URL of a model/reference answer |
| Correct Answer Text | audio_correct_answer_text |
string |
Optional | Expected textual answer (used for grading/comparison) |
| Image | image_url |
string (URL) |
Optional | Supporting image for the question |
| Explanation | explanation |
string |
Optional | Shown to the learner after answering |
| Tips | tips |
string |
Optional | Hints shown before/during the question |
| Difficulty Level | difficulty_level |
string |
Optional | EASY, MEDIUM, or HARD |
| Points | points |
int |
Optional | Score value (defaults to 1) |
Note: Hide the
optionsandshort_answersfields when AUDIO is selected — they are not used for this type.
Step 3: Build an Audio Uploader Component
Create a reusable audio uploader used for both voice_prompt and sample_answer_voice_prompt.
API Call:
POST /files/audio
Content-Type: multipart/form-data
Form field: "file" — the audio file
Constraints:
- Max file size: 50 MB
- Allowed formats:
mp3,wav,ogg,m4a,aac,webm,flac
Response:
{
"message": "Audio file uploaded successfully",
"data": {
"object_key": "audio/1710000000_recording.mp3",
"url": "https://...",
"content_type": "audio/mpeg"
},
"success": true
}
Usage:
- Admin clicks "Upload Voice Prompt" → file picker opens
- File is uploaded via
POST /files/audio - Store the returned
object_keyas the value forvoice_promptorsample_answer_voice_prompt - Display the audio player preview (see Step 4)
Step 4: Build an Audio Player / Preview Component
After uploading, let admins preview the audio.
To get a playable URL from an object key:
GET /files/url?key=<object_key>
Frontend implementation:
<audio controls src="<resolved_url>"></audio>
This component should be shown:
- Next to the voice prompt upload field (after upload)
- Next to the sample answer voice prompt upload field (after upload)
- When viewing/editing an existing AUDIO question
Step 5: Create a Practice with Audio Questions
The full admin workflow:
5.1 Create the Practice Set (Question Set)
POST /question-sets
{
"title": "Speaking Practice - Lesson 1",
"description": "Practice your pronunciation",
"set_type": "PRACTICE",
"owner_type": "SUB_COURSE",
"owner_id": 42,
"status": "DRAFT"
}
5.2 Upload Audio Files
POST /files/audio → voice_prompt object_key
POST /files/audio → sample_answer_voice_prompt object_key
5.3 Create AUDIO Questions
POST /questions
{
"question_text": "Listen and repeat the following phrase",
"question_type": "AUDIO",
"voice_prompt": "minio://audio/1710000000_prompt.mp3",
"sample_answer_voice_prompt": "minio://audio/1710000000_sample.mp3",
"audio_correct_answer_text": "Hello, how are you?",
"difficulty_level": "EASY",
"points": 10
}
5.4 Link Questions to the Practice Set
POST /question-sets/:setId/questions
{
"question_id": 123,
"display_order": 1
}
5.5 (Optional) Add Personas
POST /question-sets/:setId/personas
{
"user_id": 5,
"display_order": 1
}
5.6 (Optional) Reorder Practices in a Sub-course
PUT /course-management/practices/reorder
{
"sub_course_id": 42,
"ordered_ids": [10, 11, 12]
}
Step 6: Display Audio Questions in the Question List
When listing questions (GET /questions?question_type=AUDIO), show:
- An 🔊 audio icon or "AUDIO" badge for the question type
- A mini audio player if
voice_promptis set - The
audio_correct_answer_textvalue (if present)
When viewing a single question (GET /questions/:id), the response includes:
{
"question_type": "AUDIO",
"voice_prompt": "minio://audio/...",
"sample_answer_voice_prompt": "minio://audio/...",
"audio_correct_answer_text": "Hello, how are you?"
}
Step 7: (Optional) Admin Review of Learner Audio Submissions
⚠️ Not yet built — requires a new backend endpoint if needed.
Currently, learner audio submissions are stored in user_audio_responses but there's no admin-facing endpoint to list/review them.
If this is needed, add:
-
New SQL query in
db/query/user_audio_responses.sql:-- name: ListAudioResponsesByQuestionSet :many SELECT uar.*, u.first_name, u.last_name FROM user_audio_responses uar JOIN users u ON u.id = uar.user_id WHERE uar.question_set_id = $1 ORDER BY uar.created_at DESC LIMIT $2 OFFSET $3; -
New endpoint in
routes.go:GET /admin/question-sets/:setId/audio-responses -
Admin UI: A table showing learner name, audio player for their recording, timestamp, and the correct answer text for comparison.
API Flow Summary
┌─────────────────────────────────────────────────────────┐
│ ADMIN CREATES PRACTICE │
├─────────────────────────────────────────────────────────┤
│ │
│ POST /question-sets │
│ → Creates practice shell (set_type: "PRACTICE") │
│ │
│ POST /files/audio │
│ → Uploads voice_prompt audio file │
│ │
│ POST /files/audio │
│ → Uploads sample_answer_voice_prompt audio file │
│ │
│ POST /questions │
│ → Creates AUDIO question with voice prompt URLs │
│ and correct_answer_text │
│ │
│ POST /question-sets/:id/questions │
│ → Links question to practice set │
│ │
└─────────────────────────────────────────────────────────┘
┌─────────────────────────────────────────────────────────┐
│ LEARNER COMPLETES PRACTICE │
├─────────────────────────────────────────────────────────┤
│ │
│ GET /files/url?key=... │
│ → Streams voice prompt audio │
│ │
│ POST /questions/audio-answer │
│ → Submits learner's audio recording │
│ │
│ POST /progress/practices/:id/complete │
│ → Marks practice as completed │
│ │
└─────────────────────────────────────────────────────────┘
Required RBAC Permissions
Ensure the admin role has these permissions:
| Permission | Used By |
|---|---|
questions.create |
Creating AUDIO questions |
questions.update |
Editing AUDIO questions |
questions.list |
Listing questions (filter by AUDIO) |
questions.get |
Viewing a single question |
questions.delete |
Deleting questions |
question_sets.create |
Creating practice sets |
question_sets.update |
Updating practice sets |
question_set_items.add |
Adding questions to a set |
question_set_items.list |
Listing questions in a set |
question_set_items.remove |
Removing questions from a set |
question_set_items.update_order |
Reordering questions |
question_set_personas.add |
Adding personas |
practices.reorder |
Reordering practices in a sub-course |