How I Built an AI-Powered Personal Shopper for Sri Lanka’s Largest Online Store

Shopping for a gift online is stressful enough in your native language. Now imagine doing it in Singlish — a mix of Sinhala and English — or in Tamil script, while trying to pick the right cake, flowers, and toys for a surprise birthday delivery to a friend in Bambalapitiya by Friday afternoon.

That was the exact problem I set out to solve.

Kalpa Kapruka is a full-stack AI gifting concierge I built for Kapruka.com, Sri Lanka’s largest online gift and delivery platform. It allows shoppers to describe what they need in natural language — English, Sinhala, Tamil, Singlish, or Tanglish — and have an AI assistant automatically search the catalog, build a gift bundle, collect delivery details, and generate a secure checkout link, all in a single, human-feeling conversation.

In this post, I’ll walk you through why I built it, how the system is architected, and what I learned along the way.

Why This Problem Needed Solving

Sri Lanka has a unique linguistic landscape. Everyday conversations often blend Sinhala and English mid-sentence — a phenomenon called Singlish — or Tamil and English — known as Tanglish. Most e-commerce chatbots are trained for formal English, which means they immediately break down when a Sri Lankan user types something like:

“Machang, Galle walatada heta birthday hamper ekak yawanna, roses ekka cake ekakuth add karanna”

That translates roughly to: “Hey, I want to send a birthday hamper to Galle tomorrow, please add roses and a cake too.”

No traditional rule-based chatbot handles that gracefully. I wanted to build something that does — something that truly felt like chatting with a local shopping assistant who just happens to have access to the entire Kapruka catalog.

Additionally, Kapruka recently launched a Model Context Protocol (MCP) server, exposing their live product catalog, delivery network, and order management via standardized AI tool APIs. This was the perfect technical foundation to build on.

The Tech Stack

Here’s what powers Kalpa Kapruka under the hood:

LayerTechnology
FrontendNext.js 14 (App Router), React, Tailwind CSS
BackendNode.js, Express, TypeScript
AI / LLMGoogle Gemini API (gemini-2.0-flash)
Catalog & LogisticsKapruka MCP Server (Streamable HTTP)
Language UnderstandingCustom NLP pipeline (Gemini + rule-based fallback)
ValidationZod
Version ControlGit / GitHub

Architecture Overview

The system is broken into five major components that work in a pipeline:

Let’s break each one down.

1. The NLP Intent Classification Pipeline

The core of the system is a custom intent parser built on top of Google Gemini.

  • Items to search for (e.g. ["roses", "chocolate cake", "toy car"])
  • Delivery date (e.g. "2026-07-10")
  • Budget constraint (e.g. 5000 in LKR)
  • Recipient name, phone, address
  • Sender name (for gift cards)
  • Is it self-shopping? (boolean)
  • Is it an order tracking request? (boolean)
  • Order number (e.g. VPAY827982BA)

Here is a simplified version of what the parsed output looks like:

But Gemini alone is not enough. The API can time out or occasionally produce unexpected output. So I built a rule-based fallback parser using carefully tuned regular expressions that detects keywords, Sinhala Singlish patterns, Tamil Tanglish patterns, and common date phrases (like “heta” meaning “tomorrow”, or “aave aaththa” meaning “next Sunday”).

This dual-engine approach means the assistant keeps working even during API latency spikes.

Multilingual Script Detection

One of the most interesting engineering challenges was language detection. The system needs to detect whether the user is writing in:

  • Sinhala Unicode script (e.g. "සතියේ"),
  • Tamil Unicode script (e.g. "வாழ்த்துக்கள்"),
  • Singlish (romanized Sinhala, e.g. "oyage order eka"),
  • Tanglish (romanized Tamil, e.g. "unga order track panna"),
  • Standard English.

I implemented a character-level Unicode range checker that samples each character in the message and classifies the dominant script. The detected language is then threaded through the entire pipeline, ensuring that the AI reply, delivery status messages, and error responses are all returned in the same language and script the user wrote in.

2. The MCP Client — Live Catalog & Logistics

The Model Context Protocol (MCP) layer is what connects the AI brain to the live Kapruka product database and delivery network.

The mcpClient.ts service connects to the Kapruka MCP Streamable HTTP server and exposes a clean async API to the rest of the system. Here’s what it powers:

Product Search

Searches the Kapruka catalog by keyword, category, and budget. Results are returned as structured product cards with name, price, stock status, and direct URL.

Delivery Viability Check

Given a product ID, city, and date, the MCP returns whether delivery is possible on that date to that location — along with any perishable warnings (for fresh flowers or cakes).

Guest Checkout Link Generation

Once all delivery details are confirmed, the MCP generates a secure, time-limited guest checkout URL that takes the user directly to payment without needing to create an account.

Order Tracking

Given an order number (starting with VPAY), the MCP returns a full structured tracking log including status, delivery date, recipient details, and a timestamped activity feed.

API Key Rotation

Because Gemini API has per-minute rate limits, I built an API key rotation pool that cycles across 5 configured API keys automatically when rate limit errors are detected. This keeps the assistant responsive even during high-traffic periods.

