DEV Community

Esther Studer
Esther Studer

Posted on

I Built an AI That Matches People With Therapy Animals — Here's What I Learned

I Built an AI That Matches People With Therapy Animals — Here's What I Learned

Pet therapy works. There's decades of research backing it up — reduced cortisol, lower blood pressure, improved mood. The problem? Finding the right animal for the right person has always been manual, slow, and largely guesswork.

So I built something to fix that.

The Problem With Traditional Pet Therapy Matching

Most platforms work like this:

  1. You fill out a form ("Do you prefer dogs or cats?")
  2. Someone manually reviews it
  3. You get a recommendation in 3–5 business days

This is 2024 energy applied to a 2026 problem.

The real matching factors are way more nuanced:

  • Anxiety type (social vs. generalized vs. situational)
  • Living situation and mobility
  • Allergy profile
  • Sensory sensitivities (noise, texture, unpredictability)
  • Therapeutic goal (grounding, motivation, companionship, routine)

A golden retriever is perfect for some people. For others — too energetic, too unpredictable, overwhelming.

How the AI Matching Engine Works

Here's the core architecture I ended up with after several iterations:

import openai
from dataclasses import dataclass
from typing import Optional

@dataclass
class UserProfile:
    anxiety_type: str
    living_space: str  # 'apartment', 'house', 'shared'
    mobility: str      # 'low', 'medium', 'high'
    sensory_sensitivity: str  # 'low', 'medium', 'high'
    therapeutic_goal: str
    allergies: list[str]
    experience_with_animals: str

@dataclass  
class AnimalProfile:
    species: str
    breed: Optional[str]
    energy_level: str
    predictability: str
    care_intensity: str
    interaction_style: str  # 'active', 'calm', 'independent'
    allergy_risk: str

def generate_match_explanation(user: UserProfile, animal: AnimalProfile) -> str:
    prompt = f"""
    You are a certified animal-assisted therapy specialist.

    User profile:
    - Anxiety type: {user.anxiety_type}
    - Living space: {user.living_space}
    - Mobility: {user.mobility}
    - Sensory sensitivity: {user.sensory_sensitivity}
    - Goal: {user.therapeutic_goal}
    - Allergies: {', '.join(user.allergies) if user.allergies else 'None'}
    - Animal experience: {user.experience_with_animals}

    Proposed animal:
    - Species/Breed: {animal.species} ({animal.breed or 'mixed'})
    - Energy: {animal.energy_level}
    - Predictability: {animal.predictability}
    - Care intensity: {animal.care_intensity}
    - Interaction style: {animal.interaction_style}

    Provide a warm, clinical explanation (3-4 sentences) of why this is or isn't 
    a good match. Be specific. Reference the user's actual profile data.
    End with one concrete first-step recommendation.
    """

    response = openai.chat.completions.create(
        model="gpt-4o",
        messages=[{"role": "user", "content": prompt}],
        temperature=0.7,
        max_tokens=200
    )

    return response.choices[0].message.content

# Scoring function — weighted matching
def compute_match_score(user: UserProfile, animal: AnimalProfile) -> float:
    score = 0.0
    weights = {
        'energy_alignment': 0.25,
        'sensory_fit': 0.25,
        'care_capacity': 0.20,
        'allergy_safety': 0.20,
        'goal_alignment': 0.10
    }

    # Energy alignment
    energy_map = {'low': 1, 'medium': 2, 'high': 3}
    mobility_score = energy_map.get(user.mobility, 2)
    animal_energy = energy_map.get(animal.energy_level, 2)
    energy_diff = abs(mobility_score - animal_energy)
    score += weights['energy_alignment'] * (1 - energy_diff / 2)

    # Sensory fit (high sensitivity = prefer calm/predictable animals)
    sensory_map = {'low': 3, 'medium': 2, 'high': 1}
    user_sensory = sensory_map.get(user.sensory_sensitivity, 2)
    animal_predictability = sensory_map.get(animal.predictability, 2)
    sensory_diff = abs(user_sensory - animal_predictability)
    score += weights['sensory_fit'] * (1 - sensory_diff / 2)

    # Allergy safety
    allergy_score = 0 if any(a in animal.allergy_risk for a in user.allergies) else 1
    score += weights['allergy_safety'] * allergy_score

    # Simplified care capacity check
    care_map = {'low': 1, 'medium': 2, 'high': 3}
    mobility_care = energy_map.get(user.mobility, 2)
    animal_care = care_map.get(animal.care_intensity, 2)
    care_diff = abs(mobility_care - animal_care)
    score += weights['care_capacity'] * (1 - care_diff / 2)

    # Goal alignment (simplified rule-based)
    goal_animal_map = {
        'grounding': ['dog', 'cat', 'rabbit'],
        'motivation': ['dog'],
        'companionship': ['dog', 'cat', 'bird'],
        'routine': ['dog', 'rabbit', 'fish']
    }
    preferred = goal_animal_map.get(user.therapeutic_goal, [])
    goal_match = 1 if animal.species in preferred else 0.5
    score += weights['goal_alignment'] * goal_match

    return round(score, 3)
Enter fullscreen mode Exit fullscreen mode

The Unexpected Insights

1. Rabbits Are Criminally Underrated

I ran matching simulations across ~500 synthetic user profiles and rabbits showed up as the #1 match for users with:

  • High sensory sensitivity
  • Apartment living
  • Generalized anxiety
  • Low mobility

They're quiet, soft, predictable, and genuinely responsive to human presence. But nobody thinks "rabbit" when they think "therapy animal." The AI kept recommending them. The AI was right.

2. Fish Work — But Only for Specific Profiles

Fish are the dark horse. They score extremely high for:

  • Routine-building (feeding schedules)
  • Visual calming (proven by research on aquarium watching)
  • Zero allergy risk
  • Sensory predictability

For users with ADHD who need environmental calm without physical interaction, fish consistently ranked top 3.

3. "Experience with animals" is the most predictive feature

People who grew up with animals and then had none in adulthood respond much faster to reintroduction therapy. The model learned this pattern quickly — it would weight "bring back what you know" heavily for reconnection goals.

What I'd Do Differently

Use embeddings for goal-to-animal alignment — my rule-based goal map is weak. A vector similarity approach on therapy outcome literature would be much stronger.

Add a feedback loop — right now the model doesn't learn from outcomes. A simple thumbs up/down on matches after 30 days would make it dramatically better over time.

Structured outputs — GPT-4o's structured output mode would make the explanation generation more reliable and parseable.

Try It

If you're dealing with anxiety, burnout, or just want a science-backed reason to get a pet — MyPetTherapist.com does exactly this kind of matching, done properly.

And if you want to play with the matching code above, it's a solid weekend project. Add a small FastAPI wrapper, a Pydantic layer for the profiles, and you've got a deployable microservice in an afternoon.


Built with Python, OpenAI API, FastAPI. Drop questions in the comments — happy to go deeper on any part of the stack.

Top comments (0)