ó
    óó�jjN  ã                   óÆ   • S r SSKrSSKrSSKrSSKJr  SSKrSSKJr  SSK	J
r
Jr  SSKJr  SSKJr  SSKJr  \" \5      r " S	 S
\5      r " S S\5      rSS jrS rS rg)ziDataset examples for loading individual data points

Authors
  * Aku Rouhe 2020
  * Samuele Cornell 2020
é    N)Ú
MethodType)ÚDataset)Úload_data_csvÚload_data_json)ÚDataPipeline)Úbatch_shuffle)Ú
get_loggerc                   óô   • \ rS rSrSrSS jrS rS rSS jrSS jr	S	 r
\R                  S
 5       r0 0 0 SSS4S jr0 0 0 SSS4S jrS rS r\0 / / 4S j5       r\0 / / S4S j5       r\0 / / 4S j5       rSrg)ÚDynamicItemDataseté   a,  Dataset that reads, wrangles, and produces dicts.

Each data point dict provides some items (by key), for example, a path to a
wavefile with the key "wav_file". When a data point is fetched from this
Dataset, more items are produced dynamically, based on pre-existing items
and other dynamic created items. For example, a dynamic item could take the
wavfile path and load the audio from the disk.

The dynamic items can depend on other dynamic items: a suitable evaluation
order is used automatically,  as long as there are no circular dependencies.

A specified list of keys is collected in the output dict. These can be items
in the original data or dynamic items. If some dynamic items are not
requested, nor depended on by other requested items, they won't be computed.
So for example if a user simply wants to iterate over the text, the
time-consuming audio loading can be skipped.

About the format:
Takes a dict of dicts as the collection of data points to read/wrangle.
The top level keys are data point IDs.
Each data point (example) dict should have the same keys, corresponding to
different items in that data point.

Altogether the data collection could look like this:

>>> data = {
...     "spk1utt1": {
...         "wav_file": "/path/to/spk1utt1.wav",
...         "text": "hello world",
...         "speaker": "spk1",
...     },
...     "spk1utt2": {
...         "wav_file": "/path/to/spk1utt2.wav",
...         "text": "how are you world",
...         "speaker": "spk1",
...     },
... }

NOTE
----
    The top-level key, the data point id, is implicitly added as an item
    in the data point, with the key "id"

Each dynamic item is configured by three things: a key, a func, and a list
of argkeys. The key should be unique among all the items (dynamic or not) in
each data point. The func is any callable, and it returns the dynamic item's
value. The callable is called with the values of other items as specified
by the argkeys list (as positional args, passed in the order specified by
argkeys).

The dynamic_items configuration could look like this:

>>> import torch
>>> dynamic_items = [
...     {
...         "func": lambda l: torch.Tensor(l),
...         "takes": ["wav_loaded"],
...         "provides": "wav",
...     },
...     {
...         "func": lambda path: [
...             ord(c) / 100 for c in path
...         ],  # Fake "loading"
...         "takes": ["wav_file"],
...         "provides": "wav_loaded",
...     },
...     {
...         "func": lambda t: t.split(),
...         "takes": ["text"],
...         "provides": "words",
...     },
... ]

With these, different views of the data can be loaded:

>>> from speechbrain.dataio.dataloader import SaveableDataLoader
>>> from speechbrain.dataio.batch import PaddedBatch
>>> dataset = DynamicItemDataset(data, dynamic_items)
>>> dataloader = SaveableDataLoader(
...     dataset, collate_fn=PaddedBatch, batch_size=2
... )
>>> # First, create encoding for words:
>>> dataset.set_output_keys(["words"])
>>> encoding = {}
>>> next_id = 1
>>> for batch in dataloader:
...     for sent in batch.words:
...         for word in sent:
...             if word not in encoding:
...                 encoding[word] = next_id
...                 next_id += 1
>>> # Next, add an encoded words_tensor dynamic item:
>>> dataset.add_dynamic_item(
...     func=lambda ws: torch.tensor(
...         [encoding[w] for w in ws], dtype=torch.long
...     ),
...     takes=["words"],
...     provides="words_encoded",
... )
>>> # Now we can get word and audio tensors:
>>> dataset.set_output_keys(["id", "wav", "words_encoded"])
>>> batch = next(iter(dataloader))
>>> batch.id
['spk1utt1', 'spk1utt2']
>>> batch.wav  # +ELLIPSIS
PaddedData(data=tensor([[0.4700, 1.1200, ...
>>> batch.words_encoded
PaddedData(data=tensor([[1, 2, 0, 0],
        [3, 4, 5, 2]]), lengths=tensor([0.5000, 1.0000]))

Output keys can also be a map:

>>> dataset.set_output_keys(
...     {"id": "id", "signal": "wav", "words": "words_encoded"}
... )
>>> batch = next(iter(dataloader))
>>> batch.words
PaddedData(data=tensor([[1, 2, 0, 0],
        [3, 4, 5, 2]]), lengths=tensor([0.5000, 1.0000]))


Arguments
---------
data : dict
    Dictionary containing single data points (e.g. utterances).
dynamic_items : list, optional
    Configuration for the dynamic items produced when fetching an example.
    List of DynamicItems or dicts with the format::
        func: <callable> # To be called
        takes: <list> # key or list of keys of args this takes
        provides: key # key or list of keys that this provides
output_keys : dict, list, optional
    List of keys (either directly available in data or dynamic items)
    to include in the output dict when data points are fetched.

    If a dict is given; it is used to map internal keys to output keys.
    From the output_keys dict key:value pairs the key appears outside,
    and value is the internal key.
Nc                 ó`  • Uc  / nUc  / nXl         [        U R                   R                  5       5      U l        [        U R                   U R                  S      R                  5       5      nSU;   a  [	        S5      eUR                  S5        [        XB5      U l        U R                  U5        g )Nr   Úidz/The key 'id' is reserved for the data point id.)	ÚdataÚlistÚkeysÚdata_idsÚ
ValueErrorÚappendr   ÚpipelineÚset_output_keys)Úselfr   Údynamic_itemsÚoutput_keysÚstatic_keyss        Ú¨C:\Users\johnn\AppData\Local\Packages\PythonSoftwareFoundation.Python.3.13_qbz5n2kfra8p0\LocalCache\local-packages\Python313\site-packages\speechbrain/dataio/dataset.pyÚ__init__ÚDynamicItemDataset.__init__¥   s•   € ØÑ ØˆMØÑØˆKØŒ	Ü˜TŸY™YŸ^™^Ó-Ó.ˆŒÜ˜4Ÿ9™9 T§]¡]°1Ñ%5Ñ6×;Ñ;Ó=Ó>ˆØ�;ÓÜÐNÓOÐOà×Ñ˜tÔ$Ü$ [Ó@ˆŒØ×Ñ˜[Õ)ó    c                 ó,   • [        U R                  5      $ ©N)Úlenr   )r   s    r   Ú__len__ÚDynamicItemDataset.__len__´   s   € Ü�4—=‘=Ó!Ð!r   c                 ó|   • U R                   U   nU R                  U   nU R                  R                  SU0UE5      $ )Nr   )r   r   r   Úcompute_outputs)r   ÚindexÚdata_idÚ
data_points       r   Ú__getitem__ÚDynamicItemDataset.__getitem__·   s=   € Ø—-‘- Ñ&ˆØ—Y‘Y˜wÑ'ˆ
Ø�}‰}×,Ñ,¨d°GÐ-J¸zÐ-JÓKÐKr   c                 óØ   • U=(       d    U R                   R                  nU R                  U5         [        R                  " X(       + S9 H  nM     SSS5        g! , (       d  f       g= f)a‘  Iterates dataset once -- mainly used to warm up cache.

Arguments
---------
output_keys : Optional[list[str]]
    List of keys to use for the iteration, potentially useful for
    speeding up iterations when warming the cache is only needed on
    a subset of the slow keys and other slow keys should be ignored.
progressbar : bool
    Whether to add a tqdm progressbar for monitoring iteration time.
)ÚdisableN)r   Úoutput_mappingÚoutput_keys_asÚtqdm)r   r   ÚprogressbarÚitems       r   Úiterate_onceÚDynamicItemDataset.iterate_once¼   sM   € ð "×A T§]¡]×%AÑ%Aˆð × Ñ  Õ-ÜŸ	š	 $´Ô@�Ùñ A÷ .×-Ö-ús   ±!AÁ
A)c                 ó<   • U R                   R                  XU5        g)aŠ  Makes a new dynamic item available on the dataset.

Two calling conventions. For DynamicItem objects, just use:
add_dynamic_item(dynamic_item).
But otherwise, should use:
add_dynamic_item(func, takes, provides).

See `speechbrain.utils.data_pipeline`.

Arguments
---------
func : callable, DynamicItem
    If a DynamicItem is given, adds that directly. Otherwise a
    DynamicItem is created, and this specifies the callable to use. If
    a generator function is given, then create a GeneratorDynamicItem.
    Otherwise creates a normal DynamicItem.
takes : list, str
    List of keys. When func is called, each key is resolved to
    either an entry in the data or the output of another dynamic_item.
    The func is then called with these as positional arguments,
    in the same order as specified here.
    A single arg can be given directly.
provides : str
    Unique key or keys that this provides.
N)r   Úadd_dynamic_item)r   ÚfuncÚtakesÚprovidess       r   r5   Ú#DynamicItemDataset.add_dynamic_itemÑ   s   € ð4 	�‰×&Ñ& t°HÕ=r   c                 ó:   • U R                   R                  U5        g)aŠ  Use this to change the output keys.

These are the keys that are actually evaluated when a data point
is fetched from the dataset.

Arguments
---------
keys : dict, list
    List of keys (str) to produce in output.

    If a dict is given; it is used to map internal keys to output keys.
    From the output_keys dict key:value pairs the key appears outside,
    and value is the internal key.
N)r   r   )r   r   s     r   r   Ú"DynamicItemDataset.set_output_keysí   s   € ð 	�‰×%Ñ% dÕ+r   c              #   ó¬   #   • U R                   R                  nU R                   R                  U5        U v •  U R                   R                  U5        g7f)añ  Context manager to temporarily set output keys.

Arguments
---------
keys : list
    A set of output keys to use in the context.

Example
-------
>>> dataset = DynamicItemDataset(
...     {"a": {"x": 1, "y": 2}, "b": {"x": 3, "y": 4}},
...     output_keys=["x"],
... )
>>> with dataset.output_keys_as(["y"]):
...     print(dataset[0])
{'y': 2}
>>> print(dataset[0])
{'x': 1}

NOTE
----
Not thread-safe. While in this context manager, the output keys
are affected for any call.

Yields
------
self
N)r   r-   r   )r   r   Úsaved_outputs      r   r.   Ú!DynamicItemDataset.output_keys_asþ   s?   é € ð< —}‘}×3Ñ3ˆØ�‰×%Ñ% dÔ+ØŠ
Ø�‰×%Ñ% lÕ3ùs   ‚AAFc                 ó>   • U R                  XX4XV5      n[        X5      $ )a(  Get a filtered and/or sorted version of this, shares static data.

The reason to implement these operations in the same method is that
computing some dynamic items may be expensive, and this way the
filtering and sorting steps don't need to compute the dynamic items
twice.

Arguments
---------
key_min_value : dict
    Map from key (in data or in dynamic items) to limit, will only keep
    data_point if data_point[key] >= limit
key_max_value : dict
    Map from key (in data or in dynamic items) to limit, will only keep
    data_point if data_point[key] <= limit
key_test : dict
    Map from key (in data or in dynamic items) to func, will only keep
    data_point if bool(func(data_point[key])) == True
sort_key : None, str
    If not None, sort by data_point[sort_key]. Default is ascending
    order.
reverse : bool
    If True, sort in descending order.
select_n : None, int
    If not None, only keep (at most) the first n filtered data_points.
    The possible sorting is applied, but only on the first n data
    points found. Meant for debugging.

Returns
-------
FilteredSortedDynamicItemDataset
    Shares the static data, but has its own output keys and
    dynamic items (initially deep copied from this, so they have the
    same dynamic items available)

NOTE
----
Temporarily changes the output keys!
)Ú_filtered_sorted_idsÚ FilteredSortedDynamicItemDataset)r   Úkey_min_valueÚkey_max_valueÚkey_testÚsort_keyÚreverseÚselect_nÚfiltered_sorted_idss           r   Úfiltered_sortedÚ"DynamicItemDataset.filtered_sorted!  s/   € ð` #×7Ñ7Ø¨(¸gó
Ðô 0Øó
ð 	
r   c                 ó¶  ^^^• UUU4S jn[        TR                  5       5      [        TR                  5       5      -  [        TR                  5       5      -  [        Uc  / OU/5      -  n/ n	U R                  U5         [        U R                  5       H�  u  p«Ub  [        U	5      U:X  a    OlU R                  U   nX¼S'   U R                  R                  U5      nU" U5      (       d  MV  Ub  U	R                  XÔ   X«45        Mp  U	R                  U5        Mƒ     SSS5        Ub  [        X•S9 Vs/ s H  oîS   PM	     nnU$ U	nU$ ! , (       d  f       N2= fs  snf )zAReturns a list of data ids, fulfilling the sorting and filtering.c                 óø   >• TR                  5        H  u  pX   U:¼  a  M    g   TR                  5        H  u  pX   U::  a  M    g   TR                  5        H  u  p[        U" X   5      5      (       a  M    g   g)zApplies filter.FT)ÚitemsÚbool)ÚcomputedÚkeyÚlimitr6   rC   rB   rD   s       €€€r   Úcombined_filterÚ@DynamicItemDataset._filtered_sorted_ids.<locals>.combined_filterc  sƒ   ø€ à+×1Ñ1Ö3‘
�ð
 ‘= EÓ)ÙÙñ 4ð ,×1Ñ1Ö3‘
�Ø‘= EÓ)ÙÙñ 4ð &Ÿ^™^Ö-‘	�Ü™˜X™]Ó+×,Ñ,ÙÙñ .ð r   Nr   )rF   é   )Úsetr   r.   Ú	enumerater   r!   r   r   r%   r   Úsorted)r   rB   rC   rD   rE   rF   rG   rR   Ú	temp_keysÚfiltered_idsÚir'   r(   rO   ÚtuprH   s    ```            r   r@   Ú'DynamicItemDataset._filtered_sorted_idsX  sU  ú€ ÷	ô* �×"Ñ"Ó$Ó%Ü�-×$Ñ$Ó&Ó'ñ(ä�(—-‘-“/Ó"ñ#ô ˜Ñ(‘"¨x¨jÓ9ñ:ð 	ð ˆØ× Ñ  Õ+Ü'¨¯©Ö6‘
�ØÑ'¬C°Ó,=ÀÓ,IÙØ!ŸY™Y wÑ/�
Ø#*˜4Ñ ØŸ=™=×8Ñ8¸ÓD�Ù" 8×,Ó,ØÑ+ð %×+Ñ+¨XÑ-?ÀÐ,LÖMà$×+Ñ+¨GÖ4ñ 7÷ ,ð Ñä"(¨Ò"Gó#Ú"G˜3�A”Ñ"Gð  ð #ð
 #Ð"ð #/ÐØ"Ð"÷+ ,Õ+üò #s   Á>A(EÃ*/EÄ/EÅ
Ec                 óv   • [         R                  " X!-  5      nU R                  SU U-  nUSU n[        X5      $ )av  Creates a subset of this dataset for an overfitting
test - repeating sample_count samples to create a repeating
dataset with a total of epoch_data_count samples

Arguments
---------
sample_count: int
    the number of samples to select
total_count: int
    the total data count

Returns
-------
dataset: FilteredSortedDynamicItemDataset
    a dataset with a repeated subset
N)ÚmathÚceilr   rA   )r   Úsample_countÚtotal_countÚnum_repetitionsÚoverfit_sampless        r   Úoverfit_testÚDynamicItemDataset.overfit_test•  sA   € ô" Ÿ)š) KÑ$>Ó?ˆØŸ-™-¨¨Ð6¸ÑHˆØ)¨,¨;Ð7ˆÜ/°ÓFÐFr   c                 óD   • [        U R                  U5      n[        X5      $ )a`  Shuffles batches within a dataset. This is particularly
useful in combination with length sorting - to ensure
that the length variation within a batch is not very high,
but the batches themselves remain randomized

Arguments
---------
batch_size: int
    the batch size

Returns
-------
dataset: FilteredSortedDynamicItemDataset
    a shuffled dataset
)r   r   rA   )r   Ú
batch_sizer   s      r   r   Ú DynamicItemDataset.batch_shuffle«  s   € ô  ! §¡°
Ó;ˆÜ/°Ó?Ð?r   c                 ó*   • [        X5      nU " XSU5      $ )z<Load a data prep JSON file and create a Dataset based on it.)r   )ÚclsÚ	json_pathÚreplacementsr   r   r   s         r   Ú	from_jsonÚDynamicItemDataset.from_json¾  s   € ô
 ˜iÓ6ˆÙ�4¨Ó4Ð4r   c                 ó(   • [        XUS9nU " XcU5      $ )aØ  Load a data prep CSV file and create a Dataset based on it.

Parameters
----------
csv_path : str
    Path to the CSV file.
replacements : dict
    Substitutions for $-variables in the CSV values.
dynamic_items : list
    Dynamic items to add to the dataset.
output_keys : list
    Keys to include in the output.
col_types : dict, optional
    Mapping from column name to type, e.g.
    ``{"duration": float, "spk_id": int}``.
    Passed through to :func:`load_data_csv`.
)Ú	col_types)r   )rj   Úcsv_pathrl   r   r   rp   r   s          r   Úfrom_csvÚDynamicItemDataset.from_csvÆ  s   € ô4 ˜X¸yÑIˆÙ�4¨Ó4Ð4r   c                 óD   ^• U4S jn[        UT5      Tl        U " TX45      $ )z&Loading a prepared huggingface datasetc                 ó`   >• [        TR                  5       5       Vs/ s H  oPM     sn$ s  snf )zReturns the keys.)Úranger"   )r   rZ   Údatasets     €r   r   Ú3DynamicItemDataset.from_arrow_dataset.<locals>.keysê  s)   ø€ ä$ W§_¡_Ó%6Ô7Ó8Ò7˜!’AÑ7Ñ8Ð8ùÒ8s   �+)r   r   )rj   rw   rl   r   r   r   s    `    r   Úfrom_arrow_datasetÚ%DynamicItemDataset.from_arrow_datasetã  s%   ø€ õ	9ô
 " $¨Ó0ˆŒÙ�7˜MÓ7Ð7r   ©r   r   r   ©NN)NT)Ú__name__Ú
__module__Ú__qualname__Ú__firstlineno__Ú__doc__r   r"   r)   r2   r5   r   Ú
contextlibÚcontextmanagerr.   rI   r@   rd   r   Úclassmethodrm   rr   ry   Ú__static_attributes__© r   r   r   r      sÛ   † ñJôX*ò"òLô
ô*>ò8,ð" ×Ññ 4ó ð 4ðH ØØØØØô5
ðr ØØØØØô;#òzGò,@ð& à%'°rÀró5ó ð5ð ð ØØØó5ó ð5ð8 à#%°RÀRó8ó ó8r   r   c                   óR   • \ rS rSrSrS r\0 SS4S j5       r\0 SS4S j5       rSr	g)rA   ió  z’Possibly filtered, possibly sorted DynamicItemDataset.

Shares the static data (reference).
Has its own dynamic_items and output_keys (deepcopy).
c                 ó|   • UR                   U l         X l        [        R                  " UR                  5      U l        g r    )r   r   ÚcopyÚdeepcopyr   )r   Úfrom_datasetr   s      r   r   Ú)FilteredSortedDynamicItemDataset.__init__ú  s*   € Ø ×%Ñ%ˆŒ	Ø ŒÜŸš l×&;Ñ&;Ó<ˆ�r   Nc                 ó   • [        S5      e©Nz0Cannot create SubsetDynamicItemDataset directly!©Ú	TypeError)rj   rk   rl   r   r   s        r   rm   Ú*FilteredSortedDynamicItemDataset.from_jsonÿ  ó   € ô ÐJÓKÐKr   c                 ó   • [        S5      erŽ   r�   )rj   rq   rl   r   r   s        r   rr   Ú)FilteredSortedDynamicItemDataset.from_csv  r’   r   r{   )
r}   r~   r   r€   r�   r   r„   rm   rr   r…   r†   r   r   rA   rA   ó  sF   † ñò=ð
 à%'°tÈóLó ðLð
 à$&°dÈóLó óLr   rA   c                 ó:   • U  H  nUR                  XU5        M     g)z5Helper for adding the same item to multiple datasets.N)r5   )Údatasetsr6   r7   r8   rw   s        r   r5   r5     s   € ãˆØ× Ñ  ¨hÖ7ò r   c                 ó8   • U  H  nUR                  U5        M     g)z6Helper for setting the same item to multiple datasets.N)r   )r–   r   rw   s      r   r   r     s   € ãˆØ×Ñ Ö,ò r   c                 ó>   • U (       a  UnUnUR                  XE5      nU$ )aÜ  Applies the overfit test to the specified dataset,
as configured in the hyperparameters file

Arguments
---------

overfit_test: bool
    when True the overfitting test is performed
overfit_test_sample_count: int
    number of samples for the overfitting test
overfit_test_epoch_data_count: int
    number of epochs for the overfitting test

dataset: DynamicItemDataset
    the dataset

Returns
-------
dataset: DynamicItemDataset
    the dataset, with the overfit test apply
)rd   )rd   Úoverfit_test_sample_countÚoverfit_test_epoch_data_countrw   r`   Úepoch_data_counts         r   Úapply_overfit_testrœ     s'   € ö6 Ø0ˆØ8ÐØ×&Ñ& |ÓFˆØ€Nr   r|   )r�   r‚   r‰   r^   Útypesr   r/   Útorch.utils.datar   Úspeechbrain.dataio.dataior   r   Úspeechbrain.utils.data_pipeliner   Úspeechbrain.utils.data_utilsr   Úspeechbrain.utils.loggerr	   r}   Úloggerr   rA   r5   r   rœ   r†   r   r   Ú<module>r¤      sa   ðñó Û Û Ý ã Ý $ç CÝ 8Ý 6Ý /á	�HÓ	€ôX8˜ô X8ôvLÐ'9ô Lô28ò-ór   