IAMTFRMZA commited on
Commit
d3b24ed
Β·
verified Β·
1 Parent(s): 9424917

Update app.py

Browse files
Files changed (1) hide show
  1. app.py +134 -54
app.py CHANGED
@@ -1,4 +1,3 @@
1
- # app.py
2
  import gradio as gr
3
  import pandas as pd
4
  import gspread
@@ -8,47 +7,59 @@ from datetime import datetime, timedelta
8
  from gspread_dataframe import set_with_dataframe
9
 
10
  # -------------------- CONFIG --------------------
11
- SHEET_URL = "https://docs.google.com/spreadsheets/d/1if4KoVQvw5ZbhknfdZbzMkcTiPfsD6bz9V3a1th-bwQ"
12
- USER_SHEET_NAME = "Users" # <--- make sure this tab exists
13
 
14
  # -------------------- AUTH --------------------
15
  scope = [
16
  "https://spreadsheets.google.com/feeds",
17
  "https://www.googleapis.com/auth/drive",
18
  ]
19
- creds = ServiceAccountCredentials.from_json_keyfile_name(
20
  "deep-mile-461309-t8-0e90103411e0.json", scope
21
  )
22
  client = gspread.authorize(creds)
23
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
24
  # -------------------- SHEET UTILS --------------------
25
  def normalize_columns(df: pd.DataFrame) -> pd.DataFrame:
26
  df.columns = df.columns.str.strip().str.title()
27
  return df
28
 
29
  def load_sheet(sheet_name: str) -> pd.DataFrame:
30
- """Loads an entire sheet into a DataFrame, or returns a one-row error."""
31
  try:
32
- ws = client.open_by_url(SHEET_URL).worksheet(sheet_name)
33
  df = pd.DataFrame(ws.get_all_records())
34
  return normalize_columns(df)
35
  except Exception as e:
36
  return pd.DataFrame([{"Error": str(e)}])
37
 
38
  def load_sheet_df(sheet_name: str) -> pd.DataFrame:
39
- """Same as load_sheet but re-raises WorksheetNotFound for callers to catch."""
40
- try:
41
- ws = client.open_by_url(SHEET_URL).worksheet(sheet_name)
42
- except WorksheetNotFound:
43
- raise
44
  df = pd.DataFrame(ws.get_all_records())
45
  return normalize_columns(df)
46
 
47
- # -------------------- WEEK FILTERS --------------------
48
  def get_current_week_range():
49
  today = datetime.now().date()
50
  start = today - timedelta(days=today.weekday())
51
- end = start + timedelta(days=6)
52
  return start, end
53
 
54
  def filter_week(df, date_col, rep_col=None, rep=None):
@@ -77,18 +88,18 @@ def get_calls(rep=None):
77
  return df
78
  return filter_week(df, "Call Date", "Rep", rep)
79
 
80
- def get_appointments(rep=None):
81
- df = load_sheet("Appointments")
82
- if "Appointment Date" not in df.columns:
83
- return df
84
- return filter_week(df, "Appointment Date", "Rep", rep)
85
-
86
  def search_calls_by_date(y, m, d, rep):
87
  df = load_sheet("Calls")
88
  if "Call Date" not in df.columns:
89
  return df
90
  return filter_date(df, "Call Date", "Rep", y, m, d, rep)
91
 
 
 
 
 
 
 
92
  def search_appointments_by_date(y, m, d, rep):
93
  df = load_sheet("Appointments")
94
  if "Appointment Date" not in df.columns:
@@ -96,14 +107,15 @@ def search_appointments_by_date(y, m, d, rep):
96
  return filter_date(df, "Appointment Date", "Rep", y, m, d, rep)
97
 
98
  def get_leads_detail():
99
- df = load_sheet("AllocatedLeads")
100
- return df
101
 
102
  def get_leads_summary():
103
  df = get_leads_detail()
104
  if "Error" in df.columns:
105
  return df
106
- return df.groupby("Assigned Rep").size().reset_index(name="Leads Count")
 
 
107
 
108
  def compute_insights():
109
  calls = get_calls()
@@ -143,7 +155,6 @@ def load_users() -> pd.DataFrame:
143
  try:
144
  return load_sheet_df(USER_SHEET_NAME)
145
  except WorksheetNotFound:
146
- # fall back to empty skeleton
147
  return pd.DataFrame(columns=cols)
148
 
149
  def save_users(df: pd.DataFrame):
@@ -156,64 +167,133 @@ def save_users(df: pd.DataFrame):
156
  with gr.Blocks(title="Graffiti Admin Dashboard") as app:
157
  gr.Markdown("# πŸ“† Graffiti Admin Dashboard")
158
 
159
- # -- Calls Tab --
160
  with gr.Tab("Calls Report"):
