def post(self, request):
        printer = request.auth

        pic = request.FILES['pic']
        pic_id = int(timezone.now().timestamp())
        internal_url, external_url = save_file_obj(
            'raw/{}/{}.jpg'.format(printer.id, pic_id), pic,
            settings.PICS_CONTAINER)

        if not printer.is_printing():
            redis.printer_pic_set(printer.id, {'img_url': external_url},
                                  ex=STATUS_TTL_SECONDS)
            return command_response(printer)

        req = requests.get(settings.ML_API_HOST + '/p/',
                           params={'img': internal_url},
                           headers=ml_api_auth_headers(),
                           verify=False)
        req.raise_for_status()
        resp = req.json()

        detections = resp['detections']
        prediction, _ = PrinterPrediction.objects.get_or_create(
            printer=printer)
        update_prediction_with_detections(prediction, detections)
        prediction.save()

        pic.file.seek(
            0)  # Reset file object pointer so that we can load it again
        tagged_img = io.BytesIO()
        detections_to_visualize = [
            d for d in detections if d[1] > VISUALIZATION_THRESH
        ]
        overlay_detections(Image.open(pic),
                           detections_to_visualize).save(tagged_img, "JPEG")
        tagged_img.seek(0)
        _, external_url = save_file_obj(
            'tagged/{}/{}.jpg'.format(printer.id, pic_id), tagged_img,
            settings.PICS_CONTAINER)
        redis.printer_pic_set(printer.id, {'img_url': external_url},
                              ex=STATUS_TTL_SECONDS)

        prediction_json = serializers.serialize("json", [
            prediction,
        ])
        redis.printer_p_json_set(printer.id,
                                 pic_id,
                                 prediction_json,
                                 ex=60 * 60 * 24 * 2)

        if is_failing(prediction,
                      printer.detective_sensitivity,
                      escalating_factor=settings.ESCALATING_FACTOR):
            pause_if_needed(printer)
        elif is_failing(prediction,
                        printer.detective_sensitivity,
                        escalating_factor=1):
            alert_if_needed(printer)

        return command_response(printer)
def detect_timelapse(self, print_id):
    MAX_FRAME_NUM = 750

    _print = Print.objects.get(pk=print_id)
    tmp_dir = os.path.join(tempfile.gettempdir(), str(_print.id))
    tl_path = download_files([f'private/{_print.id}.mp4'],
                             tmp_dir,
                             container=settings.TIMELAPSE_CONTAINER)[0]

    jpgs_dir = os.path.join(tmp_dir, 'jpgs')
    shutil.rmtree(jpgs_dir, ignore_errors=True)
    os.makedirs(jpgs_dir)
    tagged_jpgs_dir = os.path.join(tmp_dir, 'tagged_jpgs')
    shutil.rmtree(tagged_jpgs_dir, ignore_errors=True)
    os.makedirs(tagged_jpgs_dir)

    ffprobe_cmd = subprocess.run(
        f'ffprobe -v error -count_frames -select_streams v:0 -show_entries stream=nb_read_frames -of default=nokey=1:noprint_wrappers=1 {tl_path}'
        .split(),
        stdout=subprocess.PIPE)
    frame_num = int(ffprobe_cmd.stdout.strip())
    fps = 30 * MAX_FRAME_NUM / frame_num if frame_num > MAX_FRAME_NUM else 30
    subprocess.run(
        f'ffmpeg -i {tl_path} -vf fps={fps} -qscale:v 2 {jpgs_dir}/{print_id}-%5d.jpg'
        .split())

    predictions = []
    last_prediction = PrinterPrediction()
    jpg_filenames = sorted(os.listdir(jpgs_dir))
    for jpg_path in jpg_filenames:
        jpg_abs_path = os.path.join(jpgs_dir, jpg_path)
        with open(jpg_abs_path, 'rb') as pic:
            internal_url, _ = save_file_obj(f'raw/uploaded_prints/{jpg_path}',
                                            pic, settings.PICS_CONTAINER)
            req = requests.get(settings.ML_API_HOST + '/p/',
                               params={'img': internal_url},
                               headers=ml_api_auth_headers(),
                               verify=False)
            req.raise_for_status()
            detections = req.json()['detections']
            update_prediction_with_detections(last_prediction, detections)
            predictions.append(last_prediction)

            if is_failing(last_prediction, 1, escalating_factor=1):
                _print.alerted_at = timezone.now()

            last_prediction = copy.deepcopy(last_prediction)
            detections_to_visualize = [
                d for d in detections if d[1] > VISUALIZATION_THRESH
            ]
            overlay_detections(Image.open(jpg_abs_path),
                               detections_to_visualize).save(
                                   os.path.join(tagged_jpgs_dir, jpg_path),
                                   "JPEG")

    predictions_json = serializers.serialize("json", predictions)
    _, json_url = save_file_obj(f'private/{_print.id}_p.json',
                                io.BytesIO(str.encode(predictions_json)),
                                settings.TIMELAPSE_CONTAINER)

    mp4_filename = f'{_print.id}_tagged.mp4'
    output_mp4 = os.path.join(tmp_dir, mp4_filename)
    subprocess.run(
        f'ffmpeg -y -r 30 -pattern_type glob -i {tagged_jpgs_dir}/*.jpg -c:v libx264 -pix_fmt yuv420p {output_mp4}'
        .split(),
        check=True)
    with open(output_mp4, 'rb') as mp4_file:
        _, mp4_file_url = save_file_obj(f'private/{mp4_filename}', mp4_file,
                                        settings.TIMELAPSE_CONTAINER)

    with open(os.path.join(jpgs_dir, jpg_filenames[-1]), 'rb') as poster_file:
        _, poster_file_url = save_file_obj(f'private/{_print.id}_poster.jpg',
                                           poster_file,
                                           settings.TIMELAPSE_CONTAINER)

    _print.tagged_video_url = mp4_file_url
    _print.prediction_json_url = json_url
    _print.poster_url = poster_file_url
    _print.save()

    shutil.rmtree(tmp_dir, ignore_errors=True)
    send_timelapse_detection_done_email(_print)
    def post(self, request):
        printer = request.auth
        printer.refresh_from_db(
        )  # Connection is keep-alive, which means printer object can be stale.

        pic = request.FILES['pic']
        pic = cap_image_size(pic)
        pic_id = str(timezone.now().timestamp())

        if not printer.current_print:  # Some times pics come in when current_print is not set - maybe because printer status is out of sync between plugin and server?
            pic_path = f'{printer.id}/0/{pic_id}.jpg'
        else:
            pic_path = f'{printer.id}/{printer.current_print.id}/{pic_id}.jpg'
        internal_url, external_url = save_file_obj(f'raw/{pic_path}',
                                                   pic,
                                                   settings.PICS_CONTAINER,
                                                   long_term_storage=False)

        if not printer.should_watch() or not printer.actively_printing():
            cache.printer_pic_set(printer.id, {'img_url': external_url},
                                  ex=IMG_URL_TTL_SECONDS)
            send_status_to_web(printer.id)
            return Response({'result': 'ok'})

        req = requests.get(settings.ML_API_HOST + '/p/',
                           params={'img': internal_url},
                           headers=ml_api_auth_headers(),
                           verify=False)
        req.raise_for_status()
        resp = req.json()

        cache.print_num_predictions_incr(printer.current_print.id)

        detections = resp['detections']
        prediction, _ = PrinterPrediction.objects.get_or_create(
            printer=printer)
        update_prediction_with_detections(prediction, detections)
        prediction.save()

        if prediction.current_p > settings.THRESHOLD_LOW * 0.2:  # Select predictions high enough for focused feedback
            cache.print_high_prediction_add(printer.current_print.id,
                                            prediction.current_p, pic_id)

        pic.file.seek(
            0)  # Reset file object pointer so that we can load it again
        tagged_img = io.BytesIO()
        detections_to_visualize = [
            d for d in detections if d[1] > VISUALIZATION_THRESH
        ]
        overlay_detections(Image.open(pic),
                           detections_to_visualize).save(tagged_img, "JPEG")
        tagged_img.seek(0)

        _, external_url = save_file_obj(f'tagged/{pic_path}',
                                        tagged_img,
                                        settings.PICS_CONTAINER,
                                        long_term_storage=False)
        cache.printer_pic_set(printer.id, {'img_url': external_url},
                              ex=IMG_URL_TTL_SECONDS)

        prediction_json = serializers.serialize("json", [
            prediction,
        ])
        p_out = io.BytesIO()
        p_out.write(prediction_json.encode('UTF-8'))
        p_out.seek(0)
        save_file_obj(
            f'p/{printer.id}/{printer.current_print.id}/{pic_id}.json',
            p_out,
            settings.PICS_CONTAINER,
            long_term_storage=False)

        if is_failing(prediction,
                      printer.detective_sensitivity,
                      escalating_factor=settings.ESCALATING_FACTOR):
            pause_if_needed(printer)
        elif is_failing(prediction,
                        printer.detective_sensitivity,
                        escalating_factor=1):
            alert_if_needed(printer)

        send_status_to_web(printer.id)
        return Response({'result': 'ok'})
