Repository: huggingface/dataset-viewer

Issue:
TransformRowsProcessingError in /rows with simple audio dataset
https://huggingface.co/datasets/GregoryVandromme/vandromme_dataset/viewer/default/test

https://datasets-server.huggingface.co/rows?dataset=GregoryVandromme/vandromme_dataset&config=default&split=test

```
{"error":"Server error while post-processing the split rows. Please report the issue."}
```

Reported here: https://huggingface.co/datasets/GregoryVandromme/vandromme_dataset/discussions/1


Discussion:
I have investigated, and apparently we no longer support audio no-script datasets on the Hub.
See:
- https://huggingface.co/datasets/albertvillanova/tmp-wav/viewer/default/train

Note that the audio path stored in the Parquet file has no extension in this case.

I am fixing it.

Resolving patch:
diff --git a/libs/libcommon/src/libcommon/viewer_utils/asset.py b/libs/libcommon/src/libcommon/viewer_utils/asset.py
--- a/libs/libcommon/src/libcommon/viewer_utils/asset.py
+++ b/libs/libcommon/src/libcommon/viewer_utils/asset.py
@@ -121,9 +121,11 @@ def create_audio_file(
                 f.write(audio_file_bytes)
         else:  # we need to convert
             # might spawn a process to convert the audio file using ffmpeg
-            with NamedTemporaryFile("wb", suffix=audio_file_extension) as tmpfile:
+            with NamedTemporaryFile("wb", suffix=audio_file_extension or None) as tmpfile:
                 tmpfile.write(audio_file_bytes)
-                segment: AudioSegment = AudioSegment.from_file(tmpfile.name)
+                segment: AudioSegment = AudioSegment.from_file(
+                    tmpfile.name, audio_file_extension[1:] if audio_file_extension else None
+                )
                 buffer = BytesIO()
                 segment.export(buffer, format=suffix[1:])
                 buffer.seek(0)
diff --git a/libs/libcommon/src/libcommon/viewer_utils/features.py b/libs/libcommon/src/libcommon/viewer_utils/features.py
--- a/libs/libcommon/src/libcommon/viewer_utils/features.py
+++ b/libs/libcommon/src/libcommon/viewer_utils/features.py
@@ -121,11 +121,8 @@ def audio(
 
     if "path" in value and isinstance(value["path"], str):
         # .split("::")[0] for chained URLs like zip://audio.wav::https://foo.bar/data.zip
+        # It might be "" for audio files downloaded from the Hub
         audio_file_extension = os.path.splitext(value["path"].split("::")[0])[1]
-        if not audio_file_extension:
-            raise ValueError(
-                f"An audio sample should have a 'path' with a valid extension but got '{audio_file_extension}'."
-            )
     elif ("path" in value and value["path"] is None) or "array" in value:
         audio_file_extension = ".wav"
     else:


Test patch:
diff --git a/libs/libcommon/tests/viewer_utils/data/test_audio_44100.wav b/libs/libcommon/tests/viewer_utils/data/test_audio_44100.wav
new file mode 100644
Binary files /dev/null and b/libs/libcommon/tests/viewer_utils/data/test_audio_44100.wav differ
diff --git a/libs/libcommon/tests/viewer_utils/test_assets.py b/libs/libcommon/tests/viewer_utils/test_assets.py
--- a/libs/libcommon/tests/viewer_utils/test_assets.py
+++ b/libs/libcommon/tests/viewer_utils/test_assets.py
@@ -1,9 +1,7 @@
 from collections.abc import Mapping
-from io import BytesIO
 from pathlib import Path
 
 import pytest
-import soundfile  # type: ignore
 import validators  # type: ignore
 from datasets import Dataset
 from PIL import Image as PILImage  # type: ignore
@@ -56,19 +54,18 @@ def test_create_image_file(datasets: Mapping[str, Dataset], public_assets_storag
     assert image is not None
 
 
-def test_create_audio_file(datasets: Mapping[str, Dataset], public_assets_storage: PublicAssetsStorage) -> None:
-    dataset = datasets["audio"]
-    value = dataset[0]["col"]
-    buffer = BytesIO()
-    soundfile.write(buffer, value["array"], value["sampling_rate"], format="wav")
-    audio_file_bytes = buffer.read()
+@pytest.mark.parametrize("audio_file_extension", [".wav", ""])  # also test audio files without extension
+def test_create_audio_file(
+    audio_file_extension: str, shared_datadir: Path, public_assets_storage: PublicAssetsStorage
+) -> None:
+    audio_file_bytes = (shared_datadir / "test_audio_44100.wav").read_bytes()
     value = create_audio_file(
         dataset="dataset",
         revision="revision",
         config="config",
         split="split",
         row_idx=7,
-        audio_file_extension=".wav",
+        audio_file_extension=audio_file_extension,
         audio_file_bytes=audio_file_bytes,
         column="col",
         filename="audio.wav",