161
- rep_calls = gr.Dropdown(choices=rep_options("Calls","Rep"), label="Optional Rep Filter", allow_custom_value=True)
162
- calls_btn = gr.Button("Load Current Week Calls")
163
- calls_tbl = gr.Dataframe()
164
- calls_btn.click(fn=get_calls, inputs=rep_calls, outputs=calls_tbl)
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
165
 
166
  gr.Markdown("### πŸ” Search Calls by Specific Date")
167
- y1,m1,d1 = gr.Textbox(label="Year"), gr.Textbox(label="Month"), gr.Textbox(label="Day")
168
- rep1 = gr.Dropdown(choices=rep_options("Calls","Rep"), label="Optional Rep Filter", allow_custom_value=True)
 
 
 
 
169
  calls_date_btn = gr.Button("Search Calls by Date")
170
- calls_date_tbl = gr.Dataframe()
171
- calls_date_btn.click(fn=search_calls_by_date, inputs=[y1,m1,d1,rep1], outputs=calls_date_tbl)
172
 
173
- # -- Appointments Tab --
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
174
  with gr.Tab("Appointments Report"):
175
- rep_appt = gr.Dropdown(choices=rep_options("Appointments","Rep"), label="Optional Rep Filter", allow_custom_value=True)
176
- appt_btn = gr.Button("Load Current Week Appointments")
177
- appt_sum = gr.Dataframe(label="πŸ“Š Weekly Appointments Summary by Rep")
178
- appt_tbl = gr.Dataframe()
 
 
 
 
 
 
 
179
  appt_btn.click(
180
- fn=lambda r: ( get_appointments(r).groupby("Rep").size().reset_index(name="Count"),
181
- get_appointments(r) ),
 
 
 
 
 
182
  inputs=rep_appt,
183
- outputs=[appt_sum, appt_tbl]
184
  )
185
 
186
  gr.Markdown("### πŸ” Search Appointments by Specific Date")
187
- y2,m2,d2 = gr.Textbox(label="Year"), gr.Textbox(label="Month"), gr.Textbox(label="Day")
188
- rep2 = gr.Dropdown(choices=rep_options("Appointments","Rep"), label="Optional Rep Filter", allow_custom_value=True)
 
 
 
 
189
  appt_date_btn = gr.Button("Search Appointments by Date")
190
- appt_date_sum = gr.Dataframe(label="πŸ“Š Appointments Summary for Date by Rep")
191
- appt_date_tbl = gr.Dataframe()
 
 
 
 
 
192
  appt_date_btn.click(
193
  fn=lambda y,m,d,r: (
194
- search_appointments_by_date(y,m,d,r).groupby("Rep").size().reset_index(name="Count"),
 
 
 
195
  search_appointments_by_date(y,m,d,r)
196
  ),
197
  inputs=[y2,m2,d2,rep2],
198
- outputs=[appt_date_sum, appt_date_tbl]
199
  )
200
 
201
- # -- Appointed Leads Tab --
202
  with gr.Tab("Appointed Leads"):
203
- leads_btn = gr.Button("View Appointed Leads")
204
- leads_sum = gr.Dataframe(label="πŸ“Š Leads Count by Rep")
205
- leads_detail = gr.Dataframe(label="πŸ”Ž Detailed Leads")
206
- leads_btn.click(fn=lambda: (get_leads_summary(), get_leads_detail()), outputs=[leads_sum, leads_detail])
 
 
 
 
 
 
 
 
207
 
208
- # -- Insights Tab --
209
  with gr.Tab("Insights"):
210
  insights_btn = gr.Button("Generate Insights")
211
  insights_tbl = gr.Dataframe()
212
  insights_btn.click(fn=compute_insights, outputs=insights_tbl)
213
 
214
- # -- User Management Tab --
215
  with gr.Tab("User Management"):
216
- gr.Markdown("### πŸ™ Manage Users\nEdit the grid and click **Save Users** to push changes.")
217
  users_tbl = gr.Dataframe(value=load_users(), interactive=True)
218
  save_btn = gr.Button("Save Users")
219
  save_msg = gr.Textbox(interactive=False)
 
 
1
  import gradio as gr
2
  import pandas as pd
3
  import gspread
 
7
  from gspread_dataframe import set_with_dataframe
8
 
9
  # -------------------- CONFIG --------------------
10
+ SHEET_URL = "https://docs.google.com/spreadsheets/d/1if4KoVQvw5ZbhknfdZbzMkcTiPfsD6bz9V3a1th-bwQ"
11
+ USER_SHEET_NAME = "Users" # <-- must match (or contain) your β€œUsers” tab
12
 
13
  # -------------------- AUTH --------------------
14
  scope = [
15
  "https://spreadsheets.google.com/feeds",
16
  "https://www.googleapis.com/auth/drive",
17
  ]
