We are currently solving the following issue within our repository. Here is the issue text:
--- BEGIN ISSUE ---
torchaudio has to be optional
@bpopeters 
The last change https://github.com/OpenNMT/OpenNMT-py/pull/1144/files
made torchaudio a requirement, not an optional one as it should be.

Can you fix it please ?
Thanks.

--- END ISSUE ---

Below are some code segments, each from a relevant file. One or more of these files may contain bugs.
--- BEGIN FILES ---
Path: `onmt/inputters/audio_dataset.py`
Content:
```
1 # -*- coding: utf-8 -*-
2 import os
3 from tqdm import tqdm
4 
5 import torch
6 import torchaudio
7 import librosa
8 import numpy as np
9 
10 from onmt.inputters.dataset_base import DatasetBase
11 
12 
13 class AudioDataset(DatasetBase):
14     data_type = 'audio'  # get rid of this class attribute asap
15 
16     @staticmethod
17     def sort_key(ex):
18         """ Sort using duration time of the sound spectrogram. """
19         return ex.src.size(1)
20 
21     @staticmethod
22     def extract_features(audio_path, sample_rate, truncate, window_size,
23                          window_stride, window, normalize_audio):
24         # torchaudio loading options recently changed. It's probably
25         # straightforward to rewrite the audio handling to make use of
26         # up-to-date torchaudio, but in the meantime there is a legacy
27         # method which uses the old defaults
28         sound, sample_rate_ = torchaudio.legacy.load(audio_path)
29         if truncate and truncate > 0:
30             if sound.size(0) > truncate:
31                 sound = sound[:truncate]
32 
33         assert sample_rate_ == sample_rate, \
34             'Sample rate of %s != -sample_rate (%d vs %d)' \
35             % (audio_path, sample_rate_, sample_rate)
36 
37         sound = sound.numpy()
38         if len(sound.shape) > 1:
39             if sound.shape[1] == 1:
40                 sound = sound.squeeze()
41             else:
42                 sound = sound.mean(axis=1)  # average multiple channels
43 
44         n_fft = int(sample_rate * window_size)
45         win_length = n_fft
46         hop_length = int(sample_rate * window_stride)
47         # STFT
48         d = librosa.stft(sound, n_fft=n_fft, hop_length=hop_length,
49                          win_length=win_length, window=window)
50         spect, _ = librosa.magphase(d)
51         spect = np.log1p(spect)
52         spect = torch.FloatTensor(spect)
53         if normalize_audio:
54             mean = spect.mean()
55             std = spect.std()
56             spect.add_(-mean)
57             spect.div_(std)
58         return spect
59 
60     @classmethod
61     def make_examples(
62         cls,
63         data,
64         src_dir,
65         side,
66         sample_rate,
67         window_size,
68         window_stride,
69         window,
70         normalize_audio,
71         truncate=None
72     ):
73         """
74         Args:
75             data: sequence of audio paths or path containing these sequences
76             src_dir (str): location of source audio files.
77             side (str): 'src' or 'tgt'.
78             sample_rate (int): sample_rate.
79             window_size (float) : window size for spectrogram in seconds.
80             window_stride (float): window stride for spectrogram in seconds.
81             window (str): window type for spectrogram generation.
82             normalize_audio (bool): subtract spectrogram by mean and divide
83                 by std or not.
84             truncate (int): maximum audio length (0 or None for unlimited).
85 
86         Yields:
87             a dictionary containing audio data for each line.
88         """
89         assert src_dir is not None and os.path.exists(src_dir),\
90             "src_dir must be a valid directory if data_type is audio"
91 
92         if isinstance(data, str):
93             data = cls._read_file(data)
94 
95         for i, line in enumerate(tqdm(data)):
96             audio_path = os.path.join(src_dir, line.strip())
97             if not os.path.exists(audio_path):
98                 audio_path = line.strip()
99 
100             assert os.path.exists(audio_path), \
101                 'audio path %s not found' % (line.strip())
102 
103             spect = AudioDataset.extract_features(
104                 audio_path, sample_rate, truncate, window_size,
105                 window_stride, window, normalize_audio
106             )
107 
108             yield {side: spect, side + '_path': line.strip(),
109                    side + '_lengths': spect.size(1), 'indices': i}
110
```
--- 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/onmt/inputters/audio_dataset.py b/onmt/inputters/audio_dataset.py
--- a/onmt/inputters/audio_dataset.py
+++ b/onmt/inputters/audio_dataset.py
@@ -3,9 +3,6 @@
 from tqdm import tqdm
 
 import torch
-import torchaudio
-import librosa
-import numpy as np
 
 from onmt.inputters.dataset_base import DatasetBase
 
@@ -21,6 +18,9 @@
     @staticmethod
     def extract_features(audio_path, sample_rate, truncate, window_size,
                          window_stride, window, normalize_audio):
+        import torchaudio
+        import librosa
+        import numpy as np
         # torchaudio loading options recently changed. It's probably
         # straightforward to rewrite the audio handling to make use of
         # up-to-date torchaudio, but in the meantime there is a legacy

{"golden_diff": "diff --git a/onmt/inputters/audio_dataset.py b/onmt/inputters/audio_dataset.py\n--- a/onmt/inputters/audio_dataset.py\n+++ b/onmt/inputters/audio_dataset.py\n@@ -3,9 +3,6 @@\n from tqdm import tqdm\n \n import torch\n-import torchaudio\n-import librosa\n-import numpy as np\n \n from onmt.inputters.dataset_base import DatasetBase\n \n@@ -21,6 +18,9 @@\n     @staticmethod\n     def extract_features(audio_path, sample_rate, truncate, window_size,\n                          window_stride, window, normalize_audio):\n+        import torchaudio\n+        import librosa\n+        import numpy as np\n         # torchaudio loading options recently changed. It's probably\n         # straightforward to rewrite the audio handling to make use of\n         # up-to-date torchaudio, but in the meantime there is a legacy\n", "issue": "torchaudio has to be optional\n@bpopeters \r\nThe last change https://github.com/OpenNMT/OpenNMT-py/pull/1144/files\r\nmade torchaudio a requirement, not an optional one as it should be.\r\n\r\nCan you fix it please ?\r\nThanks.\n", "before_files": [{"content": "# -*- coding: utf-8 -*-\nimport os\nfrom tqdm import tqdm\n\nimport torch\nimport torchaudio\nimport librosa\nimport numpy as np\n\nfrom onmt.inputters.dataset_base import DatasetBase\n\n\nclass AudioDataset(DatasetBase):\n    data_type = 'audio'  # get rid of this class attribute asap\n\n    @staticmethod\n    def sort_key(ex):\n        \"\"\" Sort using duration time of the sound spectrogram. \"\"\"\n        return ex.src.size(1)\n\n    @staticmethod\n    def extract_features(audio_path, sample_rate, truncate, window_size,\n                         window_stride, window, normalize_audio):\n        # torchaudio loading options recently changed. It's probably\n        # straightforward to rewrite the audio handling to make use of\n        # up-to-date torchaudio, but in the meantime there is a legacy\n        # method which uses the old defaults\n        sound, sample_rate_ = torchaudio.legacy.load(audio_path)\n        if truncate and truncate > 0:\n            if sound.size(0) > truncate:\n                sound = sound[:truncate]\n\n        assert sample_rate_ == sample_rate, \\\n            'Sample rate of %s != -sample_rate (%d vs %d)' \\\n            % (audio_path, sample_rate_, sample_rate)\n\n        sound = sound.numpy()\n        if len(sound.shape) > 1:\n            if sound.shape[1] == 1:\n                sound = sound.squeeze()\n            else:\n                sound = sound.mean(axis=1)  # average multiple channels\n\n        n_fft = int(sample_rate * window_size)\n        win_length = n_fft\n        hop_length = int(sample_rate * window_stride)\n        # STFT\n        d = librosa.stft(sound, n_fft=n_fft, hop_length=hop_length,\n                         win_length=win_length, window=window)\n        spect, _ = librosa.magphase(d)\n        spect = np.log1p(spect)\n        spect = torch.FloatTensor(spect)\n        if normalize_audio:\n            mean = spect.mean()\n            std = spect.std()\n            spect.add_(-mean)\n            spect.div_(std)\n        return spect\n\n    @classmethod\n    def make_examples(\n        cls,\n        data,\n        src_dir,\n        side,\n        sample_rate,\n        window_size,\n        window_stride,\n        window,\n        normalize_audio,\n        truncate=None\n    ):\n        \"\"\"\n        Args:\n            data: sequence of audio paths or path containing these sequences\n            src_dir (str): location of source audio files.\n            side (str): 'src' or 'tgt'.\n            sample_rate (int): sample_rate.\n            window_size (float) : window size for spectrogram in seconds.\n            window_stride (float): window stride for spectrogram in seconds.\n            window (str): window type for spectrogram generation.\n            normalize_audio (bool): subtract spectrogram by mean and divide\n                by std or not.\n            truncate (int): maximum audio length (0 or None for unlimited).\n\n        Yields:\n            a dictionary containing audio data for each line.\n        \"\"\"\n        assert src_dir is not None and os.path.exists(src_dir),\\\n            \"src_dir must be a valid directory if data_type is audio\"\n\n        if isinstance(data, str):\n            data = cls._read_file(data)\n\n        for i, line in enumerate(tqdm(data)):\n            audio_path = os.path.join(src_dir, line.strip())\n            if not os.path.exists(audio_path):\n                audio_path = line.strip()\n\n            assert os.path.exists(audio_path), \\\n                'audio path %s not found' % (line.strip())\n\n            spect = AudioDataset.extract_features(\n                audio_path, sample_rate, truncate, window_size,\n                window_stride, window, normalize_audio\n            )\n\n            yield {side: spect, side + '_path': line.strip(),\n                   side + '_lengths': spect.size(1), 'indices': i}\n", "path": "onmt/inputters/audio_dataset.py"}], "after_files": [{"content": "# -*- coding: utf-8 -*-\nimport os\nfrom tqdm import tqdm\n\nimport torch\n\nfrom onmt.inputters.dataset_base import DatasetBase\n\n\nclass AudioDataset(DatasetBase):\n    data_type = 'audio'  # get rid of this class attribute asap\n\n    @staticmethod\n    def sort_key(ex):\n        \"\"\" Sort using duration time of the sound spectrogram. \"\"\"\n        return ex.src.size(1)\n\n    @staticmethod\n    def extract_features(audio_path, sample_rate, truncate, window_size,\n                         window_stride, window, normalize_audio):\n        import torchaudio\n        import librosa\n        import numpy as np\n        # torchaudio loading options recently changed. It's probably\n        # straightforward to rewrite the audio handling to make use of\n        # up-to-date torchaudio, but in the meantime there is a legacy\n        # method which uses the old defaults\n        sound, sample_rate_ = torchaudio.legacy.load(audio_path)\n        if truncate and truncate > 0:\n            if sound.size(0) > truncate:\n                sound = sound[:truncate]\n\n        assert sample_rate_ == sample_rate, \\\n            'Sample rate of %s != -sample_rate (%d vs %d)' \\\n            % (audio_path, sample_rate_, sample_rate)\n\n        sound = sound.numpy()\n        if len(sound.shape) > 1:\n            if sound.shape[1] == 1:\n                sound = sound.squeeze()\n            else:\n                sound = sound.mean(axis=1)  # average multiple channels\n\n        n_fft = int(sample_rate * window_size)\n        win_length = n_fft\n        hop_length = int(sample_rate * window_stride)\n        # STFT\n        d = librosa.stft(sound, n_fft=n_fft, hop_length=hop_length,\n                         win_length=win_length, window=window)\n        spect, _ = librosa.magphase(d)\n        spect = np.log1p(spect)\n        spect = torch.FloatTensor(spect)\n        if normalize_audio:\n            mean = spect.mean()\n            std = spect.std()\n            spect.add_(-mean)\n            spect.div_(std)\n        return spect\n\n    @classmethod\n    def make_examples(\n        cls,\n        data,\n        src_dir,\n        side,\n        sample_rate,\n        window_size,\n        window_stride,\n        window,\n        normalize_audio,\n        truncate=None\n    ):\n        \"\"\"\n        Args:\n            data: sequence of audio paths or path containing these sequences\n            src_dir (str): location of source audio files.\n            side (str): 'src' or 'tgt'.\n            sample_rate (int): sample_rate.\n            window_size (float) : window size for spectrogram in seconds.\n            window_stride (float): window stride for spectrogram in seconds.\n            window (str): window type for spectrogram generation.\n            normalize_audio (bool): subtract spectrogram by mean and divide\n                by std or not.\n            truncate (int): maximum audio length (0 or None for unlimited).\n\n        Yields:\n            a dictionary containing audio data for each line.\n        \"\"\"\n        assert src_dir is not None and os.path.exists(src_dir),\\\n            \"src_dir must be a valid directory if data_type is audio\"\n\n        if isinstance(data, str):\n            data = cls._read_file(data)\n\n        for i, line in enumerate(tqdm(data)):\n            audio_path = os.path.join(src_dir, line.strip())\n            if not os.path.exists(audio_path):\n                audio_path = line.strip()\n\n            assert os.path.exists(audio_path), \\\n                'audio path %s not found' % (line.strip())\n\n            spect = AudioDataset.extract_features(\n                audio_path, sample_rate, truncate, window_size,\n                window_stride, window, normalize_audio\n            )\n\n            yield {side: spect, side + '_path': line.strip(),\n                   side + '_lengths': spect.size(1), 'indices': i}\n", "path": "onmt/inputters/audio_dataset.py"}]}