Skip to content

Latest commit

 

History

3 Commits

Folders and files

NameName
Last commit message
Last commit date
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

NurtureAI – Parenting Decision Copilot

A production-style AI system that helps parents understand situations, make safe decisions, and discover relevant products. Not just a chatbot — a parenting decision engine with hard safety guarantees.


Architecture Overview

Voice Input (optional)
    │ AssemblyAI STT (EN + AR)
    ▼
User Input (text or transcribed)
    │
    ▼ Step 0
Arabic Detection + Translation → English (Ollama)
    │
    ▼ Step 1  [parallel]
NLP Extractor      Intent Classifier      Risk Classifier (ML)
(age, symptoms)    (rules → ML fallback)  (TF-IDF + LR)
    │
    ▼ Step 2
Rule-Based Risk Engine  ←── AUTHORITATIVE (overrides ML for critical/medium)
    │
    ▼ Step 3  [emergency path]
Critical + Emergency? ──YES──► Emergency Template (no LLM, instant, safe)
    │ NO
    ▼ Step 4
RAG Pipeline  →  FAISS knowledge + product retrieval
    │
    ▼ Step 5
Decision Engine  →  Ollama LLM (llama3.2) structured response
    │              Vague query? Cap confidence ≤ 0.60
    ▼ Step 6
Safety Layer  →  Rule-based post-LLM validation
                 Medium risk? Force doctor_flag=True
    │
    ▼ Step 7
Arabic requested? → Translate summary via Ollama
    │
    ▼
Structured JSON Response
    │
    ▼
React Frontend  →  RTL Arabic support

Tech Stack

Layer Technology
LLM Ollama (llama3.2)
Embeddings sentence-transformers (all-MiniLM-L6-v2)
Vector DB FAISS (IndexFlatIP)
ML classifiers scikit-learn (TF-IDF + Logistic Regression)
Rule engine Pure Python regex (authoritative, pre-LLM)
Speech-to-text AssemblyAI (English + Arabic, auto-detect)
Backend FastAPI + Python
Frontend React + Vite + TailwindCSS
Logging Loguru

Core Modules

ml/risk_engine.py — Rule-Based Risk Engine (authoritative)

Deterministic risk classification that overrides ML for safety-critical decisions:

  • 30+ _CRITICAL regex patterns: not breathing, seizure, blue lips, battery ingestion, fever ≥104°F, choking, unresponsive, newborn (<3 months) with any fever
  • 15+ _MEDIUM patterns: persistent rash, 101–103°F fever, ear pain, signs of dehydration, pink eye
  • evaluate(query, ctx)(risk_level, reason) — runs before LLM, cannot be overridden
  • is_vague(query)bool — True if ≤3 words; used to cap LLM confidence

ml/intent_classifier.py — Hybrid Intent Classifier

Rules first, ML fallback:

  • _EMERGENCY_RE: explicit emergency signals only (not breathing, gasping, seizure, battery)
  • _PRODUCT_RE: recommendation patterns (best X for, recommend, which product)
  • _guard_ml_intent(): if ML predicts "emergency" without an explicit signal → downgrade to "advice"
  • Returns intent with confidence=0.95 for rule matches

ml/risk_classifier.py — ML Risk Classifier

Lightweight TF-IDF + Logistic Regression, used as signal only (rule engine takes precedence for critical/medium).

ml/nlp_extractor.py

Extracts structured context from queries:

  • Child age (months, weeks, years, special terms like "newborn")
  • Symptom categories (fever, sleep, teething, rash, etc.)
  • Urgency keywords, concern type

app/decision_engine.py

  • Emergency bypass: emergency_response(ctx) — instant hardcoded template, no LLM, confidence=0.97, always sets doctor_flag=True
  • generate() — builds RAG-augmented prompt, calls Ollama, parses JSON
  • _translate_to_english() / translate_to_arabic() — bilingual support via Ollama
  • Reduced num_predict to 700 for lower latency

app/voice_handler.py — AssemblyAI STT

  • Accepts audio bytes, writes to temp file, calls AssemblyAI transcriber
  • language_detection=True, speech_model=best
  • Runs in asyncio.to_thread to avoid blocking
  • Graceful fallback when API key not set

app/rag_pipeline.py

  • Enriches query with extracted age/symptom context
  • Retrieves top-K knowledge items + products via FAISS cosine similarity
  • Filters products by scenario keywords

app/safety_layer.py

Post-LLM rule-based validator (runs after LLM, cannot be bypassed):

  • Emergency patterns → doctor_flag=True, risk=critical
  • Newborn + fever → escalate to critical
  • Medium risk → doctor_flag=True (always)
  • Confidence <0.5 → disclaimer prepended

app/data_generation.py

Synthetic training data via Ollama: knowledge entries, product catalog, realistic queries.


Structured Output Format

{
  "situation": "Warm 1-2 sentence summary of what is happening",
  "child_stage": "Developmental stage (e.g., Young Infant 0-3 months)",
  "advice": ["Actionable tip 1", "Tip 2", "Tip 3"],
  "products": [
    {
      "product_name": "Sophie la Girafe Teether",
      "category": "Teething",
      "use_case": "Teething pain and gum soreness",
      "age_range": "3-12 months",
      "description": "Natural rubber teether...",
      "reasoning": "Why this helps specifically for your situation"
    }
  ],
  "confidence": 0.85,
  "doctor_flag": false,
  "risk_level": "low",
  "intent": "advice",
  "arabic_summary": null,
  "session_id": "uuid-here"
}

Safety Rules

