mirror of
https://github.com/multipleof4/devsune.git
synced 2026-01-14 08:27:55 +00:00
Update index.html
This commit is contained in:
22
index.html
22
index.html
@@ -6,15 +6,7 @@
|
||||
<script src="https://cdn.tailwindcss.com"></script>
|
||||
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/github-markdown-css@5.5.1/github-markdown-light.min.css"/>
|
||||
<link rel="stylesheet" href="https://cdn.jsdelivr.net/gh/highlightjs/cdn-release@11.9.0/build/styles/github.min.css"/>
|
||||
<style>
|
||||
.markdown-body{font-size:14px;line-height:1.6}.markdown-body pre{overflow:auto}
|
||||
.msg-bubble{overflow-x:auto}
|
||||
.copy-btn{position:absolute;top:.5rem;right:.5rem;background:#0f172a;color:#fff;border-radius:.5rem;padding:.25rem .5rem;font-size:12px;opacity:.85}
|
||||
.msg-avatar{font-size:16px}
|
||||
.menu-card{position:fixed;z-index:60;min-width:12rem;border-radius:0.75rem;border:1px solid #e5e7eb;background:#fff;box-shadow:0 10px 20px rgba(0,0,0,.08)}
|
||||
.menu-item{width:100%;text-align:left;padding:.5rem .75rem;font-size:.875rem;display:flex;align-items:center;gap:.5rem}
|
||||
#scriptEditor,#htmlEditor{outline:none}
|
||||
</style>
|
||||
<style>.markdown-body{font-size:14px;line-height:1.6}.markdown-body pre{overflow:auto}.msg-bubble{overflow-x:auto}.copy-btn{position:absolute;top:.5rem;right:.5rem;background:#0f172a;color:#fff;border-radius:.5rem;padding:.25rem .5rem;font-size:12px;opacity:.85}.msg-avatar{font-size:16px}.menu-card{position:fixed;z-index:60;min-width:12rem;border-radius:0.75rem;border:1px solid #e5e7eb;background:#fff;box-shadow:0 10px 20px rgba(0,0,0,.08)}.menu-item{width:100%;text-align:left;padding:.5rem .75rem;font-size:.875rem;display:flex;align-items:center;gap:.5rem}#scriptEditor,#htmlEditor{outline:none}</style>
|
||||
<script src="https://unpkg.com/htmx.org@1.9.12"></script>
|
||||
</head>
|
||||
<body class="bg-white text-gray-900 selection:bg-black/10" hx-on="click: if(!document.getElementById('historyMenu').contains(event.target)&&!event.target.closest('[data-thread-menu]')) hideHistoryMenu(); if(!document.getElementById('suneMenu').contains(event.target)&&!event.target.closest('[data-sune-menu]')) hideSuneMenu(); if(!document.getElementById('userMenu').contains(event.target)&&!document.getElementById('userMenuBtn').contains(event.target)) document.getElementById('userMenu').classList.add('hidden')">
|
||||
@@ -168,15 +160,7 @@ el.historyMenu.addEventListener('click',async e=>{const act=e.target.closest('[d
|
||||
el.suneList.addEventListener('click',e=>{const menuBtn=e.target.closest('[data-sune-menu]');if(menuBtn){e.stopPropagation();showSuneMenu(menuBtn,menuBtn.getAttribute('[data-sune-menu]')?menuBtn.getAttribute('[data-sune-menu]'):menuBtn.getAttribute('data-sune-menu'));return}const btn=e.target.closest('[data-sune-id]');if(!btn)return;const id=btn.getAttribute('data-sune-id');if(id){su.setActiveId(id);renderSidebar();reflectActiveSune();state.currentThreadId=null;clearChat();document.getElementById('sidebar').classList.add('-translate-x-full');document.getElementById('sidebarOverlay').classList.add('hidden')}})
|
||||
el.suneMenu.addEventListener('click',e=>{const act=e.target.closest('[data-action]')?.getAttribute('data-action');if(!act||!menuSuneId)return;const s=sunes.find(x=>x.id===menuSuneId);if(!s)return;if(act==='pin')s.pinned=!s.pinned;else if(act==='rename'){const nv=prompt('Rename sune to:',s.name);if(nv!=null)s.name=nv.trim()}else if(act==='pfp'){const url=prompt('Image URL:',s.avatar||'');if(url!==null)s.avatar=url.trim()}s.updatedAt=Date.now();su.save(sunes);hideSuneMenu();renderSidebar();reflectActiveSune()})
|
||||
function updateAttachBadge(){const n=state.attachments.length;el.attachBadge.textContent=String(n);el.attachBadge.classList.toggle('hidden',n===0)}
|
||||
async function toAttach(file){if(file instanceof File){const name=file.name||'file',mime=(file.type||'application/octet-stream').toLowerCase(),bytes=file.size||0; if(/^image\//.test(mime)||/\.(png|jpe?g|webp|gif)$/i.test(name)){const data=await asDataURL(file);return {name,bytes,mime,data,mode:'dataURL',part:{type:'image_url',image_url:{url:data}}}
|
||||
} if(mime==='application/pdf'||/\.pdf$/i.test(file.name||'')){const data=await asDataURL(file);return {name:file.name||'file.pdf',bytes:file.size||0,mime:'application/pdf',data:b64(data),mode:'base64',part:{type:'file',file:{filename:file.name||'file.pdf',file_data:b64(data)}}}
|
||||
} if(/^audio\//.test(mime)||/\.(wav|mp3)$/i.test(file.name||'')){const data=await asDataURL(file);let fmt=/mp3/.test(mime)||/\.mp3$/i.test(file.name||'')?'mp3':'wav';return {name:file.name||'audio.'+fmt,bytes:file.size||0,mime:mime,data:b64(data),mode:'base64',part:{type:'input_audio',input_audio:{data:b64(data),format:fmt}}}
|
||||
} return null}
|
||||
if(file&&file.name==null&&file.data){const name=file.name||'file',mime=(file.mime||'application/octet-stream').toLowerCase(),bytes=file.size||0; if(/^image\//.test(mime)){const data=`data:${mime};base64,${file.data}`;return {name,bytes,mime,data,mode:'dataURL',part:{type:'image_url',image_url:{url:data}}}
|
||||
} if(mime==='application/pdf'){return {name,bytes,mime,data:file.data,mode:'base64',part:{type:'file',file:{filename:name,file_data:file.data}}}
|
||||
} if(/^audio\//.test(mime)){let fmt=/mp3/.test(mime)?'mp3':'wav';return {name,bytes,mime,data:file.data,mode:'base64',part:{type:'input_audio',input_audio:{data:file.data,format:fmt}}}
|
||||
} return {name,bytes,mime,data:file.data,mode:'base64',part:{type:'file',file:{filename:name,file_data:file.data}}}}
|
||||
return null}
|
||||
async function toAttach(file){if(!file)return null;let name='file',mime='application/octet-stream',bytes=0,data='',mode='',part=null;if(file instanceof File){name=file.name||name;mime=(file.type||mime).toLowerCase();bytes=file.size||0;if(/^image\//.test(mime)||/\.(png|jpe?g|webp|gif)$/i.test(name)){data=await asDataURL(file);mode='dataURL';part={type:'image_url',image_url:{url:data}}}else if(mime==='application/pdf'||/\.pdf$/i.test(name)){const d=await asDataURL(file);data=b64(d);mode='base64';part={type:'file',file:{filename:name||'file.pdf',file_data:data}};mime='application/pdf';if(!/\.pdf$/i.test(name))name='file.pdf'}else if(/^audio\//.test(mime)||/\.(wav|mp3)$/i.test(name)){const d=await asDataURL(file);data=b64(d);mode='base64';const fmt=/mp3/.test(mime)||/\.mp3$/i.test(name)?'mp3':'wav';part={type:'input_audio',input_audio:{data,format:fmt}}}else{const d=await asDataURL(file);data=b64(d);mode='base64';part={type:'file',file:{filename:name,file_data:data}}}}else if(file&&file.data){name=file.name||name;mime=(file.mime||mime).toLowerCase();bytes=file.size||0;data=file.data;if(/^image\//.test(mime)){data=`data:${mime};base64,${data}`;mode='dataURL';part={type:'image_url',image_url:{url:data}}}else if(mime==='application/pdf'){mode='base64';part={type:'file',file:{filename:name,file_data:data}}}else if(/^audio\//.test(mime)){mode='base64';part={type:'input_audio',input_audio:{data,format:/mp3/.test(mime)?'mp3':'wav'}}}else{mode='base64';part={type:'file',file:{filename:name,file_data:data}}}}return part?{name,bytes,mime,data,mode,part}:null}
|
||||
function attachmentsText(id,arr){const head='**Attachments**',list=arr.map((a,i)=>`- [${esc(a.name)} • ${fmtSize(a.bytes)}](#dl-${id}-${i})`).join('\n');return head+'\n'+list}
|
||||
function addAttachmentTree(role,arr){if(!arr?.length)return;const id=gid(),text=attachmentsText(id,arr),meta={role,content:[{type:'text',text}],id,kind:'attachments',attachmentsMeta:arr.map(a=>({name:a.name,bytes:a.bytes,mime:a.mime,mode:a.mode,data:a.mode==='dataURL'?a.data:a.data}))};const b=addMessage(meta,true);b.dataset.mid=id}
|
||||
el.attachBtn.addEventListener('click',()=>{if(state.busy)return;if(state.attachments.length){state.attachments=[];updateAttachBadge();el.fileInput.value=''};el.fileInput.click()})
|
||||
@@ -214,7 +198,7 @@ el.importInput.addEventListener('change',async()=>{const file=el.importInput.fil
|
||||
function kbUpdate(){const vv=window.visualViewport;const overlap=vv?Math.max(0,(window.innerHeight-(vv.height+vv.offsetTop))):0;document.documentElement.style.setProperty('--kb',overlap+'px');const fh=el.footer.getBoundingClientRect().height;document.documentElement.style.setProperty('--footer-h',fh+'px');el.footer.style.transform='translateY('+(-overlap)+'px)';el.chat.style.scrollPaddingBottom=(fh+overlap+16)+'px'}
|
||||
function kbBind(){if(window.visualViewport){['resize','scroll'].forEach(ev=>visualViewport.addEventListener(ev,()=>kbUpdate(),{passive:true}))}['resize','orientationchange'].forEach(ev=>window.addEventListener(ev,()=>setTimeout(kbUpdate,50),{passive:true}));['focus','click'].forEach(ev=>el.input.addEventListener(ev,()=>{setTimeout(()=>{kbUpdate();el.input.scrollIntoView({block:'nearest',behavior:'smooth'})},0)}))}
|
||||
function activeMeta(){const a=getActiveSune();return {sune_name:a.name,model:store.model,avatar:a.avatar||''}}
|
||||
window.suneAttach=async(files,opts={toAPI:true,tree:true})=>{const arr=[];for(const f of files||[])arr.push(await toAttach(f));const clean=arr.filter(Boolean);if(!clean.length)return;const meta=activeMeta();if(opts.toAPI){const m={role:'assistant',content:[{type:'text',text:'(files attached)'}],...meta};addMessage(m);state.messages.push(m)} if(opts.tree)addAttachmentTree('assistant',clean);await persistThread()}
|
||||
window.SUNE={attach:async(files,opts={toapi:true,tree:true})=>{const arr=[];for(const f of files||[])arr.push(await toAttach(f));const clean=arr.filter(Boolean);if(!clean.length)return;const toApi=('toapi'in opts)?!!opts.toapi:('toAPI'in opts?!!opts.toAPI:true),showTree=('tree'in opts)?!!opts.tree:true;await ensureThreadOnFirstUser('(attachments)');const meta=activeMeta();if(toApi){const m={role:'assistant',content:[{type:'text',text:'(files attached)'}],...meta};addMessage(m);state.messages.push(m)}if(showTree)addAttachmentTree('assistant',clean);await persistThread()},log:async s=>{const text=String(s??'').trim();await ensureThreadOnFirstUser(text||'(log)');const meta=activeMeta(),m={role:'assistant',content:[{type:'text',text:text}],["sune_name","model","avatar"]:undefined,...meta};addMessage(m);state.messages.push(m);await persistThread()}}
|
||||
async function init(){threads=await tload();await renderHistory();renderSidebar();reflectActiveSune();clearChat();icons();kbBind();kbUpdate()}
|
||||
window.addEventListener('resize',()=>{hideHistoryMenu();hideSuneMenu()})
|
||||
init()
|
||||
|
||||
Reference in New Issue
Block a user