Supervisor / app.py
lokeshloki143's picture
Update app.py
f75809a verified
import requests
import json
import logging
import os
from datetime import datetime
from simple_salesforce import Salesforce, SalesforceAuthenticationFailed
from flask import Flask, jsonify, request, render_template, redirect, url_for
# Configure logging
logging.basicConfig(
level=logging.DEBUG,
format='%(asctime)s - %(levelname)s - %(message)s',
handlers=[logging.StreamHandler()]
)
logger = logging.getLogger(__name__)
# Load environment variables (set these in your environment)
SF_USERNAME = os.getenv("SF_USERNAME") # e.g., Ai@Coach.com
SF_PASSWORD = os.getenv("SF_PASSWORD") # e.g., Teja90325@
SF_SECURITY_TOKEN = os.getenv("SF_SECURITY_TOKEN") # e.g., clceSdBgQ30Rx9BSC66gAcRx
SF_DOMAIN = os.getenv("SF_DOMAIN", "login") # default to "login"
HUGGINGFACE_API_KEY = os.getenv("HUGGINGFACE_API_KEY") # your Hugging Face API token
# Validate environment variables
if not all([SF_USERNAME, SF_PASSWORD, SF_SECURITY_TOKEN, HUGGINGFACE_API_KEY]):
logger.error("One or more environment variables are missing.")
raise ValueError("Please set SF_USERNAME, SF_PASSWORD, SF_SECURITY_TOKEN, and HUGGINGFACE_API_KEY environment variables.")
# Constants
HUGGING_FACE_API_URL = "https://api-inference.huggingface.co/models/distilgpt2"
HUGGING_FACE_API_TOKEN = HUGGINGFACE_API_KEY
# Initialize Flask app
app = Flask(__name__)
def test_salesforce_connection():
"""
Test the Salesforce connection.
"""
try:
logger.debug("Connecting to Salesforce with username: %s", SF_USERNAME)
sf = Salesforce(
username=SF_USERNAME,
password=SF_PASSWORD,
security_token=SF_SECURITY_TOKEN,
domain=SF_DOMAIN
)
# Verify connection
sf.query("SELECT Id FROM Account LIMIT 1")
logger.info("Connected to Salesforce successfully.")
return True, None, sf
except SalesforceAuthenticationFailed as e:
logger.error("Salesforce authentication failed: %s", e)
return False, f"Authentication failed: {str(e)}", None
except Exception as e:
logger.error("Salesforce connection error: %s", e)
return False, f"Connection error: {str(e)}", None
def fetch_project_data(project_id):
"""
Fetch Project__c record data.
"""
success, error, sf = test_salesforce_connection()
if not success:
return None, error
try:
query = f"""
SELECT Supervisor_ID__c, Role__c, Project_ID__c, Weather__c, Milestones__c, Reflection_Log__c
FROM Project__c
WHERE Id = '{project_id}'
LIMIT 1
"""
result = sf.query(query)
if result['totalSize'] > 0:
record = result['records'][0]
return {
'supervisor_id': record.get('Supervisor_ID__c', ''),
'role': record.get('Role__c', ''),
'project_id': record.get('Project_ID__c', ''),
'weather': record.get('Weather__c', ''),
'milestones': record.get('Milestones__c', ''),
'reflection': record.get('Reflection_Log__c', '')
}, None
else:
return None, "No Project__c record found."
except Exception as e:
logger.error("Error fetching project data: %s", e)
return None, f"Error fetching project data: {str(e)}"
def generate_coaching_output(data):
"""
Generate coaching output using Hugging Face API.
"""
logger.info("Generating coaching output for supervisor %s", data['supervisor_id'])
milestones_json = json.dumps(data['milestones'], indent=2)
prompt = f"""
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.
Supervisor Role: {data['role']}
Project Milestones: {milestones_json}
Reflection Log: {data['reflection_log']}
Weather: {data['weather']}
Format the response as JSON:
{{
"checklist": ["item1", "item2", ...],
"tips": ["tip1", "tip2", "tip3"],
"quote": "motivational quote"
}}
"""
headers = {
"Authorization": f"Bearer {HUGGING_FACE_API_TOKEN}",
"Content-Type": "application/json"
}
payload = {
"inputs": prompt,
"parameters": {
"max_length": 200,
"temperature": 0.7,
"top_p": 0.9,
"debug": True
}
}
try:
response = requests.post(HUGGING_FACE_API_URL, headers=headers, json=payload, timeout=10)
response.raise_for_status()
result = response.json()
generated_text = result[0]["generated_text"] if isinstance(result, list) else result["generated_text"]
start_idx = generated_text.find('{')
end_idx = generated_text.rfind('}') + 1
if start_idx == -1 or end_idx == 0:
raise ValueError("No JSON found in LLM output")
json_str = generated_text[start_idx:end_idx]
output = json.loads(json_str)
logger.info("Generated coaching output successfully.")
return output, None
except requests.exceptions.HTTPError as e:
logger.error("Hugging Face API HTTP error: %s", e)
return None, f"Hugging Face API HTTP error: {str(e)}"
except (json.JSONDecodeError, ValueError) as e:
logger.error("Error parsing LLM output: %s", e)
return None, f"Error parsing LLM output: {str(e)}"
except Exception as e:
logger.error("Unexpected error during API call: %s", e)
return None, f"API call error: {str(e)}"
def save_to_coaching_log(output, supervisor_id, project_id):
"""
Save coaching output to Salesforce Coaching_Log__c.
"""
if not output:
logger.error("No coaching output to save.")
return False, "No coaching output to save."
success, error, sf = test_salesforce_connection()
if not success:
return False, error
try:
record = {
"Supervisor_ID__c": supervisor_id,
"Project_ID__c": project_id,
"Daily_Checklist__c": "\n".join(output.get("checklist", [])),
"Suggested_Tips__c": "\n".join(output.get("tips", [])),
"Quote__c": output.get("quote", ""),
"Generated_Date__c": datetime.now().strftime("%Y-%m-%d")
}
sf.Coaching_Log__c.create(record)
logger.info("Coaching log saved successfully.")
return True, None
except Exception as e:
logger.error("Error saving coaching log: %s", e)
return False, f"Error saving coaching log: {str(e)}"
@app.route('/process_new_project', methods=['POST'])
def process_new_project():
"""
Endpoint to process new Project__c creation.
"""
data = request.get_json()
if not data or 'projectId' not in data:
logger.error("Invalid request: missing projectId.")
return jsonify({"status": "error", "message": "projectId not provided"}), 400
project_id = data['projectId']
logger.info("Processing project ID: %s", project_id)
# Fetch project data from Salesforce
project_data, fetch_error = fetch_project_data(project_id)
if fetch_error:
logger.error("Error fetching project data: %s", fetch_error)
return jsonify({"status": "error", "message": fetch_error}), 500
if not project_data:
logger.error("No data found for project ID: %s", project_id)
return jsonify({"status": "error", "message": "No project data found"}), 404
# Prepare data for AI
data_for_ai = {
'supervisor_id': project_data['supervisor_id'],
'role': project_data['role'],
'project_id': project_data['project_id'],
'milestones': [m.strip() for m in project_data['milestones'].split(',') if m.strip()],
'reflection_log': project_data['reflection'],
'weather': project_data['weather']
}
# Generate coaching output
coaching_output, gen_error = generate_coaching_output(data_for_ai)
if gen_error:
logger.error("Error generating coaching output: %s", gen_error)
return jsonify({"status": "error", "message": gen_error}), 500
# Save to Salesforce
success, save_error = save_to_coaching_log(coaching_output, project_data['supervisor_id'], project_data['project_id'])
if not success:
logger.error("Error saving coaching log: %s", save_error)
return jsonify({"status": "error", "message": save_error}), 500
return jsonify({"status": "success", "message": "Coaching log generated and saved."}), 200
@app.route('/ui', methods=['GET'])
def ui():
"""
Serve UI with latest coaching log.
"""
form_data = {}
output = {}
error_msg = ""
success, error_msg, sf = test_salesforce_connection()
if not success:
return render_template('index.html', form_data={}, output={}, error=error_msg)
try:
query = """
SELECT Supervisor_ID__c, Project_ID__c, Daily_Checklist__c, Suggested_Tips__c, Quote__c
FROM Coaching_Log__c
ORDER BY Generated_Date__c DESC
LIMIT 1
"""
result = sf.query(query)
if result['totalSize'] > 0:
record = result['records'][0]
form_data = {
'supervisor_id': record.get('Supervisor_ID__c', ''),
'project_id': record.get('Project_ID__c', '')
}
output = {
'checklist': record.get('Daily_Checklist__c', '').split('\n'),
'tips': record.get('Suggested_Tips__c', '').split('\n'),
'quote': record.get('Quote__c', '')
}
else:
error_msg = "No coaching logs found."
except Exception as e:
logger.error("Error fetching coaching logs: %s", e)
error_msg = f"Error fetching coaching logs: {str(e)}"
return render_template('index.html', form_data=form_data, output=output, error=error_msg)
@app.route('/', methods=['GET'])
def root():
"""
Redirect root to /ui.
"""
return redirect(url_for('ui'))
@app.route('/health', methods=['GET'])
def health():
"""
Basic health check.
"""
return jsonify({"status": "healthy", "message": "Application is running"}), 200
if __name__ == "__main__":
# Run Flask app
app.run(host='0.0.0.0', port=7860)