@seed-ship/mcp-ui-solid 3.0.5 → 4.0.1
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/CHANGELOG.md +115 -0
- package/README.md +253 -280
- package/dist/components/ChartJSRenderer.cjs +37 -15
- package/dist/components/ChartJSRenderer.cjs.map +1 -1
- package/dist/components/ChartJSRenderer.d.ts.map +1 -1
- package/dist/components/ChartJSRenderer.js +37 -15
- package/dist/components/ChartJSRenderer.js.map +1 -1
- package/dist/components/DataPreviewSection.cjs +213 -0
- package/dist/components/DataPreviewSection.cjs.map +1 -0
- package/dist/components/DataPreviewSection.d.ts +19 -0
- package/dist/components/DataPreviewSection.d.ts.map +1 -0
- package/dist/components/DataPreviewSection.js +213 -0
- package/dist/components/DataPreviewSection.js.map +1 -0
- package/dist/components/MapRenderer.cjs +168 -26
- package/dist/components/MapRenderer.cjs.map +1 -1
- package/dist/components/MapRenderer.d.ts +2 -2
- package/dist/components/MapRenderer.d.ts.map +1 -1
- package/dist/components/MapRenderer.js +169 -27
- package/dist/components/MapRenderer.js.map +1 -1
- package/dist/components/ScratchpadPanel.cjs +83 -1
- package/dist/components/ScratchpadPanel.cjs.map +1 -1
- package/dist/components/ScratchpadPanel.d.ts.map +1 -1
- package/dist/components/ScratchpadPanel.js +84 -2
- package/dist/components/ScratchpadPanel.js.map +1 -1
- package/dist/components/VerifiedText.cjs +166 -0
- package/dist/components/VerifiedText.cjs.map +1 -0
- package/dist/components/VerifiedText.d.ts +22 -0
- package/dist/components/VerifiedText.d.ts.map +1 -0
- package/dist/components/VerifiedText.js +166 -0
- package/dist/components/VerifiedText.js.map +1 -0
- package/dist/components/index.d.ts +4 -0
- package/dist/components/index.d.ts.map +1 -1
- package/dist/components.cjs +4 -0
- package/dist/components.cjs.map +1 -1
- package/dist/components.d.cts +4 -0
- package/dist/components.d.ts +4 -0
- package/dist/components.js +4 -0
- package/dist/components.js.map +1 -1
- package/dist/hooks/index.d.ts +2 -0
- package/dist/hooks/index.d.ts.map +1 -1
- package/dist/hooks/useDataValidator.cjs +31 -0
- package/dist/hooks/useDataValidator.cjs.map +1 -0
- package/dist/hooks/useDataValidator.d.ts +42 -0
- package/dist/hooks/useDataValidator.d.ts.map +1 -0
- package/dist/hooks/useDataValidator.js +31 -0
- package/dist/hooks/useDataValidator.js.map +1 -0
- package/dist/hooks.cjs +2 -0
- package/dist/hooks.cjs.map +1 -1
- package/dist/hooks.d.cts +2 -0
- package/dist/hooks.d.ts +2 -0
- package/dist/hooks.js +2 -0
- package/dist/hooks.js.map +1 -1
- package/dist/index.cjs +8 -0
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +9 -5
- package/dist/index.d.ts +9 -5
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +8 -0
- package/dist/index.js.map +1 -1
- package/dist/node_modules/.pnpm/@mapbox_point-geometry@1.1.0/node_modules/@mapbox/point-geometry/index.cjs +290 -0
- package/dist/node_modules/.pnpm/@mapbox_point-geometry@1.1.0/node_modules/@mapbox/point-geometry/index.cjs.map +1 -0
- package/dist/node_modules/.pnpm/@mapbox_point-geometry@1.1.0/node_modules/@mapbox/point-geometry/index.js +291 -0
- package/dist/node_modules/.pnpm/@mapbox_point-geometry@1.1.0/node_modules/@mapbox/point-geometry/index.js.map +1 -0
- package/dist/node_modules/.pnpm/@mapbox_vector-tile@2.0.4/node_modules/@mapbox/vector-tile/index.cjs +243 -0
- package/dist/node_modules/.pnpm/@mapbox_vector-tile@2.0.4/node_modules/@mapbox/vector-tile/index.cjs.map +1 -0
- package/dist/node_modules/.pnpm/@mapbox_vector-tile@2.0.4/node_modules/@mapbox/vector-tile/index.js +243 -0
- package/dist/node_modules/.pnpm/@mapbox_vector-tile@2.0.4/node_modules/@mapbox/vector-tile/index.js.map +1 -0
- package/dist/node_modules/.pnpm/color2k@2.0.3/node_modules/color2k/dist/index.exports.import.es.cjs +137 -0
- package/dist/node_modules/.pnpm/color2k@2.0.3/node_modules/color2k/dist/index.exports.import.es.cjs.map +1 -0
- package/dist/node_modules/.pnpm/color2k@2.0.3/node_modules/color2k/dist/index.exports.import.es.js +137 -0
- package/dist/node_modules/.pnpm/color2k@2.0.3/node_modules/color2k/dist/index.exports.import.es.js.map +1 -0
- package/dist/node_modules/.pnpm/pbf@4.0.1/node_modules/pbf/index.cjs +686 -0
- package/dist/node_modules/.pnpm/pbf@4.0.1/node_modules/pbf/index.cjs.map +1 -0
- package/dist/node_modules/.pnpm/pbf@4.0.1/node_modules/pbf/index.js +687 -0
- package/dist/node_modules/.pnpm/pbf@4.0.1/node_modules/pbf/index.js.map +1 -0
- package/dist/node_modules/.pnpm/pmtiles@3.2.1/node_modules/pmtiles/dist/index.cjs +1366 -0
- package/dist/node_modules/.pnpm/pmtiles@3.2.1/node_modules/pmtiles/dist/index.cjs.map +1 -0
- package/dist/node_modules/.pnpm/pmtiles@3.2.1/node_modules/pmtiles/dist/index.js +1366 -0
- package/dist/node_modules/.pnpm/pmtiles@3.2.1/node_modules/pmtiles/dist/index.js.map +1 -0
- package/dist/node_modules/.pnpm/potpack@1.0.2/node_modules/potpack/index.cjs +54 -0
- package/dist/node_modules/.pnpm/potpack@1.0.2/node_modules/potpack/index.cjs.map +1 -0
- package/dist/node_modules/.pnpm/potpack@1.0.2/node_modules/potpack/index.js +55 -0
- package/dist/node_modules/.pnpm/potpack@1.0.2/node_modules/potpack/index.js.map +1 -0
- package/dist/node_modules/.pnpm/protomaps-leaflet@4.1.1/node_modules/protomaps-leaflet/dist/esm/index.cjs +1256 -0
- package/dist/node_modules/.pnpm/protomaps-leaflet@4.1.1/node_modules/protomaps-leaflet/dist/esm/index.cjs.map +1 -0
- package/dist/node_modules/.pnpm/protomaps-leaflet@4.1.1/node_modules/protomaps-leaflet/dist/esm/index.js +1256 -0
- package/dist/node_modules/.pnpm/protomaps-leaflet@4.1.1/node_modules/protomaps-leaflet/dist/esm/index.js.map +1 -0
- package/dist/node_modules/.pnpm/quickselect@2.0.0/node_modules/quickselect/index.cjs +47 -0
- package/dist/node_modules/.pnpm/quickselect@2.0.0/node_modules/quickselect/index.cjs.map +1 -0
- package/dist/node_modules/.pnpm/quickselect@2.0.0/node_modules/quickselect/index.js +48 -0
- package/dist/node_modules/.pnpm/quickselect@2.0.0/node_modules/quickselect/index.js.map +1 -0
- package/dist/node_modules/.pnpm/rbush@3.0.1/node_modules/rbush/index.cjs +378 -0
- package/dist/node_modules/.pnpm/rbush@3.0.1/node_modules/rbush/index.cjs.map +1 -0
- package/dist/node_modules/.pnpm/rbush@3.0.1/node_modules/rbush/index.js +379 -0
- package/dist/node_modules/.pnpm/rbush@3.0.1/node_modules/rbush/index.js.map +1 -0
- package/dist/services/data-validator.cjs +85 -0
- package/dist/services/data-validator.cjs.map +1 -0
- package/dist/services/data-validator.d.ts +28 -0
- package/dist/services/data-validator.d.ts.map +1 -0
- package/dist/services/data-validator.js +85 -0
- package/dist/services/data-validator.js.map +1 -0
- package/dist/services/index.d.ts +1 -0
- package/dist/services/index.d.ts.map +1 -1
- package/dist/types/chat-bus.d.ts +88 -1
- package/dist/types/chat-bus.d.ts.map +1 -1
- package/dist/types/index.d.ts +135 -6
- package/dist/types/index.d.ts.map +1 -1
- package/dist/types.d.cts +135 -6
- package/dist/types.d.ts +135 -6
- package/package.json +5 -1
- package/src/components/ChartJSRenderer.tsx +35 -13
- package/src/components/DataPreviewSection.tsx +251 -0
- package/src/components/MapRenderer.test.tsx +94 -5
- package/src/components/MapRenderer.tsx +246 -45
- package/src/components/ScratchpadPanel.tsx +19 -3
- package/src/components/VerifiedText.tsx +187 -0
- package/src/components/index.ts +7 -0
- package/src/hooks/index.ts +7 -0
- package/src/hooks/useDataValidator.ts +68 -0
- package/src/index.ts +26 -1
- package/src/services/data-validator.test.ts +151 -0
- package/src/services/data-validator.ts +149 -0
- package/src/services/index.ts +2 -0
- package/src/types/chat-bus.ts +98 -1
- package/src/types/index.ts +145 -6
- package/tsconfig.tsbuildinfo +1 -1
|
@@ -0,0 +1,166 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
|
|
3
|
+
const web = require("solid-js/web");
|
|
4
|
+
const solidJs = require("solid-js");
|
|
5
|
+
var _tmpl$ = /* @__PURE__ */ web.template(`<div class="verified-text text-sm leading-relaxed"><!$><!/><!$><!/>`), _tmpl$2 = /* @__PURE__ */ web.template(`<span>`), _tmpl$3 = /* @__PURE__ */ web.template(`<span class="inline-flex items-center gap-0.5 px-0.5 rounded bg-green-50 dark:bg-green-900/20 text-green-800 dark:text-green-300"title="Verified against source data"><!$><!/><span class="text-xs opacity-70"aria-label=verified>✅`), _tmpl$4 = /* @__PURE__ */ web.template(`<span class="inline-flex items-center px-1 rounded bg-amber-50 dark:bg-amber-900/20 text-amber-700 dark:text-amber-300 italic text-xs">[non vérifié]`), _tmpl$5 = /* @__PURE__ */ web.template(`<span class="inline-flex items-center gap-0.5 px-0.5 rounded bg-amber-50 dark:bg-amber-900/20 text-amber-800 dark:text-amber-300 cursor-help"><!$><!/><span class=text-xs aria-label=unverified>⚠️`), _tmpl$6 = /* @__PURE__ */ web.template(`<div class="mt-2 flex items-center gap-2 text-xs text-gray-500 dark:text-gray-400"><div class="flex-1 h-1.5 bg-gray-200 dark:bg-gray-700 rounded-full overflow-hidden"><div class="h-full rounded-full transition-all"></div></div><span><!$><!/>% verified (<!$><!/> unverified)`);
|
|
6
|
+
function buildAnnotatedSegments(text, validation) {
|
|
7
|
+
const hallucinatedPositions = /* @__PURE__ */ new Map();
|
|
8
|
+
for (const h of validation.hallucinated) {
|
|
9
|
+
hallucinatedPositions.set(h.position, h);
|
|
10
|
+
}
|
|
11
|
+
const verifiedPositions = /* @__PURE__ */ new Set();
|
|
12
|
+
for (const n of validation.llmNumbers) {
|
|
13
|
+
if (!hallucinatedPositions.has(n.position)) {
|
|
14
|
+
verifiedPositions.add(n.position);
|
|
15
|
+
}
|
|
16
|
+
}
|
|
17
|
+
validation.llmNumbers.map((n) => ({
|
|
18
|
+
position: n.position,
|
|
19
|
+
length: n.context.length - 20
|
|
20
|
+
})).sort((a, b) => a.position - b.position);
|
|
21
|
+
const numberRegex = /\d[\d\s,.]*\d|\d+/g;
|
|
22
|
+
const matches = [];
|
|
23
|
+
let m;
|
|
24
|
+
while ((m = numberRegex.exec(text)) !== null) {
|
|
25
|
+
matches.push({
|
|
26
|
+
start: m.index,
|
|
27
|
+
end: m.index + m[0].length
|
|
28
|
+
});
|
|
29
|
+
}
|
|
30
|
+
const matchByPosition = /* @__PURE__ */ new Map();
|
|
31
|
+
for (const match of matches) {
|
|
32
|
+
matchByPosition.set(match.start, match);
|
|
33
|
+
}
|
|
34
|
+
const segments = [];
|
|
35
|
+
let cursor = 0;
|
|
36
|
+
for (const num of validation.llmNumbers) {
|
|
37
|
+
const match = matchByPosition.get(num.position);
|
|
38
|
+
if (!match) continue;
|
|
39
|
+
if (match.start > cursor) {
|
|
40
|
+
segments.push({
|
|
41
|
+
type: "text",
|
|
42
|
+
content: text.slice(cursor, match.start)
|
|
43
|
+
});
|
|
44
|
+
}
|
|
45
|
+
const numberText = text.slice(match.start, match.end);
|
|
46
|
+
const hallucinated = hallucinatedPositions.get(num.position);
|
|
47
|
+
if (hallucinated) {
|
|
48
|
+
segments.push({
|
|
49
|
+
type: "hallucinated",
|
|
50
|
+
content: numberText,
|
|
51
|
+
item: hallucinated
|
|
52
|
+
});
|
|
53
|
+
} else {
|
|
54
|
+
segments.push({
|
|
55
|
+
type: "verified",
|
|
56
|
+
content: numberText
|
|
57
|
+
});
|
|
58
|
+
}
|
|
59
|
+
cursor = match.end;
|
|
60
|
+
}
|
|
61
|
+
if (cursor < text.length) {
|
|
62
|
+
segments.push({
|
|
63
|
+
type: "text",
|
|
64
|
+
content: text.slice(cursor)
|
|
65
|
+
});
|
|
66
|
+
}
|
|
67
|
+
return segments;
|
|
68
|
+
}
|
|
69
|
+
function VerifiedText(props) {
|
|
70
|
+
const mode = () => props.mode || "highlight";
|
|
71
|
+
const segments = solidJs.createMemo(() => {
|
|
72
|
+
if (!props.validation || props.validation.valid) {
|
|
73
|
+
return [{
|
|
74
|
+
type: "text",
|
|
75
|
+
content: props.text
|
|
76
|
+
}];
|
|
77
|
+
}
|
|
78
|
+
return buildAnnotatedSegments(props.text, props.validation);
|
|
79
|
+
});
|
|
80
|
+
return (() => {
|
|
81
|
+
var _el$ = web.getNextElement(_tmpl$), _el$2 = _el$.firstChild, [_el$3, _co$] = web.getNextMarker(_el$2.nextSibling), _el$4 = _el$3.nextSibling, [_el$5, _co$2] = web.getNextMarker(_el$4.nextSibling);
|
|
82
|
+
web.insert(_el$, web.createComponent(solidJs.For, {
|
|
83
|
+
get each() {
|
|
84
|
+
return segments();
|
|
85
|
+
},
|
|
86
|
+
children: (seg) => {
|
|
87
|
+
if (seg.type === "text") {
|
|
88
|
+
return (() => {
|
|
89
|
+
var _el$6 = web.getNextElement(_tmpl$2);
|
|
90
|
+
web.insert(_el$6, () => seg.content);
|
|
91
|
+
return _el$6;
|
|
92
|
+
})();
|
|
93
|
+
}
|
|
94
|
+
if (seg.type === "verified") {
|
|
95
|
+
return (() => {
|
|
96
|
+
var _el$7 = web.getNextElement(_tmpl$3), _el$9 = _el$7.firstChild, [_el$0, _co$3] = web.getNextMarker(_el$9.nextSibling);
|
|
97
|
+
_el$0.nextSibling;
|
|
98
|
+
web.insert(_el$7, () => seg.content, _el$0, _co$3);
|
|
99
|
+
return _el$7;
|
|
100
|
+
})();
|
|
101
|
+
}
|
|
102
|
+
const h = seg.item;
|
|
103
|
+
const tooltipText = () => {
|
|
104
|
+
if (h.closest != null && h.distance != null) {
|
|
105
|
+
return `Not found in source data. Closest: ${h.closest} (${Math.round(h.distance * 100)}% off)`;
|
|
106
|
+
}
|
|
107
|
+
return "Not found in source data";
|
|
108
|
+
};
|
|
109
|
+
if (mode() === "strip") {
|
|
110
|
+
return (() => {
|
|
111
|
+
var _el$1 = web.getNextElement(_tmpl$4);
|
|
112
|
+
web.effect(() => web.setAttribute(_el$1, "title", tooltipText()));
|
|
113
|
+
return _el$1;
|
|
114
|
+
})();
|
|
115
|
+
}
|
|
116
|
+
return (() => {
|
|
117
|
+
var _el$10 = web.getNextElement(_tmpl$5), _el$12 = _el$10.firstChild, [_el$13, _co$4] = web.getNextMarker(_el$12.nextSibling);
|
|
118
|
+
_el$13.nextSibling;
|
|
119
|
+
_el$10.$$click = () => {
|
|
120
|
+
var _a;
|
|
121
|
+
return (_a = props.onHallucinationClick) == null ? void 0 : _a.call(props, h);
|
|
122
|
+
};
|
|
123
|
+
web.insert(_el$10, () => seg.content, _el$13, _co$4);
|
|
124
|
+
web.effect((_p$) => {
|
|
125
|
+
var _v$ = tooltipText(), _v$2 = props.onHallucinationClick ? "button" : void 0;
|
|
126
|
+
_v$ !== _p$.e && web.setAttribute(_el$10, "title", _p$.e = _v$);
|
|
127
|
+
_v$2 !== _p$.t && web.setAttribute(_el$10, "role", _p$.t = _v$2);
|
|
128
|
+
return _p$;
|
|
129
|
+
}, {
|
|
130
|
+
e: void 0,
|
|
131
|
+
t: void 0
|
|
132
|
+
});
|
|
133
|
+
web.runHydrationEvents();
|
|
134
|
+
return _el$10;
|
|
135
|
+
})();
|
|
136
|
+
}
|
|
137
|
+
}), _el$3, _co$);
|
|
138
|
+
web.insert(_el$, (() => {
|
|
139
|
+
var _c$ = web.memo(() => !!(props.validation && !props.validation.valid));
|
|
140
|
+
return () => _c$() && (() => {
|
|
141
|
+
var _el$14 = web.getNextElement(_tmpl$6), _el$15 = _el$14.firstChild, _el$16 = _el$15.firstChild, _el$17 = _el$15.nextSibling, _el$20 = _el$17.firstChild, [_el$21, _co$5] = web.getNextMarker(_el$20.nextSibling), _el$18 = _el$21.nextSibling, _el$22 = _el$18.nextSibling, [_el$23, _co$6] = web.getNextMarker(_el$22.nextSibling);
|
|
142
|
+
_el$23.nextSibling;
|
|
143
|
+
web.insert(_el$17, () => Math.round(props.validation.confidence * 100), _el$21, _co$5);
|
|
144
|
+
web.insert(_el$17, () => props.validation.hallucinated.length, _el$23, _co$6);
|
|
145
|
+
web.effect((_p$) => {
|
|
146
|
+
var _v$3 = !!(props.validation.confidence >= 0.8), _v$4 = !!(props.validation.confidence >= 0.5 && props.validation.confidence < 0.8), _v$5 = !!(props.validation.confidence < 0.5), _v$6 = `${Math.round(props.validation.confidence * 100)}%`;
|
|
147
|
+
_v$3 !== _p$.e && _el$16.classList.toggle("bg-green-500", _p$.e = _v$3);
|
|
148
|
+
_v$4 !== _p$.t && _el$16.classList.toggle("bg-amber-500", _p$.t = _v$4);
|
|
149
|
+
_v$5 !== _p$.a && _el$16.classList.toggle("bg-red-500", _p$.a = _v$5);
|
|
150
|
+
_v$6 !== _p$.o && web.setStyleProperty(_el$16, "width", _p$.o = _v$6);
|
|
151
|
+
return _p$;
|
|
152
|
+
}, {
|
|
153
|
+
e: void 0,
|
|
154
|
+
t: void 0,
|
|
155
|
+
a: void 0,
|
|
156
|
+
o: void 0
|
|
157
|
+
});
|
|
158
|
+
return _el$14;
|
|
159
|
+
})();
|
|
160
|
+
})(), _el$5, _co$2);
|
|
161
|
+
return _el$;
|
|
162
|
+
})();
|
|
163
|
+
}
|
|
164
|
+
web.delegateEvents(["click"]);
|
|
165
|
+
exports.VerifiedText = VerifiedText;
|
|
166
|
+
//# sourceMappingURL=VerifiedText.cjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"VerifiedText.cjs","sources":["../../src/components/VerifiedText.tsx"],"sourcesContent":["/**\n * VerifiedText — renders LLM text with inline verification badges\n * v3.1.0: Highlights verified vs hallucinated numbers\n *\n * @experimental\n *\n * Modes:\n * - highlight: ✅/⚠️ badges next to numbers (default)\n * - strip: replaces hallucinated numbers with [non vérifié]\n * - annotate: tooltip on hover with closest source number\n */\n\nimport { createMemo, For } from 'solid-js'\nimport type { DataValidation, HallucinatedNumber } from '../types/chat-bus'\n\nexport interface VerifiedTextProps {\n text: string\n validation: DataValidation\n /** Display mode (default: 'highlight') */\n mode?: 'highlight' | 'strip' | 'annotate'\n /** Callback when a hallucinated number is clicked */\n onHallucinationClick?: (item: HallucinatedNumber) => void\n}\n\ninterface TextSegment {\n type: 'text' | 'verified' | 'hallucinated'\n content: string\n item?: HallucinatedNumber\n}\n\n/**\n * Build annotated segments by splitting text at number positions.\n * Verified numbers get ✅, hallucinated get ⚠️.\n */\nfunction buildAnnotatedSegments(text: string, validation: DataValidation): TextSegment[] {\n // Build position maps\n const hallucinatedPositions = new Map<number, HallucinatedNumber>()\n for (const h of validation.hallucinated) {\n hallucinatedPositions.set(h.position, h)\n }\n\n const verifiedPositions = new Set<number>()\n for (const n of validation.llmNumbers) {\n if (!hallucinatedPositions.has(n.position)) {\n verifiedPositions.add(n.position)\n }\n }\n\n // Build all number positions sorted\n const allPositions = validation.llmNumbers\n .map(n => ({ position: n.position, length: n.context.length - 20 })) // approximate original match length\n .sort((a, b) => a.position - b.position)\n\n // Re-extract number lengths from text for precise splitting\n const numberRegex = /\\d[\\d\\s,.]*\\d|\\d+/g\n const matches: Array<{ start: number; end: number }> = []\n let m: RegExpExecArray | null\n while ((m = numberRegex.exec(text)) !== null) {\n matches.push({ start: m.index, end: m.index + m[0].length })\n }\n\n // Build a lookup from position → match\n const matchByPosition = new Map<number, { start: number; end: number }>()\n for (const match of matches) {\n matchByPosition.set(match.start, match)\n }\n\n // Build segments\n const segments: TextSegment[] = []\n let cursor = 0\n\n for (const num of validation.llmNumbers) {\n const match = matchByPosition.get(num.position)\n if (!match) continue\n\n // Text before this number\n if (match.start > cursor) {\n segments.push({ type: 'text', content: text.slice(cursor, match.start) })\n }\n\n const numberText = text.slice(match.start, match.end)\n const hallucinated = hallucinatedPositions.get(num.position)\n\n if (hallucinated) {\n segments.push({ type: 'hallucinated', content: numberText, item: hallucinated })\n } else {\n segments.push({ type: 'verified', content: numberText })\n }\n\n cursor = match.end\n }\n\n // Remaining text\n if (cursor < text.length) {\n segments.push({ type: 'text', content: text.slice(cursor) })\n }\n\n return segments\n}\n\nexport function VerifiedText(props: VerifiedTextProps) {\n const mode = () => props.mode || 'highlight'\n\n const segments = createMemo<TextSegment[]>(() => {\n if (!props.validation || props.validation.valid) {\n return [{ type: 'text' as const, content: props.text }]\n }\n return buildAnnotatedSegments(props.text, props.validation)\n })\n\n return (\n <div class=\"verified-text text-sm leading-relaxed\">\n <For each={segments()}>\n {(seg) => {\n if (seg.type === 'text') {\n return <span>{seg.content}</span>\n }\n\n if (seg.type === 'verified') {\n return (\n <span\n class=\"inline-flex items-center gap-0.5 px-0.5 rounded bg-green-50 dark:bg-green-900/20 text-green-800 dark:text-green-300\"\n title=\"Verified against source data\"\n >\n {seg.content}\n <span class=\"text-xs opacity-70\" aria-label=\"verified\">✅</span>\n </span>\n )\n }\n\n // hallucinated\n const h = seg.item!\n const tooltipText = () => {\n if (h.closest != null && h.distance != null) {\n return `Not found in source data. Closest: ${h.closest} (${Math.round(h.distance * 100)}% off)`\n }\n return 'Not found in source data'\n }\n\n if (mode() === 'strip') {\n return (\n <span\n class=\"inline-flex items-center px-1 rounded bg-amber-50 dark:bg-amber-900/20 text-amber-700 dark:text-amber-300 italic text-xs\"\n title={tooltipText()}\n >\n [non vérifié]\n </span>\n )\n }\n\n return (\n <span\n class=\"inline-flex items-center gap-0.5 px-0.5 rounded bg-amber-50 dark:bg-amber-900/20 text-amber-800 dark:text-amber-300 cursor-help\"\n title={tooltipText()}\n onClick={() => props.onHallucinationClick?.(h)}\n role={props.onHallucinationClick ? 'button' : undefined}\n >\n {seg.content}\n <span class=\"text-xs\" aria-label=\"unverified\">⚠️</span>\n </span>\n )\n }}\n </For>\n\n {/* Confidence bar */}\n {props.validation && !props.validation.valid && (\n <div class=\"mt-2 flex items-center gap-2 text-xs text-gray-500 dark:text-gray-400\">\n <div class=\"flex-1 h-1.5 bg-gray-200 dark:bg-gray-700 rounded-full overflow-hidden\">\n <div\n class=\"h-full rounded-full transition-all\"\n classList={{\n 'bg-green-500': props.validation.confidence >= 0.8,\n 'bg-amber-500': props.validation.confidence >= 0.5 && props.validation.confidence < 0.8,\n 'bg-red-500': props.validation.confidence < 0.5,\n }}\n style={{ width: `${Math.round(props.validation.confidence * 100)}%` }}\n />\n </div>\n <span>\n {Math.round(props.validation.confidence * 100)}% verified\n ({props.validation.hallucinated.length} unverified)\n </span>\n </div>\n )}\n </div>\n )\n}\n"],"names":["buildAnnotatedSegments","text","validation","hallucinatedPositions","Map","h","hallucinated","set","position","verifiedPositions","Set","n","llmNumbers","has","add","map","length","context","sort","a","b","numberRegex","matches","m","exec","push","start","index","end","matchByPosition","match","segments","cursor","num","get","type","content","slice","numberText","item","VerifiedText","props","mode","createMemo","valid","_el$","_$getNextElement","_tmpl$","_el$2","firstChild","_el$3","_co$","_$getNextMarker","nextSibling","_el$4","_el$5","_co$2","_$insert","_$createComponent","For","each","children","seg","_el$6","_tmpl$2","_el$7","_tmpl$3","_el$9","_el$0","_co$3","tooltipText","closest","distance","Math","round","_el$1","_tmpl$4","_$effect","_$setAttribute","_el$10","_tmpl$5","_el$12","_el$13","_co$4","$$click","onHallucinationClick","_p$","_v$","_v$2","undefined","e","t","_$runHydrationEvents","_c$","_$memo","_el$14","_tmpl$6","_el$15","_el$16","_el$17","_el$20","_el$21","_co$5","_el$18","_el$22","_el$23","_co$6","confidence","_v$3","_v$4","_v$5","_v$6","classList","toggle","o","_$setStyleProperty","_$delegateEvents"],"mappings":"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"}
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* VerifiedText — renders LLM text with inline verification badges
|
|
3
|
+
* v3.1.0: Highlights verified vs hallucinated numbers
|
|
4
|
+
*
|
|
5
|
+
* @experimental
|
|
6
|
+
*
|
|
7
|
+
* Modes:
|
|
8
|
+
* - highlight: ✅/⚠️ badges next to numbers (default)
|
|
9
|
+
* - strip: replaces hallucinated numbers with [non vérifié]
|
|
10
|
+
* - annotate: tooltip on hover with closest source number
|
|
11
|
+
*/
|
|
12
|
+
import type { DataValidation, HallucinatedNumber } from '../types/chat-bus';
|
|
13
|
+
export interface VerifiedTextProps {
|
|
14
|
+
text: string;
|
|
15
|
+
validation: DataValidation;
|
|
16
|
+
/** Display mode (default: 'highlight') */
|
|
17
|
+
mode?: 'highlight' | 'strip' | 'annotate';
|
|
18
|
+
/** Callback when a hallucinated number is clicked */
|
|
19
|
+
onHallucinationClick?: (item: HallucinatedNumber) => void;
|
|
20
|
+
}
|
|
21
|
+
export declare function VerifiedText(props: VerifiedTextProps): import("solid-js").JSX.Element;
|
|
22
|
+
//# sourceMappingURL=VerifiedText.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"VerifiedText.d.ts","sourceRoot":"","sources":["../../src/components/VerifiedText.tsx"],"names":[],"mappings":"AAAA;;;;;;;;;;GAUG;AAGH,OAAO,KAAK,EAAE,cAAc,EAAE,kBAAkB,EAAE,MAAM,mBAAmB,CAAA;AAE3E,MAAM,WAAW,iBAAiB;IAChC,IAAI,EAAE,MAAM,CAAA;IACZ,UAAU,EAAE,cAAc,CAAA;IAC1B,0CAA0C;IAC1C,IAAI,CAAC,EAAE,WAAW,GAAG,OAAO,GAAG,UAAU,CAAA;IACzC,qDAAqD;IACrD,oBAAoB,CAAC,EAAE,CAAC,IAAI,EAAE,kBAAkB,KAAK,IAAI,CAAA;CAC1D;AA8ED,wBAAgB,YAAY,CAAC,KAAK,EAAE,iBAAiB,kCAsFpD"}
|
|
@@ -0,0 +1,166 @@
|
|
|
1
|
+
import { delegateEvents, getNextElement, template, getNextMarker, insert, createComponent, effect, setAttribute, runHydrationEvents, memo, setStyleProperty } from "solid-js/web";
|
|
2
|
+
import { createMemo, For } from "solid-js";
|
|
3
|
+
var _tmpl$ = /* @__PURE__ */ template(`<div class="verified-text text-sm leading-relaxed"><!$><!/><!$><!/>`), _tmpl$2 = /* @__PURE__ */ template(`<span>`), _tmpl$3 = /* @__PURE__ */ template(`<span class="inline-flex items-center gap-0.5 px-0.5 rounded bg-green-50 dark:bg-green-900/20 text-green-800 dark:text-green-300"title="Verified against source data"><!$><!/><span class="text-xs opacity-70"aria-label=verified>✅`), _tmpl$4 = /* @__PURE__ */ template(`<span class="inline-flex items-center px-1 rounded bg-amber-50 dark:bg-amber-900/20 text-amber-700 dark:text-amber-300 italic text-xs">[non vérifié]`), _tmpl$5 = /* @__PURE__ */ template(`<span class="inline-flex items-center gap-0.5 px-0.5 rounded bg-amber-50 dark:bg-amber-900/20 text-amber-800 dark:text-amber-300 cursor-help"><!$><!/><span class=text-xs aria-label=unverified>⚠️`), _tmpl$6 = /* @__PURE__ */ template(`<div class="mt-2 flex items-center gap-2 text-xs text-gray-500 dark:text-gray-400"><div class="flex-1 h-1.5 bg-gray-200 dark:bg-gray-700 rounded-full overflow-hidden"><div class="h-full rounded-full transition-all"></div></div><span><!$><!/>% verified (<!$><!/> unverified)`);
|
|
4
|
+
function buildAnnotatedSegments(text, validation) {
|
|
5
|
+
const hallucinatedPositions = /* @__PURE__ */ new Map();
|
|
6
|
+
for (const h of validation.hallucinated) {
|
|
7
|
+
hallucinatedPositions.set(h.position, h);
|
|
8
|
+
}
|
|
9
|
+
const verifiedPositions = /* @__PURE__ */ new Set();
|
|
10
|
+
for (const n of validation.llmNumbers) {
|
|
11
|
+
if (!hallucinatedPositions.has(n.position)) {
|
|
12
|
+
verifiedPositions.add(n.position);
|
|
13
|
+
}
|
|
14
|
+
}
|
|
15
|
+
validation.llmNumbers.map((n) => ({
|
|
16
|
+
position: n.position,
|
|
17
|
+
length: n.context.length - 20
|
|
18
|
+
})).sort((a, b) => a.position - b.position);
|
|
19
|
+
const numberRegex = /\d[\d\s,.]*\d|\d+/g;
|
|
20
|
+
const matches = [];
|
|
21
|
+
let m;
|
|
22
|
+
while ((m = numberRegex.exec(text)) !== null) {
|
|
23
|
+
matches.push({
|
|
24
|
+
start: m.index,
|
|
25
|
+
end: m.index + m[0].length
|
|
26
|
+
});
|
|
27
|
+
}
|
|
28
|
+
const matchByPosition = /* @__PURE__ */ new Map();
|
|
29
|
+
for (const match of matches) {
|
|
30
|
+
matchByPosition.set(match.start, match);
|
|
31
|
+
}
|
|
32
|
+
const segments = [];
|
|
33
|
+
let cursor = 0;
|
|
34
|
+
for (const num of validation.llmNumbers) {
|
|
35
|
+
const match = matchByPosition.get(num.position);
|
|
36
|
+
if (!match) continue;
|
|
37
|
+
if (match.start > cursor) {
|
|
38
|
+
segments.push({
|
|
39
|
+
type: "text",
|
|
40
|
+
content: text.slice(cursor, match.start)
|
|
41
|
+
});
|
|
42
|
+
}
|
|
43
|
+
const numberText = text.slice(match.start, match.end);
|
|
44
|
+
const hallucinated = hallucinatedPositions.get(num.position);
|
|
45
|
+
if (hallucinated) {
|
|
46
|
+
segments.push({
|
|
47
|
+
type: "hallucinated",
|
|
48
|
+
content: numberText,
|
|
49
|
+
item: hallucinated
|
|
50
|
+
});
|
|
51
|
+
} else {
|
|
52
|
+
segments.push({
|
|
53
|
+
type: "verified",
|
|
54
|
+
content: numberText
|
|
55
|
+
});
|
|
56
|
+
}
|
|
57
|
+
cursor = match.end;
|
|
58
|
+
}
|
|
59
|
+
if (cursor < text.length) {
|
|
60
|
+
segments.push({
|
|
61
|
+
type: "text",
|
|
62
|
+
content: text.slice(cursor)
|
|
63
|
+
});
|
|
64
|
+
}
|
|
65
|
+
return segments;
|
|
66
|
+
}
|
|
67
|
+
function VerifiedText(props) {
|
|
68
|
+
const mode = () => props.mode || "highlight";
|
|
69
|
+
const segments = createMemo(() => {
|
|
70
|
+
if (!props.validation || props.validation.valid) {
|
|
71
|
+
return [{
|
|
72
|
+
type: "text",
|
|
73
|
+
content: props.text
|
|
74
|
+
}];
|
|
75
|
+
}
|
|
76
|
+
return buildAnnotatedSegments(props.text, props.validation);
|
|
77
|
+
});
|
|
78
|
+
return (() => {
|
|
79
|
+
var _el$ = getNextElement(_tmpl$), _el$2 = _el$.firstChild, [_el$3, _co$] = getNextMarker(_el$2.nextSibling), _el$4 = _el$3.nextSibling, [_el$5, _co$2] = getNextMarker(_el$4.nextSibling);
|
|
80
|
+
insert(_el$, createComponent(For, {
|
|
81
|
+
get each() {
|
|
82
|
+
return segments();
|
|
83
|
+
},
|
|
84
|
+
children: (seg) => {
|
|
85
|
+
if (seg.type === "text") {
|
|
86
|
+
return (() => {
|
|
87
|
+
var _el$6 = getNextElement(_tmpl$2);
|
|
88
|
+
insert(_el$6, () => seg.content);
|
|
89
|
+
return _el$6;
|
|
90
|
+
})();
|
|
91
|
+
}
|
|
92
|
+
if (seg.type === "verified") {
|
|
93
|
+
return (() => {
|
|
94
|
+
var _el$7 = getNextElement(_tmpl$3), _el$9 = _el$7.firstChild, [_el$0, _co$3] = getNextMarker(_el$9.nextSibling);
|
|
95
|
+
_el$0.nextSibling;
|
|
96
|
+
insert(_el$7, () => seg.content, _el$0, _co$3);
|
|
97
|
+
return _el$7;
|
|
98
|
+
})();
|
|
99
|
+
}
|
|
100
|
+
const h = seg.item;
|
|
101
|
+
const tooltipText = () => {
|
|
102
|
+
if (h.closest != null && h.distance != null) {
|
|
103
|
+
return `Not found in source data. Closest: ${h.closest} (${Math.round(h.distance * 100)}% off)`;
|
|
104
|
+
}
|
|
105
|
+
return "Not found in source data";
|
|
106
|
+
};
|
|
107
|
+
if (mode() === "strip") {
|
|
108
|
+
return (() => {
|
|
109
|
+
var _el$1 = getNextElement(_tmpl$4);
|
|
110
|
+
effect(() => setAttribute(_el$1, "title", tooltipText()));
|
|
111
|
+
return _el$1;
|
|
112
|
+
})();
|
|
113
|
+
}
|
|
114
|
+
return (() => {
|
|
115
|
+
var _el$10 = getNextElement(_tmpl$5), _el$12 = _el$10.firstChild, [_el$13, _co$4] = getNextMarker(_el$12.nextSibling);
|
|
116
|
+
_el$13.nextSibling;
|
|
117
|
+
_el$10.$$click = () => {
|
|
118
|
+
var _a;
|
|
119
|
+
return (_a = props.onHallucinationClick) == null ? void 0 : _a.call(props, h);
|
|
120
|
+
};
|
|
121
|
+
insert(_el$10, () => seg.content, _el$13, _co$4);
|
|
122
|
+
effect((_p$) => {
|
|
123
|
+
var _v$ = tooltipText(), _v$2 = props.onHallucinationClick ? "button" : void 0;
|
|
124
|
+
_v$ !== _p$.e && setAttribute(_el$10, "title", _p$.e = _v$);
|
|
125
|
+
_v$2 !== _p$.t && setAttribute(_el$10, "role", _p$.t = _v$2);
|
|
126
|
+
return _p$;
|
|
127
|
+
}, {
|
|
128
|
+
e: void 0,
|
|
129
|
+
t: void 0
|
|
130
|
+
});
|
|
131
|
+
runHydrationEvents();
|
|
132
|
+
return _el$10;
|
|
133
|
+
})();
|
|
134
|
+
}
|
|
135
|
+
}), _el$3, _co$);
|
|
136
|
+
insert(_el$, (() => {
|
|
137
|
+
var _c$ = memo(() => !!(props.validation && !props.validation.valid));
|
|
138
|
+
return () => _c$() && (() => {
|
|
139
|
+
var _el$14 = getNextElement(_tmpl$6), _el$15 = _el$14.firstChild, _el$16 = _el$15.firstChild, _el$17 = _el$15.nextSibling, _el$20 = _el$17.firstChild, [_el$21, _co$5] = getNextMarker(_el$20.nextSibling), _el$18 = _el$21.nextSibling, _el$22 = _el$18.nextSibling, [_el$23, _co$6] = getNextMarker(_el$22.nextSibling);
|
|
140
|
+
_el$23.nextSibling;
|
|
141
|
+
insert(_el$17, () => Math.round(props.validation.confidence * 100), _el$21, _co$5);
|
|
142
|
+
insert(_el$17, () => props.validation.hallucinated.length, _el$23, _co$6);
|
|
143
|
+
effect((_p$) => {
|
|
144
|
+
var _v$3 = !!(props.validation.confidence >= 0.8), _v$4 = !!(props.validation.confidence >= 0.5 && props.validation.confidence < 0.8), _v$5 = !!(props.validation.confidence < 0.5), _v$6 = `${Math.round(props.validation.confidence * 100)}%`;
|
|
145
|
+
_v$3 !== _p$.e && _el$16.classList.toggle("bg-green-500", _p$.e = _v$3);
|
|
146
|
+
_v$4 !== _p$.t && _el$16.classList.toggle("bg-amber-500", _p$.t = _v$4);
|
|
147
|
+
_v$5 !== _p$.a && _el$16.classList.toggle("bg-red-500", _p$.a = _v$5);
|
|
148
|
+
_v$6 !== _p$.o && setStyleProperty(_el$16, "width", _p$.o = _v$6);
|
|
149
|
+
return _p$;
|
|
150
|
+
}, {
|
|
151
|
+
e: void 0,
|
|
152
|
+
t: void 0,
|
|
153
|
+
a: void 0,
|
|
154
|
+
o: void 0
|
|
155
|
+
});
|
|
156
|
+
return _el$14;
|
|
157
|
+
})();
|
|
158
|
+
})(), _el$5, _co$2);
|
|
159
|
+
return _el$;
|
|
160
|
+
})();
|
|
161
|
+
}
|
|
162
|
+
delegateEvents(["click"]);
|
|
163
|
+
export {
|
|
164
|
+
VerifiedText
|
|
165
|
+
};
|
|
166
|
+
//# sourceMappingURL=VerifiedText.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"VerifiedText.js","sources":["../../src/components/VerifiedText.tsx"],"sourcesContent":["/**\n * VerifiedText — renders LLM text with inline verification badges\n * v3.1.0: Highlights verified vs hallucinated numbers\n *\n * @experimental\n *\n * Modes:\n * - highlight: ✅/⚠️ badges next to numbers (default)\n * - strip: replaces hallucinated numbers with [non vérifié]\n * - annotate: tooltip on hover with closest source number\n */\n\nimport { createMemo, For } from 'solid-js'\nimport type { DataValidation, HallucinatedNumber } from '../types/chat-bus'\n\nexport interface VerifiedTextProps {\n text: string\n validation: DataValidation\n /** Display mode (default: 'highlight') */\n mode?: 'highlight' | 'strip' | 'annotate'\n /** Callback when a hallucinated number is clicked */\n onHallucinationClick?: (item: HallucinatedNumber) => void\n}\n\ninterface TextSegment {\n type: 'text' | 'verified' | 'hallucinated'\n content: string\n item?: HallucinatedNumber\n}\n\n/**\n * Build annotated segments by splitting text at number positions.\n * Verified numbers get ✅, hallucinated get ⚠️.\n */\nfunction buildAnnotatedSegments(text: string, validation: DataValidation): TextSegment[] {\n // Build position maps\n const hallucinatedPositions = new Map<number, HallucinatedNumber>()\n for (const h of validation.hallucinated) {\n hallucinatedPositions.set(h.position, h)\n }\n\n const verifiedPositions = new Set<number>()\n for (const n of validation.llmNumbers) {\n if (!hallucinatedPositions.has(n.position)) {\n verifiedPositions.add(n.position)\n }\n }\n\n // Build all number positions sorted\n const allPositions = validation.llmNumbers\n .map(n => ({ position: n.position, length: n.context.length - 20 })) // approximate original match length\n .sort((a, b) => a.position - b.position)\n\n // Re-extract number lengths from text for precise splitting\n const numberRegex = /\\d[\\d\\s,.]*\\d|\\d+/g\n const matches: Array<{ start: number; end: number }> = []\n let m: RegExpExecArray | null\n while ((m = numberRegex.exec(text)) !== null) {\n matches.push({ start: m.index, end: m.index + m[0].length })\n }\n\n // Build a lookup from position → match\n const matchByPosition = new Map<number, { start: number; end: number }>()\n for (const match of matches) {\n matchByPosition.set(match.start, match)\n }\n\n // Build segments\n const segments: TextSegment[] = []\n let cursor = 0\n\n for (const num of validation.llmNumbers) {\n const match = matchByPosition.get(num.position)\n if (!match) continue\n\n // Text before this number\n if (match.start > cursor) {\n segments.push({ type: 'text', content: text.slice(cursor, match.start) })\n }\n\n const numberText = text.slice(match.start, match.end)\n const hallucinated = hallucinatedPositions.get(num.position)\n\n if (hallucinated) {\n segments.push({ type: 'hallucinated', content: numberText, item: hallucinated })\n } else {\n segments.push({ type: 'verified', content: numberText })\n }\n\n cursor = match.end\n }\n\n // Remaining text\n if (cursor < text.length) {\n segments.push({ type: 'text', content: text.slice(cursor) })\n }\n\n return segments\n}\n\nexport function VerifiedText(props: VerifiedTextProps) {\n const mode = () => props.mode || 'highlight'\n\n const segments = createMemo<TextSegment[]>(() => {\n if (!props.validation || props.validation.valid) {\n return [{ type: 'text' as const, content: props.text }]\n }\n return buildAnnotatedSegments(props.text, props.validation)\n })\n\n return (\n <div class=\"verified-text text-sm leading-relaxed\">\n <For each={segments()}>\n {(seg) => {\n if (seg.type === 'text') {\n return <span>{seg.content}</span>\n }\n\n if (seg.type === 'verified') {\n return (\n <span\n class=\"inline-flex items-center gap-0.5 px-0.5 rounded bg-green-50 dark:bg-green-900/20 text-green-800 dark:text-green-300\"\n title=\"Verified against source data\"\n >\n {seg.content}\n <span class=\"text-xs opacity-70\" aria-label=\"verified\">✅</span>\n </span>\n )\n }\n\n // hallucinated\n const h = seg.item!\n const tooltipText = () => {\n if (h.closest != null && h.distance != null) {\n return `Not found in source data. Closest: ${h.closest} (${Math.round(h.distance * 100)}% off)`\n }\n return 'Not found in source data'\n }\n\n if (mode() === 'strip') {\n return (\n <span\n class=\"inline-flex items-center px-1 rounded bg-amber-50 dark:bg-amber-900/20 text-amber-700 dark:text-amber-300 italic text-xs\"\n title={tooltipText()}\n >\n [non vérifié]\n </span>\n )\n }\n\n return (\n <span\n class=\"inline-flex items-center gap-0.5 px-0.5 rounded bg-amber-50 dark:bg-amber-900/20 text-amber-800 dark:text-amber-300 cursor-help\"\n title={tooltipText()}\n onClick={() => props.onHallucinationClick?.(h)}\n role={props.onHallucinationClick ? 'button' : undefined}\n >\n {seg.content}\n <span class=\"text-xs\" aria-label=\"unverified\">⚠️</span>\n </span>\n )\n }}\n </For>\n\n {/* Confidence bar */}\n {props.validation && !props.validation.valid && (\n <div class=\"mt-2 flex items-center gap-2 text-xs text-gray-500 dark:text-gray-400\">\n <div class=\"flex-1 h-1.5 bg-gray-200 dark:bg-gray-700 rounded-full overflow-hidden\">\n <div\n class=\"h-full rounded-full transition-all\"\n classList={{\n 'bg-green-500': props.validation.confidence >= 0.8,\n 'bg-amber-500': props.validation.confidence >= 0.5 && props.validation.confidence < 0.8,\n 'bg-red-500': props.validation.confidence < 0.5,\n }}\n style={{ width: `${Math.round(props.validation.confidence * 100)}%` }}\n />\n </div>\n <span>\n {Math.round(props.validation.confidence * 100)}% verified\n ({props.validation.hallucinated.length} unverified)\n </span>\n </div>\n )}\n </div>\n )\n}\n"],"names":["buildAnnotatedSegments","text","validation","hallucinatedPositions","Map","h","hallucinated","set","position","verifiedPositions","Set","n","llmNumbers","has","add","map","length","context","sort","a","b","numberRegex","matches","m","exec","push","start","index","end","matchByPosition","match","segments","cursor","num","get","type","content","slice","numberText","item","VerifiedText","props","mode","createMemo","valid","_el$","_$getNextElement","_tmpl$","_el$2","firstChild","_el$3","_co$","_$getNextMarker","nextSibling","_el$4","_el$5","_co$2","_$insert","_$createComponent","For","each","children","seg","_el$6","_tmpl$2","_el$7","_tmpl$3","_el$9","_el$0","_co$3","tooltipText","closest","distance","Math","round","_el$1","_tmpl$4","_$effect","_$setAttribute","_el$10","_tmpl$5","_el$12","_el$13","_co$4","$$click","onHallucinationClick","_p$","_v$","_v$2","undefined","e","t","_$runHydrationEvents","_c$","_$memo","_el$14","_tmpl$6","_el$15","_el$16","_el$17","_el$20","_el$21","_co$5","_el$18","_el$22","_el$23","_co$6","confidence","_v$3","_v$4","_v$5","_v$6","classList","toggle","o","_$setStyleProperty","_$delegateEvents"],"mappings":"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"}
|
|
@@ -39,6 +39,10 @@ export { CodeBlockRenderer } from './CodeBlockRenderer';
|
|
|
39
39
|
export type { CodeBlockRendererProps } from './CodeBlockRenderer';
|
|
40
40
|
export { MapRenderer } from './MapRenderer';
|
|
41
41
|
export type { MapRendererProps } from './MapRenderer';
|
|
42
|
+
export { VerifiedText } from './VerifiedText';
|
|
43
|
+
export type { VerifiedTextProps } from './VerifiedText';
|
|
44
|
+
export { DataPreviewSection } from './DataPreviewSection';
|
|
45
|
+
export type { DataPreviewSectionProps } from './DataPreviewSection';
|
|
42
46
|
export { RenderContext, RenderProvider, useRenderContext } from './RenderContext';
|
|
43
47
|
export type { RenderContextValue, RenderComponentFn } from './RenderContext';
|
|
44
48
|
export { UIResourceRenderer as default } from './UIResourceRenderer';
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/components/index.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAEH,OAAO,EAAE,kBAAkB,EAAE,MAAM,sBAAsB,CAAA;AACzD,YAAY,EAAE,uBAAuB,EAAE,MAAM,sBAAsB,CAAA;AAEnE,OAAO,EAAE,mBAAmB,EAAE,MAAM,uBAAuB,CAAA;AAC3D,YAAY,EAAE,wBAAwB,EAAE,MAAM,uBAAuB,CAAA;AAErE,OAAO,EAAE,yBAAyB,EAAE,MAAM,6BAA6B,CAAA;AACvE,YAAY,EAAE,8BAA8B,EAAE,MAAM,6BAA6B,CAAA;AAGjF,OAAO,EAAE,cAAc,EAAE,MAAM,kBAAkB,CAAA;AACjD,YAAY,EAAE,qBAAqB,EAAE,MAAM,kBAAkB,CAAA;AAE7D,OAAO,EAAE,cAAc,EAAE,MAAM,kBAAkB,CAAA;AACjD,YAAY,EAAE,mBAAmB,EAAE,MAAM,kBAAkB,CAAA;AAE3D,OAAO,EAAE,gBAAgB,EAAE,MAAM,oBAAoB,CAAA;AACrD,YAAY,EAAE,uBAAuB,EAAE,MAAM,oBAAoB,CAAA;AAEjE,OAAO,EAAE,gBAAgB,EAAE,MAAM,oBAAoB,CAAA;AACrD,YAAY,EAAE,qBAAqB,EAAE,MAAM,oBAAoB,CAAA;AAE/D,OAAO,EAAE,YAAY,EAAE,MAAM,gBAAgB,CAAA;AAC7C,YAAY,EAAE,iBAAiB,EAAE,mBAAmB,EAAE,MAAM,gBAAgB,CAAA;AAG5E,OAAO,EAAE,YAAY,EAAE,MAAM,gBAAgB,CAAA;AAC7C,YAAY,EAAE,iBAAiB,EAAE,MAAM,gBAAgB,CAAA;AAEvD,OAAO,EAAE,iBAAiB,EAAE,MAAM,qBAAqB,CAAA;AACvD,YAAY,EAAE,sBAAsB,EAAE,MAAM,qBAAqB,CAAA;AAGjE,OAAO,EAAE,aAAa,EAAE,MAAM,iBAAiB,CAAA;AAC/C,YAAY,EAAE,kBAAkB,EAAE,MAAM,iBAAiB,CAAA;AAEzD,OAAO,EAAE,mBAAmB,EAAE,MAAM,uBAAuB,CAAA;AAC3D,YAAY,EAAE,wBAAwB,EAAE,MAAM,uBAAuB,CAAA;AAGrE,OAAO,EAAE,eAAe,EAAE,kBAAkB,EAAE,MAAM,mBAAmB,CAAA;AACvE,YAAY,EAAE,oBAAoB,EAAE,MAAM,mBAAmB,CAAA;AAG7D,OAAO,EAAE,eAAe,EAAE,MAAM,mBAAmB,CAAA;AACnD,YAAY,EAAE,oBAAoB,EAAE,MAAM,mBAAmB,CAAA;AAE7D,OAAO,EAAE,oBAAoB,EAAE,MAAM,wBAAwB,CAAA;AAC7D,YAAY,EAAE,yBAAyB,EAAE,MAAM,wBAAwB,CAAA;AAEvE,OAAO,EAAE,aAAa,EAAE,mBAAmB,EAAE,gBAAgB,EAAE,MAAM,iBAAiB,CAAA;AACtF,YAAY,EAAE,kBAAkB,EAAE,MAAM,iBAAiB,CAAA;AAGzD,OAAO,EAAE,iBAAiB,EAAE,MAAM,qBAAqB,CAAA;AACvD,YAAY,EAAE,sBAAsB,EAAE,MAAM,qBAAqB,CAAA;AAEjE,OAAO,EAAE,WAAW,EAAE,MAAM,eAAe,CAAA;AAC3C,YAAY,EAAE,gBAAgB,EAAE,MAAM,eAAe,CAAA;AAGrD,OAAO,EAAE,aAAa,EAAE,cAAc,EAAE,gBAAgB,EAAE,MAAM,iBAAiB,CAAA;AACjF,YAAY,EAAE,kBAAkB,EAAE,iBAAiB,EAAE,MAAM,iBAAiB,CAAA;AAG5E,OAAO,EAAE,kBAAkB,IAAI,OAAO,EAAE,MAAM,sBAAsB,CAAA"}
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/components/index.ts"],"names":[],"mappings":"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"}
|
package/dist/components.cjs
CHANGED
|
@@ -18,6 +18,8 @@ const ImageGalleryRenderer = require("./components/ImageGalleryRenderer.cjs");
|
|
|
18
18
|
const VideoRenderer = require("./components/VideoRenderer.cjs");
|
|
19
19
|
const CodeBlockRenderer = require("./components/CodeBlockRenderer.cjs");
|
|
20
20
|
const MapRenderer = require("./components/MapRenderer.cjs");
|
|
21
|
+
const VerifiedText = require("./components/VerifiedText.cjs");
|
|
22
|
+
const DataPreviewSection = require("./components/DataPreviewSection.cjs");
|
|
21
23
|
const RenderContext = require("./components/RenderContext.cjs");
|
|
22
24
|
exports.UIResourceRenderer = UIResourceRenderer.UIResourceRenderer;
|
|
23
25
|
exports.default = UIResourceRenderer.UIResourceRenderer;
|
|
@@ -41,6 +43,8 @@ exports.getVideoProvider = VideoRenderer.getVideoProvider;
|
|
|
41
43
|
exports.isSupportedVideoUrl = VideoRenderer.isSupportedVideoUrl;
|
|
42
44
|
exports.CodeBlockRenderer = CodeBlockRenderer.CodeBlockRenderer;
|
|
43
45
|
exports.MapRenderer = MapRenderer.MapRenderer;
|
|
46
|
+
exports.VerifiedText = VerifiedText.VerifiedText;
|
|
47
|
+
exports.DataPreviewSection = DataPreviewSection.DataPreviewSection;
|
|
44
48
|
exports.RenderContext = RenderContext.RenderContext;
|
|
45
49
|
exports.RenderProvider = RenderContext.RenderProvider;
|
|
46
50
|
exports.useRenderContext = RenderContext.useRenderContext;
|
package/dist/components.cjs.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"components.cjs","sources":[],"sourcesContent":[],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"components.cjs","sources":[],"sourcesContent":[],"names":[],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;"}
|
package/dist/components.d.cts
CHANGED
|
@@ -39,6 +39,10 @@ export { CodeBlockRenderer } from './CodeBlockRenderer';
|
|
|
39
39
|
export type { CodeBlockRendererProps } from './CodeBlockRenderer';
|
|
40
40
|
export { MapRenderer } from './MapRenderer';
|
|
41
41
|
export type { MapRendererProps } from './MapRenderer';
|
|
42
|
+
export { VerifiedText } from './VerifiedText';
|
|
43
|
+
export type { VerifiedTextProps } from './VerifiedText';
|
|
44
|
+
export { DataPreviewSection } from './DataPreviewSection';
|
|
45
|
+
export type { DataPreviewSectionProps } from './DataPreviewSection';
|
|
42
46
|
export { RenderContext, RenderProvider, useRenderContext } from './RenderContext';
|
|
43
47
|
export type { RenderContextValue, RenderComponentFn } from './RenderContext';
|
|
44
48
|
export { UIResourceRenderer as default } from './UIResourceRenderer';
|
package/dist/components.d.ts
CHANGED
|
@@ -39,6 +39,10 @@ export { CodeBlockRenderer } from './CodeBlockRenderer';
|
|
|
39
39
|
export type { CodeBlockRendererProps } from './CodeBlockRenderer';
|
|
40
40
|
export { MapRenderer } from './MapRenderer';
|
|
41
41
|
export type { MapRendererProps } from './MapRenderer';
|
|
42
|
+
export { VerifiedText } from './VerifiedText';
|
|
43
|
+
export type { VerifiedTextProps } from './VerifiedText';
|
|
44
|
+
export { DataPreviewSection } from './DataPreviewSection';
|
|
45
|
+
export type { DataPreviewSectionProps } from './DataPreviewSection';
|
|
42
46
|
export { RenderContext, RenderProvider, useRenderContext } from './RenderContext';
|
|
43
47
|
export type { RenderContextValue, RenderComponentFn } from './RenderContext';
|
|
44
48
|
export { UIResourceRenderer as default } from './UIResourceRenderer';
|
package/dist/components.js
CHANGED
|
@@ -16,6 +16,8 @@ import { ImageGalleryRenderer } from "./components/ImageGalleryRenderer.js";
|
|
|
16
16
|
import { VideoRenderer, getVideoProvider, isSupportedVideoUrl } from "./components/VideoRenderer.js";
|
|
17
17
|
import { CodeBlockRenderer } from "./components/CodeBlockRenderer.js";
|
|
18
18
|
import { MapRenderer } from "./components/MapRenderer.js";
|
|
19
|
+
import { VerifiedText } from "./components/VerifiedText.js";
|
|
20
|
+
import { DataPreviewSection } from "./components/DataPreviewSection.js";
|
|
19
21
|
import { RenderContext, RenderProvider, useRenderContext } from "./components/RenderContext.js";
|
|
20
22
|
export {
|
|
21
23
|
ActionGroupRenderer,
|
|
@@ -24,6 +26,7 @@ export {
|
|
|
24
26
|
CarouselRenderer,
|
|
25
27
|
ChartJSRenderer,
|
|
26
28
|
CodeBlockRenderer,
|
|
29
|
+
DataPreviewSection,
|
|
27
30
|
FooterRenderer,
|
|
28
31
|
FormFieldRenderer,
|
|
29
32
|
FormRenderer,
|
|
@@ -37,6 +40,7 @@ export {
|
|
|
37
40
|
RenderProvider,
|
|
38
41
|
StreamingUIRenderer,
|
|
39
42
|
UIResourceRenderer,
|
|
43
|
+
VerifiedText,
|
|
40
44
|
VideoRenderer,
|
|
41
45
|
UIResourceRenderer2 as default,
|
|
42
46
|
getVideoProvider,
|
package/dist/components.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"components.js","sources":[],"sourcesContent":[],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"components.js","sources":[],"sourcesContent":[],"names":[],"mappings":";;;;;;;;;;;;;;;;;;;;;"}
|
package/dist/hooks/index.d.ts
CHANGED
|
@@ -19,4 +19,6 @@ export { useResize } from './useResize';
|
|
|
19
19
|
export type { UseResizeOptions, UseResizeReturn, ResizeEdge, ResizeHandleProps, } from './useResize';
|
|
20
20
|
export { useAutocomplete } from './useAutocomplete';
|
|
21
21
|
export type { UseAutocompleteOptions, UseAutocompleteReturn, } from './useAutocomplete';
|
|
22
|
+
export { useDataValidator } from './useDataValidator';
|
|
23
|
+
export type { UseDataValidatorOptions, UseDataValidatorReturn, } from './useDataValidator';
|
|
22
24
|
//# sourceMappingURL=index.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/hooks/index.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAEH,OAAO,EAAE,cAAc,EAAE,MAAM,kBAAkB,CAAA;AACjD,YAAY,EACV,qBAAqB,EACrB,gBAAgB,EAChB,cAAc,EACd,WAAW,EACX,gBAAgB,GACjB,MAAM,kBAAkB,CAAA;AAGzB,OAAO,EAAE,SAAS,EAAE,aAAa,EAAE,MAAM,aAAa,CAAA;AACtD,YAAY,EACV,eAAe,EACf,gBAAgB,EAChB,mBAAmB,EACnB,aAAa,EACb,YAAY,GACb,MAAM,aAAa,CAAA;AAGpB,OAAO,EAAE,mBAAmB,EAAE,iBAAiB,EAAE,MAAM,uBAAuB,CAAA;AAC9E,YAAY,EAAE,0BAA0B,EAAE,MAAM,uBAAuB,CAAA;AAGvE,OAAO,EAAE,QAAQ,EAAE,eAAe,EAAE,MAAM,YAAY,CAAA;AACtD,YAAY,EAAE,cAAc,EAAE,qBAAqB,EAAE,MAAM,YAAY,CAAA;AAGvE,OAAO,EAAE,kBAAkB,EAAE,MAAM,sBAAsB,CAAA;AACzD,YAAY,EAAE,yBAAyB,EAAE,wBAAwB,EAAE,MAAM,sBAAsB,CAAA;AAG/F,OAAO,EAAE,WAAW,EAAE,MAAM,eAAe,CAAA;AAC3C,YAAY,EACV,kBAAkB,EAClB,iBAAiB,EACjB,SAAS,GACV,MAAM,eAAe,CAAA;AAEtB,OAAO,EAAE,SAAS,EAAE,MAAM,aAAa,CAAA;AACvC,YAAY,EACV,gBAAgB,EAChB,eAAe,EACf,UAAU,EACV,iBAAiB,GAClB,MAAM,aAAa,CAAA;AAGpB,OAAO,EAAE,eAAe,EAAE,MAAM,mBAAmB,CAAA;AACnD,YAAY,EACV,sBAAsB,EACtB,qBAAqB,GACtB,MAAM,mBAAmB,CAAA"}
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/hooks/index.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAEH,OAAO,EAAE,cAAc,EAAE,MAAM,kBAAkB,CAAA;AACjD,YAAY,EACV,qBAAqB,EACrB,gBAAgB,EAChB,cAAc,EACd,WAAW,EACX,gBAAgB,GACjB,MAAM,kBAAkB,CAAA;AAGzB,OAAO,EAAE,SAAS,EAAE,aAAa,EAAE,MAAM,aAAa,CAAA;AACtD,YAAY,EACV,eAAe,EACf,gBAAgB,EAChB,mBAAmB,EACnB,aAAa,EACb,YAAY,GACb,MAAM,aAAa,CAAA;AAGpB,OAAO,EAAE,mBAAmB,EAAE,iBAAiB,EAAE,MAAM,uBAAuB,CAAA;AAC9E,YAAY,EAAE,0BAA0B,EAAE,MAAM,uBAAuB,CAAA;AAGvE,OAAO,EAAE,QAAQ,EAAE,eAAe,EAAE,MAAM,YAAY,CAAA;AACtD,YAAY,EAAE,cAAc,EAAE,qBAAqB,EAAE,MAAM,YAAY,CAAA;AAGvE,OAAO,EAAE,kBAAkB,EAAE,MAAM,sBAAsB,CAAA;AACzD,YAAY,EAAE,yBAAyB,EAAE,wBAAwB,EAAE,MAAM,sBAAsB,CAAA;AAG/F,OAAO,EAAE,WAAW,EAAE,MAAM,eAAe,CAAA;AAC3C,YAAY,EACV,kBAAkB,EAClB,iBAAiB,EACjB,SAAS,GACV,MAAM,eAAe,CAAA;AAEtB,OAAO,EAAE,SAAS,EAAE,MAAM,aAAa,CAAA;AACvC,YAAY,EACV,gBAAgB,EAChB,eAAe,EACf,UAAU,EACV,iBAAiB,GAClB,MAAM,aAAa,CAAA;AAGpB,OAAO,EAAE,eAAe,EAAE,MAAM,mBAAmB,CAAA;AACnD,YAAY,EACV,sBAAsB,EACtB,qBAAqB,GACtB,MAAM,mBAAmB,CAAA;AAG1B,OAAO,EAAE,gBAAgB,EAAE,MAAM,oBAAoB,CAAA;AACrD,YAAY,EACV,uBAAuB,EACvB,sBAAsB,GACvB,MAAM,oBAAoB,CAAA"}
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
|
|
3
|
+
const solidJs = require("solid-js");
|
|
4
|
+
const dataValidator = require("../services/data-validator.cjs");
|
|
5
|
+
function useDataValidator(text, sourceRows, options = {}) {
|
|
6
|
+
const { enabled = true, ...validationOptions } = options;
|
|
7
|
+
const validation = solidJs.createMemo(() => {
|
|
8
|
+
if (!enabled) return null;
|
|
9
|
+
const t = text();
|
|
10
|
+
const rows = sourceRows();
|
|
11
|
+
if (!t || !rows || rows.length === 0) return null;
|
|
12
|
+
return dataValidator.validateAgainstSource(t, rows, validationOptions);
|
|
13
|
+
});
|
|
14
|
+
return {
|
|
15
|
+
validation,
|
|
16
|
+
valid: () => {
|
|
17
|
+
var _a;
|
|
18
|
+
return ((_a = validation()) == null ? void 0 : _a.valid) ?? true;
|
|
19
|
+
},
|
|
20
|
+
confidence: () => {
|
|
21
|
+
var _a;
|
|
22
|
+
return ((_a = validation()) == null ? void 0 : _a.confidence) ?? 1;
|
|
23
|
+
},
|
|
24
|
+
hallucinatedCount: () => {
|
|
25
|
+
var _a;
|
|
26
|
+
return ((_a = validation()) == null ? void 0 : _a.hallucinated.length) ?? 0;
|
|
27
|
+
}
|
|
28
|
+
};
|
|
29
|
+
}
|
|
30
|
+
exports.useDataValidator = useDataValidator;
|
|
31
|
+
//# sourceMappingURL=useDataValidator.cjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"useDataValidator.cjs","sources":["../../src/hooks/useDataValidator.ts"],"sourcesContent":["/**\n * useDataValidator — reactive SolidJS hook for data validation\n * v3.1.0: Wraps validateAgainstSource in a reactive memo\n *\n * @experimental\n */\n\nimport { createMemo } from 'solid-js'\nimport { validateAgainstSource } from '../services/data-validator'\nimport type { DataValidation, DataValidationOptions } from '../types/chat-bus'\n\nexport interface UseDataValidatorOptions extends DataValidationOptions {\n /** Disable validation (returns null) */\n enabled?: boolean\n}\n\nexport interface UseDataValidatorReturn {\n /** Reactive validation result (null if disabled or no text) */\n validation: () => DataValidation | null\n /** Is the text valid (no hallucinations)? */\n valid: () => boolean\n /** Confidence score 0-1 */\n confidence: () => number\n /** Count of hallucinated numbers */\n hallucinatedCount: () => number\n}\n\n/**\n * Reactive hook that validates LLM text against source data rows.\n * Re-validates automatically when text or rows change.\n *\n * @example\n * ```tsx\n * const { validation, valid, confidence } = useDataValidator(\n * () => llmResponse(),\n * () => sourceRows(),\n * { tolerance: 0.02, ignoreColumns: ['code_geo'] }\n * )\n *\n * return (\n * <Show when={!valid()}>\n * <span>⚠️ {validation()!.hallucinated.length} unverified numbers</span>\n * </Show>\n * )\n * ```\n */\nexport function useDataValidator(\n text: () => string,\n sourceRows: () => Record<string, unknown>[],\n options: UseDataValidatorOptions = {}\n): UseDataValidatorReturn {\n const { enabled = true, ...validationOptions } = options\n\n const validation = createMemo<DataValidation | null>(() => {\n if (!enabled) return null\n const t = text()\n const rows = sourceRows()\n if (!t || !rows || rows.length === 0) return null\n return validateAgainstSource(t, rows, validationOptions)\n })\n\n return {\n validation,\n valid: () => validation()?.valid ?? true,\n confidence: () => validation()?.confidence ?? 1,\n hallucinatedCount: () => validation()?.hallucinated.length ?? 0,\n }\n}\n"],"names":["createMemo","validateAgainstSource"],"mappings":";;;;AA8CO,SAAS,iBACd,MACA,YACA,UAAmC,CAAA,GACX;AACxB,QAAM,EAAE,UAAU,MAAM,GAAG,sBAAsB;AAEjD,QAAM,aAAaA,QAAAA,WAAkC,MAAM;AACzD,QAAI,CAAC,QAAS,QAAO;AACrB,UAAM,IAAI,KAAA;AACV,UAAM,OAAO,WAAA;AACb,QAAI,CAAC,KAAK,CAAC,QAAQ,KAAK,WAAW,EAAG,QAAO;AAC7C,WAAOC,oCAAsB,GAAG,MAAM,iBAAiB;AAAA,EACzD,CAAC;AAED,SAAO;AAAA,IACL;AAAA,IACA,OAAO,MAAA;;AAAM,qCAAA,mBAAc,UAAS;AAAA;AAAA,IACpC,YAAY,MAAA;;AAAM,qCAAA,mBAAc,eAAc;AAAA;AAAA,IAC9C,mBAAmB,MAAA;;AAAM,qCAAA,mBAAc,aAAa,WAAU;AAAA;AAAA,EAAA;AAElE;;"}
|
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* useDataValidator — reactive SolidJS hook for data validation
|
|
3
|
+
* v3.1.0: Wraps validateAgainstSource in a reactive memo
|
|
4
|
+
*
|
|
5
|
+
* @experimental
|
|
6
|
+
*/
|
|
7
|
+
import type { DataValidation, DataValidationOptions } from '../types/chat-bus';
|
|
8
|
+
export interface UseDataValidatorOptions extends DataValidationOptions {
|
|
9
|
+
/** Disable validation (returns null) */
|
|
10
|
+
enabled?: boolean;
|
|
11
|
+
}
|
|
12
|
+
export interface UseDataValidatorReturn {
|
|
13
|
+
/** Reactive validation result (null if disabled or no text) */
|
|
14
|
+
validation: () => DataValidation | null;
|
|
15
|
+
/** Is the text valid (no hallucinations)? */
|
|
16
|
+
valid: () => boolean;
|
|
17
|
+
/** Confidence score 0-1 */
|
|
18
|
+
confidence: () => number;
|
|
19
|
+
/** Count of hallucinated numbers */
|
|
20
|
+
hallucinatedCount: () => number;
|
|
21
|
+
}
|
|
22
|
+
/**
|
|
23
|
+
* Reactive hook that validates LLM text against source data rows.
|
|
24
|
+
* Re-validates automatically when text or rows change.
|
|
25
|
+
*
|
|
26
|
+
* @example
|
|
27
|
+
* ```tsx
|
|
28
|
+
* const { validation, valid, confidence } = useDataValidator(
|
|
29
|
+
* () => llmResponse(),
|
|
30
|
+
* () => sourceRows(),
|
|
31
|
+
* { tolerance: 0.02, ignoreColumns: ['code_geo'] }
|
|
32
|
+
* )
|
|
33
|
+
*
|
|
34
|
+
* return (
|
|
35
|
+
* <Show when={!valid()}>
|
|
36
|
+
* <span>⚠️ {validation()!.hallucinated.length} unverified numbers</span>
|
|
37
|
+
* </Show>
|
|
38
|
+
* )
|
|
39
|
+
* ```
|
|
40
|
+
*/
|
|
41
|
+
export declare function useDataValidator(text: () => string, sourceRows: () => Record<string, unknown>[], options?: UseDataValidatorOptions): UseDataValidatorReturn;
|
|
42
|
+
//# sourceMappingURL=useDataValidator.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"useDataValidator.d.ts","sourceRoot":"","sources":["../../src/hooks/useDataValidator.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAIH,OAAO,KAAK,EAAE,cAAc,EAAE,qBAAqB,EAAE,MAAM,mBAAmB,CAAA;AAE9E,MAAM,WAAW,uBAAwB,SAAQ,qBAAqB;IACpE,wCAAwC;IACxC,OAAO,CAAC,EAAE,OAAO,CAAA;CAClB;AAED,MAAM,WAAW,sBAAsB;IACrC,+DAA+D;IAC/D,UAAU,EAAE,MAAM,cAAc,GAAG,IAAI,CAAA;IACvC,6CAA6C;IAC7C,KAAK,EAAE,MAAM,OAAO,CAAA;IACpB,2BAA2B;IAC3B,UAAU,EAAE,MAAM,MAAM,CAAA;IACxB,oCAAoC;IACpC,iBAAiB,EAAE,MAAM,MAAM,CAAA;CAChC;AAED;;;;;;;;;;;;;;;;;;GAkBG;AACH,wBAAgB,gBAAgB,CAC9B,IAAI,EAAE,MAAM,MAAM,EAClB,UAAU,EAAE,MAAM,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,EAAE,EAC3C,OAAO,GAAE,uBAA4B,GACpC,sBAAsB,CAiBxB"}
|