771. Copy file to `/usr/local/searxng/searx/engines/dashboard_services.py`
882. Add the following configuration to your `settings.yml` file:
99
10- ```yaml
1110engines:
1211 - name: selfhosted
1312 engine: dashboard_services
1817 enable_http: true
1918 enable_http2: true
2019 weight: 0.5 # Higher priority than regular search engines
21- ```
2220
2321For use with https://github.com/searxng/searxng
2422"""
2523
2624from json import loads
27- from searx .result_types import EngineResults
2825
2926# Point to your self-hosted homepage instance
3027HOMEPAGE_BASE_URL = "http://X.X.X.X:3000"
5047# API endpoint
5148base_url = f"{ HOMEPAGE_BASE_URL } /api/services"
5249
50+ # Store the current query
51+ _current_query = ""
52+
5353
5454def request (query , params ):
5555 """Build the request parameters for the dashboard services API."""
56+ global _current_query
57+ _current_query = query .lower () # Store for filtering in response
58+
5659 params ["url" ] = base_url
5760 params ["method" ] = "GET"
5861 params ["headers" ] = {
@@ -62,9 +65,10 @@ def request(query, params):
6265 return params
6366
6467
65- def response (resp ) -> EngineResults :
68+ def response (resp ):
6669 """Parse the API response and return search results."""
67- results = EngineResults ()
70+ global _current_query
71+ results = []
6872
6973 try :
7074 # Check if response is empty
@@ -75,11 +79,14 @@ def response(resp) -> EngineResults:
7579 # Parse JSON response
7680 json_data = loads (resp .text )
7781
78- # Get query from the original request (simplified)
79- query = ""
80- if hasattr (resp , "url" ) and "?" in str (resp .url ):
81- # Try to extract query from URL params if available
82- pass
82+ # Get the query for filtering
83+ query = _current_query
84+ if not query :
85+ print ("Dashboard Services Engine: No query available" )
86+ return results # No query, no results
87+
88+ # Collect all matching services with their scores
89+ matched_services = []
8390
8491 # Process each group in the response
8592 for group in json_data :
@@ -88,19 +95,42 @@ def response(resp) -> EngineResults:
8895 # Process direct services
8996 if "services" in group :
9097 for service in group ["services" ]:
91- results .append (_create_service_result (service , group_name ))
98+ score = _calculate_match_score (service , group_name , query )
99+ if score > 0 : # Only include if there's a match
100+ matched_services .append (
101+ {
102+ "service" : service ,
103+ "group_name" : group_name ,
104+ "score" : score ,
105+ }
106+ )
92107
93108 # Process nested groups
94109 if "groups" in group :
95110 for subgroup in group ["groups" ]:
96111 subgroup_name = subgroup .get ("name" , "Unknown Subgroup" )
97112 if "services" in subgroup :
98113 for service in subgroup ["services" ]:
99- results .append (
100- _create_service_result (
101- service , f"{ group_name } > { subgroup_name } "
102- )
114+ score = _calculate_match_score (
115+ service , f"{ group_name } > { subgroup_name } " , query
103116 )
117+ if score > 0 : # Only include if there's a match
118+ matched_services .append (
119+ {
120+ "service" : service ,
121+ "group_name" : f"{ group_name } > { subgroup_name } " ,
122+ "score" : score ,
123+ }
124+ )
125+
126+ # Sort by score (highest first)
127+ matched_services .sort (key = lambda x : x ["score" ], reverse = True )
128+
129+ # Create results from sorted matches
130+ for match in matched_services :
131+ results .append (
132+ _create_service_result (match ["service" ], match ["group_name" ])
133+ )
104134
105135 except Exception as e :
106136 print (f"Dashboard Services Engine Error: { e } " )
@@ -111,13 +141,40 @@ def response(resp) -> EngineResults:
111141 return results
112142
113143
144+ def _calculate_match_score (service , group_name , query ):
145+ """Calculate a relevance score based on where the query matches."""
146+ score = 0
147+
148+ # Get the values to check, converting to lowercase and handling None values
149+ name = (service .get ("name" , "" ) or "" ).lower ()
150+ description = (service .get ("description" , "" ) or "" ).lower ()
151+ server = (service .get ("server" , "" ) or "" ).lower ()
152+ container = (service .get ("container" , "" ) or "" ).lower ()
153+ group_name = (group_name or "" ).lower ()
154+
155+ # Check for matches in different fields with different weights
156+ if query in name :
157+ score += 10 # Highest weight for name match
158+ if query in description :
159+ score += 5 # Medium weight for description match
160+ if query in server :
161+ score += 2 # Lower weight for server/container matches
162+ if query in container :
163+ score += 2
164+ if query in group_name :
165+ score += 3 # Medium-low weight for group match
166+
167+ return score
168+
169+
114170def _create_service_result (service , group_name ):
115171 """Create a search result from a service object."""
116172 name = service .get ("name" , "Unknown Service" )
117173 description = service .get ("description" , "No description available" )
118174 href = service .get ("href" , "#" )
119175 server = service .get ("server" , "" )
120176 container = service .get ("container" , "" )
177+ icon = service .get ("icon" , "" )
121178
122179 # Simple content creation
123180 content = description
@@ -126,9 +183,18 @@ def _create_service_result(service, group_name):
126183 if container :
127184 content += f" | Container: { container } "
128185
129- return {
186+ result = {
130187 "url" : href ,
131188 "title" : f"{ name } ({ group_name } )" ,
132189 "content" : content ,
133- "category" : "dashboard_services" ,
134190 }
191+
192+ # Add icon if available
193+ if icon :
194+ if icon .startswith ("http" ):
195+ result ["img_src" ] = icon
196+ elif icon .startswith ("/" ):
197+ # Local icon path
198+ result ["img_src" ] = f"{ HOMEPAGE_BASE_URL } { icon } "
199+
200+ return result
0 commit comments