face_verification_core 0.2.0

Cross-platform on-device face liveness and verification core.
Documentation
use serde::{de::DeserializeOwned, Deserialize, Serialize};

use crate::{
    validate_pose, verify_captured_photos, CapturedPhotoAnalysis, ChallengeStep,
    FaceVerificationEngine, FaceVerificationError, FrameAnalysis, ImageInput, LivenessChallenge,
    ModelBundle, SessionDecision, VerificationSession, VerificationThresholds,
};

#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
pub struct SessionTickJsonResult {
    pub session: VerificationSession,
    pub decision: SessionDecision,
}

pub fn generate_challenge_json() -> Result<String, FaceVerificationError> {
    let mut rng = rand::thread_rng();
    to_json(&LivenessChallenge::random(&mut rng))
}

pub fn new_session_json(
    challenge_json: &str,
    thresholds_json: &str,
) -> Result<String, FaceVerificationError> {
    let challenge = from_json::<LivenessChallenge>(challenge_json)?;
    let thresholds = from_json::<VerificationThresholds>(thresholds_json)?;
    to_json(&VerificationSession::new(challenge, thresholds))
}

pub fn tick_session_json(
    session_json: &str,
    frame_json: &str,
    timestamp_ms: u64,
) -> Result<String, FaceVerificationError> {
    let mut session = from_json::<VerificationSession>(session_json)?;
    let frame = from_json::<FrameAnalysis>(frame_json)?;
    let decision = session.tick(&frame, timestamp_ms);
    to_json(&SessionTickJsonResult { session, decision })
}

pub fn validate_pose_json(
    step_json: &str,
    frame_json: &str,
    challenge_json: &str,
    thresholds_json: &str,
) -> Result<String, FaceVerificationError> {
    let step = from_json::<ChallengeStep>(step_json)?;
    let frame = from_json::<FrameAnalysis>(frame_json)?;
    let challenge = from_json::<LivenessChallenge>(challenge_json)?;
    let thresholds = from_json::<VerificationThresholds>(thresholds_json)?;
    to_json(&validate_pose(&step, &frame, &challenge, &thresholds))
}

pub fn verify_captured_photos_json(
    photos_json: &str,
    challenge_json: &str,
    thresholds_json: &str,
) -> Result<String, FaceVerificationError> {
    let photos = from_json::<Vec<CapturedPhotoAnalysis>>(photos_json)?;
    let challenge = from_json::<LivenessChallenge>(challenge_json)?;
    let thresholds = from_json::<VerificationThresholds>(thresholds_json)?;
    to_json(&verify_captured_photos(&photos, &challenge, &thresholds))
}

pub fn validate_model_bundle_json(bundle_json: &str) -> Result<String, FaceVerificationError> {
    let bundle = from_json::<ModelBundle>(bundle_json)?;
    to_json(&bundle.validate()?)
}

pub fn analyze_image_json(
    bundle_json: &str,
    thresholds_json: &str,
    image_json: &str,
) -> Result<String, FaceVerificationError> {
    let bundle = from_json::<ModelBundle>(bundle_json)?;
    let thresholds = from_json::<VerificationThresholds>(thresholds_json)?;
    let image = from_json::<ImageInput>(image_json)?;
    let engine = FaceVerificationEngine::new(bundle, thresholds)?;
    to_json(&engine.analyze_image(&image)?)
}

pub fn verify_images_json(
    bundle_json: &str,
    thresholds_json: &str,
    images_json: &str,
    challenge_json: &str,
) -> Result<String, FaceVerificationError> {
    let bundle = from_json::<ModelBundle>(bundle_json)?;
    let thresholds = from_json::<VerificationThresholds>(thresholds_json)?;
    let images = from_json::<Vec<ImageInput>>(images_json)?;
    let challenge = from_json::<LivenessChallenge>(challenge_json)?;
    let engine = FaceVerificationEngine::new(bundle, thresholds)?;
    to_json(&engine.verify_images(&images, &challenge)?)
}

fn from_json<T: DeserializeOwned>(json: &str) -> Result<T, FaceVerificationError> {
    serde_json::from_str(json).map_err(|err| FaceVerificationError::InvalidJson(err.to_string()))
}

fn to_json<T: Serialize>(value: &T) -> Result<String, FaceVerificationError> {
    serde_json::to_string(value).map_err(|err| FaceVerificationError::InvalidJson(err.to_string()))
}