Reality123b commited on
Commit
eb07f36
·
verified ·
1 Parent(s): 53b34da

Update app.py

Browse files
Files changed (1) hide show
  1. app.py +52 -83
app.py CHANGED
@@ -1,18 +1,17 @@
1
  import gradio as gr
2
- import requests
3
  import os
4
  import time
5
  import json
6
  import re
7
  from uuid import uuid4
8
  from datetime import datetime
9
- from duckduckgo_search import DDGS # Corrected import
10
  from sentence_transformers import SentenceTransformer, util
11
  from typing import List, Dict, Any, Optional, Union, Tuple
12
  import logging
13
- import pandas as pd
14
  import numpy as np
15
  from collections import deque
 
16
 
17
  # Set up logging
18
  logging.basicConfig(level=logging.INFO, format='%(asctime)s - %(name)s - %(levelname)s - %(message)s')
@@ -23,50 +22,54 @@ HF_API_KEY = os.environ.get("HF_API_KEY")
23
  if not HF_API_KEY:
24
  raise ValueError("Please set the HF_API_KEY environment variable.")
25
 
26
- # You can use different models for different tasks
27
- MAIN_LLM_ENDPOINT = "'https://router.huggingface.co/hf-inference/models/mistralai/Mistral-Nemo-Instruct-2407/v1/chat/completions" # Replace with your actual endpoint
28
- REASONING_LLM_ENDPOINT = "https://router.huggingface.co/hf-inference/models/deepseek-ai/DeepSeek-R1-Distill-Qwen-32B/v1/chat/completions" # Can be the same as main if needed
29
- CRITIC_LLM_ENDPOINT = "https://router.huggingface.co/hf-inference/models/Qwen/QwQ-32B-Preview/v1/chat/completions" # Can be the same as main if needed
30
 
31
- MAX_ITERATIONS = 12 # Increased from 7
 
 
 
 
 
32
  TIMEOUT = 60
33
  RETRY_DELAY = 5
34
- NUM_RESULTS = 10 # Increased from 7
35
- SIMILARITY_THRESHOLD = 0.15 # Lowered from 0.2 to get more potentially relevant results
36
- MAX_CONTEXT_ITEMS = 20 # Prevent context from growing too large
37
- MAX_HISTORY_ITEMS = 5 # For keeping track of previous queries/reasoning
38
 
39
  # Load multiple embedding models for different purposes
40
  try:
41
  main_similarity_model = SentenceTransformer('all-mpnet-base-v2')
42
- concept_similarity_model = SentenceTransformer('sentence-transformers/all-MiniLM-L6-v2') # Faster, lighter model for concept matching
43
  except Exception as e:
44
  logger.error(f"Failed to load SentenceTransformer models: {e}")
45
  main_similarity_model = None
46
  concept_similarity_model = None
47
 
48
- def hf_inference(endpoint, inputs, parameters=None, retries=5):
49
- headers = {"Authorization": f"Bearer {HF_API_KEY}"}
50
- payload = {"inputs": inputs, "parameters": parameters or {}}
51
-
52
  for attempt in range(retries):
53
  try:
54
- response = requests.post(endpoint, headers=headers, json=payload, timeout=TIMEOUT)
55
- response.raise_for_status()
56
- return response.json()
57
- except requests.exceptions.RequestException as e:
 
 
 
 
58
  if attempt == retries - 1:
59
  logger.error(f"Request failed after {retries} retries: {e}")
60
  return {"error": f"Request failed after {retries} retries: {e}"}
61
- time.sleep(RETRY_DELAY * (1 + attempt)) # Exponential backoff
62
  return {"error": "Request failed after multiple retries."}
63
 
64
  def tool_search_web(query: str, num_results: int = NUM_RESULTS, safesearch: str = "moderate",
65
  time_filter: str = "", region: str = "wt-wt", language: str = "en-us") -> list:
66
  try:
67
- with DDGS() as ddgs: # Use the DDGS context manager
68
  results = [r for r in ddgs.text(query, max_results=num_results, safesearch=safesearch,
69
- time=time_filter, region=region, hreflang=language)] #Simplified call
70
  if results:
71
  return [{"title": r["title"], "snippet": r["body"], "url": r["href"]} for r in results]
72
  else:
