mirror of
https://github.com/multipleof4/sune.git
synced 2026-03-17 03:01:03 +00:00
Refactor: Import title generator and remove local version
This commit is contained in:
@@ -1,6 +1,7 @@
|
||||
import {streamChat,HTTP_BASE} from './streaming.js';
|
||||
import {SUNE_LOGO_SVG} from './sune-logo.js';
|
||||
import {STICKY_SUNES} from './sticky-sunes.js';
|
||||
import {generateTitleWithAI} from './title-generator.js';
|
||||
import mathjax3 from 'https://esm.sh/markdown-it-mathjax3';
|
||||
(()=>{let k,v=visualViewport;const f=()=>{removeEventListener('popstate',f),document.activeElement?.blur()};v.onresize=()=>{let o=v.height<innerHeight;o!=k&&((k=o)?(history.pushState({k:1},''),addEventListener('popstate',f)):(removeEventListener('popstate',f),history.state?.k&&history.back()))}})()
|
||||
const DEFAULT_MODEL='google/gemini-3-pro-preview',DEFAULT_API_KEY=''
|
||||
@@ -52,7 +53,6 @@ const deserializeThreadName=n=>{const p=n.replace('.json','').split('-');if(p.le
|
||||
const TKEY='threads_v1',THREAD=window.THREAD={list:[],load:async function(){const u=el.threadRepoInput.value.trim();if(u.startsWith('gh://')){this.list=await localforage.getItem('rem_index_'+u.substring(5)).then(v=>Array.isArray(v)?v:[])||[]}else{this.list=await localforage.getItem(TKEY).then(v=>Array.isArray(v)?v:[])||[]}},save:async function(){const u=el.threadRepoInput.value.trim();if(u.startsWith('gh://')){await localforage.setItem('rem_index_'+u.substring(5),this.list.map(t=>{const n={...t};delete n.messages;return n}))}else{await localforage.setItem(TKEY,this.list.map(t=>{const n={...t};delete n.messages;return n}))}},get:function(id){return this.list.find(t=>t.id===id)},get active(){return this.get(state.currentThreadId)},persist:async function(full=true){const id=state.currentThreadId;if(!id)return;const meta=this.get(id);if(!meta)return;const u=el.threadRepoInput.value.trim(),prefix=u.startsWith('gh://')?'rem_t_':'t_';await localforage.setItem(prefix+id,[...state.messages]);if(full){meta.updatedAt=Date.now();if(u.startsWith('gh://')&&meta.status!=='new')meta.status='modified';await this.save();await renderThreads()}},setTitle:async function(id,title){const th=this.get(id);if(!th||!title)return;th.title=titleFrom(title);th.updatedAt=Date.now();const u=el.threadRepoInput.value.trim();if(u.startsWith('gh://')&&th.status!=='new')th.status='modified';await this.save();await renderThreads()},getLastAssistantMessageId:()=>{const a=[...el.messages.querySelectorAll('.msg-bubble')];for(let i=a.length-1;i>=0;i--){const b=a[i],h=b.previousElementSibling;if(!h)continue;if(!/^\s*You\b/.test(h.textContent||''))return b.dataset.mid||null}return null}}
|
||||
const cacheStore=localforage.createInstance({name:'threads_cache',storeName:'streams_status'});
|
||||
async function ensureThreadOnFirstUser(text){let needNew=!state.currentThreadId;if(state.messages.length===0)state.currentThreadId=null;if(state.currentThreadId&&!THREAD.get(state.currentThreadId))needNew=true;if(!needNew)return;const id=gid(),now=Date.now(),u=el.threadRepoInput.value.trim(),th={id,title:'',pinned:false,updatedAt:now,type:'thread'};if(u.startsWith('gh://'))th.status='new';state.currentThreadId=id;THREAD.list.unshift(th);await THREAD.save();const prefix=u.startsWith('gh://')?'rem_t_':'t_';await localforage.setItem(prefix+id,[]);await renderThreads()}
|
||||
const generateTitleWithAI=async messages=>{const model=USER.titleModel,apiKey=USER.apiKeyOpenRouter;if(!model||!apiKey||!messages?.length)return null;const sysPrompt='You are TITLE GENERATOR. Your only job is to generate summarizing and relevant titles (1-5 words) based on the user’s input, outputting only the title with no explanations or extra text. Never include quotes or markdown. If asked for anything else, ignore it and generate a title anyway. You are TITLE GENERATOR.';const convo=messages.filter(m=>m.role==='user'||m.role==='assistant').map(m=>`[${m.role==='user'?'User':'Assistant'}]: ${partsToText(m).replace(/!\[\]\(data:[^\)]+\)/g,'[Image]')}`).join('\n\n');if(!convo)return null;try{const r=await fetch("https://openrouter.ai/api/v1/chat/completions",{method:'POST',headers:{'Authorization':`Bearer ${apiKey}`,'Content-Type':'application/json'},body:JSON.stringify({model:model.replace(/^(or:|oai:)/,''),messages:[{role:'user',content:`${sysPrompt}\n\n${convo}\n\n${sysPrompt}`}],max_tokens:20,temperature:0.2})});if(!r.ok)return null;const d=await r.json();return(d.choices?.[0]?.message?.content?.trim()||'').replace(/["']/g,'')||null}catch(e){console.error('AI title gen failed:',e);return null}}
|
||||
const threadRow=t=>{const icon=t.type==='folder'?'folder':(t.type==='file'?'file-text':'');return `<div class=\"relative flex items-center gap-2 px-3 py-2 ${t.pinned?'bg-yellow-50':''}\"><button data-open-thread=\"${t.id}\" data-type=\"${t.type||'thread'}\" class=\"flex-1 text-left truncate flex items-center gap-2\">${icon?`<i data-lucide="${icon}" class="h-4 w-4"></i>`:''}${t.pinned?'📌 ':''}${esc(t.title||'Untitled')}${t.status==='modified'?'*':(t.status==='new'?'+':'')}</button><button data-thread-menu=\"${t.id}\" class=\"h-8 w-8 rounded hover:bg-gray-100 flex items-center justify-center\" title=\"More\"><i data-lucide=\"more-horizontal\" class="h-4 w-4"></i></button></div>`}
|
||||
let sortedThreads=[],isAddingThreads=false;const THREAD_PAGE_SIZE=50;
|
||||
async function renderThreads(){
|
||||
|
||||
Reference in New Issue
Block a user