Sivainti commited on
Commit
7eb7287
·
verified ·
1 Parent(s): f668251

Update app.py

Browse files
Files changed (1) hide show
  1. app.py +314 -40
app.py CHANGED
@@ -15,7 +15,6 @@ from fastapi import FastAPI, Form, File, UploadFile
15
  from fastapi.middleware.cors import CORSMiddleware
16
  from fastapi.responses import JSONResponse
17
  from fastapi.staticfiles import StaticFiles
18
- import time # to simulate processing delay
19
 
20
  # Configure logging to show detailed messages
21
  logging.basicConfig(level=logging.DEBUG)
@@ -95,7 +94,105 @@ def generate_pdf(record_data):
95
  logger.error(f"Error generating PDF: {str(e)}", exc_info=True)
96
  return None
97
 
98
- # Function to generate project timeline and risk tags
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
99
  def generate_project_timeline(boq_file, weather, workforce, location, project_title):
100
  temp_dir = None
101
  try:
@@ -143,57 +240,234 @@ def generate_project_timeline(boq_file, weather, workforce, location, project_ti
143
 
144
  # Gradio interface function (for Gradio UI)
145
  def gradio_interface(boq_file, weather, workforce, location, project_title):
146
- # Simulate a long-running task (remove this line in your actual code)
147
- time.sleep(2)
148
-
149
  try:
150
  logger.info("Starting gradio_interface...")
151
 
152
- # Your existing logic here...
 
153
 
154
- # Simulate an image URL for output
155
- image_url = "/path/to/your/generated_gantt_chart.png" # Replace with actual URL or path
 
156
 
157
- risk_tags = "Risk tags based on weather and task durations" # Replace with actual risk tags generation
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
158
 
159
- # Returning results
160
- return image_url, risk_tags
161
  except Exception as e:
162
  logger.error(f"Error in Gradio interface: {str(e)}", exc_info=True)
163
  return None, f"Error in Gradio interface: {str(e)}"
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
164
 
165
- # Modified Gradio Interface:
166
- def create_gradio_interface():
167
- with gr.Blocks() as demo:
168
- gr.Markdown("## AI Civil Work Planner")
169
- gr.Markdown("Generate a project timeline (Gantt chart) and risk tags based on BOQ data and site parameters.")
170
-
171
- with gr.Row():
172
- with gr.Column():
173
- boq_file = gr.File(label="Upload BOQ Data (CSV format)")
174
- weather = gr.Dropdown(label="Weather", choices=["sunny", "rainy", "cloudy"], value="sunny")
175
- workforce = gr.Number(label="Workforce Size", value=10, precision=0)
176
- location = gr.Textbox(label="Location", placeholder="Enter project location")
177
- project_title = gr.Textbox(label="Project Title", placeholder="Enter project title")
178
- submit_btn = gr.Button("Generate Timeline")
179
-
180
- with gr.Column():
181
- output_image = gr.Image(label="Gantt Chart")
182
- risk_tags = gr.Textbox(label="Risk Tags and Salesforce Status")
183
-
184
- submit_btn.click(
185
- fn=gradio_interface,
186
- inputs=[boq_file, weather, workforce, location, project_title],
187
- outputs=[output_image, risk_tags],
188
- show_progress=True # Show progress while the function is running
189
  )
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
190
 
191
- return demo
 
 
 
 
192
 
193
- # Call the function to create the Gradio app
194
- demo = create_gradio_interface()
195
 
196
- # Start the app
197
  if __name__ == "__main__":
198
  import uvicorn
199
- uvicorn.run(demo, host="0.0.0.0", port=7860)
 
15
  from fastapi.middleware.cors import CORSMiddleware
16
  from fastapi.responses import JSONResponse
17
  from fastapi.staticfiles import StaticFiles
 
18
 
19
  # Configure logging to show detailed messages
20
  logging.basicConfig(level=logging.DEBUG)
 
94
  logger.error(f"Error generating PDF: {str(e)}", exc_info=True)
95
  return None
96
 
97
+ # Function to upload PDF to Salesforce and get its URL
98
+ def upload_pdf_to_salesforce(pdf_file, project_title, record_id=None):
99
+ try:
100
+ sf = get_salesforce_connection()
101
+ if not sf:
102
+ logger.error("Salesforce connection failed. Cannot upload PDF.")
103
+ return None, None
104
+
105
+ encoded_pdf_data = base64.b64encode(pdf_file.getvalue()).decode('utf-8')
106
+ logger.debug(f"Uploading PDF for project: {project_title}, record ID: {record_id}")
107
+ content_version_data = {
108
+ "Title": f"{project_title} - Gantt Chart PDF",
109
+ "PathOnClient": f"{project_title}_Gantt_Chart.pdf",
110
+ "VersionData": encoded_pdf_data,
111
+ }
112
+
113
+ if record_id:
114
+ content_version_data["FirstPublishLocationId"] = record_id
115
+
116
+ content_version = sf.ContentVersion.create(content_version_data)
117
+ content_version_id = content_version["id"]
118
+ logger.info(f"PDF uploaded to Salesforce with ContentVersion ID: {content_version_id}")
119
+
120
+ result = sf.query(f"SELECT Id, ContentDocumentId FROM ContentVersion WHERE Id = '{content_version_id}'")
121
+ if not result['records']:
122
+ logger.error("No records returned for ContentVersion query")
123
+ return content_version_id, None
124
+
125
+ content_document_id = result['records'][0]['ContentDocumentId']
126
+ file_url = f"https://{sf.sf_instance}/sfc/servlet.shepherd/version/download/{content_version_id}"
127
+ logger.debug(f"Generated PDF URL: {file_url}")
128
+ return content_version_id, file_url
129
+ except Exception as e:
130
+ logger.error(f"Error uploading PDF to Salesforce: {str(e)}", exc_info=True)
131
+ return None, None
132
+
133
+ # Function to create or update project timeline in Salesforce
134
+ def send_to_salesforce(project_title, gantt_chart_url, ai_plan_score, estimated_duration, status="Draft", record_id=None, location="", weather_type="", work_items=None, work_items_id=None):
135
+ try:
136
+ logger.debug("Starting send_to_salesforce function...")
137
+ sf = get_salesforce_connection()
138
+ if not sf:
139
+ logger.error("Salesforce connection failed. Cannot proceed with record creation/update.")
140
+ return None
141
+
142
+ try:
143
+ obj_description = sf.AI_Project_Timeline__c.describe()
144
+ logger.debug("AI_Project_Timeline__c object exists and is accessible.")
145
+ available_fields = [field['name'] for field in obj_description['fields']]
146
+ logger.debug(f"Available fields on AI_Project_Timeline__c: {available_fields}")
147
+ except Exception as e:
148
+ logger.error(f"Error: AI_Project_Timeline__c object not found or inaccessible: {str(e)}")
149
+ return None
150
+
151
+ sf_data = {
152
+ "Name": project_title[:80],
153
+ "Project_Title__c": project_title,
154
+ "Estimated_Duration__c": estimated_duration,
155
+ "AI_Plan_Score__c": ai_plan_score,
156
+ "Status__c": status,
157
+ "Location__c": location,
158
+ "Weather_Type__c": weather_type,
159
+ }
160
+
161
+ if gantt_chart_url:
162
+ sf_data["Gantt_Chart_PDF__c"] = gantt_chart_url
163
+
164
+ if work_items_id:
165
+ sf_data["Work_Items__c"] = work_items_id
166
+
167
+ logger.debug(f"Prepared Salesforce data: {sf_data}")
168
+
169
+ if record_id:
170
+ try:
171
+ logger.info(f"Attempting to update Salesforce record with ID: {record_id}")
172
+ sf.AI_Project_Timeline__c.update(record_id, sf_data)
173
+ logger.info(f"Successfully updated Salesforce record with ID: {record_id}")
174
+ return record_id
175
+ except Exception as e:
176
+ logger.error(f"Error updating record {record_id}: {str(e)}")
177
+ record_id = None
178
+
179
+ logger.info("Creating new Salesforce record...")
180
+ project_record = sf.AI_Project_Timeline__c.create(sf_data)
181
+ if not project_record.get('id'):
182
+ logger.error("Failed to create record, no ID returned")
183
+ return None
184
+
185
+ new_record_id = project_record['id']
186
+ logger.info(f"Created new Salesforce record with ID: {new_record_id}")
187
+ return new_record_id
188
+
189
+ except Exception as e:
190
+ logger.error(f"Error sending data to Salesforce: {str(e)}", exc_info=True)
191
+ if hasattr(e, 'content') and e.content:
192
+ logger.error(f"Salesforce API response: {e.content}")
193
+ return None
194
+
195
+ # Function to generate Gantt chart
196
  def generate_project_timeline(boq_file, weather, workforce, location, project_title):
197
  temp_dir = None
198
  try:
 
240
 
241
  # Gradio interface function (for Gradio UI)
242
  def gradio_interface(boq_file, weather, workforce, location, project_title):
243
+ temp_dir = None
 
 
244
  try:
245
  logger.info("Starting gradio_interface...")
246
 
247
+ if not boq_file:
248
+ return None, "Error: No BOQ file uploaded"
249
 
250
+ file_path, risk_tags, temp_dir = generate_project_timeline(boq_file, weather, workforce, location, project_title)
251
+ if not file_path:
252
+ return None, f"Error: Failed to generate timeline: {risk_tags}"
253
 
254
+ if hasattr(boq_file, 'name'):
255
+ df = pd.read_csv(boq_file.name)
256
+ else:
257
+ df = pd.read_csv(boq_file)
258
+ estimated_duration = sum(df["Duration"])
259
+ ai_plan_score = min(100, max(0, 100 - (estimated_duration / 100)))
260
+ logger.debug(f"Estimated duration: {estimated_duration}, AI plan score: {ai_plan_score}")
261
+
262
+ record_id = send_to_salesforce(
263
+ project_title=project_title,
264
+ gantt_chart_url="",
265
+ ai_plan_score=ai_plan_score,
266
+ estimated_duration=estimated_duration,
267
+ status="Draft",
268
+ record_id=None,
269
+ location=location,
270
+ weather_type=weather
271
+ )
272
+
273
+ if not record_id:
274
+ return None, f"Error: Failed to create Salesforce record - check logs for details\n\nRisk Tags:\n{risk_tags}"
275
+
276
+ boq_file_path = boq_file.name if hasattr(boq_file, 'name') else boq_file
277
+ work_items_id = upload_file_to_salesforce(boq_file_path, "Boq_data.csv", record_id)
278
+ if not work_items_id:
279
+ logger.warning("Failed to upload BOQ file, but proceeding with record creation")
280
+
281
+ record_data = {
282
+ "project_title": project_title,
283
+ "estimated_duration": estimated_duration,
284
+ "ai_plan_score": ai_plan_score,
285
+ "status": "Draft",
286
+ "risk_tags": risk_tags,
287
+ }
288
+ pdf_file = generate_pdf(record_data)
289
+ if not pdf_file:
290
+ logger.warning("Failed to generate PDF, but proceeding with record creation")
291
+
292
+ pdf_content_id, pdf_url = None, None
293
+ if pdf_file:
294
+ pdf_content_id, pdf_url = upload_pdf_to_salesforce(pdf_file, project_title, record_id)
295
+ if not pdf_content_id:
296
+ logger.warning("Failed to upload PDF, but proceeding with record creation")
297
+
298
+ update_result = send_to_salesforce(
299
+ project_title=project_title,
300
+ gantt_chart_url=pdf_url if pdf_url else "",
301
+ ai_plan_score=ai_plan_score,
302
+ estimated_duration=estimated_duration,
303
+ status="Draft",
304
+ record_id=record_id,
305
+ location=location,
306
+ weather_type=weather,
307
+ work_items_id=work_items_id if work_items_id else ""
308
+ )
309
+ if not update_result:
310
+ logger.warning("Failed to update record with PDF URL, but record was created")
311
+
312
+ # Upload Gantt chart image to Salesforce for a public URL
313
+ image_content_id = upload_file_to_salesforce(file_path, f"{project_title}_Gantt_Chart.png", record_id)
314
+ image_url = None
315
+ if image_content_id:
316
+ sf = get_salesforce_connection()
317
+ if sf:
318
+ image_url = f"https://{sf.sf_instance}/sfc/servlet.shepherd/version/download/{image_content_id}"
319
+ logger.debug(f"Generated image URL: {image_url}")
320
 
321
+ logger.info("Gradio interface completed successfully.")
322
+ return image_url if image_url else file_path, f"Successfully created Salesforce record ID: {record_id}\n\nRisk Tags:\n{risk_tags}"
323
  except Exception as e:
324
  logger.error(f"Error in Gradio interface: {str(e)}", exc_info=True)
325
  return None, f"Error in Gradio interface: {str(e)}"
326
+ finally:
327
+ if temp_dir and os.path.exists(temp_dir):
328
+ shutil.rmtree(temp_dir)
329
+ logger.debug(f"Cleaned up temporary directory: {temp_dir}")
330
+
331
+ # Create a FastAPI app and mount the Gradio app with CORS support
332
+ app = FastAPI()
333
+ app.add_middleware(
334
+ CORSMiddleware,
335
+ allow_origins=["https://aiplannerforcivilworktimel2-dev-ed.develop.lightning.force.com"],
336
+ allow_credentials=True,
337
+ allow_methods=["*"],
338
+ allow_headers=["*"],
339
+ )
340
+ app.mount("/static", StaticFiles(directory=tempfile.gettempdir()), name="static")
341
+
342
+ # FastAPI endpoint for Salesforce controller (defined before mounting Gradio)
343
+ @app.post("/api/gradio_interface")
344
+ async def api_gradio_interface(
345
+ boq_file: UploadFile = File(...),
346
+ weather: str = Form(...),
347
+ workforce: int = Form(...),
348
+ location: str = Form(...),
349
+ project_title: str = Form(...)
350
+ ):
351
+ temp_dir = None
352
+ try:
353
+ logger.info("Starting api_gradio_interface...")
354
+
355
+ # Save uploaded file to temporary path
356
+ temp_dir = tempfile.mkdtemp()
357
+ boq_file_path = os.path.join(temp_dir, boq_file.filename)
358
+ with open(boq_file_path, "wb") as f:
359
+ f.write(boq_file.file.read())
360
+
361
+ file_path, risk_tags, temp_dir = generate_project_timeline(boq_file_path, weather, workforce, location, project_title)
362
+ if not file_path:
363
+ return JSONResponse({"error": f"Failed to generate timeline: {risk_tags}"}, status_code=400)
364
+
365
+ df = pd.read_csv(boq_file_path)
366
+ estimated_duration = sum(df["Duration"])
367
+ ai_plan_score = min(100, max(0, 100 - (estimated_duration / 100)))
368
+ logger.debug(f"Estimated duration: {estimated_duration}, AI plan score: {ai_plan_score}")
369
+
370
+ record_id = send_to_salesforce(
371
+ project_title=project_title,
372
+ gantt_chart_url="",
373
+ ai_plan_score=ai_plan_score,
374
+ estimated_duration=estimated_duration,
375
+ status="Draft",
376
+ record_id=None,
377
+ location=location,
378
+ weather_type=weather
379
+ )
380
+
381
+ if not record_id:
382
+ return JSONResponse({
383
+ "error": f"Failed to create Salesforce record - check logs for details",
384
+ "text": f"Risk Tags:\n{risk_tags}"
385
+ }, status_code=500)
386
+
387
+ work_items_id = upload_file_to_salesforce(boq_file_path, "Boq_data.csv", record_id)
388
+ if not work_items_id:
389
+ logger.warning("Failed to upload BOQ file, but proceeding with record creation")
390
+
391
+ record_data = {
392
+ "project_title": project_title,
393
+ "estimated_duration": estimated_duration,
394
+ "ai_plan_score": ai_plan_score,
395
+ "status": "Draft",
396
+ "risk_tags": risk_tags,
397
+ }
398
+ pdf_file = generate_pdf(record_data)
399
+ if not pdf_file:
400
+ logger.warning("Failed to generate PDF, but proceeding with record creation")
401
 
402
+ pdf_content_id, pdf_url = None, None
403
+ if pdf_file:
404
+ pdf_content_id, pdf_url = upload_pdf_to_salesforce(pdf_file, project_title, record_id)
405
+ if not pdf_content_id:
406
+ logger.warning("Failed to upload PDF, but proceeding with record creation")
407
+
408
+ update_result = send_to_salesforce(
409
+ project_title=project_title,
410
+ gantt_chart_url=pdf_url if pdf_url else "",
411
+ ai_plan_score=ai_plan_score,
412
+ estimated_duration=estimated_duration,
413
+ status="Draft",
414
+ record_id=record_id,
415
+ location=location,
416
+ weather_type=weather,
417
+ work_items_id=work_items_id if work_items_id else ""
 
 
 
 
 
 
 
 
418
  )
419
+ if not update_result:
420
+ logger.warning("Failed to update record with PDF URL, but record was created")
421
+
422
+ image_content_id = upload_file_to_salesforce(file_path, f"{project_title}_Gantt_Chart.png", record_id)
423
+ image_url = None
424
+ if image_content_id:
425
+ sf = get_salesforce_connection()
426
+ if sf:
427
+ image_url = f"https://{sf.sf_instance}/sfc/servlet.shepherd/version/download/{image_content_id}"
428
+ logger.debug(f"Generated image URL: {image_url}")
429
+
430
+ logger.info("API gradio interface completed successfully.")
431
+ return JSONResponse({
432
+ "image": image_url if image_url else f"/static/{os.path.basename(file_path)}",
433
+ "text": f"Successfully created Salesforce record ID: {record_id}\n\nRisk Tags:\n{risk_tags}"
434
+ })
435
+ except Exception as e:
436
+ logger.error(f"Error in API gradio interface: {str(e)}", exc_info=True)
437
+ return JSONResponse({"error": f"Error in API gradio interface: {str(e)}"}, status_code=500)
438
+ finally:
439
+ if temp_dir and os.path.exists(temp_dir):
440
+ shutil.rmtree(temp_dir)
441
+ logger.debug(f"Cleaned up temporary directory: {temp_dir}")
442
+
443
+ # Create Gradio interface
444
+ demo = gr.Blocks(theme="default")
445
+ with demo:
446
+ gr.Markdown("## AI Civil Work Planner")
447
+ gr.Markdown("Generate a project timeline (Gantt chart) and risk tags based on BOQ data and site parameters.")
448
+
449
+ with gr.Row():
450
+ with gr.Column():
451
+ boq_file = gr.File(label="Upload BOQ Data (CSV format)")
452
+ weather = gr.Dropdown(label="Weather", choices=["sunny", "rainy", "cloudy"], value="sunny")
453
+ workforce = gr.Number(label="Workforce Size", value=10, precision=0)
454
+ location = gr.Textbox(label="Location", placeholder="Enter project location")
455
+ project_title = gr.Textbox(label="Project Title", placeholder="Enter project title")
456
+ submit_btn = gr.Button("Generate Timeline")
457
+
458
+ with gr.Column():
459
+ output_image = gr.Image(label="Gantt Chart")
460
+ risk_tags = gr.Textbox(label="Risk Tags and Salesforce Status")
461
 
462
+ submit_btn.click(
463
+ fn=gradio_interface,
464
+ inputs=[boq_file, weather, workforce, location, project_title],
465
+ outputs=[output_image, risk_tags],
466
+ )
467
 
468
+ # Mount Gradio app (use a different variable to avoid overwriting 'app')
469
+ gradio_app = gr.mount_gradio_app(app, demo, path="/")
470
 
 
471
  if __name__ == "__main__":
472
  import uvicorn
473
+ uvicorn.run(gradio_app, host="0.0.0.0", port=7860)