TEN LEI YẾN

Alina

AI Command Center

WELCOME TO ALINA

Claude
GPT-4
Gemini
Grok
Content & Creative
Ayla
Social Media & Ads
GPT-4
Alina
Multilingual Content
CLAUDE
Penn
Ad & Sales Copy
CLAUDE
Erik
Social Media + Visual
GEMINI
Commerce & Growth
Rex
eCommerce / Shopify
CLAUDE
Sara
SEO Strategy
GPT-4
Nova
Email Marketing
CLAUDE
Milli
Sales & Outreach
GROK
Intelligence & Ops
Orion
Research & Web Intel
GROK
Axon
Data Analyst
GPT-4
Forge
Dev / Liquid / Code
CLAUDE
Zara
Executive Assistant
CLAUDE
Kai
Customer Support
CLAUDE
Alina
Multilingual Content Specialist · Claude Sonnet · EN / VI / 中文
SYS
Alina · System
Multi-LLM routing active. Brain memory loaded. 13 agents standing by. Use @agentname to route mid-message. Chain agents or Broadcast to all simultaneously.
🌺
Alina · Multilingual Content · Claude
Hello Steven — I'm Alina, your multilingual content specialist. Give me any brief and I'll deliver English, Vietnamese, and Traditional Mandarin simultaneously.

Try ⛓ Chain to pipe my output into Sara → Erik → Nova automatically, or ⚡ Broadcast to get every agent's perspective at once.
🌺 Trilingual copy
⚙️ Shopify code
🌐 Competitor intel
📧 Email sequence
📸 IG captions
💰 Vendor pitch
🎨 Generate image
⛓ Agent Chain
Workflow Builder
Drag agents onto the canvas.
Click ⛓ to connect nodes. Run the flow.
Canvas Drop agents here to build a workflow
🔀
Drag agents here
Connect · Run · Export
Session History
Every conversation with your agents
🇺🇸 United States ● Live
 ·  Last refreshed: never   DISMISS →
