IAMTFRMZA commited on
Commit
0222536
Β·
verified Β·
1 Parent(s): 25ec218

Update app.py

Browse files
Files changed (1) hide show
  1. app.py +89 -123
app.py CHANGED
@@ -5,102 +5,80 @@ from oauth2client.service_account import ServiceAccountCredentials
5
  from datetime import datetime, timedelta
6
 
7
  # -------------------- AUTH --------------------
8
- scope = [
9
- "https://spreadsheets.google.com/feeds",
10
- "https://www.googleapis.com/auth/drive"
11
- ]
12
- creds = ServiceAccountCredentials.from_json_keyfile_name(
13
- "deep-mile-461309-t8-0e90103411e0.json",
14
- scope
15
- )
16
  client = gspread.authorize(creds)
17
  sheet_url = "https://docs.google.com/spreadsheets/d/1if4KoVQvw5ZbhknfdZbzMkcTiPfsD6bz9V3a1th-bwQ"
18
 
19
  # -------------------- UTILS --------------------
20
- def normalize_header(raw_header):
21
- # strip and titleize
22
- return [h.strip().title() for h in raw_header]
23
-
24
- def load_sheet(sheet_name: str) -> pd.DataFrame:
25
- ws = client.open_by_url(sheet_url).worksheet(sheet_name)
26
- all_vals = ws.get_all_values()
27
- if not all_vals or len(all_vals) < 2:
28
- return pd.DataFrame()
29
- header = normalize_header(all_vals[0])
30
- rows = all_vals[1:]
31
- df = pd.DataFrame(rows, columns=header)
32
  return df
33
 
 
 
 
 
 
 
 
 
 
34
  def get_current_week_range():
35
  today = datetime.now()
36
  start = today - timedelta(days=today.weekday())
37
  end = start + timedelta(days=6)
38
  return start.date(), end.date()
39
 
40
- # -------------------- CALLS --------------------
41
- def get_calls(rep=None):
42
- df = load_sheet("Calls")
43
- if "Call Date" not in df:
44
- return pd.DataFrame([{"Error": "Missing 'Call Date' column"}])
45
- df["Call Date"] = pd.to_datetime(df["Call Date"], errors="coerce").dt.date
46
  start, end = get_current_week_range()
47
- filtered = df[(df["Call Date"] >= start) & (df["Call Date"] <= end)]
48
  if rep:
49
- filtered = filtered[filtered["Rep"] == rep]
50
  return filtered
51
 
52
- def search_calls_by_date(y, m, d, rep):
53
- df = load_sheet("Calls")
54
- if "Call Date" not in df:
55
- return pd.DataFrame([{"Error": "Missing 'Call Date' column"}])
56
  try:
57
  target = datetime(int(y), int(m), int(d)).date()
58
  except:
59
  return pd.DataFrame([{"Error": "Invalid date input"}])
60
- df["Call Date"] = pd.to_datetime(df["Call Date"], errors="coerce").dt.date
61
- filtered = df[df["Call Date"] == target]
62
  if rep:
63
- filtered = filtered[filtered["Rep"] == rep]
64
  return filtered
65
 
66
- # -------------------- APPOINTMENTS --------------------
67
- def appointments_detail(rep=None):
 
 
 
 
 
 
68
  df = load_sheet("Appointments")
69
- if "Appointment Date" not in df:
70
  return pd.DataFrame([{"Error": "Missing 'Appointment Date' column"}])
71
- df["Appointment Date"] = pd.to_datetime(df["Appointment Date"], errors="coerce").dt.date
72
- start, end = get_current_week_range()
73
- filtered = df[(df["Appointment Date"] >= start) & (df["Appointment Date"] <= end)]
74
- if rep:
75
- filtered = filtered[filtered["Rep"] == rep]
76
- return filtered
77
 
78
- def appointments_summary(rep=None):
79
- det = appointments_detail(rep)
80
- if "Error" in det.columns:
81
- return det
82
- return det.groupby("Rep") \
83
- .size() \
84
- .reset_index(name="Appointment Count")
85
 
86
  def search_appointments_by_date(y, m, d, rep):
87
  df = load_sheet("Appointments")
88
- if "Appointment Date" not in df:
89
  return pd.DataFrame([{"Error": "Missing 'Appointment Date' column"}])
90
- try:
91
- target = datetime(int(y), int(m), int(d)).date()
92
- except:
93
- return pd.DataFrame([{"Error": "Invalid date input"}])
94
- df["Appointment Date"] = pd.to_datetime(df["Appointment Date"], errors="coerce").dt.date
95
- filtered = df[df["Appointment Date"] == target]
96
- if rep:
97
- filtered = filtered[filtered["Rep"] == rep]
98
- return filtered
99
 
100
- # -------------------- LEADS --------------------
101
  def get_leads_detail():
102
  df = load_sheet("AllocatedLeads")
103
- if "Assigned Rep" not in df or "Company Name" not in df:
 
 
104
  return pd.DataFrame([{"Error": "Missing 'Assigned Rep' or 'Company Name' column"}])
105
  return df
106
 
@@ -108,99 +86,87 @@ def get_leads_summary():
108
  df = get_leads_detail()
109
  if "Error" in df.columns:
110
  return df
111
- return df.groupby("Assigned Rep") \
112
- .size() \
113
- .reset_index(name="Leads Count")
114
 
115
- # -------------------- INSIGHTS --------------------
116
  def compute_insights():
117
  calls = get_calls()
118
- appt = appointments_detail()
119
  leads = get_leads_detail()
120
 
121
- def top(df, col):
122
- return df[col].value_counts().idxmax() if not df.empty else "N/A"
 
123
 
124
- return pd.DataFrame([
125
- {"Metric": "Most Calls This Week", "Rep": top(calls, "Rep")},
126
- {"Metric": "Most Appointments This Week", "Rep": top(appt, "Rep")},
127
- {"Metric": "Most Leads Allocated", "Rep": top(leads, "Assigned Rep")},
128
  ])
 
129
 
130
  # -------------------- DROPDOWN OPTIONS --------------------
131
  def rep_options(sheet_name, rep_col):
132
  df = load_sheet(sheet_name)
133
- return sorted(df[rep_col].dropna().unique().tolist()) if rep_col in df.columns else []
 
 
134
 
135
  # -------------------- UI LAYOUT --------------------
136
  with gr.Blocks(title="Graffiti Admin Dashboard") as app:
137
  gr.Markdown("# πŸ“† Graffiti Admin Dashboard")
138
 
139
- # Calls Report
140
  with gr.Tab("Calls Report"):
141
- rep_calls = gr.Dropdown("Optional Rep Filter",
142
- choices=rep_options("Calls", "Rep"),
143
- allow_custom_value=True)
144
- calls_btn = gr.Button("Load Current Week Calls")
145
  calls_table = gr.Dataframe()
146
  calls_btn.click(fn=get_calls, inputs=rep_calls, outputs=calls_table)
147
 
148
  gr.Markdown("### πŸ” Search Calls by Specific Date")
149
- y1, m1, d1 = gr.Textbox("Year"), gr.Textbox("Month"), gr.Textbox("Day")
150
- rep1 = gr.Dropdown("Optional Rep Filter",
151
- choices=rep_options("Calls", "Rep"),
152
- allow_custom_value=True)
153
- calls_date_btn = gr.Button("Search Calls by Date")
154
  calls_date_table = gr.Dataframe()
155
- calls_date_btn.click(fn=search_calls_by_date,
156
- inputs=[y1, m1, d1, rep1],
157
- outputs=calls_date_table)
158
 
159
- # Appointments Report
160
  with gr.Tab("Appointments Report"):
