Hi, I'm your AI Dad
Every day I'll send you a joke...

React to each joke and I'll learn your sense of humour โ€” getting funnier every day!

No email. No password. No app download. By messaging us, you agree to receive My Daily Dad Joke WhatsApp messages and to our Terms and Privacy Policy. Reply STOP anytime.

No faff. Just jokes.

No download. No sign-in. The entire product lives inside your existing WhatsApp.

1

Sign up for free

Click here to open WhatsApp with a pre-filled message. Hit send. That's it - you're in.

2

Get your daily joke

One joke lands in your WhatsApp every day. Two buttons to tell me whether you liked the joke. One tap and you're done.

3

AI Dad pays attention

Every reaction trains your personal taste model. The engine re-ranks your feed in real time. The more you react, the better it gets.

4

Share

Each daily joke has a unique share link. When a friend signs up through yours, both of you get extra weighting on the joke that brought them in.

Production machine learning on AWS

The delivery scheduler shards users across 168 hourly buckets with a single deterministic hash. Each send is a constant-time single-row pop.

๐Ÿง 

Semantic Embedding Layer

Every joke is a 1,024-dimensional vector from Amazon Titan Embed v2. A user's taste is the weighted mean centroid of their liked joke vectors - a position in semantic space that captures subject, register, and incongruity type simultaneously.

pgvector HNSWcosine similarityvector(1024)
๐Ÿ“Š

IQR Box Filter

After 10 likes, a 2D interquartile-range filter activates over two hand-labelled axes - wordplayโ†”situational and wholesomeโ†”cynical - narrowing the candidate pool to the user's proven taste region before the embedding layer re-ranks within it.

IQR percentile2-axis classificationdelayed activation
๐Ÿ”ฌ

Mutation Experiment Layer

Claude Fable 5 generates single-axis variants of source jokes - setup reframe, punchline rephrase, tone shift, structure shift. Each variant is reviewed by OpenAI o3 in an iterative loop (up to five rounds), with a human final check before delivery. Variants are delivered in a separate experiment corpus, keeping the preference-learning signal clean.

Amazon Bedrockcontrolled mutationcorpus isolation
โšก

Serverless Delivery Pipeline

EventBridge fires a Lambda every hour. A deterministic hash shards each user to exactly one hour per day - MOD(ABS(HASHTEXT(userId)), 7) - spreading sends across 168 buckets. Each delivery is a constant-time single-row pop from a pre-filled queue.

AWS LambdaEventBridgeO(1) delivery
๐Ÿ”—

WhatsApp API Integration

Inbound messages hit a Hono webhook Lambda that verifies HMAC-SHA256 and immediately enqueues to SQS โ€” returning 200 to Meta in ~100ms. A separate processor Lambda consumes the queue asynchronously, handling all DB writes and replies. Duplicate detection via sourceEventId prevents duplicate interaction rows.

WhatsApp Cloud APISQSHMAC-SHA256idempotent
๐Ÿ—„๏ธ

Aurora Serverless v2

PostgreSQL with pgvector. Scales to 0 ACU with auto-pause (max 4 ACU). Drizzle ORM for type-safe queries. A single schema holds jokes, embeddings, user profiles, delivery queues, and referral chains.

Aurora Serverless v2Drizzle ORMpgvector

Two models. One feeds the other.

The hybrid architecture pairs a neural embedding model with a statistical filter. Each compensates for the other's weaknesses at different points in the user's journey.

Model 1 - active after 5 liked/referred jokes

Taste Vector (Neural)

Your taste is a position in 1,024-dimensional semantic space - the weighted mean centroid of every joke you've liked. Future recommendations are ranked by cosine distance to this point.

  • Captures nuance no hand-labelled axis could: topic, register, incongruity style
  • Updates live on every reaction - no batch retraining required
  • Referral interactions are weighted 10ร— to bootstrap cold-start signal
Model 2 - activates at 10+ likes

IQR Box Filter (Statistical)

A 2D interquartile-range fence over two structural axes. Deliberate delayed activation avoids over-fitting on sparse early data while still narrowing the candidate set once sufficient signal exists.

  • Axis 1: wordplay โ†” situational (joke structure)
  • Axis 2: wholesome โ†” cynical (tonal register)
  • Dislike data informs the IQR bounds to skew the filter away from disliked patterns
Input
User taps a reaction button on today's joke. Button reply ID LIKE arrives at webhook.
Dedup
Interaction checked against sourceEventId. If already recorded, return 200 and exit.
Score update
Joke's global score incremented +1. Previous opposite reaction undone if present.
Profile rebuild
Last 50 gen-0 likes fetched. Taste vector = weighted mean of their embeddings. IQR box = percentile fence on structure & tone axes.
Upsert
New taste vector and IQR box written to userProfiles in a single upsert. Next delivery query uses this immediately.
Delivery
Next joke selected by cosine similarity to taste vector, filtered through IQR box. Pre-queued into deliveryQueue for the week ahead.

Built on Amazon Bedrock, Titan Embed, and PostgreSQL with pgvector

TypeScript end-to-end. Infrastructure-as-Code. Open source on GitHub.

TypeScript
Hono
PostgreSQL + pgvector
Aurora Serverless v2
Drizzle ORM
AWS Lambda
Lambda Function URL
Amazon Bedrock
Titan Embed v2
Claude Fable 5
OpenAI o3
EventBridge
AWS CDK
WhatsApp Cloud API
Turborepo

Free. No app required.

Works on any phone with WhatsApp. Click below and hit send - that's the whole sign-up.

Tell me a joke Dad!

No email. No password. No app download. By messaging us, you agree to receive My Daily Dad Joke WhatsApp messages and to our Terms and Privacy Policy. Reply STOP anytime.