geethareddy commited on
Commit
02615cd
·
verified ·
1 Parent(s): a117aa7

Update app.py

Browse files
Files changed (1) hide show
  1. app.py +159 -194
app.py CHANGED
@@ -1,220 +1,185 @@
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 bcrypt
7
- from urllib.parse import quote
8
-
9
- # Load environment variables
10
- load_dotenv()
11
 
12
  # Configure logging
13
- logging.basicConfig(
14
- level=logging.DEBUG, # Set to DEBUG for detailed logs
15
- format='%(asctime)s - %(levelname)s - %(message)s',
16
- handlers=[
17
- logging.FileHandler('app.log'),
18
- logging.StreamHandler()
19
- ]
20
- )
21
  logger = logging.getLogger(__name__)
22
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
23
  app = Flask(__name__)
24
- app.secret_key = os.getenv('FLASK_SECRET_KEY', 'tPhZ8oXGBoadFBQXgUkSR2kDH')
25
 
26
- # Salesforce mock data for guest users
27
- MOCK_DATA = {
28
- "supervisor_id": "GUEST",
29
- "project_id": "PROJ_001",
30
- "last_login": "Guest Mode"
31
- }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
32
 
33
- def get_salesforce_connection():
34
- """Establish a Salesforce connection with detailed error handling."""
35
  try:
36
- # Ensure you are passing the correct environment variables
37
- sf = Salesforce(
38
- username=os.getenv('SALESFORCE_USERNAME'),
39
- password=os.getenv('SALESFORCE_PASSWORD'),
40
- security_token=os.getenv('SALESFORCE_SECURITY_TOKEN'),
41
- domain=os.getenv('SALESFORCE_DOMAIN', 'login'), # 'test' is for sandbox, 'login' is for production
42
- version='60.0' # Specify Salesforce API version
43
- )
44
- logger.info("Successfully connected to Salesforce")
 
45
 
46
- # Test connection
47
- sf.query("SELECT Id FROM Supervisor__c LIMIT 1")
48
- logger.debug("Salesforce connection test query successful")
49
- return sf
50
- except SalesforceAuthenticationFailed as e:
51
- logger.error(f"Salesforce authentication failed: {str(e)}")
52
- raise Exception(f"Salesforce authentication failed: {str(e)}. Check your credentials.")
53
- except SalesforceError as e:
54
- logger.error(f"Salesforce error during connection: {str(e)}")
55
- raise Exception(f"Salesforce error: {str(e)}. Check object permissions and API access.")
56
- except Exception as e:
57
- logger.error(f"Unexpected error connecting to Salesforce: {str(e)}")
58
- raise Exception(f"Unable to connect to Salesforce: {str(e)}. Please check your configuration.")
59
-
60
-
61
- def hash_password(password):
62
- """Hash a password using bcrypt."""
63
- try:
64
- return bcrypt.hashpw(password.encode('utf-8'), bcrypt.gensalt()).decode('utf-8')
65
  except Exception as e:
66
- logger.error(f"Password hashing failed: {str(e)}")
67
- raise
68
-
69
- def verify_password(password, hashed_password):
70
- """Verify a password against its hash."""
71
- try:
72
- return bcrypt.checkpw(password.encode('utf-8'), hashed_password.encode('utf-8'))
73
- except Exception as e:
74
- logger.error(f"Password verification failed: {str(e)}")
75
  return False
76
 
77
- @app.route('/')
78
- def index():
79
- if 'supervisor_id' not in session:
80
- logger.info("User not logged in, redirecting to login page")
81
- return redirect(url_for('login_page'))
82
- return render_template('index.html')
83
-
84
- @app.route('/login', methods=['GET'])
85
- def login_page():
86
- return render_template('login.html')
87
-
88
- @app.route('/signup', methods=['GET'])
89
- def signup_page():
90
- return render_template('signup.html')
91
-
92
- @app.route('/login', methods=['POST'])
93
- def login():
94
- data = request.get_json()
95
- supervisor_id = data.get('supervisor_id')
96
- password = data.get('password')
97
-
98
- if not supervisor_id or not password:
99
- logger.warning("Login failed: Supervisor ID and password are required")
100
- return jsonify({"status": "error", "message": "Supervisor ID and password are required"}), 400
101
-
102
- if supervisor_id == 'GUEST':
103
- session['supervisor_id'] = 'GUEST'
104
- logger.info("Guest login successful")
105
- return jsonify({"status": "success", "message": "Logged in as guest"})
106
-
107
  try:
