-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathapp.js
More file actions
33 lines (33 loc) · 22.4 KB
/
Copy pathapp.js
File metadata and controls
33 lines (33 loc) · 22.4 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
let projects=[], providers=[], current=null, uploadedFileIds=[], lastJobId=null, activeDomain='All', lastOutput='', outputMode='markdown';
const $ = id => document.getElementById(id);
const UX_PATTERNS = {"Finance Document Suite": {"name": "Finance Ops Console", "accent": "#67e8f9", "layout": "Document intake → extraction → validation → approval/export", "hero": "Audit-ready finance workflow with line-item review, validation ledger, exception handling, and export controls.", "components": ["Document intake panel", "Extraction table", "Validation ledger", "Approval checklist", "Export connector cards"], "metrics": ["Extraction confidence", "Validation issues", "Approval readiness", "Export completeness"], "quick_actions": ["Validate totals", "Check duplicates", "Prepare accounting export", "Flag human review"], "review_lanes": ["Capture", "Normalize", "Validate", "Approve", "Export"], "empty_state": "Upload a finance document or paste source text. The UI will keep live-data sections empty until real files/connectors are provided.", "icon": "💳"}, "E-commerce Growth Suite": {"name": "Growth Command Center", "accent": "#a3e635", "layout": "Research → positioning → content/ads → launch queue → measurement", "hero": "Commerce-first workspace for products, offers, creative angles, listings, Shopify actions, and launch assets.", "components": ["Product/offer canvas", "Margin and pricing cards", "Platform preview board", "Creative variant matrix", "Launch checklist"], "metrics": ["Offer strength", "Margin readiness", "Channel fit", "Launch completeness"], "quick_actions": ["Build offer matrix", "Generate channel previews", "Check claims/compliance", "Create launch queue"], "review_lanes": ["Research", "Position", "Create", "Approve", "Launch"], "empty_state": "Enter a product, offer, audience, or store task. External Shopify/marketplace actions require real credentials.", "icon": "🛒"}, "Legal & Compliance Suite": {"name": "Legal Review Desk", "accent": "#c084fc", "layout": "Document intake → clause map → risk heatmap → negotiation/actions", "hero": "Contract and compliance review UX with clause grids, obligation tracking, redline planning, and risk controls.", "components": ["Clause extraction grid", "Risk heatmap", "Obligation timeline", "Redline/position panel", "Negotiation checklist"], "metrics": ["Risk exposure", "Missing clauses", "Obligations found", "Review readiness"], "quick_actions": ["Extract clauses", "Build risk matrix", "Create negotiation points", "Prepare redline checklist"], "review_lanes": ["Read", "Classify", "Risk-rate", "Negotiate", "Finalize"], "empty_state": "Paste legal text or upload a document. This is decision support, not legal advice.", "icon": "⚖️"}, "HR & Recruiting Suite": {"name": "Talent Ops Workspace", "accent": "#fbbf24", "layout": "Role/person intake → scoring → workflow stage → document/interview package", "hero": "Hiring and people-ops interface with structured scorecards, candidate/job fit, documents, and review gates.", "components": ["Candidate/role profile", "Scorecard grid", "Pipeline stage board", "Interview kit", "Compliance and tone panel"], "metrics": ["Role fit", "Skills coverage", "Risk flags", "Next-step clarity"], "quick_actions": ["Build scorecard", "Generate interview kit", "Review compensation/doc terms", "Create follow-up actions"], "review_lanes": ["Intake", "Assess", "Interview", "Decide", "Send"], "empty_state": "Paste a CV, job description, review notes, or offer inputs. ATS sync needs real connector setup.", "icon": "🧑💼"}, "Media Creator Suite": {"name": "Creator Production Studio", "accent": "#fb7185", "layout": "Brief → script/asset plan → timeline → publishing package", "hero": "Creator-oriented UX for briefs, thumbnails, transcripts, captions, storyboards, and publishing workflows.", "components": ["Creative brief canvas", "Storyboard/timeline", "Transcript or caption editor", "Platform publish checklist", "Asset quality scorecards"], "metrics": ["Hook strength", "Retention risk", "Production readiness", "Publishing completeness"], "quick_actions": ["Build storyboard", "Create caption package", "Check hook/thumbnail", "Prepare publishing checklist"], "review_lanes": ["Brief", "Script", "Produce", "Package", "Publish"], "empty_state": "Add brief, media file, transcript, or thumbnail notes. Vision/audio work needs supported provider or local model.", "icon": "🎬"}, "Medical & Research Suite": {"name": "Evidence & Safety Workbench", "accent": "#5eead4", "layout": "Source intake → evidence extraction → safety review → study/learning output", "hero": "Medical/research-safe workspace with citations, evidence grids, warning panels, and human-review gates.", "components": ["Evidence extraction table", "Citation manager", "Clinical safety warnings", "Study/learning map", "Human review checklist"], "metrics": ["Evidence completeness", "Citation coverage", "Safety flags", "Review readiness"], "quick_actions": ["Extract evidence", "Build citation list", "Check safety warnings", "Create study outputs"], "review_lanes": ["Collect", "Extract", "Verify", "Review", "Export"], "empty_state": "Paste paper text, notes, or upload source files. Clinical/medical decisions require expert verification.", "icon": "🩺"}, "Developer Productivity Suite": {"name": "Developer Workbench", "accent": "#60a5fa", "layout": "Code/schema/log intake → analysis → diff/tests/docs → implementation checklist", "hero": "Engineering-grade UX with code-aware intake, API/schema panels, test results, diffs, and implementation outputs.", "components": ["Code/source panel", "File tree summary", "Diff and patch viewer", "Test/result board", "API/schema preview"], "metrics": ["Coverage readiness", "Risk/bug count", "Implementation clarity", "Docs completeness"], "quick_actions": ["Analyze source", "Generate patch/checklist", "Create tests", "Build docs/schema output"], "review_lanes": ["Inspect", "Analyze", "Patch", "Test", "Ship"], "empty_state": "Paste code, schema, logs, or upload source files. Real repository actions require Git/CI connectors.", "icon": "</>"}, "AI Platform Core": {"name": "AI Platform Control Plane", "accent": "#818cf8", "layout": "Provider/tool intake → routing/security → execution → audit/export", "hero": "Infrastructure UX for provider routing, tools, cost, billing, artifacts, and platform-level operations.", "components": ["Provider routing matrix", "Tool registry", "Cost/billing controls", "Security settings", "Audit trail"], "metrics": ["Provider readiness", "Cost control", "Security posture", "Execution reliability"], "quick_actions": ["Configure providers", "Review routing rules", "Check security controls", "Export audit package"], "review_lanes": ["Configure", "Route", "Execute", "Audit", "Optimize"], "empty_state": "Configure local/cloud providers or paste a platform workflow. No provider keys are required for Rule Engine mode.", "icon": "🧠"}, "Security Suite": {"name": "Security Response Console", "accent": "#f87171", "layout": "Signal intake → severity/risk → evidence → remediation → report", "hero": "Security-focused UX for alerts, logs, vulnerabilities, phishing, secrets, remediation, and reports.", "components": ["Severity matrix", "Evidence/IOC panel", "Remediation checklist", "Timeline builder", "Policy/report export"], "metrics": ["Severity", "Exploitability", "Remediation priority", "Evidence quality"], "quick_actions": ["Triage severity", "Extract indicators", "Build remediation plan", "Prepare incident report"], "review_lanes": ["Detect", "Triage", "Contain", "Fix", "Report"], "empty_state": "Paste logs, URLs, CVEs, incident notes, or code. Threat intel enrichment needs real feeds/connectors.", "icon": "🛡️"}, "Supply Chain Suite": {"name": "Supply Chain Operations Desk", "accent": "#fdba74", "layout": "Document/email intake → matching → discrepancy/risk → action/export", "hero": "Operations UX for purchase, supplier, warehouse, customs, and document reconciliation workflows.", "components": ["Document matching board", "Shipment/procurement checklist", "Discrepancy table", "Supplier action panel", "Export package"], "metrics": ["Match confidence", "Discrepancies", "Compliance risk", "Action readiness"], "quick_actions": ["Match documents", "Find discrepancies", "Prepare supplier email", "Build export package"], "review_lanes": ["Receive", "Match", "Validate", "Resolve", "Export"], "empty_state": "Upload supply-chain documents or paste supplier emails. Customs/live carrier data requires real connectors.", "icon": "🚚"}, "General Automation Suite": {"name": "Automation Command Center", "accent": "#93c5fd", "layout": "Brief/data intake → structured analysis → action plan → export", "hero": "General-purpose but domain-aware automation UI with scorecards, workflow lanes, and action-oriented reports.", "components": ["Brief analyzer", "KPI cards", "Workflow board", "Decision checklist", "Report builder"], "metrics": ["Completeness", "Risk flags", "Action clarity", "Export readiness"], "quick_actions": ["Structure input", "Generate action plan", "Build scorecard", "Prepare final report"], "review_lanes": ["Intake", "Analyze", "Plan", "Review", "Export"], "empty_state": "Paste source material or upload files. Live data sections remain empty until real connectors are configured.", "icon": "⚙️"}};
function api(path, opts={}){ return fetch(path, opts).then(async r=>{ if(!r.ok) throw new Error(await r.text()); return r.json(); }); }
function node(tag, attrs={}, children=[]){ const n=document.createElement(tag); Object.entries(attrs).forEach(([k,v])=>{ if(k==='class')n.className=v; else if(k==='style')n.setAttribute('style',v); else n.setAttribute(k,v); }); (Array.isArray(children)?children:[children]).filter(v=>v!==null&&v!==undefined).forEach(c=>n.append(typeof c==='string'?document.createTextNode(c):c)); return n; }
function chip(text, cls='chip'){ return node('span',{class:cls}, String(text)); }
function safe(s){ return String(s||'').replace(/[&<>]/g,m=>({'&':'&','<':'<','>':'>'}[m])); }
function uxFor(p){ return p.ux_profile || UX_PATTERNS[p.suite] || UX_PATTERNS['General Automation Suite']; }
function setAccent(color){ document.documentElement.style.setProperty('--accent', color || '#8bd3ff'); }
function renderDomainFilter(){ const domains=['All',...new Set(projects.map(p=>p.suite||p.domain||'General'))]; const box=$('domainFilter'); box.innerHTML=''; domains.forEach(d=>{ const c=node('button',{class:'filterChip'+(activeDomain===d?' active':'')},d.replace(' Suite','')); c.onclick=()=>{activeDomain=d; renderDomainFilter(); renderProjects();}; box.appendChild(c); }); }
function renderProjects(){ const q=($('search').value||'').toLowerCase(); const list=$('projectList'); list.innerHTML=''; projects.filter(p=>activeDomain==='All'||(p.suite||p.domain)===activeDomain).filter(p=>[p.name,p.slug,p.domain,p.core_job,p.suite].join(' ').toLowerCase().includes(q)).forEach(p=>{ const ux=uxFor(p); const item=node('div',{class:'projectItem'+(current&¤t.slug===p.slug?' active':'')},[node('b',{},`${ux.icon||'AI'} ${p.name}`),node('span',{},p.domain),node('span',{},p.core_job)]); item.onclick=()=>selectProject(p.slug); list.appendChild(item); }); }
function renderField(f, form){ const wrap=node('div',{class:'field '+((f.type==='textarea'||f.type==='json'||(String(f.label||'').length>24))?'full':'')}); wrap.appendChild(node('label',{},[document.createTextNode(f.label||f.key), f.required?node('span',{class:'warnText'},'required'):null])); let input; const common={name:f.key}; if(f.type==='textarea'||f.type==='json'){ input=node('textarea',common); input.value=f.default||''; } else if(f.type==='select'||f.type==='multi_select'){ input=node('select',common); if(f.type==='multi_select') input.multiple=true; (f.options&&f.options.length?f.options:['']).forEach(o=>{ const opt=node('option',{value:o},o); if((f.default||'')===o)opt.selected=true; input.appendChild(opt); }); } else if(f.type==='slider'){ input=node('input',{...common,type:'range',min:f.min??0,max:f.max??100,value:f.default??50}); const out=node('small',{},`Value: ${input.value}`); input.oninput=()=>out.textContent=`Value: ${input.value}`; wrap.append(input,out); if(f.help)wrap.appendChild(node('small',{},f.help)); form.appendChild(wrap); return; } else { input=node('input',{...common,type:f.type==='number'?'number':'text',value:f.default||''}); }
wrap.appendChild(input); if(f.help)wrap.appendChild(node('small',{},f.help)); form.appendChild(wrap); }
function renderMetrics(p){ const ux=uxFor(p); const box=$('metricGrid'); box.innerHTML=''; const scores=[p.deep_features?.length||0, p.analysis_modules?.length||0, p.field_validations?.length||0, p.output_sections?.length||0]; (ux.metrics||[]).slice(0,4).forEach((m,i)=>{ const val=Math.min(100, Math.max(15, scores[i]*14 || 35)); const card=node('div',{class:'metricCard'},[node('small',{},m),node('b',{},`${val}%`),node('div',{class:'meter'},node('span',{style:`width:${val}%`},''))]); box.appendChild(card); }); }
function renderCockpit(p){ const ux=uxFor(p); $('cockpitTitle').textContent=ux.name || 'Domain Cockpit'; $('cockpitSub').textContent=ux.hero || ''; const grid=$('domainCockpit'); grid.innerHTML=''; (ux.components||[]).forEach((name,i)=>{ const feature=(p.deep_features||[])[i%(p.deep_features||['']).length] || 'Configured project capability'; const card=node('div',{class:'componentCard'},[node('b',{},name),node('p',{},feature),node('div',{class:'miniRows'},[node('div',{class:'miniRow'},node('span',{style:`width:${30+(i*13%55)}%`},'')),node('div',{class:'miniRow'},node('span',{style:`width:${45+(i*11%45)}%`},''))])]); grid.appendChild(card); }); }
function renderQuickActions(p){ const ux=uxFor(p); const box=$('laneRail'); box.innerHTML=''; (ux.review_lanes||[]).forEach(l=>box.appendChild(node('span',{class:'lane'},l))); }
function renderTabSwitching(){ document.querySelectorAll('.tab').forEach(t=>t.onclick=()=>{ document.querySelectorAll('.tab').forEach(x=>x.classList.remove('active')); document.querySelectorAll('.tabPane').forEach(x=>x.classList.remove('active')); t.classList.add('active'); $('tab-'+t.dataset.tab).classList.add('active'); }); document.querySelectorAll('.outputTab').forEach(t=>t.onclick=()=>{ document.querySelectorAll('.outputTab').forEach(x=>x.classList.remove('active')); t.classList.add('active'); outputMode=t.dataset.outputTab; renderOutput(); }); }
async function selectProject(slug){ current=await api('/api/projects/'+slug); const ux=uxFor(current); setAccent(ux.accent); uploadedFileIds=[]; $('uploadedFiles').textContent=''; $('domainIcon').textContent=ux.icon||'AI'; $('brandTitle').textContent=current.name; $('brandSub').textContent=ux.name||current.suite||current.domain; $('projectTitle').textContent=current.name; $('projectMeta').textContent=ux.hero || `${current.slug} • ${current.domain}`; $('projectSuite').textContent=`${current.suite || 'General Automation Suite'} • ${current.implementation_status || 'configured'}`; $('uxName').textContent=ux.name || 'Project Workspace'; $('uxLayout').textContent=ux.layout || current.core_job; renderQuickActions(current); renderMetrics(current); renderCockpit(current);
['featureChips','moduleChips','guardrails','outputSections'].forEach(id=>$(id).innerHTML=''); $('validationRules').innerHTML=''; (current.deep_features||[]).forEach(s=>$('featureChips').appendChild(chip(s))); (current.analysis_modules||[]).forEach(s=>$('moduleChips').appendChild(chip(s,'chip ok'))); (current.guardrails||[]).forEach(s=>$('guardrails').appendChild(chip(s,'chip warn'))); (current.output_sections||[]).forEach(s=>$('outputSections').appendChild(chip(s))); (current.field_validations||[]).forEach(v=>$('validationRules').appendChild(node('div',{class:'rule'},[node('b',{},v.field||'rule'),node('span',{},v.rule||'')])));
$('inputForm').innerHTML=''; (current.input_schema||[]).forEach(f=>renderField(f,$('inputForm'))); $('customForm').innerHTML=''; (current.customization_schema||[]).forEach(f=>renderField(f,$('customForm'))); $('inputCount').textContent=`${(current.input_schema||[]).length} inputs`; $('customCount').textContent=`${(current.customization_schema||[]).length} controls`; lastOutput=''; renderOutput(); $('runStatus').textContent=(ux.empty_state||'Ready.'); renderProjects(); }
function readForm(form){ const data={}; [...form.querySelectorAll('input,textarea,select')].forEach(i=>{ if(i.type==='checkbox') data[i.name]=i.checked; else if(i.multiple) data[i.name]=[...i.selectedOptions].map(o=>o.value); else data[i.name]=i.value; }); return data; }
function input(name,value='',type='text',placeholder=''){ return node('input',{name,value,type,placeholder}); }
function select(name,value,opts){ const s=node('select',{name}); opts.forEach(o=>{ const op=node('option',{value:o},o); if(String(value)===String(o))op.selected=true; s.appendChild(op); }); return s; }
function providerTemplate(p={}){ return node('div',{class:'providerRow'},[input('name',p.name||'Custom Provider'),select('provider_type',p.provider_type||'custom_openai_compatible',['rule_engine','openai','anthropic','gemini','openrouter','mistral','azure_openai','bedrock','ollama','lmstudio','vllm','custom_openai_compatible']),input('model',p.model||'model-name'),input('api_key',p.api_key_masked?'__KEEP__':'','password','API key / __KEEP__'),input('base_url',p.base_url||'','text','Base URL'),input('endpoint',p.endpoint||'','text','Endpoint / AWS region'),input('deployment',p.deployment||'','text','Azure deployment'),input('default_temperature',p.default_temperature??0.2,'number','Temperature'),input('max_tokens',p.max_tokens??4000,'number','Max tokens'),select('enabled',String(Boolean(p.enabled)),['true','false']),select('is_local',String(Boolean(p.is_local)),['true','false'])]); }
async function loadProviders(){ providers=await api('/api/providers'); const sel=$('providerSelect'); sel.innerHTML=''; providers.filter(p=>p.enabled).forEach(p=>sel.appendChild(node('option',{value:p.name},`${p.name} — ${p.model}${p.is_local?' (local)':''}`))); const box=$('providersEditor'); box.innerHTML=''; providers.forEach(p=>box.appendChild(providerTemplate(p))); }
async function saveProviders(){ const rows=[...$('providersEditor').querySelectorAll('.providerRow')].map(row=>{ const o={}; [...row.querySelectorAll('input,select')].forEach(i=>o[i.name]=i.value); o.enabled=o.enabled==='true'; o.is_local=o.is_local==='true'; o.default_temperature=Number(o.default_temperature||0.2); o.max_tokens=Number(o.max_tokens||4000); if(!o.api_key)o.api_key='__KEEP__'; return o; }); for(const r of rows){ await api('/api/providers',{method:'POST',headers:{'Content-Type':'application/json'},body:JSON.stringify(r)}); } await loadProviders(); alert('Providers saved.'); }
async function uploadFiles(files){ for(const file of files){ const fd=new FormData(); fd.append('file',file); const res=await fetch('/api/upload',{method:'POST',body:fd}); if(!res.ok) throw new Error(await res.text()); const data=await res.json(); uploadedFileIds.push(data.id); $('uploadedFiles').innerHTML += `<div class="okText">Uploaded ${safe(data.name)} — id ${data.id}</div>`; } }
async function runWorkflow(){ if(!current)return; const provider=$('providerSelect').value; if(!provider){ alert('Configure at least one provider first.'); return; } $('runStatus').textContent='Running local project engine, then selected provider if applicable...'; lastOutput=''; renderOutput(); try{ const payload={project_slug:current.slug,provider_name:provider,inputs:readForm($('inputForm')),customization:readForm($('customForm')),uploaded_file_ids:uploadedFileIds,output_style:$('outputStyle').value}; const res=await api('/api/run',{method:'POST',headers:{'Content-Type':'application/json'},body:JSON.stringify(payload)}); lastJobId=res.job_id; lastOutput=res.output||''; renderOutput(); $('runStatus').innerHTML='<span class="okText">Completed. Job #'+lastJobId+'</span>'; await loadHistory(); }catch(e){ $('runStatus').innerHTML='<span class="dangerText">Failed: '+safe(e.message)+'</span>'; } }
function renderOutput(){ const out=$('output'); out.className='output'+(outputMode==='structured'?' structured':''); if(!lastOutput){ const ux=current?uxFor(current):UX_PATTERNS['General Automation Suite']; out.innerHTML=`<span class="muted">${safe(ux.empty_state||'Run workflow to see output.')}</span>`; return; } if(outputMode==='markdown'){ out.textContent=lastOutput; return; } const lines=lastOutput.split(/\n+/).filter(Boolean); if(outputMode==='structured'){ const sections=[]; let currentTitle='Summary', body=[]; for(const line of lines){ if(/^#{1,4}\s+/.test(line)){ if(body.length)sections.push([currentTitle,body.join('\n')]); currentTitle=line.replace(/^#+\s+/,''); body=[]; } else body.push(line); } if(body.length)sections.push([currentTitle,body.join('\n')]); out.innerHTML=sections.slice(0,12).map(([h,b])=>`<div class="structuredCard"><h4>${safe(h)}</h4><p>${safe(b).replace(/\n/g,'<br>')}</p></div>`).join(''); return; } const tasks=lines.filter(l=>/^[-*]\s+|^\d+[.)]\s+|action|todo|step|check|review/i.test(l)).slice(0,30); out.innerHTML=(tasks.length?tasks:lines.slice(0,12)).map(t=>`<div class="checkItem"><span class="checkBox"></span><span>${safe(t.replace(/^[-*]\s+/,''))}</span></div>`).join(''); }
async function loadHistory(){ const jobs=await api('/api/jobs?limit=30'); const h=$('history'); h.innerHTML=''; jobs.forEach(j=>{ const d=node('div',{class:'historyItem'},[node('b',{},`#${j.id} ${j.project_slug}`),node('small',{},`${j.status} • ${j.provider_name} • ${j.created_at}`)]); d.onclick=async()=>{ const job=await api('/api/jobs/'+j.id); lastJobId=job.id; lastOutput=job.output||job.error||''; renderOutput(); }; h.appendChild(d); }); }
function exportJob(fmt){ if(!lastJobId){ alert('Run or select a job first.'); return; } window.location=`/api/jobs/${lastJobId}/export/${fmt}`; }
async function init(){ renderTabSwitching(); projects=await api('/api/projects'); projects.forEach(p=>{ if(p.ux_profile) UX_PATTERNS[p.suite]=UX_PATTERNS[p.suite]||p.ux_profile; }); await loadProviders(); renderDomainFilter(); renderProjects(); if(projects[0]) await selectProject(projects[0].slug); await loadHistory(); }
$('search').oninput=renderProjects; $('settingsBtn').onclick=()=>$('settingsModal').classList.add('open'); $('closeSettings').onclick=()=>$('settingsModal').classList.remove('open'); $('addProvider').onclick=()=>$('providersEditor').appendChild(providerTemplate()); $('saveProviders').onclick=saveProviders; $('fileInput').onchange=e=>uploadFiles(e.target.files); $('runBtn').onclick=runWorkflow; $('clearBtn').onclick=()=>{lastOutput='';$('runStatus').textContent='';renderOutput();}; document.querySelectorAll('[data-export]').forEach(b=>b.onclick=()=>exportJob(b.dataset.export)); init().catch(e=>{document.body.innerHTML='<pre>'+safe(e.stack||e.message)+'</pre>';});