data-navigator 3.2.2 → 3.3.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/dist/index.cjs +23 -10
- package/dist/index.d.cts +4 -2
- package/dist/index.d.ts +4 -2
- package/dist/index.js +23 -10
- package/dist/text-chat.cjs +8 -8
- package/dist/text-chat.js +3 -3
- package/package.json +1 -1
package/dist/index.cjs
CHANGED
|
@@ -2650,6 +2650,13 @@ var text_chat_default = (options) => {
|
|
|
2650
2650
|
},
|
|
2651
2651
|
getCurrentNode() {
|
|
2652
2652
|
return currentNodeId ? structure.nodes[currentNodeId] || null : null;
|
|
2653
|
+
},
|
|
2654
|
+
submit(text) {
|
|
2655
|
+
return handleCommand(text);
|
|
2656
|
+
},
|
|
2657
|
+
setCurrentNode(nodeId) {
|
|
2658
|
+
currentNodeId = nodeId && structure.nodes[nodeId] ? nodeId : null;
|
|
2659
|
+
pendingChoices = null;
|
|
2653
2660
|
}
|
|
2654
2661
|
};
|
|
2655
2662
|
};
|
|
@@ -2697,17 +2704,23 @@ function convexHullPath(points) {
|
|
|
2697
2704
|
return `M${fmt(first.x)},${fmt(first.y)}` + rest.map((p) => `L${fmt(p.x)},${fmt(p.y)}`).join("") + "Z";
|
|
2698
2705
|
}
|
|
2699
2706
|
function expandHull(hullPoints, padPx) {
|
|
2700
|
-
|
|
2707
|
+
const n = hullPoints.length;
|
|
2708
|
+
if (padPx === 0 || n < 3)
|
|
2701
2709
|
return hullPoints;
|
|
2702
|
-
const
|
|
2703
|
-
|
|
2704
|
-
|
|
2705
|
-
|
|
2706
|
-
|
|
2707
|
-
|
|
2708
|
-
|
|
2709
|
-
|
|
2710
|
-
|
|
2710
|
+
const area = hullPoints.reduce((s, p, i) => {
|
|
2711
|
+
const q = hullPoints[(i + 1) % n];
|
|
2712
|
+
return s + p.x * q.y - q.x * p.y;
|
|
2713
|
+
}, 0);
|
|
2714
|
+
const sign = Math.sign(area);
|
|
2715
|
+
const normal = (a, b) => {
|
|
2716
|
+
const len = Math.hypot(b.x - a.x, b.y - a.y);
|
|
2717
|
+
return { x: sign * (b.y - a.y) / len, y: sign * (a.x - b.x) / len };
|
|
2718
|
+
};
|
|
2719
|
+
return hullPoints.map((p, i) => {
|
|
2720
|
+
const n1 = normal(hullPoints[(i + n - 1) % n], p);
|
|
2721
|
+
const n2 = normal(p, hullPoints[(i + 1) % n]);
|
|
2722
|
+
const scale = padPx / (1 + n1.x * n2.x + n1.y * n2.y);
|
|
2723
|
+
return { x: p.x + (n1.x + n2.x) * scale, y: p.y + (n1.y + n2.y) * scale };
|
|
2711
2724
|
});
|
|
2712
2725
|
}
|
|
2713
2726
|
function rectCorners(r) {
|
package/dist/index.d.cts
CHANGED
|
@@ -333,6 +333,8 @@ type TextChatOptions = {
|
|
|
333
333
|
type TextChatInstance = {
|
|
334
334
|
destroy: () => void;
|
|
335
335
|
getCurrentNode: () => NodeObject | null;
|
|
336
|
+
submit: (text: string) => Promise<void>;
|
|
337
|
+
setCurrentNode: (nodeId: string | null) => void;
|
|
336
338
|
};
|
|
337
339
|
|
|
338
340
|
/**
|
|
@@ -370,8 +372,8 @@ declare function grahamScan(points: Point[]): Point[];
|
|
|
370
372
|
*/
|
|
371
373
|
declare function convexHullPath(points: Point[]): string;
|
|
372
374
|
/**
|
|
373
|
-
* Expand a convex hull polygon
|
|
374
|
-
*
|
|
375
|
+
* Expand a convex hull polygon by moving each edge outward by `padPx` pixels.
|
|
376
|
+
* Corners are placed where neighboring edges meet (miter join).
|
|
375
377
|
*/
|
|
376
378
|
declare function expandHull(hullPoints: Point[], padPx: number): Point[];
|
|
377
379
|
/**
|
package/dist/index.d.ts
CHANGED
|
@@ -333,6 +333,8 @@ type TextChatOptions = {
|
|
|
333
333
|
type TextChatInstance = {
|
|
334
334
|
destroy: () => void;
|
|
335
335
|
getCurrentNode: () => NodeObject | null;
|
|
336
|
+
submit: (text: string) => Promise<void>;
|
|
337
|
+
setCurrentNode: (nodeId: string | null) => void;
|
|
336
338
|
};
|
|
337
339
|
|
|
338
340
|
/**
|
|
@@ -370,8 +372,8 @@ declare function grahamScan(points: Point[]): Point[];
|
|
|
370
372
|
*/
|
|
371
373
|
declare function convexHullPath(points: Point[]): string;
|
|
372
374
|
/**
|
|
373
|
-
* Expand a convex hull polygon
|
|
374
|
-
*
|
|
375
|
+
* Expand a convex hull polygon by moving each edge outward by `padPx` pixels.
|
|
376
|
+
* Corners are placed where neighboring edges meet (miter join).
|
|
375
377
|
*/
|
|
376
378
|
declare function expandHull(hullPoints: Point[], padPx: number): Point[];
|
|
377
379
|
/**
|
package/dist/index.js
CHANGED
|
@@ -2616,6 +2616,13 @@ var text_chat_default = (options) => {
|
|
|
2616
2616
|
},
|
|
2617
2617
|
getCurrentNode() {
|
|
2618
2618
|
return currentNodeId ? structure.nodes[currentNodeId] || null : null;
|
|
2619
|
+
},
|
|
2620
|
+
submit(text) {
|
|
2621
|
+
return handleCommand(text);
|
|
2622
|
+
},
|
|
2623
|
+
setCurrentNode(nodeId) {
|
|
2624
|
+
currentNodeId = nodeId && structure.nodes[nodeId] ? nodeId : null;
|
|
2625
|
+
pendingChoices = null;
|
|
2619
2626
|
}
|
|
2620
2627
|
};
|
|
2621
2628
|
};
|
|
@@ -2663,17 +2670,23 @@ function convexHullPath(points) {
|
|
|
2663
2670
|
return `M${fmt(first.x)},${fmt(first.y)}` + rest.map((p) => `L${fmt(p.x)},${fmt(p.y)}`).join("") + "Z";
|
|
2664
2671
|
}
|
|
2665
2672
|
function expandHull(hullPoints, padPx) {
|
|
2666
|
-
|
|
2673
|
+
const n = hullPoints.length;
|
|
2674
|
+
if (padPx === 0 || n < 3)
|
|
2667
2675
|
return hullPoints;
|
|
2668
|
-
const
|
|
2669
|
-
|
|
2670
|
-
|
|
2671
|
-
|
|
2672
|
-
|
|
2673
|
-
|
|
2674
|
-
|
|
2675
|
-
|
|
2676
|
-
|
|
2676
|
+
const area = hullPoints.reduce((s, p, i) => {
|
|
2677
|
+
const q = hullPoints[(i + 1) % n];
|
|
2678
|
+
return s + p.x * q.y - q.x * p.y;
|
|
2679
|
+
}, 0);
|
|
2680
|
+
const sign = Math.sign(area);
|
|
2681
|
+
const normal = (a, b) => {
|
|
2682
|
+
const len = Math.hypot(b.x - a.x, b.y - a.y);
|
|
2683
|
+
return { x: sign * (b.y - a.y) / len, y: sign * (a.x - b.x) / len };
|
|
2684
|
+
};
|
|
2685
|
+
return hullPoints.map((p, i) => {
|
|
2686
|
+
const n1 = normal(hullPoints[(i + n - 1) % n], p);
|
|
2687
|
+
const n2 = normal(p, hullPoints[(i + 1) % n]);
|
|
2688
|
+
const scale = padPx / (1 + n1.x * n2.x + n1.y * n2.y);
|
|
2689
|
+
return { x: p.x + (n1.x + n2.x) * scale, y: p.y + (n1.y + n2.y) * scale };
|
|
2677
2690
|
});
|
|
2678
2691
|
}
|
|
2679
2692
|
function rectCorners(r) {
|
package/dist/text-chat.cjs
CHANGED
|
@@ -1,21 +1,21 @@
|
|
|
1
|
-
var
|
|
1
|
+
var J=Object.defineProperty;var fe=Object.getOwnPropertyDescriptor;var ye=Object.getOwnPropertyNames;var ve=Object.prototype.hasOwnProperty;var be=(t,e)=>{for(var i in e)J(t,i,{get:e[i],enumerable:!0})},we=(t,e,i,l)=>{if(e&&typeof e=="object"||typeof e=="function")for(let r of ye(e))!ve.call(t,r)&&r!==i&&J(t,r,{get:()=>e[r],enumerable:!(l=fe(e,r))||l.enumerable});return t};var ke=t=>we(J({},"__esModule",{value:!0}),t);var U=(t,e,i)=>new Promise((l,r)=>{var n=c=>{try{p(i.next(c))}catch(d){r(d)}},o=c=>{try{p(i.throw(c))}catch(d){r(d)}},p=c=>c.done?l(c.value):Promise.resolve(c.value).then(n,o);p((i=i.apply(t,e)).next())});var Re={};be(Re,{default:()=>Te});module.exports=ke(Re);var z={ArrowLeft:"left",ArrowRight:"right",ArrowUp:"up",ArrowDown:"down",Period:"forward",Comma:"backward",Escape:"drill-out",Enter:"drill-in"};var Q={left:{key:"ArrowLeft",direction:"source"},right:{key:"ArrowRight",direction:"target"},up:{key:"ArrowUp",direction:"source"},down:{key:"ArrowDown",direction:"target"},"drill-in":{key:"Enter",direction:"target"},"drill-out":{key:"Backspace",direction:"source"},backward:{key:"Comma",direction:"source"},forward:{key:"Period",direction:"target"},previous:{key:"Semicolon",direction:"source"},next:{key:"Quote",direction:"target"},exit:{key:"Escape",direction:"target"},help:{key:"KeyY",direction:"target"},undo:{key:"KeyZ",direction:"target"}};var se=t=>{let e={},i=z,l=Q;return e.moveTo=r=>{let n=t.structure.nodes[r];if(n)return n},e.move=(r,n)=>{if(r){let o=t.structure.nodes[r];if(o.edges){let p=null,c=0,d=l[n];if(!d)return;let f=(g,s)=>{if(g!==n)return null;let b={target:typeof s.target=="string"?s.target:s.target(o,r),source:typeof s.source=="string"?s.source:s.source(o,r)};return b[d.direction]!==r?b[d.direction]:null};for(c=0;c<o.edges.length;c++){let g=t.structure.edges[o.edges[c]];if(g.navigationRules.forEach(s=>{p||(p=f(s,g))}),p)break}return p?e.moveTo(p):void 0}}},e.enter=()=>{if(t.entryPoint)return e.moveTo(t.entryPoint);console.error("No entry point was specified in InputOptions, returning undefined")},e.exit=()=>{if(t.exitPoint)return t.exitPoint;console.error("No exit point was specified in InputOptions, returning undefined")},e.keydownValidator=r=>{let n=i[r.code];if(n)return n},e.focus=r=>{let n=document.getElementById(r);n&&n.focus()},e.setNavigationKeyBindings=r=>{r?(i={},l=r,Object.keys(r).forEach(n=>{let o=r[n];i[o.key]=n})):(i=z,l=Q)},e.setNavigationKeyBindings(t.navigationRules),e};var xe=t=>{var i,l,r,n;let e=typeof t.semantics=="function"?t.semantics(t,t.data):t.semantics;if(e!=null&&e.label){let o=typeof e.label=="function"?e.label(t,t.data):e.label;if(o)return o}if(!t.derivedNode)return t.data?Object.keys(t.data).map(o=>`${o}: ${t.data[o]}`).join(". ")+". Data point.":t.id;if((i=t.data)!=null&&i.dimensionKey){let o=0,p=Object.keys(t.data.divisions||{});p.forEach(d=>{o+=Object.keys(t.data.divisions[d].values||{}).length});let c=`${t.derivedNode}.`;return c+=p.length&&o?` ${p.length} division${p.length>1?"s":""}, ${o} datapoint${o>1?"s":""}.`:" No child data points.",c+=` ${t.data.type} dimension.`,c}return`${t.derivedNode}: ${(l=t.data)==null?void 0:l[t.derivedNode]}. ${Object.keys(((r=t.data)==null?void 0:r.values)||{}).length} child data point${Object.keys(((n=t.data)==null?void 0:n.values)||{}).length>1?"s":""}. Division.`},Ne=(t,e,i)=>{let l=new Set,r=i.navigationRules||{};return e.edges&&e.edges.forEach(n=>{let o=i.edges[n];o&&o.navigationRules.forEach(p=>{let c=r[p];if(!c)return;let d=c.direction==="target"?o.target:o.source,f=typeof d=="function"?d(e,t):d;f&&f!==t&&l.add(p)})}),Array.from(l)},le=t=>t.navigationRules?Object.keys(t.navigationRules):[],V=(t,e)=>{let i=t.length,l=e.length,r=Array.from({length:i+1},()=>Array(l+1).fill(0));for(let n=0;n<=i;n++)r[n][0]=n;for(let n=0;n<=l;n++)r[0][n]=n;for(let n=1;n<=i;n++)for(let o=1;o<=l;o++){let p=t[n-1]===e[o-1]?0:1;r[n][o]=Math.min(r[n-1][o]+1,r[n][o-1]+1,r[n-1][o-1]+p),n>1&&o>1&&t[n-1]===e[o-2]&&t[n-2]===e[o-1]&&(r[n][o]=Math.min(r[n][o],r[n-2][o-2]+p))}return r[i][l]},Ce=t=>t<=4?1:2,Ee=(t,e,i={})=>{let l=t.toLowerCase().trim(),r=e.find(s=>s.toLowerCase()===l);if(r)return{match:r,ambiguous:[]};let n=e.find(s=>i[s]&&i[s].toLowerCase()===l);if(n)return{match:n,ambiguous:[]};let o=e.filter(s=>s.toLowerCase().startsWith(l));if(o.length===1)return{match:o[0],ambiguous:[]};let p=e.filter(s=>{if(!i[s])return!1;let b=i[s].toLowerCase();return b.startsWith(l)?!0:b.split(/\s+/).some(L=>L.startsWith(l))}),c=new Set([...o,...p]),d=Array.from(c);if(d.length===1)return{match:d[0],ambiguous:[]};if(d.length>1)return{match:null,ambiguous:d};let f=Ce(l.length),g=[];for(let s=0;s<e.length;s++){let b=e[s],L=V(l,b.toLowerCase());if(L<=f){g.push({candidate:b,dist:L});continue}if(i[b]){let S=i[b].toLowerCase().split(/\s+/);for(let A=0;A<S.length;A++)if(V(l,S[A])<=f){g.push({candidate:b,dist:V(l,S[A])});break}}}return g.length===1?{match:g[0].candidate,ambiguous:[]}:g.length>1?(g.sort((s,b)=>s.dist-b.dist),g[0].dist<g[1].dist?{match:g[0].candidate,ambiguous:[]}:{match:null,ambiguous:g.map(s=>s.candidate)}):{match:null,ambiguous:[]}},Z=(t,e)=>e[t]?`${e[t]} (${t})`:t,Ae=(t,e,i,l=10)=>{let r=t.toLowerCase(),n=[],o=Object.keys(e.nodes);for(let p=0;p<o.length&&n.length<l;p++){let c=o[p],d=e.nodes[c],f=!1;if(d.data&&!f){let g=Object.keys(d.data);for(let s=0;s<g.length&&!f;s++){let b=d.data[g[s]];b!=null&&typeof b!="object"&&String(b).toLowerCase().includes(r)&&(f=!0)}}!f&&d.derivedNode&&d.derivedNode.toLowerCase().includes(r)&&(f=!0),!f&&c.toLowerCase().includes(r)&&(f=!0),f&&n.push({nodeId:c,description:i(d)})}return n},Te=t=>{var re,oe,ie,ae;let{structure:e,container:i,entryPoint:l,describeNode:r=xe,commandLabels:n={},onNavigate:o,onExit:p,onClick:c,onHover:d,llm:f,data:g}=t,s=typeof i=="string"?document.getElementById(i):i;if(!s)throw new Error(`textChat: container "${i}" not found`);let b=Object.keys(e.nodes).find(a=>e.nodes[a].dimensionLevel===0),L=e.dimensions?(re=e.dimensions[Object.keys(e.dimensions)[0]])==null?void 0:re.nodeId:void 0,S=l||((oe=e.frame)==null?void 0:oe.rootId)||b||((ie=e.spatialGrid)==null?void 0:ie.rootId)||((ae=e.hierarchy)==null?void 0:ae.rootId)||L||Object.keys(e.nodes)[0],A=se({structure:e,navigationRules:e.navigationRules||{},entryPoint:S}),v=null,X=Math.random().toString(36).slice(2,8),O=[],C=-1,R=null,P=[],ce=()=>{let a=`You are a data assistant helping a user explore a dataset through a text-based navigation interface.
|
|
2
2
|
|
|
3
3
|
`;if(g&&g.length>0){let h=Object.keys(g[0]),m=g.slice(0,3).map(N=>JSON.stringify(N)).join(`
|
|
4
|
-
`);
|
|
4
|
+
`);a+=`DATASET SUMMARY:
|
|
5
5
|
- Columns: ${h.join(", ")}
|
|
6
6
|
- Rows: ${g.length}
|
|
7
7
|
- Sample (first 3):
|
|
8
8
|
${m}
|
|
9
9
|
|
|
10
|
-
`,
|
|
10
|
+
`,a+=`FULL DATASET (JSON):
|
|
11
11
|
`+JSON.stringify(g)+`
|
|
12
12
|
|
|
13
|
-
`}if(
|
|
13
|
+
`}if(v){let h=e.nodes[v];a+=`CURRENT POSITION: ${h?r(h):v}
|
|
14
14
|
|
|
15
|
-
`}else
|
|
15
|
+
`}else a+=`CURRENT POSITION: Not yet navigated into the structure.
|
|
16
16
|
|
|
17
|
-
`;return
|
|
17
|
+
`;return a+=`PRIORITY: Always prefer answers that can be verified against the dataset. For any statistical or quantitative claim (averages, comparisons, trends, extremes), briefly describe the method you used. Avoid open-ended or contextual claims that go beyond what the data can support \u2014 if the user asks something that cannot be checked against the dataset, say so and suggest they verify externally.
|
|
18
18
|
|
|
19
|
-
`,
|
|
19
|
+
`,a+=`VERIFICATION: When the user asks you to verify a claim, write a short Python script (using the dataset as a JSON array) that computes the answer, and show the expected output. If the claim is too open-ended to verify with code, explain why and recommend external verification.
|
|
20
20
|
|
|
21
|
-
`,
|
|
21
|
+
`,a+='IMPORTANT: Your responses may contain errors. The user has been told they can ask you to "verify" any answer, and you will attempt to provide a Python script to check it.',a},I=document.createElement("div");I.className="dn-text-chat";let k=document.createElement("div");k.className="dn-text-chat-log",k.setAttribute("role","log"),k.setAttribute("aria-live","polite"),I.appendChild(k);let W=document.createElement("div");W.className="dn-text-chat-controls";let Y=document.createElement("label"),D=document.createElement("input");D.type="checkbox",D.checked=!0,D.addEventListener("change",()=>{k.setAttribute("aria-live",D.checked?"polite":"off")}),Y.appendChild(D),Y.appendChild(document.createTextNode(" Automatically announce to screen readers")),W.appendChild(Y),I.appendChild(W);let $=document.createElement("form");$.className="dn-text-chat-form";let M=document.createElement("label");M.setAttribute("for",`dn-text-chat-input-${X}`),M.className="dn-text-chat-sr-only",M.textContent="Navigation command";let x=document.createElement("input");x.type="text",x.id=`dn-text-chat-input-${X}`,x.autocomplete="off",x.setAttribute("placeholder","Type a command...");let q=document.createElement("button");q.type="submit",q.textContent="Send",$.appendChild(M),$.appendChild(x),$.appendChild(q),I.appendChild($),s.appendChild(I);let _="";x.addEventListener("keydown",a=>{if(a.key==="ArrowUp"){if(a.preventDefault(),O.length===0)return;C===-1?(_=x.value,C=O.length-1):C>0&&C--,x.value=O[C]}else if(a.key==="ArrowDown"){if(a.preventDefault(),C===-1)return;C<O.length-1?(C++,x.value=O[C]):(C=-1,x.value=_)}});let F=(a,h)=>{let m=document.createElement("div");m.className=`dn-text-chat-message ${h}`,m.textContent=a,k.appendChild(m),k.scrollTop=k.scrollHeight},B=a=>F(a,"dn-text-chat-system"),de=a=>F(`> ${a}`,"dn-text-chat-input-echo"),y=a=>F(a,"dn-text-chat-response"),ue=(a,h)=>{let m=document.createElement("div");m.className="dn-text-chat-message dn-text-chat-response";let N=document.createElement("span");N.textContent=a,m.appendChild(N);let E=document.createElement("ol");E.className="dn-text-chat-choices",h.forEach(K=>{let T=document.createElement("li");T.textContent=K,E.appendChild(T)}),m.appendChild(E),k.appendChild(m),k.scrollTop=k.scrollHeight},ee=a=>U(void 0,null,function*(){let h={role:"system",content:ce()};P.push({role:"user",content:a});let m=document.createElement("div");m.className="dn-text-chat-message dn-text-chat-llm-thinking",m.textContent="Thinking...",k.appendChild(m),k.scrollTop=k.scrollHeight;try{let N=yield f([h,...P]);return k.removeChild(m),N===null?(P.pop(),null):(P.push({role:"assistant",content:N}),y(N),N)}catch(N){return k.removeChild(m),P.pop(),y(`Error: ${N.message||"Could not get a response."}`),""}});f?(B('Text navigation ready. Type "enter" to begin navigating, "help" for commands, or ask a question about the data.'),B('Note: AI-generated answers may be inaccurate. You can ask the model to "verify" any answer \u2014 it will attempt to provide a Python script that checks the claim against the dataset. If a claim cannot be verified with code, it should be verified externally.')):B('Text navigation ready. Type "enter" to begin or "help" for available commands.');let te=["enter","help","more","more help","clear","click","select","hover","inspect"],ne=a=>{let h=A.moveTo(a);h?(v=h.id,o&&o(h),y(`Moved to: ${r(h)}`)):y("Could not move to that node.")},G=a=>U(void 0,null,function*(){let h=a.trim();if(!h)return;de(h);let m=h.toLowerCase();if(R){let u=parseInt(h,10);if(!isNaN(u)&&u>=1&&u<=R.length){let w=R[u-1];R=null,ne(w.nodeId);return}R=null}if(m==="clear"){k.innerHTML="",B('Chat cleared. Type "help" for available commands.');return}if(m==="enter"){if(v){y('Already in the structure. Type "help" to see available commands.');return}let u=A.enter();if(!u){y("Could not enter the structure. No entry point found.");return}v=u.id,o&&o(u),y(`Entered: ${r(u)}`);return}if(m==="help"){let u=f?" You can also type any question about the data.":"",w=[];c&&w.push('"click" or "select"'),d&&w.push('"hover" or "inspect"');let j=w.length?` Interaction: ${w.join(", ")}.`:"";if(!v)y('Not yet in the structure. Type "enter" to begin navigating, or "move to <search>" to jump to a node.'+j+u);else{let me=e.nodes[v],he=Ne(v,me,e).map(ge=>Z(ge,n));y(`Available: ${he.join(", ")}, move to <search>.`+j+u)}return}if(m==="click"||m==="select"){if(!v){y('Not in the structure. Type "enter" to begin.');return}let u=e.nodes[v];c&&u?(c(u),y(`Clicked: ${r(u)}`)):y(c?"Nothing to click here.":"Click interaction is not enabled for this chart.");return}if(m==="hover"||m==="inspect"){if(!v){y('Not in the structure. Type "enter" to begin.');return}let u=e.nodes[v];d&&u?(d(u),y(`Hovering over: ${r(u)}`)):y(d?"Nothing to hover over here.":"Hover interaction is not enabled for this chart.");return}if(m.startsWith("move to ")){let u=h.slice(8).trim();if(!u){y("Usage: move to <search term>");return}let w=Ae(u,e,r);w.length===0?y(`No nodes found matching "${u}".`):w.length===1?ne(w[0].nodeId):(R=w,ue(`Found ${w.length} matches. Type a number to move there:`,w.map(j=>j.description)));return}if(m==="more"||m==="more help"){let w=le(e).map(j=>Z(j,n));y(`All navigation rules: ${w.join(", ")}.`);return}if(!v){if(f&&(yield ee(h))!==null)return;y('Type "enter" to begin navigating the structure, or "move to <search>" to jump to a node.'+(f?" Enter an API key above to ask questions about the data.":""));return}let N=le(e),{match:E,ambiguous:K}=Ee(m,[...N,...te],n);if(E&&te.includes(E)){yield G(E);return}if(!E&&K.length>0){let u=K.map(w=>Z(w,n));y(`Did you mean: ${u.join(", ")}?`);return}if(!E){if(f&&(yield ee(h))!==null)return;let u=f?" Enter an API key above to ask questions about the data.":"";y(`Unknown command "${h}". Type "help" for available commands.`+u);return}let T=E,pe=n[T]||T;if(T==="exit"){v=null,p&&p(),y('Exited the structure. Type "enter" to re-enter.');return}let H=A.move(v,T);H?(v=H.id,o&&o(H),y(`${pe}: ${r(H)}`)):y(`Cannot move "${T}" from here.`)});return $.addEventListener("submit",a=>U(void 0,null,function*(){a.preventDefault();let h=x.value.trim();h&&(O.push(h),C=-1),yield G(x.value),x.value="",x.focus()})),{destroy(){s.removeChild(I)},getCurrentNode(){return v&&e.nodes[v]||null},submit(a){return G(a)},setCurrentNode(a){v=a&&e.nodes[a]?a:null,R=null}}};
|
package/dist/text-chat.js
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import{a as st}from"./chunk-QT52GVQM.js";import{g as F}from"./chunk-B5HGEXMZ.js";var mt=e=>{var d,u,
|
|
1
|
+
import{a as st}from"./chunk-QT52GVQM.js";import{g as F}from"./chunk-B5HGEXMZ.js";var mt=e=>{var d,u,r,o;let t=typeof e.semantics=="function"?e.semantics(e,e.data):e.semantics;if(t!=null&&t.label){let n=typeof t.label=="function"?t.label(e,e.data):t.label;if(n)return n}if(!e.derivedNode)return e.data?Object.keys(e.data).map(n=>`${n}: ${e.data[n]}`).join(". ")+". Data point.":e.id;if((d=e.data)!=null&&d.dimensionKey){let n=0,v=Object.keys(e.data.divisions||{});v.forEach(m=>{n+=Object.keys(e.data.divisions[m].values||{}).length});let b=`${e.derivedNode}.`;return b+=v.length&&n?` ${v.length} division${v.length>1?"s":""}, ${n} datapoint${n>1?"s":""}.`:" No child data points.",b+=` ${e.data.type} dimension.`,b}return`${e.derivedNode}: ${(u=e.data)==null?void 0:u[e.derivedNode]}. ${Object.keys(((r=e.data)==null?void 0:r.values)||{}).length} child data point${Object.keys(((o=e.data)==null?void 0:o.values)||{}).length>1?"s":""}. Division.`},pt=(e,t,d)=>{let u=new Set,r=d.navigationRules||{};return t.edges&&t.edges.forEach(o=>{let n=d.edges[o];n&&n.navigationRules.forEach(v=>{let b=r[v];if(!b)return;let m=b.direction==="target"?n.target:n.source,p=typeof m=="function"?m(t,e):m;p&&p!==e&&u.add(v)})}),Array.from(u)},rt=e=>e.navigationRules?Object.keys(e.navigationRules):[],B=(e,t)=>{let d=e.length,u=t.length,r=Array.from({length:d+1},()=>Array(u+1).fill(0));for(let o=0;o<=d;o++)r[o][0]=o;for(let o=0;o<=u;o++)r[0][o]=o;for(let o=1;o<=d;o++)for(let n=1;n<=u;n++){let v=e[o-1]===t[n-1]?0:1;r[o][n]=Math.min(r[o-1][n]+1,r[o][n-1]+1,r[o-1][n-1]+v),o>1&&n>1&&e[o-1]===t[n-2]&&e[o-2]===t[n-1]&&(r[o][n]=Math.min(r[o][n],r[o-2][n-2]+v))}return r[d][u]},gt=e=>e<=4?1:2,ft=(e,t,d={})=>{let u=e.toLowerCase().trim(),r=t.find(l=>l.toLowerCase()===u);if(r)return{match:r,ambiguous:[]};let o=t.find(l=>d[l]&&d[l].toLowerCase()===u);if(o)return{match:o,ambiguous:[]};let n=t.filter(l=>l.toLowerCase().startsWith(u));if(n.length===1)return{match:n[0],ambiguous:[]};let v=t.filter(l=>{if(!d[l])return!1;let x=d[l].toLowerCase();return x.startsWith(u)?!0:x.split(/\s+/).some(A=>A.startsWith(u))}),b=new Set([...n,...v]),m=Array.from(b);if(m.length===1)return{match:m[0],ambiguous:[]};if(m.length>1)return{match:null,ambiguous:m};let p=gt(u.length),g=[];for(let l=0;l<t.length;l++){let x=t[l],A=B(u,x.toLowerCase());if(A<=p){g.push({candidate:x,dist:A});continue}if(d[x]){let M=d[x].toLowerCase().split(/\s+/);for(let T=0;T<M.length;T++)if(B(u,M[T])<=p){g.push({candidate:x,dist:B(u,M[T])});break}}}return g.length===1?{match:g[0].candidate,ambiguous:[]}:g.length>1?(g.sort((l,x)=>l.dist-x.dist),g[0].dist<g[1].dist?{match:g[0].candidate,ambiguous:[]}:{match:null,ambiguous:g.map(l=>l.candidate)}):{match:null,ambiguous:[]}},G=(e,t)=>t[e]?`${t[e]} (${e})`:e,vt=(e,t,d,u=10)=>{let r=e.toLowerCase(),o=[],n=Object.keys(t.nodes);for(let v=0;v<n.length&&o.length<u;v++){let b=n[v],m=t.nodes[b],p=!1;if(m.data&&!p){let g=Object.keys(m.data);for(let l=0;l<g.length&&!p;l++){let x=m.data[g[l]];x!=null&&typeof x!="object"&&String(x).toLowerCase().includes(r)&&(p=!0)}}!p&&m.derivedNode&&m.derivedNode.toLowerCase().includes(r)&&(p=!0),!p&&b.toLowerCase().includes(r)&&(p=!0),p&&o.push({nodeId:b,description:d(m)})}return o},Ct=e=>{var tt,et,nt,ot;let{structure:t,container:d,entryPoint:u,describeNode:r=mt,commandLabels:o={},onNavigate:n,onExit:v,onClick:b,onHover:m,llm:p,data:g}=e,l=typeof d=="string"?document.getElementById(d):d;if(!l)throw new Error(`textChat: container "${d}" not found`);let x=Object.keys(t.nodes).find(s=>t.nodes[s].dimensionLevel===0),A=t.dimensions?(tt=t.dimensions[Object.keys(t.dimensions)[0]])==null?void 0:tt.nodeId:void 0,M=u||((et=t.frame)==null?void 0:et.rootId)||x||((nt=t.spatialGrid)==null?void 0:nt.rootId)||((ot=t.hierarchy)==null?void 0:ot.rootId)||A||Object.keys(t.nodes)[0],T=st({structure:t,navigationRules:t.navigationRules||{},entryPoint:M}),f=null,V=Math.random().toString(36).slice(2,8),I=[],E=-1,L=null,S=[],at=()=>{let s=`You are a data assistant helping a user explore a dataset through a text-based navigation interface.
|
|
2
2
|
|
|
3
3
|
`;if(g&&g.length>0){let c=Object.keys(g[0]),i=g.slice(0,3).map(w=>JSON.stringify(w)).join(`
|
|
4
4
|
`);s+=`DATASET SUMMARY:
|
|
@@ -10,7 +10,7 @@ import{a as st}from"./chunk-QT52GVQM.js";import{g as F}from"./chunk-B5HGEXMZ.js"
|
|
|
10
10
|
`,s+=`FULL DATASET (JSON):
|
|
11
11
|
`+JSON.stringify(g)+`
|
|
12
12
|
|
|
13
|
-
`}if(
|
|
13
|
+
`}if(f){let c=t.nodes[f];s+=`CURRENT POSITION: ${c?r(c):f}
|
|
14
14
|
|
|
15
15
|
`}else s+=`CURRENT POSITION: Not yet navigated into the structure.
|
|
16
16
|
|
|
@@ -18,4 +18,4 @@ import{a as st}from"./chunk-QT52GVQM.js";import{g as F}from"./chunk-B5HGEXMZ.js"
|
|
|
18
18
|
|
|
19
19
|
`,s+=`VERIFICATION: When the user asks you to verify a claim, write a short Python script (using the dataset as a JSON array) that computes the answer, and show the expected output. If the claim is too open-ended to verify with code, explain why and recommend external verification.
|
|
20
20
|
|
|
21
|
-
`,s+='IMPORTANT: Your responses may contain errors. The user has been told they can ask you to "verify" any answer, and you will attempt to provide a Python script to check it.',s},j=document.createElement("div");j.className="dn-text-chat";let C=document.createElement("div");C.className="dn-text-chat-log",C.setAttribute("role","log"),C.setAttribute("aria-live","polite"),j.appendChild(C);let W=document.createElement("div");W.className="dn-text-chat-controls";let Y=document.createElement("label"),P=document.createElement("input");P.type="checkbox",P.checked=!0,P.addEventListener("change",()=>{C.setAttribute("aria-live",P.checked?"polite":"off")}),Y.appendChild(P),Y.appendChild(document.createTextNode(" Automatically announce to screen readers")),W.appendChild(Y),j.appendChild(W);let O=document.createElement("form");O.className="dn-text-chat-form";let H=document.createElement("label");H.setAttribute("for",`dn-text-chat-input-${
|
|
21
|
+
`,s+='IMPORTANT: Your responses may contain errors. The user has been told they can ask you to "verify" any answer, and you will attempt to provide a Python script to check it.',s},j=document.createElement("div");j.className="dn-text-chat";let C=document.createElement("div");C.className="dn-text-chat-log",C.setAttribute("role","log"),C.setAttribute("aria-live","polite"),j.appendChild(C);let W=document.createElement("div");W.className="dn-text-chat-controls";let Y=document.createElement("label"),P=document.createElement("input");P.type="checkbox",P.checked=!0,P.addEventListener("change",()=>{C.setAttribute("aria-live",P.checked?"polite":"off")}),Y.appendChild(P),Y.appendChild(document.createTextNode(" Automatically announce to screen readers")),W.appendChild(Y),j.appendChild(W);let O=document.createElement("form");O.className="dn-text-chat-form";let H=document.createElement("label");H.setAttribute("for",`dn-text-chat-input-${V}`),H.className="dn-text-chat-sr-only",H.textContent="Navigation command";let N=document.createElement("input");N.type="text",N.id=`dn-text-chat-input-${V}`,N.autocomplete="off",N.setAttribute("placeholder","Type a command...");let J=document.createElement("button");J.type="submit",J.textContent="Send",O.appendChild(H),O.appendChild(N),O.appendChild(J),j.appendChild(O),l.appendChild(j);let Q="";N.addEventListener("keydown",s=>{if(s.key==="ArrowUp"){if(s.preventDefault(),I.length===0)return;E===-1?(Q=N.value,E=I.length-1):E>0&&E--,N.value=I[E]}else if(s.key==="ArrowDown"){if(s.preventDefault(),E===-1)return;E<I.length-1?(E++,N.value=I[E]):(E=-1,N.value=Q)}});let K=(s,c)=>{let i=document.createElement("div");i.className=`dn-text-chat-message ${c}`,i.textContent=s,C.appendChild(i),C.scrollTop=C.scrollHeight},D=s=>K(s,"dn-text-chat-system"),it=s=>K(`> ${s}`,"dn-text-chat-input-echo"),h=s=>K(s,"dn-text-chat-response"),ct=(s,c)=>{let i=document.createElement("div");i.className="dn-text-chat-message dn-text-chat-response";let w=document.createElement("span");w.textContent=s,i.appendChild(w);let k=document.createElement("ol");k.className="dn-text-chat-choices",c.forEach(U=>{let $=document.createElement("li");$.textContent=U,k.appendChild($)}),i.appendChild(k),C.appendChild(i),C.scrollTop=C.scrollHeight},X=s=>F(void 0,null,function*(){let c={role:"system",content:at()};S.push({role:"user",content:s});let i=document.createElement("div");i.className="dn-text-chat-message dn-text-chat-llm-thinking",i.textContent="Thinking...",C.appendChild(i),C.scrollTop=C.scrollHeight;try{let w=yield p([c,...S]);return C.removeChild(i),w===null?(S.pop(),null):(S.push({role:"assistant",content:w}),h(w),w)}catch(w){return C.removeChild(i),S.pop(),h(`Error: ${w.message||"Could not get a response."}`),""}});p?(D('Text navigation ready. Type "enter" to begin navigating, "help" for commands, or ask a question about the data.'),D('Note: AI-generated answers may be inaccurate. You can ask the model to "verify" any answer \u2014 it will attempt to provide a Python script that checks the claim against the dataset. If a claim cannot be verified with code, it should be verified externally.')):D('Text navigation ready. Type "enter" to begin or "help" for available commands.');let Z=["enter","help","more","more help","clear","click","select","hover","inspect"],_=s=>{let c=T.moveTo(s);c?(f=c.id,n&&n(c),h(`Moved to: ${r(c)}`)):h("Could not move to that node.")},z=s=>F(void 0,null,function*(){let c=s.trim();if(!c)return;it(c);let i=c.toLowerCase();if(L){let a=parseInt(c,10);if(!isNaN(a)&&a>=1&&a<=L.length){let y=L[a-1];L=null,_(y.nodeId);return}L=null}if(i==="clear"){C.innerHTML="",D('Chat cleared. Type "help" for available commands.');return}if(i==="enter"){if(f){h('Already in the structure. Type "help" to see available commands.');return}let a=T.enter();if(!a){h("Could not enter the structure. No entry point found.");return}f=a.id,n&&n(a),h(`Entered: ${r(a)}`);return}if(i==="help"){let a=p?" You can also type any question about the data.":"",y=[];b&&y.push('"click" or "select"'),m&&y.push('"hover" or "inspect"');let R=y.length?` Interaction: ${y.join(", ")}.`:"";if(!f)h('Not yet in the structure. Type "enter" to begin navigating, or "move to <search>" to jump to a node.'+R+a);else{let dt=t.nodes[f],ut=pt(f,dt,t).map(ht=>G(ht,o));h(`Available: ${ut.join(", ")}, move to <search>.`+R+a)}return}if(i==="click"||i==="select"){if(!f){h('Not in the structure. Type "enter" to begin.');return}let a=t.nodes[f];b&&a?(b(a),h(`Clicked: ${r(a)}`)):h(b?"Nothing to click here.":"Click interaction is not enabled for this chart.");return}if(i==="hover"||i==="inspect"){if(!f){h('Not in the structure. Type "enter" to begin.');return}let a=t.nodes[f];m&&a?(m(a),h(`Hovering over: ${r(a)}`)):h(m?"Nothing to hover over here.":"Hover interaction is not enabled for this chart.");return}if(i.startsWith("move to ")){let a=c.slice(8).trim();if(!a){h("Usage: move to <search term>");return}let y=vt(a,t,r);y.length===0?h(`No nodes found matching "${a}".`):y.length===1?_(y[0].nodeId):(L=y,ct(`Found ${y.length} matches. Type a number to move there:`,y.map(R=>R.description)));return}if(i==="more"||i==="more help"){let y=rt(t).map(R=>G(R,o));h(`All navigation rules: ${y.join(", ")}.`);return}if(!f){if(p&&(yield X(c))!==null)return;h('Type "enter" to begin navigating the structure, or "move to <search>" to jump to a node.'+(p?" Enter an API key above to ask questions about the data.":""));return}let w=rt(t),{match:k,ambiguous:U}=ft(i,[...w,...Z],o);if(k&&Z.includes(k)){yield z(k);return}if(!k&&U.length>0){let a=U.map(y=>G(y,o));h(`Did you mean: ${a.join(", ")}?`);return}if(!k){if(p&&(yield X(c))!==null)return;let a=p?" Enter an API key above to ask questions about the data.":"";h(`Unknown command "${c}". Type "help" for available commands.`+a);return}let $=k,lt=o[$]||$;if($==="exit"){f=null,v&&v(),h('Exited the structure. Type "enter" to re-enter.');return}let q=T.move(f,$);q?(f=q.id,n&&n(q),h(`${lt}: ${r(q)}`)):h(`Cannot move "${$}" from here.`)});return O.addEventListener("submit",s=>F(void 0,null,function*(){s.preventDefault();let c=N.value.trim();c&&(I.push(c),E=-1),yield z(N.value),N.value="",N.focus()})),{destroy(){l.removeChild(j)},getCurrentNode(){return f&&t.nodes[f]||null},submit(s){return z(s)},setCurrentNode(s){f=s&&t.nodes[s]?s:null,L=null}}};export{Ct as default};
|