bariweb-widget 0.1.13 → 0.1.20

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.
@@ -879,7 +879,7 @@
879
879
  html[data-bw-has-custom-content] div:not(bw-widget *) {
880
880
  color: var(--bw-custom-content) !important;
881
881
  }
882
- `}_applySettings(){let e=document.documentElement;this._ensureGlobalStyles(),e.style.setProperty(`--bw-grayscale`,this.settings.monochrome?`100%`:`0%`);let t=1;this.settings.lowSaturation&&(t=.3),this.settings.highSaturation&&(t=2.5),e.style.setProperty(`--bw-saturation`,t.toString()),this.settings.customBgHue===null?e.removeAttribute(`data-bw-has-custom-bg`):(e.style.setProperty(`--bw-custom-bg`,`hsl(${this.settings.customBgHue}, 50%, 95%)`),e.setAttribute(`data-bw-has-custom-bg`,``)),this.settings.customHeaderHue===null?e.removeAttribute(`data-bw-has-custom-header`):(e.style.setProperty(`--bw-custom-header`,`hsl(${this.settings.customHeaderHue}, 70%, 30%)`),e.setAttribute(`data-bw-has-custom-header`,``)),this.settings.customContentHue===null?e.removeAttribute(`data-bw-has-custom-content`):(e.style.setProperty(`--bw-custom-content`,`hsl(${this.settings.customContentHue}, 60%, 40%)`),e.setAttribute(`data-bw-has-custom-content`,``)),this.settings.textScale>1?e.style.fontSize=`${this.settings.textScale*100}%`:e.style.fontSize=``;let n={"data-bw-monochrome":this.settings.monochrome,"data-bw-dark-high-contrast":this.settings.darkHighContrast,"data-bw-bright-high-contrast":this.settings.brightHighContrast,"data-bw-contrast-mode":this.settings.contrastMode,"data-bw-text-spacing":this.settings.textSpacing,"data-bw-dyslexic":this.settings.dyslexicFont,"data-bw-focus-visualizer":this.settings.focusVisualizer,"data-bw-cursor-magnifier":this.settings.cursorMagnifier,"data-bw-no-animations":this.settings.animationsDisabled,"data-bw-link-highlight":this.settings.linkHighlight,"data-bw-highlight-headers":this.settings.highlightHeaders,"data-bw-enlarge-buttons":this.settings.enlargeButtons};Object.entries(n).forEach(([t,n])=>{n?e.setAttribute(t,``):e.removeAttribute(t)});let r=this.host;r&&r.style.setProperty(`--bw-font-scale`,this.settings.textScale.toString())}toggleMonochrome(){this.settings.monochrome=!this.settings.monochrome,this._saveSettings()}toggleDarkHighContrast(){this.settings.darkHighContrast=!this.settings.darkHighContrast,this.settings.darkHighContrast&&(this.settings.brightHighContrast=!1,this.settings.contrastMode=!1),this._saveSettings()}toggleBrightHighContrast(){this.settings.brightHighContrast=!this.settings.brightHighContrast,this.settings.brightHighContrast&&(this.settings.darkHighContrast=!1,this.settings.contrastMode=!1),this._saveSettings()}toggleLowSaturation(){this.settings.lowSaturation=!this.settings.lowSaturation,this.settings.lowSaturation&&(this.settings.highSaturation=!1),this._saveSettings()}toggleHighSaturation(){this.settings.highSaturation=!this.settings.highSaturation,this.settings.highSaturation&&(this.settings.lowSaturation=!1),this._saveSettings()}toggleContrastMode(){this.settings.contrastMode=!this.settings.contrastMode,this.settings.contrastMode&&(this.settings.darkHighContrast=!1,this.settings.brightHighContrast=!1),this._saveSettings()}setCustomHue(e){this.settings.activeColorTab===`background`?this.settings.customBgHue=e:this.settings.activeColorTab===`header`?this.settings.customHeaderHue=e:this.settings.customContentHue=e,this._saveSettings()}resetCustomColors(){this.settings.customBgHue=null,this.settings.customHeaderHue=null,this.settings.customContentHue=null,this._saveSettings()}toggleHighlightHeaders(){this.settings.highlightHeaders=!this.settings.highlightHeaders,this._saveSettings()}toggleEnlargeButtons(){this.settings.enlargeButtons=!this.settings.enlargeButtons,this._saveSettings()}incrementTextScale(){this.settings.textScale>=1.5?this.settings.textScale=1:this.settings.textScale=parseFloat((this.settings.textScale+.1).toFixed(1)),this._saveSettings()}toggleTextSpacing(){this.settings.textSpacing=!this.settings.textSpacing,this._saveSettings()}toggleDyslexicFont(){this.settings.dyslexicFont=!this.settings.dyslexicFont,this._saveSettings()}toggleFocusVisualizer(){this.settings.focusVisualizer=!this.settings.focusVisualizer,this._saveSettings()}toggleCursorMagnifier(){this.settings.cursorMagnifier=!this.settings.cursorMagnifier,this._saveSettings()}toggleAnimations(){this.settings.animationsDisabled=!this.settings.animationsDisabled,this._saveSettings()}toggleLinkHighlight(){this.settings.linkHighlight=!this.settings.linkHighlight,this._saveSettings()}reset(){this.settings={...G},this._saveSettings()}};function K(e){try{let t=new URL(e),n=t.pathname;n=n.replace(vt,`:id`),n=n.replace(yt,`/:id`),n=n.replace(bt,`/:slug`),n=n.replace(xt,`/:id`);let r=new URLSearchParams;t.searchParams.forEach((e,t)=>{St.has(t)?r.set(`:${t}`,``):e.length<30&&!/^\d+$/.test(e)&&r.set(t,e)});let i=r.toString();return n.replace(/\/$/,``)+(i?`?${i}`:``)}catch{return e.replace(vt,`:id`).replace(/\/\d{1,20}(?=\/|$)/g,`/:id`).split(`?`)[0]}}function mt(e){let t=[`dialog`,`tooltip`,`menu`,`listbox`,`alertdialog`],n=e;for(;n&&n!==document.body;){let e=n.getAttribute(`role`)||``;if(t.includes(e)||n.hasAttribute(`data-radix-popper-content-wrapper`)||n.hasAttribute(`data-floating-ui-portal`))return!0;let r=typeof n.className==`string`?n.className:``;if(/popover|tooltip|dropdown-menu|floating|overlay/i.test(r))return!0;n=n.parentElement}return!1}function ht(e){let t=[`li`,`article`,`tr`,`dd`],n=e.parentElement,r=0;for(;n&&n!==document.body&&r<8;){let e=n.tagName.toLowerCase();if(t.includes(e))return!0;let i=typeof n.className==`string`?n.className:``;if(/\b(card|item|tile|post|entry|product|row-item|list-item|feed-item|cell)\b/i.test(i)){let e=n.parentElement?.children;if(e&&e.length>2)return!0}let a=n.getAttribute(`role`)||``;if(a===`listitem`||a===`row`||a===`gridcell`)return!0;n=n.parentElement,r++}return!1}function gt(e){let t=e,n=(t.getAttribute(`aria-label`)||t.getAttribute(`title`)||t.innerText||t.getAttribute(`placeholder`)||``).trim().toLowerCase();return!n||n.length<2||n.length>40||/^[\d\s₸$€%.,\-+:()]+$/.test(n)||/^\d{1,2}[./]\d{1,2}/.test(n)||Ct.has(n)?``:n.replace(/^[\p{Emoji}\s]+/u,``).trim().slice(0,30)}function _t(e){let t=5381;for(let n=0;n<e.length;n++)t=(t<<5)+t^e.charCodeAt(n);return(t>>>0).toString(16)}function q(){let e=[],t=K(window.location.href);e.push(`route:${t}`);let n=document.querySelector(`h1`);if(n){let t=n.innerText?.trim().toLowerCase();t&&t.length>1&&t.length<50&&!/\d{3,}/.test(t)&&e.push(`h1:${t.slice(0,30)}`)}let r=Array.from(document.querySelectorAll(`input:not([type="hidden"]):not([type="submit"]):not([type="radio"]):not([type="checkbox"]), textarea, select`)).slice(0,8);for(let t of r){if(mt(t))continue;let n=t,r=(n.getAttribute(`name`)||n.getAttribute(`placeholder`)||n.getAttribute(`aria-label`)||``).toLowerCase().trim().slice(0,25);r&&r.length>1&&!Ct.has(r)&&e.push(`field:${r}`)}let i=Array.from(document.querySelectorAll(`nav a, [role="navigation"] a`)).slice(0,6);for(let t of i){if(mt(t))continue;let n=gt(t);n&&e.push(`nav:${n}`)}let a=document.querySelector(`main`)||document.querySelector(`[role="main"]`)||document.getElementById(`root`);return a&&Array.from(a.querySelectorAll(`button:not([aria-hidden="true"]), [role="button"]:not([aria-hidden="true"])`)).filter(e=>!mt(e)&&!ht(e)).map(gt).filter(e=>e.length>1).reduce((e,t)=>e.includes(t)?e:[...e,t],[]).slice(0,3).forEach(t=>e.push(`btn:${t}`)),[...new Set(e)].sort().slice(0,15)}function J(){return`bw-${_t(q().join(`|`))}`}var vt,yt,bt,xt,St,Ct,wt=t((()=>{vt=/[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}/gi,yt=/\/\d{1,20}(?=\/|$)/g,bt=/\/[a-z0-9]+(?:-[a-z0-9]+)*-\d+(?=\/|$)/g,xt=/\/[0-9a-f]{8,}(?=\/|$)/gi,St=new Set([`id`,`userId`,`user_id`,`orderId`,`order_id`,`itemId`,`item_id`,`productId`,`product_id`,`token`,`key`,`ref`,`code`,`session`]),Ct=new Set(`ok,ок,okay,close,закрыть,cancel,отмена,yes,da,no,нет,да,submit,отправить,back,назад,next,далее,more,ещё,еще,menu,меню,...,•,·,loading,загрузка,open,открыть,expand,collapse,toggle,sort`.split(`,`))}));function Tt(e,t){let n=new Set([...e].filter(e=>t.has(e))),r=new Set([...e,...t]);return r.size===0?1:n.size/r.size}var Et,Y,Dt=t((()=>{wt(),Et=class{constructor(e=1500){this._observer=null,this._debounceTimer=null,this._lastTokens=new Set,this._lastUrl=``,this._callbacks=[],this._discoveryCallbacks=[],this._isDiscovering=!1,this.isAutoDiscoveryEnabled=!1,this._debounceMs=e}start(){this._observer||(this._lastTokens=new Set(q()),this._lastUrl=K(window.location.href),this._observer=new MutationObserver(()=>{this._debounceTimer&&clearTimeout(this._debounceTimer),this._debounceTimer=setTimeout(()=>this._onMutation(),this._debounceMs)}),this._observer.observe(document.body,{childList:!0,subtree:!0,attributes:!1,characterData:!1}))}stop(){this._observer?.disconnect(),this._observer=null,this._debounceTimer&&clearTimeout(this._debounceTimer)}onStateChange(e){this._callbacks.push(e)}onDiscovery(e){this._discoveryCallbacks.push(e)}get isDiscovering(){return this._isDiscovering}getLiveSnapshot(){let e=(e,t)=>{if(e.hasAttribute(`bw-private`)||e.hasAttribute(`data-bw-private`))return`[MASKED]`;if(!t)return t;let n=t.replace(/(?:\d[ \-]*?){13,16}/g,`****`);return n=n.replace(/\b\d{12}\b/g,`****`),n},t=Array.from(document.querySelectorAll(`h1, h2`)).map(t=>e(t,t.innerText?.trim()||``)).filter(Boolean).slice(0,3),n=Array.from(document.querySelectorAll(`button, a[href], [role="button"]`)).map(t=>{let n=t,r=e(n,(n.getAttribute(`aria-label`)||n.innerText||``).trim().slice(0,60));return{id:n.id||``,text:r}}).filter(e=>e.text.length>0).slice(0,30);return{url:window.location.href,headings:t,fingerprint:J(),elements:n}}async _onMutation(){if(document.readyState!==`complete`)return;let e=K(window.location.href),t=new Set(q());if(t.size<2)return;let n=J(),r=e!==this._lastUrl,i=Tt(this._lastTokens,t);if(r||i<.55){let a=r?`URL: ${this._lastUrl} → ${e}`:`Sim: ${i.toFixed(2)}`;console.log(`[Watcher] Screen change (${a})`),this._lastUrl=e,this._lastTokens=t;let o=this.getLiveSnapshot();if(this.isAutoDiscoveryEnabled){let e=this._buildTypedTokens();this._discover(n,e).catch(()=>{})}this._callbacks.forEach(e=>e(o))}}_buildTypedTokens(){let e=new Set,t=[],n=(n,r)=>{let i=r.trim().slice(0,40);if(!i||i.length<2)return;let a=`${n}:${i}`;e.has(a)||(e.add(a),t.push(a))};return document.querySelectorAll(`button, [role="button"]`).forEach(e=>{let t=e.innerText?.trim();t&&n(`btn`,t)}),document.querySelectorAll(`a[href]`).forEach(e=>{let t=(e.getAttribute(`aria-label`)||e.innerText)?.trim();t&&n(`a`,t)}),document.querySelectorAll(`input:not([type=hidden]), textarea, select`).forEach(e=>{let t=e.placeholder||e.name;t&&n(`input`,t)}),t.slice(0,8)}async _discover(e,t){let n=localStorage.getItem(`bw_admin_token`);if(n){this._isDiscovering=!0;try{let r=await fetch(`http://localhost:8000/v1/training/discover`,{method:`POST`,headers:{"Content-Type":`application/json`,Authorization:`Bearer ${n}`},body:JSON.stringify({fingerprint:e,tokens:t,page_url:window.location.href})});if(r.ok){let e=await r.json();console.log(`[Discovery] ${e.status} — ${e.label}`),this._discoveryCallbacks.forEach(t=>t(e))}else r.status===401?(console.warn(`[Discovery] Token expired — disabling auto-discovery`),localStorage.removeItem(`bw_admin_token`),this.isAutoDiscoveryEnabled=!1):console.warn(`[Discovery] Server error ${r.status}`)}catch(e){console.warn(`[Discovery] Network error`,e)}finally{this._isDiscovering=!1}}}async forceDiscovery(){let e=[...new Set(q())],t=J();await this._discover(t,e)}},Y=new Et(1500)}));Dt();var Ot=`http://localhost:8000`,kt=class{constructor(e){this.isFixing=!1,this.simplifyEnabled=!1,this.autoA11yEnabled=!1,this._onParagraphKeydown=e=>{if(this.simplifyEnabled&&(e.key===`Enter`||e.key===` `)&&e.target instanceof HTMLElement){if(e.target.closest(`bw-widget`)||e.target.closest(`.bw-ai-tooltip`))return;let t=e.target.tagName.toLowerCase();if([`p`,`span`,`div`,`li`,`article`,`h1`,`h2`,`h3`,`h4`,`h5`,`h6`].includes(t)){e.preventDefault(),e.stopPropagation();let t=e.target.getBoundingClientRect();this._triggerSimplify(e.target,t.left+window.scrollX,t.bottom+window.scrollY)}}},this._onParagraphClick=async e=>{if(!this.simplifyEnabled)return;let t=e.target;if(t.closest(`bw-widget`)||t.closest(`.bw-ai-tooltip`))return;let n=t.tagName.toLowerCase();if([`p`,`span`,`div`,`li`,`article`,`h1`,`h2`,`h3`,`h4`,`h5`,`h6`].includes(n)){let n=t.innerText?.trim();n&&n.length>20&&(e.preventDefault(),e.stopPropagation(),this._triggerSimplify(t,e.pageX,e.pageY))}},(this.host=e).addController(this),this.simplifyEnabled=localStorage.getItem(`bw-ai-simplify`)===`true`,this.autoA11yEnabled=localStorage.getItem(`bw-ai-autofix`)===`true`,Y.onStateChange(()=>{this.autoA11yEnabled&&!this.isFixing&&this.fixMarkup()}),this.autoA11yEnabled&&setTimeout(()=>this.fixMarkup(),1e3)}toggleAutoA11y(){this.autoA11yEnabled=!this.autoA11yEnabled,localStorage.setItem(`bw-ai-autofix`,this.autoA11yEnabled?`true`:`false`),this.autoA11yEnabled&&!this.isFixing&&this.fixMarkup(),this.host.requestUpdate()}hostConnected(){}hostDisconnected(){this.simplifyEnabled&&(document.body.removeEventListener(`click`,this._onParagraphClick,{capture:!0}),document.body.classList.remove(`bw-simplify-mode`))}_announce(e){let t=document.getElementById(`bw-ai-announcer`);t||(t=document.createElement(`div`),t.id=`bw-ai-announcer`,t.setAttribute(`aria-live`,`polite`),t.setAttribute(`aria-atomic`,`true`),Object.assign(t.style,{position:`absolute`,width:`1px`,height:`1px`,padding:`0`,margin:`-1px`,overflow:`hidden`,clip:`rect(0, 0, 0, 0)`,whiteSpace:`nowrap`,border:`0`}),document.body.appendChild(t)),t.textContent=e}async fixMarkup(){this.isFixing=!0,this.host.requestUpdate();try{let e=[];if(document.querySelectorAll(`img:not([alt]), img[alt=""]`).forEach(t=>{t.hasAttribute(`data-bw-ai-id`)||t.setAttribute(`data-bw-ai-id`,`ai-img-`+Math.random().toString(36).substring(2,9)),e.push({id:t.getAttribute(`data-bw-ai-id`),html:t.outerHTML.substring(0,300)+(t.outerHTML.length>300?`...>`:``)})}),document.querySelectorAll(`button:not([aria-label]), a:not([aria-label]), [role="button"]:not([aria-label])`).forEach(t=>{if(t.tagName===`INPUT`)return;let n=t;n.innerText?.trim()||n.textContent?.trim()||(t.hasAttribute(`data-bw-ai-id`)||t.setAttribute(`data-bw-ai-id`,`ai-btn-`+Math.random().toString(36).substring(2,9)),e.push({id:t.getAttribute(`data-bw-ai-id`),html:t.outerHTML.substring(0,300)+(t.outerHTML.length>300?`...>`:``)}))}),e.length===0){console.log(`BariWeb AI: No broken elements found.`);return}console.log(`BariWeb AI: Found ${e.length} broken elements. Processing...`);let t=window.BariwebConfig?.clientId||``;for(let n=0;n<e.length;n+=10){let r=e.slice(n,n+10),i=await fetch(`${Ot}/v1/widget/a11y/fix`,{method:`POST`,headers:{"Content-Type":`application/json`,"X-Client-ID":t},body:JSON.stringify({elements:r})});i.ok&&(await i.json()).forEach(e=>{let t=document.querySelector(`[data-bw-ai-id="${e.id}"]`);if(t&&e.value&&(e.attribute===`alt`||e.attribute===`aria-label`)){t.setAttribute(e.attribute,e.value);let n=t,r=n.style.outline;n.style.outline=`3px solid #10b981`,setTimeout(()=>{n.style.outline=r},2e3)}})}this._announce(`Режим для незрячих отработал. AI исправил ${e.length} элементов.`)}catch(e){console.error(`BariWeb AI: A11y Fix failed`,e),this._announce(`Произошла ошибка при исправлении элементов.`)}finally{this.isFixing=!1,this.host.requestUpdate()}}toggleSimplify(){if(this.simplifyEnabled=!this.simplifyEnabled,this.simplifyEnabled){if(document.body.addEventListener(`click`,this._onParagraphClick,{capture:!0}),document.body.addEventListener(`keydown`,this._onParagraphKeydown,{capture:!0}),document.querySelectorAll(`p, h1, h2, h3, h4, h5, h6, li, article`).forEach(e=>{!e.hasAttribute(`tabindex`)&&e.textContent?.trim().length>20&&(e.setAttribute(`tabindex`,`0`),e.classList.add(`bw-simplify-focusable`))}),document.documentElement.style.setProperty(`--bw-simplify-cursor`,`help`),!document.getElementById(`bw-simplify-mode-style`)){let e=document.createElement(`style`);e.id=`bw-simplify-mode-style`,e.textContent=`
882
+ `}_applySettings(){let e=document.documentElement;this._ensureGlobalStyles(),e.style.setProperty(`--bw-grayscale`,this.settings.monochrome?`100%`:`0%`);let t=1;this.settings.lowSaturation&&(t=.3),this.settings.highSaturation&&(t=2.5),e.style.setProperty(`--bw-saturation`,t.toString()),this.settings.customBgHue===null?e.removeAttribute(`data-bw-has-custom-bg`):(e.style.setProperty(`--bw-custom-bg`,`hsl(${this.settings.customBgHue}, 50%, 95%)`),e.setAttribute(`data-bw-has-custom-bg`,``)),this.settings.customHeaderHue===null?e.removeAttribute(`data-bw-has-custom-header`):(e.style.setProperty(`--bw-custom-header`,`hsl(${this.settings.customHeaderHue}, 70%, 30%)`),e.setAttribute(`data-bw-has-custom-header`,``)),this.settings.customContentHue===null?e.removeAttribute(`data-bw-has-custom-content`):(e.style.setProperty(`--bw-custom-content`,`hsl(${this.settings.customContentHue}, 60%, 40%)`),e.setAttribute(`data-bw-has-custom-content`,``)),this.settings.textScale>1?e.style.fontSize=`${this.settings.textScale*100}%`:e.style.fontSize=``;let n={"data-bw-monochrome":this.settings.monochrome,"data-bw-dark-high-contrast":this.settings.darkHighContrast,"data-bw-bright-high-contrast":this.settings.brightHighContrast,"data-bw-contrast-mode":this.settings.contrastMode,"data-bw-text-spacing":this.settings.textSpacing,"data-bw-dyslexic":this.settings.dyslexicFont,"data-bw-focus-visualizer":this.settings.focusVisualizer,"data-bw-cursor-magnifier":this.settings.cursorMagnifier,"data-bw-no-animations":this.settings.animationsDisabled,"data-bw-link-highlight":this.settings.linkHighlight,"data-bw-highlight-headers":this.settings.highlightHeaders,"data-bw-enlarge-buttons":this.settings.enlargeButtons};Object.entries(n).forEach(([t,n])=>{n?e.setAttribute(t,``):e.removeAttribute(t)});let r=this.host;r&&r.style.setProperty(`--bw-font-scale`,this.settings.textScale.toString())}toggleMonochrome(){this.settings.monochrome=!this.settings.monochrome,this._saveSettings()}toggleDarkHighContrast(){this.settings.darkHighContrast=!this.settings.darkHighContrast,this.settings.darkHighContrast&&(this.settings.brightHighContrast=!1,this.settings.contrastMode=!1),this._saveSettings()}toggleBrightHighContrast(){this.settings.brightHighContrast=!this.settings.brightHighContrast,this.settings.brightHighContrast&&(this.settings.darkHighContrast=!1,this.settings.contrastMode=!1),this._saveSettings()}toggleLowSaturation(){this.settings.lowSaturation=!this.settings.lowSaturation,this.settings.lowSaturation&&(this.settings.highSaturation=!1),this._saveSettings()}toggleHighSaturation(){this.settings.highSaturation=!this.settings.highSaturation,this.settings.highSaturation&&(this.settings.lowSaturation=!1),this._saveSettings()}toggleContrastMode(){this.settings.contrastMode=!this.settings.contrastMode,this.settings.contrastMode&&(this.settings.darkHighContrast=!1,this.settings.brightHighContrast=!1),this._saveSettings()}setCustomHue(e){this.settings.activeColorTab===`background`?this.settings.customBgHue=e:this.settings.activeColorTab===`header`?this.settings.customHeaderHue=e:this.settings.customContentHue=e,this._saveSettings()}resetCustomColors(){this.settings.customBgHue=null,this.settings.customHeaderHue=null,this.settings.customContentHue=null,this._saveSettings()}toggleHighlightHeaders(){this.settings.highlightHeaders=!this.settings.highlightHeaders,this._saveSettings()}toggleEnlargeButtons(){this.settings.enlargeButtons=!this.settings.enlargeButtons,this._saveSettings()}incrementTextScale(){this.settings.textScale>=1.5?this.settings.textScale=1:this.settings.textScale=parseFloat((this.settings.textScale+.1).toFixed(1)),this._saveSettings()}toggleTextSpacing(){this.settings.textSpacing=!this.settings.textSpacing,this._saveSettings()}toggleDyslexicFont(){this.settings.dyslexicFont=!this.settings.dyslexicFont,this._saveSettings()}toggleFocusVisualizer(){this.settings.focusVisualizer=!this.settings.focusVisualizer,this._saveSettings()}toggleCursorMagnifier(){this.settings.cursorMagnifier=!this.settings.cursorMagnifier,this._saveSettings()}toggleAnimations(){this.settings.animationsDisabled=!this.settings.animationsDisabled,this._saveSettings()}toggleLinkHighlight(){this.settings.linkHighlight=!this.settings.linkHighlight,this._saveSettings()}reset(){this.settings={...G},this._saveSettings()}};function K(e){try{let t=new URL(e),n=t.pathname;n=n.replace(vt,`:id`),n=n.replace(yt,`/:id`),n=n.replace(bt,`/:slug`),n=n.replace(xt,`/:id`);let r=new URLSearchParams;t.searchParams.forEach((e,t)=>{St.has(t)?r.set(`:${t}`,``):e.length<30&&!/^\d+$/.test(e)&&r.set(t,e)});let i=r.toString();return n.replace(/\/$/,``)+(i?`?${i}`:``)}catch{return e.replace(vt,`:id`).replace(/\/\d{1,20}(?=\/|$)/g,`/:id`).split(`?`)[0]}}function mt(e){let t=[`dialog`,`tooltip`,`menu`,`listbox`,`alertdialog`],n=e;for(;n&&n!==document.body;){let e=n.getAttribute(`role`)||``;if(t.includes(e)||n.hasAttribute(`data-radix-popper-content-wrapper`)||n.hasAttribute(`data-floating-ui-portal`))return!0;let r=typeof n.className==`string`?n.className:``;if(/popover|tooltip|dropdown-menu|floating|overlay/i.test(r))return!0;n=n.parentElement}return!1}function ht(e){let t=[`li`,`article`,`tr`,`dd`],n=e.parentElement,r=0;for(;n&&n!==document.body&&r<8;){let e=n.tagName.toLowerCase();if(t.includes(e))return!0;let i=typeof n.className==`string`?n.className:``;if(/\b(card|item|tile|post|entry|product|row-item|list-item|feed-item|cell)\b/i.test(i)){let e=n.parentElement?.children;if(e&&e.length>2)return!0}let a=n.getAttribute(`role`)||``;if(a===`listitem`||a===`row`||a===`gridcell`)return!0;n=n.parentElement,r++}return!1}function gt(e){let t=e,n=(t.getAttribute(`aria-label`)||t.getAttribute(`title`)||t.innerText||t.getAttribute(`placeholder`)||``).trim().toLowerCase();return!n||n.length<2||n.length>40||/^[\d\s₸$€%.,\-+:()]+$/.test(n)||/^\d{1,2}[./]\d{1,2}/.test(n)||Ct.has(n)?``:n.replace(/^[\p{Emoji}\s]+/u,``).trim().slice(0,30)}function _t(e){let t=5381;for(let n=0;n<e.length;n++)t=(t<<5)+t^e.charCodeAt(n);return(t>>>0).toString(16)}function q(){let e=[],t=K(window.location.href);e.push(`route:${t}`);let n=document.querySelector(`h1`);if(n){let t=n.innerText?.trim().toLowerCase();t&&t.length>1&&t.length<50&&!/\d{3,}/.test(t)&&e.push(`h1:${t.slice(0,30)}`)}let r=Array.from(document.querySelectorAll(`input:not([type="hidden"]):not([type="submit"]):not([type="radio"]):not([type="checkbox"]), textarea, select`)).slice(0,8);for(let t of r){if(mt(t))continue;let n=t,r=(n.getAttribute(`name`)||n.getAttribute(`placeholder`)||n.getAttribute(`aria-label`)||``).toLowerCase().trim().slice(0,25);r&&r.length>1&&!Ct.has(r)&&e.push(`field:${r}`)}let i=Array.from(document.querySelectorAll(`nav a, [role="navigation"] a`)).slice(0,6);for(let t of i){if(mt(t))continue;let n=gt(t);n&&e.push(`nav:${n}`)}let a=document.querySelector(`main`)||document.querySelector(`[role="main"]`)||document.getElementById(`root`);return a&&Array.from(a.querySelectorAll(`button:not([aria-hidden="true"]), [role="button"]:not([aria-hidden="true"])`)).filter(e=>!mt(e)&&!ht(e)).map(gt).filter(e=>e.length>1).reduce((e,t)=>e.includes(t)?e:[...e,t],[]).slice(0,3).forEach(t=>e.push(`btn:${t}`)),[...new Set(e)].sort().slice(0,15)}function J(){return`bw-${_t(q().join(`|`))}`}var vt,yt,bt,xt,St,Ct,wt=t((()=>{vt=/[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}/gi,yt=/\/\d{1,20}(?=\/|$)/g,bt=/\/[a-z0-9]+(?:-[a-z0-9]+)*-\d+(?=\/|$)/g,xt=/\/[0-9a-f]{8,}(?=\/|$)/gi,St=new Set([`id`,`userId`,`user_id`,`orderId`,`order_id`,`itemId`,`item_id`,`productId`,`product_id`,`token`,`key`,`ref`,`code`,`session`]),Ct=new Set(`ok,ок,okay,close,закрыть,cancel,отмена,yes,da,no,нет,да,submit,отправить,back,назад,next,далее,more,ещё,еще,menu,меню,...,•,·,loading,загрузка,open,открыть,expand,collapse,toggle,sort`.split(`,`))}));function Tt(e,t){let n=new Set([...e].filter(e=>t.has(e))),r=new Set([...e,...t]);return r.size===0?1:n.size/r.size}var Et,Y,Dt=t((()=>{wt(),Et=class{constructor(e=1500){this._observer=null,this._debounceTimer=null,this._lastTokens=new Set,this._lastUrl=``,this._callbacks=[],this._discoveryCallbacks=[],this._isDiscovering=!1,this.isAutoDiscoveryEnabled=!1,this._debounceMs=e}start(){this._observer||(this._lastTokens=new Set(q()),this._lastUrl=K(window.location.href),this._observer=new MutationObserver(()=>{this._debounceTimer&&clearTimeout(this._debounceTimer),this._debounceTimer=setTimeout(()=>this._onMutation(),this._debounceMs)}),this._observer.observe(document.body,{childList:!0,subtree:!0,attributes:!1,characterData:!1}))}stop(){this._observer?.disconnect(),this._observer=null,this._debounceTimer&&clearTimeout(this._debounceTimer)}onStateChange(e){this._callbacks.push(e)}onDiscovery(e){this._discoveryCallbacks.push(e)}get isDiscovering(){return this._isDiscovering}getLiveSnapshot(){let e=(e,t)=>{if(e.hasAttribute(`bw-private`)||e.hasAttribute(`data-bw-private`))return`[MASKED]`;if(!t)return t;let n=t.replace(/(?:\d[ \-]*?){13,16}/g,`****`);return n=n.replace(/\b\d{12}\b/g,`****`),n},t=Array.from(document.querySelectorAll(`h1, h2`)).map(t=>e(t,t.innerText?.trim()||``)).filter(Boolean).slice(0,3),n=Array.from(document.querySelectorAll(`button, a[href], [role="button"]`)).map(t=>{let n=t,r=e(n,(n.getAttribute(`aria-label`)||n.innerText||``).trim().slice(0,60));return{id:n.id||``,text:r}}).filter(e=>e.text.length>0).slice(0,30);return{url:window.location.href,headings:t,fingerprint:J(),elements:n}}async _onMutation(){if(document.readyState!==`complete`)return;let e=K(window.location.href),t=new Set(q());if(t.size<2)return;let n=J(),r=e!==this._lastUrl,i=Tt(this._lastTokens,t);if(r||i<.55){let a=r?`URL: ${this._lastUrl} → ${e}`:`Sim: ${i.toFixed(2)}`;console.log(`[Watcher] Screen change (${a})`),this._lastUrl=e,this._lastTokens=t;let o=this.getLiveSnapshot();if(this.isAutoDiscoveryEnabled){let e=this._buildTypedTokens();this._discover(n,e).catch(()=>{})}this._callbacks.forEach(e=>e(o))}}_buildTypedTokens(){let e=new Set,t=[],n=(n,r)=>{let i=r.trim().slice(0,40);if(!i||i.length<2)return;let a=`${n}:${i}`;e.has(a)||(e.add(a),t.push(a))};return document.querySelectorAll(`button, [role="button"]`).forEach(e=>{let t=e.innerText?.trim();t&&n(`btn`,t)}),document.querySelectorAll(`a[href]`).forEach(e=>{let t=(e.getAttribute(`aria-label`)||e.innerText)?.trim();t&&n(`a`,t)}),document.querySelectorAll(`input:not([type=hidden]), textarea, select`).forEach(e=>{let t=e.placeholder||e.name;t&&n(`input`,t)}),t.slice(0,8)}async _discover(e,t){let n=localStorage.getItem(`bw_admin_token`);if(n){this._isDiscovering=!0;try{let r=await fetch(`http://localhost:8000/v1/training/discover`,{method:`POST`,headers:{"Content-Type":`application/json`,Authorization:`Bearer ${n}`},body:JSON.stringify({fingerprint:e,tokens:t,page_url:window.location.href})});if(r.ok){let e=await r.json();console.log(`[Discovery] ${e.status} — ${e.label}`),this._discoveryCallbacks.forEach(t=>t(e))}else r.status===401?(console.warn(`[Discovery] Token expired — disabling auto-discovery`),localStorage.removeItem(`bw_admin_token`),this.isAutoDiscoveryEnabled=!1):console.warn(`[Discovery] Server error ${r.status}`)}catch(e){console.warn(`[Discovery] Network error`,e)}finally{this._isDiscovering=!1}}}async forceDiscovery(){let e=[...new Set(q())],t=J();await this._discover(t,e)}},Y=new Et(1500)}));Dt();var Ot=`http://localhost:8000`,kt=class{constructor(e){this.isFixing=!1,this.simplifyEnabled=!1,this.autoA11yEnabled=!1,this._onParagraphKeydown=e=>{if(this.simplifyEnabled&&(e.key===`Enter`||e.key===` `)&&e.target instanceof HTMLElement){if(e.target.closest(`bw-widget`)||e.target.closest(`.bw-ai-tooltip`))return;let t=e.target.tagName.toLowerCase();if([`p`,`span`,`div`,`li`,`article`,`h1`,`h2`,`h3`,`h4`,`h5`,`h6`].includes(t)){e.preventDefault(),e.stopPropagation();let t=e.target.getBoundingClientRect();this._triggerSimplify(e.target,t.left+window.scrollX,t.bottom+window.scrollY)}}},this._onParagraphClick=async e=>{if(!this.simplifyEnabled)return;let t=e.target;if(t.closest(`bw-widget`)||t.closest(`.bw-ai-tooltip`))return;let n=t.tagName.toLowerCase();if([`p`,`span`,`div`,`li`,`article`,`h1`,`h2`,`h3`,`h4`,`h5`,`h6`].includes(n)){let n=t.innerText?.trim();n&&n.length>20&&(e.preventDefault(),e.stopPropagation(),this._triggerSimplify(t,e.pageX,e.pageY))}},(this.host=e).addController(this),this.simplifyEnabled=localStorage.getItem(`bw-ai-simplify`)===`true`,this.autoA11yEnabled=localStorage.getItem(`bw-ai-autofix`)===`true`,Y.onStateChange(()=>{this.autoA11yEnabled&&!this.isFixing&&this.fixMarkup()}),this.autoA11yEnabled&&setTimeout(()=>this.fixMarkup(),1e3)}toggleAutoA11y(){this.autoA11yEnabled=!this.autoA11yEnabled,localStorage.setItem(`bw-ai-autofix`,this.autoA11yEnabled?`true`:`false`),this.autoA11yEnabled&&!this.isFixing&&this.fixMarkup(),this.host.requestUpdate()}hostConnected(){}hostDisconnected(){this.simplifyEnabled&&(document.body.removeEventListener(`click`,this._onParagraphClick,{capture:!0}),document.body.classList.remove(`bw-simplify-mode`))}async fixMarkup(){this.isFixing=!0,this.host.requestUpdate();try{let e=[];if(document.querySelectorAll(`img:not([alt]), img[alt=""]`).forEach(t=>{t.hasAttribute(`data-bw-ai-id`)||t.setAttribute(`data-bw-ai-id`,`ai-img-`+Math.random().toString(36).substring(2,9)),e.push({id:t.getAttribute(`data-bw-ai-id`),html:t.outerHTML.substring(0,300)+(t.outerHTML.length>300?`...>`:``)})}),document.querySelectorAll(`button:not([aria-label]), a:not([aria-label]), [role="button"]:not([aria-label])`).forEach(t=>{if(t.tagName===`INPUT`)return;let n=t;n.innerText?.trim()||n.textContent?.trim()||(t.hasAttribute(`data-bw-ai-id`)||t.setAttribute(`data-bw-ai-id`,`ai-btn-`+Math.random().toString(36).substring(2,9)),e.push({id:t.getAttribute(`data-bw-ai-id`),html:t.outerHTML.substring(0,300)+(t.outerHTML.length>300?`...>`:``)}))}),e.length===0){console.log(`BariWeb AI: No broken elements found.`);return}console.log(`BariWeb AI: Found ${e.length} broken elements. Processing...`);let t=this.host.clientId||window.BariwebConfig?.clientId||``;for(let n=0;n<e.length;n+=10){let r=e.slice(n,n+10),i=await fetch(`${Ot}/v1/widget/a11y/fix`,{method:`POST`,headers:{"Content-Type":`application/json`,"X-Client-ID":t},body:JSON.stringify({elements:r})});i.ok&&(await i.json()).forEach(e=>{let t=document.querySelector(`[data-bw-ai-id="${e.id}"]`);if(t&&e.value&&(e.attribute===`alt`||e.attribute===`aria-label`)){t.setAttribute(e.attribute,e.value);let n=t,r=n.style.outline;n.style.outline=`3px solid #10b981`,setTimeout(()=>{n.style.outline=r},2e3)}})}}finally{this.isFixing=!1,this.host.requestUpdate()}}toggleSimplify(){if(this.simplifyEnabled=!this.simplifyEnabled,this.simplifyEnabled){if(document.body.addEventListener(`click`,this._onParagraphClick,{capture:!0}),document.body.addEventListener(`keydown`,this._onParagraphKeydown,{capture:!0}),document.querySelectorAll(`p, h1, h2, h3, h4, h5, h6, li, article`).forEach(e=>{!e.hasAttribute(`tabindex`)&&e.textContent?.trim().length>20&&(e.setAttribute(`tabindex`,`0`),e.classList.add(`bw-simplify-focusable`))}),document.documentElement.style.setProperty(`--bw-simplify-cursor`,`help`),!document.getElementById(`bw-simplify-mode-style`)){let e=document.createElement(`style`);e.id=`bw-simplify-mode-style`,e.textContent=`
883
883
  body.bw-simplify-mode *:hover {
884
884
  cursor: help !important;
885
885
  background-color: rgba(168, 85, 247, 0.1) !important;
@@ -956,7 +956,7 @@
956
956
  from { opacity: 0; transform: translateY(4px); }
957
957
  to { opacity: 1; transform: translateY(0); }
958
958
  }
