rdune71 commited on
Commit
fde6c6f
Β·
1 Parent(s): 2773c7a

Fix UI issues, restore advanced debug panel, and improve Ollama connection handling

Browse files
app.py CHANGED
@@ -10,7 +10,6 @@ from utils.config import config
10
  from core.llm import send_to_ollama, send_to_hf
11
  from core.session import session_manager
12
  from core.memory import check_redis_health
13
- from core.coordinator import coordinator
14
  import logging
15
 
16
  # Set up logging
@@ -26,10 +25,10 @@ if "last_error" not in st.session_state:
26
  st.session_state.last_error = ""
27
  if "is_sending" not in st.session_state:
28
  st.session_state.is_sending = False
29
- if "current_coordination" not in st.session_state:
30
- st.session_state.current_coordination = None
31
 
32
- # Enhanced Sidebar
33
  with st.sidebar:
34
  st.title("AI Life Coach 🧠")
35
  st.markdown("Your personal AI-powered life development assistant")
@@ -47,16 +46,44 @@ with st.sidebar:
47
  )
48
  st.session_state.selected_model = model_options[selected_model_name]
49
 
50
- # Ollama URL input
51
- st.session_state.ngrok_url = st.text_input(
 
52
  "Ollama Server URL",
53
- value=st.session_state.get("ngrok_url", "http://localhost:11434"),
54
- help="Enter the URL to your Ollama server"
 
55
  )
56
 
57
- # Enhanced Conversation History
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
58
  st.subheader("Conversation History")
59
- if st.button("Clear History πŸ—‘οΈ"):
60
  st.session_state.messages = []
61
  st.success("History cleared!")
62
 
@@ -66,64 +93,87 @@ with st.sidebar:
66
  ai_msgs = len([m for m in st.session_state.messages if m["role"] == "assistant"])
67
  st.caption(f"πŸ’¬ {user_msgs} user messages, {ai_msgs} AI responses")
68
 
69
- # Enhanced Debug Panel
70
- with st.expander("πŸ” Advanced System Monitor", expanded=True):
71
  st.subheader("πŸŽ›οΈ System Controls")
72
 
73
- # Real-time coordination status
74
- if st.session_state.current_coordination:
75
- coord = st.session_state.current_coordination
76
- st.info(f"πŸ”„ Coordination in progress...")
77
- st.caption(f"Phase: {coord.get('phase', 'Unknown')}")
78
- st.caption(f"Status: {coord.get('status', 'Unknown')}")
 
 
 
 
 
 
 
79
 
80
- # HF Endpoint Status with detailed monitoring
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
81
  try:
82
  from services.hf_endpoint_monitor import hf_monitor
83
  hf_status = hf_monitor.check_endpoint_status()
84
-
85
  if hf_status['available']:
86
  if hf_status.get('initialized'):
87
  st.success("πŸ€— HF Endpoint: Available & Initialized")
88
  else:
89
  st.warning("πŸ€— HF Endpoint: Available (Initializing)")
90
- if st.button("⚑ Wake Up HF Endpoint"):
91
- with st.spinner("Waking up HF endpoint... (2-4 minutes)"):
92
- success = hf_monitor.handle_scale_to_zero()
93
- if success:
94
- st.success("βœ… HF endpoint activated!")
95
- time.sleep(1)
96
- st.experimental_rerun()
97
  else:
98
  st.error("πŸ€— HF Endpoint: Scaled to Zero")
99
- st.caption(f"Status Code: {hf_status.get('status_code', 'N/A')}")
100
-
101
  except Exception as e:
102
  st.warning("πŸ€— HF Endpoint: Monitor unavailable")
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
103
 
104
- # Enhanced Main Interface
105
  st.title("🧠 AI Life Coach")
106
  st.markdown("Ask me anything about personal development, goal setting, or life advice!")
107
 
