lokeshloki143 commited on
Commit
070f012
·
verified ·
1 Parent(s): 79eabca

Update app.py

Browse files
Files changed (1) hide show
  1. app.py +304 -203
app.py CHANGED
@@ -1,233 +1,334 @@
1
-
2
- import gradio as gr
3
- from transformers import AutoModelForSeq2SeqLM, AutoTokenizer
4
  import os
5
- from fastapi import FastAPI
6
- from pydantic import BaseModel
7
- from simple_salesforce import Salesforce
8
  from dotenv import load_dotenv
 
 
 
 
 
9
 
10
  # Load environment variables
11
  load_dotenv()
12
 
13
- # Salesforce connection
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
14
  def get_salesforce_connection():
 
15
  try:
16
- # Load credentials from environment variables
17
- username = os.getenv("SF_USERNAME")
18
- password = os.getenv("SF_PASSWORD")
19
- security_token = os.getenv("SF_SECURITY_TOKEN")
20
- domain = os.getenv("SF_DOMAIN", "login") # Default to production (login.salesforce.com)
21
-
22
- # Validate credentials
23
- if not all([username, password, security_token, domain]):
24
- missing = []
25
- if not username:
26
- missing.append("onteddugeetha104@gmail.com")
27
- if not password:
28
- missing.append("9032590825g@")
29
- if not security_token:
30
- missing.append("tTPLQduw8wDpxdKOMJ3d9dM3o")
31
- if not domain:
32
- missing.append("SF_DOMAIN")
33
- raise ValueError(f"Missing environment variables: {', '.join(missing)}. Set them in .env or Space environment variables.")
34
-
35
- # Ensure all are strings
36
- if not all(isinstance(x, str) for x in [username, password, security_token, domain]):
37
- raise ValueError("All Salesforce credentials (SF_USERNAME, SF_PASSWORD, SF_SECURITY_TOKEN, SF_DOMAIN) must be strings.")
38
-
39
  sf = Salesforce(
40
- username=username,
41
- password=password,
42
- security_token=security_token,
43
- domain=domain
 
44
  )
45
-
46
- # Test connection by fetching user info
47
- sf.User.get(sf.user_id)
48
  return sf
 
 
 
 
 
 
49
  except Exception as e:
50
- raise Exception(f"Failed to connect to Salesforce: {str(e)}")
51
-
52
- # Load Hugging Face token
53
- HF_TOKEN = os.getenv("HF_TOKEN")
54
-
55
- # Model configuration
56
- MODEL_PATH = "facebook/bart-large" # Public model
57
- # MODEL_PATH = "your_actual_username/fine_tuned_bart_construction" # Uncomment after uploading
58
-
59
- try:
60
- model = AutoModelForSeq2SeqLM.from_pretrained(MODEL_PATH, use_auth_token=HF_TOKEN if HF_TOKEN else None)
61
- tokenizer = AutoTokenizer.from_pretrained(MODEL_PATH, use_auth_token=HF_TOKEN if HF_TOKEN else None)
62
- except Exception as e:
63
- raise Exception(f"Failed to load model: {str(e)}")
64
-
65
- # Define input model for FastAPI
66
- class ChecklistInput(BaseModel):
67
- role: str = "Supervisor"
68
- project_id: str = "Unknown"
69
- project_name: str = "Unknown Project"
70
- milestones: str = "No milestones provided"
71
- record_id: str = None
72
- supervisor_id: str = None
73
- project_id_sf: str = None
74
- reflection_log: str = None
75
- download_link: str = None
76
-
77
- # Initialize FastAPI
78
- app = FastAPI()
79
-
80
- @app.post("/generate")
81
- async def generate_checklist(data: ChecklistInput):
82
  try:
83
- inputs = f"Role: {data.role} Project: {data.project_id} ({data.project_name}) Milestones: {data.milestones}"
84
- input_ids = tokenizer(inputs, return_tensors="pt", max_length=128, truncation=True).input_ids
85
- outputs = model.generate(input_ids, max_length=128, num_beams=4, early_stopping=True)
86
- checklist = tokenizer.decode(outputs[0], skip_special_tokens=True)
87
- tips = "1. Prioritize safety checks\n2. Review milestones\n3. Log progress"
88
- kpi_flag = "delay" in data.milestones.lower() or "behind" in data.milestones.lower()
89
-
90
- if data.record_id:
91
- sf = get_salesforce_connection()
92
- existing_record = sf.Supervisor_AI_Coaching__c.get(data.record_id, default={
93
- 'Name': '',
94
- 'Supervisor_ID__c': None,
95
- 'Project_ID__c': None,
96
- 'Reflection_Log__c': '',
97
- 'Download_Link__c': '',
98
- 'Engagement_Score__c': 0,
99
- 'KPI_Flag__c': False,
100
- 'Daily_Checklist__c': '',
101
- 'Suggested_Tips__c': ''
102
- })
103
- update_data = {
104
- 'Daily_Checklist__c': checklist,
105
- 'Suggested_Tips__c': tips,
106
- 'Engagement_Score__c': existing_record.get('Engagement_Score__c', 0) + 10,
107
- 'KPI_Flag__c': kpi_flag,
108
- 'Supervisor_ID__c': data.supervisor_id if data.supervisor_id else existing_record.get('Supervisor_ID__c'),
109
- 'Project_ID__c': data.project_id_sf if data.project_id_sf else existing_record.get('Project_ID__c'),
110
- 'Reflection_Log__c': data.reflection_log if data.reflection_log else existing_record.get('Reflection_Log__c', ''),
111
- 'Download_Link__c': data.download_link if data.download_link else existing_record.get('Download_Link__c', '')
112
- }
113
- sf.Supervisor_AI_Coaching__c.update(data.record_id, update_data)
114
 
115
- return {
116
- "checklist": checklist,
117
- "tips": tips,
118
- "kpi_flag": kpi_flag
119
- }
120
  except Exception as e:
121
- return {"error": str(e)}
 
 
 
 
 
 
 
 
 
 
122
 
123
- # Login and display records
124
- def login_and_display(project_id_sf):
125
  try:
126
  sf = get_salesforce_connection()
127
- query = f"SELECT Id, Name, Supervisor_ID__c, Project_ID__c, Daily_Checklist__c, Suggested_Tips__c, Reflection_Log__c, Engagement_Score__c, KPI_Flag__c, Download_Link__c FROM Supervisor_AI_Coaching__c WHERE Project_ID__c = '{project_id_sf}'"
128
- records = sf.query(query)["records"]
129
- if not records:
130
- return "No records found for Project ID.", "", False
131
-
132
- output = "Supervisor_AI_Coaching__c Records:\n"
133
- for record in records:
134
- output += (
135
- f"Record ID: {record['Id']}\n"
136
- f"Name: {record['Name']}\n"
137
- f"Supervisor ID: {record['Supervisor_ID__c']}\n"
138
- f"Project ID: {record['Project_ID__c']}\n"
139
- f"Daily Checklist: {record['Daily_Checklist__c'] or 'N/A'}\n"
140
- f"Suggested Tips: {record['Suggested_Tips__c'] or 'N/A'}\n"
141
- f"Reflection Log: {record['Reflection_Log__c'] or 'N/A'}\n"
142
- f"Engagement Score: {record['Engagement_Score__c'] or 0}%\n"
143
- f"KPI Flag: {record['KPI_Flag__c']}\n"
144
- f"Download Link: {record['Download_Link__c'] or 'N/A'}\n"
145
- f"{'-'*50}\n"
146
- )
147
- return output, "", False
 
148
  except Exception as e:
149
- return f"Error querying Salesforce: {str(e)}", "", False
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
150
 
151
- # Generate checklist from record
152
- def gradio_generate_checklist(record_id, role="Supervisor", project_id="Unknown", project_name="Unknown Project", milestones="No milestones provided", supervisor_id="", project_id_sf="", reflection_log="", download_link=""):
153
  try:
154
  sf = get_salesforce_connection()