108
- sf = get_salesforce_connection()
109
- logger.debug(f"Querying Salesforce for Supervisor_ID__c: {supervisor_id}")
110
- supervisor_id_escaped = quote(supervisor_id, safe='')
111
- query = f"SELECT Id, Name, Password__c FROM Supervisor__c WHERE Name = '{supervisor_id_escaped}' LIMIT 1"
112
- result = sf.query(query)
113
- logger.debug(f"Salesforce query result: {result}")
114
-
115
- if not result['records']:
116
- logger.warning(f"Invalid Supervisor ID: {supervisor_id}")
117
- return jsonify({"status": "error", "message": "Invalid Supervisor ID"}), 401
118
-
119
- record = result['records'][0]
120
- stored_password = record['Password__c']
121
- if not stored_password:
122
- logger.warning(f"No password set for Supervisor ID: {supervisor_id}")
123
- return jsonify({"status": "error", "message": "No password set for this Supervisor ID"}), 401
124
-
125
- if not verify_password(password, stored_password):
126
- logger.warning(f"Invalid password for Supervisor ID: {supervisor_id}")
127
- return jsonify({"status": "error", "message": "Invalid password"}), 401
128
-
129
- session['supervisor_id'] = supervisor_id
130
- logger.info(f"Login successful for {supervisor_id}")
131
- return jsonify({"status": "success", "message": "Login successful"})
132
- except Exception as e:
133
- logger.error(f"Login error: {str(e)}")
134
- return jsonify({"status": "error", "message": str(e)}), 500
135
-
136
- @app.route('/signup', methods=['POST'])
137
- def signup():
138
- data = request.get_json()
139
- supervisor_id = data.get('supervisor_id')
140
- password = data.get('password')
141
-
142
- if not supervisor_id or not password:
143
- logger.warning("Signup failed: Supervisor ID and password are required")
144
- return jsonify({"status": "error", "message": "Supervisor ID and password are required"}), 400
145
-
146
- try:
147
- sf = get_salesforce_connection()
148
- logger.debug(f"Checking if Supervisor_ID__c {supervisor_id} already exists")
149
- supervisor_id_escaped = quote(supervisor_id, safe='')
150
- query = f"SELECT Id FROM Supervisor__c WHERE Name = '{supervisor_id_escaped}' LIMIT 1"
151
- result = sf.query(query)
152
- if result['records']:
153
- logger.warning(f"Signup failed: Supervisor ID {supervisor_id} already exists")
154
- return jsonify({"status": "error", "message": "Supervisor ID already exists"}), 400
155
-
156
- hashed_password = hash_password(password)
157
- logger.debug(f"Creating new Supervisor__c record for {supervisor_id}")
158
- new_record = {
159
- 'Name': supervisor_id,
160
- 'Password__c': hashed_password
161
-
162
  }
163
- response = sf.Supervisor__c.create(new_record)
164
- logger.debug(f"Salesforce create response: {response}")
165
 
166
- if not response.get('success'):
167
- logger.error(f"Failed to create Supervisor record: {response.get('errors')}")
168
- return jsonify({"status": "error", "message": f"Failed to create record in Salesforce: {response.get('errors')}"}), 500
 
 
 
169
 
170
- session['supervisor_id'] = supervisor_id
171
- logger.info(f"Signup successful for {supervisor_id}")
172
- return jsonify({"status": "success", "message": "Signup successful, you are now logged in"})
173
  except Exception as e:
174
- logger.error(f"Signup error: {str(e)}")
175
- return jsonify({"status": "error", "message": str(e)}), 500
176
-
177
- @app.route('/logout', methods=['POST'])
178
- def logout():
179
- supervisor_id = session.get('supervisor_id', 'Unknown')
180
- session.pop('supervisor_id', None)
181
- logger.info(f"User {supervisor_id} logged out")
182
- return jsonify({"status": "success", "message": "Logged out successfully"})
183
 
184
- @app.route('/get_supervisor_data')
185
- def get_supervisor_data():
186
- supervisor_id = session.get('supervisor_id', 'GUEST')
187
- if supervisor_id == 'GUEST':
188
- logger.info("Returning mock data for guest user")
189
- return jsonify({"status": "success", "data": MOCK_DATA})
 
 
 
 
 
 
 
190
 
 
 
 
 
 
191
  try:
192
- sf = get_salesforce_connection()
193
- supervisor_id_escaped = quote(supervisor_id, safe='')
194
- query = f"""
195
- SELECT Supervisor_ID__c, Project_ID__c
196
- FROM Supervisor__c
197
- WHERE Supervisor_ID__c = '{supervisor_id_escaped}'
198
- LIMIT 1
199
- """
200
- result = sf.query(query)
201
-
202
- if result['records']:
203
- record = result['records'][0]
204
- data = {
205
- "supervisor_id": record['Supervisor_ID__c'],
206
- "project_id": record['Project_ID__c'],
207
- "last_login": str(datetime.now())
208
- }
209
- logger.info(f"Fetched data for supervisor {supervisor_id}")
210
- return jsonify({"status": "success", "data": data})
211
  else:
