Back
12 min read

Building an AI Concierge Chatbot for a Luxury Wellness Resort

AIOpenAIHospitalityWellnessNext.jsChatbotNepalAWS

Hero Subtitle

How a simple chatbot idea turned into a deeper lesson about hospitality, prompt engineering, and why guests don't care about your tech stack.


The Hook

The Himalayan Nirvana Resort website was getting traffic. People were browsing room photos, reading about wellness programs, checking the spa menu. But they weren't converting into inquiries as much as they should.

The problem was obvious: a static FAQ page wasn't cutting it. Guests had specific questions — dietary restrictions, airport pickup availability, room upgrades, meditation schedules. Answering each one meant emailing or calling. Most people just bounced.

So I built a chatbot. Not a generic one. One that actually understood the resort.


What I Built

An AI concierge chatbot embedded directly on https://hnresort.com. Guests can ask questions in natural language and get instant, accurate answers about the resort's amenities, rooms, location, and services.

Built with:

  • OpenAI API (GPT-4) for conversation
  • Next.js for the chat widget and API routes
  • Custom context injection so the AI only answers resort-related questions
  • Rate limiting to keep API costs under control
  • Dark mode compatible (yes, the resort has a dark mode website)

The Architecture

Guest types question | v Next.js Chat Widget (React) | v Next.js API Route (/api/chat) | v Middleware (rate limit + context injection) | v OpenAI GPT-4 API (with system prompt + resort data) | v Streamed response back to widget | v Displayed in chat UI

The system prompt is the secret sauce. It contains:

  • The resort's room types, pricing ranges, and amenities
  • Location details (Pokhara, Nepal — proximity to airport, attractions)
  • Wellness program descriptions (yoga, meditation, spa)
  • Dining options
  • Policies (check-in/out, cancellation)
  • The bot's personality: helpful, warm, professional — like a real concierge

Here's a simplified version of what the system prompt looks like:

javascript
const SYSTEM_PROMPT = `
You are a friendly concierge for Himalayan Nirvana Resort, a luxury wellness resort in Pokhara, Nepal.

Rules:
- Only answer questions related to the resort, its services, bookings, and wellness programs.
- If asked something unrelated, politely redirect.
- Be warm and conversational but professional.
- Do not invent pricing — say "Please contact the resort for current pricing."
- Do not make reservations — say "I can help with information, but please reach out to our team to confirm bookings."

Resort facts:
- Location: Pokhara, Nepal (30 min from Pokhara International Airport)
- Room types: Deluxe Rooms, Suite Rooms, Premium Villas, Wellness Suites
- Wellness: daily yoga, meditation sessions, Ayurvedic spa, detox programs
- Dining: multi-cuisine restaurant, rooftop bar, organic café
- Check-in: 2 PM, Check-out: 12 PM
`;

What Surprised Me

Guests ask weird questions.

I expected "What are your room rates?" and "Is there airport pickup?"

What I got:

  • "Can I bring my own yoga mat?"
  • "Do you have gluten-free options?"
  • "Is the WiFi fast enough for Zoom calls?"
  • "Can I celebrate my anniversary there?"
  • "What's the altitude? I get altitude sickness."

The bot handled all of them well because the system prompt included enough context. But I had to iterate on it more than I expected. The first version was too rigid. Version two was too permissive and started answering general travel questions about Nepal (which is fine, but not the bot's job). Version three found a balance.

Streaming was harder than I thought.

I wanted the chatbot to stream responses character-by-character like ChatGPT. Getting SSE (Server-Sent Events) right with Next.js edge runtime took a few tries. The key was using the stream: true option on OpenAI's API and piping the response through a readable stream.

javascript
// Simplified streaming handler
const response = await openai.chat.completions.create({
  model: 'gpt-4',
  messages,
  stream: true,
});

const stream = new ReadableStream({
  async start(controller) {
    for await (const chunk of response) {
      const text = chunk.choices[0]?.delta?.content || '';
      if (text) {
        controller.enqueue(new TextEncoder().encode(text));
      }
    }
    controller.close();
  },
});

return new Response(stream, {
  headers: {
    'Content-Type': 'text/event-stream',
    'Cache-Control': 'no-cache',
  },
});

Mistakes I Made

1. No rate limiting on day one.

The first day I deployed it, someone (probably me testing) sent 200 requests in an hour. The bill was a wake-up call. I added per-IP rate limiting using a simple in-memory map with TTL. For production, I'd move this to Redis or DynamoDB.

javascript
const rateLimit = new Map();

function checkRateLimit(ip: string): boolean {
  const now = Date.now();
  const windowMs = 60 * 1000; // 1 minute
  const maxRequests = 10;

  const timestamps = rateLimit.get(ip) || [];
  const recent = timestamps.filter((t: number) => now - t < windowMs);

  if (recent.length >= maxRequests) return false;

  recent.push(now);
  rateLimit.set(ip, recent);
  return true;
}

2. Not logging conversations.

For the first week, I had zero visibility into what guests were asking. I added logging (anonymized) to a simple database so I could see which questions were common and improve the system prompt. This also helped identify edge cases.

3. Over-engineering the UI.

I spent two days building a fancy chat widget with animations, typing indicators, and message bubbles. The resort owner asked: "Can I just make the input box bigger?" Two-hour fix. The UI lesson stuck.


Cost Considerations

Running GPT-4 for a resort chatbot is surprisingly cheap if you control it properly.

  • Average conversation: 3-5 messages
  • Cost per conversation: roughly $0.02 - $0.05
  • At 100 conversations/month: $2 - $5

The real cost wasn't API calls. It was the development time figuring out prompt engineering and edge cases.

If you're deploying something similar, start with GPT-3.5-turbo for the first month. It's cheaper and fast enough for most use cases. Then upgrade to GPT-4 for the final polish. Or use Claude if you want a model that follows formatting instructions better.


Security Considerations

  • The API key lives in environment variables, never exposed to the client
  • The chat widget only hits my API route — the OpenAI key is server-side only
  • Rate limiting prevents abuse
  • Content filtering in the system prompt prevents the bot from going off-topic
  • No user data is stored long-term (we log anonymized conversations for improvement)

Future Improvements

What I'd build next:

  • Conversation memory using Redis to maintain context across sessions
  • Human handoff — when the bot can't answer, route to a real person
  • Multilingual support — the resort gets international guests
  • Booking integration — let the bot check availability and initiate bookings
  • Voice interface — guests could speak their questions on mobile

I'm experimenting with AWS Bedrock as an alternative to OpenAI. The main reason is data residency — for a Nepalese resort, keeping data within AWS regions might become important. Bedrock also offers models from Anthropic and Meta that work well for this use case.


What I'd Do Differently

Start simpler. I should have launched with a basic Q&A bot using a curated FAQ list before jumping to GPT-4. The simpler version would have validated demand and uncovered the most common questions faster.

Also — I'd add a feedback button ("Was this helpful?") from day one. We added it later and the data was eye-opening. Some responses looked good to me but confused actual guests.


What Readers Should Try

If you're building anything with LLMs in production:

  1. Ship the dumbest version first. Copy-paste FAQs into a prompt. See if people even use it.
  2. Log everything (anonymized). The questions real users ask will surprise you.
  3. Rate limit from day one. Your wallet will thank you.
  4. System prompts matter more than model choice. A well-prompted GPT-3.5 beats a poorly prompted GPT-4.

I'd love feedback from anyone who's built something similar. What surprised you about production LLMs? What did users ask that you never expected?