155
- existing_record = sf.Supervisor_AI_Coaching__c.get(record_id, default={
156
- 'Name': '',
157
- 'Supervisor_ID__c': None,
158
- 'Project_ID__c': None,
159
- 'Reflection_Log__c': '',
160
- 'Download_Link__c': '',
161
- 'Engagement_Score__c': 0,
162
- 'KPI_Flag__c': False,
163
- 'Daily_Checklist__c': '',
164
- 'Suggested_Tips__c': ''
165
- })
166
- inputs = f"Role: {role} Project: {project_id} ({project_name}) Milestones: {milestones}"
167
- input_ids = tokenizer(inputs, return_tensors="pt", max_length=128, truncation=True).input_ids
168
- outputs = model.generate(input_ids, max_length=128, num_beams=4, early_stopping=True)
169
- checklist = tokenizer.decode(outputs[0], skip_special_tokens=True)
170
- tips = "1. Prioritize safety checks\n2. Review milestones\n3. Log progress"
171
- kpi_flag = "delay" in milestones.lower() or "behind" in milestones.lower()
172
-
173
- update_data = {
174
- 'Daily_Checklist__c': checklist,
175
- 'Suggested_Tips__c': tips,
176
- 'Engagement_Score__c': existing_record.get('Engagement_Score__c', 0) + 10,
177
- 'KPI_Flag__c': kpi_flag,
178
- 'Supervisor_ID__c': supervisor_id if supervisor_id else existing_record.get('Supervisor_ID__c'),
179
- 'Project_ID__c': project_id_sf if project_id_sf else existing_record.get('Project_ID__c'),
180
- 'Reflection_Log__c': reflection_log if reflection_log else existing_record.get('Reflection_Log__c', ''),
181
- 'Download_Link__c': download_link if download_link else existing_record.get('Download_Link__c', '')
182
  }
183
- sf.Supervisor_AI_Coaching__c.update(record_id, update_data)
184
- status = f"Updated Salesforce record {record_id}"
185
 
186
- return checklist, tips, kpi_flag, status
 
 
 
 
187
  except Exception as e:
188
- return f"Error: {str(e)}", "", False, ""
189
-
190
- # Define Gradio interface
191
- with gr.Blocks() as iface:
192
- gr.Markdown("# AI Coach for Site Supervisors")
193
- gr.Markdown("Enter a Project ID to view Supervisor_AI_Coaching__c records and generate checklists.")
194
-
195
- with gr.Tab("Login"):
196
- project_id_input = gr.Textbox(label="Project ID (Salesforce Project__c ID)", placeholder="Enter Project ID")
197
- login_button = gr.Button("Submit")
198
- records_output = gr.Textbox(label="Records", lines=10)
199
- login_button.click(
200
- fn=login_and_display,
201
- inputs=project_id_input,
202
- outputs=[records_output, gr.Textbox(visible=False), gr.Checkbox(visible=False)]
203
- )
204
 
205
- with gr.Tab("Generate Checklist"):
206
- record_id = gr.Textbox(label="Record ID", placeholder="Enter Record ID from above")
207
- role = gr.Textbox(label="Role", value="Supervisor")
208
- project_id = gr.Textbox(label="Project ID", value="P001")
209
- project_name = gr.Textbox(label="Project Name", value="Building A")
210
- milestones = gr.Textbox(label="Milestones", value="Complete foundation by 5/15")
211
- supervisor_id = gr.Textbox(label="Supervisor ID (Salesforce User ID, optional)", value="")
212
- project_id_sf = gr.Textbox(label="Project ID (Salesforce Project__c ID, optional)", value="")
213
- reflection_log = gr.Textbox(label="Reflection Log (optional)", value="")
214
- download_link = gr.Textbox(label="Download Link (optional)", value="")
215
- generate_button = gr.Button("Generate and Update")
216
- checklist_output = gr.Textbox(label="Checklist")
217
- tips_output = gr.Textbox(label="Tips")
218
- kpi_flag_output = gr.Checkbox(label="KPI Flag")
219
- status_output = gr.Textbox(label="Salesforce Status")
220
- generate_button.click(
221
- fn=gradio_generate_checklist,
222
- inputs=[record_id, role, project_id, project_name, milestones, supervisor_id, project_id_sf, reflection_log, download_link],
223
- outputs=[checklist_output, tips_output, kpi_flag_output, status_output]
224
- )
225
 
226
- # Mount FastAPI
227
- iface.app = app
 
 
 
 
 
 
 
 
 
 
228
 
229
- if __name__ == "__main__":
 
 
230
  try:
231
- iface.launch(server_name="0.0.0.0", server_port=7860, share=False)
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
232
  except Exception as e:
