/** * Dify Dataset 客户端 API 模块 * * 提供浏览器端调用 Dify 知识库 API 的函数 * 通过 Remix API Routes 代理请求 * * @module api/dify-dataset/client */ import axios from 'axios'; import type { Dataset, DatasetsResponse, DocumentsResponse, SegmentsResponse, Document, OperationResult, IndexingStatusResponse, UploadFileInfo, UpdateDatasetRequest, } from './types'; // ============================================================================ // 基础配置 // ============================================================================ /** * API 基础 URL * 指向 Remix API Routes(/api/dataset/*) */ const API_URL = '/api/dataset'; // ============================================================================ // 知识库 API // ============================================================================ /** * 获取知识库列表 * * @param page - 页码,默认 1 * @param limit - 每页数量,默认 20 * @returns 知识库列表响应 */ export async function fetchDatasets( page: number = 1, limit: number = 20 ): Promise { const params = new URLSearchParams({ page: page.toString(), limit: limit.toString(), }); const response = await axios.get( `${API_URL}/datasets?${params}`, { withCredentials: true } ); return response.data; } /** * 获取单个知识库详情 * * @param datasetId - 知识库 ID * @returns 知识库详情 */ export async function fetchDataset(datasetId: string): Promise { const response = await axios.get( `${API_URL}/datasets/${datasetId}`, { withCredentials: true } ); return response.data; } /** * 更新知识库详情 * * @param datasetId - 知识库 ID * @param data - 更新数据 * @returns 更新后的知识库详情 */ export async function updateDataset( datasetId: string, data: UpdateDatasetRequest ): Promise { console.log('[Dataset Client] 更新知识库:', { datasetId, data }); const response = await axios.patch( `${API_URL}/datasets/${datasetId}`, data, { headers: { 'Content-Type': 'application/json' }, withCredentials: true, } ); return response.data; } // ============================================================================ // 文档 API // ============================================================================ /** * 获取知识库文档列表 * * @param datasetId - 知识库 ID * @param page - 页码,默认 1 * @param limit - 每页数量,默认 20 * @param keyword - 搜索关键词 * @returns 文档列表响应 */ export async function fetchDocuments( datasetId: string, page: number = 1, limit: number = 20, keyword?: string ): Promise { const params = new URLSearchParams({ page: page.toString(), limit: limit.toString(), }); if (keyword) { params.append('keyword', keyword); } console.log('[Dataset Client] 获取文档列表:', { datasetId, page, limit, keyword }); const response = await axios.get( `${API_URL}/datasets/${datasetId}/documents?${params}`, { withCredentials: true } ); return response.data; } /** * 获取单个文档详情 * * @param datasetId - 知识库 ID * @param documentId - 文档 ID * @returns 文档详情 */ export async function fetchDocument( datasetId: string, documentId: string ): Promise { const response = await axios.get( `${API_URL}/datasets/${datasetId}/documents/${documentId}`, { withCredentials: true } ); return response.data; } /** * 删除文档 * * @param datasetId - 知识库 ID * @param documentId - 文档 ID * @returns 操作结果 */ export async function deleteDocument( datasetId: string, documentId: string ): Promise { console.log('[Dataset Client] 删除文档:', { datasetId, documentId }); const response = await axios.delete( `${API_URL}/datasets/${datasetId}/documents/${documentId}`, { withCredentials: true } ); return response.data; } /** * 启用/禁用文档 * Dify API: PATCH /datasets/{dataset_id}/documents/status/{action} * action: enable / disable / archive / un_archive * * @param datasetId - 知识库 ID * @param documentId - 文档 ID * @param enabled - 是否启用 * @returns 操作结果 */ export async function toggleDocumentStatus( datasetId: string, documentId: string, enabled: boolean ): Promise { const action = enabled ? 'enable' : 'disable'; console.log('[Dataset Client] 切换文档状态:', { datasetId, documentId, action }); const response = await axios.patch( `${API_URL}/datasets/${datasetId}/documents/status/${action}`, { document_ids: [documentId] }, { headers: { 'Content-Type': 'application/json' }, withCredentials: true, } ); return response.data; } // ============================================================================ // 文档分段 API // ============================================================================ /** * 获取文档分段列表 * * @param datasetId - 知识库 ID * @param documentId - 文档 ID * @param page - 页码,默认 1 * @param limit - 每页数量,默认 20 * @param keyword - 搜索关键词 * @returns 分段列表响应 */ export async function fetchSegments( datasetId: string, documentId: string, page: number = 1, limit: number = 20, keyword?: string ): Promise { const params = new URLSearchParams({ page: page.toString(), limit: limit.toString(), }); if (keyword) { params.append('keyword', keyword); } console.log('[Dataset Client] 获取分段列表:', { datasetId, documentId, page, limit }); const response = await axios.get( `${API_URL}/datasets/${datasetId}/documents/${documentId}/segments?${params}`, { withCredentials: true } ); return response.data; } /** * 删除分段 * * @param datasetId - 知识库 ID * @param documentId - 文档 ID * @param segmentId - 分段 ID * @returns 操作结果 */ export async function deleteSegment( datasetId: string, documentId: string, segmentId: string ): Promise { console.log('[Dataset Client] 删除分段:', { datasetId, documentId, segmentId }); const response = await axios.delete( `${API_URL}/datasets/${datasetId}/documents/${documentId}/segments/${segmentId}`, { withCredentials: true } ); return response.data; } /** * 启用/禁用分段 * Dify API: POST /datasets/{dataset_id}/documents/{document_id}/segments/{segment_id} * 通过更新分段的方式来切换状态 * * @param datasetId - 知识库 ID * @param documentId - 文档 ID * @param segmentId - 分段 ID * @param enabled - 是否启用 * @returns 操作结果 */ export async function toggleSegmentStatus( datasetId: string, documentId: string, segmentId: string, enabled: boolean ): Promise { console.log('[Dataset Client] 切换分段状态:', { datasetId, documentId, segmentId, enabled }); const response = await axios.post( `${API_URL}/datasets/${datasetId}/documents/${documentId}/segments/${segmentId}`, { segment: { enabled } }, { headers: { 'Content-Type': 'application/json' }, withCredentials: true, } ); return response.data; } // ============================================================================ // 文件上传 API // ============================================================================ /** * 上传文件到知识库 * * @param datasetId - 知识库 ID * @param file - 文件对象 * @param onProgress - 上传进度回调 * @returns 创建的文档信息 */ export async function uploadDocument( datasetId: string, file: File, onProgress?: (percent: number) => void ): Promise { const formData = new FormData(); formData.append('file', file); formData.append('data', JSON.stringify({ indexing_technique: 'high_quality', process_rule: { mode: 'automatic', }, })); console.log('[Dataset Client] 上传文档:', { datasetId, fileName: file.name }); const response = await axios.post( `${API_URL}/datasets/${datasetId}/documents`, formData, { withCredentials: true, onUploadProgress: (progressEvent) => { if (progressEvent.total && onProgress) { const percent = Math.round((progressEvent.loaded * 100) / progressEvent.total); onProgress(percent); } }, } ); return response.data; } /** * 获取文档嵌入状态(索引进度) * * @param datasetId - 知识库 ID * @param batch - 上传文档的批次号 * @returns 索引状态列表 */ export async function fetchIndexingStatus( datasetId: string, batch: string ): Promise { console.log('[Dataset Client] 获取索引状态:', { datasetId, batch }); const response = await axios.get( `${API_URL}/datasets/${datasetId}/documents/${batch}/indexing-status`, { withCredentials: true } ); return response.data; } /** * 获取文档上传文件信息 * * @param datasetId - 知识库 ID * @param documentId - 文档 ID * @returns 上传文件信息 */ export async function fetchUploadFileInfo( datasetId: string, documentId: string ): Promise { console.log('[Dataset Client] 获取上传文件信息:', { datasetId, documentId }); const response = await axios.get( `${API_URL}/datasets/${datasetId}/documents/${documentId}/upload-file`, { withCredentials: true } ); return response.data; }