Issue
I am using FastAPI to create an API that receives small audio files from a mobile app. In this API I do processing of the signal and I am able to return a response after classifying that sound. The final goal is to send the classification back to the user.
Here's what I am doing so far:
@app.post("/predict")
def predict(file: UploadFile = File(...)): # Upload the wav audio sent from the mobile app user
with open(name_file, "wb") as buffer:
shutil.copyfileobj(file.file, buffer) #creating a file with the received audio data
...
prev= test.my_classification_module(name_file) #some processing and the goal response in PREV variable
In my_classification_module()
, I have this :
X, sr = librosa.load(sound_file)
I want to avoid creating a file to be classified with librosa
. I would like to do this with a temporary file, without using memory unecessarily and to avoid the overlap of files when the app is used by multiple users.
Solution
If your function supports a file-like object, you could use the .file
attribute of UploadFile
, e.g., file.file
(which is a SpooledTemporaryFile
instance), or if your function requires the file in bytes
format, use the .read()
async method (see the documentation). If you wish to keep your route defined with def
instead of async def
(have a look at this answer for more info on def
vs async def
), you could use the .read()
method of the file-like object directly, e.g., file.file.read()
.
Update - How to resolve File contains data in an unknown format
error
Make sure the audio file is not corrupted. If, let's say, you saved it and opened it with a media player, would the sound file play?
Make sure you have the latest version of
librosa
module installed.Try installing
ffmpeg
and adding it to the system path, as suggested here.As described here and in the documentation,
librosa.load()
can take a file-like object as an alternative to a file path - thus, usingfile.file
orfile.file._file
should normally be fine (as per the documentation,_file
attribute is either anio.BytesIO
orio.TextIOWrapper
object...).However, as described in the documentation here and here, as well as in this github discussion, you could also use the soundfile module to read audio from file-like objects. Example:
import soundfile as sf data, samplerate = sf.read(file.file)
You could also write the file
contents
of the uploaded file to a BytesIO stream, and then pass it to eithersf.read()
orlibrosa.load()
:from io import BytesIO contents = file.file.read() buffer = BytesIO(contents) data, samplerate = librosa.load(buffer) # ussing librosa module #data, samplerate = sf.read(buffer) # using soundfile module buffer.close()
Another option would be to save the file
contents
to aNamedTemporaryFile
, which "has a visible name in the file system" that "can be used to open the file". Once you are done with it, you can manually delete it using theremove()
orunlink()
method.from tempfile import NamedTemporaryFile import os contents = file.file.read() temp = NamedTemporaryFile(delete=False) try: with temp as f: f.write(contents); data, samplerate = librosa.load(temp.name) # ussing librosa module #data, samplerate = sf.read(temp.name) # using soundfile module finally: temp.close() os.unlink(temp.name)
Answered By - Chris Answer Checked By - Katrina (PHPFixing Volunteer)
0 Comments:
Post a Comment
Note: Only a member of this blog may post a comment.