From 88d5e27fe8f2211ef2b4222b4e4f4d13ee7f445b Mon Sep 17 00:00:00 2001 From: Garfield Dai Date: Mon, 15 Sep 2025 14:49:23 +0800 Subject: [PATCH 01/70] Release/e-1.8.1 (#25613) Co-authored-by: zxhlyh Co-authored-by: GareArc Co-authored-by: autofix-ci[bot] <114827586+autofix-ci[bot]@users.noreply.github.com> Co-authored-by: hjlarry --- ...dd_credential_status_for_provider_table.py | 33 +++++++++++++++ .../enterprise/plugin_manager_service.py | 6 +-- .../model-auth/authorized/credential-item.tsx | 6 +-- .../switch-credential-in-load-balancing.tsx | 41 +++++++++++-------- .../model-provider-page/model-modal/index.tsx | 8 ++-- .../plugin-auth/authorized-in-node.tsx | 20 ++++++++- .../plugins/plugin-auth/authorized/index.tsx | 3 +- web/hooks/use-document-title.ts | 20 +++++++++ web/i18n/en-US/plugin.ts | 1 + web/i18n/zh-Hans/plugin.ts | 1 + 10 files changed, 109 insertions(+), 30 deletions(-) create mode 100644 api/migrations/versions/2025_09_11_1537-cf7c38a32b2d_add_credential_status_for_provider_table.py diff --git a/api/migrations/versions/2025_09_11_1537-cf7c38a32b2d_add_credential_status_for_provider_table.py b/api/migrations/versions/2025_09_11_1537-cf7c38a32b2d_add_credential_status_for_provider_table.py new file mode 100644 index 0000000000..17467e6495 --- /dev/null +++ b/api/migrations/versions/2025_09_11_1537-cf7c38a32b2d_add_credential_status_for_provider_table.py @@ -0,0 +1,33 @@ +"""Add credential status for provider table + +Revision ID: cf7c38a32b2d +Revises: c20211f18133 +Create Date: 2025-09-11 15:37:17.771298 + +""" +from alembic import op +import models as models +import sqlalchemy as sa + + +# revision identifiers, used by Alembic. +revision = 'cf7c38a32b2d' +down_revision = 'c20211f18133' +branch_labels = None +depends_on = None + + +def upgrade(): + # ### commands auto generated by Alembic - please adjust! ### + with op.batch_alter_table('providers', schema=None) as batch_op: + batch_op.add_column(sa.Column('credential_status', sa.String(length=20), server_default=sa.text("'active'::character varying"), nullable=True)) + + # ### end Alembic commands ### + + +def downgrade(): + # ### commands auto generated by Alembic - please adjust! ### + with op.batch_alter_table('providers', schema=None) as batch_op: + batch_op.drop_column('credential_status') + + # ### end Alembic commands ### \ No newline at end of file diff --git a/api/services/enterprise/plugin_manager_service.py b/api/services/enterprise/plugin_manager_service.py index ee8a932ded..1065d3842a 100644 --- a/api/services/enterprise/plugin_manager_service.py +++ b/api/services/enterprise/plugin_manager_service.py @@ -9,9 +9,9 @@ from services.errors.base import BaseServiceError logger = logging.getLogger(__name__) -class PluginCredentialType(enum.IntEnum): - MODEL = enum.auto() - TOOL = enum.auto() +class PluginCredentialType(enum.Enum): + MODEL = 0 # must be 0 for API contract compatibility + TOOL = 1 # must be 1 for API contract compatibility def to_number(self): return self.value diff --git a/web/app/components/header/account-setting/model-provider-page/model-auth/authorized/credential-item.tsx b/web/app/components/header/account-setting/model-provider-page/model-auth/authorized/credential-item.tsx index 2d792d1705..0aa4ac6fbc 100644 --- a/web/app/components/header/account-setting/model-provider-page/model-auth/authorized/credential-item.tsx +++ b/web/app/components/header/account-setting/model-provider-page/model-auth/authorized/credential-item.tsx @@ -92,10 +92,10 @@ const CredentialItem = ({ ) } { - showAction && ( + showAction && !credential.from_enterprise && (
{ - !disableEdit && !credential.not_allowed_to_use && !credential.from_enterprise && ( + !disableEdit && !credential.not_allowed_to_use && ( { const { t } = useTranslation() - + const notAllowCustomCredential = provider.allow_custom_token === false const handleItemClick = useCallback((credential: Credential) => { setCustomModelCredential(credential) }, [setCustomModelCredential]) const renderTrigger = useCallback(() => { const selectedCredentialId = customModelCredential?.credential_id - const authRemoved = !selectedCredentialId && !!credentials?.length + const currentCredential = credentials?.find(c => c.credential_id === selectedCredentialId) + const empty = !credentials?.length + const authRemoved = selectedCredentialId && !currentCredential && !empty + const unavailable = currentCredential?.not_allowed_to_use + let color = 'green' - if (authRemoved && !customModelCredential?.not_allowed_to_use) + if (authRemoved || unavailable) color = 'red' - if (customModelCredential?.not_allowed_to_use) - color = 'gray' const Item = ( ) - if (customModelCredential?.not_allowed_to_use) { + if (empty && notAllowCustomCredential) { return ( ) } diff --git a/web/app/components/header/account-setting/model-provider-page/model-modal/index.tsx b/web/app/components/header/account-setting/model-provider-page/model-modal/index.tsx index 4ffbc8f191..9916fbbf04 100644 --- a/web/app/components/header/account-setting/model-provider-page/model-modal/index.tsx +++ b/web/app/components/header/account-setting/model-provider-page/model-modal/index.tsx @@ -114,7 +114,7 @@ const ModelModal: FC = ({ const formRef1 = useRef(null) const [selectedCredential, setSelectedCredential] = useState() const formRef2 = useRef(null) - const isEditMode = !!Object.keys(formValues).filter((key) => { + const isEditMode = !!credential && !!Object.keys(formSchemasValue || {}).filter((key) => { return key !== '__model_name' && key !== '__model_type' && !!formValues[key] }).length && isCurrentWorkspaceManager @@ -376,16 +376,16 @@ const ModelModal: FC = ({ !provider.help.url && e.preventDefault()} > {provider.help.title?.[language] || provider.help.url[language] || provider.help.title?.en_US || provider.help.url.en_US} - + ) :
} -
+
{ isEditMode && ( -
- )} - {activeTab === 'api' && data && } -
- {activeTab === 'dataset' && ( - <> - - {!systemFeatures.branding.enabled && } - {showTagManagementModal && ( - - )} - - )} - {activeTab === 'api' && data && } - - {showExternalApiPanel && setShowExternalApiPanel(false)} />} -
- ) -} - -export default Container diff --git a/web/app/(commonLayout)/datasets/create-from-pipeline/page.tsx b/web/app/(commonLayout)/datasets/create-from-pipeline/page.tsx new file mode 100644 index 0000000000..72f5ecdfd9 --- /dev/null +++ b/web/app/(commonLayout)/datasets/create-from-pipeline/page.tsx @@ -0,0 +1,10 @@ +import React from 'react' +import CreateFromPipeline from '@/app/components/datasets/create-from-pipeline' + +const DatasetCreation = async () => { + return ( + + ) +} + +export default DatasetCreation diff --git a/web/app/(commonLayout)/datasets/dataset-card.tsx b/web/app/(commonLayout)/datasets/dataset-card.tsx deleted file mode 100644 index 3e913ca52f..0000000000 --- a/web/app/(commonLayout)/datasets/dataset-card.tsx +++ /dev/null @@ -1,249 +0,0 @@ -'use client' - -import { useContext } from 'use-context-selector' -import { useRouter } from 'next/navigation' -import { useCallback, useEffect, useState } from 'react' -import { useTranslation } from 'react-i18next' -import { RiMoreFill } from '@remixicon/react' -import { mutate } from 'swr' -import cn from '@/utils/classnames' -import Confirm from '@/app/components/base/confirm' -import { ToastContext } from '@/app/components/base/toast' -import { checkIsUsedInApp, deleteDataset } from '@/service/datasets' -import type { DataSet } from '@/models/datasets' -import Tooltip from '@/app/components/base/tooltip' -import { Folder } from '@/app/components/base/icons/src/vender/solid/files' -import type { HtmlContentProps } from '@/app/components/base/popover' -import CustomPopover from '@/app/components/base/popover' -import Divider from '@/app/components/base/divider' -import RenameDatasetModal from '@/app/components/datasets/rename-modal' -import type { Tag } from '@/app/components/base/tag-management/constant' -import TagSelector from '@/app/components/base/tag-management/selector' -import CornerLabel from '@/app/components/base/corner-label' -import { useAppContext } from '@/context/app-context' - -export type DatasetCardProps = { - dataset: DataSet - onSuccess?: () => void -} - -const DatasetCard = ({ - dataset, - onSuccess, -}: DatasetCardProps) => { - const { t } = useTranslation() - const { notify } = useContext(ToastContext) - const { push } = useRouter() - const EXTERNAL_PROVIDER = 'external' as const - - const { isCurrentWorkspaceDatasetOperator } = useAppContext() - const [tags, setTags] = useState(dataset.tags) - - const [showRenameModal, setShowRenameModal] = useState(false) - const [showConfirmDelete, setShowConfirmDelete] = useState(false) - const [confirmMessage, setConfirmMessage] = useState('') - const isExternalProvider = (provider: string): boolean => provider === EXTERNAL_PROVIDER - const detectIsUsedByApp = useCallback(async () => { - try { - const { is_using: isUsedByApp } = await checkIsUsedInApp(dataset.id) - setConfirmMessage(isUsedByApp ? t('dataset.datasetUsedByApp')! : t('dataset.deleteDatasetConfirmContent')!) - } - catch (e: any) { - const res = await e.json() - notify({ type: 'error', message: res?.message || 'Unknown error' }) - } - - setShowConfirmDelete(true) - }, [dataset.id, notify, t]) - const onConfirmDelete = useCallback(async () => { - try { - await deleteDataset(dataset.id) - - // Clear SWR cache to prevent stale data in knowledge retrieval nodes - mutate( - (key) => { - if (typeof key === 'string') return key.includes('/datasets') - if (typeof key === 'object' && key !== null) - return key.url === '/datasets' || key.url?.includes('/datasets') - return false - }, - undefined, - { revalidate: true }, - ) - - notify({ type: 'success', message: t('dataset.datasetDeleted') }) - if (onSuccess) - onSuccess() - } - catch { - } - setShowConfirmDelete(false) - }, [dataset.id, notify, onSuccess, t]) - - const Operations = (props: HtmlContentProps & { showDelete: boolean }) => { - const onMouseLeave = async () => { - props.onClose?.() - } - const onClickRename = async (e: React.MouseEvent) => { - e.stopPropagation() - props.onClick?.() - e.preventDefault() - setShowRenameModal(true) - } - const onClickDelete = async (e: React.MouseEvent) => { - e.stopPropagation() - props.onClick?.() - e.preventDefault() - detectIsUsedByApp() - } - return ( -
-
- {t('common.operation.settings')} -
- {props.showDelete && ( - <> - -
- - {t('common.operation.delete')} - -
- - )} -
- ) - } - - useEffect(() => { - setTags(dataset.tags) - }, [dataset]) - - return ( - <> -
{ - e.preventDefault() - isExternalProvider(dataset.provider) - ? push(`/datasets/${dataset.id}/hitTesting`) - : push(`/datasets/${dataset.id}/documents`) - }} - > - {isExternalProvider(dataset.provider) && } -
-
- -
-
-
-
{dataset.name}
- {!dataset.embedding_available && ( - - {t('dataset.unavailable')} - - )} -
-
-
- {dataset.provider === 'external' - ? <> - {dataset.app_count}{t('dataset.appCount')} - - : <> - {dataset.document_count}{t('dataset.documentCount')} - · - {Math.round(dataset.word_count / 1000)}{t('dataset.wordCount')} - · - {dataset.app_count}{t('dataset.appCount')} - - } -
-
-
-
-
- {dataset.description} -
-
-
{ - e.stopPropagation() - e.preventDefault() - }}> -
- tag.id)} - selectedTags={tags} - onCacheUpdate={setTags} - onChange={onSuccess} - /> -
-
-
-
- } - position="br" - trigger="click" - btnElement={ -
- -
- } - btnClassName={open => - cn( - open ? '!bg-state-base-hover !shadow-none' : '!bg-transparent', - 'h-8 w-8 rounded-md border-none !p-2 hover:!bg-state-base-hover', - ) - } - className={'!z-20 h-fit !w-[128px]'} - /> -
-
-
- {showRenameModal && ( - setShowRenameModal(false)} - onSuccess={onSuccess} - /> - )} - {showConfirmDelete && ( - setShowConfirmDelete(false)} - /> - )} - - ) -} - -export default DatasetCard diff --git a/web/app/(commonLayout)/datasets/datasets.tsx b/web/app/(commonLayout)/datasets/datasets.tsx deleted file mode 100644 index 4e116c6d39..0000000000 --- a/web/app/(commonLayout)/datasets/datasets.tsx +++ /dev/null @@ -1,96 +0,0 @@ -'use client' - -import { useCallback, useEffect, useRef } from 'react' -import useSWRInfinite from 'swr/infinite' -import { debounce } from 'lodash-es' -import NewDatasetCard from './new-dataset-card' -import DatasetCard from './dataset-card' -import type { DataSetListResponse, FetchDatasetsParams } from '@/models/datasets' -import { fetchDatasets } from '@/service/datasets' -import { useAppContext } from '@/context/app-context' -import { useTranslation } from 'react-i18next' - -const getKey = ( - pageIndex: number, - previousPageData: DataSetListResponse, - tags: string[], - keyword: string, - includeAll: boolean, -) => { - if (!pageIndex || previousPageData.has_more) { - const params: FetchDatasetsParams = { - url: 'datasets', - params: { - page: pageIndex + 1, - limit: 30, - include_all: includeAll, - }, - } - if (tags.length) - params.params.tag_ids = tags - if (keyword) - params.params.keyword = keyword - return params - } - return null -} - -type Props = { - containerRef: React.RefObject - tags: string[] - keywords: string - includeAll: boolean -} - -const Datasets = ({ - containerRef, - tags, - keywords, - includeAll, -}: Props) => { - const { t } = useTranslation() - const { isCurrentWorkspaceEditor } = useAppContext() - const { data, isLoading, setSize, mutate } = useSWRInfinite( - (pageIndex: number, previousPageData: DataSetListResponse) => getKey(pageIndex, previousPageData, tags, keywords, includeAll), - fetchDatasets, - { revalidateFirstPage: false, revalidateAll: true }, - ) - const loadingStateRef = useRef(false) - const anchorRef = useRef(null) - - useEffect(() => { - loadingStateRef.current = isLoading - }, [isLoading, t]) - - const onScroll = useCallback( - debounce(() => { - if (!loadingStateRef.current && containerRef.current && anchorRef.current) { - const { scrollTop, clientHeight } = containerRef.current - const anchorOffset = anchorRef.current.offsetTop - if (anchorOffset - scrollTop - clientHeight < 100) - setSize(size => size + 1) - } - }, 50), - [setSize], - ) - - useEffect(() => { - const currentContainer = containerRef.current - currentContainer?.addEventListener('scroll', onScroll) - return () => { - currentContainer?.removeEventListener('scroll', onScroll) - onScroll.cancel() - } - }, [containerRef, onScroll]) - - return ( - - ) -} - -export default Datasets diff --git a/web/app/(commonLayout)/datasets/doc.tsx b/web/app/(commonLayout)/datasets/doc.tsx deleted file mode 100644 index c31dad3c00..0000000000 --- a/web/app/(commonLayout)/datasets/doc.tsx +++ /dev/null @@ -1,203 +0,0 @@ -'use client' - -import { useEffect, useMemo, useState } from 'react' -import { useContext } from 'use-context-selector' -import { useTranslation } from 'react-i18next' -import { RiCloseLine, RiListUnordered } from '@remixicon/react' -import TemplateEn from './template/template.en.mdx' -import TemplateZh from './template/template.zh.mdx' -import TemplateJa from './template/template.ja.mdx' -import I18n from '@/context/i18n' -import { LanguagesSupported } from '@/i18n-config/language' -import useTheme from '@/hooks/use-theme' -import { Theme } from '@/types/app' -import cn from '@/utils/classnames' - -type DocProps = { - apiBaseUrl: string -} - -const Doc = ({ apiBaseUrl }: DocProps) => { - const { locale } = useContext(I18n) - const { t } = useTranslation() - const [toc, setToc] = useState>([]) - const [isTocExpanded, setIsTocExpanded] = useState(false) - const [activeSection, setActiveSection] = useState('') - const { theme } = useTheme() - - // Set initial TOC expanded state based on screen width - useEffect(() => { - const mediaQuery = window.matchMedia('(min-width: 1280px)') - setIsTocExpanded(mediaQuery.matches) - }, []) - - // Extract TOC from article content - useEffect(() => { - const extractTOC = () => { - const article = document.querySelector('article') - if (article) { - const headings = article.querySelectorAll('h2') - const tocItems = Array.from(headings).map((heading) => { - const anchor = heading.querySelector('a') - if (anchor) { - return { - href: anchor.getAttribute('href') || '', - text: anchor.textContent || '', - } - } - return null - }).filter((item): item is { href: string; text: string } => item !== null) - setToc(tocItems) - // Set initial active section - if (tocItems.length > 0) - setActiveSection(tocItems[0].href.replace('#', '')) - } - } - - setTimeout(extractTOC, 0) - }, [locale]) - - // Track scroll position for active section highlighting - useEffect(() => { - const handleScroll = () => { - const scrollContainer = document.querySelector('.scroll-container') - if (!scrollContainer || toc.length === 0) - return - - // Find active section based on scroll position - let currentSection = '' - toc.forEach((item) => { - const targetId = item.href.replace('#', '') - const element = document.getElementById(targetId) - if (element) { - const rect = element.getBoundingClientRect() - // Consider section active if its top is above the middle of viewport - if (rect.top <= window.innerHeight / 2) - currentSection = targetId - } - }) - - if (currentSection && currentSection !== activeSection) - setActiveSection(currentSection) - } - - const scrollContainer = document.querySelector('.scroll-container') - if (scrollContainer) { - scrollContainer.addEventListener('scroll', handleScroll) - handleScroll() // Initial check - return () => scrollContainer.removeEventListener('scroll', handleScroll) - } - }, [toc, activeSection]) - - // Handle TOC item click - const handleTocClick = (e: React.MouseEvent, item: { href: string; text: string }) => { - e.preventDefault() - const targetId = item.href.replace('#', '') - const element = document.getElementById(targetId) - if (element) { - const scrollContainer = document.querySelector('.scroll-container') - if (scrollContainer) { - const headerOffset = -40 - const elementTop = element.offsetTop - headerOffset - scrollContainer.scrollTo({ - top: elementTop, - behavior: 'smooth', - }) - } - } - } - - const Template = useMemo(() => { - switch (locale) { - case LanguagesSupported[1]: - return - case LanguagesSupported[7]: - return - default: - return - } - }, [apiBaseUrl, locale]) - - return ( -
-
- {isTocExpanded - ? ( - - ) - : ( - - )} -
-
- {Template} -
-
- ) -} - -export default Doc diff --git a/web/app/(commonLayout)/datasets/new-dataset-card.tsx b/web/app/(commonLayout)/datasets/new-dataset-card.tsx deleted file mode 100644 index 62f6a34be0..0000000000 --- a/web/app/(commonLayout)/datasets/new-dataset-card.tsx +++ /dev/null @@ -1,41 +0,0 @@ -'use client' -import { useTranslation } from 'react-i18next' -import { - RiAddLine, - RiArrowRightLine, -} from '@remixicon/react' -import Link from 'next/link' - -type CreateAppCardProps = { - ref?: React.Ref -} - -const CreateAppCard = ({ ref }: CreateAppCardProps) => { - const { t } = useTranslation() - - return ( -
- -
-
- -
-
{t('dataset.createDataset')}
-
- -
{t('dataset.createDatasetIntro')}
- -
{t('dataset.connectDataset')}
- - -
- ) -} - -CreateAppCard.displayName = 'CreateAppCard' - -export default CreateAppCard diff --git a/web/app/(commonLayout)/datasets/page.tsx b/web/app/(commonLayout)/datasets/page.tsx index cbfe25ebd2..8388b69468 100644 --- a/web/app/(commonLayout)/datasets/page.tsx +++ b/web/app/(commonLayout)/datasets/page.tsx @@ -1,12 +1,7 @@ -'use client' -import { useTranslation } from 'react-i18next' -import Container from './container' -import useDocumentTitle from '@/hooks/use-document-title' +import List from '../../components/datasets/list' -const AppList = () => { - const { t } = useTranslation() - useDocumentTitle(t('common.menus.datasets')) - return +const DatasetList = async () => { + return } -export default AppList +export default DatasetList diff --git a/web/app/(commonLayout)/datasets/store.ts b/web/app/(commonLayout)/datasets/store.ts deleted file mode 100644 index 40b7b15594..0000000000 --- a/web/app/(commonLayout)/datasets/store.ts +++ /dev/null @@ -1,11 +0,0 @@ -import { create } from 'zustand' - -type DatasetStore = { - showExternalApiPanel: boolean - setShowExternalApiPanel: (show: boolean) => void -} - -export const useDatasetStore = create(set => ({ - showExternalApiPanel: false, - setShowExternalApiPanel: show => set({ showExternalApiPanel: show }), -})) diff --git a/web/app/(commonLayout)/datasets/template/template.en.mdx b/web/app/(commonLayout)/datasets/template/template.en.mdx deleted file mode 100644 index ccbc73aef0..0000000000 --- a/web/app/(commonLayout)/datasets/template/template.en.mdx +++ /dev/null @@ -1,2894 +0,0 @@ -{/** - * @typedef Props - * @property {string} apiBaseUrl - */} - -import { CodeGroup } from '@/app/components/develop/code.tsx' -import { Row, Col, Properties, Property, Heading, SubProperty, PropertyInstruction, Paragraph } from '@/app/components/develop/md.tsx' - -# Knowledge API - -
- ### Authentication - - Service API authenticates using an `API-Key`. - - It is suggested that developers store the `API-Key` in the backend instead of sharing or storing it in the client side to avoid the leakage of the `API-Key`, which may lead to property loss. - - All API requests should include your `API-Key` in the **`Authorization`** HTTP Header, as shown below: - - - ```javascript - Authorization: Bearer {API_KEY} - - ``` - -
- -
- - - - - This API is based on an existing knowledge and creates a new document through text based on this knowledge. - - ### Path - - - Knowledge ID - - - - ### Request Body - - - Document name - - - Document content - - - Index mode - - high_quality High quality: Embedding using embedding model, built as vector database index - - economy Economy: Build using inverted index of keyword table index - - - Format of indexed content - - text_model Text documents are directly embedded; `economy` mode defaults to using this form - - hierarchical_model Parent-child mode - - qa_model Q&A Mode: Generates Q&A pairs for segmented documents and then embeds the questions - - - In Q&A mode, specify the language of the document, for example: English, Chinese - - - Processing rules - - mode (string) Cleaning, segmentation mode, automatic / custom / hierarchical - - rules (object) Custom rules (in automatic mode, this field is empty) - - pre_processing_rules (array[object]) Preprocessing rules - - id (string) Unique identifier for the preprocessing rule - - enumerate - - remove_extra_spaces Replace consecutive spaces, newlines, tabs - - remove_urls_emails Delete URL, email address - - enabled (bool) Whether to select this rule or not. If no document ID is passed in, it represents the default value. - - segmentation (object) Segmentation rules - - separator Custom segment identifier, currently only allows one delimiter to be set. Default is \n - - max_tokens Maximum length (token) defaults to 1000 - - parent_mode Retrieval mode of parent chunks: full-doc full text retrieval / paragraph paragraph retrieval - - subchunk_segmentation (object) Child chunk rules - - separator Segmentation identifier. Currently, only one delimiter is allowed. The default is *** - - max_tokens The maximum length (tokens) must be validated to be shorter than the length of the parent chunk - - chunk_overlap Define the overlap between adjacent chunks (optional) - - When no parameters are set for the knowledge base, the first upload requires the following parameters to be provided; if not provided, the default parameters will be used. - - Retrieval model - - search_method (string) Search method - - hybrid_search Hybrid search - - semantic_search Semantic search - - full_text_search Full-text search - - reranking_enable (bool) Whether to enable reranking - - reranking_mode (object) Rerank model configuration - - reranking_provider_name (string) Rerank model provider - - reranking_model_name (string) Rerank model name - - top_k (int) Number of results to return - - score_threshold_enabled (bool) Whether to enable score threshold - - score_threshold (float) Score threshold - - - Embedding model name - - - Embedding model provider - - - - - - ```bash {{ title: 'cURL' }} - curl --location --request POST '${props.apiBaseUrl}/datasets/{dataset_id}/document/create-by-text' \ - --header 'Authorization: Bearer {api_key}' \ - --header 'Content-Type: application/json' \ - --data-raw '{ - "name": "text", - "text": "text", - "indexing_technique": "high_quality", - "process_rule": { - "mode": "automatic" - } - }' - ``` - - - ```json {{ title: 'Response' }} - { - "document": { - "id": "", - "position": 1, - "data_source_type": "upload_file", - "data_source_info": { - "upload_file_id": "" - }, - "dataset_process_rule_id": "", - "name": "text.txt", - "created_from": "api", - "created_by": "", - "created_at": 1695690280, - "tokens": 0, - "indexing_status": "waiting", - "error": null, - "enabled": true, - "disabled_at": null, - "disabled_by": null, - "archived": false, - "display_status": "queuing", - "word_count": 0, - "hit_count": 0, - "doc_form": "text_model" - }, - "batch": "" - } - ``` - - - - -
- - - - - This API is based on an existing knowledge and creates a new document through a file based on this knowledge. - - ### Path - - - Knowledge ID - - - - ### Request Body - - - - original_document_id Source document ID (optional) - - Used to re-upload the document or modify the document cleaning and segmentation configuration. The missing information is copied from the source document - - The source document cannot be an archived document - - When original_document_id is passed in, the update operation is performed on behalf of the document. process_rule is a fillable item. If not filled in, the segmentation method of the source document will be used by default - - When original_document_id is not passed in, the new operation is performed on behalf of the document, and process_rule is required - - - indexing_technique Index mode - - high_quality High quality: embedding using embedding model, built as vector database index - - economy Economy: Build using inverted index of keyword table index - - - doc_form Format of indexed content - - text_model Text documents are directly embedded; `economy` mode defaults to using this form - - hierarchical_model Parent-child mode - - qa_model Q&A Mode: Generates Q&A pairs for segmented documents and then embeds the questions - - - doc_language In Q&A mode, specify the language of the document, for example: English, Chinese - - - process_rule Processing rules - - mode (string) Cleaning, segmentation mode, automatic / custom / hierarchical - - rules (object) Custom rules (in automatic mode, this field is empty) - - pre_processing_rules (array[object]) Preprocessing rules - - id (string) Unique identifier for the preprocessing rule - - enumerate - - remove_extra_spaces Replace consecutive spaces, newlines, tabs - - remove_urls_emails Delete URL, email address - - enabled (bool) Whether to select this rule or not. If no document ID is passed in, it represents the default value. - - segmentation (object) Segmentation rules - - separator Custom segment identifier, currently only allows one delimiter to be set. Default is \n - - max_tokens Maximum length (token) defaults to 1000 - - parent_mode Retrieval mode of parent chunks: full-doc full text retrieval / paragraph paragraph retrieval - - subchunk_segmentation (object) Child chunk rules - - separator Segmentation identifier. Currently, only one delimiter is allowed. The default is *** - - max_tokens The maximum length (tokens) must be validated to be shorter than the length of the parent chunk - - chunk_overlap Define the overlap between adjacent chunks (optional) - - - Files that need to be uploaded. - - When no parameters are set for the knowledge base, the first upload requires the following parameters to be provided; if not provided, the default parameters will be used. - - Retrieval model - - search_method (string) Search method - - hybrid_search Hybrid search - - semantic_search Semantic search - - full_text_search Full-text search - - reranking_enable (bool) Whether to enable reranking - - reranking_mode (object) Rerank model configuration - - reranking_provider_name (string) Rerank model provider - - reranking_model_name (string) Rerank model name - - top_k (int) Number of results to return - - score_threshold_enabled (bool) Whether to enable score threshold - - score_threshold (float) Score threshold - - - Embedding model name - - - Embedding model provider - - - - - - ```bash {{ title: 'cURL' }} - curl --location --request POST '${props.apiBaseUrl}/datasets/{dataset_id}/document/create-by-file' \ - --header 'Authorization: Bearer {api_key}' \ - --form 'data="{\"name\":\"Dify\",\"indexing_technique\":\"high_quality\",\"process_rule\":{\"rules\":{\"pre_processing_rules\":[{\"id\":\"remove_extra_spaces\",\"enabled\":true},{\"id\":\"remove_urls_emails\",\"enabled\":true}],\"segmentation\":{\"separator\":\"###\",\"max_tokens\":500}},\"mode\":\"custom\"}}";type=text/plain' \ - --form 'file=@"/path/to/file"' - ``` - - - ```json {{ title: 'Response' }} - { - "document": { - "id": "", - "position": 1, - "data_source_type": "upload_file", - "data_source_info": { - "upload_file_id": "" - }, - "dataset_process_rule_id": "", - "name": "Dify.txt", - "created_from": "api", - "created_by": "", - "created_at": 1695308667, - "tokens": 0, - "indexing_status": "waiting", - "error": null, - "enabled": true, - "disabled_at": null, - "disabled_by": null, - "archived": false, - "display_status": "queuing", - "word_count": 0, - "hit_count": 0, - "doc_form": "text_model" - }, - "batch": "" - } - ``` - - - - -
- - - - - ### Request Body - - - Knowledge name - - - Knowledge description (optional) - - - Index technique (optional) - If this is not set, embedding_model, embedding_model_provider and retrieval_model will be set to null - - high_quality High quality - - economy Economy - - - Permission - - only_me Only me - - all_team_members All team members - - partial_members Partial members - - - Provider (optional, default: vendor) - - vendor Vendor - - external External knowledge - - - External knowledge API ID (optional) - - - External knowledge ID (optional) - - - Embedding model name (optional) - - - Embedding model provider name (optional) - - - Retrieval model (optional) - - search_method (string) Search method - - hybrid_search Hybrid search - - semantic_search Semantic search - - full_text_search Full-text search - - reranking_enable (bool) Whether to enable reranking - - reranking_model (object) Rerank model configuration - - reranking_provider_name (string) Rerank model provider - - reranking_model_name (string) Rerank model name - - top_k (int) Number of results to return - - score_threshold_enabled (bool) Whether to enable score threshold - - score_threshold (float) Score threshold - - - - - - ```bash {{ title: 'cURL' }} - curl --location --request POST '${apiBaseUrl}/v1/datasets' \ - --header 'Authorization: Bearer {api_key}' \ - --header 'Content-Type: application/json' \ - --data-raw '{ - "name": "name", - "permission": "only_me" - }' - ``` - - - ```json {{ title: 'Response' }} - { - "id": "", - "name": "name", - "description": null, - "provider": "vendor", - "permission": "only_me", - "data_source_type": null, - "indexing_technique": null, - "app_count": 0, - "document_count": 0, - "word_count": 0, - "created_by": "", - "created_at": 1695636173, - "updated_by": "", - "updated_at": 1695636173, - "embedding_model": null, - "embedding_model_provider": null, - "embedding_available": null - } - ``` - - - - -
- - - - - ### Query - - - Search keyword, optional - - - Tag ID list, optional - - - Page number, optional, default 1 - - - Number of items returned, optional, default 20, range 1-100 - - - Whether to include all datasets (only effective for owners), optional, defaults to false - - - - - - ```bash {{ title: 'cURL' }} - curl --location --request GET '${props.apiBaseUrl}/datasets?page=1&limit=20' \ - --header 'Authorization: Bearer {api_key}' - ``` - - - ```json {{ title: 'Response' }} - { - "data": [ - { - "id": "", - "name": "name", - "description": "desc", - "permission": "only_me", - "data_source_type": "upload_file", - "indexing_technique": "", - "app_count": 2, - "document_count": 10, - "word_count": 1200, - "created_by": "", - "created_at": "", - "updated_by": "", - "updated_at": "" - }, - ... - ], - "has_more": true, - "limit": 20, - "total": 50, - "page": 1 - } - ``` - - - - -
- - - - - ### Path - - - Knowledge Base ID - - - - - - ```bash {{ title: 'cURL' }} - curl --location --request GET '${props.apiBaseUrl}/datasets/{dataset_id}' \ - --header 'Authorization: Bearer {api_key}' - ``` - - - ```json {{ title: 'Response' }} - { - "id": "eaedb485-95ac-4ffd-ab1e-18da6d676a2f", - "name": "Test Knowledge Base", - "description": "", - "provider": "vendor", - "permission": "only_me", - "data_source_type": null, - "indexing_technique": null, - "app_count": 0, - "document_count": 0, - "word_count": 0, - "created_by": "e99a1635-f725-4951-a99a-1daaaa76cfc6", - "created_at": 1735620612, - "updated_by": "e99a1635-f725-4951-a99a-1daaaa76cfc6", - "updated_at": 1735620612, - "embedding_model": null, - "embedding_model_provider": null, - "embedding_available": true, - "retrieval_model_dict": { - "search_method": "semantic_search", - "reranking_enable": false, - "reranking_mode": null, - "reranking_model": { - "reranking_provider_name": "", - "reranking_model_name": "" - }, - "weights": null, - "top_k": 2, - "score_threshold_enabled": false, - "score_threshold": null - }, - "tags": [], - "doc_form": null, - "external_knowledge_info": { - "external_knowledge_id": null, - "external_knowledge_api_id": null, - "external_knowledge_api_name": null, - "external_knowledge_api_endpoint": null - }, - "external_retrieval_model": { - "top_k": 2, - "score_threshold": 0.0, - "score_threshold_enabled": null - } - } - ``` - - - - -
- - - - - ### Path - - - Knowledge Base ID - - - Index technique (optional) - - high_quality High quality - - economy Economy - - - Permission - - only_me Only me - - all_team_members All team members - - partial_members Partial members - - - Specified embedding model provider, must be set up in the system first, corresponding to the provider field(Optional) - - - Specified embedding model, corresponding to the model field(Optional) - - - Retrieval model (optional, if not filled, it will be recalled according to the default method) - - search_method (text) Search method: One of the following four keywords is required - - keyword_search Keyword search - - semantic_search Semantic search - - full_text_search Full-text search - - hybrid_search Hybrid search - - reranking_enable (bool) Whether to enable reranking, required if the search mode is semantic_search or hybrid_search (optional) - - reranking_mode (object) Rerank model configuration, required if reranking is enabled - - reranking_provider_name (string) Rerank model provider - - reranking_model_name (string) Rerank model name - - weights (float) Semantic search weight setting in hybrid search mode - - top_k (integer) Number of results to return (optional) - - score_threshold_enabled (bool) Whether to enable score threshold - - score_threshold (float) Score threshold - - - Partial member list(Optional) - - - - - - ```bash {{ title: 'cURL' }} - curl --location --request PATCH '${props.apiBaseUrl}/datasets/{dataset_id}' \ - --header 'Authorization: Bearer {api_key}' \ - --header 'Content-Type: application/json' \ - --data-raw '{ - "name": "Test Knowledge Base", - "indexing_technique": "high_quality", - "permission": "only_me", - "embedding_model_provider": "zhipuai", - "embedding_model": "embedding-3", - "retrieval_model": { - "search_method": "keyword_search", - "reranking_enable": false, - "reranking_mode": null, - "reranking_model": { - "reranking_provider_name": "", - "reranking_model_name": "" - }, - "weights": null, - "top_k": 1, - "score_threshold_enabled": false, - "score_threshold": null - }, - "partial_member_list": [] - }' - ``` - - - ```json {{ title: 'Response' }} - { - "id": "eaedb485-95ac-4ffd-ab1e-18da6d676a2f", - "name": "Test Knowledge Base", - "description": "", - "provider": "vendor", - "permission": "only_me", - "data_source_type": null, - "indexing_technique": "high_quality", - "app_count": 0, - "document_count": 0, - "word_count": 0, - "created_by": "e99a1635-f725-4951-a99a-1daaaa76cfc6", - "created_at": 1735620612, - "updated_by": "e99a1635-f725-4951-a99a-1daaaa76cfc6", - "updated_at": 1735622679, - "embedding_model": "embedding-3", - "embedding_model_provider": "zhipuai", - "embedding_available": null, - "retrieval_model_dict": { - "search_method": "semantic_search", - "reranking_enable": false, - "reranking_mode": null, - "reranking_model": { - "reranking_provider_name": "", - "reranking_model_name": "" - }, - "weights": null, - "top_k": 2, - "score_threshold_enabled": false, - "score_threshold": null - }, - "tags": [], - "doc_form": null, - "external_knowledge_info": { - "external_knowledge_id": null, - "external_knowledge_api_id": null, - "external_knowledge_api_name": null, - "external_knowledge_api_endpoint": null - }, - "external_retrieval_model": { - "top_k": 2, - "score_threshold": 0.0, - "score_threshold_enabled": null - }, - "partial_member_list": [] - } - ``` - - - - -
- - - - - ### Path - - - Knowledge ID - - - - - - ```bash {{ title: 'cURL' }} - curl --location --request DELETE '${props.apiBaseUrl}/datasets/{dataset_id}' \ - --header 'Authorization: Bearer {api_key}' - ``` - - - ```text {{ title: 'Response' }} - 204 No Content - ``` - - - - -
- - - - - This API is based on an existing knowledge and updates the document through text based on this knowledge. - - ### Path - - - Knowledge ID - - - Document ID - - - - ### Request Body - - - Document name (optional) - - - Document content (optional) - - - Processing rules - - mode (string) Cleaning, segmentation mode, automatic / custom / hierarchical - - rules (object) Custom rules (in automatic mode, this field is empty) - - pre_processing_rules (array[object]) Preprocessing rules - - id (string) Unique identifier for the preprocessing rule - - enumerate - - remove_extra_spaces Replace consecutive spaces, newlines, tabs - - remove_urls_emails Delete URL, email address - - enabled (bool) Whether to select this rule or not. If no document ID is passed in, it represents the default value. - - segmentation (object) Segmentation rules - - separator Custom segment identifier, currently only allows one delimiter to be set. Default is \n - - max_tokens Maximum length (token) defaults to 1000 - - parent_mode Retrieval mode of parent chunks: full-doc full text retrieval / paragraph paragraph retrieval - - subchunk_segmentation (object) Child chunk rules - - separator Segmentation identifier. Currently, only one delimiter is allowed. The default is *** - - max_tokens The maximum length (tokens) must be validated to be shorter than the length of the parent chunk - - chunk_overlap Define the overlap between adjacent chunks (optional) - - - - - - ```bash {{ title: 'cURL' }} - curl --location --request POST '${props.apiBaseUrl}/datasets/{dataset_id}/documents/{document_id}/update-by-text' \ - --header 'Authorization: Bearer {api_key}' \ - --header 'Content-Type: application/json' \ - --data-raw '{ - "name": "name", - "text": "text" - }' - ``` - - - ```json {{ title: 'Response' }} - { - "document": { - "id": "", - "position": 1, - "data_source_type": "upload_file", - "data_source_info": { - "upload_file_id": "" - }, - "dataset_process_rule_id": "", - "name": "name.txt", - "created_from": "api", - "created_by": "", - "created_at": 1695308667, - "tokens": 0, - "indexing_status": "waiting", - "error": null, - "enabled": true, - "disabled_at": null, - "disabled_by": null, - "archived": false, - "display_status": "queuing", - "word_count": 0, - "hit_count": 0, - "doc_form": "text_model" - }, - "batch": "" - } - ``` - - - - -
- - - - - This API is based on an existing knowledge, and updates documents through files based on this knowledge - - ### Path - - - Knowledge ID - - - Document ID - - - - ### Request Body - - - Document name (optional) - - - Files to be uploaded - - - Processing rules - - mode (string) Cleaning, segmentation mode, automatic / custom / hierarchical - - rules (object) Custom rules (in automatic mode, this field is empty) - - pre_processing_rules (array[object]) Preprocessing rules - - id (string) Unique identifier for the preprocessing rule - - enumerate - - remove_extra_spaces Replace consecutive spaces, newlines, tabs - - remove_urls_emails Delete URL, email address - - enabled (bool) Whether to select this rule or not. If no document ID is passed in, it represents the default value. - - segmentation (object) Segmentation rules - - separator Custom segment identifier, currently only allows one delimiter to be set. Default is \n - - max_tokens Maximum length (token) defaults to 1000 - - parent_mode Retrieval mode of parent chunks: full-doc full text retrieval / paragraph paragraph retrieval - - subchunk_segmentation (object) Child chunk rules - - separator Segmentation identifier. Currently, only one delimiter is allowed. The default is *** - - max_tokens The maximum length (tokens) must be validated to be shorter than the length of the parent chunk - - chunk_overlap Define the overlap between adjacent chunks (optional) - - - - - - ```bash {{ title: 'cURL' }} - curl --location --request POST '${props.apiBaseUrl}/datasets/{dataset_id}/documents/{document_id}/update-by-file' \ - --header 'Authorization: Bearer {api_key}' \ - --form 'data="{\"name\":\"Dify\",\"indexing_technique\":\"high_quality\",\"process_rule\":{\"rules\":{\"pre_processing_rules\":[{\"id\":\"remove_extra_spaces\",\"enabled\":true},{\"id\":\"remove_urls_emails\",\"enabled\":true}],\"segmentation\":{\"separator\":\"###\",\"max_tokens\":500}},\"mode\":\"custom\"}}";type=text/plain' \ - --form 'file=@"/path/to/file"' - ``` - - - ```json {{ title: 'Response' }} - { - "document": { - "id": "", - "position": 1, - "data_source_type": "upload_file", - "data_source_info": { - "upload_file_id": "" - }, - "dataset_process_rule_id": "", - "name": "Dify.txt", - "created_from": "api", - "created_by": "", - "created_at": 1695308667, - "tokens": 0, - "indexing_status": "waiting", - "error": null, - "enabled": true, - "disabled_at": null, - "disabled_by": null, - "archived": false, - "display_status": "queuing", - "word_count": 0, - "hit_count": 0, - "doc_form": "text_model" - }, - "batch": "20230921150427533684" - } - ``` - - - - -
- - - - - ### Path - - - Knowledge ID - - - Batch number of uploaded documents - - - - - - ```bash {{ title: 'cURL' }} - curl --location --request GET '${props.apiBaseUrl}/datasets/{dataset_id}/documents/{batch}/indexing-status' \ - --header 'Authorization: Bearer {api_key}' \ - ``` - - - ```json {{ title: 'Response' }} - { - "data":[{ - "id": "", - "indexing_status": "indexing", - "processing_started_at": 1681623462.0, - "parsing_completed_at": 1681623462.0, - "cleaning_completed_at": 1681623462.0, - "splitting_completed_at": 1681623462.0, - "completed_at": null, - "paused_at": null, - "error": null, - "stopped_at": null, - "completed_segments": 24, - "total_segments": 100 - }] - } - ``` - - - - -
- - - - - ### Path - - - Knowledge ID - - - Document ID - - - - - - ```bash {{ title: 'cURL' }} - curl --location --request DELETE '${props.apiBaseUrl}/datasets/{dataset_id}/documents/{document_id}' \ - --header 'Authorization: Bearer {api_key}' \ - ``` - - - ```text {{ title: 'Response' }} - 204 No Content - ``` - - - - -
- - - - - ### Path - - - Knowledge ID - - - - ### Query - - - Search keywords, currently only search document names (optional) - - - Page number (optional) - - - Number of items returned, default 20, range 1-100 (optional) - - - - - - ```bash {{ title: 'cURL' }} - curl --location --request GET '${props.apiBaseUrl}/datasets/{dataset_id}/documents' \ - --header 'Authorization: Bearer {api_key}' \ - ``` - - - ```json {{ title: 'Response' }} - { - "data": [ - { - "id": "", - "position": 1, - "data_source_type": "file_upload", - "data_source_info": null, - "dataset_process_rule_id": null, - "name": "dify", - "created_from": "", - "created_by": "", - "created_at": 1681623639, - "tokens": 0, - "indexing_status": "waiting", - "error": null, - "enabled": true, - "disabled_at": null, - "disabled_by": null, - "archived": false - }, - ], - "has_more": false, - "limit": 20, - "total": 9, - "page": 1 - } - ``` - - - - -
- - - - - Get a document's detail. - ### Path - - `dataset_id` (string) Dataset ID - - `document_id` (string) Document ID - - ### Query - - `metadata` (string) Metadata filter, can be `all`, `only`, or `without`. Default is `all`. - - ### Response - Returns the document's detail. - - - ### Request Example - - ```bash {{ title: 'cURL' }} - curl -X GET '${props.apiBaseUrl}/datasets/{dataset_id}/documents/{document_id}' \ - -H 'Authorization: Bearer {api_key}' - ``` - - - ### Response Example - - ```json {{ title: 'Response' }} - { - "id": "f46ae30c-5c11-471b-96d0-464f5f32a7b2", - "position": 1, - "data_source_type": "upload_file", - "data_source_info": { - "upload_file": { - ... - } - }, - "dataset_process_rule_id": "24b99906-845e-499f-9e3c-d5565dd6962c", - "dataset_process_rule": { - "mode": "hierarchical", - "rules": { - "pre_processing_rules": [ - { - "id": "remove_extra_spaces", - "enabled": true - }, - { - "id": "remove_urls_emails", - "enabled": false - } - ], - "segmentation": { - "separator": "**********page_ending**********", - "max_tokens": 1024, - "chunk_overlap": 0 - }, - "parent_mode": "paragraph", - "subchunk_segmentation": { - "separator": "\n", - "max_tokens": 512, - "chunk_overlap": 0 - } - } - }, - "document_process_rule": { - "id": "24b99906-845e-499f-9e3c-d5565dd6962c", - "dataset_id": "48a0db76-d1a9-46c1-ae35-2baaa919a8a9", - "mode": "hierarchical", - "rules": { - "pre_processing_rules": [ - { - "id": "remove_extra_spaces", - "enabled": true - }, - { - "id": "remove_urls_emails", - "enabled": false - } - ], - "segmentation": { - "separator": "**********page_ending**********", - "max_tokens": 1024, - "chunk_overlap": 0 - }, - "parent_mode": "paragraph", - "subchunk_segmentation": { - "separator": "\n", - "max_tokens": 512, - "chunk_overlap": 0 - } - } - }, - "name": "xxxx", - "created_from": "web", - "created_by": "17f71940-a7b5-4c77-b60f-2bd645c1ffa0", - "created_at": 1750464191, - "tokens": null, - "indexing_status": "waiting", - "completed_at": null, - "updated_at": 1750464191, - "indexing_latency": null, - "error": null, - "enabled": true, - "disabled_at": null, - "disabled_by": null, - "archived": false, - "segment_count": 0, - "average_segment_length": 0, - "hit_count": null, - "display_status": "queuing", - "doc_form": "hierarchical_model", - "doc_language": "Chinese Simplified" - } - ``` - - - -___ -
- - - - - ### Path - - - Knowledge ID - - - - `enable` - Enable document - - `disable` - Disable document - - `archive` - Archive document - - `un_archive` - Unarchive document - - - - ### Request Body - - - List of document IDs - - - - - - ```bash {{ title: 'cURL' }} - curl --location --request PATCH '${props.apiBaseUrl}/datasets/{dataset_id}/documents/status/{action}' \ - --header 'Authorization: Bearer {api_key}' \ - --header 'Content-Type: application/json' \ - --data-raw '{ - "document_ids": ["doc-id-1", "doc-id-2"] - }' - ``` - - - - ```json {{ title: 'Response' }} - { - "result": "success" - } - ``` - - - - -
- - - - - ### Path - - - Knowledge ID - - - Document ID - - - - ### Request Body - - - - content (text) Text content / question content, required - - answer (text) Answer content, if the mode of the knowledge is Q&A mode, pass the value (optional) - - keywords (list) Keywords (optional) - - - - - - ```bash {{ title: 'cURL' }} - curl --location --request POST '${props.apiBaseUrl}/datasets/{dataset_id}/documents/{document_id}/segments' \ - --header 'Authorization: Bearer {api_key}' \ - --header 'Content-Type: application/json' \ - --data-raw '{ - "segments": [ - { - "content": "1", - "answer": "1", - "keywords": ["a"] - } - ] - }' - ``` - - - ```json {{ title: 'Response' }} - { - "data": [{ - "id": "", - "position": 1, - "document_id": "", - "content": "1", - "answer": "1", - "word_count": 25, - "tokens": 0, - "keywords": [ - "a" - ], - "index_node_id": "", - "index_node_hash": "", - "hit_count": 0, - "enabled": true, - "disabled_at": null, - "disabled_by": null, - "status": "completed", - "created_by": "", - "created_at": 1695312007, - "indexing_at": 1695312007, - "completed_at": 1695312007, - "error": null, - "stopped_at": null - }], - "doc_form": "text_model" - } - ``` - - - - -
- - - - - ### Path - - - Knowledge ID - - - Document ID - - - - ### Query - - - Keyword (optional) - - - Search status, completed - - - Page number (optional) - - - Number of items returned, default 20, range 1-100 (optional) - - - - - - ```bash {{ title: 'cURL' }} - curl --location --request GET '${props.apiBaseUrl}/datasets/{dataset_id}/documents/{document_id}/segments' \ - --header 'Authorization: Bearer {api_key}' \ - --header 'Content-Type: application/json' - ``` - - - ```json {{ title: 'Response' }} - { - "data": [{ - "id": "", - "position": 1, - "document_id": "", - "content": "1", - "answer": "1", - "word_count": 25, - "tokens": 0, - "keywords": [ - "a" - ], - "index_node_id": "", - "index_node_hash": "", - "hit_count": 0, - "enabled": true, - "disabled_at": null, - "disabled_by": null, - "status": "completed", - "created_by": "", - "created_at": 1695312007, - "indexing_at": 1695312007, - "completed_at": 1695312007, - "error": null, - "stopped_at": null - }], - "doc_form": "text_model", - "has_more": false, - "limit": 20, - "total": 9, - "page": 1 - } - ``` - - - - -
- - - - - Get details of a specific document segment in the specified knowledge base - - ### Path - - - Knowledge Base ID - - - Document ID - - - Segment ID - - - - - - ```bash {{ title: 'cURL' }} - curl --location --request GET '${props.apiBaseUrl}/datasets/{dataset_id}/documents/{document_id}/segments/{segment_id}' \ - --header 'Authorization: Bearer {api_key}' - ``` - - - ```json {{ title: 'Response' }} - { - "data": { - "id": "chunk_id", - "position": 2, - "document_id": "document_id", - "content": "Segment content text", - "sign_content": "Signature content text", - "answer": "Answer content (if in Q&A mode)", - "word_count": 470, - "tokens": 382, - "keywords": ["keyword1", "keyword2"], - "index_node_id": "index_node_id", - "index_node_hash": "index_node_hash", - "hit_count": 0, - "enabled": true, - "status": "completed", - "created_by": "creator_id", - "created_at": creation_timestamp, - "updated_at": update_timestamp, - "indexing_at": indexing_timestamp, - "completed_at": completion_timestamp, - "error": null, - "child_chunks": [] - }, - "doc_form": "text_model" - } - ``` - - - - -
- - - - - ### Path - - - Knowledge ID - - - Document ID - - - Document Segment ID - - - - - - ```bash {{ title: 'cURL' }} - curl --location --request DELETE '${props.apiBaseUrl}/datasets/{dataset_id}/documents/{document_id}/segments/{segment_id}' \ - --header 'Authorization: Bearer {api_key}' \ - --header 'Content-Type: application/json' - ``` - - - ```text {{ title: 'Response' }} - 204 No Content - ``` - - - - -
- - - - - ### POST - - - Knowledge ID - - - Document ID - - - Document Segment ID - - - - ### Request Body - - - - content (text) Text content / question content, required - - answer (text) Answer content, passed if the knowledge is in Q&A mode (optional) - - keywords (list) Keyword (optional) - - enabled (bool) False / true (optional) - - regenerate_child_chunks (bool) Whether to regenerate child chunks (optional) - - - - - - ```bash {{ title: 'cURL' }} - curl --location --request POST '${props.apiBaseUrl}/datasets/{dataset_id}/documents/{document_id}/segments/{segment_id}' \ - --header 'Content-Type: application/json' \ - --data-raw '{ - "segment": { - "content": "1", - "answer": "1", - "keywords": ["a"], - "enabled": false - } - }' - ``` - - - ```json {{ title: 'Response' }} - { - "data": { - "id": "", - "position": 1, - "document_id": "", - "content": "1", - "answer": "1", - "word_count": 25, - "tokens": 0, - "keywords": [ - "a" - ], - "index_node_id": "", - "index_node_hash": "", - "hit_count": 0, - "enabled": true, - "disabled_at": null, - "disabled_by": null, - "status": "completed", - "created_by": "", - "created_at": 1695312007, - "indexing_at": 1695312007, - "completed_at": 1695312007, - "error": null, - "stopped_at": null - }, - "doc_form": "text_model" - } - ``` - - - - -
- - - - - ### Path - - - Knowledge ID - - - Document ID - - - Segment ID - - - - ### Request Body - - - Child chunk content - - - - - - ```bash {{ title: 'cURL' }} - curl --location --request POST '${props.apiBaseUrl}/datasets/{dataset_id}/documents/{document_id}/segments/{segment_id}/child_chunks' \ - --header 'Authorization: Bearer {api_key}' \ - --header 'Content-Type: application/json' \ - --data-raw '{ - "content": "Child chunk content" - }' - ``` - - - ```json {{ title: 'Response' }} - { - "data": { - "id": "", - "segment_id": "", - "content": "Child chunk content", - "word_count": 25, - "tokens": 0, - "index_node_id": "", - "index_node_hash": "", - "status": "completed", - "created_by": "", - "created_at": 1695312007, - "indexing_at": 1695312007, - "completed_at": 1695312007, - "error": null, - "stopped_at": null - } - } - ``` - - - - -
- - - - - ### Path - - - Knowledge ID - - - Document ID - - - Segment ID - - - - ### Query - - - Search keyword (optional) - - - Page number (optional, default: 1) - - - Items per page (optional, default: 20, max: 100) - - - - - - ```bash {{ title: 'cURL' }} - curl --location --request GET '${props.apiBaseUrl}/datasets/{dataset_id}/documents/{document_id}/segments/{segment_id}/child_chunks?page=1&limit=20' \ - --header 'Authorization: Bearer {api_key}' - ``` - - - ```json {{ title: 'Response' }} - { - "data": [{ - "id": "", - "segment_id": "", - "content": "Child chunk content", - "word_count": 25, - "tokens": 0, - "index_node_id": "", - "index_node_hash": "", - "status": "completed", - "created_by": "", - "created_at": 1695312007, - "indexing_at": 1695312007, - "completed_at": 1695312007, - "error": null, - "stopped_at": null - }], - "total": 1, - "total_pages": 1, - "page": 1, - "limit": 20 - } - ``` - - - - -
- - - - - ### Path - - - Knowledge ID - - - Document ID - - - Segment ID - - - Child Chunk ID - - - - - - ```bash {{ title: 'cURL' }} - curl --location --request DELETE '${props.apiBaseUrl}/datasets/{dataset_id}/documents/{document_id}/segments/{segment_id}/child_chunks/{child_chunk_id}' \ - --header 'Authorization: Bearer {api_key}' - ``` - - - ```text {{ title: 'Response' }} - 204 No Content - ``` - - - - -
- - - - - ### Path - - - Knowledge ID - - - Document ID - - - Segment ID - - - Child Chunk ID - - - - ### Request Body - - - Child chunk content - - - - - - ```bash {{ title: 'cURL' }} - curl --location --request PATCH '${props.apiBaseUrl}/datasets/{dataset_id}/documents/{document_id}/segments/{segment_id}/child_chunks/{child_chunk_id}' \ - --header 'Authorization: Bearer {api_key}' \ - --header 'Content-Type: application/json' \ - --data-raw '{ - "content": "Updated child chunk content" - }' - ``` - - - ```json {{ title: 'Response' }} - { - "data": { - "id": "", - "segment_id": "", - "content": "Updated child chunk content", - "word_count": 25, - "tokens": 0, - "index_node_id": "", - "index_node_hash": "", - "status": "completed", - "created_by": "", - "created_at": 1695312007, - "indexing_at": 1695312007, - "completed_at": 1695312007, - "error": null, - "stopped_at": null - } - } - ``` - - - - -
- - - - - ### Path - - - Knowledge ID - - - - ### Request Body - - - Query keyword - - - Retrieval parameters (optional, if not filled, it will be recalled according to the default method) - - search_method (text) Search method: One of the following four keywords is required - - keyword_search Keyword search - - semantic_search Semantic search - - full_text_search Full-text search - - hybrid_search Hybrid search - - reranking_enable (bool) Whether to enable reranking, required if the search mode is semantic_search or hybrid_search (optional) - - reranking_mode (object) Rerank model configuration, required if reranking is enabled - - reranking_provider_name (string) Rerank model provider - - reranking_model_name (string) Rerank model name - - weights (float) Semantic search weight setting in hybrid search mode - - top_k (integer) Number of results to return (optional) - - score_threshold_enabled (bool) Whether to enable score threshold - - score_threshold (float) Score threshold - - metadata_filtering_conditions (object) Metadata filtering conditions - - logical_operator (string) Logical operator: and | or - - conditions (array[object]) Conditions list - - name (string) Metadata field name - - comparison_operator (string) Comparison operator, allowed values: - - String comparison: - - contains: Contains - - not contains: Does not contain - - start with: Starts with - - end with: Ends with - - is: Equals - - is not: Does not equal - - empty: Is empty - - not empty: Is not empty - - Numeric comparison: - - =: Equals - - : Does not equal - - >: Greater than - - < : Less than - - : Greater than or equal - - : Less than or equal - - Time comparison: - - before: Before - - after: After - - value (string|number|null) Comparison value - - - Unused field - - - - - - ```bash {{ title: 'cURL' }} - curl --location --request POST '${props.apiBaseUrl}/datasets/{dataset_id}/retrieve' \ - --header 'Authorization: Bearer {api_key}' \ - --header 'Content-Type: application/json' \ - --data-raw '{ - "query": "test", - "retrieval_model": { - "search_method": "keyword_search", - "reranking_enable": false, - "reranking_mode": null, - "reranking_model": { - "reranking_provider_name": "", - "reranking_model_name": "" - }, - "weights": null, - "top_k": 2, - "score_threshold_enabled": false, - "score_threshold": null - } - }' - ``` - - - ```json {{ title: 'Response' }} - { - "query": { - "content": "test" - }, - "records": [ - { - "segment": { - "id": "7fa6f24f-8679-48b3-bc9d-bdf28d73f218", - "position": 1, - "document_id": "a8c6c36f-9f5d-4d7a-8472-f5d7b75d71d2", - "content": "Operation guide", - "answer": null, - "word_count": 847, - "tokens": 280, - "keywords": [ - "install", - "java", - "base", - "scripts", - "jdk", - "manual", - "internal", - "opens", - "add", - "vmoptions" - ], - "index_node_id": "39dd8443-d960-45a8-bb46-7275ad7fbc8e", - "index_node_hash": "0189157697b3c6a418ccf8264a09699f25858975578f3467c76d6bfc94df1d73", - "hit_count": 0, - "enabled": true, - "disabled_at": null, - "disabled_by": null, - "status": "completed", - "created_by": "dbcb1ab5-90c8-41a7-8b78-73b235eb6f6f", - "created_at": 1728734540, - "indexing_at": 1728734552, - "completed_at": 1728734584, - "error": null, - "stopped_at": null, - "document": { - "id": "a8c6c36f-9f5d-4d7a-8472-f5d7b75d71d2", - "data_source_type": "upload_file", - "name": "readme.txt", - } - }, - "score": 3.730463140527718e-05, - "tsne_position": null - } - ] - } - ``` - - - - -
- - - - - ### Path - - - Knowledge ID - - - - ### Request Body - - - - type (string) Metadata type, required - - name (string) Metadata name, required - - - - - - ```bash {{ title: 'cURL' }} - ``` - - - ```json {{ title: 'Response' }} - { - "id": "abc", - "type": "string", - "name": "test", - } - ``` - - - - -
- - - - - ### Path - - - Knowledge ID - - - Metadata ID - - - - ### Request Body - - - - name (string) Metadata name, required - - - - - - ```bash {{ title: 'cURL' }} - ``` - - - ```json {{ title: 'Response' }} - { - "id": "abc", - "type": "string", - "name": "test", - } - ``` - - - - -
- - - - - ### Path - - - Knowledge ID - - - Metadata ID - - - - - - ```bash {{ title: 'cURL' }} - ``` - - - - -
- - - - - ### Path - - - Knowledge ID - - - disable/enable - - - - - - ```bash {{ title: 'cURL' }} - ``` - - - - -
- - - - - ### Path - - - Knowledge ID - - - - ### Request Body - - - - document_id (string) Document ID - - metadata_list (list) Metadata list - - id (string) Metadata ID - - value (string) Metadata value - - name (string) Metadata name - - - - - - ```bash {{ title: 'cURL' }} - - - -
- - - - - ### Params - - - Knowledge ID - - - - - - ```bash {{ title: 'cURL' }} - ``` - - - ```json {{ title: 'Response' }} - { - "doc_metadata": [ - { - "id": "", - "name": "name", - "type": "string", - "use_count": 0, - }, - ... - ], - "built_in_field_enabled": true - } - ``` - - - - -
- - - - - ### Query - - - - - - ```bash {{ title: 'cURL' }} - curl --location --request GET '${props.apiBaseUrl}/workspaces/current/models/model-types/text-embedding' \ - --header 'Authorization: Bearer {api_key}' \ - --header 'Content-Type: application/json' \ - ``` - - - ```json {{ title: 'Response' }} - { - "data": [ - { - "provider": "zhipuai", - "label": { - "zh_Hans": "智谱 AI", - "en_US": "ZHIPU AI" - }, - "icon_small": { - "zh_Hans": "http://127.0.0.1:5001/console/api/workspaces/current/model-providers/zhipuai/icon_small/zh_Hans", - "en_US": "http://127.0.0.1:5001/console/api/workspaces/current/model-providers/zhipuai/icon_small/en_US" - }, - "icon_large": { - "zh_Hans": "http://127.0.0.1:5001/console/api/workspaces/current/model-providers/zhipuai/icon_large/zh_Hans", - "en_US": "http://127.0.0.1:5001/console/api/workspaces/current/model-providers/zhipuai/icon_large/en_US" - }, - "status": "active", - "models": [ - { - "model": "embedding-3", - "label": { - "zh_Hans": "embedding-3", - "en_US": "embedding-3" - }, - "model_type": "text-embedding", - "features": null, - "fetch_from": "predefined-model", - "model_properties": { - "context_size": 8192 - }, - "deprecated": false, - "status": "active", - "load_balancing_enabled": false - }, - { - "model": "embedding-2", - "label": { - "zh_Hans": "embedding-2", - "en_US": "embedding-2" - }, - "model_type": "text-embedding", - "features": null, - "fetch_from": "predefined-model", - "model_properties": { - "context_size": 8192 - }, - "deprecated": false, - "status": "active", - "load_balancing_enabled": false - }, - { - "model": "text_embedding", - "label": { - "zh_Hans": "text_embedding", - "en_US": "text_embedding" - }, - "model_type": "text-embedding", - "features": null, - "fetch_from": "predefined-model", - "model_properties": { - "context_size": 512 - }, - "deprecated": false, - "status": "active", - "load_balancing_enabled": false - } - ] - } - ] - } - ``` - - - - -
-Okay, I will translate the Chinese text in your document while keeping all formatting and code content unchanged. - - - - - ### Request Body - - - (text) New tag name, required, maximum length 50 - - - - - - ```bash {{ title: 'cURL' }} - curl --location --request POST '${props.apiBaseUrl}/datasets/tags' \ - --header 'Authorization: Bearer {api_key}' \ - --header 'Content-Type: application/json' \ - --data-raw '{"name": "testtag1"}' - ``` - - - ```json {{ title: 'Response' }} - { - "id": "eddb66c2-04a1-4e3a-8cb2-75abd01e12a6", - "name": "testtag1", - "type": "knowledge", - "binding_count": 0 - } - ``` - - - - - -
- - - - - ### Request Body - - - - ```bash {{ title: 'cURL' }} - curl --location --request GET '${props.apiBaseUrl}/datasets/tags' \ - --header 'Authorization: Bearer {api_key}' \ - --header 'Content-Type: application/json' - ``` - - - ```json {{ title: 'Response' }} - [ - { - "id": "39d6934c-ed36-463d-b4a7-377fa1503dc0", - "name": "testtag1", - "type": "knowledge", - "binding_count": "0" - }, - ... - ] - ``` - - - - -
- - - - - ### Request Body - - - (text) Modified tag name, required, maximum length 50 - - - (text) Tag ID, required - - - - - - ```bash {{ title: 'cURL' }} - curl --location --request PATCH '${props.apiBaseUrl}/datasets/tags' \ - --header 'Authorization: Bearer {api_key}' \ - --header 'Content-Type: application/json' \ - --data-raw '{"name": "testtag2", "tag_id": "e1a0a3db-ee34-4e04-842a-81555d5316fd"}' - ``` - - - ```json {{ title: 'Response' }} - { - "id": "eddb66c2-04a1-4e3a-8cb2-75abd01e12a6", - "name": "tag-renamed", - "type": "knowledge", - "binding_count": 0 - } - ``` - - - - -
- - - - - - ### Request Body - - - (text) Tag ID, required - - - - - - ```bash {{ title: 'cURL' }} - curl --location --request DELETE '${props.apiBaseUrl}/datasets/tags' \ - --header 'Authorization: Bearer {api_key}' \ - --header 'Content-Type: application/json' \ - --data-raw '{"tag_id": "e1a0a3db-ee34-4e04-842a-81555d5316fd"}' - ``` - - - ```json {{ title: 'Response' }} - - {"result": "success"} - - ``` - - - - -
- - - - - ### Request Body - - - (list) List of Tag IDs, required - - - (text) Dataset ID, required - - - - - - ```bash {{ title: 'cURL' }} - curl --location --request POST '${props.apiBaseUrl}/datasets/tags/binding' \ - --header 'Authorization: Bearer {api_key}' \ - --header 'Content-Type: application/json' \ - --data-raw '{"tag_ids": ["65cc29be-d072-4e26-adf4-2f727644da29","1e5348f3-d3ff-42b8-a1b7-0a86d518001a"], "target_id": "a932ea9f-fae1-4b2c-9b65-71c56e2cacd6"}' - ``` - - - ```json {{ title: 'Response' }} - {"result": "success"} - ``` - - - - -
- - - - - ### Request Body - - - (text) Tag ID, required - - - (text) Dataset ID, required - - - - - - ```bash {{ title: 'cURL' }} - curl --location --request POST '${props.apiBaseUrl}/datasets/tags/unbinding' \ - --header 'Authorization: Bearer {api_key}' \ - --header 'Content-Type: application/json' \ - --data-raw '{"tag_id": "1e5348f3-d3ff-42b8-a1b7-0a86d518001a", "target_id": "a932ea9f-fae1-4b2c-9b65-71c56e2cacd6"}' - ``` - - - ```json {{ title: 'Response' }} - {"result": "success"} - ``` - - - - - -
- - - - - ### Path - - - (text) Dataset ID - - - - - /tags' \\\n--header 'Authorization: Bearer {api_key}' \\\n--header 'Content-Type: application/json' \\\n`} - > - ```bash {{ title: 'cURL' }} - curl --location --request POST '${props.apiBaseUrl}/datasets//tags' \ - --header 'Authorization: Bearer {api_key}' \ - --header 'Content-Type: application/json' \ - ``` - - - ```json {{ title: 'Response' }} - { - "data": - [ - {"id": "4a601f4f-f8a2-4166-ae7c-58c3b252a524", - "name": "123" - }, - ... - ], - "total": 3 - } - ``` - - - - - -
- - - - - ### Error message - - - Error code - - - - - Error status - - - - - Error message - - - - - - ```json {{ title: 'Response' }} - { - "code": "no_file_uploaded", - "message": "Please upload your file.", - "status": 400 - } - ``` - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
codestatusmessage
no_file_uploaded400Please upload your file.
too_many_files400Only one file is allowed.
file_too_large413File size exceeded.
unsupported_file_type415File type not allowed.
high_quality_dataset_only400Current operation only supports 'high-quality' datasets.
dataset_not_initialized400The dataset is still being initialized or indexing. Please wait a moment.
archived_document_immutable403The archived document is not editable.
dataset_name_duplicate409The dataset name already exists. Please modify your dataset name.
invalid_action400Invalid action.
document_already_finished400The document has been processed. Please refresh the page or go to the document details.
document_indexing400The document is being processed and cannot be edited.
invalid_metadata400The metadata content is incorrect. Please check and verify.
-
diff --git a/web/app/(commonLayout)/datasets/template/template.ja.mdx b/web/app/(commonLayout)/datasets/template/template.ja.mdx deleted file mode 100644 index de332aad87..0000000000 --- a/web/app/(commonLayout)/datasets/template/template.ja.mdx +++ /dev/null @@ -1,2545 +0,0 @@ -{/** - * @typedef Props - * @property {string} apiBaseUrl - */} - -import { CodeGroup } from '@/app/components/develop/code.tsx' -import { Row, Col, Properties, Property, Heading, SubProperty, PropertyInstruction, Paragraph } from '@/app/components/develop/md.tsx' - -# ナレッジ API - -
- ### 認証 - - Dify のサービス API は `API-Key` を使用して認証します。 - - 開発者は、`API-Key` をクライアント側で共有または保存するのではなく、バックエンドに保存することを推奨します。これにより、`API-Key` の漏洩による財産損失を防ぐことができます。 - - すべての API リクエストには、以下のように **`Authorization`** HTTP ヘッダーに `API-Key` を含める必要があります: - - - ```javascript - Authorization: Bearer {API_KEY} - - ``` - -
- -
- - - - - この API は既存のナレッジに基づいており、このナレッジを基にテキストを使用して新しいドキュメントを作成します。 - - ### パス - - - ナレッジ ID - - - - ### リクエストボディ - - - ドキュメント名 - - - ドキュメント内容 - - - インデックスモード - - high_quality 高品質: 埋め込みモデルを使用してベクトルデータベースインデックスを構築 - - economy 経済: キーワードテーブルインデックスの反転インデックスを構築 - - - インデックス化された内容の形式 - - text_model テキストドキュメントは直接埋め込まれます; `economy` モードではこの形式がデフォルト - - hierarchical_model 親子モード - - qa_model Q&A モード: 分割されたドキュメントの質問と回答ペアを生成し、質問を埋め込みます - - - Q&A モードでは、ドキュメントの言語を指定します。例: English, Chinese - - - 処理ルール - - mode (string) クリーニング、セグメンテーションモード、自動 / カスタム - - rules (object) カスタムルール (自動モードでは、このフィールドは空) - - pre_processing_rules (array[object]) 前処理ルール - - id (string) 前処理ルールの一意識別子 - - 列挙 - - remove_extra_spaces 連続するスペース、改行、タブを置換 - - remove_urls_emails URL、メールアドレスを削除 - - enabled (bool) このルールを選択するかどうか。ドキュメント ID が渡されない場合、デフォルト値を表します。 - - segmentation (object) セグメンテーションルール - - separator カスタムセグメント識別子。現在は 1 つの区切り文字のみ設定可能。デフォルトは \n - - max_tokens 最大長 (トークン) デフォルトは 1000 - - parent_mode 親チャンクの検索モード: full-doc 全文検索 / paragraph 段落検索 - - subchunk_segmentation (object) 子チャンクルール - - separator セグメンテーション識別子。現在は 1 つの区切り文字のみ許可。デフォルトは *** - - max_tokens 最大長 (トークン) は親チャンクの長さより短いことを検証する必要があります - - chunk_overlap 隣接するチャンク間の重なりを定義 (オプション) - - ナレッジベースにパラメータが設定されていない場合、最初のアップロードには以下のパラメータを提供する必要があります。提供されない場合、デフォルトパラメータが使用されます。 - - 検索モデル - - search_method (string) 検索方法 - - hybrid_search ハイブリッド検索 - - semantic_search セマンティック検索 - - full_text_search 全文検索 - - reranking_enable (bool) 再ランキングを有効にするかどうか - - reranking_mode (object) 再ランキングモデル構成 - - reranking_provider_name (string) 再ランキングモデルプロバイダー - - reranking_model_name (string) 再ランキングモデル名 - - top_k (int) 返される結果の数 - - score_threshold_enabled (bool) スコア閾値を有効にするかどうか - - score_threshold (float) スコア閾値 - - - 埋め込みモデル名 - - - 埋め込みモデルプロバイダー - - - - - - ```bash {{ title: 'cURL' }} - curl --location --request POST '${props.apiBaseUrl}/datasets/{dataset_id}/document/create-by-text' \ - --header 'Authorization: Bearer {api_key}' \ - --header 'Content-Type: application/json' \ - --data-raw '{ - "name": "text", - "text": "text", - "indexing_technique": "high_quality", - "process_rule": { - "mode": "automatic" - } - }' - ``` - - - ```json {{ title: 'Response' }} - { - "document": { - "id": "", - "position": 1, - "data_source_type": "upload_file", - "data_source_info": { - "upload_file_id": "" - }, - "dataset_process_rule_id": "", - "name": "text.txt", - "created_from": "api", - "created_by": "", - "created_at": 1695690280, - "tokens": 0, - "indexing_status": "waiting", - "error": null, - "enabled": true, - "disabled_at": null, - "disabled_by": null, - "archived": false, - "display_status": "queuing", - "word_count": 0, - "hit_count": 0, - "doc_form": "text_model" - }, - "batch": "" - } - ``` - - - - -
- - - - - この API は既存のナレッジに基づいており、このナレッジを基にファイルを使用して新しいドキュメントを作成します。 - - ### パス - - - ナレッジ ID - - - - ### リクエストボディ - - - - original_document_id 元のドキュメント ID (オプション) - - ドキュメントを再アップロードまたはクリーニングとセグメンテーション構成を変更するために使用されます。欠落している情報は元のドキュメントからコピーされます。 - - 元のドキュメントはアーカイブされたドキュメントであってはなりません。 - - original_document_id が渡された場合、更新操作が実行されます。process_rule は入力可能な項目です。入力されない場合、元のドキュメントのセグメンテーション方法がデフォルトで使用されます。 - - original_document_id が渡されない場合、新しい操作が実行され、process_rule が必要です。 - - - indexing_technique インデックスモード - - high_quality 高品質:埋め込みモデルを使用してベクトルデータベースインデックスを構築 - - economy 経済:キーワードテーブルインデックスの反転インデックスを構築 - - - doc_form インデックス化された内容の形式 - - text_model テキストドキュメントは直接埋め込まれます; `economy` モードではこの形式がデフォルト - - hierarchical_model 親子モード - - qa_model Q&A モード:分割されたドキュメントの質問と回答ペアを生成し、質問を埋め込みます - - - doc_language Q&A モードでは、ドキュメントの言語を指定します。例:English, Chinese - - - process_rule 処理ルール - - mode (string) クリーニング、セグメンテーションモード、自動 / カスタム - - rules (object) カスタムルール (自動モードでは、このフィールドは空) - - pre_processing_rules (array[object]) 前処理ルール - - id (string) 前処理ルールの一意識別子 - - 列挙 - - remove_extra_spaces 連続するスペース、改行、タブを置換 - - remove_urls_emails URL、メールアドレスを削除 - - enabled (bool) このルールを選択するかどうか。ドキュメント ID が渡されない場合、デフォルト値を表します。 - - segmentation (object) セグメンテーションルール - - separator カスタムセグメント識別子。現在は 1 つの区切り文字のみ設定可能。デフォルトは \n - - max_tokens 最大長 (トークン) デフォルトは 1000 - - parent_mode 親チャンクの検索モード:full-doc 全文検索 / paragraph 段落検索 - - subchunk_segmentation (object) 子チャンクルール - - separator セグメンテーション識別子。現在は 1 つの区切り文字のみ許可。デフォルトは *** - - max_tokens 最大長 (トークン) は親チャンクの長さより短いことを検証する必要があります - - chunk_overlap 隣接するチャンク間の重なりを定義 (オプション) - - - アップロードする必要があるファイル。 - - ナレッジベースにパラメータが設定されていない場合、最初のアップロードには以下のパラメータを提供する必要があります。提供されない場合、デフォルトパラメータが使用されます。 - - 検索モデル - - search_method (string) 検索方法 - - hybrid_search ハイブリッド検索 - - semantic_search セマンティック検索 - - full_text_search 全文検索 - - reranking_enable (bool) 再ランキングを有効にするかどうか - - reranking_mode (object) 再ランキングモデル構成 - - reranking_provider_name (string) 再ランキングモデルプロバイダー - - reranking_model_name (string) 再ランキングモデル名 - - top_k (int) 返される結果の数 - - score_threshold_enabled (bool) スコア閾値を有効にするかどうか - - score_threshold (float) スコア閾値 - - - 埋め込みモデル名 - - - 埋め込みモデルプロバイダー - - - - - - ```bash {{ title: 'cURL' }} - curl --location --request POST '${props.apiBaseUrl}/datasets/{dataset_id}/document/create-by-file' \ - --header 'Authorization: Bearer {api_key}' \ - --form 'data="{\"name\":\"Dify\",\"indexing_technique\":\"high_quality\",\"process_rule\":{\"rules\":{\"pre_processing_rules\":[{\"id\":\"remove_extra_spaces\",\"enabled\":true},{\"id\":\"remove_urls_emails\",\"enabled\":true}],\"segmentation\":{\"separator\":\"###\",\"max_tokens\":500}},\"mode\":\"custom\"}}";type=text/plain' \ - --form 'file=@"/path/to/file"' - ``` - - - ```json {{ title: 'Response' }} - { - "document": { - "id": "", - "position": 1, - "data_source_type": "upload_file", - "data_source_info": { - "upload_file_id": "" - }, - "dataset_process_rule_id": "", - "name": "Dify.txt", - "created_from": "api", - "created_by": "", - "created_at": 1695308667, - "tokens": 0, - "indexing_status": "waiting", - "error": null, - "enabled": true, - "disabled_at": null, - "disabled_by": null, - "archived": false, - "display_status": "queuing", - "word_count": 0, - "hit_count": 0, - "doc_form": "text_model" - }, - "batch": "" - } - ``` - - - - -
- - - - - ### リクエストボディ - - - ナレッジ名 - - - ナレッジの説明 (オプション) - - - インデックス技術 (オプション) - - high_quality 高品質 - - economy 経済 - - - 権限 - - only_me 自分のみ - - all_team_members すべてのチームメンバー - - partial_members 一部のメンバー - - - プロバイダー (オプション、デフォルト:vendor) - - vendor ベンダー - - external 外部ナレッジ - - - 外部ナレッジ API ID (オプション) - - - 外部ナレッジ ID (オプション) - - - 埋め込みモデル名(任意) - - - 埋め込みモデルのプロバイダ名(任意) - - - 検索モデル(任意) - - search_method (文字列) 検索方法 - - hybrid_search ハイブリッド検索 - - semantic_search セマンティック検索 - - full_text_search 全文検索 - - reranking_enable (ブール値) リランキングを有効にするかどうか - - reranking_model (オブジェクト) リランクモデルの設定 - - reranking_provider_name (文字列) リランクモデルのプロバイダ - - reranking_model_name (文字列) リランクモデル名 - - top_k (整数) 返される結果の数 - - score_threshold_enabled (ブール値) スコア閾値を有効にするかどうか - - score_threshold (浮動小数点数) スコア閾値 - - - - - - ```bash {{ title: 'cURL' }} - curl --location --request POST '${apiBaseUrl}/v1/datasets' \ - --header 'Authorization: Bearer {api_key}' \ - --header 'Content-Type: application/json' \ - --data-raw '{ - "name": "name", - "permission": "only_me" - }' - ``` - - - ```json {{ title: 'Response' }} - { - "id": "", - "name": "name", - "description": null, - "provider": "vendor", - "permission": "only_me", - "data_source_type": null, - "indexing_technique": null, - "app_count": 0, - "document_count": 0, - "word_count": 0, - "created_by": "", - "created_at": 1695636173, - "updated_by": "", - "updated_at": 1695636173, - "embedding_model": null, - "embedding_model_provider": null, - "embedding_available": null - } - ``` - - - - -
- - - - - ### クエリ - - - 検索キーワード、オプション - - - タグ ID リスト、オプション - - - ページ番号、オプション、デフォルト 1 - - - 返されるアイテム数、オプション、デフォルト 20、範囲 1-100 - - - すべてのデータセットを含めるかどうか(所有者のみ有効)、オプション、デフォルトは false - - - - - - ```bash {{ title: 'cURL' }} - curl --location --request GET '${props.apiBaseUrl}/datasets?page=1&limit=20' \ - --header 'Authorization: Bearer {api_key}' - ``` - - - ```json {{ title: 'Response' }} - { - "data": [ - { - "id": "", - "name": "name", - "description": "desc", - "permission": "only_me", - "data_source_type": "upload_file", - "indexing_technique": "", - "app_count": 2, - "document_count": 10, - "word_count": 1200, - "created_by": "", - "created_at": "", - "updated_by": "", - "updated_at": "" - }, - ... - ], - "has_more": true, - "limit": 20, - "total": 50, - "page": 1 - } - ``` - - - - -
- - - - - ### パラメータ - - - ナレッジ ID - - - - - - ```bash {{ title: 'cURL' }} - curl --location --request DELETE '${props.apiBaseUrl}/datasets/{dataset_id}' \ - --header 'Authorization: Bearer {api_key}' - ``` - - - ```text {{ title: 'レスポンス' }} - 204 No Content - ``` - - - - -
- - - - - この API は既存のナレッジに基づいており、このナレッジを基にテキストを使用してドキュメントを更新します。 - - ### パス - - - ナレッジ ID - - - ドキュメント ID - - - - ### リクエストボディ - - - ドキュメント名 (オプション) - - - ドキュメント内容 (オプション) - - - 処理ルール - - mode (string) クリーニング、セグメンテーションモード、自動 / カスタム - - rules (object) カスタムルール (自動モードでは、このフィールドは空) - - pre_processing_rules (array[object]) 前処理ルール - - id (string) 前処理ルールの一意識別子 - - 列挙 - - remove_extra_spaces 連続するスペース、改行、タブを置換 - - remove_urls_emails URL、メールアドレスを削除 - - enabled (bool) このルールを選択するかどうか。ドキュメント ID が渡されない場合、デフォルト値を表します。 - - segmentation (object) セグメンテーションルール - - separator カスタムセグメント識別子。現在は 1 つの区切り文字のみ設定可能。デフォルトは \n - - max_tokens 最大長 (トークン) デフォルトは 1000 - - parent_mode 親チャンクの検索モード: full-doc 全文検索 / paragraph 段落検索 - - subchunk_segmentation (object) 子チャンクルール - - separator セグメンテーション識別子。現在は 1 つの区切り文字のみ許可。デフォルトは *** - - max_tokens 最大長 (トークン) は親チャンクの長さより短いことを検証する必要があります - - chunk_overlap 隣接するチャンク間の重なりを定義 (オプション) - - - - - - ```bash {{ title: 'cURL' }} - curl --location --request POST '${props.apiBaseUrl}/datasets/{dataset_id}/documents/{document_id}/update-by-text' \ - --header 'Authorization: Bearer {api_key}' \ - --header 'Content-Type: application/json' \ - --data-raw '{ - "name": "name", - "text": "text" - }' - ``` - - - ```json {{ title: 'Response' }} - { - "document": { - "id": "", - "position": 1, - "data_source_type": "upload_file", - "data_source_info": { - "upload_file_id": "" - }, - "dataset_process_rule_id": "", - "name": "name.txt", - "created_from": "api", - "created_by": "", - "created_at": 1695308667, - "tokens": 0, - "indexing_status": "waiting", - "error": null, - "enabled": true, - "disabled_at": null, - "disabled_by": null, - "archived": false, - "display_status": "queuing", - "word_count": 0, - "hit_count": 0, - "doc_form": "text_model" - }, - "batch": "" - } - ``` - - - - -
- - - - - この API は既存のナレッジに基づいており、このナレッジを基にファイルを使用してドキュメントを更新します。 - - ### パス - - - ナレッジ ID - - - ドキュメント ID - - - - ### リクエストボディ - - - ドキュメント名 (オプション) - - - アップロードするファイル - - - 処理ルール - - mode (string) クリーニング、セグメンテーションモード、自動 / カスタム - - rules (object) カスタムルール (自動モードでは、このフィールドは空) - - pre_processing_rules (array[object]) 前処理ルール - - id (string) 前処理ルールの一意識別子 - - 列挙 - - remove_extra_spaces 連続するスペース、改行、タブを置換 - - remove_urls_emails URL、メールアドレスを削除 - - enabled (bool) このルールを選択するかどうか。ドキュメント ID が渡されない場合、デフォルト値を表します。 - - segmentation (object) セグメンテーションルール - - separator カスタムセグメント識別子。現在は 1 つの区切り文字のみ設定可能。デフォルトは \n - - max_tokens 最大長 (トークン) デフォルトは 1000 - - parent_mode 親チャンクの検索モード: full-doc 全文検索 / paragraph 段落検索 - - subchunk_segmentation (object) 子チャンクルール - - separator セグメンテーション識別子。現在は 1 つの区切り文字のみ許可。デフォルトは *** - - max_tokens 最大長 (トークン) は親チャンクの長さより短いことを検証する必要があります - - chunk_overlap 隣接するチャンク間の重なりを定義 (オプション) - - - - - - ```bash {{ title: 'cURL' }} - curl --location --request POST '${props.apiBaseUrl}/datasets/{dataset_id}/documents/{document_id}/update-by-file' \ - --header 'Authorization: Bearer {api_key}' \ - --form 'data="{\"name\":\"Dify\",\"indexing_technique\":\"high_quality\",\"process_rule\":{\"rules\":{\"pre_processing_rules\":[{\"id\":\"remove_extra_spaces\",\"enabled\":true},{\"id\":\"remove_urls_emails\",\"enabled\":true}],\"segmentation\":{\"separator\":\"###\",\"max_tokens\":500}},\"mode\":\"custom\"}}";type=text/plain' \ - --form 'file=@"/path/to/file"' - ``` - - - ```json {{ title: 'Response' }} - { - "document": { - "id": "", - "position": 1, - "data_source_type": "upload_file", - "data_source_info": { - "upload_file_id": "" - }, - "dataset_process_rule_id": "", - "name": "Dify.txt", - "created_from": "api", - "created_by": "", - "created_at": 1695308667, - "tokens": 0, - "indexing_status": "waiting", - "error": null, - "enabled": true, - "disabled_at": null, - "disabled_by": null, - "archived": false, - "display_status": "queuing", - "word_count": 0, - "hit_count": 0, - "doc_form": "text_model" - }, - "batch": "20230921150427533684" - } - ``` - - - - -
- - - - - ### パラメータ - - - ナレッジ ID - - - アップロードされたドキュメントのバッチ番号 - - - - - - ```bash {{ title: 'cURL' }} - curl --location --request GET '${props.apiBaseUrl}/datasets/{dataset_id}/documents/{batch}/indexing-status' \ - --header 'Authorization: Bearer {api_key}' \ - ``` - - - ```json {{ title: 'Response' }} - { - "data":[{ - "id": "", - "indexing_status": "indexing", - "processing_started_at": 1681623462.0, - "parsing_completed_at": 1681623462.0, - "cleaning_completed_at": 1681623462.0, - "splitting_completed_at": 1681623462.0, - "completed_at": null, - "paused_at": null, - "error": null, - "stopped_at": null, - "completed_segments": 24, - "total_segments": 100 - }] - } - ``` - - - - -
- - - - - ### パス - - - ナレッジ ID - - - ドキュメント ID - - - - - - ```bash {{ title: 'cURL' }} - curl --location --request DELETE '${props.apiBaseUrl}/datasets/{dataset_id}/documents/{document_id}' \ - --header 'Authorization: Bearer {api_key}' \ - ``` - - - ```text {{ title: 'レスポンス' }} - 204 No Content - ``` - - - - -
- - - - - ### パス - - - ナレッジ ID - - - - ### クエリ - - - 検索キーワード、現在はドキュメント名のみ検索 (オプション) - - - ページ番号 (オプション) - - - 返されるアイテム数、デフォルトは 20、範囲は 1-100 (オプション) - - - - - - ```bash {{ title: 'cURL' }} - curl --location --request GET '${props.apiBaseUrl}/datasets/{dataset_id}/documents' \ - --header 'Authorization: Bearer {api_key}' \ - ``` - - - ```json {{ title: 'Response' }} - { - "data": [ - { - "id": "", - "position": 1, - "data_source_type": "file_upload", - "data_source_info": null, - "dataset_process_rule_id": null, - "name": "dify", - "created_from": "", - "created_by": "", - "created_at": 1681623639, - "tokens": 0, - "indexing_status": "waiting", - "error": null, - "enabled": true, - "disabled_at": null, - "disabled_by": null, - "archived": false - }, - ], - "has_more": false, - "limit": 20, - "total": 9, - "page": 1 - } - ``` - - - - -
- - - - - ドキュメントの詳細を取得. - ### Path - - `dataset_id` (string) ナレッジベースID - - `document_id` (string) ドキュメントID - - ### Query - - `metadata` (string) metadataのフィルター条件 `all`、`only`、または`without`。デフォルトは `all`。 - - ### Response - ナレッジベースドキュメントの詳細を返す. - - - ### Request Example - - ```bash {{ title: 'cURL' }} - curl -X GET '${props.apiBaseUrl}/datasets/{dataset_id}/documents/{document_id}' \ - -H 'Authorization: Bearer {api_key}' - ``` - - - ### Response Example - - ```json {{ title: 'Response' }} - { - "id": "f46ae30c-5c11-471b-96d0-464f5f32a7b2", - "position": 1, - "data_source_type": "upload_file", - "data_source_info": { - "upload_file": { - ... - } - }, - "dataset_process_rule_id": "24b99906-845e-499f-9e3c-d5565dd6962c", - "dataset_process_rule": { - "mode": "hierarchical", - "rules": { - "pre_processing_rules": [ - { - "id": "remove_extra_spaces", - "enabled": true - }, - { - "id": "remove_urls_emails", - "enabled": false - } - ], - "segmentation": { - "separator": "**********page_ending**********", - "max_tokens": 1024, - "chunk_overlap": 0 - }, - "parent_mode": "paragraph", - "subchunk_segmentation": { - "separator": "\n", - "max_tokens": 512, - "chunk_overlap": 0 - } - } - }, - "document_process_rule": { - "id": "24b99906-845e-499f-9e3c-d5565dd6962c", - "dataset_id": "48a0db76-d1a9-46c1-ae35-2baaa919a8a9", - "mode": "hierarchical", - "rules": { - "pre_processing_rules": [ - { - "id": "remove_extra_spaces", - "enabled": true - }, - { - "id": "remove_urls_emails", - "enabled": false - } - ], - "segmentation": { - "separator": "**********page_ending**********", - "max_tokens": 1024, - "chunk_overlap": 0 - }, - "parent_mode": "paragraph", - "subchunk_segmentation": { - "separator": "\n", - "max_tokens": 512, - "chunk_overlap": 0 - } - } - }, - "name": "xxxx", - "created_from": "web", - "created_by": "17f71940-a7b5-4c77-b60f-2bd645c1ffa0", - "created_at": 1750464191, - "tokens": null, - "indexing_status": "waiting", - "completed_at": null, - "updated_at": 1750464191, - "indexing_latency": null, - "error": null, - "enabled": true, - "disabled_at": null, - "disabled_by": null, - "archived": false, - "segment_count": 0, - "average_segment_length": 0, - "hit_count": null, - "display_status": "queuing", - "doc_form": "hierarchical_model", - "doc_language": "Chinese Simplified" - } - ``` - - - -___ -
- - - - - - ### パス - - - ナレッジ ID - - - - `enable` - ドキュメントを有効化 - - `disable` - ドキュメントを無効化 - - `archive` - ドキュメントをアーカイブ - - `un_archive` - ドキュメントのアーカイブを解除 - - - - ### リクエストボディ - - - ドキュメントIDのリスト - - - - - - ```bash {{ title: 'cURL' }} - curl --location --request PATCH '${props.apiBaseUrl}/datasets/{dataset_id}/documents/status/{action}' \ - --header 'Authorization: Bearer {api_key}' \ - --header 'Content-Type: application/json' \ - --data-raw '{ - "document_ids": ["doc-id-1", "doc-id-2"] - }' - ``` - - - - ```json {{ title: 'Response' }} - { - "result": "success" - } - ``` - - - - -
- - - - - ### パス - - - ナレッジ ID - - - ドキュメント ID - - - - ### リクエストボディ - - - - content (text) テキスト内容 / 質問内容、必須 - - answer (text) 回答内容、ナレッジのモードが Q&A モードの場合に値を渡します (オプション) - - keywords (list) キーワード (オプション) - - - - - - ```bash {{ title: 'cURL' }} - curl --location --request POST '${props.apiBaseUrl}/datasets/{dataset_id}/documents/{document_id}/segments' \ - --header 'Authorization: Bearer {api_key}' \ - --header 'Content-Type: application/json' \ - --data-raw '{ - "segments": [ - { - "content": "1", - "answer": "1", - "keywords": ["a"] - } - ] - }' - ``` - - - ```json {{ title: 'Response' }} - { - "data": [{ - "id": "", - "position": 1, - "document_id": "", - "content": "1", - "answer": "1", - "word_count": 25, - "tokens": 0, - "keywords": [ - "a" - ], - "index_node_id": "", - "index_node_hash": "", - "hit_count": 0, - "enabled": true, - "disabled_at": null, - "disabled_by": null, - "status": "completed", - "created_by": "", - "created_at": 1695312007, - "indexing_at": 1695312007, - "completed_at": 1695312007, - "error": null, - "stopped_at": null - }], - "doc_form": "text_model" - } - ``` - - - - -
- - - - - ### パス - - - ナレッジ ID - - - ドキュメント ID - - - - ### クエリ - - - キーワード (オプション) - - - 検索ステータス、completed - - - ページ番号 (オプション) - - - 返されるアイテム数、デフォルトは 20、範囲は 1-100 (オプション) - - - - - - ```bash {{ title: 'cURL' }} - curl --location --request GET '${props.apiBaseUrl}/datasets/{dataset_id}/documents/{document_id}/segments' \ - --header 'Authorization: Bearer {api_key}' \ - --header 'Content-Type: application/json' - ``` - - - ```json {{ title: 'Response' }} - { - "data": [{ - "id": "", - "position": 1, - "document_id": "", - "content": "1", - "answer": "1", - "word_count": 25, - "tokens": 0, - "keywords": [ - "a" - ], - "index_node_id": "", - "index_node_hash": "", - "hit_count": 0, - "enabled": true, - "disabled_at": null, - "disabled_by": null, - "status": "completed", - "created_by": "", - "created_at": 1695312007, - "indexing_at": 1695312007, - "completed_at": 1695312007, - "error": null, - "stopped_at": null - }], - "doc_form": "text_model", - "has_more": false, - "limit": 20, - "total": 9, - "page": 1 - } - ``` - - - - -
- - - - - 指定されたナレッジベース内の特定のドキュメントセグメントの詳細を表示します - - ### パス - - - ナレッジベースID - - - ドキュメントID - - - セグメントID - - - - - - ```bash {{ title: 'cURL' }} - curl --location --request GET '${props.apiBaseUrl}/datasets/{dataset_id}/documents/{document_id}/segments/{segment_id}' \ - --header 'Authorization: Bearer {api_key}' - ``` - - - ```json {{ title: 'Response' }} - { - "data": { - "id": "セグメントID", - "position": 2, - "document_id": "ドキュメントID", - "content": "セグメント内容テキスト", - "sign_content": "署名内容テキスト", - "answer": "回答内容(Q&Aモードの場合)", - "word_count": 470, - "tokens": 382, - "keywords": ["キーワード1", "キーワード2"], - "index_node_id": "インデックスノードID", - "index_node_hash": "インデックスノードハッシュ", - "hit_count": 0, - "enabled": true, - "status": "completed", - "created_by": "作成者ID", - "created_at": 作成タイムスタンプ, - "updated_at": 更新タイムスタンプ, - "indexing_at": インデックス作成タイムスタンプ, - "completed_at": 完了タイムスタンプ, - "error": null, - "child_chunks": [] - }, - "doc_form": "text_model" - } - ``` - - - - -
- - - - - ### パス - - - ナレッジ ID - - - ドキュメント ID - - - ドキュメントセグメント ID - - - - - - ```bash {{ title: 'cURL' }} - curl --location --request DELETE '${props.apiBaseUrl}/datasets/{dataset_id}/documents/{document_id}/segments/{segment_id}' \ - --header 'Authorization: Bearer {api_key}' \ - --header 'Content-Type: application/json' - ``` - - - ```text {{ title: 'レスポンス' }} - 204 No Content - ``` - - - - -
- - - - - ### POST - - - ナレッジ ID - - - ドキュメント ID - - - ドキュメントセグメント ID - - - - ### リクエストボディ - - - - content (text) テキスト内容 / 質問内容、必須 - - answer (text) 回答内容、ナレッジが Q&A モードの場合に値を渡します (オプション) - - keywords (list) キーワード (オプション) - - enabled (bool) False / true (オプション) - - regenerate_child_chunks (bool) 子チャンクを再生成するかどうか (オプション) - - - - - - ```bash {{ title: 'cURL' }} - curl --location --request POST '${props.apiBaseUrl}/datasets/{dataset_id}/documents/{document_id}/segments/{segment_id}' \ - --header 'Content-Type: application/json' \ - --data-raw '{ - "segment": { - "content": "1", - "answer": "1", - "keywords": ["a"], - "enabled": false - } - }' - ``` - - - ```json {{ title: 'Response' }} - { - "data": { - "id": "", - "position": 1, - "document_id": "", - "content": "1", - "answer": "1", - "word_count": 25, - "tokens": 0, - "keywords": [ - "a" - ], - "index_node_id": "", - "index_node_hash": "", - "hit_count": 0, - "enabled": true, - "disabled_at": null, - "disabled_by": null, - "status": "completed", - "created_by": "", - "created_at": 1695312007, - "indexing_at": 1695312007, - "completed_at": 1695312007, - "error": null, - "stopped_at": null - }, - "doc_form": "text_model" - } - ``` - - - - -
- - - - - ### パス - - - ナレッジ ID - - - ドキュメント ID - - - セグメント ID - - - - ### リクエストボディ - - - 子チャンクの内容 - - - - - - ```bash {{ title: 'cURL' }} - curl --location --request POST '${props.apiBaseUrl}/datasets/{dataset_id}/documents/{document_id}/segments/{segment_id}/child_chunks' \ - --header 'Authorization: Bearer {api_key}' \ - --header 'Content-Type: application/json' \ - --data-raw '{ - "content": "Child chunk content" - }' - ``` - - - ```json {{ title: 'Response' }} - { - "data": { - "id": "", - "segment_id": "", - "content": "Child chunk content", - "word_count": 25, - "tokens": 0, - "index_node_id": "", - "index_node_hash": "", - "status": "completed", - "created_by": "", - "created_at": 1695312007, - "indexing_at": 1695312007, - "completed_at": 1695312007, - "error": null, - "stopped_at": null - } - } - ``` - - - - -
- - - - - ### パス - - - ナレッジ ID - - - ドキュメント ID - - - セグメント ID - - - - ### クエリ - - - 検索キーワード (オプション) - - - ページ番号 (オプション、デフォルト: 1) - - - ページあたりのアイテム数 (オプション、デフォルト: 20、最大: 100) - - - - - - ```bash {{ title: 'cURL' }} - curl --location --request GET '${props.apiBaseUrl}/datasets/{dataset_id}/documents/{document_id}/segments/{segment_id}/child_chunks?page=1&limit=20' \ - --header 'Authorization: Bearer {api_key}' - ``` - - - ```json {{ title: 'Response' }} - { - "data": [{ - "id": "", - "segment_id": "", - "content": "Child chunk content", - "word_count": 25, - "tokens": 0, - "index_node_id": "", - "index_node_hash": "", - "status": "completed", - "created_by": "", - "created_at": 1695312007, - "indexing_at": 1695312007, - "completed_at": 1695312007, - "error": null, - "stopped_at": null - }], - "total": 1, - "total_pages": 1, - "page": 1, - "limit": 20 - } - ``` - - - - -
- - - - - ### パス - - - ナレッジ ID - - - ドキュメント ID - - - セグメント ID - - - 子チャンク ID - - - - - - ```bash {{ title: 'cURL' }} - curl --location --request DELETE '${props.apiBaseUrl}/datasets/{dataset_id}/documents/{document_id}/segments/{segment_id}/child_chunks/{child_chunk_id}' \ - --header 'Authorization: Bearer {api_key}' - ``` - - - ```text {{ title: 'レスポンス' }} - 204 No Content - ``` - - - - -
- - - - - ### パス - - - ナレッジ ID - - - ドキュメント ID - - - セグメント ID - - - 子チャンク ID - - - - ### リクエストボディ - - - 子チャンクの内容 - - - - - - ```bash {{ title: 'cURL' }} - curl --location --request PATCH '${props.apiBaseUrl}/datasets/{dataset_id}/documents/{document_id}/segments/{segment_id}/child_chunks/{child_chunk_id}' \ - --header 'Authorization: Bearer {api_key}' \ - --header 'Content-Type: application/json' \ - --data-raw '{ - "content": "Updated child chunk content" - }' - ``` - - - ```json {{ title: 'Response' }} - { - "data": { - "id": "", - "segment_id": "", - "content": "Updated child chunk content", - "word_count": 25, - "tokens": 0, - "index_node_id": "", - "index_node_hash": "", - "status": "completed", - "created_by": "", - "created_at": 1695312007, - "indexing_at": 1695312007, - "completed_at": 1695312007, - "error": null, - "stopped_at": null - } - } - ``` - - - - -
- - - - - ### パス - - - ナレッジ ID - - - - ### リクエストボディ - - - クエリキーワード - - - 検索パラメータ(オプション、入力されない場合はデフォルトの方法でリコールされます) - - search_method (text) 検索方法: 以下の4つのキーワードのいずれかが必要です - - keyword_search キーワード検索 - - semantic_search セマンティック検索 - - full_text_search 全文検索 - - hybrid_search ハイブリッド検索 - - reranking_enable (bool) 再ランキングを有効にするかどうか、検索モードがsemantic_searchまたはhybrid_searchの場合に必須(オプション) - - reranking_mode (object) 再ランキングモデル構成、再ランキングが有効な場合に必須 - - reranking_provider_name (string) 再ランキングモデルプロバイダー - - reranking_model_name (string) 再ランキングモデル名 - - weights (float) ハイブリッド検索モードでのセマンティック検索の重み設定 - - top_k (integer) 返される結果の数(オプション) - - score_threshold_enabled (bool) スコア閾値を有効にするかどうか - - score_threshold (float) スコア閾値 - - metadata_filtering_conditions (object) メタデータフィルタリング条件 - - logical_operator (string) 論理演算子: and | or - - conditions (array[object]) 条件リスト - - name (string) メタデータフィールド名 - - comparison_operator (string) 比較演算子、許可される値: - - 文字列比較: - - contains: 含む - - not contains: 含まない - - start with: で始まる - - end with: で終わる - - is: 等しい - - is not: 等しくない - - empty: 空 - - not empty: 空でない - - 数値比較: - - =: 等しい - - : 等しくない - - >: より大きい - - < : より小さい - - : 以上 - - : 以下 - - 時間比較: - - before: より前 - - after: より後 - - value (string|number|null) 比較値 - - - 未使用フィールド - - - - - - ```bash {{ title: 'cURL' }} - curl --location --request POST '${props.apiBaseUrl}/datasets/{dataset_id}/retrieve' \ - --header 'Authorization: Bearer {api_key}' \ - --header 'Content-Type: application/json' \ - --data-raw '{ - "query": "test", - "retrieval_model": { - "search_method": "keyword_search", - "reranking_enable": false, - "reranking_mode": null, - "reranking_model": { - "reranking_provider_name": "", - "reranking_model_name": "" - }, - "weights": null, - "top_k": 2, - "score_threshold_enabled": false, - "score_threshold": null - } - }' - ``` - - - ```json {{ title: 'Response' }} - { - "query": { - "content": "test" - }, - "records": [ - { - "segment": { - "id": "7fa6f24f-8679-48b3-bc9d-bdf28d73f218", - "position": 1, - "document_id": "a8c6c36f-9f5d-4d7a-8472-f5d7b75d71d2", - "content": "Operation guide", - "answer": null, - "word_count": 847, - "tokens": 280, - "keywords": [ - "install", - "java", - "base", - "scripts", - "jdk", - "manual", - "internal", - "opens", - "add", - "vmoptions" - ], - "index_node_id": "39dd8443-d960-45a8-bb46-7275ad7fbc8e", - "index_node_hash": "0189157697b3c6a418ccf8264a09699f25858975578f3467c76d6bfc94df1d73", - "hit_count": 0, - "enabled": true, - "disabled_at": null, - "disabled_by": null, - "status": "completed", - "created_by": "dbcb1ab5-90c8-41a7-8b78-73b235eb6f6f", - "created_at": 1728734540, - "indexing_at": 1728734552, - "completed_at": 1728734584, - "error": null, - "stopped_at": null, - "document": { - "id": "a8c6c36f-9f5d-4d7a-8472-f5d7b75d71d2", - "data_source_type": "upload_file", - "name": "readme.txt", - } - }, - "score": 3.730463140527718e-05, - "tsne_position": null - } - ] - } - ``` - - - - -
- - - - - ### パス - - - ナレッジ ID - - - - ### リクエストボディ - - - - type (string) メタデータの種類、必須 - - name (string) メタデータの名前、必須 - - - - - - ```bash {{ title: 'cURL' }} - ``` - - - ```json {{ title: 'Response' }} - { - "id": "abc", - "type": "string", - "name": "test", - } - ``` - - - - -
- - - - - ### パス - - - ナレッジ ID - - - メタデータ ID - - - - ### リクエストボディ - - - - name (string) メタデータの名前、必須 - - - - - - ```bash {{ title: 'cURL' }} - ``` - - - ```json {{ title: 'Response' }} - { - "id": "abc", - "type": "string", - "name": "test", - } - ``` - - - - -
- - - - - ### パス - - - ナレッジ ID - - - メタデータ ID - - - - - - ```bash {{ title: 'cURL' }} - ``` - - - - -
- - - - - ### パス - - - ナレッジ ID - - - disable/enable - - - - - - ```bash {{ title: 'cURL' }} - ``` - - - - -
- - - - - ### パス - - - ナレッジ ID - - - - ### リクエストボディ - - - - document_id (string) ドキュメント ID - - metadata_list (list) メタデータリスト - - id (string) メタデータ ID - - value (string) メタデータの値 - - name (string) メタデータの名前 - - - - - - ```bash {{ title: 'cURL' }} - ``` - - - - -
- - - - - ### パス - - - ナレッジ ID - - - - - - ```bash {{ title: 'cURL' }} - ``` - - - ```json {{ title: 'Response' }} - { - "doc_metadata": [ - { - "id": "", - "name": "name", - "type": "string", - "use_count": 0, - }, - ... - ], - "built_in_field_enabled": true - } - ``` - - - - -
- - - - ### Request Body - - - (text) 新しいタグ名、必須、最大長 50 文字 - - - - - - ```bash {{ title: 'cURL' }} - curl --location --request POST '${props.apiBaseUrl}/datasets/tags' \ - --header 'Authorization: Bearer {api_key}' \ - --header 'Content-Type: application/json' \ - --data-raw '{"name": "testtag1"}' - ``` - - - ```json {{ title: 'Response' }} - { - "id": "eddb66c2-04a1-4e3a-8cb2-75abd01e12a6", - "name": "testtag1", - "type": "knowledge", - "binding_count": 0 - } - ``` - - - - - -
- - - - - ### Request Body - - - - ```bash {{ title: 'cURL' }} - curl --location --request GET '${props.apiBaseUrl}/datasets/tags' \ - --header 'Authorization: Bearer {api_key}' \ - --header 'Content-Type: application/json' - ``` - - - ```json {{ title: 'Response' }} - [ - { - "id": "39d6934c-ed36-463d-b4a7-377fa1503dc0", - "name": "testtag1", - "type": "knowledge", - "binding_count": "0" - }, - ... - ] - ``` - - - - -
- - - - - ### Request Body - - - (text) 変更後のタグ名、必須、最大長 50 文字 - - - (text) タグ ID、必須 - - - - - - ```bash {{ title: 'cURL' }} - curl --location --request PATCH '${props.apiBaseUrl}/datasets/tags' \ - --header 'Authorization: Bearer {api_key}' \ - --header 'Content-Type: application/json' \ - --data-raw '{"name": "testtag2", "tag_id": "e1a0a3db-ee34-4e04-842a-81555d5316fd"}' - ``` - - - ```json {{ title: 'Response' }} - { - "id": "eddb66c2-04a1-4e3a-8cb2-75abd01e12a6", - "name": "tag-renamed", - "type": "knowledge", - "binding_count": 0 - } - ``` - - - - -
- - - - - - ### Request Body - - - (text) タグ ID、必須 - - - - - - ```bash {{ title: 'cURL' }} - curl --location --request DELETE '${props.apiBaseUrl}/datasets/tags' \ - --header 'Authorization: Bearer {api_key}' \ - --header 'Content-Type: application/json' \ - --data-raw '{"tag_id": "e1a0a3db-ee34-4e04-842a-81555d5316fd"}' - ``` - - - ```json {{ title: 'Response' }} - - {"result": "success"} - - ``` - - - - -
- - - - - ### Request Body - - - (list) タグ ID リスト、必須 - - - (text) ナレッジベース ID、必須 - - - - - - ```bash {{ title: 'cURL' }} - curl --location --request POST '${props.apiBaseUrl}/datasets/tags/binding' \ - --header 'Authorization: Bearer {api_key}' \ - --header 'Content-Type: application/json' \ - --data-raw '{"tag_ids": ["65cc29be-d072-4e26-adf4-2f727644da29","1e5348f3-d3ff-42b8-a1b7-0a86d518001a"], "target_id": "a932ea9f-fae1-4b2c-9b65-71c56e2cacd6"}' - ``` - - - ```json {{ title: 'Response' }} - {"result": "success"} - ``` - - - - -
- - - - - ### Request Body - - - (text) タグ ID、必須 - - - (text) ナレッジベース ID、必須 - - - - - - ```bash {{ title: 'cURL' }} - curl --location --request POST '${props.apiBaseUrl}/datasets/tags/unbinding' \ - --header 'Authorization: Bearer {api_key}' \ - --header 'Content-Type: application/json' \ - --data-raw '{"tag_id": "1e5348f3-d3ff-42b8-a1b7-0a86d518001a", "target_id": "a932ea9f-fae1-4b2c-9b65-71c56e2cacd6"}' - ``` - - - ```json {{ title: 'Response' }} - {"result": "success"} - ``` - - - - - -
- - - - - ### Path - - - (text) ナレッジベース ID - - - - - /tags' \\\n--header 'Authorization: Bearer {api_key}' \\\n--header 'Content-Type: application/json' \\\n`} - > - ```bash {{ title: 'cURL' }} - curl --location --request POST '${props.apiBaseUrl}/datasets//tags' \ - --header 'Authorization: Bearer {api_key}' \ - --header 'Content-Type: application/json' \ - ``` - - - ```json {{ title: 'Response' }} - { - "data": - [ - {"id": "4a601f4f-f8a2-4166-ae7c-58c3b252a524", - "name": "123" - }, - ... - ], - "total": 3 - } - ``` - - - - - -
- - - - ### エラーメッセージ - - - エラーコード - - - - - エラーステータス - - - - - エラーメッセージ - - - - - - ```json {{ title: 'Response' }} - { - "code": "no_file_uploaded", - "message": "Please upload your file.", - "status": 400 - } - ``` - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
codestatusmessage
no_file_uploaded400Please upload your file.
too_many_files400Only one file is allowed.
file_too_large413File size exceeded.
unsupported_file_type415File type not allowed.
high_quality_dataset_only400Current operation only supports 'high-quality' datasets.
dataset_not_initialized400The dataset is still being initialized or indexing. Please wait a moment.
archived_document_immutable403The archived document is not editable.
dataset_name_duplicate409The dataset name already exists. Please modify your dataset name.
invalid_action400Invalid action.
document_already_finished400The document has been processed. Please refresh the page or go to the document details.
document_indexing400The document is being processed and cannot be edited.
invalid_metadata400The metadata content is incorrect. Please check and verify.
-
diff --git a/web/app/(commonLayout)/datasets/template/template.zh.mdx b/web/app/(commonLayout)/datasets/template/template.zh.mdx deleted file mode 100644 index 1971d9ff84..0000000000 --- a/web/app/(commonLayout)/datasets/template/template.zh.mdx +++ /dev/null @@ -1,2936 +0,0 @@ -{/** - * @typedef Props - * @property {string} apiBaseUrl - */} - -import { CodeGroup } from '@/app/components/develop/code.tsx' -import { Row, Col, Properties, Property, Heading, SubProperty, PropertyInstruction, Paragraph } from '@/app/components/develop/md.tsx' - -# 知识库 API - -
- ### 鉴权 - - Service API 使用 `API-Key` 进行鉴权。 - - 建议开发者把 `API-Key` 放在后端存储,而非分享或者放在客户端存储,以免 `API-Key` 泄露,导致财产损失。 - - 所有 API 请求都应在 **`Authorization`** HTTP Header 中包含您的 `API-Key`,如下所示: - - - ```javascript - Authorization: Bearer {API_KEY} - - ``` - -
- -
- - - - - 此接口基于已存在知识库,在此知识库的基础上通过文本创建新的文档 - - ### Path - - - 知识库 ID - - - - ### Request Body - - - 文档名称 - - - 文档内容 - - - 索引方式 - - high_quality 高质量:使用 - Embedding 模型进行嵌入,构建为向量数据库索引 - - economy 经济:使用 keyword table index 的倒排索引进行构建 - - - 索引内容的形式 - - text_model text 文档直接 embedding,经济模式默认为该模式 - - hierarchical_model parent-child 模式 - - qa_model Q&A 模式:为分片文档生成 Q&A 对,然后对问题进行 embedding - - - 在 Q&A 模式下,指定文档的语言,例如:EnglishChinese - - - 处理规则 - - mode (string) 清洗、分段模式 ,automatic 自动 / custom 自定义 / hierarchical 父子 - - rules (object) 自定义规则(自动模式下,该字段为空) - - pre_processing_rules (array[object]) 预处理规则 - - id (string) 预处理规则的唯一标识符 - - 枚举: - - remove_extra_spaces 替换连续空格、换行符、制表符 - - remove_urls_emails 删除 URL、电子邮件地址 - - enabled (bool) 是否选中该规则,不传入文档 ID 时代表默认值 - - segmentation (object) 分段规则 - - separator 自定义分段标识符,目前仅允许设置一个分隔符。默认为 \n - - max_tokens 最大长度(token)默认为 1000 - - parent_mode 父分段的召回模式 full-doc 全文召回 / paragraph 段落召回 - - subchunk_segmentation (object) 子分段规则 - - separator 分段标识符,目前仅允许设置一个分隔符。默认为 *** - - max_tokens 最大长度 (token) 需要校验小于父级的长度 - - chunk_overlap 分段重叠指的是在对数据进行分段时,段与段之间存在一定的重叠部分(选填) - - 当知识库未设置任何参数的时候,首次上传需要提供以下参数,未提供则使用默认选项: - - 检索模式 - - search_method (string) 检索方法 - - hybrid_search 混合检索 - - semantic_search 语义检索 - - full_text_search 全文检索 - - reranking_enable (bool) 是否开启rerank - - reranking_mode (String) 混合检索 - - weighted_score 权重设置 - - reranking_model Rerank 模型 - - reranking_model (object) Rerank 模型配置 - - reranking_provider_name (string) Rerank 模型的提供商 - - reranking_model_name (string) Rerank 模型的名称 - - top_k (int) 召回条数 - - score_threshold_enabled (bool)是否开启召回分数限制 - - score_threshold (float) 召回分数限制 - - - Embedding 模型名称 - - - Embedding 模型供应商 - - - - - - ```bash {{ title: 'cURL' }} - curl --location --request --request POST '${props.apiBaseUrl}/datasets/{dataset_id}/document/create-by-text' \ - --header 'Authorization: Bearer {api_key}' \ - --header 'Content-Type: application/json' \ - --data-raw '{ - "name": "text", - "text": "text", - "indexing_technique": "high_quality", - "process_rule": { - "mode": "automatic" - } - }' - ``` - - - ```json {{ title: 'Response' }} - { - "document": { - "id": "", - "position": 1, - "data_source_type": "upload_file", - "data_source_info": { - "upload_file_id": "" - }, - "dataset_process_rule_id": "", - "name": "text.txt", - "created_from": "api", - "created_by": "", - "created_at": 1695690280, - "tokens": 0, - "indexing_status": "waiting", - "error": null, - "enabled": true, - "disabled_at": null, - "disabled_by": null, - "archived": false, - "display_status": "queuing", - "word_count": 0, - "hit_count": 0, - "doc_form": "text_model" - }, - "batch": "" - } - ``` - - - - -
- - - - - 此接口基于已存在知识库,在此知识库的基础上通过文件创建新的文档 - - ### Path - - - 知识库 ID - - - - ### Request Body - - - - original_document_id 源文档 ID(选填) - - 用于重新上传文档或修改文档清洗、分段配置,缺失的信息从源文档复制 - - 源文档不可为归档的文档 - - 当传入 original_document_id 时,代表文档进行更新操作,process_rule 为可填项目,不填默认使用源文档的分段方式 - - 未传入 original_document_id 时,代表文档进行新增操作,process_rule 为必填 - - - indexing_technique 索引方式 - - high_quality 高质量:使用 embedding 模型进行嵌入,构建为向量数据库索引 - - economy 经济:使用 keyword table index 的倒排索引进行构建 - - - doc_form 索引内容的形式 - - text_model text 文档直接 embedding,经济模式默认为该模式 - - hierarchical_model parent-child 模式 - - qa_model Q&A 模式:为分片文档生成 Q&A 对,然后对问题进行 embedding - - - doc_language 在 Q&A 模式下,指定文档的语言,例如:EnglishChinese - - - process_rule 处理规则 - - mode (string) 清洗、分段模式,automatic 自动 / custom 自定义 / hierarchical 父子 - - rules (object) 自定义规则(自动模式下,该字段为空) - - pre_processing_rules (array[object]) 预处理规则 - - id (string) 预处理规则的唯一标识符 - - 枚举: - - remove_extra_spaces 替换连续空格、换行符、制表符 - - remove_urls_emails 删除 URL、电子邮件地址 - - enabled (bool) 是否选中该规则,不传入文档 ID 时代表默认值 - - segmentation (object) 分段规则 - - separator 自定义分段标识符,目前仅允许设置一个分隔符。默认为 \n - - max_tokens 最大长度(token)默认为 1000 - - parent_mode 父分段的召回模式 full-doc 全文召回 / paragraph 段落召回 - - subchunk_segmentation (object) 子分段规则 - - separator 分段标识符,目前仅允许设置一个分隔符。默认为 *** - - max_tokens 最大长度 (token) 需要校验小于父级的长度 - - chunk_overlap 分段重叠指的是在对数据进行分段时,段与段之间存在一定的重叠部分(选填) - - - 需要上传的文件。 - - 当知识库未设置任何参数的时候,首次上传需要提供以下参数,未提供则使用默认选项: - - 检索模式 - - search_method (string) 检索方法 - - hybrid_search 混合检索 - - semantic_search 语义检索 - - full_text_search 全文检索 - - reranking_enable (bool) 是否开启 rerank - - reranking_model (object) Rerank 模型配置 - - reranking_provider_name (string) Rerank 模型的提供商 - - reranking_model_name (string) Rerank 模型的名称 - - top_k (int) 召回条数 - - score_threshold_enabled (bool) 是否开启召回分数限制 - - score_threshold (float) 召回分数限制 - - - Embedding 模型名称 - - - Embedding 模型供应商 - - - - - - ```bash {{ title: 'cURL' }} - curl --location --request POST '${props.apiBaseUrl}/datasets/{dataset_id}/document/create-by-file' \ - --header 'Authorization: Bearer {api_key}' \ - --form 'data="{\"name\":\"Dify\",\"indexing_technique\":\"high_quality\",\"process_rule\":{\"rules\":{\"pre_processing_rules\":[{\"id\":\"remove_extra_spaces\",\"enabled\":true},{\"id\":\"remove_urls_emails\",\"enabled\":true}],\"segmentation\":{\"separator\":\"###\",\"max_tokens\":500}},\"mode\":\"custom\"}}";type=text/plain' \ - --form 'file=@"/path/to/file"' - ``` - - - ```json {{ title: 'Response' }} - { - "document": { - "id": "", - "position": 1, - "data_source_type": "upload_file", - "data_source_info": { - "upload_file_id": "" - }, - "dataset_process_rule_id": "", - "name": "Dify.txt", - "created_from": "api", - "created_by": "", - "created_at": 1695308667, - "tokens": 0, - "indexing_status": "waiting", - "error": null, - "enabled": true, - "disabled_at": null, - "disabled_by": null, - "archived": false, - "display_status": "queuing", - "word_count": 0, - "hit_count": 0, - "doc_form": "text_model" - }, - "batch": "" - } - ``` - - - - -
- - - - - ### Request Body - - - 知识库名称(必填) - - - 知识库描述(选填) - - - 索引模式(选填,建议填写) - - high_quality 高质量 - - economy 经济 - - - 权限(选填,默认 only_me) - - only_me 仅自己 - - all_team_members 所有团队成员 - - partial_members 部分团队成员 - - - Provider(选填,默认 vendor) - - vendor 上传文件 - - external 外部知识库 - - - 外部知识库 API_ID(选填) - - - 外部知识库 ID(选填) - - - Embedding 模型名称 - - - Embedding 模型供应商 - - - 检索模式 - - search_method (string) 检索方法 - - hybrid_search 混合检索 - - semantic_search 语义检索 - - full_text_search 全文检索 - - reranking_enable (bool) 是否开启 rerank - - reranking_model (object) Rerank 模型配置 - - reranking_provider_name (string) Rerank 模型的提供商 - - reranking_model_name (string) Rerank 模型的名称 - - top_k (int) 召回条数 - - score_threshold_enabled (bool) 是否开启召回分数限制 - - score_threshold (float) 召回分数限制 - - - - - - ```bash {{ title: 'cURL' }} - curl --location --request POST '${props.apiBaseUrl}/datasets' \ - --header 'Authorization: Bearer {api_key}' \ - --header 'Content-Type: application/json' \ - --data-raw '{ - "name": "name", - "permission": "only_me" - }' - ``` - - - ```json {{ title: 'Response' }} - { - "id": "", - "name": "name", - "description": null, - "provider": "vendor", - "permission": "only_me", - "data_source_type": null, - "indexing_technique": null, - "app_count": 0, - "document_count": 0, - "word_count": 0, - "created_by": "", - "created_at": 1695636173, - "updated_by": "", - "updated_at": 1695636173, - "embedding_model": null, - "embedding_model_provider": null, - "embedding_available": null - } - ``` - - - - -
- - - - - ### Query - - - 搜索关键词,可选 - - - 标签 ID 列表,可选 - - - 页码,可选,默认为 1 - - - 返回条数,可选,默认 20,范围 1-100 - - - 是否包含所有数据集(仅对所有者生效),可选,默认为 false - - - - - - ```bash {{ title: 'cURL' }} - curl --location --request GET '${props.apiBaseUrl}/datasets?page=1&limit=20' \ - --header 'Authorization: Bearer {api_key}' - ``` - - - ```json {{ title: 'Response' }} - { - "data": [ - { - "id": "", - "name": "知识库名称", - "description": "描述信息", - "permission": "only_me", - "data_source_type": "upload_file", - "indexing_technique": "", - "app_count": 2, - "document_count": 10, - "word_count": 1200, - "created_by": "", - "created_at": "", - "updated_by": "", - "updated_at": "" - }, - ... - ], - "has_more": true, - "limit": 20, - "total": 50, - "page": 1 - } - ``` - - - - -
- - - - - ### Path - - - 知识库 ID - - - - - - ```bash {{ title: 'cURL' }} - curl --location --request GET '${props.apiBaseUrl}/datasets/{dataset_id}' \ - --header 'Authorization: Bearer {api_key}' - ``` - - - ```json {{ title: 'Response' }} - { - "id": "eaedb485-95ac-4ffd-ab1e-18da6d676a2f", - "name": "Test Knowledge Base", - "description": "", - "provider": "vendor", - "permission": "only_me", - "data_source_type": null, - "indexing_technique": null, - "app_count": 0, - "document_count": 0, - "word_count": 0, - "created_by": "e99a1635-f725-4951-a99a-1daaaa76cfc6", - "created_at": 1735620612, - "updated_by": "e99a1635-f725-4951-a99a-1daaaa76cfc6", - "updated_at": 1735620612, - "embedding_model": null, - "embedding_model_provider": null, - "embedding_available": true, - "retrieval_model_dict": { - "search_method": "semantic_search", - "reranking_enable": false, - "reranking_mode": null, - "reranking_model": { - "reranking_provider_name": "", - "reranking_model_name": "" - }, - "weights": null, - "top_k": 2, - "score_threshold_enabled": false, - "score_threshold": null - }, - "tags": [], - "doc_form": null, - "external_knowledge_info": { - "external_knowledge_id": null, - "external_knowledge_api_id": null, - "external_knowledge_api_name": null, - "external_knowledge_api_endpoint": null - }, - "external_retrieval_model": { - "top_k": 2, - "score_threshold": 0.0, - "score_threshold_enabled": null - } - } - ``` - - - - -
- - - - - ### Path - - - 知识库 ID - - - - ### Request Body - - - 索引模式(选填,建议填写) - - high_quality 高质量 - - economy 经济 - - - 权限(选填,默认 only_me) - - only_me 仅自己 - - all_team_members 所有团队成员 - - partial_members 部分团队成员 - - - 嵌入模型提供商(选填), 必须先在系统内设定好接入的模型,对应的是provider字段 - - - 嵌入模型(选填) - - - 检索参数(选填,如不填,按照默认方式召回) - - search_method (text) 检索方法:以下四个关键字之一,必填 - - keyword_search 关键字检索 - - semantic_search 语义检索 - - full_text_search 全文检索 - - hybrid_search 混合检索 - - reranking_enable (bool) 是否启用 Reranking,非必填,如果检索模式为 semantic_search 模式或者 hybrid_search 则传值 - - reranking_mode (object) Rerank 模型配置,非必填,如果启用了 reranking 则传值 - - reranking_provider_name (string) Rerank 模型提供商 - - reranking_model_name (string) Rerank 模型名称 - - weights (float) 混合检索模式下语意检索的权重设置 - - top_k (integer) 返回结果数量,非必填 - - score_threshold_enabled (bool) 是否开启 score 阈值 - - score_threshold (float) Score 阈值 - - - 部分团队成员 ID 列表(选填) - - - - - - ```bash {{ title: 'cURL' }} - curl --location --request PATCH '${props.apiBaseUrl}/datasets/{dataset_id}' \ - --header 'Authorization: Bearer {api_key}' \ - --header 'Content-Type: application/json' \ - --data-raw '{ - "name": "Test Knowledge Base", - "indexing_technique": "high_quality", - "permission": "only_me", - "embedding_model_provider": "zhipuai", - "embedding_model": "embedding-3", - "retrieval_model": { - "search_method": "keyword_search", - "reranking_enable": false, - "reranking_mode": null, - "reranking_model": { - "reranking_provider_name": "", - "reranking_model_name": "" - }, - "weights": null, - "top_k": 1, - "score_threshold_enabled": false, - "score_threshold": null - }, - "partial_member_list": [] - }' - ``` - - - ```json {{ title: 'Response' }} - { - "id": "eaedb485-95ac-4ffd-ab1e-18da6d676a2f", - "name": "Test Knowledge Base", - "description": "", - "provider": "vendor", - "permission": "only_me", - "data_source_type": null, - "indexing_technique": "high_quality", - "app_count": 0, - "document_count": 0, - "word_count": 0, - "created_by": "e99a1635-f725-4951-a99a-1daaaa76cfc6", - "created_at": 1735620612, - "updated_by": "e99a1635-f725-4951-a99a-1daaaa76cfc6", - "updated_at": 1735622679, - "embedding_model": "embedding-3", - "embedding_model_provider": "zhipuai", - "embedding_available": null, - "retrieval_model_dict": { - "search_method": "semantic_search", - "reranking_enable": false, - "reranking_mode": null, - "reranking_model": { - "reranking_provider_name": "", - "reranking_model_name": "" - }, - "weights": null, - "top_k": 2, - "score_threshold_enabled": false, - "score_threshold": null - }, - "tags": [], - "doc_form": null, - "external_knowledge_info": { - "external_knowledge_id": null, - "external_knowledge_api_id": null, - "external_knowledge_api_name": null, - "external_knowledge_api_endpoint": null - }, - "external_retrieval_model": { - "top_k": 2, - "score_threshold": 0.0, - "score_threshold_enabled": null - }, - "partial_member_list": [] - } - ``` - - - - -
- - - - - ### Path - - - 知识库 ID - - - - - - ```bash {{ title: 'cURL' }} - curl --location --request DELETE '${props.apiBaseUrl}/datasets/{dataset_id}' \ - --header 'Authorization: Bearer {api_key}' - ``` - - - ```text {{ title: 'Response' }} - 204 No Content - ``` - - - - -
- - - - - 此接口基于已存在知识库,在此知识库的基础上通过文本更新文档 - - ### Path - - - 知识库 ID - - - 文档 ID - - - - ### Request Body - - - 文档名称(选填) - - - 文档内容(选填) - - - 处理规则(选填) - - mode (string) 清洗、分段模式 ,automatic 自动 / custom 自定义 / hierarchical 父子 - - rules (object) 自定义规则(自动模式下,该字段为空) - - pre_processing_rules (array[object]) 预处理规则 - - id (string) 预处理规则的唯一标识符 - - 枚举: - - remove_extra_spaces 替换连续空格、换行符、制表符 - - remove_urls_emails 删除 URL、电子邮件地址 - - enabled (bool) 是否选中该规则,不传入文档 ID 时代表默认值 - - segmentation (object) 分段规则 - - separator 自定义分段标识符,目前仅允许设置一个分隔符。默认为 \n - - max_tokens 最大长度(token)默认为 1000 - - parent_mode 父分段的召回模式 full-doc 全文召回 / paragraph 段落召回 - - subchunk_segmentation (object) 子分段规则 - - separator 分段标识符,目前仅允许设置一个分隔符。默认为 *** - - max_tokens 最大长度 (token) 需要校验小于父级的长度 - - chunk_overlap 分段重叠指的是在对数据进行分段时,段与段之间存在一定的重叠部分(选填) - - - - - - ```bash {{ title: 'cURL' }} - curl --location --request POST '${props.apiBaseUrl}/datasets/{dataset_id}/documents/{document_id}/update-by-text' \ - --header 'Authorization: Bearer {api_key}' \ - --header 'Content-Type: application/json' \ - --data-raw '{ - "name": "name", - "text": "text" - }' - ``` - - - ```json {{ title: 'Response' }} - { - "document": { - "id": "", - "position": 1, - "data_source_type": "upload_file", - "data_source_info": { - "upload_file_id": "" - }, - "dataset_process_rule_id": "", - "name": "name.txt", - "created_from": "api", - "created_by": "", - "created_at": 1695308667, - "tokens": 0, - "indexing_status": "waiting", - "error": null, - "enabled": true, - "disabled_at": null, - "disabled_by": null, - "archived": false, - "display_status": "queuing", - "word_count": 0, - "hit_count": 0, - "doc_form": "text_model" - }, - "batch": "" - } - ``` - - - - -
- - - - - 此接口基于已存在知识库,在此知识库的基础上通过文件更新文档的操作。 - - ### Path - - - 知识库 ID - - - 文档 ID - - - - ### Request Body - - - 文档名称(选填) - - - 需要上传的文件 - - - 处理规则(选填) - - mode (string) 清洗、分段模式 ,automatic 自动 / custom 自定义 / hierarchical 父子 - - rules (object) 自定义规则(自动模式下,该字段为空) - - pre_processing_rules (array[object]) 预处理规则 - - id (string) 预处理规则的唯一标识符 - - 枚举: - - remove_extra_spaces 替换连续空格、换行符、制表符 - - remove_urls_emails 删除 URL、电子邮件地址 - - enabled (bool) 是否选中该规则,不传入文档 ID 时代表默认值 - - segmentation (object) 分段规则 - - separator 自定义分段标识符,目前仅允许设置一个分隔符。默认为 \n - - max_tokens 最大长度(token)默认为 1000 - - parent_mode 父分段的召回模式 full-doc 全文召回 / paragraph 段落召回 - - subchunk_segmentation (object) 子分段规则 - - separator 分段标识符,目前仅允许设置一个分隔符。默认为 *** - - max_tokens 最大长度 (token) 需要校验小于父级的长度 - - chunk_overlap 分段重叠指的是在对数据进行分段时,段与段之间存在一定的重叠部分(选填) - - - - - - ```bash {{ title: 'cURL' }} - curl --location --request POST '${props.apiBaseUrl}/datasets/{dataset_id}/documents/{document_id}/update-by-file' \ - --header 'Authorization: Bearer {api_key}' \ - --form 'data="{\"name\":\"Dify\",\"indexing_technique\":\"high_quality\",\"process_rule\":{\"rules\":{\"pre_processing_rules\":[{\"id\":\"remove_extra_spaces\",\"enabled\":true},{\"id\":\"remove_urls_emails\",\"enabled\":true}],\"segmentation\":{\"separator\":\"###\",\"max_tokens\":500}},\"mode\":\"custom\"}}";type=text/plain' \ - --form 'file=@"/path/to/file"' - ``` - - - ```json {{ title: 'Response' }} - { - "document": { - "id": "", - "position": 1, - "data_source_type": "upload_file", - "data_source_info": { - "upload_file_id": "" - }, - "dataset_process_rule_id": "", - "name": "Dify.txt", - "created_from": "api", - "created_by": "", - "created_at": 1695308667, - "tokens": 0, - "indexing_status": "waiting", - "error": null, - "enabled": true, - "disabled_at": null, - "disabled_by": null, - "archived": false, - "display_status": "queuing", - "word_count": 0, - "hit_count": 0, - "doc_form": "text_model" - }, - "batch": "20230921150427533684" - } - ``` - - - - -
- - - - - ### Path - - - 知识库 ID - - - 上传文档的批次号 - - - - - - ```bash {{ title: 'cURL' }} - curl --location --request GET '${props.apiBaseUrl}/datasets/{dataset_id}/documents/{batch}/indexing-status' \ - --header 'Authorization: Bearer {api_key}' \ - ``` - - - ```json {{ title: 'Response' }} - { - "data":[{ - "id": "", - "indexing_status": "indexing", - "processing_started_at": 1681623462.0, - "parsing_completed_at": 1681623462.0, - "cleaning_completed_at": 1681623462.0, - "splitting_completed_at": 1681623462.0, - "completed_at": null, - "paused_at": null, - "error": null, - "stopped_at": null, - "completed_segments": 24, - "total_segments": 100 - }] - } - ``` - - - - -
- - - - - ### Path - - - 知识库 ID - - - 文档 ID - - - - - - ```bash {{ title: 'cURL' }} - curl --location --request DELETE '${props.apiBaseUrl}/datasets/{dataset_id}/documents/{document_id}' \ - --header 'Authorization: Bearer {api_key}' \ - ``` - - - ```text {{ title: 'Response' }} - 204 No Content - ``` - - - - -
- - - - - ### Path - - - 知识库 ID - - - - ### Query - - - 搜索关键词,可选,目前仅搜索文档名称 - - - 页码,可选 - - - 返回条数,可选,默认 20,范围 1-100 - - - - - - ```bash {{ title: 'cURL' }} - curl --location --request GET '${props.apiBaseUrl}/datasets/{dataset_id}/documents' \ - --header 'Authorization: Bearer {api_key}' \ - ``` - - - ```json {{ title: 'Response' }} - { - "data": [ - { - "id": "", - "position": 1, - "data_source_type": "file_upload", - "data_source_info": null, - "dataset_process_rule_id": null, - "name": "dify", - "created_from": "", - "created_by": "", - "created_at": 1681623639, - "tokens": 0, - "indexing_status": "waiting", - "error": null, - "enabled": true, - "disabled_at": null, - "disabled_by": null, - "archived": false - }, - ], - "has_more": false, - "limit": 20, - "total": 9, - "page": 1 - } - ``` - - - - -
- - - - - 获取文档详情. - ### Path - - `dataset_id` (string) 知识库 ID - - `document_id` (string) 文档 ID - - ### Query - - `metadata` (string) metadata 过滤条件 `all`, `only`, 或者 `without`. 默认是 `all`. - - ### Response - 返回知识库文档的详情. - - - ### Request Example - - ```bash {{ title: 'cURL' }} - curl -X GET '${props.apiBaseUrl}/datasets/{dataset_id}/documents/{document_id}' \ - -H 'Authorization: Bearer {api_key}' - ``` - - - ### Response Example - - ```json {{ title: 'Response' }} - { - "id": "f46ae30c-5c11-471b-96d0-464f5f32a7b2", - "position": 1, - "data_source_type": "upload_file", - "data_source_info": { - "upload_file": { - ... - } - }, - "dataset_process_rule_id": "24b99906-845e-499f-9e3c-d5565dd6962c", - "dataset_process_rule": { - "mode": "hierarchical", - "rules": { - "pre_processing_rules": [ - { - "id": "remove_extra_spaces", - "enabled": true - }, - { - "id": "remove_urls_emails", - "enabled": false - } - ], - "segmentation": { - "separator": "**********page_ending**********", - "max_tokens": 1024, - "chunk_overlap": 0 - }, - "parent_mode": "paragraph", - "subchunk_segmentation": { - "separator": "\n", - "max_tokens": 512, - "chunk_overlap": 0 - } - } - }, - "document_process_rule": { - "id": "24b99906-845e-499f-9e3c-d5565dd6962c", - "dataset_id": "48a0db76-d1a9-46c1-ae35-2baaa919a8a9", - "mode": "hierarchical", - "rules": { - "pre_processing_rules": [ - { - "id": "remove_extra_spaces", - "enabled": true - }, - { - "id": "remove_urls_emails", - "enabled": false - } - ], - "segmentation": { - "separator": "**********page_ending**********", - "max_tokens": 1024, - "chunk_overlap": 0 - }, - "parent_mode": "paragraph", - "subchunk_segmentation": { - "separator": "\n", - "max_tokens": 512, - "chunk_overlap": 0 - } - } - }, - "name": "xxxx", - "created_from": "web", - "created_by": "17f71940-a7b5-4c77-b60f-2bd645c1ffa0", - "created_at": 1750464191, - "tokens": null, - "indexing_status": "waiting", - "completed_at": null, - "updated_at": 1750464191, - "indexing_latency": null, - "error": null, - "enabled": true, - "disabled_at": null, - "disabled_by": null, - "archived": false, - "segment_count": 0, - "average_segment_length": 0, - "hit_count": null, - "display_status": "queuing", - "doc_form": "hierarchical_model", - "doc_language": "Chinese Simplified" - } - ``` - - - -___ -
- - - - - - ### Path - - - 知识库 ID - - - - `enable` - 启用文档 - - `disable` - 禁用文档 - - `archive` - 归档文档 - - `un_archive` - 取消归档文档 - - - - ### Request Body - - - 文档ID列表 - - - - - - ```bash {{ title: 'cURL' }} - curl --location --request PATCH '${props.apiBaseUrl}/datasets/{dataset_id}/documents/status/{action}' \ - --header 'Authorization: Bearer {api_key}' \ - --header 'Content-Type: application/json' \ - --data-raw '{ - "document_ids": ["doc-id-1", "doc-id-2"] - }' - ``` - - - - ```json {{ title: 'Response' }} - { - "result": "success" - } - ``` - - - - -
- - - - - ### Path - - - 知识库 ID - - - 文档 ID - - - - ### Request Body - - - - content (text) 文本内容/问题内容,必填 - - answer (text) 答案内容,非必填,如果知识库的模式为 Q&A 模式则传值 - - keywords (list) 关键字,非必填 - - - - - - ```bash {{ title: 'cURL' }} - curl --location --request POST '${props.apiBaseUrl}/datasets/{dataset_id}/documents/{document_id}/segments' \ - --header 'Authorization: Bearer {api_key}' \ - --header 'Content-Type: application/json' \ - --data-raw '{ - "segments": [ - { - "content": "1", - "answer": "1", - "keywords": ["a"] - } - ] - }' - ``` - - - ```json {{ title: 'Response' }} - { - "data": [{ - "id": "", - "position": 1, - "document_id": "", - "content": "1", - "answer": "1", - "word_count": 25, - "tokens": 0, - "keywords": [ - "a" - ], - "index_node_id": "", - "index_node_hash": "", - "hit_count": 0, - "enabled": true, - "disabled_at": null, - "disabled_by": null, - "status": "completed", - "created_by": "", - "created_at": 1695312007, - "indexing_at": 1695312007, - "completed_at": 1695312007, - "error": null, - "stopped_at": null - }], - "doc_form": "text_model" - } - ``` - - - - -
- - - - - ### Path - - - 知识库 ID - - - 文档 ID - - - - ### Query - - - 搜索关键词,可选 - - - 搜索状态,completed - - - 页码,可选 - - - 返回条数,可选,默认 20,范围 1-100 - - - - - - ```bash {{ title: 'cURL' }} - curl --location --request GET '${props.apiBaseUrl}/datasets/{dataset_id}/documents/{document_id}/segments' \ - --header 'Authorization: Bearer {api_key}' \ - --header 'Content-Type: application/json' - ``` - - - ```json {{ title: 'Response' }} - { - "data": [{ - "id": "", - "position": 1, - "document_id": "", - "content": "1", - "answer": "1", - "word_count": 25, - "tokens": 0, - "keywords": [ - "a" - ], - "index_node_id": "", - "index_node_hash": "", - "hit_count": 0, - "enabled": true, - "disabled_at": null, - "disabled_by": null, - "status": "completed", - "created_by": "", - "created_at": 1695312007, - "indexing_at": 1695312007, - "completed_at": 1695312007, - "error": null, - "stopped_at": null - }], - "doc_form": "text_model", - "has_more": false, - "limit": 20, - "total": 9, - "page": 1 - } - ``` - - - - -
- - - - - ### Path - - - 知识库 ID - - - 文档 ID - - - 文档分段 ID - - - - - - ```bash {{ title: 'cURL' }} - curl --location --request DELETE '${props.apiBaseUrl}/datasets/{dataset_id}/documents/{document_id}/segments/{segment_id}' \ - --header 'Authorization: Bearer {api_key}' \ - --header 'Content-Type: application/json' - ``` - - - ```text {{ title: 'Response' }} - 204 No Content - ``` - - - - -
- - - - - 查看指定知识库中特定文档的分段详情 - - ### Path - - - 知识库 ID - - - 文档 ID - - - 分段 ID - - - - - - ```bash {{ title: 'cURL' }} - curl --location --request GET '${props.apiBaseUrl}/datasets/{dataset_id}/documents/{document_id}/segments/{segment_id}' \ - --header 'Authorization: Bearer {api_key}' - ``` - - - ```json {{ title: 'Response' }} - { - "data": { - "id": "分段唯一ID", - "position": 2, - "document_id": "所属文档ID", - "content": "分段内容文本", - "sign_content": "签名内容文本", - "answer": "答案内容(如果有)", - "word_count": 470, - "tokens": 382, - "keywords": ["关键词1", "关键词2"], - "index_node_id": "索引节点ID", - "index_node_hash": "索引节点哈希值", - "hit_count": 0, - "enabled": true, - "status": "completed", - "created_by": "创建者ID", - "created_at": 创建时间戳, - "updated_at": 更新时间戳, - "indexing_at": 索引时间戳, - "completed_at": 完成时间戳, - "error": null, - "child_chunks": [] - }, - "doc_form": "text_model" - } - ``` - - - - -
- - - - - ### POST - - - 知识库 ID - - - 文档 ID - - - 文档分段 ID - - - - ### Request Body - - - - content (text) 文本内容/问题内容,必填 - - answer (text) 答案内容,非必填,如果知识库的模式为 Q&A 模式则传值 - - keywords (list) 关键字,非必填 - - enabled (bool) false/true,非必填 - - regenerate_child_chunks (bool) 是否重新生成子分段,非必填 - - - - - - ```bash {{ title: 'cURL' }} - curl --location --request POST '${props.apiBaseUrl}/datasets/{dataset_id}/documents/{document_id}/segments/{segment_id}' \ - --header 'Authorization: Bearer {api_key}' \ - --header 'Content-Type: application/json' \ - --data-raw '{ - "segment": { - "content": "1", - "answer": "1", - "keywords": ["a"], - "enabled": false - } - }' - ``` - - - ```json {{ title: 'Response' }} - { - "data": { - "id": "", - "position": 1, - "document_id": "", - "content": "1", - "answer": "1", - "word_count": 25, - "tokens": 0, - "keywords": [ - "a" - ], - "index_node_id": "", - "index_node_hash": "", - "hit_count": 0, - "enabled": true, - "disabled_at": null, - "disabled_by": null, - "status": "completed", - "created_by": "", - "created_at": 1695312007, - "indexing_at": 1695312007, - "completed_at": 1695312007, - "error": null, - "stopped_at": null - }, - "doc_form": "text_model" - } - ``` - - - - -
- - - - - ### Path - - - 知识库 ID - - - 文档 ID - - - 分段 ID - - - - ### Request Body - - - 子分段内容 - - - - - - ```bash {{ title: 'cURL' }} - curl --location --request POST '${props.apiBaseUrl}/datasets/{dataset_id}/documents/{document_id}/segments/{segment_id}/child_chunks' \ - --header 'Authorization: Bearer {api_key}' \ - --header 'Content-Type: application/json' \ - --data-raw '{ - "content": "子分段内容" - }' - ``` - - - ```json {{ title: 'Response' }} - { - "data": { - "id": "", - "segment_id": "", - "content": "子分段内容", - "word_count": 25, - "tokens": 0, - "index_node_id": "", - "index_node_hash": "", - "status": "completed", - "created_by": "", - "created_at": 1695312007, - "indexing_at": 1695312007, - "completed_at": 1695312007, - "error": null, - "stopped_at": null - } - } - ``` - - - - -
- - - - - ### Path - - - 知识库 ID - - - 文档 ID - - - 分段 ID - - - - ### Query - - - 搜索关键词(选填) - - - 页码(选填,默认1) - - - 每页数量(选填,默认20,最大100) - - - - - - ```bash {{ title: 'cURL' }} - curl --location --request GET '${props.apiBaseUrl}/datasets/{dataset_id}/documents/{document_id}/segments/{segment_id}/child_chunks?page=1&limit=20' \ - --header 'Authorization: Bearer {api_key}' - ``` - - - ```json {{ title: 'Response' }} - { - "data": [{ - "id": "", - "segment_id": "", - "content": "子分段内容", - "word_count": 25, - "tokens": 0, - "index_node_id": "", - "index_node_hash": "", - "status": "completed", - "created_by": "", - "created_at": 1695312007, - "indexing_at": 1695312007, - "completed_at": 1695312007, - "error": null, - "stopped_at": null - }], - "total": 1, - "total_pages": 1, - "page": 1, - "limit": 20 - } - ``` - - - - -
- - - - - ### Path - - - 知识库 ID - - - 文档 ID - - - 分段 ID - - - 子分段 ID - - - - - - ```bash {{ title: 'cURL' }} - curl --location --request DELETE '${props.apiBaseUrl}/datasets/{dataset_id}/documents/{document_id}/segments/{segment_id}/child_chunks/{child_chunk_id}' \ - --header 'Authorization: Bearer {api_key}' - ``` - - - ```text {{ title: 'Response' }} - 204 No Content - ``` - - - - -
- - - - ### 错误信息 - - - 返回的错误代码 - - - - - 返回的错误状态 - - - - - 返回的错误信息 - - - - - - ```json {{ title: 'Response' }} - { - "code": "no_file_uploaded", - "message": "Please upload your file.", - "status": 400 - } - ``` - - - - -
- - - - - ### Path - - - 知识库 ID - - - 文档 ID - - - 分段 ID - - - 子分段 ID - - - - ### Request Body - - - 子分段内容 - - - - - - ```bash {{ title: 'cURL' }} - curl --location --request PATCH '${props.apiBaseUrl}/datasets/{dataset_id}/documents/{document_id}/segments/{segment_id}/child_chunks/{child_chunk_id}' \ - --header 'Authorization: Bearer {api_key}' \ - --header 'Content-Type: application/json' \ - --data-raw '{ - "content": "更新的子分段内容" - }' - ``` - - - ```json {{ title: 'Response' }} - { - "data": { - "id": "", - "segment_id": "", - "content": "更新的子分段内容", - "word_count": 25, - "tokens": 0, - "index_node_id": "", - "index_node_hash": "", - "status": "completed", - "created_by": "", - "created_at": 1695312007, - "indexing_at": 1695312007, - "completed_at": 1695312007, - "error": null, - "stopped_at": null - } - } - ``` - - - - -
- - - - - ### Path - - - 知识库 ID - - - - ### Request Body - - - 检索关键词 - - - 检索参数(选填,如不填,按照默认方式召回) - - search_method (text) 检索方法:以下四个关键字之一,必填 - - keyword_search 关键字检索 - - semantic_search 语义检索 - - full_text_search 全文检索 - - hybrid_search 混合检索 - - reranking_enable (bool) 是否启用 Reranking,非必填,如果检索模式为 semantic_search 模式或者 hybrid_search 则传值 - - reranking_mode (object) Rerank 模型配置,非必填,如果启用了 reranking 则传值 - - reranking_provider_name (string) Rerank 模型提供商 - - reranking_model_name (string) Rerank 模型名称 - - weights (float) 混合检索模式下语意检索的权重设置 - - top_k (integer) 返回结果数量,非必填 - - score_threshold_enabled (bool) 是否开启 score 阈值 - - score_threshold (float) Score 阈值 - - metadata_filtering_conditions (object) 元数据过滤条件 - - logical_operator (string) 逻辑运算符: and | or - - conditions (array[object]) 条件列表 - - name (string) 元数据字段名 - - comparison_operator (string) 比较运算符,可选值: - - 字符串比较: - - contains: 包含 - - not contains: 不包含 - - start with: 以...开头 - - end with: 以...结尾 - - is: 等于 - - is not: 不等于 - - empty: 为空 - - not empty: 不为空 - - 数值比较: - - =: 等于 - - : 不等于 - - >: 大于 - - < : 小于 - - : 大于等于 - - : 小于等于 - - 时间比较: - - before: 早于 - - after: 晚于 - - value (string|number|null) 比较值 - - - 未启用字段 - - - - - - ```bash {{ title: 'cURL' }} - curl --location --request POST '${props.apiBaseUrl}/datasets/{dataset_id}/retrieve' \ - --header 'Authorization: Bearer {api_key}' \ - --header 'Content-Type: application/json' \ - --data-raw '{ - "query": "test", - "retrieval_model": { - "search_method": "keyword_search", - "reranking_enable": false, - "reranking_mode": null, - "reranking_model": { - "reranking_provider_name": "", - "reranking_model_name": "" - }, - "weights": null, - "top_k": 2, - "score_threshold_enabled": false, - "score_threshold": null - } - }' - ``` - - - ```json {{ title: 'Response' }} - { - "query": { - "content": "test" - }, - "records": [ - { - "segment": { - "id": "7fa6f24f-8679-48b3-bc9d-bdf28d73f218", - "position": 1, - "document_id": "a8c6c36f-9f5d-4d7a-8472-f5d7b75d71d2", - "content": "Operation guide", - "answer": null, - "word_count": 847, - "tokens": 280, - "keywords": [ - "install", - "java", - "base", - "scripts", - "jdk", - "manual", - "internal", - "opens", - "add", - "vmoptions" - ], - "index_node_id": "39dd8443-d960-45a8-bb46-7275ad7fbc8e", - "index_node_hash": "0189157697b3c6a418ccf8264a09699f25858975578f3467c76d6bfc94df1d73", - "hit_count": 0, - "enabled": true, - "disabled_at": null, - "disabled_by": null, - "status": "completed", - "created_by": "dbcb1ab5-90c8-41a7-8b78-73b235eb6f6f", - "created_at": 1728734540, - "indexing_at": 1728734552, - "completed_at": 1728734584, - "error": null, - "stopped_at": null, - "document": { - "id": "a8c6c36f-9f5d-4d7a-8472-f5d7b75d71d2", - "data_source_type": "upload_file", - "name": "readme.txt", - } - }, - "score": 3.730463140527718e-05, - "tsne_position": null - } - ] - } - ``` - - - - -
- - - - - ### Params - - - 知识库 ID - - - - ### Request Body - - - - type (string) 元数据类型,必填 - - name (string) 元数据名称,必填 - - - - - - ```bash {{ title: 'cURL' }} - ``` - - - ```json {{ title: 'Response' }} - { - "id": "abc", - "type": "string", - "name": "test", - } - ``` - - - - -
- - - - - ### Path - - - 知识库 ID - - - 元数据 ID - - - - ### Request Body - - - - name (string) 元数据名称,必填 - - - - - - ```bash {{ title: 'cURL' }} - ``` - - - ```json {{ title: 'Response' }} - { - "id": "abc", - "type": "string", - "name": "test", - } - ``` - - - - -
- - - - - ### Path - - - 知识库 ID - - - 元数据 ID - - - - - - ```bash {{ title: 'cURL' }} - ``` - - - - -
- - - - - ### Path - - - 知识库 ID - - - disable/enable - - - - - - ```bash {{ title: 'cURL' }} - ``` - - - - -
- - - - - ### Path - - - 知识库 ID - - - - ### Request Body - - - - document_id (string) 文档 ID - - metadata_list (list) 元数据列表 - - id (string) 元数据 ID - - value (string) 元数据值 - - name (string) 元数据名称 - - - - - - ```bash {{ title: 'cURL' }} - ``` - - - - -
- - - - - ### Path - - - 知识库 ID - - - - - - ```bash {{ title: 'cURL' }} - ``` - - - ```json {{ title: 'Response' }} - { - "doc_metadata": [ - { - "id": "", - "name": "name", - "type": "string", - "use_count": 0, - }, - ... - ], - "built_in_field_enabled": true - } - ``` - - - - -
- - - - - ### Query - - - - - - ```bash {{ title: 'cURL' }} - curl --location --request GET '${props.apiBaseUrl}/workspaces/current/models/model-types/text-embedding' \ - --header 'Authorization: Bearer {api_key}' \ - --header 'Content-Type: application/json' \ - ``` - - - ```json {{ title: 'Response' }} - { - "data": [ - { - "provider": "zhipuai", - "label": { - "zh_Hans": "智谱 AI", - "en_US": "ZHIPU AI" - }, - "icon_small": { - "zh_Hans": "http://127.0.0.1:5001/console/api/workspaces/current/model-providers/zhipuai/icon_small/zh_Hans", - "en_US": "http://127.0.0.1:5001/console/api/workspaces/current/model-providers/zhipuai/icon_small/en_US" - }, - "icon_large": { - "zh_Hans": "http://127.0.0.1:5001/console/api/workspaces/current/model-providers/zhipuai/icon_large/zh_Hans", - "en_US": "http://127.0.0.1:5001/console/api/workspaces/current/model-providers/zhipuai/icon_large/en_US" - }, - "status": "active", - "models": [ - { - "model": "embedding-3", - "label": { - "zh_Hans": "embedding-3", - "en_US": "embedding-3" - }, - "model_type": "text-embedding", - "features": null, - "fetch_from": "predefined-model", - "model_properties": { - "context_size": 8192 - }, - "deprecated": false, - "status": "active", - "load_balancing_enabled": false - }, - { - "model": "embedding-2", - "label": { - "zh_Hans": "embedding-2", - "en_US": "embedding-2" - }, - "model_type": "text-embedding", - "features": null, - "fetch_from": "predefined-model", - "model_properties": { - "context_size": 8192 - }, - "deprecated": false, - "status": "active", - "load_balancing_enabled": false - }, - { - "model": "text_embedding", - "label": { - "zh_Hans": "text_embedding", - "en_US": "text_embedding" - }, - "model_type": "text-embedding", - "features": null, - "fetch_from": "predefined-model", - "model_properties": { - "context_size": 512 - }, - "deprecated": false, - "status": "active", - "load_balancing_enabled": false - } - ] - } - ] - } - ``` - - - - -
- - - - - ### Request Body - - - (text) 新标签名称,必填,最大长度为 50 - - - - - - ```bash {{ title: 'cURL' }} - curl --location --request POST '${props.apiBaseUrl}/datasets/tags' \ - --header 'Authorization: Bearer {api_key}' \ - --header 'Content-Type: application/json' \ - --data-raw '{"name": "testtag1"}' - ``` - - - ```json {{ title: 'Response' }} - { - "id": "eddb66c2-04a1-4e3a-8cb2-75abd01e12a6", - "name": "testtag1", - "type": "knowledge", - "binding_count": 0 - } - ``` - - - - - -
- - - - - ### Request Body - - - - ```bash {{ title: 'cURL' }} - curl --location --request GET '${props.apiBaseUrl}/datasets/tags' \ - --header 'Authorization: Bearer {api_key}' \ - --header 'Content-Type: application/json' - ``` - - - ```json {{ title: 'Response' }} - [ - { - "id": "39d6934c-ed36-463d-b4a7-377fa1503dc0", - "name": "testtag1", - "type": "knowledge", - "binding_count": "0" - }, - ... - ] - ``` - - - - -
- - - - - ### Request Body - - - (text) 修改后的标签名称,必填,最大长度为 50 - - - (text) 标签 ID,必填 - - - - - - ```bash {{ title: 'cURL' }} - curl --location --request PATCH '${props.apiBaseUrl}/datasets/tags' \ - --header 'Authorization: Bearer {api_key}' \ - --header 'Content-Type: application/json' \ - --data-raw '{"name": "testtag2", "tag_id": "e1a0a3db-ee34-4e04-842a-81555d5316fd"}' - ``` - - - ```json {{ title: 'Response' }} - { - "id": "eddb66c2-04a1-4e3a-8cb2-75abd01e12a6", - "name": "tag-renamed", - "type": "knowledge", - "binding_count": 0 - } - ``` - - - - -
- - - - - - ### Request Body - - - (text) 标签 ID,必填 - - - - - - ```bash {{ title: 'cURL' }} - curl --location --request DELETE '${props.apiBaseUrl}/datasets/tags' \ - --header 'Authorization: Bearer {api_key}' \ - --header 'Content-Type: application/json' \ - --data-raw '{"tag_id": "e1a0a3db-ee34-4e04-842a-81555d5316fd"}' - ``` - - - ```json {{ title: 'Response' }} - - {"result": "success"} - - ``` - - - - -
- - - - - ### Request Body - - - (list) 标签 ID 列表,必填 - - - (text) 知识库 ID,必填 - - - - - - ```bash {{ title: 'cURL' }} - curl --location --request POST '${props.apiBaseUrl}/datasets/tags/binding' \ - --header 'Authorization: Bearer {api_key}' \ - --header 'Content-Type: application/json' \ - --data-raw '{"tag_ids": ["65cc29be-d072-4e26-adf4-2f727644da29","1e5348f3-d3ff-42b8-a1b7-0a86d518001a"], "target_id": "a932ea9f-fae1-4b2c-9b65-71c56e2cacd6"}' - ``` - - - ```json {{ title: 'Response' }} - {"result": "success"} - ``` - - - - -
- - - - - ### Request Body - - - (text) 标签 ID,必填 - - - (text) 知识库 ID,必填 - - - - - - ```bash {{ title: 'cURL' }} - curl --location --request POST '${props.apiBaseUrl}/datasets/tags/unbinding' \ - --header 'Authorization: Bearer {api_key}' \ - --header 'Content-Type: application/json' \ - --data-raw '{"tag_id": "1e5348f3-d3ff-42b8-a1b7-0a86d518001a", "target_id": "a932ea9f-fae1-4b2c-9b65-71c56e2cacd6"}' - ``` - - - ```json {{ title: 'Response' }} - {"result": "success"} - ``` - - - - - -
- - - - - ### Path - - - (text) 知识库 ID - - - - - /tags' \\\n--header 'Authorization: Bearer {api_key}' \\\n--header 'Content-Type: application/json' \\\n`} - > - ```bash {{ title: 'cURL' }} - curl --location --request POST '${props.apiBaseUrl}/datasets//tags' \ - --header 'Authorization: Bearer {api_key}' \ - --header 'Content-Type: application/json' \ - ``` - - - ```json {{ title: 'Response' }} - { - "data": - [ - {"id": "4a601f4f-f8a2-4166-ae7c-58c3b252a524", - "name": "123" - }, - ... - ], - "total": 3 - } - ``` - - - - - -
- - - - ### 错误信息 - - - 返回的错误代码 - - - - - 返回的错误状态 - - - - - 返回的错误信息 - - - - - - ```json {{ title: 'Response' }} - { - "code": "no_file_uploaded", - "message": "Please upload your file.", - "status": 400 - } - ``` - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
codestatusmessage
no_file_uploaded400Please upload your file.
too_many_files400Only one file is allowed.
file_too_large413File size exceeded.
unsupported_file_type415File type not allowed.
high_quality_dataset_only400Current operation only supports 'high-quality' datasets.
dataset_not_initialized400The dataset is still being initialized or indexing. Please wait a moment.
archived_document_immutable403The archived document is not editable.
dataset_name_duplicate409The dataset name already exists. Please modify your dataset name.
invalid_action400Invalid action.
document_already_finished400The document has been processed. Please refresh the page or go to the document details.
document_indexing400The document is being processed and cannot be edited.
invalid_metadata400The metadata content is incorrect. Please check and verify.
-
diff --git a/web/app/components/app-sidebar/app-info.tsx b/web/app/components/app-sidebar/app-info.tsx index dc13d59f2b..d22577c9ad 100644 --- a/web/app/components/app-sidebar/app-info.tsx +++ b/web/app/components/app-sidebar/app-info.tsx @@ -144,9 +144,11 @@ const AppInfo = ({ expand, onlyShowDetail = false, openState = false, onDetailEx }) const a = document.createElement('a') const file = new Blob([data], { type: 'application/yaml' }) - a.href = URL.createObjectURL(file) + const url = URL.createObjectURL(file) + a.href = url a.download = `${appDetail.name}.yml` a.click() + URL.revokeObjectURL(url) } catch { notify({ type: 'error', message: t('app.exportFailed') }) @@ -313,7 +315,7 @@ const AppInfo = ({ expand, onlyShowDetail = false, openState = false, onDetailEx
- - - -type Props = { - isExternal?: boolean - name: string - description: string - expand: boolean - extraInfo?: React.ReactNode -} - -const DatasetInfo: FC = ({ - name, - description, - isExternal, - expand, - extraInfo, -}) => { - const { t } = useTranslation() - return ( -
-
- -
-
-
- {name} -
-
{isExternal ? t('dataset.externalTag') : t('dataset.localDocs')}
-
{description}
-
- {extraInfo} -
- ) -} -export default React.memo(DatasetInfo) diff --git a/web/app/components/app-sidebar/dataset-info/dropdown.tsx b/web/app/components/app-sidebar/dataset-info/dropdown.tsx new file mode 100644 index 0000000000..ff110f70bd --- /dev/null +++ b/web/app/components/app-sidebar/dataset-info/dropdown.tsx @@ -0,0 +1,152 @@ +import React, { useCallback, useState } from 'react' +import { PortalToFollowElem, PortalToFollowElemContent, PortalToFollowElemTrigger } from '../../base/portal-to-follow-elem' +import ActionButton from '../../base/action-button' +import { RiMoreFill } from '@remixicon/react' +import cn from '@/utils/classnames' +import Menu from './menu' +import { useSelector as useAppContextWithSelector } from '@/context/app-context' +import { useDatasetDetailContextWithSelector } from '@/context/dataset-detail' +import type { DataSet } from '@/models/datasets' +import { datasetDetailQueryKeyPrefix, useInvalidDatasetList } from '@/service/knowledge/use-dataset' +import { useInvalid } from '@/service/use-base' +import { useExportPipelineDSL } from '@/service/use-pipeline' +import Toast from '../../base/toast' +import { useTranslation } from 'react-i18next' +import RenameDatasetModal from '../../datasets/rename-modal' +import { checkIsUsedInApp, deleteDataset } from '@/service/datasets' +import Confirm from '../../base/confirm' +import { useRouter } from 'next/navigation' + +type DropDownProps = { + expand: boolean +} + +const DropDown = ({ + expand, +}: DropDownProps) => { + const { t } = useTranslation() + const { replace } = useRouter() + const [open, setOpen] = useState(false) + const [showRenameModal, setShowRenameModal] = useState(false) + const [confirmMessage, setConfirmMessage] = useState('') + const [showConfirmDelete, setShowConfirmDelete] = useState(false) + + const isCurrentWorkspaceDatasetOperator = useAppContextWithSelector(state => state.isCurrentWorkspaceDatasetOperator) + const dataset = useDatasetDetailContextWithSelector(state => state.dataset) as DataSet + + const handleTrigger = useCallback(() => { + setOpen(prev => !prev) + }, []) + + const invalidDatasetList = useInvalidDatasetList() + const invalidDatasetDetail = useInvalid([...datasetDetailQueryKeyPrefix, dataset.id]) + + const refreshDataset = useCallback(() => { + invalidDatasetList() + invalidDatasetDetail() + }, [invalidDatasetDetail, invalidDatasetList]) + + const openRenameModal = useCallback(() => { + setShowRenameModal(true) + handleTrigger() + }, [handleTrigger]) + + const { mutateAsync: exportPipelineConfig } = useExportPipelineDSL() + + const handleExportPipeline = useCallback(async (include = false) => { + const { pipeline_id, name } = dataset + if (!pipeline_id) + return + handleTrigger() + try { + const { data } = await exportPipelineConfig({ + pipelineId: pipeline_id, + include, + }) + const a = document.createElement('a') + const file = new Blob([data], { type: 'application/yaml' }) + const url = URL.createObjectURL(file) + a.href = url + a.download = `${name}.pipeline` + a.click() + URL.revokeObjectURL(url) + } + catch { + Toast.notify({ type: 'error', message: t('app.exportFailed') }) + } + }, [dataset, exportPipelineConfig, handleTrigger, t]) + + const detectIsUsedByApp = useCallback(async () => { + try { + const { is_using: isUsedByApp } = await checkIsUsedInApp(dataset.id) + setConfirmMessage(isUsedByApp ? t('dataset.datasetUsedByApp')! : t('dataset.deleteDatasetConfirmContent')!) + setShowConfirmDelete(true) + } + catch (e: any) { + const res = await e.json() + Toast.notify({ type: 'error', message: res?.message || 'Unknown error' }) + } + finally { + handleTrigger() + } + }, [dataset.id, handleTrigger, t]) + + const onConfirmDelete = useCallback(async () => { + try { + await deleteDataset(dataset.id) + Toast.notify({ type: 'success', message: t('dataset.datasetDeleted') }) + invalidDatasetList() + replace('/datasets') + } + finally { + setShowConfirmDelete(false) + } + }, [dataset.id, replace, invalidDatasetList, t]) + + return ( + + + + + + + + + + {showRenameModal && ( + setShowRenameModal(false)} + onSuccess={refreshDataset} + /> + )} + {showConfirmDelete && ( + setShowConfirmDelete(false)} + /> + )} + + ) +} + +export default React.memo(DropDown) diff --git a/web/app/components/app-sidebar/dataset-info/index.tsx b/web/app/components/app-sidebar/dataset-info/index.tsx new file mode 100644 index 0000000000..44b0baa72b --- /dev/null +++ b/web/app/components/app-sidebar/dataset-info/index.tsx @@ -0,0 +1,91 @@ +'use client' +import type { FC } from 'react' +import React, { useMemo } from 'react' +import { useTranslation } from 'react-i18next' +import AppIcon from '../../base/app-icon' +import Effect from '../../base/effect' +import { useDatasetDetailContextWithSelector } from '@/context/dataset-detail' +import type { DataSet } from '@/models/datasets' +import { DOC_FORM_TEXT } from '@/models/datasets' +import { useKnowledge } from '@/hooks/use-knowledge' +import cn from '@/utils/classnames' +import Dropdown from './dropdown' + +type DatasetInfoProps = { + expand: boolean +} + +const DatasetInfo: FC = ({ + expand, +}) => { + const { t } = useTranslation() + const dataset = useDatasetDetailContextWithSelector(state => state.dataset) as DataSet + const iconInfo = dataset.icon_info || { + icon: '📙', + icon_type: 'emoji', + icon_background: '#FFF4ED', + icon_url: '', + } + const isExternalProvider = dataset.provider === 'external' + const isPipelinePublished = useMemo(() => { + return dataset.runtime_mode === 'rag_pipeline' && dataset.is_published + }, [dataset.runtime_mode, dataset.is_published]) + const { formatIndexingTechniqueAndMethod } = useKnowledge() + + return ( +
+ {expand && ( + + )} + +
+
+
+ +
+ {expand && ( +
+ +
+ )} +
+ {!expand && ( +
+ +
+ )} + {expand && ( +
+
+ {dataset.name} +
+
+ {isExternalProvider && t('dataset.externalTag')} + {!isExternalProvider && isPipelinePublished && dataset.doc_form && dataset.indexing_technique && ( +
+ {t(`dataset.chunkingMode.${DOC_FORM_TEXT[dataset.doc_form]}`)} + {formatIndexingTechniqueAndMethod(dataset.indexing_technique, dataset.retrieval_model_dict?.search_method)} +
+ )} +
+ {!!dataset.description && ( +

+ {dataset.description} +

+ )} +
+ )} +
+
+ ) +} +export default React.memo(DatasetInfo) diff --git a/web/app/components/app-sidebar/dataset-info/menu-item.tsx b/web/app/components/app-sidebar/dataset-info/menu-item.tsx new file mode 100644 index 0000000000..47645bc134 --- /dev/null +++ b/web/app/components/app-sidebar/dataset-info/menu-item.tsx @@ -0,0 +1,30 @@ +import React from 'react' +import type { RemixiconComponentType } from '@remixicon/react' + +type MenuItemProps = { + name: string + Icon: RemixiconComponentType + handleClick?: () => void +} + +const MenuItem = ({ + Icon, + name, + handleClick, +}: MenuItemProps) => { + return ( +
{ + e.preventDefault() + e.stopPropagation() + handleClick?.() + }} + > + + {name} +
+ ) +} + +export default React.memo(MenuItem) diff --git a/web/app/components/app-sidebar/dataset-info/menu.tsx b/web/app/components/app-sidebar/dataset-info/menu.tsx new file mode 100644 index 0000000000..fd560ce643 --- /dev/null +++ b/web/app/components/app-sidebar/dataset-info/menu.tsx @@ -0,0 +1,52 @@ +import React from 'react' +import { useTranslation } from 'react-i18next' +import MenuItem from './menu-item' +import { RiDeleteBinLine, RiEditLine, RiFileDownloadLine } from '@remixicon/react' +import Divider from '../../base/divider' + +type MenuProps = { + showDelete: boolean + openRenameModal: () => void + handleExportPipeline: () => void + detectIsUsedByApp: () => void +} + +const Menu = ({ + showDelete, + openRenameModal, + handleExportPipeline, + detectIsUsedByApp, +}: MenuProps) => { + const { t } = useTranslation() + + return ( +
+
+ + +
+ {showDelete && ( + <> + +
+ +
+ + )} +
+ ) +} + +export default React.memo(Menu) diff --git a/web/app/components/app-sidebar/dataset-sidebar-dropdown.tsx b/web/app/components/app-sidebar/dataset-sidebar-dropdown.tsx new file mode 100644 index 0000000000..ac07333712 --- /dev/null +++ b/web/app/components/app-sidebar/dataset-sidebar-dropdown.tsx @@ -0,0 +1,164 @@ +import React, { useCallback, useRef, useState } from 'react' +import { + RiMenuLine, +} from '@remixicon/react' +import { + PortalToFollowElem, + PortalToFollowElemContent, + PortalToFollowElemTrigger, +} from '@/app/components/base/portal-to-follow-elem' +import AppIcon from '../base/app-icon' +import Divider from '../base/divider' +import NavLink from './navLink' +import type { NavIcon } from './navLink' +import cn from '@/utils/classnames' +import { useDatasetDetailContextWithSelector } from '@/context/dataset-detail' +import Effect from '../base/effect' +import Dropdown from './dataset-info/dropdown' +import type { DataSet } from '@/models/datasets' +import { DOC_FORM_TEXT } from '@/models/datasets' +import { useKnowledge } from '@/hooks/use-knowledge' +import { useTranslation } from 'react-i18next' +import { useDatasetRelatedApps } from '@/service/knowledge/use-dataset' +import ExtraInfo from '../datasets/extra-info' + +type DatasetSidebarDropdownProps = { + navigation: Array<{ + name: string + href: string + icon: NavIcon + selectedIcon: NavIcon + disabled?: boolean + }> +} + +const DatasetSidebarDropdown = ({ + navigation, +}: DatasetSidebarDropdownProps) => { + const { t } = useTranslation() + const dataset = useDatasetDetailContextWithSelector(state => state.dataset) as DataSet + + const { data: relatedApps } = useDatasetRelatedApps(dataset.id) + + const [open, doSetOpen] = useState(false) + const openRef = useRef(open) + const setOpen = useCallback((v: boolean) => { + doSetOpen(v) + openRef.current = v + }, [doSetOpen]) + const handleTrigger = useCallback(() => { + setOpen(!openRef.current) + }, [setOpen]) + + const iconInfo = dataset.icon_info || { + icon: '📙', + icon_type: 'emoji', + icon_background: '#FFF4ED', + icon_url: '', + } + const isExternalProvider = dataset.provider === 'external' + const { formatIndexingTechniqueAndMethod } = useKnowledge() + + if (!dataset) + return null + + return ( + <> +
+ + +
+ + +
+
+ +
+ +
+
+ + +
+
+
+ {dataset.name} +
+
+ {isExternalProvider && t('dataset.externalTag')} + {!isExternalProvider && dataset.doc_form && dataset.indexing_technique && ( +
+ {t(`dataset.chunkingMode.${DOC_FORM_TEXT[dataset.doc_form]}`)} + {formatIndexingTechniqueAndMethod(dataset.indexing_technique, dataset.retrieval_model_dict?.search_method)} +
+ )} +
+
+ {!!dataset.description && ( +

+ {dataset.description} +

+ )} +
+
+ +
+ + +
+
+
+
+ + ) +} + +export default DatasetSidebarDropdown diff --git a/web/app/components/app-sidebar/index.tsx b/web/app/components/app-sidebar/index.tsx index c60aa26f5d..86de2e2034 100644 --- a/web/app/components/app-sidebar/index.tsx +++ b/web/app/components/app-sidebar/index.tsx @@ -1,10 +1,8 @@ -import React, { useEffect, useState } from 'react' +import React, { useCallback, useEffect, useState } from 'react' import { usePathname } from 'next/navigation' import { useShallow } from 'zustand/react/shallow' -import { RiLayoutLeft2Line, RiLayoutRight2Line } from '@remixicon/react' import NavLink from './navLink' import type { NavIcon } from './navLink' -import AppBasic from './basic' import AppInfo from './app-info' import DatasetInfo from './dataset-info' import AppSidebarDropdown from './app-sidebar-dropdown' @@ -12,39 +10,48 @@ import useBreakpoints, { MediaType } from '@/hooks/use-breakpoints' import { useStore as useAppStore } from '@/app/components/app/store' import { useEventEmitterContextContext } from '@/context/event-emitter' import cn from '@/utils/classnames' +import Divider from '../base/divider' +import { useHover, useKeyPress } from 'ahooks' +import ToggleButton from './toggle-button' +import { getKeyboardKeyCodeBySystem } from '../workflow/utils' +import DatasetSidebarDropdown from './dataset-sidebar-dropdown' export type IAppDetailNavProps = { - iconType?: 'app' | 'dataset' | 'notion' - title: string - desc: string - isExternal?: boolean - icon: string - icon_background: string | null + iconType?: 'app' | 'dataset' navigation: Array<{ name: string href: string icon: NavIcon selectedIcon: NavIcon + disabled?: boolean }> extraInfo?: (modeState: string) => React.ReactNode } -const AppDetailNav = ({ title, desc, isExternal, icon, icon_background, navigation, extraInfo, iconType = 'app' }: IAppDetailNavProps) => { - const { appSidebarExpand, setAppSiderbarExpand } = useAppStore(useShallow(state => ({ +const AppDetailNav = ({ + navigation, + extraInfo, + iconType = 'app', +}: IAppDetailNavProps) => { + const { appSidebarExpand, setAppSidebarExpand } = useAppStore(useShallow(state => ({ appSidebarExpand: state.appSidebarExpand, - setAppSiderbarExpand: state.setAppSiderbarExpand, + setAppSidebarExpand: state.setAppSidebarExpand, }))) + const sidebarRef = React.useRef(null) const media = useBreakpoints() const isMobile = media === MediaType.mobile const expand = appSidebarExpand === 'expand' - const handleToggle = (state: string) => { - setAppSiderbarExpand(state === 'expand' ? 'collapse' : 'expand') - } + const handleToggle = useCallback(() => { + setAppSidebarExpand(appSidebarExpand === 'expand' ? 'collapse' : 'expand') + }, [appSidebarExpand, setAppSidebarExpand]) - // // Check if the current path is a workflow canvas & fullscreen + const isHoveringSidebar = useHover(sidebarRef) + + // Check if the current path is a workflow canvas & fullscreen const pathname = usePathname() const inWorkflowCanvas = pathname.endsWith('/workflow') + const isPipelineCanvas = pathname.endsWith('/pipeline') const workflowCanvasMaximize = localStorage.getItem('workflow-canvas-maximize') === 'true' const [hideHeader, setHideHeader] = useState(workflowCanvasMaximize) const { eventEmitter } = useEventEmitterContextContext() @@ -57,9 +64,14 @@ const AppDetailNav = ({ title, desc, isExternal, icon, icon_background, navigati useEffect(() => { if (appSidebarExpand) { localStorage.setItem('app-detail-collapse-or-expand', appSidebarExpand) - setAppSiderbarExpand(appSidebarExpand) + setAppSidebarExpand(appSidebarExpand) } - }, [appSidebarExpand, setAppSiderbarExpand]) + }, [appSidebarExpand, setAppSidebarExpand]) + + useKeyPress(`${getKeyboardKeyCodeBySystem('ctrl')}.b`, (e) => { + e.preventDefault() + handleToggle() + }, { exactMatch: true, useCapture: true }) if (inWorkflowCanvas && hideHeader) { return ( @@ -69,76 +81,74 @@ const AppDetailNav = ({ title, desc, isExternal, icon, icon_background, navigati ) } + if (isPipelineCanvas && hideHeader) { + return ( +
+ +
+ ) + } + return (
{iconType === 'app' && ( )} - {iconType === 'dataset' && ( - - )} - {!['app', 'dataset'].includes(iconType) && ( - + {iconType !== 'app' && ( + )}
-
-
+
+ + {!isMobile && isHoveringSidebar && ( + + )}
- { - !isMobile && ( -
-
handleToggle(appSidebarExpand)} - > - { - expand - ? - : - } -
-
- ) - } + {iconType !== 'app' && extraInfo && extraInfo(appSidebarExpand)}
) } diff --git a/web/app/components/app-sidebar/navLink.spec.tsx b/web/app/components/app-sidebar/navLink.spec.tsx index 6f26c44269..51f62e669b 100644 --- a/web/app/components/app-sidebar/navLink.spec.tsx +++ b/web/app/components/app-sidebar/navLink.spec.tsx @@ -25,7 +25,7 @@ const MockIcon = ({ className }: { className?: string }) => ( ) -describe('NavLink Text Animation Issues', () => { +describe('NavLink Animation and Layout Issues', () => { const mockProps: NavLinkProps = { name: 'Orchestrate', href: '/app/123/workflow', @@ -61,108 +61,129 @@ describe('NavLink Text Animation Issues', () => { const textElement = screen.getByText('Orchestrate') expect(textElement).toBeInTheDocument() expect(textElement).toHaveClass('opacity-0') - expect(textElement).toHaveClass('w-0') + expect(textElement).toHaveClass('max-w-0') expect(textElement).toHaveClass('overflow-hidden') // Icon should still be present expect(screen.getByTestId('nav-icon')).toBeInTheDocument() - // Check padding in collapse mode + // Check consistent padding in collapse mode const linkElement = screen.getByTestId('nav-link') - expect(linkElement).toHaveClass('px-2.5') + expect(linkElement).toHaveClass('pl-3') + expect(linkElement).toHaveClass('pr-1') - // Switch to expand mode - this is where the squeeze effect occurs + // Switch to expand mode - should have smooth text transition rerender() - // Text should now appear + // Text should now be visible with opacity animation expect(screen.getByText('Orchestrate')).toBeInTheDocument() - // Check padding change - this contributes to the squeeze effect - expect(linkElement).toHaveClass('px-3') + // Check padding remains consistent - no layout shift + expect(linkElement).toHaveClass('pl-3') + expect(linkElement).toHaveClass('pr-1') - // The bug: text appears abruptly without smooth transition - // This test documents the current behavior that causes the squeeze effect + // Fixed: text now uses max-width animation instead of abrupt show/hide const expandedTextElement = screen.getByText('Orchestrate') expect(expandedTextElement).toBeInTheDocument() + expect(expandedTextElement).toHaveClass('max-w-none') + expect(expandedTextElement).toHaveClass('opacity-100') - // In a properly animated version, we would expect: + // The fix provides: // - Opacity transition from 0 to 1 - // - Width transition from 0 to auto - // - No layout shift from padding changes + // - Max-width transition from 0 to none (prevents squashing) + // - No layout shift from consistent padding }) - it('should maintain icon position consistency during text appearance', () => { + it('should maintain icon position consistency using wrapper div', () => { const { rerender } = render() const iconElement = screen.getByTestId('nav-icon') - const initialIconClasses = iconElement.className + const iconWrapper = iconElement.parentElement - // Icon should have mr-0 in collapse mode - expect(iconElement).toHaveClass('mr-0') + // Icon wrapper should have -ml-1 micro-adjustment in collapse mode for centering + expect(iconWrapper).toHaveClass('-ml-1') rerender() - const expandedIconClasses = iconElement.className + // In expand mode, wrapper should not have the micro-adjustment + const expandedIconWrapper = screen.getByTestId('nav-icon').parentElement + expect(expandedIconWrapper).not.toHaveClass('-ml-1') - // Icon should have mr-2 in expand mode - this shift contributes to the squeeze effect - expect(iconElement).toHaveClass('mr-2') + // Icon itself maintains consistent classes - no margin changes + expect(iconElement).toHaveClass('h-4') + expect(iconElement).toHaveClass('w-4') + expect(iconElement).toHaveClass('shrink-0') - console.log('Collapsed icon classes:', initialIconClasses) - console.log('Expanded icon classes:', expandedIconClasses) - - // This margin change causes the icon to shift when text appears + // This wrapper approach eliminates the icon margin shift issue }) - it('should document the abrupt text rendering issue', () => { + it('should provide smooth text transition with max-width animation', () => { const { rerender } = render() - // Text is present in DOM but hidden via CSS classes + // Text is always in DOM but controlled via CSS classes const collapsedText = screen.getByText('Orchestrate') expect(collapsedText).toBeInTheDocument() expect(collapsedText).toHaveClass('opacity-0') - expect(collapsedText).toHaveClass('pointer-events-none') + expect(collapsedText).toHaveClass('max-w-0') + expect(collapsedText).toHaveClass('overflow-hidden') rerender() - // Text suddenly appears in DOM - no transition - expect(screen.getByText('Orchestrate')).toBeInTheDocument() + // Text smoothly transitions to visible state + const expandedText = screen.getByText('Orchestrate') + expect(expandedText).toBeInTheDocument() + expect(expandedText).toHaveClass('opacity-100') + expect(expandedText).toHaveClass('max-w-none') - // The issue: {mode === 'expand' && name} causes abrupt show/hide - // instead of smooth opacity/width transition + // Fixed: Always present in DOM with smooth CSS transitions + // instead of abrupt conditional rendering }) }) - describe('Layout Shift Issues', () => { - it('should detect padding differences causing layout shifts', () => { + describe('Layout Consistency Improvements', () => { + it('should maintain consistent padding across all states', () => { const { rerender } = render() const linkElement = screen.getByTestId('nav-link') - // Collapsed state padding - expect(linkElement).toHaveClass('px-2.5') + // Consistent padding in collapsed state + expect(linkElement).toHaveClass('pl-3') + expect(linkElement).toHaveClass('pr-1') rerender() - // Expanded state padding - different value causes layout shift - expect(linkElement).toHaveClass('px-3') + // Same padding in expanded state - no layout shift + expect(linkElement).toHaveClass('pl-3') + expect(linkElement).toHaveClass('pr-1') - // This 2px difference (10px vs 12px) contributes to the squeeze effect + // This consistency eliminates the layout shift issue }) - it('should detect icon margin changes causing shifts', () => { + it('should use wrapper-based icon positioning instead of margin changes', () => { const { rerender } = render() const iconElement = screen.getByTestId('nav-icon') + const iconWrapper = iconElement.parentElement - // Collapsed: no right margin - expect(iconElement).toHaveClass('mr-0') + // Collapsed: wrapper has micro-adjustment for centering + expect(iconWrapper).toHaveClass('-ml-1') + + // Icon itself has consistent classes + expect(iconElement).toHaveClass('h-4') + expect(iconElement).toHaveClass('w-4') + expect(iconElement).toHaveClass('shrink-0') rerender() - // Expanded: 8px right margin (mr-2) - expect(iconElement).toHaveClass('mr-2') + const expandedIconWrapper = screen.getByTestId('nav-icon').parentElement - // This sudden margin appearance causes the squeeze effect + // Expanded: no wrapper adjustment needed + expect(expandedIconWrapper).not.toHaveClass('-ml-1') + + // Icon classes remain consistent - no margin shifts + expect(iconElement).toHaveClass('h-4') + expect(iconElement).toHaveClass('w-4') + expect(iconElement).toHaveClass('shrink-0') }) }) @@ -172,7 +193,7 @@ describe('NavLink Text Animation Issues', () => { const { rerender } = render() let linkElement = screen.getByTestId('nav-link') - expect(linkElement).not.toHaveClass('bg-state-accent-active') + expect(linkElement).not.toHaveClass('bg-components-menu-item-bg-active') // Test with active state (when href matches current segment) const activeProps = { @@ -183,7 +204,63 @@ describe('NavLink Text Animation Issues', () => { rerender() linkElement = screen.getByTestId('nav-link') - expect(linkElement).toHaveClass('bg-state-accent-active') + expect(linkElement).toHaveClass('bg-components-menu-item-bg-active') + expect(linkElement).toHaveClass('text-text-accent-light-mode-only') + }) + }) + + describe('Text Animation Classes', () => { + it('should have proper text classes in collapsed mode', () => { + render() + + const textElement = screen.getByText('Orchestrate') + + expect(textElement).toHaveClass('overflow-hidden') + expect(textElement).toHaveClass('whitespace-nowrap') + expect(textElement).toHaveClass('transition-all') + expect(textElement).toHaveClass('duration-200') + expect(textElement).toHaveClass('ease-in-out') + expect(textElement).toHaveClass('ml-0') + expect(textElement).toHaveClass('max-w-0') + expect(textElement).toHaveClass('opacity-0') + }) + + it('should have proper text classes in expanded mode', () => { + render() + + const textElement = screen.getByText('Orchestrate') + + expect(textElement).toHaveClass('overflow-hidden') + expect(textElement).toHaveClass('whitespace-nowrap') + expect(textElement).toHaveClass('transition-all') + expect(textElement).toHaveClass('duration-200') + expect(textElement).toHaveClass('ease-in-out') + expect(textElement).toHaveClass('ml-2') + expect(textElement).toHaveClass('max-w-none') + expect(textElement).toHaveClass('opacity-100') + }) + }) + + describe('Disabled State', () => { + it('should render as button when disabled', () => { + render() + + const buttonElement = screen.getByRole('button') + expect(buttonElement).toBeInTheDocument() + expect(buttonElement).toBeDisabled() + expect(buttonElement).toHaveClass('cursor-not-allowed') + expect(buttonElement).toHaveClass('opacity-30') + }) + + it('should maintain consistent styling in disabled state', () => { + render() + + const buttonElement = screen.getByRole('button') + expect(buttonElement).toHaveClass('pl-3') + expect(buttonElement).toHaveClass('pr-1') + + const iconWrapper = screen.getByTestId('nav-icon').parentElement + expect(iconWrapper).toHaveClass('-ml-1') }) }) }) diff --git a/web/app/components/app-sidebar/navLink.tsx b/web/app/components/app-sidebar/navLink.tsx index 4607f7b693..ad90b91250 100644 --- a/web/app/components/app-sidebar/navLink.tsx +++ b/web/app/components/app-sidebar/navLink.tsx @@ -1,15 +1,15 @@ 'use client' - +import React from 'react' import { useSelectedLayoutSegment } from 'next/navigation' import Link from 'next/link' import classNames from '@/utils/classnames' import type { RemixiconComponentType } from '@remixicon/react' export type NavIcon = React.ComponentType< -React.PropsWithoutRef> & { - title?: string | undefined - titleId?: string | undefined -}> | RemixiconComponentType + React.PropsWithoutRef> & { + title?: string | undefined + titleId?: string | undefined + }> | RemixiconComponentType export type NavLinkProps = { name: string @@ -19,14 +19,16 @@ export type NavLinkProps = { normal: NavIcon } mode?: string + disabled?: boolean } -export default function NavLink({ +const NavLink = ({ name, href, iconMap, mode = 'expand', -}: NavLinkProps) { + disabled = false, +}: NavLinkProps) => { const segment = useSelectedLayoutSegment() const formattedSegment = (() => { let res = segment?.toLowerCase() @@ -39,30 +41,59 @@ export default function NavLink({ const isActive = href.toLowerCase().split('/')?.pop() === formattedSegment const NavIcon = isActive ? iconMap.selected : iconMap.normal + const renderIcon = () => ( +
+
+ ) + + if (disabled) { + return ( + + ) + } + return ( -