959
- `,document.head.appendChild(e)}document.body.classList.add(`bw-simplify-mode`),this._announce(`Режим AI Упрощение текста включен. Используйте Tab для навигации по тексту и Enter для упрощения.`)}else document.body.removeEventListener(`click`,this._onParagraphClick,{capture:!0}),document.body.removeEventListener(`keydown`,this._onParagraphKeydown,{capture:!0}),document.querySelectorAll(`.bw-simplify-focusable`).forEach(e=>{e.removeAttribute(`tabindex`),e.classList.remove(`bw-simplify-focusable`)}),document.body.classList.remove(`bw-simplify-mode`),document.documentElement.style.removeProperty(`--bw-simplify-cursor`),this._announce(`Режим AI Упрощение текста выключен.`);this.host.requestUpdate()}async _triggerSimplify(e,t,n){let r=e.innerText?.trim();if(!r)return;document.querySelectorAll(`.bw-ai-tooltip`).forEach(e=>e.remove());let i=document.createElement(`div`);i.className=`bw-ai-tooltip bw-ai-tooltip-loading`,i.tabIndex=-1,i.innerHTML=`
959
+ `,document.head.appendChild(e)}document.body.classList.add(`bw-simplify-mode`)}else document.body.removeEventListener(`click`,this._onParagraphClick,{capture:!0}),document.body.removeEventListener(`keydown`,this._onParagraphKeydown,{capture:!0}),document.querySelectorAll(`.bw-simplify-focusable`).forEach(e=>{e.removeAttribute(`tabindex`),e.classList.remove(`bw-simplify-focusable`)}),document.body.classList.remove(`bw-simplify-mode`),document.documentElement.style.removeProperty(`--bw-simplify-cursor`);this.host.requestUpdate()}async _triggerSimplify(e,t,n){let r=e.innerText?.trim();if(!r)return;document.querySelectorAll(`.bw-ai-tooltip`).forEach(e=>e.remove());let i=document.createElement(`div`);i.className=`bw-ai-tooltip bw-ai-tooltip-loading`,i.tabIndex=-1,i.innerHTML=`
960
960
  <div class="bw-ai-tooltip-header">
