umar8902 commited on
Commit
8998f83
·
verified ·
1 Parent(s): f82c7ef

Update app.py

Browse files
Files changed (1) hide show
  1. app.py +86 -68
app.py CHANGED
@@ -1,6 +1,7 @@
1
  import os
2
  import re
3
  import time
 
4
  import logging
5
  import io
6
  import json
@@ -103,82 +104,98 @@ def detect_tools(message):
103
  return tools
104
 
105
  # --- Internet Search Feature ---
106
- def web_search(query: str, max_results: int = 5) -> list:
107
- """Search the web using DuckDuckGo for free. No API key required."""
108
- try:
109
- # Added timeout to DDGS to prevent long hangs
110
- with DDGS(timeout=10) as ddgs:
111
- results = list(ddgs.text(query, max_results=max_results))
112
- return results
113
- except Exception as e:
114
- logger.error(f"Search failed: {str(e)}")
115
- return [{"error": f"Search failed: {str(e)}"}]
116
-
117
- def search_news(query: str, max_results: int = 5) -> list:
118
- """Search news using DuckDuckGo for free."""
119
- try:
120
- # Added timeout to DDGS to prevent long hangs
121
- with DDGS(timeout=10) as ddgs:
122
- results = list(ddgs.news(query, max_results=max_results))
123
- return results
124
- except Exception as e:
125
- logger.error(f"News search failed: {str(e)}")
126
- return [{"error": f"News search failed: {str(e)}"}]
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
127
 
128
- def format_results(results: list) -> str:
129
- """Format search results with citations."""
130
- try:
131
- if not results:
132
- return "No results found."
133
- if isinstance(results, list) and len(results) > 0 and isinstance(results[0], dict) and "error" in results[0]:
134
- return results[0]["error"]
135
-
136
- formatted = []
137
- # Ensure results is a list of dicts
138
- if not isinstance(results, list):
139
- return "Unexpected search result format."
140
-
141
- for i, r in enumerate(results, 1):
142
- if not isinstance(r, dict): continue
143
- title = r.get("title", "No title")
144
- url = r.get("href", r.get("url", "#"))
145
- body = r.get("body", r.get("snippet", "No description"))[:300]
146
- formatted.append(f"{i}. [{title}]({url})\n {body}")
147
-
148
- return "\n\n".join(formatted) if formatted else "No results found."
149
- except Exception as e:
150
- logger.error(f"Formatting failed: {e}")
151
- return f"Error formatting results: {str(e)}"
152
 
153
  def perform_search(query):
154
  try:
155
  # Clean query for better search results
156
  search_query = query.lower().replace('search for', '').replace('find out about', '').replace('/search', '').strip()
157
- logger.info(f"🔍 Searching for: {search_query}")
158
-
159
- # Try text search first
160
- results = web_search(search_query)
161
 
162
- # If no results or error, try news search as fallback
163
- if not results or (isinstance(results[0], dict) and "error" in results[0]):
164
- logger.info("Web search empty or failed, trying News search...")
165
- news_results = search_news(search_query)
166
- # If news search returned actual results, use them
167
- if news_results and not (isinstance(news_results[0], dict) and "error" in news_results[0]):
168
- results = news_results
169
 
170
- # Check if we have valid results now
171
- if results and isinstance(results[0], dict) and "error" not in results[0]:
172
- logger.info(f"✅ Found {len(results)} results")
173
- return results, None
174
  else:
175
- error_msg = results[0]["error"] if results and isinstance(results[0], dict) and "error" in results[0] else "No results found."
176
  logger.warning(f"❌ Search failed: {error_msg}")
177
- return [], error_msg
178
 
179
  except Exception as e:
180
  logger.error(f"⚠️ Global Search Error: {str(e)}")
181
- return [], str(e)
182
 
183
  # --- Image Generation Feature ---
184
  @app.route('/api/image', methods=['POST'])
@@ -412,15 +429,16 @@ def search_api():
412
  if not query:
413
  return jsonify({"error": "No query provided"}), 400
414
 
415
- results, error = perform_search(query)
416
- if error and not results:
417
  return jsonify({"response": error, "results": []})
418
- if not results:
419
  return jsonify({"response": "No results found.", "results": []})
420
 
421
  return jsonify({
422
- "response": format_results(results),
423
- "results": results,
 
424
  "status": "success"
425
  })
426
  except Exception as e:
 
1
  import os
2
  import re
3
  import time
4
+ import random
5
  import logging
6
  import io
7
  import json
 
104
  return tools
105
 
106
  # --- Internet Search Feature ---
