#!/usr/bin/env python3 import tempfile import os from flask import request, jsonify, current_app, abort, Response from flask_classful import FlaskView, route from model import db, Default, AIModel from minio.error import BucketAlreadyExists, BucketAlreadyOwnedByYou, ResponseError, NoSuchKey from schemas import AIModelSchema, DefaultSchema, InfoSchema from marshmallow.exceptions import ValidationError from utils import json_required, storage from pyAudioAnalysis.audioTrainTest import load_model, load_model_knn class ModelView(FlaskView): aimodel_schema = AIModelSchema(many=False) default_schema = DefaultSchema(many=False) info_schema = InfoSchema(many=False) def _ensure_buckets(self): for bucket_name in [current_app.config['MINIO_MEANS_BUCKET_NAME'], current_app.config['MINIO_MODEL_BUCKET_NAME']]: try: storage.connection.make_bucket(bucket_name) except BucketAlreadyOwnedByYou as err: pass except BucketAlreadyExists as err: pass # Everything else should be raised def post(self): # get important data from the request try: info = self.info_schema.loads(request.form.get('info')) except ValidationError as e: abort(400, str(e)) # check for conflict m = AIModel.query.filter_by(id=info['id']).first() if m: abort(409) # get and validate file model_file = request.files['modelFile'] if model_file.content_length <= 0: abort(411, f"Content length for modelFile is not a positive integer or missing.") means_file = request.files['meansFile'] if means_file.content_length <= 0: abort(411, f"Content length for meansFile is not a positive integer or missing.") # create bucket if necessary self._ensure_buckets() # Temporarily save the file, because pyAudioAnalysis can only read files _, temp_model_filename = tempfile.mkstemp() temp_means_filename = temp_model_filename + "MEANS" model_file.save(temp_model_filename) means_file.save(temp_means_filename) try: if info['type'] == 'knn': _, _, _, _, mid_window, mid_step, short_window, short_step, compute_beat \ = load_model_knn(temp_model_filename) else: _, _, _, _, mid_window, mid_step, short_window, short_step, compute_beat \ = load_model(temp_model_filename) # Because of pyAudiomeme the files already saved, so we just use the file uploader functions storage.connection.fput_object( current_app.config['MINIO_MODEL_BUCKET_NAME'], str(info['id']), temp_model_filename ) storage.connection.fput_object( current_app.config['MINIO_MEANS_BUCKET_NAME'], str(info['id']), temp_means_filename ) finally: os.remove(temp_model_filename) os.remove(temp_means_filename) m = AIModel(mid_window=mid_window, mid_step=mid_step, short_window=short_window, short_step=short_step, compute_beat=compute_beat, type=info['type']) db.session.add(m) db.session.commit() return jsonify(self.aimodel_schema.dump(m)), 200 def get(self, _id: str): if _id == "$default": default = Default.query.first_or_404() # TODO: Kitalálni, hogy inkább a latestestest-el térjen-e vissza m = default.default else: m = AIModel.query.fiter_by(id=_id).first_or_404() try: data = storage.connection.get_object(current_app.config['MINIO_BUCKET_NAME'], str(m.id)) except NoSuchKey: abort(500, "The ID is stored in the database but not int the Object Store") return Response(data.stream(), mimetype=data.headers['Content-type']) @route('<_id>/details') def get_details(self, _id: str): if _id == "$default": default = Default.query.first_or_404() # TODO: Kitalálni, hogy inkább a latestestest-el térjen-e vissza m = default.default else: m = AIModel.query.fiter_by(id=_id).first_or_404() return jsonify(self.aimodel_schema.dump(m)) def delete(self, _id: str): m = AIModel.query.fiter_by(id=_id).first_or_404() storage.connection.remove_object(current_app.config['MINIO_BUCKET_NAME'], m.id) db.session.delete(m) db.session.commit() return '', 204 @json_required @route('$default', methods=['PUT']) def put_default(self): try: req = self.default_schema.load(request.json()) except ValidationError as e: abort(404, str(e)) m = AIModel.query.fiter_by(id=req['id']).first_or_404() Default.query.delete() new_default = Default(m) db.session.add(new_default) db.session.commit() return '', 204