Files
maternal-app/maternal-web/app/api/voice/transcribe/route.ts
Andrei 79966a6a6d
Some checks failed
CI/CD Pipeline / Lint and Test (push) Has been cancelled
CI/CD Pipeline / E2E Tests (push) Has been cancelled
CI/CD Pipeline / Build Application (push) Has been cancelled
Add voice intent classification for hands-free tracking
Implemented comprehensive voice command understanding system:

**Intent Classification:**
- Feeding intent (bottle, breastfeeding, solid food)
- Sleep intent (naps, nighttime sleep)
- Diaper intent (wet, dirty, both, dry)
- Unknown intent handling

**Entity Extraction:**
- Amounts with units (ml, oz, tbsp): "120 ml", "4 ounces"
- Durations in minutes: "15 minutes", "for 20 mins"
- Time expressions: "at 3:30 pm", "30 minutes ago", "just now"
- Breast feeding side: "left", "right", "both"
- Diaper types: "wet", "dirty", "both"
- Sleep types: "nap", "night"

**Structured Data Output:**
- FeedingData: type, amount, unit, duration, side, timestamps
- SleepData: type, duration, start/end times
- DiaperData: type, timestamp
- Ready for direct activity creation

**Pattern Matching:**
- 15+ feeding patterns (bottle, breast, solid)
- 8+ sleep patterns (nap, sleep, woke up)
- 8+ diaper patterns (wet, dirty, bowel movement)
- Robust keyword detection with variations

**Confidence Scoring:**
- High: >= 0.8 (strong match)
- Medium: 0.5-0.79 (probable match)
- Low: < 0.5 (uncertain)
- Minimum threshold: 0.3 for validation

**API Endpoint:**
- POST /api/voice/transcribe - Classify text or audio
- GET /api/voice/transcribe - Get supported commands
- JSON response with intent, confidence, entities, structured data
- Audio transcription placeholder (Whisper integration ready)

**Implementation Files:**
- lib/voice/intentClassifier.ts - Core classification (600+ lines)
- app/api/voice/transcribe/route.ts - API endpoint
- scripts/test-voice-intent.mjs - Test suite (25 tests)
- lib/voice/README.md - Complete documentation

**Test Coverage:** 25 tests, 100% pass rate
 Bottle feeding (3 tests)
 Breastfeeding (3 tests)
 Solid food (2 tests)
 Sleep tracking (6 tests)
 Diaper changes (7 tests)
 Edge cases (4 tests)

**Example Commands:**
- "Fed baby 120 ml" → bottle, 120ml
- "Nursed on left breast for 15 minutes" → breast_left, 15min
- "Changed wet and dirty diaper" → both
- "Napped for 45 minutes" → nap, 45min

System converts natural language to structured tracking data with
high accuracy for common parenting voice commands.

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>
2025-10-01 20:20:07 +00:00

140 lines
4.2 KiB
TypeScript

import { NextRequest, NextResponse } from 'next/server';
import { classifyIntent, validateClassification, getConfidenceLevel } from '@/lib/voice/intentClassifier';
/**
* Voice transcription and intent classification endpoint
*
* Accepts audio file or transcribed text and returns:
* - Intent classification (feeding/sleep/diaper)
* - Extracted entities (amounts, times, durations)
* - Structured data ready for activity creation
*/
export async function POST(request: NextRequest) {
try {
const contentType = request.headers.get('content-type') || '';
let transcribedText: string;
if (contentType.includes('application/json')) {
// Text input (already transcribed)
const body = await request.json();
transcribedText = body.text;
if (!transcribedText || typeof transcribedText !== 'string') {
return NextResponse.json(
{
error: 'VOICE_INVALID_INPUT',
message: 'Text must be a non-empty string',
},
{ status: 400 }
);
}
} else if (contentType.includes('multipart/form-data')) {
// Audio file upload (needs transcription)
// TODO: Implement Whisper API integration for audio transcription
// For now, return not implemented
return NextResponse.json(
{
error: 'VOICE_AUDIO_NOT_IMPLEMENTED',
message: 'Audio transcription not yet implemented. Use text input for now.',
hint: 'Send JSON with { "text": "your voice command" }',
},
{ status: 501 }
);
} else {
return NextResponse.json(
{
error: 'VOICE_INVALID_CONTENT_TYPE',
message: 'Content-Type must be application/json or multipart/form-data',
},
{ status: 400 }
);
}
// Classify intent
const classification = classifyIntent(transcribedText);
// Validate classification
if (!validateClassification(classification)) {
return NextResponse.json(
{
error: 'VOICE_CLASSIFICATION_FAILED',
message: 'Could not understand the command. Please try again.',
suggestion: 'Try saying something like "Fed baby 100ml" or "Changed wet diaper"',
classification: {
intent: classification.intent,
confidence: classification.confidence,
confidenceLevel: getConfidenceLevel(classification.confidence),
},
},
{ status: 400 }
);
}
// Return classification result
return NextResponse.json(
{
success: true,
transcription: transcribedText,
classification: {
intent: classification.intent,
confidence: classification.confidence,
confidenceLevel: getConfidenceLevel(classification.confidence),
entities: classification.entities,
structuredData: classification.structuredData,
},
},
{ status: 200 }
);
} catch (error) {
console.error('[Voice] Transcription error:', error);
return NextResponse.json(
{
error: 'VOICE_TRANSCRIPTION_FAILED',
message: 'Failed to process voice command. Please try again.',
},
{ status: 500 }
);
}
}
/**
* Get supported voice commands and examples
*/
export async function GET() {
return NextResponse.json(
{
supportedIntents: ['feeding', 'sleep', 'diaper'],
examples: {
feeding: [
'Fed baby 120 ml',
'Gave him 4 ounces',
'Nursed on left breast for 15 minutes',
'Breastfed on both sides',
'Baby ate solid food',
],
sleep: [
'Baby fell asleep',
'Napped for 45 minutes',
'Put baby down for bedtime',
'Baby woke up',
],
diaper: [
'Changed wet diaper',
'Dirty diaper change',
'Changed a wet and dirty diaper',
'Baby had a bowel movement',
],
},
entities: {
amounts: ['120 ml', '4 oz', '2 tablespoons'],
durations: ['15 minutes', '45 mins', '2 hours'],
times: ['at 3:30 pm', '30 minutes ago', 'just now'],
breastSides: ['left breast', 'right side', 'both sides'],
diaperTypes: ['wet', 'dirty', 'wet and dirty', 'bowel movement'],
},
},
{ status: 200 }
);
}