choice of audios

Hi,

I'd like to set up a choice task between audios. choice currently doesn't accept "audio", only "image". Is this planned? I tried two workarounds.

Feed audios as html

While urls work charmlessly, e.g.

{"id": 1, "html": '<audio controls> <source src="https://www.computerhope.com/jargon/m/example.mp3" /> </audio>'}

... paths to local files don't. I tried absolute and relative paths like:
'<audio controls> <source src="file:///path/to/file.wav" /> </audio>'. None worked. Also embedding local images didn't work.

Change from choice to blocks

See the code below. I (more or less) understood the expected "json task" for blocks and obviously it's not clear to me how this should work in my case as the field "audio" would need to be used twice.

import prodigy
from prodigy.components.loaders import Audio


@prodigy.recipe("choose-audio")
def view_audios(dataset, folder1, folder2):

    blocks = [
        {"view_id": "audio", "field_id": "audio1"},
        {"view_id": "audio", "field_id": "audio2"},
    ]

    stream1 = Audio(folder1)
    stream2 = Audio(folder2)

    def get_stream():
        for audio1, audio2 in zip(stream1, stream2):
            # yield audio1  # this works but displays same audio for both fields
            # yield {"audio1": audio1, "audio2": audio2} doesn't work
            # yield {"blocks": [{"audio1": audio1}, {"audio2": audio2}]} doesn't work
            # yield {"blocks": {"audio1": audio1, "audio2": audio2}} doesn't work

    return {
        "dataset": dataset,
        "stream": get_stream(),
        "view_id": "blocks",
        "config": {
            "blocks": blocks,
            'audio_loop': False,
            "audio_minimap": False
        }
    }

Hi! Embedding from local paths is not going to work, due to security settings in your browser, which will block them: javascript - Cannot open local file - Chrome: Not allowed to load local resource - Stack Overflow (while you can sometimes disable this, it's not something I'd recommend because it does open up vulnerabilities).

So the main options for loading files are like images and audio files are:

  • Use the base64-encoded file instead of the file path: This is what Prodigy does by default for images and audio files, and it works fine for smaller files and it ensures you never lose the reference to the original file. You can also use the before_db callback in your recipe to remove the data from the JSON before it's stored in the DB to save space. However, once your files are getting too large, sending them back and forth via the REST API is inefficient and can cause problems.
  • Use a local web server: Prodigy supports this for directories of images and audio input files via the image-server and audio-server loaders, but you can also just spin up a quick local web server on a different port from a given directory (e.g. using Python's http.server) and then use the localhost paths instead.
  • Use a URL: For instance, you can put your files in an S3 bucket or similar and load them from there. This requires one more step, but it's more organised and will work across machines.

I haven't tried this yet, but what happens when you add an "audio" property to your choice options using a localhost path or URL? In theory, it should work, because the "options" can have the same format as regular tasks – but thinking about it, it's possible that multiple audio players per page currently don't work because Prodigy isn't isolating them correctly. If that's the case, this is definitely something we should be able to fix!

Did you mean the following? Code to reproduce:

@prodigy.recipe("choice-audio")
def view_audios(dataset):

    def get_stream():
        options = [
            {"id": 1, "audio": "https://www.computerhope.com/jargon/m/example.mp3"},
            {"id": 2, "audio": "https://www.computerhope.com/jargon/m/example.mp3"}
        ]
        yield {"label": "emotion", "options": options}

    return {
        "dataset": dataset,
        "stream": get_stream(),
        "view_id": "choice",
        "config": {
            "choice_style": "single",
        }
    }

leads to an error in the web server. The same also for only 1 single choice option.

TypeError: l is not a function
    in t
    in Jss(t)
    in Unknown
    in div
    in div
    in t
    in Jss(t)
    in div
    in div
    in Shortcuts
    in Unknown
    in div
    in t
    in Jss(t)
    in div
    in t
    in Jss(t)
    in Unknown
    in t
    in Jss(t)
    in div
    in div
    in t
    in Jss(t)
    in Connect(Jss(t))
    in main
    in div
    in Shortcuts
    in t
    in n
    in Jss(n)
    in Connect(Jss(n))
    in t
    in t
    in Connect(t)
    in t
    in t

html solution

Okay, thanks a lot for explaining. There are some viable options for me among them.