We are currently solving the following issue within our repository. Here is the issue text:
--- BEGIN ISSUE ---
Sound category mismatch
## Description
<!-- Concisely describe the bug. -->
The `sound` category for audio doesn't work on the front-end.
There seems to be a mismatch between the `audio` category of `sound_effect`:
If you go to `https://api.openverse.engineering/v1/audio/?q=cat&categories=sound`, you will get a 400 response:
```
HTTP 400 Bad Request
Allow: GET, HEAD, OPTIONS
Content-Type: application/json
Vary: Accept

{
    "detail": {
        "categories": [
            "Invalid category: sound. Available options: {'music', 'audiobook', 'podcast', 'news', 'sound_effect'}"
        ]
    }
}
```

However, if you access a single audio result, you will see that it returns `sound` for the category:
https://api.openverse.engineering/v1/audio/1bb94f50-009c-4371-a605-dd289562a9f5/

## Expectation
<!-- Concisely describe what you expected to happen. -->
Both the query category parameter and the result category property for sound effect should have the same name.

## Additional context
The catalog sets the category as `sound`, so that is the value we get from the database:
https://github.com/WordPress/openverse-catalog/blob/cb19f839e96de7ae1a55e8b7dc82a7d2bf5588e8/openverse_catalog/dags/providers/provider_api_scripts/freesound.py#L33-L34

## Resolution
<!-- Replace the [ ] with [x] to check the box. -->
- [ ] 🙋 I would be interested in resolving this bug.


--- END ISSUE ---

Below are some code segments, each from a relevant file. One or more of these files may contain bugs.
--- BEGIN FILES ---
Path: `api/catalog/api/serializers/audio_serializers.py`
Content:
```
1 from catalog.api.controllers.search_controller import get_sources
2 from catalog.api.docs.media_docs import fields_to_md
3 from catalog.api.models import AudioReport
4 from catalog.api.models.audio import Audio
5 from catalog.api.serializers.media_serializers import (
6     MediaSearchRequestSerializer,
7     MediaSearchSerializer,
8     MediaSerializer,
9     _validate_enum,
10 )
11 from elasticsearch_dsl.response import Hit
12 from rest_framework import serializers
13 
14 
15 class AudioSetSerializer(serializers.Serializer):
16     """An audio set, rendered as a part of the ``AudioSerializer`` output."""
17 
18     title = serializers.CharField(help_text="The name of the media.", required=False)
19     foreign_landing_url = serializers.URLField(
20         required=False, help_text="A foreign landing link for the image."
21     )
22 
23     creator = serializers.CharField(
24         help_text="The name of the media creator.", required=False, allow_blank=True
25     )
26     creator_url = serializers.URLField(
27         required=False, help_text="A direct link to the media creator."
28     )
29 
30     url = serializers.URLField(help_text="The actual URL to the media file.")
31     filesize = serializers.CharField(
32         required=False, help_text="Number in bytes, e.g. 1024."
33     )
34     filetype = serializers.CharField(
35         required=False,
36         help_text="The type of the file, related to the file extension.",
37     )
38 
39 
40 class AudioSearchRequestSerializer(MediaSearchRequestSerializer):
41     """Parse and validate search query string parameters."""
42 
43     fields_names = [
44         *MediaSearchRequestSerializer.fields_names,
45         "source",
46         "categories",
47         "duration",
48     ]
49     """
50     Keep the fields names in sync with the actual fields below as this list is
51     used to generate Swagger documentation.
52     """
53 
54     source = serializers.CharField(
55         label="provider",
56         help_text="A comma separated list of data sources to search. Valid "
57         "inputs: "
58         f"`{list(get_sources('audio').keys())}`",
59         required=False,
60     )
61     categories = serializers.CharField(
62         label="categories",
63         help_text="A comma separated list of categories; available categories "
64         "include `music`, `sound_effect`, `podcast`, `audiobook`, "
65         "and `news`.",
66         required=False,
67     )
68     duration = serializers.CharField(
69         label="duration",
70         help_text="A comma separated list of audio lengths; available lengths "
71         "include `short`, and `long`.",
72         required=False,
73     )
74 
75     @staticmethod
76     def validate_source(input_sources):
77         allowed_sources = list(get_sources("audio").keys())
78         input_sources = input_sources.split(",")
79         input_sources = [x for x in input_sources if x in allowed_sources]
80         input_sources = ",".join(input_sources)
81         return input_sources.lower()
82 
83     @staticmethod
84     def validate_categories(value):
85         valid_categories = {
86             "music",
87             "sound_effect",
88             "podcast",
89             "news",
90             "audiobook",
91         }
92         _validate_enum("category", valid_categories, value)
93         return value.lower()
94 
95     @staticmethod
96     def validate_duration(value):
97         valid_durations = {"short", "long"}  # TODO: Finalise duration filters
98         _validate_enum("duration", valid_durations, value)
99         return value.lower()
100 
101 
102 class AudioSerializer(MediaSerializer):
103     """A single audio file. Used in search results."""
104 
105     fields_names = [
106         *MediaSerializer.fields_names,
107         "audio_set",
108         "genre",
109         "duration",
110         "bit_rate",
111         "sample_rate",
112         "alt_files",
113         "detail_url",
114         "related_url",
115         "category",
116     ]
117     """
118     Keep the fields names in sync with the actual fields below as this list is
119     used to generate Swagger documentation.
120     """
121 
122     audio_set = AudioSetSerializer(
123         required=False,
124         help_text="Reference to set of which this track is a part.",
125         read_only=True,
126     )
127 
128     genres = serializers.ListField(
129         child=serializers.CharField(),
130         required=False,
131         help_text="An array of audio genres such as "
132         "`rock`, `electronic` for `music` category, or "
133         "`politics`, `sport`, `education` for `podcast` category",
134     )
135 
136     duration = serializers.IntegerField(
137         required=False, help_text="The time length of the audio file in milliseconds."
138     )
139     bit_rate = serializers.IntegerField(
140         required=False, help_text="Number in bits per second, eg. 128000."
141     )
142     sample_rate = serializers.IntegerField(
143         required=False, help_text="Number in hertz, eg. 44100."
144     )
145 
146     alt_files = serializers.JSONField(
147         required=False, help_text="JSON describing alternative files for this audio."
148     )
149 
150     # Hyperlinks
151     thumbnail = serializers.HyperlinkedIdentityField(
152         read_only=True,
153         view_name="audio-thumb",
154         lookup_field="identifier",
155         help_text="A direct link to the miniature artwork.",
156     )
157     waveform = serializers.HyperlinkedIdentityField(
158         read_only=True,
159         view_name="audio-waveform",
160         lookup_field="identifier",
161         help_text="A direct link to the waveform peaks.",
162     )
163     detail_url = serializers.HyperlinkedIdentityField(
164         read_only=True,
165         view_name="audio-detail",
166         lookup_field="identifier",
167         help_text="A direct link to the detail view of this audio file.",
168     )
169     related_url = serializers.HyperlinkedIdentityField(
170         read_only=True,
171         view_name="audio-related",
172         lookup_field="identifier",
173         help_text="A link to an endpoint that provides similar audio files.",
174     )
175 
176     # Add-on data
177     peaks = serializers.SerializerMethodField()
178 
179     @staticmethod
180     def get_peaks(obj):
181         if isinstance(obj, Hit):
182             obj = Audio.objects.get(identifier=obj.identifier)
183         return obj.get_waveform()
184 
185 
186 class AudioSearchSerializer(MediaSearchSerializer):
187     """
188     The full audio search response.
189     This serializer is purely representational and not actually used to
190     serialize the response.
191     """
192 
193     results = AudioSerializer(
194         many=True,
195         help_text=(
196             "An array of audios and their details such as "
197             f"{fields_to_md(AudioSerializer.fields_names)}."
198         ),
199     )
200 
201 
202 class AudioReportSerializer(serializers.ModelSerializer):
203     class Meta:
204         model = AudioReport
205         fields = ("identifier", "reason", "description")
206         read_only_fields = ("identifier",)
207 
208     def create(self, validated_data):
209         if (
210             validated_data["reason"] == "other"
211             and (
212                 "description" not in validated_data
213                 or len(validated_data["description"])
214             )
215             < 20
216         ):
217             raise serializers.ValidationError(
218                 "Description must be at least be 20 characters long"
219             )
220         return AudioReport.objects.create(**validated_data)
221 
222 
223 class AudioWaveformSerializer(serializers.Serializer):
224     len = serializers.SerializerMethodField()
225     points = serializers.ListField(
226         child=serializers.FloatField(min_value=0, max_value=1)
227     )
228 
229     @staticmethod
230     def get_len(obj) -> int:
231         return len(obj.get("points", []))
232
```
--- END FILES ---

