@absolutejs/absolute 0.19.0-beta.603 → 0.19.0-beta.605
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/ai/client/index.js +244 -10
- package/dist/ai/client/index.js.map +4 -4
- package/dist/ai/client/ui.js +248 -10
- package/dist/ai/client/ui.js.map +4 -4
- package/dist/ai/index.js +1003 -110
- package/dist/ai/index.js.map +8 -8
- package/dist/ai/rag/quality.js +27 -6
- package/dist/ai/rag/quality.js.map +3 -3
- package/dist/ai/rag/ui.js +248 -10
- package/dist/ai/rag/ui.js.map +4 -4
- package/dist/ai-client/angular/ai/index.js +243 -9
- package/dist/ai-client/react/ai/index.js +258 -10
- package/dist/ai-client/vue/ai/index.js +347 -101
- package/dist/angular/ai/index.js +244 -10
- package/dist/angular/ai/index.js.map +4 -4
- package/dist/react/ai/index.js +259 -11
- package/dist/react/ai/index.js.map +6 -6
- package/dist/src/ai/client/ui.d.ts +1 -1
- package/dist/src/ai/rag/index.d.ts +1 -1
- package/dist/src/ai/rag/presentation.d.ts +12 -1
- package/dist/src/ai/rag/ui.d.ts +1 -1
- package/dist/src/react/ai/useRAG.d.ts +5 -0
- package/dist/src/react/ai/useRAGChunkPreview.d.ts +4 -0
- package/dist/src/react/ai/useRAGSources.d.ts +1 -0
- package/dist/src/svelte/ai/createRAG.d.ts +5 -0
- package/dist/src/svelte/ai/createRAGChunkPreview.d.ts +4 -0
- package/dist/src/svelte/ai/createRAGSources.d.ts +1 -0
- package/dist/src/vue/ai/useRAG.d.ts +125 -0
- package/dist/src/vue/ai/useRAGChunkPreview.d.ts +54 -0
- package/dist/src/vue/ai/useRAGDocuments.d.ts +20 -0
- package/dist/src/vue/ai/useRAGIndexAdmin.d.ts +10 -0
- package/dist/src/vue/ai/useRAGSearch.d.ts +40 -0
- package/dist/src/vue/ai/useRAGSources.d.ts +1 -0
- package/dist/svelte/ai/index.js +305 -57
- package/dist/svelte/ai/index.js.map +6 -6
- package/dist/types/ai.d.ts +102 -1
- package/dist/vue/ai/index.js +311 -63
- package/dist/vue/ai/index.js.map +6 -6
- package/package.json +1 -1
|
@@ -631,7 +631,7 @@ var useAIStream = (path, conversationId) => {
|
|
|
631
631
|
};
|
|
632
632
|
};
|
|
633
633
|
// src/vue/ai/useRAGChunkPreview.ts
|
|
634
|
-
import { ref as ref2 } from "vue";
|
|
634
|
+
import { computed, ref as ref2 } from "vue";
|
|
635
635
|
|
|
636
636
|
// src/constants.ts
|
|
637
637
|
var HOURS_IN_DAY = 24;
|
|
@@ -1714,48 +1714,6 @@ var createRAGClient = (options) => {
|
|
|
1714
1714
|
};
|
|
1715
1715
|
};
|
|
1716
1716
|
|
|
1717
|
-
// src/vue/ai/useRAGChunkPreview.ts
|
|
1718
|
-
var useRAGChunkPreview = (path) => {
|
|
1719
|
-
const client = createRAGClient({ path });
|
|
1720
|
-
const preview = ref2(null);
|
|
1721
|
-
const error = ref2(null);
|
|
1722
|
-
const isLoading = ref2(false);
|
|
1723
|
-
const inspect = async (id) => {
|
|
1724
|
-
isLoading.value = true;
|
|
1725
|
-
error.value = null;
|
|
1726
|
-
try {
|
|
1727
|
-
const response = await client.documentChunks(id);
|
|
1728
|
-
if (!response.ok) {
|
|
1729
|
-
throw new Error(response.error);
|
|
1730
|
-
}
|
|
1731
|
-
preview.value = response;
|
|
1732
|
-
return response;
|
|
1733
|
-
} catch (caught) {
|
|
1734
|
-
error.value = caught instanceof Error ? caught.message : String(caught);
|
|
1735
|
-
throw caught;
|
|
1736
|
-
} finally {
|
|
1737
|
-
isLoading.value = false;
|
|
1738
|
-
}
|
|
1739
|
-
};
|
|
1740
|
-
const clear = () => {
|
|
1741
|
-
error.value = null;
|
|
1742
|
-
isLoading.value = false;
|
|
1743
|
-
preview.value = null;
|
|
1744
|
-
};
|
|
1745
|
-
return {
|
|
1746
|
-
clear,
|
|
1747
|
-
error,
|
|
1748
|
-
inspect,
|
|
1749
|
-
isLoading,
|
|
1750
|
-
preview
|
|
1751
|
-
};
|
|
1752
|
-
};
|
|
1753
|
-
// src/vue/ai/useRAG.ts
|
|
1754
|
-
import { computed as computed8 } from "vue";
|
|
1755
|
-
|
|
1756
|
-
// src/vue/ai/useRAGCitations.ts
|
|
1757
|
-
import { computed } from "vue";
|
|
1758
|
-
|
|
1759
1717
|
// src/ai/rag/grounding.ts
|
|
1760
1718
|
var getContextString = (value) => typeof value === "string" && value.trim().length > 0 ? value.trim() : undefined;
|
|
1761
1719
|
var getContextNumber = (value) => typeof value === "number" && Number.isFinite(value) ? value : undefined;
|
|
@@ -1783,6 +1741,10 @@ var buildContextLabel = (metadata) => {
|
|
|
1783
1741
|
return from ? `Message from ${from}` : "Message evidence";
|
|
1784
1742
|
}
|
|
1785
1743
|
const page = getContextNumber(metadata.page) ?? getContextNumber(metadata.pageNumber) ?? (typeof metadata.pageIndex === "number" ? metadata.pageIndex + 1 : undefined);
|
|
1744
|
+
const region = getContextNumber(metadata.regionNumber) ?? (typeof metadata.regionIndex === "number" ? metadata.regionIndex + 1 : undefined);
|
|
1745
|
+
if (page && region) {
|
|
1746
|
+
return `Page ${page} region ${region}`;
|
|
1747
|
+
}
|
|
1786
1748
|
if (page) {
|
|
1787
1749
|
return `Page ${page}`;
|
|
1788
1750
|
}
|
|
@@ -1806,6 +1768,11 @@ var buildContextLabel = (metadata) => {
|
|
|
1806
1768
|
if (speaker) {
|
|
1807
1769
|
return `Speaker ${speaker}`;
|
|
1808
1770
|
}
|
|
1771
|
+
const sectionPath = Array.isArray(metadata.sectionPath) ? metadata.sectionPath.map((value) => getContextString(value)).filter((value) => typeof value === "string") : [];
|
|
1772
|
+
const sectionTitle = getContextString(metadata.sectionTitle) ?? sectionPath.at(-1);
|
|
1773
|
+
if (sectionTitle) {
|
|
1774
|
+
return `Section ${sectionTitle}`;
|
|
1775
|
+
}
|
|
1809
1776
|
return;
|
|
1810
1777
|
};
|
|
1811
1778
|
var formatMediaTimestamp = (value) => {
|
|
@@ -1823,6 +1790,10 @@ var buildLocatorLabel = (metadata, source, title) => {
|
|
|
1823
1790
|
return;
|
|
1824
1791
|
}
|
|
1825
1792
|
const page = getContextNumber(metadata.page) ?? getContextNumber(metadata.pageNumber) ?? (typeof metadata.pageIndex === "number" ? metadata.pageIndex + 1 : undefined);
|
|
1793
|
+
const region = getContextNumber(metadata.regionNumber) ?? (typeof metadata.regionIndex === "number" ? metadata.regionIndex + 1 : undefined);
|
|
1794
|
+
if (page && region) {
|
|
1795
|
+
return `Page ${page} · Region ${region}`;
|
|
1796
|
+
}
|
|
1826
1797
|
if (page) {
|
|
1827
1798
|
return `Page ${page}`;
|
|
1828
1799
|
}
|
|
@@ -1851,6 +1822,10 @@ var buildLocatorLabel = (metadata, source, title) => {
|
|
|
1851
1822
|
if (mediaStart) {
|
|
1852
1823
|
return `Timestamp ${mediaStart}`;
|
|
1853
1824
|
}
|
|
1825
|
+
const sectionPath = Array.isArray(metadata.sectionPath) ? metadata.sectionPath.map((value) => getContextString(value)).filter((value) => typeof value === "string") : [];
|
|
1826
|
+
if (sectionPath.length > 0) {
|
|
1827
|
+
return `Section ${sectionPath.join(" > ")}`;
|
|
1828
|
+
}
|
|
1854
1829
|
return;
|
|
1855
1830
|
};
|
|
1856
1831
|
var formatTimestampLabel = (value) => {
|
|
@@ -1875,9 +1850,11 @@ var buildProvenanceLabel = (metadata) => {
|
|
|
1875
1850
|
const transcriptSource = getContextString(metadata.transcriptSource);
|
|
1876
1851
|
const pdfTextMode = getContextString(metadata.pdfTextMode);
|
|
1877
1852
|
const ocrEngine = getContextString(metadata.ocrEngine);
|
|
1853
|
+
const ocrConfidence = getContextNumber(metadata.ocrRegionConfidence) ?? getContextNumber(metadata.ocrConfidence);
|
|
1878
1854
|
const labels = [
|
|
1879
1855
|
pdfTextMode ? `PDF ${pdfTextMode}` : "",
|
|
1880
1856
|
ocrEngine ? `OCR ${ocrEngine}` : "",
|
|
1857
|
+
typeof ocrConfidence === "number" ? `Confidence ${ocrConfidence.toFixed(2)}` : "",
|
|
1881
1858
|
mediaKind ? `Media ${mediaKind}` : "",
|
|
1882
1859
|
transcriptSource ? `Transcript ${transcriptSource}` : "",
|
|
1883
1860
|
threadTopic ? `Thread ${threadTopic}` : "",
|
|
@@ -1898,8 +1875,10 @@ var buildExcerpt = (text, maxLength = 160) => {
|
|
|
1898
1875
|
var buildGroundingReferenceEvidenceLabel = (reference) => [reference.label, reference.locatorLabel, reference.contextLabel].filter((value) => Boolean(value && value.length > 0)).filter((value, index, values) => values.findIndex((entry) => entry === value) === index).join(" · ");
|
|
1899
1876
|
var buildGroundingReferenceEvidenceSummary = (reference) => [
|
|
1900
1877
|
reference.source ?? reference.title ?? reference.chunkId,
|
|
1878
|
+
reference.locatorLabel,
|
|
1879
|
+
reference.contextLabel,
|
|
1901
1880
|
reference.provenanceLabel
|
|
1902
|
-
].filter((value) => Boolean(value && value.length > 0)).join(" · ");
|
|
1881
|
+
].filter((value) => Boolean(value && value.length > 0)).filter((value, index, values) => values.findIndex((entry) => entry === value) === index).join(" · ");
|
|
1903
1882
|
var buildGroundedAnswerCitationDetail = (reference) => ({
|
|
1904
1883
|
contextLabel: reference.contextLabel,
|
|
1905
1884
|
evidenceLabel: buildGroundingReferenceEvidenceLabel(reference),
|
|
@@ -1923,12 +1902,12 @@ var buildRAGCitations = (sources) => {
|
|
|
1923
1902
|
continue;
|
|
1924
1903
|
unique.set(key, {
|
|
1925
1904
|
chunkId: source.chunkId,
|
|
1926
|
-
contextLabel: buildContextLabel(source.metadata),
|
|
1905
|
+
contextLabel: source.labels?.contextLabel ?? buildContextLabel(source.metadata),
|
|
1927
1906
|
key,
|
|
1928
1907
|
label: buildSourceLabel(source),
|
|
1929
|
-
locatorLabel: buildLocatorLabel(source.metadata, source.source, source.title),
|
|
1908
|
+
locatorLabel: source.labels?.locatorLabel ?? buildLocatorLabel(source.metadata, source.source, source.title),
|
|
1930
1909
|
metadata: source.metadata,
|
|
1931
|
-
provenanceLabel: buildProvenanceLabel(source.metadata),
|
|
1910
|
+
provenanceLabel: source.labels?.provenanceLabel ?? buildProvenanceLabel(source.metadata),
|
|
1932
1911
|
score: source.score,
|
|
1933
1912
|
source: source.source,
|
|
1934
1913
|
text: source.text,
|
|
@@ -1998,7 +1977,7 @@ var buildRAGGroundingReferences = (sources) => {
|
|
|
1998
1977
|
const citationReferenceMap = buildRAGCitationReferenceMap(citations);
|
|
1999
1978
|
return citations.map((citation) => ({
|
|
2000
1979
|
chunkId: citation.chunkId,
|
|
2001
|
-
contextLabel: buildContextLabel(citation.metadata),
|
|
1980
|
+
contextLabel: citation.contextLabel ?? buildContextLabel(citation.metadata),
|
|
2002
1981
|
excerpt: buildExcerpt(citation.text),
|
|
2003
1982
|
label: citation.label,
|
|
2004
1983
|
locatorLabel: citation.locatorLabel ?? buildLocatorLabel(citation.metadata, citation.source, citation.title),
|
|
@@ -2068,6 +2047,10 @@ var buildContextLabel2 = (metadata) => {
|
|
|
2068
2047
|
return from ? `Message from ${from}` : "Message evidence";
|
|
2069
2048
|
}
|
|
2070
2049
|
const page = getContextNumber2(metadata.page) ?? getContextNumber2(metadata.pageNumber) ?? (typeof metadata.pageIndex === "number" ? metadata.pageIndex + 1 : undefined);
|
|
2050
|
+
const region = getContextNumber2(metadata.regionNumber) ?? (typeof metadata.regionIndex === "number" ? metadata.regionIndex + 1 : undefined);
|
|
2051
|
+
if (page && region) {
|
|
2052
|
+
return `Page ${page} region ${region}`;
|
|
2053
|
+
}
|
|
2071
2054
|
if (page) {
|
|
2072
2055
|
return `Page ${page}`;
|
|
2073
2056
|
}
|
|
@@ -2091,6 +2074,11 @@ var buildContextLabel2 = (metadata) => {
|
|
|
2091
2074
|
if (speaker) {
|
|
2092
2075
|
return `Speaker ${speaker}`;
|
|
2093
2076
|
}
|
|
2077
|
+
const sectionPath = Array.isArray(metadata.sectionPath) ? metadata.sectionPath.map((value) => getContextString2(value)).filter((value) => typeof value === "string") : [];
|
|
2078
|
+
const sectionTitle = getContextString2(metadata.sectionTitle) ?? sectionPath.at(-1);
|
|
2079
|
+
if (sectionTitle) {
|
|
2080
|
+
return `Section ${sectionTitle}`;
|
|
2081
|
+
}
|
|
2094
2082
|
return;
|
|
2095
2083
|
};
|
|
2096
2084
|
var buildLocatorLabel2 = (metadata, source, title) => {
|
|
@@ -2098,6 +2086,10 @@ var buildLocatorLabel2 = (metadata, source, title) => {
|
|
|
2098
2086
|
return;
|
|
2099
2087
|
}
|
|
2100
2088
|
const page = getContextNumber2(metadata.page) ?? getContextNumber2(metadata.pageNumber) ?? (typeof metadata.pageIndex === "number" ? metadata.pageIndex + 1 : undefined);
|
|
2089
|
+
const region = getContextNumber2(metadata.regionNumber) ?? (typeof metadata.regionIndex === "number" ? metadata.regionIndex + 1 : undefined);
|
|
2090
|
+
if (page && region) {
|
|
2091
|
+
return `Page ${page} · Region ${region}`;
|
|
2092
|
+
}
|
|
2101
2093
|
if (page) {
|
|
2102
2094
|
return `Page ${page}`;
|
|
2103
2095
|
}
|
|
@@ -2126,6 +2118,10 @@ var buildLocatorLabel2 = (metadata, source, title) => {
|
|
|
2126
2118
|
if (mediaStart) {
|
|
2127
2119
|
return `Timestamp ${mediaStart}`;
|
|
2128
2120
|
}
|
|
2121
|
+
const sectionPath = Array.isArray(metadata.sectionPath) ? metadata.sectionPath.map((value) => getContextString2(value)).filter((value) => typeof value === "string") : [];
|
|
2122
|
+
if (sectionPath.length > 0) {
|
|
2123
|
+
return `Section ${sectionPath.join(" > ")}`;
|
|
2124
|
+
}
|
|
2129
2125
|
return;
|
|
2130
2126
|
};
|
|
2131
2127
|
var buildProvenanceLabel2 = (metadata) => {
|
|
@@ -2140,9 +2136,11 @@ var buildProvenanceLabel2 = (metadata) => {
|
|
|
2140
2136
|
const transcriptSource = getContextString2(metadata.transcriptSource);
|
|
2141
2137
|
const pdfTextMode = getContextString2(metadata.pdfTextMode);
|
|
2142
2138
|
const ocrEngine = getContextString2(metadata.ocrEngine);
|
|
2139
|
+
const ocrConfidence = getContextNumber2(metadata.ocrRegionConfidence) ?? getContextNumber2(metadata.ocrConfidence);
|
|
2143
2140
|
const labels = [
|
|
2144
2141
|
pdfTextMode ? `PDF ${pdfTextMode}` : "",
|
|
2145
2142
|
ocrEngine ? `OCR ${ocrEngine}` : "",
|
|
2143
|
+
typeof ocrConfidence === "number" ? `Confidence ${ocrConfidence.toFixed(2)}` : "",
|
|
2146
2144
|
mediaKind ? `Media ${mediaKind}` : "",
|
|
2147
2145
|
transcriptSource ? `Transcript ${transcriptSource}` : "",
|
|
2148
2146
|
threadTopic ? `Thread ${threadTopic}` : "",
|
|
@@ -2152,6 +2150,50 @@ var buildProvenanceLabel2 = (metadata) => {
|
|
|
2152
2150
|
].filter((value) => value.length > 0);
|
|
2153
2151
|
return labels.length > 0 ? labels.join(" · ") : undefined;
|
|
2154
2152
|
};
|
|
2153
|
+
var buildRAGSourceLabels = ({
|
|
2154
|
+
metadata,
|
|
2155
|
+
source,
|
|
2156
|
+
title
|
|
2157
|
+
}) => {
|
|
2158
|
+
const contextLabel = buildContextLabel2(metadata);
|
|
2159
|
+
const locatorLabel = buildLocatorLabel2(metadata, source, title);
|
|
2160
|
+
const provenanceLabel = buildProvenanceLabel2(metadata);
|
|
2161
|
+
if (!contextLabel && !locatorLabel && !provenanceLabel) {
|
|
2162
|
+
return;
|
|
2163
|
+
}
|
|
2164
|
+
return {
|
|
2165
|
+
contextLabel,
|
|
2166
|
+
locatorLabel,
|
|
2167
|
+
provenanceLabel
|
|
2168
|
+
};
|
|
2169
|
+
};
|
|
2170
|
+
var buildRAGChunkStructure = (metadata) => {
|
|
2171
|
+
if (!metadata) {
|
|
2172
|
+
return;
|
|
2173
|
+
}
|
|
2174
|
+
const sectionPath = Array.isArray(metadata.sectionPath) ? metadata.sectionPath.filter((value) => typeof value === "string" && value.trim().length > 0) : undefined;
|
|
2175
|
+
const sectionKind = metadata.sectionKind === "markdown_heading" || metadata.sectionKind === "html_heading" ? metadata.sectionKind : undefined;
|
|
2176
|
+
const section = {
|
|
2177
|
+
depth: getContextNumber2(metadata.sectionDepth),
|
|
2178
|
+
kind: sectionKind,
|
|
2179
|
+
path: sectionPath && sectionPath.length > 0 ? sectionPath : undefined,
|
|
2180
|
+
title: getContextString2(metadata.sectionTitle)
|
|
2181
|
+
};
|
|
2182
|
+
const sequence = {
|
|
2183
|
+
nextChunkId: getContextString2(metadata.nextChunkId),
|
|
2184
|
+
previousChunkId: getContextString2(metadata.previousChunkId),
|
|
2185
|
+
sectionChunkCount: getContextNumber2(metadata.sectionChunkCount),
|
|
2186
|
+
sectionChunkId: getContextString2(metadata.sectionChunkId),
|
|
2187
|
+
sectionChunkIndex: getContextNumber2(metadata.sectionChunkIndex)
|
|
2188
|
+
};
|
|
2189
|
+
if (!section.title && (!section.path || section.path.length === 0) && typeof section.depth !== "number" && !section.kind && !sequence.nextChunkId && !sequence.previousChunkId && typeof sequence.sectionChunkCount !== "number" && !sequence.sectionChunkId && typeof sequence.sectionChunkIndex !== "number") {
|
|
2190
|
+
return;
|
|
2191
|
+
}
|
|
2192
|
+
return {
|
|
2193
|
+
section: section.title || section.path && section.path.length > 0 || typeof section.depth === "number" || section.kind ? section : undefined,
|
|
2194
|
+
sequence: sequence.nextChunkId || sequence.previousChunkId || typeof sequence.sectionChunkCount === "number" || sequence.sectionChunkId || typeof sequence.sectionChunkIndex === "number" ? sequence : undefined
|
|
2195
|
+
};
|
|
2196
|
+
};
|
|
2155
2197
|
var buildExcerpt2 = (text, maxLength = 160) => {
|
|
2156
2198
|
const normalized = text.replaceAll(/\s+/g, " ").trim();
|
|
2157
2199
|
if (normalized.length <= maxLength) {
|
|
@@ -2159,6 +2201,136 @@ var buildExcerpt2 = (text, maxLength = 160) => {
|
|
|
2159
2201
|
}
|
|
2160
2202
|
return `${normalized.slice(0, Math.max(0, maxLength - 1)).trimEnd()}…`;
|
|
2161
2203
|
};
|
|
2204
|
+
var buildRAGChunkGraph = (chunks) => {
|
|
2205
|
+
const nodes = [];
|
|
2206
|
+
const edges = [];
|
|
2207
|
+
const edgeKeys = new Set;
|
|
2208
|
+
const sections = new Map;
|
|
2209
|
+
for (const chunk of chunks) {
|
|
2210
|
+
const labels = chunk.labels ?? buildRAGSourceLabels({
|
|
2211
|
+
metadata: chunk.metadata,
|
|
2212
|
+
source: chunk.source,
|
|
2213
|
+
title: chunk.title
|
|
2214
|
+
});
|
|
2215
|
+
const structure = chunk.structure ?? buildRAGChunkStructure(chunk.metadata);
|
|
2216
|
+
nodes.push({
|
|
2217
|
+
chunkId: chunk.chunkId,
|
|
2218
|
+
contextLabel: labels?.contextLabel,
|
|
2219
|
+
label: chunk.source ?? chunk.title ?? chunk.chunkId,
|
|
2220
|
+
locatorLabel: labels?.locatorLabel,
|
|
2221
|
+
provenanceLabel: labels?.provenanceLabel,
|
|
2222
|
+
score: chunk.score,
|
|
2223
|
+
source: chunk.source,
|
|
2224
|
+
structure,
|
|
2225
|
+
title: chunk.title
|
|
2226
|
+
});
|
|
2227
|
+
const previousChunkId = structure?.sequence?.previousChunkId;
|
|
2228
|
+
if (previousChunkId) {
|
|
2229
|
+
const key = `previous:${previousChunkId}:${chunk.chunkId}`;
|
|
2230
|
+
if (!edgeKeys.has(key)) {
|
|
2231
|
+
edgeKeys.add(key);
|
|
2232
|
+
edges.push({
|
|
2233
|
+
fromChunkId: previousChunkId,
|
|
2234
|
+
relation: "previous",
|
|
2235
|
+
toChunkId: chunk.chunkId
|
|
2236
|
+
});
|
|
2237
|
+
}
|
|
2238
|
+
}
|
|
2239
|
+
const nextChunkId = structure?.sequence?.nextChunkId;
|
|
2240
|
+
if (nextChunkId) {
|
|
2241
|
+
const key = `next:${chunk.chunkId}:${nextChunkId}`;
|
|
2242
|
+
if (!edgeKeys.has(key)) {
|
|
2243
|
+
edgeKeys.add(key);
|
|
2244
|
+
edges.push({
|
|
2245
|
+
fromChunkId: chunk.chunkId,
|
|
2246
|
+
relation: "next",
|
|
2247
|
+
toChunkId: nextChunkId
|
|
2248
|
+
});
|
|
2249
|
+
}
|
|
2250
|
+
}
|
|
2251
|
+
const sectionId = structure?.sequence?.sectionChunkId;
|
|
2252
|
+
if (sectionId) {
|
|
2253
|
+
const existing = sections.get(sectionId);
|
|
2254
|
+
if (!existing) {
|
|
2255
|
+
sections.set(sectionId, {
|
|
2256
|
+
chunkCount: structure.sequence?.sectionChunkCount ?? 1,
|
|
2257
|
+
chunkIds: [chunk.chunkId],
|
|
2258
|
+
depth: structure.section?.depth,
|
|
2259
|
+
id: sectionId,
|
|
2260
|
+
kind: structure.section?.kind,
|
|
2261
|
+
path: structure.section?.path,
|
|
2262
|
+
title: structure.section?.title
|
|
2263
|
+
});
|
|
2264
|
+
continue;
|
|
2265
|
+
}
|
|
2266
|
+
if (!existing.chunkIds.includes(chunk.chunkId)) {
|
|
2267
|
+
existing.chunkIds.push(chunk.chunkId);
|
|
2268
|
+
}
|
|
2269
|
+
existing.chunkCount = Math.max(existing.chunkCount, structure.sequence?.sectionChunkCount ?? existing.chunkCount);
|
|
2270
|
+
}
|
|
2271
|
+
}
|
|
2272
|
+
for (const section of sections.values()) {
|
|
2273
|
+
section.chunkIds.sort((left, right) => {
|
|
2274
|
+
const leftNode = nodes.find((node) => node.chunkId === left);
|
|
2275
|
+
const rightNode = nodes.find((node) => node.chunkId === right);
|
|
2276
|
+
const leftIndex = leftNode?.structure?.sequence?.sectionChunkIndex ?? Number.MAX_SAFE_INTEGER;
|
|
2277
|
+
const rightIndex = rightNode?.structure?.sequence?.sectionChunkIndex ?? Number.MAX_SAFE_INTEGER;
|
|
2278
|
+
if (leftIndex !== rightIndex) {
|
|
2279
|
+
return leftIndex - rightIndex;
|
|
2280
|
+
}
|
|
2281
|
+
return left.localeCompare(right);
|
|
2282
|
+
});
|
|
2283
|
+
}
|
|
2284
|
+
nodes.sort((left, right) => {
|
|
2285
|
+
const leftSection = left.structure?.sequence?.sectionChunkIndex ?? Number.MAX_SAFE_INTEGER;
|
|
2286
|
+
const rightSection = right.structure?.sequence?.sectionChunkIndex ?? Number.MAX_SAFE_INTEGER;
|
|
2287
|
+
if (leftSection !== rightSection) {
|
|
2288
|
+
return leftSection - rightSection;
|
|
2289
|
+
}
|
|
2290
|
+
const leftScore = left.score ?? Number.NEGATIVE_INFINITY;
|
|
2291
|
+
const rightScore = right.score ?? Number.NEGATIVE_INFINITY;
|
|
2292
|
+
if (leftScore !== rightScore) {
|
|
2293
|
+
return rightScore - leftScore;
|
|
2294
|
+
}
|
|
2295
|
+
return left.label.localeCompare(right.label);
|
|
2296
|
+
});
|
|
2297
|
+
return {
|
|
2298
|
+
edges,
|
|
2299
|
+
nodes,
|
|
2300
|
+
sections: [...sections.values()].sort((left, right) => (left.title ?? left.id).localeCompare(right.title ?? right.id))
|
|
2301
|
+
};
|
|
2302
|
+
};
|
|
2303
|
+
var buildRAGChunkPreviewGraph = (preview) => buildRAGChunkGraph(preview.chunks.map((chunk) => ({
|
|
2304
|
+
chunkId: chunk.chunkId,
|
|
2305
|
+
labels: chunk.labels,
|
|
2306
|
+
metadata: chunk.metadata,
|
|
2307
|
+
source: chunk.source ?? preview.document.source,
|
|
2308
|
+
structure: chunk.structure,
|
|
2309
|
+
title: chunk.title ?? preview.document.title
|
|
2310
|
+
})));
|
|
2311
|
+
var buildRAGChunkPreviewNavigation = (preview, activeChunkId) => buildRAGChunkGraphNavigation(buildRAGChunkPreviewGraph(preview), activeChunkId);
|
|
2312
|
+
var buildRAGChunkGraphNavigation = (graph, activeChunkId) => {
|
|
2313
|
+
if (graph.nodes.length === 0) {
|
|
2314
|
+
return {
|
|
2315
|
+
activeChunkId,
|
|
2316
|
+
sectionNodes: []
|
|
2317
|
+
};
|
|
2318
|
+
}
|
|
2319
|
+
const activeNode = (activeChunkId ? graph.nodes.find((node) => node.chunkId === activeChunkId) : undefined) ?? graph.nodes[0];
|
|
2320
|
+
const resolvedActiveChunkId = activeNode?.chunkId;
|
|
2321
|
+
const previousNode = activeNode?.structure?.sequence?.previousChunkId ? graph.nodes.find((node) => node.chunkId === activeNode.structure?.sequence?.previousChunkId) : undefined;
|
|
2322
|
+
const nextNode = activeNode?.structure?.sequence?.nextChunkId ? graph.nodes.find((node) => node.chunkId === activeNode.structure?.sequence?.nextChunkId) : undefined;
|
|
2323
|
+
const section = activeNode?.structure?.sequence?.sectionChunkId ? graph.sections.find((entry) => entry.id === activeNode.structure?.sequence?.sectionChunkId) : undefined;
|
|
2324
|
+
const sectionNodes = section ? section.chunkIds.map((chunkId) => graph.nodes.find((node) => node.chunkId === chunkId)).filter((node) => Boolean(node)) : activeNode ? [activeNode] : [];
|
|
2325
|
+
return {
|
|
2326
|
+
activeChunkId: resolvedActiveChunkId,
|
|
2327
|
+
activeNode,
|
|
2328
|
+
nextNode,
|
|
2329
|
+
previousNode,
|
|
2330
|
+
section,
|
|
2331
|
+
sectionNodes
|
|
2332
|
+
};
|
|
2333
|
+
};
|
|
2162
2334
|
var buildRAGRetrievedState = (messages) => {
|
|
2163
2335
|
const message = getLatestRetrievedMessage(messages);
|
|
2164
2336
|
if (!message) {
|
|
@@ -2193,13 +2365,14 @@ var buildRAGSourceSummaries = (sources) => {
|
|
|
2193
2365
|
citationNumbers: groupCitations.map((citation) => citationReferenceMap[citation.chunkId] ?? 0),
|
|
2194
2366
|
citations: groupCitations,
|
|
2195
2367
|
chunkIds: group.chunks.map((chunk) => chunk.chunkId),
|
|
2196
|
-
contextLabel: buildContextLabel2(leadChunk?.metadata),
|
|
2368
|
+
contextLabel: leadChunk?.labels?.contextLabel ?? buildContextLabel2(leadChunk?.metadata),
|
|
2197
2369
|
count: group.count,
|
|
2198
2370
|
excerpt: buildExcerpt2(leadChunk?.text ?? ""),
|
|
2199
2371
|
key: group.key,
|
|
2200
2372
|
label: group.label,
|
|
2201
|
-
locatorLabel: buildLocatorLabel2(leadChunk?.metadata, leadChunk?.source, leadChunk?.title),
|
|
2202
|
-
provenanceLabel: buildProvenanceLabel2(leadChunk?.metadata),
|
|
2373
|
+
locatorLabel: leadChunk?.labels?.locatorLabel ?? buildLocatorLabel2(leadChunk?.metadata, leadChunk?.source, leadChunk?.title),
|
|
2374
|
+
provenanceLabel: leadChunk?.labels?.provenanceLabel ?? buildProvenanceLabel2(leadChunk?.metadata),
|
|
2375
|
+
structure: leadChunk?.structure ?? buildRAGChunkStructure(leadChunk?.metadata),
|
|
2203
2376
|
source: group.source,
|
|
2204
2377
|
title: group.title
|
|
2205
2378
|
};
|
|
@@ -2323,6 +2496,12 @@ var buildSourceGroup = (source, key) => ({
|
|
|
2323
2496
|
count: 1,
|
|
2324
2497
|
key,
|
|
2325
2498
|
label: buildSourceLabel2(source),
|
|
2499
|
+
labels: source.labels ?? buildRAGSourceLabels({
|
|
2500
|
+
metadata: source.metadata,
|
|
2501
|
+
source: source.source,
|
|
2502
|
+
title: source.title
|
|
2503
|
+
}),
|
|
2504
|
+
structure: source.structure ?? buildRAGChunkStructure(source.metadata),
|
|
2326
2505
|
source: source.source,
|
|
2327
2506
|
title: source.title
|
|
2328
2507
|
});
|
|
@@ -2333,7 +2512,20 @@ var updateSourceGroup = (groups, source) => {
|
|
|
2333
2512
|
groups.set(key, buildSourceGroup(source, key));
|
|
2334
2513
|
return;
|
|
2335
2514
|
}
|
|
2336
|
-
|
|
2515
|
+
if (source.score > existing.bestScore) {
|
|
2516
|
+
existing.bestScore = source.score;
|
|
2517
|
+
existing.label = buildSourceLabel2(source);
|
|
2518
|
+
existing.labels = source.labels ?? buildRAGSourceLabels({
|
|
2519
|
+
metadata: source.metadata,
|
|
2520
|
+
source: source.source,
|
|
2521
|
+
title: source.title
|
|
2522
|
+
});
|
|
2523
|
+
existing.structure = source.structure ?? buildRAGChunkStructure(source.metadata);
|
|
2524
|
+
existing.source = source.source;
|
|
2525
|
+
existing.title = source.title;
|
|
2526
|
+
} else {
|
|
2527
|
+
existing.bestScore = Math.max(existing.bestScore, source.score);
|
|
2528
|
+
}
|
|
2337
2529
|
existing.count += 1;
|
|
2338
2530
|
existing.chunks.push(source);
|
|
2339
2531
|
};
|
|
@@ -2382,13 +2574,65 @@ var resolveRAGStreamStage = ({
|
|
|
2382
2574
|
}
|
|
2383
2575
|
return "streaming";
|
|
2384
2576
|
};
|
|
2577
|
+
// src/vue/ai/useRAGChunkPreview.ts
|
|
2578
|
+
var useRAGChunkPreview = (path) => {
|
|
2579
|
+
const client = createRAGClient({ path });
|
|
2580
|
+
const preview = ref2(null);
|
|
2581
|
+
const activeChunkId = ref2(null);
|
|
2582
|
+
const error = ref2(null);
|
|
2583
|
+
const isLoading = ref2(false);
|
|
2584
|
+
const chunkGraph = computed(() => preview.value ? buildRAGChunkPreviewGraph(preview.value) : null);
|
|
2585
|
+
const navigation = computed(() => preview.value ? buildRAGChunkPreviewNavigation(preview.value, activeChunkId.value ?? undefined) : null);
|
|
2586
|
+
const inspect = async (id) => {
|
|
2587
|
+
isLoading.value = true;
|
|
2588
|
+
error.value = null;
|
|
2589
|
+
try {
|
|
2590
|
+
const response = await client.documentChunks(id);
|
|
2591
|
+
if (!response.ok) {
|
|
2592
|
+
throw new Error(response.error);
|
|
2593
|
+
}
|
|
2594
|
+
preview.value = response;
|
|
2595
|
+
activeChunkId.value = response.chunks[0]?.chunkId ?? null;
|
|
2596
|
+
return response;
|
|
2597
|
+
} catch (caught) {
|
|
2598
|
+
error.value = caught instanceof Error ? caught.message : String(caught);
|
|
2599
|
+
throw caught;
|
|
2600
|
+
} finally {
|
|
2601
|
+
isLoading.value = false;
|
|
2602
|
+
}
|
|
2603
|
+
};
|
|
2604
|
+
const clear = () => {
|
|
2605
|
+
error.value = null;
|
|
2606
|
+
isLoading.value = false;
|
|
2607
|
+
activeChunkId.value = null;
|
|
2608
|
+
preview.value = null;
|
|
2609
|
+
};
|
|
2610
|
+
const selectChunk = (id) => {
|
|
2611
|
+
activeChunkId.value = id;
|
|
2612
|
+
};
|
|
2613
|
+
return {
|
|
2614
|
+
activeChunkId,
|
|
2615
|
+
clear,
|
|
2616
|
+
chunkGraph,
|
|
2617
|
+
error,
|
|
2618
|
+
inspect,
|
|
2619
|
+
isLoading,
|
|
2620
|
+
navigation,
|
|
2621
|
+
preview,
|
|
2622
|
+
selectChunk
|
|
2623
|
+
};
|
|
2624
|
+
};
|
|
2625
|
+
// src/vue/ai/useRAG.ts
|
|
2626
|
+
import { computed as computed9 } from "vue";
|
|
2627
|
+
|
|
2385
2628
|
// src/vue/ai/useRAGCitations.ts
|
|
2629
|
+
import { computed as computed2 } from "vue";
|
|
2386
2630
|
var useRAGCitations = (sources) => {
|
|
2387
|
-
const citations =
|
|
2388
|
-
const citationReferenceMap =
|
|
2389
|
-
const sourceGroups =
|
|
2390
|
-
const sourceSummaries =
|
|
2391
|
-
const hasCitations =
|
|
2631
|
+
const citations = computed2(() => buildRAGCitations(sources.value));
|
|
2632
|
+
const citationReferenceMap = computed2(() => buildRAGCitationReferenceMap(citations.value));
|
|
2633
|
+
const sourceGroups = computed2(() => buildRAGSourceGroups(sources.value));
|
|
2634
|
+
const sourceSummaries = computed2(() => buildRAGSourceSummaries(sources.value));
|
|
2635
|
+
const hasCitations = computed2(() => citations.value.length > 0);
|
|
2392
2636
|
return {
|
|
2393
2637
|
citationReferenceMap,
|
|
2394
2638
|
citations,
|
|
@@ -2438,7 +2682,7 @@ var useRAGDocuments = (path) => {
|
|
|
2438
2682
|
};
|
|
2439
2683
|
|
|
2440
2684
|
// src/vue/ai/useRAGEvaluate.ts
|
|
2441
|
-
import { computed as
|
|
2685
|
+
import { computed as computed3, ref as ref4 } from "vue";
|
|
2442
2686
|
|
|
2443
2687
|
// src/ai/rag/quality.ts
|
|
2444
2688
|
var {mkdir, readFile, writeFile} = (() => ({}));
|
|
@@ -2869,7 +3113,7 @@ var useRAGEvaluate = (path) => {
|
|
|
2869
3113
|
const clearRuns = () => {
|
|
2870
3114
|
suiteRuns.value = [];
|
|
2871
3115
|
};
|
|
2872
|
-
const leaderboard =
|
|
3116
|
+
const leaderboard = computed3(() => buildRAGEvaluationLeaderboard(suiteRuns.value));
|
|
2873
3117
|
const reset = () => {
|
|
2874
3118
|
error.value = null;
|
|
2875
3119
|
lastRequest.value = null;
|
|
@@ -2894,14 +3138,14 @@ var useRAGEvaluate = (path) => {
|
|
|
2894
3138
|
};
|
|
2895
3139
|
|
|
2896
3140
|
// src/vue/ai/useRAGGrounding.ts
|
|
2897
|
-
import { computed as
|
|
3141
|
+
import { computed as computed4 } from "vue";
|
|
2898
3142
|
var useRAGGrounding = (content, sources) => {
|
|
2899
|
-
const groundedAnswer =
|
|
2900
|
-
const references =
|
|
2901
|
-
const hasCitations =
|
|
2902
|
-
const hasGrounding =
|
|
2903
|
-
const coverage =
|
|
2904
|
-
const ungroundedReferenceNumbers =
|
|
3143
|
+
const groundedAnswer = computed4(() => buildRAGGroundedAnswer(content.value, sources.value));
|
|
3144
|
+
const references = computed4(() => buildRAGGroundingReferences(sources.value));
|
|
3145
|
+
const hasCitations = computed4(() => groundedAnswer.value.hasCitations);
|
|
3146
|
+
const hasGrounding = computed4(() => references.value.length > 0);
|
|
3147
|
+
const coverage = computed4(() => groundedAnswer.value.coverage);
|
|
3148
|
+
const ungroundedReferenceNumbers = computed4(() => groundedAnswer.value.ungroundedReferenceNumbers);
|
|
2905
3149
|
return {
|
|
2906
3150
|
coverage,
|
|
2907
3151
|
groundedAnswer,
|
|
@@ -3312,16 +3556,18 @@ var useRAGSearch = (path) => {
|
|
|
3312
3556
|
};
|
|
3313
3557
|
|
|
3314
3558
|
// src/vue/ai/useRAGSources.ts
|
|
3315
|
-
import { computed as
|
|
3559
|
+
import { computed as computed5 } from "vue";
|
|
3316
3560
|
var useRAGSources = (messages) => {
|
|
3317
|
-
const latestAssistantMessage =
|
|
3318
|
-
const sources =
|
|
3319
|
-
const sourceGroups =
|
|
3320
|
-
const sourceSummaries =
|
|
3321
|
-
const
|
|
3322
|
-
const
|
|
3561
|
+
const latestAssistantMessage = computed5(() => getLatestAssistantMessage(messages.value));
|
|
3562
|
+
const sources = computed5(() => getLatestRAGSources(messages.value));
|
|
3563
|
+
const sourceGroups = computed5(() => buildRAGSourceGroups(sources.value));
|
|
3564
|
+
const sourceSummaries = computed5(() => buildRAGSourceSummaries(sources.value));
|
|
3565
|
+
const chunkGraph = computed5(() => buildRAGChunkGraph(sources.value));
|
|
3566
|
+
const citationReferenceMap = computed5(() => buildRAGCitationReferenceMap(sourceSummaries.value.flatMap((summary) => summary.citations)));
|
|
3567
|
+
const hasSources = computed5(() => sources.value.length > 0);
|
|
3323
3568
|
return {
|
|
3324
3569
|
citationReferenceMap,
|
|
3570
|
+
chunkGraph,
|
|
3325
3571
|
hasSources,
|
|
3326
3572
|
latestAssistantMessage,
|
|
3327
3573
|
sourceGroups,
|
|
@@ -3377,14 +3623,14 @@ var useRAGStatus = (path, autoLoad = true) => {
|
|
|
3377
3623
|
};
|
|
3378
3624
|
|
|
3379
3625
|
// src/vue/ai/useRAGWorkflow.ts
|
|
3380
|
-
import { computed as
|
|
3626
|
+
import { computed as computed8 } from "vue";
|
|
3381
3627
|
|
|
3382
3628
|
// src/vue/ai/useRAGStream.ts
|
|
3383
|
-
import { computed as
|
|
3629
|
+
import { computed as computed7 } from "vue";
|
|
3384
3630
|
|
|
3385
3631
|
// src/vue/ai/useRAGStreamProgress.ts
|
|
3386
|
-
import { computed as
|
|
3387
|
-
var useRAGStreamProgress = (params) =>
|
|
3632
|
+
import { computed as computed6 } from "vue";
|
|
3633
|
+
var useRAGStreamProgress = (params) => computed6(() => buildRAGStreamProgress({
|
|
3388
3634
|
error: params.error.value,
|
|
3389
3635
|
isStreaming: params.isStreaming.value,
|
|
3390
3636
|
messages: params.messages.value
|
|
@@ -3393,7 +3639,7 @@ var useRAGStreamProgress = (params) => computed5(() => buildRAGStreamProgress({
|
|
|
3393
3639
|
// src/vue/ai/useRAGStream.ts
|
|
3394
3640
|
var useRAGStream = (path, conversationId) => {
|
|
3395
3641
|
const stream = useAIStream(path, conversationId);
|
|
3396
|
-
const workflow =
|
|
3642
|
+
const workflow = computed7(() => buildRAGAnswerWorkflowState({
|
|
3397
3643
|
error: stream.error.value,
|
|
3398
3644
|
isStreaming: stream.isStreaming.value,
|
|
3399
3645
|
messages: stream.messages.value
|
|
@@ -3406,37 +3652,37 @@ var useRAGStream = (path, conversationId) => {
|
|
|
3406
3652
|
const query = (content, attachments) => {
|
|
3407
3653
|
stream.send(content, attachments);
|
|
3408
3654
|
};
|
|
3409
|
-
const hasRetrieved =
|
|
3410
|
-
const isRetrieving =
|
|
3411
|
-
const isRetrieved =
|
|
3412
|
-
const isAnswerStreaming =
|
|
3413
|
-
const isComplete =
|
|
3414
|
-
const hasSources =
|
|
3655
|
+
const hasRetrieved = computed7(() => workflow.value.hasRetrieved);
|
|
3656
|
+
const isRetrieving = computed7(() => workflow.value.isRetrieving);
|
|
3657
|
+
const isRetrieved = computed7(() => workflow.value.isRetrieved);
|
|
3658
|
+
const isAnswerStreaming = computed7(() => workflow.value.isAnswerStreaming);
|
|
3659
|
+
const isComplete = computed7(() => workflow.value.isComplete);
|
|
3660
|
+
const hasSources = computed7(() => workflow.value.hasSources);
|
|
3415
3661
|
return {
|
|
3416
3662
|
...stream,
|
|
3417
|
-
citationReferenceMap:
|
|
3418
|
-
citations:
|
|
3419
|
-
coverage:
|
|
3420
|
-
groundedAnswer:
|
|
3421
|
-
groundingReferences:
|
|
3422
|
-
hasGrounding:
|
|
3663
|
+
citationReferenceMap: computed7(() => workflow.value.citationReferenceMap),
|
|
3664
|
+
citations: computed7(() => workflow.value.citations),
|
|
3665
|
+
coverage: computed7(() => workflow.value.coverage),
|
|
3666
|
+
groundedAnswer: computed7(() => workflow.value.groundedAnswer),
|
|
3667
|
+
groundingReferences: computed7(() => workflow.value.groundingReferences),
|
|
3668
|
+
hasGrounding: computed7(() => workflow.value.hasGrounding),
|
|
3423
3669
|
hasRetrieved,
|
|
3424
3670
|
hasSources,
|
|
3425
3671
|
isAnswerStreaming,
|
|
3426
3672
|
isComplete,
|
|
3427
|
-
isError:
|
|
3673
|
+
isError: computed7(() => workflow.value.isError),
|
|
3428
3674
|
isRetrieved,
|
|
3429
3675
|
isRetrieving,
|
|
3430
|
-
isRunning:
|
|
3431
|
-
latestAssistantMessage:
|
|
3676
|
+
isRunning: computed7(() => workflow.value.isRunning),
|
|
3677
|
+
latestAssistantMessage: computed7(() => workflow.value.latestAssistantMessage),
|
|
3432
3678
|
progress,
|
|
3433
3679
|
query,
|
|
3434
|
-
retrieval:
|
|
3435
|
-
sourceGroups:
|
|
3436
|
-
sourceSummaries:
|
|
3437
|
-
sources:
|
|
3438
|
-
stage:
|
|
3439
|
-
ungroundedReferenceNumbers:
|
|
3680
|
+
retrieval: computed7(() => workflow.value.retrieval),
|
|
3681
|
+
sourceGroups: computed7(() => workflow.value.sourceGroups),
|
|
3682
|
+
sourceSummaries: computed7(() => workflow.value.sourceSummaries),
|
|
3683
|
+
sources: computed7(() => workflow.value.sources),
|
|
3684
|
+
stage: computed7(() => workflow.value.stage),
|
|
3685
|
+
ungroundedReferenceNumbers: computed7(() => workflow.value.ungroundedReferenceNumbers),
|
|
3440
3686
|
workflow
|
|
3441
3687
|
};
|
|
3442
3688
|
};
|
|
@@ -3444,7 +3690,7 @@ var useRAGStream = (path, conversationId) => {
|
|
|
3444
3690
|
// src/vue/ai/useRAGWorkflow.ts
|
|
3445
3691
|
var useRAGWorkflow = (path, conversationId) => {
|
|
3446
3692
|
const stream = useRAGStream(path, conversationId);
|
|
3447
|
-
const state =
|
|
3693
|
+
const state = computed8(() => stream.workflow.value);
|
|
3448
3694
|
return {
|
|
3449
3695
|
...stream,
|
|
3450
3696
|
state
|
|
@@ -3464,7 +3710,7 @@ var useRAG = (path, options = {}) => {
|
|
|
3464
3710
|
const workflow = useRAGWorkflow(options.streamPath ?? path, options.conversationId);
|
|
3465
3711
|
const sources = useRAGSources(workflow.messages);
|
|
3466
3712
|
const citations = useRAGCitations(sources.sources);
|
|
3467
|
-
const grounding = useRAGGrounding(
|
|
3713
|
+
const grounding = useRAGGrounding(computed9(() => workflow.latestAssistantMessage.value?.content ?? ""), sources.sources);
|
|
3468
3714
|
return {
|
|
3469
3715
|
chunkPreview,
|
|
3470
3716
|
citations,
|