searxng/searx/answerers/__init__.py
Grant Lanham fed105b09e Implement models for searx/answerers
sort froms

Import List from typing to support Python 3.8

Use SearchQuery model

Remove list for List

use Dict instead of dict

Use RawTextQuery instead of SearchQuery, type a dict, and remove unecessary str() method in webapp

improve docstring, remove test code

Implement a BaseQuery class and use that, improve answerer tests based on updated types

Add back sys

fix new linting issues

add space

Update answerer.py - use dict

use future annotations

use BaseQuery for RawTextQuery
2024-03-19 19:54:13 -04:00

57 lines
1.8 KiB
Python

# SPDX-License-Identifier: AGPL-3.0-or-later
# pylint: disable=missing-module-docstring
from __future__ import annotations
import sys
from collections import defaultdict
from os import listdir
from os.path import realpath, dirname, join, isdir
from typing import Callable
from searx.answerers.models import AnswerModule, AnswerDict
from searx.search.models import BaseQuery
from searx.utils import load_module
answerers_dir = dirname(realpath(__file__))
def load_answerers() -> list[AnswerModule]:
answerers = [] # pylint: disable=redefined-outer-name
for filename in listdir(answerers_dir):
if not isdir(join(answerers_dir, filename)) or filename.startswith('_'):
continue
module = load_module('answerer.py', join(answerers_dir, filename))
if not hasattr(module, 'keywords') or not isinstance(module.keywords, tuple) or not module.keywords:
sys.exit(2)
answerers.append(module)
return answerers
def get_answerers_by_keywords(
answerers: list[AnswerModule], # pylint: disable=redefined-outer-name
) -> dict[str, list[Callable[[BaseQuery], list[AnswerDict]]]]:
by_keyword = defaultdict(list)
for answerer in answerers:
for keyword in answerer.keywords:
for keyword in answerer.keywords:
by_keyword[keyword].append(answerer.answer)
return by_keyword
def ask(query: BaseQuery) -> list[list[AnswerDict]]:
results: list[list[AnswerDict]] = []
query_parts = list(filter(None, query.query.split()))
if not query_parts or query_parts[0] not in answerers_by_keywords:
return results
for answerer in answerers_by_keywords[query_parts[0]]:
result = answerer(query)
if result:
results.append(result)
return results
answerers = load_answerers()
answerers_by_keywords = get_answerers_by_keywords(answerers)