Skip to content

Commit

Permalink
CV responses can included representative taxon photos
Browse files Browse the repository at this point in the history
  • Loading branch information
pleary committed Dec 12, 2024
1 parent eb303e8 commit a3cb5ee
Showing 1 changed file with 64 additions and 1 deletion.
65 changes: 64 additions & 1 deletion lib/controllers/v1/computervision_controller.js
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ const PromisePool = require( "es6-promise-pool" );
const csv = require( "fast-csv" );
const crypto = require( "crypto" );
const pgClient = require( "../../pg_client" );
const esClient = require( "../../es_client" );
const TaxaController = require( "./taxa_controller" );
const InaturalistAPI = require( "../../inaturalist_api" );
const config = require( "../../../config" );
Expand Down Expand Up @@ -262,6 +263,62 @@ const ComputervisionController = class ComputervisionController {
return scores;
}

static async addRepresentativePhotos( results, embedding ) {
if ( _.isEmpty( embedding ) ) {
return;
}
const taxonIDsToLookup = _.map( _.filter(
results, result => result.rank_level < 30
), "taxon_id" );
if ( _.isEmpty( taxonIDsToLookup ) ) {
return;
}
const embeddingsResponse = await esClient.search( "taxon_photos", {
body: {
query: {
bool: {
filter: [
{ terms: { taxon_ids: taxonIDsToLookup } }
]
}
},
knn: {
field: "embedding",
query_vector: embedding,
k: 10,
num_candidates: 500
},
size: 10000,
_source: [
"id",
"taxon_id",
"photo_id",
"ancestor_ids"
]
}
} );
const embeddingsHits = _.map( embeddingsResponse.hits.hits, "_source" );
// TODO: remove this once the ancestor_ids data in the index has been fixed
_.each( embeddingsHits, hit => {
hit.ancestor_ids = _.remove( hit.ancestor_ids, ancestorID => ancestorID === hit.id );
hit.ancestor_ids.push( hit.taxon_id );
} );
await ObservationPreload.assignObservationPhotoPhotos( embeddingsHits );
_.each( results, result => {
if ( result && result.taxon && result.taxon.default_photo ) {
const firstMatch = _.find( embeddingsHits, h => (
h?.photo?.url
&& _.includes( h.ancestor_ids, result.taxon.id )
) );
if ( firstMatch ) {
result.taxon.default_photo.url = firstMatch.photo.url.replace( "medium", "square" );
result.taxon.default_photo.medium_url = firstMatch.photo.url;
result.taxon.default_photo.square_url = firstMatch.photo.url.replace( "medium", "square" );
}
}
} );
}

static async delegatedScoresProcessing( req, visionApiResponse ) {
const localeOpts = util.localeOpts( req );
const prepareTaxon = t => {
Expand Down Expand Up @@ -312,13 +369,19 @@ const ComputervisionController = class ComputervisionController {
} );

await ESModel.fetchBelongsTo( withTaxa, Taxon, taxonOpts );
await Taxon.preloadIntoTaxonPhotos( _.map( withTaxa, "taxon" ), { localeOpts } );
await Taxon.preloadIntoTaxonPhotos( _.map( _.filter( withTaxa, "taxon" ), "taxon" ), { localeOpts } );

if ( !( req.body.aggregated || req.query.aggregated ) ) {
_.each( withTaxa, s => {
delete s.taxon_id;
} );
}

await ComputervisionController.addRepresentativePhotos(
withTaxa,
visionApiResponse.embedding
);

// remove attributes of common_ancestor that should not be in the response
if ( response.common_ancestor ) {
await TaxaController.assignPlaces( [response.common_ancestor.taxon] );
Expand Down

0 comments on commit a3cb5ee

Please sign in to comment.