IAMTFRMZA commited on
Commit
d5ae19a
Β·
verified Β·
1 Parent(s): 593765d

Update app.py

Browse files
Files changed (1) hide show
  1. app.py +159 -90
app.py CHANGED
@@ -3,109 +3,178 @@ import gspread
3
  import gradio as gr
4
  from oauth2client.service_account import ServiceAccountCredentials
5
  from datetime import datetime
6
- from geopy.distance import geodesic
7
- import folium
8
- from io import BytesIO
9
 
10
- # Google Sheets Auth
 
 
 
 
 
 
 
11
  scope = ["https://spreadsheets.google.com/feeds", "https://www.googleapis.com/auth/drive"]
12
  creds = ServiceAccountCredentials.from_json_keyfile_name("credentials.json", scope)
13
  client = gspread.authorize(creds)
14
  sheet_file = client.open("userAccess")
15
 
16
- # Load Data
17
  def load_tab(sheet_name):
18
  try:
19
  df = pd.DataFrame(sheet_file.worksheet(sheet_name).get_all_records())
20
  return df
21
  except:
22
- return pd.DataFrame(["⚠️ Could not load sheet."], columns=["Error"])
23
-
24
- # GPS calculations
25
- def calculate_gps_data(df):
26
- df = df.sort_values(['Date', 'Time']).reset_index(drop=True)
27
- df[['Latitude', 'Longitude']] = df['Location'].str.split(', ', expand=True).astype(float)
28
-
29
- df['Kms Travelled'] = 0.0
30
- df['Duration Between Calls (min)'] = 0.0
31
-
32
- for i in range(1, len(df)):
33
- prev_coords = (df.at[i-1, 'Latitude'], df.at[i-1, 'Longitude'])
34
- current_coords = (df.at[i, 'Latitude'], df.at[i, 'Longitude'])
35
- df.at[i, 'Kms Travelled'] = geodesic(prev_coords, current_coords).km
36
-
37
- prev_time = pd.to_datetime(df.at[i-1, 'Date'] + ' ' + df.at[i-1, 'Time'])
38
- current_time = pd.to_datetime(df.at[i, 'Date'] + ' ' + df.at[i, 'Time'])
39
- df.at[i, 'Duration Between Calls (min)'] = (current_time - prev_time).total_seconds() / 60.0
40
-
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
41
  return df
42
 
43
- # Load and process Field Sales data
44
- field_sales_df = calculate_gps_data(load_tab("Field Sales"))
45
-
46
- # Map generation
47
- def generate_map(df):
48
- if df.empty or df[['Latitude', 'Longitude']].isna().all().all():
49
- return None
50
-
51
- coords = df[['Latitude', 'Longitude']].dropna().values
52
- map_center = coords[0]
53
- m = folium.Map(location=map_center, zoom_start=12)
54
-
55
- for idx, coord in enumerate(coords):
56
- folium.Marker(location=coord, popup=f"Visit {idx+1}").add_to(m)
57
-
58
- folium.PolyLine(coords, color='blue').add_to(m)
59
-
60
- buf = BytesIO()
61
- m.save(buf, close_file=False)
62
- return buf.getvalue().decode()
63
-
64
- # Gradio Interface
65
  with gr.Blocks() as app:
66
- gr.Markdown("## πŸš— CarMat Dashboard")
67
-
68
- unique_dates = sorted(field_sales_df['Date'].unique(), reverse=True)
69
-
70
- # Field Sales Tab
71
- with gr.Tab("πŸ—ΊοΈ Field Sales"):
72
- date_selector = gr.Dropdown(label="Select Date", choices=unique_dates)
73
- data_output = gr.DataFrame()
74
- map_html = gr.HTML()
75
-
76
- def update_field_sales(date):
77
- day_df = field_sales_df[field_sales_df['Date'] == date]
78
- map_render = generate_map(day_df)
79
- return day_df, map_render
80
-
81
- date_selector.change(fn=update_field_sales, inputs=date_selector, outputs=[data_output, map_html])
82
-
83
- # Summary Tab
84
- with gr.Tab("πŸ“Š Summary"):
85
- date_summary = gr.Dropdown(label="Select Date", choices=unique_dates)
86
- summary_visits = gr.DataFrame()
87
-
88
- def update_summary(date):
89
- day_df = field_sales_df[field_sales_df['Date'] == date]
90
- visits = day_df.groupby("Rep").size().reset_index(name="Total Visits")
91
- return visits
92
-
93
- date_summary.change(fn=update_summary, inputs=date_summary, outputs=summary_visits)
94
-
95
- # Orders Tab
96
- with gr.Tab("πŸ“¦ Orders"):
97
- order_date = gr.Dropdown(label="Select Date", choices=unique_dates)
98
- orders_output = gr.DataFrame()
99
-
100
- def orders_summary(date):
101
- day_df = field_sales_df[field_sales_df['Date'] == date]
102
- orders_df = day_df[day_df["Order Received"] == "Yes"]
103
- summary = orders_df.groupby("Rep").agg({
104
- "Order Value": "sum",
105
- "Order Received": "count"
106
- }).rename(columns={"Order Received": "Orders Count"}).reset_index()
107
- return summary
108
-
109
- order_date.change(fn=orders_summary, inputs=order_date, outputs=orders_output)
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
110
 
