sonuprasad23 commited on
Commit
5dd9976
·
1 Parent(s): 711e833

Added the files

Browse files
Files changed (4) hide show
  1. Dockerfile +18 -0
  2. README.md +0 -2
  3. main.py +196 -0
  4. requirements.txt +6 -0
Dockerfile ADDED
@@ -0,0 +1,18 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ # Use an official Python runtime as a parent image
2
+ FROM python:3.11-slim
3
+
4
+ # Set the working directory in the container
5
+ WORKDIR /code
6
+
7
+ # Copy the requirements file into the container at /code
8
+ COPY ./requirements.txt /code/requirements.txt
9
+
10
+ # Install any needed packages specified in requirements.txt
11
+ RUN pip install --no-cache-dir --upgrade -r /code/requirements.txt
12
+
13
+ # Copy the rest of the application's code into the container at /code
14
+ COPY . /code/
15
+
16
+ # Tell uvicorn to run on all available network interfaces (0.0.0.0)
17
+ # and on the port Hugging Face Spaces expects (7860).
18
+ CMD ["uvicorn", "main:app", "--host", "0.0.0.0", "--port", "7860"]
README.md CHANGED
@@ -7,5 +7,3 @@ sdk: docker
7
  pinned: false
8
  license: apache-2.0
9
  ---
10
-
11
- Check out the configuration reference at https://huggingface.co/docs/hub/spaces-config-reference
 
7
  pinned: false
8
  license: apache-2.0
9
  ---
 
 