108
- # Display chat messages with enhanced formatting
109
- for i, message in enumerate(st.session_state.messages):
110
  with st.chat_message(message["role"]):
111
- # Add message metadata
112
- if message["role"] == "assistant":
113
- # Show which model responded
114
- if "Note: A more comprehensive analysis" in message["content"]:
115
- st.caption("πŸ¦™ Ollama (initial response)")
116
- elif "🎯 HF analysis complete" in str(message.get("metadata", "")):
117
- st.caption("πŸ€— HF Endpoint (deep analysis)")
118
-
119
  st.markdown(message["content"])
120
-
121
- # Show message timestamp
122
  if "timestamp" in message:
123
  st.caption(f"πŸ•’ {message['timestamp']}")
124
 
125
- # Enhanced chat input with better feedback
126
- col1, col2, col3 = st.columns([3, 1, 1])
127
  with col1:
128
  user_input = st.text_input(
129
  "Your message...",
@@ -134,21 +184,17 @@ with col1:
134
  )
135
  with col2:
136
  send_button = st.button(
137
- "Send πŸš€" if not st.session_state.is_sending else "Sending...",
138
  key="send_message_button",
139
  use_container_width=True,
140
  disabled=st.session_state.is_sending or not user_input.strip()
141
  )
142
- with col3:
143
- # Add a "thinking" indicator
144
- if st.session_state.is_sending:
145
- st.info("🧠 Thinking...")
146
 
147
- # Enhanced message sending with coordination feedback
148
  if send_button and user_input.strip() and not st.session_state.is_sending:
149
  st.session_state.is_sending = True
150
 
151
- # Display user message immediately
152
  with st.chat_message("user"):
153
  st.markdown(user_input)
154
 
@@ -162,97 +208,72 @@ if send_button and user_input.strip() and not st.session_state.is_sending:
162
  # Reset error state
163
  st.session_state.last_error = ""
164
 
165
- # Enhanced coordination processing
166
  with st.chat_message("assistant"):
167
- # Create containers for different response components
168
- ollama_container = st.empty()
169
- coordination_status = st.empty()
170
- hf_thinking_container = st.empty()
171
- final_response_container = st.empty()
172
-
173
- try:
174
- # Use enhanced coordinator with real-time feedback
175
- import asyncio
176
 
177
- async def process_with_feedback():
178
- user_id = "default_user"
179
- full_response = ""
180
- ollama_response = ""
181
- hf_response = ""
182
-
183
- # Track coordination phases
184
- st.session_state.current_coordination = {
185
- "phase": "starting",
186
- "status": "Initializing coordination..."
187
- }
188
 
189
- async for response_chunk in coordinator.coordinate_hierarchical_conversation(user_id, user_input):
190
- st.session_state.current_coordination = {
191
- "phase": response_chunk['type'],
192
- "status": response_chunk['content'][:100]
193
- }
 
 
 
 
 
 
 
 
 
 
194
 
195
- if response_chunk['type'] == 'initial_response':
196
- ollama_response = response_chunk['content']
197
- ollama_container.markdown(f"**πŸ¦™ Ollama (Fast Response):**\n\n{ollama_response}")
198
- full_response = ollama_response
199
-
200
- elif response_chunk['type'] == 'coordination_status':
201
- coordination_status.info(f"πŸ€– {response_chunk['content']}")
 
 
 
 
 
 
202
 
203
- elif response_chunk['type'] == 'hf_thinking':
204
- hf_response += response_chunk['content']
205
- with hf_thinking_container.container():
206
- st.markdown(f"**πŸ€— HF Endpoint (Deep Analysis):**")
207
- st.info(hf_response)
208
- full_response = hf_response
209
 
210
- elif response_chunk['type'] == 'final_response':
211
- hf_response = response_chunk['content']
212
- final_response_container.markdown(f"**🎯 Final Response:**\n\n{hf_response}")
213
- full_response = hf_response
214
- coordination_status.success("βœ… Coordination complete!")
215
-
216
- return full_response
217
-
218
- # Run the enhanced processing
219
- full_response = asyncio.run(process_with_feedback())
220
-
221
- # Update session with complete conversation
222
- user_session = session_manager.get_session("default_user")
223
- conversation = user_session.get("conversation", [])
224
- conversation.append({"role": "user", "content": user_input})
225
- conversation.append({"role": "assistant", "content": full_response})
226
- user_session["conversation"] = conversation
227
- session_manager.update_session("default_user", user_session)
228
 
229
- # Add to message history
230
- st.session_state.messages.append({
231
- "role": "assistant",
232
- "content": full_response,
233
- "timestamp": datetime.now().strftime("%H:%M:%S"),
234
- "metadata": {"source": "coordinated_response"}
235
- })
236
-
237
- except Exception as e:
238
- st.error(f"❌ Error: {str(e)}")
239
- st.session_state.last_error = str(e)
240
- finally:
241
- st.session_state.is_sending = False
242
- st.session_state.current_coordination = None
243
-
244
- # Force rerun to update UI
245
- st.experimental_rerun()
246
 
247
- # Add conversation export feature
248
- if st.session_state.messages and st.sidebar.button("πŸ“€ Export Conversation"):
249
- conversation_text = ""
250
- for msg in st.session_state.messages:
251
- conversation_text += f"{msg['role'].upper()}: {msg['content']}\n\n"
252
-
253
- st.sidebar.download_button(
254
- label="πŸ’Ύ Download Conversation",
255
- data=conversation_text,
256
- file_name=f"ai_life_coach_conversation_{datetime.now().strftime('%Y%m%d_%H%M%S')}.txt",
257
- mime="text/plain"
258
- )
 
10
  from core.llm import send_to_ollama, send_to_hf
11
  from core.session import session_manager
12
  from core.memory import check_redis_health
 
13
  import logging
14
 
15
  # Set up logging
 
25
  st.session_state.last_error = ""
26
  if "is_sending" not in st.session_state:
27
  st.session_state.is_sending = False
28
+ if "ngrok_url_temp" not in st.session_state:
29
+ st.session_state.ngrok_url_temp = st.session_state.get("ngrok_url", "https://7bcc180dffd1.ngrok-free.app")
30
 
31
+ # Sidebar with restored advanced debug panel
32
  with st.sidebar:
33
  st.title("AI Life Coach 🧠")
34
  st.markdown("Your personal AI-powered life development assistant")
 
46
  )
47
  st.session_state.selected_model = model_options[selected_model_name]
48
 
49
+ # Ollama URL input with better feedback
50
+ st.subheader("Ollama Configuration")
51
+ ngrok_url_input = st.text_input(
52
  "Ollama Server URL",
53
+ value=st.session_state.ngrok_url_temp,
54
+ help="Enter your ngrok URL (e.g., https://abcd1234.ngrok-free.app)",
55
+ key="ngrok_url_input"
56
  )
57
 
58
+ # Update URL with feedback
59
+ if ngrok_url_input != st.session_state.ngrok_url_temp:
60
+ st.session_state.ngrok_url_temp = ngrok_url_input
61
+ st.success("βœ… URL updated! Click 'Test Connection' below.")
62
+
63
+ # Test connection button
64
+ if st.button("πŸ“‘ Test Ollama Connection"):
65
+ try:
66
+ import requests
67
+ headers = {
68
+ "ngrok-skip-browser-warning": "true",
69
+ "User-Agent": "AI-Life-Coach-Test"
70
+ }
71
+ response = requests.get(
72
+ f"{ngrok_url_input}/api/tags",
73
+ headers=headers,
74
+ timeout=10
75
+ )
76
+ if response.status_code == 200:
77
+ st.success("βœ… Ollama connection successful!")
78
+ st.session_state.ngrok_url = ngrok_url_input
79
+ else:
80
+ st.error(f"❌ Connection failed: {response.status_code}")
81
+ except Exception as e:
82
+ st.error(f"❌ Connection error: {str(e)}")
83
+
84
+ # Conversation history
85
  st.subheader("Conversation History")
