|
19 | 19 | from predict import initModel
|
20 | 20 | from utils.utils import AudioList
|
21 | 21 |
|
| 22 | +from google.cloud import storage |
| 23 | +import io |
| 24 | + |
22 | 25 | import logging
|
23 | 26 | logging.basicConfig(level=logging.INFO, format='%(asctime)s - %(levelname)s - %(message)s')
|
24 | 27 |
|
@@ -55,16 +58,68 @@ def send_email(subject, body):
|
55 | 58 | logging.error(f"Error sending email: {e}")
|
56 | 59 |
|
57 | 60 |
|
| 61 | +from pydub import AudioSegment |
| 62 | +import io |
| 63 | + |
| 64 | +def convert_mp3_to_wav(mp3_file_object): |
| 65 | + # Load MP3 file from file object |
| 66 | + audio = AudioSegment.from_file(mp3_file_object, format="mp3") |
| 67 | + |
| 68 | + # Convert to WAV |
| 69 | + wav_file_object = io.BytesIO() |
| 70 | + audio.export(wav_file_object, format="wav") |
| 71 | + wav_file_object.seek(0) # Move file pointer to the start |
| 72 | + |
| 73 | + return wav_file_object |
| 74 | + |
| 75 | + |
| 76 | +def fetch_audio_data(bucket_name, blob_name): |
| 77 | + """ |
| 78 | + Fetches audio data from Google Cloud Storage. |
| 79 | +
|
| 80 | + Parameters: |
| 81 | + bucket_name (str): The name of the GCS bucket. |
| 82 | + blob_name (str): The name of the blob (file) in the GCS bucket. |
| 83 | +
|
| 84 | + Returns: |
| 85 | + BytesIO: An in-memory file object of the audio data. |
| 86 | + """ |
| 87 | + # Create a GCS client |
| 88 | + from google.oauth2 import service_account |
| 89 | + import google.auth |
| 90 | + |
| 91 | + credentials = service_account.Credentials.from_service_account_file( |
| 92 | + '/app/cloud_analysis/g_application_credentials.json' |
| 93 | +) |
| 94 | + |
| 95 | + storage_client = storage.Client(credentials=credentials) |
| 96 | + |
| 97 | + # Get the GCS bucket and blob |
| 98 | + bucket = storage_client.get_bucket(bucket_name) |
| 99 | + blob = bucket.blob(blob_name) |
| 100 | + |
| 101 | + # Download the file into an in-memory file object |
| 102 | + audio_file_object = io.BytesIO() |
| 103 | + blob.download_to_file(audio_file_object) |
| 104 | + audio_file_object.seek(0) # Move file pointer to the start |
| 105 | + |
| 106 | + # Convert MP3 to WAV |
| 107 | + wav_file_object = convert_mp3_to_wav(audio_file_object) |
| 108 | + |
| 109 | + return wav_file_object |
| 110 | + |
| 111 | + |
58 | 112 | def analyseAudioFile(
|
59 |
| - audio_file_path, batch_size=1, num_workers=4, min_hr = 0.1, min_conf = 0.99 |
| 113 | + audio_file_object, batch_size=1, num_workers=4, min_hr = 0.1, min_conf = 0.99 |
60 | 114 | ):
|
| 115 | + |
61 | 116 | # Initiate model
|
62 | 117 | device = torch.device("cuda" if torch.cuda.is_available() else "cpu")
|
63 | 118 | model_path = "/app/audioclip/assets/snowmobile_model.pth"
|
64 | 119 | model = initModel(model_path=model_path, device=device)
|
65 | 120 |
|
66 | 121 | # Run the predictions
|
67 |
| - list_preds = AudioList().get_processed_list(audio_file_path) |
| 122 | + list_preds = AudioList().get_processed_list(audio_file_object) |
68 | 123 | predLoader = DataLoader(list_preds, batch_size=batch_size, num_workers=num_workers, pin_memory=False)
|
69 | 124 | prob_audioclip_array, hr_array = predict(predLoader, model, device)
|
70 | 125 |
|
@@ -93,15 +148,14 @@ def analyseAudioFile(
|
93 | 148 |
|
94 | 149 | return results
|
95 | 150 |
|
96 |
| -def on_process_audio( |
97 |
| - audio_id: str, audio_rec: dict, audio_file_path: str |
98 |
| -): |
| 151 | +def on_process_audio(audio_id: str, audio_rec: dict, bucket_name: str, blob_name: str): |
99 | 152 |
|
100 | 153 | print(f"PROCESSING audioId={audio_id}")
|
101 | 154 | location = audio_rec["location"]
|
102 | 155 |
|
103 | 156 | # A call out to your code here. Optionally we can pass on the recorder coordinates
|
104 |
| - results = analyseAudioFile(audio_file_path) |
| 157 | + audio_file_object = fetch_audio_data(bucket_name, blob_name) |
| 158 | + results = analyseAudioFile(audio_file_object) |
105 | 159 | # The object results is a list containing detections in the form:
|
106 | 160 | # [start, end, confidence, harmonic ratio]
|
107 | 161 |
|
@@ -130,15 +184,17 @@ def on_process_audio(
|
130 | 184 |
|
131 | 185 | @app.route('/process-audio', methods=['POST'])
|
132 | 186 | def process_audio_endpoint():
|
133 |
| - audio_file_path = request.json['audio_file_path'] |
134 |
| - audio_id = request.json['audio_id'] |
135 |
| - audio_rec = request.json['audio_rec'] |
| 187 | + data = request.json |
| 188 | + bucket_name = data['bucket_name'] |
| 189 | + blob_name = data['blob_name'] |
| 190 | + audio_id = data['audio_id'] |
| 191 | + audio_rec = data['audio_rec'] |
136 | 192 |
|
137 |
| - detection_count = on_process_audio(audio_id, audio_rec, audio_file_path) |
| 193 | + results = on_process_audio(audio_id, audio_rec, bucket_name, blob_name) |
| 194 | + |
| 195 | + if results > 0: |
| 196 | + send_email("Snowmobile Detection Alert", f"{results} snowmobile detections were made in the audio file!") |
138 | 197 |
|
139 |
| - if detection_count > 0: |
140 |
| - send_email("Snowmobile Detection Alert", f"{detection_count} snowmobile detections were made in the audio file!") |
141 |
| - |
142 | 198 | return jsonify({"message": "Audio processing completed!"})
|
143 | 199 |
|
144 | 200 |
|
|
0 commit comments