Support for recognize v3.8 (fix #618)
Signed-off-by: Varun Patil <radialapps@gmail.com>pull/653/head
parent
e1986b6991
commit
429c821fbf
|
@ -57,9 +57,13 @@ class RecognizeBackend extends Backend
|
||||||
|
|
||||||
public function transformDayQuery(&$query, bool $aggregate): void
|
public function transformDayQuery(&$query, bool $aggregate): void
|
||||||
{
|
{
|
||||||
$faceStr = (string) $this->request->getParam('recognize');
|
// Check if Recognize is enabled
|
||||||
|
if (!$this->isEnabled()) {
|
||||||
|
throw \OCA\Memories\Exceptions::NotEnabled('Recognize');
|
||||||
|
}
|
||||||
|
|
||||||
// Get name and uid of face user
|
// Get name and uid of face user
|
||||||
|
$faceStr = (string) $this->request->getParam('recognize');
|
||||||
$faceNames = explode('/', $faceStr);
|
$faceNames = explode('/', $faceStr);
|
||||||
if (2 !== \count($faceNames)) {
|
if (2 !== \count($faceNames)) {
|
||||||
throw new \Exception('Invalid face query');
|
throw new \Exception('Invalid face query');
|
||||||
|
|
|
@ -92,7 +92,7 @@ class Util
|
||||||
}
|
}
|
||||||
|
|
||||||
$v = $appManager->getAppVersion('recognize');
|
$v = $appManager->getAppVersion('recognize');
|
||||||
if (!version_compare($v, '3.0.0-alpha', '>=')) {
|
if (!version_compare($v, '3.8.0', '>=')) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -801,17 +801,23 @@ export default defineComponent({
|
||||||
|
|
||||||
// Check photo ownership
|
// Check photo ownership
|
||||||
if (this.$route.params.user !== getCurrentUser()?.uid) {
|
if (this.$route.params.user !== getCurrentUser()?.uid) {
|
||||||
showError(
|
showError(this.t('memories', 'Only user "{user}" can update this person', { user }));
|
||||||
this.t('memories', 'Only user "{user}" can update this person', {
|
|
||||||
user,
|
|
||||||
})
|
|
||||||
);
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Run query
|
// Make map to get back photo from faceid
|
||||||
for await (let delIds of dav.removeFaceImages(<string>user, <string>name, Array.from(selection.values()))) {
|
const map = new Map<number, IPhoto>();
|
||||||
this.deleteSelectedPhotosById(delIds, selection);
|
for (const photo of selection.values()) {
|
||||||
|
if (photo.faceid) {
|
||||||
|
map.set(photo.faceid, photo);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
const photos = Array.from(map.values());
|
||||||
|
|
||||||
|
// Run WebDAV query
|
||||||
|
for await (let delIds of dav.recognizeDeleteFaceImages(user, name, photos)) {
|
||||||
|
const fileIds = delIds.map((id) => map.get(id)?.fileid ?? 0).filter((id) => id);
|
||||||
|
this.deleteSelectedPhotosById(fileIds, selection);
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
|
|
|
@ -77,9 +77,9 @@ export default defineComponent({
|
||||||
async save() {
|
async save() {
|
||||||
try {
|
try {
|
||||||
if (this.$route.name === 'recognize') {
|
if (this.$route.name === 'recognize') {
|
||||||
await client.deleteFile(`/recognize/${this.user}/faces/${this.name}`);
|
await dav.recognizeDeleteFace(this.user, this.name);
|
||||||
} else {
|
} else {
|
||||||
await dav.setVisibilityPeopleFaceRecognition(this.name, false);
|
await dav.faceRecognitionSetPersonVisibility(this.name, false);
|
||||||
}
|
}
|
||||||
this.$router.push({ name: this.$route.name as string });
|
this.$router.push({ name: this.$route.name as string });
|
||||||
this.close();
|
this.close();
|
||||||
|
|
|
@ -89,12 +89,9 @@ export default defineComponent({
|
||||||
async save() {
|
async save() {
|
||||||
try {
|
try {
|
||||||
if (this.$route.name === 'recognize') {
|
if (this.$route.name === 'recognize') {
|
||||||
await client.moveFile(
|
await dav.recognizeRenameFace(this.user, this.oldName, this.name);
|
||||||
`/recognize/${this.user}/faces/${this.oldName}`,
|
|
||||||
`/recognize/${this.user}/faces/${this.name}`
|
|
||||||
);
|
|
||||||
} else {
|
} else {
|
||||||
await dav.renamePeopleFaceRecognition(this.oldName, this.name);
|
await dav.faceRecognitionRenamePerson(this.oldName, this.name);
|
||||||
}
|
}
|
||||||
this.$router.push({
|
this.$router.push({
|
||||||
name: this.$route.name as string,
|
name: this.$route.name as string,
|
||||||
|
|
|
@ -89,14 +89,13 @@ export default defineComponent({
|
||||||
async clickFace(face: IFace) {
|
async clickFace(face: IFace) {
|
||||||
const user = this.$route.params.user || '';
|
const user = this.$route.params.user || '';
|
||||||
const name = this.$route.params.name || '';
|
const name = this.$route.params.name || '';
|
||||||
|
const target = String(face.name || face.cluster_id);
|
||||||
const newName = String(face.name || face.cluster_id);
|
|
||||||
|
|
||||||
if (
|
if (
|
||||||
!confirm(
|
!confirm(
|
||||||
this.t('memories', 'Are you sure you want to move the selected photos from {name} to {newName}?', {
|
this.t('memories', 'Are you sure you want to move the selected photos from {name} to {target}?', {
|
||||||
name,
|
name,
|
||||||
newName,
|
target,
|
||||||
})
|
})
|
||||||
)
|
)
|
||||||
) {
|
) {
|
||||||
|
@ -108,31 +107,19 @@ export default defineComponent({
|
||||||
this.updateLoading(1);
|
this.updateLoading(1);
|
||||||
|
|
||||||
// Create map to return IPhoto later
|
// Create map to return IPhoto later
|
||||||
let photoMap = new Map<number, IPhoto>();
|
const map = new Map<number, IPhoto>();
|
||||||
for (const photo of this.photos) {
|
for (const photo of this.photos.filter((p) => p.faceid)) {
|
||||||
photoMap.set(photo.fileid, photo);
|
map.set(photo.faceid!, photo);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Create move calls
|
// Run WebDAV query
|
||||||
const calls = this.photos.map((p) => async () => {
|
const photos = Array.from(map.values());
|
||||||
try {
|
for await (let delIds of dav.recognizeMoveFaceImages(user, name, target, photos)) {
|
||||||
await client.moveFile(
|
this.moved(delIds.filter((id) => id).map((id) => map.get(id)!));
|
||||||
`/recognize/${user}/faces/${name}/${p.fileid}-${p.basename}`,
|
|
||||||
`/recognize/${face.user_id}/faces/${newName}/${p.fileid}-${p.basename}`
|
|
||||||
);
|
|
||||||
return photoMap.get(p.fileid);
|
|
||||||
} catch (e) {
|
|
||||||
console.error(e);
|
|
||||||
showError(this.t('memories', 'Error while moving {basename}', <any>p));
|
|
||||||
}
|
|
||||||
});
|
|
||||||
for await (const resp of dav.runInParallel(calls, 10)) {
|
|
||||||
const valid = resp.filter((r): r is IPhoto => r !== undefined);
|
|
||||||
this.moved(valid);
|
|
||||||
}
|
}
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
console.error(error);
|
console.error(error);
|
||||||
showError(this.t('photos', 'Failed to move {name}.', { name }));
|
showError(this.t('photos', 'An error occured while moving photos from {name}.', { name }));
|
||||||
} finally {
|
} finally {
|
||||||
this.updateLoading(-1);
|
this.updateLoading(-1);
|
||||||
this.close();
|
this.close();
|
||||||
|
|
|
@ -11,7 +11,12 @@ export async function getFaceList(app: 'recognize' | 'facerecognition') {
|
||||||
return (await axios.get<IFace[]>(API.FACE_LIST(app))).data;
|
return (await axios.get<IFace[]>(API.FACE_LIST(app))).data;
|
||||||
}
|
}
|
||||||
|
|
||||||
export async function updatePeopleFaceRecognition(name: string, params: object) {
|
/**
|
||||||
|
* Update a person or cluster in face recognition
|
||||||
|
* @param name Name of face (or ID)
|
||||||
|
* @param params Parameters to update
|
||||||
|
*/
|
||||||
|
export async function faceRecognitionUpdatePerson(name: string, params: object) {
|
||||||
if (Number.isInteger(Number(name))) {
|
if (Number.isInteger(Number(name))) {
|
||||||
return await axios.put(generateUrl(`/apps/facerecognition/api/2.0/cluster/${name}`), params);
|
return await axios.put(generateUrl(`/apps/facerecognition/api/2.0/cluster/${name}`), params);
|
||||||
} else {
|
} else {
|
||||||
|
@ -19,16 +24,22 @@ export async function updatePeopleFaceRecognition(name: string, params: object)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
export async function renamePeopleFaceRecognition(name: string, newName: string) {
|
/**
|
||||||
return await updatePeopleFaceRecognition(name, {
|
* Rename a face in face recognition
|
||||||
name: newName,
|
* @param name Name of face (or ID)
|
||||||
});
|
* @param target Target name of face
|
||||||
|
*/
|
||||||
|
export async function faceRecognitionRenamePerson(name: string, target: string) {
|
||||||
|
return await faceRecognitionUpdatePerson(name, { name: target });
|
||||||
}
|
}
|
||||||
|
|
||||||
export async function setVisibilityPeopleFaceRecognition(name: string, visibility: boolean) {
|
/**
|
||||||
return await updatePeopleFaceRecognition(name, {
|
* Set visibility of a face
|
||||||
visible: visibility,
|
* @param name Name of face (or ID)
|
||||||
});
|
* @param visible Visibility of face
|
||||||
|
*/
|
||||||
|
export async function faceRecognitionSetPersonVisibility(name: string, visible: boolean) {
|
||||||
|
return await faceRecognitionUpdatePerson(name, { visible });
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -37,19 +48,19 @@ export async function setVisibilityPeopleFaceRecognition(name: string, visibilit
|
||||||
* @param user User ID of face
|
* @param user User ID of face
|
||||||
* @param name Name of face (or ID)
|
* @param name Name of face (or ID)
|
||||||
* @param photos List of photos to remove
|
* @param photos List of photos to remove
|
||||||
* @returns Generator
|
* @returns Generator for face IDs
|
||||||
*/
|
*/
|
||||||
export async function* removeFaceImages(user: string, name: string, photos: IPhoto[]) {
|
export async function* recognizeDeleteFaceImages(user: string, name: string, photos: IPhoto[]) {
|
||||||
// Remove each file
|
// Remove each file
|
||||||
const calls = photos.map((f) => async () => {
|
const calls = photos.map((p) => async () => {
|
||||||
try {
|
try {
|
||||||
await client.deleteFile(`/recognize/${user}/faces/${name}/${f.fileid}-${f.basename}`);
|
await client.deleteFile(`/recognize/${user}/faces/${name}/${p.faceid}-${p.basename}`);
|
||||||
return f.fileid;
|
return p.faceid!;
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
console.error(e);
|
console.error(e);
|
||||||
showError(
|
showError(
|
||||||
t('memories', 'Failed to remove {filename} from face.', {
|
t('memories', 'Failed to remove {filename} from face.', {
|
||||||
filename: f.basename ?? f.fileid,
|
filename: p.basename ?? p.fileid,
|
||||||
})
|
})
|
||||||
);
|
);
|
||||||
return 0;
|
return 0;
|
||||||
|
@ -58,3 +69,56 @@ export async function* removeFaceImages(user: string, name: string, photos: IPho
|
||||||
|
|
||||||
yield* base.runInParallel(calls, 10);
|
yield* base.runInParallel(calls, 10);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Move faces from one face to another
|
||||||
|
*
|
||||||
|
* @param user User ID of face
|
||||||
|
* @param face Name of face (or ID)
|
||||||
|
* @param target Name of target face (or ID)
|
||||||
|
* @param photos List of photos to move
|
||||||
|
* @returns Generator for face IDs
|
||||||
|
*/
|
||||||
|
export async function* recognizeMoveFaceImages(user: string, face: string, target: string, photos: IPhoto[]) {
|
||||||
|
// Remove each file
|
||||||
|
const calls = photos.map((p) => async () => {
|
||||||
|
try {
|
||||||
|
await client.moveFile(
|
||||||
|
`/recognize/${user}/faces/${face}/${p.faceid}-${p.basename}`,
|
||||||
|
`/recognize/${user}/faces/${target}/${p.faceid}-${p.basename}`
|
||||||
|
);
|
||||||
|
return p.faceid!;
|
||||||
|
} catch (e) {
|
||||||
|
console.error(e);
|
||||||
|
showError(
|
||||||
|
t('memories', 'Failed to move {filename} from face.', {
|
||||||
|
filename: p.basename ?? p.fileid,
|
||||||
|
})
|
||||||
|
);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
yield* base.runInParallel(calls, 10);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Remove a face entirely
|
||||||
|
*
|
||||||
|
* @param user User ID of face
|
||||||
|
* @param name Name of face (or ID)
|
||||||
|
*/
|
||||||
|
export async function recognizeDeleteFace(user: string, name: string) {
|
||||||
|
return await client.deleteFile(`/recognize/${user}/faces/${name}`);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Rename a face in recognize
|
||||||
|
*
|
||||||
|
* @param user User ID of face
|
||||||
|
* @param name Name of face (or ID)
|
||||||
|
* @param target Target name of face
|
||||||
|
*/
|
||||||
|
export async function recognizeRenameFace(user: string, name: string, target: string) {
|
||||||
|
await client.moveFile(`/recognize/${user}/faces/${name}`, `/recognize/${user}/faces/${target}`);
|
||||||
|
}
|
||||||
|
|
Loading…
Reference in New Issue