audio_manual interface duplicates audio_spans when video field is present

Hi Prodigy team,

When using the audio_manual interface with both audio_spans and a video field, the audio_spans regions are rendered twice in the interface (appears duplicated).

Here is my recipe function:

@prodigy.recipe('video.example')
def example():
    stream = [{
        'video': 'VIDEO_FILE_WITH_AUDIO.mp4',
        'audio_spans': [
            {'start': 1.89, 'end': 2.83, 'label': 'Segment_1'}
        ]
    }]
    stream = Stream.from_iterable(stream)

    view_id = 'audio_manual'
    dataset = 'test'

    return {
        'view_id': view_id,
        'dataset': dataset,
        'stream': stream,
        'config': {
            'labels': ['Example']
        }
    }

My questions:

  • Is this a known bug with audio_manual when a video field is present?
  • Is there a recommended approach for combined video + audio span annotation?

Thank you!

Welcome to the forum @xieh! :waving_hand:

Hi,

Thanks for the detailed write-up and the recipe β€” that helped a lot.

When I load the same task through a normal media path (e.g. fetch_media/base64), the pre-set audio_spans render once, as expected β€” I couldn't get the duplication you're describing. Looking at the rendering code, pre-set spans go through a single path that clears existing regions before drawing, so a genuine double-render of the same span shouldn't happen on current versions.

So there's a piece of your real setup that isn't in the snippet, and it's almost certainly the key to what you're seeing. To get us to the same state, could you share:

  1. Your Prodigy version β€” output of prodigy stats.
  2. How the video is actually loaded β€” since a bare filename won't render, what's the real value of the video field in your stream? A full http(s):// URL, a base64 data URI, a custom static mount, or a fetch_media/preprocessing step you didn't include in the snippet?
  3. A screenshot or short recording of the duplicated regions.

On your second question: audio_manual with a video field is the supported way to do combined video + audio-span annotation, so your overall approach is correct. Once we can load your video the same way you do, we'll be able to pin down (and fix) whatever's causing the doubling.

Hi,

The output of my prodigy stats is:

Version          1.18.5
License Type     Prodigy Personal
Location         E:\prodigy-example\.venv\Lib\site-packages\prodigy
Prodigy Home     .prodigy
Platform         Windows-11-10.0.26200-SP0
Python Version   3.13.5
spaCy Version    3.8.14
Database Name    SQLite
Database Id      sqlite
Total Datasets   1
Total Sessions   1

My test example and video data are in this GitHub repository: GitHub - xieh97/prodigy-example Β· GitHub

The file Prodigy - Google Chrome 2026-06-17 10-14-24.mp4 is a short screen recording of the duplicated regions.

Another issue: in my test example, the Segment_1 region provided for BigBuckBunny_320x180_segment_1.mp4 also renders on the second video BigBuckBunny_320x180_segment_2.mp4.

The problem also occurs on macOS with Prodigy 1.18.4 in both Safari and Chrome.

Thank you!

Thanks β€” the repo and the screen recording were exactly what we needed, and I can now reproduce it on our end. This is a genuine bug, not something wrong with your setup, so thank you for the careful write-up.

The key detail is that it's intermittent: on some page loads the pre-set audio_spans render once, and on others the same span is drawn twice, superimposed on top of itself β€” and a refresh can flip between the two. That inconsistency points to a timing/race condition in how audio_manual loads pre-set spans, and it's specific to the combination you're using: a task with a video field (so the interface attaches the waveform to a single shared video element), and media loaded as an inline base64 data URI (which is what fetch_media produces).

Because the base64 media is available essentially instantly, the step that draws your pre-set audio_spans can run before the regions layer is fully initialized, and the source ends up being applied more than once. Depending on which wins the race on a given load, the span is drawn once or twice. The same incomplete-cleanup is why, after you drag a duplicated region, it can bleed onto the next example (your Segment_1 showing up on segment_2).

The audio-only path doesn't hit this, which is why it only shows up once a video field is present β€” matching exactly what you reported.

We've logged this as a frontend bug for a fix in an upcoming release and I'll follow up here once the fix lands. Thanks again for a very detailed report!

1 Like

Hi @xieh,

We have just released 1.18.6 with the patch for the bug you reported - thanks again!

You should be able to pip install with the --upgrade flag:

python -m pip install --upgrade prodigy --extra-index-url https://XXXX-XXXX-XXXX-XXXX@download.prodi.gy
1 Like

Hi @magdaaniol,

Thank you for the lightning-fast fix. Appreciated!

Now, I'm afraid I've come across another small issue. In the second example, when I click the reset button, it clears Segment_2 and then displays Segment_1 (the preset span from the first example).

A short recording (Prodigy - Google Chrome 2026-06-25 11-13-57.mp4) about this is available in the repo.

I'd expect the reset to only affect Segment_2 and restore its own original preset span, without touching or showing Segment_1.

Thanks again for your great support!

Hi @xieh!

Thanks for flagging this β€” it's another race condition in the same area as the duplication issue: when you advance to the next example, the interface sometimes reuses the same player instead of rebuilding it, and in that case the reset button restores the previous example's preset spans instead of the current one's β€” it depends on media-load timing, which is why it can come and go.

We are working on the fix, of course. I'll update when it's out.

Thanks again for the detailed, reproducible reports!

1 Like

Just an update the the patch has been shipped in 1.18.7.
Thanks again for the report!

1 Like