Welcome to GeneOS

How would you like to get started?

🔑
I have a token
Access your DNA results and health account. Token found on your kit sticker or confirmation email.
✨
Start fresh
Complete the health intake wizard and generate a new profile.
32 hex characters — found on your kit sticker or confirmation email.
GeneOS
Human Genetic Operating System
Health Account 🚪 Sign Out
GeneOS 🧬 Continue Health Intake
GeneOS
GeneOS is ready
Step 1/10: Basics
📤
Uploading...
Processing your file
`; const blob=new Blob([html],{type:'text/html'}); const url=URL.createObjectURL(blob); const win=window.open(url,'_blank'); if(!win){ const a=document.createElement('a'); a.href=url;a.download='GeneOS-Clinical-Report.html';a.click(); } setTimeout(()=>URL.revokeObjectURL(url),10000); } // ── Step Guidance ── let _nudgeTimer=null; function _clearPendingChips(){ // Remove any chip rows still in the chat that haven't been acted on const thread=$('chat-thread'); if(!thread)return; thread.querySelectorAll('.chips-row').forEach(r=>{ r.style.transition='opacity 0.2s ease'; r.style.opacity='0'; setTimeout(()=>r.remove(),220); }); } async function triggerStepGuide(){ // Sweep out any unanswered chip rows from the previous step _clearPendingChips(); const tags = _getStepTags(currentStep, healthProfile); if (tags.length > 0) { // Data already exists for this step — card shows saved items. // Call interview with __open__ so the AI asks a smart follow-up // (e.g. dosing details for a saved med, severity for a saved condition) // rather than just staying silent. _askNewInterviewQuestion(); return; } // First time on this step — ask the 83-question advisor for the most // protocol-impactful opening question, falling back to STEP_GUIDES. _askNewInterviewQuestion(); // Quick-select chips — adaptive based on accumulated profile const chips = _getAdaptiveChips(currentStep, healthProfile); if(chips && chips.length) addChips(chips, chipSelected); if(currentStep === 0) addChips(['Male','Female','Intersex','Prefer not to say'], chipSelected); // 20s nudge if user hasn't typed anything yet clearTimeout(_nudgeTimer); _nudgeTimer = setTimeout(()=>{ if(_getStepTags(currentStep, healthProfile).length === 0 && NUDGES[currentStep]){ addMsg('hypatia', NUDGES[currentStep]); speak(NUDGES[currentStep]); } }, 20000); } // Ask the new 83-question interview system for the opening/follow-up // question at the current step. The special __open__ message tells the // backend to skip extraction and just return the best next question. async function _askNewInterviewQuestion(){ try{ showTyping(); const d = await api('/health/wizard/interview',{ step: currentStep, message: '__open__', history: _chatHistory.slice(-12), profile_summary: _profileSummary(), // backend uses this to skip already-filled sections }); hideTyping(); if(d.ok && d.reply && d.reply !== '__open__'){ _chatHistory.push({role:'assistant', text: d.reply}); addMsg('hypatia', d.reply); speak(d.reply); } else { // Fallback: use the hard-coded guide if the API fails or returns empty const guide = STEP_GUIDES[currentStep]; if(guide){ addMsg('hypatia', guide); speak(guide); } } } catch(e){ hideTyping(); const guide = STEP_GUIDES[currentStep]; if(guide){ addMsg('hypatia', guide); speak(guide); } } } // ── Entry Gate JS ── var _gatePath = null; var _wizardIdentityReady = false; (function gateSetup() { // Check URL param ?token= const params = new URLSearchParams(location.search); const urlToken = params.get('token'); const urlEnrollment = params.get('enroll'); if (urlEnrollment && /^gxr_[A-Za-z0-9_-]{12,120}$/.test(urlEnrollment)) { _gatePath='enroll'; document.getElementById('gate-token-box').classList.add('show'); document.getElementById('gate-continue-btn').disabled=true; document.getElementById('gate-continue-btn').textContent='Importing kit access…'; enterWithEnrollment(urlEnrollment); return; } if (urlToken && /^[a-f0-9]{32}$/i.test(urlToken)) { // Keep the gate visible until the server validates the token. _gatePath='token'; document.getElementById('gate-token-box').classList.add('show'); document.getElementById('gate-token-input').value=urlToken.toLowerCase(); document.getElementById('gate-continue-btn').disabled=true; document.getElementById('gate-continue-btn').textContent='Verifying…'; enterWithToken(urlToken); return; } // Check if already have a geneos_session cookie (simple presence check) if (document.cookie.includes('geneos_session=')) { document.getElementById('gate-card-add').style.display = 'flex'; } // Check BarcodeDetector for QR scan button if ('BarcodeDetector' in window) { document.getElementById('gate-scan-btn').style.display = 'inline-flex'; } else { const hint = document.getElementById('gate-hint'); if (hint) hint.textContent = 'Type your 32-character hex token above.'; } })(); function selectGatePath(path) { _gatePath = path; // Deselect all cards document.querySelectorAll('#wiz-gate .gate-card').forEach(c => c.classList.remove('selected')); const card = document.getElementById('gate-card-' + path); if (card) card.classList.add('selected'); const tokenBox = document.getElementById('gate-token-box'); const continueBtn = document.getElementById('gate-continue-btn'); if (path === 'token' || path === 'add') { tokenBox.classList.add('show'); document.getElementById('gate-token-input').focus(); continueBtn.disabled = false; } else if (path === 'fresh') { tokenBox.classList.remove('show'); continueBtn.disabled = false; } } async function continueGate() { if (!_gatePath) return; if (_gatePath === 'fresh') { const ready=await (window._wizardInitPromise||Promise.resolve(false)); if(!ready || !_wizardIdentityReady){ const err=document.getElementById('gate-token-err'); if(err){err.textContent='Sign in first to create and save a health profile.';err.style.display='block';} return; } // Identity and health profile persistence are confirmed — show wizard. document.getElementById('wiz-gate').style.display = 'none'; return; } // Token path const tok = (document.getElementById('gate-token-input').value || '').trim().toLowerCase(); const errEl = document.getElementById('gate-token-err'); errEl.style.display = 'none'; if (!tok) { errEl.textContent = 'Please enter your token.'; errEl.style.display = 'block'; return; } if (!/^[a-f0-9]{32}$/.test(tok)) { errEl.textContent = 'Token must be 32 hex characters. Check your kit or email.'; errEl.style.display = 'block'; return; } await enterWithToken(tok); } async function enterWithEnrollment(reference) { const errEl = document.getElementById('gate-token-err'); const continueBtn = document.getElementById('gate-continue-btn'); if (continueBtn) { continueBtn.disabled = true; continueBtn.textContent = 'Importing kit access…'; } try { const r = await fetch('/api/ideas/geneos/auth/enrollment-resume', { method: 'POST', headers: { 'Content-Type': 'application/json' }, credentials: 'include', body: JSON.stringify({ enrollment_ref: reference }) }).then(resp => resp.json()); if (!r.ok) throw new Error(r.error || 'Kit access reference could not be imported.'); window.GENEOS_ENROLLMENT_REF = reference; let ready = await (window._wizardInitPromise || Promise.resolve(false)); if (!ready) { window._wizardInitPromise = init(); ready = await window._wizardInitPromise; } if (!ready || !_wizardIdentityReady) { throw new Error('GeneOS could not initialize this kit-scoped wizard session.'); } document.getElementById('wiz-gate').style.display = 'none'; addMsg('system','✓ Kit access imported — your GeneOS intake is ready.'); } catch(e) { if (errEl) { errEl.textContent = e.message || 'Network error. Please try again.'; errEl.style.display = 'block'; } if (continueBtn) { continueBtn.disabled = false; continueBtn.textContent = 'Continue →'; } } } async function enterWithToken(tok) { const errEl = document.getElementById('gate-token-err'); const continueBtn = document.getElementById('gate-continue-btn'); if (continueBtn) { continueBtn.disabled = true; continueBtn.textContent = 'Verifying…'; } try { const r = await fetch('/api/ideas/geneos/auth/token-resume', { method: 'POST', headers: { 'Content-Type': 'application/json' }, credentials: 'include', body: JSON.stringify({ token: tok }) }).then(resp => resp.json()); if (r.ok) { // The QR token is a wizard credential. Stay here so the collection and // intake flow can run in the token-scoped session; Health Account remains // an intentional exit after the user has completed or skipped intake. window.GENEOS_TOKEN = tok; let ready = await (window._wizardInitPromise || Promise.resolve(false)); if (!ready) { window._wizardInitPromise = init(); ready = await window._wizardInitPromise; } if (!ready || !_wizardIdentityReady) { throw new Error('GeneOS could not initialize this token-scoped wizard session.'); } document.getElementById('wiz-gate').style.display = 'none'; if (continueBtn) { continueBtn.disabled = false; continueBtn.textContent = 'Continue →'; } addMsg('system','✓ Token verified — your GeneOS intake is ready.'); return; } else { if (errEl) { errEl.textContent = r.error || 'Token not found. Please check your kit and try again.'; errEl.style.display = 'block'; } if (continueBtn) { continueBtn.disabled = false; continueBtn.textContent = 'Continue →'; } } } catch(e) { if (errEl) { errEl.textContent = 'Network error. Please try again.'; errEl.style.display = 'block'; } if (continueBtn) { continueBtn.disabled = false; continueBtn.textContent = 'Continue →'; } } } async function startQRScan() { if (!('BarcodeDetector' in window)) return; try { const stream = await navigator.mediaDevices.getUserMedia({ video: { facingMode: 'environment' } }); const video = document.createElement('video'); video.srcObject = stream; video.setAttribute('playsinline', true); video.play(); const detector = new window.BarcodeDetector({ formats: ['qr_code'] }); const scanLoop = setInterval(async () => { if (video.readyState === video.HAVE_ENOUGH_DATA) { try { const barcodes = await detector.detect(video); if (barcodes.length > 0) { clearInterval(scanLoop); stream.getTracks().forEach(t => t.stop()); const rawVal = barcodes[0].rawValue || ''; // Extract an opaque enrollment reference or a legacy raw token. let tok = rawVal; let enrollmentRef = ''; try { const u = new URL(rawVal); enrollmentRef = u.searchParams.get('enroll') || ''; tok = u.searchParams.get('token') || rawVal; } catch(e) { /* not a URL, use as-is */ } if (/^gxr_[A-Za-z0-9_-]{12,120}$/.test(enrollmentRef)) { _gatePath = 'enroll'; enterWithEnrollment(enrollmentRef); return; } tok = tok.replace(/[^a-f0-9]/gi, '').toLowerCase(); const input = document.getElementById('gate-token-input'); if (input) { input.value = tok; } selectGatePath('token'); } } catch(e) { /* ignore detect errors */ } } }, 200); // Auto-stop after 30s setTimeout(() => { clearInterval(scanLoop); stream.getTracks().forEach(t => t.stop()); }, 30000); } catch(e) { const hint = document.getElementById('gate-hint'); if (hint) hint.textContent = 'Camera access denied. Please type your token manually.'; } } // ── Init ── async function init(){ syncMuteUI(); // Auth — GeneOS pattern: soft check, never redirect, show login bar if needed const whoami=await apiGet('/auth/whoami'); if(whoami.ok&&whoami.viewer){viewer=whoami.viewer} else{ try{ const gw=await api('/geneos/auth/whoami',{}); if(gw.ok&&gw.authenticated&&gw.customer){ viewer={display_name:gw.display_name||gw.customer.token||'user',role:'user',email:'',app:'brain'}; window.GENEOS_CUSTOMER=gw.customer; } }catch(e){} if(!viewer)return false; } retailHandoff=await validateRetailHandoff(); if(retailHandoff.requested&&!retailHandoff.allowed){ window.location.replace('/geneos/console.html?retail=pending'); return; } // Load profile + wizard state const pd=await api('/health/profile',{}); if(!pd.ok)return false; healthProfile=pd.profile||{}; await _loadHealthCatalog(); _wizardIdentityReady=true; await loadWizState(); renderProgress(); renderStepPanel(); // Welcome const doneCount=wizState.steps.filter(s=>s==='done').length; let greeting; if(retailHandoff?.allowed&&retailHandoff.requested){ greeting='Your selected test results are loaded into this Health Wizard. Let’s add the context needed to personalize your report.'; }else if(wizState.completed_at){ // Returning user — reference what they have on file const dem = healthProfile.demographics||{}; const cCount = (healthProfile.conditions||[]).length; const mCount = (healthProfile.medications||[]).length; const bCount = (healthProfile.biomarkers||[]).length; const parts = []; if(dem.age) parts.push(`${dem.age}y ${dem.sex||''}`+((cCount?`, ${cCount} conditions`:''))+(mCount?`, ${mCount} meds`:'')+(bCount?`, ${bCount} biomarkers`:'')); greeting = 'Clinical profile on file' + (parts.length?' ('+parts[0]+')':'') + '. Add new lab results, update medications, or ask clinical questions about your protocol.'; }else if(doneCount>0){ const remaining = TOTAL - doneCount; const nxt = LABELS[currentStep]; greeting = `${doneCount}/${TOTAL} sections complete. ${remaining} remaining — resuming at ${nxt}.`; }else{ // Brand new account — warm, confident, specific about what's coming const dem = healthProfile.demographics||{}; const hasSomething = dem.age||dem.sex||(healthProfile.conditions||[]).length>0; if(hasSomething){ const cCount=(healthProfile.conditions||[]).length; greeting = `Profile started${cCount?` — ${cCount} conditions on file`:''}. Let's complete the intake so we can build your precision protocol. ${TOTAL-doneCount} steps remaining.`; }else{ greeting = `GeneOS clinical intake — ${TOTAL} steps, under 2 minutes each. Your answers build a precision medicine profile: every supplement recommendation, peptide protocol, and lifestyle adjustment will be tailored specifically to your biology. Start with your age and sex.`; } } addMsg('hypatia',greeting); speak(greeting); // Clear history on fresh load (prevents stale context from prior session) _chatHistory=[]; // Then show step-specific guidance after greeting setTimeout(()=>{ if(!wizState.completed_at) triggerStepGuide(); },2000); // 2026-05-25 — Simli avatar disabled until lip-sync drift fix is // validated in production on voice-avatar.html. Static image shows // in the avatar ring instead. TTS via browser SpeechSynthesis still // works. Re-enable by uncommenting initSimli() below. // initSimli(); return true; } window._wizardInitPromise=init();