diff --git a/ai_answers.py b/ai_answers.py index 72e8bb8..38097a0 100644 --- a/ai_answers.py +++ b/ai_answers.py @@ -183,7 +183,7 @@ INTERACTIVE_HTML = ''' ''' -CITATION_HELPER_JS = ''' +CITATION_HELPER_JS = r''' function renderCitations(text, urls) { const fragment = document.createDocumentFragment(); const re = /\[(\d{1,2}(?:\s*,\s*\d{1,2})*)\]/g; @@ -237,7 +237,7 @@ CITATION_HELPER_JS = ''' } ''' -INTERACTIVE_JS = ''' +INTERACTIVE_JS = r''' const footer = document.getElementById('sxng-footer'); const input = document.getElementById('sxng-action-input'); // Inherited from outer scope: box, data, conversation @@ -572,13 +572,23 @@ class SXNGPlugin(Plugin): results = [] limit = self.context_deep_count + self.context_shallow_count for r in raw_results[:limit]: - results.append({ - 'title': r.get('title', ''), - 'content': r.get('content', ''), - 'url': r.get('url', ''), - 'publishedDate': r.get('publishedDate', '') - }) - + # Handle both MainResult (attribute access) and LegacyResult (dict access) + if hasattr(r, 'title'): + results.append({ + 'title': getattr(r, 'title', ''), + 'content': getattr(r, 'content', ''), + 'url': getattr(r, 'url', ''), + 'publishedDate': getattr(r, 'publishedDate', '') + }) + else: + # Legacy dictionary-style access + results.append({ + 'title': r.get('title', ''), + 'content': r.get('content', ''), + 'url': r.get('url', ''), + 'publishedDate': r.get('publishedDate', '') + }) + # SearXNG already merges infoboxes by ID - take first with full content infoboxes = [] for ib in raw_infoboxes[:1]: @@ -875,9 +885,7 @@ class SXNGPlugin(Plugin): generator = stream_gemini if self.is_gemini else stream_openai_compatible - # If configured, force-unload Ollama model right after finishing the stream. - - # This uses the native /api/chat endpoint with keep_alive=0. + # Force-unload Ollama model after stream via keep_alive=0 if self.provider == 'ollama' and getattr(self, 'ollama_unload_after', False): @@ -934,13 +942,13 @@ class SXNGPlugin(Plugin): # Deep sources: full content deep_lines = [] for i, r in enumerate(raw_results[:self.context_deep_count]): - url = r.get('url', '') + url = getattr(r, 'url', '') if hasattr(r, 'url') else r.get('url', '') result_urls.append(url) domain = urlparse(url).netloc.replace('www.', '') - date = r.get('publishedDate') + date = getattr(r, 'publishedDate', '') if hasattr(r, 'publishedDate') else r.get('publishedDate') date_str = f" ({date})" if date else "" - title = (r.get('title') or "").replace('\n', ' ').strip() - content = str(r.get('content', '')).replace('\n', ' ').strip()[:800] + title = (getattr(r, 'title', '') if hasattr(r, 'title') else r.get('title') or "").replace('\n', ' ').strip() + content = str(getattr(r, 'content', '') if hasattr(r, 'content') else r.get('content', '')).replace('\n', ' ').strip()[:800] idx = i + 1 + offset deep_lines.append(f"[{idx}] {domain}{date_str}: {title}: {content}") @@ -953,10 +961,10 @@ class SXNGPlugin(Plugin): start_idx = self.context_deep_count end_idx = self.context_deep_count + self.context_shallow_count for i, r in enumerate(raw_results[start_idx:end_idx]): - url = r.get('url', '') + url = getattr(r, 'url', '') if hasattr(r, 'url') else r.get('url', '') result_urls.append(url) domain = urlparse(url).netloc.replace('www.', '') - title = (r.get('title') or '').replace('\n', ' ').strip()[:60] + title = (getattr(r, 'title', '') if hasattr(r, 'title') else r.get('title') or '').replace('\n', ' ').strip()[:60] idx = i + 1 + start_idx + offset shallow_lines.append(f"[{idx}] {domain}: {title}") @@ -1002,7 +1010,7 @@ class SXNGPlugin(Plugin): js_q = json.dumps(q_clean) js_lang = json.dumps(lang) total_context_count = self.context_deep_count + self.context_shallow_count - js_urls = json.dumps([r.get('url') for r in raw_results[:total_context_count]]) + js_urls = json.dumps([getattr(r, 'url', '') if hasattr(r, 'url') else r.get('url', '') for r in raw_results[:total_context_count]]) is_interactive = self.interactive @@ -1015,7 +1023,7 @@ class SXNGPlugin(Plugin): stream_q = 'overrideQ || q_init' if is_interactive else 'q_init' stream_body = f'''prev_answer: prevAnswer''' if is_interactive else '' - html_payload = f''' + html_payload = rf'''