123 lines
25 KiB
Plaintext
123 lines
25 KiB
Plaintext
<!DOCTYPE html><html lang="en"><head><meta charset="UTF-8"><meta name="viewport" content="width=device-width,initial-scale=1"><title>Consultancy Framework — Mek-Tech</title><link href="https://fonts.googleapis.com/css2?family=Inter:wght@300;400;500;600;700;800;900&display=swap" rel="stylesheet"><link rel="stylesheet" href="/css/style.css"><link rel="stylesheet" href="/css/dynamic.css"><link rel="icon" href="/img/favicon.svg"><style>
|
||
.consult-page{max-width:860px;margin:0 auto;padding:1.5rem 0 3rem}
|
||
.consult-page h1{font-size:1.5rem;font-weight:800;letter-spacing:-.4px;margin-bottom:4px;background:linear-gradient(135deg,var(--text),var(--accent));-webkit-background-clip:text;-webkit-text-fill-color:transparent;background-clip:text}
|
||
.consult-page .sub{font-size:.75rem;color:var(--text-muted)}
|
||
.cp-bar{display:flex;gap:.5rem;align-items:center;margin:.75rem 0 1rem;padding:.6rem .9rem;background:var(--bg-card);border:1px solid var(--border);border-radius:10px;flex-wrap:wrap}
|
||
.cp-bar select{flex:1;min-width:180px;padding:.4rem .55rem;background:var(--bg);border:1px solid var(--border);border-radius:6px;color:var(--text);font-size:.76rem;font-family:inherit}.cp-bar select:focus{outline:none;border-color:var(--accent)}
|
||
.cp-bar .cp-link{display:inline-flex;align-items:center;gap:.3rem;padding:.3rem .65rem;border-radius:5px;font-size:.66rem;font-weight:600;cursor:pointer;border:1px solid var(--border);background:var(--bg);color:var(--text-muted);text-decoration:none;font-family:inherit}.cp-bar .cp-link:hover{color:var(--text)}
|
||
.cp-bar .cp-on{font-size:.62rem;color:var(--green);display:flex;align-items:center;gap:.25rem}.cp-bar .cp-on::before{content:'';width:6px;height:6px;border-radius:50%;background:var(--green);animation:pulse 2s ease infinite}
|
||
|
||
.alert{background:var(--green-bg);border:1px solid var(--green);color:var(--green);padding:.4rem .7rem;border-radius:6px;font-size:.7rem;margin-bottom:.75rem}
|
||
.prev{background:var(--bg-card);border:1px solid var(--border);border-radius:8px;padding:.6rem .9rem;margin-bottom:.75rem;display:flex;align-items:center;gap:.6rem;flex-wrap:wrap;font-size:.7rem}.prev span{color:var(--text-dim);font-size:.6rem}.prev a{font-size:.62rem;text-decoration:none;padding:.25rem .55rem;border-radius:5px;white-space:nowrap}
|
||
|
||
.steps-row{display:flex;gap:2px;margin-bottom:1rem;background:var(--bg-card);border:1px solid var(--border);border-radius:8px;padding:3px}
|
||
.sb{flex:1;display:flex;align-items:center;gap:.35rem;padding:.42rem .45rem;border:none;background:none;color:var(--text-dim);font-family:inherit;font-size:.63rem;font-weight:600;cursor:pointer;border-radius:6px}.sb:hover{color:var(--text);background:var(--border-light)}.sb.active{color:var(--accent);background:rgba(88,166,255,.06)}.sb.done{color:var(--green)}
|
||
.sb .si{width:20px;height:20px;border-radius:50%;display:flex;align-items:center;justify-content:center;font-size:.56rem;font-weight:800;border:2px solid currentColor;flex-shrink:0}.sb.active .si{background:var(--accent);color:#fff;border-color:var(--accent)}.sb.done .si{background:var(--green);color:#fff;border-color:var(--green)}
|
||
|
||
.qc{background:var(--bg-card);border:1px solid var(--border);border-radius:10px;padding:1.3rem;animation:fadeIn .4s ease}.qc h2{font-size:1rem;font-weight:700;color:var(--text);margin-bottom:2px}.qc .sub{font-size:.68rem;color:var(--text-muted);margin-bottom:1rem}
|
||
.qg{display:grid;grid-template-columns:1fr 1fr;gap:.65rem}@media(max-width:600px){.qg{grid-template-columns:1fr}}
|
||
.qf{display:flex;flex-direction:column;gap:2px}.qf.full{grid-column:1/-1}
|
||
.qf label{font-size:.6rem;font-weight:700;color:var(--text-dim);text-transform:uppercase;letter-spacing:.3px}
|
||
.qf input,.qf select,.qf textarea{padding:.4rem .55rem;background:var(--bg);border:1px solid var(--border);border-radius:5px;color:var(--text);font-size:.73rem;font-family:inherit;width:100%}
|
||
.qf input:focus,.qf select:focus,.qf textarea:focus{outline:none;border-color:var(--accent);box-shadow:0 0 0 2px rgba(88,166,255,.08)}.qf textarea{resize:vertical;min-height:60px}.qf .hint{font-size:.55rem;color:var(--text-dim)}
|
||
.qa{display:flex;justify-content:space-between;align-items:center;margin-top:1.2rem;gap:.4rem}.qa .step-num{font-size:.62rem;color:var(--text-dim)}
|
||
.btn{display:inline-flex;align-items:center;gap:.3rem;padding:.4rem .85rem;border-radius:6px;font-size:.7rem;font-weight:600;cursor:pointer;border:none;font-family:inherit;text-decoration:none;transition:all .12s}
|
||
.btn-o{background:var(--bg);color:var(--text-muted);border:1px solid var(--border)}.btn-o:hover{color:var(--text)}.btn-p{background:var(--accent);color:#fff}.btn-p:hover{background:var(--accent-hover)}.btn-g{background:var(--green);color:#fff}.btn-g:hover{filter:brightness(1.1)}
|
||
.res-h{text-align:center;padding:1.5rem;background:linear-gradient(135deg,var(--bg-card),rgba(88,166,255,.03));border:1px solid var(--border);border-radius:10px;margin-bottom:.75rem}
|
||
.res-h h2{font-size:1.2rem;font-weight:800;color:var(--text);margin-bottom:3px}.res-h .rp{font-size:.68rem;color:var(--text-muted)}.res-h .tier{display:inline-flex;gap:.2rem;margin-top:5px}
|
||
.tb{padding:.12rem .5rem;border-radius:999px;font-size:.62rem;font-weight:700}.tb.a{background:var(--green-bg);color:var(--green)}.tb.b{background:var(--orange-bg);color:var(--orange)}.tb.c{background:var(--red-bg);color:var(--red)}
|
||
.sec{margin-top:1rem}.sec h3{font-size:.78rem;font-weight:700;color:var(--text);margin-bottom:.45rem}
|
||
.tg{display:grid;grid-template-columns:repeat(auto-fill,minmax(140px,1fr));gap:.35rem}
|
||
.ti{background:var(--bg);border:1px solid var(--border-light);border-radius:6px;padding:.5rem .65rem}.ti .tl{font-size:.54rem;color:var(--text-dim);text-transform:uppercase;letter-spacing:.3px;font-weight:700;margin-bottom:2px}.ti .tv{font-size:.7rem;color:var(--text);font-weight:600}
|
||
.ph{background:var(--bg-card);border:1px solid var(--border);border-radius:8px;padding:.8rem 1rem;margin-bottom:.4rem;border-left:3px solid var(--accent)}.ph h4{font-size:.76rem;font-weight:700;color:var(--text);margin-bottom:.25rem}.ph ul{list-style:none}.ph li{padding:.12rem 0;font-size:.68rem;color:var(--text-muted);display:flex;gap:.3rem}.ph li::before{content:'→';color:var(--accent);font-weight:700;flex-shrink:0}.ph.note{border-left-color:var(--orange)}.ph.note.red{border-left-color:var(--red)}
|
||
@keyframes fadeIn{from{opacity:0;transform:translateY(8px)}to{opacity:1;transform:translateY(0)}}
|
||
@keyframes pulse{0%,100%{opacity:1}50%{opacity:.5}}
|
||
|
||
/* Agent */
|
||
.agent-float{position:fixed;bottom:1.2rem;right:1.2rem;width:46px;height:46px;border-radius:50%;background:linear-gradient(135deg,var(--accent),var(--purple));color:#fff;border:none;cursor:pointer;font-size:1.1rem;box-shadow:0 4px 16px rgba(88,166,255,.2);z-index:50;transition:transform .15s}
|
||
.agent-float:hover{transform:scale(1.06)}
|
||
.agent-popup{display:none;position:fixed;bottom:4.5rem;right:1rem;width:350px;max-height:440px;background:var(--bg-card);border:1px solid var(--border);border-radius:10px;z-index:49;flex-direction:column;box-shadow:0 8px 40px rgba(0,0,0,.3)}
|
||
.agent-popup.open{display:flex}.agent-popup .ah{border-bottom:1px solid var(--border);padding:.5rem .7rem;display:flex;align-items:center;gap:.35rem;font-size:.68rem;font-weight:700;color:var(--text)}.agent-popup .ah .dot{width:6px;height:6px;border-radius:50%;background:var(--green);animation:pulse 2s ease infinite}.agent-popup .ah span{flex:1}.agent-popup .ah button{background:none;border:none;color:var(--text-dim);cursor:pointer;font-size:.9rem}
|
||
.agent-popup .ab{flex:1;overflow-y:auto;padding:.5rem;display:flex;flex-direction:column;gap:.4rem;max-height:300px}
|
||
.agent-popup .af{border-top:1px solid var(--border);padding:.45rem;display:flex;gap:.25rem}.agent-popup .af input{flex:1;padding:.3rem .45rem;background:var(--bg);border:1px solid var(--border);border-radius:5px;color:var(--text);font-size:.66rem;font-family:inherit}.agent-popup .af input:focus{outline:none;border-color:var(--accent)}.agent-popup .af button{background:var(--accent);color:#fff;border:none;border-radius:5px;padding:.3rem .55rem;font-size:.63rem;font-weight:600;cursor:pointer}
|
||
.am{padding:.4rem .55rem;border-radius:6px;font-size:.64rem;line-height:1.4;max-width:88%}.am.user{align-self:flex-end;background:var(--accent);color:#fff}.am.agent{align-self:flex-start;background:var(--border-light);color:var(--text)}.am .who{display:block;font-size:.55rem;color:var(--text-dim);margin-bottom:2px;font-weight:600}
|
||
</style></head><body>
|
||
<nav class="navbar"><div class="nav-inner"><a href="/" class="nav-brand"><img src="/img/logo.svg" class="nav-logo" alt="Mek-Tech"></a><div style="display:flex;align-items:center;gap:.4rem"><a href="/" class="nav-icon-btn" title="Dashboard"><i data-lucide="layout-dashboard" style="width:15px;height:15px"></i> Dashboard</a><button class="theme-toggle" id="themeToggle" onclick="toggleTheme()"></button><a href="/auth/logout" class="nav-icon-btn" style="color:var(--red)"><i data-lucide="log-out" style="width:15px;height:15px"></i> Uitloggen</a></div></div></nav>
|
||
|
||
<div class="main-area" style="max-width:960px;margin:0 auto;padding:1.5rem 2rem 3rem">
|
||
<div class="consult-page">
|
||
<a href="javascript:history.back()" class="back-link"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"><polyline points="15 18 9 12 15 6"/></svg> Back</a>
|
||
<h1>Enterprise Solution Architect</h1>
|
||
<p class="sub">Connect a client, complete the 5-step assessment, generate a full architecture roadmap</p>
|
||
|
||
<% if (saved) { %><div class="alert">✓ Assessment saved to <strong><%= client ? client.name : 'client' %></strong></div><% } %>
|
||
|
||
<div class="cp-bar">
|
||
<select id="cs" onchange="selectClient(this.value)"><option value="">— Select a client —</option><% clients.forEach(function(c){ %><option value="<%= c.id %>" <%= String(c.id)===String(clientId)?'selected':'' %>><%= c.name %></option><% }) %></select>
|
||
<% if(clientId){ %><span class="cp-on">Connected</span><a href="/clients/<%= clientId %>" class="cp-link">View Client</a><% } %>
|
||
</div>
|
||
|
||
<% if (prevAssessment && !loadedAnswers) { %>
|
||
<div class="prev"><strong style="color:var(--text)">Previous assessment</strong> <span><%= new Date(prevAssessment.created_at).toLocaleString('en-US') %></span>
|
||
<a href="/consulting/report/<%= prevAssessment.id %>" class="cp-link">View</a>
|
||
<a href="/consulting?client_id=<%= clientId %>" class="cp-link" style="border-color:var(--accent);color:var(--accent)">New</a></div><% } %>
|
||
|
||
<div id="stepsRow" class="steps-row"></div>
|
||
<div id="qArea"></div>
|
||
<div id="results" style="display:none"></div>
|
||
</div></div>
|
||
|
||
<button class="agent-float" onclick="toggleAgent()">🧠</button>
|
||
<div class="agent-popup" id="apop"><div class="ah"><span class="dot"></span><span>AI Consultant</span><button onclick="toggleAgent()">×</button></div><div class="ab" id="amsgs"><div class="am agent"><span class="who">Agent</span>Hello! I analyze your assessment in real-time. Ask about industry benchmarks, data lake sizing, AI platforms, budgets, or roadmaps.</div></div><div class="af"><input id="ainp" placeholder="Ask me anything..." onkeydown="if(event.keyCode===13)send()"><button onclick="send()">Send</button></div></div>
|
||
|
||
<script src="/js/theme.js"></script>
|
||
<script>
|
||
const STEPS=[{title:"Company Profile",sub:"Organization details & context",flds:[{n:'company',l:'Organization Name',t:'text',r:true,h:'Full legal/brand name'},{n:'industry',l:'Industry',t:'sel',o:['Banking & Finance','Insurance','Healthcare','Retail & E-commerce','Manufacturing','Telecom & Media','Energy & Utilities','Government','Education & Research','Technology & SaaS','Other'],r:true},{n:'employees',l:'Workforce Size',t:'sel',o:['1-50','51-200','201-1000','1001-5000','5001-20000','20000+']},{n:'challenge',l:'Primary Challenge',t:'area',r:true,h:'Key business/technical problem to solve'},{n:'tech',l:'Current Tech Stack',t:'area',h:'E.g. Oracle on-prem, Power BI, manual Excel'}]},{title:"Infrastructure",sub:"Current infrastructure landscape",flds:[{n:'infra',l:'Infrastructure Model',t:'sel',o:['Fully on-premise','Hybrid (on-prem+cloud)','Single cloud','Multi-cloud','Fully cloud-native'],r:true},{n:'servers',l:'Server Footprint',t:'sel',o:['< 10','10-50','50-200','200-1000','1000+']},{n:'cloud',l:'Cloud Provider',t:'sel',o:['None','AWS','Azure','GCP','Multi-cloud']},{n:'virt',l:'Virtualization',t:'sel',o:['VMware vSphere','Proxmox','Hyper-V','Docker/K8s','Bare metal']},{n:'net',l:'Network Fabric',t:'sel',o:['1GbE','10GbE','25GbE','40GbE','100GbE+']}]},{title:"Data & Analytics",sub:"Data landscape & tooling",flds:[{n:'dvol',l:'Data Volume',t:'sel',o:['< 100 GB','100 GB - 1 TB','1-10 TB','10-100 TB','100 TB - 1 PB','> 1 PB'],r:true},{n:'dgrowth',l:'Monthly Growth',t:'sel',o:['< 1%','1-5%','5-15%','15-30%','> 30%']},{n:'dtypes',l:'Data Variety',t:'sel',o:['Structured only','Structured + semi-structured','All types (streaming,IoT)']},{n:'bi',l:'BI/Analytics Tools',t:'sel',o:['Excel only','Power BI','Tableau','Looker','SAP Analytics Cloud','Multiple']},{n:'gov',l:'Data Governance',t:'sel',o:['None','Basic access control','GDPR/AVG','GDPR+sector','Full enterprise']}]},{title:"AI & Machine Learning",sub:"AI maturity & goals",flds:[{n:'aimat',l:'AI Maturity',t:'sel',o:['No AI/ML','Basic reporting','PoC ML','Production ML','Advanced AI (LLMs,CV)'],r:true},{n:'aigoal',l:'AI Goal',t:'sel',o:['Predictive analytics','NLP/chatbots/LLMs','Computer vision','Recommendation engines','Generative AI','Process automation','Exploring']},{n:'aiteam',l:'AI Team Size',t:'sel',o:['None','1-3','4-10','10-30','30+']},{n:'aipref',l:'AI Model Preference',t:'sel',o:['Open-source (Llama,DeepSeek)','Cloud AI services','Proprietary (OpenAI,Anthropic)','Hybrid','Undecided']}]},{title:"Requirements",sub:"Performance, security, budget & timeline",flds:[{n:'perf',l:'Performance',t:'sel',o:['Standard','Low latency','Real-time/streaming','Batch']},{n:'avail',l:'Availability SLA',t:'sel',o:['99%','99.5%','99.9%','99.99%','99.999%']},{n:'sec',l:'Security Level',t:'sel',o:['Standard','Enhanced (Zero Trust)','High (HSM,encryption)','Mission critical']},{n:'budget',l:'Annual IT Budget',t:'sel',o:['< €50K','€50K-€250K','€250K-€1M','€1M-€5M','> €5M']},{n:'timeline',l:'Timeline',t:'sel',o:['ASAP (<3 months)','3-6 months','6-12 months','12-24 months','Flexible/phased']}]}];
|
||
let step=0,ans={},cid='<%= clientId||"" %>';
|
||
|
||
<% if(loadedAnswers){ %>ans=<%- JSON.stringify(loadedAnswers) %>;<% } %>
|
||
<% if(loadedReport){ %>
|
||
document.getElementById('stepsRow').style.display='none';
|
||
document.getElementById('results').innerHTML=buildRes(<%- JSON.stringify(loadedReport) %>,ans)+'<div class="qa" style="margin-top:1rem"><a href="/consulting?client_id='+cid+'" class="btn btn-o">New Assessment</a></div>';
|
||
document.getElementById('results').style.display='block';
|
||
<% }else{ %>rStep(0);<% } %>
|
||
|
||
function rStep(i){step=i;const s=STEPS[i];
|
||
let h='';STEPS.forEach((x,j)=>{h+='<button class="sb'+(j===step?' active':j<step?' done':'')+'" onclick="goStep('+j+')"><span class="si">'+(j+1)+'</span>'+(window.innerWidth>600?x.title:'')+'</button>'});
|
||
document.getElementById('stepsRow').innerHTML=h;
|
||
h='<div class="qc"><h2>'+s.title+'</h2><div class="sub">'+s.sub+'</div><div class="qg">';
|
||
s.flds.forEach(f=>{const v=ans[f.n]||'';h+='<div class="qf'+(f.t==='area'?' full':'')+'"><label>'+f.l+'</label>';
|
||
if(f.t==='sel'){h+='<select name="'+f.n+'" onchange="sv()"><option value="">— Select —</option>';f.o.forEach(o=>h+='<option value="'+o+'"'+(v===o?' selected':'')+'>'+o+'</option>');h+='</select>'}
|
||
else if(f.t==='area')h+='<textarea name="'+f.n+'" onchange="sv()" rows="2">'+v+'</textarea>';
|
||
else h+='<input type="text" name="'+f.n+'" onchange="sv()" value="'+v+'">';
|
||
if(f.h)h+='<span class="hint">'+f.h+'</span>';h+='</div>'});
|
||
h+='</div><div class="qa"><span class="step-num">Step '+(i+1)+' of '+STEPS.length+'</span><div style="display:flex;gap:.4rem">';
|
||
if(i>0)h+='<button class="btn btn-o" onclick="prev()">Back</button>';
|
||
h+=i<STEPS.length-1?'<button class="btn btn-p" onclick="next()">Next</button>':'<button class="btn btn-g" onclick="finish()">Generate Solution</button>';
|
||
h+='</div></div></div>';document.getElementById('qArea').innerHTML=h;document.getElementById('qArea').scrollIntoView({behavior:'smooth',block:'start'})}
|
||
function sv(){STEPS[step].flds.forEach(f=>{const el=document.querySelector('[name="'+f.n+'"]');if(el)ans[f.n]=el.value})}
|
||
function prev(){sv();if(step>0)rStep(step-1)}
|
||
function goStep(i){if(i<=step){sv();rStep(i)}}
|
||
function next(){sv();const req=STEPS[step].flds.filter(f=>f.r);let ok=true;req.forEach(f=>{if(!ans[f.n]||!ans[f.n].trim()){const el=document.querySelector('[name="'+f.n+'"]');if(el)el.style.borderColor='#f85149';ok=false}});if(!ok)return;if(step<STEPS.length-1)rStep(step+1)}
|
||
function selectClient(v){window.location.href=v?'/consulting?client_id='+v:'/consulting'}
|
||
function finish(){sv();if(!cid){addMsg('agent','Connect to a client first.');return}const req=STEPS[4].flds.filter(f=>f.r);let ok=true;req.forEach(f=>{if(!ans[f.n]||!ans[f.n].trim())ok=false});if(!ok){addMsg('agent','Fill in all required fields.');return}const rpt=genRpt();fetch('/consulting/save',{method:'POST',headers:{'Content-Type':'application/json'},body:JSON.stringify({client_id:parseInt(cid),answers:ans,report:rpt})}).then(r=>r.json()).then(()=>{document.getElementById('qArea').style.display='none';document.getElementById('results').innerHTML=buildRes(rpt,ans)+'<div class="qa" style="margin-top:1rem"><a href="/consulting?client_id='+cid+'" class="btn btn-o">New Assessment</a><a href="/clients/'+cid+'" class="btn btn-p" style="margin-left:auto">View Client →</a></div>';document.getElementById('results').style.display='block';document.getElementById('results').scrollIntoView({behavior:'smooth'});addMsg('agent','✅ Architecture solution generated & saved!')}).catch(e=>addMsg('agent','Error: '+e.message))}
|
||
function genRpt(){let dwT='Standard',aiT='Standard',inT='Standard';const dv=(ans.dvol||''),vg=(ans.aigoal||''),am=(ans.aimat||''),it=(ans.infra||''),bg=(ans.budget||'');if(dv.includes('PB')||dv.includes('100 TB'))dwT='Enterprise';else if(dv.includes('10 TB'))dwT='Advanced';if(vg.includes('Generative')||vg.includes('LLM')||am.includes('Advanced'))aiT='Enterprise';else if(vg.includes('NLP')||vg.includes('Computer')||am.includes('Production'))aiT='Advanced';if(bg.includes('5M')||bg.includes('1M')||it.includes('Multi-cloud'))inT='Enterprise';else if(bg.includes('250K')||it.includes('Hybrid'))inT='Advanced';let dwS={},aiS={},inS={};
|
||
if(dwT==='Enterprise')dwS={Lakehouse:'MinIO + Iceberg + Kubernetes','Query Engine':'Spark Streaming + Trino + dbt',Catalog:'Hive Metastore + DataHub',Governance:'Apache Atlas + Ranger',Storage:'S3 (MinIO multi-site)'};
|
||
else if(dwT==='Advanced')dwS={Lakehouse:'MinIO + Iceberg + K8s','Query Engine':'Spark + Trino + dbt',Catalog:'Hive Metastore',Governance:'Apache Ranger',Storage:'MinIO/S3'};
|
||
else dwS={Lakehouse:'MinIO/S3 + PostgreSQL','Query Engine':'Spark batch + dbt',Catalog:'Basic metadata',Governance:'IAM + audit',Storage:'MinIO'};
|
||
if(aiT==='Enterprise')aiS={Serving:'vLLM + SGLang (multi-GPU)',Orchestrator:'Kubeflow + MLflow + Ray',Monitoring:'Prometheus + Grafana + Evidently',Frameworks:'PyTorch + LangChain + LlamaIndex',GPU:'NVIDIA H100 / L40S'};
|
||
else if(aiT==='Advanced')aiS={Serving:'Ollama + vLLM',Orchestrator:'MLflow + Prefect',Monitoring:'Grafana + MLflow',Frameworks:'PyTorch + scikit-learn + XGBoost',GPU:'NVIDIA L40S / A10'};
|
||
else aiS={Serving:'Ollama / HuggingFace',Orchestrator:'MLflow basic',Monitoring:'Streamlit',Frameworks:'scikit-learn + XGBoost',GPU:'CPU + optional GPU'};
|
||
if(inT==='Enterprise')inS={Compute:'vSphere + Rancher/K8s + bare metal',Network:'100GbE leaf-spine','Storage':'Pure Storage + NetApp AFF','Sec/DR':'Zero Trust + HSM + Veeam',Obs:'Grafana + Loki + Tempo'};
|
||
else if(inT==='Advanced')inS={Compute:'vSphere + Proxmox + Docker',Network:'25GbE','Storage':'NetApp FAS + MinIO','Sec/DR':'Zero Trust + Veeam',Obs:'Grafana + Prometheus'};
|
||
else inS={Compute:'Proxmox VE + Docker',Network:'10GbE','Storage':'TrueNAS + MinIO','Sec/DR':'pfSense + PBS',Obs:'Grafana + Netdata'};
|
||
let g=dwT==='Standard'&&aiT==='Standard'?'C':(dwT==='Enterprise'||aiT==='Enterprise'?'A':'B');return{dwT,aiT,inT,grade:g,dwS,aiS,inS}}
|
||
function buildRes(rpt,a){let h='<div class="res-h"><h2>'+(a.company||'Organization')+'</h2><div class="rp">'+a.industry+' · '+a.employees+' · '+a.budget+' · '+a.timeline+'</div><div class="tier"><span class="tb '+rpt.grade.toLowerCase()+'">Grade: '+rpt.grade+'</span><span class="tb b">Data: '+rpt.dwT+'</span><span class="tb b">AI: '+rpt.aiT+'</span></div></div>';h+='<div class="sec"><h3>Data Lakehouse — '+rpt.dwT+'</h3><div class="tg">';for(const[k,v] of Object.entries(rpt.dwS))h+='<div class="ti"><div class="tl">'+k+'</div><div class="tv">'+v+'</div></div>';h+='</div></div><div class="sec"><h3>AI/ML Platform — '+rpt.aiT+'</h3><div class="tg">';for(const[k,v] of Object.entries(rpt.aiS))h+='<div class="ti"><div class="tl">'+k+'</div><div class="tv">'+v+'</div></div>';h+='</div></div><div class="sec"><h3>Infrastructure — '+rpt.inT+'</h3><div class="tg">';for(const[k,v] of Object.entries(rpt.inS))h+='<div class="ti"><div class="tl">'+k+'</div><div class="tv">'+v+'</div></div>';h+='</div></div><div class="sec"><h3>Implementation Roadmap</h3>';[{t:'Phase 1: Foundation (0-3m)',i:['Infrastructure audit & baseline','PoC: Data lake on MinIO + Spark','AI readiness assessment','Security baseline','Team training: data engineering']},{t:'Phase 2: Build (3-6m)',i:['Lakehouse implementation (Iceberg+Trino+dbt)','Data catalog & governance rollout','CI/CD pipeline (GitOps)','ML platform (MLflow)','Data pipeline migration']},{t:'Phase 3: Scale (6-12m)',i:['AI model serving (vLLM/SGLang)','Automated retraining + monitoring','Real-time streaming (Kafka/Flink)','Self-service analytics','FinOps implementation']},{t:'Phase 4: Optimize (12m+)',i:['Multi-region replication','Advanced AI (RAG, agents)','Data mesh evaluation','Enterprise observability','Continuous optimization']}].forEach(p=>{h+='<div class="ph"><h4>'+p.t+'</h4><ul>';p.i.forEach(it=>h+='<li>'+it+'</li>');h+='</ul></div>'});return h+'</div>'}
|
||
function toggleAgent(){document.getElementById('apop').classList.toggle('open')}
|
||
function addMsg(role,txt){const c=document.getElementById('amsgs');const d=document.createElement('div');d.className='am '+role;d.innerHTML=(role==='agent'?'<span class="who">Agent</span>':'')+txt;c.appendChild(d);c.scrollTop=c.scrollHeight}
|
||
function send(){const i=document.getElementById('ainp');const t=i.value.trim();if(!t)return;addMsg('user',t);i.value='';setTimeout(()=>agentReply(t),300)}
|
||
function agentReply(q){const ql=q.toLowerCase();let r='';const ind=(ans.industry||'').toLowerCase();const kb={banking:'Azure Synapse + Databricks + Snowflake (DW), Azure ML + risk models (AI), Cisco/HPE/Oracle (Infra). PSD2/DORA compliance required.',insurance:'Azure Synapse + Teradata (DW), Azure ML + SAS (AI), Cisco/Dell/NetApp (Infra). Solvency II compliance.',healthcare:'Databricks + Snowflake + Azure (DW), PyTorch + MONAI (AI), Dell/HPE/Pure (Infra). HIPAA/NEN 7510 compliance.',retail:'BigQuery + dbt + Databricks (DW), Vertex AI + Python (AI), GCP/Cisco/Dell (Infra). Real-time personalization.',manufacturing:'Azure Synapse + SAP BW + Databricks (DW), Azure ML + CV (AI). IoT & edge computing.',telecom:'Snowflake + Oracle + dbt (DW), Vertex AI + Python (AI), Nokia/Cisco/Dell (Infra). 5G & streaming.',energy:'Azure Synapse + Databricks (DW), TensorFlow + Python (AI). Smart grid & IoT.',government:'Oracle Exadata + Azure Synapse (DW), Azure ML + Python (AI), Cisco/Dell/NetApp (Infra).'};(ql.includes('industry')||ql.includes('sector'))?(Object.entries(kb).find(([k])=>ind.includes(k))?(r='<b>'+ans.industry+'</b>: '+Object.entries(kb).find(([k])=>ind.includes(k))[1]):(r='Tell me the industry (Step 1) to get benchmarks.')):(ql.includes('data')||ql.includes('lake'))?(r=(dv=ans.dvol||'').includes('PB')||dv.includes('100 TB')?'Enterprise lakehouse: MinIO + Iceberg + Spark Streaming + Trino + dbt on K8s. Multi-site S3 storage.':dv.includes('10 TB')?'Advanced: MinIO + Iceberg + Spark + dbt on K8s.':dv?'Standard: MinIO/S3 + Spark batch + dbt.':'What is your data volume? (Step 3)'):(ql.includes('ai')||ql.includes('ml')||ql.includes('model'))?(r=(ans.aigoal||'')?(ans.aigoal.includes('Generative')||ans.aigoal.includes('LLM')?'Enterprise AI: vLLM + SGLang on H100 GPUs, LangChain + LlamaIndex, Kubeflow + MLflow.':ans.aigoal.includes('NLP')||ans.aigoal.includes('Computer')?'Advanced: Ollama/vLLM on L40S, MLflow + PyTorch.':'Standard: scikit-learn + XGBoost + Streamlit. CPU + optional GPU.'):'What is your AI goal? (Step 4)'):(ql.includes('budget')||ql.includes('cost'))?(r=(ans.budget||'')?(ans.budget.includes('5M')||ans.budget.includes('1M')?'Enterprise: 100GbE, multi-GPU, Pure+NetApp, Zero Trust. €1-5M/yr.':ans.budget.includes('250K')?'Advanced: 25GbE, 1-2 GPUs, NetApp+MinIO. €250K-1M/yr.':'Standard: 10GbE, Proxmox+Docker, TrueNAS+MinIO.'):'What is your budget? (Step 5)'):(ql.includes('help')||ql.includes('guide'))?r='Ask about: <b>industry benchmarks</b>, <b>data lake size</b>, <b>AI models</b>, <b>budget planning</b>, or <b>roadmap</b>.':r='Try asking: <b>"data lake"</b>, <b>"AI platform"</b>, <b>"budget"</b>, or <b>"help"</b>.';addMsg('agent',r)}
|
||
rStep(0);
|
||
</script>
|
||
</body></html>
|