rdune71 commited on
Commit
a3e0ade
Β·
1 Parent(s): 084503a

Implement enhanced UI with proper response display and feedback

Browse files
Files changed (2) hide show
  1. app.py +55 -84
  2. src/ui/chat_handler.py +133 -0
app.py CHANGED
@@ -7,12 +7,13 @@ from datetime import datetime
7
  from pathlib import Path
8
  sys.path.append(str(Path(__file__).parent))
9
 
 
 
10
  from utils.config import config
11
  from core.session import session_manager
12
  from core.memory import check_redis_health
13
  from core.errors import translate_error
14
  from core.personality import personality
15
- from core.providers.ollama import OllamaProvider
16
  import logging
17
 
18
  # Set up logging
@@ -41,7 +42,7 @@ with st.sidebar:
41
  # Model selection
42
  model_options = {
43
  "Mistral 7B (Local)": "mistral:latest",
44
- "Llama 2 7B (Local)": "llama2:latest",
45
  "OpenChat 3.5 (Local)": "openchat:latest"
46
  }
47
  selected_model_name = st.selectbox(
@@ -70,6 +71,7 @@ with st.sidebar:
70
 
71
  if st.button("πŸ“‘ Test Connection"):
72
  try:
 
73
  ollama_provider = OllamaProvider(st.session_state.selected_model)
74
  is_valid = ollama_provider.validate_model()
75
  if is_valid:
@@ -81,12 +83,14 @@ with st.sidebar:
81
 
82
  if st.button("πŸ—‘οΈ Clear History"):
83
  st.session_state.messages = []
 
 
84
  st.success("History cleared!")
85
 
86
  st.divider()
87
 
88
- # System Status
89
- with st.expander("πŸ” System Status", expanded=False):
90
  st.subheader("πŸ“Š Status")
91
 
92
  # Ollama Status
@@ -100,11 +104,45 @@ with st.sidebar:
100
  except:
101
  st.info("πŸ¦™ Ollama: Unknown")
102
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
103
  # Redis Status
104
- if check_redis_health():
105
- st.success("πŸ’Ύ Redis: Connected")
106
- else:
107
- st.error("πŸ’Ύ Redis: Disconnected")
 
 
 
108
 
109
  st.divider()
110
 
@@ -124,88 +162,19 @@ if st.session_state.show_welcome:
124
  st.markdown(greeting)
125
  st.session_state.show_welcome = False
126
 
127
- # Display messages
128
  for message in st.session_state.messages:
129
  with st.chat_message(message["role"]):
130
  st.markdown(message["content"])
131
  if "timestamp" in message:
132
- st.caption(f"πŸ•’ {message['timestamp']}")
 
133
 
134
- # Chat input
135
- user_input = st.chat_input("Type your message here...", disabled=st.session_state.is_processing)
136
 
137
- # Process message
138
- if user_input and not st.session_state.is_processing:
139
- st.session_state.is_processing = True
140
-
141
- # Display user message
142
- with st.chat_message("user"):
143
- st.markdown(user_input)
144
-
145
- # Add to history
146
- timestamp = datetime.now().strftime("%H:%M:%S")
147
- st.session_state.messages.append({
148
- "role": "user",
149
- "content": user_input,
150
- "timestamp": timestamp
151
- })
152
-
153
- # Process response
154
- try:
155
- # Get conversation history
156
- user_session = session_manager.get_session("default_user")
157
- conversation_history = user_session.get("conversation", []).copy()
158
- conversation_history.append({"role": "user", "content": user_input})
159
-
160
- # Generate response
161
- try:
162
- ollama_provider = OllamaProvider(st.session_state.selected_model)
163
- ai_response = ollama_provider.generate(user_input, conversation_history)
164
-
165
- if ai_response and ai_response.strip():
166
- with st.chat_message("assistant"):
167
- st.markdown(ai_response)
168
- status = "βœ… Response received!"
169
- else:
170
- with st.chat_message("assistant"):
171
- st.warning("⚠️ Received empty response")
172
- ai_response = "I received your message but couldn't generate a proper response."
173
-
174
- except Exception as e:
175
- error_message = str(e)
176
- with st.chat_message("assistant"):
177
- st.error(f"❌ Error: {error_message[:100]}...")
178
- ai_response = f"Error: {error_message[:100]}..."
179
-
180
- # Save to session
181
- if ai_response:
182
- try:
183
- conversation = user_session.get("conversation", []).copy()
184
- conversation.append({"role": "user", "content": user_input})
185
- conversation.append({"role": "assistant", "content": str(ai_response)})
186
- session_manager.update_session("default_user", {"conversation": conversation})
187
-
188
- st.session_state.messages.append({
189
- "role": "assistant",
190
- "content": str(ai_response),
191
- "timestamp": timestamp
192
- })
193
- except Exception as session_error:
194
- logger.error(f"Session update error: {session_error}")
195
-
196
- except Exception as e:
197
- error_msg = f"System error: {str(e)}"
198
- logger.error(f"Processing error: {error_msg}")
199
- with st.chat_message("assistant"):
200
- st.error(error_msg)
201
- st.session_state.messages.append({
202
- "role": "assistant",
203
- "content": error_msg,
204
- "timestamp": timestamp
205
- })
206
- finally:
207
- st.session_state.is_processing = False
208
- st.experimental_rerun()
209
 
210
  # About tab
211
  st.divider()
@@ -220,11 +189,13 @@ with tab1:
220
  - **Local AI processing** with Ollama models
221
  - **Persistent memory** using Redis
222
  - **Space-themed personality** for fun interactions
 
223
 
224
  ### πŸš€ Cosmic Mode
225
  When enabled, the AI responds with space-themed language and metaphors.
226
 
227
  ### πŸ› οΈ Technical Architecture
228
  - **Primary model**: Ollama (local processing)
 
229
  - **Memory system**: Redis-based session management
230
  """)
 
7
  from pathlib import Path
8
  sys.path.append(str(Path(__file__).parent))
9
 
10
+ # Import our new handler
11
+ from src.ui.chat_handler import chat_handler
12
  from utils.config import config
13
  from core.session import session_manager
14
  from core.memory import check_redis_health
15
  from core.errors import translate_error
16
  from core.personality import personality
 
17
  import logging
18
 
19
  # Set up logging
 
42
  # Model selection
43
  model_options = {
44
  "Mistral 7B (Local)": "mistral:latest",
45
+ "Llama 2 7B (Local)": "llama2:latest",
46
  "OpenChat 3.5 (Local)": "openchat:latest"
47
  }
48
  selected_model_name = st.selectbox(
 
71
 
72
  if st.button("πŸ“‘ Test Connection"):
73
  try:
74
+ from core.providers.ollama import OllamaProvider
75
  ollama_provider = OllamaProvider(st.session_state.selected_model)
76
  is_valid = ollama_provider.validate_model()
77
  if is_valid:
 
83
 
84
  if st.button("πŸ—‘οΈ Clear History"):
85
  st.session_state.messages = []
86
+ # Also clear backend session
87
+ session_manager.clear_session("default_user")
88
  st.success("History cleared!")
89
 
90
  st.divider()
91
 
92
+ # System Status with enhanced HF monitoring
93
+ with st.expander("πŸ” System Status", expanded=True):
94
  st.subheader("πŸ“Š Status")
95
 
96
  # Ollama Status
 
104
  except:
105
  st.info("πŸ¦™ Ollama: Unknown")
106
 
107
+ # HF Endpoint Status (Enhanced)
108
+ try:
109
+ from src.services.hf_monitor import hf_monitor
110
+ status_message = hf_monitor.get_human_readable_status()
111
+
112
+ # Display appropriate status icon
113
+ if "🟒" in status_message:
114
+ st.success(status_message)
115
+ elif "🟑" in status_message:
116
+ st.warning(status_message)
117
+ elif "πŸ”΄" in status_message or "❌" in status_message:
118
+ st.error(status_message)
119
+ elif "⏳" in status_message:
120
+ st.info(status_message)
121
+ else:
122
+ st.info(status_message)
123
+
124
+ # Add wake-up button if scaled to zero
125
+ if "scaled to zero" in status_message.lower():
126
+ if st.button("⚑ Wake Up HF Endpoint", key="wake_up_hf"):
127
+ with st.spinner("Waking up HF endpoint... This may take 2-4 minutes..."):
128
+ if hf_monitor.attempt_wake_up():
129
+ st.success("βœ… HF endpoint is waking up! Try your request again in a moment.")
130
+ time.sleep(2)
131
+ st.experimental_rerun()
132
+ else:
133
+ st.error("❌ Failed to wake up HF endpoint. Please try again.")
134
+
135
+ except Exception as e:
136
+ st.info(f"πŸ€— HF Endpoint: Error checking status - {str(e)}")
137
+
138
  # Redis Status
139
+ try:
140
+ if check_redis_health():
141
+ st.success("πŸ’Ύ Redis: Connected")
142
+ else:
143
+ st.error("πŸ’Ύ Redis: Disconnected")
144
+ except:
145
+ st.info("πŸ’Ύ Redis: Unknown")
146
 
147
  st.divider()
148
 
 
162
  st.markdown(greeting)
163
  st.session_state.show_welcome = False
164
 
165
+ # Display conversation history
166
  for message in st.session_state.messages:
167
  with st.chat_message(message["role"]):
168
  st.markdown(message["content"])
169
  if "timestamp" in message:
170
+ provider_info = f" (via {message.get('provider', 'unknown')})" if message["role"] == "assistant" else ""
171
+ st.caption(f"πŸ•’ {message['timestamp']}{provider_info}")
172
 
173
+ # Chat input with enhanced processing
174
+ user_input = st.chat_input("Type your message here...", key="chat_input")
175
 
176
+ if user_input:
177
+ chat_handler.process_user_message(user_input, selected_model_name)
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
178
 
179
  # About tab
180
  st.divider()
 
189
  - **Local AI processing** with Ollama models
190
  - **Persistent memory** using Redis
191
  - **Space-themed personality** for fun interactions
192
+ - **HF Endpoint integration** for advanced capabilities
193
 
194
  ### πŸš€ Cosmic Mode
195
  When enabled, the AI responds with space-themed language and metaphors.
196
 
197
  ### πŸ› οΈ Technical Architecture
198
  - **Primary model**: Ollama (local processing)
199
+ - **Secondary model**: HF Endpoint (advanced processing)
200
  - **Memory system**: Redis-based session management
201
  """)
