Intro:

We tackled the Skyscanner challenge and took it one step further by integrating a chatbot in the flight finder webpage that takes live feedback from the users and updates the recommandations accordingly

Building:

Core logic in Python

travel_planner.py contains the orchestration: gathering inputs, calling the flight data layer, computing normalized scores, and ranking destinations.

test_preferences.py provides unit coverage for the preference math.

Flight data layer

A mock data generator simulates realistic costs, durations, and CO₂ based on airport-to-airport distances.

Skyscanner API integration stubs are isolated so switching to real API calls only requires toggling mock_api=False.

Web interface with Flask

app.py defines minimal routes (/ for input form, /results for rendering output).

Jinja2 templates and simple HTML/CSS/JS sliders allow users to rate cities and adjust weighting without modifying code.

Concurrency

Used concurrent.futures.ThreadPoolExecutor to fetch or simulate each route in parallel, dramatically improving response time for multi-origin groups.

Challenges we ran into

Mock data realism: Crafting a mock flight generator that “feels” real required approximating distances, airline price ranges, and availability unpredictability.

Preference normalization: Merging star-ratings (1–5) with avoid-lists and mapping them into a continuous 0–1 score exposed edge cases (e.g., all destinations rated equally or everyone avoiding too many cities).

Thread-safety in Flask: Storing intermediate preference state in globals caused race conditions under concurrent requests. We refactored into request-scoped data structures.

Balancing UX and logic: Keeping the web form simple (just upload travelers + sliders) while still exposing advanced configuration (weights, mock vs. real API) led to several iterations of the template.

Accomplishments that we're proud of

End-to-end flow in a weekend hack: From form to ranked results, the core planner was up and running in under 48 hours.

Modular mock API design: Isolating all external data interactions means we can swap in a real Skyscanner key without touching ranking logic.

Interactive weighting UI: Users can instantly see how shifting emphasis between cost, emissions, and taste affects recommendations.

Unit tests for preference math: Ensured our normalization and scoring algorithms behave correctly on edge cases.

What we learned

Python concurrency pitfalls: Discovered the importance of request-local state in Flask and thread-safe data handling.

Rapid prototyping with Flask: How to wire up a quick form + results page and deploy on port 8080 with minimal ceremony.

Importance of clear abstractions: Separating flights, preferences, and web logic into distinct modules made later refactors much easier.

What's next for the travel assistant

Skyscanner API integration for live pricing and real-time availability.

Connecting-flights support and layover duration handling.

Booking and hotel API hooks to let users reserve directly from results.

Map visualization (Google Maps or Leaflet) showing meeting points geographically.

Enhanced preference system with group chat suggestions (via ChatGPT) and social sharing.

Persistent user profiles and session saving so travelers can revisit past plans.

Mobile-friendly UI or a lightweight React frontend for on-the-go planning.

Share this project:

Updates