233
- print(f"Failed to launch Gradio: {str(e)}")
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ from flask import Flask, request, jsonify, session, redirect, url_for, render_template
2
+ from simple_salesforce import Salesforce, SalesforceAuthenticationFailed, SalesforceError
 
3
  import os
 
 
 
4
  from dotenv import load_dotenv
5
+ import logging
6
+ import requests
7
+ import json
8
+ from datetime import datetime
9
+ from urllib.parse import quote
10
 
11
  # Load environment variables
12
  load_dotenv()
13
 
14
+ # Configure logging
15
+ logging.basicConfig(
16
+ level=logging.DEBUG,
17
+ format='%(asctime)s - %(levelname)s - %(message)s',
18
+ handlers=[logging.FileHandler('app.log'), logging.StreamHandler()]
19
+ )
20
+ logger = logging.getLogger(__name__)
21
+
22
+ app = Flask(__name__)
23
+ app.secret_key = os.getenv('FLASK_SECRET_KEY', 'tTPLQduw8wDpxdKOMJ3d9dM3o')
24
+
25
+ # Salesforce credentials from .env
26
+ SALESFORCE_USERNAME = os.getenv('SALESFORCE_USERNAME')
27
+ SALESFORCE_PASSWORD = os.getenv('SALESFORCE_PASSWORD')
28
+ SALESFORCE_SECURITY_TOKEN = os.getenv('SALESFORCE_SECURITY_TOKEN')
29
+ SALESFORCE_DOMAIN = os.getenv('SALESFORCE_DOMAIN', 'login')
30
+ HUGGING_FACE_API_TOKEN = os.getenv('HUGGING_FACE_API_TOKEN')
31
+ HUGGING_FACE_API_URL = os.getenv('HUGGING_FACE_API_URL', 'https://api-inference.huggingface.co/models/facebook/bart-large')
32
+
33
  def get_salesforce_connection():
34
+ """Establish a Salesforce connection with detailed error handling."""
35
  try:
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
36
  sf = Salesforce(
37
+ username=SALESFORCE_USERNAME,
38
+ password=SALESFORCE_PASSWORD,
39
+ security_token=SALESFORCE_SECURITY_TOKEN,
40
+ domain=SALESFORCE_DOMAIN,
41
+ version='60.0'
42
  )
43
+ logger.info("Successfully connected to Salesforce")
44
+ sf.query("SELECT Id FROM Supervisor_AI_Coaching__c LIMIT 1")
45
+ logger.debug("Salesforce connection test query successful")
46
  return sf
47
+ except SalesforceAuthenticationFailed as e:
48
+ logger.error(f"Salesforce authentication failed: {str(e)}")
49
+ raise Exception(f"Salesforce authentication failed: {str(e)}")
50
+ except SalesforceError as e:
51
+ logger.error(f"Salesforce error during connection: {str(e)}")
52
+ raise Exception(f"Salesforce error: {str(e)}")
53
  except Exception as e:
54
+ logger.error(f"Unexpected error connecting to Salesforce: {str(e)}")
55
+ raise Exception(f"Unable to connect to Salesforce: {str(e)}")
56
+
57
+ @app.route('/')
58
+ def index():
59
+ if 'supervisor_id' not in session:
60
+ logger.info("User not logged in, redirecting to login page")
61
+ return redirect(url_for('login_page'))
62
+ return redirect(url_for('dashboard'))
63
+
64
+ @app.route('/login', methods=['GET'])
65
+ def login_page():
66
+ return render_template('login.html')
67
+
68
+ @app.route('/signup', methods=['GET'])
69
+ def signup_page():
70
+ return render_template('signup.html')
71
+
72
+ @app.route('/login', methods=['POST'])
73
+ def login():
74
+ data = request.get_json()
75
+ supervisor_id = data.get('supervisor_id')
76
+
77
+ if not supervisor_id:
78
+ logger.warning("Login failed: Supervisor ID is required")
79
+ return jsonify({"status": "error", "message": "Supervisor ID is required"}), 400
80
+
 
 
 
 
 
81
  try:
