AI sections fall back to fetch with no Qt bridge, for non-React web frontends
ai_sections.html fetches {API_BASE}+path when window.qt is absent; a page-check case routes those requests to server_stub.dispatch(). AI SKILL.md step 6 and frontend.md send plain-HTML/Vue/Angular/Svelte projects to it.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
1 parent
344718007e
commit
461798127a
6 files changed
+100
-13
No files matched your search
@@ -2,9 +2,11 @@
|
||||
Paste this whole block into the no-AI dashboard.html, just before </body>. It adds a Review
|
||||
tab: band legend, band filters, the source document beside its extracted fields, drafts,
|
||||
Verify, and Approve. Plain HTML, the page's own theme tokens, no build step.
|
||||
Every request goes over the Qt bridge as one slot call, ai_request(id, method, path, body),
|
||||
and comes back as an `ai_response` envelope (see ../contract.md, "Desktop"). The approve
|
||||
gate is the Python backend's: this page only asks, and shows the refusal.
|
||||
In PyQt, every request goes over the Qt bridge as one slot call, ai_request(id, method, path,
|
||||
body), and comes back as an `ai_response` envelope (see ../contract.md, "Desktop"). With no
|
||||
Qt (a plain-HTML web project), it fetches {API_BASE}{path} from the backend instead, the
|
||||
web endpoints in ../contract.md. The approve gate is the backend's: this page only asks,
|
||||
and shows the refusal.
|
||||
-->
|
||||
<style>
|
||||
/* BAND COLOURS: semantic only (swatches, the rule down a field). The same in every preset and both modes. */
|
||||
@@ -117,10 +119,19 @@ showTab=t=>{
|
||||
};
|
||||
window.addEventListener('beforeunload',e=>{ if(dirty().length) e.preventDefault(); });
|
||||
|
||||
// ----- transport: one bridge slot out, one `ai_response` envelope back -----
|
||||
// ----- transport: in PyQt, one bridge slot out, one `ai_response` envelope back;
|
||||
// with no Qt (a plain web page), fetch {API_BASE}{path} from the backend -----
|
||||
const pending={}; let seq=0;
|
||||
async function aiFetch(method,path,body){
|
||||
const r=await fetch(API_BASE+path,{method,headers:{'Content-Type':'application/json'},
|
||||
body:method==='GET'?undefined:JSON.stringify(body||{})});
|
||||
const b=await r.json().catch(()=>({}));
|
||||
if(!r.ok) throw new Error(b.detail||`Error ${r.status}`);
|
||||
return b;
|
||||
}
|
||||
function ai(method,path,body){
|
||||
if(!bridge) return Promise.reject(new Error('Review needs the desktop app (no Qt bridge here).'));
|
||||
if(!window.qt) return aiFetch(method,path,body);
|
||||
if(!bridge) return Promise.reject(new Error('The Qt bridge is not ready yet. Try again.'));
|
||||
return new Promise((ok,fail)=>{ const id=++seq; pending[id]=[ok,fail];
|
||||
bridge.ai_request(id,method,path,JSON.stringify(body||{})); });
|
||||
}
|
||||
@@ -149,7 +160,8 @@ function openRun(id){
|
||||
clearTimeout(timer);
|
||||
jobId=id; run=null; rows=[]; drafts={}; refusal=null;
|
||||
$('rv-doc-pick').value=id;
|
||||
ai('GET',`/runs/${id}/document`).then(doc=>{ if(id===jobId) $('rv-doc').src=
|
||||
if(!window.qt) $('rv-doc').src=`${API_BASE}/runs/${encodeURIComponent(id)}/document`; // web: the URL itself
|
||||
else ai('GET',`/runs/${id}/document`).then(doc=>{ if(id===jobId) $('rv-doc').src=
|
||||
String(doc).startsWith('<') ? 'data:image/svg+xml;charset=utf-8,'+encodeURIComponent(doc) : doc; }).catch(()=>{});
|
||||
render(); tick(id);
|
||||
}
|
||||
|
||||
Reference in new issue
Block a user