feat(knowledge): 可跳转 wikilink + 真实相关 note + 一对话多页
- [[wikilink]] 解析器:note id / vault_path / 标题 / vault 元页 / missing
- 前端 MarkdownRenderer 把非数字 [[...]] 渲染成可点链接,元页弹窗查看,缺失置灰
- vault 脚手架补建项目 hub 页,三个结构性链接(index/taxonomy/hub)始终可跳
- capture 时按标题+摘要+区分性标签检索同主题 note,注入真实 [[标题]] 到 Related + 记 related 图谱边
- LLM 提取支持 notes[] 数组,一次对话拆 1~4 页并按标题互链(multi_note_enabled 开关)
- 新增接口 POST /resolve、GET /notes/{id}/wikilinks、GET /vault-page
- 新增配置 related_notes_enabled / related_notes_limit / multi_note_enabled
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
1 parent
92a46003f8
commit
df3fac1032
13 files changed
+668
-72
No files matched your search
@@ -10,6 +10,8 @@ import type {
|
||||
KnowledgeListResponse,
|
||||
KnowledgeNote,
|
||||
KnowledgeSearchItem,
|
||||
VaultPage,
|
||||
WikilinkResolutionMap,
|
||||
} from "./types";
|
||||
|
||||
const baseUrl = () => `${getBackendBaseURL()}/api/knowledge`;
|
||||
@@ -125,6 +127,35 @@ export async function ingestThreadsBatch(payload: BatchIngestPayload = {}) {
|
||||
);
|
||||
}
|
||||
|
||||
/** Resolve `[[wikilink]]` targets to note ids / vault pages. */
|
||||
export async function resolveWikilinks(targets: string[]) {
|
||||
const res = await parseResponse<{ resolved: WikilinkResolutionMap }>(
|
||||
await apiFetch(`${baseUrl()}/resolve`, {
|
||||
method: "POST",
|
||||
headers: { "Content-Type": "application/json" },
|
||||
body: JSON.stringify({ targets }),
|
||||
}),
|
||||
);
|
||||
return res.resolved;
|
||||
}
|
||||
|
||||
/** Resolve every `[[wikilink]]` inside a note's body in one call. */
|
||||
export async function resolveNoteWikilinks(noteId: string) {
|
||||
const res = await parseResponse<{ resolved: WikilinkResolutionMap }>(
|
||||
await apiFetch(
|
||||
`${baseUrl()}/notes/${encodeURIComponent(noteId)}/wikilinks`,
|
||||
),
|
||||
);
|
||||
return res.resolved;
|
||||
}
|
||||
|
||||
/** Fetch a raw vault meta/hub Markdown page (no DB note) by its path. */
|
||||
export async function fetchVaultPage(path: string) {
|
||||
return parseResponse<VaultPage>(
|
||||
await apiFetch(`${baseUrl()}/vault-page?path=${encodeURIComponent(path)}`),
|
||||
);
|
||||
}
|
||||
|
||||
export async function exportKnowledgeGraph() {
|
||||
return parseResponse<GraphExportResult>(
|
||||
await apiFetch(`${baseUrl()}/export/graph`, { method: "POST" }),
|
||||
|
||||
@@ -9,12 +9,14 @@ import {
|
||||
createKnowledgeNote,
|
||||
deleteKnowledgeNote,
|
||||
exportKnowledgeGraph,
|
||||
fetchVaultPage,
|
||||
getKnowledgeNote,
|
||||
ingestThread,
|
||||
ingestThreadsBatch,
|
||||
listDuplicates,
|
||||
listKnowledgeNotes,
|
||||
mergeKnowledgeNotes,
|
||||
resolveNoteWikilinks,
|
||||
searchKnowledge,
|
||||
updateKnowledgeNote,
|
||||
} from "./api";
|
||||
@@ -40,6 +42,24 @@ export function useKnowledgeNote(noteId: string | undefined) {
|
||||
});
|
||||
}
|
||||
|
||||
export function useNoteWikilinks(noteId: string | undefined) {
|
||||
return useQuery({
|
||||
queryKey: [...ROOT_KEY, "wikilinks", noteId],
|
||||
queryFn: () => resolveNoteWikilinks(noteId as string),
|
||||
enabled: !!noteId,
|
||||
refetchOnWindowFocus: false,
|
||||
});
|
||||
}
|
||||
|
||||
export function useVaultPage(path: string | undefined) {
|
||||
return useQuery({
|
||||
queryKey: [...ROOT_KEY, "vault-page", path],
|
||||
queryFn: () => fetchVaultPage(path as string),
|
||||
enabled: !!path,
|
||||
refetchOnWindowFocus: false,
|
||||
});
|
||||
}
|
||||
|
||||
export function useKnowledgeSearch(query: string, enabled: boolean) {
|
||||
return useQuery({
|
||||
queryKey: [...ROOT_KEY, "search", query],
|
||||
|
||||
@@ -52,6 +52,27 @@ export interface KnowledgeListParams {
|
||||
offset?: number;
|
||||
}
|
||||
|
||||
export type WikilinkKind = "note" | "vault" | "missing";
|
||||
|
||||
export interface WikilinkResolution {
|
||||
target: string;
|
||||
normalized?: string;
|
||||
kind: WikilinkKind;
|
||||
exists: boolean;
|
||||
note_id?: string;
|
||||
vault_path?: string;
|
||||
title?: string;
|
||||
}
|
||||
|
||||
/** Map of original `[[target]]` string → its resolution. */
|
||||
export type WikilinkResolutionMap = Record<string, WikilinkResolution>;
|
||||
|
||||
export interface VaultPage {
|
||||
path: string;
|
||||
title: string;
|
||||
content_md: string;
|
||||
}
|
||||
|
||||
export interface KnowledgeSearchItem {
|
||||
note_id: string;
|
||||
chunk_id?: string | null;
|
||||
|
||||
Reference in new issue
Block a user