Spaces:
Running
Running
Update app.py
Browse files
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
|
| 107 |
-
|
| 108 |
-
|
| 109 |
-
|
| 110 |
-
with DDGS(
|
| 111 |
-
|
| 112 |
-
|
| 113 |
-
|
| 114 |
-
|
| 115 |
-
|
| 116 |
-
|
| 117 |
-
|
| 118 |
-
|
| 119 |
-
|
| 120 |
-
|
| 121 |
-
|
| 122 |
-
|
| 123 |
-
|
| 124 |
-
|
| 125 |
-
|
| 126 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 127 |
|
| 128 |
-
def format_results(
|
| 129 |
-
""
|
| 130 |
-
|
| 131 |
-
|
| 132 |
-
|
| 133 |
-
|
| 134 |
-
|
| 135 |
-
|
| 136 |
-
|
| 137 |
-
|
| 138 |
-
|
| 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 |
-
|
| 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 |
-
|
| 171 |
-
|
| 172 |
-
|
| 173 |
-
return results, None
|
| 174 |
else:
|
| 175 |
-
error_msg =
|
| 176 |
logger.warning(f"❌ Search failed: {error_msg}")
|
| 177 |
-
return
|
| 178 |
|
| 179 |
except Exception as e:
|
| 180 |
logger.error(f"⚠️ Global Search Error: {str(e)}")
|
| 181 |
-
return
|
| 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 |
-
|
| 416 |
-
if error and not
|
| 417 |
return jsonify({"response": error, "results": []})
|
| 418 |
-
if not
|
| 419 |
return jsonify({"response": "No results found.", "results": []})
|
| 420 |
|
| 421 |
return jsonify({
|
| 422 |
-
"response": format_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:
|