86
+ if st.button("πŸ—‘οΈ Clear History"):
87
  st.session_state.messages = []
88
  st.success("History cleared!")
89
 
 
93
  ai_msgs = len([m for m in st.session_state.messages if m["role"] == "assistant"])
94
  st.caption(f"πŸ’¬ {user_msgs} user messages, {ai_msgs} AI responses")
95
 
96
+ # Restored Advanced Debug Panel
97
+ with st.expander("πŸ” Advanced System Monitor", expanded=False):
98
  st.subheader("πŸŽ›οΈ System Controls")
99
 
100
+ # Fallback Mode Toggle
101
+ fallback_mode = st.checkbox(
102
+ "Enable Provider Fallback",
103
+ value=config.use_fallback,
104
+ help="Enable automatic fallback between AI providers"
105
+ )
106
+
107
+ # HF Deep Analysis Toggle
108
+ hf_analysis = st.checkbox(
109
+ "Enable HF Deep Analysis",
110
+ value=bool(config.hf_token),
111
+ help="Enable Hugging Face endpoint for deep analysis"
112
+ )
113
 
114
+ st.divider()
115
+
116
+ st.subheader("πŸ“Š Provider Status")
117
+
118
+ # Ollama Status
119
+ try:
120
+ from services.ollama_monitor import check_ollama_status
121
+ ollama_status = check_ollama_status()
122
+ if ollama_status.get("running"):
123
+ st.success(f"πŸ¦™ Ollama: Running")
124
+ if ollama_status.get("model_loaded"):
125
+ st.caption(f"Model: {ollama_status['model_loaded']}")
126
+ else:
127
+ st.error("πŸ¦™ Ollama: Unavailable")
128
+ except Exception as e:
129
+ st.warning("πŸ¦™ Ollama: Status check failed")
130
+
131
+ # HF Endpoint Status
132
  try:
133
  from services.hf_endpoint_monitor import hf_monitor
134
  hf_status = hf_monitor.check_endpoint_status()
 
135
  if hf_status['available']:
136
  if hf_status.get('initialized'):
137
  st.success("πŸ€— HF Endpoint: Available & Initialized")
138
  else:
139
  st.warning("πŸ€— HF Endpoint: Available (Initializing)")
 
 
 
 
 
 
 
140
  else:
141
  st.error("πŸ€— HF Endpoint: Scaled to Zero")
 
 
142
  except Exception as e:
143
  st.warning("πŸ€— HF Endpoint: Monitor unavailable")
144
+
145
+ # Redis Status
146
+ redis_healthy = check_redis_health()
147
+ if redis_healthy:
148
+ st.success("πŸ’Ύ Redis: Connected")
149
+ else:
150
+ st.error("πŸ’Ύ Redis: Disconnected")
151
+
152
+ st.divider()
153
+
154
+ st.subheader("πŸ“ˆ Session Statistics")
155
+
156
+ # Session Stats
157
+ try:
158
+ user_session = session_manager.get_session("default_user")
159
+ conversation = user_session.get("conversation", [])
160
+ st.caption(f"πŸ’¬ Messages: {len(conversation)}")
161
+ except Exception as e:
162
+ st.caption("πŸ’¬ Session: Not initialized")
163
 
164
+ # Main chat interface
165
  st.title("🧠 AI Life Coach")
166
  st.markdown("Ask me anything about personal development, goal setting, or life advice!")
167
 
168
+ # Display chat messages
169
+ for message in st.session_state.messages:
170
  with st.chat_message(message["role"]):
 
 
 
 
 
 
 
 
171
  st.markdown(message["content"])
 
 
172
  if "timestamp" in message:
173
  st.caption(f"πŸ•’ {message['timestamp']}")
174
 
175
+ # Enhanced chat input with proper feedback
176
+ col1, col2 = st.columns([4, 1])
177
  with col1:
178
  user_input = st.text_input(
179
  "Your message...",
 
184
  )
185
  with col2:
186
  send_button = st.button(
187
+ "Send" if not st.session_state.is_sending else "⏳ Sending...",
188
  key="send_message_button",
189
  use_container_width=True,
190
  disabled=st.session_state.is_sending or not user_input.strip()
191
  )
 
 
 
 
192
 
193
+ # Improved message sending
194
  if send_button and user_input.strip() and not st.session_state.is_sending:
195
  st.session_state.is_sending = True
196
 
197
+ # Display user message immediately and clear input
198
  with st.chat_message("user"):
199
  st.markdown(user_input)
200
 
 
208
  # Reset error state
209
  st.session_state.last_error = ""
210
 
211
+ # Process AI response
212
  with st.chat_message("assistant"):
213
+ with st.spinner("🧠 AI Coach is thinking..."):
214
+ ai_response = None
215
+ error_msg = ""
 
 
 
 
 
 
216
 
217
+ try:
218
+ # Use session manager for conversation history
219
+ user_session = session_manager.get_session("default_user")
220
+ conversation = user_session.get("conversation", [])
221
+ conversation_history = conversation[-5:] # Last 5 messages
222
+ conversation_history.append({"role": "user", "content": user_input})
 
 
 
 
 
223
 
224
+ # Try Ollama first with improved timeout handling
225
+ try:
226
+ ai_response = send_to_ollama(
227
+ user_input,
228
+ conversation_history,
229
+ st.session_state.ngrok_url_temp,
230
+ st.session_state.selected_model
231
+ )
232
+ if ai_response:
233
+ st.success("βœ… Response received!")
234
+ else:
235
+ st.warning("⚠️ Empty response from Ollama")
236
+ except Exception as e:
237
+ error_msg = f"Ollama error: {str(e)}"
238
+ st.error(f"❌ Ollama failed: {str(e)[:100]}...")
239
 
240
+ # Fallback to Hugging Face if configured
241
+ if config.hf_token:
242
+ try:
243
+ st.info("πŸ”„ Falling back to Hugging Face...")
244
+ ai_response = send_to_hf(user_input, conversation_history)
245
+ if ai_response:
246
+ st.success("βœ… HF Response received!")
247
+ except Exception as hf_e:
248
+ error_msg += f" | HF error: {str(hf_e)}"
249
+ st.error(f"❌ HF also failed: {str(hf_e)[:100]}...")
250
+
251
+ if ai_response:
252
+ st.markdown(ai_response)
253
 
254
+ # Update conversation history
255
+ conversation.append({"role": "user", "content": user_input})
256
+ conversation.append({"role": "assistant", "content": ai_response})
257
+ user_session["conversation"] = conversation
258
+ session_manager.update_session("default_user", user_session)
 
259
 
260
+ # Add assistant response to history
261
+ st.session_state.messages.append({
262
+ "role": "assistant",
263
+ "content": ai_response,
264
+ "timestamp": datetime.now().strftime("%H:%M:%S")
265
+ })
266
+ else:
267
+ st.error("❌ Failed to get response from any provider.")
268
+ st.session_state.last_error = error_msg or "No response from either provider"
 
 
 
 
 
 
 
 
 
269
 
270
+ except Exception as e:
271
+ st.error(f"❌ Unexpected error: {str(e)}")
272
+ st.session_state.last_error = str(e)
273
+ finally:
274
+ st.session_state.is_sending = False
 
 
 
 
 
 
 
 
 
 
 
 
275
 
