facecheck.ts
1 // /pages/api/facecheck.ts 2 import type { NextApiRequest, NextApiResponse } from 'next'; 3 import FormData from 'form-data'; 4 import { addSocialsToPersonDocument, createPersonDocument } from '@/utils/firebase'; 5 import { getStorage, ref, uploadBytesResumable, getDownloadURL } from "firebase/storage"; 6 import axios from 'axios'; 7 8 9 10 const TESTING_MODE = false; 11 const APITOKEN = process.env.NEXT_PUBLIC_FACECHECK_APITOKEN; 12 13 14 15 16 export const uploadImage = async (imageData: string): Promise<Blob> => { 17 const storage = getStorage(); 18 const imageRef = ref(storage, `images/${Date.now()}.jpg`); 19 20 // Convert base64 to Blob 21 const byteCharacters = atob(imageData.split(',')[1]); 22 const byteNumbers = new Array(byteCharacters.length); 23 for (let i = 0; i < byteCharacters.length; i++) { 24 byteNumbers[i] = byteCharacters.charCodeAt(i); 25 } 26 const byteArray = new Uint8Array(byteNumbers); 27 const blob = new Blob([byteArray], {type: 'image/jpeg'}); 28 29 const uploadTask = uploadBytesResumable(imageRef, blob); 30 31 return new Promise((resolve, reject) => { 32 uploadTask.on('state_changed', 33 (snapshot) => { 34 // Progress function 35 const progress = (snapshot.bytesTransferred / snapshot.totalBytes) * 100; 36 console.log('Upload is ' + progress + '% done'); 37 }, 38 (error) => { 39 // Error function 40 console.log('Error uploading image: ', error); 41 reject(error); 42 }, 43 () => { 44 // Complete function 45 getDownloadURL(uploadTask.snapshot.ref).then((downloadURL) => { 46 console.log('File available at', downloadURL); 47 resolve(downloadURL as unknown as Blob); 48 return downloadURL 49 }); 50 } 51 ); 52 }); 53 }; 54 55 56 const search_by_face = async (imageUrl: string): Promise<[string | null, any[] | null]> => { 57 if (TESTING_MODE) { 58 console.log('****** TESTING MODE search, results are inaccurate, and queue wait is long, but credits are NOT deducted ******'); 59 } 60 61 const site = 'https://facecheck.id'; 62 const headers = { 63 accept: 'application/json', 64 Authorization: APITOKEN, 65 }; 66 67 const url = await uploadImage(imageUrl) 68 // @ts-ignore 69 const responseImage = await axios.get(url, { responseType: 'arraybuffer' }); 70 const imageData = Buffer.from(responseImage.data, 'binary'); 71 72 73 74 let form = new FormData(); 75 form.append('images', imageData, { filename: 'image.jpg' }); 76 form.append('id_search', ''); 77 78 let response = await axios.post(site+'/api/upload_pic', form, { headers: { 79 ...form.getHeaders(), 80 'accept': 'application/json', 81 'Authorization': APITOKEN 82 } }); 83 response = response.data; 84 // @ts-ignore 85 if (response.error) { 86 // @ts-ignore 87 return [`${response.error} (${response.code})`, null]; 88 } 89 // @ts-ignore 90 91 const id_search = response.id_search; 92 // @ts-ignore 93 94 console.log(`${response.message} id_search=${id_search}`); 95 const json_data = { 96 id_search: id_search, 97 with_progress: true, 98 status_only: false, 99 demo: TESTING_MODE, 100 }; 101 // @ts-ignore 102 while (true) { 103 console.log('waiting for search results') 104 response = await axios.post(site+'/api/search', json_data, { headers: headers }); 105 response = response.data; 106 // @ts-ignore 107 108 if (response?.error) { 109 // @ts-ignore 110 111 return [`${response.error} (${response?.code})`, null]; 112 }// @ts-ignore 113 114 if (response?.output) { 115 // @ts-ignore 116 117 return [null, response?.output?.items]; 118 } 119 // @ts-ignore 120 121 console.log(`${response?.message} progress: ${response?.progress}%`); 122 await new Promise(r => setTimeout(r, 1000)); 123 } 124 }; 125 126 export default async function handler( 127 req: NextApiRequest, 128 res: NextApiResponse 129 ) { 130 if (req.method === 'POST') { 131 const imageData = req.body.imageData; 132 const personDocID = req.body.personDocID; 133 134 135 const [error, urls_images] = await search_by_face(imageData); 136 137 if (urls_images) { 138 console.log("got some urls"); 139 urls_images.sort((a, b) => b.score - a.score); 140 const formatted_urls = urls_images.map(im => { 141 142 const score = im.score; // 0 to 100 score how well the face is matching found image 143 const url = im.url; // url to webpage where the person was found 144 // const image_base64 = im.base64; // thumbnail image encoded as base64 string 145 return { score, url }; 146 }); 147 await addSocialsToPersonDocument(formatted_urls, personDocID); 148 res.status(200).json(formatted_urls); 149 } else { 150 res.status(500).json({ error }); 151 } 152 } else { 153 res.setHeader('Allow', ['POST']); 154 res.status(405).end(`Method ${req.method} Not Allowed`); 155 } 156 }