82
+ sf = get_salesforce_connection()
83
+ logger.debug(f"Querying Salesforce for Supervisor_AI_Coaching_Name__c: {supervisor_id}")
84
+ supervisor_id_escaped = quote(supervisor_id, safe='')
85
+ query = f"SELECT Id, Supervisor_AI_Coaching_Name__c, Project_ID__c FROM Supervisor_AI_Coaching__c WHERE Supervisor_AI_Coaching_Name__c = '{supervisor_id_escaped}' LIMIT 1"
86
+ result = sf.query(query)
87
+ logger.debug(f"Salesforce query result: {result}")
88
+
89
+ if not result['records']:
90
+ logger.warning(f"Invalid Supervisor ID: {supervisor_id}")
91
+ return jsonify({"status": "error", "message": "Invalid Supervisor ID"}), 401
92
+
93
+ session['supervisor_id'] = supervisor_id
94
+ logger.info(f"Login successful for {supervisor_id}")
95
+ return jsonify({"status": "success", "message": "Login successful", "redirect": "/dashboard"})
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
96
 
 
 
 
 
 
97
  except Exception as e:
98
+ logger.error(f"Login error: {str(e)}")
99
+ return jsonify({"status": "error", "message": str(e)}), 500
100
+
101
+ @app.route('/signup', methods=['POST'])
102
+ def signup():
103
+ data = request.get_json()
104
+ supervisor_id = data.get('supervisor_id')
105
+
106
+ if not supervisor_id:
107
+ logger.warning("Signup failed: Supervisor ID is required")
108
+ return jsonify({"status": "error", "message": "Supervisor ID is required"}), 400
109
 
 
 
110
  try:
111
  sf = get_salesforce_connection()
112
+ logger.debug(f"Checking if Supervisor_AI_Coaching_Name__c {supervisor_id} already exists")
113
+ supervisor_id_escaped = quote(supervisor_id, safe='')
114
+ query = f"SELECT Id FROM Supervisor_AI_Coaching__c WHERE Supervisor_AI_Coaching_Name__c = '{supervisor_id_escaped}' LIMIT 1"
115
+ result = sf.query(query)
116
+ if result['records']:
117
+ logger.warning(f"Signup failed: Supervisor ID {supervisor_id} already exists")
118
+ return jsonify({"status": "error", "message": "Supervisor ID already exists"}), 400
119
+
120
+ logger.debug(f"Creating new Supervisor_AI_Coaching__c record for {supervisor_id}")
121
+ new_record = {
122
+ 'Supervisor_AI_Coaching_Name__c': supervisor_id
123
+ }
124
+ response = sf.Supervisor_AI_Coaching__c.create(new_record)
125
+ logger.debug(f"Salesforce create response: {response}")
126
+
127
+ if not response.get('success'):
128
+ logger.error(f"Failed to create Supervisor record: {response.get('errors')}")
129
+ return jsonify({"status": "error", "message": f"Failed to create record in Salesforce: {response.get('errors')}"}), 500
130
+
131
+ session['supervisor_id'] = supervisor_id
132
+ logger.info(f"Signup successful for {supervisor_id}")
133
+ return jsonify({"status": "success", "message": "Signup successful, you are now logged in", "redirect": "/dashboard"})
134
  except Exception as e:
