nagur-shareef-shaik's picture
Added Plan Recommendations Functionality
28baf2e
import logging
from enum import Enum
from typing import List, Optional, Any, Type, Dict
from pydantic import BaseModel, Field
class IntentType(str, Enum):
"""
Enum for the types of user query intents.
This provides a controlled vocabulary for our RAG strategies.
"""
SIMPLE = "Simple"
AMBIGUOUS = "Ambiguous (RAG-Fusion)"
COMPLEX = "Complex (Decomposition)"
CONCISE = "Concise (Step-Back)"
class QueryIntent(BaseModel):
"""
Pydantic model for the structured output of the query intent classifier.
This model ensures the LLM's response is predictable and directly usable.
"""
intent: IntentType = Field(
...,
description="The classified intent of the user's query."
)
reasoning: str = Field(
...,
description="A brief explanation of why the query was classified with this intent."
)
transformed_queries: List[str] = Field(
...,
description=(
"The transformed query/queries suitable for the classified intent. "
"For SIMPLE, this is the original query. "
"For AMBIGUOUS, these are multiple variations for RAG-Fusion. "
"For COMPLEX, these are the decomposed sub-queries. "
"For CONCISE, this is a single 'step-back' question."
)
)
class TransformedQueries(BaseModel):
"""
Pydantic model for the structured output of the query transformation step.
"""
transformed_queries: List[str] = Field(
...,
description=(
"A list of transformed queries suitable for the classified intent. "
"For SIMPLE, this should be the original query in a list. "
"For AMBIGUOUS, these should be multiple variations for RAG-Fusion. "
"For COMPLEX, these should be the decomposed sub-queries. "
"For SPECULATIVE, this should be a single hypothetical document in a list. "
"For CONCISE, this should be a single 'step-back' question in a list."
)
)
class UserProfile(BaseModel):
"""
Pydantic model for the user's 360-degree profile.
"""
# --- Mandatory fields provided initially ---
zip_code: str = Field(..., description="User's 5-digit ZIP code.")
county: str = Field(..., description="User's county, derived from ZIP code.")
state: str = Field(..., description="User's state, derived from ZIP code.")
age: int = Field(..., description="User's age in years.")
gender: str = Field(..., description="User's gender (e.g., 'Male', 'Female', 'Other').")
household_size: int = Field(..., description="Number of people in the user's household.")
income: int = Field(..., description="Annual household income.")
employment_status: str = Field(..., description="User's employment status.")
citizenship: str = Field(..., description="User's citizenship status.")
# --- Fields to be populated by the ProfileAgent ---
medical_history: Optional[List[str]] = Field(
None, description="List of chronic conditions or significant medical history."
)
medications: Optional[List[str]] = Field(
None, description="List of current prescription medications."
)
special_cases: Optional[List[str]] = Field(
None, description="Special circumstances like pregnancy, tobacco use, etc."
)
class GeoDataResponse(BaseModel):
"""
The response model for the /geodata endpoint.
"""
zip_code: str
county: str
city: str
state: str
state_abbreviation: str
class ChatRequest(BaseModel):
"""
The request model for the main /chat endpoint.
"""
thread_id: str
user_profile: Dict[str, Optional[Any]]
message: str
conversation_history: List[str] = Field(default_factory=list)
is_profile_complete: bool
class ChatResponse(BaseModel):
"""
The response model for the /chat endpoint.
"""
agent_response: str
updated_profile: Dict[str, Any]
updated_history: List[str]
is_profile_complete: bool
plan_recommendations: Optional[Dict[str, Any]]