From b86c12fc9224aa253eaca846cf728fc27828f766 Mon Sep 17 00:00:00 2001 From: James Ketrenos Date: Wed, 25 Jan 2023 13:43:43 -0800 Subject: [PATCH] Can now create blank identities Signed-off-by: James Ketrenos --- client/src/App.css | 17 +++- client/src/App.tsx | 85 ++++++++++++++------ server/routes/identities.js | 152 +++++++++++++++++++----------------- 3 files changed, 157 insertions(+), 97 deletions(-) diff --git a/client/src/App.css b/client/src/App.css index b386a25..9584df9 100644 --- a/client/src/App.css +++ b/client/src/App.css @@ -121,7 +121,15 @@ div { .IdentityForm { display: grid; + gap: 0.25rem; grid-template-columns: 1fr 1fr; + align-items: center; + justify-items: flex-end; +} + +.IdentityForm input { + min-height: 1rem; + padding: 0.25rem; } .Face.Active, @@ -145,11 +153,18 @@ div { color: white; } +.Info .Face .Image { + width: 10rem; + height: 10rem; +} + .Face .Image { position: relative; box-sizing: border-box; display: flex; justify-content: center; + min-width: 8rem; + min-height: 8rem; } .Cluster { @@ -175,8 +190,6 @@ div { object-fit: cover; /* contain */ width: 100%; height: 100%; - min-width: 8rem; - min-height: 8rem; } .Cluster .Faces { diff --git a/client/src/App.tsx b/client/src/App.tsx index 5a493aa..d9410f7 100644 --- a/client/src/App.tsx +++ b/client/src/App.tsx @@ -209,7 +209,7 @@ const Face = ({ face, onFaceClick, title, isSelected }: any) => { type ClusterProps = { identity: IdentityData, - setIdentity(identity: IdentityData | undefined): void, + setIdentity(identity: IdentityData): void, identities: IdentityData[], setIdentities(identiteis: IdentityData[]): void, setImage(image: number): void, @@ -275,7 +275,7 @@ const Cluster = ({ if (index !== -1) { identities.splice(index, 1); } - setIdentity(undefined); + setIdentity(EmptyIdentity); setIdentities([...identities]); } catch (error) { console.error(error); @@ -338,27 +338,37 @@ const Cluster = ({ return (
-
-
Last name:
- -
First name:
- -
Middle name:
-
Display name:
- -
+
+
+
Last name:
+ +
First name:
+ +
Middle name:
+
Display name:
+ +
+ {}} + title={`${identity.displayName} (${identity.facesCount})`} /> +
- - + { identity.identityId !== -1 && <> + + + }
Faces: {identity.relatedFaces.length}
@@ -405,6 +415,32 @@ type IdentityData = { faceId: number }; + +const EmptyIdentity: IdentityData = { + lastName: '', + middleName: '', + firstName: '', + descriptors: [], + identityId: -1, + displayName: '', + relatedFaces: [], + facesCount: 0, + faceId: -1 +}; + +const UnknownFace = { + faceId: -1, + photoId: -1, + identityId: -1, + distance: 0, + descriptors: [], + top: 0, + left: 0, + bottom: 0, + right: 0, + identity: EmptyIdentity +}; + interface IdentitiesProps { identities: IdentityData[], onFaceClick(e: any, face: FaceData): void @@ -448,7 +484,7 @@ const App = () => { const [identities, setIdentities] = useState([]); const { identityId, faceId } = useParams(); const [selectedIdentities, setSelectedIdentities] = useState([]); - const [identity, setIdentity] = useState(undefined); + const [identity, setIdentity] = useState(EmptyIdentity); const [image, setImage] = useState(0); const [guess, setGuess] = useState(undefined); const { loading, data } = useApi( /* TODO: Switch away from using useApi */ @@ -575,7 +611,7 @@ const App = () => { if (index !== -1) { identities.splice(index, 1); } - setIdentity(undefined); + setIdentity(EmptyIdentity); setIdentities([...identities]); } catch (error) { console.error(error); @@ -721,7 +757,6 @@ const App = () => { autoSaveId="persistence" direction="horizontal"> {loading &&
Loading...
} - { !loading && identity !== undefined && { setImage, selected, setSelected, - }} /> } + }} /> {!loading && identity === undefined &&
Select identity to edit
} diff --git a/server/routes/identities.js b/server/routes/identities.js index a57df3b..e3fd017 100755 --- a/server/routes/identities.js +++ b/server/routes/identities.js @@ -44,6 +44,7 @@ const upsertIdentity = async(id, { replacements: identity }); identity.identityId = lastId; + console.log('Created identity: ', identity) } else { await photoDB.sequelize.query( `UPDATE identities ` + @@ -55,6 +56,7 @@ const upsertIdentity = async(id, { 'WHERE id=:identityId', { replacements: identity }); + console.log('Updated identity: ', identity) } return identity; @@ -502,82 +504,92 @@ const updateIdentityFaces = async (identity) => { .parseFloat(euclideanDistanceArray(identity.descriptors, average)) .toFixed(4); - /* If the average position has not changed, then face distances should - * not change either! */ - await Promise.map(faces, async (face) => { - /* All the buffer are already arrays, so use the short-cut version */ - const distance = Number - .parseFloat(euclideanDistanceArray(face.descriptors, average)) - .toFixed(4); + const t = await photoDB.sequelize.transaction(); + try { + /* If the average position has not changed, then face distances should + * not change either! */ + await Promise.map(faces, async (face) => { + /* All the buffer are already arrays, so use the short-cut version */ + const distance = Number + .parseFloat(euclideanDistanceArray(face.descriptors, average)) + .toFixed(4); + + if (Math.abs(distance - face.distance) > MIN_DISTANCE_COMMIT) { + console.log( + `Updating face ${face.id} to ${round(distance, 2)} ` + + `(${distance - face.distance}) ` + + `from identity ${identity.identityId} (${identity.displayName})`); + face.distance = distance; + await photoDB.sequelize.query( + 'UPDATE faces SET distance=:distance WHERE id=:id', { + replacements: face, + transaction: t + } + ); + } + }, { + concurrency: 5 + }); - if (Math.abs(distance - face.distance) > MIN_DISTANCE_COMMIT) { + let sql = ''; + /* If there is a new closestId, then set the faceId field */ + if (closestId !== -1 && closestId !== identity.faceId) { console.log( - `Updating face ${face.id} to ${round(distance, 2)} ` + - `(${distance - face.distance}) ` + - `from identity ${identity.identityId} (${identity.displayName})`); - face.distance = distance; + `Updating identity ${identity.identityId} closest face to ${closestId}`); + sql = `${sql} faceId=:faceId`; + identity.faceId = closestId; + } + + /* If the centroid changed, update the identity descriptors to + * the new average */ + if (Math.abs(moved) > MIN_DISTANCE_COMMIT) { + console.log( + `Updating identity ${identity.identityId} centroid ` + + `(moved ${Number.parseFloat(moved).toFixed(4)}).`); + if (sql !== '') { + sql = `${sql}, `; + } + sql = `${sql} descriptors=:descriptors`; + // this: identity.descriptors = average; + // gives: Invalid value Float64Array(2622) + // + // this: identity.descriptors = new Blob(average); + // gives: Invalid value Blob { size: 54008, type: '' } + // + // this: identity.descriptors = Buffer.from(average); + // gives: all zeroes + // + // this: identity.descriptors = Buffer.from(average.buffer); + // gives: IT WORKS!!! + identity.descriptors = Buffer.from(average.buffer); + } + + /* If the number of faces changed, update the facesCount */ + if (identity.facesCount !== faces.length) { + if (sql !== '') { + sql = `${sql}, `; + } + console.log( + `Updating identity ${identity.identityId} face count to ${faces.length}`); + identity.facesCount = faces.length; + sql = `${sql} facesCount=${faces.length}`; + } + + /* If any of the above required changes, actually commit to the DB */ + if (sql !== '') { await photoDB.sequelize.query( - 'UPDATE faces SET distance=:distance WHERE id=:id', { - replacements: face + `UPDATE identities SET ${sql} ` + + `WHERE id=:identityId`, { + replacements: identity, + transaction: t } ); } - }, { - concurrency: 5 - }); - - let sql = ''; - /* If there is a new closestId, then set the faceId field */ - if (closestId !== -1 && closestId !== identity.faceId) { - console.log( - `Updating identity ${identity.identityId} closest face to ${closestId}`); - sql = `${sql} faceId=:faceId`; - identity.faceId = closestId; - } - - /* If the centroid changed, update the identity descriptors to - * the new average */ - if (Math.abs(moved) > MIN_DISTANCE_COMMIT) { - console.log( - `Updating identity ${identity.identityId} centroid ` + - `(moved ${Number.parseFloat(moved).toFixed(4)}).`); - if (sql !== '') { - sql = `${sql}, `; - } - sql = `${sql} descriptors=:descriptors`; - // this: identity.descriptors = average; - // gives: Invalid value Float64Array(2622) - // - // this: identity.descriptors = new Blob(average); - // gives: Invalid value Blob { size: 54008, type: '' } - // - // this: identity.descriptors = Buffer.from(average); - // gives: all zeroes - // - // this: identity.descriptors = Buffer.from(average.buffer); - // gives: IT WORKS!!! - identity.descriptors = Buffer.from(average.buffer); - } - - /* If the number of faces changed, update the facesCount */ - if (identity.facesCount !== faces.length) { - if (sql !== '') { - sql = `${sql}, `; - } - console.log( - `Updating identity ${identity.identityId} face count to ${faces.length}`); - identity.facesCount = faces.length; - sql = `${sql} facesCount=${faces.length}`; - } - - /* If any of the above required changes, actually commit to the DB */ - if (sql !== '') { - await photoDB.sequelize.query( - `UPDATE identities SET ${sql} ` + - `WHERE id=:identityId`, { - replacements: identity - } - ); + t.commit(); + } catch (error) { + console.error(error); + t.rollback(); + return; } };