feat(knowledge): add configuration components and refactor general form

feat(hooks): add llm-related hooks and constants
docs: add architecture analysis for reference projects
This commit is contained in:
2025-10-15 16:24:53 +08:00
parent 486815d83e
commit fe8747983e
33 changed files with 2627 additions and 812 deletions

View File

@@ -17,6 +17,7 @@ export interface UseDocumentListState {
// 文档列表Hook返回值接口
export interface UseDocumentListReturn extends UseDocumentListState {
fetchDocuments: (params?: IFetchKnowledgeListRequestParams) => Promise<void>;
fetchDocumentsFilter: () => Promise<void>;
setKeywords: (keywords: string) => void;
setCurrentPage: (page: number) => void;
setPageSize: (size: number) => void;
@@ -95,6 +96,27 @@ export const useDocumentList = (
}
}, [kbId, keywords, currentPage, pageSize]);
/**
* 获取文档过滤器
*/
const fetchDocumentsFilter = useCallback(async () => {
if (!kbId) return;
try {
const response = await knowledgeService.getDocumentFilter({
kb_id: kbId,
});
if (response.data.code === 0) {
const data = response.data.data;
} else {
throw new Error(response.data.message || '获取文档过滤器失败');
}
} catch (error: any) {
const errorMessage = error.response?.data?.message || error.message || '获取文档过滤器失败';
console.error('Failed to fetch document filter:', error);
}
}, [kbId, keywords]);
/**
* 刷新当前页面数据
*/
@@ -139,6 +161,7 @@ export const useDocumentList = (
pageSize,
keywords,
fetchDocuments,
fetchDocumentsFilter,
setKeywords: handleSetKeywords,
setCurrentPage: handleSetCurrentPage,
setPageSize: handleSetPageSize,

View File

@@ -1,6 +1,6 @@
import { useState, useEffect, useCallback } from 'react';
import knowledgeService from '@/services/knowledge_service';
import type { IKnowledge, IKnowledgeResult } from '@/interfaces/database/knowledge';
import type { IKnowledge, IKnowledgeResult, IParserConfig } from '@/interfaces/database/knowledge';
import type { IFetchKnowledgeListRequestParams } from '@/interfaces/request/knowledge';
/**
@@ -299,11 +299,9 @@ export const useKnowledgeOperations = () => {
* 包括嵌入模型、解析器配置、相似度阈值等
*/
const updateKnowledgeModelConfig = useCallback(async (data: {
id: string;
kb_id: string;
embd_id?: string;
// parser_config?: Partial<ParserConfig>;
similarity_threshold?: number;
vector_similarity_weight?: number;
parser_config?: Partial<IParserConfig>;
parser_id?: string;
}) => {
try {
@@ -311,7 +309,6 @@ export const useKnowledgeOperations = () => {
setError(null);
const updateData = {
kb_id: data.id,
...data,
};

195
src/hooks/llm-hooks.ts Normal file
View File

@@ -0,0 +1,195 @@
import { useState, useEffect, useCallback, useMemo } from 'react';
import { LLM_MODEL_TYPES, type LlmModelType } from "@/constants/knowledge";
import type { IThirdOAIModelCollection, IThirdOAIModel } from "@/interfaces/database/llm";
import userService from "@/services/user_service";
/**
* 获取LLM模型列表的Hook
* @param modelType 可选的模型类型过滤
* @returns LLM模型数据和相关状态
*/
export function useLlmList(modelType?: LlmModelType) {
const [data, setData] = useState<IThirdOAIModelCollection>({});
const [loading, setLoading] = useState(false);
const [error, setError] = useState<string | null>(null);
const fetchLlmList = useCallback(async () => {
try {
setLoading(true);
setError(null);
const response = await userService.llm_list({ model_type: modelType });
if (response.data?.code === 0) {
setData(response.data?.data ?? {});
} else {
setError(response.data?.message || '获取LLM列表失败');
}
} catch (err) {
setError(err instanceof Error ? err.message : '获取LLM列表失败');
} finally {
setLoading(false);
}
}, [modelType]);
useEffect(() => {
fetchLlmList();
}, [fetchLlmList]);
return {
data,
loading,
error,
refresh: fetchLlmList,
};
}
/**
* 获取可用的LLM选项列表
* @param modelType 可选的模型类型过滤
* @returns 格式化的选项列表
*/
export function useLlmOptions(modelType?: LlmModelType) {
const { data: llmInfo, loading, error } = useLlmList(modelType);
const options = useMemo(() => {
return Object.entries(llmInfo).map(([key, value]) => {
return {
label: key,
options: value
.filter((x) => x.available) // 只显示可用的模型
.map((x) => ({
label: x.llm_name,
value: `${x.llm_name}@${x.fid}`,
disabled: !x.available,
model: x,
})),
};
}).filter((group) => group.options.length > 0); // 过滤掉空组
}, [llmInfo]);
return {
options,
loading,
error,
};
}
/**
* 根据模型类型获取分组的LLM选项
* @returns 按模型类型分组的选项
*/
export function useLlmOptionsByModelType() {
const { data: llmInfo, loading, error } = useLlmList();
const getOptionsByModelType = useCallback((modelType: LlmModelType) => {
return Object.entries(llmInfo)
.filter(([, value]) =>
modelType
? value.some((x) => x.model_type.includes(modelType))
: true,
)
.map(([key, value]) => {
return {
label: key,
options: value
.filter(
(x) =>
(modelType ? x.model_type.includes(modelType) : true) &&
x.available,
)
.map((x) => ({
label: x.llm_name,
value: `${x.llm_name}@${x.fid}`,
disabled: !x.available,
model: x,
})),
};
})
.filter((x) => x.options.length > 0);
}, [llmInfo]);
return {
getOptionsByModelType,
loading,
error,
};
}
/**
* 获取嵌入模型选项
* @returns 嵌入模型选项列表
*/
export function useEmbeddingModelOptions() {
return useLlmOptions(LLM_MODEL_TYPES.Embedding);
}
/**
* 获取聊天模型选项
* @returns 聊天模型选项列表
*/
export function useChatModelOptions() {
return useLlmOptions(LLM_MODEL_TYPES.Chat);
}
/**
* 获取重排序模型选项
* @returns 重排序模型选项列表
*/
export function useRerankModelOptions() {
return useLlmOptions(LLM_MODEL_TYPES.Rerank);
}
/**
* 获取图像转文本模型选项
* @returns 图像转文本模型选项列表
*/
export function useImage2TextModelOptions() {
return useLlmOptions(LLM_MODEL_TYPES.Image2text);
}
/**
* 获取语音转文本模型选项
* @returns 语音转文本模型选项列表
*/
export function useSpeech2TextModelOptions() {
return useLlmOptions(LLM_MODEL_TYPES.Speech2text);
}
/**
* 获取文本转语音模型选项
* @returns 文本转语音模型选项列表
*/
export function useTTSModelOptions() {
return useLlmOptions(LLM_MODEL_TYPES.TTS);
}
/**
* 根据模型ID获取模型详情
* @param modelId 模型ID (格式: llm_name@fid)
* @returns 模型详情
*/
export function useLlmModelDetail(modelId?: string) {
const { data: llmInfo, loading, error } = useLlmList();
const modelDetail = useMemo(() => {
if (!modelId || !llmInfo) return null;
const [llmName, fid] = modelId.split('@');
for (const models of Object.values(llmInfo)) {
const model = models.find(
(m) => m.llm_name === llmName && m.fid === fid
);
if (model) return model;
}
return null;
}, [modelId, llmInfo]);
return {
modelDetail,
loading,
error,
};
}