961
961
  <span>✨ AI Упрощение</span>
962
962
  <button class="bw-ai-tooltip-close" aria-label="Закрыть">✕</button>
@@ -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=this.host.clientId||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._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)}}isVoiceModeActive(){return this._voiceMode}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})),t=-1;for(let n=e.length-1;n>=0;n--)if(e[n].role===`user`){t=n;break}if(t===-1)return e.slice(-5);let n=-1;for(let r=t-1;r>=0;r--)if(e[r].role===`user`){n=r;break}let r=[];if(n!==-1){r.push(e[n]);let i=e.slice(n+1,t).filter(e=>e.role===`assistant`).pop();i&&r.push(i)}r.push(e[t]);let i=e.slice(t+1).filter(e=>e.role===`assistant`);return r.push(...i.slice(-2)),r}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._hadPendingConfirmation=!1,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(){this._authError=``;let e=this.clientId||window.BariwebConfig?.clientId||``;if(!e){this._authError=`Client ID not configured`;return}try{let t=await fetch(`http://localhost:8000/auth/login/widget`,{method:`POST`,headers:{"Content-Type":`application/json`},body:JSON.stringify({client_public_id:e,admin_key:this._adminPassword})});if(t.ok){let{access_token:e}=await t.json();localStorage.setItem(`bw_admin_token`,e),this._isAdmin=!0,this._showAdminLogin=!1,this._loadAdminUI()}else this._authError=(await t.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=this.clientId||window.BariwebConfig?.clientId||``,n=await fetch(`http://localhost:8000/v1/training/match-screen`,{method:`POST`,headers:{"Content-Type":`application/json`,"X-Client-ID":t},body:JSON.stringify({fingerprint:e.fingerprint})});if(n.ok){let e=await n.json();this._currentScreenLabel=e.matched?e.label:``}}catch{}}),window.addEventListener(`keydown`,this._handleGlobalKeydown)}updated(e){super.updated(e);let t=!!this._chat.pendingConfirmation;t&&!this._hadPendingConfirmation&&this._chat.isVoiceModeActive()&&setTimeout(()=>{this._sttState===`idle`&&this._startRecording()},500),this._hadPendingConfirmation=t}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!==`idle`,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">
@@ -1175,19 +1175,19 @@
1175
1175
  <p class="chat-empty-title">${i(`chatEmptyTitle`)}</p>
