Can now create blank identities

Signed-off-by: James Ketrenos <james_git@ketrenos.com>
This commit is contained in:
James Ketr 2023-01-25 13:43:43 -08:00
parent df764ad342
commit b86c12fc92
3 changed files with 157 additions and 97 deletions

View File

@ -121,7 +121,15 @@ div {
.IdentityForm { .IdentityForm {
display: grid; display: grid;
gap: 0.25rem;
grid-template-columns: 1fr 1fr; grid-template-columns: 1fr 1fr;
align-items: center;
justify-items: flex-end;
}
.IdentityForm input {
min-height: 1rem;
padding: 0.25rem;
} }
.Face.Active, .Face.Active,
@ -145,11 +153,18 @@ div {
color: white; color: white;
} }
.Info .Face .Image {
width: 10rem;
height: 10rem;
}
.Face .Image { .Face .Image {
position: relative; position: relative;
box-sizing: border-box; box-sizing: border-box;
display: flex; display: flex;
justify-content: center; justify-content: center;
min-width: 8rem;
min-height: 8rem;
} }
.Cluster { .Cluster {
@ -175,8 +190,6 @@ div {
object-fit: cover; /* contain */ object-fit: cover; /* contain */
width: 100%; width: 100%;
height: 100%; height: 100%;
min-width: 8rem;
min-height: 8rem;
} }
.Cluster .Faces { .Cluster .Faces {

View File

@ -209,7 +209,7 @@ const Face = ({ face, onFaceClick, title, isSelected }: any) => {
type ClusterProps = { type ClusterProps = {
identity: IdentityData, identity: IdentityData,
setIdentity(identity: IdentityData | undefined): void, setIdentity(identity: IdentityData): void,
identities: IdentityData[], identities: IdentityData[],
setIdentities(identiteis: IdentityData[]): void, setIdentities(identiteis: IdentityData[]): void,
setImage(image: number): void, setImage(image: number): void,
@ -275,7 +275,7 @@ const Cluster = ({
if (index !== -1) { if (index !== -1) {
identities.splice(index, 1); identities.splice(index, 1);
} }
setIdentity(undefined); setIdentity(EmptyIdentity);
setIdentities([...identities]); setIdentities([...identities]);
} catch (error) { } catch (error) {
console.error(error); console.error(error);
@ -338,6 +338,7 @@ const Cluster = ({
return ( return (
<div className='Cluster'> <div className='Cluster'>
<div className="Info"> <div className="Info">
<div style={{ display: "flex", flexDirection: "row", gap: "0.25rem" }}>
<form className="IdentityForm"> <form className="IdentityForm">
<div>Last name:</div> <div>Last name:</div>
<input type="text" <input type="text"
@ -355,10 +356,19 @@ const Cluster = ({
value={identity.displayName} value={identity.displayName}
onChange={displayNameChanged} /> onChange={displayNameChanged} />
</form> </form>
<Face
face={identity.relatedFaces.length
? identity.relatedFaces[0]
: UnknownFace}
onFaceClick={() => {}}
title={`${identity.displayName} (${identity.facesCount})`} />
</div>
<div className="Actions"> <div className="Actions">
<Button onClick={createIdentity}>Create</Button> <Button onClick={createIdentity}>Create</Button>
{ identity.identityId !== -1 && <>
<Button onClick={updateIdentity}>Update</Button> <Button onClick={updateIdentity}>Update</Button>
<Button onClick={deleteIdentity}>Delete</Button> <Button onClick={deleteIdentity}>Delete</Button>
</> }
</div> </div>
</div> </div>
<div>Faces: {identity.relatedFaces.length}</div> <div>Faces: {identity.relatedFaces.length}</div>
@ -405,6 +415,32 @@ type IdentityData = {
faceId: number 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 { interface IdentitiesProps {
identities: IdentityData[], identities: IdentityData[],
onFaceClick(e: any, face: FaceData): void onFaceClick(e: any, face: FaceData): void
@ -448,7 +484,7 @@ const App = () => {
const [identities, setIdentities] = useState<IdentityData[]>([]); const [identities, setIdentities] = useState<IdentityData[]>([]);
const { identityId, faceId } = useParams(); const { identityId, faceId } = useParams();
const [selectedIdentities, setSelectedIdentities] = useState<number[]>([]); const [selectedIdentities, setSelectedIdentities] = useState<number[]>([]);
const [identity, setIdentity] = useState<IdentityData | undefined>(undefined); const [identity, setIdentity] = useState<IdentityData>(EmptyIdentity);
const [image, setImage] = useState<number>(0); const [image, setImage] = useState<number>(0);
const [guess, setGuess] = useState<FaceData|undefined>(undefined); const [guess, setGuess] = useState<FaceData|undefined>(undefined);
const { loading, data } = useApi( /* TODO: Switch away from using useApi */ const { loading, data } = useApi( /* TODO: Switch away from using useApi */
@ -575,7 +611,7 @@ const App = () => {
if (index !== -1) { if (index !== -1) {
identities.splice(index, 1); identities.splice(index, 1);
} }
setIdentity(undefined); setIdentity(EmptyIdentity);
setIdentities([...identities]); setIdentities([...identities]);
} catch (error) { } catch (error) {
console.error(error); console.error(error);
@ -721,7 +757,6 @@ const App = () => {
autoSaveId="persistence" direction="horizontal"> autoSaveId="persistence" direction="horizontal">
<Panel defaultSize={50} className="ClusterEditor"> <Panel defaultSize={50} className="ClusterEditor">
{loading && <div style={{ margin: '1rem' }}>Loading...</div>} {loading && <div style={{ margin: '1rem' }}>Loading...</div>}
{ !loading && identity !== undefined &&
<Cluster {...{ <Cluster {...{
identity, identity,
setIdentity, setIdentity,
@ -730,7 +765,7 @@ const App = () => {
setImage, setImage,
selected, selected,
setSelected, setSelected,
}} /> } }} />
{!loading && identity === undefined && <div className="Cluster"> {!loading && identity === undefined && <div className="Cluster">
Select identity to edit Select identity to edit
</div>} </div>}

View File

@ -44,6 +44,7 @@ const upsertIdentity = async(id, {
replacements: identity replacements: identity
}); });
identity.identityId = lastId; identity.identityId = lastId;
console.log('Created identity: ', identity)
} else { } else {
await photoDB.sequelize.query( await photoDB.sequelize.query(
`UPDATE identities ` + `UPDATE identities ` +
@ -55,6 +56,7 @@ const upsertIdentity = async(id, {
'WHERE id=:identityId', { 'WHERE id=:identityId', {
replacements: identity replacements: identity
}); });
console.log('Updated identity: ', identity)
} }
return identity; return identity;
@ -502,6 +504,8 @@ const updateIdentityFaces = async (identity) => {
.parseFloat(euclideanDistanceArray(identity.descriptors, average)) .parseFloat(euclideanDistanceArray(identity.descriptors, average))
.toFixed(4); .toFixed(4);
const t = await photoDB.sequelize.transaction();
try {
/* If the average position has not changed, then face distances should /* If the average position has not changed, then face distances should
* not change either! */ * not change either! */
await Promise.map(faces, async (face) => { await Promise.map(faces, async (face) => {
@ -518,7 +522,8 @@ const updateIdentityFaces = async (identity) => {
face.distance = distance; face.distance = distance;
await photoDB.sequelize.query( await photoDB.sequelize.query(
'UPDATE faces SET distance=:distance WHERE id=:id', { 'UPDATE faces SET distance=:distance WHERE id=:id', {
replacements: face replacements: face,
transaction: t
} }
); );
} }
@ -575,10 +580,17 @@ const updateIdentityFaces = async (identity) => {
await photoDB.sequelize.query( await photoDB.sequelize.query(
`UPDATE identities SET ${sql} ` + `UPDATE identities SET ${sql} ` +
`WHERE id=:identityId`, { `WHERE id=:identityId`, {
replacements: identity replacements: identity,
transaction: t
} }
); );
} }
t.commit();
} catch (error) {
console.error(error);
t.rollback();
return;
}
}; };
router.get("/:id?", async (req, res) => { router.get("/:id?", async (req, res) => {