18
+ creds = ServiceAccountCredentials.from_json_keyfile_name(
19
  "deep-mile-461309-t8-0e90103411e0.json", scope
20
  )
21
  client = gspread.authorize(creds)
22
 
23
+ # -------------------- FUZZY WORKSHEET LOOKUP --------------------
24
+ def open_ws_by_substring(substr: str):
25
+ """
26
+ Try exact match, then fall back to the first worksheet
27
+ whose title contains `substr` (case-insensitive).
28
+ """
29
+ sh = client.open_by_url(SHEET_URL)
30
+ try:
31
+ return sh.worksheet(substr)
32
+ except WorksheetNotFound:
33
+ for ws in sh.worksheets():
34
+ if substr.lower() in ws.title.lower():
35
+ return ws
36
+ raise WorksheetNotFound(f"No tab matching '{substr}'")
37
+
38
  # -------------------- SHEET UTILS --------------------
39
  def normalize_columns(df: pd.DataFrame) -> pd.DataFrame:
40
  df.columns = df.columns.str.strip().str.title()
41
  return df
42
 
43
  def load_sheet(sheet_name: str) -> pd.DataFrame:
44
+ """Return a DataFrame of the entire sheet, or an Error row."""
45
  try:
46
+ ws = open_ws_by_substring(sheet_name)
47
  df = pd.DataFrame(ws.get_all_records())
48
  return normalize_columns(df)
49
  except Exception as e:
50
  return pd.DataFrame([{"Error": str(e)}])
51
 
52
  def load_sheet_df(sheet_name: str) -> pd.DataFrame:
53
+ """Like load_sheet, but lets WorksheetNotFound bubble up."""
54
+ ws = open_ws_by_substring(sheet_name)
 
 
 
55
  df = pd.DataFrame(ws.get_all_records())
56
  return normalize_columns(df)
57
 
58
+ # -------------------- DATE FILTER HELPERS --------------------
59
  def get_current_week_range():
60
  today = datetime.now().date()
61
  start = today - timedelta(days=today.weekday())
62
+ end = start + timedelta(days=6)
63
  return start, end
64
 
65
  def filter_week(df, date_col, rep_col=None, rep=None):
 
88
  return df
89
  return filter_week(df, "Call Date", "Rep", rep)
90
 
 
 
 
 
 
 
91
  def search_calls_by_date(y, m, d, rep):
92
  df = load_sheet("Calls")
93
  if "Call Date" not in df.columns:
94
  return df
95
  return filter_date(df, "Call Date", "Rep", y, m, d, rep)
96
 
97
+ def get_appointments(rep=None):
98
+ df = load_sheet("Appointments")
99
+ if "Appointment Date" not in df.columns:
100
+ return df
101
+ return filter_week(df, "Appointment Date", "Rep", rep)
102
+
103
  def search_appointments_by_date(y, m, d, rep):
104
  df = load_sheet("Appointments")
105
  if "Appointment Date" not in df.columns:
 
107
  return filter_date(df, "Appointment Date", "Rep", y, m, d, rep)
108
 
109
  def get_leads_detail():
110
+ return load_sheet("AllocatedLeads")
 
111
 
112
  def get_leads_summary():
113
  df = get_leads_detail()
114
  if "Error" in df.columns:
115
  return df
116
+ return df.groupby("Assigned Rep")\
117
+ .size()\
118
+ .reset_index(name="Leads Count")
119
 
120
  def compute_insights():
121
  calls = get_calls()
 
155
  try:
156
  return load_sheet_df(USER_SHEET_NAME)
157
  except WorksheetNotFound:
 
158
  return pd.DataFrame(columns=cols)
159
 
160
  def save_users(df: pd.DataFrame):
 
167
  with gr.Blocks(title="Graffiti Admin Dashboard") as app:
168
  gr.Markdown("# πŸ“† Graffiti Admin Dashboard")
169
 
170
+ # -- Calls Report --
171
  with gr.Tab("Calls Report"):
172
+ rep_calls = gr.Dropdown(choices=rep_options("Calls","Rep"),
173
+ label="Optional Rep Filter",
174
+ allow_custom_value=True)
175
+ calls_btn = gr.Button("Load Current Week Calls")
176
+
177
+ with gr.Row():
178
+ with gr.Column():
179
+ calls_sum = gr.Dataframe(label="πŸ“Š Calls by Rep")
180
+ with gr.Column():
181
+ calls_det = gr.Dataframe(label="πŸ”Ž Detailed Calls")
182
+
183
+ calls_btn.click(
184
+ fn=lambda r: (
185
+ get_calls(r).groupby("Rep")
186
+ .size()
187
+ .reset_index(name="Count"),
188
+ get_calls(r)
189
+ ),
190
+ inputs=rep_calls,
191
+ outputs=[calls_sum, calls_det]
192
+ )
193
 
194
  gr.Markdown("### πŸ” Search Calls by Specific Date")
195
+ y1 = gr.Textbox(label="Year")
196
+ m1 = gr.Textbox(label="Month")
197
+ d1 = gr.Textbox(label="Day")
198
+ rep1 = gr.Dropdown(choices=rep_options("Calls","Rep"),
199
+ label="Optional Rep Filter",
200
+ allow_custom_value=True)
201
  calls_date_btn = gr.Button("Search Calls by Date")
 
 
202
 
203
+ with gr.Row():
204
+ with gr.Column():
205
+ calls_date_sum = gr.Dataframe(label="πŸ“Š Calls by Rep on Date")
206
+ with gr.Column():
207
+ calls_date_det = gr.Dataframe(label="πŸ”Ž Detailed Calls on Date")
208
+
209
+ calls_date_btn.click(
210
+ fn=lambda y,m,d,r: (
211
+ search_calls_by_date(y,m,d,r)
212
+ .groupby("Rep")
213
+ .size()
214
+ .reset_index(name="Count"),
215
+ search_calls_by_date(y,m,d,r)
216
+ ),
217
+ inputs=[y1,m1,d1,rep1],
218
+ outputs=[calls_date_sum, calls_date_det]
219
+ )
220
+
221
+ # -- Appointments Report --
222
  with gr.Tab("Appointments Report"):
223
+ rep_appt = gr.Dropdown(choices=rep_options("Appointments","Rep"),
224
+ label="Optional Rep Filter",
225
+ allow_custom_value=True)
226
+ appt_btn = gr.Button("Load Current Week Appointments")
227
+
228
+ with gr.Row():
229
+ with gr.Column():
230
+ appt_sum = gr.Dataframe(label="πŸ“Š Weekly Appointments Summary by Rep")
231
+ with gr.Column():
232
+ appt_det = gr.Dataframe(label="πŸ”Ž Detailed Appointments")
233
+
234
  appt_btn.click(
235
+ fn=lambda r: (
236
+ get_appointments(r)
237
+ .groupby("Rep")
238
+ .size()
239
+ .reset_index(name="Count"),
240
+ get_appointments(r)
241
+ ),
242
  inputs=rep_appt,
243
+ outputs=[appt_sum, appt_det]
244
  )
245
 
246
  gr.Markdown("### πŸ” Search Appointments by Specific Date")
247
+ y2 = gr.Textbox(label="Year")
248
+ m2 = gr.Textbox(label="Month")
249
+ d2 = gr.Textbox(label="Day")
250
+ rep2 = gr.Dropdown(choices=rep_options("Appointments","Rep"),
251
+ label="Optional Rep Filter",
252
+ allow_custom_value=True)
253
  appt_date_btn = gr.Button("Search Appointments by Date")
254
+
255
+ with gr.Row():
256
+ with gr.Column():
257
+ appt_date_sum = gr.Dataframe(label="πŸ“Š Appts by Rep on Date")
258
+ with gr.Column():
259
+ appt_date_det = gr.Dataframe(label="πŸ”Ž Detailed Appts on Date")
260
+
261
  appt_date_btn.click(
262
  fn=lambda y,m,d,r: (
263
+ search_appointments_by_date(y,m,d,r)
264
+ .groupby("Rep")
265
+ .size()
266
+ .reset_index(name="Count"),
267
  search_appointments_by_date(y,m,d,r)
268
  ),
269
  inputs=[y2,m2,d2,rep2],
270
+ outputs=[appt_date_sum, appt_date_det]
271
  )
272
 
273
+ # -- Appointed Leads --
274
  with gr.Tab("Appointed Leads"):
275
+ leads_btn = gr.Button("View Appointed Leads")
276
+
277
+ with gr.Row():
278
+ with gr.Column():
279
+ leads_sum = gr.Dataframe(label="πŸ“Š Leads Count by Rep")
280
+ with gr.Column():
281
+ leads_det = gr.Dataframe(label="πŸ”Ž Detailed Leads")
282
+
283
+ leads_btn.click(
284
+ fn=lambda: (get_leads_summary(), get_leads_detail()),
285
+ outputs=[leads_sum, leads_det]
286
+ )
287
 
288
+ # -- Insights --
289
  with gr.Tab("Insights"):
290
  insights_btn = gr.Button("Generate Insights")
291
  insights_tbl = gr.Dataframe()
292
  insights_btn.click(fn=compute_insights, outputs=insights_tbl)
293
 
294
+ # -- User Management --
295
  with gr.Tab("User Management"):
296
+ gr.Markdown("### πŸ™ Manage Users \nEdit the grid and click **Save Users**.")
297
  users_tbl = gr.Dataframe(value=load_users(), interactive=True)
298
  save_btn = gr.Button("Save Users")
299
  save_msg = gr.Textbox(interactive=False)