def nnrange(self, target = None, filter = None, num_results = None): if not filter and not target: return json.dumps({'error':True,'result':"At least introduce either a filter or a target"}) if not num_results: num_results = [DEFAULT_NUMBER_OF_RESULTS] if filter: filter = filter[0] pf = parse_filter(filter.replace("'",'"')) else: pf = [] if target: target = target[0] pt = parse_target(target.replace("'",'"')) else: pt = {} if type(pf) != list or type(pt) != dict: message = "" if type(pf) == str: message += pf if type(pt) == str: message += pt if message == "": message = "Invalid filter or target." return json.dumps({'error':True,'result':message}) #raise ReturnError(400, "BadRequest", {"explanation": message}) return json.dumps(self.gaia.query_dataset({'target':pt,'filter':pf}, num_results[0]))
def api_search(self, request, target_type=None, target=None, filter=None, num_results=settings.N_RESULTS): if filter: try: result = parse_filter( filter[0].replace("'", '"'), self.gaia.descriptor_names['fixed-length']) if type(result) == str: return self.fail(result) elif type(result) != list: return self.fail(messages.INVALID_FILTER) except Exception as e: return self.fail(messages.INVALID_FILTER) if target_type == 'descriptor_values' and target: metric_descriptor_names = parse_metric_descriptors( ','.join(target.keys()), self.gaia.descriptor_names['fixed-length']) else: metric_descriptor_names = False result = self.gaia.api_search( target_type, target, filter, settings.DEFAULT_PRESET, metric_descriptor_names, num_results, 0, # TODO None) parsed_results = [] for r in range(len(result["result"]["results"])): sound_id = result["result"]["results"][r][0] if not sound_id in self.filenames: return self.fail(messages.FILE_NOT_FOUND, settings.NOT_FOUND_CODE) parsed_results.append(self.sound_dict(sound_id)) result["result"]["results"] = parsed_results return json.dumps(result)
def api_search(self, request, target_type=None, target=None, filter=None, preset=[DEFAULT_PRESET], metric_descriptor_names=None, num_results=[DEFAULT_NUMBER_OF_RESULTS], offset=[0], in_ids=None): ''' This function is used as an interface to all search-related gaia funcionalities we use in freesound. This function allows the definition of a query point that will be used by gaia as the target for the search (i.e. gaia will sort the results by similarity according to this point), and a filter to reduce the scope of the search. The query point is defined with the target and target_type parameters, and can be either a sound id from the gaia index, a list of descriptors with values or the content of a file attached to a post request. Ex: target=1234 target_type=sound_id target=.lowlevel.pitch.mean:220 target_type=descriptors_values target=.lowlevel.scvalleys.mean:-8.0,-11.0,-13.0,-15.0,-16.0,-15.0 target_type=descriptors_values The filter is defined as a string following the same syntax as solr filter that is then parsed and translated to a representation that gaia can understand. Ex: filter=.lowlevel.pitch.mean:[100 TO *] TODO: how to filter multidimensional features Along with target and filter other parameters can be specified: - preset: set of descriptors that will be used to determine the similarity distance (by default 'lowlevel' preset) - metric_descriptor_names*: a list of descriptor names (separated by ,) that will be used as to build the distance metric (preset will be overwritten) * this parameter is bypassed with the descriptor_values target type, as the list is automatically built with the descriptors specified in the target - num_results, offset: to control the number of returned results and the offset since the first result (so pagination is possible) ''' if in_ids: in_ids = in_ids[0].split(',') if not target and not filter: if target_type: if target_type[0] != 'file': return json.dumps({ 'error': True, 'result': 'At least \'target\' or \'filter\' should be specified.', 'status_code': BAD_REQUEST_CODE }) else: return json.dumps({ 'error': True, 'result': 'At least \'target\' or \'filter\' should be specified.', 'status_code': BAD_REQUEST_CODE }) if target and not target_type: return json.dumps({ 'error': True, 'result': 'Parameter \'target_type\' should be specified.', 'status_code': BAD_REQUEST_CODE }) if target_type: target_type = target_type[0] if target or target_type == 'file': if target_type == 'sound_id': try: target = int(target[0]) except: return json.dumps({ 'error': True, 'result': 'Invalid sound id.', 'status_code': BAD_REQUEST_CODE }) elif target_type == 'descriptor_values': try: target = parse_target( target[0].replace("'", '"'), self.gaia.descriptor_names['fixed-length']) if type(target) != dict: if type(target) == str: return json.dumps({ 'error': True, 'result': target, 'status_code': BAD_REQUEST_CODE }) else: return json.dumps({ 'error': True, 'result': 'Invalid descriptor values for target.', 'status_code': BAD_REQUEST_CODE }) if not target.items(): return json.dumps({ 'error': True, 'result': 'Invalid target.', 'status_code': BAD_REQUEST_CODE }) except Exception as e: return json.dumps({ 'error': True, 'result': 'Invalid descriptor values for target.', 'status_code': BAD_REQUEST_CODE }) elif target_type == 'file': data = request.content.getvalue().split( '&' )[0] # If more than one file attached, just get the first one if not data: return json.dumps({ 'error': True, 'result': 'You specified \'file\' as target file but attached no analysis file.', 'status_code': BAD_REQUEST_CODE }) try: target = yaml.load(data) except: return json.dumps({ 'error': True, 'result': 'Analysis file could not be parsed.', 'status_code': BAD_REQUEST_CODE }) else: return json.dumps({ 'error': True, 'result': 'Invalid target type.', 'status_code': BAD_REQUEST_CODE }) if filter: try: filter = parse_filter( filter[0].replace("'", '"'), self.gaia.descriptor_names['fixed-length']) if type(filter) != list: if type(filter) == str: return json.dumps({ 'error': True, 'result': filter, 'status_code': BAD_REQUEST_CODE }) else: return json.dumps({ 'error': True, 'result': 'Invalid filter.', 'status_code': BAD_REQUEST_CODE }) except Exception as e: return json.dumps({ 'error': True, 'result': 'Invalid filter.', 'status_code': BAD_REQUEST_CODE }) ''' if preset: if preset[0] not in PRESETS: preset = DEFAULT_PRESET else: preset = preset[0] ''' preset = 'pca' # For the moment we only admit pca preset, in the future we may allow more presets if not num_results[0]: num_results = int(DEFAULT_NUMBER_OF_RESULTS) else: num_results = int(num_results[0]) if not offset[0]: offset = 0 else: offset = int(offset[0]) if target_type == 'descriptor_values' and target: metric_descriptor_names = parse_metric_descriptors( ','.join(target.keys()), self.gaia.descriptor_names['fixed-length']) else: metric_descriptor_names = False # For the moment metric_descriptor_names can only be set by us return json.dumps( self.gaia.api_search(target_type, target, filter, preset, metric_descriptor_names, num_results, offset, in_ids))
class SimilarityServer(resource.Resource): def __init__(self): resource.Resource.__init__(self) self.methods = server_interface(self) self.isLeaf = False self.gaia = GaiaWrapper() self.request = None def error(self, message): return json.dumps({'Error': message}) def getChild(self, name, request): return self def render_GET(self, request): return self.methods[request.prepath[1]](request=request, **request.args) def render_POST(self, request): return self.methods[request.prepath[1]](request=request, **request.args) def add_point(self, request, location, sound_id): return json.dumps(self.gaia.add_point(location[0], sound_id[0])) def delete_point(self, request, sound_id): return json.dumps(self.gaia.delete_point(sound_id[0])) def contains(self, request, sound_id): return json.dumps(self.gaia.contains(sound_id[0])) def get_all_point_names(self, request): return json.dumps(self.gaia.get_all_point_names()) def get_descriptor_names(self, request): return json.dumps({ 'error': False, 'result': self.gaia.descriptor_names }) def get_sounds_descriptors(self, request, sound_ids, descriptor_names=None, normalization=[0], only_leaf_descriptors=[0]): kwargs = dict() if descriptor_names: kwargs['descriptor_names'] = [ name for name in descriptor_names[0].split(',') if name ] kwargs['normalization'] = normalization[0] == '1' kwargs['only_leaf_descriptors'] = only_leaf_descriptors[0] == '1' return json.dumps( self.gaia.get_sounds_descriptors(sound_ids[0].split(','), **kwargs)) def nnsearch(self, request, sound_id=None, num_results=None, preset=None, offset=[0]): preset = [ 'pca' ] # For the moment we only admit pca preset, in the future we may allow more presets if not num_results: num_results = [DEFAULT_NUMBER_OF_RESULTS] return json.dumps( self.gaia.search_dataset(sound_id[0], num_results[0], preset_name=preset[0], offset=offset[0])) def api_search(self, request, target_type=None, target=None, filter=None, preset=[DEFAULT_PRESET], metric_descriptor_names=None, num_results=[DEFAULT_NUMBER_OF_RESULTS], offset=[0], in_ids=None): ''' This function is used as an interface to all search-related gaia funcionalities we use in freesound. This function allows the definition of a query point that will be used by gaia as the target for the search (i.e. gaia will sort the results by similarity according to this point), and a filter to reduce the scope of the search. The query point is defined with the target and target_type parameters, and can be either a sound id from the gaia index, a list of descriptors with values or the content of a file attached to a post request. Ex: target=1234 target_type=sound_id target=.lowlevel.pitch.mean:220 target_type=descriptors_values target=.lowlevel.scvalleys.mean:-8.0,-11.0,-13.0,-15.0,-16.0,-15.0 target_type=descriptors_values The filter is defined as a string following the same syntax as solr filter that is then parsed and translated to a representation that gaia can understand. Ex: filter=.lowlevel.pitch.mean:[100 TO *] TODO: how to filter multidimensional features Along with target and filter other parameters can be specified: - preset: set of descriptors that will be used to determine the similarity distance (by default 'lowlevel' preset) - metric_descriptor_names*: a list of descriptor names (separated by ,) that will be used as to build the distance metric (preset will be overwritten) * this parameter is bypassed with the descriptor_values target type, as the list is automatically built with the descriptors specified in the target - num_results, offset: to control the number of returned results and the offset since the first result (so pagination is possible) ''' if in_ids: in_ids = in_ids[0].split(',') if not target and not filter: if target_type: if target_type[0] != 'file': return json.dumps({ 'error': True, 'result': 'At least \'target\' or \'filter\' should be specified.', 'status_code': BAD_REQUEST_CODE }) else: return json.dumps({ 'error': True, 'result': 'At least \'target\' or \'filter\' should be specified.', 'status_code': BAD_REQUEST_CODE }) if target and not target_type: return json.dumps({ 'error': True, 'result': 'Parameter \'target_type\' should be specified.', 'status_code': BAD_REQUEST_CODE }) if target_type: target_type = target_type[0] if target or target_type == 'file': if target_type == 'sound_id': try: target = int(target[0]) except: return json.dumps({ 'error': True, 'result': 'Invalid sound id.', 'status_code': BAD_REQUEST_CODE }) elif target_type == 'descriptor_values': try: target = parse_target( target[0].replace("'", '"'), self.gaia.descriptor_names['fixed-length']) if type(target) != dict: if type(target) == str: return json.dumps({ 'error': True, 'result': target, 'status_code': BAD_REQUEST_CODE }) else: return json.dumps({ 'error': True, 'result': 'Invalid descriptor values for target.', 'status_code': BAD_REQUEST_CODE }) if not target.items(): return json.dumps({ 'error': True, 'result': 'Invalid target.', 'status_code': BAD_REQUEST_CODE }) except Exception, e: return json.dumps({ 'error': True, 'result': 'Invalid descriptor values for target.', 'status_code': BAD_REQUEST_CODE }) elif target_type == 'file': data = request.content.getvalue().split( '&' )[0] # If more than one file attached, just get the first one if not data: return json.dumps({ 'error': True, 'result': 'You specified \'file\' as target file but attached no analysis file.', 'status_code': BAD_REQUEST_CODE }) try: target = yaml.load(data) except: return json.dumps({ 'error': True, 'result': 'Analysis file could not be parsed.', 'status_code': BAD_REQUEST_CODE }) else: return json.dumps({ 'error': True, 'result': 'Invalid target type.', 'status_code': BAD_REQUEST_CODE }) if filter: try: filter = parse_filter( filter[0].replace("'", '"'), self.gaia.descriptor_names['fixed-length']) if type(filter) != list: if type(filter) == str: return json.dumps({ 'error': True, 'result': filter, 'status_code': BAD_REQUEST_CODE }) else: return json.dumps({ 'error': True, 'result': 'Invalid filter.', 'status_code': BAD_REQUEST_CODE }) except Exception, e: return json.dumps({ 'error': True, 'result': 'Invalid filter.', 'status_code': BAD_REQUEST_CODE })
def api_search(self, request, target_type=None, target=None, filter=None, preset=[DEFAULT_PRESET], metric_descriptor_names=None, num_results=[DEFAULT_NUMBER_OF_RESULTS], offset=[0], in_ids=None): ''' This function is used as an interface to all search-related gaia funcionalities we use in freesound. This function allows the definition of a query point that will be used by gaia as the target for the search (i.e. gaia will sort the results by similarity according to this point), and a filter to reduce the scope of the search. The query point is defined with the target and target_type parameters, and can be either a sound id from the gaia index, a list of descriptors with values or the content of a file attached to a post request. Ex: target=1234 target_type=sound_id target=.lowlevel.pitch.mean:220 target_type=descriptors_values target=.lowlevel.scvalleys.mean:-8.0,-11.0,-13.0,-15.0,-16.0,-15.0 target_type=descriptors_values The filter is defined as a string following the same syntax as solr filter that is then parsed and translated to a representation that gaia can understand. Ex: filter=.lowlevel.pitch.mean:[100 TO *] TODO: how to filter multidimensional features Along with target and filter other parameters can be specified: - preset: set of descriptors that will be used to determine the similarity distance (by default 'lowlevel' preset) - metric_descriptor_names*: a list of descriptor names (separated by ,) that will be used as to build the distance metric (preset will be overwritten) * this parameter is bypassed with the descriptor_values target type, as the list is automatically built with the descriptors specified in the target - num_results, offset: to control the number of returned results and the offset since the first result (so pagination is possible) ''' if in_ids: in_ids = in_ids[0].split(',') if not target and not filter: if target_type: if target_type[0] != 'file': return json.dumps({'error': True, 'result': 'At least \'target\' or \'filter\' should be specified.', 'status_code': BAD_REQUEST_CODE}) else: return json.dumps({'error': True, 'result': 'At least \'target\' or \'filter\' should be specified.', 'status_code': BAD_REQUEST_CODE}) if target and not target_type: return json.dumps({'error': True, 'result': 'Parameter \'target_type\' should be specified.', 'status_code': BAD_REQUEST_CODE}) if target_type: target_type = target_type[0] if target or target_type == 'file': if target_type == 'sound_id': try: target = int(target[0]) except: return json.dumps({'error': True, 'result': 'Invalid sound id.', 'status_code': BAD_REQUEST_CODE}) elif target_type == 'descriptor_values': try: target = parse_target(target[0].replace("'", '"'), self.gaia.descriptor_names['fixed-length']) if type(target) != dict: if type(target) == str: return json.dumps({'error': True, 'result': target, 'status_code': BAD_REQUEST_CODE}) else: return json.dumps({'error': True, 'result': 'Invalid descriptor values for target.', 'status_code': BAD_REQUEST_CODE}) if not target.items(): return json.dumps({'error': True, 'result': 'Invalid target.', 'status_code': BAD_REQUEST_CODE}) except Exception as e: return json.dumps({'error': True, 'result': 'Invalid descriptor values for target.', 'status_code': BAD_REQUEST_CODE}) elif target_type == 'file': data = request.content.getvalue().split('&')[0] # If more than one file attached, just get the first one if not data: return json.dumps({'error': True, 'result': 'You specified \'file\' as target file but attached no analysis file.', 'status_code': BAD_REQUEST_CODE}) try: target = yaml.load(data) except: return json.dumps({'error': True, 'result': 'Analysis file could not be parsed.', 'status_code': BAD_REQUEST_CODE}) else: return json.dumps({'error': True, 'result': 'Invalid target type.', 'status_code': BAD_REQUEST_CODE}) if filter: try: filter = parse_filter(filter[0].replace("'", '"'), self.gaia.descriptor_names['fixed-length']) if type(filter) != list: if type(filter) == str: return json.dumps({'error': True, 'result': filter, 'status_code': BAD_REQUEST_CODE}) else: return json.dumps({'error': True, 'result': 'Invalid filter.', 'status_code': BAD_REQUEST_CODE}) except Exception as e: return json.dumps({'error': True, 'result': 'Invalid filter.', 'status_code': BAD_REQUEST_CODE}) ''' if preset: if preset[0] not in PRESETS: preset = DEFAULT_PRESET else: preset = preset[0] ''' preset = 'pca' # For the moment we only admit pca preset, in the future we may allow more presets if not num_results[0]: num_results = int(DEFAULT_NUMBER_OF_RESULTS) else: num_results = int(num_results[0]) if not offset[0]: offset = 0 else: offset = int(offset[0]) if target_type == 'descriptor_values' and target: metric_descriptor_names = parse_metric_descriptors(','.join(target.keys()), self.gaia.descriptor_names['fixed-length']) else: metric_descriptor_names = False # For the moment metric_descriptor_names can only be set by us return json.dumps(self.gaia.api_search(target_type, target, filter, preset, metric_descriptor_names, num_results, offset, in_ids))
def nnrange(self, request, target=None, filter=None, num_results=None, offset=[0], preset=None): descriptors_data = None if not filter: if not target: # check if instead of a target, an analysis file was attached data = request.content.getvalue().split('&')[0] # If more than one file attached, just get the first one if not data: return json.dumps({'error': True, 'result': 'You should at least specify a descriptors_filter, descriptors_target or attach an analysis file for content based search.', 'status_code': BAD_REQUEST_CODE}) try: descriptors_data = yaml.load(data) except: return json.dumps({'error': True, 'result': 'Analysis file could not be parsed.', 'status_code': BAD_REQUEST_CODE}) if not num_results: num_results = [DEFAULT_NUMBER_OF_RESULTS] if not preset: preset = [DEFAULT_PRESET] else: if preset[0] not in PRESETS: preset = [DEFAULT_PRESET] if filter: filter = filter[0] pf = parse_filter(filter.replace("'", '"'), self.gaia.descriptor_names['fixed-length']) else: pf = [] target_sound_id = False use_file_as_target = False if target: target = target[0] try: # If target can be parsed as an integer, we assume it corresponds to a sound_id target_sound_id = int(target) pt = {} except: pt = parse_target(target.replace("'", '"'), self.gaia.descriptor_names['fixed-length']) else: pt = {} if descriptors_data: use_file_as_target = True if type(pf) != list or type(pt) != dict: message = "" if type(pf) == str: message += pf if type(pt) == str: message += pt if message == "": message = "Invalid filter or target." return json.dumps({'error': True, 'result': message, 'status_code': BAD_REQUEST_CODE}) return json.dumps(self.gaia.query_dataset({'target': pt, 'filter': pf}, num_results[0], preset_name=preset[0], offset=offset[0], target_sound_id=target_sound_id, use_file_as_target=use_file_as_target, descriptors_data=descriptors_data))