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>
140 lines
4.2 KiB
TypeScript
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 }
|
|
);
|
|
}
|