"""
.. _NumericalEntity:
Numerical Entity
============
Provides the entity class for representing numbers in natural language. This entity is obtained via :ref:`DucklingPlugin<DucklingPlugin>`.
Plugin Walkthrough
------------------
.. ipython::
In [1]: from dialogy.plugins import DucklingPlugin
In [2]: duckling_plugin = DucklingPlugin(
...: dest="output.entities",
...: dimensions=["number"],
...: locale="en_IN",
...: timezone="Asia/Kolkata",
...: )
In [3]: duckling_plugin.parse("12")
In [4]: duckling_plugin.parse("twenty two")
Workflow Integration
--------------------
.. ipython::
In [1]: from dialogy.base import Input
...: from dialogy.plugins import DucklingPlugin
...: from dialogy.workflow import Workflow
In [2]: duckling_plugin = DucklingPlugin(
...: dest="output.entities",
...: dimensions=["number"],
...: locale="en_IN",
...: timezone="Asia/Kolkata",
...: )
In [3]: workflow = Workflow([duckling_plugin])
In [4]: _, output = workflow.run(Input(utterances=["seventy two", "4 fruits"]))
In [5]: output
CASTING
--------
We have noticed that there is a need to cast numerical values to time. The :ref:`as_time<number_entity_as_time>` method can be used to do this.
The default assumption is to use the number as :code:`day` but we can also replace the :code:`month` and :code:`hour`.
.. ipython::
In [1]: import pytz
...: from datetime import datetime
...: from dialogy.workflow import Workflow
...: from dialogy.base import Input
...: from dialogy.types import Intent
...: from dialogy.plugins import DucklingPlugin
...: from dialogy.utils import dt2timestamp
In [2]: duckling_plugin = DucklingPlugin(
...: dest="output.entities",
...: dimensions=["number"],
...: locale="en_IN",
...: timezone="Asia/Kolkata",
...: )
In [3]: reference_dt = datetime(2022, 1, 1, 12, 0, 0, tzinfo=pytz.timezone("Asia/Kolkata"))
...: reference_time = dt2timestamp(reference_dt)
In [4]: entities = duckling_plugin.parse("12")
In [5]: [entity.as_time(reference_time, "Asia/Kolkata") for entity in entities]
"""
from __future__ import annotations
from datetime import datetime
from typing import Any, Dict, Optional
import attr
from dialogy import constants as const
from dialogy.types.entity.base_entity import BaseEntity
from dialogy.types.entity.deserialize import EntityDeserializer
from dialogy.types.entity.time import TimeEntity
from dialogy.utils import unix_ts_to_datetime
[docs]@EntityDeserializer.register(const.NUMBER)
@attr.s
class NumericalEntity(BaseEntity):
"""
Numerical Entity Type
Use this type for handling all entities that can be parsed to obtain:
- numbers
- date
- time
- datetime
Attributes:
- `dim` dimension of the entity from duckling parser
- `type` is the type of the entity which can have values in ["value", "interval"]
"""
origin = attr.ib(
type=str, default="value", validator=attr.validators.instance_of(str)
)
entity_type: Optional[str] = attr.ib(default=const.NUMBER, order=False)
[docs] @classmethod
def from_duckling(
cls, d: Dict[str, Any], alternative_index: int, **kwargs: Any
) -> NumericalEntity:
value = d[const.VALUE][const.VALUE]
return cls(
range={const.START: d[const.START], const.END: d[const.END]},
body=d[const.BODY],
dim=d[const.DIM],
alternative_index=alternative_index,
values=[{const.VALUE: value}],
latent=d[const.LATENT],
)
[docs] def as_time(
self, reference_unix_ts: int, timezone: str, replace: str = "day"
) -> TimeEntity:
"""
Converts a duration entity to a time entity.
.. _number_entity_as_time:
"""
reference_datetime: datetime = unix_ts_to_datetime(
reference_unix_ts, timezone=timezone
)
if replace not in [const.HOUR, const.DAY, const.MONTH]:
raise RuntimeError(
f"Expected replace to be one of {[const.HOUR, const.DAY, const.MONTH]}"
)
value = reference_datetime.replace(**{replace: self.value}).isoformat()
entity = TimeEntity(
range={
const.START: self.range[const.START],
const.END: self.range[const.END],
},
body=self.body,
score=self.score,
dim="time",
alternative_index=self.alternative_index,
latent=self.latent,
values=[{const.VALUE: value}],
grain=replace,
)
entity.set_entity_type()
return entity