shl-recommender / app /main.py
devpatel1012's picture
updated main.py
71a3245
Raw
History Blame Contribute Delete
4.9 kB
from fastapi import FastAPI
from fastapi.responses import HTMLResponse
from pydantic import BaseModel, Field
from contextlib import asynccontextmanager
from typing import List, Optional
from app.database import db_manager
from app.agent import shl_agent
# 1. Define Schemas inside main.py to ensure compliance
class Recommendation(BaseModel):
name: str
url: str
test_type: str
class ChatMessage(BaseModel):
role: str
content: str
class ChatRequest(BaseModel):
# CRITICAL: The grader expects 'messages', not 'conversation'
messages: List[ChatMessage]
class ChatResponse(BaseModel):
reply: str
recommendations: List[Recommendation] = Field(default_factory=list)
end_of_conversation: bool = False
# 2. Lifecycle
@asynccontextmanager
async def lifespan(app: FastAPI):
catalog_file_path = "shl_product_catalog.json"
db_manager.initialize_catalog(catalog_file_path)
yield
app = FastAPI(lifespan=lifespan)
# 3. Frontend UI
html_content = """
<!DOCTYPE html>
<html>
<head>
<title>SHL Assessment Consultant</title>
<style>
body { font-family: Arial, sans-serif; max-width: 800px; margin: 0 auto; padding: 20px; background-color: #f4f4f9; }
#chat-container { background: white; padding: 20px; border-radius: 8px; box-shadow: 0 4px 8px rgba(0,0,0,0.1); height: 500px; overflow-y: auto; margin-bottom: 20px; }
.message { margin-bottom: 15px; padding: 10px; border-radius: 5px; }
.user { background-color: #e3f2fd; text-align: right; border-left: 4px solid #2196f3; }
.agent { background-color: #f1f8e9; text-align: left; border-left: 4px solid #4caf50; }
.system { text-align: center; color: #888; font-style: italic; font-size: 0.9em; }
table { width: 100%; border-collapse: collapse; margin-top: 10px; font-size: 0.9em; }
th, td { border: 1px solid #ddd; padding: 8px; text-align: left; }
th { background-color: #4caf50; color: white; }
.input-area { display: flex; gap: 10px; }
input[type="text"] { flex-grow: 1; padding: 10px; border: 1px solid #ccc; border-radius: 4px; }
button { padding: 10px 20px; background-color: #2196f3; color: white; border: none; border-radius: 4px; cursor: pointer; }
</style>
</head>
<body>
<h2>SHL Assessment Consultant</h2>
<div id="chat-container">
<div class="message system">Start a conversation. E.g., "I'm hiring a Java developer."</div>
</div>
<div class="input-area">
<input type="text" id="user-input" placeholder="Type your message..." onkeypress="if(event.key === 'Enter') sendMessage()">
<button onclick="sendMessage()">Send</button>
</div>
<script>
let conversationHistory = [];
async function sendMessage() {
const inputField = document.getElementById('user-input');
const userText = inputField.value.trim();
if (!userText) return;
const chatContainer = document.getElementById('chat-container');
chatContainer.innerHTML += `<div class="message user"><strong>You:</strong> ${userText}</div>`;
conversationHistory.push({ "role": "user", "content": userText });
inputField.value = '';
try {
// CRITICAL: Sending 'messages' key, not 'conversation'
const response = await fetch('/chat', {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({ messages: conversationHistory })
});
const data = await response.json();
chatContainer.innerHTML += `<div class="message agent"><strong>Consultant:</strong> ${data.reply}</div>`;
conversationHistory.push({ "role": "assistant", "content": data.reply });
if (data.end_of_conversation) {
conversationHistory = [];
}
} catch (error) {
chatContainer.innerHTML += `<div class="message system" style="color:red;">Error.</div>`;
}
chatContainer.scrollTop = chatContainer.scrollHeight;
}
</script>
</body>
</html>
"""
@app.get("/", response_class=HTMLResponse)
async def get_frontend():
return html_content
@app.get("/health")
def health_check():
return {"status": "ok"}
@app.post("/chat", response_model=ChatResponse)
def chat_endpoint(request: ChatRequest):
try:
# CRITICAL: Processing 'messages' not 'conversation'
response_dict = shl_agent.handle_conversation(request.messages)
return ChatResponse(**response_dict)
except Exception as e:
return ChatResponse(
reply="I ran into an issue — could you rephrase it?",
recommendations=[],
end_of_conversation=False
)