bariweb-widget 0.1.13 → 0.1.15

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -964,7 +964,7 @@
964
964
  <div class="bw-ai-tooltip-content" role="status" aria-live="polite">
965
965
  Ожидаем ответ от ИИ...
966
966
  </div>
967
- `,document.body.appendChild(i),i.style.left=`${Math.max(10,t-160)}px`,i.style.top=`${n+20}px`;let a=e.style.outline,o=e.style.backgroundColor;e.style.outline=`2px dashed #a855f7`,e.style.backgroundColor=`rgba(168, 85, 247, 0.05)`,i.querySelector(`.bw-ai-tooltip-close`)?.addEventListener(`click`,()=>{i.remove(),e.style.outline=a,e.style.backgroundColor=o});try{let e=window.BariwebConfig?.clientId||``,t=await fetch(`${Ot}/v1/widget/a11y/simplify`,{method:`POST`,headers:{"Content-Type":`application/json`,"X-Client-ID":e},body:JSON.stringify({text:r})});if(t.ok){let e=await t.json();if(e.text)i.classList.remove(`bw-ai-tooltip-loading`),i.querySelector(`.bw-ai-tooltip-content`).innerHTML=e.text,i.focus();else throw Error(`Empty response`)}else throw Error(`Server error`)}catch(e){console.error(`BariWeb AI: Simplify failed`,e),i.classList.remove(`bw-ai-tooltip-loading`),i.querySelector(`.bw-ai-tooltip-content`).innerHTML=`<span style="color:#ef4444; font-size:13px;">Ошибка создания упрощенного текста. Попробуйте еще раз.</span>`,i.focus()}}},At=`bw-tts-enabled-v1`,jt=class{constructor(){this.enabled=!0,this.enabled=this.loadEnabled(),`speechSynthesis`in window&&(window.speechSynthesis.getVoices(),window.speechSynthesis.onvoiceschanged=()=>{window.speechSynthesis.getVoices()})}isEnabled(){return this.enabled}setEnabled(e){this.enabled=e;try{localStorage.setItem(At,e?`1`:`0`)}catch{}e||this.stop()}stop(){`speechSynthesis`in window&&window.speechSynthesis.cancel()}speak(e){if(!this.enabled||!(`speechSynthesis`in window))return;let t=(e||``).trim();if(t)try{window.speechSynthesis.resume(),window.speechSynthesis.cancel();let e=new SpeechSynthesisUtterance(t),n=this.detectLanguage(t);e.lang=n;let r=this.pickVoice(n);r&&(e.voice=r),e.rate=1,e.pitch=1,e.volume=1,window.speechSynthesis.speak(e)}catch(e){console.warn(`TTS speak failed`,e)}}loadEnabled(){try{let e=localStorage.getItem(At);return e===null?!0:e!==`0`}catch{return!0}}detectLanguage(e){return/[\u04D8\u04D9\u0492\u0493\u04AE\u04AF\u049A\u049B\u04E8\u04E9\u04BA\u04BB\u0406\u0456\u04A2\u04A3]/u.test(e)?`kk-KZ`:/[\u0400-\u04FF]/u.test(e)?`ru-RU`:/[a-z]/i.test(e)?`en-US`:`ru-RU`}pickVoice(e){if(!(`speechSynthesis`in window))return null;let t=window.speechSynthesis.getVoices();if(!t||t.length===0)return null;let n=e.split(`-`)[0].toLowerCase();return t.find(t=>t.lang.toLowerCase()===e.toLowerCase())||t.find(e=>e.lang.toLowerCase().startsWith(n))||t[0]||null}};wt();var Mt=`http://localhost:8000`,Nt=5,Pt=[/(submit|отправить|оплатить|сгенерировать|сохранить|перевести|подтвердит|купить|удалить|delete|pay|purchase|buy|send|transfer|confirm|place.?order|checkout|remove|drop|unsubscribe|sign.?out|выйти|уволить)/i];function Ft(e){if(e.type!==`click_element`||!e.element_id)return!1;let t=document.getElementById(e.element_id);if(!t)return!1;if(t.getAttribute(`type`)===`submit`||t.tagName.toLowerCase()===`button`&&t.closest(`form`)!==null&&t.getAttribute(`type`)!==`button`)return!0;let n=[t.textContent?.trim()||``,t.getAttribute(`aria-label`)||``,t.getAttribute(`title`)||``,t.getAttribute(`name`)||``,t.getAttribute(`value`)||``].join(` `);return Pt.some(e=>e.test(n))}var It=class{constructor(e){this.messages=[],this.isLoading=!1,this.error=null,this._tts=new jt,this._voiceMode=!1,this.pendingConfirmation=null,(this.host=e).addController(this),this._loadMessages()}hostConnected(){}hostDisconnected(){this._tts.stop()}_shouldSpeak(){return this._voiceMode||this._tts.isEnabled()}_loadMessages(){try{let e=sessionStorage.getItem(`bw-chat-history`);e&&(this.messages=JSON.parse(e),this.messages.length>0&&typeof this.host.setOpen==`function`&&setTimeout(()=>this.host.setOpen(!0),100));let t=sessionStorage.getItem(`bw-auto-resume`);if(t===`true`||t===`verify-only`){sessionStorage.removeItem(`bw-auto-resume`);let e=t===`verify-only`?`Страница загрузилась после отправки формы. Проверь новый DOM: если авторизация прошла успешно (нет формы входа, есть контент приложения) — сообщи об успехе. НЕ нажимай ничего снова.`:`Страница загрузилась. Продолжай выполнение задачи с учетом нового контекста и DOM.`;setTimeout(()=>{this._agentStep(e)},1e3)}}catch(e){console.error(`Failed to load chat history`,e)}}_saveMessages(){try{sessionStorage.setItem(`bw-chat-history`,JSON.stringify(this.messages))}catch(e){console.error(`Failed to save chat history`,e)}}gatherContext(){let e=window.location.href,t=document.body?.innerText?.slice(0,3e3)??``,n=Array.from(document.querySelectorAll(`a[href], button, [role="button"], input:not([type="hidden"]), textarea, select`)).filter(e=>!e.hasAttribute(`bw-private`)).map(e=>{let t=e,n=t.tagName.toLowerCase(),r=n===`input`||n===`textarea`||n===`select`,i=t.getAttribute(`type`)||(n===`input`?`text`:n===`button`?`button`:n),a=t.getAttribute(`name`)||``,o=t.getAttribute(`placeholder`)||``,s=r?(t.value||``).slice(0,80):``;s&&=(s=s.replace(/\b\d{13,19}\b/g,e=>e.slice(0,4)+` **** **** `+e.slice(-4)),s.replace(/\b\d{12}\b/g,`**** **** ****`));let c=t.id&&!t.getAttribute(`data-bw-auto`)?t.id:t.getAttribute(`data-id`)||t.getAttribute(`data-testid`)||``;if(!c){let e=`${n}|${i}|${a}|${o}|${(t.className||``).toString().replace(/\s+/g,`-`).slice(0,40)}|${t.href||``}|${(t.textContent||``).trim().slice(0,30)}|${t.parentElement?.tagName?.toLowerCase()||`root`}`,r=5381;for(let t=0;t<e.length;t++)r=(r<<5)+r^e.charCodeAt(t);c=`bw-${(r>>>0).toString(16)}`,t.id=c,t.setAttribute(`data-bw-auto`,`true`)}let l=t.getAttribute(`aria-label`)||``;if(!l&&c){let e=document.querySelector(`label[for="${c}"]`);e&&(l=e.textContent?.trim()||``)}if(!l){let e=t.parentElement;for(;e&&e.tagName.toLowerCase()!==`form`&&e.tagName.toLowerCase()!==`body`;){if(e.tagName.toLowerCase()===`label`){l=(e.textContent||``).replace(t.textContent||``,``).trim();break}e=e.parentElement}}if(l||=(t.textContent||``).trim().slice(0,80),l||=t.getAttribute(`title`)||``,!l&&o&&(l=o),!l&&n===`button`){let e=t.querySelector(`svg`);if(e&&typeof e.className?.baseVal==`string`){let t=e.className.baseVal.match(/lucide-([a-z0-9\-]+)/);l=t?`[icon:${t[1]}]`:`[icon]`}else l=`[btn:${(t.className||``).toString().slice(0,30)}]`}return{id:c,label:l.trim(),tag:n,type:i,name:a,placeholder:o,value:s}}).filter(e=>e.label.length>0||(e.placeholder??``).length>0||(e.name??``).length>0).slice(0,100).map(e=>`[`+[e.tag,e.type||``,e.id,e.name||``,e.placeholder||``,e.value||``,e.label].join(`|`)+`]`).join(``),r=t;return r=r.replace(/\b\d{13,19}\b/g,`**** **** **** ****`),r=r.replace(/\b\d{12}\b/g,`**** **** ****`),{page_text:r,elements:n,page_url:e}}executeAction(e){if(e.type===`click_element`&&e.element_id){let t=document.getElementById(e.element_id);if(t){if(t.tagName.toLowerCase()===`a`&&t.href){let n=t.href;return new URL(n,window.location.origin).origin===window.location.origin&&sessionStorage.setItem(`bw-auto-resume`,`true`),t.click(),{result:`✅ Нажал на "${t.textContent?.trim()||e.element_id}"`,causesNavigation:!0}}return t.getAttribute(`type`)===`submit`||t.tagName.toLowerCase()===`button`&&t.closest(`form`)!==null&&t.getAttribute(`type`)!==`button`?(sessionStorage.setItem(`bw-auto-resume`,`verify-only`),t.click(),{result:`✅ Нажал на "${t.textContent?.trim()||e.element_id}"`,causesNavigation:!0}):(t.click(),{result:`✅ Нажал на "${t.textContent?.trim()||e.element_id}"`,causesNavigation:!1})}return{result:`⚠️ Элемент "${e.element_id}" не найден.`,causesNavigation:!1}}if(e.type===`navigate`&&e.url)return sessionStorage.setItem(`bw-auto-resume`,`true`),window.location.href=e.url,{result:`🔀 Перехожу на ${e.url}...`,causesNavigation:!0};if(e.type===`input_text`&&e.element_id&&e.value!==void 0){let t=document.getElementById(e.element_id);if(t){let n=Object.getOwnPropertyDescriptor(window.HTMLInputElement.prototype,`value`)?.set,r=Object.getOwnPropertyDescriptor(window.HTMLTextAreaElement.prototype,`value`)?.set;return t.tagName.toLowerCase()===`textarea`&&r?r.call(t,e.value):n?n.call(t,e.value):t.value=e.value,t.dispatchEvent(new Event(`input`,{bubbles:!0})),t.dispatchEvent(new Event(`change`,{bubbles:!0})),{result:`⌨️ Ввел текст "${e.value}" в поле.`,causesNavigation:!1}}return{result:`⚠️ Поле ввода "${e.element_id}" не найдено.`,causesNavigation:!1}}return e.type===`continue`?{result:`🔄 Анализирую страницу...`,causesNavigation:!1}:{result:`⚠️ Неизвестное действие.`,causesNavigation:!1}}async _callAPI(e){let{page_text:t,elements:n,page_url:r}=this.gatherContext(),i=J(),a=this.host.clientId||window.__BARIWEB_CLIENT_ID__||``,o=null;try{let e=await fetch(`${Mt}/v1/training/match-screen`,{method:`POST`,headers:{"Content-Type":`application/json`,"X-Client-ID":a},body:JSON.stringify({fingerprint:i})});if(e.ok){let t=await e.json();t.matched&&(o=t.label)}}catch(e){console.warn(`Failed to match screen fingerprint`,e)}let s=await fetch(`${Mt}/v1/chat`,{method:`POST`,headers:{"Content-Type":`application/json`,"X-Client-ID":a},body:JSON.stringify({query:e,history:this._compressedHistory(),page_text:t,elements:n,page_url:r,screen_label:o,screen_fingerprint:i})});if(!s.ok)throw Error(`HTTP ${s.status}: ${s.statusText}`);let c=await s.json();if(c.text&&c.text.trimStart().startsWith(`{`))try{let e=JSON.parse(c.text);e.text&&(c.text=e.text,e.action&&!c.action&&(c.action=e.action))}catch{c.text=c.text.replace(/^\{"text"\s*:\s*"/,``).replace(/",?\s*"action".*$/,``)}return c}_compressedHistory(){let e=this.messages.map(e=>({role:e.role,text:e.text}));if(e.length<=3)return e;let t=-1;for(let n=e.length-1;n>=0;n--)if(e[n].role===`user`){t=n;break}return t===-1?e.slice(-3):[e[t],...e.slice(t+1).filter(e=>e.role===`assistant`).slice(-2)]}async _agentLoop(e,t,n=!1){if(this.isLoading)return;this.isLoading=!0,this.error=null,this._voiceMode=n,t&&(this.messages=[...this.messages,{role:`user`,text:e,timestamp:Date.now()}],this._saveMessages()),this.host.requestUpdate();let r=e,i=0;try{for(;i<Nt;){i++;let e=await this._callAPI(r),t=e.text;if(e.action){if(Ft(e.action)){let t=document.getElementById(e.action.element_id||``)?.textContent?.trim()||e.action.element_id||`кнопку`;this.pendingConfirmation={text:`${e.text}\n\n⚠️ Нажать «${t}»?`,action:e.action,currentQuery:r,step:i},this.messages=[...this.messages,{role:`assistant`,text:`${e.text}\n\n🛑 **Подтвердите действие:** нажать «${t}»?`,timestamp:Date.now()}],this._saveMessages(),this._shouldSpeak()&&this._tts.speak(e.text),this.isLoading=!1,this.host.requestUpdate();return}let n=this.gatherContext().page_text,{result:a,causesNavigation:o}=this.executeAction(e.action);if(e.action.type===`continue`){this.messages=[...this.messages,{role:`assistant`,text:`🔄 Анализирую...`,timestamp:Date.now()}],this._saveMessages(),this._shouldSpeak()&&this._tts.speak(`Анализирую...`),this.host.requestUpdate(),await this._waitForDom(800),r=`Страница обновилась. Продолжай задачу, прочитай DOM.`;continue}if(t=`${e.text}\n${a}`,o){this.messages=[...this.messages,{role:`assistant`,text:t,timestamp:Date.now()}],this._saveMessages(),this._shouldSpeak()&&this._tts.speak(t),this.host.requestUpdate(),await this._waitForDom(1500);let e=sessionStorage.getItem(`bw-auto-resume`);if(e===`true`||e===`verify-only`){sessionStorage.removeItem(`bw-auto-resume`),r=e===`verify-only`?`Страница загрузилась после отправки формы (SPA навигация). Проверь новый DOM: если задача выполнена — сообщи об успехе. НЕ нажимай ничего снова.`:`Страница загрузилась (SPA навигация). Продолжай задачу, прочитай новый DOM.`;continue}break}this.messages=[...this.messages,{role:`assistant`,text:t,timestamp:Date.now()}],this._saveMessages(),this._shouldSpeak()&&this._tts.speak(t),this.host.requestUpdate(),e.action.type===`input_text`&&e.action.element_id?(await this._waitForDom(800),r=(document.getElementById(e.action.element_id)?.value??``).length>0?`✅ Поле заполнено. Переходи к СЛЕДУЮЩЕМУ незаполненному полю или нажми кнопку отправки. НЕ повторяй ввод.`:`⚠️ Поле не получило значение. Попробуй ввести снова в id="${e.action.element_id}".`):(await this._waitForDom(800),r=n===this.gatherContext().page_text?`⚠️ Страница не изменилась. Возможно кнопка не сработала. Проверь DOM.`:`Действие выполнено. Если задача готова — сообщи. Иначе продолжай.`);continue}this.messages=[...this.messages,{role:`assistant`,text:t,timestamp:Date.now()}],this._saveMessages(),this._shouldSpeak()&&this._tts.speak(t);break}}catch(e){this.error=e.message??`Ошибка соединения`,this.messages=[...this.messages,{role:`assistant`,text:`❌ Ошибка: ${this.error}`,timestamp:Date.now()}],this._saveMessages(),this._shouldSpeak()&&this._tts.speak(`Ошибка: ${this.error}`)}finally{this.isLoading=!1,this.host.requestUpdate()}}async confirmAction(){if(!this.pendingConfirmation)return;let{action:e}=this.pendingConfirmation;this.pendingConfirmation=null,this.messages=[...this.messages,{role:`user`,text:`✅ Подтверждаю`,timestamp:Date.now()}],this._saveMessages(),this.host.requestUpdate();let{result:t,causesNavigation:n}=this.executeAction(e);this.messages=[...this.messages,{role:`assistant`,text:t,timestamp:Date.now()}],this._saveMessages(),this._shouldSpeak()&&this._tts.speak(t),this.host.requestUpdate(),!n&&(await this._waitForDom(1200),await this._agentStep(`Действие подтверждено и выполнено. Проверь результат в DOM.`))}cancelAction(){this.pendingConfirmation&&(this.pendingConfirmation=null,this.messages=[...this.messages,{role:`user`,text:`❌ Отмена`,timestamp:Date.now()},{role:`assistant`,text:`🚫 Действие отменено. Чем ещё могу помочь?`,timestamp:Date.now()}],this._saveMessages(),this._shouldSpeak()&&this._tts.speak(`Действие отменено. Чем ещё могу помочь?`),this.host.requestUpdate())}_waitForDom(e){return new Promise(t=>setTimeout(t,e))}async sendMessage(e,t=!1){!e.trim()||this.isLoading||(await this._agentLoop(e,!0,t),this.host.updateComplete?.then(()=>{let e=this.host.renderRoot?.querySelector(`.chat-messages`);e&&(e.scrollTop=e.scrollHeight)}))}async _agentStep(e){await this._agentLoop(e,!1,this._voiceMode),this.host.updateComplete?.then(()=>{let e=this.host.renderRoot?.querySelector(`.chat-messages`);e&&(e.scrollTop=e.scrollHeight)})}clearMessages(){this.messages=[],this.error=null,this.pendingConfirmation=null,this._saveMessages(),this.host.requestUpdate()}isTtsEnabled(){return this._tts.isEnabled()}setTtsEnabled(e){this._tts.setEnabled(e),this.host.requestUpdate()}async transcribeAudio(e,t){let n=this.host.clientId||window.__BARIWEB_CLIENT_ID__||``,r=new FormData;r.append(`language_mode`,t),r.append(`audio`,e,`speech.wav`);let i=await fetch(`${Mt}/v1/stt/transcribe`,{method:`POST`,headers:{"X-Client-ID":n},body:r});if(!i.ok){let e=`HTTP ${i.status}`;try{e=(await i.json())?.detail||e}catch{}throw Error(e)}return await i.json()}};function X(e,t,n,r){var i=arguments.length,a=i<3?t:r===null?r=Object.getOwnPropertyDescriptor(t,n):r,o;if(typeof Reflect==`object`&&typeof Reflect.decorate==`function`)a=Reflect.decorate(e,t,n,r);else for(var s=e.length-1;s>=0;s--)(o=e[s])&&(a=(i<3?o(a):i>3?o(t,n,a):o(t,n))||a);return i>3&&a&&Object.defineProperty(t,n,a),a}var Lt=n({initAdminMode:()=>Vt,mountAdminPanel:()=>Bt});function Rt(){if(!Z)return;let e=q(),t=J(),n=Q?.is_trained===!0,r=Q&&!Q.is_trained,i=Q?.label||null,a=Q?.description||null,o=n?`active`:r?`draft`:`idle`,s=n?`trained`:r?`draft`:`idle`,c=n?`✅ Обучено`:r?`📝 Черновик (не подтверждено)`:`🔍 Сканирование...`,l=Z.querySelector(`#bw-admin-panel`);l&&(l.className=n?`trained`:`discovering`,l.id=`bw-admin-panel`,n&&l.classList.add(`trained`));let u=Z.querySelector(`#bw-panel-content`);u&&(u.innerHTML=`
967
+ `,document.body.appendChild(i),i.style.left=`${Math.max(10,t-160)}px`,i.style.top=`${n+20}px`;let a=e.style.outline,o=e.style.backgroundColor;e.style.outline=`2px dashed #a855f7`,e.style.backgroundColor=`rgba(168, 85, 247, 0.05)`,i.querySelector(`.bw-ai-tooltip-close`)?.addEventListener(`click`,()=>{i.remove(),e.style.outline=a,e.style.backgroundColor=o});try{let e=window.BariwebConfig?.clientId||``,t=await fetch(`${Ot}/v1/widget/a11y/simplify`,{method:`POST`,headers:{"Content-Type":`application/json`,"X-Client-ID":e},body:JSON.stringify({text:r})});if(t.ok){let e=await t.json();if(e.text)i.classList.remove(`bw-ai-tooltip-loading`),i.querySelector(`.bw-ai-tooltip-content`).innerHTML=e.text,i.focus();else throw Error(`Empty response`)}else throw Error(`Server error`)}catch(e){console.error(`BariWeb AI: Simplify failed`,e),i.classList.remove(`bw-ai-tooltip-loading`),i.querySelector(`.bw-ai-tooltip-content`).innerHTML=`<span style="color:#ef4444; font-size:13px;">Ошибка создания упрощенного текста. Попробуйте еще раз.</span>`,i.focus()}}},At=`bw-tts-enabled-v1`,jt=class{constructor(){this.enabled=!1,this.enabled=this.loadEnabled(),`speechSynthesis`in window&&(window.speechSynthesis.getVoices(),window.speechSynthesis.onvoiceschanged=()=>{window.speechSynthesis.getVoices()})}isEnabled(){return this.enabled}setEnabled(e){this.enabled=e;try{localStorage.setItem(At,e?`1`:`0`)}catch{}e||this.stop()}stop(){`speechSynthesis`in window&&window.speechSynthesis.cancel()}speak(e){if(!this.enabled||!(`speechSynthesis`in window))return;let t=(e||``).trim();if(t)try{window.speechSynthesis.resume(),window.speechSynthesis.cancel();let e=new SpeechSynthesisUtterance(t),n=this.detectLanguage(t);e.lang=n;let r=this.pickVoice(n);r&&(e.voice=r),e.rate=1,e.pitch=1,e.volume=1,window.speechSynthesis.speak(e)}catch(e){console.warn(`TTS speak failed`,e)}}loadEnabled(){try{let e=localStorage.getItem(At);return e===null?!1:e!==`0`}catch{return!1}}detectLanguage(e){return/[\u04D8\u04D9\u0492\u0493\u04AE\u04AF\u049A\u049B\u04E8\u04E9\u04BA\u04BB\u0406\u0456\u04A2\u04A3]/u.test(e)?`kk-KZ`:/[\u0400-\u04FF]/u.test(e)?`ru-RU`:/[a-z]/i.test(e)?`en-US`:`ru-RU`}pickVoice(e){if(!(`speechSynthesis`in window))return null;let t=window.speechSynthesis.getVoices();if(!t||t.length===0)return null;let n=e.split(`-`)[0].toLowerCase();return t.find(t=>t.lang.toLowerCase()===e.toLowerCase())||t.find(e=>e.lang.toLowerCase().startsWith(n))||t[0]||null}};wt();var Mt=`http://localhost:8000`,Nt=5,Pt=[/(submit|отправить|оплатить|сгенерировать|сохранить|перевести|подтвердит|купить|удалить|delete|pay|purchase|buy|send|transfer|confirm|place.?order|checkout|remove|drop|unsubscribe|sign.?out|выйти|уволить)/i];function Ft(e){if(e.type!==`click_element`||!e.element_id)return!1;let t=document.getElementById(e.element_id);if(!t)return!1;if(t.getAttribute(`type`)===`submit`||t.tagName.toLowerCase()===`button`&&t.closest(`form`)!==null&&t.getAttribute(`type`)!==`button`)return!0;let n=[t.textContent?.trim()||``,t.getAttribute(`aria-label`)||``,t.getAttribute(`title`)||``,t.getAttribute(`name`)||``,t.getAttribute(`value`)||``].join(` `);return Pt.some(e=>e.test(n))}var It=class{constructor(e){this.messages=[],this.isLoading=!1,this.error=null,this._tts=new jt,this._voiceMode=!1,this.pendingConfirmation=null,(this.host=e).addController(this),this._loadMessages()}hostConnected(){}hostDisconnected(){this._tts.stop()}_shouldSpeak(){return this._voiceMode||this._tts.isEnabled()}_loadMessages(){try{let e=sessionStorage.getItem(`bw-chat-history`);e&&(this.messages=JSON.parse(e),this.messages.length>0&&typeof this.host.setOpen==`function`&&setTimeout(()=>this.host.setOpen(!0),100));let t=sessionStorage.getItem(`bw-auto-resume`);if(t===`true`||t===`verify-only`){sessionStorage.removeItem(`bw-auto-resume`);let e=t===`verify-only`?`Страница загрузилась после отправки формы. Проверь новый DOM: если авторизация прошла успешно (нет формы входа, есть контент приложения) — сообщи об успехе. НЕ нажимай ничего снова.`:`Страница загрузилась. Продолжай выполнение задачи с учетом нового контекста и DOM.`;setTimeout(()=>{this._agentStep(e)},1e3)}}catch(e){console.error(`Failed to load chat history`,e)}}_saveMessages(){try{sessionStorage.setItem(`bw-chat-history`,JSON.stringify(this.messages))}catch(e){console.error(`Failed to save chat history`,e)}}gatherContext(){let e=window.location.href,t=document.body?.innerText?.slice(0,3e3)??``,n=Array.from(document.querySelectorAll(`a[href], button, [role="button"], input:not([type="hidden"]), textarea, select`)).filter(e=>!e.hasAttribute(`bw-private`)).map(e=>{let t=e,n=t.tagName.toLowerCase(),r=n===`input`||n===`textarea`||n===`select`,i=t.getAttribute(`type`)||(n===`input`?`text`:n===`button`?`button`:n),a=t.getAttribute(`name`)||``,o=t.getAttribute(`placeholder`)||``,s=r?(t.value||``).slice(0,80):``;s&&=(s=s.replace(/\b\d{13,19}\b/g,e=>e.slice(0,4)+` **** **** `+e.slice(-4)),s.replace(/\b\d{12}\b/g,`**** **** ****`));let c=t.id&&!t.getAttribute(`data-bw-auto`)?t.id:t.getAttribute(`data-id`)||t.getAttribute(`data-testid`)||``;if(!c){let e=`${n}|${i}|${a}|${o}|${(t.className||``).toString().replace(/\s+/g,`-`).slice(0,40)}|${t.href||``}|${(t.textContent||``).trim().slice(0,30)}|${t.parentElement?.tagName?.toLowerCase()||`root`}`,r=5381;for(let t=0;t<e.length;t++)r=(r<<5)+r^e.charCodeAt(t);c=`bw-${(r>>>0).toString(16)}`,t.id=c,t.setAttribute(`data-bw-auto`,`true`)}let l=t.getAttribute(`aria-label`)||``;if(!l&&c){let e=document.querySelector(`label[for="${c}"]`);e&&(l=e.textContent?.trim()||``)}if(!l){let e=t.parentElement;for(;e&&e.tagName.toLowerCase()!==`form`&&e.tagName.toLowerCase()!==`body`;){if(e.tagName.toLowerCase()===`label`){l=(e.textContent||``).replace(t.textContent||``,``).trim();break}e=e.parentElement}}if(l||=(t.textContent||``).trim().slice(0,80),l||=t.getAttribute(`title`)||``,!l&&o&&(l=o),!l&&n===`button`){let e=t.querySelector(`svg`);if(e&&typeof e.className?.baseVal==`string`){let t=e.className.baseVal.match(/lucide-([a-z0-9\-]+)/);l=t?`[icon:${t[1]}]`:`[icon]`}else l=`[btn:${(t.className||``).toString().slice(0,30)}]`}return{id:c,label:l.trim(),tag:n,type:i,name:a,placeholder:o,value:s}}).filter(e=>e.label.length>0||(e.placeholder??``).length>0||(e.name??``).length>0).slice(0,100).map(e=>`[`+[e.tag,e.type||``,e.id,e.name||``,e.placeholder||``,e.value||``,e.label].join(`|`)+`]`).join(``),r=t;return r=r.replace(/\b\d{13,19}\b/g,`**** **** **** ****`),r=r.replace(/\b\d{12}\b/g,`**** **** ****`),{page_text:r,elements:n,page_url:e}}executeAction(e){if(e.type===`click_element`&&e.element_id){let t=document.getElementById(e.element_id);if(t){if(t.tagName.toLowerCase()===`a`&&t.href){let n=t.href;return new URL(n,window.location.origin).origin===window.location.origin&&sessionStorage.setItem(`bw-auto-resume`,`true`),t.click(),{result:`✅ Нажал на "${t.textContent?.trim()||e.element_id}"`,causesNavigation:!0}}return t.getAttribute(`type`)===`submit`||t.tagName.toLowerCase()===`button`&&t.closest(`form`)!==null&&t.getAttribute(`type`)!==`button`?(sessionStorage.setItem(`bw-auto-resume`,`verify-only`),t.click(),{result:`✅ Нажал на "${t.textContent?.trim()||e.element_id}"`,causesNavigation:!0}):(t.click(),{result:`✅ Нажал на "${t.textContent?.trim()||e.element_id}"`,causesNavigation:!1})}return{result:`⚠️ Элемент "${e.element_id}" не найден.`,causesNavigation:!1}}if(e.type===`navigate`&&e.url)return sessionStorage.setItem(`bw-auto-resume`,`true`),window.location.href=e.url,{result:`🔀 Перехожу на ${e.url}...`,causesNavigation:!0};if(e.type===`input_text`&&e.element_id&&e.value!==void 0){let t=document.getElementById(e.element_id);if(t){let n=Object.getOwnPropertyDescriptor(window.HTMLInputElement.prototype,`value`)?.set,r=Object.getOwnPropertyDescriptor(window.HTMLTextAreaElement.prototype,`value`)?.set;return t.tagName.toLowerCase()===`textarea`&&r?r.call(t,e.value):n?n.call(t,e.value):t.value=e.value,t.dispatchEvent(new Event(`input`,{bubbles:!0})),t.dispatchEvent(new Event(`change`,{bubbles:!0})),{result:`⌨️ Ввел текст "${e.value}" в поле.`,causesNavigation:!1}}return{result:`⚠️ Поле ввода "${e.element_id}" не найдено.`,causesNavigation:!1}}return e.type===`continue`?{result:`🔄 Анализирую страницу...`,causesNavigation:!1}:{result:`⚠️ Неизвестное действие.`,causesNavigation:!1}}async _callAPI(e){let{page_text:t,elements:n,page_url:r}=this.gatherContext(),i=J(),a=this.host.clientId||window.__BARIWEB_CLIENT_ID__||``,o=null;try{let e=await fetch(`${Mt}/v1/training/match-screen`,{method:`POST`,headers:{"Content-Type":`application/json`,"X-Client-ID":a},body:JSON.stringify({fingerprint:i})});if(e.ok){let t=await e.json();t.matched&&(o=t.label)}}catch(e){console.warn(`Failed to match screen fingerprint`,e)}let s=await fetch(`${Mt}/v1/chat`,{method:`POST`,headers:{"Content-Type":`application/json`,"X-Client-ID":a},body:JSON.stringify({query:e,history:this._compressedHistory(),page_text:t,elements:n,page_url:r,screen_label:o,screen_fingerprint:i})});if(!s.ok)throw Error(`HTTP ${s.status}: ${s.statusText}`);let c=await s.json();if(c.text&&c.text.trimStart().startsWith(`{`))try{let e=JSON.parse(c.text);e.text&&(c.text=e.text,e.action&&!c.action&&(c.action=e.action))}catch{c.text=c.text.replace(/^\{"text"\s*:\s*"/,``).replace(/",?\s*"action".*$/,``)}return c}_compressedHistory(){let e=this.messages.map(e=>({role:e.role,text:e.text}));if(e.length<=3)return e;let t=-1;for(let n=e.length-1;n>=0;n--)if(e[n].role===`user`){t=n;break}return t===-1?e.slice(-3):[e[t],...e.slice(t+1).filter(e=>e.role===`assistant`).slice(-2)]}async _agentLoop(e,t,n=!1){if(this.isLoading)return;this.isLoading=!0,this.error=null,this._voiceMode=n,t&&(this.messages=[...this.messages,{role:`user`,text:e,timestamp:Date.now()}],this._saveMessages()),this.host.requestUpdate();let r=e,i=0;try{for(;i<Nt;){i++;let e=await this._callAPI(r),t=e.text;if(e.action){if(Ft(e.action)){let t=document.getElementById(e.action.element_id||``)?.textContent?.trim()||e.action.element_id||`кнопку`;this.pendingConfirmation={text:`${e.text}\n\n⚠️ Нажать «${t}»?`,action:e.action,currentQuery:r,step:i},this.messages=[...this.messages,{role:`assistant`,text:`${e.text}\n\n🛑 **Подтвердите действие:** нажать «${t}»?`,timestamp:Date.now()}],this._saveMessages(),this._shouldSpeak()&&this._tts.speak(e.text),this.isLoading=!1,this.host.requestUpdate();return}let n=this.gatherContext().page_text,{result:a,causesNavigation:o}=this.executeAction(e.action);if(e.action.type===`continue`){this.messages=[...this.messages,{role:`assistant`,text:`🔄 Анализирую...`,timestamp:Date.now()}],this._saveMessages(),this._shouldSpeak()&&this._tts.speak(`Анализирую...`),this.host.requestUpdate(),await this._waitForDom(800),r=`Страница обновилась. Продолжай задачу, прочитай DOM.`;continue}if(t=`${e.text}\n${a}`,o){this.messages=[...this.messages,{role:`assistant`,text:t,timestamp:Date.now()}],this._saveMessages(),this._shouldSpeak()&&this._tts.speak(t),this.host.requestUpdate(),await this._waitForDom(1500);let e=sessionStorage.getItem(`bw-auto-resume`);if(e===`true`||e===`verify-only`){sessionStorage.removeItem(`bw-auto-resume`),r=e===`verify-only`?`Страница загрузилась после отправки формы (SPA навигация). Проверь новый DOM: если задача выполнена — сообщи об успехе. НЕ нажимай ничего снова.`:`Страница загрузилась (SPA навигация). Продолжай задачу, прочитай новый DOM.`;continue}break}this.messages=[...this.messages,{role:`assistant`,text:t,timestamp:Date.now()}],this._saveMessages(),this._shouldSpeak()&&this._tts.speak(t),this.host.requestUpdate(),e.action.type===`input_text`&&e.action.element_id?(await this._waitForDom(800),r=(document.getElementById(e.action.element_id)?.value??``).length>0?`✅ Поле заполнено. Переходи к СЛЕДУЮЩЕМУ незаполненному полю или нажми кнопку отправки. НЕ повторяй ввод.`:`⚠️ Поле не получило значение. Попробуй ввести снова в id="${e.action.element_id}".`):(await this._waitForDom(800),r=n===this.gatherContext().page_text?`⚠️ Страница не изменилась. Возможно кнопка не сработала. Проверь DOM.`:`Действие выполнено. Если задача готова — сообщи. Иначе продолжай.`);continue}this.messages=[...this.messages,{role:`assistant`,text:t,timestamp:Date.now()}],this._saveMessages(),this._shouldSpeak()&&this._tts.speak(t);break}}catch(e){this.error=e.message??`Ошибка соединения`,this.messages=[...this.messages,{role:`assistant`,text:`❌ Ошибка: ${this.error}`,timestamp:Date.now()}],this._saveMessages(),this._shouldSpeak()&&this._tts.speak(`Ошибка: ${this.error}`)}finally{this.isLoading=!1,this.host.requestUpdate()}}async confirmAction(){if(!this.pendingConfirmation)return;let{action:e}=this.pendingConfirmation;this.pendingConfirmation=null,this.messages=[...this.messages,{role:`user`,text:`✅ Подтверждаю`,timestamp:Date.now()}],this._saveMessages(),this.host.requestUpdate();let{result:t,causesNavigation:n}=this.executeAction(e);this.messages=[...this.messages,{role:`assistant`,text:t,timestamp:Date.now()}],this._saveMessages(),this._shouldSpeak()&&this._tts.speak(t),this.host.requestUpdate(),!n&&(await this._waitForDom(1200),await this._agentStep(`Действие подтверждено и выполнено. Проверь результат в DOM.`))}cancelAction(){this.pendingConfirmation&&(this.pendingConfirmation=null,this.messages=[...this.messages,{role:`user`,text:`❌ Отмена`,timestamp:Date.now()},{role:`assistant`,text:`🚫 Действие отменено. Чем ещё могу помочь?`,timestamp:Date.now()}],this._saveMessages(),this._shouldSpeak()&&this._tts.speak(`Действие отменено. Чем ещё могу помочь?`),this.host.requestUpdate())}_waitForDom(e){return new Promise(t=>setTimeout(t,e))}async sendMessage(e,t=!1){!e.trim()||this.isLoading||(await this._agentLoop(e,!0,t),this.host.updateComplete?.then(()=>{let e=this.host.renderRoot?.querySelector(`.chat-messages`);e&&(e.scrollTop=e.scrollHeight)}))}async _agentStep(e){await this._agentLoop(e,!1,this._voiceMode),this.host.updateComplete?.then(()=>{let e=this.host.renderRoot?.querySelector(`.chat-messages`);e&&(e.scrollTop=e.scrollHeight)})}clearMessages(){this.messages=[],this.error=null,this.pendingConfirmation=null,this._saveMessages(),this.host.requestUpdate()}isTtsEnabled(){return this._tts.isEnabled()}setTtsEnabled(e){this._tts.setEnabled(e),this.host.requestUpdate()}async transcribeAudio(e,t){let n=this.host.clientId||window.__BARIWEB_CLIENT_ID__||``,r=new FormData;r.append(`language_mode`,t),r.append(`audio`,e,`speech.wav`);let i=await fetch(`${Mt}/v1/stt/transcribe`,{method:`POST`,headers:{"X-Client-ID":n},body:r});if(!i.ok){let e=`HTTP ${i.status}`;try{e=(await i.json())?.detail||e}catch{}throw Error(e)}return await i.json()}};function X(e,t,n,r){var i=arguments.length,a=i<3?t:r===null?r=Object.getOwnPropertyDescriptor(t,n):r,o;if(typeof Reflect==`object`&&typeof Reflect.decorate==`function`)a=Reflect.decorate(e,t,n,r);else for(var s=e.length-1;s>=0;s--)(o=e[s])&&(a=(i<3?o(a):i>3?o(t,n,a):o(t,n))||a);return i>3&&a&&Object.defineProperty(t,n,a),a}var Lt=n({initAdminMode:()=>Vt,mountAdminPanel:()=>Bt});function Rt(){if(!Z)return;let e=q(),t=J(),n=Q?.is_trained===!0,r=Q&&!Q.is_trained,i=Q?.label||null,a=Q?.description||null,o=n?`active`:r?`draft`:`idle`,s=n?`trained`:r?`draft`:`idle`,c=n?`✅ Обучено`:r?`📝 Черновик (не подтверждено)`:`🔍 Сканирование...`,l=Z.querySelector(`#bw-admin-panel`);l&&(l.className=n?`trained`:`discovering`,l.id=`bw-admin-panel`,n&&l.classList.add(`trained`));let u=Z.querySelector(`#bw-panel-content`);u&&(u.innerHTML=`
968
968
  <div class="bw-status-box ${n?`trained`:r?`draft`:``}">
969
969
  <div class="bw-status-indicator">
970
970
  <span class="bw-status-dot ${o}"></span>
@@ -1160,7 +1160,7 @@
1160
1160
  border-radius: 4px;
1161
1161
  transition: all 0.15s ease-out;
1162
1162
  }
1163
- `,Z=null,Q=null}));Dt();var Wt=`bw-stt-lang-v1`,Gt=200,Kt=.015,qt=1200,Jt=2e4,Yt=350,Xt={ru:{announceVoiceInputAvailable:`Голосовой ввод доступен. Кнопка в нижнем правом углу.`,announceWidgetOpened:`Виджет открыт.`,announceSwitchedToChat:`Переход в чат. Голосовой ввод доступен.`,errorMicNotSupported:`Микрофон не поддерживается.`,errorNoMicAccess:`Нет доступа к микрофону.`,errorProcessing:`Ошибка обработки.`,errorTooShort:`Слишком короткая запись.`,errorSpeechNotRecognized:`Речь не распознана.`,errorRecognition:`Ошибка распознавания.`,screenLabelPrefix:`На странице:`,chatEmptyTitle:`Ваш помощник`,chatEmptySub:`Опишите задачу — я найду нужные кнопки и заполню поля за вас.`,confirmAction:`Подтвердить действие`,cancel:`Отменить`,listening:`Слушаю... (остановлюсь по тишине)`,recognizingSpeech:`Распознаю речь...`,micAria:`Включить голосовой ввод (удерживайте для записи)`,inputPlaceholder:`Введите сообщение...`,inputAria:`Текстовое поле ввода сообщения`,ttsDisableAria:`Выключить озвучку ответа`,ttsEnableAria:`Включить озвучку ответа`,sendAria:`Отправить сообщение`,tileTextSize:`Размер текста`,tileMonochrome:`Ч/Б`,valueMonochrome:`Монохром`,tileContrast:`Контраст`,valueDark:`Тёмный`,tileLinks:`Ссылки`,valueHighlight:`Выделить`,tileSpacing:`Отступы`,valueEnlarge:`Увеличить`,tileFont:`Шрифт`,valueDyslexia:`Дислексия`,tileCursor:`Курсор`,tileVoice:`Голос`,valueRecording:`Запись...`,valuePress:`Нажмите`,colorSetup:`Настройка цвета`,tabBackground:`Фон`,tabHeader:`Шапка`,tabText:`Текст`,decrease:`Уменьшить`,hue:`Оттенок`,increase:`Увеличить`,recognitionLanguage:`Язык`,changeRecognitionLanguage:`Изменить язык распознавания`,languageAuto:`Автоопределение`,languageKz:`Казахский`,languageRu:`Русский`,languageEn:`Английский`,aiSimplify:`AI Упрощение текста`,aiBlindMode:`Режим для незрячих (AI)`,on:`ВКЛ`,off:`ВЫКЛ`,resetSettings:`Сбросить настройки`,adminMode:`Режим администратора`,adminAccess:`Admin доступ`,adminLoggedIn:`Вы вошли как администратор`,adminLogout:`Выйти из аккаунта`,adminPrompt:`Введите ключ для активации режима обучения`,adminLogin:`Войти`,close:`Закрыть`,inclusion:`Инклюзия`,tabChat:`Чат`,tabSettings:`Настройки`,madeInKazakhstan:`Сделано в Казахстане 🇰🇿`,closeWidgetAria:`Закрыть`,widgetDialogAria:`BariWeb Accessibility Widget`,triggerAria:`Открыть/Закрыть меню доступности`,adminKeyPlaceholder:`Admin Key`},kz:{announceVoiceInputAvailable:`Дауыстық енгізу қолжетімді. Түйме төменгі оң жақ бұрышта.`,announceWidgetOpened:`Виджет ашылды.`,announceSwitchedToChat:`Чатқа ауысты. Дауыстық енгізу қолжетімді.`,errorMicNotSupported:`Микрофонға қолдау жоқ.`,errorNoMicAccess:`Микрофонға рұқсат жоқ.`,errorProcessing:`Өңдеу қатесі.`,errorTooShort:`Жазба тым қысқа.`,errorSpeechNotRecognized:`Сөйлеу танылмады.`,errorRecognition:`Тану қатесі.`,screenLabelPrefix:`Бетте:`,chatEmptyTitle:`Сіздің көмекшіңіз`,chatEmptySub:`Міндетті сипаттаңыз — мен керек батырмаларды тауып, өрістерді толтырамын.`,confirmAction:`Әрекетті растау`,cancel:`Бас тарту`,listening:`Тыңдап тұрмын... (үнсіздікте тоқтаймын)`,recognizingSpeech:`Сөйлеуді танып жатырмын...`,micAria:`Дауыстық енгізуді қосу (жазу үшін ұстап тұрыңыз)`,inputPlaceholder:`Хабарлама енгізіңіз...`,inputAria:`Хабарлама енгізу өрісі`,ttsDisableAria:`Жауап дауысын өшіру`,ttsEnableAria:`Жауап дауысын қосу`,sendAria:`Хабарламаны жіберу`,tileTextSize:`Мәтін өлшемі`,tileMonochrome:`Қ/А`,valueMonochrome:`Монохром`,tileContrast:`Контраст`,valueDark:`Қою`,tileLinks:`Сілтемелер`,valueHighlight:`Белгілеу`,tileSpacing:`Аралықтар`,valueEnlarge:`Үлкейту`,tileFont:`Қаріп`,valueDyslexia:`Дислексия`,tileCursor:`Курсор`,tileVoice:`Дауыс`,valueRecording:`Жазып жатыр...`,valuePress:`Басыңыз`,colorSetup:`Түсті баптау`,tabBackground:`Фон`,tabHeader:`Тақырып`,tabText:`Мәтін`,decrease:`Азайту`,hue:`Реңк`,increase:`Көбейту`,recognitionLanguage:`Тіл`,changeRecognitionLanguage:`Тану тілін өзгерту`,languageAuto:`Автоанықтау`,languageKz:`Қазақша`,languageRu:`Орысша`,languageEn:`Ағылшынша`,aiSimplify:`AI мәтінді жеңілдету`,aiBlindMode:`Көру қабілеті нашарларға режим (AI)`,on:`ҚОС`,off:`ӨШІК`,resetSettings:`Баптауларды қалпына келтіру`,adminMode:`Әкімші режимі`,adminAccess:`Admin қолжетімділігі`,adminLoggedIn:`Сіз әкімші ретінде кірдіңіз`,adminLogout:`Аккаунттан шығу`,adminPrompt:`Оқыту режимін қосу үшін кілт енгізіңіз`,adminLogin:`Кіру`,close:`Жабу`,inclusion:`Инклюзия`,tabChat:`Чат`,tabSettings:`Баптаулар`,madeInKazakhstan:`Қазақстанда жасалған 🇰🇿`,closeWidgetAria:`Жабу`,widgetDialogAria:`BariWeb қолжетімділік виджеті`,triggerAria:`Қолжетімділік мәзірін ашу/жабу`,adminKeyPlaceholder:`Admin Key`},en:{announceVoiceInputAvailable:`Voice input is available. The button is in the bottom-right corner.`,announceWidgetOpened:`Widget opened.`,announceSwitchedToChat:`Switched to chat. Voice input is available.`,errorMicNotSupported:`Microphone is not supported.`,errorNoMicAccess:`No access to microphone.`,errorProcessing:`Processing error.`,errorTooShort:`Recording is too short.`,errorSpeechNotRecognized:`Speech was not recognized.`,errorRecognition:`Recognition error.`,screenLabelPrefix:`On page:`,chatEmptyTitle:`Your assistant`,chatEmptySub:`Describe your task — I will find the right buttons and fill fields for you.`,confirmAction:`Confirm action`,cancel:`Cancel`,listening:`Listening... (will stop on silence)`,recognizingSpeech:`Recognizing speech...`,micAria:`Enable voice input (hold to record)`,inputPlaceholder:`Type a message...`,inputAria:`Message input field`,ttsDisableAria:`Disable answer voice`,ttsEnableAria:`Enable answer voice`,sendAria:`Send message`,tileTextSize:`Text size`,tileMonochrome:`B/W`,valueMonochrome:`Monochrome`,tileContrast:`Contrast`,valueDark:`Dark`,tileLinks:`Links`,valueHighlight:`Highlight`,tileSpacing:`Spacing`,valueEnlarge:`Enlarge`,tileFont:`Font`,valueDyslexia:`Dyslexia`,tileCursor:`Cursor`,tileVoice:`Voice`,valueRecording:`Recording...`,valuePress:`Press`,colorSetup:`Color setup`,tabBackground:`Background`,tabHeader:`Header`,tabText:`Text`,decrease:`Decrease`,hue:`Hue`,increase:`Increase`,recognitionLanguage:`Language`,changeRecognitionLanguage:`Change recognition language`,languageAuto:`Auto detect`,languageKz:`Kazakh`,languageRu:`Russian`,languageEn:`English`,aiSimplify:`AI text simplification`,aiBlindMode:`Blind mode (AI)`,on:`ON`,off:`OFF`,resetSettings:`Reset settings`,adminMode:`Administrator mode`,adminAccess:`Admin access`,adminLoggedIn:`You are logged in as administrator`,adminLogout:`Log out`,adminPrompt:`Enter key to activate training mode`,adminLogin:`Log in`,close:`Close`,inclusion:`Inclusion`,tabChat:`Chat`,tabSettings:`Settings`,madeInKazakhstan:`Made in Kazakhstan 🇰🇿`,closeWidgetAria:`Close`,widgetDialogAria:`BariWeb Accessibility Widget`,triggerAria:`Open/close accessibility menu`,adminKeyPlaceholder:`Admin Key`}},$=class extends B{static{this.styles=[dt]}constructor(){super(),this._a11y=new pt(this),this._aiA11y=new kt(this),this._chat=new It(this),this.clientId=``,this._isOpen=!1,this._activeTab=`chat`,this._inputValue=``,this._isAdmin=!1,this._adminPassword=``,this._authError=``,this._currentScreenLabel=``,this._sttState=`idle`,this._sttLanguageMode=`auto`,this._sttError=``,this._adminClickCount=0,this._showAdminLogin=!1,this._mediaStream=null,this._audioContext=null,this._analyser=null,this._scriptProcessor=null,this._pcmChunks=[],this._sampleRate=44100,this._recordingStartTs=0,this._silenceStartedTs=null,this._silenceIntervalId=null,this._maxDurationTimeoutId=null,this._adminClickTimer=null,this._handleGlobalKeydown=e=>{this._isOpen&&e.altKey&&e.code===`KeyV`&&(e.preventDefault(),this._toggleVoice())};try{let e=localStorage.getItem(Wt);(e===`auto`||e===`kz`||e===`ru`||e===`en`)&&(this._sttLanguageMode=e)}catch{}this._checkAuthStatus()}_setSttLanguageMode(e){this._sttLanguageMode=e;try{localStorage.setItem(Wt,e)}catch{}}_uiLang(){return this._sttLanguageMode===`kz`?`kz`:this._sttLanguageMode===`en`?`en`:`ru`}_t(e){return Xt[this._uiLang()][e]??Xt.ru[e]??e}async _checkAuthStatus(){let e=localStorage.getItem(`bw_admin_token`);if(e)try{(await fetch(`http://localhost:8000/auth/login/widget/verify`,{headers:{Authorization:`Bearer ${e}`}})).ok?(this._isAdmin=!0,this._loadAdminUI()):localStorage.removeItem(`bw_admin_token`)}catch{try{let t=JSON.parse(atob(e.split(`.`)[1]));t.exp*1e3>Date.now()&&t.role===`admin`?(this._isAdmin=!0,this._loadAdminUI()):localStorage.removeItem(`bw_admin_token`)}catch{localStorage.removeItem(`bw_admin_token`)}}}async _loadAdminUI(){try{let{initAdminMode:e}=await Promise.resolve().then(()=>(Ut(),Lt));e(),Y.isAutoDiscoveryEnabled=!0}catch(e){console.error(`Admin UI load failed`,e)}}async _handleAdminLogin(){if(this._authError=``,!this.clientId){this._authError=`Client ID not configured`;return}try{let e=await fetch(`http://localhost:8000/auth/login/widget`,{method:`POST`,headers:{"Content-Type":`application/json`},body:JSON.stringify({client_public_id:this.clientId,admin_key:this._adminPassword})});if(e.ok){let{access_token:t}=await e.json();localStorage.setItem(`bw_admin_token`,t),this._isAdmin=!0,this._showAdminLogin=!1,this._loadAdminUI()}else this._authError=(await e.json().catch(()=>({}))).detail||`Invalid admin key`}catch{this._authError=`Connection failed`}}_handleAdminLogout(){localStorage.removeItem(`bw_admin_token`),this._isAdmin=!1,this._adminPassword=``,this._showAdminLogin=!1,Y.isAutoDiscoveryEnabled=!1,document.querySelector(`#bw-admin-wrapper`)?.remove()}_handleLogoClick(){this._adminClickCount++,this._adminClickCount>=5&&(this._showAdminLogin=!this._showAdminLogin,this._adminClickCount=0),this._adminClickTimer&&clearTimeout(this._adminClickTimer),this._adminClickTimer=setTimeout(()=>{this._adminClickCount=0},2e3)}connectedCallback(){super.connectedCallback(),Y.start(),Y.onStateChange(async e=>{try{let t=await fetch(`http://localhost:8000/v1/training/match-screen`,{method:`POST`,headers:{"Content-Type":`application/json`,"X-Client-ID":this.clientId||window.__BARIWEB_CLIENT_ID__||``},body:JSON.stringify({fingerprint:e.fingerprint})});if(t.ok){let e=await t.json();this._currentScreenLabel=e.matched?e.label:``}}catch{}}),window.addEventListener(`keydown`,this._handleGlobalKeydown)}disconnectedCallback(){super.disconnectedCallback(),Y.stop(),this._cleanupRecording(),window.removeEventListener(`keydown`,this._handleGlobalKeydown)}_announce(e){if(`speechSynthesis`in window){let t=new SpeechSynthesisUtterance(e);t.lang=this._uiLang()===`kz`?`kk-KZ`:this._uiLang()===`en`?`en-US`:`ru-RU`,window.speechSynthesis.speak(t)}}_beep(e){try{let t=new(window.AudioContext||window.webkitAudioContext),n=t.createOscillator(),r=t.createGain();n.type=`sine`,n.frequency.setValueAtTime(e,t.currentTime),r.gain.setValueAtTime(.1,t.currentTime),r.gain.exponentialRampToValueAtTime(1e-5,t.currentTime+.1),n.connect(r),r.connect(t.destination),n.start(),n.stop(t.currentTime+.1)}catch{}}_toggle(){this._isOpen=!this._isOpen,this._isOpen&&(setTimeout(()=>this._announce(this._t(`announceVoiceInputAvailable`)),500),this._scrollMessages())}setOpen(e){this._isOpen=e,e&&(this._announce(this._t(`announceWidgetOpened`)),this._scrollMessages())}_setTab(e){this._activeTab=e,e===`chat`&&(this._announce(this._t(`announceSwitchedToChat`)),this._scrollMessages(),setTimeout(()=>{this.renderRoot?.querySelector(`#bw-voice-btn`)?.focus()},300))}_handleInput(e){this._inputValue=e.target.value}_handleKeydown(e){e.key===`Enter`&&!e.shiftKey&&(e.preventDefault(),this._handleSend()),e.code===`Space`&&e.target.tagName!==`INPUT`&&(e.preventDefault(),this._sttState===`idle`&&this._startRecording())}async _handleSend(){let e=this._inputValue.trim();if(!e||this._chat.isLoading||this._sttState!==`idle`)return;this._inputValue=``;let t=this._chat.sendMessage(e,!1);this._scrollMessages(),await t,this._scrollMessages()}_scrollMessages(){this.updateComplete.then(()=>{this._messagesEl&&(this._messagesEl.scrollTop=this._messagesEl.scrollHeight)})}_getCurrentHue(){let e=this._a11y.settings;return e.activeColorTab===`background`?e.customBgHue||0:e.activeColorTab===`header`?e.customHeaderHue||0:e.customContentHue||0}_resetWidgetSettings(){this._a11y.reset(),this._aiA11y.simplifyEnabled&&this._aiA11y.toggleSimplify(),this._aiA11y.autoA11yEnabled&&this._aiA11y.toggleAutoA11y(),this._setSttLanguageMode(`auto`),this.requestUpdate()}_clearSttTimers(){this._silenceIntervalId!==null&&(window.clearInterval(this._silenceIntervalId),this._silenceIntervalId=null),this._maxDurationTimeoutId!==null&&(window.clearTimeout(this._maxDurationTimeoutId),this._maxDurationTimeoutId=null)}_cleanupRecording(){this._clearSttTimers(),this._analyser=null,this._scriptProcessor&&=(this._scriptProcessor.disconnect(),this._scriptProcessor.onaudioprocess=null,null),this._audioContext&&=(this._audioContext.close().catch(()=>{}),null),this._mediaStream&&=(this._mediaStream.getTracks().forEach(e=>e.stop()),null),this._pcmChunks=[],this._silenceStartedTs=null}async _toggleVoice(){if(this._sttState!==`processing`){if(this._sttState===`recording`){this._stopRecording();return}await this._startRecording()}}async _startRecording(){if(!navigator.mediaDevices?.getUserMedia){this._sttState=`error`,this._sttError=this._t(`errorMicNotSupported`);return}try{this._cleanupRecording(),this._sttError=``;let e=await navigator.mediaDevices.getUserMedia({audio:!0});this._mediaStream=e,this._pcmChunks=[],this._recordingStartTs=Date.now(),this._silenceStartedTs=null,this._audioContext=new AudioContext,this._sampleRate=this._audioContext.sampleRate;let t=this._audioContext.createMediaStreamSource(e);this._analyser=this._audioContext.createAnalyser(),this._analyser.fftSize=2048,t.connect(this._analyser),this._scriptProcessor=this._audioContext.createScriptProcessor(4096,1,1),t.connect(this._scriptProcessor),this._scriptProcessor.connect(this._audioContext.destination),this._scriptProcessor.onaudioprocess=e=>{this._sttState===`recording`&&(this._pcmChunks.push(new Float32Array(e.inputBuffer.getChannelData(0))),e.outputBuffer.getChannelData(0).fill(0))},this._sttState=`recording`,this._beep(880),this._maxDurationTimeoutId=window.setTimeout(()=>{this._sttState===`recording`&&this._stopRecording()},Jt);let n=new Uint8Array(this._analyser.fftSize);this._silenceIntervalId=window.setInterval(()=>{if(!this._analyser||this._sttState!==`recording`)return;this._analyser.getByteTimeDomainData(n);let e=0;for(let t=0;t<n.length;t++){let r=(n[t]-128)/128;e+=r*r}Math.sqrt(e/n.length)<Kt?this._silenceStartedTs?Date.now()-this._silenceStartedTs>=qt&&this._stopRecording():this._silenceStartedTs=Date.now():this._silenceStartedTs=null},Gt)}catch{this._sttState=`error`,this._sttError=this._t(`errorNoMicAccess`),this._cleanupRecording()}}_stopRecording(){this._sttState===`recording`&&(this._clearSttTimers(),this._sttState=`processing`,this._beep(440),this._finalizeRecording().catch(e=>{this._sttState=`error`,this._sttError=e?.message||this._t(`errorProcessing`)}))}async _finalizeRecording(){let e=Date.now()-this._recordingStartTs,t=this._pcmChunks.reduce((e,t)=>e+t.length,0),n=new Float32Array(t),r=0;for(let e of this._pcmChunks)n.set(e,r),r+=e.length;let i=this._encodeWav(n,this._sampleRate);if(this._cleanupRecording(),e<Yt||i.size===0){this._sttState=`error`,this._sttError=this._t(`errorTooShort`);return}try{let e=(await this._chat.transcribeAudio(i,this._sttLanguageMode)).text?.trim();if(!e){this._sttState=`error`,this._sttError=this._t(`errorSpeechNotRecognized`);return}await this._chat.sendMessage(e,!0),this._sttState=`idle`,this._sttError=``,this._inputValue=``,this._scrollMessages()}catch(e){this._sttState=`error`,this._sttError=e?.message||this._t(`errorRecognition`)}}_encodeWav(e,t){let n=t*2,r=e.length*2,i=new ArrayBuffer(44+r),a=new DataView(i),o=(e,t)=>{for(let n=0;n<t.length;n++)a.setUint8(e+n,t.charCodeAt(n))};o(0,`RIFF`),a.setUint32(4,36+r,!0),o(8,`WAVE`),o(12,`fmt `),a.setUint32(16,16,!0),a.setUint16(20,1,!0),a.setUint16(22,1,!0),a.setUint32(24,t,!0),a.setUint32(28,n,!0),a.setUint16(32,2,!0),a.setUint16(34,16,!0),o(36,`data`),a.setUint32(40,r,!0);let s=44;for(let t=0;t<e.length;t++){let n=Math.max(-1,Math.min(1,e[t]));a.setInt16(s,n<0?n*32768:n*32767,!0),s+=2}return new Blob([i],{type:`audio/wav`})}_vibrate(){`vibrate`in navigator&&navigator.vibrate(20)}_renderChatTab(){let e=this._chat.messages,t=this._chat.isLoading,n=this._chat.pendingConfirmation,r=t||this._sttState===`processing`,i=e=>this._t(e);return j`
1163
+ `,Z=null,Q=null}));Dt();var Wt=`bw-stt-lang-v1`,Gt=200,Kt=.015,qt=1200,Jt=2e4,Yt=350,Xt={ru:{announceVoiceInputAvailable:`Голосовой ввод доступен. Кнопка в нижнем правом углу.`,announceWidgetOpened:`Виджет открыт.`,announceSwitchedToChat:`Переход в чат. Голосовой ввод доступен.`,errorMicNotSupported:`Микрофон не поддерживается.`,errorNoMicAccess:`Нет доступа к микрофону.`,errorProcessing:`Ошибка обработки.`,errorTooShort:`Слишком короткая запись.`,errorSpeechNotRecognized:`Речь не распознана.`,errorRecognition:`Ошибка распознавания.`,screenLabelPrefix:`На странице:`,chatEmptyTitle:`Ваш помощник`,chatEmptySub:`Опишите задачу — я найду нужные кнопки и заполню поля за вас.`,confirmAction:`Подтвердить действие`,cancel:`Отменить`,listening:`Слушаю... (остановлюсь по тишине)`,recognizingSpeech:`Распознаю речь...`,micAria:`Включить голосовой ввод (удерживайте для записи)`,inputPlaceholder:`Введите сообщение...`,inputAria:`Текстовое поле ввода сообщения`,ttsDisableAria:`Выключить озвучку ответа`,ttsEnableAria:`Включить озвучку ответа`,sendAria:`Отправить сообщение`,tileTextSize:`Размер текста`,tileMonochrome:`Ч/Б`,valueMonochrome:`Монохром`,tileContrast:`Контраст`,valueDark:`Тёмный`,tileLinks:`Ссылки`,valueHighlight:`Выделить`,tileSpacing:`Отступы`,valueEnlarge:`Увеличить`,tileFont:`Шрифт`,valueDyslexia:`Дислексия`,tileCursor:`Курсор`,tileVoice:`Голос`,valueRecording:`Запись...`,valuePress:`Нажмите`,colorSetup:`Настройка цвета`,tabBackground:`Фон`,tabHeader:`Шапка`,tabText:`Текст`,decrease:`Уменьшить`,hue:`Оттенок`,increase:`Увеличить`,recognitionLanguage:`Язык`,changeRecognitionLanguage:`Изменить язык распознавания`,languageAuto:`Автоопределение`,languageKz:`Казахский`,languageRu:`Русский`,languageEn:`Английский`,aiSimplify:`AI Упрощение текста`,aiBlindMode:`Режим для незрячих (AI)`,on:`ВКЛ`,off:`ВЫКЛ`,resetSettings:`Сбросить настройки`,adminMode:`Режим администратора`,adminAccess:`Admin доступ`,adminLoggedIn:`Вы вошли как администратор`,adminLogout:`Выйти из аккаунта`,adminPrompt:`Введите ключ для активации режима обучения`,adminLogin:`Войти`,close:`Закрыть`,inclusion:`Инклюзия`,tabChat:`Чат`,tabSettings:`Настройки`,madeInKazakhstan:`Сделано в Казахстане 🇰🇿`,closeWidgetAria:`Закрыть`,widgetDialogAria:`BariWeb Accessibility Widget`,triggerAria:`Открыть/Закрыть меню доступности`,adminKeyPlaceholder:`Admin Key`},kz:{announceVoiceInputAvailable:`Дауыстық енгізу қолжетімді. Түйме төменгі оң жақ бұрышта.`,announceWidgetOpened:`Виджет ашылды.`,announceSwitchedToChat:`Чатқа ауысты. Дауыстық енгізу қолжетімді.`,errorMicNotSupported:`Микрофонға қолдау жоқ.`,errorNoMicAccess:`Микрофонға рұқсат жоқ.`,errorProcessing:`Өңдеу қатесі.`,errorTooShort:`Жазба тым қысқа.`,errorSpeechNotRecognized:`Сөйлеу танылмады.`,errorRecognition:`Тану қатесі.`,screenLabelPrefix:`Бетте:`,chatEmptyTitle:`Сіздің көмекшіңіз`,chatEmptySub:`Міндетті сипаттаңыз — мен керек батырмаларды тауып, өрістерді толтырамын.`,confirmAction:`Әрекетті растау`,cancel:`Бас тарту`,listening:`Тыңдап тұрмын... (үнсіздікте тоқтаймын)`,recognizingSpeech:`Сөйлеуді танып жатырмын...`,micAria:`Дауыстық енгізуді қосу (жазу үшін ұстап тұрыңыз)`,inputPlaceholder:`Хабарлама енгізіңіз...`,inputAria:`Хабарлама енгізу өрісі`,ttsDisableAria:`Жауап дауысын өшіру`,ttsEnableAria:`Жауап дауысын қосу`,sendAria:`Хабарламаны жіберу`,tileTextSize:`Мәтін өлшемі`,tileMonochrome:`Қ/А`,valueMonochrome:`Монохром`,tileContrast:`Контраст`,valueDark:`Қою`,tileLinks:`Сілтемелер`,valueHighlight:`Белгілеу`,tileSpacing:`Аралықтар`,valueEnlarge:`Үлкейту`,tileFont:`Қаріп`,valueDyslexia:`Дислексия`,tileCursor:`Курсор`,tileVoice:`Дауыс`,valueRecording:`Жазып жатыр...`,valuePress:`Басыңыз`,colorSetup:`Түсті баптау`,tabBackground:`Фон`,tabHeader:`Тақырып`,tabText:`Мәтін`,decrease:`Азайту`,hue:`Реңк`,increase:`Көбейту`,recognitionLanguage:`Тіл`,changeRecognitionLanguage:`Тану тілін өзгерту`,languageAuto:`Автоанықтау`,languageKz:`Қазақша`,languageRu:`Орысша`,languageEn:`Ағылшынша`,aiSimplify:`AI мәтінді жеңілдету`,aiBlindMode:`Көру қабілеті нашарларға режим (AI)`,on:`ҚОС`,off:`ӨШІК`,resetSettings:`Баптауларды қалпына келтіру`,adminMode:`Әкімші режимі`,adminAccess:`Admin қолжетімділігі`,adminLoggedIn:`Сіз әкімші ретінде кірдіңіз`,adminLogout:`Аккаунттан шығу`,adminPrompt:`Оқыту режимін қосу үшін кілт енгізіңіз`,adminLogin:`Кіру`,close:`Жабу`,inclusion:`Инклюзия`,tabChat:`Чат`,tabSettings:`Баптаулар`,madeInKazakhstan:`Қазақстанда жасалған 🇰🇿`,closeWidgetAria:`Жабу`,widgetDialogAria:`BariWeb қолжетімділік виджеті`,triggerAria:`Қолжетімділік мәзірін ашу/жабу`,adminKeyPlaceholder:`Admin Key`},en:{announceVoiceInputAvailable:`Voice input is available. The button is in the bottom-right corner.`,announceWidgetOpened:`Widget opened.`,announceSwitchedToChat:`Switched to chat. Voice input is available.`,errorMicNotSupported:`Microphone is not supported.`,errorNoMicAccess:`No access to microphone.`,errorProcessing:`Processing error.`,errorTooShort:`Recording is too short.`,errorSpeechNotRecognized:`Speech was not recognized.`,errorRecognition:`Recognition error.`,screenLabelPrefix:`On page:`,chatEmptyTitle:`Your assistant`,chatEmptySub:`Describe your task — I will find the right buttons and fill fields for you.`,confirmAction:`Confirm action`,cancel:`Cancel`,listening:`Listening... (will stop on silence)`,recognizingSpeech:`Recognizing speech...`,micAria:`Enable voice input (hold to record)`,inputPlaceholder:`Type a message...`,inputAria:`Message input field`,ttsDisableAria:`Disable answer voice`,ttsEnableAria:`Enable answer voice`,sendAria:`Send message`,tileTextSize:`Text size`,tileMonochrome:`B/W`,valueMonochrome:`Monochrome`,tileContrast:`Contrast`,valueDark:`Dark`,tileLinks:`Links`,valueHighlight:`Highlight`,tileSpacing:`Spacing`,valueEnlarge:`Enlarge`,tileFont:`Font`,valueDyslexia:`Dyslexia`,tileCursor:`Cursor`,tileVoice:`Voice`,valueRecording:`Recording...`,valuePress:`Press`,colorSetup:`Color setup`,tabBackground:`Background`,tabHeader:`Header`,tabText:`Text`,decrease:`Decrease`,hue:`Hue`,increase:`Increase`,recognitionLanguage:`Language`,changeRecognitionLanguage:`Change recognition language`,languageAuto:`Auto detect`,languageKz:`Kazakh`,languageRu:`Russian`,languageEn:`English`,aiSimplify:`AI text simplification`,aiBlindMode:`Blind mode (AI)`,on:`ON`,off:`OFF`,resetSettings:`Reset settings`,adminMode:`Administrator mode`,adminAccess:`Admin access`,adminLoggedIn:`You are logged in as administrator`,adminLogout:`Log out`,adminPrompt:`Enter key to activate training mode`,adminLogin:`Log in`,close:`Close`,inclusion:`Inclusion`,tabChat:`Chat`,tabSettings:`Settings`,madeInKazakhstan:`Made in Kazakhstan 🇰🇿`,closeWidgetAria:`Close`,widgetDialogAria:`BariWeb Accessibility Widget`,triggerAria:`Open/close accessibility menu`,adminKeyPlaceholder:`Admin Key`}},$=class extends B{static{this.styles=[dt]}constructor(){super(),this._a11y=new pt(this),this._aiA11y=new kt(this),this._chat=new It(this),this.clientId=``,this._isOpen=!1,this._activeTab=`chat`,this._inputValue=``,this._isAdmin=!1,this._adminPassword=``,this._authError=``,this._currentScreenLabel=``,this._sttState=`idle`,this._sttLanguageMode=`auto`,this._sttError=``,this._adminClickCount=0,this._showAdminLogin=!1,this._mediaStream=null,this._audioContext=null,this._analyser=null,this._scriptProcessor=null,this._pcmChunks=[],this._sampleRate=44100,this._recordingStartTs=0,this._silenceStartedTs=null,this._silenceIntervalId=null,this._maxDurationTimeoutId=null,this._adminClickTimer=null,this._handleGlobalKeydown=e=>{this._isOpen&&e.altKey&&e.code===`KeyV`&&(e.preventDefault(),this._toggleVoice())};try{let e=localStorage.getItem(Wt);(e===`auto`||e===`kz`||e===`ru`||e===`en`)&&(this._sttLanguageMode=e)}catch{}this._checkAuthStatus()}_setSttLanguageMode(e){this._sttLanguageMode=e;try{localStorage.setItem(Wt,e)}catch{}}_uiLang(){return this._sttLanguageMode===`kz`?`kz`:this._sttLanguageMode===`en`?`en`:`ru`}_t(e){return Xt[this._uiLang()][e]??Xt.ru[e]??e}async _checkAuthStatus(){let e=localStorage.getItem(`bw_admin_token`);if(e)try{(await fetch(`http://localhost:8000/auth/login/widget/verify`,{headers:{Authorization:`Bearer ${e}`}})).ok?(this._isAdmin=!0,this._loadAdminUI()):localStorage.removeItem(`bw_admin_token`)}catch{try{let t=JSON.parse(atob(e.split(`.`)[1]));t.exp*1e3>Date.now()&&t.role===`admin`?(this._isAdmin=!0,this._loadAdminUI()):localStorage.removeItem(`bw_admin_token`)}catch{localStorage.removeItem(`bw_admin_token`)}}}async _loadAdminUI(){try{let{initAdminMode:e}=await Promise.resolve().then(()=>(Ut(),Lt));e(),Y.isAutoDiscoveryEnabled=!0}catch(e){console.error(`Admin UI load failed`,e)}}async _handleAdminLogin(){if(this._authError=``,!this.clientId){this._authError=`Client ID not configured`;return}try{let e=await fetch(`http://localhost:8000/auth/login/widget`,{method:`POST`,headers:{"Content-Type":`application/json`},body:JSON.stringify({client_public_id:this.clientId,admin_key:this._adminPassword})});if(e.ok){let{access_token:t}=await e.json();localStorage.setItem(`bw_admin_token`,t),this._isAdmin=!0,this._showAdminLogin=!1,this._loadAdminUI()}else this._authError=(await e.json().catch(()=>({}))).detail||`Invalid admin key`}catch{this._authError=`Connection failed`}}_handleAdminLogout(){localStorage.removeItem(`bw_admin_token`),this._isAdmin=!1,this._adminPassword=``,this._showAdminLogin=!1,Y.isAutoDiscoveryEnabled=!1,document.querySelector(`#bw-admin-wrapper`)?.remove()}_handleLogoClick(){this._adminClickCount++,this._adminClickCount>=5&&(this._showAdminLogin=!this._showAdminLogin,this._adminClickCount=0),this._adminClickTimer&&clearTimeout(this._adminClickTimer),this._adminClickTimer=setTimeout(()=>{this._adminClickCount=0},2e3)}connectedCallback(){super.connectedCallback(),Y.start(),Y.onStateChange(async e=>{try{let t=await fetch(`http://localhost:8000/v1/training/match-screen`,{method:`POST`,headers:{"Content-Type":`application/json`,"X-Client-ID":this.clientId||window.__BARIWEB_CLIENT_ID__||``},body:JSON.stringify({fingerprint:e.fingerprint})});if(t.ok){let e=await t.json();this._currentScreenLabel=e.matched?e.label:``}}catch{}}),window.addEventListener(`keydown`,this._handleGlobalKeydown)}disconnectedCallback(){super.disconnectedCallback(),Y.stop(),this._cleanupRecording(),window.removeEventListener(`keydown`,this._handleGlobalKeydown)}_beep(e){try{let t=new(window.AudioContext||window.webkitAudioContext),n=t.createOscillator(),r=t.createGain();n.type=`sine`,n.frequency.setValueAtTime(e,t.currentTime),r.gain.setValueAtTime(.1,t.currentTime),r.gain.exponentialRampToValueAtTime(1e-5,t.currentTime+.1),n.connect(r),r.connect(t.destination),n.start(),n.stop(t.currentTime+.1)}catch{}}_toggle(){this._isOpen=!this._isOpen,this._isOpen&&this._scrollMessages()}setOpen(e){this._isOpen=e,e&&this._scrollMessages()}_setTab(e){this._activeTab=e,e===`chat`&&(this._scrollMessages(),setTimeout(()=>{this.renderRoot?.querySelector(`#bw-voice-btn`)?.focus()},300))}_handleInput(e){this._inputValue=e.target.value}_handleKeydown(e){e.key===`Enter`&&!e.shiftKey&&(e.preventDefault(),this._handleSend()),e.code===`Space`&&e.target.tagName!==`INPUT`&&(e.preventDefault(),this._sttState===`idle`&&this._startRecording())}async _handleSend(){let e=this._inputValue.trim();if(!e||this._chat.isLoading||this._sttState!==`idle`)return;this._inputValue=``;let t=this._chat.sendMessage(e,!1);this._scrollMessages(),await t,this._scrollMessages()}_scrollMessages(){this.updateComplete.then(()=>{this._messagesEl&&(this._messagesEl.scrollTop=this._messagesEl.scrollHeight)})}_getCurrentHue(){let e=this._a11y.settings;return e.activeColorTab===`background`?e.customBgHue||0:e.activeColorTab===`header`?e.customHeaderHue||0:e.customContentHue||0}_resetWidgetSettings(){this._a11y.reset(),this._aiA11y.simplifyEnabled&&this._aiA11y.toggleSimplify(),this._aiA11y.autoA11yEnabled&&this._aiA11y.toggleAutoA11y(),this._setSttLanguageMode(`auto`),this.requestUpdate()}_clearSttTimers(){this._silenceIntervalId!==null&&(window.clearInterval(this._silenceIntervalId),this._silenceIntervalId=null),this._maxDurationTimeoutId!==null&&(window.clearTimeout(this._maxDurationTimeoutId),this._maxDurationTimeoutId=null)}_cleanupRecording(){this._clearSttTimers(),this._analyser=null,this._scriptProcessor&&=(this._scriptProcessor.disconnect(),this._scriptProcessor.onaudioprocess=null,null),this._audioContext&&=(this._audioContext.close().catch(()=>{}),null),this._mediaStream&&=(this._mediaStream.getTracks().forEach(e=>e.stop()),null),this._pcmChunks=[],this._silenceStartedTs=null}async _toggleVoice(){if(this._sttState!==`processing`){if(this._sttState===`recording`){this._stopRecording();return}await this._startRecording()}}async _startRecording(){if(!navigator.mediaDevices?.getUserMedia){this._sttState=`error`,this._sttError=this._t(`errorMicNotSupported`);return}try{this._cleanupRecording(),this._sttError=``;let e=await navigator.mediaDevices.getUserMedia({audio:!0});this._mediaStream=e,this._pcmChunks=[],this._recordingStartTs=Date.now(),this._silenceStartedTs=null,this._audioContext=new AudioContext,this._sampleRate=this._audioContext.sampleRate;let t=this._audioContext.createMediaStreamSource(e);this._analyser=this._audioContext.createAnalyser(),this._analyser.fftSize=2048,t.connect(this._analyser),this._scriptProcessor=this._audioContext.createScriptProcessor(4096,1,1),t.connect(this._scriptProcessor),this._scriptProcessor.connect(this._audioContext.destination),this._scriptProcessor.onaudioprocess=e=>{this._sttState===`recording`&&(this._pcmChunks.push(new Float32Array(e.inputBuffer.getChannelData(0))),e.outputBuffer.getChannelData(0).fill(0))},this._sttState=`recording`,this._beep(880),this._maxDurationTimeoutId=window.setTimeout(()=>{this._sttState===`recording`&&this._stopRecording()},Jt);let n=new Uint8Array(this._analyser.fftSize);this._silenceIntervalId=window.setInterval(()=>{if(!this._analyser||this._sttState!==`recording`)return;this._analyser.getByteTimeDomainData(n);let e=0;for(let t=0;t<n.length;t++){let r=(n[t]-128)/128;e+=r*r}Math.sqrt(e/n.length)<Kt?this._silenceStartedTs?Date.now()-this._silenceStartedTs>=qt&&this._stopRecording():this._silenceStartedTs=Date.now():this._silenceStartedTs=null},Gt)}catch{this._sttState=`error`,this._sttError=this._t(`errorNoMicAccess`),this._cleanupRecording()}}_stopRecording(){this._sttState===`recording`&&(this._clearSttTimers(),this._sttState=`processing`,this._beep(440),this._finalizeRecording().catch(e=>{this._sttState=`error`,this._sttError=e?.message||this._t(`errorProcessing`)}))}async _finalizeRecording(){let e=Date.now()-this._recordingStartTs,t=this._pcmChunks.reduce((e,t)=>e+t.length,0),n=new Float32Array(t),r=0;for(let e of this._pcmChunks)n.set(e,r),r+=e.length;let i=this._encodeWav(n,this._sampleRate);if(this._cleanupRecording(),e<Yt||i.size===0){this._sttState=`error`,this._sttError=this._t(`errorTooShort`);return}try{let e=(await this._chat.transcribeAudio(i,this._sttLanguageMode)).text?.trim();if(!e){this._sttState=`error`,this._sttError=this._t(`errorSpeechNotRecognized`);return}await this._chat.sendMessage(e,!0),this._sttState=`idle`,this._sttError=``,this._inputValue=``,this._scrollMessages()}catch(e){this._sttState=`error`,this._sttError=e?.message||this._t(`errorRecognition`)}}_encodeWav(e,t){let n=t*2,r=e.length*2,i=new ArrayBuffer(44+r),a=new DataView(i),o=(e,t)=>{for(let n=0;n<t.length;n++)a.setUint8(e+n,t.charCodeAt(n))};o(0,`RIFF`),a.setUint32(4,36+r,!0),o(8,`WAVE`),o(12,`fmt `),a.setUint32(16,16,!0),a.setUint16(20,1,!0),a.setUint16(22,1,!0),a.setUint32(24,t,!0),a.setUint32(28,n,!0),a.setUint16(32,2,!0),a.setUint16(34,16,!0),o(36,`data`),a.setUint32(40,r,!0);let s=44;for(let t=0;t<e.length;t++){let n=Math.max(-1,Math.min(1,e[t]));a.setInt16(s,n<0?n*32768:n*32767,!0),s+=2}return new Blob([i],{type:`audio/wav`})}_vibrate(){`vibrate`in navigator&&navigator.vibrate(20)}_renderChatTab(){let e=this._chat.messages,t=this._chat.isLoading,n=this._chat.pendingConfirmation,r=t||this._sttState===`processing`,i=e=>this._t(e);return j`
1164
1164
  <div class="chat-messages" id="bw-chat-messages">