276
+ # Clear input and refresh (this helps clear the text input)
277
+ if st.session_state.is_sending:
278
+ time.sleep(0.1) # Brief pause
279
+ st.experimental_rerun()
 
 
 
 
 
 
 
 
core/__pycache__/coordinator.cpython-313.pyc CHANGED
Binary files a/core/__pycache__/coordinator.cpython-313.pyc and b/core/__pycache__/coordinator.cpython-313.pyc differ
 
core/providers/ollama.py CHANGED
@@ -10,7 +10,7 @@ logger = logging.getLogger(__name__)
10
  class OllamaProvider(LLMProvider):
11
  """Ollama LLM provider implementation"""
12
 
13
- def __init__(self, model_name: str, timeout: int = 30, max_retries: int = 3):
14
  super().__init__(model_name, timeout, max_retries)
15
  self.host = self._sanitize_host(config.ollama_host or "http://localhost:11434")
16
  # Headers to skip ngrok browser warning
@@ -18,24 +18,20 @@ class OllamaProvider(LLMProvider):
18
  "ngrok-skip-browser-warning": "true",
19
  "User-Agent": "AI-Life-Coach-Ollama"
20
  }
21
-
22
  def _sanitize_host(self, host: str) -> str:
23
  """Sanitize host URL by removing whitespace and control characters"""
24
  if not host:
25
  return "http://localhost:11434"
26
-
27
  # Remove leading/trailing whitespace and control characters
28
  host = host.strip()
29
-
30
  # Remove any newlines or control characters
31
  host = re.sub(r'[\r\n\t\0]+', '', host)
32
-
33
  # Ensure URL has a scheme
34
  if not host.startswith(('http://', 'https://')):
35
  host = 'http://' + host
36
-
37
  return host
38
-
39
  def generate(self, prompt: str, conversation_history: List[Dict]) -> Optional[str]:
40
  """Generate a response synchronously"""
41
  try:
@@ -43,7 +39,7 @@ class OllamaProvider(LLMProvider):
43
  except Exception as e:
44
  logger.error(f"Ollama generation failed: {e}")
45
  return None
46
-
47
  def stream_generate(self, prompt: str, conversation_history: List[Dict]) -> Optional[Union[str, List[str]]]:
48
  """Generate a response with streaming support"""
49
  try:
@@ -51,7 +47,7 @@ class OllamaProvider(LLMProvider):
51
  except Exception as e:
52
  logger.error(f"Ollama stream generation failed: {e}")
53
  return None
54
-
55
  def validate_model(self) -> bool:
56
  """Validate if the model is available"""
57
  try:
@@ -60,7 +56,6 @@ class OllamaProvider(LLMProvider):
60
  headers=self.headers,
61
  timeout=self.timeout
62
  )
63
-
64
  if response.status_code == 200:
65
  models = response.json().get("models", [])
66
  model_names = [model.get("name") for model in models]
@@ -73,62 +68,53 @@ class OllamaProvider(LLMProvider):
73
  timeout=self.timeout
74
  )
75
  return response2.status_code == 200
76
-
77
  return False
78
  except Exception as e:
79
  logger.error(f"Model validation failed: {e}")
80
  return False
81
-
82
  def _generate_impl(self, prompt: str, conversation_history: List[Dict]) -> str:
83
  """Implementation of synchronous generation"""
84
  url = f"{self.host}/api/chat"
85
  messages = conversation_history.copy()
86
-
87
  # Add the current prompt if not already in history
88
  if not messages or messages[-1].get("content") != prompt:
89
  messages.append({"role": "user", "content": prompt})
90
-
91
  payload = {
92
  "model": self.model_name,
93
  "messages": messages,
94
  "stream": False
95
  }
96
-
97
  response = requests.post(
98
- url,
99
- json=payload,
100
  headers=self.headers,
101
  timeout=self.timeout
102
  )
103
  response.raise_for_status()
104
-
105
  result = response.json()
106
  return result["message"]["content"]
107
-
108
  def _stream_generate_impl(self, prompt: str, conversation_history: List[Dict]) -> List[str]:
109
  """Implementation of streaming generation"""
110
  url = f"{self.host}/api/chat"
111
  messages = conversation_history.copy()
112
-
113
  # Add the current prompt if not already in history
114
  if not messages or messages[-1].get("content") != prompt:
115
  messages.append({"role": "user", "content": prompt})
116
-
117
  payload = {
118
  "model": self.model_name,
119
  "messages": messages,
120
  "stream": True
121
  }
122
-
123
  response = requests.post(
124
- url,
125
- json=payload,
126
  headers=self.headers,
127
  timeout=self.timeout,
128
  stream=True
129
  )
130
  response.raise_for_status()
131
-
132
  chunks = []
133
  for line in response.iter_lines():
134
  if line:
@@ -140,5 +126,4 @@ class OllamaProvider(LLMProvider):
140
  chunks.append(content)
141
  except:
142
  continue
143
-
144
  return chunks
 
10
  class OllamaProvider(LLMProvider):
11
  """Ollama LLM provider implementation"""
12
 
13
+ def __init__(self, model_name: str, timeout: int = 60, max_retries: int = 3): # Increased timeout from 30 to 60
14
  super().__init__(model_name, timeout, max_retries)
15
  self.host = self._sanitize_host(config.ollama_host or "http://localhost:11434")
16
  # Headers to skip ngrok browser warning
 
18
  "ngrok-skip-browser-warning": "true",
19
  "User-Agent": "AI-Life-Coach-Ollama"
20
  }
21
+
22
  def _sanitize_host(self, host: str) -> str:
23
  """Sanitize host URL by removing whitespace and control characters"""
24
  if not host:
25
  return "http://localhost:11434"
 
26
  # Remove leading/trailing whitespace and control characters
27
  host = host.strip()
 
28
  # Remove any newlines or control characters
29
  host = re.sub(r'[\r\n\t\0]+', '', host)
 
30
  # Ensure URL has a scheme
31
  if not host.startswith(('http://', 'https://')):
32
  host = 'http://' + host
 
33
  return host
34
+
35
  def generate(self, prompt: str, conversation_history: List[Dict]) -> Optional[str]:
36
  """Generate a response synchronously"""
37
  try:
 
39
  except Exception as e:
40
  logger.error(f"Ollama generation failed: {e}")
41
  return None
42
+
43
  def stream_generate(self, prompt: str, conversation_history: List[Dict]) -> Optional[Union[str, List[str]]]:
44
  """Generate a response with streaming support"""
45
  try:
 
47
  except Exception as e:
48
  logger.error(f"Ollama stream generation failed: {e}")
49
  return None
50
+
51
  def validate_model(self) -> bool:
52
  """Validate if the model is available"""
53
  try:
 
56
  headers=self.headers,
57
  timeout=self.timeout
58
  )
 
59
  if response.status_code == 200:
60
  models = response.json().get("models", [])
61
  model_names = [model.get("name") for model in models]
 
68
  timeout=self.timeout
69
  )
70
  return response2.status_code == 200
 
71
  return False
72
  except Exception as e:
73
  logger.error(f"Model validation failed: {e}")
74
  return False
75
+
76
  def _generate_impl(self, prompt: str, conversation_history: List[Dict]) -> str:
77
  """Implementation of synchronous generation"""
78
  url = f"{self.host}/api/chat"
79
  messages = conversation_history.copy()
 
80
  # Add the current prompt if not already in history
81
  if not messages or messages[-1].get("content") != prompt:
82
  messages.append({"role": "user", "content": prompt})
 
83
  payload = {
84
  "model": self.model_name,
85
  "messages": messages,
86
  "stream": False
87
  }
 
88
  response = requests.post(
89
+ url,
90
+ json=payload,
91
  headers=self.headers,
92
  timeout=self.timeout
93
  )
94
  response.raise_for_status()
 
95
  result = response.json()
96
  return result["message"]["content"]