161
- rep_appt = gr.Dropdown("Optional Rep Filter",
162
- choices=rep_options("Appointments", "Rep"),
163
- allow_custom_value=True)
164
- load_btn = gr.Button("Load Current Week Appointments")
165
- appt_sum = gr.Dataframe(label="πŸ“Š Weekly Appointments Summary by Rep")
166
- appt_det = gr.Dataframe(label="πŸ”Ž Detailed Appointments")
167
- load_btn.click(
168
- fn=lambda rep: (appointments_summary(rep), appointments_detail(rep)),
169
  inputs=rep_appt,
170
- outputs=[appt_sum, appt_det]
171
  )
172
 
173
  gr.Markdown("### πŸ” Search Appointments by Specific Date")
174
- y2, m2, d2 = gr.Textbox("Year"), gr.Textbox("Month"), gr.Textbox("Day")
175
- rep2 = gr.Dropdown("Optional Rep Filter",
176
- choices=rep_options("Appointments", "Rep"),
177
- allow_custom_value=True)
178
- date_btn = gr.Button("Search Appointments by Date")
179
- date_sum = gr.Dataframe(label="πŸ“Š Appointments Summary for Date by Rep")
180
- date_det = gr.Dataframe(label="πŸ”Ž Detailed Appointments")
181
- def by_date(y, m, d, rep):
182
- df = search_appointments_by_date(y, m, d, rep)
183
- if "Error" in df.columns:
184
- return df, df
185
- return (
186
- df.groupby("Rep").size().reset_index(name="Appointment Count"),
187
- df
188
- )
189
- date_btn.click(fn=by_date,
190
- inputs=[y2, m2, d2, rep2],
191
- outputs=[date_sum, date_det])
192
-
193
- # Appointed Leads
194
  with gr.Tab("Appointed Leads"):
195
- leads_btn = gr.Button("View Appointed Leads")
196
- leads_sum = gr.Dataframe(label="πŸ“Š Leads Count by Rep")
197
- leads_det = gr.Dataframe(label="πŸ”Ž Detailed Leads")
198
  leads_btn.click(
199
  fn=lambda: (get_leads_summary(), get_leads_detail()),
200
- outputs=[leads_sum, leads_det]
201
  )
202
 
203
- # Insights
204
  with gr.Tab("Insights"):
205
  insights_btn = gr.Button("Generate Insights")
206
  insights_tbl = gr.Dataframe()
 
5
  from datetime import datetime, timedelta
6
 
7
  # -------------------- AUTH --------------------
8
+ scope = ["https://spreadsheets.google.com/feeds", "https://www.googleapis.com/auth/drive"]
9
+ creds = ServiceAccountCredentials.from_json_keyfile_name("deep-mile-461309-t8-0e90103411e0.json", scope)
 
 
 
 
 
 
10
  client = gspread.authorize(creds)
11
  sheet_url = "https://docs.google.com/spreadsheets/d/1if4KoVQvw5ZbhknfdZbzMkcTiPfsD6bz9V3a1th-bwQ"
12
 
13
  # -------------------- UTILS --------------------
14
+ def normalize_columns(df):
15
+ df.columns = df.columns.str.strip().str.title() # e.g. β€œappointment date ” β†’ β€œAppointment Date”
 
 
 
 
 
 
 
 
 
 
16
  return df
17
 
18
+ def load_sheet(sheet_name):
19
+ try:
20
+ sheet = client.open_by_url(sheet_url).worksheet(sheet_name)
21
+ df = pd.DataFrame(sheet.get_all_records())
22
+ df = normalize_columns(df)
23
+ return df
24
+ except Exception as e:
25
+ return pd.DataFrame([{"Error": str(e)}])
26
+
27
  def get_current_week_range():
28
  today = datetime.now()
29
  start = today - timedelta(days=today.weekday())
30
  end = start + timedelta(days=6)
31
  return start.date(), end.date()
32
 
33
+ def filter_week(df, date_column, rep_column=None, rep=None):
34
+ df[date_column] = pd.to_datetime(df[date_column], errors='coerce').dt.date
 
 
 
 
35
  start, end = get_current_week_range()
