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

Update app.py

Browse files
Files changed (1) hide show
  1. app.py +142 -84
app.py CHANGED
@@ -3,7 +3,12 @@ import torch
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,12 +19,8 @@ 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
- # 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,7 +29,7 @@ if tokenizer.pad_token is None:
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,7 +55,96 @@ Suggestions:
54
  -
55
  """
56
 
57
- # Salesforce Functions
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
58
  def get_roles_from_salesforce():
59
  try:
60
  sf = Salesforce(
@@ -67,7 +157,7 @@ def get_roles_from_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,11 +167,10 @@ def get_supervisor_name_by_role(role):
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,54 +181,36 @@ 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,55 +220,31 @@ def generate_outputs(role, supervisor_name, project_id, milestones, reflection):
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,8 +255,8 @@ def create_interface():
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,24 +266,35 @@ def create_interface():
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()
 
 
 
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
  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
  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
  -
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
  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
  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
  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
  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
  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
 
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
+