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.
- package/dist/bariweb.iife.js +32 -30
- package/dist/bariweb.js +91 -94
- package/package.json +1 -1
package/dist/bariweb.iife.js
CHANGED
|
@@ -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`)
|
|
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=>
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
${
|
|
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`<
|
|
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
|
|
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
|
|
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")
|
|
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")
|
|
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 = !
|
|
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 ? !
|
|
2204
|
+
return e === null ? !1 : e !== "0";
|
|
2222
2205
|
} catch {
|
|
2223
|
-
return !
|
|
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.
|
|
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
|
-
|
|
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
|
-
|
|
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
|
|
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:
|
|
2877
|
+
client_public_id: e,
|
|
2878
2878
|
admin_key: this._adminPassword
|
|
2879
2879
|
})
|
|
2880
2880
|
});
|
|
2881
|
-
if (
|
|
2882
|
-
let { access_token:
|
|
2883
|
-
localStorage.setItem("bw_admin_token",
|
|
2884
|
-
} else this._authError = (await
|
|
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":
|
|
2904
|
+
"X-Client-ID": t
|
|
2905
2905
|
},
|
|
2906
2906
|
body: JSON.stringify({ fingerprint: e.fingerprint })
|
|
2907
2907
|
});
|
|
2908
|
-
if (
|
|
2909
|
-
let e = await
|
|
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 &&
|
|
2932
|
+
this._isOpen = !this._isOpen, this._isOpen && this._scrollMessages();
|
|
2932
2933
|
}
|
|
2933
2934
|
setOpen(e) {
|
|
2934
|
-
this._isOpen = e, e &&
|
|
2935
|
+
this._isOpen = e, e && this._scrollMessages();
|
|
2935
2936
|
}
|
|
2936
2937
|
_setTab(e) {
|
|
2937
|
-
this._activeTab = e, e === "chat" && (this.
|
|
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
|
|
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
|
-
|
|
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.
|
|
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.
|
|
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.
|
|
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.
|
|
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.
|
|
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.
|
|
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
|
-
]
|
|
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`<
|
|
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"
|
|
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"
|
|
3374
|
+
aria-selected=${this._activeTab === "a11y"} id="bw-tab-settings">
|
|
3378
3375
|
${Y.settings} ${e("tabSettings")}
|
|
3379
3376
|
</button>
|
|
3380
3377
|
</div>
|