Skip to content

Latest commit

Β 

History

216 Commits

Folders and files

NameName
Last commit message
Last commit date
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 

Repository files navigation

emoFuneral

An emotion healing web app that helps users process negative emotions through ritual-based interactions, powered by AI. Users express their worries, receive AI-driven emotion analysis, and undergo therapeutic rituals (Fire/Water/Earth) grounded in CBT, AEDP, and ACT methodologies.

Tech Stack

Layer Stack
Frontend Bun, React 19, Vite, TypeScript, Tailwind CSS, Framer Motion, Zustand, i18next
Backend Python 3.12+, uv, FastAPI, Google ADK, SQLAlchemy, SQLite, Alembic, Pydantic, Giskard, pydantic-evals
AI/ML Gemini 3 Flash (reasoning), Gemini 2.5 Flash Lite (routing/ASR/search), Gemini 2.5 Flash Image (generation)
Tooling just, Docker Compose, Biome, Ruff, ty, Bandit, GitHub Actions
Deployment Render.com, Logfire (tracing)

Features

  • Multi-modal input - Text and voice (Gemini ASR with multilingual support)
  • AI emotion detection - Classifies emotions (Anger, Anxiety, Grief, Shame, Depression, Frustration) and recommends a matching ritual
  • Three therapeutic rituals
    • Fire (CBT) - Cognitive restructuring and challenging negative thoughts
    • Water (AEDP) - Emotional acceptance, validation, and flow
    • Earth (ACT) - Grounding, present-moment awareness, and values
  • Crisis detection - Query routing agent identifies high-risk content and provides safety resources
  • AI-generated ritual images - Feedback loop with up to 3 retry attempts on safety blocks
  • Emotion Museum - Gallery of completed rituals as flip-card memories
  • 3D particle orbs - Canvas-based particle system that morphs to emotion image colors
  • Internationalization - English and Chinese support
  • Animated ritual sequences - Fire/water/earth video animations with audio effects and BGM

User Flow

sequenceDiagram
    actor User
    participant Frontend
    participant Backend
    participant Gemini as Gemini AI

    User->>Frontend: Write worry (text or voice 🎀)
    Frontend->>Backend: POST /analyze
    Backend->>Gemini: Query Routing Agent (guardrail + risk classification)

    alt Invalid content
        Gemini-->>Backend: blocked=True
        Backend-->>Frontend: 400 CONTENT_BLOCKED
    else High risk (self-harm/crisis)
        Gemini-->>Backend: is_high_risk=True
        Note over Backend: Skip emotion analysis, emotion="Crisis"
        Backend->>Gemini: Image Prompt Agent + Image Generation (parallel)
        Gemini-->>Backend: image_path
        Backend-->>Frontend: {record_id, "Crisis", "fire", image_path}
    else Normal worry
        Gemini-->>Backend: is_high_risk=False
        Backend->>Gemini: Emotion Agent + Image Pipeline (parallel)
        Gemini-->>Backend: emotion_label, recommended_ritual, image_path
        Backend-->>Frontend: {record_id, emotion_label, recommended_ritual, image_path}
    end

    User->>Frontend: Select ritual (πŸ”₯/🌍/πŸ’§)
    Frontend->>Backend: POST /ritual

    alt High risk record
        Backend->>Gemini: Crisis Support Agent
        Gemini-->>Backend: 3 safety suggestions + emergency summary
    else Normal record
        Backend->>Gemini: Ritual Agent (Fire CBT / Earth ACT / Water AEDP)
        Note over Backend,Gemini: May call Web Search Agent for timely worries
        Gemini-->>Backend: 3 perspectives + summary
    end
    Backend-->>Frontend: {perspectives, summary}

    User->>Frontend: Select perspective
    Frontend->>Frontend: Play totem animation πŸ”₯
    Frontend->>Backend: POST /complete
    Frontend-->>User: Show totem ✨ + summary
Loading

Technical Architecture

