-
Notifications
You must be signed in to change notification settings - Fork 1
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
[ADD] Folder containing cloud_analysis scripts
- Loading branch information
1 parent
96f8eb8
commit 5bf8189
Showing
3 changed files
with
216 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,33 @@ | ||
FROM python:3.8-bullseye | ||
|
||
ARG PACKAGES="ffmpeg build-essential unzip gcsfuse" | ||
|
||
ARG DEBIAN_FRONTEND=noninteractive | ||
RUN \ | ||
echo "deb https://packages.cloud.google.com/apt gcsfuse-bullseye main" | tee /etc/apt/sources.list.d/gcsfuse.list && \ | ||
curl https://packages.cloud.google.com/apt/doc/apt-key.gpg | apt-key add - && \ | ||
apt-get update && \ | ||
apt-get install -qq $PACKAGES && \ | ||
rm -rf /var/lib/apt/lists/* | ||
|
||
RUN pip3 install poetry | ||
|
||
WORKDIR /app | ||
|
||
# Clone the repository and download assets | ||
RUN mkdir audioclip | ||
RUN cd audioclip | ||
RUN wget https://zenodo.org/record/7969521/files/assets.zip?download=1 | ||
RUN unzip ./assets.zip?download=1 | ||
RUN cd ../ | ||
|
||
# Package install | ||
COPY . ./ | ||
RUN poetry config virtualenvs.create false | ||
RUN poetry install --no-root | ||
|
||
|
||
|
||
ENV PYTHONPATH "${PYTHONPATH}:/app:/app/audioclip:/app:/app/src" | ||
ENTRYPOINT ["python", "/app/cloud_analysis/main.py"] | ||
|
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,64 @@ | ||
# Documentation on running a Docker container on google cloud | ||
|
||
## General stuff with GCloud UI | ||
|
||
- If lost, there is a button `console` on the upper right corner that brings us back to the projects | ||
|
||
|
||
## Login stuff | ||
|
||
1- Generate the Google Cloud credentials: | ||
|
||
``` | ||
gcloud auth application-default login | ||
``` | ||
|
||
The credentials are stored in `~/.config/gcloud/` | ||
|
||
2- Login to your Google Cloud account: | ||
|
||
``` | ||
gcloud auth login | ||
``` | ||
|
||
3- Log in to the project | ||
|
||
``` | ||
gcloud config set project snokuter-akustikk | ||
``` | ||
|
||
## Docker stuff | ||
|
||
1- Enable services | ||
|
||
Enable the Cloud Functions, Cloud Run, and Cloud Build APIs: | ||
|
||
``` | ||
gcloud services enable cloudfunctions.googleapis.com | ||
gcloud services enable run.googleapis.com | ||
gcloud services enable cloudbuild.googleapis.com | ||
``` | ||
|
||
2- Set up credentials on Google Cloud: | ||
|
||
The credentials are stored in `~/.docker/config.json` | ||
|
||
``` | ||
gcloud auth configure-docker | ||
``` | ||
|
||
3- Change the name of the image to push it on GCloud | ||
|
||
The Docker image will be saved in Google's container registry, which is directly supported by Cloud Run | ||
|
||
``` | ||
docker tag ghcr.io/ninanor/snowmobile_analyzer:main gcr.io/snoskuter-akustikk/snowmobile_analyzer:main | ||
docker push gcr.io/snoskuter-akustikk/snowmobile_analyzer:main | ||
``` | ||
|
||
4- Deploy the Docker image to Google Cloud run | ||
|
||
``` | ||
gcloud run deploy model --image gcr.io/snoskuter-akustikk/snowmobile_analyzer:main | ||
``` |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,119 @@ | ||
|
||
#!/usr/env/bin python3 | ||
|
||
from flask import Flask, request, jsonify | ||
app = Flask(__name__) | ||
|
||
import argparse | ||
import numpy as np | ||
|
||
import torch | ||
from torch.utils.data import DataLoader | ||
|
||
from predict import predict | ||
from predict import initModel | ||
from utils.utils import AudioList | ||
|
||
|
||
def analyseAudioFile( | ||
audio_file_path, batch_size=1, num_workers=4, min_hr = 0.1, min_conf = 0.99 | ||
): | ||
# Initiate model | ||
device = torch.device("cuda" if torch.cuda.is_available() else "cpu") | ||
model_path = "./assets/snowmobile_model.pth" | ||
model = initModel(model_path=model_path, device=device) | ||
|
||
# Run the predictions | ||
list_preds = AudioList().get_processed_list(audio_file_path) | ||
predLoader = DataLoader(list_preds, batch_size=batch_size, num_workers=num_workers, pin_memory=False) | ||
prob_audioclip_array, hr_array = predict(predLoader, model, device) | ||
|
||
# Set index of the array to 0 (beginning) | ||
idx_begin = 0 | ||
|
||
# List of results | ||
results = [] | ||
|
||
for item_audioclip, item_hr in zip(prob_audioclip_array, hr_array): | ||
|
||
# Get the properties of the detection (start, end, label, confidence and harmonic ratio) | ||
idx_end = idx_begin + 3 | ||
conf = np.array(item_audioclip) | ||
label = np.argmax(conf, axis=0) | ||
confidence = conf.max() | ||
hr = np.array(item_hr) | ||
|
||
# If the label is not "soundscape" then write the row: | ||
if label != 0 and hr > min_hr and confidence > min_conf: | ||
item_properties = [idx_begin, idx_end, confidence, hr] | ||
results.append(item_properties) | ||
|
||
# Update the start time of the detection | ||
idx_begin = idx_end | ||
|
||
return results | ||
|
||
def on_process_audio( | ||
audio_id: str, audio_rec: dict, audio_file_path: str | ||
): | ||
|
||
print(f"PROCESSING audioId={audio_id}") | ||
location = audio_rec["location"] | ||
|
||
# A call out to your code here. Optionally we can pass on the recorder coordinates | ||
results = analyseAudioFile(audio_file_path) | ||
# The object results is a list containing detections in the form: | ||
# [start, end, confidence, harmonic ratio] | ||
|
||
# After processing we record each detection in the database. | ||
# Each detection should have a start and end time which is used to create an audio clip later. | ||
detections = [] | ||
for r in results: | ||
start, end, confidence, harmonic_ratio = r | ||
# create the detections | ||
detections.append({ | ||
u"start": start, | ||
u"end": end, | ||
u"tags": ["snowmobile"], | ||
#u"analysisId": analysis_id, | ||
# Add any other information you want to record here | ||
u"confidence": confidence, | ||
u"harmonic_ratio": harmonic_ratio | ||
}) | ||
|
||
print(detections) | ||
print(f"{audio_id} completed with {len(detections)} detections") | ||
|
||
|
||
@app.route('/process-audio', methods=['POST']) | ||
def process_audio_endpoint(): | ||
audio_file_path = request.json['audio_file_path'] | ||
audio_id = request.json['audio_id'] | ||
audio_rec = request.json['audio_rec'] | ||
|
||
on_process_audio(audio_id, audio_rec, audio_file_path) | ||
|
||
return jsonify({"message": "Audio processing completed!"}) | ||
|
||
|
||
if __name__ == "__main__": | ||
|
||
|
||
parser = argparse.ArgumentParser() | ||
|
||
parser.add_argument( | ||
"--input", | ||
help="Path to the file to analyze", | ||
required=True, | ||
type=str, | ||
) | ||
|
||
cli_args = parser.parse_args() | ||
|
||
on_process_audio("my-audio-id", { | ||
"location": { | ||
"latitude": 0, | ||
"longitude": 0 | ||
} | ||
}, cli_args.input) | ||
|