3. The Colombo Suburb Resolver — A Real-World Edge Case

One bug that took real investigation to fix: Kapruka’s delivery API doesn’t accept colloquial area names like “Bambalapitiya” or “Kollupitiya” — it expects canonical postal zone names like “Colombo 04” or “Colombo 03”.

When a user types their address as "octave - bambalapitiya", the raw string fails the delivery check, causing a city_not_deliverable error.

The fix? A local Colombo suburb-to-zone dictionary baked into the resolveCanonicalCity() function:

The function normalizes hyphens and spaces, then scans the input against the dictionary before falling back to the live MCP city lookup. Now, any colloquial Colombo address resolves correctly.

4. The Bundle Compiler

The bundle compiler takes the parsed intent and the raw MCP search results and produces a clean, structured gift hamper. It:

  • Deduplicates search results
  • Enforces budget constraints (prioritizing items within the limit)
  • Flags out-of-stock products
  • Calculates delivery charges and the estimated total
  • Merges the compiled hamper with the user’s manually added UI cart items

5. The Frontend Dashboard

The frontend is a Next.js 14 App Router application with Tailwind CSS, designed to feel like a premium gifting concierge service — not a generic chatbot.

Key UI Panels

Left Column — Context Canvas:

  • Gift bundle display with product cards, quantities, and pricing
  • Logistics panel showing delivery city, date, and shipping availability
  • Contact details collection form (recipient, phone, address, sender name)
  • A countdown-timer payment gateway card for checkout

Right Column — Chat Interface:

  • A live conversation feed with typing indicators and AI message bubbles
  • Bilingual product search prompts
  • Voice input support via the Web Speech API

Post-Sale Tracking Card:
When a user provides a VPAY order number, a premium tracking card renders below the logistics panel featuring:

  • A horizontal stepper (Confirmed → Preparing → Dispatched → Delivered) with animated progress
  • A vertical timeline log of every activity event pulled from the MCP tracking API
  • Recipient details and estimated delivery date

Key Engineering Challenges

Challenge 1: Handling Incomplete Conversational Context

Users rarely provide all delivery details in one message. The AI assistant needs to progressively collect missing fields — city, date, address, recipient name, phone number — across multiple turns, without losing context.

I solved this by threading the full ParsedIntent state through every backend request, merging newly extracted fields with the accumulated conversation history on each turn.

Challenge 2: Preventing False Checkout Triggers

Early in development, the system would sometimes treat normal product searches as checkout requests — especially when product names contained words like “payment” or when order IDs like VPAY827982BA (which contain the substring “pay”) were mentioned.

I implemented an intent interceptor that checks for tracking keywords and order ID patterns before evaluating checkout triggers.

Challenge 3: Timeout Resilience

The Kapruka MCP server occasionally experiences latency spikes. Without resilience logic, the entire assistant response would fail silently. I added:

  • Parallel search execution using Promise.allSettled() so that individual product search failures don’t block the rest of the hamper
  • Rule-based fallback parsing when Gemini itself times out
  • Graceful degradation messages that let the user know in their local language if something is temporarily unavailable

What I Learned

Building Kalpa Kapruka taught me several things that go beyond textbook software engineering:

  1. LLMs are powerful but need guardrails. Gemini is remarkably capable at understanding Singlish, but it occasionally hallucinates city names or incorrectly sets booleans. The rule-based fallback saved the experience more times than I expected.
  2. Real-world APIs have rough edges. The Kapruka delivery API returns deliverable: false for valid city names that just aren’t in the canonical format. Bridging the gap between how users naturally describe their location and what an API expects is a genuine engineering problem.
  3. Localization is more than translation. Supporting Singlish and Tanglish is not just about detecting the language — it means crafting responses that feel authentic to the cultural register the user is speaking in. A stilted, formal response in Singlish breaks trust immediately.
  4. MCP is a genuinely exciting protocol. Being able to connect an LLM directly to a live e-commerce backend via structured tool calls — without building custom API adapters for every interaction — dramatically accelerated development. I expect MCP to become a standard part of AI application architecture.

Results & Reception

The project was submitted to the Kapruka AI development team and received positive recognition for:

  • Its ability to handle all five Sri Lankan language/dialect modes
  • The premium visual design of the frontend dashboard
  • The practical integration of live delivery viability checking into the AI conversation flow
  • The resilience engineering in both the NLP pipeline and the MCP client

Try It Yourself

The full project is open source on GitHub:

👉 github.com/hamdhanhasmy/kapruka-ai-shopping-agent

See live demo here:

👉 kapruka-ai-shopping-agent.vercel.app

Final Thoughts

Building a genuine AI shopping concierge for a specific cultural context is a completely different challenge than building a generic chatbot. The biggest wins came not from the AI itself, but from the engineering work around it — the suburb resolver, the dual-parser resilience, the multilingual state threading, and the real-time MCP integrations.

If you’re working on a similar project or want to discuss the architecture in more detail, feel free to reach out. I’d love to hear what you’re building.


Leave a Comment

Your email address will not be published. Required fields are marked *

Scroll to Top