1
0
mirror of https://github.com/haiwen/seahub.git synced 2025-09-23 20:37:42 +00:00

feat: file details ai (#7251)

Co-authored-by: 杨国璇 <ygx@Hello-word.local>
This commit is contained in:
杨国璇
2024-12-25 13:53:26 +08:00
committed by GitHub
parent b139c235f7
commit 9b8b7c9324
17 changed files with 432 additions and 179 deletions

View File

@@ -0,0 +1,109 @@
import React, { useContext, useCallback, useMemo } from 'react';
import metadataAPI from '../metadata/api';
import { Utils } from '../utils/utils';
import toaster from '../components/toast';
import { PRIVATE_COLUMN_KEY, EVENT_BUS_TYPE } from '../metadata/constants';
import { gettext, lang } from '../utils/constants';
// This hook provides content related to metadata ai operation
const MetadataAIOperationsContext = React.createContext(null);
export const MetadataAIOperationsProvider = ({
repoID,
enableMetadata = false,
enableOCR = false,
enableTags = false,
tagsLang,
repoInfo,
children
}) => {
const permission = useMemo(() => repoInfo.permission !== 'admin' && repoInfo.permission !== 'rw' ? 'r' : 'rw', [repoInfo]);
const canModify = useMemo(() => permission === 'rw', [permission]);
const OCRSuccessCallBack = useCallback(({ parentDir, fileName, ocrResult } = {}) => {
toaster.success(gettext('Successfully OCR'));
if (!ocrResult) return;
const update = { [PRIVATE_COLUMN_KEY.OCR]: ocrResult };
metadataAPI.modifyRecord(repoID, { parentDir, fileName }, update).then(res => {
const eventBus = window?.sfMetadataContext?.eventBus;
eventBus && eventBus.dispatch(EVENT_BUS_TYPE.LOCAL_RECORD_CHANGED, { parentDir, fileName }, update);
});
}, [repoID]);
const onOCR = useCallback(({ parentDir, fileName }, { success_callback, fail_callback } = {}) => {
const filePath = Utils.joinPath(parentDir, fileName);
metadataAPI.ocr(repoID, filePath).then(res => {
const ocrResult = res.data.ocr_result;
const validResult = Array.isArray(ocrResult) && ocrResult.length > 0 ? JSON.stringify(ocrResult) : null;
success_callback && success_callback({ parentDir, fileName, ocrResult: validResult });
}).catch(error => {
const errorMessage = gettext('OCR failed');
toaster.danger(errorMessage);
fail_callback && fail_callback();
});
}, [repoID]);
const generateDescription = useCallback(({ parentDir, fileName }, { success_callback, fail_callback } = {}) => {
const filePath = Utils.joinPath(parentDir, fileName);
const isImage = Utils.imageCheck(fileName);
let APIName = '';
if (Utils.isDescriptionSupportedFile(fileName)) {
APIName = isImage ? 'imageCaption' : 'generateDescription';
}
if (!APIName) return;
metadataAPI[APIName](repoID, filePath, lang).then(res => {
const description = res?.data?.summary || res.data.desc || '';
success_callback && success_callback({ parentDir, fileName, description });
}).catch(error => {
const errorMessage = isImage ? gettext('Failed to generate image description') : gettext('Failed to generate description');
toaster.danger(errorMessage);
fail_callback && fail_callback();
});
}, [repoID]);
const extractFilesDetails = useCallback((objIds, { success_callback, fail_callback } = {}) => {
metadataAPI.extractFileDetails(repoID, objIds).then(res => {
const details = res?.data?.details || [];
success_callback && success_callback({ details });
}).catch(error => {
const errorMessage = gettext('Failed to extract file details');
toaster.danger(errorMessage);
fail_callback && fail_callback();
});
}, [repoID]);
const extractFileDetails = useCallback((objId, { success_callback, fail_callback } = {}) => {
extractFilesDetails([objId], {
success_callback: ({ details }) => {
success_callback && success_callback({ detail: details[0] });
},
fail_callback
});
}, [extractFilesDetails]);
return (
<MetadataAIOperationsContext.Provider value={{
enableMetadata,
enableOCR,
enableTags,
tagsLang,
canModify,
onOCR,
OCRSuccessCallBack,
generateDescription,
extractFilesDetails,
extractFileDetails,
}}>
{children}
</MetadataAIOperationsContext.Provider>
);
};
export const useMetadataAIOperations = () => {
const context = useContext(MetadataAIOperationsContext);
if (!context) {
throw new Error('\'MetadataAIOperationsContext\' is null');
}
return context;
};

View File

@@ -1,54 +0,0 @@
import React, { useContext, useCallback, useMemo } from 'react';
import metadataAPI from '../metadata/api';
import { Utils } from '../utils/utils';
import toaster from '../components/toast';
import { PRIVATE_COLUMN_KEY, EVENT_BUS_TYPE } from '../metadata/constants';
import { gettext } from '../utils/constants';
// This hook provides content related to metadata record operation
const MetadataOperationsContext = React.createContext(null);
export const MetadataOperationsProvider = ({ repoID, enableMetadata, enableOCR, repoInfo, children }) => {
const permission = useMemo(() => repoInfo.permission !== 'admin' && repoInfo.permission !== 'rw' ? 'r' : 'rw', [repoInfo]);
const canModify = useMemo(() => permission === 'rw', [permission]);
const onOCR = useCallback((parentDir, fileName) => {
const filePath = Utils.joinPath(parentDir, fileName);
metadataAPI.ocr(repoID, filePath).then(res => {
const ocrResult = res.data.ocr_result;
const validResult = Array.isArray(ocrResult) && ocrResult.length > 0 ? JSON.stringify(ocrResult) : null;
toaster.success(gettext('Successfully OCR'));
if (validResult) {
const update = { [PRIVATE_COLUMN_KEY.OCR]: validResult };
metadataAPI.modifyRecord(repoID, { parentDir, fileName }, update).then(res => {
const eventBus = window?.sfMetadataContext?.eventBus;
if (eventBus) {
eventBus.dispatch(EVENT_BUS_TYPE.LOCAL_RECORD_CHANGED, { parentDir, fileName }, update);
}
});
}
}).catch(error => {
const errorMessage = Utils.getErrorMsg(error);
toaster.danger(errorMessage);
});
}, [repoID]);
let value = {};
if (canModify && enableMetadata && enableOCR) {
value['onOCR'] = onOCR;
}
return (
<MetadataOperationsContext.Provider value={value}>
{children}
</MetadataOperationsContext.Provider>
);
};
export const useMetadataOperations = () => {
const context = useContext(MetadataOperationsContext);
if (!context) {
throw new Error('\'MetadataOperationsContext\' is null');
}
return context;
};

View File

@@ -2,7 +2,7 @@ import React, { useContext, useEffect, useCallback, useState, useMemo } from 're
import metadataAPI from '../metadata/api';
import { Utils } from '../utils/utils';
import toaster from '../components/toast';
import { MetadataOperationsProvider } from './metadata-operation';
import { MetadataAIOperationsProvider } from './metadata-ai-operation';
// This hook provides content related to seahub interaction, such as whether to enable extended attributes
const MetadataStatusContext = React.createContext(null);
@@ -119,14 +119,16 @@ export const MetadataStatusProvider = ({ repoID, currentRepoInfo, hideMetadataVi
}}
>
{!isLoading && (
<MetadataOperationsProvider
<MetadataAIOperationsProvider
repoID={repoID}
enableMetadata={enableMetadata}
enableOCR={enableOCR}
enableTags={enableTags}
tagsLang={tagsLang}
repoInfo={currentRepoInfo}
>
{children}
</MetadataOperationsProvider>
</MetadataAIOperationsProvider>
)}
</MetadataStatusContext.Provider>
);