mirror of
https://github.com/haiwen/seahub.git
synced 2025-09-09 02:42:47 +00:00
feat: init sdoc summary when add summary column (#6449)
* feat: init sdoc summary when add summary column * feat/meta: add summary single sdoc * optimize some naming * add summarize files api * optimize code * feat: update code * feat: optimzie code * feat: rebase code * fix/mv: fix invalid path param when create summary * feat/mv: add batch update summary text func * feat/mv: add some details in parameter judgment * feat: optimize code * feat: delete useless import * execute return api * feat/summary: execute file not found situation * fix: summary --------- Co-authored-by: 杨国璇 <ygx@Hello-word.local>
This commit is contained in:
@@ -186,6 +186,15 @@ class MetadataManagerAPI {
|
|||||||
};
|
};
|
||||||
return this.req.put(url, params);
|
return this.req.put(url, params);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
// ai
|
||||||
|
generateSummary = (repoID, filePaths) => {
|
||||||
|
const url = this.server + '/api/v2.1/repos/' + repoID + '/metadata/ai/summarize-documents/';
|
||||||
|
const params = {
|
||||||
|
file_paths_list: filePaths,
|
||||||
|
};
|
||||||
|
return this.req.post(url, params);
|
||||||
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
const metadataAPI = new MetadataManagerAPI();
|
const metadataAPI = new MetadataManagerAPI();
|
||||||
|
@@ -8,7 +8,7 @@ import { CellType, isFunction, Z_INDEX, getCellValueByColumn, getColumnOptionNam
|
|||||||
import { isCellValueChanged } from '../../../utils/cell-comparer';
|
import { isCellValueChanged } from '../../../utils/cell-comparer';
|
||||||
import { EVENT_BUS_TYPE } from '../../../constants';
|
import { EVENT_BUS_TYPE } from '../../../constants';
|
||||||
import Editor from '../editor';
|
import Editor from '../editor';
|
||||||
import { canEditCell } from '../../../utils/column-utils';
|
import { canEditCell, getColumnOriginName } from '../../../utils/column-utils';
|
||||||
|
|
||||||
const NOT_SUPPORT_EDITOR_COLUMN_TYPES = [
|
const NOT_SUPPORT_EDITOR_COLUMN_TYPES = [
|
||||||
CellType.CTIME, CellType.MTIME, CellType.CREATOR, CellType.LAST_MODIFIER, CellType.FILE_NAME
|
CellType.CTIME, CellType.MTIME, CellType.CREATOR, CellType.LAST_MODIFIER, CellType.FILE_NAME
|
||||||
@@ -124,7 +124,8 @@ class PopupEditorContainer extends React.Component {
|
|||||||
|
|
||||||
getOldRowData = (originalOldCellValue) => {
|
getOldRowData = (originalOldCellValue) => {
|
||||||
const { column } = this.props;
|
const { column } = this.props;
|
||||||
const { key: columnKey, name: columnName, type: columnType } = column;
|
const columnName = getColumnOriginName(column);
|
||||||
|
const { key: columnKey, type: columnType } = column;
|
||||||
let oldValue = originalOldCellValue;
|
let oldValue = originalOldCellValue;
|
||||||
if (this.getEditor().getOldValue) {
|
if (this.getEditor().getOldValue) {
|
||||||
const original = this.getEditor().getOldValue();
|
const original = this.getEditor().getOldValue();
|
||||||
@@ -133,7 +134,7 @@ class PopupEditorContainer extends React.Component {
|
|||||||
if (columnType === CellType.LONG_TEXT) {
|
if (columnType === CellType.LONG_TEXT) {
|
||||||
oldValue = this.getEditor().getValue(); // long-text cell value need format to {text: '', links: [], ...}
|
oldValue = this.getEditor().getValue(); // long-text cell value need format to {text: '', links: [], ...}
|
||||||
}
|
}
|
||||||
const oldRowData = PRIVATE_COLUMN_KEYS.includes(columnKey) ? { [columnName]: oldValue } : { [columnName]: oldValue } ;
|
const oldRowData = { [columnName]: oldValue };
|
||||||
const originalOldRowData = { [columnKey]: originalOldCellValue }; // { [column.key]: cellValue }
|
const originalOldRowData = { [columnKey]: originalOldCellValue }; // { [column.key]: cellValue }
|
||||||
return { oldRowData, originalOldRowData };
|
return { oldRowData, originalOldRowData };
|
||||||
};
|
};
|
||||||
|
@@ -1,9 +1,11 @@
|
|||||||
import React, { useState, useRef, useEffect, useCallback, useMemo } from 'react';
|
import React, { useState, useRef, useEffect, useCallback, useMemo } from 'react';
|
||||||
import PropTypes from 'prop-types';
|
import PropTypes from 'prop-types';
|
||||||
import { PRIVATE_COLUMN_KEY } from '../../_basic';
|
import { getColumnByKey, PRIVATE_COLUMN_KEY } from '../../_basic';
|
||||||
import { gettext } from '../../utils';
|
import { gettext } from '../../utils';
|
||||||
import { siteRoot } from '../../../../utils/constants';
|
import { siteRoot } from '../../../../utils/constants';
|
||||||
import { Utils } from '../../../../utils/utils';
|
import { Utils } from '../../../../utils/utils';
|
||||||
|
import { useMetadata } from '../../hooks';
|
||||||
|
import toaster from '../../../../components/toast';
|
||||||
|
|
||||||
import './index.css';
|
import './index.css';
|
||||||
|
|
||||||
@@ -12,6 +14,7 @@ const OPERATION = {
|
|||||||
COPY_SELECTED: 'copy-selected',
|
COPY_SELECTED: 'copy-selected',
|
||||||
OPEN_PARENT_FOLDER: 'open-parent-folder',
|
OPEN_PARENT_FOLDER: 'open-parent-folder',
|
||||||
OPEN_IN_NEW_TAB: 'open-new-tab',
|
OPEN_IN_NEW_TAB: 'open-new-tab',
|
||||||
|
GENERATE_SUMMARY: 'generate-summary',
|
||||||
};
|
};
|
||||||
|
|
||||||
const ContextMenu = ({
|
const ContextMenu = ({
|
||||||
@@ -22,23 +25,55 @@ const ContextMenu = ({
|
|||||||
recordGetterByIndex,
|
recordGetterByIndex,
|
||||||
onClearSelected,
|
onClearSelected,
|
||||||
onCopySelected,
|
onCopySelected,
|
||||||
|
updateRecords,
|
||||||
}) => {
|
}) => {
|
||||||
const menuRef = useRef(null);
|
const menuRef = useRef(null);
|
||||||
const [visible, setVisible] = useState(false);
|
const [visible, setVisible] = useState(false);
|
||||||
const [position, setPosition] = useState({ top: 0, left: 0 });
|
const [position, setPosition] = useState({ top: 0, left: 0 });
|
||||||
|
const { metadata } = useMetadata();
|
||||||
|
|
||||||
const options = useMemo(() => {
|
const options = useMemo(() => {
|
||||||
|
if (!visible) return [];
|
||||||
const permission = window.sfMetadataContext.getPermission();
|
const permission = window.sfMetadataContext.getPermission();
|
||||||
const isReadonly = permission === 'r';
|
const isReadonly = permission === 'r';
|
||||||
|
const { columns } = metadata;
|
||||||
|
const summaryColumn = getColumnByKey(columns, PRIVATE_COLUMN_KEY.FILE_SUMMARY);
|
||||||
|
const canModifyRow = window.sfMetadataContext.canModifyRow;
|
||||||
let list = [];
|
let list = [];
|
||||||
|
|
||||||
if (selectedRange) {
|
if (selectedRange) {
|
||||||
!isReadonly && list.push({ value: OPERATION.CLEAR_SELECTED, label: gettext('Clear selected') });
|
!isReadonly && list.push({ value: OPERATION.CLEAR_SELECTED, label: gettext('Clear selected') });
|
||||||
list.push({ value: OPERATION.COPY_SELECTED, label: gettext('Copy selected') });
|
list.push({ value: OPERATION.COPY_SELECTED, label: gettext('Copy selected') });
|
||||||
|
|
||||||
|
if (summaryColumn) {
|
||||||
|
const { topLeft, bottomRight } = selectedRange;
|
||||||
|
for (let i = topLeft.rowIdx; i <= bottomRight.rowIdx; i++) {
|
||||||
|
const record = recordGetterByIndex({ isGroupView, groupRecordIndex: topLeft.groupRecordIndex, recordIndex: i });
|
||||||
|
const fileName = record[PRIVATE_COLUMN_KEY.FILE_NAME];
|
||||||
|
if (Utils.isSdocFile(fileName) && canModifyRow(record)) {
|
||||||
|
list.push({ value: OPERATION.GENERATE_SUMMARY, label: gettext('Generate summary') });
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
return list;
|
return list;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (Object.keys(recordMetrics.idSelectedRecordMap).length > 1) {
|
const selectedRecords = Object.keys(recordMetrics.idSelectedRecordMap);
|
||||||
|
if (selectedRecords.length > 1) {
|
||||||
|
if (summaryColumn) {
|
||||||
|
const isIncludeSdocRecord = selectedRecords.filter(id => {
|
||||||
|
const record = metadata.id_row_map[id];
|
||||||
|
if (record) {
|
||||||
|
const fileName = record[PRIVATE_COLUMN_KEY.FILE_NAME];
|
||||||
|
return Utils.isSdocFile(fileName) && canModifyRow(record);
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
});
|
||||||
|
if (isIncludeSdocRecord.length > 0) {
|
||||||
|
list.push({ value: OPERATION.GENERATE_SUMMARY, label: gettext('Generate summary') });
|
||||||
|
}
|
||||||
|
}
|
||||||
return list;
|
return list;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -49,9 +84,15 @@ const ContextMenu = ({
|
|||||||
const isFolder = record[PRIVATE_COLUMN_KEY.IS_DIR];
|
const isFolder = record[PRIVATE_COLUMN_KEY.IS_DIR];
|
||||||
list.push({ value: OPERATION.OPEN_IN_NEW_TAB, label: isFolder ? gettext('Open folder in new tab') : gettext('Open file in new tab') });
|
list.push({ value: OPERATION.OPEN_IN_NEW_TAB, label: isFolder ? gettext('Open folder in new tab') : gettext('Open file in new tab') });
|
||||||
list.push({ value: OPERATION.OPEN_PARENT_FOLDER, label: gettext('Open parent folder') });
|
list.push({ value: OPERATION.OPEN_PARENT_FOLDER, label: gettext('Open parent folder') });
|
||||||
|
if (summaryColumn) {
|
||||||
|
const fileName = record[PRIVATE_COLUMN_KEY.FILE_NAME];
|
||||||
|
if (Utils.isSdocFile(fileName) && canModifyRow(record)) {
|
||||||
|
list.push({ value: OPERATION.GENERATE_SUMMARY, label: gettext('Generate summary') });
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
return list;
|
return list;
|
||||||
}, [isGroupView, selectedPosition, recordMetrics, selectedRange, recordGetterByIndex]);
|
}, [visible, isGroupView, selectedPosition, recordMetrics, selectedRange, metadata, recordGetterByIndex]);
|
||||||
|
|
||||||
const handleHide = useCallback((event) => {
|
const handleHide = useCallback((event) => {
|
||||||
if (menuRef.current && !menuRef.current.contains(event.target)) {
|
if (menuRef.current && !menuRef.current.contains(event.target)) {
|
||||||
@@ -89,6 +130,66 @@ const ContextMenu = ({
|
|||||||
window.open(url, '_blank');
|
window.open(url, '_blank');
|
||||||
}, [isGroupView, recordGetterByIndex, selectedPosition]);
|
}, [isGroupView, recordGetterByIndex, selectedPosition]);
|
||||||
|
|
||||||
|
const generateSummary = useCallback(() => {
|
||||||
|
const canModifyRow = window.sfMetadataContext.canModifyRow;
|
||||||
|
const selectedRecords = Object.keys(recordMetrics.idSelectedRecordMap);
|
||||||
|
const summaryColumnKey = PRIVATE_COLUMN_KEY.FILE_SUMMARY;
|
||||||
|
let paths = [];
|
||||||
|
let idOldRecordData = {};
|
||||||
|
let idOriginalOldRecordData = {};
|
||||||
|
if (selectedRange) {
|
||||||
|
const { topLeft, bottomRight } = selectedRange;
|
||||||
|
for (let i = topLeft.rowIdx; i <= bottomRight.rowIdx; i++) {
|
||||||
|
const record = recordGetterByIndex({ isGroupView, groupRecordIndex: topLeft.groupRecordIndex, recordIndex: i });
|
||||||
|
if (!canModifyRow(record)) continue;
|
||||||
|
const fileName = record[PRIVATE_COLUMN_KEY.FILE_NAME];
|
||||||
|
if (!Utils.isSdocFile(fileName)) continue;
|
||||||
|
const parentDir = record[PRIVATE_COLUMN_KEY.PARENT_DIR];
|
||||||
|
paths.push(Utils.joinPath(parentDir, fileName));
|
||||||
|
idOldRecordData[record[PRIVATE_COLUMN_KEY.ID]] = { [summaryColumnKey]: record[summaryColumnKey] };
|
||||||
|
idOriginalOldRecordData[record[PRIVATE_COLUMN_KEY.ID]] = { [summaryColumnKey]: record[summaryColumnKey] };
|
||||||
|
}
|
||||||
|
} else if (selectedRecords.length > 0) {
|
||||||
|
selectedRecords.forEach(recordId => {
|
||||||
|
const record = metadata.id_row_map[recordId];
|
||||||
|
const fileName = record[PRIVATE_COLUMN_KEY.FILE_NAME];
|
||||||
|
if (Utils.isSdocFile(fileName) && canModifyRow(record)) {
|
||||||
|
const parentDir = record[PRIVATE_COLUMN_KEY.PARENT_DIR];
|
||||||
|
paths.push(Utils.joinPath(parentDir, fileName));
|
||||||
|
idOldRecordData[record[PRIVATE_COLUMN_KEY.ID]] = { [summaryColumnKey]: record[summaryColumnKey] };
|
||||||
|
idOriginalOldRecordData[record[PRIVATE_COLUMN_KEY.ID]] = { [summaryColumnKey]: record[summaryColumnKey] };
|
||||||
|
}
|
||||||
|
});
|
||||||
|
} else if (selectedPosition) {
|
||||||
|
const { groupRecordIndex, rowIdx } = selectedPosition;
|
||||||
|
const record = recordGetterByIndex({ isGroupView, groupRecordIndex, recordIndex: rowIdx });
|
||||||
|
const fileName = record[PRIVATE_COLUMN_KEY.FILE_NAME];
|
||||||
|
if (Utils.isSdocFile(fileName) && canModifyRow(record)) {
|
||||||
|
const parentDir = record[PRIVATE_COLUMN_KEY.PARENT_DIR];
|
||||||
|
paths.push(Utils.joinPath(parentDir, fileName));
|
||||||
|
idOldRecordData[record[PRIVATE_COLUMN_KEY.ID]] = { [summaryColumnKey]: record[summaryColumnKey] };
|
||||||
|
idOriginalOldRecordData[record[PRIVATE_COLUMN_KEY.ID]] = { [summaryColumnKey]: record[summaryColumnKey] };
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (paths.length === 0) return;
|
||||||
|
window.sfMetadataContext.generateSummary(paths).then(res => {
|
||||||
|
const updatedRecords = res.data.rows;
|
||||||
|
let recordIds = [];
|
||||||
|
let idRecordUpdates = {};
|
||||||
|
let idOriginalRecordUpdates = {};
|
||||||
|
updatedRecords.forEach(updatedRecord => {
|
||||||
|
const { _id: updateRecordId, _summary } = updatedRecord;
|
||||||
|
recordIds.push(updateRecordId);
|
||||||
|
idRecordUpdates[updateRecordId] = { [summaryColumnKey]: _summary };
|
||||||
|
idOriginalRecordUpdates[updateRecordId] = { [summaryColumnKey]: _summary };
|
||||||
|
});
|
||||||
|
updateRecords({ recordIds, idRecordUpdates, idOriginalRecordUpdates, idOldRecordData, idOriginalOldRecordData });
|
||||||
|
}).catch(error => {
|
||||||
|
const errorMessage = gettext('Failed to generate summary');
|
||||||
|
toaster.danger(errorMessage);
|
||||||
|
});
|
||||||
|
}, [isGroupView, selectedRange, selectedPosition, recordMetrics, metadata, recordGetterByIndex, updateRecords]);
|
||||||
|
|
||||||
const handleOptionClick = useCallback((event, option) => {
|
const handleOptionClick = useCallback((event, option) => {
|
||||||
event.stopPropagation();
|
event.stopPropagation();
|
||||||
switch (option.value) {
|
switch (option.value) {
|
||||||
@@ -108,12 +209,16 @@ const ContextMenu = ({
|
|||||||
onClearSelected && onClearSelected();
|
onClearSelected && onClearSelected();
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
case OPERATION.GENERATE_SUMMARY: {
|
||||||
|
generateSummary && generateSummary();
|
||||||
|
break;
|
||||||
|
}
|
||||||
default: {
|
default: {
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
setVisible(false);
|
setVisible(false);
|
||||||
}, [onOpenFileInNewTab, onOpenParentFolder, onCopySelected, onClearSelected]);
|
}, [onOpenFileInNewTab, onOpenParentFolder, onCopySelected, onClearSelected, generateSummary]);
|
||||||
|
|
||||||
const getMenuPosition = (x = 0, y = 0) => {
|
const getMenuPosition = (x = 0, y = 0) => {
|
||||||
let menuStyles = {
|
let menuStyles = {
|
||||||
|
@@ -610,14 +610,14 @@ class Records extends Component {
|
|||||||
};
|
};
|
||||||
|
|
||||||
renderRecordsBody = ({ containerWidth }) => {
|
renderRecordsBody = ({ containerWidth }) => {
|
||||||
const { isGroupView, recordGetterByIndex } = this.props;
|
const { isGroupView, recordGetterByIndex, updateRecords } = this.props;
|
||||||
const { recordMetrics, columnMetrics, colOverScanStartIdx, colOverScanEndIdx } = this.state;
|
const { recordMetrics, columnMetrics, colOverScanStartIdx, colOverScanEndIdx } = this.state;
|
||||||
const { columns, allColumns, totalWidth, lastFrozenColumnKey, frozenColumnsWidth } = columnMetrics;
|
const { columns, allColumns, totalWidth, lastFrozenColumnKey, frozenColumnsWidth } = columnMetrics;
|
||||||
const commonProps = {
|
const commonProps = {
|
||||||
...this.props,
|
...this.props,
|
||||||
columns, allColumns, totalWidth, lastFrozenColumnKey, frozenColumnsWidth,
|
columns, allColumns, totalWidth, lastFrozenColumnKey, frozenColumnsWidth,
|
||||||
recordMetrics, colOverScanStartIdx, colOverScanEndIdx,
|
recordMetrics, colOverScanStartIdx, colOverScanEndIdx,
|
||||||
contextMenu: (<ContextMenu isGroupView={isGroupView} recordGetterByIndex={recordGetterByIndex} />),
|
contextMenu: (<ContextMenu isGroupView={isGroupView} recordGetterByIndex={recordGetterByIndex} updateRecords={updateRecords} />),
|
||||||
hasSelectedRecord: this.hasSelectedRecord(),
|
hasSelectedRecord: this.hasSelectedRecord(),
|
||||||
getScrollLeft: this.getScrollLeft,
|
getScrollLeft: this.getScrollLeft,
|
||||||
getScrollTop: this.getScrollTop,
|
getScrollTop: this.getScrollTop,
|
||||||
|
@@ -73,6 +73,11 @@ class Context {
|
|||||||
return this.metadataAPI.getMetadata(repoID, params);
|
return this.metadataAPI.getMetadata(repoID, params);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
getRecord = (parentDir, fileName) => {
|
||||||
|
const repoID = this.settings['repoID'];
|
||||||
|
return this.metadataAPI.getMetadataRecordInfo(repoID, parentDir, fileName);
|
||||||
|
};
|
||||||
|
|
||||||
getViews = () => {
|
getViews = () => {
|
||||||
const repoID = this.settings['repoID'];
|
const repoID = this.settings['repoID'];
|
||||||
return this.metadataAPI.listViews(repoID);
|
return this.metadataAPI.listViews(repoID);
|
||||||
@@ -186,6 +191,11 @@ class Context {
|
|||||||
// todo
|
// todo
|
||||||
};
|
};
|
||||||
|
|
||||||
|
// ai
|
||||||
|
generateSummary = (filePaths) => {
|
||||||
|
const repoID = this.settings['repoID'];
|
||||||
|
return this.metadataAPI.generateSummary(repoID, filePaths);
|
||||||
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
export default Context;
|
export default Context;
|
||||||
|
@@ -11,11 +11,13 @@ from seahub.api2.throttling import UserRateThrottle
|
|||||||
from seahub.api2.authentication import TokenAuthentication
|
from seahub.api2.authentication import TokenAuthentication
|
||||||
from seahub.repo_metadata.models import RepoMetadata, RepoMetadataViews
|
from seahub.repo_metadata.models import RepoMetadata, RepoMetadataViews
|
||||||
from seahub.views import check_folder_permission
|
from seahub.views import check_folder_permission
|
||||||
from seahub.repo_metadata.utils import add_init_metadata_task, gen_unique_id, init_metadata, get_sys_columns
|
from seahub.repo_metadata.utils import add_init_metadata_task, gen_unique_id, init_metadata, \
|
||||||
|
get_sys_columns, update_docs_summary
|
||||||
from seahub.repo_metadata.metadata_server_api import MetadataServerAPI, list_metadata_view_records
|
from seahub.repo_metadata.metadata_server_api import MetadataServerAPI, list_metadata_view_records
|
||||||
from seahub.utils.timeutils import datetime_to_isoformat_timestr
|
from seahub.utils.timeutils import datetime_to_isoformat_timestr
|
||||||
from seahub.utils.repo import is_repo_admin
|
from seahub.utils.repo import is_repo_admin
|
||||||
|
from seahub.ai.utils import get_file_download_token
|
||||||
|
from pysearpc import SearpcError
|
||||||
from seaserv import seafile_api
|
from seaserv import seafile_api
|
||||||
|
|
||||||
|
|
||||||
@@ -781,3 +783,62 @@ class MetadataViewsMoveView(APIView):
|
|||||||
return api_error(status.HTTP_500_INTERNAL_SERVER_ERROR, error_msg)
|
return api_error(status.HTTP_500_INTERNAL_SERVER_ERROR, error_msg)
|
||||||
|
|
||||||
return Response({'navigation': results['navigation']})
|
return Response({'navigation': results['navigation']})
|
||||||
|
|
||||||
|
|
||||||
|
class MetadataSummarizeDocs(APIView):
|
||||||
|
authentication_classes = (TokenAuthentication, SessionAuthentication)
|
||||||
|
permission_classes = (IsAuthenticated,)
|
||||||
|
throttle_classes = (UserRateThrottle,)
|
||||||
|
|
||||||
|
def post(self, request, repo_id):
|
||||||
|
file_paths_list = request.data.get('file_paths_list', '')
|
||||||
|
|
||||||
|
if not file_paths_list or not isinstance(file_paths_list, list):
|
||||||
|
error_msg = 'file_paths_list should be a non-empty list..'
|
||||||
|
return api_error(status.HTTP_400_BAD_REQUEST, error_msg)
|
||||||
|
|
||||||
|
record = RepoMetadata.objects.filter(repo_id=repo_id).first()
|
||||||
|
if not record or not record.enabled:
|
||||||
|
error_msg = f'The metadata module is disabled for repo {repo_id}.'
|
||||||
|
return api_error(status.HTTP_404_NOT_FOUND, error_msg)
|
||||||
|
|
||||||
|
repo = seafile_api.get_repo(repo_id)
|
||||||
|
if not repo:
|
||||||
|
error_msg = 'Library %s not found.' % repo_id
|
||||||
|
return api_error(status.HTTP_404_NOT_FOUND, error_msg)
|
||||||
|
|
||||||
|
permission = check_folder_permission(request, repo_id, '/')
|
||||||
|
if permission != 'rw':
|
||||||
|
error_msg = 'Permission denied.'
|
||||||
|
return api_error(status.HTTP_403_FORBIDDEN, error_msg)
|
||||||
|
|
||||||
|
files_info_list = []
|
||||||
|
for file_path in file_paths_list:
|
||||||
|
try:
|
||||||
|
file_id = seafile_api.get_file_id_by_path(repo_id, file_path)
|
||||||
|
except SearpcError as e:
|
||||||
|
logger.error(e)
|
||||||
|
return api_error(
|
||||||
|
status.HTTP_500_INTERNAL_SERVER_ERROR, 'Internal Server Error'
|
||||||
|
)
|
||||||
|
if not file_id:
|
||||||
|
return api_error(
|
||||||
|
status.HTTP_404_NOT_FOUND, f"File {file_path} not found"
|
||||||
|
)
|
||||||
|
|
||||||
|
if token := get_file_download_token(repo_id, file_id, request.user.username):
|
||||||
|
files_info_list.append(
|
||||||
|
{'file_path': file_path, 'download_token': token}
|
||||||
|
)
|
||||||
|
else:
|
||||||
|
error_msg = 'Internal Server Error'
|
||||||
|
return api_error(status.HTTP_500_INTERNAL_SERVER_ERROR, error_msg)
|
||||||
|
|
||||||
|
try:
|
||||||
|
resp = update_docs_summary(repo_id, files_info_list)
|
||||||
|
resp_json = resp.json()
|
||||||
|
except Exception as e:
|
||||||
|
error_msg = 'Internal Server Error'
|
||||||
|
return api_error(status.HTTP_500_INTERNAL_SERVER_ERROR, error_msg)
|
||||||
|
|
||||||
|
return Response(resp_json, resp.status_code)
|
||||||
|
@@ -5,7 +5,7 @@ import json
|
|||||||
import random
|
import random
|
||||||
from urllib.parse import urljoin
|
from urllib.parse import urljoin
|
||||||
|
|
||||||
from seahub.settings import SECRET_KEY, SEAFEVENTS_SERVER_URL
|
from seahub.settings import SECRET_KEY, SEAFEVENTS_SERVER_URL, SEAFILE_AI_SECRET_KEY, SEAFILE_AI_SERVER_URL
|
||||||
|
|
||||||
|
|
||||||
def add_init_metadata_task(params):
|
def add_init_metadata_task(params):
|
||||||
@@ -63,3 +63,16 @@ def init_metadata(metadata_server_api):
|
|||||||
# init sys column
|
# init sys column
|
||||||
sys_columns = get_sys_columns()
|
sys_columns = get_sys_columns()
|
||||||
metadata_server_api.add_columns(METADATA_TABLE.id, sys_columns)
|
metadata_server_api.add_columns(METADATA_TABLE.id, sys_columns)
|
||||||
|
|
||||||
|
|
||||||
|
def update_docs_summary(repo_id, files_info_list):
|
||||||
|
payload = {'exp': int(time.time()) + 300, }
|
||||||
|
token = jwt.encode(payload, SEAFILE_AI_SECRET_KEY, algorithm='HS256')
|
||||||
|
headers = {"Authorization": "Token %s" % token}
|
||||||
|
url = urljoin(SEAFILE_AI_SERVER_URL, '/api/v1/update-docs-summary')
|
||||||
|
params = {
|
||||||
|
'repo_id': repo_id,
|
||||||
|
'files_info_list': files_info_list,
|
||||||
|
}
|
||||||
|
resp = requests.post(url, json=params, headers=headers)
|
||||||
|
return resp
|
||||||
|
@@ -899,6 +899,13 @@ METADATA_FILE_TYPES = {
|
|||||||
'_audio': ('mp3', 'oga', 'ogg', 'wav', 'flac', 'opus', 'aac', 'au', 'm4a', 'aif', 'aiff', 'wma', 'rm', 'mp1', 'mp2')
|
'_audio': ('mp3', 'oga', 'ogg', 'wav', 'flac', 'opus', 'aac', 'au', 'm4a', 'aif', 'aiff', 'wma', 'rm', 'mp1', 'mp2')
|
||||||
}
|
}
|
||||||
|
|
||||||
|
##############################
|
||||||
|
# seafile ai #
|
||||||
|
##############################
|
||||||
|
|
||||||
|
SEAFILE_AI_SERVER_URL = ''
|
||||||
|
SEAFILE_AI_SECRET_KEY = ''
|
||||||
|
|
||||||
d = os.path.dirname
|
d = os.path.dirname
|
||||||
EVENTS_CONFIG_FILE = os.environ.get(
|
EVENTS_CONFIG_FILE = os.environ.get(
|
||||||
'EVENTS_CONFIG_FILE',
|
'EVENTS_CONFIG_FILE',
|
||||||
|
@@ -209,7 +209,7 @@ from seahub.api2.endpoints.wiki2 import Wikis2View, Wiki2View, Wiki2ConfigView,
|
|||||||
Wiki2DuplicatePageView, WikiPageTrashView
|
Wiki2DuplicatePageView, WikiPageTrashView
|
||||||
from seahub.api2.endpoints.subscription import SubscriptionView, SubscriptionPlansView, SubscriptionLogsView
|
from seahub.api2.endpoints.subscription import SubscriptionView, SubscriptionPlansView, SubscriptionLogsView
|
||||||
from seahub.api2.endpoints.metadata_manage import MetadataRecords, MetadataManage, MetadataColumns, MetadataRecordInfo, \
|
from seahub.api2.endpoints.metadata_manage import MetadataRecords, MetadataManage, MetadataColumns, MetadataRecordInfo, \
|
||||||
MetadataViews, MetadataViewsMoveView, MetadataViewsDetailView
|
MetadataViews, MetadataViewsMoveView, MetadataViewsDetailView, MetadataSummarizeDocs
|
||||||
from seahub.api2.endpoints.user_list import UserListView
|
from seahub.api2.endpoints.user_list import UserListView
|
||||||
|
|
||||||
|
|
||||||
@@ -1042,5 +1042,6 @@ if settings.ENABLE_METADATA_MANAGEMENT:
|
|||||||
re_path(r'^api/v2.1/repos/(?P<repo_id>[-0-9a-f]{36})/metadata/views/$', MetadataViews.as_view(), name='api-v2.1-metadata-views'),
|
re_path(r'^api/v2.1/repos/(?P<repo_id>[-0-9a-f]{36})/metadata/views/$', MetadataViews.as_view(), name='api-v2.1-metadata-views'),
|
||||||
re_path(r'^api/v2.1/repos/(?P<repo_id>[-0-9a-f]{36})/metadata/views/(?P<view_id>[-0-9a-zA-Z]{4})/$', MetadataViewsDetailView.as_view(), name='api-v2.1-metadata-views-detail'),
|
re_path(r'^api/v2.1/repos/(?P<repo_id>[-0-9a-f]{36})/metadata/views/(?P<view_id>[-0-9a-zA-Z]{4})/$', MetadataViewsDetailView.as_view(), name='api-v2.1-metadata-views-detail'),
|
||||||
re_path(r'^api/v2.1/repos/(?P<repo_id>[-0-9a-f]{36})/metadata/move-views/$', MetadataViewsMoveView.as_view(), name='api-v2.1-metadata-views-move'),
|
re_path(r'^api/v2.1/repos/(?P<repo_id>[-0-9a-f]{36})/metadata/move-views/$', MetadataViewsMoveView.as_view(), name='api-v2.1-metadata-views-move'),
|
||||||
|
re_path(r'^api/v2.1/repos/(?P<repo_id>[-0-9a-f]{36})/metadata/ai/summarize-documents/$', MetadataSummarizeDocs.as_view(), name='api-v2.1-metadata-summarize-documents'),
|
||||||
|
|
||||||
]
|
]
|
||||||
|
Reference in New Issue
Block a user