376 lines
10 KiB
TypeScript
376 lines
10 KiB
TypeScript
/**
|
||
* 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<DatasetsResponse> {
|
||
const params = new URLSearchParams({
|
||
page: page.toString(),
|
||
limit: limit.toString(),
|
||
});
|
||
|
||
const response = await axios.get<DatasetsResponse>(
|
||
`${API_URL}/datasets?${params}`,
|
||
{ withCredentials: true }
|
||
);
|
||
return response.data;
|
||
}
|
||
|
||
/**
|
||
* 获取单个知识库详情
|
||
*
|
||
* @param datasetId - 知识库 ID
|
||
* @returns 知识库详情
|
||
*/
|
||
export async function fetchDataset(datasetId: string): Promise<Dataset> {
|
||
const response = await axios.get<Dataset>(
|
||
`${API_URL}/datasets/${datasetId}`,
|
||
{ withCredentials: true }
|
||
);
|
||
return response.data;
|
||
}
|
||
|
||
/**
|
||
* 更新知识库详情
|
||
*
|
||
* @param datasetId - 知识库 ID
|
||
* @param data - 更新数据
|
||
* @returns 更新后的知识库详情
|
||
*/
|
||
export async function updateDataset(
|
||
datasetId: string,
|
||
data: UpdateDatasetRequest
|
||
): Promise<Dataset> {
|
||
console.log('[Dataset Client] 更新知识库:', { datasetId, data });
|
||
|
||
const response = await axios.patch<Dataset>(
|
||
`${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<DocumentsResponse> {
|
||
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<DocumentsResponse>(
|
||
`${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<Document> {
|
||
const response = await axios.get<Document>(
|
||
`${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<OperationResult> {
|
||
console.log('[Dataset Client] 删除文档:', { datasetId, documentId });
|
||
|
||
const response = await axios.delete<OperationResult>(
|
||
`${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<OperationResult> {
|
||
const action = enabled ? 'enable' : 'disable';
|
||
console.log('[Dataset Client] 切换文档状态:', { datasetId, documentId, action });
|
||
|
||
const response = await axios.patch<OperationResult>(
|
||
`${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<SegmentsResponse> {
|
||
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<SegmentsResponse>(
|
||
`${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<OperationResult> {
|
||
console.log('[Dataset Client] 删除分段:', { datasetId, documentId, segmentId });
|
||
|
||
const response = await axios.delete<OperationResult>(
|
||
`${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<OperationResult> {
|
||
console.log('[Dataset Client] 切换分段状态:', { datasetId, documentId, segmentId, enabled });
|
||
|
||
const response = await axios.post<OperationResult>(
|
||
`${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<any> {
|
||
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<IndexingStatusResponse> {
|
||
console.log('[Dataset Client] 获取索引状态:', { datasetId, batch });
|
||
|
||
const response = await axios.get<IndexingStatusResponse>(
|
||
`${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<UploadFileInfo> {
|
||
console.log('[Dataset Client] 获取上传文件信息:', { datasetId, documentId });
|
||
|
||
const response = await axios.get<UploadFileInfo>(
|
||
`${API_URL}/datasets/${datasetId}/documents/${documentId}/upload-file`,
|
||
{ withCredentials: true }
|
||
);
|
||
return response.data;
|
||
}
|