main.py ADDED
@@ -0,0 +1,196 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ from fastapi import FastAPI, HTTPException, Query
2
+ from fastapi.middleware.cors import CORSMiddleware
3
+ import requests
4
+ import pandas as pd
5
+ from datetime import datetime
6
+ import google.generativeai as genai
7
+ import os
8
+ from dotenv import load_dotenv
9
+
10
+ load_dotenv()
11
+ app = FastAPI()
12
+
13
+ origins = ["*"]
14
+
15
+ app.add_middleware(
16
+ CORSMiddleware,
17
+ allow_origins=origins,
18
+ allow_credentials=True,
19
+ allow_methods=["*"],
20
+ allow_headers=["*"],
21
+ )
22
+
23
+ FLIGHT_API_KEY = os.getenv("FLIGHT_API_KEY")
24
+ GEMINI_API_KEY = os.getenv("GEMINI_API_KEY")
25
+
26
+ # print(f"--- DEBUG: Loaded Gemini Key: {GEMINI_API_KEY} ---")
27
+ if GEMINI_API_KEY:
28
+ try:
29
+ genai.configure(api_key=GEMINI_API_KEY)
30
+ except Exception as e:
31
+ print(f"Could not configure Gemini API: {e}")
32
+
33
+
34
+ AUSTRALIAN_CITY_CODES = {
35
+ "Sydney": "SYD", "Melbourne": "MEL", "Brisbane": "BNE", "Perth": "PER",
36
+ "Adelaide": "ADL", "Canberra": "CBR", "Gold Coast": "OOL", "Cairns": "CNS",
37
+ "Hobart": "HBA", "Darwin": "DRW"
38
+ }
39
+
40
+ def fetch_flight_data(api_key, departure_airport, arrival_airport, date_str):
41
+ url = f"https://api.flightapi.io/onewaytrip/{api_key}/{departure_airport}/{arrival_airport}/{date_str}/1/0/0/Economy/AUD"
42
+ try:
43
+ response = requests.get(url, timeout=30)
44
+ response.raise_for_status()
45
+ return response.json()
46
+ except requests.exceptions.RequestException as e:
47
+ print(f"Error fetching flight data: {e}")
48
+ return None
49
+
50
+ def parse_and_process_data(data, origin_code, dest_code, search_date):
51
+ if not data or 'itineraries' not in data:
52
+ return pd.DataFrame()
53
+
54
+ carriers = {c['id']: c for c in data.get('carriers', [])}
55
+ places = {p['id']: p['name'] for p in data.get('places', [])}
56
+
57
+ flight_options = []
58
+
59
+ if not data.get('itineraries'):
60
+ return pd.DataFrame()
61
+
62
+ for i, itinerary in enumerate(data.get('itineraries', [])):
63
+ if not itinerary.get('pricing_options'):
64
+ continue
65
+
66
+ price_info = itinerary['pricing_options'][0].get('price', {})
67
+ price = price_info.get('amount')
68
+
69
+ if not itinerary.get('leg_ids'):
70
+ continue
71
+
72
+ leg_id = itinerary['leg_ids'][0]
73
+ leg = next((l for l in data.get('legs', []) if l['id'] == leg_id), None)
74
+
75
+ if not leg or not price:
76
+ continue
77
+
78
+ marketing_carrier_id = leg.get('marketing_carrier_ids', [None])[0]
79
+ carrier_info = carriers.get(marketing_carrier_id, {})
80
+ airline_name = carrier_info.get('name', "Unknown Airline")
81
+
82
+ flight_number = "N/A"
83
+ if leg.get('segment_ids'):
84
+ segment_id = leg['segment_ids'][0]
85
+ segment = next((s for s in data.get('segments', []) if s['id'] == segment_id), None)
86
+ if segment:
87
+ carrier_code = carrier_info.get('code', "XX")
88
+ flight_num_part = segment.get('marketing_flight_number', leg['id'][:3])
89
+ flight_number = f"{carrier_code}{flight_num_part}"
90
+
91
+ flight_options.append({
92
+ "id": i,
93
+ "airline": airline_name,
94
+ "flight": flight_number,
95
+ "departure": pd.to_datetime(leg['departure']).strftime('%H:%M'),
96
+ "arrival": pd.to_datetime(leg['arrival']).strftime('%H:%M'),
97
+ "price": price
98
+ })
99
+
100
+ if not flight_options:
101
+ return pd.DataFrame()
102
+
103
+ df = pd.DataFrame(flight_options)
104
+ return df.sort_values(by="price").reset_index(drop=True)
105
+
106
+
107
+ def get_ai_insights(df, origin, destination, date):
108
+ if df.empty:
109
+ return "No flight data was available to analyze."
110
+
111
+ if not GEMINI_API_KEY:
112
+ return "**AI Analysis Skipped:** Gemini API key not configured on the backend."
113
+
114
+ summary_df = df.head(10)
115
+ data_summary = f"""
116
+ Flight Price Data Summary:
117
+ - Route: {origin} to {destination}
118
+ - Date: {date}
119
+ - Number of flights found: {len(df)}
120
+ - Cheapest flight: AUD {df['price'].min()} on {df.loc[df['price'].idxmin(), 'airline']}
121
+ - Average price of top 10 cheapest: AUD {summary_df['price'].mean():.2f}
122
+ """
123
+
124
+ prompt = f"""
125
+ You are a market analyst for a chain of Australian hostels. Your goal is to provide a brief, actionable report based on flight data.
126
+
127
+ **Data Provided:**
128
+ {data_summary}
129
+
130
+ **Your Task:**
131
+ Provide a bullet-point summary in Markdown format for a hostel manager. The tone should be concise and professional. Focus on:
132
+ - **Top Insight:** What is the single most important takeaway? (e.g., "The route is highly competitive today, driving prices down.")
133
+ - **Price Trends:** Is it a good day to travel for budget-conscious guests? What is the cheapest price found?
134
+ - **Key Airlines:** Which 1-2 airlines are dominating the budget-friendly options?
135
+ - **Actionable Advice:** Give one concrete recommendation. (e.g., "Target marketing efforts towards customers arriving on Rex or Jetstar flights.")
136
+ """
137
+
138
+ try:
139
+ model = genai.GenerativeModel('gemini-1.5-flash-latest')
140
+ response = model.generate_content(prompt)
141
+ report_header = f"Based on the data for **{origin} to {destination}** on **{date}**, here are the key insights:"
142
+ return f"{report_header}\n\n{response.text}"
143
+ except Exception as e:
144
+ return f"Could not generate AI insights. Error: {e}"
145
+
146
+ @app.get("/api/analyze-demand")
147
+ def analyze_demand(
148
+ origin: str = Query(..., description="Origin city name, e.g., Sydney"),
149
+ destination: str = Query(..., description="Destination city name, e.g., Melbourne"),
150
+ date: str = Query(..., description="Departure date in YYYY-MM-DD format")
151
+ ):
152
+ if not FLIGHT_API_KEY:
153
+ raise HTTPException(status_code=500, detail="Flight API key not configured on the server.")
154
+
155
+ origin_code = AUSTRALIAN_CITY_CODES.get(origin)
156
+ dest_code = AUSTRALIAN_CITY_CODES.get(destination)
157
+
158
+ if not origin_code or not dest_code:
159
+ raise HTTPException(status_code=400, detail="Invalid origin or destination city name.")
160
+
161
+ raw_data = fetch_flight_data(FLIGHT_API_KEY, origin_code, dest_code, date)
162
+ if not raw_data:
163
+ raise HTTPException(status_code=404, detail="No flight data found for the specified route and date.")
164
+
165
+ flight_df = parse_and_process_data(raw_data, origin_code, dest_code, date)
166
+ if flight_df.empty:
167
+ raise HTTPException(status_code=404, detail="No flight options could be parsed for this route.")
168
+
169
+ ai_report = get_ai_insights(flight_df, origin, destination, date)
170
+
171
+ cheapest_flight_row = flight_df.loc[flight_df['price'].idxmin()]
172
+ insight_cards = {
173
+ "cheapestFlight": {
174
+ "price": cheapest_flight_row['price'],
175
+ "airline": cheapest_flight_row['airline'],
176
+ "flightNumber": cheapest_flight_row['flight']
177
+ },
178
+ "busiestAirline": {
179
+ "name": flight_df['airline'].mode()[0],
180
+ "flightCount": len(flight_df)
181
+ },
182
+ "bestDeal": {
183
+ "name": cheapest_flight_row['airline'],
184
+ "savings": "Top Value"
185
+ }
186
+ }
187
+
188
+ chart_data = flight_df.groupby('airline')['price'].min().reset_index()
189
+ chart_data.rename(columns={'airline': 'name', 'price': 'price'}, inplace=True)
190
+
191
+ return {
192
+ "insightCards": insight_cards,
193
+ "aiAnalystReport": ai_report,
194
+ "flightPriceChart": chart_data.to_dict('records'),
195
+ "flightDataTable": flight_df.to_dict('records')
196
+ }
requirements.txt ADDED
@@ -0,0 +1,6 @@
 
 
 
 
 
 
 
1
+ fastapi
2
+ uvicorn[standard]
3
+ python-dotenv
4
+ requests
5
+ pandas
6
+ google-generativeai