Skip to content

Commit

Permalink
Merge remote-tracking branch 'origin/main' into build_info
Browse files Browse the repository at this point in the history
  • Loading branch information
sylvain-morin committed Jul 1, 2024
2 parents 94f656c + b149195 commit 8feabf6
Show file tree
Hide file tree
Showing 7 changed files with 141 additions and 4 deletions.
6 changes: 4 additions & 2 deletions config.docker.js
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,8 @@ const {
INAT_AWS_OPENDATA_REGION,
INAT_AWS_OPENDATA_ACL,
INAT_TAXA_FILE_PATH,
INAT_SEEK_EXCEPTION_LIST_ID
INAT_SEEK_EXCEPTION_LIST_ID,
INAT_NLS_URL
} = process.env;

module.exports = {
Expand Down Expand Up @@ -53,7 +54,8 @@ module.exports = {
taxaFilePath: INAT_TAXA_FILE_PATH || "",
geomodel: true,
combinedThreshold: 0.001,
frequencyBackend: "redis"
frequencyBackend: "redis",
inatnlsURL: INAT_NLS_URL || ""
},
redis: {
host: INAT_REDIS_HOST || "127.0.0.1",
Expand Down
69 changes: 69 additions & 0 deletions lib/controllers/v1/computervision_controller.js
Original file line number Diff line number Diff line change
Expand Up @@ -617,6 +617,75 @@ const ComputervisionController = class ComputervisionController {
}
return { total_bounds: json };
}

static async languageSearch( req ) {
if ( _.isEmpty( req.query.q ) ) {
throw util.httpError( 422, "Missing required parameter `q`" );
}
const { page, perPage } = InaturalistAPI.paginationData( req, { default: 30, max: 100 } );
const languageSearchParams = {
query: req.query.q,
page,
per_page: perPage
};
if ( req.query.taxon_id ) {
languageSearchParams.taxon_id = req.query.taxon_id;
}
const urlParams = new URLSearchParams( languageSearchParams );

const requestAbortController = new AbortController( );
const requestTimeout = setTimeout( ( ) => {
requestAbortController.abort( );
}, 60000 );
let json;
try {
const response = await fetch( `${config.imageProcesing.inatnlsURL}/?${urlParams.toString( )}`, {
method: "POST",
signal: requestAbortController.signal
} );
if ( !response.ok ) {
throw util.httpError( 500, "Langauge search failed" );
}
json = await response.json( );
} catch ( error ) {
throw util.httpError( 500, "Langauge search failed" );
} finally {
clearTimeout( requestTimeout );
}

const photos = _.keyBy( json.results, "photo_id" );
const photosQuery = squel
.select( )
.field( "op.photo_id, op.observation_id" )
.from( "observation_photos op" )
.where( "op.photo_id IN ?", _.keys( photos ) );
const { rows } = await pgClient.replica.query( photosQuery.toString( ) );
const resultsObject = { };
_.each( _.reverse( _.sortBy( rows, "observation_id" ) ), row => {
if ( _.has( resultsObject, row.photo_id ) ) {
return;
}
resultsObject[row.photo_id] = {
observation_id: row.observation_id,
photo_id: row.photo_id,
score: photos[row.photo_id].score
};
} );
const results = _.values( resultsObject );
const localeOpts = util.localeOpts( req );
await Observation.preloadInto( req, results, { ...localeOpts, minimal: true } );
_.each( results, r => {
delete r.observation_id;
} );

const response = {
total_results: _.size( results ),
page: Number( req.query.page ) || 1,
per_page: _.size( results ),
results: _.reverse( _.sortBy( results, "score" ) )
};
return response;
}
};

module.exports = ComputervisionController;
1 change: 1 addition & 0 deletions lib/inaturalist_api.js
Original file line number Diff line number Diff line change
Expand Up @@ -231,6 +231,7 @@ InaturalistAPI.server = async ( ) => {
dfault( "get", "/v1/computervision/score_observation/:id", ComputervisionController.scoreObservation );
dfault( "get", "/v1/computervision/taxon_h3_cells/:id", ComputervisionController.taxonH3Cells );
dfault( "get", "/v1/computervision/taxon_geomodel_bounds/:id", ComputervisionController.taxonGeomodelBounds );
dfault( "get", "/v1/computervision/language_search", ComputervisionController.languageSearch );
}

app.get( "/", routesV1.docs );
Expand Down
6 changes: 4 additions & 2 deletions lib/models/observation_preload.js
Original file line number Diff line number Diff line change
Expand Up @@ -171,11 +171,13 @@ const ObservationPreload = class ObservationPreload {
o.observation_photos = _.sortBy( unsortedObsObsPhotos, ["position", "id"] );
_.each( o.observation_photos, ( op, i ) => {
op.position = i;
// observation_id attribute of observationPhoto is no longer needed
delete op.observation_id;
} );
o.photos = _.map( o.observation_photos, "photo" );
} );
_.each( _.flatten( _.map( obs, "observation_photos" ) ), op => {
// observation_id attribute of observationPhoto is no longer needed
delete op.observation_id;
} );
}

static async assignObservationPhotoPhotos( observationPhotos ) {
Expand Down
38 changes: 38 additions & 0 deletions openapi/paths/v2/computervision/language_search.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
const _ = require( "lodash" );
const languageSearchSchema = require( "../../../schema/request/language_search" );
const transform = require( "../../../joi_to_openapi_parameter" );
const computervisionController = require( "../../../../lib/controllers/v1/computervision_controller" );

module.exports = sendWrapper => {
async function GET( req, res ) {
const results = await computervisionController.languageSearch( req );
sendWrapper( req, res, null, results );
}

GET.apiDoc = {
tags: ["Computer Vision"],
summary: "Fetch language demo search results for a search term",
"x-unpublished": true,
parameters: _.map(
languageSearchSchema.$_terms.keys, child => (
transform( child.schema.label( child.key ) )
)
),
responses: {
200: {
description: "An array of language demo search results",
content: {
"application/json": {
schema: {
$ref: "#/components/schemas/ResultsLanguageSearch"
}
}
}
}
}
};

return {
GET
};
};
10 changes: 10 additions & 0 deletions openapi/schema/request/language_search.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
const Joi = require( "joi" );

module.exports = Joi.object( ).keys( {
q: Joi.string( ),
taxon_id: Joi.array( ).items( Joi.number( ).integer( ) ),
locale: Joi.string( ),
page: Joi.number( ).integer( ),
per_page: Joi.number( ).integer( ),
fields: Joi.any( )
} ).unknown( false ).meta( { unpublished: true } );
15 changes: 15 additions & 0 deletions openapi/schema/response/results_language_search.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
const Joi = require( "joi" );
const observation = require( "./observation" );

module.exports = Joi.object( ).keys( {
total_results: Joi.number( ).integer( ).required( ),
page: Joi.number( ).integer( ).required( ),
per_page: Joi.number( ).integer( ).required( ),
results: Joi.array( ).items(
Joi.object( {
photo_id: Joi.number( ).integer( ).required( ),
score: Joi.number( ).required( ),
observation
} )
).required( )
} ).unknown( false ).meta( { unpublished: true } );

0 comments on commit 8feabf6

Please sign in to comment.