135
+ logger.error(f"Signup error: {str(e)}")
136
+ return jsonify({"status": "error", "message": str(e)}), 500
137
+
138
+ @app.route('/dashboard', methods=['GET'])
139
+ def dashboard():
140
+ return render_template('dashboard.html')
141
+
142
+ @app.route('/home')
143
+ def home():
144
+ return render_template('home.html')
145
+
146
+ def generate_coaching_output(data):
147
+ """Generate daily checklist and tips using Hugging Face LLM."""
148
+ logger.info("Generating coaching output for supervisor %s", data['supervisor_id'])
149
+ milestones_json = json.dumps(data['milestones'], indent=2)
150
+ prompt = f"""
151
+ You are an AI Coach for construction site supervisors. Based on the following data, generate a daily checklist, three focus tips, and a motivational quote. Ensure outputs are concise, actionable, and tailored to the supervisor's role, project status, and reflection log.
152
+ Supervisor ID: {data['supervisor_id']}
153
+ Project Milestones: {milestones_json}
154
+ Reflection Log: {data['reflection_log']}
155
+ Weather: {data['weather']}
156
+ Format the response as JSON:
157
+ {{
158
+ "checklist": ["item1", "item2", ...],
159
+ "tips": ["tip1", "tip2", "tip3"],
160
+ "quote": "motivational quote"
161
+ }}
162
+ """
163
+ headers = {
164
+ "Authorization": f"Bearer {HUGGING_FACE_API_TOKEN}",
165
+ "Content-Type": "application/json"
166
+ }
167
+ payload = {
168
+ "inputs": prompt,
169
+ "parameters": {
170
+ "max_length": 200,
171
+ "temperature": 0.7,
172
+ "top_p": 0.9
173
+ }
174
+ }
175
+
176
+ try:
177
+ response = requests.post(HUGGING_FACE_API_URL, headers=headers, json=payload, timeout=5)
178
+ response.raise_for_status()
179
+ result = response.json()
180
+ generated_text = result[0]["generated_text"] if isinstance(result, list) else result["generated_text"]
181
+
182
+ start_idx = generated_text.find('{')
183
+ end_idx = generated_text.rfind('}') + 1
184
+ if start_idx == -1 or end_idx == 0:
185
+ logger.error("No valid JSON found in LLM output")
186
+ raise ValueError("No valid JSON found in LLM output")
187
+
188
+ json_str = generated_text[start_idx:end_idx]
189
+ output = json.loads(json_str)
190
+ logger.info("Successfully generated coaching output")
191
+ return output
192
+
193
+ except requests.exceptions.HTTPError as e:
194
+ logger.error("Hugging Face API HTTP error: %s", e)
195
+ return None
196
+ except (json.JSONDecodeError, ValueError) as e:
197
+ logger.error("Error parsing LLM output: %s", e)
198
+ return None
199
+ except Exception as e:
200
+ logger.error("Unexpected error in Hugging Face API call: %s", e)
201
+ return None
202
+
203
+ def save_to_salesforce(output, supervisor_id, project_id):
204
+ """Save coaching output to Salesforce Supervisor_AI_Coaching__c object."""
205
+ if not output:
206
+ logger.error("No coaching output to save")
207
+ return False
208
 
 
 
209
  try:
210
  sf = get_salesforce_connection()
211
+ logger.info("Connected to Salesforce")
212
+
213
+ coaching_record = {
214
+ "Supervisor_AI_Coaching_Name__c": supervisor_id,
215
+ "Project_ID__c": project_id,
216
+ "Daily_Checklist__c": "\n".join(output["checklist"]),
217
+ "Suggested_Tips__c": "\n".join(output["tips"]),
218
+ "Quote__c": output["quote"],
219
+ "Generated_Date__c": datetime.now().strftime("%Y-%m-%d")
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
220
  }
 
 
221
 
222
+ external_id = f"{supervisor_id}_{datetime.now().strftime('%Y-%m-%d')}"
223
+ sf.Supervisor_AI_Coaching__c.upsert(f"Supervisor_AI_Coaching_Name__c/{external_id}", coaching_record)
224
+ logger.info("Successfully saved coaching record to Salesforce for supervisor %s", supervisor_id)
225
+ return True
226
+
227
  except Exception as e:
228
+ logger.error("Salesforce error: %s", e)
229
+ return False
 
 
 
 
 
 
 
 
 
 
 
 
 
 
230
 
231
+ @app.route('/generate', methods=['POST'])
232
+ def generate_endpoint():
233
+ """Endpoint to generate coaching output based on supervisor data."""
234
+ try:
235
+ data = request.get_json()
236
+ required_keys = ['supervisor_id', 'project_id', 'milestones', 'reflection_log', 'weather']
237
+ if not data or not all(key in data for key in required_keys):
238
+ return jsonify({"status": "error", "message": "Invalid or missing supervisor data"}), 400
 
 
 
 
 
 
 
 
 
 
 
 
239
 
240
+ coaching_output = generate_coaching_output(data)
241
+ if coaching_output:
242
+ success = save_to_salesforce(coaching_output, data["supervisor_id"], data["project_id"])
243
+ if success:
244
+ return jsonify({"status": "success", "output": coaching_output}), 200
245
+ else:
246
+ return jsonify({"status": "error", "message": "Failed to save to Salesforce"}), 500
247
+ else:
248
+ return jsonify({"status": "error", "message": "Failed to generate coaching output"}), 500
249
+ except Exception as e:
250
+ logger.error("Error in generate endpoint: %s", e)
251
+ return jsonify({"status": "error", "message": str(e)}), 500
252
 
