AI case study · Function calling · Charity

Donating by conversation, safely

People donate goods or ask an NGO for help just by chatting. The assistant fills in the forms for them, creating and tracking real records, without ever being trusted with who the user is.

Role
Fullstack Developer
Model
Gemini, native function calling
Timeline
October 2026

How one message becomes a donation

  1. User“I have two bags of children’s clothes to give.”
  2. Laravel APIAdds the last 50 messages; keeps the user ID to itself.
  3. GeminiChooses from 10 approved tools, e.g. create_donation.
  4. Validated toolArguments checked; owner taken from the session.
  5. MySQL recordDonation saved; the reply confirms it.

The problem

Forms put people off giving or asking for help. A chat is easier, but an AI that writes to a database is dangerous if it can be talked into acting for someone else, if it loops, or if it stops answering halfway through a donation.

How it stays safe

Security boundary

The AI never knows who you are

The backend takes the user from the login session, not from the model. Every tool argument is treated as untrusted and validated, and repositories check ownership before any read or write.

Bounded loop

Many tools, never forever

Gemini can call several tools in one turn and gets all results back together. The loop stops after 8 rounds.

Problems I hit, and how I solved them

  1. Problem

    Free-tier rate limits

    Gemini’s free tier allows only a few requests a minute per model, and a single donation can take several model calls.

    Solution

    Wait when it’s short, switch when it isn’t

    On a “too many requests” error, the backend reads how long the provider asks it to wait. If that’s a few seconds, it waits and retries once; if not, it moves straight to the next model. Everything runs inside one 25-second budget, so the user is never left hanging.

  2. Problem

    Every model is down

    Out of quota, overloaded or timed out: a chat that just stops halfway through a donation loses the donor.

    Solution

    A guided flow takes over

    A built-in step-by-step flow finishes the conversation without the AI. Its progress is remembered between messages, and if a tool already created the donation, it says so instead of creating a second one.

  3. Problem

    Context costs tokens

    The model needs the conversation to make sense of “yes, those ones”, but sending all of it every time gets expensive.

    Solution

    Save the conversation, send a window

    Every conversation is saved in the database, and only the latest 50 messages go to the model. The window is trimmed so it never starts halfway through a tool call.

  4. Problem

    Prompts stuffed with data

    Loading a user’s profile and history into every prompt is slow, costly and risky.

    Solution

    Fetch real data only when it’s needed

    The prompt holds no user data at all. Gemini calls a tool, such as list_my_donations, only when the conversation needs that fact, and gets back just that user’s records.

How it’s built

Laravel (PHP 8.3) and MySQL with thin controllers, services and repositories · React + TypeScript + Vite front end · Gemini function calling written directly against the API, no framework · six docs covering AI, API, architecture, auth, database and development.

Have a project or a role in mind?