36
+ filtered = df[(df[date_column] >= start) & (df[date_column] <= end)]
37
  if rep:
38
+ filtered = filtered[filtered[rep_column] == rep]
39
  return filtered
40
 
41
+ def filter_date(df, date_column, rep_column, y, m, d, rep):
 
 
 
42
  try:
43
  target = datetime(int(y), int(m), int(d)).date()
44
  except:
45
  return pd.DataFrame([{"Error": "Invalid date input"}])
46
+ df[date_column] = pd.to_datetime(df[date_column], errors='coerce').dt.date
47
+ filtered = df[df[date_column] == target]
48
  if rep:
49
+ filtered = filtered[filtered[rep_column] == rep]
50
  return filtered
51
 
52
+ # -------------------- REPORT FUNCTIONS --------------------
53
+ def get_calls(rep=None):
54
+ df = load_sheet("Calls")
55
+ if "Call Date" not in df.columns:
56
+ return pd.DataFrame([{"Error": "Missing 'Call Date' column"}])
57
+ return filter_week(df, "Call Date", "Rep", rep)
58
+
59
+ def get_appointments(rep=None):
60
  df = load_sheet("Appointments")
61
+ if "Appointment Date" not in df.columns:
62
  return pd.DataFrame([{"Error": "Missing 'Appointment Date' column"}])
63
+ return filter_week(df, "Appointment Date", "Rep", rep)
 
 
 
 
 
64
 
65
+ def search_calls_by_date(y, m, d, rep):
66
+ df = load_sheet("Calls")
67
+ if "Call Date" not in df.columns:
68
+ return pd.DataFrame([{"Error": "Missing 'Call Date' column"}])
69
+ return filter_date(df, "Call Date", "Rep", y, m, d, rep)
 
 
70
 
71
  def search_appointments_by_date(y, m, d, rep):
72
  df = load_sheet("Appointments")
73
+ if "Appointment Date" not in df.columns:
74
  return pd.DataFrame([{"Error": "Missing 'Appointment Date' column"}])
75
+ return filter_date(df, "Appointment Date", "Rep", y, m, d, rep)
 
 
 
 
 
 
 
 
76
 
 
77
  def get_leads_detail():
78
  df = load_sheet("AllocatedLeads")
79
+ # normalize expected names if necessary:
80
+ df = df.rename(columns={"Assigned Rep": "Assigned Rep", "Company Name": "Company Name"})
81
+ if "Assigned Rep" not in df.columns or "Company Name" not in df.columns:
82
  return pd.DataFrame([{"Error": "Missing 'Assigned Rep' or 'Company Name' column"}])
83
  return df
84
 
 
86
  df = get_leads_detail()
87
  if "Error" in df.columns:
88
  return df
89
+ # count number of leads per rep
90
+ summary = df.groupby("Assigned Rep").size().reset_index(name="Leads Count")
91
+ return summary
92
 
93
+ # -------------------- INSIGHTS (Top Performers) --------------------
94
  def compute_insights():
95
  calls = get_calls()
96
+ appts = get_appointments()
97
  leads = get_leads_detail()
98
 
99
+ top_calls = calls.groupby("Rep").size().idxmax() if not calls.empty else "N/A"
100
+ top_appts = appts.groupby("Rep").size().idxmax() if not appts.empty else "N/A"
101
+ top_leads = leads.groupby("Assigned Rep").size().idxmax() if "Assigned Rep" in leads.columns else "N/A"
102
 
103
+ insights = pd.DataFrame([
104
+ {"Metric": "Most Calls This Week", "Rep": top_calls},
105
+ {"Metric": "Most Appointments This Week", "Rep": top_appts},
106
+ {"Metric": "Most Leads Allocated", "Rep": top_leads},
107
  ])
108
+ return insights
109
 
110
  # -------------------- DROPDOWN OPTIONS --------------------
111
  def rep_options(sheet_name, rep_col):
112
  df = load_sheet(sheet_name)
113
+ if rep_col in df.columns:
114
+ return sorted(df[rep_col].dropna().unique().tolist())
115
+ return []
116
 
117
  # -------------------- UI LAYOUT --------------------
118
  with gr.Blocks(title="Graffiti Admin Dashboard") as app:
119
  gr.Markdown("# πŸ“† Graffiti Admin Dashboard")
120
 
 
121
  with gr.Tab("Calls Report"):
122
+ rep_calls = gr.Dropdown(label="Optional Rep Filter", choices=rep_options("Calls", "Rep"), allow_custom_value=True)
123
+ calls_btn = gr.Button("Load Current Week Calls")
 
 
124
  calls_table = gr.Dataframe()
125
  calls_btn.click(fn=get_calls, inputs=rep_calls, outputs=calls_table)
126
 
127
  gr.Markdown("### πŸ” Search Calls by Specific Date")
128
+ y1, m1, d1 = gr.Textbox(label="Year"), gr.Textbox(label="Month"), gr.Textbox(label="Day")
129
+ rep1 = gr.Dropdown(label="Optional Rep Filter", choices=rep_options("Calls", "Rep"), allow_custom_value=True)
130
+ calls_date_btn = gr.Button("Search Calls by Date")
 
 
131
  calls_date_table = gr.Dataframe()
132
+ calls_date_btn.click(fn=search_calls_by_date, inputs=[y1, m1, d1, rep1], outputs=calls_date_table)
 
 
133
 
 
134
  with gr.Tab("Appointments Report"):
135
+ rep_appt = gr.Dropdown(label="Optional Rep Filter", choices=rep_options("Appointments", "Rep"), allow_custom_value=True)
136
+ appt_btn = gr.Button("Load Current Week Appointments")
137
+ appt_summary = gr.Dataframe(label="πŸ“Š Weekly Appointments Summary by Rep")
138
+ appt_table = gr.Dataframe()
139
+ appt_btn.click(
140
+ fn=lambda rep: (get_appointments(rep).groupby("Rep").size().reset_index(name="Count"),
141
+ get_appointments(rep)),
 
142
  inputs=rep_appt,
143
+ outputs=[appt_summary, appt_table]
144
  )
145
 
146
  gr.Markdown("### πŸ” Search Appointments by Specific Date")
147
+ y2, m2, d2 = gr.Textbox(label="Year"), gr.Textbox(label="Month"), gr.Textbox(label="Day")
148
+ rep2 = gr.Dropdown(label="Optional Rep Filter", choices=rep_options("Appointments", "Rep"), allow_custom_value=True)
149
+ appt_date_btn = gr.Button("Search Appointments by Date")
150
+ appt_date_summary = gr.Dataframe(label="πŸ“Š Appointments Summary for Date by Rep")
151
+ appt_date_table = gr.Dataframe()
152
+ appt_date_btn.click(
153
+ fn=lambda y,m,d,rep: (
154
+ search_appointments_by_date(y,m,d,rep).groupby("Rep").size().reset_index(name="Count"),
155
+ search_appointments_by_date(y,m,d,rep)
156
+ ),
157
+ inputs=[y2, m2, d2, rep2],
158
+ outputs=[appt_date_summary, appt_date_table]
159
+ )
160
+
 
 
 
 
 
 
161
  with gr.Tab("Appointed Leads"):
162
+ leads_btn = gr.Button("View Appointed Leads")
163
+ leads_summary= gr.Dataframe(label="πŸ“Š Leads Count by Rep")
164
+ leads_detail = gr.Dataframe(label="πŸ”Ž Detailed Leads")
165
  leads_btn.click(
166
  fn=lambda: (get_leads_summary(), get_leads_detail()),
167
+ outputs=[leads_summary, leads_detail]
168
  )
169
 
 
170
  with gr.Tab("Insights"):
171
  insights_btn = gr.Button("Generate Insights")
172
  insights_tbl = gr.Dataframe()