IAMTFRMZA commited on
Commit
35f7fbb
ยท
verified ยท
1 Parent(s): 87d485d

Update app.py

Browse files
Files changed (1) hide show
  1. app.py +41 -36
app.py CHANGED
@@ -9,13 +9,12 @@ scope = ["https://spreadsheets.google.com/feeds", "https://www.googleapis.com/au
9
  creds = ServiceAccountCredentials.from_json_keyfile_name("tough-star.json", scope)
10
  client = gspread.authorize(creds)
11
 
12
- # === Load sheet data ===
13
  sheet_url = "https://docs.google.com/spreadsheets/d/1bpeFS6yihb6niCavpwjWmVEypaSkGxONGg2jZfKX_sA"
14
  sheet = client.open_by_url(sheet_url).worksheet("Calls")
15
  data = sheet.get_all_records()
16
  df = pd.DataFrame(data)
17
 
18
- # === Parse and clean ===
19
  df['Timestamp'] = pd.to_datetime(df['Timestamp'], dayfirst=True, errors='coerce')
20
  df['Date'] = df['Timestamp'].dt.date.astype(str)
21
  df['Time'] = df['Timestamp'].dt.time
@@ -27,16 +26,26 @@ df = df.dropna(subset=['Date', 'Rep Name', 'Latitude', 'Longitude'])
27
  df = df[(df['Latitude'] != 0) & (df['Longitude'] != 0)]
28
  df = df.sort_values(by=['Rep Name', 'Timestamp'])
29
  df['Time Diff (min)'] = df.groupby(['Rep Name', 'Date'])['Timestamp'].diff().dt.total_seconds().div(60).fillna(0)
30
-
31
- # Add Visit Order
32
  df['Visit Order'] = df.groupby(['Rep Name', 'Date']).cumcount() + 1
33
 
34
- # Construct image thumbnail URLs from Google Drive folder
35
- drive_folder_url = "https://drive.google.com/uc?id="
36
- df['Image ID'] = df['Image'].str.extract(r'Calls_Images/([^.]+)')
37
- df['Image URL'] = df['Image ID'].apply(lambda x: f"{drive_folder_url}{x}" if pd.notna(x) else "")
 
 
 
 
 
38
 
39
- # === Functions ===
 
 
 
 
 
 
 
40
  def get_reps(date_str):
41
  reps = df[df['Date'] == date_str]['Rep Name'].dropna().unique()
42
  return sorted(reps)
@@ -48,8 +57,6 @@ def show_map(date_str, rep):
48
 
49
  subset = subset.sort_values(by='Timestamp').copy()
50
  subset['Visit Order'] = range(1, len(subset) + 1)
51
-
52
- # Center and zoom
53
  center_lat = subset['Latitude'].mean()
54
  center_lon = subset['Longitude'].mean()
55
 
@@ -85,54 +92,52 @@ def show_map(date_str, rep):
85
 
86
  fig.update_layout(mapbox_style="open-street-map", title=f"๐Ÿ“ {rep}'s Route on {date_str}")
87
 
88
- # === Build display table
89
  table = subset[[
90
- 'Visit Order', 'Dealership Name', 'Time', 'Time Diff (min)',
91
- 'Type of call', 'Sales or service', 'Image URL'
92
- ]]
93
- table = table.rename(columns={
94
  'Dealership Name': '๐Ÿงญ Dealer',
95
  'Time': '๐Ÿ•’ Time',
96
  'Time Diff (min)': 'โฑ๏ธ Time Spent',
97
  'Type of call': '๐Ÿ“ž Call Type',
98
- 'Sales or service': '๐Ÿ’ผ Category',
99
- 'Image URL': '๐Ÿ“ธ Photo'
100
  })
101
 
102
- # Add time summary
103
  total_time = round(table['โฑ๏ธ Time Spent'].sum(), 2)
104
  summary_row = pd.DataFrame([{
105
- '๐Ÿงญ Dealer': f"๐Ÿงฎ Total Time: {total_time} min",
106
  'Visit Order': '',
 
107
  '๐Ÿ•’ Time': '',
108
  'โฑ๏ธ Time Spent': '',
109
  '๐Ÿ“ž Call Type': '',
110
- '๐Ÿ’ผ Category': '',
111
- '๐Ÿ“ธ Photo': ''
112
  }])
113
  table = pd.concat([table, summary_row], ignore_index=True)
114
 
115
  return table, fig
116
 
117
  # === Gradio UI ===
118
- def update(date_str):
119
- return gr.Dropdown(choices=get_reps(date_str), label="Select Rep")
120
-
121
  with gr.Blocks() as app:
122
- gr.Markdown("## ๐Ÿ—บ๏ธ Rep Route & Visit Visualizer")
123
 
124
- date_picker = gr.Dropdown(
125
- label="Select Date",
126
- choices=sorted(df['Date'].unique(), reverse=True)
127
- )
128
- rep_picker = gr.Dropdown(label="Select Rep")
 
129
 
130
- btn = gr.Button("Show Route")
 
 
 
131
 
132
- table = gr.Dataframe(label="Call Table")
133
- map_plot = gr.Plot(label="Map")
134
 
135
- date_picker.change(fn=update, inputs=date_picker, outputs=rep_picker)
136
- btn.click(fn=show_map, inputs=[date_picker, rep_picker], outputs=[table, map_plot])
137
 
138
  app.launch()
 
9
  creds = ServiceAccountCredentials.from_json_keyfile_name("tough-star.json", scope)
10
  client = gspread.authorize(creds)
11
 
12
+ # === Load and clean sheet data ===
13
  sheet_url = "https://docs.google.com/spreadsheets/d/1bpeFS6yihb6niCavpwjWmVEypaSkGxONGg2jZfKX_sA"
14
  sheet = client.open_by_url(sheet_url).worksheet("Calls")
15
  data = sheet.get_all_records()
16
  df = pd.DataFrame(data)
17
 
 
18
  df['Timestamp'] = pd.to_datetime(df['Timestamp'], dayfirst=True, errors='coerce')
19
  df['Date'] = df['Timestamp'].dt.date.astype(str)
20
  df['Time'] = df['Timestamp'].dt.time
 
26
  df = df[(df['Latitude'] != 0) & (df['Longitude'] != 0)]
27
  df = df.sort_values(by=['Rep Name', 'Timestamp'])
28
  df['Time Diff (min)'] = df.groupby(['Rep Name', 'Date'])['Timestamp'].diff().dt.total_seconds().div(60).fillna(0)
 
 
29
  df['Visit Order'] = df.groupby(['Rep Name', 'Date']).cumcount() + 1
30
 
31
+ # === Helper: All unique reps in dataset ===
32
+ all_reps = sorted(df['Rep Name'].dropna().unique())
33
+
34
+ # === Tab 1: Summary ===
35
+ def generate_summary(date_str):
36
+ day_df = df[df['Date'] == date_str]
37
+
38
+ # Active reps and their total stops
39
+ active = day_df.groupby('Rep Name').size().reset_index(name='Total Visits')
40
 
41
+ # Detect inactive reps
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
+
46
+ return active, inactive_df
47
+
48
+ # === Tab 2: KAMs ===
49
  def get_reps(date_str):
50
  reps = df[df['Date'] == date_str]['Rep Name'].dropna().unique()
51
  return sorted(reps)
 
57
 
58
  subset = subset.sort_values(by='Timestamp').copy()
59
  subset['Visit Order'] = range(1, len(subset) + 1)
 
 
60
  center_lat = subset['Latitude'].mean()
61
  center_lon = subset['Longitude'].mean()
62
 
 
92
 
93
  fig.update_layout(mapbox_style="open-street-map", title=f"๐Ÿ“ {rep}'s Route on {date_str}")
94
 
95
+ # Final table (without photo)
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',
101
  'Time': '๐Ÿ•’ Time',
102
  'Time Diff (min)': 'โฑ๏ธ Time Spent',
103
  'Type of call': '๐Ÿ“ž Call Type',
104
+ 'Sales or service': '๐Ÿ’ผ Category'
 
105
  })