1176
1176
  <p class="chat-empty-sub">${i(`chatEmptySub`)}</p>
1177
1177
  </div>
1178
- `:e.map(e=>{if(e.role===`assistant`&&(e.text.includes(`✅`)||e.text.includes(`⌨️`)||e.text.includes(`🔄`))){let t=e.text.split(`
1179
- `)[0];return j`
1178
+ `:e.map(e=>e.role===`assistant`&&(e.text.includes(`✅`)||e.text.includes(`⌨️`)||e.text.includes(`🔄`))?j`
1180
1179
  <details class="system-log">
1181
1180
  <summary class="system-log-header">
1182
- ${W.code} <span>${t}</span>
1181
+ <span>${e.text.split(`
1182
+ `)[0]}</span>
1183
1183
  </summary>
1184
1184
  <div class="system-log-details">${e.text}</div>
1185
1185
  </details>
1186
- `}return j`
1186
+ `:j`
1187
1187
  <div class="chat-bubble ${e.role}">
1188
1188
  ${e.text}
1189
1189
  </div>
1190
- `})}
1190
+ `)}
1191
1191
 
1192
1192
  ${t?j`
1193
1193
  <div class="typing-indicator">
@@ -1256,10 +1256,27 @@
1256
1256
  </div>
1257
1257
  </div>
1258
1258
  `}
