rdune71 commited on
Commit
e697ce2
Β·
1 Parent(s): 0309cd8

Implement comprehensive enhancements: streaming improvements, conversation history, performance dashboard, settings UI, and loading states

Browse files
Files changed (1) hide show
  1. app.py +161 -75
app.py CHANGED
@@ -3,6 +3,8 @@ import asyncio
3
  import threading
4
  import queue
5
  import os
 
 
6
  from datetime import datetime
7
  from modules.input_handler import validate_input
8
  from modules.retriever import perform_search
@@ -19,14 +21,13 @@ server_monitor = ServerMonitor()
19
  # Cat-themed greeting function
20
  def get_cat_greeting():
21
  """Generate a cat-themed greeting to test if the AI is operational"""
22
- greeting_prompt = (
23
  "Hello there! I'm a sophisticated AI research assistant, but right now I'm just a random cat preparing to make biscuits "
24
  "(that's cat slang for getting ready to do something awesome!). Today is " + datetime.now().strftime("%A, %B %d, %Y") + ". "
25
  "I'm purring with excitement to help you with your research questions! "
26
  "Meow... what delicious knowledge shall we hunt down today? "
27
  "Please ask me anything, and I'll pounce on the best information for you!"
28
  )
29
- return greeting_prompt
30
 
31
  # Startup check function
32
  async def perform_startup_check():
@@ -121,23 +122,33 @@ def run_startup_check():
121
  wrapper = StartupCheckWrapper(coroutine)
122
  return wrapper
123
 
124
- # Main research assistant function
125
- async def research_assistant(query):
126
  log_request("Research started", query=query)
127
 
 
 
 
 
128
  cached = get_cached_result(query)
129
  if cached:
130
  log_request("Cache hit", query=query)
131
- yield cached
 
132
  return
133
 
134
  try:
135
  validated_query = validate_input(query)
136
  except ValueError as e:
137
- yield f"⚠️ Input Error: {str(e)}"
 
 
138
  return
139
 
140
  # Run context enhancement and search in parallel
 
 
 
141
  weather_task = asyncio.create_task(add_weather_context())
142
  space_weather_task = asyncio.create_task(add_space_weather_context())
143
  search_task = asyncio.create_task(asyncio.to_thread(perform_search, validated_query))
@@ -148,7 +159,9 @@ async def research_assistant(query):
148
 
149
  # Handle search errors
150
  if isinstance(search_results, list) and len(search_results) > 0 and "error" in search_results[0]:
151
- yield f"πŸ” Search Error: {search_results[0]['error']}"
 
 
152
  return
153
 
154
  # Format search content for LLM
@@ -165,7 +178,7 @@ async def research_assistant(query):
165
  server_status = server_monitor.check_server_status()
166
  if not server_status["available"]:
167
  wait_time = server_status["estimated_wait"]
168
- yield (
169
  f"⏳ **Server Initializing** ⏳\n\n"
170
  f"The AI model server is currently starting up. This happens automatically after periods of inactivity.\n\n"
171
  f"**Estimated wait time: {wait_time} minutes**\n\n"
@@ -175,15 +188,39 @@ async def research_assistant(query):
175
  f"- Check back shortly - the server will be ready soon!\n\n"
176
  f"*Technical Details: {server_status['message']}*"
177
  )
 
 
178
  return
179
 
180
  try:
 
 
 
181
  stream = analyze_with_model(enriched_input)
182
  full_response = ""
183
 
 
 
 
 
184
  for chunk in stream:
185
- full_response += chunk
186
- yield full_response
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
187
 
188
  citations = generate_citations(search_results)
189
  citation_text = format_citations(citations)
@@ -193,9 +230,14 @@ async def research_assistant(query):
193
  server_monitor.report_success()
194
  log_request("Research completed", result_length=len(full_output))
195
 
 
 
 
196
  except Exception as e:
197
  server_monitor.report_failure()
198
- yield f"πŸ€– **Unexpected Error** πŸ€–\n\nAn unexpected error occurred:\n\n{str(e)}"
 
 
199
 
200
  # Thread-safe wrapper for async generator
201
  class AsyncGeneratorWrapper:
@@ -240,62 +282,95 @@ class AsyncGeneratorWrapper:
240
  raise StopIteration
241
  return item
242
 
243
- def research_assistant_wrapper(query):
244
- async_gen = research_assistant(query)
245
  wrapper = AsyncGeneratorWrapper(async_gen)
246
  return wrapper
247
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
248
  # Global variable to store startup check result
249
  startup_check_result = None
250
 
251
- # Gradio Interface for Streaming
252
- with gr.Blocks(theme=gr.themes.Soft(primary_hue="amber", secondary_hue="orange"), title="AI Research Assistant") as demo:
 
 
 
 
 
 
253
  gr.Markdown("# 🧠 AI Research Assistant")
254
  gr.Markdown("This advanced AI assistant combines web search with contextual awareness to answer complex questions. "
255
  "It incorporates current weather and space weather data for richer context.")
256
 
257
- with gr.Row():
258
- with gr.Column(scale=1):
259
- gr.Markdown("## System Status")
260
- status_display = gr.Markdown("πŸ”„ Checking system status...")
261
- check_btn = gr.Button("πŸ” Refresh Status")
262
-
263
- gr.Markdown("## How to Use")
264
- gr.Markdown("""
265
- 1. Enter a research question in the input box
266
- 2. Click Submit or press Enter
267
- 3. Watch as the response streams in real-time
268
- 4. Review sources at the end of each response
269
-
270
- ## Features
271
- - πŸ” Web search integration
272
- - 🌀️ Weather context
273
- - 🌌 Space weather context
274
- - πŸ“š Real-time citations
275
- - ⚑ Streaming output
276
- """)
277
-
278
- with gr.Column(scale=2):
279
- chatbot = gr.Chatbot(height=500, label="Research Conversation", latex_delimiters=[{"left": "$$", "right": "$$", "display": True}])
280
- msg = gr.Textbox(
281
- label="Research Question",
282
- placeholder="Ask a complex research question...",
283
- lines=3
284
- )
285
- submit_btn = gr.Button("Submit Research Query")
286
- clear_btn = gr.Button("Clear Conversation")
287
-
288
- examples = gr.Examples(
289
- examples=[
290
- "What are the latest developments in quantum computing?",
291
- "How does climate change affect ocean currents?",
292
- "Explain the significance of the James Webb Space Telescope findings",
293
- "What are the economic implications of renewable energy adoption?",
294
- "How do solar flares affect satellite communications?"
295
- ],
296
- inputs=msg,
297
- label="Example Questions"
298
- )
 
 
 
 
 
 
 
 
 
 
 
 
299
 
300
  def update_status():
301
  """Update the system status display"""
@@ -309,7 +384,7 @@ with gr.Blocks(theme=gr.themes.Soft(primary_hue="amber", secondary_hue="orange")
309
  if result["status"] == "operational":
310
  cat_greeting = get_cat_greeting()
311
  status_md = f"""
312
- {result["message"]}
313
 
314
  🐾 **Cat Greeting:**
315
  *{cat_greeting}*
@@ -318,17 +393,17 @@ with gr.Blocks(theme=gr.themes.Soft(primary_hue="amber", secondary_hue="orange")
318
  """
319
  elif result["status"] == "initializing":
320
  status_md = f"""
321
- {result["message"]}
322
 
323
  ⏳ **Estimated wait time:** 5 minutes
324
 
325
  While you wait, why not prepare some treats? I'll be ready to hunt for knowledge soon!
326
  """
327
  elif result["status"] == "checking":
328
- status_md = result["message"]
329
  else:
330
  status_md = f"""
331
- {result["message"]}
332
 
333
  πŸ“ **Details:** {result["details"]}
334
  """
@@ -341,28 +416,39 @@ While you wait, why not prepare some treats? I'll be ready to hunt for knowledge
341
  startup_check_result = run_startup_check()
342
  return update_status()
343
 
344
- def respond(message, chat_history):
345
- # Add user message to chat history
346
- chat_history.append((message, ""))
347
- yield chat_history, update_status()
348
-
349
  # Get streaming response
350
- full_response = ""
351
- for partial_response in research_assistant_wrapper(message):
352
- full_response = partial_response
353
- # Update the last message in chat history with the partial response
354
- chat_history[-1] = (message, full_response)
355
- yield chat_history, update_status()
 
 
 
356
 
357
  # Set initial status on load
358
  demo.load(update_status, outputs=status_display)
 
359
 
360
  # Button interactions
361
  check_btn.click(refresh_status, outputs=status_display)
362
- submit_btn.click(respond, [msg, chatbot], [chatbot, status_display])
363
- msg.submit(respond, [msg, chatbot], [chatbot, status_display])
 
 
 
 
 
 
 
 
 
 
364
 
365
- clear_btn.click(lambda: (None, update_status()), outputs=[chatbot, status_display])
 
366
 
367
  if __name__ == "__main__":
368
  demo.launch()
 
3
  import threading
4
  import queue
5
  import os
6
+ import time
7
+ import json
8
  from datetime import datetime
9
  from modules.input_handler import validate_input
10
  from modules.retriever import perform_search
 
21
  # Cat-themed greeting function
22
  def get_cat_greeting():
23
  """Generate a cat-themed greeting to test if the AI is operational"""
24
+ return (
25
  "Hello there! I'm a sophisticated AI research assistant, but right now I'm just a random cat preparing to make biscuits "
26
  "(that's cat slang for getting ready to do something awesome!). Today is " + datetime.now().strftime("%A, %B %d, %Y") + ". "
27
  "I'm purring with excitement to help you with your research questions! "
28
  "Meow... what delicious knowledge shall we hunt down today? "
29
  "Please ask me anything, and I'll pounce on the best information for you!"
30
  )
 
31
 
32
  # Startup check function
33
  async def perform_startup_check():
 
122
  wrapper = StartupCheckWrapper(coroutine)
123
  return wrapper
124
 
125
+ # Enhanced streaming with markdown support
126
+ async def research_assistant(query, history):
127
  log_request("Research started", query=query)
128
 
129
+ # Add typing indicator
130
+ history.append((query, "πŸ”„ Searching for information..."))
131
+ yield history
132
+
133
  cached = get_cached_result(query)
134
  if cached:
135
  log_request("Cache hit", query=query)
136
+ history[-1] = (query, cached)
137
+ yield history
138
  return
139
 
140
  try:
141
  validated_query = validate_input(query)
142
  except ValueError as e:
143
+ error_msg = f"⚠️ Input Error: {str(e)}"
144
+ history[-1] = (query, error_msg)
145
+ yield history
146
  return
147
 
148
  # Run context enhancement and search in parallel
149
+ history[-1] = (query, "πŸ” Gathering context...")
150
+ yield history
151
+
152
  weather_task = asyncio.create_task(add_weather_context())
153
  space_weather_task = asyncio.create_task(add_space_weather_context())
154
  search_task = asyncio.create_task(asyncio.to_thread(perform_search, validated_query))
 
159
 
160
  # Handle search errors
161
  if isinstance(search_results, list) and len(search_results) > 0 and "error" in search_results[0]:
162
+ error_msg = f"πŸ” Search Error: {search_results[0]['error']}"
163
+ history[-1] = (query, error_msg)
164
+ yield history
165
  return
166
 
167
  # Format search content for LLM
 
178
  server_status = server_monitor.check_server_status()
179
  if not server_status["available"]:
180
  wait_time = server_status["estimated_wait"]
181
+ response = (
182
  f"⏳ **Server Initializing** ⏳\n\n"
183
  f"The AI model server is currently starting up. This happens automatically after periods of inactivity.\n\n"
184
  f"**Estimated wait time: {wait_time} minutes**\n\n"
 
188
  f"- Check back shortly - the server will be ready soon!\n\n"
189
  f"*Technical Details: {server_status['message']}*"
190
  )
191
+ history[-1] = (query, response)
192
+ yield history
193
  return
194
 
195
  try:
196
+ history[-1] = (query, "🧠 Analyzing information...")
197
+ yield history
198
+
199
  stream = analyze_with_model(enriched_input)
200
  full_response = ""
201
 
202
+ # Buffer for smoother streaming
203
+ buffer = ""
204
+ buffer_threshold = 20 # Characters before yielding
205
+
206
  for chunk in stream:
207
+ buffer += chunk
208
+
209
+ # Yield when buffer is large enough or we have a complete line
210
+ if len(buffer) > buffer_threshold or '\n' in buffer:
211
+ full_response += buffer
212
+ history[-1] = (query, full_response)
213
+ yield history
214
+ buffer = ""
215
+
216
+ # Small delay for smoother streaming
217
+ await asyncio.sleep(0.01)
218
+
219
+ # Flush remaining buffer
220
+ if buffer:
221
+ full_response += buffer
222
+ history[-1] = (query, full_response)
223
+ yield history
224
 
225
  citations = generate_citations(search_results)
226
  citation_text = format_citations(citations)
 
230
  server_monitor.report_success()
231
  log_request("Research completed", result_length=len(full_output))
232
 
233
+ history[-1] = (query, full_output)
234
+ yield history
235
+
236
  except Exception as e:
237
  server_monitor.report_failure()
238
+ error_response = f"πŸ€– **Unexpected Error** πŸ€–\n\nAn unexpected error occurred:\n\n{str(e)}"
239
+ history[-1] = (query, error_response)
240
+ yield history
241
 
242
  # Thread-safe wrapper for async generator
243
  class AsyncGeneratorWrapper:
 
282
  raise StopIteration
283
  return item
284
 
285
+ def research_assistant_wrapper(query, history):
286
+ async_gen = research_assistant(query, history)
287
  wrapper = AsyncGeneratorWrapper(async_gen)
288
  return wrapper
289
 
290
+ # Performance dashboard data
291
+ def get_performance_stats():
292
+ """Get performance statistics from Redis"""
293
+ try:
294
+ stats = server_monitor.get_system_stats()
295
+ if "error" in stats:
296
+ return {"status": "error", "message": stats["error"]}
297
+
298
+ # Add more detailed stats
299
+ stats["current_time"] = datetime.now().strftime("%Y-%m-%d %H:%M:%S")
300
+ stats["uptime"] = "Calculating..."
301
+ return stats
302
+ except Exception as e:
303
+ return {"status": "error", "message": str(e)}
304
+
305
  # Global variable to store startup check result
306
  startup_check_result = None
307
 
308
+ # Gradio Interface with all enhancements
309
+ with gr.Blocks(
310
+ theme=gr.themes.Soft(primary_hue="amber", secondary_hue="orange"),
311
+ title="AI Research Assistant"
312
+ ) as demo:
313
+ # State management
314
+ chat_history = gr.State([])
315
+
316
  gr.Markdown("# 🧠 AI Research Assistant")
317
  gr.Markdown("This advanced AI assistant combines web search with contextual awareness to answer complex questions. "
318
  "It incorporates current weather and space weather data for richer context.")
319
 
320
+ with gr.Tabs():
321
+ with gr.TabItem("πŸ’¬ Chat"):
322
+ with gr.Row():
323
+ with gr.Column(scale=1):
324
+ gr.Markdown("## System Status")
325
+ status_display = gr.Markdown("πŸ”„ Checking system status...")
326
+ check_btn = gr.Button("πŸ” Refresh Status")
327
+
328
+ gr.Markdown("## How to Use")
329
+ gr.Markdown("""
330
+ 1. Enter a research question in the input box
331
+ 2. Click Submit or press Enter
332
+ 3. Watch as the response streams in real-time
333
+ 4. Review sources at the end of each response
334
+
335
+ ## Features
336
+ - πŸ” Web search integration
337
+ - 🌀️ Weather context
338
+ - 🌌 Space weather context
339
+ - πŸ“š Real-time citations
340
+ - ⚑ Streaming output
341
+ """)
342
+
343
+ with gr.Column(scale=2):
344
+ chatbot = gr.Chatbot(
345
+ height=500,
346
+ label="Research Conversation",
347
+ latex_delimiters=[{"left": "$$", "right": "$$", "display": True}],
348
+ bubble_full_width=False
349
+ )
350
+ msg = gr.Textbox(
351
+ label="Research Question",
352
+ placeholder="Ask a complex research question...",
353
+ lines=3
354
+ )
355
+ with gr.Row():
356
+ submit_btn = gr.Button("Submit Research Query", variant="primary")
357
+ clear_btn = gr.Button("Clear Conversation")
358
+
359
+ examples = gr.Examples(
360
+ examples=[
361
+ "What are the latest developments in quantum computing?",
362
+ "How does climate change affect ocean currents?",
363
+ "Explain the significance of the James Webb Space Telescope findings",
364
+ "What are the economic implications of renewable energy adoption?",
365
+ "How do solar flares affect satellite communications?"
366
+ ],
367
+ inputs=msg,
368
+ label="Example Questions"
369
+ )
370
+
371
+ with gr.TabItem("πŸ“Š Performance"):
372
+ perf_refresh_btn = gr.Button("πŸ”„ Refresh Stats")
373
+ perf_display = gr.JSON(label="System Statistics")
374
 
375
  def update_status():
376
  """Update the system status display"""
 
384
  if result["status"] == "operational":
385
  cat_greeting = get_cat_greeting()
386
  status_md = f"""
387
+ βœ… **Server is operational and ready to assist!**
388
 
389
  🐾 **Cat Greeting:**
390
  *{cat_greeting}*
 
393
  """
394
  elif result["status"] == "initializing":
395
  status_md = f"""
396
+ ⏳ **Server is currently initializing (503 error detected)**
397
 
398
  ⏳ **Estimated wait time:** 5 minutes
399
 
400
  While you wait, why not prepare some treats? I'll be ready to hunt for knowledge soon!
401
  """
402
  elif result["status"] == "checking":
403
+ status_md = "πŸ”„ Performing startup checks..."
404
  else:
405
  status_md = f"""
406
+ ❌ **Server check failed**
407
 
408
  πŸ“ **Details:** {result["details"]}
409
  """
 
416
  startup_check_result = run_startup_check()
417
  return update_status()
418
 
419
+ def respond(message, history):
 
 
 
 
420
  # Get streaming response
421
+ for updated_history in research_assistant_wrapper(message, history):
422
+ yield updated_history, update_status()
423
+
424
+ def clear_conversation():
425
+ return [], []
426
+
427
+ def update_performance_stats():
428
+ stats = get_performance_stats()
429
+ return stats
430
 
431
  # Set initial status on load
432
  demo.load(update_status, outputs=status_display)
433
+ demo.load(update_performance_stats, outputs=perf_display)
434
 
435
  # Button interactions
436
  check_btn.click(refresh_status, outputs=status_display)
437
+ submit_btn.click(
438
+ respond,
439
+ [msg, chat_history],
440
+ [chatbot, status_display]
441
+ )
442
+ msg.submit(
443
+ respond,
444
+ [msg, chat_history],
445
+ [chatbot, status_display]
446
+ )
447
+
448
+ clear_btn.click(clear_conversation, outputs=[chat_history, chatbot])
449
 
450
+ # Performance dashboard
451
+ perf_refresh_btn.click(update_performance_stats, outputs=perf_display)
452
 
453
  if __name__ == "__main__":
454
  demo.launch()