253
+ @app.route('/submit_reflection', methods=['POST'])
254
+ def submit_reflection():
255
+ """Endpoint to submit a reflection and update Salesforce."""
256
  try:
257
+ data = request.get_json()
258
+ reflection = data.get('reflection')
259
+ supervisor_id = session.get('supervisor_id')
260
+
261
+ if not reflection or not supervisor_id:
262
+ return jsonify({"status": "error", "message": "Reflection and supervisor ID are required"}), 400
263
+
264
+ sf = get_salesforce_connection()
265
+ query = f"SELECT Id FROM Supervisor_AI_Coaching__c WHERE Supervisor_AI_Coaching_Name__c = '{quote(supervisor_id, safe='')}' LIMIT 1"
266
+ result = sf.query(query)
267
+
268
+ if not result['records']:
269
+ return jsonify({"status": "error", "message": "Supervisor not found"}), 404
270
+
271
+ record_id = result['records'][0]['Id']
272
+ sf.Supervisor_AI_Coaching__c.update(record_id, {"Reflection_Log__c": reflection})
273
+ logger.info(f"Reflection saved for supervisor {supervisor_id}")
274
+ return jsonify({"status": "success", "message": "Reflection submitted successfully"})
275
+
276
  except Exception as e:
277
+ logger.error(f"Error submitting reflection: {str(e)}")
278
+ return jsonify({"status": "error", "message": str(e)}), 500
279
+
280
+ @app.route('/get_supervisor_data', methods=['GET'])
281
+ def get_supervisor_data():
282
+ supervisor_id = session.get('supervisor_id')
283
+ if not supervisor_id:
284
+ logger.warning("No supervisor ID in session")
285
+ return jsonify({"status": "error", "message": "User not logged in"}), 401
286
+
287
+ try:
288
+ sf = get_salesforce_connection()
289
+ supervisor_id_escaped = quote(supervisor_id, safe='')
290
+ query = f"""
291
+ SELECT Supervisor_AI_Coaching_Name__c, Project_ID__c, Daily_Checklist__c, Suggested_Tips__c,
292
+ Reflection_Log__c, Engagement_Score__c, KPI_Flag__c, Quote__c
293
+ FROM Supervisor_AI_Coaching__c
294
+ WHERE Supervisor_AI_Coaching_Name__c = '{supervisor_id_escaped}'
295
+ LIMIT 1
296
+ """
297
+ result = sf.query(query)
298
+
299
+ if result['records']:
300
+ record = result['records'][0]
301
+ data = {
302
+ "supervisor_id": record['Supervisor_AI_Coaching_Name__c'],
303
+ "project_id": record['Project_ID__c'],
304
+ "daily_checklist": record['Daily_Checklist__c'],
305
+ "suggested_tips": record['Suggested_Tips__c'],
306
+ "reflection_log": record['Reflection_Log__c'],
307
+ "engagement_score": record['Engagement_Score__c'] or 0,
308
+ "kpi_flag": record['KPI_Flag__c'] or False,
309
+ "quote": record['Quote__c'],
310
+ "last_login": str(datetime.now())
311
+ }
312
+ logger.info(f"Fetched data for supervisor {supervisor_id}")
313
+ return jsonify({"status": "success", "data": data})
314
+ else:
315
+ logger.warning(f"No data found for supervisor {supervisor_id}")
316
+ return jsonify({"status": "error", "message": "No data found for this supervisor"}), 404
317
+ except Exception as e:
318
+ logger.error(f"Error fetching supervisor data: {str(e)}")
319
+ return jsonify({"status": "error", "message": str(e)}), 500
320
+
321
+ @app.route('/logout', methods=['POST'])
322
+ def logout():
323
+ supervisor_id = session.get('supervisor_id', 'Unknown')
324
+ session.pop('supervisor_id', None)
325
+ logger.info(f"User {supervisor_id} logged out")
326
+ return jsonify({"status": "success", "message": "Logged out successfully"})
327
+
328
+ @app.route('/health', methods=['GET'])
329
+ def health_check():
330
+ return jsonify({"status": "healthy", "message": "Application is running"}), 200
331
+
332
+ if __name__ == '__main__':
333
+ port = int(os.getenv('PORT', 5000))
334
+ app.run(host='0.0.0.0', port=port, debug=True)