AI_Coach / app.py
geethareddy's picture
Update app.py
e3b42ef verified
raw
history blame
8.78 kB
import logging
import os
import uvicorn
from fastapi import FastAPI, HTTPException
from fastapi.responses import FileResponse
from pydantic import BaseModel
from simple_salesforce import Salesforce
from contextlib import asynccontextmanager
import requests
from typing import Optional
# Set up logging early
logging.basicConfig(level=logging.INFO)
logger = logging.getLogger(__name__)
logger.info("Starting application initialization")
# Load environment variables
SF_USERNAME = os.getenv('[email protected]')
SF_PASSWORD = os.getenv('Teja90325@')
SF_SECURITY_TOKEN = os.getenv('BNgBGeH986OPZk0fWxPlIR3Is')
# Validate environment variables
required_vars = {
'SF_USERNAME': SF_USERNAME,
'SF_PASSWORD': SF_PASSWORD,
'SF_SECURITY_TOKEN': SF_SECURITY_TOKEN
}
missing_vars = [var for var, value in required_vars.items() if not value]
if missing_vars:
logger.error(f"Missing required environment variables: {', '.join(missing_vars)}")
raise ValueError(f"Missing required environment variables: {', '.join(missing_vars)}")
# Global Salesforce connection
sf = None
@asynccontextmanager
async def lifespan(app: FastAPI):
"""Manage application lifecycle."""
global sf
logger.info("Starting application lifecycle")
# Initialize Salesforce connection
try:
sf = Salesforce(
username=SF_USERNAME,
password=SF_PASSWORD,
security_token=SF_SECURITY_TOKEN,
instance_url='https://aicoachforsitesupervisors-dev-ed.develop.my.salesforce.com',
version='63.0'
)
logger.info("Successfully connected to Salesforce")
except Exception as e:
logger.error(f"Failed to connect to Salesforce: {str(e)}")
sf = None
logger.info("Application initialized successfully")
yield
logger.info("Shutting down application")
# Initialize FastAPI app with lifespan
app = FastAPI(lifespan=lifespan)
# OpenWeatherMap API key (hardcoded as it works and doesn't cause issues)
WEATHER_API_KEY = "60c00e1b8293d3c0482f8d6ca1a37003"
# Pydantic model for request body
class ProjectRequest(BaseModel):
projectId: str
projectName: str
milestones: Optional[str] = None
weatherLogs: Optional[str] = None
safetyLogs: Optional[str] = None
role: str
def fetch_weather_data(location: str) -> str:
"""Fetch weather data for a given location."""
try:
url = f"http://api.openweathermap.org/data/2.5/weather?q={location}&appid={WEATHER_API_KEY}&units=metric"
response = requests.get(url)
response.raise_for_status()
data = response.json()
weather = data['weather'][0]['description']
temp = data['main']['temp']
return f"{weather}, {temp}°C"
except Exception as e:
logger.error(f"Failed to fetch weather data: {str(e)}")
return "Weather data unavailable"
def generate_coaching_data(project: dict, role: str) -> dict:
"""Mock AI model to generate checklist, tips, and engagement score."""
logger.info(f"Generating coaching data for project {project.get('Name')}")
checklist = f"1. Review safety protocols for {project.get('Project_Name__c', 'project')}\n2. Check {role} tasks\n3. Update milestones"
tips = f"1. Prioritize safety due to {project.get('Weather_Logs__c', 'conditions')}\n2. Focus on {role} responsibilities\n3. Communicate progress"
engagement_score = 85.0 # Mock score; replace with real AI model
return {
"checklist": checklist,
"tips": tips,
"engagementScore": engagement_score
}
@app.get("/api/latest-project")
async def get_latest_project():
"""Fetch the latest Project__c record based on CreatedDate."""
if sf is None:
logger.error("Salesforce connection not initialized")
raise HTTPException(status_code=500, detail="Salesforce connection not initialized")
try:
query = """
SELECT Id, Name, Project_Name__c, Milestones__c, Weather_Logs__c, Safety_Logs__c, Location__c, Supervisor_ID__c
FROM Project__c
ORDER BY CreatedDate DESC
LIMIT 1
"""
logger.info(f"Executing SOQL query for latest project: {query}")
result = sf.query(query)
if result['totalSize'] == 0:
logger.warning("No Project__c records found")
raise HTTPException(status_code=404, detail="No projects found")
project = result['records'][0]
logger.info(f"Fetched latest project: {project['Name']}")
# Prepare response with extracted fields
response = {
"projectId": project['Name'],
"projectName": project['Project_Name__c'],
"milestones": project.get('Milestones__c', ''),
"weatherLogs": project.get('Weather_Logs__c', ''),
"safetyLogs": project.get('Safety_Logs__c', ''),
"role": "Site Manager" # Default role; can be updated based on Supervisor_ID__c if needed
}
return response
except Exception as e:
logger.error(f"Error fetching latest project: {str(e)}")
raise HTTPException(status_code=500, detail=str(e))
@app.post("/api/generate")
async def generate_coaching(request: ProjectRequest):
if sf is None:
logger.error("Salesforce connection not initialized")
raise HTTPException(status_code=500, detail="Salesforce connection not initialized")
try:
# Query Project__c by projectId to get the full record
query = f"SELECT Id, Name, Project_Name__c, Milestones__c, Weather_Logs__c, Safety_Logs__c, Location__c, Supervisor_ID__c FROM Project__c WHERE Name = '{request.projectId}' LIMIT 1"
logger.info(f"Executing SOQL query: {query}")
result = sf.query(query)
if result['totalSize'] == 0:
logger.warning(f"Project {request.projectId} not found")
raise HTTPException(status_code=404, detail="Project not found")
project = result['records'][0]
logger.info(f"Retrieved project: {project['Name']}")
# Update weather logs if location available
if project.get('Location__c'):
project['Weather_Logs__c'] = fetch_weather_data(project['Location__c'])
# Generate coaching data
coaching_data = generate_coaching_data(project, request.role)
# Prepare response with extracted fields and generated results
response = {
"projectId": project['Name'],
"projectName": project['Project_Name__c'],
"milestones": project.get('Milestones__c', ''),
"weatherLogs": project.get('Weather_Logs__c', ''),
"safetyLogs": project.get('Safety_Logs__c', ''),
"role": request.role,
"checklist": coaching_data['checklist'],
"tips": coaching_data['tips'],
"engagementScore": coaching_data['engagementScore']
}
# Insert into Supervisor_AI_Coaching__c
try:
coaching_record = {
'Project_ID__c': project['Id'], # Updated to correct API name for Lookup field
'Checklist__c': coaching_data['checklist'],
'Tips__c': coaching_data['tips'],
'Engagement_Score__c': coaching_data['engagementScore'],
'Role__c': request.role,
'Project_Name__c': project['Project_Name__c'],
'Milestones__c': project.get('Milestones__c', ''),
'Weather_Logs__c': project.get('Weather_Logs__c', ''),
'Safety_Logs__c': project.get('Safety_Logs__c', '')
}
sf.Supervisor_AI_Coaching__c.create(coaching_record)
logger.info(f"Inserted coaching data into Supervisor_AI_Coaching__c for project {project['Name']}")
except Exception as e:
logger.error(f"Failed to insert into Supervisor_AI_Coaching__c: {str(e)}")
raise HTTPException(status_code=500, detail=f"Failed to save coaching data: {str(e)}")
logger.info(f"Generated coaching response: {response}")
return response
except Exception as e:
logger.error(f"Error generating coaching data: {str(e)}")
raise HTTPException(status_code=500, detail=str(e))
@app.get("/")
async def root():
logger.info("Serving index.html from root directory")
return FileResponse("index.html")
@app.get("/styles.css")
async def serve_styles():
logger.info("Serving styles.css from root directory")
return FileResponse("styles.css", media_type="text/css")
# Start Uvicorn server for Hugging Face Spaces
logger.info("Starting Uvicorn server for Hugging Face Spaces")
uvicorn.run(app, host="0.0.0.0", port=7860)