graph TB
    subgraph GitHub
        Repo[Repository]
    end

    subgraph Render[Render.com Serverless Host]
        subgraph FE[Frontend]
            React[React + Vite + TypeScript]
            Tailwind[Tailwind CSS]
            Framer[Framer Motion]
            Zustand[Zustand Store]
            I18n[i18next]
        end

        subgraph BE[Backend]
            FastAPI[FastAPI + Python 3.12]
            Logfire[Logfire Observability]

            subgraph AgentLayer[AI Agents - Google ADK]
                RoutingAgent[πŸ›‘οΈ Query Routing Agent<br/>Guardrail + Risk Classification]
                EmotionAgent[🎭 Emotion Analysis Agent]
                RitualAgents[πŸ”₯ Fire CBT / 🌍 Earth ACT / πŸ’§ Water AEDP]
                CrisisAgent[🚨 Crisis Support Agent]
                SearchAgent[πŸ” Web Search Agent<br/>google_search tool]
                ImagePromptAgent[πŸ–ΌοΈ Image Prompt Agent<br/>🧠 Thinking Mode]
            end

            subgraph Services[Services]
                ImageGen[Image Generation<br/>google-genai direct]
                ASR[🎀 ASR Service<br/>Speech-to-Text]
            end

            SQLAlchemy[SQLAlchemy + Alembic]
        end

        subgraph Storage
            VOL[(Volume /var/data)]
            DB[(db.sqlite)]
            IMG[images/]
        end
    end

    subgraph External[Gemini API Models]
        GeminiMain[gemini-3-flash-preview<br/>🧠 Thinking Mode<br/>Main / Crisis / Image Prompt]
        GeminiLite[gemini-2.5-flash-lite<br/>Routing / Guardrail / Search / ASR]
        GeminiImage[gemini-2.5-flash-image<br/>🎨 Native Image Generation]
    end

    subgraph Testing[AI Governance]
        Evals[πŸ§ͺ LLM Evaluation Testing<br/><br/>🐒 Giskard<br/>Safety Scans<br/>Harmfulness / Sycophancy / Hallucination / Prompt Injection<br/><br/>πŸ“Š pydantic-evals<br/>Quality Checks<br/>LLMJudge Rubrics / Perspective Count / Word Limits / Ritual Matching]
    end

    Repo -->|git push| Render
    React --> FastAPI
    FastAPI --> RoutingAgent
    RoutingAgent -->|valid| EmotionAgent
    RoutingAgent -->|high risk| CrisisAgent
    EmotionAgent --> RitualAgents
    RitualAgents -->|tool call| SearchAgent
    CrisisAgent -->|tool call| SearchAgent
    SQLAlchemy -->|history context| RitualAgents
    SQLAlchemy -->|history context| CrisisAgent
    ImagePromptAgent --> ImageGen

    RoutingAgent -->|Google ADK| GeminiLite
    EmotionAgent -->|Google ADK| GeminiMain
    RitualAgents -->|Google ADK| GeminiMain
    CrisisAgent -->|Google ADK| GeminiMain
    SearchAgent -->|grounding| GeminiLite
    ImagePromptAgent -->|Google ADK| GeminiMain
    ImageGen --> GeminiImage
    ASR --> GeminiLite

    Logfire -.->|trace| AgentLayer
    Evals -.->|test| AgentLayer
    FastAPI --> SQLAlchemy
    SQLAlchemy --> VOL
    VOL --> DB
    VOL --> IMG
Loading

Backend Agents

Agent Model Purpose
Query Router gemini-2.5-flash-lite Content validation and risk detection
Emotion Detector gemini-3-flash-preview Emotion classification and ritual recommendation
Fire Ritual gemini-3-flash-preview CBT therapeutic perspectives
Water Ritual gemini-3-flash-preview AEDP therapeutic perspectives
Earth Ritual gemini-3-flash-preview ACT therapeutic perspectives
Crisis Support gemini-3-flash-preview High-risk content safety suggestions
Image Prompt gemini-3-flash-preview Ritual image prompt generation
Web Search gemini-2.5-flash-lite Fact-checking user claims
ASR gemini-2.5-flash-lite Audio transcription
Image Gen gemini-2.5-flash-image Ritual image generation

API Endpoints

Method Path Purpose
GET /health Health check
POST /api/analyze Emotion detection and ritual recommendation
POST /api/ritual Generate therapeutic perspectives
POST /api/complete Mark ritual as completed
GET /api/records List completed rituals
POST /api/transcribe Audio-to-text transcription
GET /api/images/{device_id}/{filename} Serve ritual images