1165
1165
  ${this._currentScreenLabel?j`
1166
1166
  <div class="screen-label-badge">
package/dist/bariweb.js CHANGED
@@ -2185,7 +2185,7 @@ var it = nt(q), J = (e) => I`${it(`
2185
2185
  }
2186
2186
  }, ut = "bw-tts-enabled-v1", dt = class {
2187
2187
  constructor() {
2188
- this.enabled = !0, this.enabled = this.loadEnabled(), "speechSynthesis" in window && (window.speechSynthesis.getVoices(), window.speechSynthesis.onvoiceschanged = () => {
2188
+ this.enabled = !1, this.enabled = this.loadEnabled(), "speechSynthesis" in window && (window.speechSynthesis.getVoices(), window.speechSynthesis.onvoiceschanged = () => {
2189
2189
  window.speechSynthesis.getVoices();
2190
2190
  });
2191
2191
  }
@@ -2218,9 +2218,9 @@ var it = nt(q), J = (e) => I`${it(`
2218
2218
  loadEnabled() {
2219
2219
  try {
2220
2220
  let e = localStorage.getItem(ut);
2221
- return e === null ? !0 : e !== "0";
2221
+ return e === null ? !1 : e !== "0";
2222
2222
  } catch {
2223
- return !0;
2223
+ return !1;
2224
2224
  }
2225
2225
  }
2226
2226
  detectLanguage(e) {
@@ -2915,12 +2915,6 @@ var gt = "bw-stt-lang-v1", _t = 200, vt = .015, yt = 1200, bt = 2e4, xt = 350, S
2915
2915
  disconnectedCallback() {
2916
2916
  super.disconnectedCallback(), t.stop(), this._cleanupRecording(), window.removeEventListener("keydown", this._handleGlobalKeydown);
2917
2917
  }
2918
- _announce(e) {
2919
- if ("speechSynthesis" in window) {
2920
- let t = new SpeechSynthesisUtterance(e);
2921
- t.lang = this._uiLang() === "kz" ? "kk-KZ" : this._uiLang() === "en" ? "en-US" : "ru-RU", window.speechSynthesis.speak(t);
2922
- }
2923
- }
2924
2918
  _beep(e) {
2925
2919
  try {
2926
2920
  let t = new (window.AudioContext || window.webkitAudioContext)(), n = t.createOscillator(), r = t.createGain();
@@ -2928,13 +2922,13 @@ var gt = "bw-stt-lang-v1", _t = 200, vt = .015, yt = 1200, bt = 2e4, xt = 350, S
2928
2922
  } catch {}
2929
2923
  }
2930
2924
  _toggle() {
2931
- this._isOpen = !this._isOpen, this._isOpen && (setTimeout(() => this._announce(this._t("announceVoiceInputAvailable")), 500), this._scrollMessages());
2925
+ this._isOpen = !this._isOpen, this._isOpen && this._scrollMessages();
2932
2926
  }
2933
2927
  setOpen(e) {
2934
- this._isOpen = e, e && (this._announce(this._t("announceWidgetOpened")), this._scrollMessages());
2928
+ this._isOpen = e, e && this._scrollMessages();
2935
2929
  }
2936
2930
  _setTab(e) {
2937
- this._activeTab = e, e === "chat" && (this._announce(this._t("announceSwitchedToChat")), this._scrollMessages(), setTimeout(() => {
2931
+ this._activeTab = e, e === "chat" && (this._scrollMessages(), setTimeout(() => {
2938
2932
  this.renderRoot?.querySelector("#bw-voice-btn")?.focus();
2939
2933
  }, 300));
2940
2934
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "bariweb-widget",
3
- "version": "0.1.13",
3
+ "version": "0.1.15",
4
4
  "type": "module",
5
5
  "main": "./dist/bariweb.iife.js",
6
6
  "module": "./dist/bariweb.js",