IAMTFRMZA commited on
Commit
d685333
Β·
verified Β·
1 Parent(s): 6cca50e

Update app.py

Browse files
Files changed (1) hide show
  1. app.py +48 -61
app.py CHANGED
@@ -1,22 +1,20 @@
 
1
  import pandas as pd
2
  import gspread
3
  from oauth2client.service_account import ServiceAccountCredentials
4
- import gradio as gr
5
  import plotly.express as px
6
 
7
- # === Allowed Users ===
8
- allowed_users = {
9
  "[email protected]": "Pass.123",
10
  "[email protected]": "Pass.123",
11
  "[email protected]": "Pass.123"
12
  }
13
 
14
- # === Google Sheets Auth ===
15
  scope = ["https://spreadsheets.google.com/feeds", "https://www.googleapis.com/auth/drive"]
16
  creds = ServiceAccountCredentials.from_json_keyfile_name("tough-star.json", scope)
17
  client = gspread.authorize(creds)
18
-
19
- # === Load and clean sheet data ===
20
  sheet_url = "https://docs.google.com/spreadsheets/d/1bpeFS6yihb6niCavpwjWmVEypaSkGxONGg2jZfKX_sA"
21
  sheet = client.open_by_url(sheet_url).worksheet("Calls")
22
  data = sheet.get_all_records()
@@ -35,15 +33,14 @@ df = df.sort_values(by=['Rep Name', 'Timestamp'])
35
  df['Time Diff (min)'] = df.groupby(['Rep Name', 'Date'])['Timestamp'].diff().dt.total_seconds().div(60).fillna(0)
36
  df['Visit Order'] = df.groupby(['Rep Name', 'Date']).cumcount() + 1
37
 
38
- # === All reps ===
39
- all_reps = sorted(df['Rep Name'].dropna().unique())
40
 
41
- # === Dashboard Logic ===
42
  def generate_summary(date_str):
43
  day_df = df[df['Date'] == date_str]
44
  active = day_df.groupby('Rep Name').size().reset_index(name='Total Visits')
45
  active_list = active['Rep Name'].tolist()
46
- inactive_list = [rep for rep in all_reps if rep not in active_list]
47
  inactive_df = pd.DataFrame({'Inactive Reps': inactive_list})
48
  return active, inactive_df
49
 
@@ -93,8 +90,8 @@ def show_map(date_str, rep):
93
 
94
  fig.update_layout(mapbox_style="open-street-map", title=f"πŸ“ {rep}'s Route on {date_str}")
95
 
96
- table = subset[[
97
- 'Visit Order', 'Dealership Name', 'Time', 'Time Diff (min)',
98
  'Type of call', 'Sales or service'
99
  ]].rename(columns={
100
  'Dealership Name': '🧭 Dealer',
@@ -114,57 +111,47 @@ def show_map(date_str, rep):
114
  'πŸ’Ό Category': ''
115
  }])
116
  table = pd.concat([table, summary_row], ignore_index=True)
117
-
118
  return table, fig
119
 
120
- # === Login Auth ===
121
- def check_login(email, password):
122
- if email in allowed_users and allowed_users[email] == password:
123
- return True
124
- return False
125
-
126
- # === MAIN APP ===
127
- def main_app():
128
- with gr.Blocks() as app:
129
- gr.Markdown("## πŸ—‚οΈ Carfind Rep Tracker")
130
-
131
- with gr.Tab("πŸ“Š Summary"):
132
- date_summary = gr.Dropdown(label="Select Date", choices=sorted(df['Date'].unique(), reverse=True))
133
- active_table = gr.Dataframe(label="βœ… Active Reps (with total visits)")
134
- inactive_table = gr.Dataframe(label="⚠️ Inactive Reps")
135
- date_summary.change(fn=generate_summary, inputs=date_summary, outputs=[active_table, inactive_table])
136
-
137
- with gr.Tab("πŸ‘€ KAM's"):
138
- with gr.Row():
139
- with gr.Column(scale=1):
140
- date_picker = gr.Dropdown(label="Select Date", choices=sorted(df['Date'].unique(), reverse=True))
141
- rep_picker = gr.Dropdown(label="Select Rep")
142
- btn = gr.Button("Show Route")
143
- with gr.Column(scale=2):
144
- table = gr.Dataframe(label="Call Table")
145
-
146
- map_plot = gr.Plot(label="Map")
147
-
148
- date_picker.change(fn=get_reps, inputs=date_picker, outputs=rep_picker)
149
- btn.click(fn=show_map, inputs=[date_picker, rep_picker], outputs=[table, map_plot])
150
- return app
151
-
152
- # === LOGIN WRAPPER ===
153
- with gr.Blocks() as login_app:
154
- gr.Markdown("## πŸ” Login to Access Carfind Dashboard")
155
- email = gr.Textbox(label="Email")
156
- password = gr.Textbox(label="Password", type="password")
157
- login_btn = gr.Button("Login")
158
- login_status = gr.Markdown("")
159
-
160
- def do_login(user_email, user_password):
161
- if check_login(user_email, user_password):
162
- import gradio as gr2
163
- login_app.close()
164
- main_app().launch(share=False) # launch the main app
165
  else:
166
- return "❌ Invalid credentials. Try again."
167
 
168
- login_btn.click(fn=do_login, inputs=[email, password], outputs=[login_status])
169
 
170
- login_app.launch()
 
1
+ import gradio as gr
2
  import pandas as pd
3
  import gspread
4
  from oauth2client.service_account import ServiceAccountCredentials
 
5
  import plotly.express as px
6
 
7
+ # ------------------ Authentication ------------------
8
+ VALID_USERS = {
9
  "[email protected]": "Pass.123",
10
  "[email protected]": "Pass.123",
11
  "[email protected]": "Pass.123"
12
  }
13
 
14
+ # ------------------ Data Setup ------------------
15
  scope = ["https://spreadsheets.google.com/feeds", "https://www.googleapis.com/auth/drive"]
16
  creds = ServiceAccountCredentials.from_json_keyfile_name("tough-star.json", scope)
17
  client = gspread.authorize(creds)
 
 
18
  sheet_url = "https://docs.google.com/spreadsheets/d/1bpeFS6yihb6niCavpwjWmVEypaSkGxONGg2jZfKX_sA"
19
  sheet = client.open_by_url(sheet_url).worksheet("Calls")
20
  data = sheet.get_all_records()
 
33
  df['Time Diff (min)'] = df.groupby(['Rep Name', 'Date'])['Timestamp'].diff().dt.total_seconds().div(60).fillna(0)
34
  df['Visit Order'] = df.groupby(['Rep Name', 'Date']).cumcount() + 1
35
 
36
+ ALL_REPS = sorted(df['Rep Name'].dropna().unique())
 
37
 
38
+ # ------------------ App Logic ------------------
39
  def generate_summary(date_str):
40
  day_df = df[df['Date'] == date_str]
41
  active = day_df.groupby('Rep Name').size().reset_index(name='Total Visits')
42
  active_list = active['Rep Name'].tolist()
43
+ inactive_list = [rep for rep in ALL_REPS if rep not in active_list]
44
  inactive_df = pd.DataFrame({'Inactive Reps': inactive_list})
45
  return active, inactive_df
46
 
 
90
 
91
  fig.update_layout(mapbox_style="open-street-map", title=f"πŸ“ {rep}'s Route on {date_str}")
92
 
93
+ table = subset[[
94
+ 'Visit Order', 'Dealership Name', 'Time', 'Time Diff (min)',
95
  'Type of call', 'Sales or service'
96
  ]].rename(columns={
97
  'Dealership Name': '🧭 Dealer',
 
111
  'πŸ’Ό Category': ''
112
  }])
113
  table = pd.concat([table, summary_row], ignore_index=True)
 
114
  return table, fig
115
 
116
+ # ------------------ Login + Protected UI ------------------
117
+ with gr.Blocks() as app:
118
+ state = gr.State(False)
119
+
120
+ with gr.Row():
121
+ with gr.Column(scale=1):
122
+ login_title = gr.Markdown("## πŸ” Login Required")
123
+ email = gr.Textbox(label="Email")
124
+ password = gr.Textbox(label="Password", type="password")
125
+ login_btn = gr.Button("Login")
126
+ login_msg = gr.Markdown("")
127
+
128
+ with gr.Column(visible=False) as main_ui:
129
+ gr.Markdown("## πŸ—‚οΈ Carfind Rep Tracker")
130
+ with gr.Tab("πŸ“Š Summary"):
131
+ date_summary = gr.Dropdown(label="Select Date", choices=sorted(df['Date'].unique(), reverse=True))
132
+ active_table = gr.Dataframe(label="βœ… Active Reps (with total visits)")
133
+ inactive_table = gr.Dataframe(label="⚠️ Inactive Reps")
134
+ date_summary.change(fn=generate_summary, inputs=date_summary, outputs=[active_table, inactive_table])
135
+
136
+ with gr.Tab("πŸ‘€ KAM's"):
137
+ with gr.Row():
138
+ with gr.Column(scale=1):
139
+ date_picker = gr.Dropdown(label="Select Date", choices=sorted(df['Date'].unique(), reverse=True))
140
+ rep_picker = gr.Dropdown(label="Select Rep")
141
+ btn = gr.Button("Show Route")
142
+ with gr.Column(scale=2):
143
+ table = gr.Dataframe(label="Call Table")
144
+
145
+ map_plot = gr.Plot(label="Map")
146
+ date_picker.change(fn=get_reps, inputs=date_picker, outputs=rep_picker)
147
+ btn.click(fn=show_map, inputs=[date_picker, rep_picker], outputs=[table, map_plot])
148
+
149
+ def check_login(u, p):
150
+ if VALID_USERS.get(u) == p:
151
+ return gr.update(visible=False), gr.update(visible=True), ""
 
 
 
 
 
 
 
 
 
152
  else:
153
+ return gr.update(), gr.update(), "❌ Incorrect email or password."
154
 
155
+ login_btn.click(fn=check_login, inputs=[email, password], outputs=[login_title, main_ui, login_msg])
156
 
157
+ app.launch()