107
+ def ddg_search(query, max_results=5):
108
+ try:
109
+ from duckduckgo_search import DDGS
110
+ time.sleep(random.uniform(1, 3))
111
+ with DDGS(headers={"User-Agent": "Mozilla/5.0 (X11; Linux x86_64)"}) as ddgs:
112
+ return list(ddgs.text(query, max_results=max_results))
113
+ except:
114
+ return []
115
+
116
+ def bing_search(query, max_results=5):
117
+ headers = {"User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.0"}
118
+ try:
119
+ url = f"https://www.bing.com/search?q={requests.utils.quote(query)}"
120
+ r = requests.get(url, headers=headers, timeout=10)
121
+ links = re.findall(r'<a[^>]*href="(https?://[^"]+)"[^>]*h="[^"]*"', r.text)
122
+ titles = re.findall(r'<a[^>]*href="https?://[^"]+"[^>]*h="[^"]*"[^>]*>(.*?)</a>', r.text)
123
+ results = []
124
+ for i in range(min(max_results, len(links))):
125
+ results.append({
126
+ "title": re.sub(r'<[^>]+>', '', titles[i]) if i < len(titles) else "No title",
127
+ "href": links[i],
128
+ "body": ""
129
+ })
130
+ return results
131
+ except:
132
+ return []
133
+
134
+ def wiki_search(query, max_results=3):
135
+ try:
136
+ url = "https://en.wikipedia.org/w/api.php"
137
+ params = {"action": "query", "list": "search", "srsearch": query, "format": "json", "srlimit": max_results}
138
+ r = requests.get(url, params=params, timeout=10)
139
+ data = r.json()
140
+ return [{"title": i["title"], "href": f"https://en.wikipedia.org/wiki/{i['title'].replace(' ', '_')}",
141
+ "body": i["snippet"].replace('<span class="searchmatch">', '').replace('</span>', '')}
142
+ for i in data["query"]["search"]]
143
+ except:
144
+ return []
145
+
146
+ def web_search(query, max_results=5):
147
+ # Try DDG
148
+ logger.info(f"🔍 Searching DDG: {query}")
149
+ ddg = ddg_search(query, max_results)
150
+ if ddg:
151
+ return {"engine": "DuckDuckGo", "results": ddg}
152
+
153
+ logger.warning("⚠️ DDG failed, trying Bing in 2s...")
154
+ time.sleep(2)
155
+ # Try Bing
156
+ bing = bing_search(query, max_results)
157
+ if bing:
158
+ return {"engine": "Bing", "results": bing}
159
+
160
+ logger.warning("⚠️ Bing failed, trying Wikipedia in 2s...")
161
+ time.sleep(2)
162
+ # Try Wikipedia
163
+ wiki = wiki_search(query, max_results)
164
+ if wiki:
165
+ return {"engine": "Wikipedia", "results": wiki}
166
+
167
+ return {"engine": "Failed", "results": [{"error": "All engines failed"}]}
168
 
169
+ def format_results(data):
170
+ if not data or not data.get("results") or (isinstance(data["results"][0], dict) and "error" in data["results"][0]):
171
+ return "No results found."
172
+
173
+ out = [f"Source: {data['engine']}\n"]
174
+ for i, r in enumerate(data["results"], 1):
175
+ title = r.get("title", "No title")
176
+ url = r.get("href", r.get("url", "#"))
177
+ body = r.get("body", r.get("snippet", ""))[:200]
178
+ out.append(f"{i}. [{title}]({url})\n {body}")
179
+ return "\n\n".join(out)
 
 
 
 
 
 
 
 
 
 
 
 
 
180
 
181
  def perform_search(query):
182
  try:
183
  # Clean query for better search results
184
  search_query = query.lower().replace('search for', '').replace('find out about', '').replace('/search', '').strip()
 
 
 
 
185
 
186
+ search_data = web_search(search_query)
 
 
 
 
 
 
187
 
188
+ if search_data["engine"] != "Failed":
189
+ logger.info(f"✅ Found {len(search_data['results'])} results via {search_data['engine']}")
190
+ return search_data, None
 
191
  else:
192
+ error_msg = search_data["results"][0].get("error", "All search engines failed.")
193
  logger.warning(f"❌ Search failed: {error_msg}")
194
+ return None, error_msg
195
 
196
  except Exception as e:
197
  logger.error(f"⚠️ Global Search Error: {str(e)}")
198
+ return None, str(e)
199
 
200
  # --- Image Generation Feature ---
201
  @app.route('/api/image', methods=['POST'])
 
429
  if not query:
430
  return jsonify({"error": "No query provided"}), 400
431
 
432
+ search_data, error = perform_search(query)
433
+ if error and not search_data:
434
  return jsonify({"response": error, "results": []})
435
+ if not search_data:
436
  return jsonify({"response": "No results found.", "results": []})
437
 
438
  return jsonify({
439
+ "response": format_results(search_data),
440
+ "results": search_data["results"],
441
+ "engine": search_data["engine"],
442
  "status": "success"
443
  })
444
  except Exception as e: