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
10+ \ ```yaml
1111engines:
1212 - name: selfhosted
1313 engine: dashboard_services
1818 enable_http: true
1919 enable_http2: true
2020 weight: 0.5 # Higher priority than regular search engines
21- ```
21+ \ ```
2222
2323For use with https://github.com/searxng/searxng
2424"""
4040}
4141
4242# Engine configuration
43- engine_type = " online"
44- categories = [" general" ]
43+ engine_type = ' online'
44+ categories = [' general' ]
4545disabled = False
4646timeout = 10.0
4747paging = False
5050# API endpoint
5151base_url = f"{ HOMEPAGE_BASE_URL } /api/services"
5252
53+ # Store the current query
54+ _current_query = ""
5355
5456def request (query , params ):
5557 """Build the request parameters for the dashboard services API."""
56- params ["url" ] = base_url
57- params ["method" ] = "GET"
58- params ["headers" ] = {
59- "Accept" : "application/json" ,
60- "User-Agent" : "SearXNG Dashboard Services Engine" ,
58+ global _current_query
59+ _current_query = query .lower () # Store for filtering in response
60+
61+ params ['url' ] = base_url
62+ params ['method' ] = 'GET'
63+ params ['headers' ] = {
64+ 'Accept' : 'application/json' ,
65+ 'User-Agent' : 'SearXNG Dashboard Services Engine'
6166 }
6267 return params
6368
64-
65- def response (resp ) -> EngineResults :
69+ def response (resp ):
6670 """Parse the API response and return search results."""
67- results = EngineResults ()
71+ global _current_query
72+ results = []
6873
6974 try :
7075 # Check if response is empty
@@ -75,49 +80,90 @@ def response(resp) -> EngineResults:
7580 # Parse JSON response
7681 json_data = loads (resp .text )
7782
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
83+ # Get the query for filtering
84+ query = _current_query
85+ if not query :
86+ print ("Dashboard Services Engine: No query available" )
87+ return results # No query, no results
88+
89+ # Collect all matching services with their scores
90+ matched_services = []
8391
8492 # Process each group in the response
8593 for group in json_data :
86- group_name = group .get (" name" , " Unknown Group" )
94+ group_name = group .get (' name' , ' Unknown Group' )
8795
8896 # Process direct services
89- if "services" in group :
90- for service in group ["services" ]:
91- results .append (_create_service_result (service , group_name ))
97+ if 'services' in group :
98+ for service in group ['services' ]:
99+ score = _calculate_match_score (service , group_name , query )
100+ if score > 0 : # Only include if there's a match
101+ matched_services .append ({
102+ 'service' : service ,
103+ 'group_name' : group_name ,
104+ 'score' : score
105+ })
92106
93107 # Process nested groups
94- if "groups" in group :
95- for subgroup in group ["groups" ]:
96- subgroup_name = subgroup .get ("name" , "Unknown Subgroup" )
97- if "services" in subgroup :
98- for service in subgroup ["services" ]:
99- results .append (
100- _create_service_result (
101- service , f"{ group_name } > { subgroup_name } "
102- )
103- )
108+ if 'groups' in group :
109+ for subgroup in group ['groups' ]:
110+ subgroup_name = subgroup .get ('name' , 'Unknown Subgroup' )
111+ if 'services' in subgroup :
112+ for service in subgroup ['services' ]:
113+ score = _calculate_match_score (service , f"{ group_name } > { subgroup_name } " , query )
114+ if score > 0 : # Only include if there's a match
115+ matched_services .append ({
116+ 'service' : service ,
117+ 'group_name' : f"{ group_name } > { subgroup_name } " ,
118+ 'score' : score
119+ })
120+
121+ # Sort by score (highest first)
122+ matched_services .sort (key = lambda x : x ['score' ], reverse = True )
123+
124+ # Create results from sorted matches
125+ for match in matched_services :
126+ results .append (_create_service_result (match ['service' ], match ['group_name' ]))
104127
105128 except Exception as e :
106129 print (f"Dashboard Services Engine Error: { e } " )
107- print (
108- f"Response content: { resp .text [:200 ]} ..."
109- ) # Show first 200 chars for debugging
130+ print (f"Response content: { resp .text [:200 ]} ..." ) # Show first 200 chars for debugging
110131
111132 return results
112133
134+ def _calculate_match_score (service , group_name , query ):
135+ """Calculate a relevance score based on where the query matches."""
136+ score = 0
137+
138+ # Get the values to check, converting to lowercase and handling None values
139+ name = (service .get ('name' , '' ) or '' ).lower ()
140+ description = (service .get ('description' , '' ) or '' ).lower ()
141+ server = (service .get ('server' , '' ) or '' ).lower ()
142+ container = (service .get ('container' , '' ) or '' ).lower ()
143+ group_name = (group_name or '' ).lower ()
144+
145+ # Check for matches in different fields with different weights
146+ if query in name :
147+ score += 10 # Highest weight for name match
148+ if query in description :
149+ score += 5 # Medium weight for description match
150+ if query in server :
151+ score += 2 # Lower weight for server/container matches
152+ if query in container :
153+ score += 2
154+ if query in group_name :
155+ score += 3 # Medium-low weight for group match
156+
157+ return score
113158
114159def _create_service_result (service , group_name ):
115160 """Create a search result from a service object."""
116- name = service .get ("name" , "Unknown Service" )
117- description = service .get ("description" , "No description available" )
118- href = service .get ("href" , "#" )
119- server = service .get ("server" , "" )
120- container = service .get ("container" , "" )
161+ name = service .get ('name' , 'Unknown Service' )
162+ description = service .get ('description' , 'No description available' )
163+ href = service .get ('href' , '#' )
164+ server = service .get ('server' , '' )
165+ container = service .get ('container' , '' )
166+ icon = service .get ('icon' , '' )
121167
122168 # Simple content creation
123169 content = description
@@ -126,9 +172,18 @@ def _create_service_result(service, group_name):
126172 if container :
127173 content += f" | Container: { container } "
128174
129- return {
130- "url" : href ,
131- "title" : f"{ name } ({ group_name } )" ,
132- "content" : content ,
133- "category" : "dashboard_services" ,
175+ result = {
176+ 'url' : href ,
177+ 'title' : f"{ name } ({ group_name } )" ,
178+ 'content' : content ,
134179 }
180+
181+ # Add icon if available
182+ if icon :
183+ if icon .startswith ('http' ):
184+ result ['img_src' ] = icon
185+ elif icon .startswith ('/' ):
186+ # Local icon path
187+ result ['img_src' ] = f"{ HOMEPAGE_BASE_URL } { icon } "
188+
189+ return result
0 commit comments