embed786 commited on
Commit
7e4cf1d
·
verified ·
1 Parent(s): e46b545

Update app.py

Browse files
Files changed (1) hide show
  1. app.py +4 -414
app.py CHANGED
@@ -1,413 +1,3 @@
1
- # import streamlit as st
2
- # from datetime import date
3
- # from streamlit.components.v1 import html as st_html
4
-
5
- # from planmate import utils
6
- # from planmate.config import APP_TITLE, APP_TAGLINE, THEME, CURRENCY
7
- # from planmate.flights import search_flights
8
- # from planmate.weather import summarize_forecast_for_range, geocode_city
9
- # from planmate.attractions import get_attractions_and_stays
10
- # from planmate.llm import rank_accommodations, resolve_city_to_iata_ai
11
- # from planmate.itinerary import build_itinerary
12
-
13
- # st.set_page_config(page_title=APP_TITLE, page_icon="✈️", layout="wide")
14
-
15
- # # ---------- Styles ----------
16
- # st.markdown(
17
- # f"""
18
- # <style>
19
- # html, body, [class*="block-container"] {{
20
- # color: {THEME['text']};
21
- # background-color: {THEME['bg']};
22
- # }}
23
- # .label {{
24
- # color: {THEME['label']};
25
- # font-weight: 600;
26
- # }}
27
- # .card {{
28
- # border: 1px solid {THEME['border']};
29
- # border-radius: 10px;
30
- # padding: 12px;
31
- # margin-bottom: 10px;
32
- # background: #ffffff;
33
- # }}
34
- # .btn-primary {{
35
- # background: {THEME['label']};
36
- # color: white;
37
- # border: none;
38
- # padding: 8px 12px;
39
- # border-radius: 8px;
40
- # }}
41
- # hr {{
42
- # border-top: 1px solid {THEME['border']};
43
- # opacity: 0.2;
44
- # }}
45
- # </style>
46
- # """,
47
- # unsafe_allow_html=True,
48
- # )
49
-
50
- # # ---------- Header ----------
51
- # colH1, colH2 = st.columns([0.8, 0.2])
52
- # with colH1:
53
- # st.title(APP_TITLE)
54
- # st.caption(APP_TAGLINE)
55
- # with colH2:
56
- # if st.button("🔁 Start over", use_container_width=True):
57
- # for k in list(st.session_state.keys()):
58
- # del st.session_state[k]
59
- # st.rerun()
60
-
61
- # # ---------- Sidebar Inputs ----------
62
- # with st.sidebar:
63
- # st.subheader("Trip Basics")
64
- # src_city = st.text_input("Source City", value="Lahore")
65
- # dst_city = st.text_input("Destination City", value="Dubai")
66
- # start_date = st.date_input("Start Date", value=date.today())
67
- # num_days = st.number_input("Number of Days", min_value=1, max_value=30, value=5, step=1)
68
- # adults = st.number_input("Adults", min_value=1, max_value=9, value=1, step=1)
69
- # non_stop = st.checkbox("Non-stop only", value=False)
70
-
71
- # advanced = st.expander("Advanced (optional): Override IATA codes returned by AI")
72
- # with advanced:
73
- # override_origin = st.text_input("Origin IATA (optional)")
74
- # override_dest = st.text_input("Destination IATA (optional)")
75
-
76
- # go = st.button("Plan my trip", type="primary")
77
-
78
-
79
- # # ---------- Helpers ----------
80
- # def set_planned(**kwargs):
81
- # """Persist a 'planned' flag and any key/value to session."""
82
- # st.session_state.planned = True
83
- # for k, v in kwargs.items():
84
- # st.session_state[k] = v
85
-
86
-
87
- # def not_planned():
88
- # return not st.session_state.get("planned", False)
89
-
90
-
91
- # def scroll_to(target_id: str):
92
- # """
93
- # Smooth-scroll to a section with the given DOM id.
94
- # Uses a short delay so the element exists in the DOM on rerun.
95
- # """
96
- # st_html(
97
- # f"""
98
- # <script>
99
- # setTimeout(function() {{
100
- # const el = parent.document.getElementById("{target_id}");
101
- # if (el) el.scrollIntoView({{ behavior: "smooth", block: "start" }});
102
- # }}, 120);
103
- # </script>
104
- # """,
105
- # height=0,
106
- # )
107
-
108
-
109
- # # flight panel visibility toggle
110
- # if "show_flights" not in st.session_state:
111
- # st.session_state.show_flights = False
112
-
113
-
114
- # # ---------- First click: plan & fetch flights ----------
115
- # if go:
116
- # # Country hints (optional) to improve AI IATA mapping
117
- # src_country = None
118
- # dst_country = None
119
- # try:
120
- # src_country = geocode_city(src_city).get("country")
121
- # except Exception:
122
- # pass
123
- # try:
124
- # dst_country = geocode_city(dst_city).get("country")
125
- # except Exception:
126
- # pass
127
-
128
- # # Resolve to IATA via AI, with optional overrides
129
- # try:
130
- # if override_origin.strip():
131
- # origin_code, origin_label, origin_kind = (
132
- # override_origin.strip().upper(),
133
- # f"(override) {override_origin.strip().upper()}",
134
- # "OVERRIDE",
135
- # )
136
- # else:
137
- # code, name, kind = resolve_city_to_iata_ai(src_city, src_country)
138
- # origin_code, origin_label, origin_kind = code, f"{name} ({code})", kind
139
-
140
- # #if code == "":
141
- # # st.error(f"AI could not find a valid IATA code for the source city: {src_city}")
142
- # # pass
143
- # if override_dest.strip():
144
- # dest_code, dest_label, dest_kind = (
145
- # override_dest.strip().upper(),
146
- # f"(override) {override_dest.strip().upper()}",
147
- # "OVERRIDE",
148
- # )
149
- # else:
150
- # code, name, kind = resolve_city_to_iata_ai(dst_city, dst_country)
151
- # dest_code, dest_label, dest_kind = code, f"{name} ({code})", kind
152
-
153
- # #if code == "":
154
- # # st.error(f"AI could not find a valid IATA code for the destination city: {dst_city}")
155
- # # pass
156
- # # st.write(f"Resolved IATA codes: {dest_code} {dest_label} {dest_kind}, {origin_code} {origin_label} {origin_kind}")
157
- # except Exception as e:
158
- # st.error(f"Either city was not found or it does not have an airport")
159
- # st.stop()
160
-
161
- # # Compute return date
162
- # ret_date = utils.compute_return_date(start_date, int(num_days))
163
-
164
- # # Fetch flights once and store
165
- # try:
166
- # with st.spinner("Searching flights (Amadeus Sandbox)..."):
167
- # flights = search_flights(
168
- # origin_code,
169
- # dest_code,
170
- # utils.to_iso(start_date),
171
- # utils.to_iso(ret_date),
172
- # int(adults),
173
- # CURRENCY,
174
- # non_stop=non_stop,
175
- # )
176
- # except Exception as e:
177
- # st.error(f"Flight search failed: {e}")
178
- # st.stop()
179
-
180
- # set_planned(
181
- # src_city=src_city,
182
- # dst_city=dst_city,
183
- # start_date=start_date,
184
- # num_days=int(num_days),
185
- # adults=int(adults),
186
- # non_stop=bool(non_stop),
187
- # origin_code=origin_code,
188
- # origin_label=origin_label,
189
- # origin_kind=origin_kind,
190
- # dest_code=dest_code,
191
- # dest_label=dest_label,
192
- # dest_kind=dest_kind,
193
- # ret_date=ret_date,
194
- # flights=flights,
195
- # flight_idx=None, # not selected yet
196
- # show_flights=True, # show list now
197
- # weather=None,
198
- # pois=None,
199
- # selected_stay=None,
200
- # itinerary_md=None,
201
- # scroll_target=None,
202
- # )
203
-
204
- # # ---------- Render results if we have a planned trip ----------
205
- # if not_planned():
206
- # st.info("Fill the details in the sidebar and click **Plan my trip** to get started.")
207
- # st.stop()
208
-
209
- # # Banner for resolved IATA
210
- # st.success(
211
- # f"Resolved by AI: **{st.session_state.src_city} → {st.session_state.origin_label} "
212
- # f"[{st.session_state.origin_kind}]**, "
213
- # f"**{st.session_state.dst_city} → {st.session_state.dest_label} "
214
- # f"[{st.session_state.dest_kind}]**"
215
- # )
216
-
217
- # # ---------- Flights ----------
218
- # st.markdown("---")
219
- # st.markdown('<div id="section-flights"></div>', unsafe_allow_html=True)
220
- # st.subheader("✈️ Flight Options")
221
-
222
- # fl = st.session_state.get("flights", {"flights": []})
223
-
224
- # # If user has selected a flight, show a compact summary (panel hidden)
225
- # if st.session_state.get("flight_idx") is not None:
226
- # sel_offer = fl["flights"][st.session_state.flight_idx]
227
- # with st.container():
228
- # st.markdown('<div class="card">', unsafe_allow_html=True)
229
- # st.write(f"**Selected Flight** — {sel_offer['price_label']}")
230
- # for leg_i, segs in enumerate(sel_offer["legs"]):
231
- # st.write(f"_Leg {leg_i+1}_")
232
- # for s in segs:
233
- # st.write(
234
- # f"- {s['from']} → {s['to']} | {s['dep']} → {s['arr']} | {s['carrier']} {s['number']}"
235
- # )
236
- # # Allow changing selection (re-open list, clear downstream steps)
237
- # if st.button("Change flight"):
238
- # st.session_state.flight_idx = None
239
- # st.session_state.show_flights = True
240
- # st.session_state.weather = None
241
- # st.session_state.pois = None
242
- # st.session_state.itinerary_md = None
243
- # # optional: scroll back to flights list
244
- # st.session_state.scroll_target = "section-flights"
245
- # st.rerun()
246
- # st.markdown("</div>", unsafe_allow_html=True)
247
-
248
- # else:
249
- # if not fl.get("flights"):
250
- # st.warning("No flight offers found for the selected dates/route. Try different dates or cities.")
251
- # else:
252
- # if st.session_state.get("show_flights", True):
253
- # for idx, offer in enumerate(fl["flights"][:10]):
254
- # with st.container():
255
- # st.markdown('<div class="card">', unsafe_allow_html=True)
256
- # st.write(f"**Option {idx+1} — {offer['price_label']}**")
257
- # for leg_i, segs in enumerate(offer["legs"]):
258
- # st.write(f"_Leg {leg_i+1}_")
259
- # for s in segs:
260
- # st.write(
261
- # f"- {s['from']} → {s['to']} | {s['dep']} → {s['arr']} | {s['carrier']} {s['number']}"
262
- # )
263
- # if st.button("Select this flight", key=f"select-flight-{idx}"):
264
- # # store selection, hide the panel, clear downstream (so they refresh for the chosen flight)
265
- # st.session_state.flight_idx = idx
266
- # st.session_state.show_flights = False
267
- # st.session_state.weather = None
268
- # st.session_state.pois = None
269
- # st.session_state.itinerary_md = None
270
-
271
- # # ➜ tell the next render to scroll to the Weather section
272
- # st.session_state.scroll_target = "section-weather"
273
-
274
- # st.rerun()
275
- # st.markdown("</div>", unsafe_allow_html=True)
276
- # else:
277
- # # Safety net: if hidden but nothing is selected, show a reopen button
278
- # if st.button("Show flight options"):
279
- # st.session_state.show_flights = True
280
- # st.rerun()
281
-
282
- # # Gate further steps until a flight is selected
283
- # if st.session_state.get("flight_idx") is None:
284
- # st.info("Select a flight to proceed to weather, attractions, and itinerary.")
285
- # # Perform any pending scroll (unlikely here, but safe)
286
- # if st.session_state.get("scroll_target"):
287
- # scroll_to(st.session_state["scroll_target"])
288
- # st.session_state["scroll_target"] = None
289
- # st.stop()
290
-
291
- # # ---------- Weather ----------
292
- # st.markdown("---")
293
- # st.markdown('<div id="section-weather"></div>', unsafe_allow_html=True)
294
- # st.subheader("🌦️ Weather During Your Dates")
295
- # if st.session_state.weather is None:
296
- # try:
297
- # with st.spinner("Fetching weather..."):
298
- # st.session_state.weather = summarize_forecast_for_range(
299
- # st.session_state.dst_city, st.session_state.start_date, st.session_state.num_days
300
- # )
301
- # except Exception as e:
302
- # st.warning(f"Weather unavailable: {e}")
303
- # st.session_state.weather = {"summary_text": "Weather data not available", "daily": []}
304
-
305
- # weather = st.session_state.weather
306
- # if "location" in weather:
307
- # st.success(f"Location: {weather['location'].get('name')}, {weather['location'].get('country')}")
308
- # for r in weather.get("daily", []):
309
- # st.write(f"- **{r['date']}**: {r['desc']} | avg {r['temp_avg']}°C | wind {r['wind']} m/s")
310
-
311
- # # ---------- Attractions & Stays ----------
312
- # st.markdown("---")
313
- # st.markdown('<div id="section-attractions"></div>', unsafe_allow_html=True)
314
- # st.subheader("📍 Attractions & Places to Stay")
315
-
316
- # if st.session_state.pois is None:
317
- # try:
318
- # with st.spinner("Looking up attractions and stays..."):
319
- # loc = geocode_city(st.session_state.dst_city)
320
- # st.session_state.pois = get_attractions_and_stays(lat=loc["lat"], lon=loc["lon"], radius=8000)
321
- # except Exception as e:
322
- # st.error(f"Attractions lookup failed: {e}")
323
- # st.session_state.pois = {"attractions": [], "stays": []}
324
-
325
- # pois = st.session_state.pois
326
- # attractions = pois.get("attractions", [])[:30]
327
- # stays = pois.get("stays", [])[:30]
328
-
329
- # # Select attractions
330
- # st.write("**Top Attractions**")
331
- # selected_attractions = []
332
- # for i, a in enumerate(attractions[:12]):
333
- # colA, colB = st.columns([0.8, 0.2])
334
- # with colA:
335
- # st.write(f"- {a['name']} ({a.get('kinds','')})")
336
- # with colB:
337
- # add = st.checkbox("Add", key=f"attr-{i}")
338
- # if add:
339
- # selected_attractions.append(a)
340
- # if not selected_attractions:
341
- # st.info("Tip: Select at least a few attractions you’d like to include.")
342
-
343
- # # Stays with LLM ranking
344
- # st.write("**Places to Stay (from OpenTripMap, no live prices)**")
345
- # try:
346
- # ranked_stays = rank_accommodations(stays, prefs="central, well-reviewed, convenient")
347
- # except Exception:
348
- # ranked_stays = stays
349
-
350
- # stay_names = [s["name"] for s in ranked_stays[:15]]
351
- # chosen_stay_name = st.selectbox("Pick a place to stay (optional)", options=["(None)"] + stay_names)
352
- # selected_stay = None if chosen_stay_name == "(None)" else next(
353
- # (s for s in ranked_stays if s["name"] == chosen_stay_name), None
354
- # )
355
- # st.session_state.selected_stay = selected_stay
356
-
357
- # # ---------- Review & Booking (Mock) ----------
358
- # st.markdown("---")
359
- # st.markdown('<div id="section-booking"></div>', unsafe_allow_html=True)
360
- # st.subheader("🧾 Review & Booking (Sandbox/Mock)")
361
- # st.write("**Flight Selected**")
362
- # sel_offer = fl["flights"][st.session_state.flight_idx]
363
- # st.write(f"- Total: {sel_offer['price_label']}")
364
- # st.write("**Booking is simulated for MVP (no actual ticketing)**")
365
-
366
- # passenger_name = st.text_input("Passenger Full Name", value="Test User")
367
- # passenger_email = st.text_input("Contact Email", value="test@example.com")
368
- # if st.button("Reserve Flight (Mock)"):
369
- # import uuid
370
-
371
- # pnr = str(uuid.uuid4())[:8].upper()
372
- # st.success(f"Flight reserved (mock). Reference: {pnr}")
373
- # st.session_state.flight_pnr = pnr
374
-
375
- # if st.session_state.selected_stay:
376
- # st.write(f"**Hotel Selected:** {st.session_state.selected_stay['name']} (mock booking)")
377
- # if st.button("Reserve Hotel (Mock)"):
378
- # import uuid
379
-
380
- # hid = str(uuid.uuid4())[:10].upper()
381
- # st.success(f"Hotel reserved (mock). Ref: {hid}")
382
- # st.session_state.hotel_ref = hid
383
-
384
- # # ---------- Itinerary ----------
385
- # st.markdown("---")
386
- # st.markdown('<div id="section-itinerary"></div>', unsafe_allow_html=True)
387
- # st.subheader("🗓️ AI Itinerary")
388
- # if st.button("Generate Itinerary"):
389
- # with st.spinner("AI planning..."):
390
- # try:
391
- # st.session_state.itinerary_md = build_itinerary(
392
- # st.session_state.dst_city,
393
- # utils.to_iso(st.session_state.start_date),
394
- # int(st.session_state.num_days),
395
- # selected_attractions,
396
- # st.session_state.selected_stay,
397
- # weather.get("summary_text", ""),
398
- # )
399
- # # Optionally scroll to itinerary when generated
400
- # st.session_state.scroll_target = "section-itinerary"
401
- # except Exception as e:
402
- # st.error(f"Itinerary generation failed: {e}")
403
-
404
- # if st.session_state.get("itinerary_md"):
405
- # st.markdown(st.session_state.itinerary_md)
406
-
407
- # # ---------- Final: perform any pending scroll ----------
408
- # if st.session_state.get("scroll_target"):
409
- # scroll_to(st.session_state["scroll_target"])
410
-
411
  import streamlit as st
412
  from datetime import date
413
  from streamlit.components.v1 import html as st_html
@@ -846,10 +436,10 @@ with st.sidebar:
846
  with col4:
847
  non_stop = st.checkbox("✈️ Non-stop", value=False, help="Direct flights only")
848
 
849
- # with st.expander("⚙️ Advanced Options", expanded=False):
850
- # st.markdown("*Override AI-suggested airport codes*")
851
- # override_origin = st.text_input("Origin IATA Code", placeholder="e.g., LHE", help="Optional: Force specific origin airport")
852
- # override_dest = st.text_input("Destination IATA Code", placeholder="e.g., DXB", help="Optional: Force specific destination airport")
853
 
854
  st.markdown("---")
855
  go = st.button("🚀 Plan My Trip", type="primary", use_container_width=True)
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
  import streamlit as st
2
  from datetime import date
3
  from streamlit.components.v1 import html as st_html
 
436
  with col4:
437
  non_stop = st.checkbox("✈️ Non-stop", value=False, help="Direct flights only")
438
 
439
+ with st.expander("⚙️ Advanced Options", expanded=False):
440
+ st.markdown("*Override AI-suggested airport codes*")
441
+ override_origin = st.text_input("Origin IATA Code", placeholder="e.g., LHE", help="Optional: Force specific origin airport")
442
+ override_dest = st.text_input("Destination IATA Code", placeholder="e.g., DXB", help="Optional: Force specific destination airport")
443
 
444
  st.markdown("---")
445
  go = st.button("🚀 Plan My Trip", type="primary", use_container_width=True)