IAMTFRMZA commited on
Commit
01139ed
·
verified ·
1 Parent(s): 1c4332a

Update app.py

Browse files
Files changed (1) hide show
  1. app.py +143 -137
app.py CHANGED
@@ -1,8 +1,10 @@
1
  import gradio as gr
2
  import pandas as pd
3
  import gspread
 
4
  from oauth2client.service_account import ServiceAccountCredentials
5
  from datetime import datetime, timedelta
 
6
 
7
  # -------------------- AUTH --------------------
8
  scope = [
@@ -13,84 +15,97 @@ creds = ServiceAccountCredentials.from_json_keyfile_name(
13
  "deep-mile-461309-t8-0e90103411e0.json", scope
14
  )
15
  client = gspread.authorize(creds)
16
- sheet_url = (
17
- "https://docs.google.com/spreadsheets/d/1if4KoVQvw5ZbhknfdZbzMkcTiPfsD6bz9V3a1th-bwQ"
18
- )
19
 
20
  # -------------------- UTILS --------------------
21
- def normalize_columns(df: pd.DataFrame) -> pd.DataFrame:
22
- df.columns = df.columns.str.strip().str.title()
23
- return df
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
24
 
25
- # Replace get_all_records() to avoid duplicate-header errors
26
- def load_sheet(sheet_name: str) -> pd.DataFrame:
27
- try:
28
- ws = client.open_by_url(sheet_url).worksheet(sheet_name)
29
- all_values = ws.get_all_values()
30
- if not all_values:
31
- return pd.DataFrame()
32
- headers = [h.strip().title() for h in all_values[0]]
33
- data = all_values[1:]
34
- return pd.DataFrame(data, columns=headers)
35
- except Exception as e:
36
- return pd.DataFrame([{"Error": str(e)}])
37
-
38
- # date utilities
39
  def get_current_week_range():
40
- today = datetime.now()
41
  start = today - timedelta(days=today.weekday())
42
  end = start + timedelta(days=6)
43
- return start.date(), end.date()
44
 
45
- def filter_week(df: pd.DataFrame, date_col: str, rep_col: str = None, rep=None):
46
  if date_col not in df.columns:
47
- return df
48
- df[date_col] = pd.to_datetime(df[date_col], errors='coerce').dt.date
 
49
  start, end = get_current_week_range()
50
- out = df[(df[date_col] >= start) & (df[date_col] <= end)]
51
- if rep and rep_col in df.columns:
52
- out = out[out[rep_col] == rep]
53
- return out
54
 
55
- def filter_date(df: pd.DataFrame, date_col: str, rep_col: str, y, m, d, rep):
56
  try:
57
  target = datetime(int(y), int(m), int(d)).date()
58
  except:
59
- return pd.DataFrame([{"Error": "Invalid date input"}])
60
  if date_col not in df.columns:
61
  return pd.DataFrame([{"Error": f"Missing '{date_col}' column"}])
62
- df[date_col] = pd.to_datetime(df[date_col], errors='coerce').dt.date
63
- out = df[df[date_col] == target]
64
- if rep and rep_col in df.columns:
65
- out = out[out[rep_col] == rep]
66
- return out
 
 
 
 
 
67
 
68
  # -------------------- REPORT FUNCTIONS --------------------
69
  def get_calls(rep=None):
70
- df = load_sheet("Calls")
71
- return filter_week(df, "Call Date", "Rep", rep)
72
 
73
  def get_appointments(rep=None):
74
- df = load_sheet("Appointments")
75
- return filter_week(df, "Appointment Date", "Rep", rep)
76
-
77
- def search_calls_by_date(y,m,d,rep):
78
- df = load_sheet("Calls")
79
- return filter_date(df, "Call Date", "Rep", y,m,d,rep)
80
 
81
- def search_appointments_by_date(y,m,d,rep):
82
- df = load_sheet("Appointments")
83
- return filter_date(df, "Appointment Date", "Rep", y,m,d,rep)
84
 
85
- # Leads
 
 
86
 
 
87
  def get_leads_detail():
88
- df = load_sheet("AllocatedLeads")
89
  return df
90
 
91
  def get_leads_summary():
92
  df = get_leads_detail()
93
- if "Assigned Rep" not in df.columns:
94
  return pd.DataFrame([{"Error": "Missing 'Assigned Rep'"}])
95
  return df.groupby("Assigned Rep").size().reset_index(name="Leads Count")
96
 
@@ -99,111 +114,102 @@ def compute_insights():
99
  calls = get_calls()
100
  appts = get_appointments()
101
  leads = get_leads_detail()
102
- def top(df, col):
103
- if col in df.columns and not df.empty:
104
- try:
105
- return df[col].mode()[0]
106
- except:
107
- return "N/A"
108
  return "N/A"
109
- insights = pd.DataFrame([
 
110
  {"Metric": "Most Calls This Week", "Rep": top(calls, "Rep")},
111
  {"Metric": "Most Appointments This Week", "Rep": top(appts, "Rep")},
112
  {"Metric": "Most Leads Allocated", "Rep": top(leads, "Assigned Rep")},
113
- ])
114
- return insights
115
-
116
- # -------------------- DROPDOWN OPTIONS --------------------
117
- def rep_options(sheet_name, rep_col):
118
- df = load_sheet(sheet_name)
119
- if rep_col in df.columns:
120
- return sorted(df[rep_col].dropna().unique().tolist())
121
- return []
122
 
123
  # -------------------- USER MANAGEMENT --------------------
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
124
  def save_users(df):
125
- ws = client.open_by_url(sheet_url).worksheet("User")
126
- headers = df.columns.tolist()
127
- rows = df.fillna("").values.tolist()
128
  ws.clear()
129
- ws.update([headers] + rows)
130
- return pd.DataFrame([{"Status": "Users saved."}])
131
 
132
- # -------------------- UI --------------------
133
  with gr.Blocks(title="Graffiti Admin Dashboard") as app:
134
  gr.Markdown("# 📆 Graffiti Admin Dashboard")
135
 
 
136
  with gr.Tab("Calls Report"):
137
- rep_calls = gr.Dropdown(label="Optional Rep Filter",
138
- choices=rep_options("Calls","Rep"),
139
- allow_custom_value=True)
140
- calls_btn = gr.Button("Load Current Week Calls")
141
- calls_tbl = gr.Dataframe()
142
- calls_btn.click(fn=get_calls, inputs=rep_calls, outputs=calls_tbl)
143
-
144
- gr.Markdown("### 🔍 Search Calls by Specific Date")
145
- y1,m1,d1 = gr.Textbox(label="Year"), gr.Textbox(label="Month"), gr.Textbox(label="Day")
146
- rep1 = gr.Dropdown(label="Optional Rep Filter",
147
- choices=rep_options("Calls","Rep"),
148
- allow_custom_value=True)
149
- calls_date_btn = gr.Button("Search Calls by Date")
150
- calls_date_tbl = gr.Dataframe()
151
- calls_date_btn.click(fn=search_calls_by_date,
152
- inputs=[y1,m1,d1,rep1],
153
- outputs=calls_date_tbl)
154
-
155
  with gr.Tab("Appointments Report"):
156
- rep_appt = gr.Dropdown(label="Optional Rep Filter",
157
- choices=rep_options("Appointments","Rep"),
158
- allow_custom_value=True)
159
- appt_btn = gr.Button("Load Current Week Appointments")
160
- appt_summary = gr.Dataframe(label="📊 Weekly Appointments Summary by Rep")
161
- appt_tbl = gr.Dataframe()
162
- appt_btn.click(
163
- fn=lambda rep: (
164
- get_appointments(rep).groupby("Rep").size().reset_index(name="Count"),
165
- get_appointments(rep)
166
- ),
167
- inputs=rep_appt,
168
- outputs=[appt_summary, appt_tbl]
169
- )
170
-
171
- gr.Markdown("### 🔍 Search Appointments by Specific Date")
172
- y2,m2,d2 = gr.Textbox(label="Year"), gr.Textbox(label="Month"), gr.Textbox(label="Day")
173
- rep2 = gr.Dropdown(label="Optional Rep Filter",
174
- choices=rep_options("Appointments","Rep"),
175
- allow_custom_value=True)
176
- appt_date_btn = gr.Button("Search Appointments by Date")
177
- appt_date_sum = gr.Dataframe(label="📊 Appointments Summary for Date by Rep")
178
- appt_date_tbl = gr.Dataframe()
179
- appt_date_btn.click(
180
- fn=lambda y,m,d,rep: (
181
- search_appointments_by_date(y,m,d,rep)
182
- .groupby("Rep").size().reset_index(name="Count"),
183
- search_appointments_by_date(y,m,d,rep)
184
- ),
185
- inputs=[y2,m2,d2,rep2],
186
- outputs=[appt_date_sum, appt_date_tbl]
187
- )
188
-
189
  with gr.Tab("Appointed Leads"):
190
- leads_btn = gr.Button("View Appointed Leads")
191
- leads_sum = gr.Dataframe(label="📊 Leads Count by Rep")
192
- leads_det = gr.Dataframe(label="🔎 Detailed Leads")
193
- leads_btn.click(fn=lambda: (get_leads_summary(), get_leads_detail()),
194
- outputs=[leads_sum, leads_det])
195
 
 
196
  with gr.Tab("Insights"):
197
- insights_btn = gr.Button("Generate Insights")
198
- insights_tbl = gr.Dataframe()
199
- insights_btn.click(fn=compute_insights, outputs=insights_tbl)
200
 
 
201
  with gr.Tab("User Management"):
202
- gr.Markdown("## 👤 Manage Users\nEdit the grid and click **Save Users** to push changes.")
203
- users_df = load_sheet("User")
204
- users_grid = gr.Dataframe(value=users_df, interactive=True)
205
  save_btn = gr.Button("Save Users")
206
- status = gr.Dataframe()
207
- save_btn.click(fn=save_users, inputs=users_grid, outputs=status)
208
 
209
- app.launch()
 
1
  import gradio as gr
2
  import pandas as pd
3
  import gspread
4
+ from gspread_dataframe import set_with_dataframe
5
  from oauth2client.service_account import ServiceAccountCredentials
6
  from datetime import datetime, timedelta
7
+ from collections import Counter
8
 
9
  # -------------------- AUTH --------------------
10
  scope = [
 
15
  "deep-mile-461309-t8-0e90103411e0.json", scope
16
  )
17
  client = gspread.authorize(creds)
18
+
19
+ # YOUR SPREADSHEET URL
20
+ SHEET_URL = "https://docs.google.com/spreadsheets/d/1if4KoVQvw5ZbhknfdZbzMkcTiPfsD6bz9V3a1th-bwQ"
21
 
22
  # -------------------- UTILS --------------------
23
+ def normalize_columns(cols):
24
+ return [c.strip().title() for c in cols]
25
+
26
+ def load_sheet_df(name):
27
+ """
28
+ Load a sheet into a DataFrame without confusing duplicates in
29
+ the header row. We fetch all values, dedupe the first row,
30
+ then build a DataFrame.
31
+ """
32
+ ws = client.open_by_url(SHEET_URL).worksheet(name)
33
+ data = ws.get_all_values()
34
+ if not data:
35
+ return pd.DataFrame()
36
+ raw_header, *rows = data
37
+ # make header unique
38
+ counts = Counter()
39
+ header = []
40
+ for col in raw_header:
41
+ counts[col] += 1
42
+ if counts[col] > 1:
43
+ header.append(f"{col}_{counts[col]}")
44
+ else:
45
+ header.append(col)
46
+ header = normalize_columns(header)
47
+ return pd.DataFrame(rows, columns=header)
48
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
49
  def get_current_week_range():
50
+ today = datetime.now().date()
51
  start = today - timedelta(days=today.weekday())
52
  end = start + timedelta(days=6)
53
+ return start, end
54
 
55
+ def filter_by_week(df, date_col, rep=None):
56
  if date_col not in df.columns:
57
+ return pd.DataFrame([{"Error": f"Missing '{date_col}' column"}])
58
+ df = df.copy()
59
+ df[date_col] = pd.to_datetime(df[date_col], errors="coerce").dt.date
60
  start, end = get_current_week_range()
61
+ m = df[date_col].between(start, end)
62
+ if rep:
63
+ m &= df.get("Rep", pd.Series()).astype(str) == rep
64
+ return df[m]
65
 
66
+ def filter_by_date(df, date_col, y, m, d, rep=None):
67
  try:
68
  target = datetime(int(y), int(m), int(d)).date()
69
  except:
70
+ return pd.DataFrame([{"Error": "Invalid date"}])
71
  if date_col not in df.columns:
72
  return pd.DataFrame([{"Error": f"Missing '{date_col}' column"}])
73
+ df = df.copy()
74
+ df[date_col] = pd.to_datetime(df[date_col], errors="coerce").dt.date
75
+ m = df[date_col] == target
76
+ if rep:
77
+ m &= df.get("Rep", pd.Series()).astype(str) == rep
78
+ return df[m]
79
+
80
+ def rep_choices(sheet, col="Rep"):
81
+ df = load_sheet_df(sheet)
82
+ return sorted(df[col].dropna().unique().tolist()) if col in df else []
83
 
84
  # -------------------- REPORT FUNCTIONS --------------------
85
  def get_calls(rep=None):
86
+ df = load_sheet_df("Calls")
87
+ return filter_by_week(df, "Call Date", rep)
88
 
89
  def get_appointments(rep=None):
90
+ df = load_sheet_df("Appointments")
91
+ return filter_by_week(df, "Appointment Date", rep)
 
 
 
 
92
 
93
+ def search_calls(y, m, d, rep=None):
94
+ df = load_sheet_df("Calls")
95
+ return filter_by_date(df, "Call Date", y, m, d, rep)
96
 
97
+ def search_appointments(y, m, d, rep=None):
98
+ df = load_sheet_df("Appointments")
99
+ return filter_by_date(df, "Appointment Date", y, m, d, rep)
100
 
101
+ # -------------------- LEADS --------------------
102
  def get_leads_detail():
103
+ df = load_sheet_df("AllocatedLeads")
104
  return df
105
 
106
  def get_leads_summary():
107
  df = get_leads_detail()
108
+ if "Assigned Rep" not in df:
109
  return pd.DataFrame([{"Error": "Missing 'Assigned Rep'"}])
110
  return df.groupby("Assigned Rep").size().reset_index(name="Leads Count")
111
 
 
114
  calls = get_calls()
115
  appts = get_appointments()
116
  leads = get_leads_detail()
117
+
118
+ def top(df, col="Rep"):
119
+ if col in df and not df.empty:
120
+ vc = df[col].value_counts()
121
+ return vc.idxmax() if not vc.empty else "N/A"
 
122
  return "N/A"
123
+
124
+ data = [
125
  {"Metric": "Most Calls This Week", "Rep": top(calls, "Rep")},
126
  {"Metric": "Most Appointments This Week", "Rep": top(appts, "Rep")},
127
  {"Metric": "Most Leads Allocated", "Rep": top(leads, "Assigned Rep")},
128
+ ]
129
+ return pd.DataFrame(data)
 
 
 
 
 
 
 
130
 
131
  # -------------------- USER MANAGEMENT --------------------
132
+ def load_users():
133
+ df = load_sheet_df("User")
134
+ # select & rename your columns as needed
135
+ want = [
136
+ "Id", "Email", "Name", "Business", "Role",
137
+ "Daily Phone Call Target", "Daily Phone Appointment Target",
138
+ "Daily Quote Number Target", "Daily Quote Revenue Target",
139
+ "Weekly Phone Call Target", "Weekly Phone Appointment Target",
140
+ "Weekly Quote Number Target", "Weekly Quote Revenue Target",
141
+ "Monthly Phone Call Target", "Monthly Phone Appointment Target",
142
+ "Monthly Quote Number Target", "Monthly Quote Revenue Target",
143
+ "Monthly Sales Revenue Target"
144
+ ]
145
+ exist = [c for c in want if c in df.columns]
146
+ return df[exist]
147
+
148
  def save_users(df):
149
+ ws = client.open_by_url(SHEET_URL).worksheet("User")
 
 
150
  ws.clear()
151
+ set_with_dataframe(ws, df) # writes headers + data
152
+ return " Users saved!"
153
 
154
+ # -------------------- UI LAYOUT --------------------
155
  with gr.Blocks(title="Graffiti Admin Dashboard") as app:
156
  gr.Markdown("# 📆 Graffiti Admin Dashboard")
157
 
158
+ # -- Calls Tab --
159
  with gr.Tab("Calls Report"):
160
+ rep_c = gr.Dropdown(choices=rep_choices("Calls"), label="Filter by Rep", allow_custom_value=True)
161
+ btn_c = gr.Button("Load This Week’s Calls")
162
+ tbl_c = gr.Dataframe()
163
+ btn_c.click(get_calls, rep_c, tbl_c)
164
+
165
+ gr.Markdown("### Search Calls by Date")
166
+ y1, m1, d1 = gr.Textbox(label="Year"), gr.Textbox(label="Month"), gr.Textbox(label="Day")
167
+ rep_c2 = gr.Dropdown(choices=rep_choices("Calls"), label="Filter by Rep", allow_custom_value=True)
168
+ btn_c2 = gr.Button("Search")
169
+ tbl_c2 = gr.Dataframe()
170
+ btn_c2.click(search_calls, [y1, m1, d1, rep_c2], tbl_c2)
171
+
172
+ # -- Appointments Tab --
 
 
 
 
 
173
  with gr.Tab("Appointments Report"):
174
+ rep_a = gr.Dropdown(choices=rep_choices("Appointments"), label="Filter by Rep", allow_custom_value=True)
175
+ btn_a = gr.Button("Load This Week’s Appts")
176
+ sum_a = gr.Dataframe(label="📊 Appts by Rep")
177
+ tbl_a = gr.Dataframe()
178
+ def _load_appts(r):
179
+ df = get_appointments(r)
180
+ return df.groupby("Rep").size().reset_index(name="Count"), df
181
+ btn_a.click(_load_appts, rep_a, [sum_a, tbl_a])
182
+
183
+ gr.Markdown("### Search Appts by Date")
184
+ y2, m2, d2 = gr.Textbox(label="Year"), gr.Textbox(label="Month"), gr.Textbox(label="Day")
185
+ rep_a2 = gr.Dropdown(choices=rep_choices("Appointments"), label="Filter by Rep", allow_custom_value=True)
186
+ btn_a2 = gr.Button("Search")
187
+ sum_a2 = gr.Dataframe(label="📊 Appts by Rep")
188
+ tbl_a2 = gr.Dataframe()
189
+ def _search_appts(y,m,d,r):
190
+ df = search_appointments(y,m,d,r)
191
+ return df.groupby("Rep").size().reset_index(name="Count"), df
192
+ btn_a2.click(_search_appts, [y2,m2,d2,rep_a2], [sum_a2, tbl_a2])
193
+
194
+ # -- Appointed Leads --
 
 
 
 
 
 
 
 
 
 
 
 
195
  with gr.Tab("Appointed Leads"):
196
+ btn_l = gr.Button("View Leads")
197
+ sum_l = gr.Dataframe(label="📊 Leads by Rep")
198
+ det_l = gr.Dataframe(label="🔎 Details")
199
+ btn_l.click(lambda: (get_leads_summary(), get_leads_detail()), None, [sum_l, det_l])
 
200
 
201
+ # -- Insights --
202
  with gr.Tab("Insights"):
203
+ btn_i = gr.Button("Generate Insights")
204
+ out_i = gr.Dataframe()
205
+ btn_i.click(compute_insights, None, out_i)
206
 
207
+ # -- User Management --
208
  with gr.Tab("User Management"):
209
+ gr.Markdown("## 👤 Manage Users\nEdit the grid below then click **Save Users** to push back to the sheet.")
210
+ users_tbl = gr.Dataframe(value=load_users(), interactive=True)
 
211
  save_btn = gr.Button("Save Users")
212
+ save_out = gr.Textbox()
213
+ save_btn.click(save_users, users_tbl, save_out)
214
 
215
+ app.launch()