All /api/* endpoints require an X-Device-Id header (UUID).

Prerequisites

  • Bun (v1.0+)
  • uv (Python package manager)
  • just (command runner)
  • Docker (optional, for containerized dev)

Quick Start

# Clone the repo
git clone https://github.com/your-org/emoFuneral.git
cd emoFuneral

# Copy environment files
cp frontend/.env.example frontend/.env
cp backend/.env.example backend/.env
# Edit backend/.env to set GOOGLE_API_KEY

# Install dependencies
cd frontend && bun install && cd ..
cd backend && uv sync && cd ..

# Start development servers
just dev-frontend  # in one terminal
just dev-backend   # in another terminal

Or use Docker:

just up

Development Commands

just                  # List all commands

# Frontend
just dev-frontend     # Start Vite dev server
just lint-frontend    # Run Biome lint
just format-frontend  # Format with Biome
just test-frontend    # Run Bun test
just typecheck-frontend  # TypeScript check

# Backend
just dev-backend      # Start FastAPI server
just lint-backend     # Run Ruff lint
just format-backend   # Format with Ruff
just test-backend     # Run pytest
just typecheck-backend   # Run ty type check
just security-backend    # Run Bandit security scan
just migrate          # Run database migrations

# All
just lint             # Lint frontend + backend
just format           # Format all
just fix              # Auto-fix formatting + linting
just test             # Test all
just ci               # Run all CI checks (lint, typecheck, security, env-check, test)

# LLM Evaluation (real API calls, NOT in CI)
just eval-giskard-safety  # Giskard safety-critical tests (~3-5 min)
just eval-giskard         # All Giskard eval tests
just eval-pydantic        # pydantic-evals tests (LLMJudge + deterministic evaluators)
just eval                 # All evaluation tests (Giskard + pydantic-evals)
just eval-giskard-scan    # Full Giskard vulnerability scan (~30+ min, HTML reports)

# Docker
just up               # Start containers
just down             # Stop containers
just up-build         # Rebuild and start

Project Structure

emoFuneral/
β”œβ”€β”€ frontend/                  # React + Vite frontend
β”‚   └── src/
β”‚       β”œβ”€β”€ api/               # API client with case conversion
β”‚       β”œβ”€β”€ components/        # React components
β”‚       β”‚   β”œβ”€β”€ Ritual/        # Ritual flow steps (input β†’ analyze β†’ select β†’ animate β†’ complete)
β”‚       β”‚   β”œβ”€β”€ Museum/        # Emotion museum carousel and totem cards
β”‚       β”‚   └── common/        # Shared UI (EmotionOrb, GlassButton, VoiceInput, etc.)
β”‚       β”œβ”€β”€ hooks/             # Custom hooks (animation, audio, viewport, speech)
β”‚       β”œβ”€β”€ stores/            # Zustand state management
β”‚       β”œβ”€β”€ i18n/              # Translations (en, zh)
β”‚       β”œβ”€β”€ config/            # Animation timings, sizes, API config
β”‚       β”œβ”€β”€ mocks/             # MSW handlers for development
β”‚       └── types/             # TypeScript type definitions
β”œβ”€β”€ backend/                   # FastAPI backend
β”‚   └── app/
β”‚       β”œβ”€β”€ routers/           # API endpoint handlers
β”‚       β”œβ”€β”€ services/          # AI agents and business logic
β”‚       β”‚   β”œβ”€β”€ query_routing_agent/    # Content validation + risk detection
β”‚       β”‚   β”œβ”€β”€ ritual_recommend_agent/ # Emotion detection + ritual recommendation
β”‚       β”‚   β”œβ”€β”€ ritual_agents/          # Fire (CBT), Water (AEDP), Earth (ACT), Crisis
β”‚       β”‚   β”œβ”€β”€ image_prompt_agent/     # Ritual image prompt generation
β”‚       β”‚   β”œβ”€β”€ web_search_agent/       # Fact-checking via Google Search
β”‚       β”‚   β”œβ”€β”€ image_gen/              # Image generation with feedback loop
β”‚       β”‚   └── asr/                    # Audio transcription
β”‚   β”œβ”€β”€ tests/
β”‚   β”‚   β”œβ”€β”€ evaluation/               # LLM eval tests (71 tests, --run-eval)
β”‚   β”‚   β”‚   β”œβ”€β”€ conftest.py           # Real API key + Giskard/pydantic-evals config
β”‚   β”‚   β”‚   β”œβ”€β”€ datasets.py           # Hand-crafted test inputs (shared)
β”‚   β”‚   β”‚   β”œβ”€β”€ giskard_evals/        # Giskard scan + direct assertion tests
β”‚   β”‚   β”‚   └── pydantic_evals/       # pydantic-evals (LLMJudge + deterministic evaluators)
β”‚   β”‚   └── ...                       # Unit tests (154 tests)
β”‚       β”œβ”€β”€ db/                # SQLAlchemy models and session management
β”‚       β”œβ”€β”€ schemas/           # Pydantic request/response models
β”‚       β”œβ”€β”€ middleware/        # Device ID validation
β”‚       β”œβ”€β”€ fallbacks/         # Static fallback content when AI fails
β”‚       └── core/              # Configuration and settings
β”œβ”€β”€ docs/                      # Documentation
β”‚   β”œβ”€β”€ prd.md                 # Product requirements
β”‚   β”œβ”€β”€ tech-spec.md           # Technical specification
β”‚   └── architecture.md        # System architecture diagrams
β”œβ”€β”€ .github/workflows/         # CI: backend, frontend, env, docs checks
β”œβ”€β”€ justfile                   # Development commands
β”œβ”€β”€ docker-compose.yml         # Local containerized dev
└── render.yaml                # Render.com deployment blueprint

Documentation

Environment Variables

See .env.example files in frontend/ and backend/ directories.

Backend (backend/.env.example)

Variable Default Description
GOOGLE_API_KEY (required) Google Gemini API key
GEMINI_MODEL gemini-3-flash-preview Primary reasoning model
GEMINI_GUARDRAIL_MODEL gemini-2.5-flash-lite Guardrail content classifier
GEMINI_ROUTING_MODEL gemini-2.5-flash-lite Query routing / risk classifier
GEMINI_CRISIS_MODEL gemini-3-flash-preview Crisis support agent
GEMINI_IMAGE_MODEL gemini-2.5-flash-image Image generation
GEMINI_ASR_MODEL gemini-2.5-flash-lite Audio transcription
GEMINI_SEARCH_MODEL gemini-2.5-flash-lite Web search agent
GEMINI_PROMPT_MODEL gemini-3-flash-preview Image prompt generation
GEMINI_THINKING_LEVEL LOW Extended thinking (MINIMAL/LOW/MEDIUM/HIGH)
GEMINI_IMAGE_BLOCK_LEVEL BLOCK_ONLY_HIGH Image safety threshold
GEMINI_MAX_OUTPUT_TOKENS 4096 Max output tokens for agents
GEMINI_SEARCH_MAX_TOKENS 350 Web search output limit
WORRY_HISTORY_LIMIT 5 Max past worries in ritual context
PERSPECTIVE_MAX_WORDS 20 Max words per perspective/summary
IMAGE_PROMPT_MAX_ATTEMPTS 3 Image generation feedback loop retries
AGENT_MAX_RETRIES 2 Agent call retries
AGENT_RETRY_DELAY 0.5 Initial retry delay (seconds, exponential backoff)
CONTENT_MAX_LENGTH 500 Max user input characters
GUARDRAIL_MAX_TOKENS 50 Guardrail judge output limit
DB_POOL_RECYCLE 1800 DB connection recycle interval (seconds)
LOGFIRE_TOKEN (optional) Logfire tracing token
RATE_LIMIT_PER_MINUTE 100 API rate limit
DATA_DIR /var/data Data/image storage directory
GISKARD_EVAL_MODEL gemini/gemini-3-flash-preview Giskard scan evaluator LLM (litellm provider/model)
GISKARD_EMBEDDING_MODEL gemini/gemini-embedding-001 Giskard scan embedding model (litellm provider/model)
PYDANTIC_EVAL_MODEL google-gla:gemini-3-flash-preview pydantic-evals LLMJudge model (pydantic-ai provider:model)
CORS_ORIGINS_STR http://localhost:5173 Comma-separated allowed origins

Frontend (frontend/.env.example)

Variable Default Description
VITE_API_URL http://localhost:8000 Backend API URL
VITE_API_TIMEOUT 60000 API request timeout (ms)
VITE_RITUAL_CONTENT_MAX_CHARS 500 Max input characters
VITE_BGM_VOLUME 0.2 Background music volume (0-1)
VITE_EFFECT_VOLUME 0.5 Ritual sound effect volume (0-1)
VITE_ENABLE_MOCKS false Force MSW mocks (true/false)

About

No description, website, or topics provided.

Resources

Stars

0 stars

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages