geethareddy commited on
Commit
77c2912
·
verified ·
1 Parent(s): 8430872

Update app.py

Browse files
Files changed (1) hide show
  1. app.py +84 -142
app.py CHANGED
@@ -3,12 +3,7 @@ import torch
3
  from transformers import AutoModelForCausalLM, AutoTokenizer
4
  from simple_salesforce import Salesforce
5
  import os
6
- import base64
7
- import datetime
8
  from dotenv import load_dotenv
9
- from fpdf import FPDF
10
- import shutil
11
- import html
12
 
13
  # Load environment variables
14
  load_dotenv()
@@ -19,8 +14,12 @@ missing_vars = [var for var in required_env_vars if not os.getenv(var)]
19
  if missing_vars:
20
  raise EnvironmentError(f"Missing required environment variables: {missing_vars}")
21
 
22
- # Load model and tokenizer
23
- model_name = "distilgpt2"
 
 
 
 
24
  tokenizer = AutoTokenizer.from_pretrained(model_name, use_fast=True)
25
  model = AutoModelForCausalLM.from_pretrained(model_name, low_cpu_mem_usage=True)
26
 
@@ -29,7 +28,7 @@ if tokenizer.pad_token is None:
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 assistant for construction supervisors. Given the role, project, milestones, and a reflection log, generate:
34
 
35
  1. A Daily Checklist with clear and concise tasks based on the role and milestones.
@@ -55,96 +54,7 @@ Suggestions:
55
  -
56
  """
57
 
58
- # Function to clean the text for PDF
59
- def clean_text_for_pdf(text):
60
- return html.unescape(text).encode('latin-1', 'replace').decode('latin-1')
61
-
62
- # Save report as PDF
63
- def save_report_as_pdf(role, supervisor_name, project_id, checklist, suggestions):
64
- now = datetime.datetime.now().strftime("%Y%m%d%H%M%S")
65
- filename = f"report_{supervisor_name}_{project_id}_{now}.pdf"
66
- file_path = f"./reports/{filename}"
67
- os.makedirs("reports", exist_ok=True)
68
-
69
- pdf = FPDF()
70
- pdf.add_page()
71
- pdf.set_font("Arial", 'B', 14)
72
- pdf.cell(200, 10, txt="Supervisor Daily Report", ln=True, align="C")
73
- pdf.set_font("Arial", size=12)
74
- pdf.cell(200, 10, txt=clean_text_for_pdf(f"Role: {role}"), ln=True)
75
- pdf.cell(200, 10, txt=clean_text_for_pdf(f"Supervisor: {supervisor_name}"), ln=True)
76
- pdf.cell(200, 10, txt=clean_text_for_pdf(f"Project ID: {project_id}"), ln=True)
77
- pdf.ln(5)
78
- pdf.set_font("Arial", 'B', 12)
79
- pdf.cell(200, 10, txt="Daily Checklist", ln=True)
80
- pdf.set_font("Arial", size=12)
81
- for line in checklist.split("\n"):
82
- pdf.multi_cell(0, 10, clean_text_for_pdf(line))
83
- pdf.ln(5)
84
- pdf.set_font("Arial", 'B', 12)
85
- pdf.cell(200, 10, txt="Focus Suggestions", ln=True)
86
- pdf.set_font("Arial", size=12)
87
- for line in suggestions.split("\n"):
88
- pdf.multi_cell(0, 10, clean_text_for_pdf(line))
89
- pdf.output(file_path)
90
-
91
- # Copy the file to a temporary directory for Gradio to access
92
- temp_pdf_path = "/tmp/" + os.path.basename(file_path) # Use /tmp/ or current directory for Gradio
93
- shutil.copy(file_path, temp_pdf_path)
94
-
95
- return temp_pdf_path, filename
96
-
97
- # Upload to Salesforce and update record with the generated URL
98
- def upload_pdf_to_salesforce_and_update_link(supervisor_name, project_id, pdf_path, pdf_name):
99
- try:
100
- sf = Salesforce(
101
- username=os.getenv('SF_USERNAME'),
102
- password=os.getenv('SF_PASSWORD'),
103
- security_token=os.getenv('SF_SECURITY_TOKEN'),
104
- domain=os.getenv('SF_DOMAIN', 'login')
105
- )
106
-
107
- # Read and encode the file as base64
108
- with open(pdf_path, "rb") as f:
109
- encoded = base64.b64encode(f.read()).decode()
110
-
111
- # Create ContentVersion record to upload the PDF to Salesforce
112
- content = sf.ContentVersion.create({
113
- 'Title': pdf_name,
114
- 'PathOnClient': pdf_name,
115
- 'VersionData': encoded
116
- })
117
-
118
- # Get the ContentDocumentId for the uploaded PDF
119
- content_id = content['id']
120
-
121
- # Generate the download URL for the uploaded PDF
122
- download_url = f"https://{sf.sf_instance}/sfc/servlet.shepherd/version/download/{content_id}"
123
-
124
- # Query Salesforce to find the specific Supervisor_AI_Coaching__c record
125
- query = sf.query(f"""
126
- SELECT Id FROM Supervisor_AI_Coaching__c
127
- WHERE Project_ID__c = '{project_id}'
128
- AND Name = '{supervisor_name}'
129
- LIMIT 1
130
- """)
131
-
132
- if query['totalSize'] > 0:
133
- # Get the ID of the Supervisor_AI_Coaching__c record
134
- coaching_id = query['records'][0]['Id']
135
-
136
- # Update the Supervisor_AI_Coaching__c record with the download URL
137
- sf.Supervisor_AI_Coaching__c.update(coaching_id, {
138
- 'Download_Link__c': download_url # Update the Download_Link__c field with the URL
139
- })
140
-
141
- return download_url
142
-
143
- except Exception as e:
144
- print(f"⚠️ Upload error: {e}")
145
- return ""
146
-
147
- # Salesforce helpers
148
  def get_roles_from_salesforce():
149
  try:
150
  sf = Salesforce(
@@ -157,7 +67,7 @@ def get_roles_from_salesforce():
157
  return list(set(record['Role__c'] for record in result['records']))
158
  except Exception as e:
159
  print(f"⚠️ Error fetching roles: {e}")
160
- return []
161
 
162
  def get_supervisor_name_by_role(role):
163
  try:
@@ -167,10 +77,11 @@ def get_supervisor_name_by_role(role):
167
  security_token=os.getenv('SF_SECURITY_TOKEN'),
168
  domain=os.getenv('SF_DOMAIN', 'login')
169
  )
 
170
  result = sf.query(f"SELECT Name FROM Supervisor__c WHERE Role__c = '{role}'")
171
  return [record['Name'] for record in result['records']]
172
  except Exception as e:
173
- print(f"⚠️ Error fetching names: {e}")
174
  return []
175
 
176
  def get_projects_for_supervisor(supervisor_name):
@@ -181,36 +92,54 @@ def get_projects_for_supervisor(supervisor_name):
181
  security_token=os.getenv('SF_SECURITY_TOKEN'),
182
  domain=os.getenv('SF_DOMAIN', 'login')
183
  )
184
- result = sf.query(f"SELECT Id FROM Supervisor__c WHERE Name = '{supervisor_name}' LIMIT 1")
185
- if result['totalSize'] == 0:
 
186
  return ""
187
- supervisor_id = result['records'][0]['Id']
188
  project_result = sf.query(f"SELECT Name FROM Project__c WHERE Supervisor_ID__c = '{supervisor_id}' LIMIT 1")
189
  return project_result['records'][0]['Name'] if project_result['totalSize'] > 0 else ""
190
  except Exception as e:
191
  print(f"⚠️ Error fetching project: {e}")
192
  return ""
193
 
194
- # Generate Salesforce dashboard URL
 
 
 
 
 
 
 
 
195
  def generate_salesforce_dashboard_url(supervisor_name, project_id):
 
196
  return f"https://aicoachforsitesupervisors-dev-ed--c.develop.vf.force.com/apex/DashboardPage?supervisorName={supervisor_name}&projectId={project_id}"
197
 
 
198
  def open_dashboard(role, supervisor_name, project_id):
199
- url = generate_salesforce_dashboard_url(supervisor_name, project_id)
200
- return f'<a href="{url}" target="_blank">Open Salesforce Dashboard</a>'
 
201
 
202
- # Generate AI output and return the correct file for download
203
  def generate_outputs(role, supervisor_name, project_id, milestones, reflection):
204
  if not all([role, supervisor_name, project_id, milestones, reflection]):
205
- return "❗ Please fill all fields.", "", None, ""
 
 
 
 
 
 
 
206
 
207
- prompt = PROMPT_TEMPLATE.format(role=role, project_id=project_id, milestones=milestones, reflection=reflection)
208
  inputs = tokenizer(prompt, return_tensors="pt", padding=True, truncation=True, max_length=512)
209
  try:
210
  with torch.no_grad():
211
  outputs = model.generate(
212
  inputs['input_ids'],
213
- max_new_tokens=150,
214
  no_repeat_ngram_size=2,
215
  do_sample=True,
216
  top_p=0.9,
@@ -220,31 +149,55 @@ def generate_outputs(role, supervisor_name, project_id, milestones, reflection):
220
  result = tokenizer.decode(outputs[0], skip_special_tokens=True)
221
  except Exception as e:
222
  print(f"⚠️ Generation error: {e}")
223
- return "", "", None, ""
224
 
225
  def extract_between(text, start, end):
226
  s = text.find(start)
227
  e = text.find(end, s) if end else len(text)
228
  return text[s + len(start):e].strip() if s != -1 else ""
229
 
 
230
  checklist = extract_between(result, "Checklist:\n", "Suggestions:")
231
  suggestions = extract_between(result, "Suggestions:\n", None)
232
 
 
233
  if not checklist.strip():
234
- checklist = "- Perform daily safety inspection"
235
  if not suggestions.strip():
236
- suggestions = "- Monitor team coordination\n- Review safety protocols with the team"
237
-
238
- pdf_path, pdf_name = save_report_as_pdf(role, supervisor_name, project_id, checklist, suggestions)
239
- pdf_url = upload_pdf_to_salesforce_and_update_link(supervisor_name, project_id, pdf_path, pdf_name)
240
-
241
- if pdf_url:
242
- suggestions += f"\n\n🔗 [Download PDF Report]({pdf_url})"
243
-
244
- # Return the generated checklist, suggestions, and the path to the PDF
245
- return checklist, suggestions, pdf_path, pdf_name
246
-
247
- # Gradio Interface
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
248
  def create_interface():
249
  roles = get_roles_from_salesforce()
250
  with gr.Blocks(theme="soft") as demo:
@@ -255,8 +208,8 @@ def create_interface():
255
  supervisor_name = gr.Dropdown(choices=[], label="Supervisor Name")
256
  project_id = gr.Textbox(label="Project ID", interactive=False)
257
 
258
- milestones = gr.Textbox(label="Milestones (comma-separated KPIs)")
259
- reflection = gr.Textbox(label="Reflection Log", lines=4)
260
 
261
  with gr.Row():
262
  generate = gr.Button("Generate")
@@ -266,35 +219,24 @@ def create_interface():
266
 
267
  checklist_output = gr.Textbox(label="✅ Daily Checklist")
268
  suggestions_output = gr.Textbox(label="💡 Focus Suggestions")
269
- download_button = gr.File(label="⬇ Download Report")
270
- pdf_link = gr.HTML()
271
- dashboard_link = gr.HTML()
272
 
273
  role.change(fn=lambda r: gr.update(choices=get_supervisor_name_by_role(r)), inputs=role, outputs=supervisor_name)
274
  supervisor_name.change(fn=get_projects_for_supervisor, inputs=supervisor_name, outputs=project_id)
275
 
276
- def handle_generate(role, supervisor_name, project_id, milestones, reflection):
277
- checklist, suggestions, pdf_path, pdf_name = generate_outputs(role, supervisor_name, project_id, milestones, reflection)
278
- return checklist, suggestions, pdf_path, pdf_name
279
-
280
- generate.click(fn=handle_generate,
281
  inputs=[role, supervisor_name, project_id, milestones, reflection],
282
- outputs=[checklist_output, suggestions_output, download_button, pdf_link])
283
 
284
- clear.click(fn=lambda: ("", "", "", "", ""),
285
- inputs=None,
286
  outputs=[role, supervisor_name, project_id, milestones, reflection])
287
 
288
  refresh.click(fn=lambda: gr.update(choices=get_roles_from_salesforce()), outputs=role)
289
 
290
- dashboard_btn.click(fn=open_dashboard,
291
- inputs=[role, supervisor_name, project_id],
292
- outputs=dashboard_link)
293
 
294
  return demo
295
 
296
  if __name__ == "__main__":
297
  app = create_interface()
298
  app.launch()
299
-
300
-
 
3
  from transformers import AutoModelForCausalLM, AutoTokenizer
4
  from simple_salesforce import Salesforce
5
  import os
 
 
6
  from dotenv import load_dotenv
 
 
 
7
 
8
  # Load environment variables
9
  load_dotenv()
 
14
  if missing_vars:
15
  raise EnvironmentError(f"Missing required environment variables: {missing_vars}")
16
 
17
+ # Defaults
18
+ KPI_FLAG_DEFAULT = os.getenv('KPI_FLAG', 'True') == 'True'
19
+ ENGAGEMENT_SCORE_DEFAULT = float(os.getenv('ENGAGEMENT_SCORE', '85.0'))
20
+
21
+ # Load model and tokenizer (Updated to use distilgpt2)
22
+ model_name = "distilgpt2" # Using distilgpt2 for faster response
23
  tokenizer = AutoTokenizer.from_pretrained(model_name, use_fast=True)
24
  model = AutoModelForCausalLM.from_pretrained(model_name, low_cpu_mem_usage=True)
25
 
 
28
  tokenizer.pad_token_id = tokenizer.convert_tokens_to_ids(tokenizer.pad_token)
29
  model.config.pad_token_id = tokenizer.pad_token_id
30
 
31
+ # Refined Prompt to generate day-by-day tasks based on milestones
32
  PROMPT_TEMPLATE = """You are an AI assistant for construction supervisors. Given the role, project, milestones, and a reflection log, generate:
33
 
34
  1. A Daily Checklist with clear and concise tasks based on the role and milestones.
 
54
  -
55
  """
56
 
57
+ # Salesforce Functions
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
58
  def get_roles_from_salesforce():
59
  try:
60
  sf = Salesforce(
 
67
  return list(set(record['Role__c'] for record in result['records']))
68
  except Exception as e:
69
  print(f"⚠️ Error fetching roles: {e}")
70
+ return ["Site Manager", "Safety Officer", "Project Lead"]
71
 
72
  def get_supervisor_name_by_role(role):
73
  try:
 
77
  security_token=os.getenv('SF_SECURITY_TOKEN'),
78
  domain=os.getenv('SF_DOMAIN', 'login')
79
  )
80
+ role = role.replace("'", "\\'")
81
  result = sf.query(f"SELECT Name FROM Supervisor__c WHERE Role__c = '{role}'")
82
  return [record['Name'] for record in result['records']]
83
  except Exception as e:
84
+ print(f"⚠️ Error fetching supervisor names: {e}")
85
  return []
86
 
87
  def get_projects_for_supervisor(supervisor_name):
 
92
  security_token=os.getenv('SF_SECURITY_TOKEN'),
93
  domain=os.getenv('SF_DOMAIN', 'login')
94
  )
95
+ supervisor_name = supervisor_name.replace("'", "\\'")
96
+ supervisor_result = sf.query(f"SELECT Id FROM Supervisor__c WHERE Name = '{supervisor_name}' LIMIT 1")
97
+ if supervisor_result['totalSize'] == 0:
98
  return ""
99
+ supervisor_id = supervisor_result['records'][0]['Id']
100
  project_result = sf.query(f"SELECT Name FROM Project__c WHERE Supervisor_ID__c = '{supervisor_id}' LIMIT 1")
101
  return project_result['records'][0]['Name'] if project_result['totalSize'] > 0 else ""
102
  except Exception as e:
103
  print(f"⚠️ Error fetching project: {e}")
104
  return ""
105
 
106
+ def field_exists(sf, object_name, field_name):
107
+ try:
108
+ obj_desc = getattr(sf, object_name).describe()
109
+ return field_name in [field['name'] for field in obj_desc['fields']]
110
+ except Exception as e:
111
+ print(f"⚠️ Error checking field {field_name}: {e}")
112
+ return False
113
+
114
+ # New function to generate Salesforce dashboard URL (Visualforce Page)
115
  def generate_salesforce_dashboard_url(supervisor_name, project_id):
116
+ # Use the provided Salesforce Visualforce URL with supervisorName and projectId as parameters
117
  return f"https://aicoachforsitesupervisors-dev-ed--c.develop.vf.force.com/apex/DashboardPage?supervisorName={supervisor_name}&projectId={project_id}"
118
 
119
+ # Dashboard button function
120
  def open_dashboard(role, supervisor_name, project_id):
121
+ # Generate dynamic URL based on supervisor and project
122
+ dashboard_url = generate_salesforce_dashboard_url(supervisor_name, project_id)
123
+ return f'<a href="{dashboard_url}" target="_blank" rel="noopener noreferrer" style="font-size:16px;">Open Salesforce Dashboard</a>'
124
 
125
+ # Generate function
126
  def generate_outputs(role, supervisor_name, project_id, milestones, reflection):
127
  if not all([role, supervisor_name, project_id, milestones, reflection]):
128
+ return "❗ Please fill all fields.", ""
129
+
130
+ prompt = PROMPT_TEMPLATE.format(
131
+ role=role,
132
+ project_id=project_id,
133
+ milestones=milestones,
134
+ reflection=reflection
135
+ )
136
 
 
137
  inputs = tokenizer(prompt, return_tensors="pt", padding=True, truncation=True, max_length=512)
138
  try:
139
  with torch.no_grad():
140
  outputs = model.generate(
141
  inputs['input_ids'],
142
+ max_new_tokens=150, # Increased max tokens to capture more content
143
  no_repeat_ngram_size=2,
144
  do_sample=True,
145
  top_p=0.9,
 
149
  result = tokenizer.decode(outputs[0], skip_special_tokens=True)
150
  except Exception as e:
151
  print(f"⚠️ Generation error: {e}")
152
+ return "", ""
153
 
154
  def extract_between(text, start, end):
155
  s = text.find(start)
156
  e = text.find(end, s) if end else len(text)
157
  return text[s + len(start):e].strip() if s != -1 else ""
158
 
159
+ # Extract the checklist and suggestions
160
  checklist = extract_between(result, "Checklist:\n", "Suggestions:")
161
  suggestions = extract_between(result, "Suggestions:\n", None)
162
 
163
+ # If checklist or suggestions are empty, generate fallback content
164
  if not checklist.strip():
165
+ checklist = generate_fallback_checklist(role, milestones)
166
  if not suggestions.strip():
167
+ suggestions = generate_fallback_suggestions(reflection)
168
+
169
+ return checklist, suggestions
170
+
171
+ # Fallback generation for checklist and suggestions
172
+ def generate_fallback_checklist(role, milestones):
173
+ checklist_items = []
174
+
175
+ # If milestones are provided, add them to the checklist directly
176
+ if milestones and milestones.strip():
177
+ kpis = [kpi.strip() for kpi in milestones.split(",")]
178
+ for kpi in kpis:
179
+ checklist_items.append(f"- Ensure progress on {kpi}")
180
+ else:
181
+ checklist_items.append("- Perform daily safety inspection")
182
+
183
+ return "\n".join(checklist_items)
184
+
185
+ def generate_fallback_suggestions(reflection):
186
+ suggestions_items = []
187
+ reflection_lower = reflection.lower()
188
+ if "student" in reflection_lower or "learning" in reflection_lower:
189
+ suggestions_items.append("- Ensure students are logging incidents consistently")
190
+ suggestions_items.append("- Provide guidance on timely incident recording")
191
+ if "incident" in reflection_lower:
192
+ suggestions_items.append("- Follow up on reported incidents with corrective actions")
193
+
194
+ if not suggestions_items:
195
+ suggestions_items.append("- Monitor team coordination")
196
+ suggestions_items.append("- Review safety protocols with the team")
197
+
198
+ return "\n".join(suggestions_items)
199
+
200
+ # Interface
201
  def create_interface():
202
  roles = get_roles_from_salesforce()
203
  with gr.Blocks(theme="soft") as demo:
 
208
  supervisor_name = gr.Dropdown(choices=[], label="Supervisor Name")
209
  project_id = gr.Textbox(label="Project ID", interactive=False)
210
 
211
+ milestones = gr.Textbox(label="Milestones (comma-separated KPIs)", placeholder="E.g. Safety training, daily inspection")
212
+ reflection = gr.Textbox(label="Reflection Log", lines=4, placeholder="Any concerns, delays, updates...")
213
 
214
  with gr.Row():
215
  generate = gr.Button("Generate")
 
219
 
220
  checklist_output = gr.Textbox(label="✅ Daily Checklist")
221
  suggestions_output = gr.Textbox(label="💡 Focus Suggestions")
222
+ dashboard_link = gr.HTML("")
 
 
223
 
224
  role.change(fn=lambda r: gr.update(choices=get_supervisor_name_by_role(r)), inputs=role, outputs=supervisor_name)
225
  supervisor_name.change(fn=get_projects_for_supervisor, inputs=supervisor_name, outputs=project_id)
226
 
227
+ generate.click(fn=generate_outputs,
 
 
 
 
228
  inputs=[role, supervisor_name, project_id, milestones, reflection],
229
+ outputs=[checklist_output, suggestions_output])
230
 
231
+ clear.click(fn=lambda: ("", "", "", "", ""), inputs=None,
 
232
  outputs=[role, supervisor_name, project_id, milestones, reflection])
233
 
234
  refresh.click(fn=lambda: gr.update(choices=get_roles_from_salesforce()), outputs=role)
235
 
236
+ dashboard_btn.click(fn=open_dashboard, inputs=[role, supervisor_name, project_id], outputs=dashboard_link)
 
 
237
 
238
  return demo
239
 
240
  if __name__ == "__main__":
241
  app = create_interface()
242
  app.launch()