Please first localize the bug based on the issue statement, and then generate a patch according to the `git diff` format fenced by three backticks.

Here is an example:

```diff
diff --git a/examples/server_async.py b/examples/server_async.py
--- a/examples/server_async.py
+++ b/examples/server_async.py
@@ -313,4 +313,4 @@
 
 
 if __name__ == "__main__":
-    asyncio.run(run_async_server("."), debug=True)
+    asyncio.run(run_async_server(), debug=True)
diff --git a/examples/server_sync.py b/examples/server_sync.py
--- a/examples/server_sync.py
+++ b/examples/server_sync.py
@@ -313,5 +313,5 @@
 
 
 if __name__ == "__main__":
-    server = run_sync_server(".")
+    server = run_sync_server()
     server.shutdown()

```

diff --git a/api/catalog/api/serializers/audio_serializers.py b/api/catalog/api/serializers/audio_serializers.py
--- a/api/catalog/api/serializers/audio_serializers.py
+++ b/api/catalog/api/serializers/audio_serializers.py
@@ -88,6 +88,7 @@
             "podcast",
             "news",
             "audiobook",
+            "pronunciation",
         }
         _validate_enum("category", valid_categories, value)
         return value.lower()

{"golden_diff": "diff --git a/api/catalog/api/serializers/audio_serializers.py b/api/catalog/api/serializers/audio_serializers.py\n--- a/api/catalog/api/serializers/audio_serializers.py\n+++ b/api/catalog/api/serializers/audio_serializers.py\n@@ -88,6 +88,7 @@\n             \"podcast\",\n             \"news\",\n             \"audiobook\",\n+            \"pronunciation\",\n         }\n         _validate_enum(\"category\", valid_categories, value)\n         return value.lower()\n", "issue": "Sound category mismatch\n## Description\r\n<!-- Concisely describe the bug. -->\r\nThe `sound` category for audio doesn't work on the front-end.\r\nThere seems to be a mismatch between the `audio` category of `sound_effect`:\r\nIf you go to `https://api.openverse.engineering/v1/audio/?q=cat&categories=sound`, you will get a 400 response:\r\n```\r\nHTTP 400 Bad Request\r\nAllow: GET, HEAD, OPTIONS\r\nContent-Type: application/json\r\nVary: Accept\r\n\r\n{\r\n    \"detail\": {\r\n        \"categories\": [\r\n            \"Invalid category: sound. Available options: {'music', 'audiobook', 'podcast', 'news', 'sound_effect'}\"\r\n        ]\r\n    }\r\n}\r\n```\r\n\r\nHowever, if you access a single audio result, you will see that it returns `sound` for the category:\r\nhttps://api.openverse.engineering/v1/audio/1bb94f50-009c-4371-a605-dd289562a9f5/\r\n\r\n## Expectation\r\n<!-- Concisely describe what you expected to happen. -->\r\nBoth the query category parameter and the result category property for sound effect should have the same name.\r\n\r\n## Additional context\r\nThe catalog sets the category as `sound`, so that is the value we get from the database:\r\nhttps://github.com/WordPress/openverse-catalog/blob/cb19f839e96de7ae1a55e8b7dc82a7d2bf5588e8/openverse_catalog/dags/providers/provider_api_scripts/freesound.py#L33-L34\r\n\r\n## Resolution\r\n<!-- Replace the [ ] with [x] to check the box. -->\r\n- [ ] \ud83d\ude4b I would be interested in resolving this bug.\r\n\n", "before_files": [{"content": "from catalog.api.controllers.search_controller import get_sources\nfrom catalog.api.docs.media_docs import fields_to_md\nfrom catalog.api.models import AudioReport\nfrom catalog.api.models.audio import Audio\nfrom catalog.api.serializers.media_serializers import (\n    MediaSearchRequestSerializer,\n    MediaSearchSerializer,\n    MediaSerializer,\n    _validate_enum,\n)\nfrom elasticsearch_dsl.response import Hit\nfrom rest_framework import serializers\n\n\nclass AudioSetSerializer(serializers.Serializer):\n    \"\"\"An audio set, rendered as a part of the ``AudioSerializer`` output.\"\"\"\n\n    title = serializers.CharField(help_text=\"The name of the media.\", required=False)\n    foreign_landing_url = serializers.URLField(\n        required=False, help_text=\"A foreign landing link for the image.\"\n    )\n\n    creator = serializers.CharField(\n        help_text=\"The name of the media creator.\", required=False, allow_blank=True\n    )\n    creator_url = serializers.URLField(\n        required=False, help_text=\"A direct link to the media creator.\"\n    )\n\n    url = serializers.URLField(help_text=\"The actual URL to the media file.\")\n    filesize = serializers.CharField(\n        required=False, help_text=\"Number in bytes, e.g. 1024.\"\n    )\n    filetype = serializers.CharField(\n        required=False,\n        help_text=\"The type of the file, related to the file extension.\",\n    )\n\n\nclass AudioSearchRequestSerializer(MediaSearchRequestSerializer):\n    \"\"\"Parse and validate search query string parameters.\"\"\"\n\n    fields_names = [\n        *MediaSearchRequestSerializer.fields_names,\n        \"source\",\n        \"categories\",\n        \"duration\",\n    ]\n    \"\"\"\n    Keep the fields names in sync with the actual fields below as this list is\n    used to generate Swagger documentation.\n    \"\"\"\n\n    source = serializers.CharField(\n        label=\"provider\",\n        help_text=\"A comma separated list of data sources to search. Valid \"\n        \"inputs: \"\n        f\"`{list(get_sources('audio').keys())}`\",\n        required=False,\n    )\n    categories = serializers.CharField(\n        label=\"categories\",\n        help_text=\"A comma separated list of categories; available categories \"\n        \"include `music`, `sound_effect`, `podcast`, `audiobook`, \"\n        \"and `news`.\",\n        required=False,\n    )\n    duration = serializers.CharField(\n        label=\"duration\",\n        help_text=\"A comma separated list of audio lengths; available lengths \"\n        \"include `short`, and `long`.\",\n        required=False,\n    )\n\n    @staticmethod\n    def validate_source(input_sources):\n        allowed_sources = list(get_sources(\"audio\").keys())\n        input_sources = input_sources.split(\",\")\n        input_sources = [x for x in input_sources if x in allowed_sources]\n        input_sources = \",\".join(input_sources)\n        return input_sources.lower()\n\n    @staticmethod\n    def validate_categories(value):\n        valid_categories = {\n            \"music\",\n            \"sound_effect\",\n            \"podcast\",\n            \"news\",\n            \"audiobook\",\n        }\n        _validate_enum(\"category\", valid_categories, value)\n        return value.lower()\n\n    @staticmethod\n    def validate_duration(value):\n        valid_durations = {\"short\", \"long\"}  # TODO: Finalise duration filters\n        _validate_enum(\"duration\", valid_durations, value)\n        return value.lower()\n\n\nclass AudioSerializer(MediaSerializer):\n    \"\"\"A single audio file. Used in search results.\"\"\"\n\n    fields_names = [\n        *MediaSerializer.fields_names,\n        \"audio_set\",\n        \"genre\",\n        \"duration\",\n        \"bit_rate\",\n        \"sample_rate\",\n        \"alt_files\",\n        \"detail_url\",\n        \"related_url\",\n        \"category\",\n    ]\n    \"\"\"\n    Keep the fields names in sync with the actual fields below as this list is\n    used to generate Swagger documentation.\n    \"\"\"\n\n    audio_set = AudioSetSerializer(\n        required=False,\n        help_text=\"Reference to set of which this track is a part.\",\n        read_only=True,\n    )\n\n    genres = serializers.ListField(\n        child=serializers.CharField(),\n        required=False,\n        help_text=\"An array of audio genres such as \"\n        \"`rock`, `electronic` for `music` category, or \"\n        \"`politics`, `sport`, `education` for `podcast` category\",\n    )\n\n    duration = serializers.IntegerField(\n        required=False, help_text=\"The time length of the audio file in milliseconds.\"\n    )\n    bit_rate = serializers.IntegerField(\n        required=False, help_text=\"Number in bits per second, eg. 128000.\"\n    )\n    sample_rate = serializers.IntegerField(\n        required=False, help_text=\"Number in hertz, eg. 44100.\"\n    )\n\n    alt_files = serializers.JSONField(\n        required=False, help_text=\"JSON describing alternative files for this audio.\"\n    )\n\n    # Hyperlinks\n    thumbnail = serializers.HyperlinkedIdentityField(\n        read_only=True,\n        view_name=\"audio-thumb\",\n        lookup_field=\"identifier\",\n        help_text=\"A direct link to the miniature artwork.\",\n    )\n    waveform = serializers.HyperlinkedIdentityField(\n        read_only=True,\n        view_name=\"audio-waveform\",\n        lookup_field=\"identifier\",\n        help_text=\"A direct link to the waveform peaks.\",\n    )\n    detail_url = serializers.HyperlinkedIdentityField(\n        read_only=True,\n        view_name=\"audio-detail\",\n        lookup_field=\"identifier\",\n        help_text=\"A direct link to the detail view of this audio file.\",\n    )\n    related_url = serializers.HyperlinkedIdentityField(\n        read_only=True,\n        view_name=\"audio-related\",\n        lookup_field=\"identifier\",\n        help_text=\"A link to an endpoint that provides similar audio files.\",\n    )\n\n    # Add-on data\n    peaks = serializers.SerializerMethodField()\n\n    @staticmethod\n    def get_peaks(obj):\n        if isinstance(obj, Hit):\n            obj = Audio.objects.get(identifier=obj.identifier)\n        return obj.get_waveform()\n\n\nclass AudioSearchSerializer(MediaSearchSerializer):\n    \"\"\"\n    The full audio search response.\n    This serializer is purely representational and not actually used to\n    serialize the response.\n    \"\"\"\n\n    results = AudioSerializer(\n        many=True,\n        help_text=(\n            \"An array of audios and their details such as \"\n            f\"{fields_to_md(AudioSerializer.fields_names)}.\"\n        ),\n    )\n\n\nclass AudioReportSerializer(serializers.ModelSerializer):\n    class Meta:\n        model = AudioReport\n        fields = (\"identifier\", \"reason\", \"description\")\n        read_only_fields = (\"identifier\",)\n\n    def create(self, validated_data):\n        if (\n            validated_data[\"reason\"] == \"other\"\n            and (\n                \"description\" not in validated_data\n                or len(validated_data[\"description\"])\n            )\n            < 20\n        ):\n            raise serializers.ValidationError(\n                \"Description must be at least be 20 characters long\"\n            )\n        return AudioReport.objects.create(**validated_data)\n\n\nclass AudioWaveformSerializer(serializers.Serializer):\n    len = serializers.SerializerMethodField()\n    points = serializers.ListField(\n        child=serializers.FloatField(min_value=0, max_value=1)\n    )\n\n    @staticmethod\n    def get_len(obj) -> int:\n        return len(obj.get(\"points\", []))\n", "path": "api/catalog/api/serializers/audio_serializers.py"}], "after_files": [{"content": "from catalog.api.controllers.search_controller import get_sources\nfrom catalog.api.docs.media_docs import fields_to_md\nfrom catalog.api.models import AudioReport\nfrom catalog.api.models.audio import Audio\nfrom catalog.api.serializers.media_serializers import (\n    MediaSearchRequestSerializer,\n    MediaSearchSerializer,\n    MediaSerializer,\n    _validate_enum,\n)\nfrom elasticsearch_dsl.response import Hit\nfrom rest_framework import serializers\n\n\nclass AudioSetSerializer(serializers.Serializer):\n    \"\"\"An audio set, rendered as a part of the ``AudioSerializer`` output.\"\"\"\n\n    title = serializers.CharField(help_text=\"The name of the media.\", required=False)\n    foreign_landing_url = serializers.URLField(\n        required=False, help_text=\"A foreign landing link for the image.\"\n    )\n\n    creator = serializers.CharField(\n        help_text=\"The name of the media creator.\", required=False, allow_blank=True\n    )\n    creator_url = serializers.URLField(\n        required=False, help_text=\"A direct link to the media creator.\"\n    )\n\n    url = serializers.URLField(help_text=\"The actual URL to the media file.\")\n    filesize = serializers.CharField(\n        required=False, help_text=\"Number in bytes, e.g. 1024.\"\n    )\n    filetype = serializers.CharField(\n        required=False,\n        help_text=\"The type of the file, related to the file extension.\",\n    )\n\n\nclass AudioSearchRequestSerializer(MediaSearchRequestSerializer):\n    \"\"\"Parse and validate search query string parameters.\"\"\"\n\n    fields_names = [\n        *MediaSearchRequestSerializer.fields_names,\n        \"source\",\n        \"categories\",\n        \"duration\",\n    ]\n    \"\"\"\n    Keep the fields names in sync with the actual fields below as this list is\n    used to generate Swagger documentation.\n    \"\"\"\n\n    source = serializers.CharField(\n        label=\"provider\",\n        help_text=\"A comma separated list of data sources to search. Valid \"\n        \"inputs: \"\n        f\"`{list(get_sources('audio').keys())}`\",\n        required=False,\n    )\n    categories = serializers.CharField(\n        label=\"categories\",\n        help_text=\"A comma separated list of categories; available categories \"\n        \"include `music`, `sound_effect`, `podcast`, `audiobook`, \"\n        \"and `news`.\",\n        required=False,\n    )\n    duration = serializers.CharField(\n        label=\"duration\",\n        help_text=\"A comma separated list of audio lengths; available lengths \"\n        \"include `short`, and `long`.\",\n        required=False,\n    )\n\n    @staticmethod\n    def validate_source(input_sources):\n        allowed_sources = list(get_sources(\"audio\").keys())\n        input_sources = input_sources.split(\",\")\n        input_sources = [x for x in input_sources if x in allowed_sources]\n        input_sources = \",\".join(input_sources)\n        return input_sources.lower()\n\n    @staticmethod\n    def validate_categories(value):\n        valid_categories = {\n            \"music\",\n            \"sound_effect\",\n            \"podcast\",\n            \"news\",\n            \"audiobook\",\n            \"pronunciation\",\n        }\n        _validate_enum(\"category\", valid_categories, value)\n        return value.lower()\n\n    @staticmethod\n    def validate_duration(value):\n        valid_durations = {\"short\", \"long\"}  # TODO: Finalise duration filters\n        _validate_enum(\"duration\", valid_durations, value)\n        return value.lower()\n\n\nclass AudioSerializer(MediaSerializer):\n    \"\"\"A single audio file. Used in search results.\"\"\"\n\n    fields_names = [\n        *MediaSerializer.fields_names,\n        \"audio_set\",\n        \"genre\",\n        \"duration\",\n        \"bit_rate\",\n        \"sample_rate\",\n        \"alt_files\",\n        \"detail_url\",\n        \"related_url\",\n        \"category\",\n    ]\n    \"\"\"\n    Keep the fields names in sync with the actual fields below as this list is\n    used to generate Swagger documentation.\n    \"\"\"\n\n    audio_set = AudioSetSerializer(\n        required=False,\n        help_text=\"Reference to set of which this track is a part.\",\n        read_only=True,\n    )\n\n    genres = serializers.ListField(\n        child=serializers.CharField(),\n        required=False,\n        help_text=\"An array of audio genres such as \"\n        \"`rock`, `electronic` for `music` category, or \"\n        \"`politics`, `sport`, `education` for `podcast` category\",\n    )\n\n    duration = serializers.IntegerField(\n        required=False, help_text=\"The time length of the audio file in milliseconds.\"\n    )\n    bit_rate = serializers.IntegerField(\n        required=False, help_text=\"Number in bits per second, eg. 128000.\"\n    )\n    sample_rate = serializers.IntegerField(\n        required=False, help_text=\"Number in hertz, eg. 44100.\"\n    )\n\n    alt_files = serializers.JSONField(\n        required=False, help_text=\"JSON describing alternative files for this audio.\"\n    )\n\n    # Hyperlinks\n    thumbnail = serializers.HyperlinkedIdentityField(\n        read_only=True,\n        view_name=\"audio-thumb\",\n        lookup_field=\"identifier\",\n        help_text=\"A direct link to the miniature artwork.\",\n    )\n    waveform = serializers.HyperlinkedIdentityField(\n        read_only=True,\n        view_name=\"audio-waveform\",\n        lookup_field=\"identifier\",\n        help_text=\"A direct link to the waveform peaks.\",\n    )\n    detail_url = serializers.HyperlinkedIdentityField(\n        read_only=True,\n        view_name=\"audio-detail\",\n        lookup_field=\"identifier\",\n        help_text=\"A direct link to the detail view of this audio file.\",\n    )\n    related_url = serializers.HyperlinkedIdentityField(\n        read_only=True,\n        view_name=\"audio-related\",\n        lookup_field=\"identifier\",\n        help_text=\"A link to an endpoint that provides similar audio files.\",\n    )\n\n    # Add-on data\n    peaks = serializers.SerializerMethodField()\n\n    @staticmethod\n    def get_peaks(obj):\n        if isinstance(obj, Hit):\n            obj = Audio.objects.get(identifier=obj.identifier)\n        return obj.get_waveform()\n\n\nclass AudioSearchSerializer(MediaSearchSerializer):\n    \"\"\"\n    The full audio search response.\n    This serializer is purely representational and not actually used to\n    serialize the response.\n    \"\"\"\n\n    results = AudioSerializer(\n        many=True,\n        help_text=(\n            \"An array of audios and their details such as \"\n            f\"{fields_to_md(AudioSerializer.fields_names)}.\"\n        ),\n    )\n\n\nclass AudioReportSerializer(serializers.ModelSerializer):\n    class Meta:\n        model = AudioReport\n        fields = (\"identifier\", \"reason\", \"description\")\n        read_only_fields = (\"identifier\",)\n\n    def create(self, validated_data):\n        if (\n            validated_data[\"reason\"] == \"other\"\n            and (\n                \"description\" not in validated_data\n                or len(validated_data[\"description\"])\n            )\n            < 20\n        ):\n            raise serializers.ValidationError(\n                \"Description must be at least be 20 characters long\"\n            )\n        return AudioReport.objects.create(**validated_data)\n\n\nclass AudioWaveformSerializer(serializers.Serializer):\n    len = serializers.SerializerMethodField()\n    points = serializers.ListField(\n        child=serializers.FloatField(min_value=0, max_value=1)\n    )\n\n    @staticmethod\n    def get_len(obj) -> int:\n        return len(obj.get(\"points\", []))\n", "path": "api/catalog/api/serializers/audio_serializers.py"}]}