Identities are loading; starting to think through workflow

Signed-off-by: James Ketrenos <james_git@ketrenos.com>
This commit is contained in:
James Ketr 2023-01-16 18:11:33 -08:00
parent 1ed1b1d1ea
commit e8de846ed0
4 changed files with 146 additions and 56 deletions

View File

@ -26,20 +26,30 @@ div {
border: 1px solid green;
}
.Identity {
.Face {
display: flex;
box-sizing: border-box;
flex-direction: column;
position: relative;
margin: 0.125rem;
border: 1px solid transparent;
}
.Identity:hover {
border: 1px solid yellow;
.Face:hover {
cursor: pointer;
}
.Identity .Title {
.Face .Image {
border: 0.25rem solid transparent;
}
.Face:hover .Image {
border: 0.25rem solid yellow;
}
.Face.Selected .Image {
border: 0.25rem solid blue;
}
.Face .Title {
position: absolute;
top: 0;
left: 0;
@ -50,7 +60,9 @@ div {
color: white;
}
.Identity .Face {
.Face .Image {
position: relative;
box-sizing: border-box;
width: 8rem;
height: 8rem;
background-size: contain !important;
@ -58,16 +70,18 @@ div {
background-position: 50% 50% !important;;
}
.Cluster {
display: flex;
flex-direction: column;
overflow-y: scroll;
flex-grow: 1;
border: 1px solid red;
padding: 0.5rem;
}
.Cluster .Face.Selected {
/* filter: grayscale(100%); */
}
.Cluster .Info {
display: flex;
flex-direction: column;

View File

@ -3,6 +3,21 @@ import React, { useState, useMemo, useEffect } from 'react';
import { useApi } from './useApi';
import './App.css';
const Face = ({ faceId, onClick, title }: any) => {
const idPath = String(faceId % 100).padStart(2, '0');
return (
<div onClick={(e) => { onClick(e, faceId) }}
className='Face'>
<div className='Image'
style={{
background: `url("/faces/${idPath}/${faceId}.jpg")`,
}}>
<div className='Title'>{title}</div>
</div>
</div>
);
};
type ClusterProps = {
id: number
};
@ -23,48 +38,113 @@ const Cluster = ({ id }: ClusterProps) => {
}
}, [data]);
const relatedFacesJSX = useMemo(() => {
const faceClicked = (e: any, id: any) => {
if (!identity) {
return;
}
const el = e.currentTarget;
const face = identity.relatedFaces.find(item => item.faceId === id);
el.classList.toggle('Selected');
console.log(face);
}
if (identity === undefined) {
return <></>;
}
return identity.relatedFaces.map((face) => {
const idPath = String(face.faceId % 100).padStart(2, '0');
return (
<div key={face.faceId}
className='Identity'>
<div className='Title'>
{face.distance}
</div>
<div className='Face'
style={{
background: `url("/faces/${idPath}/${face.faceId}.jpg")`,
}} />
</div>
);
});
return identity.relatedFaces.map(face =>
<Face key={face.faceId}
faceId={face.faceId}
onClick={faceClicked}
title={face.distance}/>
);
}, [identity]);
const lastNameChanged = (e: any) => {
setIdentity(Object.assign(
{},
identity, {
lastName: e.currentTarget.value
}
));
};
const firstNameChanged = (e: any) => {
setIdentity(Object.assign(
{},
identity, {
firstName: e.currentTarget.value
}
));
};
const middleNameChanged = (e: any) => {
setIdentity(Object.assign(
{},
identity, {
middleName: e.currentTarget.value
}
));
};
const displayNameChanged = (e: any) => {
setIdentity(Object.assign(
{},
identity, {
displayName: e.currentTarget.value
}
));
};
if (loading) {
return (<div className='Cluster'>
{loading && `Loading ${id}...`}
</div>);
}
if (identity === undefined) {
return (<div className='Cluster'>
Select identity to load.
</div>);
}
return (
<div className='Cluster'>
{ loading && `Loading ${id}`}
{ identity !== undefined && <div className="Info">
<div>{identity.lastName}</div>
<div>{identity.firstName}</div>
<div>{identity.middleName}</div>
<div>{identity.displayName}</div>
<div className="Info">
<form>
<div><label>Last name:<input type="text"
value={identity.lastName}
onChange={lastNameChanged}/>
</label></div>
<div><label>First name:<input type="text"
value={identity.firstName}
onChange={firstNameChanged} />
</label></div>
<div><label>Middle name:<input type="text"
value={identity.middleName}
onChange={middleNameChanged} />
</label></div>
<div><label>Display name:<input type="text"
value={identity.displayName}
onChange={displayNameChanged} />
</label></div>
<div>Faces: {identity.relatedFaces.length}</div>
</div> }
{ identity !== undefined && <div className="Faces">
</form>
</div>
<div className="Faces">
{ relatedFacesJSX }
</div> }
</div>
</div>
);
};
type Face = {
distance: number,
type FaceData = {
faceId: number,
photoId: number
lastName: string,
firstName: string,
middleName: string,
displayName: string,
identityId: number,
distance: number,
descriptors: any[]
};
type Identity = {
@ -74,7 +154,7 @@ type Identity = {
descriptors: number[],
id: number
displayName: string,
relatedFaces: Face[]
relatedFaces: FaceData[]
};
interface IdentitiesProps {
@ -83,8 +163,6 @@ interface IdentitiesProps {
};
const Identities = ({ identities, setIdentity } : IdentitiesProps) => {
const identitiesJSX = useMemo(() => {
const loadIdentity = (id: number): void => {
if (setIdentity) {
@ -93,19 +171,11 @@ const Identities = ({ identities, setIdentity } : IdentitiesProps) => {
};
return identities.map((identity) => {
const face = identity.relatedFaces[0];
const idPath = String(face.faceId % 100).padStart(2, '0');
return (
<div key={face.faceId}
<Face key={face.faceId}
faceId={face.faceId}
onClick={() => loadIdentity(identity.id)}
className='Identity'>
<div className='Title'>
{identity.displayName}
</div>
<div className='Face'
style={{
background: `url("/faces/${idPath}/${face.faceId}.jpg")`,
}}/>
</div>
title={identity.displayName}/>
);
});
}, [ setIdentity, identities ]);
@ -133,7 +203,7 @@ const App = () => {
return (
<div className="App">
<div className="Worksheet">
{ loading && <div>Loading...</div> }
{ loading && <div style={{margin:'1rem'}}>Loading...</div> }
{ !loading && identity !== 0 && <Cluster id={identity} />}
{ !loading && identity === 0 && <div className="Cluster">
Select identity to edit

View File

@ -8,31 +8,30 @@ type UseApi = {
};
const useApi = (_url: string, _options?: {}) : UseApi => {
const [loading, setLoading] = useState(false);
const [loading, setLoading] = useState(true);
const [data, setData] = useState(undefined);
const [error, setError] = useState<any>(undefined);
useEffect(() => {
if (_url === '' || loading) {
if (_url === '') {
return;
}
const fetchApi = async () => {
console.log(`Fetching ${_url}...`);
setLoading(true);
try {
const res = await window.fetch(_url, _options);
const data = await res.json();
setData(data);
setLoading(false);
} catch (e) {
console.log(e);
setError(e)
} finally {
setLoading(false);
};
};
fetchApi();
}, [_url, _options, loading]);
}, [_url, _options]);
return { loading, data, error };
};

7
reset-identities.sh Normal file
View File

@ -0,0 +1,7 @@
#!/bin/bash
. .env
cat << EOF | ./query.sh
update faces set identityId=NULL where identityId is not null;
delete from identities where id>0;
delete from sqlite_sequence where name='identities';
EOF