🧬
Loading your health data...
'); w.document.close(); setTimeout(()=>w.print(),400); haToast('Print/PDF dialog opened β€” choose Save as PDF to download'); } // ── Health Data Upload Section ── let _haUploadTab='all'; const _HA_TABS=[ {id:'all', icon:'πŸ“',label:'All Files'}, {id:'genes',icon:'🧬',label:'Genes / DNA'}, {id:'labs', icon:'πŸ§ͺ',label:'Labs / Biomarkers'}, {id:'other',icon:'πŸ“„',label:'Other / Reports'}, ]; const _HA_ACCEPT={'all':'.txt,.csv,.tsv,.vcf,.pdf,.doc,.docx,.png,.jpg,.jpeg,.webp,.zip','genes':'.txt,.csv,.tsv,.vcf,.pdf,.zip','labs':'.pdf,.png,.jpg,.jpeg,.webp,.doc,.docx,.csv','other':'.pdf,.txt,.csv,.doc,.docx,.png,.jpg,.jpeg,.webp'}; const _HA_FORMAT_TEXT={'all':'TXT, CSV, VCF, PDF, DOC, images','genes':'23andMe TXT, Ancestry CSV, VCF, PDF gene reports','labs':'Lab PDF, images of results, CSV','other':'PDF, DOC, images, text files'}; function renderUploadSection(){ const tabs=_HA_TABS.map(t=>``).join(''); return '
'+ '
πŸ“€ UPLOAD HEALTH DATA
'+ '
Drop files here to add genes, biomarkers, lab results, or any health documents to your account. Hypatia will extract and integrate the data automatically.
'+ '
'+tabs+'
'+ '
'+ '
πŸ“€
'+ '
Click to browse or drag & drop files here
'+ '
Accepted: '+esc(_HA_FORMAT_TEXT[_haUploadTab])+'
'+ '
'+ ''+ '
'+ '
'+ '
'; } function _haSetTab(id){ _haUploadTab=id; document.querySelectorAll('.ha-upload-tab').forEach(b=>b.classList.toggle('active',b.textContent.includes(_HA_TABS.find(t=>t.id===id).label))); const fi=document.getElementById('ha-file-input'); if(fi)fi.accept=_HA_ACCEPT[id]||_HA_ACCEPT.all; const fmt=document.getElementById('ha-dropzone-formats'); if(fmt)fmt.textContent='Accepted: '+(_HA_FORMAT_TEXT[id]||_HA_FORMAT_TEXT.all); } function _haInitDropzone(){ const dz=document.getElementById('ha-dropzone'); if(!dz)return; dz.addEventListener('dragover',e=>{e.preventDefault();dz.classList.add('drag-over');}); dz.addEventListener('dragleave',()=>dz.classList.remove('drag-over')); dz.addEventListener('drop',e=>{e.preventDefault();dz.classList.remove('drag-over');_haHandleFiles(e.dataTransfer.files);}); } async function _haHandleFiles(files){ if(!files||!files.length)return; const list=document.getElementById('ha-upload-list'); for(const file of files){ const isGene=_haUploadTab==='genes'||_haIsGeneFile(file.name); const icon=isGene?'🧬':_haIsLabFile(file.name)?'πŸ§ͺ':'πŸ“„'; const itemId='ha-up-'+Date.now()+'-'+Math.random().toString(36).slice(2,6); const size=file.size<1024?(file.size+'B'):file.size<1048576?((file.size/1024).toFixed(1)+'KB'):((file.size/1048576).toFixed(1)+'MB'); list.insertAdjacentHTML('beforeend', '
'+ '
'+icon+'
'+ '
'+ '
'+esc(file.name)+'
'+ '
'+esc(size)+' Β· '+(isGene?'Genetic data':'Health document')+'
'+ '
'+ '
Uploading
'+ '
'); try{ const b64=await _haReadFile(file); if(isGene){ await _haUploadGene(file,b64,itemId); }else{ await _haUploadDoc(file,b64,itemId); } }catch(e){ const st=document.getElementById(itemId+'-status'); if(st){st.textContent='Error';st.className='ha-upload-item-status error';} haToast('Upload failed: '+e.message,false); } } // Reset file input so same file can be re-selected const fi=document.getElementById('ha-file-input');if(fi)fi.value=''; } function _haReadFile(file){ return new Promise((resolve,reject)=>{ const reader=new FileReader(); reader.onload=e=>resolve(e.target.result); reader.onerror=()=>reject(new Error('Failed to read file')); reader.readAsDataURL(file); }); } function _haIsGeneFile(name){ const n=(name||'').toLowerCase(); return n.includes('23andme')||n.includes('ancestry')||n.endsWith('.vcf')||n.includes('genome')||n.includes('dna')||n.includes('snp')||n.includes('genotype'); } function _haIsLabFile(name){ const n=(name||'').toLowerCase(); return n.includes('lab')||n.includes('blood')||n.includes('panel')||n.includes('cbc')||n.includes('cmp')||n.includes('lipid')||n.includes('thyroid')||n.includes('metabolic')||n.includes('biomarker'); } async function _haUploadGene(file,b64,itemId){ const st=document.getElementById(itemId+'-status'); if(st){st.textContent='Processing';st.className='ha-upload-item-status processing';} const ext=(file.name||'').split('.').pop().toLowerCase(); const isBinary=['pdf','doc','docx','png','jpg','jpeg','webp'].includes(ext); const payload=isBinary ?{content_b64:b64,filename:file.name} :{content:typeof b64==='string'&&b64.includes(',')?atob(b64.split(',')[1]):b64,filename:file.name}; const d=await API('/devlab/gene/upload',payload); if(d.ok){ if(st){st.textContent='Done';st.className='ha-upload-item-status done';} haToast('🧬 '+file.name+': '+(d.total_matched||0)+' variants matched'); // Show results inline const item=document.getElementById(itemId); if(item&&d.matched&&d.matched.length){ const critical=(d.matched||[]).filter(v=>['high','critical','moderate'].includes(v.severity||v.impact||'')); let rh='
🧬 '+(d.total_parsed||0)+' parsed · '+(d.total_matched||0)+' matched'; if(critical.length){ rh+='
⚠️ '+critical.length+' notable finding'+(critical.length>1?'s':'')+':
'; critical.slice(0,4).forEach(v=>{rh+='
β€’ '+esc(v.card_title||v.gene||v.rsid||'?')+' ('+esc(v.genotype||'')+')
';}); if(critical.length>4)rh+='
+'+(critical.length-4)+' more
'; } rh+='
'; item.insertAdjacentHTML('beforeend',rh); } // Also store in health docs try{await API('/health/upload',{filename:file.name,content:b64})}catch(e){} }else{ if(st){st.textContent='Error';st.className='ha-upload-item-status error';} haToast(d.error||'Gene upload failed',false); } } async function _haUploadDoc(file,b64,itemId){ const st=document.getElementById(itemId+'-status'); if(st){st.textContent='Processing';st.className='ha-upload-item-status processing';} const d=await API('/health/upload',{filename:file.name,content:b64}); if(d.ok){ if(st){st.textContent='Extracting';st.className='ha-upload-item-status processing';} haToast('πŸ“„ '+file.name+' uploaded β€” AI extracting data…'); _haPolIDigest(file.name,itemId); }else{ if(st){st.textContent='Error';st.className='ha-upload-item-status error';} haToast(d.error||'Upload failed',false); } } function _haPolIDigest(filename,itemId){ let tries=0; const iv=setInterval(async()=>{ tries++; if(tries>20){clearInterval(iv);const st=document.getElementById(itemId+'-status');if(st){st.textContent='Done';st.className='ha-upload-item-status done';}return;} try{ const docs=await API('/health/documents',{}); if(!docs.ok)return; const doc=(docs.documents||[]).find(d=>d.original_filename===filename||d.filename===filename); if(doc&&doc.digested){ clearInterval(iv); const st=document.getElementById(itemId+'-status'); if(st){st.textContent='Done';st.className='ha-upload-item-status done';} haToast('βœ… '+filename+' fully processed'); } }catch(e){} },2000); } // Load previously uploaded documents on page init async function _haLoadUploadHistory(){ try{ const d=await API('/health/documents',{}); if(!d.ok||!d.documents||!d.documents.length)return; const el=document.getElementById('ha-upload-history'); if(!el)return; const docs=d.documents.slice(0,10); let h='
πŸ“‹ Previously Uploaded ('+(d.documents.length)+')
'; docs.forEach(doc=>{ const name=doc.original_filename||doc.filename||'Unknown'; const isGene=_haIsGeneFile(name); const icon=isGene?'🧬':_haIsLabFile(name)?'πŸ§ͺ':'πŸ“„'; const date=doc.uploaded_at?(new Date(doc.uploaded_at)).toLocaleDateString():''; const status=doc.digested?'Done':'Pending'; const cls=doc.digested?'done':'pending'; h+='
'+ '
'+icon+'
'+ '
'+ '
'+esc(name)+'
'+ '
'+esc(date)+'
'+ '
'+ '
'+status+'
'+ '
'; }); if(d.documents.length>10) h+='
Showing 10 of '+d.documents.length+' documents
'; el.innerHTML=h; }catch(e){} } init();