mirror of
https://github.com/haiwen/seahub.git
synced 2025-09-25 06:33:48 +00:00
face recognition menu
This commit is contained in:
@@ -92,6 +92,20 @@ export const MetadataAIOperationsProvider = ({
|
||||
});
|
||||
}, [extractFilesDetails]);
|
||||
|
||||
const faceRecognition = useCallback((objIds, { success_callback, fail_callback } = {}) => {
|
||||
const inProgressToaster = toaster.notifyInProgress(gettext('Recognize faces by AI...'), { duration: null });
|
||||
metadataAPI.recognizeFaces(repoID, objIds).then(res => {
|
||||
inProgressToaster.close();
|
||||
toaster.success(gettext('Faces recognized'));
|
||||
success_callback && success_callback();
|
||||
}).catch(error => {
|
||||
inProgressToaster.close();
|
||||
const errorMessage = gettext('Failed to recognize faces');
|
||||
toaster.danger(errorMessage);
|
||||
fail_callback && fail_callback();
|
||||
});
|
||||
}, [repoID]);
|
||||
|
||||
return (
|
||||
<MetadataAIOperationsContext.Provider value={{
|
||||
enableMetadata,
|
||||
@@ -104,6 +118,7 @@ export const MetadataAIOperationsProvider = ({
|
||||
generateDescription,
|
||||
extractFilesDetails,
|
||||
extractFileDetails,
|
||||
faceRecognition,
|
||||
}}>
|
||||
{children}
|
||||
</MetadataAIOperationsContext.Provider>
|
||||
|
@@ -334,6 +334,14 @@ class MetadataManagerAPI {
|
||||
return this.req.delete(url);
|
||||
};
|
||||
|
||||
recognizeFaces = (repoID, objIds) => {
|
||||
const url = this.server + '/api/v2.1/repos/' + repoID + '/metadata/recognize-faces/';
|
||||
const params = {
|
||||
obj_ids: objIds,
|
||||
};
|
||||
return this.req.post(url, params);
|
||||
};
|
||||
|
||||
getFaceData = (repoID, start = 0, limit = 1000) => {
|
||||
const url = this.server + '/api/v2.1/repos/' + repoID + '/metadata/face-records/?start=' + start + '&limit=' + limit;
|
||||
return this.req.get(url);
|
||||
|
@@ -44,6 +44,7 @@ export const EVENT_BUS_TYPE = {
|
||||
MOVE_RECORD: 'move_record',
|
||||
DELETE_RECORDS: 'delete_records',
|
||||
UPDATE_RECORD_DETAILS: 'update_record_details',
|
||||
UPDATE_FACE_RECOGNITION: 'update_face_recognition',
|
||||
GENERATE_DESCRIPTION: 'generate_description',
|
||||
OCR: 'ocr',
|
||||
|
||||
|
@@ -38,7 +38,7 @@ export const MetadataViewProvider = ({
|
||||
|
||||
const { collaborators } = useCollaborators();
|
||||
const { isBeingBuilt, setIsBeingBuilt } = useMetadata();
|
||||
const { onOCR, generateDescription, extractFilesDetails } = useMetadataAIOperations();
|
||||
const { onOCR, generateDescription, extractFilesDetails, faceRecognition } = useMetadataAIOperations();
|
||||
|
||||
const tableChanged = useCallback(() => {
|
||||
setMetadata(storeRef.current.data);
|
||||
@@ -348,6 +348,15 @@ export const MetadataViewProvider = ({
|
||||
});
|
||||
}, [metadata, extractFilesDetails, modifyRecords]);
|
||||
|
||||
const updateFaceRecognition = useCallback((records) => {
|
||||
const recordObjIds = records.map(record => getFileObjIdFromRecord(record));
|
||||
if (recordObjIds.length > 50) {
|
||||
toaster.danger(gettext('Select up to 50 files'));
|
||||
return;
|
||||
}
|
||||
faceRecognition(recordObjIds);
|
||||
}, [faceRecognition]);
|
||||
|
||||
const updateRecordDescription = useCallback((record) => {
|
||||
const parentDir = getParentDirFromRecord(record);
|
||||
const fileName = getFileNameFromRecord(record);
|
||||
@@ -429,6 +438,7 @@ export const MetadataViewProvider = ({
|
||||
const unsubscribeMoveRecord = eventBus.subscribe(EVENT_BUS_TYPE.MOVE_RECORD, moveRecord);
|
||||
const unsubscribeDeleteRecords = eventBus.subscribe(EVENT_BUS_TYPE.DELETE_RECORDS, deleteRecords);
|
||||
const unsubscribeUpdateDetails = eventBus.subscribe(EVENT_BUS_TYPE.UPDATE_RECORD_DETAILS, updateRecordDetails);
|
||||
const unsubscribeUpdateFaceRecognition = eventBus.subscribe(EVENT_BUS_TYPE.UPDATE_FACE_RECOGNITION, updateFaceRecognition);
|
||||
const unsubscribeUpdateDescription = eventBus.subscribe(EVENT_BUS_TYPE.GENERATE_DESCRIPTION, updateRecordDescription);
|
||||
const unsubscribeOCR = eventBus.subscribe(EVENT_BUS_TYPE.OCR, ocr);
|
||||
|
||||
@@ -454,6 +464,7 @@ export const MetadataViewProvider = ({
|
||||
unsubscribeMoveRecord();
|
||||
unsubscribeDeleteRecords();
|
||||
unsubscribeUpdateDetails();
|
||||
unsubscribeUpdateFaceRecognition();
|
||||
unsubscribeUpdateDescription();
|
||||
unsubscribeOCR();
|
||||
delayReloadDataTimer.current && clearTimeout(delayReloadDataTimer.current);
|
||||
@@ -493,6 +504,7 @@ export const MetadataViewProvider = ({
|
||||
updateCurrentPath: params.updateCurrentPath,
|
||||
updateSelectedRecordIds,
|
||||
updateRecordDetails,
|
||||
updateFaceRecognition,
|
||||
updateRecordDescription,
|
||||
ocr,
|
||||
}}
|
||||
|
@@ -30,13 +30,14 @@ const OPERATION = {
|
||||
RENAME_FILE: 'rename-file',
|
||||
FILE_DETAIL: 'file-detail',
|
||||
FILE_DETAILS: 'file-details',
|
||||
FACE_RECOGNITION: 'face-recognition',
|
||||
MOVE: 'move',
|
||||
};
|
||||
|
||||
const ContextMenu = ({
|
||||
isGroupView, selectedRange, selectedPosition, recordMetrics, recordGetterByIndex, onClearSelected, onCopySelected,
|
||||
getTableContentRect, getTableCanvasContainerRect, deleteRecords, selectNone, updateFileTags, moveRecord, addFolder, updateRecordDetails,
|
||||
updateRecordDescription, ocr,
|
||||
updateFaceRecognition, updateRecordDescription, ocr,
|
||||
}) => {
|
||||
const currentRecord = useRef(null);
|
||||
|
||||
@@ -119,6 +120,13 @@ const ContextMenu = ({
|
||||
if (imageOrVideoRecords.length > 0) {
|
||||
list.push({ value: OPERATION.FILE_DETAILS, label: gettext('Extract file details'), records: imageOrVideoRecords });
|
||||
}
|
||||
const imageRecords = records.filter(record => {
|
||||
const fileName = getFileNameFromRecord(record);
|
||||
return Utils.imageCheck(fileName);
|
||||
});
|
||||
if (imageRecords.length > 0) {
|
||||
list.push({ value: OPERATION.FACE_RECOGNITION, label: gettext('Face recognition'), records: imageRecords });
|
||||
}
|
||||
return list;
|
||||
}
|
||||
|
||||
@@ -148,6 +156,17 @@ const ContextMenu = ({
|
||||
if (imageOrVideoRecords.length > 0) {
|
||||
list.push({ value: OPERATION.FILE_DETAILS, label: gettext('Extract file details'), records: imageOrVideoRecords });
|
||||
}
|
||||
const imageRecords = records.filter(record => {
|
||||
const isFolder = checkIsDir(record);
|
||||
if (isFolder) return false;
|
||||
const canModifyRow = checkCanModifyRow(record);
|
||||
if (!canModifyRow) return false;
|
||||
const fileName = getFileNameFromRecord(record);
|
||||
return Utils.imageCheck(fileName);
|
||||
});
|
||||
if (imageRecords.length > 0) {
|
||||
list.push({ value: OPERATION.FACE_RECOGNITION, label: gettext('Face recognition'), records: imageRecords });
|
||||
}
|
||||
return list;
|
||||
}
|
||||
|
||||
@@ -193,6 +212,9 @@ const ContextMenu = ({
|
||||
if (isImage || isVideo) {
|
||||
aiOptions.push({ value: OPERATION.FILE_DETAIL, label: gettext('Extract file detail'), record: record });
|
||||
}
|
||||
if (isImage) {
|
||||
aiOptions.push({ value: OPERATION.FACE_RECOGNITION, label: gettext('Face recognition'), records: [record] });
|
||||
}
|
||||
|
||||
if (descriptionColumn && isDescribableFile) {
|
||||
aiOptions.push({
|
||||
@@ -305,6 +327,11 @@ const ContextMenu = ({
|
||||
updateRecordDetails([record]);
|
||||
break;
|
||||
}
|
||||
case OPERATION.FACE_RECOGNITION: {
|
||||
const { records } = option;
|
||||
updateFaceRecognition(records);
|
||||
break;
|
||||
}
|
||||
case OPERATION.MOVE: {
|
||||
const { record } = option;
|
||||
if (!record) break;
|
||||
@@ -315,7 +342,7 @@ const ContextMenu = ({
|
||||
break;
|
||||
}
|
||||
}
|
||||
}, [repoID, onCopySelected, onClearSelected, updateRecordDescription, ocr, deleteRecords, toggleDeleteFolderDialog, selectNone, updateRecordDetails, toggleFileTagsRecord, toggleMoveDialog]);
|
||||
}, [repoID, onCopySelected, onClearSelected, updateRecordDescription, toggleFileTagsRecord, ocr, deleteRecords, toggleDeleteFolderDialog, selectNone, updateRecordDetails, updateFaceRecognition, toggleMoveDialog]);
|
||||
|
||||
useEffect(() => {
|
||||
const unsubscribeToggleMoveDialog = window.sfMetadataContext.eventBus.subscribe(EVENT_BUS_TYPE.TOGGLE_MOVE_DIALOG, toggleMoveDialog);
|
||||
|
@@ -30,6 +30,7 @@ const Table = () => {
|
||||
addFolder,
|
||||
updateSelectedRecordIds,
|
||||
updateRecordDetails,
|
||||
updateFaceRecognition,
|
||||
updateRecordDescription,
|
||||
ocr,
|
||||
} = useMetadataView();
|
||||
@@ -182,6 +183,7 @@ const Table = () => {
|
||||
addFolder={addFolder}
|
||||
updateSelectedRecordIds={updateSelectedRecordIds}
|
||||
updateRecordDetails={updateRecordDetails}
|
||||
updateFaceRecognition={updateFaceRecognition}
|
||||
updateRecordDescription={updateRecordDescription}
|
||||
ocr={ocr}
|
||||
/>
|
||||
|
@@ -646,6 +646,7 @@ class Records extends Component {
|
||||
addFolder={this.props.addFolder}
|
||||
selectNone={this.selectNone}
|
||||
updateRecordDetails={this.props.updateRecordDetails}
|
||||
updateFaceRecognition={this.props.updateFaceRecognition}
|
||||
updateRecordDescription={this.props.updateRecordDescription}
|
||||
ocr={this.props.ocr}
|
||||
/>
|
||||
|
Reference in New Issue
Block a user