feat(rag): align LightRAG native citations and MCP bridge
This commit is contained in:
@@ -994,6 +994,14 @@ pub struct OfficePreviewQuery {
|
||||
source_map_path: Option<String>,
|
||||
#[serde(default, alias = "blockId")]
|
||||
block_id: Option<String>,
|
||||
#[serde(default, alias = "paragraphOrdinal")]
|
||||
paragraph_ordinal: Option<String>,
|
||||
#[serde(default, alias = "paraIdStart")]
|
||||
para_id_start: Option<String>,
|
||||
#[serde(default, alias = "paraIdEnd")]
|
||||
para_id_end: Option<String>,
|
||||
#[serde(default, alias = "textFingerprint")]
|
||||
text_fingerprint: Option<String>,
|
||||
#[serde(default, alias = "evidenceText")]
|
||||
evidence_text: Option<String>,
|
||||
#[serde(default, alias = "searchQuery")]
|
||||
@@ -1032,6 +1040,10 @@ pub async fn office_preview_page(Query(query): Query<OfficePreviewQuery>) -> Res
|
||||
let target_bbox = query.bbox.unwrap_or_default();
|
||||
let target_source_map_path = query.source_map_path.unwrap_or_default();
|
||||
let target_block_id = query.block_id.unwrap_or_default();
|
||||
let target_paragraph_ordinal = query.paragraph_ordinal.unwrap_or_default();
|
||||
let target_para_id_start = query.para_id_start.unwrap_or_default();
|
||||
let target_para_id_end = query.para_id_end.unwrap_or_default();
|
||||
let target_text_fingerprint = query.text_fingerprint.unwrap_or_default();
|
||||
let target_evidence_text = query.evidence_text.unwrap_or_default();
|
||||
let target_search_query = query.search_query.unwrap_or_default();
|
||||
let html = format!(
|
||||
@@ -1080,7 +1092,7 @@ pub async fn office_preview_page(Query(query): Query<OfficePreviewQuery>) -> Res
|
||||
}}
|
||||
</style>
|
||||
</head>
|
||||
<body data-file-url="{file_url}" data-file-name="{file_name}" data-file-type="{file_type}" data-page-width-content-type="{page_width_content_type}" data-workspace-id="{workspace_id}" data-mnote-source-kind="{source_kind}" data-mnote-root-uri="{root_uri}" data-document-id="{document_id}" data-evidence-page="{target_page}" data-evidence-bbox="{target_bbox}" data-evidence-source-map-path="{target_source_map_path}" data-evidence-block-id="{target_block_id}" data-evidence-text="{target_evidence_text}" data-evidence-search-query="{target_search_query}">
|
||||
<body data-file-url="{file_url}" data-file-name="{file_name}" data-file-type="{file_type}" data-page-width-content-type="{page_width_content_type}" data-workspace-id="{workspace_id}" data-mnote-source-kind="{source_kind}" data-mnote-root-uri="{root_uri}" data-document-id="{document_id}" data-evidence-page="{target_page}" data-evidence-bbox="{target_bbox}" data-evidence-source-map-path="{target_source_map_path}" data-evidence-block-id="{target_block_id}" data-evidence-paragraph-ordinal="{target_paragraph_ordinal}" data-evidence-para-id-start="{target_para_id_start}" data-evidence-para-id-end="{target_para_id_end}" data-evidence-text-fingerprint="{target_text_fingerprint}" data-evidence-text="{target_evidence_text}" data-evidence-search-query="{target_search_query}">
|
||||
<main class="mnote-office-preview">
|
||||
<section class="mnote-office-viewer" id="mnote-office-viewer"></section>
|
||||
</main>
|
||||
@@ -1099,6 +1111,10 @@ pub async fn office_preview_page(Query(query): Query<OfficePreviewQuery>) -> Res
|
||||
let evidenceBbox = body.dataset.evidenceBbox || '';
|
||||
let evidenceSourceMapPath = body.dataset.evidenceSourceMapPath || '';
|
||||
let evidenceBlockId = body.dataset.evidenceBlockId || '';
|
||||
let evidenceParagraphOrdinal = body.dataset.evidenceParagraphOrdinal || '';
|
||||
let evidenceParaIdStart = body.dataset.evidenceParaIdStart || '';
|
||||
let evidenceParaIdEnd = body.dataset.evidenceParaIdEnd || '';
|
||||
let evidenceTextFingerprint = body.dataset.evidenceTextFingerprint || '';
|
||||
let evidenceText = body.dataset.evidenceText || '';
|
||||
let evidenceSearchQuery = body.dataset.evidenceSearchQuery || '';
|
||||
let currentPptxBuffer = null;
|
||||
@@ -1484,6 +1500,17 @@ pub async fn office_preview_page(Query(query): Query<OfficePreviewQuery>) -> Res
|
||||
if (queryIndex >= 0 && normalized.length > 24) push(normalized.slice(0, 36), {{ allowShort: true }});
|
||||
}}
|
||||
const prefixWindow = cleaned.slice(0, 260);
|
||||
if (queryCompact.length >= 2) {{
|
||||
const prefixCompact = compactEvidenceText(prefixWindow);
|
||||
const compactIndex = prefixCompact.indexOf(queryCompact);
|
||||
if (compactIndex >= 0) {{
|
||||
const queryIndex = prefixWindow.indexOf(evidenceSearchQuery);
|
||||
const start = queryIndex >= 0 ? queryIndex : 0;
|
||||
const queryWindow = prefixWindow.slice(start, start + 96).split(/[。;;]/)[0];
|
||||
push(queryWindow, {{ allowShort: true }});
|
||||
queryWindow.split(/[,,]/).slice(0, 2).forEach(part => push(part, {{ allowShort: true }}));
|
||||
}}
|
||||
}}
|
||||
const catalogMatches = prefixWindow.match(/[^,,。;;#]{{2,56}}[,,]\s*[0-90-9]{{1,5}}/g) || [];
|
||||
catalogMatches.slice(0, 8).forEach(match => {{
|
||||
const value = normalizeEvidenceText(match);
|
||||
@@ -1711,6 +1738,42 @@ pub async fn office_preview_page(Query(query): Query<OfficePreviewQuery>) -> Res
|
||||
return markEvidenceTarget(marker);
|
||||
}}
|
||||
|
||||
function evidenceParagraphElements() {{
|
||||
if (!viewer) return [];
|
||||
const paragraphs = Array.from(viewer.querySelectorAll('p, li, td, th, blockquote'))
|
||||
.filter(node => node instanceof HTMLElement)
|
||||
.filter(node => normalizeEvidenceText(node.textContent || '').length > 0);
|
||||
if (paragraphs.length) return paragraphs;
|
||||
return Array.from(viewer.querySelectorAll('div, section.docx, section.mnote-docx'))
|
||||
.filter(node => node instanceof HTMLElement)
|
||||
.filter(node => normalizeEvidenceText(node.textContent || '').length > 0);
|
||||
}}
|
||||
|
||||
function scrollToEvidenceParagraphOrdinal() {{
|
||||
const ordinal = Number(evidenceParagraphOrdinal);
|
||||
if (!Number.isFinite(ordinal) || ordinal < 0) return false;
|
||||
const elements = evidenceParagraphElements();
|
||||
if (!elements.length) return false;
|
||||
const anchors = evidenceParagraphAnchors(evidenceText || evidenceSearchQuery);
|
||||
const indices = [];
|
||||
for (let offset = 0; offset <= 4; offset += 1) {{
|
||||
if (offset === 0) indices.push(ordinal);
|
||||
else {{
|
||||
indices.push(ordinal - offset);
|
||||
indices.push(ordinal + offset);
|
||||
}}
|
||||
}}
|
||||
let best = null;
|
||||
for (const index of indices) {{
|
||||
if (index < 0 || index >= elements.length) continue;
|
||||
const element = elements[index];
|
||||
const score = anchors.length ? scoreEvidenceParagraphElement(element, anchors) : 0;
|
||||
if (!best || score > best.score) best = {{ element, score }};
|
||||
if (score >= 2400 && evidenceElementMatchesSearchQuery(element)) break;
|
||||
}}
|
||||
return best ? markEvidenceTarget(best.element) : false;
|
||||
}}
|
||||
|
||||
function scrollToEvidencePageFallback() {{
|
||||
if (!viewer || !Number.isFinite(evidencePage) || evidencePage <= 0) return false;
|
||||
const pages = Array.from(viewer.querySelectorAll('section.docx, section.mnote-docx, .pptx-preview-slide-wrapper'));
|
||||
@@ -1719,16 +1782,18 @@ pub async fn office_preview_page(Query(query): Query<OfficePreviewQuery>) -> Res
|
||||
}}
|
||||
|
||||
async function applyEvidenceLocator() {{
|
||||
if (!viewer || (!evidencePage && !evidenceBlockId && !evidenceBbox && !evidenceText)) return;
|
||||
if (!viewer || (!evidencePage && !evidenceBlockId && !evidenceBbox && !evidenceText && !evidenceParagraphOrdinal && !evidenceTextFingerprint)) return;
|
||||
try {{
|
||||
const sourceMap = await fetchEvidenceSourceMap();
|
||||
const block = findEvidenceBlockInSourceMap(sourceMap);
|
||||
if (evidenceParagraphOrdinal && scrollToEvidenceParagraphOrdinal()) return;
|
||||
if (evidenceText && scrollToEvidenceParagraph(evidenceText)) return;
|
||||
if (block && scrollToEvidenceParagraph(block.text)) return;
|
||||
if (evidenceText && scrollToEvidenceTextCandidates(evidenceText)) return;
|
||||
if (block && scrollToEvidenceTextCandidates(block.text)) return;
|
||||
if (scrollToEvidenceCoordinate(sourceMap, block)) return;
|
||||
}} catch (_) {{}}
|
||||
if (evidenceParagraphOrdinal && scrollToEvidenceParagraphOrdinal()) return;
|
||||
if (evidenceText && scrollToEvidenceParagraph(evidenceText)) return;
|
||||
if (evidenceText && scrollToEvidenceTextCandidates(evidenceText)) return;
|
||||
scrollToEvidencePageFallback();
|
||||
@@ -1740,12 +1805,20 @@ pub async fn office_preview_page(Query(query): Query<OfficePreviewQuery>) -> Res
|
||||
evidenceBbox = String(next.bbox || '');
|
||||
evidenceSourceMapPath = String(next.sourceMapPath || '');
|
||||
evidenceBlockId = String(next.blockId || '');
|
||||
evidenceParagraphOrdinal = String(next.paragraphOrdinal || '');
|
||||
evidenceParaIdStart = String(next.paraIdStart || '');
|
||||
evidenceParaIdEnd = String(next.paraIdEnd || '');
|
||||
evidenceTextFingerprint = String(next.textFingerprint || '');
|
||||
evidenceText = String(next.evidenceText || next.query || '');
|
||||
evidenceSearchQuery = String(next.searchQuery || '');
|
||||
body.dataset.evidencePage = evidencePage ? String(evidencePage) : '';
|
||||
body.dataset.evidenceBbox = evidenceBbox;
|
||||
body.dataset.evidenceSourceMapPath = evidenceSourceMapPath;
|
||||
body.dataset.evidenceBlockId = evidenceBlockId;
|
||||
body.dataset.evidenceParagraphOrdinal = evidenceParagraphOrdinal;
|
||||
body.dataset.evidenceParaIdStart = evidenceParaIdStart;
|
||||
body.dataset.evidenceParaIdEnd = evidenceParaIdEnd;
|
||||
body.dataset.evidenceTextFingerprint = evidenceTextFingerprint;
|
||||
body.dataset.evidenceText = evidenceText;
|
||||
body.dataset.evidenceSearchQuery = evidenceSearchQuery;
|
||||
document.documentElement.removeAttribute('data-mnote-office-evidence-applied');
|
||||
@@ -1969,6 +2042,10 @@ pub async fn office_preview_page(Query(query): Query<OfficePreviewQuery>) -> Res
|
||||
target_bbox = escape_html(&target_bbox),
|
||||
target_source_map_path = escape_html(&target_source_map_path),
|
||||
target_block_id = escape_html(&target_block_id),
|
||||
target_paragraph_ordinal = escape_html(&target_paragraph_ordinal),
|
||||
target_para_id_start = escape_html(&target_para_id_start),
|
||||
target_para_id_end = escape_html(&target_para_id_end),
|
||||
target_text_fingerprint = escape_html(&target_text_fingerprint),
|
||||
target_evidence_text = escape_html(&target_evidence_text),
|
||||
);
|
||||
let mut response = Html(html).into_response();
|
||||
|
||||
Reference in New Issue
Block a user