wip checkpoint
This commit is contained in:
@@ -16,7 +16,7 @@ import { UnidentifiedFaces } from "@/new/photos/components/PeopleList";
|
||||
import { PhotoDateTimePicker } from "@/new/photos/components/PhotoDateTimePicker";
|
||||
import { photoSwipeZIndex } from "@/new/photos/components/PhotoViewer";
|
||||
import { tagNumericValue, type RawExifTags } from "@/new/photos/services/exif";
|
||||
import { annotatedFaceIDsForFile, isMLEnabled } from "@/new/photos/services/ml";
|
||||
import { annotatedFaceIDsForFile, AnnotatedFacesForFile, getAnnotatedFacesForFile, getFacesForFile, isMLEnabled } from "@/new/photos/services/ml";
|
||||
import { EnteFile } from "@/new/photos/types/file";
|
||||
import { formattedByteSize } from "@/new/photos/utils/units";
|
||||
import CopyButton from "@ente/shared/components/CodeBlock/CopyButton";
|
||||
@@ -98,6 +98,7 @@ export const FileInfo: React.FC<FileInfoProps> = ({
|
||||
|
||||
const [exifInfo, setExifInfo] = useState<ExifInfo | undefined>();
|
||||
const [openRawExif, setOpenRawExif] = useState(false);
|
||||
const [annotatedFaces, setAnnotatedFaces] = useState<AnnotatedFacesForFile | undefined>();
|
||||
|
||||
const location = useMemo(() => {
|
||||
if (file) {
|
||||
@@ -107,23 +108,19 @@ export const FileInfo: React.FC<FileInfoProps> = ({
|
||||
return exif?.parsed?.location;
|
||||
}, [file, exif]);
|
||||
|
||||
const [annotatedPeopleFaceIDs, otherFaceIDs] =
|
||||
useMemoSingleThreaded(async () => {
|
||||
if (!file) return [[], []];
|
||||
const annotatedFaceIDs = await annotatedFaceIDsForFile(file);
|
||||
return annotatedFaceIDs.reduce(
|
||||
([people, other], item) => {
|
||||
if (item[1]) {
|
||||
people.push(item);
|
||||
} else {
|
||||
other.push(item[0]);
|
||||
}
|
||||
return [people, other];
|
||||
},
|
||||
[[], []],
|
||||
);
|
||||
|
||||
useEffect(() => {
|
||||
let didCancel = false;
|
||||
|
||||
void (async () => {
|
||||
const result = await getAnnotatedFacesForFile(file);
|
||||
!didCancel && setAnnotatedFaces(result);
|
||||
})();
|
||||
|
||||
return () => { didCancel = true;}
|
||||
}, [file]);
|
||||
|
||||
|
||||
useEffect(() => {
|
||||
setExifInfo(parseExifInfo(exif));
|
||||
}, [exif]);
|
||||
@@ -287,7 +284,8 @@ export const FileInfo: React.FC<FileInfoProps> = ({
|
||||
|
||||
{isMLEnabled() && (
|
||||
<>
|
||||
{/* TODO-Cluster <PhotoPeopleList file={file} /> */}
|
||||
{annotatedFaces?.annotatedFaceIDs.length &&
|
||||
// {/* TODO-Cluster <PhotoPeopleList file={file} /> */}
|
||||
<UnidentifiedFaces enteFile={file} />
|
||||
</>
|
||||
)}
|
||||
|
||||
@@ -1,12 +1,11 @@
|
||||
import { useIsMobileWidth } from "@/base/hooks";
|
||||
import { faceCrop, unidentifiedFaceIDs } from "@/new/photos/services/ml";
|
||||
import { faceCrop, type AnnotatedFaceID } from "@/new/photos/services/ml";
|
||||
import type { Person } from "@/new/photos/services/ml/people";
|
||||
import type { EnteFile } from "@/new/photos/types/file";
|
||||
import { Skeleton, Typography, styled } from "@mui/material";
|
||||
import { t } from "i18next";
|
||||
import React, { useEffect, useState } from "react";
|
||||
import { UnstyledButton } from "./mui-custom";
|
||||
import type { CGroup } from "../services/user-entity";
|
||||
|
||||
export interface SearchPeopleListProps {
|
||||
people: Person[];
|
||||
@@ -67,28 +66,21 @@ const SearchPeopleButton = styled(UnstyledButton)(
|
||||
`,
|
||||
);
|
||||
|
||||
export interface CGroupPeopleListProps {
|
||||
export interface AnnotatedFacePeopleListProps {
|
||||
annotatedFaceIDs: AnnotatedFaceID[];
|
||||
/**
|
||||
* List of cgroup people to show.
|
||||
*
|
||||
* The current types don't reflect this, but these are all guaranteed to be
|
||||
* {@link Person}s with type "cgroup"
|
||||
* Called when the user selects a face in the list.
|
||||
*/
|
||||
people: Person[];
|
||||
/**
|
||||
* Called when the user selects a person in the list.
|
||||
*/
|
||||
onSelectPerson: (person: Person) => void;
|
||||
onSelectFace: (annotatedFaceID: AnnotatedFaceID) => void;
|
||||
}
|
||||
|
||||
/**
|
||||
* Show the list of faces in the given file that are not linked to a a specific
|
||||
* cgroup ("people").
|
||||
* Show the list of faces in the given file that are associated with a specific
|
||||
* person.
|
||||
*/
|
||||
export const CGroupPeopleList: React.FC<SearchPeopleListProps> = ({
|
||||
people,
|
||||
onSelectPerson,
|
||||
}) => {
|
||||
export const AnnotatedFacePeopleList: React.FC<
|
||||
AnnotatedFacePeopleListProps
|
||||
> = ({ annotatedFaceIDs, onSelectFace }) => {
|
||||
const isMobileWidth = useIsMobileWidth();
|
||||
return (
|
||||
<SearchPeopleContainer
|
||||
@@ -182,21 +174,6 @@ export const UnidentifiedFaces: React.FC<UnidentifiedFacesProps> = ({
|
||||
}) => {
|
||||
const [faceIDs, setFaceIDs] = useState<string[]>([]);
|
||||
|
||||
useEffect(() => {
|
||||
let didCancel = false;
|
||||
|
||||
const go = async () => {
|
||||
const faceIDs = await unidentifiedFaceIDs(enteFile);
|
||||
!didCancel && setFaceIDs(faceIDs);
|
||||
};
|
||||
|
||||
void go();
|
||||
|
||||
return () => {
|
||||
didCancel = true;
|
||||
};
|
||||
}, [enteFile]);
|
||||
|
||||
if (faceIDs.length == 0) return <></>;
|
||||
|
||||
return (
|
||||
|
||||
@@ -592,18 +592,39 @@ export const clipMatches = (
|
||||
): Promise<CLIPMatches | undefined> =>
|
||||
worker().then((w) => w.clipMatches(searchPhrase));
|
||||
|
||||
/** A face ID annotated with the ID of the person to which it is associated. */
|
||||
export interface AnnotatedFaceID {
|
||||
faceID: string;
|
||||
personID: string;
|
||||
}
|
||||
|
||||
/**
|
||||
* List of faces found in a file
|
||||
*
|
||||
* It is actually a pair of lists, one annotated by the person ids, and one with
|
||||
* just the face ids.
|
||||
*/
|
||||
export interface AnnotatedFacesForFile {
|
||||
/**
|
||||
* A list of {@link AnnotatedFaceID}s for all faces in the file that are
|
||||
* also associated with a {@link Person}.
|
||||
*/
|
||||
annotatedFaceIDs: AnnotatedFaceID[];
|
||||
/* A list of the remaining face (ids). */
|
||||
otherFaceIDs: string[];
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the list of faces found in the given {@link enteFile}.
|
||||
*
|
||||
* Each item is returned as a (faceID, personID) tuple, where the faceID is the
|
||||
* ID of the face, and the personID is the id of the corresponding person that
|
||||
* this face is associated to (if any).
|
||||
*/
|
||||
export const annotatedFaceIDsForFile = async (
|
||||
export const getAnnotatedFacesForFile = async (
|
||||
enteFile: EnteFile,
|
||||
): Promise<[string, string | undefined][]> => {
|
||||
): Promise<AnnotatedFacesForFile> => {
|
||||
const annotatedFaceIDs: AnnotatedFaceID[] = [];
|
||||
const otherFaceIDs: string[] = [];
|
||||
|
||||
const index = await getFaceIndex(enteFile.id);
|
||||
if (!index) return [];
|
||||
if (!index) return { annotatedFaceIDs, otherFaceIDs };
|
||||
|
||||
const people = _state.peopleSnapshot ?? [];
|
||||
|
||||
@@ -620,10 +641,16 @@ export const annotatedFaceIDsForFile = async (
|
||||
}
|
||||
}
|
||||
|
||||
return index.faces.map(({ faceID }) => [
|
||||
faceID,
|
||||
faceIDToPersonID.get(faceID),
|
||||
]);
|
||||
for (const { faceID } of index.faces) {
|
||||
const personID = faceIDToPersonID.get(faceID);
|
||||
if (personID) {
|
||||
annotatedFaceIDs.push({ faceID, personID });
|
||||
} else {
|
||||
otherFaceIDs.push(faceID);
|
||||
}
|
||||
}
|
||||
|
||||
return { annotatedFaceIDs, otherFaceIDs };
|
||||
};
|
||||
|
||||
/**
|
||||
|
||||
Reference in New Issue
Block a user