mirror of
https://github.com/infiniflow/ragflow.git
synced 2025-12-08 20:42:30 +08:00
Feat: add initial Google Drive connector support (#11147)
### What problem does this PR solve? This feature is primarily ported from the [Onyx](https://github.com/onyx-dot-app/onyx) project with necessary modifications. Thanks for such a brilliant project. Minor: consistently use `google_drive` rather than `google_driver`. <img width="566" height="731" alt="image" src="https://github.com/user-attachments/assets/6f64e70e-881e-42c7-b45f-809d3e0024a4" /> <img width="904" height="830" alt="image" src="https://github.com/user-attachments/assets/dfa7d1ef-819a-4a82-8c52-0999f48ed4a6" /> <img width="911" height="869" alt="image" src="https://github.com/user-attachments/assets/39e792fb-9fbe-4f3d-9b3c-b2265186bc22" /> <img width="947" height="323" alt="image" src="https://github.com/user-attachments/assets/27d70e96-d9c0-42d9-8c89-276919b6d61d" /> ### Type of change - [x] New Feature (non-breaking change which adds functionality)
This commit is contained in:
8
web/src/assets/svg/data-source/google-drive.svg
Normal file
8
web/src/assets/svg/data-source/google-drive.svg
Normal file
@ -0,0 +1,8 @@
|
||||
<svg viewBox="0 0 87.3 78" xmlns="http://www.w3.org/2000/svg">
|
||||
<path d="m6.6 66.85 3.85 6.65c.8 1.4 1.95 2.5 3.3 3.3l13.75-23.8h-27.5c0 1.55.4 3.1 1.2 4.5z" fill="#0066da"/>
|
||||
<path d="m43.65 25-13.75-23.8c-1.35.8-2.5 1.9-3.3 3.3l-25.4 44a9.06 9.06 0 0 0 -1.2 4.5h27.5z" fill="#00ac47"/>
|
||||
<path d="m73.55 76.8c1.35-.8 2.5-1.9 3.3-3.3l1.6-2.75 7.65-13.25c.8-1.4 1.2-2.95 1.2-4.5h-27.502l5.852 11.5z" fill="#ea4335"/>
|
||||
<path d="m43.65 25 13.75-23.8c-1.35-.8-2.9-1.2-4.5-1.2h-18.5c-1.6 0-3.15.45-4.5 1.2z" fill="#00832d"/>
|
||||
<path d="m59.8 53h-32.3l-13.75 23.8c1.35.8 2.9 1.2 4.5 1.2h50.8c1.6 0 3.15-.45 4.5-1.2z" fill="#2684fc"/>
|
||||
<path d="m73.4 26.5-12.7-22c-.8-1.4-1.95-2.5-3.3-3.3l-13.75 23.8 16.15 28h27.45c0-1.55-.4-3.1-1.2-4.5z" fill="#ffba00"/>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 755 B |
@ -704,6 +704,16 @@ This auto-tagging feature enhances retrieval by adding another layer of domain-s
|
||||
'Link your Discord server to access and analyze chat data.',
|
||||
notionDescription:
|
||||
'Sync pages and databases from Notion for knowledge retrieval.',
|
||||
google_driveDescription:
|
||||
'Connect your Google Drive via OAuth and sync specific folders or drives.',
|
||||
google_driveTokenTip:
|
||||
'Upload the OAuth token JSON generated from the OAuth helper or Google Cloud Console. You may also upload a client_secret JSON from an "installed" or "web" application. If this is your first sync, a browser window will open to complete the OAuth consent. If the JSON already contains a refresh token, it will be reused automatically.',
|
||||
google_drivePrimaryAdminTip:
|
||||
'Email address that has access to the Drive content being synced.',
|
||||
google_driveMyDriveEmailsTip:
|
||||
'Comma-separated emails whose “My Drive” contents should be indexed (include the primary admin).',
|
||||
google_driveSharedFoldersTip:
|
||||
'Comma-separated Google Drive folder links to crawl.',
|
||||
availableSourcesDescription: 'Select a data source to add',
|
||||
availableSources: 'Available Sources',
|
||||
datasourceDescription: 'Manage your data source and connections',
|
||||
|
||||
@ -690,6 +690,15 @@ General:实体和关系提取提示来自 GitHub - microsoft/graphrag:基于
|
||||
s3Description: ' 连接你的 AWS S3 存储桶以导入和同步文件。',
|
||||
discordDescription: ' 连接你的 Discord 服务器以访问和分析聊天数据。',
|
||||
notionDescription: ' 同步 Notion 页面与数据库,用于知识检索。',
|
||||
google_driveDescription:
|
||||
'通过 OAuth 连接 Google Drive,并同步指定的文件夹或云端硬盘。',
|
||||
google_driveTokenTip:
|
||||
'请上传由 OAuth helper 或 Google Cloud Console 导出的 OAuth token JSON。也支持上传 “installed” 或 “web” 类型的 client_secret JSON。若为首次同步,将自动弹出浏览器完成 OAuth 授权流程;如果该 JSON 已包含 refresh token,将会被自动复用。',
|
||||
google_drivePrimaryAdminTip: '拥有相应 Drive 访问权限的管理员邮箱。',
|
||||
google_driveMyDriveEmailsTip:
|
||||
'需要索引其 “我的云端硬盘” 的邮箱,多个邮箱用逗号分隔(建议包含管理员)。',
|
||||
google_driveSharedFoldersTip:
|
||||
'需要同步的 Google Drive 文件夹链接,多个链接用逗号分隔。',
|
||||
availableSourcesDescription: '选择要添加的数据源',
|
||||
availableSources: '可用数据源',
|
||||
datasourceDescription: '管理您的数据源和连接',
|
||||
@ -1759,8 +1768,8 @@ Tokenizer 会根据所选方式将内容存储为对应的数据结构。`,
|
||||
changeStepModalCancelText: '取消',
|
||||
unlinkPipelineModalTitle: '解绑pipeline',
|
||||
unlinkPipelineModalContent: `
|
||||
<p>一旦取消链接,该数据集将不再连接到当前数据管道。</p>
|
||||
<p>正在解析的文件将继续解析,直到完成。</p>
|
||||
<p>一旦取消链接,该数据集将不再连接到当前数据管道。</p>
|
||||
<p>正在解析的文件将继续解析,直到完成。</p>
|
||||
<p>尚未解析的文件将不再被处理。</p> <br/>
|
||||
<p>你确定要继续吗?</p> `,
|
||||
unlinkPipelineModalConfirmText: '解绑',
|
||||
|
||||
@ -0,0 +1,66 @@
|
||||
import { useMemo, useState } from 'react';
|
||||
|
||||
import { FileUploader } from '@/components/file-uploader';
|
||||
import message from '@/components/ui/message';
|
||||
import { Textarea } from '@/components/ui/textarea';
|
||||
import { FileMimeType } from '@/constants/common';
|
||||
|
||||
type GoogleDriveTokenFieldProps = {
|
||||
value?: string;
|
||||
onChange: (value: any) => void;
|
||||
placeholder?: string;
|
||||
};
|
||||
|
||||
const GoogleDriveTokenField = ({
|
||||
value,
|
||||
onChange,
|
||||
placeholder,
|
||||
}: GoogleDriveTokenFieldProps) => {
|
||||
const [files, setFiles] = useState<File[]>([]);
|
||||
|
||||
const handleValueChange = useMemo(
|
||||
() => (nextFiles: File[]) => {
|
||||
if (!nextFiles.length) {
|
||||
setFiles([]);
|
||||
return;
|
||||
}
|
||||
const file = nextFiles[nextFiles.length - 1];
|
||||
file
|
||||
.text()
|
||||
.then((text) => {
|
||||
JSON.parse(text);
|
||||
onChange(text);
|
||||
setFiles([file]);
|
||||
message.success('JSON uploaded');
|
||||
})
|
||||
.catch(() => {
|
||||
message.error('Invalid JSON file.');
|
||||
setFiles([]);
|
||||
});
|
||||
},
|
||||
[onChange],
|
||||
);
|
||||
|
||||
return (
|
||||
<div className="flex flex-col gap-2">
|
||||
<Textarea
|
||||
value={value || ''}
|
||||
onChange={(event) => onChange(event.target.value)}
|
||||
placeholder={
|
||||
placeholder ||
|
||||
'{ "token": "...", "refresh_token": "...", "client_id": "...", ... }'
|
||||
}
|
||||
className="min-h-[120px] max-h-60 overflow-y-auto"
|
||||
/>
|
||||
<FileUploader
|
||||
className="py-4"
|
||||
value={files}
|
||||
onValueChange={handleValueChange}
|
||||
accept={{ '*.json': [FileMimeType.Json] }}
|
||||
maxFileCount={1}
|
||||
/>
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
export default GoogleDriveTokenField;
|
||||
@ -1,14 +1,15 @@
|
||||
import { FormFieldType } from '@/components/dynamic-form';
|
||||
import SvgIcon from '@/components/svg-icon';
|
||||
import { t } from 'i18next';
|
||||
import GoogleDriveTokenField from './component/google-drive-token-field';
|
||||
|
||||
export enum DataSourceKey {
|
||||
CONFLUENCE = 'confluence',
|
||||
S3 = 's3',
|
||||
NOTION = 'notion',
|
||||
DISCORD = 'discord',
|
||||
GOOGLE_DRIVE = 'google_drive',
|
||||
// GMAIL = 'gmail',
|
||||
// GOOGLE_DRIVER = 'google_driver',
|
||||
// JIRA = 'jira',
|
||||
// SHAREPOINT = 'sharepoint',
|
||||
// SLACK = 'slack',
|
||||
@ -36,6 +37,11 @@ export const DataSourceInfo = {
|
||||
description: t(`setting.${DataSourceKey.CONFLUENCE}Description`),
|
||||
icon: <SvgIcon name={'data-source/confluence'} width={38} />,
|
||||
},
|
||||
[DataSourceKey.GOOGLE_DRIVE]: {
|
||||
name: 'Google Drive',
|
||||
description: t(`setting.${DataSourceKey.GOOGLE_DRIVE}Description`),
|
||||
icon: <SvgIcon name={'data-source/google-drive'} width={38} />,
|
||||
},
|
||||
};
|
||||
|
||||
export const DataSourceFormBaseFields = [
|
||||
@ -170,6 +176,101 @@ export const DataSourceFormFields = {
|
||||
'Check if this is a Confluence Cloud instance, uncheck for Confluence Server/Data Center',
|
||||
},
|
||||
],
|
||||
[DataSourceKey.GOOGLE_DRIVE]: [
|
||||
{
|
||||
label: 'Primary Admin Email',
|
||||
name: 'config.credentials.google_primary_admin',
|
||||
type: FormFieldType.Text,
|
||||
required: true,
|
||||
placeholder: 'admin@example.com',
|
||||
tooltip: t('setting.google_drivePrimaryAdminTip'),
|
||||
},
|
||||
{
|
||||
label: 'OAuth Token JSON',
|
||||
name: 'config.credentials.google_tokens',
|
||||
type: FormFieldType.Textarea,
|
||||
required: true,
|
||||
render: (fieldProps) => (
|
||||
<GoogleDriveTokenField
|
||||
value={fieldProps.value}
|
||||
onChange={fieldProps.onChange}
|
||||
placeholder='{ "token": "...", "refresh_token": "...", ... }'
|
||||
/>
|
||||
),
|
||||
tooltip: t('setting.google_driveTokenTip'),
|
||||
},
|
||||
{
|
||||
label: 'My Drive Emails',
|
||||
name: 'config.my_drive_emails',
|
||||
type: FormFieldType.Text,
|
||||
required: true,
|
||||
placeholder: 'user1@example.com,user2@example.com',
|
||||
tooltip: t('setting.google_driveMyDriveEmailsTip'),
|
||||
},
|
||||
{
|
||||
label: 'Shared Folder URLs',
|
||||
name: 'config.shared_folder_urls',
|
||||
type: FormFieldType.Textarea,
|
||||
required: true,
|
||||
placeholder:
|
||||
'https://drive.google.com/drive/folders/XXXXX,https://drive.google.com/drive/folders/YYYYY',
|
||||
tooltip: t('setting.google_driveSharedFoldersTip'),
|
||||
},
|
||||
// The fields below are intentionally disabled for now. Uncomment them when we
|
||||
// reintroduce shared drive controls or advanced impersonation options.
|
||||
// {
|
||||
// label: 'Shared Drive URLs',
|
||||
// name: 'config.shared_drive_urls',
|
||||
// type: FormFieldType.Text,
|
||||
// required: false,
|
||||
// placeholder:
|
||||
// 'Optional: comma-separated shared drive links if you want to include them.',
|
||||
// },
|
||||
// {
|
||||
// label: 'Specific User Emails',
|
||||
// name: 'config.specific_user_emails',
|
||||
// type: FormFieldType.Text,
|
||||
// required: false,
|
||||
// placeholder:
|
||||
// 'Optional: comma-separated list of users to impersonate (overrides defaults).',
|
||||
// },
|
||||
// {
|
||||
// label: 'Include My Drive',
|
||||
// name: 'config.include_my_drives',
|
||||
// type: FormFieldType.Checkbox,
|
||||
// required: false,
|
||||
// defaultValue: true,
|
||||
// },
|
||||
// {
|
||||
// label: 'Include Shared Drives',
|
||||
// name: 'config.include_shared_drives',
|
||||
// type: FormFieldType.Checkbox,
|
||||
// required: false,
|
||||
// defaultValue: false,
|
||||
// },
|
||||
// {
|
||||
// label: 'Include “Shared with me”',
|
||||
// name: 'config.include_files_shared_with_me',
|
||||
// type: FormFieldType.Checkbox,
|
||||
// required: false,
|
||||
// defaultValue: false,
|
||||
// },
|
||||
// {
|
||||
// label: 'Allow Images',
|
||||
// name: 'config.allow_images',
|
||||
// type: FormFieldType.Checkbox,
|
||||
// required: false,
|
||||
// defaultValue: false,
|
||||
// },
|
||||
{
|
||||
label: '',
|
||||
name: 'config.credentials.authentication_method',
|
||||
type: FormFieldType.Text,
|
||||
required: false,
|
||||
hidden: true,
|
||||
defaultValue: 'uploaded',
|
||||
},
|
||||
],
|
||||
};
|
||||
|
||||
export const DataSourceFormDefaultValues = {
|
||||
@ -219,4 +320,23 @@ export const DataSourceFormDefaultValues = {
|
||||
},
|
||||
},
|
||||
},
|
||||
[DataSourceKey.GOOGLE_DRIVE]: {
|
||||
name: '',
|
||||
source: DataSourceKey.GOOGLE_DRIVE,
|
||||
config: {
|
||||
include_shared_drives: false,
|
||||
include_my_drives: true,
|
||||
include_files_shared_with_me: false,
|
||||
allow_images: false,
|
||||
shared_drive_urls: '',
|
||||
shared_folder_urls: '',
|
||||
my_drive_emails: '',
|
||||
specific_user_emails: '',
|
||||
credentials: {
|
||||
google_primary_admin: '',
|
||||
google_tokens: '',
|
||||
authentication_method: 'uploaded',
|
||||
},
|
||||
},
|
||||
},
|
||||
};
|
||||
|
||||
@ -23,6 +23,12 @@ const dataSourceTemplates = [
|
||||
description: DataSourceInfo[DataSourceKey.S3].description,
|
||||
icon: DataSourceInfo[DataSourceKey.S3].icon,
|
||||
},
|
||||
{
|
||||
id: DataSourceKey.GOOGLE_DRIVE,
|
||||
name: DataSourceInfo[DataSourceKey.GOOGLE_DRIVE].name,
|
||||
description: DataSourceInfo[DataSourceKey.GOOGLE_DRIVE].description,
|
||||
icon: DataSourceInfo[DataSourceKey.GOOGLE_DRIVE].icon,
|
||||
},
|
||||
{
|
||||
id: DataSourceKey.DISCORD,
|
||||
name: DataSourceInfo[DataSourceKey.DISCORD].name,
|
||||
|
||||
Reference in New Issue
Block a user