106
 
107
+ # Summary footer
108
  total_time = round(table['โฑ๏ธ Time Spent'].sum(), 2)
109
  summary_row = pd.DataFrame([{
 
110
  'Visit Order': '',
111
+ '๐Ÿงญ Dealer': f"๐Ÿงฎ Total Time: {total_time} min",
112
  '๐Ÿ•’ Time': '',
113
  'โฑ๏ธ Time Spent': '',
114
  '๐Ÿ“ž Call Type': '',
115
+ '๐Ÿ’ผ Category': ''
 
116
  }])
117
  table = pd.concat([table, summary_row], ignore_index=True)
118
 
119
  return table, fig
120
 
121
  # === Gradio UI ===
 
 
 
122
  with gr.Blocks() as app:
123
+ gr.Markdown("## ๐Ÿ—‚๏ธ Carfind Rep Tracker")
124
 
125
+ with gr.Tab("๐Ÿ“Š Summary"):
126
+ date_summary = gr.Dropdown(label="Select Date", choices=sorted(df['Date'].unique(), reverse=True))
127
+ active_table = gr.Dataframe(label="โœ… Active Reps (with total visits)")
128
+ inactive_table = gr.Dataframe(label="โš ๏ธ Inactive Reps")
129
+
130
+ date_summary.change(fn=generate_summary, inputs=date_summary, outputs=[active_table, inactive_table])
131
 
132
+ with gr.Tab("๐Ÿ‘ค KAM's"):
133
+ date_picker = gr.Dropdown(label="Select Date", choices=sorted(df['Date'].unique(), reverse=True))
134
+ rep_picker = gr.Dropdown(label="Select Rep")
135
+ btn = gr.Button("Show Route")
136
 
137
+ table = gr.Dataframe(label="Call Table")
138
+ map_plot = gr.Plot(label="Map")
139
 
140
+ date_picker.change(fn=get_reps, inputs=date_picker, outputs=rep_picker)
141
+ btn.click(fn=show_map, inputs=[date_picker, rep_picker], outputs=[table, map_plot])
142
 
143
  app.launch()