diff --git a/searx/result_types/__init__.py b/searx/result_types/__init__.py index e9a115ec3..8a82cf8d4 100644 --- a/searx/result_types/__init__.py +++ b/searx/result_types/__init__.py @@ -13,14 +13,14 @@ from __future__ import annotations -__all__ = ["Result", "MainResult", "KeyValue", "EngineResults", "AnswerSet", "Answer", "Translations"] +__all__ = ["Result", "MainResult", "KeyValue", "EngineResults", "AnswerSet", "Answer", "Translations", "Weather"] import abc from searx import enginelib from ._base import Result, MainResult, LegacyResult -from .answer import AnswerSet, Answer, Translations +from .answer import AnswerSet, Answer, Translations, Weather from .keyvalue import KeyValue @@ -35,6 +35,7 @@ class ResultList(list, abc.ABC): MainResult = MainResult Result = Result Translations = Translations + Weather = Weather # for backward compatibility LegacyResult = LegacyResult diff --git a/searx/result_types/answer.py b/searx/result_types/answer.py index a9f580e0e..d5793fac3 100644 --- a/searx/result_types/answer.py +++ b/searx/result_types/answer.py @@ -18,6 +18,10 @@ template. :members: :show-inheritance: +.. autoclass:: Weather + :members: + :show-inheritance: + .. autoclass:: AnswerSet :members: :show-inheritance: @@ -26,7 +30,7 @@ template. from __future__ import annotations -__all__ = ["AnswerSet", "Answer", "Translations"] +__all__ = ["AnswerSet", "Answer", "Translations", "Weather"] import msgspec @@ -143,3 +147,51 @@ class Translations(BaseAnswer, kw_only=True): synonyms: list[str] = [] """List of synonyms for the requested translation.""" + + +class Weather(BaseAnswer, kw_only=True): + """Answer type for weather data.""" + + template: str = "answer/weather.html" + """The template is located at :origin:`answer/weather.html + `""" + + location: str + """The geo-location the weather data is from (e.g. `Berlin, Germany`).""" + + current: Weather.DataItem + """Current weather at ``location``.""" + + forecasts: list[Weather.DataItem] = [] + """Weather forecasts for ``location``.""" + + def __post_init__(self): + if not self.location: + raise ValueError("Weather answer is missing a location") + + class DataItem(msgspec.Struct, kw_only=True): + """A container for weather data such as temperature, humidity, ...""" + + time: str | None = None + """Time of the forecast - not needed for the current weather.""" + + condition: str + """Weather condition, e.g. `cloudy`, `rainy`, `sunny` ...""" + + temperature: str + """Temperature string, e.g. `17°C`""" + + feelsLike: str | None = None + """Felt temperature string, should be formatted like ``temperature``""" + + humidity: str | None = None + """Humidity percentage string, e.g. `60%`""" + + pressure: str | None = None + """Pressure string, e.g. `1030hPa`""" + + wind: str | None = None + """Information about the wind, e.g. `W, 231°, 10 m/s`""" + + attributes: dict[str] = [] + """Key-Value dict of additional weather attributes that are not available above""" diff --git a/searx/templates/simple/answer/weather.html b/searx/templates/simple/answer/weather.html new file mode 100644 index 000000000..4cea9b683 --- /dev/null +++ b/searx/templates/simple/answer/weather.html @@ -0,0 +1,67 @@ +{% macro show_weather_data(data) %} + + + {%- if data.condition -%} + + + + + {%- endif -%} + {%- if data.temperature -%} + + + + + {%- endif -%} + {%- if data.feelsLike -%} + + + + + {%- endif -%} + {%- if data.wind -%} + + + + + {%- endif -%} + {%- if data.humidity -%} + + + + + {%- endif -%} + {%- if data.pressure -%} + + + + + {%- endif -%} + + {%- for name, value in data.attributes.items() -%} + + + + + {%- endfor -%} + +
{{ _("Condition") }}{{ data.condition }}
{{ _("Temperature") }}{{ data.temperature }}
{{ _("Feels Like") }}{{ data.feelsLike }}
{{ _("Wind") }}{{ data.wind }}
{{ _("Humidity") }}{{ data.humidity }}
{{ _("Pressure") }}{{ data.pressure }}
{{ name }}{{ value }}
+{% endmacro %} + +
+ It's currently {{ answer.current.condition }}, {{ answer.current.temperature }} in {{ answer.location }} +
+

{{ answer.location }}

+

{{ _("Current condition") }}

+ {{ show_weather_data(answer.current) }} + + {%- if answer.forecasts -%} +
+ {%- for forecast in answer.forecasts -%} +

{{ forecast.time }}

+ {{ show_weather_data(forecast) }} + {%- endfor -%} +
+ {%- endif -%} +
+