Skip to content

Commit f5c724d

Browse files
committed
Add AI-powered LLM answer plugin for SearXNG
Introduces a new SearXNG plugin that generates contextual, AI-powered answers using LangChain and an LLM, with results formatted in Markdown and rendered via a custom HTML template. Updates the README with usage details and adds supporting documentation and image assets.
1 parent ebe27b2 commit f5c724d

File tree

7 files changed

+613
-2
lines changed

7 files changed

+613
-2
lines changed

README.md

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
<!-- Generated on 2025-07-16 09:14:32+00:00 -->
1+
<!-- Generated on 2025-08-02 05:15:44+00:00 -->
22

33
<!-- Do not edit this file. Edit README.md/base.md.j2 instead. -->
44
# Scripts
@@ -23,6 +23,7 @@ Got scripts? See [Contributing](.github/CONTRIBUTING.md).
2323

2424
| Title | Filename | Type | Description |
2525
| -------------------------------------- | ------------------------------------------------------------------------------------------------------ | ---------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ |
26+
| SearXNG AI Search Assist | [`dashboard_services.py`](python/searxng-addons/search_answers_llm/plugins_langchain_llm.py) | SearXNG Addon | Get instant, AI-powered answers summarized from top search results, displayed directly on the page. [**`Demo 🖼️`**](/docs/search_llm_assist.png) |
2627
| SearXNG Self-Hosted Service Index | [`dashboard_services.py`](python/searxng-addons/dashboard_services.py) | SearXNG Addon | Integrates with [`gethomepage/homepage`](https://github.com/gethomepage/homepage) to search through your self-hosted services and applications. [**`Demo 🖼️`**](/docs/searxng-homepage.png) |
2728
| LiteLLM Spend Tracker | [`openfaas-function/`](openfaas-function/README.md) | Serverless | Hierarchical spend visibility across multiple time horizons is provided by a time-segmented API cost tracker that aggregates LLM usage data. |
2829
| Portainer Service Recovery Function | [`openfaas-function/`](openfaas-function/README.md) | Serverless | On-demand service stack recovery solution that intelligently identifies and remediates service disruptions in Portainer-managed containers. |

docs/scripts.xls

512 Bytes
Binary file not shown.

docs/search_llm_assist.png

87.9 KB
Loading

docs/templates/scripts.md.j2

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
| Title | Filename | Type | Description |
22
| -------------------------------------- | ------------------------------------------------------------------------------------------------------ | ---------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ |
3+
| SearXNG AI Search Assist | [`dashboard_services.py`](python/searxng-addons/search_answers_llm/plugins_langchain_llm.py) | SearXNG Addon | Get instant, AI-powered answers summarized from top search results, displayed directly on the page. [**`Demo 🖼️`**](/docs/search_llm_assist.png) |
34
| SearXNG Self-Hosted Service Index | [`dashboard_services.py`](python/searxng-addons/dashboard_services.py) | SearXNG Addon | Integrates with [`gethomepage/homepage`](https://github.com/gethomepage/homepage) to search through your self-hosted services and applications. [**`Demo 🖼️`**](/docs/searxng-homepage.png) |
45
| LiteLLM Spend Tracker | [`openfaas-function/`](openfaas-function/README.md) | Serverless | Hierarchical spend visibility across multiple time horizons is provided by a time-segmented API cost tracker that aggregates LLM usage data. |
56
| Portainer Service Recovery Function | [`openfaas-function/`](openfaas-function/README.md) | Serverless | On-demand service stack recovery solution that intelligently identifies and remediates service disruptions in Portainer-managed containers. |

python/searxng-addons/README.md

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,13 @@ This repository contains custom engine implementations that extend SearXNG's cap
88

99
## 🔍 Available Engines
1010

11-
### 1. Homepage Dashboard Integration (`dashboard_services.py`)
11+
### 1. AI Search Assist (`search_answers_llm\plugins_langchain_llm.py`)
12+
13+
This SearXNG plugin generates contextual, AI-powered answers by hooking into the `post_search` process. It programmatically executes a secondary, targeted search against Google and DuckDuckGo using `SearchQuery` and `EngineRef` to gather real-time context for the user's query. This context is then sent to a LLM. The plugin injects this response as a custom `Answer` result type, overriding the default template to use a custom one with the `|safe` filter, ensuring the rich text is rendered correctly on the results page.
14+
15+
![SearXNG LLM Assist](/docs/search_llm_assist.png)
16+
17+
### 2. Homepage Dashboard Integration (`dashboard_services.py`)
1218

1319
Integrates with [`gethomepage/homepage`](https://github.com/gethomepage/homepage), a customizable home or startpage with Docker and service API support. This enables your home lab dashboard to become fully searchable using SearXNG.
1420

Lines changed: 211 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,211 @@
1+
<div class="llm-answer-container">
2+
<div class="llm-answer-content">
3+
{{ answer.answer|safe }}
4+
</div>
5+
6+
<style>
7+
.llm-answer-container {
8+
background: var(--color-answer-background);
9+
color: var(--color-answer-font);
10+
border-left: 4px solid var(--color-btn-background);
11+
padding: 16px;
12+
margin: 12px 0;
13+
border-radius: 6px;
14+
box-shadow: 0 2px 4px rgba(0, 0, 0, 0.1);
15+
border: 1px solid var(--color-result-border);
16+
}
17+
18+
/* Header styling */
19+
.llm-answer-container .llm-header {
20+
margin-bottom: 12px;
21+
display: flex;
22+
align-items: center;
23+
gap: 8px;
24+
}
25+
26+
.llm-answer-container .llm-header strong {
27+
color: var(--color-btn-background);
28+
}
29+
30+
.llm-answer-container .llm-header span {
31+
color: var(--color-base-font);
32+
opacity: 0.8;
33+
}
34+
35+
/* Content styling */
36+
.llm-answer-container .llm-content {
37+
margin-bottom: 12px;
38+
line-height: 1.6;
39+
}
40+
41+
/* Markdown-generated content styling using theme variables */
42+
.llm-answer-container h1,
43+
.llm-answer-container h2,
44+
.llm-answer-container h3,
45+
.llm-answer-container h4,
46+
.llm-answer-container h5,
47+
.llm-answer-container h6 {
48+
margin-top: 16px;
49+
margin-bottom: 8px;
50+
color: var(--color-answer-font);
51+
}
52+
53+
.llm-answer-container h2 {
54+
font-size: 1.2em;
55+
border-bottom: 1px solid var(--color-result-border);
56+
padding-bottom: 4px;
57+
}
58+
59+
.llm-answer-container h3 {
60+
font-size: 1.1em;
61+
}
62+
63+
.llm-answer-container ul,
64+
.llm-answer-container ol {
65+
margin: 8px 0;
66+
padding-left: 20px;
67+
}
68+
69+
.llm-answer-container li {
70+
margin: 4px 0;
71+
}
72+
73+
.llm-answer-container p {
74+
margin: 8px 0;
75+
line-height: 1.5;
76+
}
77+
78+
.llm-answer-container code {
79+
background: var(--color-doc-code-background);
80+
color: var(--color-doc-code);
81+
padding: 2px 4px;
82+
border-radius: 3px;
83+
font-family: 'Monaco', 'Menlo', 'Ubuntu Mono', monospace;
84+
font-size: 0.9em;
85+
}
86+
87+
.llm-answer-container pre {
88+
background: var(--color-doc-code-background);
89+
color: var(--color-doc-code);
90+
border: 1px solid var(--color-result-border);
91+
border-radius: 4px;
92+
padding: 12px;
93+
overflow-x: auto;
94+
margin: 12px 0;
95+
}
96+
97+
.llm-answer-container pre code {
98+
background: none;
99+
padding: 0;
100+
}
101+
102+
.llm-answer-container blockquote {
103+
border-left: 3px solid var(--color-btn-background);
104+
margin: 12px 0;
105+
padding-left: 12px;
106+
color: var(--color-base-font);
107+
font-style: italic;
108+
opacity: 0.9;
109+
}
110+
111+
.llm-answer-container strong {
112+
color: var(--color-answer-font);
113+
font-weight: 600;
114+
}
115+
116+
.llm-answer-container em {
117+
color: var(--color-base-font);
118+
opacity: 0.9;
119+
}
120+
121+
.llm-answer-container a {
122+
color: var(--color-result-link-font);
123+
text-decoration: underline;
124+
}
125+
126+
.llm-answer-container a:hover {
127+
color: var(--color-result-link-font-highlight);
128+
}
129+
130+
.llm-answer-container a:visited {
131+
color: var(--color-result-link-visited-font);
132+
}
133+
134+
/* Footer styling */
135+
.llm-answer-container .llm-footer {
136+
border-top: 1px solid var(--color-result-border);
137+
padding-top: 8px;
138+
margin-top: 12px;
139+
font-size: 0.85em;
140+
color: var(--color-base-font);
141+
display: flex;
142+
justify-content: space-between;
143+
align-items: center;
144+
flex-wrap: wrap;
145+
gap: 8px;
146+
}
147+
148+
.llm-answer-container .llm-footer .model-info {
149+
display: flex;
150+
align-items: center;
151+
gap: 12px;
152+
flex-wrap: wrap;
153+
}
154+
155+
.llm-answer-container .llm-footer .model-name {
156+
font-weight: 600;
157+
color: var(--color-answer-font);
158+
}
159+
160+
.llm-answer-container .llm-footer .disclaimer {
161+
opacity: 0.8;
162+
}
163+
164+
/* GitHub button styling with theme support */
165+
.llm-answer-container .github-link {
166+
display: inline-flex;
167+
align-items: center;
168+
background: var(--color-toolkit-badge-background);
169+
color: var(--color-toolkit-badge-font);
170+
padding: 4px 8px;
171+
border-radius: 4px;
172+
text-decoration: none;
173+
font-size: 0.8em;
174+
transition: all 0.2s ease;
175+
border: 1px solid var(--color-result-border);
176+
}
177+
178+
.llm-answer-container .github-link:hover {
179+
background: var(--color-btn-background);
180+
color: var(--color-btn-font);
181+
transform: translateY(-1px);
182+
text-decoration: none;
183+
}
184+
185+
.llm-answer-container .github-link svg {
186+
width: 16px;
187+
height: 16px;
188+
margin-right: 4px;
189+
fill: currentColor;
190+
transition: transform 0.2s ease;
191+
}
192+
193+
.llm-answer-container .github-link:hover svg {
194+
transform: scale(1.1);
195+
}
196+
197+
/* Responsive design */
198+
@media (max-width: 50em) {
199+
.llm-answer-container .llm-footer {
200+
flex-direction: column;
201+
align-items: flex-start;
202+
}
203+
204+
.llm-answer-container .llm-footer .model-info {
205+
flex-direction: column;
206+
align-items: flex-start;
207+
gap: 4px;
208+
}
209+
}
210+
</style>
211+
</div>

0 commit comments

Comments
 (0)