Fix chat interface response issues: proper session handling, error handling, and UI display fixes
Browse files- api/chat.py +50 -24
- app.py +4 -4
- core/llm.py +17 -32
api/chat.py
CHANGED
|
@@ -1,44 +1,70 @@
|
|
| 1 |
import json
|
| 2 |
from fastapi import APIRouter, HTTPException
|
| 3 |
-
from fastapi.responses import
|
| 4 |
from core.llm import LLMClient
|
| 5 |
-
from core.memory import save_user_state, load_user_state
|
| 6 |
from core.session import session_manager
|
| 7 |
import logging
|
| 8 |
|
| 9 |
router = APIRouter()
|
| 10 |
logger = logging.getLogger(__name__)
|
| 11 |
|
| 12 |
-
|
|
|
|
| 13 |
|
| 14 |
@router.post("/chat")
|
| 15 |
async def chat(user_id: str, message: str):
|
| 16 |
-
|
|
|
|
|
|
|
|
|
|
| 17 |
raise HTTPException(status_code=400, detail="Message is required")
|
| 18 |
-
|
| 19 |
try:
|
| 20 |
-
#
|
| 21 |
session = session_manager.get_session(user_id)
|
| 22 |
conversation_history = session.get("conversation", [])
|
| 23 |
|
| 24 |
# Add user message to history
|
| 25 |
-
conversation_history.append({
|
| 26 |
-
|
| 27 |
-
|
| 28 |
-
|
| 29 |
-
|
| 30 |
-
|
| 31 |
-
|
| 32 |
-
|
| 33 |
-
|
| 34 |
-
|
| 35 |
-
|
| 36 |
-
|
| 37 |
-
|
| 38 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 39 |
logger.info(f"Successfully processed chat for user {user_id}")
|
| 40 |
-
return
|
| 41 |
-
|
|
|
|
|
|
|
|
|
|
| 42 |
except Exception as e:
|
| 43 |
-
logger.error(f"
|
| 44 |
-
raise HTTPException(
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
import json
|
| 2 |
from fastapi import APIRouter, HTTPException
|
| 3 |
+
from fastapi.responses import JSONResponse
|
| 4 |
from core.llm import LLMClient
|
|
|
|
| 5 |
from core.session import session_manager
|
| 6 |
import logging
|
| 7 |
|
| 8 |
router = APIRouter()
|
| 9 |
logger = logging.getLogger(__name__)
|
| 10 |
|
| 11 |
+
# Initialize LLM client with fallback support
|
| 12 |
+
llm_client = LLMClient()
|
| 13 |
|
| 14 |
@router.post("/chat")
|
| 15 |
async def chat(user_id: str, message: str):
|
| 16 |
+
"""
|
| 17 |
+
Handle chat requests with proper session management and error handling.
|
| 18 |
+
"""
|
| 19 |
+
if not message or not message.strip():
|
| 20 |
raise HTTPException(status_code=400, detail="Message is required")
|
| 21 |
+
|
| 22 |
try:
|
| 23 |
+
# Get session using session manager
|
| 24 |
session = session_manager.get_session(user_id)
|
| 25 |
conversation_history = session.get("conversation", [])
|
| 26 |
|
| 27 |
# Add user message to history
|
| 28 |
+
conversation_history.append({
|
| 29 |
+
"role": "user",
|
| 30 |
+
"content": message
|
| 31 |
+
})
|
| 32 |
+
|
| 33 |
+
# Generate AI response using factory pattern
|
| 34 |
+
try:
|
| 35 |
+
ai_response = llm_client.generate(
|
| 36 |
+
prompt=message,
|
| 37 |
+
conversation_history=conversation_history
|
| 38 |
+
)
|
| 39 |
+
|
| 40 |
+
if not ai_response:
|
| 41 |
+
raise Exception("Empty response from LLM")
|
| 42 |
+
|
| 43 |
+
except Exception as e:
|
| 44 |
+
logger.error(f"LLM generation failed: {e}")
|
| 45 |
+
# Try to provide a graceful fallback
|
| 46 |
+
ai_response = "I'm having trouble processing your request right now. Please try again."
|
| 47 |
+
|
| 48 |
+
# Add AI response to conversation history
|
| 49 |
+
conversation_history.append({
|
| 50 |
+
"role": "assistant",
|
| 51 |
+
"content": ai_response
|
| 52 |
+
})
|
| 53 |
+
|
| 54 |
+
# Update session with new conversation history
|
| 55 |
+
session_manager.update_session(user_id, {
|
| 56 |
+
"conversation": conversation_history
|
| 57 |
+
})
|
| 58 |
+
|
| 59 |
logger.info(f"Successfully processed chat for user {user_id}")
|
| 60 |
+
return JSONResponse(
|
| 61 |
+
content={"response": ai_response},
|
| 62 |
+
status_code=200
|
| 63 |
+
)
|
| 64 |
+
|
| 65 |
except Exception as e:
|
| 66 |
+
logger.error(f"Chat processing failed for user {user_id}: {e}")
|
| 67 |
+
raise HTTPException(
|
| 68 |
+
status_code=500,
|
| 69 |
+
detail=f"Failed to process chat: {str(e)}"
|
| 70 |
+
)
|
app.py
CHANGED
|
@@ -252,7 +252,7 @@ def validate_user_input(text):
|
|
| 252 |
|
| 253 |
return True, text.strip()
|
| 254 |
|
| 255 |
-
# Chat input - FIXED VERSION
|
| 256 |
user_input = st.chat_input("Type your message here...", disabled=st.session_state.is_processing)
|
| 257 |
|
| 258 |
# Process message when received
|
|
@@ -278,8 +278,8 @@ if user_input and not st.session_state.is_processing:
|
|
| 278 |
|
| 279 |
# Process AI response
|
| 280 |
with st.chat_message("assistant"):
|
| 281 |
-
response_placeholder = st.empty()
|
| 282 |
status_placeholder = st.empty()
|
|
|
|
| 283 |
|
| 284 |
try:
|
| 285 |
# Get conversation history
|
|
@@ -460,7 +460,7 @@ if user_input and not st.session_state.is_processing:
|
|
| 460 |
finally:
|
| 461 |
st.session_state.is_processing = False
|
| 462 |
# Force UI update
|
| 463 |
-
st.experimental_rerun()
|
| 464 |
|
| 465 |
# Add evaluation dashboard tab (separate from chat interface) - ONLY ABOUT TAB NOW
|
| 466 |
st.divider()
|
|
@@ -506,4 +506,4 @@ if user_input and user_input.lower().strip() in ["tell me a story", "tell me a c
|
|
| 506 |
"timestamp": datetime.now().strftime("%H:%M:%S")
|
| 507 |
})
|
| 508 |
st.session_state.is_processing = False
|
| 509 |
-
st.
|
|
|
|
| 252 |
|
| 253 |
return True, text.strip()
|
| 254 |
|
| 255 |
+
# Chat input - FIXED VERSION
|
| 256 |
user_input = st.chat_input("Type your message here...", disabled=st.session_state.is_processing)
|
| 257 |
|
| 258 |
# Process message when received
|
|
|
|
| 278 |
|
| 279 |
# Process AI response
|
| 280 |
with st.chat_message("assistant"):
|
|
|
|
| 281 |
status_placeholder = st.empty()
|
| 282 |
+
response_placeholder = st.empty()
|
| 283 |
|
| 284 |
try:
|
| 285 |
# Get conversation history
|
|
|
|
| 460 |
finally:
|
| 461 |
st.session_state.is_processing = False
|
| 462 |
# Force UI update
|
| 463 |
+
st.rerun() # Changed from experimental_rerun() to rerun()
|
| 464 |
|
| 465 |
# Add evaluation dashboard tab (separate from chat interface) - ONLY ABOUT TAB NOW
|
| 466 |
st.divider()
|
|
|
|
| 506 |
"timestamp": datetime.now().strftime("%H:%M:%S")
|
| 507 |
})
|
| 508 |
st.session_state.is_processing = False
|
| 509 |
+
st.rerun()
|
core/llm.py
CHANGED
|
@@ -5,47 +5,32 @@ from core.llm_factory import llm_factory, ProviderNotAvailableError
|
|
| 5 |
logger = logging.getLogger(__name__)
|
| 6 |
|
| 7 |
class LLMClient:
|
| 8 |
-
"""High-level LLM client that uses the factory pattern"""
|
| 9 |
-
|
| 10 |
-
def __init__(self
|
| 11 |
-
self.provider_name = provider
|
| 12 |
try:
|
| 13 |
-
self.provider = llm_factory.get_provider(
|
| 14 |
except ProviderNotAvailableError:
|
| 15 |
self.provider = None
|
| 16 |
logger.error("No LLM providers available")
|
| 17 |
-
|
| 18 |
-
def generate(self, prompt: str, conversation_history: List[Dict], stream: bool = False):
|
| 19 |
-
"""
|
|
|
|
|
|
|
| 20 |
if not self.provider:
|
| 21 |
raise ProviderNotAvailableError("No LLM provider available")
|
| 22 |
-
|
| 23 |
try:
|
| 24 |
if stream:
|
| 25 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
| 26 |
else:
|
| 27 |
return self.provider.generate(prompt, conversation_history)
|
|
|
|
| 28 |
except Exception as e:
|
| 29 |
logger.error(f"LLM generation failed: {e}")
|
| 30 |
-
raise
|
| 31 |
-
|
| 32 |
-
def send_to_ollama(prompt: str, conversation_history: List[Dict], ollama_url: str, model: str) -> Optional[str]:
|
| 33 |
-
"""Legacy function for backward compatibility"""
|
| 34 |
-
try:
|
| 35 |
-
from core.providers.ollama import OllamaProvider
|
| 36 |
-
provider = OllamaProvider(model)
|
| 37 |
-
return provider.generate(prompt, conversation_history)
|
| 38 |
-
except Exception as e:
|
| 39 |
-
logger.error(f"Ollama call failed: {e}")
|
| 40 |
-
return None
|
| 41 |
-
|
| 42 |
-
def send_to_hf(prompt: str, conversation_history: List[Dict]) -> Optional[str]:
|
| 43 |
-
"""Legacy function for backward compatibility"""
|
| 44 |
-
try:
|
| 45 |
-
from utils.config import config
|
| 46 |
-
from core.providers.huggingface import HuggingFaceProvider
|
| 47 |
-
provider = HuggingFaceProvider("meta-llama/Llama-2-7b-chat-hf")
|
| 48 |
-
return provider.generate(prompt, conversation_history)
|
| 49 |
-
except Exception as e:
|
| 50 |
-
logger.error(f"Hugging Face call failed: {e}")
|
| 51 |
-
return None
|
|
|
|
| 5 |
logger = logging.getLogger(__name__)
|
| 6 |
|
| 7 |
class LLMClient:
|
| 8 |
+
"""High-level LLM client that uses the factory pattern with improved error handling"""
|
| 9 |
+
|
| 10 |
+
def __init__(self):
|
|
|
|
| 11 |
try:
|
| 12 |
+
self.provider = llm_factory.get_provider()
|
| 13 |
except ProviderNotAvailableError:
|
| 14 |
self.provider = None
|
| 15 |
logger.error("No LLM providers available")
|
| 16 |
+
|
| 17 |
+
def generate(self, prompt: str, conversation_history: List[Dict], stream: bool = False) -> Optional[str]:
|
| 18 |
+
"""
|
| 19 |
+
Generate a response with robust error handling.
|
| 20 |
+
"""
|
| 21 |
if not self.provider:
|
| 22 |
raise ProviderNotAvailableError("No LLM provider available")
|
| 23 |
+
|
| 24 |
try:
|
| 25 |
if stream:
|
| 26 |
+
result = self.provider.stream_generate(prompt, conversation_history)
|
| 27 |
+
# For streaming, combine chunks into single response
|
| 28 |
+
if isinstance(result, list):
|
| 29 |
+
return "".join(result)
|
| 30 |
+
return result
|
| 31 |
else:
|
| 32 |
return self.provider.generate(prompt, conversation_history)
|
| 33 |
+
|
| 34 |
except Exception as e:
|
| 35 |
logger.error(f"LLM generation failed: {e}")
|
| 36 |
+
raise # Re-raise to let caller handle appropriately
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|