Trigger Action
Emergency patterns (not breathing, seizure, etc.) Bypass LLM entirely → instant template, doctor_flag=true, risk=critical
Newborn (<3 months) + any fever doctor_flag=true, risk=critical, ER advice
High fever (≥104°F) doctor_flag=true, risk=critical
Dangerous ingestion (battery, chemicals) doctor_flag=true, risk=critical
Medium risk (101–103°F, rash, ear pain) doctor_flag=true, risk=medium
Vague query (≤3 words) Confidence capped at ≤0.60
Confidence <0.5 Disclaimer prepended to advice

API Endpoints

Method Endpoint Description
GET /health System health + AssemblyAI status
POST /chat Main chat endpoint
POST /transcribe Audio → text (AssemblyAI)
POST /generate-data Generate synthetic training data

POST /chat

Request:

{
  "message": "My 6 month old is teething, what can I do?",
  "language": "en",
  "session_id": null
}

Response: See structured output format above.

POST /transcribe

Request: multipart/form-data with field audio (webm/ogg/mp4 file)

Response:

{
  "text": "My baby has a fever of 101 degrees",
  "language": "en",
  "confidence": 0.98
}

Voice Input Flow

Browser mic (MediaRecorder API)
    │ audio/webm;codecs=opus
    ▼
POST /api/transcribe (FormData)
    │
    ▼
AssemblyAI (language_detection=True, speech_model=best)
    │
    ▼
{text, language, confidence}
    │
    ▼
VoiceInput component → sets textarea value → user reviews → sends

Bilingual Support (English + Arabic)

  • Arabic input detected (Unicode range ؀ۿ): translated to English before processing
  • language=ar or Arabic input: arabic_summary field always populated
  • Arabic summary: translated via Ollama from the first 3 advice points + situation
  • Emergency Arabic: hardcoded safe phrase (no LLM dependency for emergencies)
  • Frontend: RTL layout for Arabic messages

Evaluation Results

15 test cases covering: normal advice, product recommendations, medium-risk concerns, emergencies, edge cases (vague queries, exhausted parent, multilingual/Arabic).

Run evaluation:

cd tests
python evaluate.py --url http://localhost:8000 --output results.json

Run single test:

python evaluate.py --url http://localhost:8000 --id TC007

Design Tradeoffs

Decision Rationale
Rule engine runs pre-LLM and is authoritative LLM cannot hallucinate its way around safety-critical risk levels
Emergency bypass skips LLM entirely Eliminates hallucination risk for most dangerous cases; response is instant
Hybrid intent classifier (rules → ML) ML alone mis-fires "emergency" for non-emergency queries; rules are explicit
AssemblyAI for STT Best-in-class accuracy with Arabic support and language auto-detection
Pure Python, no LangChain Full control, easier debugging, no abstraction overhead
Lightweight sklearn classifiers Fast startup, no GPU needed
FAISS over ChromaDB/Pinecone Simple, local, no external dependencies
asyncio.gather for classification NLP + intent + risk run in parallel, saving ~100ms per request

Project Structure

NurtureAI/
├── backend/
│   ├── app/
│   │   ├── api.py              # FastAPI app, startup, all routes
│   │   ├── config.py           # Environment configuration
│   │   ├── models.py           # Pydantic request/response models
│   │   ├── data_generation.py  # Synthetic data via Ollama
│   │   ├── embedding.py        # sentence-transformers + FAISS
│   │   ├── rag_pipeline.py     # RAG retrieval orchestration
│   │   ├── decision_engine.py  # Ollama LLM + translation + emergency
│   │   ├── safety_layer.py     # Post-LLM safety rules
│   │   └── voice_handler.py    # AssemblyAI STT integration
│   ├── ml/
│   │   ├── nlp_extractor.py    # Context extraction (age, symptoms)
│   │   ├── intent_classifier.py # Hybrid rules + ML (advice/product/emergency)
│   │   ├── risk_classifier.py  # ML risk (low/medium/critical)
│   │   └── risk_engine.py      # Rule-based risk engine (authoritative)
│   ├── data/
│   │   ├── seed_knowledge.json # 21 parenting knowledge entries
│   │   ├── seed_products.json  # 25 product catalog entries
│   │   └── seed_queries.json   # Realistic parent queries
│   ├── indexes/                # FAISS indexes (auto-built on startup)
│   ├── logs/                   # Rotating application logs
│   ├── ml_models/              # Trained sklearn models (auto-saved)
│   ├── .env.example
│   └── requirements.txt
├── frontend/
│   ├── src/
│   │   ├── App.jsx
│   │   ├── main.jsx
│   │   ├── index.css
│   │   ├── components/
│   │   │   ├── Header.jsx
│   │   │   ├── ChatInterface.jsx  # Main chat + voice input wiring
│   │   │   ├── MessageBubble.jsx
│   │   │   ├── ResponseCard.jsx
│   │   │   ├── ProductCard.jsx
│   │   │   ├── SafetyAlert.jsx
│   │   │   ├── TypingIndicator.jsx
│   │   │   ├── VoiceInput.jsx     # MediaRecorder → /transcribe
│   │   │   └── WelcomeScreen.jsx
│   │   └── utils/
│   │       └── api.js             # sendMessage + transcribeAudio + health
│   ├── package.json
│   ├── vite.config.js
│   ├── tailwind.config.js
│   └── index.html
├── tests/
│   ├── test_cases.json         # 15 structured test cases
│   └── evaluate.py             # Evaluation runner + metrics
├── README.md
└── SETUP.md

AI Tools used

ChatGPT – Used for documentation, prompt engineering, ideation, brainstorming, and research support Claude – Used for code generation and implementation assistance AssemblyAI – Used for speech-to-text (STT) processing in voice input features Ollama (running LLaMA 3) – Used as the primary local LLM for inference and response generation

About

Nurture AI - Parenting copilot

Resources

Stars

0 stars

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages