1052 lines
30 KiB
TypeScript
1052 lines
30 KiB
TypeScript
import { useMutation, useQuery, useQueryClient } from "@tanstack/react-query";
|
||
|
||
import { apiFetch } from "@/core/api/fetch-client";
|
||
import { useLiveAccount } from "@/core/auth/use-live-account";
|
||
import { getBackendBaseURL } from "@/core/config";
|
||
|
||
const API = () => `${getBackendBaseURL()}/api/llmwiki`;
|
||
const PUBLIC_API = () => `${getBackendBaseURL()}/api/public/llmwiki`;
|
||
const SETTINGS_API = () => `${getBackendBaseURL()}/api/system-settings/llmwiki`;
|
||
|
||
export type LlmWikiProvider = "legacy" | "weknora";
|
||
export type LlmWikiScope = "personal" | "public" | "all";
|
||
|
||
export interface LlmWikiRuntime {
|
||
provider: LlmWikiProvider;
|
||
api_base_url: string;
|
||
web_base_url: string;
|
||
override_enabled: boolean;
|
||
}
|
||
|
||
export interface LlmWikiSettings extends LlmWikiRuntime {
|
||
file_api_base_url: string;
|
||
file_web_base_url: string;
|
||
effective_provider: LlmWikiProvider;
|
||
}
|
||
|
||
export interface LlmWikiKnowledgeBase {
|
||
id: string;
|
||
remote_status: "available" | "missing";
|
||
name: string;
|
||
description: string;
|
||
type: "document" | "faq";
|
||
publication_status: "private" | "pending" | "published" | "rejected";
|
||
owner_user_id?: string | null;
|
||
is_owner: boolean;
|
||
can_write: boolean;
|
||
knowledge_count: number;
|
||
chunk_count: number;
|
||
processing_count: number;
|
||
embedding_model_id?: string | null;
|
||
vector_store_id?: string | null;
|
||
vector_store_name?: string | null;
|
||
vector_store_source?: string | null;
|
||
vector_store_engine_type?: string | null;
|
||
vector_store_status?: string | null;
|
||
chunking_config?: Record<string, unknown>;
|
||
indexing_strategy?: Record<string, boolean>;
|
||
capabilities?: Record<string, boolean>;
|
||
extract_config?: Record<string, unknown>;
|
||
wiki_config?: Record<string, unknown>;
|
||
question_generation_config?: Record<string, unknown>;
|
||
summary_model_id?: string | null;
|
||
storage_provider?: string | null;
|
||
created_at?: string | null;
|
||
updated_at?: string | null;
|
||
published_at?: string | null;
|
||
is_conversation_deposit?: boolean;
|
||
}
|
||
|
||
export interface LlmWikiDocument {
|
||
id: string;
|
||
type?: string;
|
||
title?: string;
|
||
description?: string;
|
||
source?: string;
|
||
channel?: string;
|
||
file_name?: string;
|
||
file_type?: string;
|
||
file_size?: number;
|
||
storage_size?: number;
|
||
parse_status?: string;
|
||
pending_subtasks_count?: number;
|
||
summary_status?: string;
|
||
enable_status?: string;
|
||
embedding_model_id?: string;
|
||
created_at?: string;
|
||
updated_at?: string;
|
||
processed_at?: string;
|
||
error_message?: string;
|
||
}
|
||
|
||
export interface LlmWikiChunk {
|
||
id: string;
|
||
content: string;
|
||
chunk_index: number;
|
||
is_enabled: boolean;
|
||
status?: number | string | null;
|
||
start_at: number;
|
||
end_at: number;
|
||
chunk_type: string;
|
||
parent_chunk_id?: string;
|
||
relation_chunk_ids: string[];
|
||
indirect_relation_chunk_ids: string[];
|
||
metadata: Record<string, unknown>;
|
||
created_at?: string;
|
||
updated_at?: string;
|
||
}
|
||
|
||
export interface LlmWikiChunkPage {
|
||
items: LlmWikiChunk[];
|
||
total: number;
|
||
page: number;
|
||
page_size: number;
|
||
}
|
||
|
||
export interface LlmWikiGraph {
|
||
nodes: Array<{ id: string; title: string; type: string; link_count: number }>;
|
||
edges: Array<{ source: string; target: string }>;
|
||
meta: {
|
||
mode?: string;
|
||
total?: number;
|
||
returned?: number;
|
||
truncated?: boolean;
|
||
};
|
||
}
|
||
|
||
export interface LlmWikiWikiPage {
|
||
id: string;
|
||
slug: string;
|
||
title: string;
|
||
page_type: string;
|
||
status: string;
|
||
content: string;
|
||
summary: string;
|
||
aliases: string[];
|
||
parent_slug?: string;
|
||
category_path?: string[];
|
||
folder_id?: string;
|
||
wiki_path?: string;
|
||
depth?: number;
|
||
source_refs: string[];
|
||
in_links: string[];
|
||
out_links: string[];
|
||
version: number;
|
||
created_at?: string;
|
||
updated_at?: string;
|
||
}
|
||
|
||
export interface LlmWikiWikiPageList {
|
||
pages: LlmWikiWikiPage[];
|
||
total: number;
|
||
page: number;
|
||
page_size: number;
|
||
total_pages: number;
|
||
}
|
||
|
||
export interface LlmWikiWikiIndexStatus {
|
||
knowledge_base_id: string;
|
||
state: "not_synced" | "idle" | "running" | "partial" | "failed" | "rebuilding" | "rebuild_required";
|
||
local_index_enabled: boolean;
|
||
wiki_index_enabled: boolean;
|
||
fully_vectorized: boolean;
|
||
retrieval_mode: "vector" | "wiki_api";
|
||
local_page_count?: number;
|
||
ready_page_count?: number;
|
||
failed_page_count?: number;
|
||
vector_count?: number;
|
||
last_error?: string | null;
|
||
last_started_at?: string | null;
|
||
last_completed_at?: string | null;
|
||
}
|
||
|
||
export interface LlmWikiSourceContext {
|
||
knowledge_base_name?: string;
|
||
document_title?: string;
|
||
document_file_name?: string;
|
||
display_mode?: "wiki" | "chunks";
|
||
focus_chunk_id: string;
|
||
wiki_page?: LlmWikiWikiPage | null;
|
||
chunks: Array<{
|
||
id: string;
|
||
chunk_index?: number;
|
||
content: string;
|
||
is_focus: boolean;
|
||
}>;
|
||
}
|
||
|
||
export interface LlmWikiSearchResult {
|
||
kind: "wiki_page";
|
||
id: string;
|
||
wiki_page_id: string;
|
||
wiki_slug: string;
|
||
content: string;
|
||
knowledge_base_id: string;
|
||
knowledge_base_name: string;
|
||
title: string;
|
||
summary?: string;
|
||
page_type?: string;
|
||
page_version?: number;
|
||
updated_at?: string | null;
|
||
matched_heading?: string | null;
|
||
matched_sections?: Array<{
|
||
section_index: number;
|
||
heading?: string | null;
|
||
content: string;
|
||
score: number;
|
||
}>;
|
||
score: number;
|
||
url: string;
|
||
retrieval_mode?: "vector" | "wiki_api";
|
||
}
|
||
|
||
export interface LlmWikiSearchResponse {
|
||
query: string;
|
||
mode: "vector" | "wiki_api" | "mixed";
|
||
results: LlmWikiSearchResult[];
|
||
knowledge_base_count: number;
|
||
partial: boolean;
|
||
warnings: string[];
|
||
fallback_knowledge_base_ids: string[];
|
||
}
|
||
|
||
export interface LlmWikiWeKnoraEmbedSession {
|
||
frame_path: string;
|
||
expires_in: number;
|
||
}
|
||
|
||
export interface LlmWikiWikiPageCreate {
|
||
slug: string;
|
||
title: string;
|
||
content: string;
|
||
summary?: string;
|
||
page_type?: string;
|
||
status?: string;
|
||
aliases?: string[];
|
||
parent_slug?: string;
|
||
category_path?: string[];
|
||
folder_id?: string;
|
||
wiki_path?: string;
|
||
}
|
||
|
||
export interface LlmWikiWikiPageUpdate {
|
||
title?: string;
|
||
content?: string;
|
||
summary?: string;
|
||
page_type?: string;
|
||
status?: string;
|
||
aliases?: string[];
|
||
parent_slug?: string;
|
||
category_path?: string[];
|
||
folder_id?: string;
|
||
wiki_path?: string;
|
||
}
|
||
|
||
function userFacingKnowledgeMessage(value: string): string {
|
||
return value.replace(/weknora/gi, "知识服务");
|
||
}
|
||
|
||
async function readJson<T>(response: Response, context: string): Promise<T> {
|
||
if (!response.ok) {
|
||
const payload = await response.json().catch(() => null as unknown);
|
||
const rawDetail = payload && typeof payload === "object" && "detail" in payload
|
||
? (payload as { detail: unknown }).detail
|
||
: null;
|
||
const detail = rawDetail && typeof rawDetail === "object" && "message" in rawDetail
|
||
? String((rawDetail as { message: unknown }).message)
|
||
: rawDetail
|
||
? String(rawDetail)
|
||
: `${context}失败(${response.status})`;
|
||
throw new Error(userFacingKnowledgeMessage(detail));
|
||
}
|
||
if (response.status === 204) return undefined as T;
|
||
return (await response.json()) as T;
|
||
}
|
||
|
||
export async function getLlmWikiRuntime(): Promise<LlmWikiRuntime> {
|
||
return readJson(
|
||
await apiFetch(`${API()}/runtime`),
|
||
"读取 LLMWiki 运行模式",
|
||
);
|
||
}
|
||
|
||
export async function listLlmWikiKnowledgeBases(
|
||
scope: LlmWikiScope,
|
||
): Promise<LlmWikiKnowledgeBase[]> {
|
||
const response = await apiFetch(
|
||
`${API()}/knowledge-bases?scope=${encodeURIComponent(scope)}`,
|
||
);
|
||
const payload = await readJson<{ knowledge_bases: LlmWikiKnowledgeBase[] }>(
|
||
response,
|
||
"读取知识库",
|
||
);
|
||
return payload.knowledge_bases ?? [];
|
||
}
|
||
|
||
export async function listAgentLlmWikiKnowledgeBases(
|
||
agentId: string,
|
||
): Promise<LlmWikiKnowledgeBase[]> {
|
||
const payload = await readJson<{ knowledge_bases: LlmWikiKnowledgeBase[] }>(
|
||
await apiFetch(
|
||
`${API()}/agents/${encodeURIComponent(agentId)}/knowledge-bases`,
|
||
),
|
||
"读取智能体知识库",
|
||
);
|
||
return payload.knowledge_bases ?? [];
|
||
}
|
||
|
||
export async function getLlmWikiKnowledgeBase(
|
||
id: string,
|
||
): Promise<LlmWikiKnowledgeBase> {
|
||
return readJson(
|
||
await apiFetch(`${API()}/knowledge-bases/${encodeURIComponent(id)}`),
|
||
"读取知识库详情",
|
||
);
|
||
}
|
||
|
||
export async function createLlmWikiWeKnoraEmbedSession(
|
||
id: string,
|
||
tab: "documents" | "wiki" | "graph",
|
||
): Promise<LlmWikiWeKnoraEmbedSession> {
|
||
return readJson(
|
||
await apiFetch(
|
||
`${API()}/knowledge-bases/${encodeURIComponent(id)}/weknora/session?tab=${encodeURIComponent(tab)}`,
|
||
{ method: "POST" },
|
||
),
|
||
"创建知识库详情会话",
|
||
);
|
||
}
|
||
|
||
export async function getLlmWikiSourceContext(
|
||
knowledgeBaseId: string,
|
||
chunkId: string,
|
||
): Promise<LlmWikiSourceContext> {
|
||
const params = new URLSearchParams({
|
||
knowledge_base_id: knowledgeBaseId,
|
||
chunk_id: chunkId,
|
||
});
|
||
const payload = await readJson<{ success: boolean; data: LlmWikiSourceContext }>(
|
||
await apiFetch(`${API()}/sources/context?${params}`),
|
||
"加载参考文献原文",
|
||
);
|
||
return payload.data;
|
||
}
|
||
|
||
export async function createLlmWikiKnowledgeBase(input: {
|
||
name: string;
|
||
description: string;
|
||
type: "document" | "faq";
|
||
wiki_enabled?: boolean;
|
||
}): Promise<LlmWikiKnowledgeBase> {
|
||
return readJson(
|
||
await apiFetch(`${API()}/knowledge-bases`, {
|
||
method: "POST",
|
||
headers: { "Content-Type": "application/json" },
|
||
body: JSON.stringify(input),
|
||
}),
|
||
"创建知识库",
|
||
);
|
||
}
|
||
|
||
export async function updateLlmWikiKnowledgeBase(
|
||
id: string,
|
||
input: { name?: string; description?: string },
|
||
): Promise<LlmWikiKnowledgeBase> {
|
||
return readJson(
|
||
await apiFetch(`${API()}/knowledge-bases/${encodeURIComponent(id)}`, {
|
||
method: "PATCH",
|
||
headers: { "Content-Type": "application/json" },
|
||
body: JSON.stringify(input),
|
||
}),
|
||
"更新知识库",
|
||
);
|
||
}
|
||
|
||
export async function deleteLlmWikiKnowledgeBase(id: string): Promise<void> {
|
||
await readJson<void>(
|
||
await apiFetch(`${API()}/knowledge-bases/${encodeURIComponent(id)}`, {
|
||
method: "DELETE",
|
||
}),
|
||
"删除知识库",
|
||
);
|
||
}
|
||
|
||
export async function listLlmWikiDocuments(
|
||
knowledgeBaseId: string,
|
||
): Promise<LlmWikiDocument[]> {
|
||
const payload = await readJson<{ items: LlmWikiDocument[] }>(
|
||
await apiFetch(
|
||
`${API()}/knowledge-bases/${encodeURIComponent(knowledgeBaseId)}/documents`,
|
||
),
|
||
"读取文档",
|
||
);
|
||
return payload.items ?? [];
|
||
}
|
||
|
||
export async function getLlmWikiDocument(
|
||
knowledgeBaseId: string,
|
||
documentId: string,
|
||
): Promise<LlmWikiDocument> {
|
||
return readJson(
|
||
await apiFetch(
|
||
`${API()}/knowledge-bases/${encodeURIComponent(knowledgeBaseId)}/documents/${encodeURIComponent(documentId)}`,
|
||
),
|
||
"读取文档详情",
|
||
);
|
||
}
|
||
|
||
export async function listLlmWikiDocumentChunks(
|
||
knowledgeBaseId: string,
|
||
documentId: string,
|
||
page: number,
|
||
pageSize: number,
|
||
): Promise<LlmWikiChunkPage> {
|
||
return readJson(
|
||
await apiFetch(
|
||
`${API()}/knowledge-bases/${encodeURIComponent(knowledgeBaseId)}/documents/${encodeURIComponent(documentId)}/chunks?page=${page}&page_size=${pageSize}`,
|
||
),
|
||
"读取文档索引",
|
||
);
|
||
}
|
||
|
||
export async function getLlmWikiDocumentPreview(
|
||
knowledgeBaseId: string,
|
||
documentId: string,
|
||
): Promise<Blob> {
|
||
const response = await apiFetch(
|
||
`${API()}/knowledge-bases/${encodeURIComponent(knowledgeBaseId)}/documents/${encodeURIComponent(documentId)}/preview`,
|
||
);
|
||
if (!response.ok) {
|
||
await readJson<void>(response, "读取文档原件");
|
||
throw new Error("读取文档原件失败");
|
||
}
|
||
return response.blob();
|
||
}
|
||
|
||
export async function getLlmWikiGraph(knowledgeBaseId: string): Promise<LlmWikiGraph> {
|
||
return readJson(
|
||
await apiFetch(`${API()}/knowledge-bases/${encodeURIComponent(knowledgeBaseId)}/graph?limit=200`),
|
||
"读取知识图谱",
|
||
);
|
||
}
|
||
|
||
export async function listLlmWikiWikiPages(
|
||
knowledgeBaseId: string,
|
||
page: number,
|
||
pageSize: number,
|
||
query = "",
|
||
): Promise<LlmWikiWikiPageList> {
|
||
const params = new URLSearchParams({ page: String(page), page_size: String(pageSize) });
|
||
if (query.trim()) params.set("query", query.trim());
|
||
return readJson(
|
||
await apiFetch(
|
||
`${API()}/knowledge-bases/${encodeURIComponent(knowledgeBaseId)}/wiki/pages?${params.toString()}`,
|
||
),
|
||
"读取 Wiki 页面",
|
||
);
|
||
}
|
||
|
||
export async function getLlmWikiWikiPage(
|
||
knowledgeBaseId: string,
|
||
slug: string,
|
||
): Promise<LlmWikiWikiPage> {
|
||
const safeSlug = slug.split("/").map(encodeURIComponent).join("/");
|
||
return readJson(
|
||
await apiFetch(
|
||
`${API()}/knowledge-bases/${encodeURIComponent(knowledgeBaseId)}/wiki/pages/${safeSlug}`,
|
||
),
|
||
"读取 Wiki 页面详情",
|
||
);
|
||
}
|
||
|
||
export async function getLlmWikiWikiIndexStatus(
|
||
knowledgeBaseId: string,
|
||
): Promise<LlmWikiWikiIndexStatus> {
|
||
return readJson(
|
||
await apiFetch(
|
||
`${API()}/knowledge-bases/${encodeURIComponent(knowledgeBaseId)}/wiki-index-status`,
|
||
),
|
||
"读取 Wiki 向量化状态",
|
||
);
|
||
}
|
||
|
||
export async function vectorizeLlmWikiKnowledgeBase(
|
||
knowledgeBaseId: string,
|
||
): Promise<{ job_id: string; status: string; knowledge_base_id: string }> {
|
||
return readJson(
|
||
await apiFetch(
|
||
`${API()}/knowledge-bases/${encodeURIComponent(knowledgeBaseId)}/vectorize`,
|
||
{ method: "POST" },
|
||
),
|
||
"触发 Wiki 向量化",
|
||
);
|
||
}
|
||
|
||
export async function exportLlmWikiWikiExcel(
|
||
knowledgeBaseId: string,
|
||
knowledgeBaseName = "LLMWiki",
|
||
): Promise<void> {
|
||
const response = await apiFetch(
|
||
`${API()}/knowledge-bases/${encodeURIComponent(knowledgeBaseId)}/wiki/export.xlsx`,
|
||
);
|
||
if (!response.ok) {
|
||
await readJson<void>(response, "导出 Wiki Excel");
|
||
return;
|
||
}
|
||
const blob = await response.blob();
|
||
const objectUrl = URL.createObjectURL(blob);
|
||
const link = document.createElement("a");
|
||
link.href = objectUrl;
|
||
link.download = `${knowledgeBaseName.replace(/[\\/:*?"<>|]/g, "_") || "LLMWiki"}-Wiki.xlsx`;
|
||
document.body.appendChild(link);
|
||
link.click();
|
||
link.remove();
|
||
URL.revokeObjectURL(objectUrl);
|
||
}
|
||
|
||
/** Read the DeerFlow-local Wiki mirror used by new vector citations. */
|
||
export async function getLocalLlmWikiWikiPage(
|
||
knowledgeBaseId: string,
|
||
slug: string,
|
||
): Promise<LlmWikiWikiPage> {
|
||
const safeSlug = slug.split("/").map(encodeURIComponent).join("/");
|
||
const page = await readJson<LlmWikiWikiPage & { page_version?: number }>(
|
||
await apiFetch(
|
||
`${API()}/knowledge-bases/${encodeURIComponent(knowledgeBaseId)}/local-wiki/pages/${safeSlug}`,
|
||
),
|
||
"读取本地 Wiki 页面详情",
|
||
);
|
||
return { ...page, version: page.version ?? page.page_version ?? 0 };
|
||
}
|
||
|
||
export async function createLlmWikiWikiPage(
|
||
knowledgeBaseId: string,
|
||
input: LlmWikiWikiPageCreate,
|
||
): Promise<LlmWikiWikiPage> {
|
||
return readJson(
|
||
await apiFetch(
|
||
`${API()}/knowledge-bases/${encodeURIComponent(knowledgeBaseId)}/wiki/pages`,
|
||
{
|
||
method: "POST",
|
||
headers: { "Content-Type": "application/json" },
|
||
body: JSON.stringify(input),
|
||
},
|
||
),
|
||
"创建 Wiki 页面",
|
||
);
|
||
}
|
||
|
||
export async function updateLlmWikiWikiPage(
|
||
knowledgeBaseId: string,
|
||
slug: string,
|
||
input: LlmWikiWikiPageUpdate,
|
||
): Promise<LlmWikiWikiPage> {
|
||
const safeSlug = slug.split("/").map(encodeURIComponent).join("/");
|
||
return readJson(
|
||
await apiFetch(
|
||
`${API()}/knowledge-bases/${encodeURIComponent(knowledgeBaseId)}/wiki/pages/${safeSlug}`,
|
||
{
|
||
method: "PATCH",
|
||
headers: { "Content-Type": "application/json" },
|
||
body: JSON.stringify(input),
|
||
},
|
||
),
|
||
"鏇存柊 Wiki 椤甸潰",
|
||
);
|
||
}
|
||
|
||
export async function deleteLlmWikiWikiPage(
|
||
knowledgeBaseId: string,
|
||
slug: string,
|
||
): Promise<void> {
|
||
const safeSlug = slug.split("/").map(encodeURIComponent).join("/");
|
||
await readJson<void>(
|
||
await apiFetch(
|
||
`${API()}/knowledge-bases/${encodeURIComponent(knowledgeBaseId)}/wiki/pages/${safeSlug}`,
|
||
{ method: "DELETE" },
|
||
),
|
||
"鍒犻櫎 Wiki 椤甸潰",
|
||
);
|
||
}
|
||
|
||
export async function uploadLlmWikiDocument(
|
||
knowledgeBaseId: string,
|
||
file: File,
|
||
): Promise<LlmWikiDocument> {
|
||
const form = new FormData();
|
||
form.append("file", file);
|
||
return readJson(
|
||
await apiFetch(
|
||
`${API()}/knowledge-bases/${encodeURIComponent(knowledgeBaseId)}/documents`,
|
||
{ method: "POST", body: form },
|
||
),
|
||
"上传文档",
|
||
);
|
||
}
|
||
|
||
export async function importLlmWikiDocumentUrl(
|
||
knowledgeBaseId: string,
|
||
url: string,
|
||
): Promise<LlmWikiDocument> {
|
||
return readJson(
|
||
await apiFetch(
|
||
`${API()}/knowledge-bases/${encodeURIComponent(knowledgeBaseId)}/documents/url`,
|
||
{
|
||
method: "POST",
|
||
headers: { "Content-Type": "application/json" },
|
||
body: JSON.stringify({ url }),
|
||
},
|
||
),
|
||
"导入网页",
|
||
);
|
||
}
|
||
|
||
export async function createManualLlmWikiDocument(
|
||
knowledgeBaseId: string,
|
||
input: { title: string; content: string },
|
||
): Promise<LlmWikiDocument> {
|
||
return readJson(
|
||
await apiFetch(
|
||
`${API()}/knowledge-bases/${encodeURIComponent(knowledgeBaseId)}/documents/manual`,
|
||
{
|
||
method: "POST",
|
||
headers: { "Content-Type": "application/json" },
|
||
body: JSON.stringify(input),
|
||
},
|
||
),
|
||
"创建 Wiki 内容",
|
||
);
|
||
}
|
||
|
||
export async function deleteLlmWikiDocument(
|
||
knowledgeBaseId: string,
|
||
documentId: string,
|
||
): Promise<void> {
|
||
await readJson<void>(
|
||
await apiFetch(
|
||
`${API()}/knowledge-bases/${encodeURIComponent(knowledgeBaseId)}/documents/${encodeURIComponent(documentId)}`,
|
||
{ method: "DELETE" },
|
||
),
|
||
"删除文档",
|
||
);
|
||
}
|
||
|
||
export async function reprocessLlmWikiDocument(
|
||
knowledgeBaseId: string,
|
||
documentId: string,
|
||
): Promise<void> {
|
||
await readJson(
|
||
await apiFetch(
|
||
`${API()}/knowledge-bases/${encodeURIComponent(knowledgeBaseId)}/documents/${encodeURIComponent(documentId)}/reprocess`,
|
||
{ method: "POST" },
|
||
),
|
||
"重新解析文档",
|
||
);
|
||
}
|
||
|
||
export async function setLlmWikiPublication(
|
||
knowledgeBaseId: string,
|
||
publish: boolean,
|
||
): Promise<void> {
|
||
await readJson(
|
||
await apiFetch(
|
||
`${API()}/knowledge-bases/${encodeURIComponent(knowledgeBaseId)}/${publish ? "publish" : "unpublish"}`,
|
||
{ method: "POST" },
|
||
),
|
||
publish ? "发布知识库" : "取消发布",
|
||
);
|
||
}
|
||
|
||
export async function searchLlmWiki(input: {
|
||
query: string;
|
||
scope: LlmWikiScope;
|
||
knowledge_base_ids?: string[];
|
||
}): Promise<LlmWikiSearchResponse> {
|
||
return readJson<LlmWikiSearchResponse>(
|
||
await apiFetch(`${API()}/search`, {
|
||
method: "POST",
|
||
headers: { "Content-Type": "application/json" },
|
||
body: JSON.stringify(input),
|
||
}),
|
||
"检索知识库",
|
||
);
|
||
}
|
||
|
||
export async function getPublicLlmWikiKnowledgeBase(
|
||
id: string,
|
||
): Promise<LlmWikiKnowledgeBase> {
|
||
return readJson(
|
||
await apiFetch(`${PUBLIC_API()}/knowledge-bases/${encodeURIComponent(id)}`),
|
||
"读取公开知识库详情",
|
||
);
|
||
}
|
||
|
||
export async function listPublicLlmWikiWikiPages(
|
||
knowledgeBaseId: string,
|
||
page: number,
|
||
pageSize: number,
|
||
query = "",
|
||
): Promise<LlmWikiWikiPageList> {
|
||
const params = new URLSearchParams({ page: String(page), page_size: String(pageSize) });
|
||
if (query.trim()) params.set("query", query.trim());
|
||
return readJson(
|
||
await apiFetch(
|
||
`${PUBLIC_API()}/knowledge-bases/${encodeURIComponent(knowledgeBaseId)}/wiki/pages?${params.toString()}`,
|
||
),
|
||
"读取公开 Wiki 页面",
|
||
);
|
||
}
|
||
|
||
export async function getPublicLlmWikiWikiPage(
|
||
knowledgeBaseId: string,
|
||
slug: string,
|
||
): Promise<LlmWikiWikiPage> {
|
||
const safeSlug = slug.split("/").map(encodeURIComponent).join("/");
|
||
return readJson(
|
||
await apiFetch(
|
||
`${PUBLIC_API()}/knowledge-bases/${encodeURIComponent(knowledgeBaseId)}/wiki/pages/${safeSlug}`,
|
||
),
|
||
"读取公开 Wiki 页面详情",
|
||
);
|
||
}
|
||
|
||
export async function createLlmWikiConversationDeposit(input: {
|
||
thread_id: string;
|
||
question: string;
|
||
answer: string;
|
||
human_message_id?: string | null;
|
||
assistant_message_id: string;
|
||
assistant_id?: string | null;
|
||
knowledge_base_ids?: string[];
|
||
}): Promise<{ queued: boolean; provider: LlmWikiProvider }> {
|
||
return readJson(
|
||
await apiFetch(`${API()}/conversation-deposits/turn`, {
|
||
method: "POST",
|
||
headers: { "Content-Type": "application/json" },
|
||
body: JSON.stringify(input),
|
||
}),
|
||
"写入对话沉淀",
|
||
);
|
||
}
|
||
|
||
export async function getLlmWikiSettings(): Promise<LlmWikiSettings> {
|
||
return readJson(await apiFetch(SETTINGS_API()), "读取知识服务连接配置");
|
||
}
|
||
|
||
export async function saveLlmWikiSettings(input: {
|
||
override_enabled: boolean;
|
||
api_base_url: string;
|
||
web_base_url: string;
|
||
}): Promise<LlmWikiRuntime> {
|
||
return readJson(
|
||
await apiFetch(SETTINGS_API(), {
|
||
method: "PUT",
|
||
headers: { "Content-Type": "application/json" },
|
||
body: JSON.stringify(input),
|
||
}),
|
||
"保存知识服务连接配置",
|
||
);
|
||
}
|
||
|
||
export async function resetLlmWikiSettings(): Promise<LlmWikiRuntime> {
|
||
return readJson(
|
||
await apiFetch(`${SETTINGS_API()}/override`, { method: "DELETE" }),
|
||
"恢复配置文件设置",
|
||
);
|
||
}
|
||
|
||
export async function testLlmWikiConnection(
|
||
apiBaseUrl: string,
|
||
): Promise<void> {
|
||
await readJson(
|
||
await apiFetch(`${SETTINGS_API()}/test`, {
|
||
method: "POST",
|
||
headers: { "Content-Type": "application/json" },
|
||
body: JSON.stringify({ api_base_url: apiBaseUrl }),
|
||
}),
|
||
"测试知识服务连接",
|
||
);
|
||
}
|
||
|
||
const runtimeKey = ["llmwiki", "runtime"] as const;
|
||
const settingsKey = ["llmwiki", "settings"] as const;
|
||
const knowledgeBasesKey = (userId: string | null, scope: LlmWikiScope) =>
|
||
["llmwiki", "knowledge-bases", userId ?? "anonymous", scope] as const;
|
||
|
||
export function useLlmWikiRuntime() {
|
||
return useQuery({
|
||
queryKey: runtimeKey,
|
||
queryFn: getLlmWikiRuntime,
|
||
staleTime: 30_000,
|
||
retry: 1,
|
||
});
|
||
}
|
||
|
||
export function useLlmWikiKnowledgeBases(
|
||
scope: LlmWikiScope,
|
||
enabled = true,
|
||
) {
|
||
const { userId } = useLiveAccount();
|
||
return useQuery({
|
||
queryKey: knowledgeBasesKey(userId, scope),
|
||
queryFn: () => listLlmWikiKnowledgeBases(scope),
|
||
enabled,
|
||
refetchInterval: 15_000,
|
||
});
|
||
}
|
||
|
||
export function useAgentLlmWikiKnowledgeBases(
|
||
agentId: string | null | undefined,
|
||
enabled = true,
|
||
) {
|
||
const { userId } = useLiveAccount();
|
||
return useQuery({
|
||
queryKey: ["llmwiki", "agents", agentId, "knowledge-bases", userId ?? "anonymous"],
|
||
queryFn: () => listAgentLlmWikiKnowledgeBases(agentId!),
|
||
enabled: enabled && !!agentId,
|
||
});
|
||
}
|
||
|
||
export function useLlmWikiKnowledgeBase(
|
||
knowledgeBaseId: string | null,
|
||
enabled = true,
|
||
) {
|
||
const { userId } = useLiveAccount();
|
||
return useQuery({
|
||
queryKey: ["llmwiki", "knowledge-base", knowledgeBaseId, userId ?? "anonymous"],
|
||
queryFn: () => getLlmWikiKnowledgeBase(knowledgeBaseId!),
|
||
enabled: enabled && !!knowledgeBaseId,
|
||
refetchInterval: 8_000,
|
||
});
|
||
}
|
||
|
||
export function useLlmWikiDocuments(
|
||
knowledgeBaseId: string | null,
|
||
enabled = true,
|
||
) {
|
||
const { userId } = useLiveAccount();
|
||
return useQuery({
|
||
queryKey: ["llmwiki", "documents", knowledgeBaseId, userId ?? "anonymous"],
|
||
queryFn: () => listLlmWikiDocuments(knowledgeBaseId!),
|
||
enabled: enabled && !!knowledgeBaseId,
|
||
refetchInterval: 8_000,
|
||
});
|
||
}
|
||
|
||
export function useLlmWikiDocument(
|
||
knowledgeBaseId: string | null,
|
||
documentId: string | null,
|
||
enabled = true,
|
||
) {
|
||
const { userId } = useLiveAccount();
|
||
return useQuery({
|
||
queryKey: ["llmwiki", "document", knowledgeBaseId, documentId, userId ?? "anonymous"],
|
||
queryFn: () => getLlmWikiDocument(knowledgeBaseId!, documentId!),
|
||
enabled: enabled && !!knowledgeBaseId && !!documentId,
|
||
});
|
||
}
|
||
|
||
export function useLlmWikiDocumentChunks(
|
||
knowledgeBaseId: string | null,
|
||
documentId: string | null,
|
||
page: number,
|
||
pageSize = 20,
|
||
enabled = true,
|
||
) {
|
||
const { userId } = useLiveAccount();
|
||
return useQuery({
|
||
queryKey: ["llmwiki", "document-chunks", knowledgeBaseId, documentId, page, pageSize, userId ?? "anonymous"],
|
||
queryFn: () => listLlmWikiDocumentChunks(knowledgeBaseId!, documentId!, page, pageSize),
|
||
enabled: enabled && !!knowledgeBaseId && !!documentId,
|
||
});
|
||
}
|
||
|
||
export function useLlmWikiGraph(knowledgeBaseId: string | null, enabled = true) {
|
||
const { userId } = useLiveAccount();
|
||
return useQuery({
|
||
queryKey: ["llmwiki", "graph", knowledgeBaseId, userId ?? "anonymous"],
|
||
queryFn: () => getLlmWikiGraph(knowledgeBaseId!),
|
||
enabled: enabled && !!knowledgeBaseId,
|
||
});
|
||
}
|
||
|
||
export function useLlmWikiWikiPages(
|
||
knowledgeBaseId: string | null,
|
||
page: number,
|
||
pageSize = 50,
|
||
query = "",
|
||
enabled = true,
|
||
) {
|
||
const { userId } = useLiveAccount();
|
||
return useQuery({
|
||
queryKey: ["llmwiki", "wiki-pages", knowledgeBaseId, page, pageSize, query, userId ?? "anonymous"],
|
||
queryFn: () => listLlmWikiWikiPages(knowledgeBaseId!, page, pageSize, query),
|
||
enabled: enabled && !!knowledgeBaseId,
|
||
refetchInterval: 10_000,
|
||
});
|
||
}
|
||
|
||
export function useLlmWikiWikiPage(
|
||
knowledgeBaseId: string | null,
|
||
slug: string | null,
|
||
enabled = true,
|
||
) {
|
||
const { userId } = useLiveAccount();
|
||
return useQuery({
|
||
queryKey: ["llmwiki", "wiki-page", knowledgeBaseId, slug, userId ?? "anonymous"],
|
||
queryFn: () => getLlmWikiWikiPage(knowledgeBaseId!, slug!),
|
||
enabled: enabled && !!knowledgeBaseId && !!slug,
|
||
});
|
||
}
|
||
|
||
export function usePublicLlmWikiKnowledgeBase(
|
||
knowledgeBaseId: string | null,
|
||
enabled = true,
|
||
) {
|
||
return useQuery({
|
||
queryKey: ["public-llmwiki", "knowledge-base", knowledgeBaseId],
|
||
queryFn: () => getPublicLlmWikiKnowledgeBase(knowledgeBaseId!),
|
||
enabled: enabled && !!knowledgeBaseId,
|
||
staleTime: 60_000,
|
||
});
|
||
}
|
||
|
||
export function usePublicLlmWikiWikiPages(
|
||
knowledgeBaseId: string | null,
|
||
page: number,
|
||
pageSize = 50,
|
||
query = "",
|
||
enabled = true,
|
||
) {
|
||
return useQuery({
|
||
queryKey: ["public-llmwiki", "wiki-pages", knowledgeBaseId, page, pageSize, query],
|
||
queryFn: () => listPublicLlmWikiWikiPages(knowledgeBaseId!, page, pageSize, query),
|
||
enabled: enabled && !!knowledgeBaseId,
|
||
staleTime: 60_000,
|
||
});
|
||
}
|
||
|
||
export function usePublicLlmWikiWikiPage(
|
||
knowledgeBaseId: string | null,
|
||
slug: string | null,
|
||
enabled = true,
|
||
) {
|
||
return useQuery({
|
||
queryKey: ["public-llmwiki", "wiki-page", knowledgeBaseId, slug],
|
||
queryFn: () => getPublicLlmWikiWikiPage(knowledgeBaseId!, slug!),
|
||
enabled: enabled && !!knowledgeBaseId && !!slug,
|
||
staleTime: 60_000,
|
||
});
|
||
}
|
||
|
||
export function useLlmWikiWikiIndexStatus(
|
||
knowledgeBaseId: string | null,
|
||
enabled = true,
|
||
) {
|
||
const { userId } = useLiveAccount();
|
||
return useQuery({
|
||
queryKey: ["llmwiki", "wiki-index-status", knowledgeBaseId, userId ?? "anonymous"],
|
||
queryFn: () => getLlmWikiWikiIndexStatus(knowledgeBaseId!),
|
||
enabled: enabled && !!knowledgeBaseId,
|
||
refetchInterval: (query) => {
|
||
const state = query.state.data?.state;
|
||
return state === "running" || state === "rebuilding" ? 2_000 : 10_000;
|
||
},
|
||
});
|
||
}
|
||
|
||
export function useLlmWikiSettings(enabled = true) {
|
||
const { userId } = useLiveAccount();
|
||
return useQuery({
|
||
queryKey: [...settingsKey, userId ?? "anonymous"],
|
||
queryFn: getLlmWikiSettings,
|
||
enabled,
|
||
});
|
||
}
|
||
|
||
export function useLlmWikiActions() {
|
||
const queryClient = useQueryClient();
|
||
const invalidateKnowledge = () =>
|
||
queryClient.invalidateQueries({ queryKey: ["llmwiki"] });
|
||
return {
|
||
create: useMutation({
|
||
mutationFn: createLlmWikiKnowledgeBase,
|
||
onSuccess: invalidateKnowledge,
|
||
}),
|
||
update: useMutation({
|
||
mutationFn: ({ id, ...input }: { id: string; name?: string; description?: string }) =>
|
||
updateLlmWikiKnowledgeBase(id, input),
|
||
onSuccess: invalidateKnowledge,
|
||
}),
|
||
remove: useMutation({
|
||
mutationFn: deleteLlmWikiKnowledgeBase,
|
||
onSuccess: invalidateKnowledge,
|
||
}),
|
||
upload: useMutation({
|
||
mutationFn: ({ id, file }: { id: string; file: File }) =>
|
||
uploadLlmWikiDocument(id, file),
|
||
onSuccess: invalidateKnowledge,
|
||
}),
|
||
importUrl: useMutation({
|
||
mutationFn: ({ id, url }: { id: string; url: string }) =>
|
||
importLlmWikiDocumentUrl(id, url),
|
||
onSuccess: invalidateKnowledge,
|
||
}),
|
||
createManual: useMutation({
|
||
mutationFn: ({ id, title, content }: { id: string; title: string; content: string }) =>
|
||
createManualLlmWikiDocument(id, { title, content }),
|
||
onSuccess: invalidateKnowledge,
|
||
}),
|
||
removeDocument: useMutation({
|
||
mutationFn: ({ id, documentId }: { id: string; documentId: string }) =>
|
||
deleteLlmWikiDocument(id, documentId),
|
||
onSuccess: invalidateKnowledge,
|
||
}),
|
||
reprocessDocument: useMutation({
|
||
mutationFn: ({ id, documentId }: { id: string; documentId: string }) =>
|
||
reprocessLlmWikiDocument(id, documentId),
|
||
onSuccess: invalidateKnowledge,
|
||
}),
|
||
createWikiPage: useMutation({
|
||
mutationFn: ({ id, input }: { id: string; input: LlmWikiWikiPageCreate }) =>
|
||
createLlmWikiWikiPage(id, input),
|
||
onSuccess: invalidateKnowledge,
|
||
}),
|
||
updateWikiPage: useMutation({
|
||
mutationFn: ({ id, slug, input }: { id: string; slug: string; input: LlmWikiWikiPageUpdate }) =>
|
||
updateLlmWikiWikiPage(id, slug, input),
|
||
onSuccess: invalidateKnowledge,
|
||
}),
|
||
removeWikiPage: useMutation({
|
||
mutationFn: ({ id, slug }: { id: string; slug: string }) =>
|
||
deleteLlmWikiWikiPage(id, slug),
|
||
onSuccess: invalidateKnowledge,
|
||
}),
|
||
vectorizeWiki: useMutation({
|
||
mutationFn: ({ id }: { id: string }) => vectorizeLlmWikiKnowledgeBase(id),
|
||
onSuccess: invalidateKnowledge,
|
||
}),
|
||
exportWikiExcel: useMutation({
|
||
mutationFn: ({ id, name }: { id: string; name?: string }) =>
|
||
exportLlmWikiWikiExcel(id, name),
|
||
}),
|
||
publication: useMutation({
|
||
mutationFn: ({ id, publish }: { id: string; publish: boolean }) =>
|
||
setLlmWikiPublication(id, publish),
|
||
onSuccess: invalidateKnowledge,
|
||
}),
|
||
};
|
||
}
|
||
|
||
export function useLlmWikiSettingsActions() {
|
||
const queryClient = useQueryClient();
|
||
const invalidate = async () => {
|
||
await queryClient.invalidateQueries({ queryKey: ["llmwiki"] });
|
||
};
|
||
return {
|
||
save: useMutation({ mutationFn: saveLlmWikiSettings, onSuccess: invalidate }),
|
||
reset: useMutation({ mutationFn: resetLlmWikiSettings, onSuccess: invalidate }),
|
||
test: useMutation({ mutationFn: testLlmWikiConnection }),
|
||
};
|
||
}
|