IAMTFRMZA commited on
Commit
79e1d8c
·
verified ·
1 Parent(s): 0222536

Update app.py

Browse files
Files changed (1) hide show
  1. app.py +104 -107
app.py CHANGED
@@ -5,22 +5,23 @@ from oauth2client.service_account import ServiceAccountCredentials
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
 
@@ -30,146 +31,142 @@ def get_current_week_range():
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
 
85
  def get_leads_summary():
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()
173
- insights_btn.click(fn=compute_insights, outputs=insights_tbl)
174
 
175
  app.launch()
 
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(
10
+ "deep-mile-461309-t8-0e90103411e0.json", scope
11
+ )
12
  client = gspread.authorize(creds)
13
  sheet_url = "https://docs.google.com/spreadsheets/d/1if4KoVQvw5ZbhknfdZbzMkcTiPfsD6bz9V3a1th-bwQ"
14
 
15
  # -------------------- UTILS --------------------
16
  def normalize_columns(df):
17
+ df.columns = df.columns.str.strip().str.title()
18
  return df
19
 
20
+ def load_sheet(name):
21
  try:
22
+ ws = client.open_by_url(sheet_url).worksheet(name)
23
+ df = pd.DataFrame(ws.get_all_records())
24
+ return normalize_columns(df)
 
25
  except Exception as e:
26
  return pd.DataFrame([{"Error": str(e)}])
27
 
 
31
  end = start + timedelta(days=6)
32
  return start.date(), end.date()
33
 
34
+ def filter_week(df, date_col, rep_col=None, rep=None):
35
+ df[date_col] = pd.to_datetime(df[date_col], errors="coerce").dt.date
36
+ s, e = get_current_week_range()
37
+ out = df[(df[date_col] >= s) & (df[date_col] <= e)]
38
  if rep:
39
+ out = out[out[rep_col] == rep]
40
+ return out
41
 
42
+ def filter_date(df, date_col, rep_col, y, m, d, rep):
43
  try:
44
+ target = datetime(int(y),int(m),int(d)).date()
45
  except:
46
+ return pd.DataFrame([{"Error":"Invalid date input"}])
47
+ df[date_col] = pd.to_datetime(df[date_col], errors="coerce").dt.date
48
+ out = df[df[date_col] == target]
49
  if rep:
50
+ out = out[out[rep_col] == rep]
51
+ return out
52
 
53
  # -------------------- REPORT FUNCTIONS --------------------
54
  def get_calls(rep=None):
55
  df = load_sheet("Calls")
56
+ if "Call Date" not in df: return pd.DataFrame([{"Error":"Missing 'Call Date' column"}])
57
+ return filter_week(df,"Call Date","Rep",rep)
 
58
 
59
+ def search_calls_by_date(y,m,d,rep):
 
 
 
 
 
 
60
  df = load_sheet("Calls")
61
+ if "Call Date" not in df: return pd.DataFrame([{"Error":"Missing 'Call Date' column"}])
62
+ return filter_date(df,"Call Date","Rep",y,m,d,rep)
 
63
 
64
+ # -------------------- APPOINTMENTS (UPCOMING) --------------------
65
+ def upcoming_summary_and_detail(rep=None):
66
  df = load_sheet("Appointments")
67
+ if "Appointment Date" not in df:
68
+ return pd.DataFrame([{"Error":"Missing 'Appointment Date' column"}]), pd.DataFrame()
69
+ df["Appointment Date"] = pd.to_datetime(df["Appointment Date"], errors="coerce").dt.date
70
+ today = datetime.now().date()
71
+ future = df[df["Appointment Date"] >= today]
72
+ if rep:
73
+ future = future[future["Rep"] == rep]
74
+ summary = future.groupby("Rep").size().reset_index(name="Appointment Count")
75
+ return summary, future
76
 
77
+ def search_appointments_by_date(y,m,d,rep):
78
+ df = load_sheet("Appointments")
79
+ if "Appointment Date" not in df:
80
+ return pd.DataFrame([{"Error":"Missing 'Appointment Date' column"}]), pd.DataFrame()
81
+ try:
82
+ target = datetime(int(y),int(m),int(d)).date()
83
+ except:
84
+ return pd.DataFrame([{"Error":"Invalid date input"}]), pd.DataFrame()
85
+ df["Appointment Date"] = pd.to_datetime(df["Appointment Date"], errors="coerce").dt.date
86
+ out = df[df["Appointment Date"] == target]
87
+ if rep:
88
+ out = out[out["Rep"] == rep]
89
+ summary = out.groupby("Rep").size().reset_index(name="Appointment Count")
90
+ return summary, out
91
+
92
+ # -------------------- LEADS --------------------
93
  def get_leads_detail():
94
  df = load_sheet("AllocatedLeads")
95
+ if "Assigned Rep" not in df or "Company Name" not in df:
96
+ return pd.DataFrame([{"Error":"Missing 'Assigned Rep' or 'Company Name' column"}])
 
 
97
  return df
98
 
99
  def get_leads_summary():
100
  df = get_leads_detail()
101
+ if "Error" in df.columns: return df
102
+ return df.groupby("Assigned Rep").size().reset_index(name="Leads Count")
 
 
 
103
 
104
+ # -------------------- INSIGHTS --------------------
105
  def compute_insights():
106
  calls = get_calls()
107
+ appt_summary, _ = upcoming_summary_and_detail()
108
  leads = get_leads_detail()
109
+ def top(df,col):
110
+ return df[col].value_counts().idxmax() if not df.empty else "N/A"
111
+ return pd.DataFrame([
112
+ {"Metric":"Most Calls This Week", "Rep": top(calls,"Rep")},
113
+ {"Metric":"Most Upcoming Appointments", "Rep": top(appt_summary,"Rep")},
114
+ {"Metric":"Most Leads Allocated", "Rep": top(leads,"Assigned Rep")},
 
 
 
115
  ])
 
116
 
117
  # -------------------- DROPDOWN OPTIONS --------------------
118
+ def rep_options(sheet, col):
119
+ df = load_sheet(sheet)
120
+ return sorted(df[col].dropna().unique().tolist()) if col in df else []
 
 
121
 
122
  # -------------------- UI LAYOUT --------------------
123
  with gr.Blocks(title="Graffiti Admin Dashboard") as app:
124
  gr.Markdown("# 📆 Graffiti Admin Dashboard")
125
 
126
+ # Calls Report
127
  with gr.Tab("Calls Report"):
128
+ rc = gr.Dropdown("Optional Rep Filter", choices=rep_options("Calls","Rep"))
129
+ btn_calls = gr.Button("Load Current Week Calls")
130
+ tbl_calls = gr.Dataframe()
131
+ btn_calls.click(fn=get_calls, inputs=rc, outputs=tbl_calls)
132
 
133
  gr.Markdown("### 🔍 Search Calls by Specific Date")
134
+ y1,m1,d1 = gr.Textbox("Year"), gr.Textbox("Month"), gr.Textbox("Day")
135
+ rc2 = gr.Dropdown("Optional Rep Filter", choices=rep_options("Calls","Rep"))
136
+ btn_cd = gr.Button("Search Calls by Date")
137
+ tbl_cd = gr.Dataframe()
138
+ btn_cd.click(fn=search_calls_by_date, inputs=[y1,m1,d1,rc2], outputs=tbl_cd)
139
 
140
+ # Appointments Report
141
  with gr.Tab("Appointments Report"):
142
+ ra = gr.Dropdown("Optional Rep Filter", choices=rep_options("Appointments","Rep"))
143
+ btn_appt = gr.Button("Load Upcoming Appointments")
144
+ sum_appt = gr.Dataframe(label="📊 Summary by Rep")
145
+ det_appt = gr.Dataframe(label="🔎 Detailed")
146
+ btn_appt.click(fn=upcoming_summary_and_detail, inputs=ra, outputs=[sum_appt,det_appt])
 
 
 
 
 
147
 
148
  gr.Markdown("### 🔍 Search Appointments by Specific Date")
149
+ y2,m2,d2 = gr.Textbox("Year"), gr.Textbox("Month"), gr.Textbox("Day")
150
+ ra2 = gr.Dropdown("Optional Rep Filter", choices=rep_options("Appointments","Rep"))
151
+ btn_ad = gr.Button("Search Appointments by Date")
152
+ sum_ad = gr.Dataframe(label="📊 Summary by Rep")
153
+ det_ad = gr.Dataframe(label="🔎 Detailed")
154
+ btn_ad.click(fn=search_appointments_by_date,
155
+ inputs=[y2,m2,d2,ra2],
156
+ outputs=[sum_ad,det_ad])
157
+
158
+ # Appointed Leads
 
 
 
 
159
  with gr.Tab("Appointed Leads"):
160
+ btn_leads = gr.Button("View Appointed Leads")
161
+ sum_leads = gr.Dataframe(label="📊 Leads Count by Rep")
162
+ det_leads = gr.Dataframe(label="🔎 Detailed")
163
+ btn_leads.click(fn=lambda:(get_leads_summary(),get_leads_detail()),
164
+ outputs=[sum_leads,det_leads])
 
 
165
 
166
+ # Insights
167
  with gr.Tab("Insights"):
168
+ btn_ins = gr.Button("Generate Insights")
169
+ tbl_ins = gr.Dataframe()
170
+ btn_ins.click(fn=compute_insights, outputs=tbl_ins)
171
 
172
  app.launch()