diff --git a/python/searxng-addons/dashboard_services.py b/python/searxng-addons/dashboard_services.py index 5decc02..f6c6110 100644 --- a/python/searxng-addons/dashboard_services.py +++ b/python/searxng-addons/dashboard_services.py @@ -7,7 +7,7 @@ 1. Copy file to `/usr/local/searxng/searx/engines/dashboard_services.py` 2. Add the following configuration to your `settings.yml` file: -```yaml +\```yaml engines: - name: selfhosted engine: dashboard_services @@ -18,7 +18,7 @@ enable_http: true enable_http2: true weight: 0.5 # Higher priority than regular search engines -``` +\``` For use with https://github.com/searxng/searxng """ @@ -40,8 +40,8 @@ } # Engine configuration -engine_type = "online" -categories = ["general"] +engine_type = 'online' +categories = ['general'] disabled = False timeout = 10.0 paging = False @@ -50,21 +50,28 @@ # API endpoint base_url = f"{HOMEPAGE_BASE_URL}/api/services" +# Store the current query +_current_query = "" + def request(query, params): """Build the request parameters for the dashboard services API.""" - params["url"] = base_url - params["method"] = "GET" - params["headers"] = { - "Accept": "application/json", - "User-Agent": "SearXNG Dashboard Services Engine", + global _current_query + _current_query = query.lower() # Store for filtering in response + + params['url'] = base_url + params['method'] = 'GET' + params['headers'] = { + 'Accept': 'application/json', + 'User-Agent': 'SearXNG Dashboard Services Engine' } return params -def response(resp) -> EngineResults: +def response(resp): """Parse the API response and return search results.""" - results = EngineResults() + global _current_query + results = [] try: # Check if response is empty @@ -75,49 +82,95 @@ def response(resp) -> EngineResults: # Parse JSON response json_data = loads(resp.text) - # Get query from the original request (simplified) - query = "" - if hasattr(resp, "url") and "?" in str(resp.url): - # Try to extract query from URL params if available - pass + # Get the query for filtering + query = _current_query + if not query: + print("Dashboard Services Engine: No query available") + return results # No query, no results + + # Collect all matching services with their scores + matched_services = [] # Process each group in the response for group in json_data: - group_name = group.get("name", "Unknown Group") + group_name = group.get('name', 'Unknown Group') # Process direct services - if "services" in group: - for service in group["services"]: - results.append(_create_service_result(service, group_name)) + if 'services' in group: + for service in group['services']: + score = _calculate_match_score(service, group_name, query) + if score > 0: # Only include if there's a match + matched_services.append({ + 'service': service, + 'group_name': group_name, + 'score': score + }) # Process nested groups - if "groups" in group: - for subgroup in group["groups"]: - subgroup_name = subgroup.get("name", "Unknown Subgroup") - if "services" in subgroup: - for service in subgroup["services"]: - results.append( - _create_service_result( - service, f"{group_name} > {subgroup_name}" - ) - ) + if 'groups' in group: + for subgroup in group['groups']: + subgroup_name = subgroup.get('name', 'Unknown Subgroup') + if 'services' in subgroup: + for service in subgroup['services']: + score = _calculate_match_score( + service, f"{group_name} > {subgroup_name}", query) + if score > 0: # Only include if there's a match + matched_services.append({ + 'service': service, + 'group_name': f"{group_name} > {subgroup_name}", + 'score': score + }) + + # Sort by score (highest first) + matched_services.sort(key=lambda x: x['score'], reverse=True) + + # Create results from sorted matches + for match in matched_services: + results.append(_create_service_result( + match['service'], match['group_name'])) except Exception as e: print(f"Dashboard Services Engine Error: {e}") - print( - f"Response content: {resp.text[:200]}..." - ) # Show first 200 chars for debugging + # Show first 200 chars for debugging + print(f"Response content: {resp.text[:200]}...") return results +def _calculate_match_score(service, group_name, query): + """Calculate a relevance score based on where the query matches.""" + score = 0 + + # Get the values to check, converting to lowercase and handling None values + name = (service.get('name', '') or '').lower() + description = (service.get('description', '') or '').lower() + server = (service.get('server', '') or '').lower() + container = (service.get('container', '') or '').lower() + group_name = (group_name or '').lower() + + # Check for matches in different fields with different weights + if query in name: + score += 10 # Highest weight for name match + if query in description: + score += 5 # Medium weight for description match + if query in server: + score += 2 # Lower weight for server/container matches + if query in container: + score += 2 + if query in group_name: + score += 3 # Medium-low weight for group match + + return score + + def _create_service_result(service, group_name): """Create a search result from a service object.""" - name = service.get("name", "Unknown Service") - description = service.get("description", "No description available") - href = service.get("href", "#") - server = service.get("server", "") - container = service.get("container", "") + name = service.get('name', 'Unknown Service') + description = service.get('description', 'No description available') + href = service.get('href', '#') + server = service.get('server', '') + container = service.get('container', '') + icon = service.get('icon', '') # Simple content creation content = description @@ -126,9 +179,18 @@ def _create_service_result(service, group_name): if container: content += f" | Container: {container}" - return { - "url": href, - "title": f"{name} ({group_name})", - "content": content, - "category": "dashboard_services", + result = { + 'url': href, + 'title': f"{name} ({group_name})", + 'content': content, } + + # Add icon if available + if icon: + if icon.startswith('http'): + result['img_src'] = icon + elif icon.startswith('/'): + # Local icon path + result['img_src'] = f"{HOMEPAGE_BASE_URL}{icon}" + + return result