Roles & Stack
Impact
- Context-aware travel recommendations
- Multi-turn conversation support
- Personalized itinerary suggestions
- Local insights and cultural tips
Year
2025
Category
AI & Machine Learning
Deliverables
- Conversational AI System
- OpenAI API Integration
- Travel Knowledge Prompt Engineering
- Interactive Jupyter Demo
The Situation: Static Travel Resources
Travelers planning a trip to Paris face information overload: thousands of blog posts, outdated guidebooks, and generic recommendations that don't account for personal preferences. Finding authentic local experiences requires hours of research.
The opportunity was to create an interactive AI assistant that could answer travel questions naturally, provide personalized recommendations, and adapt to each user's interests—whether they're foodies, art lovers, or adventure seekers.
The Problem: Generic AI Doesn't Feel Local
A basic ChatGPT query about Paris returns generic tourist information. The challenge was engineering a system that feels like talking to a knowledgeable local friend—someone who knows the best croissants in Le Marais, the optimal museum visiting times, and the neighborhoods tourists should avoid.
The key problems to solve: establishing a consistent persona, injecting domain-specific knowledge, and maintaining context across a multi-turn conversation.
The Solution: Persona-Based Prompt Engineering
I designed a system prompt that establishes the AI as a Parisian local with specific personality traits and deep knowledge of the city. The prompt includes instructions for conversational style, areas of expertise, and how to handle different types of queries.
The persona approach creates a more engaging experience than generic Q&A, making travelers feel like they have a personal guide rather than a search engine.
System Prompt: Creating Marie
The system prompt establishes 'Marie', a lifelong Parisian art curator, as the AI persona. The prompt defines her expertise areas, communication style, and behavioral guidelines:
| 1 | import openai |
| 2 | from typing import List, Dict |
| 3 | |
| 4 | SYSTEM_PROMPT = """ |
| 5 | You are Marie, a lifelong Parisian who works as an art curator |
| 6 | at the Musée d'Orsay. You are 34 years old and have lived in |
| 7 | Paris your entire life. |
| 8 | |
| 9 | Your areas of expertise: |
| 10 | - Hidden cafés and restaurants that locals love |
| 11 | - Art history and optimal museum visiting strategies |
| 12 | - Neighborhood personalities, safety tips, and Metro navigation |
| 13 | - Seasonal events, local customs, and French etiquette |
| 14 | - Shopping areas: both luxury and vintage finds |
| 15 | |
| 16 | Communication style: |
| 17 | - Speak warmly but directly, like a friend giving advice |
| 18 | - Use occasional French phrases naturally (with translations) |
| 19 | - Always ask a follow-up question to understand preferences better |
| 20 | - Avoid tourist traps unless specifically asked about them |
| 21 | - Share personal anecdotes when relevant |
| 22 | """ |
Conversation Engine: Context Management
The core function maintains conversation history to enable multi-turn dialogues. Each exchange is stored and passed back to the API, allowing Marie to reference earlier parts of the conversation:
| 1 | def get_travel_advice( |
| 2 | conversation_history: List[Dict[str, str]], |
| 3 | user_message: str |
| 4 | ) -> str: |
| 5 | """Get personalized Paris travel advice from Marie.""" |
| 6 | |
| 7 | # Build messages with system prompt + history + new message |
| 8 | messages = [{"role": "system", "content": SYSTEM_PROMPT}] |
| 9 | messages.extend(conversation_history) |
| 10 | messages.append({"role": "user", "content": user_message}) |
| 11 | |
| 12 | response = openai.chat.completions.create( |
| 13 | model="gpt-4o-mini", |
| 14 | messages=messages, |
| 15 | temperature=0.8, # Higher creativity for engaging conversation |
| 16 | max_tokens=500 |
| 17 | ) |
| 18 | |
| 19 | assistant_reply = response.choices[0].message.content |
| 20 | |
| 21 | # Update history for next turn |
| 22 | conversation_history.append({"role": "user", "content": user_message}) |
| 23 | conversation_history.append({"role": "assistant", "content": assistant_reply}) |
| 24 | |
| 25 | return assistant_reply |
Interactive Demo: Chat Session
The interactive demo allows users to have natural conversations with Marie. Here's an example session showing the contextual understanding:
| 1 | # Initialize conversation |
| 2 | history = [] |
| 3 | |
| 4 | # First question |
| 5 | print("You: What's the best area to stay for a first visit?") |
| 6 | response = get_travel_advice(history, "What's the best area to stay for a first visit?") |
| 7 | print(f"Marie: {response}") |
| 8 | |
| 9 | # Follow-up (Marie remembers context) |
| 10 | print("\nYou: I'm mostly interested in art and good food.") |
| 11 | response = get_travel_advice(history, "I'm mostly interested in art and good food.") |
| 12 | print(f"Marie: {response}") |
| 13 | |
| 14 | # Another follow-up |
| 15 | print("\nYou: What about your favorite café nearby?") |
| 16 | response = get_travel_advice(history, "What about your favorite café nearby?") |
| 17 | print(f"Marie: {response}") |
| 18 | |
| 19 | print(f"\n[Conversation length: {len(history)} messages]") |
Impact & Future Roadmap
The travel guide demonstrates that effective AI assistants require careful prompt engineering, not just raw model capability. The persona approach creates a more engaging experience than generic Q&A.
Future iterations could include: integration with booking APIs for real-time availability, map visualizations for recommended routes, and expansion to other cities using the same modular architecture. The Marie persona could also be fine-tuned with user feedback to improve recommendation quality over time.
Gallery
Process visuals
Explore next
E-commerce Review Analysis with Text Embeddings
A data science project that applies OpenAI text embeddings and t-SNE dimensionality reduction to analyze and visualize customer reviews from a women's clothing e-commerce dataset. The system processes 23,000+ reviews, converts them to vector embeddings, and reveals hidden sentiment clusters through interactive 2D visualization.