import io import os import re import time import numpy as np import logging import urllib.request from flask import Blueprint, request, jsonify from PIL import Image from app.models.sql_factory import search_by_phash, add_phash from app.utils.im_utils import compute_phash_int from app.utils.file_utils import sha256_stream sanitize_re = re.compile('[\W]+') valid_exts = ['.gif', '.jpg', '.jpeg', '.png'] LIMIT = 9 api = Blueprint('api', __name__) @api.route('/') def index(): """ API status test endpoint """ return jsonify({ 'status': 'ok' }) @api.route('/v1/match', methods=['POST']) def match(): """ Search by uploading an image """ start = time.time() try: threshold = int(request.form.get('threshold') or 6) limit = int(request.form.get('limit') or 1) add = str(request.form.get('add') or 'true') == 'true' except: return jsonify({ 'success': False, 'match': False, 'error': 'param_error' }) if 'q' in request.files: file = request.files['q'] fn = file.filename if fn.endswith('blob'): # FIX PNG IMAGES? logging.debug('received a blob, assuming JPEG') fn = 'filename.jpg' basename, ext = os.path.splitext(fn) if ext.lower() not in valid_exts: return jsonify({ 'success': False, 'match': False, 'error': 'not_an_image' }) im = Image.open(file.stream).convert('RGB') else: url = request.form.get('url') if not url: return jsonify({ 'success': False, 'match': False, 'error': 'no_image' }) basename, ext = os.path.splitext(url) if ext.lower() not in valid_exts: return jsonify({ 'success': False, 'match': False, 'error': 'not_an_image' }) remote_request = urllib.request.Request(url) remote_response = urllib.request.urlopen(remote_request) raw = remote_response.read() im = Image.open(io.BytesIO(raw)).convert('RGB') phash = compute_phash_int(im) ext = ext[1:].lower() results = search_by_phash(phash=phash, threshold=threshold, limit=limit) if len(results) == 0: if add and url: # hash = sha256_stream(file) hash = sha256_stream(io.BytesIO(raw)) add_phash(sha256=hash, phash=phash, ext=ext, url=url) match = False else: match = True logging.debug('query took {0:.2g} s.'.format(time.time() - start)) if limit > 1: return jsonify({ 'success': True, 'match': match, 'results': results, 'timing': time.time() - start, }) return jsonify({ 'success': True, 'match': match, 'closest_match': results[0] if len(results) else None, 'timing': time.time() - start, })