geethareddy commited on
Commit
d85f039
·
verified ·
1 Parent(s): 1c68d9d

Update app.py

Browse files
Files changed (1) hide show
  1. app.py +194 -159
app.py CHANGED
@@ -1,185 +1,220 @@
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)))
 
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)