Esempio n. 4
0
    def post(self, request):
        printer = request.auth
        printer.refresh_from_db() # Connection is keep-alive, which means printer object can be stale.

        if not request.path.startswith('/api/v1'):
            LOGGER.warn(f'Beta plugin connecting from {printer.id}')

        pic = request.FILES['pic']
        pic_id = int(timezone.now().timestamp())
        internal_url, external_url = save_file_obj('raw/{}/{}.jpg'.format(printer.id, pic_id), pic, settings.PICS_CONTAINER)

        if not printer.should_watch() or not printer.actively_printing():
            redis.printer_pic_set(printer.id, {'img_url': external_url}, ex=STATUS_TTL_SECONDS)
            send_status_to_web(printer.id)
            return Response({'result': 'ok'})

        req = requests.get(settings.ML_API_HOST + '/p/', params={'img': internal_url}, headers=ml_api_auth_headers(), verify=False)
        req.raise_for_status()
        resp = req.json()

        detections = resp['detections']
        prediction, _ = PrinterPrediction.objects.get_or_create(printer=printer)
        update_prediction_with_detections(prediction, detections)
        prediction.save()

        pic.file.seek(0)  # Reset file object pointer so that we can load it again
        tagged_img = io.BytesIO()
        detections_to_visualize = [d for d in detections if d[1] > VISUALIZATION_THRESH]
        overlay_detections(Image.open(pic), detections_to_visualize).save(tagged_img, "JPEG")
        tagged_img.seek(0)
        _, external_url = save_file_obj('tagged/{}/{}.jpg'.format(printer.id, pic_id), tagged_img, settings.PICS_CONTAINER)
        redis.printer_pic_set(printer.id, {'img_url': external_url}, ex=STATUS_TTL_SECONDS)

        prediction_json = serializers.serialize("json", [prediction, ])
        redis.printer_p_json_set(printer.id, pic_id, prediction_json, ex=60*60*24*2)

        if is_failing(prediction, printer.detective_sensitivity, escalating_factor=settings.ESCALATING_FACTOR):
            pause_if_needed(printer)
        elif is_failing(prediction, printer.detective_sensitivity, escalating_factor=1):
            alert_if_needed(printer)

        redis.print_num_predictions_incr(printer.current_print.id)
        send_status_to_web(printer.id)
        return Response({'result': 'ok'})