111
  app.launch()
 
3
  import gradio as gr
4
  from oauth2client.service_account import ServiceAccountCredentials
5
  from datetime import datetime
 
 
 
6
 
7
+ # ------------------ AUTH ------------------
8
+ VALID_USERS = {
9
+ "[email protected]": "Pass.123",
10
+ "[email protected]": "Pass.123",
11
+ "[email protected]": "Pass.123"
12
+ }
13
+
14
+ # ------------------ GOOGLE SHEET SETUP ------------------
15
  scope = ["https://spreadsheets.google.com/feeds", "https://www.googleapis.com/auth/drive"]
16
  creds = ServiceAccountCredentials.from_json_keyfile_name("credentials.json", scope)
17
  client = gspread.authorize(creds)
18
  sheet_file = client.open("userAccess")
19
 
20
+ # ------------------ HELPERS ------------------
21
  def load_tab(sheet_name):
22
  try:
23
  df = pd.DataFrame(sheet_file.worksheet(sheet_name).get_all_records())
24
  return df
25
  except:
26
+ return pd.DataFrame([["⚠️ Could not load sheet."]], columns=["Error"])
27
+
28
+ def get_combined_orders(date_str):
29
+ df_field = load_tab("Field Sales")
30
+ df_ts = load_tab("TeleSales")
31
+
32
+ combined = []
33
+
34
+ if not df_field.empty:
35
+ df_field['Date'] = pd.to_datetime(df_field['Date'], errors='coerce')
36
+ df_field['DateStr'] = df_field['Date'].dt.date.astype(str)
37
+ df_field = df_field[df_field['DateStr'] == date_str.strip()]
38
+ df_field['Order Value'] = pd.to_numeric(df_field['Order Value'], errors='coerce').fillna(0)
39
+ df_field_orders = df_field.groupby("Rep").agg({
40
+ "Order Received": lambda x: (x == "Yes").sum(),
41
+ "Order Value": "sum"
42
+ }).reset_index().rename(columns={
43
+ "Order Received": "Orders Received",
44
+ "Order Value": "Total Order Value"
45
+ })
46
+ df_field_orders["Source"] = "Field Sales"
47
+ combined.append(df_field_orders)
48
+
49
+ if not df_ts.empty:
50
+ df_ts['Date'] = pd.to_datetime(df_ts['Date'], errors='coerce')
51
+ df_ts['DateStr'] = df_ts['Date'].dt.date.astype(str)
52
+ df_ts = df_ts[df_ts['DateStr'] == date_str.strip()]
53
+ df_ts['Order Value'] = pd.to_numeric(df_ts['Order Value'], errors='coerce').fillna(0)
54
+ df_ts_orders = df_ts.groupby("Rep").agg({
55
+ "Order Received": lambda x: (x == "Yes").sum(),
56
+ "Order Value": "sum"
57
+ }).reset_index().rename(columns={
58
+ "Order Received": "Orders Received",
59
+ "Order Value": "Total Order Value"
60
+ })
61
+ df_ts_orders["Source"] = "TeleSales"
62
+ combined.append(df_ts_orders)
63
+
64
+ if combined:
65
+ return pd.concat(combined, ignore_index=True)
66
+ else:
67
+ return pd.DataFrame([["No orders on this date"]], columns=["Message"])
68
+
69
+ def get_requests():
70
+ df = load_tab("Customer Requests")
71
+ return df if not df.empty else pd.DataFrame([["No requests yet."]], columns=["Message"])
72
+
73
+ def get_listings():
74
+ df = load_tab("CustomerListings")
75
+ return df if not df.empty else pd.DataFrame([["No listings found."]], columns=["Message"])
76
+
77
+ def get_users():
78
+ df = load_tab("Users")
79
+ return df if not df.empty else pd.DataFrame([["No users configured."]], columns=["Message"])
80
+
81
+ def get_telesales_summary():
82
+ df = load_tab("TeleSales")
83
+ if df.empty or "Rep" not in df.columns:
84
+ return pd.DataFrame([["No Telesales data available"]], columns=["Message"])
85
+ return df.groupby("Rep").size().reset_index(name="Total Calls Made")
86
+
87
+ def get_oem_summary():
88
+ df = load_tab("OEM Visit")
89
+ if df.empty or "Rep" not in df.columns:
90
+ return pd.DataFrame([["No OEM data available"]], columns=["Message"])
91
+ return df.groupby("Rep").size().reset_index(name="Total OEM Visits")
92
+
93
+ def get_escalations():
94
+ df = load_tab("Field Sales")
95
+ if df.empty:
96
+ return pd.DataFrame([["No data in Field Sales"]], columns=["Message"])
97
+ col = "Customer Type & Status"
98
+ if col in df.columns:
99
+ flagged = df[df[col].str.contains("Second", na=False)]
100
+ return flagged if not flagged.empty else pd.DataFrame([["No second-hand dealerships flagged."]], columns=["Message"])
101
+ else:
102
+ return pd.DataFrame([["⚠️ Column 'Customer Type & Status' not found."]], columns=["Message"])
103
+
104
+ def load_field_sales():
105
+ df = load_tab("Field Sales")
106
+ if df.empty:
107
+ return pd.DataFrame()
108
+ df["Date"] = pd.to_datetime(df.get("Date", datetime.today()), errors='coerce')
109
+ df["DateStr"] = df["Date"].dt.date.astype(str)
110
  return df
