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 (
-
+
+
+
{}}
+ 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;
}
};