@@ -98,7 +101,7 @@ def tool_reason(prompt: str, search_results: list, reasoning_context: list = [],
98
 
99
  reasoning_input += "\nProvide a thorough, nuanced analysis that builds upon previous reasoning if applicable. Consider multiple perspectives and potential contradictions in the search results."
100
 
101
- reasoning_output = hf_inference(REASONING_LLM_ENDPOINT, reasoning_input)
102
 
103
  if isinstance(reasoning_output, dict) and "generated_text" in reasoning_output:
104
  return reasoning_output["generated_text"].strip()
@@ -111,14 +114,14 @@ def tool_summarize(insights: list, prompt: str, contradictions: list = []) -> st
111
  return "No insights to summarize."
112
 
113
  summarization_input = f"Synthesize the following insights into a cohesive and comprehensive summary regarding: '{prompt}'\n\n"
114
- summarization_input += "\n\n".join(insights[-MAX_HISTORY_ITEMS:]) # Only use most recent insights
115
 
116
  if contradictions:
117
  summarization_input += "\n\nAddress these specific contradictions:\n" + "\n".join(contradictions)
118
 
119
  summarization_input += "\n\nProvide a well-structured summary that:\n1. Presents the main findings\n2. Acknowledges limitations and uncertainties\n3. Highlights areas of consensus and disagreement\n4. Suggests potential directions for further inquiry"
120
 
121
- summarization_output = hf_inference(MAIN_LLM_ENDPOINT, summarization_input)
122
 
123
  if isinstance(summarization_output, dict) and "generated_text" in summarization_output:
124
  return summarization_output["generated_text"].strip()
@@ -127,7 +130,7 @@ def tool_summarize(insights: list, prompt: str, contradictions: list = []) -> st
127
  return "Could not generate a summary due to an error."
128
 
129
  def tool_generate_search_query(prompt: str, previous_queries: list = [],
130
- failed_queries: list = [], focus_areas: list = []) -> str:
131
  query_gen_input = f"Generate an effective search query for the following prompt: {prompt}\n"
132
 
133
  if previous_queries:
@@ -143,7 +146,7 @@ def tool_generate_search_query(prompt: str, previous_queries: list = [],
143
  query_gen_input += "Refine the search query based on previous queries, aiming for more precise results.\n"
144
  query_gen_input += "Search Query:"
145
 
146
- query_gen_output = hf_inference(MAIN_LLM_ENDPOINT, query_gen_input)
147
 
148
  if isinstance(query_gen_output, dict) and 'generated_text' in query_gen_output:
149
  return query_gen_output['generated_text'].strip()
@@ -152,7 +155,7 @@ def tool_generate_search_query(prompt: str, previous_queries: list = [],
152
  return ""
153
 
154
  def tool_critique_reasoning(reasoning_output: str, prompt: str,
155
- previous_critiques: list = []) -> str:
156
  critique_input = f"Critically evaluate the following reasoning output in relation to the prompt:\n\nPrompt: {prompt}\n\nReasoning: {reasoning_output}\n\n"
157
 
158
  if previous_critiques:
@@ -160,7 +163,7 @@ def tool_critique_reasoning(reasoning_output: str, prompt: str,
160
 
161
  critique_input += "Identify any flaws, biases, logical fallacies, unsupported claims, or areas for improvement. Be specific and constructive. Suggest concrete ways to enhance the reasoning."
162
 
163
- critique_output = hf_inference(CRITIC_LLM_ENDPOINT, critique_input)
164
 
165
  if isinstance(critique_output, dict) and "generated_text" in critique_output:
166
  return critique_output["generated_text"].strip()
@@ -175,14 +178,13 @@ def tool_identify_contradictions(insights: list) -> list:
175
  contradiction_input = "Identify specific contradictions in these insights:\n\n" + "\n\n".join(insights[-MAX_HISTORY_ITEMS:])
176
  contradiction_input += "\n\nList each contradiction as a separate numbered point. If no contradictions exist, respond with 'No contradictions found.'"
177
 
178
- contradiction_output = hf_inference(CRITIC_LLM_ENDPOINT, contradiction_input)
179
 
180
  if isinstance(contradiction_output, dict) and "generated_text" in contradiction_output:
181
  result = contradiction_output["generated_text"].strip()
182
  if result == "No contradictions found.":
183
  return []
184
 
185
- # Extract numbered contradictions
186
  contradictions = re.findall(r'\d+\.\s+(.*?)(?=\d+\.|$)', result, re.DOTALL)
187
  return [c.strip() for c in contradictions if c.strip()]
188
 
@@ -190,24 +192,23 @@ def tool_identify_contradictions(insights: list) -> list:
190
  return []
191
 
192
  def tool_identify_focus_areas(prompt: str, insights: list = [],
193
- failed_areas: list = []) -> list:
194
  focus_input = f"Based on this research prompt: '{prompt}'\n\n"
195
 
196
  if insights:
197
- focus_input += "And these existing insights:\n" + "\n".join(insights[-3:]) + "\n\n" # Last 3 insights
198
 
199
  if failed_areas:
200
  focus_input += f"These focus areas didn't yield useful results: {', '.join(failed_areas)}\n\n"
201
 
202
  focus_input += "Identify 2-3 specific aspects that should be investigated further to get a complete understanding. Be precise and prioritize underexplored areas."
203
 
204
- focus_output = hf_inference(MAIN_LLM_ENDPOINT, focus_input)
205
 
206
  if isinstance(focus_output, dict) and "generated_text" in focus_output:
207
  result = focus_output["generated_text"].strip()
208
- # Extract areas, assuming they're listed with numbers, bullets, or in separate lines
209
  areas = re.findall(r'(?:^|\n)(?:\d+\.|\*|\-)\s*(.*?)(?=(?:\n(?:\d+\.|\*|\-|$))|$)', result)
210
- return [area.strip() for area in areas if area.strip()][:3] # Limit to top 3
211
 
212
  logger.error(f"Failed to identify focus areas: {focus_output}")
213
  return []
@@ -220,7 +221,6 @@ def filter_results(search_results, prompt, previous_snippets=None):
220
  prompt_embedding = main_similarity_model.encode(prompt, convert_to_tensor=True)
221
  filtered_results = []
222
 
223
- # Keep track of snippets we've already seen
224
  seen_snippets = set()
225
  if previous_snippets:
226
  seen_snippets.update(previous_snippets)
@@ -228,7 +228,6 @@ def filter_results(search_results, prompt, previous_snippets=None):
228
  for result in search_results:
229
  combined_text = result['title'] + " " + result['snippet']
230
 
231
- # Skip if we've seen this exact snippet before
232
  if result['snippet'] in seen_snippets:
233
  continue
234
 
@@ -240,7 +239,6 @@ def filter_results(search_results, prompt, previous_snippets=None):
240
  filtered_results.append(result)
241
  seen_snippets.add(result['snippet'])
242
 
243
- # Sort by relevance score
244
  filtered_results.sort(key=lambda x: x.get('relevance_score', 0), reverse=True)
245
  return filtered_results
246
 
@@ -248,22 +246,19 @@ def filter_results(search_results, prompt, previous_snippets=None):
248
  logger.error(f"Error during filtering: {e}")
249
  return search_results
250
 
251
- # New tool: Extract entities for focused research
252
  def tool_extract_key_entities(prompt: str) -> list:
253
  entity_input = f"Extract the key entities (people, organizations, concepts, technologies, etc.) from this research prompt that should be investigated individually:\n\n{prompt}\n\nList only the most important 3-5 entities, one per line."
254
 
255
- entity_output = hf_inference(MAIN_LLM_ENDPOINT, entity_input)
256
 
257
  if isinstance(entity_output, dict) and "generated_text" in entity_output:
258
  result = entity_output["generated_text"].strip()
259
- # Split by lines and clean up
260
  entities = [e.strip() for e in result.split('\n') if e.strip()]
261
- return entities[:5] # Limit to 5 entities
262
 
263
  logger.error(f"Failed to extract key entities: {entity_output}")
264
  return []
265
 
266
- # New tool: Meta-analyze across entities
267
  def tool_meta_analyze(entity_insights: Dict[str, list], prompt: str) -> str:
268
  if not entity_insights:
269
  return "No entity insights to analyze."
@@ -272,11 +267,11 @@ def tool_meta_analyze(entity_insights: Dict[str, list], prompt: str) -> str:
272
 
273
  for entity, insights in entity_insights.items():
274
  if insights:
275
- meta_input += f"\n--- {entity} ---\n" + insights[-1] + "\n" # Just use the latest insight for each entity
276
 
277
  meta_input += "\nProvide a high-level synthesis that identifies:\n1. Common themes across entities\n2. Important differences\n3. How these entities interact or influence each other\n4. The broader implications for the original research question"
278
 
279
- meta_output = hf_inference(MAIN_LLM_ENDPOINT, meta_input)
280
 
281
  if isinstance(meta_output, dict) and "generated_text" in meta_output:
282
  return meta_output["generated_text"].strip()
@@ -284,7 +279,6 @@ def tool_meta_analyze(entity_insights: Dict[str, list], prompt: str) -> str:
284
  logger.error(f"Failed to perform meta-analysis: {meta_output}")
285
  return "Could not generate a meta-analysis due to an error."
286
 
287
- # Update tools dictionary with enhanced functionality
288
  tools = {
289
  "search_web": {
290
  "function": tool_search_web,
@@ -371,10 +365,8 @@ tools = {
371
 
372
  def create_prompt(task_description, user_input, available_tools, context):
373
  prompt = f"""{task_description}
374
-
375
  User Input:
376
  {user_input}
377
-
378
  Available Tools:
379
  """
380
  for tool_name, tool_data in available_tools.items():
@@ -383,7 +375,6 @@ Available Tools:
383
  for param_name, param_data in tool_data["parameters"].items():
384
  prompt += f" - {param_name} ({param_data['type']}): {param_data['description']}\n"
385
 
386
- # Only include most recent context items to avoid exceeding context limits
387
  recent_context = context[-MAX_CONTEXT_ITEMS:] if len(context) > MAX_CONTEXT_ITEMS else context
388
 
389
  prompt += "\nContext (most recent items):\n"
@@ -394,10 +385,8 @@ Available Tools:
394
  Instructions:
395
  Select the BEST tool and parameters for the current research stage. Output valid JSON. If no tool is appropriate, respond with {}.
396
  Only use provided tools. Be strategic about which tool to use next based on the research progress so far.
397
-
398
  Example:
399
  {"tool": "search_web", "parameters": {"query": "Eiffel Tower location"}}
400
-
401
  Output:
402
  """
403
  return prompt
@@ -418,20 +407,16 @@ def deep_research(prompt):
418
  contradictions = []
419
  research_session_id = str(uuid4())
420
 
421
- # Start with entity extraction for multi-pronged research
422
  key_entities = tool_extract_key_entities(prompt=prompt)
423
  if key_entities:
424
  context.append(f"Identified key entities: {key_entities}")
425
  intermediate_output += f"Identified key entities for focused research: {key_entities}\n"
426
 
427
- # Tracking progress for each entity
428
  entity_progress = {entity: {'queries': [], 'insights': []} for entity in key_entities}
429
- entity_progress['general'] = {'queries': [], 'insights': []} # For general research not tied to specific entities
430
 
431
  for i in range(MAX_ITERATIONS):
432
- # Decide which entity to focus on this iteration, or general research
433
  if key_entities and i > 0:
434
- # Simple round-robin for entities, with general research every few iterations
435
  entities_to_process = key_entities + ['general']
436
  current_entity = entities_to_process[i % len(entities_to_process)]
437
  else:
@@ -439,7 +424,6 @@ def deep_research(prompt):
439
 
440
  context.append(f"Current focus: {current_entity}")
441
 
442
- # First iteration: general query and initial research
443
  if i == 0:
444
  initial_query = tool_generate_search_query(prompt=prompt)
445
  if initial_query:
@@ -463,7 +447,6 @@ def deep_research(prompt):
463
  failed_queries.append(initial_query)
464
  context.append(f"Initial query yielded no relevant results: {initial_query}")
465
 
466
- # Generate current entity-specific query if applicable
467
  elif current_entity != 'general':
468
  entity_query = tool_generate_search_query(
469
  prompt=f"{prompt} focusing specifically on {current_entity}",
@@ -475,20 +458,17 @@ def deep_research(prompt):
475
  previous_queries.append(entity_query)
476
  entity_progress[current_entity]['queries'].append(entity_query)
477
 
478
- # Search with entity focus
479
  search_results = tool_search_web(query=entity_query)
480
  filtered_search_results = filter_results(search_results,
481
  f"{prompt} {current_entity}",
482
  previous_snippets=seen_snippets)
483
 
484
- # Update seen snippets
485
  for result in filtered_search_results:
486
  seen_snippets.add(result['snippet'])
487
 
488
  if filtered_search_results:
489
  context.append(f"Entity Search for {current_entity}: {len(filtered_search_results)} results")
490
 
491
- # Get entity-specific reasoning
492
  entity_reasoning = tool_reason(
493
  prompt=f"{prompt} focusing on {current_entity}",
494
  search_results=filtered_search_results,
@@ -500,7 +480,6 @@ def deep_research(prompt):
500
  all_insights.append(entity_reasoning)
501
  entity_progress[current_entity]['insights'].append(entity_reasoning)
502
 
503
- # Store in entity-specific insights dictionary for meta-analysis
504
  if current_entity not in entity_specific_insights:
505
  entity_specific_insights[current_entity] = []
506
  entity_specific_insights[current_entity].append(entity_reasoning)
@@ -510,9 +489,8 @@ def deep_research(prompt):
510
  failed_queries.append(entity_query)
511
  context.append(f"Entity query for {current_entity} yielded no relevant results")
512
 
513
- # Generate LLM decision for next tool
514
  llm_prompt = create_prompt(task_description, prompt, tools, context)
515
- llm_response = hf_inference(MAIN_LLM_ENDPOINT, llm_prompt)
516
 
517
  if isinstance(llm_response, dict) and "error" in llm_response:
518
  intermediate_output += f"LLM Error: {llm_response['error']}\n"
@@ -536,8 +514,7 @@ def deep_research(prompt):
536
 
537
  if not tool_name:
538
  if all_insights:
539
- # If we have insights but no tool selected, maybe we're done
540
- if i > MAX_ITERATIONS // 2: # Only consider ending early after half the iterations
541
  break
542
  continue
543
 
@@ -597,7 +574,6 @@ def deep_research(prompt):
597
  prompt if current_entity == 'general' else f"{prompt} {current_entity}",
598
  previous_snippets=seen_snippets)
599
 
600
- # Update seen snippets
601
  for r in filtered_result:
602
  seen_snippets.add(r['snippet'])
603
 
@@ -627,7 +603,7 @@ def deep_research(prompt):
627
  elif tool_name == "identify_contradictions":
628
  result = tool["function"](**parameters)
629
  if result:
630
- contradictions = result # Store for later use in summarization
631
  context.append(f"Identified contradictions: {result}")
632
 
633
  elif tool_name == "identify_focus_areas":
@@ -635,7 +611,6 @@ def deep_research(prompt):
635
  parameters['failed_areas'] = failed_areas
636
  result = tool["function"](**parameters)
637
  if result:
638
- # Update focus areas, but keep track of ones that didn't yield results
639
  old_focus = set(focus_areas)
640
  focus_areas = result
641
  failed_areas.extend([area for area in old_focus if area not in result])
@@ -648,45 +623,40 @@ def deep_research(prompt):
648
  parameters['prompt'] = prompt
649
  result = tool["function"](**parameters)
650
  if result:
651
- all_insights.append(result) # Add meta-analysis to insights
652
  context.append(f"Meta-analysis across entities: {result[:200]}...")
653
 
654
  else:
655
  result = tool["function"](**parameters)
656
 
657
- # Truncate very long results for the intermediate output
658
  result_str = str(result)
659
  if len(result_str) > 500:
660
  result_str = result_str[:500] + "..."
661
 
662
  intermediate_output += f"Iteration {i+1} - Result: {result_str}\n"
663
 
664
- # Add truncated result to context
665
  result_context = result_str
666
- if len(result_str) > 300: # Even shorter for context
667
  result_context = result_str[:300] + "..."
668
  context.append(f"Used: {tool_name}, Result: {result_context}")
669
 
670
  except Exception as e:
671
  logger.error(f"Error with {tool_name}: {str(e)}")
672
  context.append(f"Error with {tool_name}: {str(e)}")
673
- intermediate_output += f"Iteration {i+1} - Error: {str(e)}\n" # Added \n and closing quote
674
  continue
675
 
676
- # Perform final meta-analysis if we have entity-specific insights
677
  if len(entity_specific_insights) > 1 and len(all_insights) > 2:
678
  meta_analysis = tool_meta_analyze(entity_insights=entity_specific_insights, prompt=prompt)
679
  if meta_analysis:
680
  all_insights.append(meta_analysis)
681
  intermediate_output += f"Final Meta-Analysis: {meta_analysis[:500]}...\n"
682
 
683
- # Generate the final summary
684
  if all_insights:
685
  final_result = tool_summarize(all_insights, prompt, contradictions)
686
  else:
687
  final_result = "Could not find meaningful information despite multiple attempts."
688
 
689
- # Prepare the full output with detailed tracking
690
  full_output = f"**Research Prompt:** {prompt}\n\n"
691
 
692
  if key_entities:
@@ -702,7 +672,6 @@ def deep_research(prompt):
702
 
703
  full_output += f"**Final Analysis:**\n{final_result}\n\n"
704
 
705
- # Add session info for potential follow-up
706
  full_output += f"Research Session ID: {research_session_id}\n"
707
  full_output += f"Completed at: {datetime.now().strftime('%Y-%m-%d %H:%M:%S')}\n"
708
  full_output += f"Total iterations: {i+1}\n"
@@ -752,7 +721,7 @@ iface = gr.Interface(
752
  ["How has artificial intelligence influenced medical diagnostics in the past five years, and what are the ethical considerations?"]
753
  ],
754
  theme="default",
755
- cache_examples=False, # Add this line # gr.themes.Base() is more explicit, but "default" also works
756
  css=custom_css,
757
  flagging_mode='never',
758
  analytics_enabled=False,
@@ -765,7 +734,7 @@ footer_html = """
765
  <p>Results should be verified with additional sources. Not suitable for medical, legal, or emergency use.</p>
766
  </div>
767
  """
768
- #iface = iface.add_html(footer_html) #gr.Interface object has no attribute add_html
769
 
770
  # Launch the interface
771
  iface.launch(share=False)
 
1
  import gradio as gr
 
2
  import os
3
  import time
4
  import json
5
  import re
6
  from uuid import uuid4
7
  from datetime import datetime
8
+ from duckduckgo_search import DDGS
9
  from sentence_transformers import SentenceTransformer, util
10
  from typing import List, Dict, Any, Optional, Union, Tuple
11
  import logging
 
12
  import numpy as np
13
  from collections import deque
14
+ from huggingface_hub import InferenceClient
15
 
16
  # Set up logging
17
  logging.basicConfig(level=logging.INFO, format='%(asctime)s - %(name)s - %(levelname)s - %(message)s')
 
22
  if not HF_API_KEY:
23
  raise ValueError("Please set the HF_API_KEY environment variable.")
24
 
25
+ # Initialize Hugging Face Inference Client
26
+ client = InferenceClient(provider="hf-inference", api_key=HF_API_KEY)
 
 
27
 
28
+ # Model endpoints
29
+ MAIN_LLM_MODEL = "mistralai/Mistral-Nemo-Instruct-2407"
30
+ REASONING_LLM_MODEL = "deepseek-ai/DeepSeek-R1-Distill-Qwen-32B"
31
+ CRITIC_LLM_MODEL = "Qwen/QwQ-32B-Preview"
32
+
33
+ MAX_ITERATIONS = 12
34
  TIMEOUT = 60
35
  RETRY_DELAY = 5
36
+ NUM_RESULTS = 10
37
+ SIMILARITY_THRESHOLD = 0.15
38
+ MAX_CONTEXT_ITEMS = 20
39
+ MAX_HISTORY_ITEMS = 5
40
 
41
  # Load multiple embedding models for different purposes
42
  try:
43
  main_similarity_model = SentenceTransformer('all-mpnet-base-v2')
44
+ concept_similarity_model = SentenceTransformer('sentence-transformers/all-MiniLM-L6-v2')
45
  except Exception as e:
46
  logger.error(f"Failed to load SentenceTransformer models: {e}")
47
  main_similarity_model = None
48
  concept_similarity_model = None
49
 
50
+ def hf_inference(model_name, prompt, max_tokens=500, retries=5):
 
 
 
51
  for attempt in range(retries):
52
  try:
53
+ messages = [{"role": "user", "content": prompt}]
54
+ response = client.chat.completions.create(
55
+ model=model_name,
56
+ messages=messages,
57
+ max_tokens=max_tokens
58
+ )
59
+ return {"generated_text": response.choices[0].message.content}
60
+ except Exception as e:
61
  if attempt == retries - 1:
62
  logger.error(f"Request failed after {retries} retries: {e}")
63
  return {"error": f"Request failed after {retries} retries: {e}"}
64
+ time.sleep(RETRY_DELAY * (1 + attempt))
65
  return {"error": "Request failed after multiple retries."}
66
 
67
  def tool_search_web(query: str, num_results: int = NUM_RESULTS, safesearch: str = "moderate",
68
  time_filter: str = "", region: str = "wt-wt", language: str = "en-us") -> list:
69
  try:
70
+ with DDGS() as ddgs:
71
  results = [r for r in ddgs.text(query, max_results=num_results, safesearch=safesearch,
72
+ time=time_filter, region=region, hreflang=language)]
73
  if results:
74
  return [{"title": r["title"], "snippet": r["body"], "url": r["href"]} for r in results]
75
  else:
 
101
 
102
  reasoning_input += "\nProvide a thorough, nuanced analysis that builds upon previous reasoning if applicable. Consider multiple perspectives and potential contradictions in the search results."
103
 
104
+ reasoning_output = hf_inference(REASONING_LLM_MODEL, reasoning_input)
105
 
106
  if isinstance(reasoning_output, dict) and "generated_text" in reasoning_output:
107
  return reasoning_output["generated_text"].strip()
 
114
  return "No insights to summarize."
115
 
116
  summarization_input = f"Synthesize the following insights into a cohesive and comprehensive summary regarding: '{prompt}'\n\n"
117
+ summarization_input += "\n\n".join(insights[-MAX_HISTORY_ITEMS:])
118
 
119
  if contradictions:
120
  summarization_input += "\n\nAddress these specific contradictions:\n" + "\n".join(contradictions)
121
 
122
  summarization_input += "\n\nProvide a well-structured summary that:\n1. Presents the main findings\n2. Acknowledges limitations and uncertainties\n3. Highlights areas of consensus and disagreement\n4. Suggests potential directions for further inquiry"
123
 
124
+ summarization_output = hf_inference(MAIN_LLM_MODEL, summarization_input)
125
 
126
  if isinstance(summarization_output, dict) and "generated_text" in summarization_output:
127
  return summarization_output["generated_text"].strip()
 
130
  return "Could not generate a summary due to an error."
131
 
132
  def tool_generate_search_query(prompt: str, previous_queries: list = [],
133
+ failed_queries: list = [], focus_areas: list = []) -> str:
134
  query_gen_input = f"Generate an effective search query for the following prompt: {prompt}\n"
135
 
136
  if previous_queries:
 
146
  query_gen_input += "Refine the search query based on previous queries, aiming for more precise results.\n"
147
  query_gen_input += "Search Query:"
148
 
149
+ query_gen_output = hf_inference(MAIN_LLM_MODEL, query_gen_input)
150
 
151
  if isinstance(query_gen_output, dict) and 'generated_text' in query_gen_output:
152
  return query_gen_output['generated_text'].strip()
 
155
  return ""
156
 
157
  def tool_critique_reasoning(reasoning_output: str, prompt: str,
158
+ previous_critiques: list = []) -> str:
159
  critique_input = f"Critically evaluate the following reasoning output in relation to the prompt:\n\nPrompt: {prompt}\n\nReasoning: {reasoning_output}\n\n"
160
 
161
  if previous_critiques:
 
163
 
164
  critique_input += "Identify any flaws, biases, logical fallacies, unsupported claims, or areas for improvement. Be specific and constructive. Suggest concrete ways to enhance the reasoning."
165
 
166
+ critique_output = hf_inference(CRITIC_LLM_MODEL, critique_input)
167
 
168
  if isinstance(critique_output, dict) and "generated_text" in critique_output:
169
  return critique_output["generated_text"].strip()
 
178
  contradiction_input = "Identify specific contradictions in these insights:\n\n" + "\n\n".join(insights[-MAX_HISTORY_ITEMS:])
179
  contradiction_input += "\n\nList each contradiction as a separate numbered point. If no contradictions exist, respond with 'No contradictions found.'"
180
 
181
+ contradiction_output = hf_inference(CRITIC_LLM_MODEL, contradiction_input)
182
 
183
  if isinstance(contradiction_output, dict) and "generated_text" in contradiction_output:
184
  result = contradiction_output["generated_text"].strip()
185
  if result == "No contradictions found.":
186
  return []
187
 
 
188
  contradictions = re.findall(r'\d+\.\s+(.*?)(?=\d+\.|$)', result, re.DOTALL)
189
  return [c.strip() for c in contradictions if c.strip()]
190
 
 
192
  return []
193
 
194
  def tool_identify_focus_areas(prompt: str, insights: list = [],
195
+ failed_areas: list = []) -> list:
196
  focus_input = f"Based on this research prompt: '{prompt}'\n\n"
197
 
198
  if insights:
199
+ focus_input += "And these existing insights:\n" + "\n".join(insights[-3:]) + "\n\n"
200
 
201
  if failed_areas:
202
  focus_input += f"These focus areas didn't yield useful results: {', '.join(failed_areas)}\n\n"
203
 
204
  focus_input += "Identify 2-3 specific aspects that should be investigated further to get a complete understanding. Be precise and prioritize underexplored areas."
205
 
206
+ focus_output = hf_inference(MAIN_LLM_MODEL, focus_input)
207
 
208
  if isinstance(focus_output, dict) and "generated_text" in focus_output:
209
  result = focus_output["generated_text"].strip()
 
210
  areas = re.findall(r'(?:^|\n)(?:\d+\.|\*|\-)\s*(.*?)(?=(?:\n(?:\d+\.|\*|\-|$))|$)', result)
211
+ return [area.strip() for area in areas if area.strip()][:3]
212
 
213
  logger.error(f"Failed to identify focus areas: {focus_output}")
214
  return []
 
221
  prompt_embedding = main_similarity_model.encode(prompt, convert_to_tensor=True)
222
  filtered_results = []
223
 
 
224
  seen_snippets = set()
225
  if previous_snippets:
226
  seen_snippets.update(previous_snippets)
 
228
  for result in search_results:
229
  combined_text = result['title'] + " " + result['snippet']
230
 
 
231
  if result['snippet'] in seen_snippets:
232
  continue
233
 
 
239
  filtered_results.append(result)
240
  seen_snippets.add(result['snippet'])
241
 
 
242
  filtered_results.sort(key=lambda x: x.get('relevance_score', 0), reverse=True)
243
  return filtered_results
244
 
 
246
  logger.error(f"Error during filtering: {e}")
247
  return search_results
248
 
 
249
  def tool_extract_key_entities(prompt: str) -> list:
250
  entity_input = f"Extract the key entities (people, organizations, concepts, technologies, etc.) from this research prompt that should be investigated individually:\n\n{prompt}\n\nList only the most important 3-5 entities, one per line."
251
 
252
+ entity_output = hf_inference(MAIN_LLM_MODEL, entity_input)
253
 
254
  if isinstance(entity_output, dict) and "generated_text" in entity_output:
255
  result = entity_output["generated_text"].strip()
 
256
  entities = [e.strip() for e in result.split('\n') if e.strip()]
257
+ return entities[:5]
258
 
259
  logger.error(f"Failed to extract key entities: {entity_output}")
260
  return []
261
 
 
262
  def tool_meta_analyze(entity_insights: Dict[str, list], prompt: str) -> str:
263
  if not entity_insights:
264
  return "No entity insights to analyze."
 
267
 
268
  for entity, insights in entity_insights.items():
269
  if insights:
270
+ meta_input += f"\n--- {entity} ---\n" + insights[-1] + "\n"
271
 
272
  meta_input += "\nProvide a high-level synthesis that identifies:\n1. Common themes across entities\n2. Important differences\n3. How these entities interact or influence each other\n4. The broader implications for the original research question"
273
 
274
+ meta_output = hf_inference(MAIN_LLM_MODEL, meta_input)
275
 
276
  if isinstance(meta_output, dict) and "generated_text" in meta_output:
277
  return meta_output["generated_text"].strip()
 
279
  logger.error(f"Failed to perform meta-analysis: {meta_output}")
280
  return "Could not generate a meta-analysis due to an error."
281
 
 
282
  tools = {
283
  "search_web": {
284
  "function": tool_search_web,
 
365
 
366
  def create_prompt(task_description, user_input, available_tools, context):
367
  prompt = f"""{task_description}
 
368
  User Input:
369
  {user_input}
 
370
  Available Tools:
371
  """
372
  for tool_name, tool_data in available_tools.items():
 
375
  for param_name, param_data in tool_data["parameters"].items():
376
  prompt += f" - {param_name} ({param_data['type']}): {param_data['description']}\n"
377
 
 
378
  recent_context = context[-MAX_CONTEXT_ITEMS:] if len(context) > MAX_CONTEXT_ITEMS else context
379
 
380
  prompt += "\nContext (most recent items):\n"
 
385
  Instructions:
386
  Select the BEST tool and parameters for the current research stage. Output valid JSON. If no tool is appropriate, respond with {}.
387
  Only use provided tools. Be strategic about which tool to use next based on the research progress so far.
 
388
  Example:
389
  {"tool": "search_web", "parameters": {"query": "Eiffel Tower location"}}
 
390
  Output:
391
  """
392
  return prompt
 
407
  contradictions = []
408
  research_session_id = str(uuid4())
409
 
 
410
  key_entities = tool_extract_key_entities(prompt=prompt)
411
  if key_entities:
412
  context.append(f"Identified key entities: {key_entities}")
413
  intermediate_output += f"Identified key entities for focused research: {key_entities}\n"
414
 
 
415
  entity_progress = {entity: {'queries': [], 'insights': []} for entity in key_entities}
416
+ entity_progress['general'] = {'queries': [], 'insights': []}
417
 
418
  for i in range(MAX_ITERATIONS):
 
419
  if key_entities and i > 0:
 
420
  entities_to_process = key_entities + ['general']
421
  current_entity = entities_to_process[i % len(entities_to_process)]
422
  else:
 
424
 
425
  context.append(f"Current focus: {current_entity}")
426
 
 
427
  if i == 0:
428
  initial_query = tool_generate_search_query(prompt=prompt)
429
  if initial_query:
 
447
  failed_queries.append(initial_query)
448
  context.append(f"Initial query yielded no relevant results: {initial_query}")
449
 
 
450
  elif current_entity != 'general':
451
  entity_query = tool_generate_search_query(
452
  prompt=f"{prompt} focusing specifically on {current_entity}",
 
458
  previous_queries.append(entity_query)
459
  entity_progress[current_entity]['queries'].append(entity_query)
460
 
 
461
  search_results = tool_search_web(query=entity_query)
462
  filtered_search_results = filter_results(search_results,
463
  f"{prompt} {current_entity}",
464
  previous_snippets=seen_snippets)
465
 
 
466
  for result in filtered_search_results:
467
  seen_snippets.add(result['snippet'])
468
 
469
  if filtered_search_results:
470
  context.append(f"Entity Search for {current_entity}: {len(filtered_search_results)} results")
471
 
 
472
  entity_reasoning = tool_reason(
473
  prompt=f"{prompt} focusing on {current_entity}",
474
  search_results=filtered_search_results,
 
480
  all_insights.append(entity_reasoning)
481
  entity_progress[current_entity]['insights'].append(entity_reasoning)
482
 
 
483
  if current_entity not in entity_specific_insights:
484
  entity_specific_insights[current_entity] = []
485
  entity_specific_insights[current_entity].append(entity_reasoning)
 
489
  failed_queries.append(entity_query)
490
  context.append(f"Entity query for {current_entity} yielded no relevant results")
491
 
 
492
  llm_prompt = create_prompt(task_description, prompt, tools, context)
493
+ llm_response = hf_inference(MAIN_LLM_MODEL, llm_prompt)
494
 
495
  if isinstance(llm_response, dict) and "error" in llm_response:
496
  intermediate_output += f"LLM Error: {llm_response['error']}\n"
 
514
 
515
  if not tool_name:
516
  if all_insights:
517
+ if i > MAX_ITERATIONS // 2:
 
518
  break
519
  continue
520
 
 
574
  prompt if current_entity == 'general' else f"{prompt} {current_entity}",
575
  previous_snippets=seen_snippets)
576
 
 
577
  for r in filtered_result:
578
  seen_snippets.add(r['snippet'])
579
 
 
603
  elif tool_name == "identify_contradictions":
604
  result = tool["function"](**parameters)
605
  if result:
606
+ contradictions = result
607
  context.append(f"Identified contradictions: {result}")
608
 
609
  elif tool_name == "identify_focus_areas":
 
611
  parameters['failed_areas'] = failed_areas
612
  result = tool["function"](**parameters)
613
  if result:
 
614
  old_focus = set(focus_areas)
615
  focus_areas = result
616
  failed_areas.extend([area for area in old_focus if area not in result])
 
623
  parameters['prompt'] = prompt
624
  result = tool["function"](**parameters)
625
  if result:
626
+ all_insights.append(result)
627
  context.append(f"Meta-analysis across entities: {result[:200]}...")
628
 
629
  else:
630
  result = tool["function"](**parameters)
631
 
 
632
  result_str = str(result)
633
  if len(result_str) > 500:
634
  result_str = result_str[:500] + "..."
635
 
636
  intermediate_output += f"Iteration {i+1} - Result: {result_str}\n"
637
 
 
638
  result_context = result_str
639
+ if len(result_str) > 300:
640
  result_context = result_str[:300] + "..."
641
  context.append(f"Used: {tool_name}, Result: {result_context}")
642
 
643
  except Exception as e:
644
  logger.error(f"Error with {tool_name}: {str(e)}")
645
  context.append(f"Error with {tool_name}: {str(e)}")
646
+ intermediate_output += f"Iteration {i+1} - Error: {str(e)}\n"
647
  continue
648
 
 
649
  if len(entity_specific_insights) > 1 and len(all_insights) > 2:
650
  meta_analysis = tool_meta_analyze(entity_insights=entity_specific_insights, prompt=prompt)
651
  if meta_analysis:
652
  all_insights.append(meta_analysis)
653
  intermediate_output += f"Final Meta-Analysis: {meta_analysis[:500]}...\n"
654
 
 
655
  if all_insights:
656
  final_result = tool_summarize(all_insights, prompt, contradictions)
657
  else:
658
  final_result = "Could not find meaningful information despite multiple attempts."
659
 
 
660
  full_output = f"**Research Prompt:** {prompt}\n\n"
661
 
662
  if key_entities:
 
672
 
673
  full_output += f"**Final Analysis:**\n{final_result}\n\n"
674
 
 
675
  full_output += f"Research Session ID: {research_session_id}\n"
676
  full_output += f"Completed at: {datetime.now().strftime('%Y-%m-%d %H:%M:%S')}\n"
677
  full_output += f"Total iterations: {i+1}\n"
 
721
  ["How has artificial intelligence influenced medical diagnostics in the past five years, and what are the ethical considerations?"]
722
  ],
723
  theme="default",
724
+ cache_examples=False,
725
  css=custom_css,
726
  flagging_mode='never',
727
  analytics_enabled=False,
 
734
  <p>Results should be verified with additional sources. Not suitable for medical, legal, or emergency use.</p>
735
  </div>
736
  """
737
+
738
 
739
  # Launch the interface
740
  iface.launch(share=False)