prompt: We are currently solving the following issue within our repository. Here is the issue text:
  --- BEGIN ISSUE ---
  The 'speaker' field in the stcmds dataset is incorrect
  The file 20170001P00001I0001.wav is spoken by a female, 
  and the file 20170001P00001A0001.wav is spoken by a male.
  But they have the same speaker ID P00001
  
  --- END ISSUE ---
  
  Below are some code segments, each from a relevant file. One or more of these files may contain bugs.
  --- BEGIN FILES ---
  Path: `lhotse/recipes/stcmds.py`
  Content:
  ```
  1 """
  2 Stcmds is an open-source  Chinese Mandarin corpus by Surfingtech (www.surfing.ai), containing utterances from 855 speakers, 102600 utterances;
  3 Publicly available on https://www.openslr.org/resources/38
  4 ST-CMDS (110 hours)
  5 
  6 """
  7 import logging
  8 import os
  9 import shutil
  10 import tarfile
  11 from collections import defaultdict
  12 from pathlib import Path
  13 from typing import Dict, Optional, Union
  14 
  15 from tqdm.auto import tqdm
  16 
  17 from lhotse import fix_manifests, validate_recordings_and_supervisions
  18 from lhotse.audio import Recording, RecordingSet
  19 from lhotse.supervision import SupervisionSegment, SupervisionSet
  20 from lhotse.utils import Pathlike, resumable_download, safe_extract
  21 
  22 
  23 def text_normalize(line: str):
  24     """
  25     Modified from https://github.com/wenet-e2e/wenet/blob/main/examples/multi_cn/s0/local/stcmds_data_prep.sh#L42
  26     paste -d' ' $data/utt.list $data/text.list |\
  27     sed 's/，//g' |\
  28     tr '[a-z]' '[A-Z]' |\
  29     awk '{if (NF > 1) print $0;}' > $data/train/text
  30     """
  31     line = line.replace("，", "")
  32     line = line.upper()
  33     return line
  34 
  35 
  36 def download_stcmds(
  37     target_dir: Pathlike = ".",
  38     force_download: bool = False,
  39     base_url: str = "http://www.openslr.org/resources",
  40 ) -> Path:
  41     """
  42     Downdload and untar the dataset
  43     :param target_dir: Pathlike, the path of the dir to storage the dataset.
  44     :param force_download: Bool, if True, download the tars no matter if the tars exist.
  45     :param base_url: str, the url of the OpenSLR resources.
  46     :return: the path to downloaded and extracted directory with data.
  47     """
  48     url = f"{base_url}/38"
  49     target_dir = Path(target_dir)
  50     target_dir.mkdir(parents=True, exist_ok=True)
  51     corpus_dir = target_dir / "stcmds"
  52     dataset_tar_name = "ST-CMDS-20170001_1-OS.tar.gz"
  53     for tar_name in [dataset_tar_name]:
  54         tar_path = target_dir / tar_name
  55         extracted_dir = corpus_dir / tar_name[:-7]
  56         completed_detector = extracted_dir / ".completed"
  57         if completed_detector.is_file():
  58             logging.info(f"Skipping download of because {completed_detector} exists.")
  59             continue
  60         resumable_download(
  61             f"{url}/{tar_name}", filename=tar_path, force_download=force_download
  62         )
  63         shutil.rmtree(extracted_dir, ignore_errors=True)
  64         with tarfile.open(tar_path) as tar:
  65             safe_extract(tar, path=corpus_dir)
  66         completed_detector.touch()
  67 
  68     return corpus_dir
  69 
  70 
  71 def prepare_stcmds(
  72     corpus_dir: Pathlike, output_dir: Optional[Pathlike] = None
  73 ) -> Dict[str, Dict[str, Union[RecordingSet, SupervisionSet]]]:
  74     """
  75     Returns the manifests which consist of the Recordings and Supervisions
  76     :param corpus_dir: Pathlike, the path of the data dir.
  77     :param output_dir: Pathlike, the path where to write the manifests.
  78     :return: a Dict whose key is the dataset part, and the value is Dicts with the keys 'recordings' and 'supervisions'.
  79     """
  80     corpus_dir = Path(corpus_dir)
  81     assert corpus_dir.is_dir(), f"No such directory: {corpus_dir}"
  82     if output_dir is not None:
  83         output_dir = Path(output_dir)
  84         output_dir.mkdir(parents=True, exist_ok=True)
  85 
  86     path = corpus_dir / "ST-CMDS-20170001_1-OS"
  87     transcript_dict = {}
  88     for text_path in path.rglob("**/*.txt"):
  89         idx = text_path.stem
  90         logging.info(f"processing stcmds transcript  {text_path}")
  91         with open(text_path, "r", encoding="utf-8") as f:
  92             for line in f:
  93                 line = text_normalize(line)
  94                 transcript_dict[idx] = line
  95 
  96     manifests = defaultdict(dict)
  97     dataset_parts = ["train"]
  98     for part in tqdm(
  99         dataset_parts,
  100         desc="process stcmds audio, it needs waste about 2169 seconds time.",
  101     ):
  102         logging.info(f"Processing stcmds {part}")
  103         recordings = []
  104         supervisions = []
  105         for audio_path in path.rglob("**/*.wav"):
  106             idx = audio_path.stem
  107             speaker = "".join(list(idx)[8:14])
  108             if idx not in transcript_dict:
  109                 logging.warning(f"No transcript: {idx}")
  110                 logging.warning(f"{audio_path} has no transcript")
  111                 continue
  112             text = transcript_dict[idx]
  113             if not audio_path.is_file():
  114                 logging.warning(f"No such file: {audio_path}")
  115                 continue
  116             recording = Recording.from_file(audio_path)
  117             recordings.append(recording)
  118             segment = SupervisionSegment(
  119                 id=idx,
  120                 recording_id=idx,
  121                 start=0.0,
  122                 duration=recording.duration,
  123                 channel=0,
  124                 language="Chinese",
  125                 speaker=speaker,
  126                 text=text.strip(),
  127             )
  128             supervisions.append(segment)
  129 
  130         recording_set = RecordingSet.from_recordings(recordings)
  131         supervision_set = SupervisionSet.from_segments(supervisions)
  132 
  133         recording_set, supervision_set = fix_manifests(recording_set, supervision_set)
  134         validate_recordings_and_supervisions(recording_set, supervision_set)
  135 
  136         if output_dir is not None:
  137             supervision_set.to_file(output_dir / f"stcmds_supervisions_{part}.jsonl.gz")
  138             recording_set.to_file(output_dir / f"stcmds_recordings_{part}.jsonl.gz")
  139 
  140         manifests[part] = {"recordings": recording_set, "supervisions": supervision_set}
  141 
  142     return manifests
  143
  ```
  --- 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()
  
  ```
  
golden_diff: diff --git a/lhotse/recipes/stcmds.py b/lhotse/recipes/stcmds.py
  --- a/lhotse/recipes/stcmds.py
  +++ b/lhotse/recipes/stcmds.py
  @@ -104,7 +104,7 @@
           supervisions = []
           for audio_path in path.rglob("**/*.wav"):
               idx = audio_path.stem
  -            speaker = "".join(list(idx)[8:14])
  +            speaker = "".join(list(idx)[8:15])
               if idx not in transcript_dict:
                   logging.warning(f"No transcript: {idx}")
                   logging.warning(f"{audio_path} has no transcript")
  
verification_info: {"golden_diff": "diff --git a/lhotse/recipes/stcmds.py b/lhotse/recipes/stcmds.py\n--- a/lhotse/recipes/stcmds.py\n+++ b/lhotse/recipes/stcmds.py\n@@ -104,7 +104,7 @@\n         supervisions = []\n         for audio_path in path.rglob(\"**/*.wav\"):\n             idx = audio_path.stem\n-            speaker = \"\".join(list(idx)[8:14])\n+            speaker = \"\".join(list(idx)[8:15])\n             if idx not in transcript_dict:\n                 logging.warning(f\"No transcript: {idx}\")\n                 logging.warning(f\"{audio_path} has no transcript\")\n", "issue": "The 'speaker' field in the stcmds dataset is incorrect\nThe file 20170001P00001I0001.wav is spoken by a female, \r\nand the file 20170001P00001A0001.wav is spoken by a male.\r\nBut they have the same speaker ID P00001\n", "before_files": [{"content": "\"\"\"\nStcmds is an open-source  Chinese Mandarin corpus by Surfingtech (www.surfing.ai), containing utterances from 855 speakers, 102600 utterances;\nPublicly available on https://www.openslr.org/resources/38\nST-CMDS (110 hours)\n\n\"\"\"\nimport logging\nimport os\nimport shutil\nimport tarfile\nfrom collections import defaultdict\nfrom pathlib import Path\nfrom typing import Dict, Optional, Union\n\nfrom tqdm.auto import tqdm\n\nfrom lhotse import fix_manifests, validate_recordings_and_supervisions\nfrom lhotse.audio import Recording, RecordingSet\nfrom lhotse.supervision import SupervisionSegment, SupervisionSet\nfrom lhotse.utils import Pathlike, resumable_download, safe_extract\n\n\ndef text_normalize(line: str):\n    \"\"\"\n    Modified from https://github.com/wenet-e2e/wenet/blob/main/examples/multi_cn/s0/local/stcmds_data_prep.sh#L42\n    paste -d' ' $data/utt.list $data/text.list |\\\n    sed 's/\uff0c//g' |\\\n    tr '[a-z]' '[A-Z]' |\\\n    awk '{if (NF > 1) print $0;}' > $data/train/text\n    \"\"\"\n    line = line.replace(\"\uff0c\", \"\")\n    line = line.upper()\n    return line\n\n\ndef download_stcmds(\n    target_dir: Pathlike = \".\",\n    force_download: bool = False,\n    base_url: str = \"http://www.openslr.org/resources\",\n) -> Path:\n    \"\"\"\n    Downdload and untar the dataset\n    :param target_dir: Pathlike, the path of the dir to storage the dataset.\n    :param force_download: Bool, if True, download the tars no matter if the tars exist.\n    :param base_url: str, the url of the OpenSLR resources.\n    :return: the path to downloaded and extracted directory with data.\n    \"\"\"\n    url = f\"{base_url}/38\"\n    target_dir = Path(target_dir)\n    target_dir.mkdir(parents=True, exist_ok=True)\n    corpus_dir = target_dir / \"stcmds\"\n    dataset_tar_name = \"ST-CMDS-20170001_1-OS.tar.gz\"\n    for tar_name in [dataset_tar_name]:\n        tar_path = target_dir / tar_name\n        extracted_dir = corpus_dir / tar_name[:-7]\n        completed_detector = extracted_dir / \".completed\"\n        if completed_detector.is_file():\n            logging.info(f\"Skipping download of because {completed_detector} exists.\")\n            continue\n        resumable_download(\n            f\"{url}/{tar_name}\", filename=tar_path, force_download=force_download\n        )\n        shutil.rmtree(extracted_dir, ignore_errors=True)\n        with tarfile.open(tar_path) as tar:\n            safe_extract(tar, path=corpus_dir)\n        completed_detector.touch()\n\n    return corpus_dir\n\n\ndef prepare_stcmds(\n    corpus_dir: Pathlike, output_dir: Optional[Pathlike] = None\n) -> Dict[str, Dict[str, Union[RecordingSet, SupervisionSet]]]:\n    \"\"\"\n    Returns the manifests which consist of the Recordings and Supervisions\n    :param corpus_dir: Pathlike, the path of the data dir.\n    :param output_dir: Pathlike, the path where to write the manifests.\n    :return: a Dict whose key is the dataset part, and the value is Dicts with the keys 'recordings' and 'supervisions'.\n    \"\"\"\n    corpus_dir = Path(corpus_dir)\n    assert corpus_dir.is_dir(), f\"No such directory: {corpus_dir}\"\n    if output_dir is not None:\n        output_dir = Path(output_dir)\n        output_dir.mkdir(parents=True, exist_ok=True)\n\n    path = corpus_dir / \"ST-CMDS-20170001_1-OS\"\n    transcript_dict = {}\n    for text_path in path.rglob(\"**/*.txt\"):\n        idx = text_path.stem\n        logging.info(f\"processing stcmds transcript  {text_path}\")\n        with open(text_path, \"r\", encoding=\"utf-8\") as f:\n            for line in f:\n                line = text_normalize(line)\n                transcript_dict[idx] = line\n\n    manifests = defaultdict(dict)\n    dataset_parts = [\"train\"]\n    for part in tqdm(\n        dataset_parts,\n        desc=\"process stcmds audio, it needs waste about 2169 seconds time.\",\n    ):\n        logging.info(f\"Processing stcmds {part}\")\n        recordings = []\n        supervisions = []\n        for audio_path in path.rglob(\"**/*.wav\"):\n            idx = audio_path.stem\n            speaker = \"\".join(list(idx)[8:14])\n            if idx not in transcript_dict:\n                logging.warning(f\"No transcript: {idx}\")\n                logging.warning(f\"{audio_path} has no transcript\")\n                continue\n            text = transcript_dict[idx]\n            if not audio_path.is_file():\n                logging.warning(f\"No such file: {audio_path}\")\n                continue\n            recording = Recording.from_file(audio_path)\n            recordings.append(recording)\n            segment = SupervisionSegment(\n                id=idx,\n                recording_id=idx,\n                start=0.0,\n                duration=recording.duration,\n                channel=0,\n                language=\"Chinese\",\n                speaker=speaker,\n                text=text.strip(),\n            )\n            supervisions.append(segment)\n\n        recording_set = RecordingSet.from_recordings(recordings)\n        supervision_set = SupervisionSet.from_segments(supervisions)\n\n        recording_set, supervision_set = fix_manifests(recording_set, supervision_set)\n        validate_recordings_and_supervisions(recording_set, supervision_set)\n\n        if output_dir is not None:\n            supervision_set.to_file(output_dir / f\"stcmds_supervisions_{part}.jsonl.gz\")\n            recording_set.to_file(output_dir / f\"stcmds_recordings_{part}.jsonl.gz\")\n\n        manifests[part] = {\"recordings\": recording_set, \"supervisions\": supervision_set}\n\n    return manifests\n", "path": "lhotse/recipes/stcmds.py"}], "after_files": [{"content": "\"\"\"\nStcmds is an open-source  Chinese Mandarin corpus by Surfingtech (www.surfing.ai), containing utterances from 855 speakers, 102600 utterances;\nPublicly available on https://www.openslr.org/resources/38\nST-CMDS (110 hours)\n\n\"\"\"\nimport logging\nimport os\nimport shutil\nimport tarfile\nfrom collections import defaultdict\nfrom pathlib import Path\nfrom typing import Dict, Optional, Union\n\nfrom tqdm.auto import tqdm\n\nfrom lhotse import fix_manifests, validate_recordings_and_supervisions\nfrom lhotse.audio import Recording, RecordingSet\nfrom lhotse.supervision import SupervisionSegment, SupervisionSet\nfrom lhotse.utils import Pathlike, resumable_download, safe_extract\n\n\ndef text_normalize(line: str):\n    \"\"\"\n    Modified from https://github.com/wenet-e2e/wenet/blob/main/examples/multi_cn/s0/local/stcmds_data_prep.sh#L42\n    paste -d' ' $data/utt.list $data/text.list |\\\n    sed 's/\uff0c//g' |\\\n    tr '[a-z]' '[A-Z]' |\\\n    awk '{if (NF > 1) print $0;}' > $data/train/text\n    \"\"\"\n    line = line.replace(\"\uff0c\", \"\")\n    line = line.upper()\n    return line\n\n\ndef download_stcmds(\n    target_dir: Pathlike = \".\",\n    force_download: bool = False,\n    base_url: str = \"http://www.openslr.org/resources\",\n) -> Path:\n    \"\"\"\n    Downdload and untar the dataset\n    :param target_dir: Pathlike, the path of the dir to storage the dataset.\n    :param force_download: Bool, if True, download the tars no matter if the tars exist.\n    :param base_url: str, the url of the OpenSLR resources.\n    :return: the path to downloaded and extracted directory with data.\n    \"\"\"\n    url = f\"{base_url}/38\"\n    target_dir = Path(target_dir)\n    target_dir.mkdir(parents=True, exist_ok=True)\n    corpus_dir = target_dir / \"stcmds\"\n    dataset_tar_name = \"ST-CMDS-20170001_1-OS.tar.gz\"\n    for tar_name in [dataset_tar_name]:\n        tar_path = target_dir / tar_name\n        extracted_dir = corpus_dir / tar_name[:-7]\n        completed_detector = extracted_dir / \".completed\"\n        if completed_detector.is_file():\n            logging.info(f\"Skipping download of because {completed_detector} exists.\")\n            continue\n        resumable_download(\n            f\"{url}/{tar_name}\", filename=tar_path, force_download=force_download\n        )\n        shutil.rmtree(extracted_dir, ignore_errors=True)\n        with tarfile.open(tar_path) as tar:\n            safe_extract(tar, path=corpus_dir)\n        completed_detector.touch()\n\n    return corpus_dir\n\n\ndef prepare_stcmds(\n    corpus_dir: Pathlike, output_dir: Optional[Pathlike] = None\n) -> Dict[str, Dict[str, Union[RecordingSet, SupervisionSet]]]:\n    \"\"\"\n    Returns the manifests which consist of the Recordings and Supervisions\n    :param corpus_dir: Pathlike, the path of the data dir.\n    :param output_dir: Pathlike, the path where to write the manifests.\n    :return: a Dict whose key is the dataset part, and the value is Dicts with the keys 'recordings' and 'supervisions'.\n    \"\"\"\n    corpus_dir = Path(corpus_dir)\n    assert corpus_dir.is_dir(), f\"No such directory: {corpus_dir}\"\n    if output_dir is not None:\n        output_dir = Path(output_dir)\n        output_dir.mkdir(parents=True, exist_ok=True)\n\n    path = corpus_dir / \"ST-CMDS-20170001_1-OS\"\n    transcript_dict = {}\n    for text_path in path.rglob(\"**/*.txt\"):\n        idx = text_path.stem\n        logging.info(f\"processing stcmds transcript  {text_path}\")\n        with open(text_path, \"r\", encoding=\"utf-8\") as f:\n            for line in f:\n                line = text_normalize(line)\n                transcript_dict[idx] = line\n\n    manifests = defaultdict(dict)\n    dataset_parts = [\"train\"]\n    for part in tqdm(\n        dataset_parts,\n        desc=\"process stcmds audio, it needs waste about 2169 seconds time.\",\n    ):\n        logging.info(f\"Processing stcmds {part}\")\n        recordings = []\n        supervisions = []\n        for audio_path in path.rglob(\"**/*.wav\"):\n            idx = audio_path.stem\n            speaker = \"\".join(list(idx)[8:15])\n            if idx not in transcript_dict:\n                logging.warning(f\"No transcript: {idx}\")\n                logging.warning(f\"{audio_path} has no transcript\")\n                continue\n            text = transcript_dict[idx]\n            if not audio_path.is_file():\n                logging.warning(f\"No such file: {audio_path}\")\n                continue\n            recording = Recording.from_file(audio_path)\n            recordings.append(recording)\n            segment = SupervisionSegment(\n                id=idx,\n                recording_id=idx,\n                start=0.0,\n                duration=recording.duration,\n                channel=0,\n                language=\"Chinese\",\n                speaker=speaker,\n                text=text.strip(),\n            )\n            supervisions.append(segment)\n\n        recording_set = RecordingSet.from_recordings(recordings)\n        supervision_set = SupervisionSet.from_segments(supervisions)\n\n        recording_set, supervision_set = fix_manifests(recording_set, supervision_set)\n        validate_recordings_and_supervisions(recording_set, supervision_set)\n\n        if output_dir is not None:\n            supervision_set.to_file(output_dir / f\"stcmds_supervisions_{part}.jsonl.gz\")\n            recording_set.to_file(output_dir / f\"stcmds_recordings_{part}.jsonl.gz\")\n\n        manifests[part] = {\"recordings\": recording_set, \"supervisions\": supervision_set}\n\n    return manifests\n", "path": "lhotse/recipes/stcmds.py"}]}