DEV Community

Esther Studer
Esther Studer

Posted on

I Built an AI That Matches Lonely People with Therapy Pets — Here's What I Learned

Ever had a bad week and thought, "I just need to hug a dog right now"?

You're not alone. Science agrees. And I built something about it.

This post is about MyPetTherapist — an AI-powered platform that matches people with certified therapy animals — and all the weird technical decisions I made along the way.


The Problem Worth Solving

Therapy animals work. Studies show pet therapy reduces cortisol by up to 37%, lowers blood pressure, and reduces anxiety faster than most medications. But most people have no idea:

  • Which animal type actually fits their emotional need
  • Whether their living situation (apartment, allergy-prone, busy schedule) is compatible
  • How to find certified therapy animals vs. just... someone's emotional support peacock

Enter: AI.


The Stack (The Honest Version)

I'm going to be real — the first version was a mess.

# Version 1: The Embarrassing Version
def match_pet(user_input):
    if "sad" in user_input:
        return "dog"
    if "stressed" in user_input:
        return "cat"
    return "fish"  # the "I give up" option
Enter fullscreen mode Exit fullscreen mode

Yeah. A dictionary pretending to be AI.

Version 2 was better:

# Version 2: Actual Semantic Matching
from sentence_transformers import SentenceTransformer
import numpy as np

model = SentenceTransformer('all-MiniLM-L6-v2')

def embed_profile(text: str) -> np.ndarray:
    return model.encode(text, normalize_embeddings=True)

def match_therapy_animal(user_profile: str, animal_profiles: list[dict]) -> dict:
    user_vec = embed_profile(user_profile)

    scores = []
    for animal in animal_profiles:
        animal_vec = embed_profile(animal['description'])
        similarity = float(np.dot(user_vec, animal_vec))
        scores.append((similarity, animal))

    scores.sort(key=lambda x: x[0], reverse=True)
    return scores[0][1]  # Best match
Enter fullscreen mode Exit fullscreen mode

This was 10x better. But still missing the nuance of why someone needs therapy support.


The Breakthrough: Structured Emotional Intake

The real game-changer was treating the matching problem like a multi-dimensional vector search problem, not a keyword problem.

Users answer 5 questions. We don't analyze the words — we analyze the emotional signature:

class EmotionalProfile:
    dimensions = [
        'anxiety_level',      # 0-10
        'social_energy',      # introvert <-> extrovert
        'physical_activity',  # couch potato <-> hiker
        'commitment_capacity',# time/energy available
        'touch_sensitivity'   # some people hate fur, love scales
    ]

    def score(self, responses: dict) -> np.ndarray:
        # NLP scoring via fine-tuned classifier
        return np.array([self._score_dimension(d, responses) 
                         for d in self.dimensions])
Enter fullscreen mode Exit fullscreen mode

Each therapy animal type also gets scored on these same 5 dimensions. The match is a cosine similarity in emotional space.


What Actually Surprised Me

Rabbits outperform dogs for anxiety. High-anxiety users matched better with rabbits — quieter, don't demand attention, warm and furry. This never would have come from keyword matching.

Fish are underrated for insomnia. The visual rhythm of a fish tank is legitimately studied as a sleep aid. Users who reported sleep issues matched fish tanks 40% of the time.

The intake form itself was therapeutic. Multiple users said just answering the questions helped them understand what they were feeling. The AI wasn't doing the heavy lifting — the reflection was.


The Infrastructure (Keep It Simple, Stupid)

I deliberately kept the stack boring:

  • Backend: Python + FastAPI
  • Embeddings: sentence-transformers (local, free, fast enough)
  • Database: PostgreSQL with pgvector extension for similarity search
  • Frontend: WordPress (I know. I know. It works.)
  • Hosting: Single VPS, no Kubernetes drama
-- pgvector similarity search
SELECT 
  animal_id,
  name,
  species,
  1 - (embedding <=> $1) AS similarity_score
FROM therapy_animals
WHERE is_certified = true
ORDER BY embedding <=> $1
LIMIT 5;
Enter fullscreen mode Exit fullscreen mode

The query that powers the entire matching engine is 8 lines of SQL. No LangChain. No vector database SaaS. Just PostgreSQL doing what it's always done.


Lessons for Anyone Building Wellness AI

1. Start with the emotion, not the solution. Most health-tech apps ask "what do you want?" — that's the wrong question. Ask "how do you feel?" and let the AI figure out the solution.

2. Interpretability matters more than accuracy. If a user gets matched with a rabbit and you can't explain why, they won't trust it. Show your work.

3. The AI is the last 20%. The first 80% is the intake design, the database of certified providers, the trust-building UX. AI is the finishing touch, not the foundation.

4. Boring infrastructure scales. I see people reaching for Pinecone on day 1. Start with pgvector. You'll save $300/month and learn more.


What's Next

Currently working on:

  • Live session matching — not just animal type, but specific available sessions near you
  • Outcome tracking — did the match actually help? 30-day check-in flows
  • Provider onboarding API — so certified therapy animal organizations can self-register

If you're curious about the project: mypettherapist.com — it's live, it's free to try the matching quiz, and yes, you might get matched with a guinea pig. Lean into it.


What's the weirdest "AI for wellness" use case you've seen? Drop it in the comments — genuinely collecting data points here.

Top comments (0)