Skip to main content

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:

EventDataKapan 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
}
}
}