nagur-shareef-shaik's picture
Added Plan Recommendations Functionality
28baf2e
import logging
from fastapi import APIRouter, HTTPException, Body
from typing import Dict, Any
# Import our services, agents, and models
from insucompass.services.zip_client import get_geo_data_from_zip
from insucompass.core.models import GeoDataResponse, ChatRequest, ChatResponse
from insucompass.core.agents.profile_agent import profile_builder
from insucompass.core.agent_orchestrator import app as orchestrator # The compiled LangGraph app
from insucompass.services.database import get_db_connection, create_or_update_user_profile, get_user_profile
# Configure logging
logger = logging.getLogger(__name__)
# Create the API router
router = APIRouter()
logger = logging.getLogger(__name__)
router = APIRouter()
@router.get("/geodata/{zip_code}", response_model=GeoDataResponse)
def get_geolocation_data(zip_code: str):
"""Endpoint to get county, city, and state information from a given ZIP code."""
if not zip_code.isdigit() or len(zip_code) != 5:
raise HTTPException(status_code=400, detail="Invalid ZIP code format.")
geo_data = get_geo_data_from_zip(zip_code)
if not geo_data:
raise HTTPException(status_code=404, detail="Could not find location data.")
return GeoDataResponse(
zip_code=zip_code, county=geo_data.county.replace(" County", ""),
city=geo_data.city, state=geo_data.state, state_abbreviation=geo_data.state_abbr
)
@router.post("/chat", response_model=ChatResponse)
async def chat(request: ChatRequest):
"""
Handles the entire conversational flow using the unified LangGraph orchestrator.
The orchestrator manages the state, including profile building and Q&A.
"""
logger.info(f"Received unified chat request for thread_id: {request.thread_id}")
# LangGraph needs a thread_id to save/load conversation state from its checkpointer
thread_config = {"configurable": {"thread_id": request.thread_id}}
# The graph's state is loaded automatically by LangGraph using the thread_id.
# We only need to provide the inputs for the current turn.
inputs = {
"user_profile": request.user_profile,
"user_message": request.message,
"is_profile_complete": request.is_profile_complete,
"conversation_history": request.conversation_history,
}
try:
# We invoke the graph. It will load the previous state, run the necessary nodes,
# and save the new state, all in one call.
final_state = orchestrator.invoke(inputs, config=thread_config)
# Extract the relevant data from the final state of the graph
agent_response = final_state.get("generation")
updated_profile = final_state.get("user_profile")
updated_history = final_state.get("conversation_history")
is_profile_complete = final_state.get("is_profile_complete")
plan_recs = final_state.get("plan_recommendations")
if not agent_response:
agent_response = "I'm sorry, I encountered an issue. Could you please rephrase?"
logger.info("Unified graph execution completed successfully.")
return ChatResponse(
agent_response=agent_response,
updated_profile=updated_profile,
updated_history=updated_history,
is_profile_complete=is_profile_complete,
plan_recommendations=plan_recs
)
except Exception as e:
logger.error(f"Error during unified graph orchestration: {e}", exc_info=True)
raise HTTPException(status_code=500, detail="An internal error occurred in the AI orchestrator.")