1259
- `}_renderA11yTab(){let e=this._a11y.settings,t=e=>this._t(e);return j`
1259
+ `}_renderA11yTab(){let e=this._a11y.settings,t=e=>this._t(e),n=[{id:`bw-tile-textscale`,icon:W.textSize,label:t(`tileTextSize`),value:`${Math.round(e.textScale*100)}%`,active:e.textScale>1,action:()=>this._a11y.incrementTextScale()},{id:`bw-tile-monochrome`,icon:W.visualImpair,label:t(`tileMonochrome`),value:t(`valueMonochrome`),active:e.monochrome,action:()=>this._a11y.toggleMonochrome()},{id:`bw-tile-contrast`,icon:W.moon,label:t(`tileContrast`),value:t(`valueDark`),active:e.darkHighContrast,action:()=>this._a11y.toggleDarkHighContrast()},{id:`bw-tile-links`,icon:W.visualImpair,label:t(`tileLinks`),value:t(`valueHighlight`),active:e.linkHighlight,action:()=>this._a11y.toggleLinkHighlight()},{id:`bw-tile-spacing`,icon:W.textSize,label:t(`tileSpacing`),value:t(`valueEnlarge`),active:e.textSpacing,action:()=>this._a11y.toggleTextSpacing()},{id:`bw-tile-font`,icon:W.textSize,label:t(`tileFont`),value:t(`valueDyslexia`),active:e.dyslexicFont,action:()=>this._a11y.toggleDyslexicFont()},{id:`bw-tile-cursor`,icon:W.cursor,label:t(`tileCursor`),value:t(`valueEnlarge`),active:e.cursorMagnifier,action:()=>this._a11y.toggleCursorMagnifier()},{id:`bw-tile-voice`,icon:null,label:t(`tileVoice`),value:this._sttState===`recording`?t(`valueRecording`):t(`valuePress`),active:this._sttState===`recording`,action:()=>this._toggleVoice()}];return j`
1260
1260
  <div class="a11y-scroller">
1261
+ <div style="padding: 16px 16px 0;">
1262
+ <div style="display: flex; align-items: center; justify-content: space-between; padding: 12px; background: var(--bw-bg-subtle, #f8fafc); border-radius: var(--bw-radius, 14px); margin-bottom: 0px;">
1263
+ <div style="display: flex; align-items: center; gap: 10px; font-weight: 600; font-size: 14px; color: var(--bw-fg, #1e293b);">
1264
+ ${W.languages} ${t(`recognitionLanguage`)}
1265
+ </div>
1266
+ <select style="height: 34px; padding: 0 8px; border: 1px solid var(--bw-primary, #6d28d9); border-radius: 8px; background: rgba(109, 40, 217, 0.05); color: var(--bw-primary, #6d28d9); cursor: pointer; outline: none; font-size: 13px; font-weight: 600;"
1267
+ .value=${this._sttLanguageMode}
1268
+ @change=${e=>{this._setSttLanguageMode(e.target.value),this.requestUpdate()}}
1269
+ aria-label=${t(`changeRecognitionLanguage`)}>
1270
+ <option value="auto">${t(`languageAuto`)}</option>
1271
+ <option value="kz">${t(`languageKz`)}</option>
1272
+ <option value="ru">${t(`languageRu`)}</option>
1273
+ <option value="en">${t(`languageEn`)}</option>
1274
+ </select>
1275
+ </div>
1276
+ </div>
1277
+
1261
1278
  <div class="settings-grid">
1262
- ${[{id:`bw-tile-textscale`,icon:W.textSize,label:t(`tileTextSize`),value:`${Math.round(e.textScale*100)}%`,active:e.textScale>1,action:()=>this._a11y.incrementTextScale()},{id:`bw-tile-monochrome`,icon:W.palette,label:t(`tileMonochrome`),value:t(`valueMonochrome`),active:e.monochrome,action:()=>this._a11y.toggleMonochrome()},{id:`bw-tile-contrast`,icon:W.sun,label:t(`tileContrast`),value:t(`valueDark`),active:e.darkHighContrast,action:()=>this._a11y.toggleDarkHighContrast()},{id:`bw-tile-links`,icon:W.link,label:t(`tileLinks`),value:t(`valueHighlight`),active:e.linkHighlight,action:()=>this._a11y.toggleLinkHighlight()},{id:`bw-tile-spacing`,icon:W.type,label:t(`tileSpacing`),value:t(`valueEnlarge`),active:e.textSpacing,action:()=>this._a11y.toggleTextSpacing()},{id:`bw-tile-font`,icon:W.type,label:t(`tileFont`),value:t(`valueDyslexia`),active:e.dyslexicFont,action:()=>this._a11y.toggleDyslexicFont()},{id:`bw-tile-cursor`,icon:W.mouse,label:t(`tileCursor`),value:t(`valueEnlarge`),active:e.cursorMagnifier,action:()=>this._a11y.toggleCursorMagnifier()},{id:`bw-tile-voice`,icon:null,label:t(`tileVoice`),value:this._sttState===`recording`?t(`valueRecording`):t(`valuePress`),active:this._sttState===`recording`,action:()=>this._toggleVoice()}].map(e=>j`
1279
+ ${n.map(e=>j`
1263
1280
  <button class="settings-card" ?active=${e.active} @click=${e.action} id=${e.id}
1264
1281
  aria-pressed=${e.active?`true`:`false`} aria-label=${e.label}>
1265
1282
  ${e.icon||W.mic}
@@ -1293,22 +1310,7 @@
1293
1310
  </div>
1294
1311
  </div>
1295
1312
 
1296
- <div class="ai-tools-section">
1297
- <div style="display: flex; align-items: center; justify-content: space-between; padding: 12px; background: var(--bw-bg-subtle, #f8fafc); border-radius: var(--bw-radius, 14px); margin-bottom: 12px;">
1298
- <div class="lang-row-label" style="display: flex; align-items: center; gap: 10px; font-weight: 600; font-size: 14px; color: var(--bw-fg, #1e293b);">
1299
- <span class="lang-row-icon">${W.languages}</span>${t(`recognitionLanguage`)}
1300
- </div>
1301
- <select style="height: 34px; padding: 0 8px; border: 1px solid var(--bw-border); border-radius: 8px; background: #fff; cursor: pointer; outline: none; font-size: 13px;"
1302
- .value=${this._sttLanguageMode}
1303
- @change=${e=>{this._setSttLanguageMode(e.target.value),this.requestUpdate()}}
1304
- aria-label=${t(`changeRecognitionLanguage`)}>
1305
- <option value="auto">${t(`languageAuto`)}</option>
1306
- <option value="kz">${t(`languageKz`)}</option>
1307
- <option value="ru">${t(`languageRu`)}</option>
1308
- <option value="en">${t(`languageEn`)}</option>
1309
- </select>
1310
- </div>
1311
-
1313
+ <div class="ai-tools-section" style="margin-top: 16px;">
1312
1314
  <button class="ai-tool-btn ${this._aiA11y.simplifyEnabled?`active`:``}"
1313
1315
  @click=${()=>this._aiA11y.toggleSimplify()} id="bw-ai-simplify">
1314
1316
  ${W.textSize}
@@ -1349,7 +1351,7 @@
1349
1351
  .value=${this._adminPassword}
1350
1352
  @input=${e=>{this._adminPassword=e.target.value}}
1351
1353
  @keydown=${e=>{e.key===`Enter`&&this._handleAdminLogin()}} />
1352
- ${this._authError?j`<div class="auth-error">${this._authError}</div>`:``}
1354
+ ${this._authError?j`<p class="auth-error">${this._authError}</p>`:``}
1353
1355
  <button class="admin-login-btn" @click=${this._handleAdminLogin}>${e(`adminLogin`)}</button>
1354
1356
  `}
1355
1357
  <button class="admin-close-btn" @click=${()=>{this._showAdminLogin=!1,this._authError=``}}>
@@ -1377,12 +1379,12 @@
1377
1379
  <div class="bw-tabs" role="tablist">
1378
1380
  <button class="bw-tab" ?active=${this._activeTab===`chat`}
1379
1381
  @click=${()=>this._setTab(`chat`)} role="tab"
1380
- aria-selected=${this._activeTab===`chat`?`true`:`false`} id="bw-tab-chat">
1382
+ aria-selected=${this._activeTab===`chat`} id="bw-tab-chat">
1381
1383
  ${W.chat} ${e(`tabChat`)}
1382
1384
  </button>
1383
1385
  <button class="bw-tab" ?active=${this._activeTab===`a11y`}
1384
1386
  @click=${()=>this._setTab(`a11y`)} role="tab"
1385
- aria-selected=${this._activeTab===`a11y`?`true`:`false`} id="bw-tab-settings">
1387
+ aria-selected=${this._activeTab===`a11y`} id="bw-tab-settings">
1386
1388
  ${W.settings} ${e(`tabSettings`)}
1387
1389
  </button>
1388
1390
  </div>
package/dist/bariweb.js CHANGED
@@ -2078,20 +2078,6 @@ var it = nt(q), J = (e) => I`${it(`
2078
2078
  hostDisconnected() {
2079
2079
  this.simplifyEnabled && (document.body.removeEventListener("click", this._onParagraphClick, { capture: !0 }), document.body.classList.remove("bw-simplify-mode"));
2080
2080
  }
2081
- _announce(e) {
2082
- let t = document.getElementById("bw-ai-announcer");
2083
- t || (t = document.createElement("div"), t.id = "bw-ai-announcer", t.setAttribute("aria-live", "polite"), t.setAttribute("aria-atomic", "true"), Object.assign(t.style, {
2084
- position: "absolute",
2085
- width: "1px",
2086
- height: "1px",
2087
- padding: "0",
2088
- margin: "-1px",
2089
- overflow: "hidden",
2090
- clip: "rect(0, 0, 0, 0)",
2091
- whiteSpace: "nowrap",
2092
- border: "0"
2093
- }), document.body.appendChild(t)), t.textContent = e;
2094
- }
2095
2081
  async fixMarkup() {
2096
2082
  this.isFixing = !0, this.host.requestUpdate();
2097
2083
  try {
@@ -2113,7 +2099,7 @@ var it = nt(q), J = (e) => I`${it(`
2113
2099
  return;
2114
2100
  }
2115
2101
  console.log(`BariWeb AI: Found ${e.length} broken elements. Processing...`);
2116
- let t = window.BariwebConfig?.clientId || "";
2102
+ let t = this.host.clientId || window.BariwebConfig?.clientId || "";
2117
2103
  for (let n = 0; n < e.length; n += 10) {
2118
2104
  let r = e.slice(n, n + 10), i = await fetch(`${ct}/v1/widget/a11y/fix`, {
2119
2105
  method: "POST",
@@ -2134,9 +2120,6 @@ var it = nt(q), J = (e) => I`${it(`
2134
2120
  }
2135
2121
  });
2136
2122
  }
2137
- this._announce(`Режим для незрячих отработал. AI исправил ${e.length} элементов.`);
2138
- } catch (e) {
2139
- console.error("BariWeb AI: A11y Fix failed", e), this._announce("Произошла ошибка при исправлении элементов.");
2140
2123
  } finally {
2141
2124
  this.isFixing = !1, this.host.requestUpdate();
2142
2125
  }
@@ -2149,10 +2132,10 @@ var it = nt(q), J = (e) => I`${it(`
2149
2132
  let e = document.createElement("style");
2150
2133
  e.id = "bw-simplify-mode-style", e.textContent = "\n body.bw-simplify-mode *:hover {\n cursor: help !important;\n background-color: rgba(168, 85, 247, 0.1) !important;\n outline: 1px dashed rgba(168, 85, 247, 0.4) !important;\n }\n bw-widget.bw-simplify-mode *:hover, .bw-ai-tooltip *:hover {\n cursor: inherit !important;\n background-color: transparent !important;\n outline: none !important;\n }\n .bw-ai-tooltip {\n position: absolute;\n width: 320px;\n background: #ffffff;\n border: 1px solid #e2e8f0;\n border-radius: 12px;\n box-shadow: 0 10px 25px -5px rgba(0, 0, 0, 0.1), 0 8px 10px -6px rgba(0, 0, 0, 0.1);\n color: #0f172a;\n font-family: system-ui, -apple-system, sans-serif;\n z-index: 999999;\n overflow: hidden;\n animation: bwAiFadeIn 0.2s ease-out;\n }\n .bw-ai-tooltip[data-theme=\"dark\"] {\n background: #1e293b;\n border-color: #334155;\n color: #f8fafc;\n }\n .bw-ai-tooltip-header {\n display: flex;\n justify-content: space-between;\n align-items: center;\n padding: 8px 12px;\n background: #f8fafc;\n border-bottom: 1px solid #e2e8f0;\n font-size: 11px;\n font-weight: 700;\n color: #64748b;\n }\n .bw-ai-tooltip[data-theme=\"dark\"] .bw-ai-tooltip-header {\n background: #0f172a;\n border-bottom-color: #334155;\n color: #94a3b8;\n }\n .bw-ai-tooltip-close {\n background: transparent;\n border: none;\n color: inherit;\n cursor: pointer;\n font-size: 14px;\n padding: 2px 6px;\n border-radius: 4px;\n }\n .bw-ai-tooltip-close:hover {\n background: rgba(0,0,0,0.05);\n }\n .bw-ai-tooltip[data-theme=\"dark\"] .bw-ai-tooltip-close:hover {\n background: rgba(255,255,255,0.1);\n }\n .bw-ai-tooltip-content {\n padding: 14px;\n font-size: 14px;\n line-height: 1.6;\n }\n .bw-ai-tooltip-loading .bw-ai-tooltip-content {\n display: flex;\n align-items: center;\n gap: 10px;\n color: #64748b;\n font-style: italic;\n font-size: 13px;\n }\n @keyframes bwAiFadeIn {\n from { opacity: 0; transform: translateY(4px); }\n to { opacity: 1; transform: translateY(0); }\n }\n ", document.head.appendChild(e);
2151
2134
  }
2152
- document.body.classList.add("bw-simplify-mode"), this._announce("Режим AI Упрощение текста включен. Используйте Tab для навигации по тексту и Enter для упрощения.");
2135
+ document.body.classList.add("bw-simplify-mode");
2153
2136
  } else document.body.removeEventListener("click", this._onParagraphClick, { capture: !0 }), document.body.removeEventListener("keydown", this._onParagraphKeydown, { capture: !0 }), document.querySelectorAll(".bw-simplify-focusable").forEach((e) => {
2154
2137
  e.removeAttribute("tabindex"), e.classList.remove("bw-simplify-focusable");
2155
- }), document.body.classList.remove("bw-simplify-mode"), document.documentElement.style.removeProperty("--bw-simplify-cursor"), this._announce("Режим AI Упрощение текста выключен.");
2138
+ }), document.body.classList.remove("bw-simplify-mode"), document.documentElement.style.removeProperty("--bw-simplify-cursor");
2156
2139
  this.host.requestUpdate();
2157
2140
  }
2158
2141
  async _triggerSimplify(e, t, n) {
@@ -2166,7 +2149,7 @@ var it = nt(q), J = (e) => I`${it(`
2166
2149
  i.remove(), e.style.outline = a, e.style.backgroundColor = o;
2167
2150
  });
2168
2151
  try {
2169
- let e = window.BariwebConfig?.clientId || "", t = await fetch(`${ct}/v1/widget/a11y/simplify`, {
2152
+ let e = this.host.clientId || window.BariwebConfig?.clientId || "", t = await fetch(`${ct}/v1/widget/a11y/simplify`, {
2170
2153
  method: "POST",
2171
2154
  headers: {
2172
2155
  "Content-Type": "application/json",
@@ -2185,7 +2168,7 @@ var it = nt(q), J = (e) => I`${it(`
2185
2168
  }
2186
2169
  }, ut = "bw-tts-enabled-v1", dt = class {
2187
2170
  constructor() {
2188
- this.enabled = !0, this.enabled = this.loadEnabled(), "speechSynthesis" in window && (window.speechSynthesis.getVoices(), window.speechSynthesis.onvoiceschanged = () => {
2171
+ this.enabled = !1, this.enabled = this.loadEnabled(), "speechSynthesis" in window && (window.speechSynthesis.getVoices(), window.speechSynthesis.onvoiceschanged = () => {
2189
2172
  window.speechSynthesis.getVoices();
2190
2173
  });
2191
2174
  }
@@ -2218,9 +2201,9 @@ var it = nt(q), J = (e) => I`${it(`
2218
2201
  loadEnabled() {
2219
2202
  try {
2220
2203
  let e = localStorage.getItem(ut);
2221
- return e === null ? !0 : e !== "0";
2204
+ return e === null ? !1 : e !== "0";
2222
2205
  } catch {
2223
- return !0;
2206
+ return !1;
2224
2207
  }
2225
2208
  }
2226
2209
  detectLanguage(e) {
@@ -2257,7 +2240,7 @@ var ht = class {
2257
2240
  this._tts.stop();
2258
2241
  }
2259
2242
  _shouldSpeak() {
2260
- return this._voiceMode || this._tts.isEnabled();
2243
+ return this._tts.isEnabled();
2261
2244
  }
2262
2245
  _loadMessages() {
2263
2246
  try {
@@ -2282,6 +2265,9 @@ var ht = class {
2282
2265
  console.error("Failed to save chat history", e);
2283
2266
  }
2284
2267
  }
2268
+ isVoiceModeActive() {
2269
+ return this._voiceMode;
2270
+ }
2285
2271
  gatherContext() {
2286
2272
  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) => {
2287
2273
  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) : "";
@@ -2436,14 +2422,26 @@ var ht = class {
2436
2422
  let e = this.messages.map((e) => ({
2437
2423
  role: e.role,
2438
2424
  text: e.text
2439
- }));
2440
- if (e.length <= 3) return e;
2441
- let t = -1;
2425
+ })), t = -1;
2442
2426
  for (let n = e.length - 1; n >= 0; n--) if (e[n].role === "user") {
2443
2427
  t = n;
2444
2428
  break;
2445
2429
  }
2446
- return t === -1 ? e.slice(-3) : [e[t], ...e.slice(t + 1).filter((e) => e.role === "assistant").slice(-2)];
2430
+ if (t === -1) return e.slice(-5);
2431
+ let n = -1;
2432
+ for (let r = t - 1; r >= 0; r--) if (e[r].role === "user") {
2433
+ n = r;
2434
+ break;
2435
+ }
2436
+ let r = [];
2437
+ if (n !== -1) {
2438
+ r.push(e[n]);
2439
+ let i = e.slice(n + 1, t).filter((e) => e.role === "assistant").pop();
2440
+ i && r.push(i);
2441
+ }
2442
+ r.push(e[t]);
2443
+ let i = e.slice(t + 1).filter((e) => e.role === "assistant");
2444
+ return r.push(...i.slice(-2)), r;
2447
2445
  }
2448
2446
  async _agentLoop(e, t, n = !1) {
2449
2447
  if (this.isLoading) return;
@@ -2822,7 +2820,7 @@ var gt = "bw-stt-lang-v1", _t = 200, vt = .015, yt = 1200, bt = 2e4, xt = 350, S
2822
2820
  this.styles = [at];
2823
2821
  }
2824
2822
  constructor() {
2825
- super(), this._a11y = new st(this), this._aiA11y = new lt(this), this._chat = new ht(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) => {
2823
+ super(), this._a11y = new st(this), this._aiA11y = new lt(this), this._chat = new ht(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._hadPendingConfirmation = !1, this._handleGlobalKeydown = (e) => {
2826
2824
  this._isOpen && e.altKey && e.code === "KeyV" && (e.preventDefault(), this._toggleVoice());
2827
2825
  };
2828
2826
  try {
@@ -2865,23 +2863,25 @@ var gt = "bw-stt-lang-v1", _t = 200, vt = .015, yt = 1200, bt = 2e4, xt = 350, S
2865
2863
  }
2866
2864
  }
2867
2865
  async _handleAdminLogin() {
2868
- if (this._authError = "", !this.clientId) {
2866
+ this._authError = "";
2867
+ let e = this.clientId || window.BariwebConfig?.clientId || "";
2868
+ if (!e) {
2869
2869
  this._authError = "Client ID not configured";
2870
2870
  return;
2871
2871
  }
2872
2872
  try {
2873
- let e = await fetch("http://localhost:8000/auth/login/widget", {
2873
+ let t = await fetch("http://localhost:8000/auth/login/widget", {
2874
2874
  method: "POST",
2875
2875
  headers: { "Content-Type": "application/json" },
2876
2876
  body: JSON.stringify({
2877
- client_public_id: this.clientId,
2877
+ client_public_id: e,
2878
2878
  admin_key: this._adminPassword
2879
2879
  })
2880
2880
  });
2881
- if (e.ok) {
2882
- let { access_token: t } = await e.json();
2883
- localStorage.setItem("bw_admin_token", t), this._isAdmin = !0, this._showAdminLogin = !1, this._loadAdminUI();
2884
- } else this._authError = (await e.json().catch(() => ({}))).detail || "Invalid admin key";
2881
+ if (t.ok) {
2882
+ let { access_token: e } = await t.json();
2883
+ localStorage.setItem("bw_admin_token", e), this._isAdmin = !0, this._showAdminLogin = !1, this._loadAdminUI();
2884
+ } else this._authError = (await t.json().catch(() => ({}))).detail || "Invalid admin key";
2885
2885
  } catch {
2886
2886
  this._authError = "Connection failed";
2887
2887
  }
@@ -2897,30 +2897,31 @@ var gt = "bw-stt-lang-v1", _t = 200, vt = .015, yt = 1200, bt = 2e4, xt = 350, S
2897
2897
  connectedCallback() {
2898
2898
  super.connectedCallback(), t.start(), t.onStateChange(async (e) => {
2899
2899
  try {
2900
- let t = await fetch("http://localhost:8000/v1/training/match-screen", {
2900
+ let t = this.clientId || window.BariwebConfig?.clientId || "", n = await fetch("http://localhost:8000/v1/training/match-screen", {
2901
2901
  method: "POST",
2902
2902
  headers: {
2903
2903
  "Content-Type": "application/json",
2904
- "X-Client-ID": this.clientId || window.__BARIWEB_CLIENT_ID__ || ""
2904
+ "X-Client-ID": t
2905
2905
  },
2906
2906
  body: JSON.stringify({ fingerprint: e.fingerprint })
2907
2907
  });
2908
- if (t.ok) {
2909
- let e = await t.json();
2908
+ if (n.ok) {
2909
+ let e = await n.json();
2910
2910
  this._currentScreenLabel = e.matched ? e.label : "";
2911
2911
  }
2912
2912
  } catch {}
2913
2913
  }), window.addEventListener("keydown", this._handleGlobalKeydown);
2914
2914
  }
2915
+ updated(e) {
2916
+ super.updated(e);
2917
+ let t = !!this._chat.pendingConfirmation;
2918
+ t && !this._hadPendingConfirmation && this._chat.isVoiceModeActive() && setTimeout(() => {
2919
+ this._sttState === "idle" && this._startRecording();
2920
+ }, 500), this._hadPendingConfirmation = t;
2921
+ }
2915
2922
  disconnectedCallback() {
2916
2923
  super.disconnectedCallback(), t.stop(), this._cleanupRecording(), window.removeEventListener("keydown", this._handleGlobalKeydown);
2917
2924
  }
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
2925
  _beep(e) {
2925
2926
  try {
2926
2927
  let t = new (window.AudioContext || window.webkitAudioContext)(), n = t.createOscillator(), r = t.createGain();
@@ -2928,13 +2929,13 @@ var gt = "bw-stt-lang-v1", _t = 200, vt = .015, yt = 1200, bt = 2e4, xt = 350, S
2928
2929
  } catch {}
2929
2930
  }
2930
2931
  _toggle() {
2931
- this._isOpen = !this._isOpen, this._isOpen && (setTimeout(() => this._announce(this._t("announceVoiceInputAvailable")), 500), this._scrollMessages());
2932
+ this._isOpen = !this._isOpen, this._isOpen && this._scrollMessages();
2932
2933
  }
2933
2934
  setOpen(e) {
2934
- this._isOpen = e, e && (this._announce(this._t("announceWidgetOpened")), this._scrollMessages());
2935
+ this._isOpen = e, e && this._scrollMessages();
2935
2936
  }
2936
2937
  _setTab(e) {
2937
- this._activeTab = e, e === "chat" && (this._announce(this._t("announceSwitchedToChat")), this._scrollMessages(), setTimeout(() => {
2938
+ this._activeTab = e, e === "chat" && (this._scrollMessages(), setTimeout(() => {
2938
2939
  this.renderRoot?.querySelector("#bw-voice-btn")?.focus();
2939
2940
  }, 300));
2940
2941
  }
@@ -3048,7 +3049,7 @@ var gt = "bw-stt-lang-v1", _t = 200, vt = .015, yt = 1200, bt = 2e4, xt = 350, S
3048
3049
  "vibrate" in navigator && navigator.vibrate(20);
3049
3050
  }
3050
3051
  _renderChatTab() {
3051
- let e = this._chat.messages, t = this._chat.isLoading, n = this._chat.pendingConfirmation, r = t || this._sttState === "processing", i = (e) => this._t(e);
3052
+ let e = this._chat.messages, t = this._chat.isLoading, n = this._chat.pendingConfirmation, r = t || this._sttState !== "idle", i = (e) => this._t(e);
3052
3053
  return I`
3053
3054
  <div class="chat-messages" id="bw-chat-messages">
3054
3055
  ${this._currentScreenLabel ? I`
@@ -3064,24 +3065,18 @@ var gt = "bw-stt-lang-v1", _t = 200, vt = .015, yt = 1200, bt = 2e4, xt = 350, S
3064
3065
  <p class="chat-empty-title">${i("chatEmptyTitle")}</p>
3065
3066
  <p class="chat-empty-sub">${i("chatEmptySub")}</p>
3066
3067
  </div>
3067
- ` : e.map((e) => {
3068
- if (e.role === "assistant" && (e.text.includes("✅") || e.text.includes("⌨️") || e.text.includes("🔄"))) {
3069
- let t = e.text.split("\n")[0];
3070
- return I`
3068
+ ` : e.map((e) => e.role === "assistant" && (e.text.includes("✅") || e.text.includes("⌨️") || e.text.includes("🔄")) ? I`
3071
3069
  <details class="system-log">
3072
3070
  <summary class="system-log-header">
3073
- ${Y.code} <span>${t}</span>
3071
+ <span>${e.text.split("\n")[0]}</span>
3074
3072
  </summary>
3075
3073
  <div class="system-log-details">${e.text}</div>
3076
3074
  </details>
3077
- `;
3078
- }
3079
- return I`
3075
+ ` : I`
3080
3076
  <div class="chat-bubble ${e.role}">
3081
3077
  ${e.text}
3082
3078
  </div>
3083
- `;
3084
- })}
3079
+ `)}
3085
3080
 
3086
3081
  ${t ? I`
3087
3082
  <div class="typing-indicator">
@@ -3159,11 +3154,7 @@ var gt = "bw-stt-lang-v1", _t = 200, vt = .015, yt = 1200, bt = 2e4, xt = 350, S
3159
3154
  `;
3160
3155
  }
3161
3156
  _renderA11yTab() {
3162
- let e = this._a11y.settings, t = (e) => this._t(e);
3163
- return I`
3164
- <div class="a11y-scroller">
3165
- <div class="settings-grid">
3166
- ${[
3157
+ let e = this._a11y.settings, t = (e) => this._t(e), n = [
3167
3158
  {
3168
3159
  id: "bw-tile-textscale",
3169
3160
  icon: Y.textSize,
@@ -3174,7 +3165,7 @@ var gt = "bw-stt-lang-v1", _t = 200, vt = .015, yt = 1200, bt = 2e4, xt = 350, S
3174
3165
  },
3175
3166
  {
3176
3167
  id: "bw-tile-monochrome",
3177
- icon: Y.palette,
3168
+ icon: Y.visualImpair,
3178
3169
  label: t("tileMonochrome"),
3179
3170
  value: t("valueMonochrome"),
3180
3171
  active: e.monochrome,
@@ -3182,7 +3173,7 @@ var gt = "bw-stt-lang-v1", _t = 200, vt = .015, yt = 1200, bt = 2e4, xt = 350, S
3182
3173
  },
3183
3174
  {
3184
3175
  id: "bw-tile-contrast",
3185
- icon: Y.sun,
3176
+ icon: Y.moon,
3186
3177
  label: t("tileContrast"),
3187
3178
  value: t("valueDark"),
3188
3179
  active: e.darkHighContrast,
@@ -3190,7 +3181,7 @@ var gt = "bw-stt-lang-v1", _t = 200, vt = .015, yt = 1200, bt = 2e4, xt = 350, S
3190
3181
  },
3191
3182
  {
3192
3183
  id: "bw-tile-links",
3193
- icon: Y.link,
3184
+ icon: Y.visualImpair,
3194
3185
  label: t("tileLinks"),
3195
3186
  value: t("valueHighlight"),
3196
3187
  active: e.linkHighlight,
@@ -3198,7 +3189,7 @@ var gt = "bw-stt-lang-v1", _t = 200, vt = .015, yt = 1200, bt = 2e4, xt = 350, S
3198
3189
  },
3199
3190
  {
3200
3191
  id: "bw-tile-spacing",
3201
- icon: Y.type,
3192
+ icon: Y.textSize,
3202
3193
  label: t("tileSpacing"),
3203
3194
  value: t("valueEnlarge"),
3204
3195
  active: e.textSpacing,
@@ -3206,7 +3197,7 @@ var gt = "bw-stt-lang-v1", _t = 200, vt = .015, yt = 1200, bt = 2e4, xt = 350, S
3206
3197
  },
3207
3198
  {
3208
3199
  id: "bw-tile-font",
3209
- icon: Y.type,
3200
+ icon: Y.textSize,
3210
3201
  label: t("tileFont"),
3211
3202
  value: t("valueDyslexia"),
3212
3203
  active: e.dyslexicFont,
@@ -3214,7 +3205,7 @@ var gt = "bw-stt-lang-v1", _t = 200, vt = .015, yt = 1200, bt = 2e4, xt = 350, S
3214
3205
  },
3215
3206
  {
3216
3207
  id: "bw-tile-cursor",
3217
- icon: Y.mouse,
3208
+ icon: Y.cursor,
3218
3209
  label: t("tileCursor"),
3219
3210
  value: t("valueEnlarge"),
3220
3211
  active: e.cursorMagnifier,
@@ -3228,7 +3219,30 @@ var gt = "bw-stt-lang-v1", _t = 200, vt = .015, yt = 1200, bt = 2e4, xt = 350, S
3228
3219
  active: this._sttState === "recording",
3229
3220
  action: () => this._toggleVoice()
3230
3221
  }
3231
- ].map((e) => I`
3222
+ ];
3223
+ return I`
3224
+ <div class="a11y-scroller">
3225
+ <div style="padding: 16px 16px 0;">
3226
+ <div style="display: flex; align-items: center; justify-content: space-between; padding: 12px; background: var(--bw-bg-subtle, #f8fafc); border-radius: var(--bw-radius, 14px); margin-bottom: 0px;">
3227
+ <div style="display: flex; align-items: center; gap: 10px; font-weight: 600; font-size: 14px; color: var(--bw-fg, #1e293b);">
3228
+ ${Y.languages} ${t("recognitionLanguage")}
3229
+ </div>
3230
+ <select style="height: 34px; padding: 0 8px; border: 1px solid var(--bw-primary, #6d28d9); border-radius: 8px; background: rgba(109, 40, 217, 0.05); color: var(--bw-primary, #6d28d9); cursor: pointer; outline: none; font-size: 13px; font-weight: 600;"
3231
+ .value=${this._sttLanguageMode}
3232
+ @change=${(e) => {
3233
+ this._setSttLanguageMode(e.target.value), this.requestUpdate();
3234
+ }}
3235
+ aria-label=${t("changeRecognitionLanguage")}>
3236
+ <option value="auto">${t("languageAuto")}</option>
3237
+ <option value="kz">${t("languageKz")}</option>
3238
+ <option value="ru">${t("languageRu")}</option>
3239
+ <option value="en">${t("languageEn")}</option>
3240
+ </select>
3241
+ </div>
3242
+ </div>
3243
+
3244
+ <div class="settings-grid">
3245
+ ${n.map((e) => I`
3232
3246
  <button class="settings-card" ?active=${e.active} @click=${e.action} id=${e.id}
3233
3247
  aria-pressed=${e.active ? "true" : "false"} aria-label=${e.label}>
3234
3248
  ${e.icon || Y.mic}
@@ -3268,24 +3282,7 @@ var gt = "bw-stt-lang-v1", _t = 200, vt = .015, yt = 1200, bt = 2e4, xt = 350, S
3268
3282
  </div>
3269
3283
  </div>
3270
3284
 
3271
- <div class="ai-tools-section">
3272
- <div style="display: flex; align-items: center; justify-content: space-between; padding: 12px; background: var(--bw-bg-subtle, #f8fafc); border-radius: var(--bw-radius, 14px); margin-bottom: 12px;">
3273
- <div class="lang-row-label" style="display: flex; align-items: center; gap: 10px; font-weight: 600; font-size: 14px; color: var(--bw-fg, #1e293b);">
3274
- <span class="lang-row-icon">${Y.languages}</span>${t("recognitionLanguage")}
3275
- </div>
3276
- <select style="height: 34px; padding: 0 8px; border: 1px solid var(--bw-border); border-radius: 8px; background: #fff; cursor: pointer; outline: none; font-size: 13px;"
3277
- .value=${this._sttLanguageMode}
3278
- @change=${(e) => {
3279
- this._setSttLanguageMode(e.target.value), this.requestUpdate();
3280
- }}
3281
- aria-label=${t("changeRecognitionLanguage")}>
3282
- <option value="auto">${t("languageAuto")}</option>
3283
- <option value="kz">${t("languageKz")}</option>
3284
- <option value="ru">${t("languageRu")}</option>
3285
- <option value="en">${t("languageEn")}</option>
3286
- </select>
3287
- </div>
3288
-
3285
+ <div class="ai-tools-section" style="margin-top: 16px;">
3289
3286
  <button class="ai-tool-btn ${this._aiA11y.simplifyEnabled ? "active" : ""}"
3290
3287
  @click=${() => this._aiA11y.toggleSimplify()} id="bw-ai-simplify">
3291
3288
  ${Y.textSize}
@@ -3335,7 +3332,7 @@ var gt = "bw-stt-lang-v1", _t = 200, vt = .015, yt = 1200, bt = 2e4, xt = 350, S
3335
3332
  @keydown=${(e) => {
3336
3333
  e.key === "Enter" && this._handleAdminLogin();
3337
3334
  }} />
3338
- ${this._authError ? I`<div class="auth-error">${this._authError}</div>` : ""}
3335
+ ${this._authError ? I`<p class="auth-error">${this._authError}</p>` : ""}
3339
3336
  <button class="admin-login-btn" @click=${this._handleAdminLogin}>${e("adminLogin")}</button>
3340
3337
  `}
3341
3338
  <button class="admin-close-btn" @click=${() => {
@@ -3369,12 +3366,12 @@ var gt = "bw-stt-lang-v1", _t = 200, vt = .015, yt = 1200, bt = 2e4, xt = 350, S
3369
3366
  <div class="bw-tabs" role="tablist">
3370
3367
  <button class="bw-tab" ?active=${this._activeTab === "chat"}
3371
3368
  @click=${() => this._setTab("chat")} role="tab"
3372
- aria-selected=${this._activeTab === "chat" ? "true" : "false"} id="bw-tab-chat">
3369
+ aria-selected=${this._activeTab === "chat"} id="bw-tab-chat">
3373
3370
  ${Y.chat} ${e("tabChat")}
3374
3371
  </button>
3375
3372
  <button class="bw-tab" ?active=${this._activeTab === "a11y"}
3376
3373
  @click=${() => this._setTab("a11y")} role="tab"
3377
- aria-selected=${this._activeTab === "a11y" ? "true" : "false"} id="bw-tab-settings">
3374
+ aria-selected=${this._activeTab === "a11y"} id="bw-tab-settings">
3378
3375
  ${Y.settings} ${e("tabSettings")}
3379
3376
  </button>
3380
3377
  </div>
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "bariweb-widget",
3
- "version": "0.1.13",
3
+ "version": "0.1.20",
4
4
  "type": "module",
5
5
  "main": "./dist/bariweb.iife.js",
6
6
  "module": "./dist/bariweb.js",