212
- logger.warning(f"No data found for supervisor {supervisor_id}")
213
- return jsonify({"status": "error", "message": "No data found for this supervisor"}), 404
214
  except Exception as e:
215
- logger.error(f"Error fetching supervisor data: {str(e)}")
216
  return jsonify({"status": "error", "message": str(e)}), 500
217
 
218
- if __name__ == '__main__':
219
- port = int(os.getenv('PORT', 5000))
220
- app.run(host='0.0.0.0', port=port, debug=True)
 
 
 
 
 
 
 
1
+ import requests
2
+ import json
3
  import os
 
4
  import logging
5
+ from datetime import datetime
6
+ from dotenv import load_dotenv
7
+ from simple_salesforce import Salesforce
8
+ from flask import Flask, jsonify, request, render_template, redirect, url_for
 
9
 
10
  # Configure logging
11
+ logging.basicConfig(level=logging.INFO, format='%(asctime)s - %(levelname)s - %(message)s')
 
 
 
 
 
 
 
12
  logger = logging.getLogger(__name__)
13
 
14
+ # Load environment variables
15
+ load_dotenv()
16
+
17
+ # Hugging Face API configuration
18
+ HUGGING_FACE_API_URL = os.getenv("HUGGING_FACE_API_URL", "https://api-inference.huggingface.co/models/distilgpt2")
19
+ HUGGING_FACE_API_TOKEN = os.getenv("HUGGING_FACE_API_TOKEN")
20
+
21
+ # Salesforce configuration
22
+ SALESFORCE_USERNAME = os.getenv("SALESFORCE_USERNAME")
23
+ SALESFORCE_PASSWORD = os.getenv("SALESFORCE_PASSWORD")
24
+ SALESFORCE_SECURITY_TOKEN = os.getenv("SALESFORCE_SECURITY_TOKEN")
25
+ SALESFORCE_DOMAIN = os.getenv("SALESFORCE_DOMAIN", "login")
26
+
27
+ # Validate environment variables
28
+ if not HUGGING_FACE_API_TOKEN:
29
+ logger.error("HUGGING_FACE_API_TOKEN is not set")
30
+ raise ValueError("HUGGING_FACE_API_TOKEN environment variable is not set")
31
+ if not HUGGING_FACE_API_URL.startswith("https://api-inference.huggingface.co/models/"):
32
+ logger.error("Invalid HUGGING_FACE_API_URL: %s", HUGGING_FACE_API_URL)
33
+ raise ValueError("HUGGING_FACE_API_URL must point to a valid Hugging Face model")
34
+ if not all([SALESFORCE_USERNAME, SALESFORCE_PASSWORD, SALESFORCE_SECURITY_TOKEN]):
35
+ logger.error("Salesforce credentials are incomplete")
36
+ raise ValueError("Salesforce credentials must be set")
37
+
38
+ # Initialize Flask app
39
  app = Flask(__name__)
 
40
 
41
+ def generate_coaching_output(data):
42
+ """
43
+ Generate daily checklist and tips using Hugging Face LLM.
44
+ """
45
+ logger.info("Generating coaching output for supervisor %s", data['supervisor_id'])
46
+ milestones_json = json.dumps(data['milestones'], indent=2)
47
+ prompt = f"""
48
+ 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.
49
+
50
+ Supervisor Role: {data['role']}
51
+ Project Milestones: {milestones_json}
52
+ Reflection Log: {data['reflection_log']}
53
+ Weather: {data['weather']}
54
+
55
+ Format the response as JSON:
56
+ {{
57
+ "checklist": ["item1", "item2", ...],
58
+ "tips": ["tip1", "tip2", "tip3"],
59
+ "quote": "motivational quote"
60
+ }}
61
+ """
62
+
63
+ headers = {
64
+ "Authorization": f"Bearer {HUGGING_FACE_API_TOKEN}",
65
+ "Content-Type": "application/json"
66
+ }
67
+ payload = {
68
+ "inputs": prompt,
69
+ "parameters": {
70
+ "max_length": 200,
71
+ "temperature": 0.7,
72
+ "top_p": 0.9
73
+ }
74
+ }
75
 
 
 
76
  try:
77
+ response = requests.post(HUGGING_FACE_API_URL, headers=headers, json=payload, timeout=5)
78
+ response.raise_for_status()
79
+ result = response.json()
80
+ generated_text = result[0]["generated_text"] if isinstance(result, list) else result["generated_text"]
81
+
82
+ start_idx = generated_text.find('{')
83
+ end_idx = generated_text.rfind('}') + 1
84
+ if start_idx == -1 or end_idx == 0:
85
+ logger.error("No valid JSON found in LLM output")
86
+ raise ValueError("No valid JSON found in LLM output")
87
 
88
+ json_str = generated_text[start_idx:end_idx]
89
+ output = json.loads(json_str)
90
+ logger.info("Successfully generated coaching output")
91
+ return output
92
+
93
+ except requests.exceptions.HTTPError as e:
94
+ logger.error("Hugging Face API HTTP error: %s", e)
95
+ return None
96
+ except (json.JSONDecodeError, ValueError) as e:
97
+ logger.error("Error parsing LLM output: %s", e)
98
+ return None
 
 
 
 
 
 
 
 
99
  except Exception as e:
100
+ logger.error("Unexpected error in Hugging Face API call: %s", e)
101
+ return None
102
+
103
+ def save_to_salesforce(output, supervisor_id, project_id):
104
+ """
105
+ Save coaching output to Salesforce Supervisor_AI_Coaching__c object.
106
+ """
107
+ if not output:
108
+ logger.error("No coaching output to save")
109
  return False
110
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
111
  try:
112
+ sf = Salesforce(
113
+ username=SALESFORCE_USERNAME,
114
+ password=SALESFORCE_PASSWORD,
115
+ security_token=SALESFORCE_SECURITY_TOKEN,
116
+ domain=SALESFORCE_DOMAIN
117
+ )
118
+ logger.info("Connected to Salesforce")
119
+
120
+ coaching_record = {
121
+ "Supervisor_ID__c": supervisor_id,
122
+ "Project_ID__c": project_id,
123
+ "Daily_Checklist__c": "\n".join(output["checklist"]),
124
+ "Suggested_Tips__c": "\n".join(output["tips"]),
125
+ "Quote__c": output["quote"],
126
+ "Generated_Date__c": datetime.now().strftime("%Y-%m-%d")
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
127
  }
 
 
128
 
129
+ sf.Supervisor_AI_Coaching__c.upsert(
130
+ f"Supervisor_ID__c/{supervisor_id}_{datetime.now().strftime('%Y-%m-%d')}",
131
+ coaching_record
132
+ )
133
+ logger.info("Successfully saved coaching record to Salesforce for supervisor %s", supervisor_id)
134
+ return True
135
 
 
 
 
136
  except Exception as e:
137
+ logger.error("Salesforce error: %s", e)
138
+ return False
 
 
 
 
 
 
 
139
 
140
+ @app.route('/', methods=['GET'])
141
+ def redirect_to_ui():
142
+ """
143
+ Redirect root URL to the UI.
144
+ """
145
+ return redirect(url_for('ui'))
146
+
147
+ @app.route('/ui', methods=['GET'])
148
+ def ui():
149
+ """
150
+ Serve the HTML user interface.
151
+ """
152
+ return render_template('index.html')
153
 
154
+ @app.route('/generate', methods=['POST'])
155
+ def generate_endpoint():
156
+ """
157
+ Endpoint to generate coaching output based on supervisor data.
158
+ """
159
  try:
160
+ data = request.get_json()
161
+ if not data or not all(key in data for key in ['supervisor_id', 'role', 'project_id', 'milestones', 'reflection_log', 'weather']):
162
+ return jsonify({"status": "error", "message": "Invalid or missing supervisor data"}), 400
163
+
164
+ coaching_output = generate_coaching_output(data)
165
+ if coaching_output:
166
+ success = save_to_salesforce(coaching_output, data["supervisor_id"], data["project_id"])
167
+ if success:
168
+ return jsonify({"status": "success", "output": coaching_output}), 200
169
+ else:
170
+ return jsonify({"status": "error", "message": "Failed to save to Salesforce"}), 500
 
 
 
 
 
 
 
 
171
  else:
172
+ return jsonify({"status": "error", "message": "Failed to generate coaching output"}), 500
 
173
  except Exception as e:
174
+ logger.error("Error in generate endpoint: %s", e)
175
  return jsonify({"status": "error", "message": str(e)}), 500
176
 
177
+ @app.route('/health', methods=['GET'])
178
+ def health_check():
179
+ """
180
+ Health check endpoint.
181
+ """
182
+ return jsonify({"status": "healthy", "message": "Application is running"}), 200
183
+
184
+ if __name__ == "__main__":
185
+ app.run(host="0.0.0.0", port=int(os.getenv("PORT", 7860)))