04 — API: Conversation & Speaking Practice
Endpoint untuk sesi speaking practice, AI conversation, dan SSE streaming.
Conversation Sessions
POST /conversations
Buat sesi percakapan baru (biasanya dipanggil dari POST /missions/:id/start).
Access: Authenticated
// Request Body
{
"missionId": "mis_abc123", // Opsional: link ke mission
"mode": "role_play",
"contentId": "sc_meetingDiscussion01",
"difficulty": "intermediate"
}
// Response 201
{
"success": true,
"data": {
"sessionId": "cs_V1StGXR8_Z5j",
"mode": "role_play",
"topicTitle": "Weekly Marketing Meeting",
"difficulty": "intermediate",
"status": "active",
"openingMessage": {
"role": "assistant",
"content": "Good morning! Welcome to our weekly marketing meeting. I'd like to hear your thoughts on our new social media campaign. What's your overall impression so far?",
"audioUrl": "https://r2.eljoy.id/tts/cs_V1StGXR8_Z5j_0.mp3",
"turnIndex": 0
},
"sessionConfig": {
"maxTurns": 10,
"maxDurationMin": 10,
"tipsEnabled": true
}
}
}
POST /conversations/:sessionId/turn ⚡ SSE
Endpoint paling penting — mengirim audio user dan menerima respons AI secara streaming.
Access: Authenticated
Response: text/event-stream (SSE)
POST /api/v1/conversations/cs_V1StGXR8_Z5j/turn
Content-Type: multipart/form-data
audio: <file> (webm/mp3, max 10MB)
SSE Response Stream:
event: status
data: {"phase": "transcribing"}
event: transcript
data: {"text": "I think we should focus more on Instagram and TikTok for the younger demographic", "confidence": 0.95}
event: status
data: {"phase": "thinking"}
event: token
data: {"text": "That's"}
event: token
data: {"text": " an excellent"}
event: token
data: {"text": " point"}
event: token
data: {"text": ", especially"}
event: token
data: {"text": " considering"}
event: token
data: {"text": " our target"}
event: token
data: {"text": " audience."}
event: token
data: {"text": " What specific"}
event: token
data: {"text": " content strategy"}
event: token
data: {"text": " would you"}
event: token
data: {"text": " suggest?"}
event: feedback
data: {
"pronunciation": 78,
"corrections": [
{
"word": "demographic",
"issue": "stress_pattern",
"suggestion": "Tekanan di suku kata ketiga: de-mo-GRAPH-ic",
"severity": "minor"
}
],
"tip": "Great use of 'focus on' — very natural expression! 👍"
}
event: audio
data: {"url": "https://r2.eljoy.id/tts/cs_V1StGXR8_Z5j_2.mp3", "durationMs": 4200}
event: done
data: {
"turnIndex": 2,
"turnsRemaining": 7,
"sessionDurationMs": 125000,
"companionMood": "engaged"
}
Event Types:
| Event | Data | Kapan Dikirim |
|---|---|---|
status | { phase: string } | Saat memproses (transcribing, thinking, generating) |
transcript | { text: string, confidence: number } | Setelah STT selesai |
token | { text: string } | Setiap token dari LLM (real-time) |
feedback | { pronunciation, corrections[], tip } | Setelah evaluasi user speech |
audio | { url: string, durationMs: number } | Setelah TTS selesai |
done | { turnIndex, turnsRemaining, ... } | Saat turn selesai |
error | { code: string, message: string } | Kalau terjadi error |
POST /conversations/:sessionId/end
Akhiri sesi percakapan dan dapatkan evaluasi akhir.
Access: Authenticated
// Response 200
{
"success": true,
"data": {
"sessionId": "cs_V1StGXR8_Z5j",
"status": "completed",
"durationMinutes": 6,
"turnCount": 8,
"evaluation": {
"overallScore": 75,
"pronunciation": 78,
"grammar": 70,
"vocabulary": 72,
"fluency": 68,
"coherence": 80,
"strengths": [
"Kamu menggunakan ekspresi bisnis yang tepat seperti 'focus on', 'target audience'",
"Koherensi jawabanmu bagus — setiap poin terhubung dengan baik"
],
"improvements": [
"Coba kurangi jeda 'um' dan 'uh' — latih dengan shadowing",
"Perhatikan tekanan kata pada 'demographic' (de-mo-GRAPH-ic)"
],
"detailedFeedback": "Sesi role play yang bagus! Kamu sudah bisa berpartisipasi aktif dalam diskusi meeting. Untuk meningkatkan fluency, coba latihan shadowing dengan native speaker recordings. Overall, kamu menunjukkan progress yang baik! 🎯",
"corrections": [
{
"original": "I think we should focusing",
"corrected": "I think we should focus",
"explanation": "Setelah 'should', gunakan base verb (tanpa -ing)"
},
{
"original": "more better",
"corrected": "much better",
"explanation": "'Better' sudah comparative — gunakan 'much' untuk penekanan, bukan 'more'"
}
]
},
"xpEarned": 50,
"missionCompleted": true,
"streakUpdated": true,
"nextSuggestion": {
"missionId": "mis_def456",
"title": "Shadow a Native Speaker",
"reason": "Latihan shadowing akan membantu mengurangi jeda saat bicara"
}
}
}
GET /conversations/:sessionId/messages
Ambil riwayat pesan dalam satu sesi.
Access: Authenticated
// Response 200
{
"success": true,
"data": [
{
"id": "msg_001",
"role": "assistant",
"content": "Good morning! Welcome to our weekly marketing meeting...",
"audioUrl": "https://r2.eljoy.id/tts/cs_V1StGXR8_Z5j_0.mp3",
"turnIndex": 0,
"createdAt": "2026-09-20T07:00:00Z"
},
{
"id": "msg_002",
"role": "user",
"content": "I think we should focus more on Instagram and TikTok...",
"audioUrl": "https://r2.eljoy.id/audio/cs_V1StGXR8_Z5j_1.webm",
"evaluation": {
"pronunciation": 78,
"corrections": [ ... ]
},
"turnIndex": 1,
"createdAt": "2026-09-20T07:00:30Z"
},
{
"id": "msg_003",
"role": "assistant",
"content": "That's an excellent point, especially considering our target audience...",
"audioUrl": "https://r2.eljoy.id/tts/cs_V1StGXR8_Z5j_2.mp3",
"turnIndex": 2,
"createdAt": "2026-09-20T07:00:35Z"
}
]
}
GET /conversations
Ambil riwayat semua sesi percakapan.
Access: Authenticated
// Query: ?page=1&limit=10&mode=role_play
// Response 200
{
"success": true,
"data": [
{
"sessionId": "cs_V1StGXR8_Z5j",
"mode": "role_play",
"topicTitle": "Weekly Marketing Meeting",
"status": "completed",
"overallScore": 75,
"turnCount": 8,
"durationMinutes": 6,
"completedAt": "2026-09-20T07:06:00Z"
},
...
],
"pagination": { ... }
}
Mode-Specific Behaviors
Setiap mode memiliki variasi kecil di API:
Repeat After Me / Shadowing
// POST /conversations — extra config
{
"mode": "repeat_after_me",
"contentId": "sc_repeatMeeting01"
}
// Opening message berisi kalimat yang harus ditiru
{
"openingMessage": {
"role": "assistant",
"content": "Listen carefully and repeat after me:",
"stimulus": {
"text": "I'd like to schedule a meeting for next Tuesday at 2 PM.",
"audioUrl": "https://r2.eljoy.id/content/repeat-meeting-01.mp3",
"canReplay": true
}
}
}
Picture Description
// Opening message berisi gambar
{
"openingMessage": {
"role": "assistant",
"content": "Look at this image carefully. Describe what you see in 1-2 minutes.",
"stimulus": {
"imageUrl": "https://r2.eljoy.id/content/picture-office-01.jpg",
"instruction": "Describe the scene, people, and activities you observe"
}
}
}
Storytelling / Opinion Giving
// Opening message berisi prompt
{
"openingMessage": {
"role": "assistant",
"content": "Here's your topic. Take 30 seconds to prepare, then share your opinion.",
"stimulus": {
"prompt": "Should companies allow employees to work from home permanently?",
"guidingQuestions": [
"What are the benefits?",
"What are the challenges?",
"What's your personal opinion?"
],
"prepTimeSeconds": 30,
"speakingTimeSeconds": 120
}
}
}