src/ui/chat_handler.py ADDED
@@ -0,0 +1,133 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import streamlit as st
2
+ import time
3
+ import logging
4
+ from typing import Optional
5
+ from src.llm.factory import llm_factory, ProviderNotAvailableError
6
+ from src.services.hf_monitor import hf_monitor
7
+ from core.session import session_manager
8
+
9
+ logger = logging.getLogger(__name__)
10
+
11
+ class ChatHandler:
12
+ """Handles chat interactions with better UI feedback"""
13
+
14
+ def __init__(self):
15
+ self.is_processing = False
16
+
17
+ def process_user_message(self, user_input: str, selected_model: str):
18
+ """Process user message with enhanced UI feedback"""
19
+ if not user_input or not user_input.strip():
20
+ st.warning("Please enter a message")
21
+ return
22
+
23
+ if self.is_processing:
24
+ st.warning("Still processing previous request...")
25
+ return
26
+
27
+ self.is_processing = True
28
+
29
+ try:
30
+ # Show user message immediately
31
+ timestamp = time.strftime("%H:%M:%S")
32
+ with st.chat_message("user"):
33
+ st.markdown(user_input)
34
+ st.caption(f"πŸ•’ {timestamp}")
35
+
36
+ # Add to session history
37
+ st.session_state.messages.append({
38
+ "role": "user",
39
+ "content": user_input,
40
+ "timestamp": timestamp
41
+ })
42
+
43
+ # Show processing status
44
+ with st.chat_message("assistant"):
45
+ status_placeholder = st.empty()
46
+ response_placeholder = st.empty()
47
+
48
+ try:
49
+ # Determine provider based on model selection
50
+ provider_name = self._get_provider_for_model(selected_model)
51
+ status_placeholder.info(f"πŸš€ Contacting {self._get_provider_display_name(provider_name)}...")
52
+
53
+ # Get response
54
+ response = self._get_ai_response(user_input, provider_name)
55
+
56
+ if response:
57
+ status_placeholder.success("βœ… Response received!")
58
+ response_placeholder.markdown(response)
59
+
60
+ # Add to session history
61
+ st.session_state.messages.append({
62
+ "role": "assistant",
63
+ "content": response,
64
+ "timestamp": time.strftime("%H:%M:%S"),
65
+ "provider": provider_name
66
+ })
67
+ else:
68
+ status_placeholder.error("❌ Empty response received")
69
+ response_placeholder.markdown("I received your message but couldn't generate a proper response.")
70
+
71
+ except ProviderNotAvailableError as e:
72
+ status_placeholder.error("❌ No AI providers available")
73
+ response_placeholder.markdown("No AI providers are configured. Please check your settings.")
74
+ logger.error(f"Provider not available: {e}")
75
+
76
+ except Exception as e:
77
+ status_placeholder.error(f"❌ Error: {str(e)[:100]}...")
78
+ response_placeholder.markdown(f"Sorry, I encountered an error: {str(e)[:100]}...")
79
+ logger.error(f"Chat processing error: {e}")
80
+
81
+ finally:
82
+ self.is_processing = False
83
+ time.sleep(0.1) # Small delay to ensure UI updates
84
+ # st.experimental_rerun() # Removed to prevent automatic rerun
85
+
86
+ def _get_provider_for_model(self, selected_model: str) -> str:
87
+ """Determine which provider to use based on model selection"""
88
+ model_map = {
89
+ "Mistral 7B (Local)": "ollama",
90
+ "Llama 2 7B (Local)": "ollama",
91
+ "OpenChat 3.5 (Local)": "ollama"
92
+ }
93
+ return model_map.get(selected_model, "ollama")
94
+
95
+ def _get_provider_display_name(self, provider_name: str) -> str:
96
+ """Get display name for provider"""
97
+ display_names = {
98
+ "ollama": "πŸ¦™ Ollama",
99
+ "huggingface": "πŸ€— HF Endpoint"
100
+ }
101
+ return display_names.get(provider_name, provider_name)
102
+
103
+ def _get_ai_response(self, user_input: str, provider_name: str) -> Optional[str]:
104
+ """Get AI response from specified provider"""
105
+ try:
106
+ # Get session and conversation history
107
+ user_session = session_manager.get_session("default_user")
108
+ conversation_history = user_session.get("conversation", []).copy()
109
+
110
+ # Add current user message
111
+ conversation_history.append({"role": "user", "content": user_input})
112
+
113
+ # Get provider
114
+ provider = llm_factory.get_provider(provider_name)
115
+
116
+ # Generate response
117
+ response = provider.generate(user_input, conversation_history)
118
+
119
+ # Update session with conversation
120
+ if response:
121
+ conversation = user_session.get("conversation", []).copy()
122
+ conversation.append({"role": "user", "content": user_input})
123
+ conversation.append({"role": "assistant", "content": response})
124
+ session_manager.update_session("default_user", {"conversation": conversation})
125
+
126
+ return response
127
+
128
+ except Exception as e:
129
+ logger.error(f"AI response generation failed: {e}")
130
+ raise
131
+
132
+ # Global instance
133
+ chat_handler = ChatHandler()