← Files RAGOpsARCHIVED FILE
skills/evaluate-ai-release/scripts/vendor/ragops/web/app.js
3 KB · Oct 4, 2026 · 12:29 UTC
const byId=(id)=>document.getElementById(id);
const scenario=byId('scenario'),responses=byId('responses'),apiKey=byId('api-key');
scenario.value='{"schema_version":"0.2","id":"demo","name":"Demo","thresholds":{"citation_coverage":1,"citation_precision":1,"lexical_groundedness":0.5,"max_latency_ms":3000,"max_cost_usd":0.03},"cases":[{"id":"q1","question":"What is the policy?","evidence":["The policy requires human approval."],"required_citation_ids":["policy-1"],"category":"policy","severity":"high","language":"en"}]}';
responses.value='[{"case_id":"q1","answer":"The policy requires human approval.","citation_ids":["policy-1"],"latency_ms":900,"cost_usd":0.01}]';
const authHeaders=()=>apiKey.value?{'x-api-key':apiKey.value}:{};
const clear=(node)=>node.replaceChildren();
const element=(tag,text,className)=>{const node=document.createElement(tag);node.textContent=String(text);if(className)node.className=className;return node};
function renderMetrics(metrics){const container=byId('metrics');clear(container);Object.entries(metrics).forEach(([key,value])=>{const row=element('div','', 'metric');row.append(element('span',key),element('strong',Number(value).toFixed(4)));container.append(row)})}
function renderGates(gates){const container=byId('gates');clear(container);(gates.length?gates:['None']).forEach((gate)=>container.append(element('li',gate)))}
function renderRuns(runs){const container=byId('runs');clear(container);if(!runs.length){container.append(element('p','No runs saved.'));return}runs.forEach((run)=>{const row=element('div','', 'run');row.append(element('b',run.label||run.id.slice(0,8)),element('span',run.scenario_id),element('span',run.review_status,'badge'),element('span',run.passed?'PASS':'FAIL'));container.append(row)})}
byId('run').addEventListener('click',async()=>{const status=byId('status'),errorMessage=byId('evaluation-error');errorMessage.hidden=true;try{const response=await fetch('/v1/evaluate',{method:'POST',headers:{'content-type':'application/json',...authHeaders()},body:JSON.stringify({scenario:JSON.parse(scenario.value),responses:JSON.parse(responses.value)})});const data=await response.json();if(!response.ok)throw Error(data.detail||'Evaluation failed');status.textContent=data.passed?'PASS':'FAIL';status.className='status '+(data.passed?'pass':'fail');renderMetrics(data.metrics);renderGates(data.failed_gates)}catch(error){status.textContent='NOT EVALUATED';status.className='status';errorMessage.textContent=error.message;errorMessage.hidden=false;clear(byId('metrics'));renderGates(['Not evaluated'])}});
byId('load').addEventListener('click',async()=>{const message=byId('history-message'),limit=byId('limit').value;try{const response=await fetch(`/v1/runs?limit=${encodeURIComponent(limit)}`,{headers:authHeaders()});const data=await response.json();if(!response.ok)throw Error(data.detail||'History failed');message.textContent=`${data.length} saved runs`;message.className='lede';renderRuns(data)}catch(error){message.textContent=error.message;message.className='lede error';clear(byId('runs'))}});
SHA-256: 06fe55f31c07d7cc2b20037f62db3a0f14287b7824c024e9f5e5b0511254e73a