Spaces:
Runtime error
Runtime error
| 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)}" | |
| 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 | |
| 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) | |
| def root(): | |
| """ | |
| Redirect root to /ui. | |
| """ | |
| return redirect(url_for('ui')) | |
| 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) |