geethareddy commited on
Commit
ff01f98
·
verified ·
1 Parent(s): 3023b63

Update app.py

Browse files
Files changed (1) hide show
  1. app.py +48 -129
app.py CHANGED
@@ -8,35 +8,35 @@ from dotenv import load_dotenv
8
  # Load environment variables
9
  load_dotenv()
10
 
11
- # Check if required environment variables are set
12
  required_env_vars = ['SF_USERNAME', 'SF_PASSWORD', 'SF_SECURITY_TOKEN']
13
  missing_vars = [var for var in required_env_vars if not os.getenv(var)]
14
  if missing_vars:
15
  raise EnvironmentError(f"Missing required environment variables: {missing_vars}")
16
 
17
- # Get configurable values for KPI_Flag__c and Engagement_Score__c
18
- KPI_FLAG_DEFAULT = os.getenv('KPI_FLAG', 'True') == 'True' # Default to True if not set
19
- ENGAGEMENT_SCORE_DEFAULT = float(os.getenv('ENGAGEMENT_SCORE', '85.0')) # Default to 85.0
20
 
21
- # Initialize model and tokenizer
22
  model_name = "distilgpt2"
23
- tokenizer = AutoTokenizer.from_pretrained(model_name)
24
- model = AutoModelForCausalLM.from_pretrained(model_name)
25
 
26
- # Avoid warnings by setting pad token
27
  if tokenizer.pad_token is None:
28
- tokenizer.pad_token = tokenizer.eos_token if tokenizer.eos_token else "[PAD]"
29
  tokenizer.pad_token_id = tokenizer.convert_tokens_to_ids(tokenizer.pad_token)
30
  model.config.pad_token_id = tokenizer.pad_token_id
31
 
32
- # Prompt template for generating structured output
33
  PROMPT_TEMPLATE = """You are an AI coach for construction supervisors. Based on the following inputs, generate a daily checklist, focus suggestions, and a motivational quote.
34
  Inputs:
35
  Role: {role}
36
  Project: {project_id}
37
  Milestones: {milestones}
38
  Reflection: {reflection}
39
- Format your response clearly like this:
40
  Checklist:
41
  - {milestones_list}
42
  Suggestions:
@@ -45,7 +45,7 @@ Quote:
45
  - Your motivational quote here
46
  """
47
 
48
- # Function to get all roles from Salesforce
49
  def get_roles_from_salesforce():
50
  try:
51
  sf = Salesforce(
@@ -54,23 +54,14 @@ def get_roles_from_salesforce():
54
  security_token=os.getenv('SF_SECURITY_TOKEN'),
55
  domain=os.getenv('SF_DOMAIN', 'login')
56
  )
57
-
58
- # Query distinct Role__c values
59
  result = sf.query("SELECT Role__c FROM Supervisor__c WHERE Role__c != NULL")
60
-
61
- # Extract roles and remove duplicates
62
  roles = list(set(record['Role__c'] for record in result.get('records', [])))
63
-
64
- print(f"✅ Fetched {len(roles)} unique roles from Salesforce")
65
  return roles
66
-
67
  except Exception as e:
68
- print(f"⚠️ Error fetching roles from Salesforce: {e}")
69
- print("Using fallback roles...")
70
- return ["Site Manager", "Safety Officer", "Project Lead"] # Match actual active roles
71
-
72
 
73
- # Function to get supervisor's Name (Auto Number) by role
74
  def get_supervisor_name_by_role(role):
75
  try:
76
  sf = Salesforce(
@@ -79,81 +70,51 @@ def get_supervisor_name_by_role(role):
79
  security_token=os.getenv('SF_SECURITY_TOKEN'),
80
  domain=os.getenv('SF_DOMAIN', 'login')
81
  )
82
-
83
- # Escape single quotes in the role to prevent SOQL injection
84
  role = role.replace("'", "\\'")
85
-
86
- # Query all supervisors for the selected role
87
  result = sf.query(f"SELECT Name FROM Supervisor__c WHERE Role__c = '{role}'")
88
  if result['totalSize'] == 0:
89
- print("❌ No matching supervisors found.")
90
  return []
91
-
92
- # Extract all supervisor names
93
- supervisor_names = [record['Name'] for record in result['records']]
94
- print(f"✅ Found supervisors: {supervisor_names} for role: {role}")
95
- return supervisor_names
96
-
97
  except Exception as e:
98
  print(f"⚠️ Error fetching supervisor names: {e}")
99
  return []
100
 
101
-
102
- # Function to get project IDs and names assigned to selected supervisor
103
  def get_projects_for_supervisor(supervisor_name):
104
  try:
105
- # Use the selected supervisor name to fetch the associated project
106
  sf = Salesforce(
107
  username=os.getenv('SF_USERNAME'),
108
  password=os.getenv('SF_PASSWORD'),
109
  security_token=os.getenv('SF_SECURITY_TOKEN'),
110
  domain=os.getenv('SF_DOMAIN', 'login')
111
  )
112
-
113
- # Escape single quotes in the supervisor_name
114
  supervisor_name = supervisor_name.replace("'", "\\'")
115
-
116
- # Step 1: Get the Salesforce record ID of the supervisor based on the Name
117
  supervisor_result = sf.query(f"SELECT Id FROM Supervisor__c WHERE Name = '{supervisor_name}' LIMIT 1")
118
  if supervisor_result['totalSize'] == 0:
119
- print("❌ No supervisor found with the given name.")
120
  return ""
121
-
122
  supervisor_id = supervisor_result['records'][0]['Id']
123
-
124
- # Step 2: Query Project__c records where Supervisor_ID__c matches the supervisor's record ID
125
  project_result = sf.query(f"SELECT Name FROM Project__c WHERE Supervisor_ID__c = '{supervisor_id}' LIMIT 1")
126
-
127
  if project_result['totalSize'] == 0:
128
- print("❌ No project found for supervisor.")
129
  return ""
130
-
131
- project_name = project_result['records'][0]['Name']
132
- print(f"✅ Found project: {project_name} for supervisor: {supervisor_name}")
133
- return project_name
134
-
135
  except Exception as e:
136
- print(f"⚠️ Error fetching project for supervisor: {e}")
137
  return ""
138
 
139
-
140
- # Function to generate AI-based coaching output
141
  def generate_outputs(role, supervisor_name, project_id, milestones, reflection):
142
  if not all([role, supervisor_name, project_id, milestones, reflection]):
143
  return "Error: All fields are required.", "", ""
144
 
145
- # Format the prompt
146
  milestones_list = "\n- ".join([m.strip() for m in milestones.split(",")])
147
-
148
  suggestions_list = ""
149
  if "delays" in reflection.lower():
150
- suggestions_list = "- Consider adjusting timelines to accommodate delays.\n- Communicate delays to all relevant stakeholders."
151
  elif "weather" in reflection.lower():
152
- suggestions_list = "- Ensure team has rain gear.\n- Monitor weather updates for possible further delays."
153
  elif "equipment" in reflection.lower():
154
- suggestions_list = "- Inspect all equipment to ensure no malfunctions.\n- Schedule maintenance if necessary."
155
 
156
- # Fill in the prompt template
157
  prompt = PROMPT_TEMPLATE.format(
158
  role=role,
159
  project_id=project_id,
@@ -163,30 +124,28 @@ def generate_outputs(role, supervisor_name, project_id, milestones, reflection):
163
  suggestions_list=suggestions_list
164
  )
165
 
166
- # Tokenize input
167
- inputs = tokenizer(prompt, return_tensors="pt", max_length=512, truncation=True, padding=True)
168
 
169
- # Generate response
170
  try:
171
  with torch.no_grad():
172
  outputs = model.generate(
173
  inputs['input_ids'],
174
- max_length=1024, # Increased to allow for longer outputs
175
  num_return_sequences=1,
176
  no_repeat_ngram_size=2,
177
  do_sample=True,
178
- top_p=0.9,
179
- temperature=0.8,
180
  pad_token_id=tokenizer.pad_token_id
181
  )
182
-
183
  generated_text = tokenizer.decode(outputs[0], skip_special_tokens=True)
184
-
185
  except Exception as e:
186
- print(f"⚠️ Error during model generation: {e}")
187
  return "Error: Failed to generate outputs.", "", ""
188
 
189
- # Parse sections
190
  def extract_section(text, start_marker, end_marker):
191
  start = text.find(start_marker)
192
  if start == -1:
@@ -204,20 +163,16 @@ def generate_outputs(role, supervisor_name, project_id, milestones, reflection):
204
 
205
  return checklist, suggestions, quote
206
 
207
-
208
- # Function to check if a field exists in a Salesforce object
209
  def field_exists(sf, object_name, field_name):
210
  try:
211
- # Describe the object to get its fields
212
  obj_desc = getattr(sf, object_name).describe()
213
- fields = [field['name'] for field in obj_desc['fields']]
214
- return field_name in fields
215
  except Exception as e:
216
- print(f"⚠️ Error checking if field {field_name} exists in {object_name}: {e}")
217
  return False
218
 
219
-
220
- # Function to create a record in Salesforce
221
  def save_to_salesforce(role, project_id, milestones, reflection, checklist, suggestions, quote, supervisor_name):
222
  try:
223
  sf = Salesforce(
@@ -226,125 +181,89 @@ def save_to_salesforce(role, project_id, milestones, reflection, checklist, sugg
226
  security_token=os.getenv('SF_SECURITY_TOKEN'),
227
  domain=os.getenv('SF_DOMAIN', 'login')
228
  )
229
-
230
- # Escape single quotes in supervisor_name and project_id
231
  supervisor_name = supervisor_name.replace("'", "\\'")
232
  project_id = project_id.replace("'", "\\'")
233
-
234
- # Step 1: Get the Salesforce record ID for the supervisor
235
  supervisor_result = sf.query(f"SELECT Id FROM Supervisor__c WHERE Name = '{supervisor_name}' LIMIT 1")
236
  if supervisor_result['totalSize'] == 0:
237
- print(f"❌ No supervisor found with Name: {supervisor_name}")
238
  return
239
-
240
  supervisor_id = supervisor_result['records'][0]['Id']
241
-
242
- # Step 2: Get the Salesforce record ID for the project
243
  project_result = sf.query(f"SELECT Id FROM Project__c WHERE Name = '{project_id}' LIMIT 1")
244
  if project_result['totalSize'] == 0:
245
- print(f"❌ No project found with Name: {project_id}")
246
  return
247
-
248
  project_record_id = project_result['records'][0]['Id']
249
 
250
- # Truncate text fields to avoid exceeding Salesforce field length limits (assuming 255 characters for simplicity)
251
  MAX_TEXT_LENGTH = 255
252
  checklist = checklist[:MAX_TEXT_LENGTH] if checklist else ""
253
  suggestions = suggestions[:MAX_TEXT_LENGTH] if suggestions else ""
254
  reflection = reflection[:MAX_TEXT_LENGTH] if reflection else ""
255
 
256
- # Prepare data for Salesforce with explicit mapping
257
  data = {
258
- 'Supervisor_ID__c': supervisor_id, # Lookup field expects the record ID of Supervisor__c
259
- 'Project_ID__c': project_record_id, # Lookup field expects the record ID of Project__c
260
- 'Daily_Checklist__c': checklist, # Maps to the generated Daily Checklist
261
- 'Suggested_Tips__c': suggestions, # Maps to the generated Focus Suggestions
262
- 'Reflection_Log__c': reflection, # Maps to the Reflection Log input
263
- 'KPI_Flag__c': KPI_FLAG_DEFAULT, # Configurable via .env
264
- 'Engagement_Score__c': ENGAGEMENT_SCORE_DEFAULT # Configurable via .env
265
  }
266
 
267
- # Check if Milestones_KPIs__c field exists before mapping
268
  if field_exists(sf, 'Supervisor_AI_Coaching__c', 'Milestones_KPIs__c'):
269
- # Truncate milestones as well if the field exists
270
  milestones = milestones[:MAX_TEXT_LENGTH] if milestones else ""
271
  data['Milestones_KPIs__c'] = milestones
272
- else:
273
- print("⚠️ Milestones_KPIs__c field does not exist in Supervisor_AI_Coaching__c. Skipping mapping.")
274
-
275
- # Create record
276
- response = sf.Supervisor_AI_Coaching__c.create(data)
277
- print("✅ Record created successfully in Salesforce.")
278
- print("Record ID:", response['id'])
279
 
 
 
280
  except Exception as e:
281
  print(f"❌ Error saving to Salesforce: {e}")
282
- print("Data being sent:", data)
283
- if hasattr(e, 'content'):
284
- print("Salesforce API response:", e.content)
285
 
286
-
287
- # Gradio Interface
288
  def create_interface():
289
- # Fetch roles from Salesforce
290
  roles = get_roles_from_salesforce()
291
- print(f"Fetched Roles: {roles}")
292
-
293
  with gr.Blocks(theme="soft") as demo:
294
  gr.Markdown("# 🏗️ Construction Supervisor AI Coach")
295
- gr.Markdown("Enter details to generate a daily checklist, focus suggestions, and a motivational quote.")
296
-
297
  with gr.Row():
298
  role = gr.Dropdown(choices=roles, label="Role")
299
  supervisor_name = gr.Dropdown(choices=[], label="Supervisor Name")
300
  project_id = gr.Textbox(label="Project ID", interactive=False)
301
-
302
  milestones = gr.Textbox(label="Milestones (comma-separated KPIs)")
303
  reflection = gr.Textbox(label="Reflection Log", lines=4)
304
-
305
  with gr.Row():
306
  submit = gr.Button("Generate", variant="primary")
307
  clear = gr.Button("Clear")
308
  refresh_btn = gr.Button("🔄 Refresh Roles")
309
-
310
  checklist_output = gr.Textbox(label="✅ Daily Checklist")
311
  suggestions_output = gr.Textbox(label="💡 Focus Suggestions")
312
  quote_output = gr.Textbox(label="✨ Motivational Quote")
313
 
314
- # Event: When role changes, update supervisor name dropdown
315
  role.change(
316
  fn=lambda r: gr.update(choices=get_supervisor_name_by_role(r)),
317
  inputs=[role],
318
  outputs=[supervisor_name]
319
  )
320
-
321
- # Event: When supervisor name changes, update project ID
322
  supervisor_name.change(
323
  fn=get_projects_for_supervisor,
324
  inputs=[supervisor_name],
325
  outputs=[project_id]
326
  )
327
-
328
  submit.click(
329
  fn=generate_outputs,
330
  inputs=[role, supervisor_name, project_id, milestones, reflection],
331
  outputs=[checklist_output, suggestions_output, quote_output]
332
  )
333
-
334
  clear.click(
335
  fn=lambda: ("", "", "", "", ""),
336
  inputs=None,
337
  outputs=[role, supervisor_name, project_id, milestones, reflection]
338
  )
339
-
340
  refresh_btn.click(
341
  fn=lambda: gr.update(choices=get_roles_from_salesforce()),
342
  outputs=role
343
  )
344
-
345
  return demo
346
 
347
-
348
  if __name__ == "__main__":
349
  app = create_interface()
350
  app.launch()
 
8
  # Load environment variables
9
  load_dotenv()
10
 
11
+ # Check for required environment variables
12
  required_env_vars = ['SF_USERNAME', 'SF_PASSWORD', 'SF_SECURITY_TOKEN']
13
  missing_vars = [var for var in required_env_vars if not os.getenv(var)]
14
  if missing_vars:
15
  raise EnvironmentError(f"Missing required environment variables: {missing_vars}")
16
 
17
+ # Configurable defaults
18
+ KPI_FLAG_DEFAULT = os.getenv('KPI_FLAG', 'True') == 'True'
19
+ ENGAGEMENT_SCORE_DEFAULT = float(os.getenv('ENGAGEMENT_SCORE', '85.0'))
20
 
21
+ # Initialize model and tokenizer with optimized settings
22
  model_name = "distilgpt2"
23
+ tokenizer = AutoTokenizer.from_pretrained(model_name, use_fast=True) # Use fast tokenizer
24
+ model = AutoModelForCausalLM.from_pretrained(model_name, low_cpu_mem_usage=True) # Optimize memory usage
25
 
26
+ # Set pad token
27
  if tokenizer.pad_token is None:
28
+ tokenizer.pad_token = tokenizer.eos_token or "[PAD]"
29
  tokenizer.pad_token_id = tokenizer.convert_tokens_to_ids(tokenizer.pad_token)
30
  model.config.pad_token_id = tokenizer.pad_token_id
31
 
32
+ # Prompt template
33
  PROMPT_TEMPLATE = """You are an AI coach for construction supervisors. Based on the following inputs, generate a daily checklist, focus suggestions, and a motivational quote.
34
  Inputs:
35
  Role: {role}
36
  Project: {project_id}
37
  Milestones: {milestones}
38
  Reflection: {reflection}
39
+ Format:
40
  Checklist:
41
  - {milestones_list}
42
  Suggestions:
 
45
  - Your motivational quote here
46
  """
47
 
48
+ # Fetch roles from Salesforce
49
  def get_roles_from_salesforce():
50
  try:
51
  sf = Salesforce(
 
54
  security_token=os.getenv('SF_SECURITY_TOKEN'),
55
  domain=os.getenv('SF_DOMAIN', 'login')
56
  )
 
 
57
  result = sf.query("SELECT Role__c FROM Supervisor__c WHERE Role__c != NULL")
 
 
58
  roles = list(set(record['Role__c'] for record in result.get('records', [])))
 
 
59
  return roles
 
60
  except Exception as e:
61
+ print(f"⚠️ Error fetching roles: {e}")
62
+ return ["Site Manager", "Safety Officer", "Project Lead"]
 
 
63
 
64
+ # Fetch supervisor names by role
65
  def get_supervisor_name_by_role(role):
66
  try:
67
  sf = Salesforce(
 
70
  security_token=os.getenv('SF_SECURITY_TOKEN'),
71
  domain=os.getenv('SF_DOMAIN', 'login')
72
  )
 
 
73
  role = role.replace("'", "\\'")
 
 
74
  result = sf.query(f"SELECT Name FROM Supervisor__c WHERE Role__c = '{role}'")
75
  if result['totalSize'] == 0:
 
76
  return []
77
+ return [record['Name'] for record in result['records']]
 
 
 
 
 
78
  except Exception as e:
79
  print(f"⚠️ Error fetching supervisor names: {e}")
80
  return []
81
 
82
+ # Fetch project for supervisor
 
83
  def get_projects_for_supervisor(supervisor_name):
84
  try:
 
85
  sf = Salesforce(
86
  username=os.getenv('SF_USERNAME'),
87
  password=os.getenv('SF_PASSWORD'),
88
  security_token=os.getenv('SF_SECURITY_TOKEN'),
89
  domain=os.getenv('SF_DOMAIN', 'login')
90
  )
 
 
91
  supervisor_name = supervisor_name.replace("'", "\\'")
 
 
92
  supervisor_result = sf.query(f"SELECT Id FROM Supervisor__c WHERE Name = '{supervisor_name}' LIMIT 1")
93
  if supervisor_result['totalSize'] == 0:
 
94
  return ""
 
95
  supervisor_id = supervisor_result['records'][0]['Id']
 
 
96
  project_result = sf.query(f"SELECT Name FROM Project__c WHERE Supervisor_ID__c = '{supervisor_id}' LIMIT 1")
 
97
  if project_result['totalSize'] == 0:
 
98
  return ""
99
+ return project_result['records'][0]['Name']
 
 
 
 
100
  except Exception as e:
101
+ print(f"⚠️ Error fetching project: {e}")
102
  return ""
103
 
104
+ # Generate AI outputs
 
105
  def generate_outputs(role, supervisor_name, project_id, milestones, reflection):
106
  if not all([role, supervisor_name, project_id, milestones, reflection]):
107
  return "Error: All fields are required.", "", ""
108
 
 
109
  milestones_list = "\n- ".join([m.strip() for m in milestones.split(",")])
 
110
  suggestions_list = ""
111
  if "delays" in reflection.lower():
112
+ suggestions_list = "- Adjust timelines for delays.\n- Inform stakeholders."
113
  elif "weather" in reflection.lower():
114
+ suggestions_list = "- Ensure rain gear availability.\n- Monitor weather updates."
115
  elif "equipment" in reflection.lower():
116
+ suggestions_list = "- Inspect equipment.\n- Schedule maintenance."
117
 
 
118
  prompt = PROMPT_TEMPLATE.format(
119
  role=role,
120
  project_id=project_id,
 
124
  suggestions_list=suggestions_list
125
  )
126
 
127
+ # Tokenize with optimized settings
128
+ inputs = tokenizer(prompt, return_tensors="pt", max_length=256, truncation=True, padding=True)
129
 
130
+ # Faster generation with adjusted parameters
131
  try:
132
  with torch.no_grad():
133
  outputs = model.generate(
134
  inputs['input_ids'],
135
+ max_length=512, # Reduced for speed
136
  num_return_sequences=1,
137
  no_repeat_ngram_size=2,
138
  do_sample=True,
139
+ top_p=0.85, # Slightly tighter for faster convergence
140
+ temperature=0.7, # Lower for more deterministic output
141
  pad_token_id=tokenizer.pad_token_id
142
  )
 
143
  generated_text = tokenizer.decode(outputs[0], skip_special_tokens=True)
 
144
  except Exception as e:
145
+ print(f"⚠️ Error during generation: {e}")
146
  return "Error: Failed to generate outputs.", "", ""
147
 
148
+ # Extract sections
149
  def extract_section(text, start_marker, end_marker):
150
  start = text.find(start_marker)
151
  if start == -1:
 
163
 
164
  return checklist, suggestions, quote
165
 
166
+ # Check if Salesforce field exists
 
167
  def field_exists(sf, object_name, field_name):
168
  try:
 
169
  obj_desc = getattr(sf, object_name).describe()
170
+ return field_name in [field['name'] for field in obj_desc['fields']]
 
171
  except Exception as e:
172
+ print(f"⚠️ Error checking field {field_name}: {e}")
173
  return False
174
 
175
+ # Save to Salesforce
 
176
  def save_to_salesforce(role, project_id, milestones, reflection, checklist, suggestions, quote, supervisor_name):
177
  try:
178
  sf = Salesforce(
 
181
  security_token=os.getenv('SF_SECURITY_TOKEN'),
182
  domain=os.getenv('SF_DOMAIN', 'login')
183
  )
 
 
184
  supervisor_name = supervisor_name.replace("'", "\\'")
185
  project_id = project_id.replace("'", "\\'")
 
 
186
  supervisor_result = sf.query(f"SELECT Id FROM Supervisor__c WHERE Name = '{supervisor_name}' LIMIT 1")
187
  if supervisor_result['totalSize'] == 0:
188
+ print(f"❌ No supervisor found: {supervisor_name}")
189
  return
 
190
  supervisor_id = supervisor_result['records'][0]['Id']
 
 
191
  project_result = sf.query(f"SELECT Id FROM Project__c WHERE Name = '{project_id}' LIMIT 1")
192
  if project_result['totalSize'] == 0:
193
+ print(f"❌ No project found: {project_id}")
194
  return
 
195
  project_record_id = project_result['records'][0]['Id']
196
 
 
197
  MAX_TEXT_LENGTH = 255
198
  checklist = checklist[:MAX_TEXT_LENGTH] if checklist else ""
199
  suggestions = suggestions[:MAX_TEXT_LENGTH] if suggestions else ""
200
  reflection = reflection[:MAX_TEXT_LENGTH] if reflection else ""
201
 
 
202
  data = {
203
+ 'Supervisor_ID__c': supervisor_id,
204
+ 'Project_ID__c': project_record_id,
205
+ 'Daily_Checklist__c': checklist,
206
+ 'Suggested_Tips__c': suggestions,
207
+ 'Reflection_Log__c': reflection,
208
+ 'KPI_Flag__c': KPI_FLAG_DEFAULT,
209
+ 'Engagement_Score__c': ENGAGEMENT_SCORE_DEFAULT
210
  }
211
 
 
212
  if field_exists(sf, 'Supervisor_AI_Coaching__c', 'Milestones_KPIs__c'):
 
213
  milestones = milestones[:MAX_TEXT_LENGTH] if milestones else ""
214
  data['Milestones_KPIs__c'] = milestones
 
 
 
 
 
 
 
215
 
216
+ sf.Supervisor_AI_Coaching__c.create(data)
217
+ print("✅ Record created in Salesforce.")
218
  except Exception as e:
219
  print(f"❌ Error saving to Salesforce: {e}")
 
 
 
220
 
221
+ # Create Gradio interface
 
222
  def create_interface():
 
223
  roles = get_roles_from_salesforce()
 
 
224
  with gr.Blocks(theme="soft") as demo:
225
  gr.Markdown("# 🏗️ Construction Supervisor AI Coach")
226
+ gr.Markdown("Enter details for daily checklist, suggestions, and quote.")
 
227
  with gr.Row():
228
  role = gr.Dropdown(choices=roles, label="Role")
229
  supervisor_name = gr.Dropdown(choices=[], label="Supervisor Name")
230
  project_id = gr.Textbox(label="Project ID", interactive=False)
 
231
  milestones = gr.Textbox(label="Milestones (comma-separated KPIs)")
232
  reflection = gr.Textbox(label="Reflection Log", lines=4)
 
233
  with gr.Row():
234
  submit = gr.Button("Generate", variant="primary")
235
  clear = gr.Button("Clear")
236
  refresh_btn = gr.Button("🔄 Refresh Roles")
 
237
  checklist_output = gr.Textbox(label="✅ Daily Checklist")
238
  suggestions_output = gr.Textbox(label="💡 Focus Suggestions")
239
  quote_output = gr.Textbox(label="✨ Motivational Quote")
240
 
 
241
  role.change(
242
  fn=lambda r: gr.update(choices=get_supervisor_name_by_role(r)),
243
  inputs=[role],
244
  outputs=[supervisor_name]
245
  )
 
 
246
  supervisor_name.change(
247
  fn=get_projects_for_supervisor,
248
  inputs=[supervisor_name],
249
  outputs=[project_id]
250
  )
 
251
  submit.click(
252
  fn=generate_outputs,
253
  inputs=[role, supervisor_name, project_id, milestones, reflection],
254
  outputs=[checklist_output, suggestions_output, quote_output]
255
  )
 
256
  clear.click(
257
  fn=lambda: ("", "", "", "", ""),
258
  inputs=None,
259
  outputs=[role, supervisor_name, project_id, milestones, reflection]
260
  )
 
261
  refresh_btn.click(
262
  fn=lambda: gr.update(choices=get_roles_from_salesforce()),
263
  outputs=role
264
  )
 
265
  return demo
266
 
 
267
  if __name__ == "__main__":
268
  app = create_interface()
269
  app.launch()