Runs the same detect → align → embed pipeline as /v1/embed independently on two images, then returns their cosine similarity and a boolean match decision against COMPARE_THRESHOLD.

Request

file
required
First image, as multipart/form-data. Same constraints as /v1/embed’s image field.
file
required
Second image, same constraints.

Response

float
Cosine similarity between the two embeddings, in [-1, 1] (in practice, real face pairs from this model land roughly in [0, 0.7] — see Models → Similarity threshold for the actual observed distribution).
boolean
similarity >= threshold.
float
The threshold that was actually used for this request (echoes COMPARE_THRESHOLD, so clients don’t have to know the server-side default out of band).
object
{ det_score, bbox } for the face found in image1 — same shape as /v1/embed’s top-level fields.
object
Same, for image2.

Errors

Same as /v1/embed, but every error response includes a field key ("image1" or "image2") identifying which upload failed — including missing_field_image1_or_image2 if either form field is absent entirely.
The two images are processed sequentially within one worker-pool job, not in parallel — the simplest correct implementation, not the fastest possible one. If /v1/compare latency becomes a bottleneck under load, this is the first thing to split into two parallel enqueue() calls joined by a result-combiner (see the NOTE comment in CompareController.cpp).