Personal project · live demo

Jexa

An AI travel planner that only plans with places that exist. Real places from the Google Places API go into the prompt as context.

Problem

Language models asked for a travel plan tend to invent restaurants and sights. A plan with places that don't exist is useless on the ground.

Solution

Context injection instead of a cleverer prompt. For each destination, Jexa first fetches real attractions, restaurants and cafés from the Google Places API, for all cities in parallel. These places go into the prompt as a list of verified places, with the rule to use only those. The model returns the itinerary as strict JSON, which the app turns into an interactive day-by-day plan.

  • Up to 6 destinations. Days are split evenly across the cities.
  • Groq API with Llama 4 Scout. If that call fails, the same request goes to Qwen 3 32B.
  • Places results are cached for 24 hours to save API calls.
  • The prompt treats special needs such as halal, vegan or wheelchair access as non-negotiable constraints.
  • Costs are shown in local and home currency and marked as estimates.
  • If the APIs are not available, Jexa returns a simple template plan instead of an error.
  • In the browser: check off activities, replan with one click, copy, download or print the plan.
Condensed from tools/jexa.py
# Models: primary and fallback
GROQ_MODEL_PRIMARY = "meta-llama/llama-4-scout-17b-16e-instruct"
GROQ_MODEL_BACKUP = "qwen/qwen3-32b"

# Real places for all cities, fetched in parallel
results = await asyncio.gather(*[
    gather_real_places(city, preferences, must_visit, must_eat)
    for city in formatted_destinations
])

# First rule in the prompt
"1. Use ONLY the VERIFIED PLACES provided below. Do NOT invent new places."

# Try primary model first, then backup
for model in [GROQ_MODEL_PRIMARY, GROQ_MODEL_BACKUP]:
    response = await client.post(url, headers=headers, json=payload)
    if response.status_code == 200:
        return response.json()["choices"][0]["message"]["content"]

Stack

  • Python
  • FastAPI
  • httpx (async)
  • Google Places API
  • Groq API
  • Llama 4 Scout
  • Qwen 3 32B (fallback)
  • JavaScript
  • Docker
  • Railway

Result

Generates a multi-day itinerary with real, existing places in under a minute.

My role

Concept, development and deployment.

What I learned

Constraining the model with real data beats better prompting. Once Jexa only planned with places from the Google Places API, the model had far less room to invent locations. The second lesson was reliability: if the primary model call fails, the same request goes to a fallback model, and if both fail, the user still gets a simple template plan instead of an error.