I am working on a Flutter mobile app that is using a ML model in the app. I am sending my files to a Flask API on a Heroku server to extract the features through python and send them back to the app. My model used the StandardScaler library to scale data, so I recently made changes to export the scaler for use in my API as well so the features can be scaled the same way as my dataset. I had a previous version of this API that was working fine, and when I demoed the new version on my local machine it also worked. But for some reason when I make requests from the mobile app to the server it always times out.
The web app itself is running, and there are no errors in the logs either.
I post the request to the url https://tunetracer-featureextraction-d0dee5876f1e.herokuapp.com:5000/extract_features'
API Directory
app/
|-features.py
|-Procfile
|-requirements.txt
|-scaler
Procfile
web: gunicorn --bind 0.0.0.0:$PORT features:app
features.py
from flask import Flask, request, jsonify
import librosa
import numpy as np
import joblib
from sklearn.preprocessing import StandardScaler
import os
app = Flask(__name__)
@app.route('/extract_features', methods=['POST'])
def extract_features():
# Check if the POST request has the file part
if 'file' not in request.files:
return jsonify({'error': 'No file part'})
file = request.files['file']
# If user does not select file, browser also
# submit an empty part without filename
if file.filename == '':
return jsonify({'error': 'No selected file'})
if file:
try:
scaler = joblib.load('scaler')
y, sr = librosa.load(file, mono=True, duration=30)
chroma_stft = librosa.feature.chroma_stft(y=y, sr=sr)
rmse = librosa.feature.rms(y=y)
spec_cent = librosa.feature.spectral_centroid(y=y, sr=sr)
spec_bw = librosa.feature.spectral_bandwidth(y=y, sr=sr)
rolloff = librosa.feature.spectral_rolloff(y=y, sr=sr)
zcr = librosa.feature.zero_crossing_rate(y)
mfcc = librosa.feature.mfcc(y=y, sr=sr)
list = [[]]
#read features into a list
list[0] = [np.mean(chroma_stft), np.mean(rmse), np.mean(spec_cent), np.mean(spec_bw), np.mean(rolloff), np.mean(zcr)]
list[0] += [np.mean(e) for e in mfcc]
#scale the list
list[0] = np.array(scaler.transform(list), dtype = float)
#change floats to strings
feature_list = [str(f) for f in list[0][0]]
#send list back to app
return jsonify({'features': feature_list})
except Exception as e:
return jsonify({'error': str(e)})
port = int(os.environ.get("PORT", 5000))
if __name__ == '__main__':
app.run(debug=True, port=port, host='0.0.0.0')
requirements.txt
Flask==3.0.2
gunicorn==21.2.0
joblib==1.3.2
librosa==0.10.1
numpy==1.26.4
sklearn-preprocessing==0.1.0
StandardScaler==0.5
logs
2024-04-11T18:34:09.432238+00:00 heroku[web.1]: State changed from crashed to starting
2024-04-11T18:34:25.336192+00:00 heroku[web.1]: Starting process with command `gunicorn --bind 0.0.0.0:39275 features:app`
2024-04-11T18:34:26.050154+00:00 app[web.1]: Python buildpack: Detected 512 MB available memory and 8 CPU cores.
2024-04-11T18:34:26.050248+00:00 app[web.1]: Python buildpack: Defaulting WEB_CONCURRENCY to 2 based on the available memory.
2024-04-11T18:34:26.267579+00:00 app[web.1]: [2024-04-11 18:34:26 +0000] [2] [INFO] Starting gunicorn 21.2.0
2024-04-11T18:34:26.267900+00:00 app[web.1]: [2024-04-11 18:34:26 +0000] [2] [INFO] Listening at: http://0.0.0.0:39275 (2)
2024-04-11T18:34:26.267933+00:00 app[web.1]: [2024-04-11 18:34:26 +0000] [2] [INFO] Using worker: sync
2024-04-11T18:34:26.270092+00:00 app[web.1]: [2024-04-11 18:34:26 +0000] [9] [INFO] Booting worker with pid: 9
2024-04-11T18:34:26.352229+00:00 app[web.1]: [2024-04-11 18:34:26 +0000] [10] [INFO] Booting worker with pid: 10
2024-04-11T18:34:26.644297+00:00 heroku[web.1]: State changed from starting to up
2024-04-11T18:34:40.000000+00:00 app[api]: Build succeeded
Your heroku app should be reached without using a port number. Use the URL https://tunetracer-featureextraction-d0dee5876f1e.herokuapp.com/extract_features
(without :5000
). Heroku does the reverse proxying to the dynamic port it assigns to your app ($PORT
). So you can just reach it on standard http(s) ports.