Domain Rating
34
▲ +3 past 6 mo
Ahrefs Rank
#1.8M
▲ +140K
Referring Domains
312
▲ +18 this month
Backlinks
2,140
▲ +86 this month
Organic Traffic
3,820
▲ +14% MoM
Organic Traffic
Full report →
3,820
est. monthly visits  ▲ +14%
Keywords by Position
View all →
#1 – 3
42
#4 – 10
78
#11 – 20
96
#21 – 50
106
#51 – 100
65
Referring Domains
Full report →
312
unique domains  ▲ +18
Traffic by Country
View all →
🇺🇸United States
82%
🇻🇳Vietnam
8%
🇨🇦Canada
5%
🇹🇼Taiwan
3%
🌏Other
2%
Site Audit Health
Run full audit →
75
HEALTH SCORE
Needs Work
~380 pages · crawled 2h ago
Errors
18
Warnings
41
Notices
58
Passed
263
Steven · You
${esc(content)}
`;} else if(role==='system'){d.innerHTML=`
SYS
System
${esc(content)}
`;} else if(role==='agent'&&a){d.innerHTML=`
${a.emoji}
${a.name} · ${a.model.toUpperCase()}
${fmt(esc(content))}
`;} msgs.appendChild(d);msgs.scrollTop=msgs.scrollHeight;return d; } function addSystemMsg(msg){addMsg('system',msg);} function addTyping(k){const msgs=document.getElementById('messages'),a=AGENTS[k],d=document.createElement('div');d.className='msg agent';d.id='typing-ind';d.innerHTML=`
${a.emoji}
${a.name} · Thinking
`;msgs.appendChild(d);msgs.scrollTop=msgs.scrollHeight;} function removeTyping(){document.getElementById('typing-ind')?.remove();} function fmt(t){return t.replace(/\*\*(.*?)\*\*/g,'$1').replace(/\*(.*?)\*/g,'$1').replace(/`(.*?)`/g,'$1').replace(//g,'

').replace(/\n/g,'
');} function esc(t){return t.replace(/&/g,'&').replace(//g,'>');} function getKey(m){return localStorage.getItem('alina_key_'+m)||'';} // ══════ IMAGE GENERATION ══════ async function generateImageDalle(prompt){ const k=getKey('gpt'); if(!k)throw new Error('No GPT API key found. Add it in Settings to use DALL-E image generation.'); const r=await fetch('https://api.openai.com/v1/images/generations',{ method:'POST', headers:{'Content-Type':'application/json','Authorization':'Bearer '+k}, body:JSON.stringify({model:'dall-e-3',prompt:prompt,n:1,size:'1024x1024',quality:'standard'}) }); const d=await r.json(); if(d.error)throw new Error(d.error.message); return {url:d.data[0].url,revised_prompt:d.data[0].revised_prompt||prompt}; } async function generateImageGemini(prompt){ const k=getKey('gemini'); if(!k)throw new Error('No Gemini API key found. Add it in Settings to use Imagen.'); const r=await fetch('https://generativelanguage.googleapis.com/v1beta/models/gemini-2.5-flash-image:generateContent?key='+k,{ method:'POST', headers:{'Content-Type':'application/json'}, body:JSON.stringify({contents:[{parts:[{text:'Generate an image: '+prompt}]}],generationConfig:{responseModalities:['TEXT','IMAGE']}}) }); const d=await r.json(); if(d.error)throw new Error(d.error.message); const parts=d.candidates?.[0]?.content?.parts||[]; const imgPart=parts.find(p=>p.inlineData); const txtPart=parts.find(p=>p.text); if(imgPart){return {base64:imgPart.inlineData.data,mime:imgPart.inlineData.mimeType,caption:txtPart?.text||''};} throw new Error('Gemini did not return an image. Try rephrasing your prompt.'); } function isImageRequest(msg){ const lower=msg.toLowerCase(); return /^\/(image|img|generate|draw|create image|picture)\b/.test(lower)|| /\b(generate|create|make|draw|design)\s+(an?\s+)?(image|picture|photo|illustration|graphic|visual|banner|logo|poster|thumbnail)/i.test(msg); } async function handleImageGeneration(agentKey,prompt){ const a=AGENTS[agentKey]; const cleanPrompt=prompt.replace(/^\/(image|img|generate|draw|create image|picture)\s*/i,'').trim()||prompt; addTyping(agentKey); try{ let result; if(a.model==='gemini'){ result=await generateImageGemini(cleanPrompt); removeTyping(); if(result.base64){ addImageMsg(agentKey,'data:'+result.mime+';base64,'+result.base64,result.caption||cleanPrompt); } } else { result=await generateImageDalle(cleanPrompt); removeTyping(); addImageMsg(agentKey,result.url,result.revised_prompt||cleanPrompt); } saveSession(agentKey,cleanPrompt,'[Image generated] '+(result.revised_prompt||result.caption||cleanPrompt)); }catch(e){ removeTyping(); addSystemMsg('\u26A0 Image generation failed: '+e.message); } } function addImageMsg(agentKey,src,caption){ const msgs=document.getElementById('messages'),a=AGENTS[agentKey],d=document.createElement('div'); d.className='msg agent'; d.innerHTML=`
${a.emoji}
${a.name} \u00b7 ${a.model.toUpperCase()} \u00b7 Image
Generated image
${esc(caption)}
`; msgs.appendChild(d); msgs.scrollTop=msgs.scrollHeight; return d; } async function callAgent(agentKey,messages,maxTokens=1400){ const a=AGENTS[agentKey],sys=`${a.system}--- BRAIN MEMORY ---\n${brainMemory}--- RULES ---\nBe specific, actionable, production-ready. Stay in character as ${a.name}. Suggest handoffs when relevant.`; const fallback=async()=>{const ck=getKey('claude');if(!ck)throw new Error('No API key found. Add it in ⚙️ Settings.');const r=await fetch('https://api.anthropic.com/v1/messages',{method:'POST',headers:{'Content-Type':'application/json','x-api-key':ck,'anthropic-version':'2023-06-01','anthropic-dangerous-direct-browser-access':'true'},body:JSON.stringify({model:'claude-sonnet-4-20250514',max_tokens:maxTokens,system:sys,messages})});const d=await r.json();if(d.error)throw new Error(d.error.message);return d.content[0]?.text||'';}; if(a.model==='claude'){return fallback();} if(a.model==='gpt'){const k=getKey('gpt');if(!k)return fallback();const msgs=[{role:'system',content:sys},...messages];const r=await fetch('https://api.openai.com/v1/chat/completions',{method:'POST',headers:{'Content-Type':'application/json','Authorization':'Bearer '+k},body:JSON.stringify({model:'gpt-4o',max_tokens:maxTokens,messages:msgs})});const d=await r.json();if(d.error)throw new Error(d.error.message);return d.choices[0]?.message?.content||'';} if(a.model==='gemini'){const k=getKey('gemini');if(!k)return fallback();const contents=[];contents.push({role:'user',parts:[{text:sys+'Acknowledge and stay in character.'}]});contents.push({role:'model',parts:[{text:'Understood. I am '+a.name+'. Ready.'}]});messages.forEach(m=>{contents.push({role:m.role==='user'?'user':'model',parts:[{text:m.content}]});});const r=await fetch(`https://generativelanguage.googleapis.com/v1beta/models/gemini-2.5-flash:generateContent?key=${k}`,{method:'POST',headers:{'Content-Type':'application/json'},body:JSON.stringify({contents})});const d=await r.json();if(d.error)throw new Error(d.error.message);return d.candidates[0]?.content?.parts[0]?.text||'';} if(a.model==='grok'){const k=getKey('grok');if(!k)return fallback();const msgs=[{role:'system',content:sys},...messages];const r=await fetch('https://api.x.ai/v1/chat/completions',{method:'POST',headers:{'Content-Type':'application/json','Authorization':'Bearer '+k},body:JSON.stringify({model:'grok-3-latest',max_tokens:maxTokens,messages:msgs})});const d=await r.json();if(d.error)throw new Error(d.error.message);return d.choices[0]?.message?.content||'';} throw new Error('Unknown model'); } async function sendMessage(){ if(isLoading)return;const input=document.getElementById('chat-input'),msg=input.value.trim();if(!msg)return; let target=currentAgent;const m=msg.match(/@(\w+)/);if(m){const nm=m[1].toLowerCase();const f=Object.keys(AGENTS).find(k=>k===nm||AGENTS[k].name.toLowerCase()===nm);if(f)target=f;} input.value='';autoResize(input);addMsg('user',msg);isLoading=true;document.getElementById('send-btn').disabled=true; // Check if this is an image generation request if(isImageRequest(msg)){ await handleImageGeneration(target,msg); isLoading=false;document.getElementById('send-btn').disabled=false; return; } addTyping(target); if(!convHistory[target])convHistory[target]=[];convHistory[target].push({role:'user',content:msg}); try{const reply=await callAgent(target,convHistory[target]);convHistory[target].push({role:'assistant',content:reply});removeTyping();addMsg('agent',reply,target);saveSession(target,msg,reply);generateSummary(target,msg,reply);} catch(e){removeTyping();addSystemMsg(`⚠ ${e.message}`);} isLoading=false;document.getElementById('send-btn').disabled=false; } let currentChain=[...CHAIN_PRESETS.content]; function renderChainSteps(chain){ currentChain=chain;const tasks={alina:'Draft trilingual content (EN/VI/中文)',seraph:'Add SEO keywords & meta description',echo:'Format for social + visual direction',nova:'Wrap into email campaign',rex:'Build Shopify section / product page',penn:'Rewrite for ad copy & conversions',milli:'Add sales angle & outreach hooks',orion:'Research & competitive intelligence',axon:'Analyze data & add metrics',zara:'Summarize & organize action items',forge:'Generate production-ready code',kai:'Add customer-facing support copy',ayla:'Create social media ads & campaign strategy'}; document.getElementById('chain-steps').innerHTML=chain.map((k,i)=>{const a=AGENTS[k];return`
${i+1}
${a.emoji} ${a.name}
${tasks[k]||a.role}
○ Waiting
`;}).join(''); } function toggleChain(){chainOpen=!chainOpen;document.getElementById('chain-panel').classList.toggle('open',chainOpen);} async function runChain(){ if(isLoading){addSystemMsg('⚠ Please wait — another task is running.');return;} isLoading=true;document.getElementById('send-btn').disabled=true; const brief=document.getElementById('chain-brief').value.trim()||"Write a premium product spotlight for Ten Lei Yen's bird's nest, highlighting health benefits for the Vietnamese and Chinese-American community."; chainOutputLog=[];addSystemMsg(`⛓ Chain started: ${currentChain.map(k=>AGENTS[k].name).join(' → ')}`);let last=brief; for(let i=0;isetTimeout(r,300));} addSystemMsg(`⛓ Chain complete — ${chainOutputLog.length} agents ran.`); saveWorkflowSession('chain',brief,currentChain,chainOutputLog); isLoading=false;document.getElementById('send-btn').disabled=false; } function exportChain(){if(!chainOutputLog.length){addSystemMsg('⚠ Run a chain first.');return;}let doc=`ALINA CHAIN EXPORT\n${'═'.repeat(60)}\nGenerated: ${new Date().toLocaleString()}\nChain: ${chainOutputLog.map(c=>c.name).join(' → ')}\n${'═'.repeat(60)}`;chainOutputLog.forEach((c,i)=>{doc+=`STEP ${i+1}: ${c.emoji} ${c.name.toUpperCase()}\n${'─'.repeat(40)}\n${c.output}`;});downloadTxt(doc,`alina-chain-${Date.now()}.txt`);} function openBroadcast(){document.getElementById('broadcast-chips').innerHTML=Object.entries(AGENTS).map(([k,a])=>`
${a.emoji} ${a.name}
`).join('');openOverlay('broadcast-overlay');} async function runBroadcast(){ const msg=document.getElementById('broadcast-msg').value.trim();if(!msg)return; const sel=[...document.querySelectorAll('#broadcast-chips .agent-chip.sel')].map(c=>c.dataset.key);closeOverlay('broadcast-overlay'); addMsg('user',`[BROADCAST] ${msg}`);addSystemMsg(`⚡ Broadcasting to ${sel.length} agents: ${sel.map(k=>AGENTS[k].name).join(', ')}`); for(const k of sel){addTyping(k);try{const r=await callAgent(k,[{role:'user',content:`[BROADCAST — respond from your specialty angle only, be concise] ${msg}`}],500);removeTyping();addMsg('agent',r,k);saveSession(k,msg,r);}catch(e){removeTyping();addSystemMsg(`⚠ ${AGENTS[k].name}: ${e.message}`);}await new Promise(r=>setTimeout(r,150));} addSystemMsg(`⚡ Broadcast complete.`); } function exportChat(){const msgs=document.querySelectorAll('#messages .msg');let doc=`ALINA CHAT EXPORT\n${'═'.repeat(60)}\nAgent: ${AGENTS[currentAgent].name}\nExported: ${new Date().toLocaleString()}\n${'═'.repeat(60)}`;msgs.forEach(m=>{const meta=m.querySelector('.msg-who')?.textContent||'',bubble=m.querySelector('.msg-bubble')?.innerText||'';if(bubble&&bubble.trim().length>3)doc+=`[${meta}]\n${bubble}`;});downloadTxt(doc,`alina-chat-${currentAgent}-${Date.now()}.txt`);} function downloadTxt(content,filename){const a=document.createElement('a');a.href=URL.createObjectURL(new Blob([content],{type:'text/plain'}));a.download=filename;a.click();addSystemMsg(`⬇ Exported: ${filename}`);} let _summaryTimer=null; async function generateSummary(ak,um,ar){ if(_summaryTimer)clearTimeout(_summaryTimer); _summaryTimer=setTimeout(async()=>{ try{if(!sessionHistory.length)return;var newest=sessionHistory[0];if(newest.summary)return;var prompt=[{role:'user',content:'Summarize this conversation in under 8 words as a short title. Only output the summary title, nothing else. User said: '+um.substring(0,200)+' Assistant replied: '+ar.substring(0,200)}];var summary=await callAgent(ak,prompt,60);if(summary&&summary.length<80&&summary.length>2){newest.summary=summary.replace(/^["'\s]+|["'\s]+$/g,'');localStorage.setItem('alina_sessions',JSON.stringify(sessionHistory));if(typeof renderHistoryView==='function')renderHistoryView();}}catch(e){console.warn('Summary gen failed:',e);} },2000); } function saveSession(agentKey,userMsg,agentReply){const s={id:Date.now(),agent:agentKey,agentName:AGENTS[agentKey].name,emoji:AGENTS[agentKey].emoji,userMsg:userMsg.slice(0,120),agentReply:agentReply.slice(0,300),time:new Date().toLocaleString(),summary:''};sessionHistory.unshift(s);if(sessionHistory.length>200)sessionHistory=sessionHistory.slice(0,200);localStorage.setItem('alina_sessions', JSON.stringify(sessionHistory)\n );} function saveWorkflowSession(type,brief,steps,results){ var lastResult=results.length?results[results.length-1].output||results[results.length-1]:''; var stepsArr=steps.map(function(st){return typeof st==='string'?st:(st.agentKey||st.id||'')}); var agentNames=stepsArr.map(function(k){return AGENTS[k]?AGENTS[k].name:k}).join(' \u2192 '); var s={id:Date.now(),agent:stepsArr[0]||'alina',agentName:agentNames,emoji:type==='chain'?'\u26D3':'\uD83D\uDD00',userMsg:brief.slice(0,120),agentReply:typeof lastResult==='string'?lastResult.slice(0,300):JSON.stringify(lastResult).slice(0,300),time:new Date().toLocaleString(),summary:'',type:type,steps:results}; sessionHistory.unshift(s); if(sessionHistory.length>200)sessionHistory=sessionHistory.slice(0,200); localStorage.setItem('alina_sessions',JSON.stringify(sessionHistory)); if(typeof renderHistoryView==='function')renderHistoryView(); generateSummary(stepsArr[0]||'alina',brief,typeof lastResult==='string'?lastResult:JSON.stringify(lastResult)); } function renderHistoryView(){const el=document.getElementById('history-list');if(!sessionHistory.length){el.innerHTML='
No sessions yet — start chatting
';return;}el.innerHTML=sessionHistory.map(s=>{var preview=s.summary?esc(s.summary):(s.type==='chain'||s.type==='workflow'?('\u{1F4CB} '+esc(s.userMsg)):('You: '+esc(s.userMsg)));var excerpt=s.agentReply?esc((typeof s.agentReply==='string'?s.agentReply:'').substring(0,100)):'';return `
${s.emoji} ${s.agentName}
${s.time}
${preview}
${excerpt?'
'+excerpt+'
':''}
`;}).join('');} function resumeConversation(id){closeOverlay('history-overlay');var sessions=JSON.parse(localStorage.getItem('alina_sessions')||'[]');var s=sessions.find(function(x){return x.id===id});if(!s)return;var agentKey=s.agent;var agent=AGENTS[agentKey];if(!agent){addSystemMsg('Agent not found');return;}currentAgent=agentKey;document.getElementById('hdr-name').textContent=agent.name;document.getElementById('hdr-role').textContent=agent.fullRole||'';document.getElementById('hdr-avi').textContent=agent.emoji;document.getElementById('messages').innerHTML='';addMsg('user',s.userMsg,agentKey);addMsg('agent',s.agentReply,agentKey);var chatPill=document.querySelector('.nav-pill');switchView('chat',chatPill);addSystemMsg('Resumed conversation from '+s.time);} function resumeWorkflowConversation(id){ closeOverlay('history-overlay'); var sessions=JSON.parse(localStorage.getItem('alina_sessions')||'[]'); var s=sessions.find(function(x){return x.id===id}); if(!s)return; var isChain=s.type==='chain'; document.getElementById('messages').innerHTML=''; addSystemMsg((isChain?'\u26D3 Chain':'\uD83D\uDD00 Workflow')+' resumed: '+s.agentName); addMsg('user',s.userMsg,s.agent); if(s.steps&&s.steps.length){ s.steps.forEach(function(st,i){ var agentName=st.name||st.agent||(AGENTS[st.agentKey]?AGENTS[st.agentKey].name:'Agent '+(i+1)); var agentKey=st.agentKey||s.agent; var result=st.output||st.result||st; addSystemMsg('Step '+(i+1)+': '+agentName); addMsg('agent',typeof result==='string'?result:JSON.stringify(result),agentKey); }); } else { addMsg('agent',s.agentReply,s.agent); } currentAgent=s.agent; var agent=AGENTS[s.agent]; if(agent){ document.getElementById('hdr-name').textContent=agent.name; document.getElementById('hdr-role').textContent=agent.fullRole||''; document.getElementById('hdr-avi').textContent=agent.emoji; } var chatPill=document.querySelector('.nav-pill'); switchView('chat',chatPill); addSystemMsg('You can continue chatting with '+((agent&&agent.name)||'the agent')+' from here.'); } function showHistoryDetail(id){ var sessions=JSON.parse(localStorage.getItem('alina_sessions')||'[]'); var s=sessions.find(function(x){return x.id===id}); if(!s)return; document.getElementById('hist-detail-title').textContent=s.summary||s.agentName||'Conversation'; var body=''; if(s.type==='chain'||s.type==='workflow'){ body+='
'+(s.type==='chain'?'\u26D3 Chain':'\uD83D\uDD00 Workflow')+' \u2022 '+s.agentName+'
'; if(s.steps&&s.steps.length){ s.steps.forEach(function(st,i){ var agentName=st.name||st.agent||(AGENTS[st.agentKey]?AGENTS[st.agentKey].name:'Agent '+(i+1)); var result=st.output||st.result||st; body+='
Step '+(i+1)+': '+esc(agentName)+'
'+fmt(typeof result==='string'?result:JSON.stringify(result))+'
'; }); } else { body+='
'+fmt(s.agentReply)+'
'; } } else { body+='
'+esc(s.agentName)+' \u2022 '+s.time+'
'; body+='
You: '+esc(s.userMsg)+'
'; body+='
'+fmt(s.agentReply)+'
'; } body+='
'; if(s.type==='chain'||s.type==='workflow'){ body+=''; } else { body+=''; } body+='
'; document.getElementById('hist-detail-body').innerHTML=body; openOverlay('history-overlay'); } function clearHistory(){if(!confirm('Clear all session history?'))return;sessionHistory=[];localStorage.removeItem('alina_sessions');renderHistoryView();} function loadKeys(){['claude','gpt','gemini','grok'].forEach(m=>{const v=localStorage.getItem('alina_key_'+m),el=document.getElementById('key-'+m),ks=document.getElementById('ks-'+m);if(el&&v)el.value=v;if(ks){ks.textContent=v?'✓':'—';ks.style.color=v?'#16a34a':'var(--text4)';}});const bi=document.getElementById('brain-input');if(bi)bi.value=brainMemory;const bti=document.getElementById('brain-tags-input');if(bti)bti.value=brainTags.join(', ');} function saveSettings(){['claude','gpt','gemini','grok'].forEach(m=>{const v=document.getElementById('key-'+m)?.value?.trim();if(v)localStorage.setItem('alina_key_'+m,v);const ks=document.getElementById('ks-'+m);if(ks){const has=!!localStorage.getItem('alina_key_'+m);ks.textContent=has?'✓':'—';ks.style.color=has?'#16a34a':'var(--text4)';}});const b=document.getElementById('brain-input')?.value?.trim();if(b){brainMemory=b;localStorage.setItem('alina_brain', b);}const bt=document.getElementById('brain-tags-input')?.value?.trim();if(bt){brainTags=bt.split(',').map(t=>t.trim()).filter(Boolean);localStorage.setItem('alina_brain_tags',bt);renderBrainPills();}closeOverlay('settings-overlay');addSystemMsg('✓ Settings saved. All agents updated.');} function openSettings(){loadKeys();openOverlay('settings-overlay');} function openOverlay(id){document.getElementById(id).classList.add('open');} function closeOverlay(id){document.getElementById(id).classList.remove('open');} function closeBgOverlay(e,id){if(e.target===document.getElementById(id))closeOverlay(id);} // WORKFLOW let wfNodes=[],wfNextId=0,dragAgentKey=null,dragNode=null,dragOffX=0,dragOffY=0,connectingFrom=null,wfConnections=[]; function buildWfSidebar(){document.getElementById('wf-agent-cards').innerHTML=Object.entries(AGENTS).map(([k,a])=>`
${a.emoji}
${a.name}
${a.role}
`).join('');} function dropOnCanvas(e){if(!dragAgentKey)return;const c=document.getElementById('wf-canvas'),r=c.getBoundingClientRect();addWfNode(dragAgentKey,Math.max(10,e.clientX-r.left+c.scrollLeft-90),Math.max(10,e.clientY-r.top+c.scrollTop-40));dragAgentKey=null;} function addWfNode(ak,x,y){ const a=AGENTS[ak],id=wfNextId++,mc={claude:'var(--claude)',gpt:'var(--gpt)',gemini:'var(--gemini)',grok:'var(--grok)'}[a.model]; wfNodes.push({id,agentKey:ak,x,y});document.getElementById('wf-empty').style.display='none'; const el=document.createElement('div');el.className='wf-node';el.id=`wf-node-${id}`;el.style.left=x+'px';el.style.top=y+'px'; el.innerHTML=`
${a.emoji}
${a.name}
${a.role}
${a.model.toUpperCase()}
`; el.addEventListener('mousedown',e=>{if(e.target.tagName==='BUTTON'||e.target.isContentEditable)return;dragNode={id,el};const r=el.getBoundingClientRect();dragOffX=e.clientX-r.left;dragOffY=e.clientY-r.top;el.style.zIndex=20;e.preventDefault();}); document.getElementById('wf-canvas').appendChild(el);updateWfStatus();drawConnectors(); } document.addEventListener('mousemove',e=>{if(!dragNode)return;const c=document.getElementById('wf-canvas'),r=c.getBoundingClientRect();const x=e.clientX-r.left+c.scrollLeft-dragOffX,y=e.clientY-r.top+c.scrollTop-dragOffY;dragNode.el.style.left=Math.max(0,x)+'px';dragNode.el.style.top=Math.max(0,y)+'px';const n=wfNodes.find(n=>n.id===dragNode.id);if(n){n.x=x;n.y=y;}drawConnectors();}); document.addEventListener('mouseup',()=>{if(dragNode){dragNode.el.style.zIndex=10;dragNode=null;}}); function startConnect(fromId){if(connectingFrom===null){connectingFrom=fromId;document.getElementById(`wf-node-${fromId}`).classList.add('sel');updateWfStatus(`Click ⛓ on another node to connect from ${AGENTS[wfNodes.find(n=>n.id===fromId)?.agentKey]?.name}…`);}else{if(connectingFrom!==fromId)wfConnections.push({from:connectingFrom,to:fromId});document.getElementById(`wf-node-${connectingFrom}`)?.classList.remove('sel');connectingFrom=null;drawConnectors();updateWfStatus();}} function drawConnectors(){const svg=document.getElementById('wf-connectors');svg.innerHTML='';wfConnections.forEach(c=>{const fn=wfNodes.find(n=>n.id===c.from),tn=wfNodes.find(n=>n.id===c.to);if(!fn||!tn)return;const x1=fn.x+180,y1=fn.y+42,x2=tn.x,y2=tn.y+42,mx=(x1+x2)/2;const path=document.createElementNS('http://www.w3.org/2000/svg','path');path.setAttribute('d',`M${x1},${y1} C${mx},${y1} ${mx},${y2} ${x2},${y2}`);path.setAttribute('stroke','var(--navy)');path.setAttribute('stroke-width','2');path.setAttribute('fill','none');path.setAttribute('stroke-dasharray','6,3');path.setAttribute('opacity','0.5');const arr=document.createElementNS('http://www.w3.org/2000/svg','polygon');arr.setAttribute('points',`${x2},${y2} ${x2-10},${y2-5} ${x2-10},${y2+5}`);arr.setAttribute('fill','var(--navy)');arr.setAttribute('opacity','0.6');svg.appendChild(path);svg.appendChild(arr);});} function removeWfNode(id){wfNodes=wfNodes.filter(n=>n.id!==id);wfConnections=wfConnections.filter(c=>c.from!==id&&c.to!==id);document.getElementById(`wf-node-${id}`)?.remove();if(!wfNodes.length)document.getElementById('wf-empty').style.display='flex';drawConnectors();updateWfStatus();} function clearCanvas(){wfNodes=[];wfConnections=[];wfNextId=0;document.querySelectorAll('.wf-node').forEach(n=>n.remove());document.getElementById('wf-empty').style.display='flex';document.getElementById('wf-connectors').innerHTML='';updateWfStatus('Drop agents to build a workflow');} function autoLayout(){if(!wfNodes.length)return;const cols=Math.ceil(Math.sqrt(wfNodes.length));wfNodes.forEach((n,i)=>{n.x=30+i%cols*210;n.y=30+Math.floor(i/cols)*155;const el=document.getElementById(`wf-node-${n.id}`);if(el){el.style.left=n.x+'px';el.style.top=n.y+'px';}});if(!wfConnections.length&&wfNodes.length>1)for(let i=0;i!wfConnections.find(c=>c.to===n.id));let cur=starts[0]||wfNodes[0];const visited=new Set();while(cur&&!visited.has(cur.id)){order.push(cur);visited.add(cur.id);const nx=wfConnections.find(c=>c.from===cur.id);cur=nx?wfNodes.find(n=>n.id===nx.to):null;}wfNodes.filter(n=>!visited.has(n.id)).forEach(n=>order.push(n));}else order=[...wfNodes]; wfOutput=[];switchView('chat',document.querySelectorAll('.nav-pill')[0]);addSystemMsg(`🔀 Workflow: ${order.map(n=>AGENTS[n.agentKey].name).join(' → ')}`);let last=prompt; for(let i=0;isetTimeout(r,300));} addSystemMsg(`🔀 Workflow complete — ${wfOutput.length} agents ran.`); saveWorkflowSession('workflow',prompt,wfNodes,wfOutput); } function exportWorkflowOutput(){if(!wfOutput.length){addSystemMsg('⚠ Run a workflow first.');return;}let doc=`ALINA WORKFLOW EXPORT\n${'═'.repeat(60)}\nGenerated: ${new Date().toLocaleString()}\nWorkflow: ${wfOutput.map(c=>c.name).join(' → ')}\n${'═'.repeat(60)}`;wfOutput.forEach((c,i)=>{doc+=`STEP ${i+1}: ${c.emoji} ${c.name.toUpperCase()}\n${'─'.repeat(40)}\n${c.output}`;});downloadTxt(doc,`alina-workflow-${Date.now()}.txt`);} function handleKey(e){if(e.key==='Enter'&&!e.shiftKey){e.preventDefault();sendMessage();}} function autoResize(el){el.style.height='auto';el.style.height=Math.min(el.scrollHeight,140)+'px';} function fillHint(t){const i=document.getElementById('chat-input');i.value=t;autoResize(i);i.focus();} // LOGIN async function hashPassword(pw){const enc=new TextEncoder(),buf=await crypto.subtle.digest('SHA-256',enc.encode(pw+'alina_salt_v2'));return Array.from(new Uint8Array(buf)).map(b=>b.toString(16).padStart(2,'0')).join('');} function showStep(id){document.getElementById('step-login').style.display=id==='step-login'?'block':'none';document.getElementById('step-setup').style.display=id==='step-setup'?'block':'none';} function {if(sessionStorage.getItem('alina_unlocked')==='1'){unlockApp();return;}const has=!!"be6d1d359f9cc69d857039a04f61b66f31c32e2aec5c5d2341eeb0c8fb293d81";if(!has){showStep('step-login');setTimeout(()=>document.getElementById('setup-pw1').focus(),100);}else{showStep('step-login');setTimeout(()=>document.getElementById('login-pw').focus(),100);}} async function setupPassword(){const pw1=document.getElementById('setup-pw1').value,pw2=document.getElementById('setup-pw2').value,err=document.getElementById('setup-err');if(pw1.length<8){err.textContent='Password must be at least 8 characters';shake();return;}if(pw1!==pw2){err.textContent='Passwords do not match';shake();return;}err.textContent='';const hash=await hashPassword(pw1);localStorage.setItem('alina_pw_hash',hash);unlockApp();} async function checkPassword(){const pw=document.getElementById('login-pw').value,stored="be6d1d359f9cc69d857039a04f61b66f31c32e2aec5c5d2341eeb0c8fb293d81",err=document.getElementById('login-err');if(!pw)return;if(await hashPassword(pw)===stored||await hashPassword(pw)===(localStorage.getItem('alina_pw_hash')||'')){err.textContent='';unlockApp();}else{err.textContent='Incorrect password';shake();document.getElementById('login-pw').value='';}} function unlockApp(){document.getElementById('login-screen').classList.add('gone');document.getElementById('app').classList.add('visible');document.title='Alina — Ten Lei Yến AI Command Center';sessionStorage.setItem('alina_unlocked','1');init();} function shake(){const c=document.getElementById('login-card');c.classList.remove('shake');void c.offsetWidth;c.classList.add('shake');} window.alinaReset=function(){if(confirm('Reset ALINA password? You will need to create a new one.')){localStorage.removeItem('alina_pw_hash');alert('Password reset. Reload the page to set a new one.');location.reload();}}; // ══════════════════════════════════════════ // SPEECH TO TEXT — Web Speech API // ══════════════════════════════════════════ let recognition=null,isRecording=false,micTargetInput='chat-input',micTargetBtn='mic-btn'; function initSpeechRecognition(){ const SR=window.SpeechRecognition||window.webkitSpeechRecognition; if(!SR){console.warn('Speech recognition not supported');return;} recognition=new SR(); recognition.continuous=true; recognition.interimResults=true; recognition.lang='en-US'; let finalTranscript=''; recognition.onresult=function(e){ let interim=''; for(let i=e.resultIndex;i' +'' +'' +data.map(function(v,i){return '';}).join(''); svg.querySelectorAll('.seo-hdot').forEach(function(d){ d.addEventListener('mouseenter',function(){d.setAttribute('opacity','1');}); d.addEventListener('mouseleave',function(){d.setAttribute('opacity','0');}); }); if (lel) lel.innerHTML = SEO_MONTHS.map(function(m){return ''+m+'';}).join(''); } function seoSpark(data) { var W=60,H=22,p=2,mn=Math.min.apply(null,data),mx=Math.max.apply(null,data),r=mx-mn||1; var xs=data.map(function(_,i){return p+(i/(data.length-1))*(W-p*2);}); var ys=data.map(function(v){return p+(1-(v-mn)/r)*(H-p*2);}); return ''; } var SEO_KW_COLOR = {gold:'#B89A4E'}; function seoKdCol(n){return n<=15?'#16a34a':n<=30?'#B89A4E':n<=50?'#9a7e3a':'#dc2626';} function seoPcls(p){return p===1||p<=3?'seo-p1':p<=10?'seo-p2':p<=20?'seo-p3':'seo-p4';} var seoKwSort = {col:-1,dir:1}; function seoRenderKw(data) { var tb = document.getElementById('seo-kw-body'); if (!tb) return; tb.innerHTML = data.map(function(k){ return '' +''+k.kw+'' +''+k.pos+'' +'
'+k.kd+'
' +''+k.vol.toLocaleString()+'' +'$'+k.cpc.toFixed(2)+'' +''+seoSpark(k.trend)+'' +''; }).join(''); } function seoFilterKw(q) { seoRenderKw(q ? SEO_KW.filter(function(k){return k.kw.indexOf(q.toLowerCase())>-1;}) : SEO_KW); } function seoSortKw(col, th) { var ths = th.closest('thead').querySelectorAll('th'); ths.forEach(function(h){h.classList.remove('sa','sd');}); seoKwSort.dir = seoKwSort.col === col ? seoKwSort.dir * -1 : 1; seoKwSort.col = col; th.classList.add(seoKwSort.dir === 1 ? 'sa' : 'sd'); var keys = ['kw','pos','kd','vol','cpc']; var sorted = SEO_KW.slice().sort(function(a,b){ return (a[keys[col]] > b[keys[col]] ? 1 : -1) * seoKwSort.dir; }); seoRenderKw(sorted); } function seoRenderBL() { var el = document.getElementById('seo-bl-list'); if (!el) return; el.innerHTML = SEO_BL.map(function(b){ return '
' +'
'+b.fav+'
' +'
'+b.dom+'
' +'
'+b.anchor+'
' +'
DR '+b.dr+'
' +'
'+(b.follow?'follow':'nofollow')+'
' +'
'+b.date+'
' +'
'; }).join(''); } function seoRenderPages() { var el = document.getElementById('seo-pages-list'); if (!el) return; el.innerHTML = SEO_PAGES.map(function(p){ return '
' +'
'+p.url+'
' +'
'+p.traffic.toLocaleString()+'
' +'
' +'
'+p.kws+'
' +'
'; }).join(''); } function seoRenderComp() { var el = document.getElementById('seo-comp-list'); if (!el) return; el.innerHTML = SEO_COMP.map(function(c,i){ return '
' +'
'+(i+1)+'
' +'
'+c.dom+(c.you?'YOU':'')+'
' +'
'+c.traffic.toLocaleString()+'
' +'
'+c.kws+'
' +'
' +'
'; }).join(''); setTimeout(function(){ document.querySelectorAll('.seo-cmpfill').forEach(function(f){f.style.width=f.dataset.p+'%';}); }, 120); } function seoInitCharts() { seoChart('seo-tchart','seo-tlabels', SEO_TRAFFIC, '#B89A4E'); seoChart('seo-rchart','seo-rlabels', SEO_REFDOMS, '#3a5a9e'); document.querySelectorAll('.seo-pfill').forEach(function(f){f.style.width=f.dataset.w+'%';}); seoRenderKw(SEO_KW); seoRenderBL(); seoRenderPages(); seoRenderComp(); } function setSeoTab(btn, paneId) { document.querySelectorAll('.seo-stab').forEach(function(b){b.classList.remove('active');}); document.querySelectorAll('.seo-tab-pane').forEach(function(p){p.style.display='none';p.classList.remove('active');}); btn.classList.add('active'); var pane = document.getElementById(paneId); if (pane) { pane.style.display='block'; pane.classList.add('active'); } if (paneId === 'seo-competitors') { setTimeout(function(){document.querySelectorAll('.seo-cmpfill').forEach(function(f){f.style.width=f.dataset.p+'%';});},100); } } function setSeoMode(btn) { btn.parentElement.querySelectorAll('button').forEach(function(b){ b.style.background='none'; b.style.color='var(--text3)'; }); btn.style.background='var(--blue-pale)'; btn.style.color='var(--navy)'; } function setSeoDate(btn) { btn.parentElement.querySelectorAll('button').forEach(function(b){ b.style.background='none'; b.style.color='var(--text3)'; b.style.borderColor='var(--border2)'; b.style.fontWeight='normal'; }); btn.style.background='var(--blue-pale)'; btn.style.color='var(--navy)'; btn.style.borderColor='var(--border3)'; btn.style.fontWeight='700'; } async function flashSeoSearch(btn) { const domainEl = document.getElementById('seo-url-input') || document.querySelector('#view-seo input[type="text"]'); const domain = domainEl ? domainEl.value.trim() : 'tenleiyen.com'; const apiKey = localStorage.getItem('alina_key_claude'); if (!apiKey) { alert('Add Claude API key in API Keys & Brain.'); return; } btn.textContent = 'SEARCHING...'; btn.disabled = true; const loadEl = document.getElementById('seo-loading'); const lastEl = document.getElementById('seo-last-crawl'); if (loadEl) { loadEl.style.display='inline'; loadEl.textContent='pulling live data...'; } function setSeoMetric(labelText, val) { if (val === null || val === undefined || val === '') return; var seoV = document.getElementById('view-seo'); if (!seoV) return; var lbl = [...seoV.querySelectorAll('.seo-mlbl')].find(el => el.textContent.trim() === labelText); if (!lbl) return; var card = lbl.closest('.seo-mc') || lbl.parentElement; var valEl = card ? card.querySelector('.seo-mval') : null; if (valEl) valEl.textContent = val; } try { const resp = await fetch('https://api.anthropic.com/v1/messages', { method: 'POST', headers: {'Content-Type':'application/json','x-api-key':apiKey,'anthropic-version':'2023-06-01','anthropic-dangerous-direct-browser-access':'true'}, body: JSON.stringify({ model: 'claude-sonnet-4-20250514', max_tokens: 800, tools: [{ type: 'web_search_20250305', name: 'web_search' }], system: 'You are an SEO data assistant. Search for current SEO metrics for the given domain. Return ONLY valid JSON starting with {. Use real numbers. If exact data unavailable give reasonable estimates. NEVER return 0 or null. Keys: domain_rating (int), ahrefs_rank (string like #1.8M), organic_traffic (int), referring_domains (int), backlinks (int), backlink_change (string), traffic_change (string).', messages: [{ role:'user', content:'SEO metrics for '+domain+'. Return JSON only.' }] }) }); const data = await resp.json(); if (data.error) throw new Error(data.error.message); const raw = (data.content||[]).filter(b=>b.type==='text').map(b=>b.text).join(''); const s = raw.indexOf('{'), e = raw.lastIndexOf('}'); if (s===-1) throw new Error('No JSON returned'); const d = JSON.parse(raw.substring(s,e+1)); if (d.domain_rating != null) setSeoMetric('Domain Rating', String(d.domain_rating)); if (d.ahrefs_rank != null) setSeoMetric('Ahrefs Rank', d.ahrefs_rank); if (d.organic_traffic != null) setSeoMetric('Organic Traffic', Number(d.organic_traffic).toLocaleString()); if (d.referring_domains != null) setSeoMetric('Referring Domains', Number(d.referring_domains).toLocaleString()); if (d.backlinks != null) setSeoMetric('Backlinks', Number(d.backlinks).toLocaleString()); const now = new Date(); const ts = now.toLocaleDateString('en-US',{month:'short',day:'numeric',year:'numeric'})+' '+now.toLocaleTimeString('en-US',{hour:'2-digit',minute:'2-digit'}); if (lastEl) lastEl.textContent = ts; localStorage.setItem('seo_last_data_'+domain, JSON.stringify({data:d,ts})); if (loadEl) loadEl.textContent = 'updated'; } catch(err) { if (lastEl) lastEl.textContent = 'Error: '+err.message.substring(0,60); console.error('SEO error:', err); } finally { btn.textContent = 'Search'; btn.disabled = false; setTimeout(()=>{ if(loadEl) loadEl.style.display='none'; }, 4000); } } // Patch switchView to init SEO charts on first open var _origSwitchView = switchView; switchView = function(v, btn) { _origSwitchView(v, btn); if (v === 'seo') { setTimeout(seoInitCharts, 80); // Restore cached SEO data const domain = 'tenleiyen.com'; const cached = localStorage.getItem('seo_last_data_' + domain); if (cached) { try { const {data: d, ts} = JSON.parse(cached); const lastEl = document.getElementById('seo-last-crawl'); if (lastEl) lastEl.textContent = ts; } catch(e) {} } } }; function initLogin(){ var stored=localStorage.getItem("alina_pw_hash"); if(stored){ document.getElementById("app").style.display="flex"; var ls=document.getElementById("login-screen"); if(ls) ls.style.display="none"; } } function checkLogin(){ var pw=document.getElementById("login-pw").value; var hash=Array.from(new Uint8Array(new TextEncoder().encode(pw))).map(b=>b.toString(16).padStart(2,"0")).join(""); // Simple check - hash against stored var stored=localStorage.getItem("alina_pw_hash"); if(!stored){ // First time - sha256 the password crypto.subtle.digest("SHA-256",new TextEncoder().encode(pw)).then(function(buf){ var hex=Array.from(new Uint8Array(buf)).map(b=>b.toString(16).padStart(2,"0")).join(""); if(hex==="be6d1d359f9cc69d857039a04f61b66f31c32e2aec5c5d2341eeb0c8fb293d81"){ localStorage.setItem("alina_pw_hash",hex); document.getElementById("app").style.display="flex"; var ls=document.getElementById("login-screen"); if(ls) ls.style.display="none"; } else { alert("Incorrect password"); } }); } else if(stored==="be6d1d359f9cc69d857039a04f61b66f31c32e2aec5c5d2341eeb0c8fb293d81"){ document.getElementById("app").style.display="flex"; var ls=document.getElementById("login-screen"); if(ls) ls.style.display="none"; } }
'; return; } document.getElementById('meta-entries').innerHTML = '
Loading ' + type + ' entries…
'; // Actual Shopify Metaobject API requires GraphQL Admin API // Show a helpful note with the correct endpoint setTimeout(() => { document.getElementById('meta-entries').innerHTML = `
Metaobject editing via API requires GraphQL Admin API access (not REST). Paste your store's metaobject IDs below, or manage them via Shopify Admin → Content → Metaobjects →. Full GraphQL metaobject editor coming in the next update.
`; }, 600); } function metaNew() { alert('New metaobject entry: coming in next update. For now, use @rex or @forge in Chat to generate metaobject schemas and Liquid code.'); } // Unified switchView — handles all 7 tabs cleanly window.switchView = function(v, btn) { // Clear ALL views: remove active class AND inline display styles document.querySelectorAll('.view').forEach(x => { x.classList.remove('active'); x.style.display = ''; }); document.querySelectorAll('.nav-pill').forEach(b => b.classList.remove('active')); // Activate target view const viewEl = document.getElementById('view-' + v); if (viewEl) viewEl.classList.add('active'); if (btn) btn.classList.add('active'); // Tab-specific init if (v === 'history') renderHistoryView(); if (v === 'seo') { if(typeof initSEO === 'function') initSEO(); } if (v === 'shopify') { const t = localStorage.getItem('shp_token'); if (t) { const domEl = document.getElementById('shp-domain'); const tokEl = document.getElementById('shp-token'); if (domEl) { const d = localStorage.getItem('shp_domain'); if(d) domEl.value = d; } if (tokEl) tokEl.value = t; const note = document.getElementById('shp-cfg-note'); if (note) note.style.display = 'none'; if (typeof shpRefresh === 'function') shpRefresh(); } } };