97
+
98
  def _stream_generate_impl(self, prompt: str, conversation_history: List[Dict]) -> List[str]:
99
  """Implementation of streaming generation"""
100
  url = f"{self.host}/api/chat"
101
  messages = conversation_history.copy()
 
102
  # Add the current prompt if not already in history
103
  if not messages or messages[-1].get("content") != prompt:
104
  messages.append({"role": "user", "content": prompt})
 
105
  payload = {
106
  "model": self.model_name,
107
  "messages": messages,
108
  "stream": True
109
  }
 
110
  response = requests.post(
111
+ url,
112
+ json=payload,
113
  headers=self.headers,
114
  timeout=self.timeout,
115
  stream=True
116
  )
117
  response.raise_for_status()
 
118
  chunks = []
119
  for line in response.iter_lines():
120
  if line:
 
126
  chunks.append(content)
127
  except:
128
  continue
 
129
  return chunks
test_ui_fixes.py ADDED
@@ -0,0 +1,89 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import sys
2
+ from pathlib import Path
3
+
4
+ # Add project root to path
5
+ project_root = Path(__file__).parent
6
+ sys.path.append(str(project_root))
7
+
8
+ def test_ui_fixes():
9
+ """Test the UI fixes and improvements"""
10
+ print("=== UI Fixes Test ===")
11
+ print()
12
+
13
+ # Test 1: Check if app.py was updated correctly
14
+ print("1. Testing app.py structure:")
15
+ try:
16
+ with open('app.py', 'r') as f:
17
+ content = f.read()
18
+
19
+ # Check for key components
20
+ required_components = [
21
+ 'st.session_state.ngrok_url_temp',
22
+ 'Test Ollama Connection',
23
+ 'Advanced System Monitor',
24
+ 'πŸ“‘ Test Ollama Connection',
25
+ 'is_sending'
26
+ ]
27
+
28
+ missing_components = []
29
+ for component in required_components:
30
+ if component not in content:
31
+ missing_components.append(component)
32
+
33
+ if missing_components:
34
+ print(f" ❌ Missing components: {missing_components}")
35
+ else:
36
+ print(" βœ… All required UI components present")
37
+
38
+ except Exception as e:
39
+ print(f" ❌ Error reading app.py: {e}")
40
+
41
+ print()
42
+
43
+ # Test 2: Check Ollama provider timeout
44
+ print("2. Testing Ollama provider timeout:")
45
+ try:
46
+ with open('core/providers/ollama.py', 'r') as f:
47
+ content = f.read()
48
+
49
+ if 'timeout: int = 60' in content:
50
+ print(" βœ… Ollama timeout increased to 60 seconds")
51
+ else:
52
+ print(" ❌ Ollama timeout not updated")
53
+
54
+ except Exception as e:
55
+ print(f" ❌ Error reading Ollama provider: {e}")
56
+
57
+ print()
58
+
59
+ # Test 3: Check for debug panel restoration
60
+ print("3. Testing debug panel restoration:")
61
+ try:
62
+ with open('app.py', 'r') as f:
63
+ content = f.read()
64
+
65
+ debug_features = [
66
+ 'Advanced System Monitor',
67
+ 'System Controls',
68
+ 'Provider Status',
69
+ 'Session Statistics'
70
+ ]
71
+
72
+ missing_features = []
73
+ for feature in debug_features:
74
+ if feature not in content:
75
+ missing_features.append(feature)
76
+
77
+ if missing_features:
78
+ print(f" ❌ Missing debug features: {missing_features}")
79
+ else:
80
+ print(" βœ… All debug panel features restored")
81
+
82
+ except Exception as e:
83
+ print(f" ❌ Error checking debug panel: {e}")
84
+
85
+ print()
86
+ print("πŸŽ‰ UI Fixes Test Completed!")
87
+
88
+ if __name__ == "__main__":
89
+ test_ui_fixes()