Browse Source

[feat] result types: add weather result answerer and template

Bnyro 1 month ago
parent
commit
d70f0a3321

+ 3 - 2
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

+ 53 - 1
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
+    <searx/templates/simple/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"""

+ 67 - 0
searx/templates/simple/answer/weather.html

@@ -0,0 +1,67 @@
+{% macro show_weather_data(data) %}
+    <table>
+      <tbody>
+        {%- if data.condition -%}
+        <tr>
+          <td>{{ _("Condition") }}</td>
+          <td>{{ data.condition }}</td>
+        </tr>
+        {%- endif -%}
+        {%- if data.temperature -%}
+        <tr>
+          <td>{{ _("Temperature") }}</td>
+          <td>{{ data.temperature }}</td>
+        </tr>
+        {%- endif -%}
+        {%- if data.feelsLike -%}
+        <tr>
+          <td>{{ _("Feels Like") }}</td>
+          <td>{{ data.feelsLike }}</td>
+        </tr>
+        {%- endif -%}
+        {%- if data.wind -%}
+        <tr>
+          <td>{{ _("Wind") }}</td>
+          <td>{{ data.wind }}</td>
+        </tr>
+        {%- endif -%}
+        {%- if data.humidity -%}
+        <tr>
+          <td>{{ _("Humidity") }}</td>
+          <td>{{ data.humidity }}</td>
+        </tr>
+        {%- endif -%}
+        {%- if data.pressure -%}
+        <tr>
+          <td>{{ _("Pressure") }}</td>
+          <td>{{ data.pressure }}</td>
+        </tr>
+        {%- endif -%}
+        <tr>
+        {%- for name, value in data.attributes.items() -%}
+        <tr>
+          <td>{{ name }}</td>
+          <td>{{ value }}</td>
+        </tr>
+        {%- endfor -%}
+      </tbody>
+    </table>
+{% endmacro %}
+
+<details class="answer-weather">
+  <summary>It's currently {{ answer.current.condition }}, {{ answer.current.temperature }} in {{ answer.location }}</summary>
+  <div>
+    <h2 class="title">{{ answer.location }}</h2>
+    <h3>{{ _("Current condition") }}</h3>
+    {{ show_weather_data(answer.current) }}
+
+    {%- if answer.forecasts -%}
+    <div class="answer-weather-forecasts">
+      {%- for forecast in answer.forecasts -%}
+      <h3>{{ forecast.time }}</h3>
+      {{ show_weather_data(forecast) }}
+      {%- endfor -%}
+    </div>
+    {%- endif -%}
+  </div>
+</details>