mihailik commited on
Commit
cc7da9d
·
1 Parent(s): 9bc9167

Improved popup again.

Browse files
Files changed (1) hide show
  1. chat-copil2-web.html +38 -30
chat-copil2-web.html CHANGED
@@ -5,22 +5,22 @@
5
  <meta name="viewport" content="width=device-width, initial-scale=1"/>
6
  <title>Local Chat with Transformers.js</title>
7
  <style>
8
- body { margin:0; font-family: system-ui, sans-serif; background:#0f1115; color:#e8eaf0; display:grid; grid-template-rows:auto 1fr auto; height:100vh; }
9
- header, footer { background:#171a21; padding:8px 12px; border-bottom:1px solid #2a2f39; }
10
- header { display:flex; gap:8px; align-items:center; flex-wrap:wrap; }
11
- select,button,textarea,input { background:#11141a; color:#e8eaf0; border:1px solid #2a2f39; border-radius:6px; padding:6px 8px; font:inherit; }
12
- button { cursor:pointer; }
13
- main { overflow:auto; padding:10px; }
14
- .chat { display:flex; flex-direction:column; gap:10px; max-width:900px; margin:auto; }
15
- .msg { display:flex; }
16
- .msg.user { justify-content:flex-end; }
17
- .bubble { padding:8px 10px; border-radius:8px; max-width:80%; white-space:pre-wrap; word-break:break-word; }
18
- .msg.user .bubble { background:#1b2433; }
19
- .msg.assistant .bubble { background:#141923; }
20
- .toast { position:fixed; bottom:12px; left:50%; transform:translateX(-50%); background:#11141a; padding:6px 10px; border:1px solid #2a2f39; border-radius:6px; opacity:0; transition:opacity .2s; }
21
- .toast.show { opacity:1; }
22
- .modal-backdrop { position:fixed; inset:0; background:rgba(0,0,0,.5); display:grid; place-items:center; }
23
- .modal { background:#171a21; padding:16px; border-radius:8px; width:min(400px,90%); }
24
  </style>
25
  </head>
26
  <body>
@@ -88,9 +88,7 @@ function showTokenModal(){
88
  tokenModal.hidden=false;
89
  tokenInput.value=localStorage.getItem('hf_token')||'';
90
  }
91
- function hideTokenModal(){
92
- tokenModal.hidden=true;
93
- }
94
  function setToken(tok){
95
  if(tok){ env.HF_TOKEN=tok; localStorage.setItem('hf_token',tok);}
96
  else{ delete env.HF_TOKEN; localStorage.removeItem('hf_token');}
@@ -103,8 +101,8 @@ async function withAuthRetry(fn){
103
  return await fn();
104
  } catch(e){
105
  if(isUnauthorizedError(e)){
106
- showTokenModal();
107
  return new Promise((resolve,reject)=>{
 
108
  tokenModal.querySelector('#token-save').onclick=()=>{
109
  const val=tokenInput.value.trim();
110
  hideTokenModal();
@@ -135,9 +133,17 @@ async function generate(text,bubble){
135
  const opts={max_new_tokens:128,temperature:0.7,top_p:0.9,repetition_penalty:1.1};
136
  let streamObj; try{ streamObj=state.pipe(text,{...opts,stream:true}); }catch{}
137
  if(isAsyncIterable(streamObj)){
138
- let full=''; for await (const out of streamObj){
139
- const t=(out.token && out.token.text)||out.text||''; full+=t; bubble.textContent=full;
140
- } return;
 
 
 
 
 
 
 
 
141
  }
142
  const out=await withAuthRetry(()=>state.pipe(text,{...opts,stream:false}));
143
  const textOut=Array.isArray(out)?(out[0]?.generated_text||out[0]?.text): (out.generated_text||out.text)||'';
@@ -145,18 +151,20 @@ async function generate(text,bubble){
145
  }
146
  async function onSend(){
147
  const val=inputEl.value.trim(); if(!val) return;
148
- inputEl.value='';
149
- addMessage('user',val);
150
- const bub=addMessage('assistant','…');
151
  try { await generate(val,bub); }
152
  catch(e){ bub.textContent='Error: '+(e.message||e); }
153
  }
154
  sendBtn.onclick=onSend;
155
  inputEl.onkeydown=e=>{ if(e.key==='Enter'&&!e.shiftKey){ e.preventDefault(); onSend(); } };
156
- document.getElementById('set-token').onclick=()=>{ showTokenModal(); tokenModal.querySelector('#token-save').onclick=()=>{
157
- const val=tokenInput.value.trim();
158
- hideTokenModal(); setToken(val); showToast(val?'Token saved':'Token cleared');
159
- }; tokenModal.querySelector('#token-cancel').onclick=()=>hideTokenModal(); };
 
 
 
 
160
 
161
  addMessage('assistant','Hello! Fully local via Transformers.js. Choose model and send a message.');
162
  </script>
 
5
  <meta name="viewport" content="width=device-width, initial-scale=1"/>
6
  <title>Local Chat with Transformers.js</title>
7
  <style>
8
+ body{margin:0;font-family:system-ui,sans-serif;background:#0f1115;color:#e8eaf0;display:grid;grid-template-rows:auto 1fr auto;height:100vh;}
9
+ header,footer{background:#171a21;padding:8px 12px;border-bottom:1px solid #2a2f39;}
10
+ header{display:flex;gap:8px;align-items:center;flex-wrap:wrap;}
11
+ select,button,textarea,input{background:#11141a;color:#e8eaf0;border:1px solid #2a2f39;border-radius:6px;padding:6px 8px;font:inherit;}
12
+ button{cursor:pointer;}
13
+ main{overflow:auto;padding:10px;}
14
+ .chat{display:flex;flex-direction:column;gap:10px;max-width:900px;margin:auto;}
15
+ .msg{display:flex;}
16
+ .msg.user{justify-content:flex-end;}
17
+ .bubble{padding:8px 10px;border-radius:8px;max-width:80%;white-space:pre-wrap;word-break:break-word;}
18
+ .msg.user .bubble{background:#1b2433;}
19
+ .msg.assistant .bubble{background:#141923;}
20
+ .toast{position:fixed;bottom:12px;left:50%;transform:translateX(-50%);background:#11141a;padding:6px 10px;border:1px solid #2a2f39;border-radius:6px;opacity:0;transition:opacity .2s;}
21
+ .toast.show{opacity:1;}
22
+ .modal-backdrop{position:fixed;inset:0;background:rgba(0,0,0,.5);display:grid;place-items:center;}
23
+ .modal{background:#171a21;padding:16px;border-radius:8px;width:min(400px,90%);}
24
  </style>
25
  </head>
26
  <body>
 
88
  tokenModal.hidden=false;
89
  tokenInput.value=localStorage.getItem('hf_token')||'';
90
  }
91
+ function hideTokenModal(){ tokenModal.hidden=true; }
 
 
92
  function setToken(tok){
93
  if(tok){ env.HF_TOKEN=tok; localStorage.setItem('hf_token',tok);}
94
  else{ delete env.HF_TOKEN; localStorage.removeItem('hf_token');}
 
101
  return await fn();
102
  } catch(e){
103
  if(isUnauthorizedError(e)){
 
104
  return new Promise((resolve,reject)=>{
105
+ showTokenModal();
106
  tokenModal.querySelector('#token-save').onclick=()=>{
107
  const val=tokenInput.value.trim();
108
  hideTokenModal();
 
133
  const opts={max_new_tokens:128,temperature:0.7,top_p:0.9,repetition_penalty:1.1};
134
  let streamObj; try{ streamObj=state.pipe(text,{...opts,stream:true}); }catch{}
135
  if(isAsyncIterable(streamObj)){
136
+ let full=''; try{
137
+ for await (const out of streamObj){
138
+ const t=(out.token && out.token.text)||out.text||''; full+=t; bubble.textContent=full;
139
+ }
140
+ return;
141
+ }catch(e){
142
+ if(isUnauthorizedError(e)){
143
+ await withAuthRetry(()=>generate(text,bubble)); return;
144
+ }
145
+ throw e;
146
+ }
147
  }
148
  const out=await withAuthRetry(()=>state.pipe(text,{...opts,stream:false}));
149
  const textOut=Array.isArray(out)?(out[0]?.generated_text||out[0]?.text): (out.generated_text||out.text)||'';
 
151
  }
152
  async function onSend(){
153
  const val=inputEl.value.trim(); if(!val) return;
154
+ inputEl.value=''; addMessage('user',val); const bub=addMessage('assistant','…');
 
 
155
  try { await generate(val,bub); }
156
  catch(e){ bub.textContent='Error: '+(e.message||e); }
157
  }
158
  sendBtn.onclick=onSend;
159
  inputEl.onkeydown=e=>{ if(e.key==='Enter'&&!e.shiftKey){ e.preventDefault(); onSend(); } };
160
+ document.getElementById('set-token').onclick=()=>{
161
+ showTokenModal();
162
+ tokenModal.querySelector('#token-save').onclick=()=>{
163
+ const val=tokenInput.value.trim();
164
+ hideTokenModal(); setToken(val); showToast(val?'Token saved':'Token cleared');
165
+ };
166
+ tokenModal.querySelector('#token-cancel').onclick=()=>hideTokenModal();
167
+ };
168
 
169
  addMessage('assistant','Hello! Fully local via Transformers.js. Choose model and send a message.');
170
  </script>