111
 
112
+ # ------------------ GRADIO APP ------------------
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
113
  with gr.Blocks() as app:
114
+ with gr.Row():
115
+ with gr.Column(visible=True) as login_ui:
116
+ gr.Markdown("## πŸ” Login Required")
117
+ email = gr.Textbox(label="Email")
118
+ password = gr.Textbox(label="Password", type="password")
119
+ login_btn = gr.Button("Login")
120
+ login_msg = gr.Markdown("")
121
+
122
+ with gr.Column(visible=False) as main_ui:
123
+ gr.Markdown("## πŸ—‚οΈ CarMat Dashboard")
124
+
125
+ df_initial = load_field_sales()
126
+ unique_dates = sorted(df_initial["DateStr"].unique(), reverse=True) if not df_initial.empty else []
127
+
128
+ # --- Tabs ---
129
+ with gr.Tab("πŸ“Š Summary"):
130
+ gr.Markdown("Summary content coming soon...")
131
+
132
+ with gr.Tab("πŸ“‚ Field Sales"):
133
+ field_df = gr.Dataframe(value=load_field_sales, label="πŸ“‚ Field Sales Records", interactive=False)
134
+ field_btn = gr.Button("πŸ”„ Refresh Field Sales")
135
+ field_btn.click(fn=load_field_sales, outputs=field_df)
136
+
137
+ with gr.Tab("πŸ“ž TeleSales"):
138
+ ts_table = gr.Dataframe(value=get_telesales_summary, label="πŸ“ž TeleSales Summary")
139
+ ts_refresh = gr.Button("πŸ”„ Refresh")
140
+ ts_refresh.click(fn=get_telesales_summary, outputs=ts_table)
141
+
142
+ with gr.Tab("πŸ“¦ Orders Summary"):
143
+ order_date = gr.Dropdown(label="Select Date", choices=unique_dates, interactive=True)
144
+ order_table = gr.Dataframe(label="🧾 Combined Order Summary")
145
+ order_date.change(fn=get_combined_orders, inputs=order_date, outputs=order_table)
146
+
147
+ with gr.Tab("🚨 Escalations"):
148
+ esc_table = gr.Dataframe(value=get_escalations, label="🚨 Used Dealership Escalations")
149
+ esc_btn = gr.Button("πŸ”„ Refresh Escalations")
150
+ esc_btn.click(fn=get_escalations, outputs=esc_table)
151
+
152
+ with gr.Tab("🏭 OEM Visits"):
153
+ oem_table = gr.Dataframe(value=get_oem_summary, label="🏭 OEM Visit Summary")
154
+ oem_refresh = gr.Button("πŸ”„ Refresh")
155
+ oem_refresh.click(fn=get_oem_summary, outputs=oem_table)
156
+
157
+ with gr.Tab("πŸ“¬ Customer Requests"):
158
+ req_table = gr.Dataframe(value=get_requests, label="πŸ“¬ Customer Requests", interactive=False)
159
+ req_refresh = gr.Button("πŸ”„ Refresh Requests")
160
+ req_refresh.click(fn=get_requests, outputs=req_table)
161
+
162
+ with gr.Tab("πŸ“‹ Dealership Directory"):
163
+ listings_table = gr.Dataframe(value=get_listings, label="πŸ“‹ Customer Listings")
164
+ listings_refresh = gr.Button("πŸ”„ Refresh Listings")
165
+ listings_refresh.click(fn=get_listings, outputs=listings_table)
166
+
167
+ with gr.Tab("πŸ‘€ Users"):
168
+ users_table = gr.Dataframe(value=get_users, label="πŸ‘₯ Users")
169
+ users_refresh = gr.Button("πŸ”„ Refresh Users")
170
+ users_refresh.click(fn=get_users, outputs=users_table)
171
+
172
+ def do_login(user, pw):
173
+ if VALID_USERS.get(user) == pw:
174
+ return gr.update(visible=False), gr.update(visible=True), ""
175
+ else:
176
+ return gr.update(visible=True), gr.update(visible=False), "❌ Invalid login."
177
+
178
+ login_btn.click(fn=do_login, inputs=[email, password], outputs=[login_ui, main_ui, login_msg])
179
 
180
  app.launch()