@foisit/react-wrapper 2.4.1 → 2.4.4
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/README.md +22 -3
- package/index.js +3 -3
- package/index.mjs +243 -178
- package/package.json +15 -2
package/README.md
CHANGED
|
@@ -134,6 +134,28 @@ Define parameters and Foisit will automatically generate forms to collect them:
|
|
|
134
134
|
}
|
|
135
135
|
```
|
|
136
136
|
|
|
137
|
+
**Enterprise-safe param collection controls**
|
|
138
|
+
|
|
139
|
+
- `collectRequiredViaForm` (default: true): force missing/invalid required params to be collected via a form instead of conversational guessing.
|
|
140
|
+
- `allowAiParamExtraction` (default: true): when false, ignore AI-extracted params and always prompt the user for required fields.
|
|
141
|
+
|
|
142
|
+
Example:
|
|
143
|
+
|
|
144
|
+
```tsx
|
|
145
|
+
{
|
|
146
|
+
command: 'secure create user',
|
|
147
|
+
description: 'No AI guessing, form-only',
|
|
148
|
+
collectRequiredViaForm: true,
|
|
149
|
+
allowAiParamExtraction: false,
|
|
150
|
+
parameters: [
|
|
151
|
+
{ name: 'fullName', type: 'string', required: true },
|
|
152
|
+
{ name: 'email', type: 'string', required: true },
|
|
153
|
+
{ name: 'age', type: 'number', required: true, min: 18 },
|
|
154
|
+
],
|
|
155
|
+
action: (params) => userService.create(params),
|
|
156
|
+
}
|
|
157
|
+
```
|
|
158
|
+
|
|
137
159
|
**Supported Parameter Types:**
|
|
138
160
|
|
|
139
161
|
- `string` - Text input
|
|
@@ -532,8 +554,6 @@ function AccountManager() {
|
|
|
532
554
|
### Full Type Definitions
|
|
533
555
|
|
|
534
556
|
```tsx
|
|
535
|
-
import { AssistantCommand, InteractiveResponse } from '@foisit/core';
|
|
536
|
-
|
|
537
557
|
// Type-safe command definition
|
|
538
558
|
const myCommand: AssistantCommand = {
|
|
539
559
|
command: 'update settings',
|
|
@@ -646,7 +666,6 @@ test('renders assistant', () => {
|
|
|
646
666
|
|
|
647
667
|
## Related Packages
|
|
648
668
|
|
|
649
|
-
- **[@foisit/core](../core)** - Core engine (auto-installed)
|
|
650
669
|
- **[@foisit/angular-wrapper](../angular-wrapper)** - Angular integration
|
|
651
670
|
- **[@foisit/vue-wrapper](../vue-wrapper)** - Vue integration
|
|
652
671
|
|
package/index.js
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
"use strict";Object.defineProperty(exports,Symbol.toStringTag,{value:"Module"});const A=require("react/jsx-runtime"),S=require("react"),W={};function N(){return A.jsx("div",{className:W.container,children:A.jsx("h1",{children:"Welcome to ReactWrapper!"})})}class T{constructor(t){this.endpoint=t||"https://foisit-ninja.netlify.app/.netlify/functions/intent"}async determineIntent(t,e,i){try{const s={userInput:t,commands:e.map(r=>({id:r.id,command:r.command,description:r.description,parameters:r.parameters})),context:i},n=await fetch(this.endpoint,{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify(s)});if(!n.ok)throw new Error(`Proxy API Error: ${n.statusText}`);return await n.json()}catch(s){return console.error("OpenAIService Error:",s),{type:"unknown"}}}}class B{constructor(t=!0){if(this.commands=new Map,this.openAIService=null,this.context=null,this.pendingConfirmation=null,this.enableSmartIntent=!0,this.selectOptionsCache=new Map,typeof t=="boolean"){this.enableSmartIntent=t,this.enableSmartIntent&&(this.openAIService=new T);return}this.enableSmartIntent=t.enableSmartIntent??!0,this.enableSmartIntent&&(this.openAIService=new T(t.intentEndpoint))}addCommand(t,e){let i;if(typeof t=="string"){if(!e)throw new Error("Action required when adding command by string.");i={id:t.toLowerCase().replace(/\s+/g,"_"),command:t.toLowerCase(),action:e}}else i={...t},i.id||(i.id=i.command.toLowerCase().replace(/\s+/g,"_"));this.commands.set(i.command.toLowerCase(),i),i.id&&(i.id,i.command)}removeCommand(t){this.commands.delete(t.toLowerCase())}async executeCommand(t){if(typeof t=="object"&&t!==null){if(this.isStructured(t)){const c=String(t.commandId),f=t.params??{},o=this.getCommandById(c);if(!o)return{message:"That command is not available.",type:"error"};const p=this.sanitizeParamsForCommand(o,f),h=(o.parameters??[]).filter(C=>C.required).filter(C=>p[C.name]==null||p[C.name]==="");return h.length>0?(this.context={commandId:this.getCommandIdentifier(o),params:p},{message:`Please provide the required details for "${o.command}".`,type:"form",fields:h}):o.critical?(this.pendingConfirmation={commandId:this.getCommandIdentifier(o),params:p},this.buildConfirmResponse(o)):this.safeRunAction(o,p)}if(!this.context)return{message:"Session expired or invalid context.",type:"error"};const n=this.getCommandById(this.context.commandId);if(!n)return this.context=null,{message:"Session expired or invalid context.",type:"error"};if(Array.isArray(t))return{message:"Invalid form payload.",type:"error"};const a={...this.context.params,...t};if(n.critical)return this.context=null,this.pendingConfirmation={commandId:this.getCommandIdentifier(n),params:a},this.buildConfirmResponse(n);const r=await this.safeRunAction(n,a);return this.context=null,this.normalizeResponse(r)}const e=t.trim().toLowerCase();if(this.pendingConfirmation){const n=e;if(["yes","y","confirm","ok","okay"].includes(n)){const{commandId:a,params:r}=this.pendingConfirmation;this.pendingConfirmation=null;const c=this.getCommandById(a);return c?this.safeRunAction(c,r):{message:"That action is no longer available.",type:"error"}}return["no","n","cancel","stop"].includes(n)?(this.pendingConfirmation=null,{message:"✅ Cancelled.",type:"success"}):{message:"Please confirm: Yes or No.",type:"confirm",options:[{label:"Yes",value:"yes"},{label:"No",value:"no"}]}}const i=this.commands.get(e);if(i){const n=i,a=(n.parameters??[]).filter(r=>r.required);return a.length>0?(this.context={commandId:this.getCommandIdentifier(n),params:{}},{message:`Please provide the required details for "${n.command}".`,type:"form",fields:a}):n.critical?(this.pendingConfirmation={commandId:this.getCommandIdentifier(n),params:{}},this.buildConfirmResponse(n)):this.safeRunAction(n,{})}const s=await this.tryDeterministicMatch(e);if(s)return s;if(this.enableSmartIntent&&this.openAIService){const n=await this.getCommandsForAI(),a=await this.openAIService.determineIntent(e,n,this.context);return this.handleAIResult(a)}return this.enableSmartIntent?this.listAllCommands():{message:"I'm not sure what you mean.",type:"error"}}async handleAIResult(t){if(t.type==="match"&&t.match){const e=this.getCommandById(t.match);if(!e)return{message:"I'm not sure what you mean.",type:"error"};const i=t.params??{},s=this.sanitizeParamsForCommand(e,i),a=(e.parameters??[]).filter(c=>c.required).filter(c=>s[c.name]==null||s[c.name]==="");if(t.incomplete||a.length>0){this.context={commandId:this.getCommandIdentifier(e),params:s};const c=a.some(f=>f.type==="select");if(a.length<=2&&!c){const f=a.map(o=>o.name).join(" and ");return{message:t.message||`Please provide ${f}.`,type:"question"}}return{message:t.message||`Please fill in the missing details for "${e.command}".`,type:"form",fields:a}}if(e.critical)return this.pendingConfirmation={commandId:this.getCommandIdentifier(e),params:s},this.buildConfirmResponse(e);const r=await e.action(s);return this.normalizeResponse(r)}return t.type==="ambiguous"&&t.options&&t.options.length?{message:t.message||"Did you mean one of these?",type:"ambiguous",options:t.options.map(e=>({label:e.label,value:e.commandId??e.label,commandId:e.commandId}))}:this.listAllCommands()}sanitizeParamsForCommand(t,e){const i={...e??{}};for(const s of t.parameters??[])if(s.type==="date"){const n=i[s.name];if(typeof n=="string"){const a=n.trim();this.isIsoDateString(a)||delete i[s.name]}}return i}isIsoDateString(t){if(!/^\d{4}-\d{2}-\d{2}$/.test(t))return!1;const e=new Date(`${t}T00:00:00Z`);return!Number.isNaN(e.getTime())}buildConfirmResponse(t){return{message:`⚠️ Are you sure you want to run "${t.command}"?`,type:"confirm",options:[{label:"Yes",value:"yes"},{label:"No",value:"no"}]}}async tryDeterministicMatch(t){const e=[];for(const r of this.commands.values()){let c=0;const f=r.command.toLowerCase();t.includes(f)&&(c+=5);const o=r.keywords??[];for(const p of o){const b=p.toLowerCase().trim();b&&(t===b?c+=4:t.includes(b)&&(c+=3))}c>0&&e.push({cmd:r,score:c})}if(e.length===0)return null;e.sort((r,c)=>c.score-r.score);const i=e[0].score,s=e.filter(r=>r.score===i).slice(0,3);if(s.length>1)return{message:"I think you mean one of these. Which one should I run?",type:"ambiguous",options:s.map(r=>({label:r.cmd.command,value:r.cmd.command,commandId:r.cmd.id}))};const n=s[0].cmd,a=(n.parameters??[]).filter(r=>r.required);return a.length>0?(this.context={commandId:this.getCommandIdentifier(n),params:{}},{message:`Please provide the required details for "${n.command}".`,type:"form",fields:a}):n.critical?(this.pendingConfirmation={commandId:this.getCommandIdentifier(n),params:{}},this.buildConfirmResponse(n)):this.safeRunAction(n,{})}async safeRunAction(t,e){try{const i=await t.action(e??{});return this.normalizeResponse(i)}catch{return{message:"Something went wrong while running that command.",type:"error"}}}async getCommandsForAI(){const t=Array.from(this.commands.values()).map(e=>({...e,parameters:e.parameters?e.parameters.map(i=>({...i})):void 0}));return await Promise.all(t.map(async e=>{e.parameters&&await Promise.all(e.parameters.map(async i=>{if(i.type!=="select"||!i.getOptions||i.options&&i.options.length)return;const s=`${e.id??e.command}:${i.name}`,n=this.selectOptionsCache.get(s),a=Date.now();if(n&&a-n.ts<6e4){i.options=n.options;return}try{const r=await i.getOptions();this.selectOptionsCache.set(s,{options:r,ts:a}),i.options=r}catch{}}))})),t}getCommandById(t){for(const e of this.commands.values())if(e.id===t)return e}listAllCommands(){return{message:"Here are the available commands:",type:"ambiguous",options:Array.from(this.commands.values()).map(e=>({label:e.command,value:e.id??e.command,commandId:e.id??e.command}))}}normalizeResponse(t){return typeof t=="string"?{message:t,type:"success"}:t&&typeof t=="object"?t:{message:"Done",type:"success"}}isStructured(t){return typeof t.commandId=="string"}getCommandIdentifier(t){return t.id||(t.id=t.command.toLowerCase().replace(/\s+/g,"_")),t.id}getCommands(){return Array.from(this.commands.keys())}}class q{constructor(){this.synth=window.speechSynthesis}speak(t,e){if(!this.synth){console.error("SpeechSynthesis API is not supported in this browser.");return}const i=new SpeechSynthesisUtterance(t);e&&(i.pitch=e.pitch||1,i.rate=e.rate||1,i.volume=e.volume||1),i.onstart=()=>{window.dispatchEvent(new CustomEvent("foisit:tts-start"))},i.onend=()=>{console.log("Speech finished."),window.dispatchEvent(new CustomEvent("foisit:tts-end"))},i.onerror=s=>{console.error("Error during speech synthesis:",s.error)},this.synth.speak(i)}stopSpeaking(){this.synth&&this.synth.cancel()}}class O{constructor(){this.fallbackMessage="Sorry, I didn’t understand that."}setFallbackMessage(t){this.fallbackMessage=t}handleFallback(t){t&&console.log(`Fallback triggered for: "${t}"`),console.log(this.fallbackMessage),new q().speak(this.fallbackMessage)}getFallbackMessage(){return this.fallbackMessage}}const P=()=>{const d=window;return d.SpeechRecognition??d.webkitSpeechRecognition??null};class z{constructor(t="en-US",e={}){this.recognition=null,this.isListening=!1,this.engineActive=!1,this.intentionallyStopped=!1,this.restartAllowed=!0,this.lastStart=0,this.backoffMs=250,this.destroyed=!1,this.resultCallback=null,this.ttsSpeaking=!1,this.debugEnabled=!0,this.restartTimer=null,this.prewarmed=!1,this.hadResultThisSession=!1,this.onTTSStart=()=>{var s;this.ttsSpeaking=!0;try{(s=this.recognition)==null||s.stop()}catch{}this.isListening&&this.emitStatus("speaking")},this.onTTSEnd=()=>{this.ttsSpeaking=!1,this.isListening&&this.restartAllowed?this.safeRestart():this.emitStatus(this.isListening?"listening":"idle")};const i=P();if(i){this.recognition=new i,this.recognition.lang=t,this.recognition.interimResults=e.interimResults??!0,this.recognition.continuous=e.continuous??!0,this.recognition.onresult=n=>this.handleResult(n,e),this.recognition.onend=()=>this.handleEnd(),this.recognition.onstart=()=>{this.log("recognition onstart"),this.engineActive=!0,this.hadResultThisSession=!1,this.restartTimer&&(clearTimeout(this.restartTimer),this.restartTimer=null),this.backoffMs=250,this.isListening&&!this.ttsSpeaking&&this.emitStatus("listening")};const s=this.recognition;s.onaudiostart=()=>this.log("onaudiostart"),s.onsoundstart=()=>this.log("onsoundstart"),s.onspeechstart=()=>this.log("onspeechstart"),s.onspeechend=()=>this.log("onspeechend"),s.onsoundend=()=>this.log("onsoundend"),s.onaudioend=()=>this.log("onaudioend"),this.recognition.onerror=n=>this.handleError(n)}else this.recognition=null,this.emitStatus("unsupported");window.addEventListener("foisit:tts-start",this.onTTSStart),window.addEventListener("foisit:tts-end",this.onTTSEnd),this.visibilityHandler=()=>{var s;if(document.hidden){try{(s=this.recognition)==null||s.stop()}catch{}this.emitStatus(this.ttsSpeaking?"speaking":"idle")}else this.isListening&&!this.ttsSpeaking&&this.safeRestart()},document.addEventListener("visibilitychange",this.visibilityHandler)}log(t){this.debugEnabled&&t&&console.log("[VoiceProcessor]",t)}warn(t){this.debugEnabled&&t&&console.warn("[VoiceProcessor]",t)}error(t){this.debugEnabled&&t&&console.error("[VoiceProcessor]",t)}isSupported(){return P()!==null}onStatusChange(t){this.statusCallback=t}startListening(t){if(!this.isSupported()||!this.recognition){this.warn("VoiceProcessor: SpeechRecognition is not supported in this browser."),this.emitStatus("unsupported");return}if(this.isListening){this.warn("VoiceProcessor: Already listening."),this.resultCallback=t;return}this.resultCallback=t,this.intentionallyStopped=!1,this.restartAllowed=!0,this.isListening=!0,this.emitStatus("listening"),this.prewarmAudio().finally(()=>{this.safeRestart()})}stopListening(){var t;this.intentionallyStopped=!0,this.restartAllowed=!1,this.isListening=!1,this.emitStatus(this.ttsSpeaking?"speaking":"idle");try{(t=this.recognition)==null||t.stop()}catch{}}destroy(){this.destroyed=!0,this.stopListening(),this.resultCallback=null,window.removeEventListener("foisit:tts-start",this.onTTSStart),window.removeEventListener("foisit:tts-end",this.onTTSEnd),this.visibilityHandler&&(document.removeEventListener("visibilitychange",this.visibilityHandler),this.visibilityHandler=void 0)}handleResult(t,e){var s,n;if(!this.resultCallback)return;const i=e.confidenceThreshold??.6;for(let a=t.resultIndex;a<t.results.length;a++){const r=t.results[a],c=r&&r[0],f=((n=(s=c==null?void 0:c.transcript)==null?void 0:s.trim)==null?void 0:n.call(s))||"",o=(c==null?void 0:c.confidence)??0;if(f&&!(!r.isFinal&&e.interimResults===!1)&&!(r.isFinal&&o<i))try{this.hadResultThisSession=!0,this.resultCallback(f,!!r.isFinal)}catch{this.error("VoiceProcessor: result callback error")}}}handleEnd(){if(this.log("recognition onend"),this.engineActive=!1,this.destroyed||this.intentionallyStopped||!this.restartAllowed||this.ttsSpeaking){this.ttsSpeaking||(this.isListening=!1,this.emitStatus("idle"));return}this.isListening=!0,this.scheduleRestart()}handleError(t){const e=t==null?void 0:t.error;if(this.warn(`Error occurred: ${e??"unknown"}`),e&&["not-allowed","service-not-allowed","bad-grammar","language-not-supported"].includes(e)){this.intentionallyStopped=!0,this.restartAllowed=!1,this.isListening=!1,this.emitStatus("error",{error:e});return}this.scheduleRestart()}safeRestart(){if(!this.recognition)return;if(this.engineActive){this.log("safeRestart: engine already active, skipping start");return}const t=Date.now();if(t-this.lastStart<300){setTimeout(()=>this.safeRestart(),300);return}this.lastStart=t;try{this.log("calling recognition.start()"),this.recognition.start(),this.backoffMs=250,this.isListening&&!this.ttsSpeaking&&this.emitStatus("listening")}catch{this.error("recognition.start() threw; scheduling restart"),this.scheduleRestart()}}scheduleRestart(){if(this.destroyed||this.intentionallyStopped||!this.restartAllowed||this.ttsSpeaking)return;if(this.engineActive){this.log("scheduleRestart: engine active, not scheduling");return}const t=Math.min(this.backoffMs,2e3);if(this.log(`scheduleRestart in ${t}ms`),this.restartTimer){this.log("scheduleRestart: restart already scheduled");return}this.restartTimer=setTimeout(()=>{this.restartTimer=null,!(this.destroyed||this.intentionallyStopped||!this.restartAllowed||this.ttsSpeaking)&&this.safeRestart()},t),this.backoffMs=Math.min(this.backoffMs*2,2e3)}async prewarmAudio(){if(!this.prewarmed)try{if(typeof navigator>"u"||!("mediaDevices"in navigator))return;const t=navigator.mediaDevices;if(!(t!=null&&t.getUserMedia))return;this.log("prewarmAudio: requesting mic");const e=await t.getUserMedia({audio:!0});for(const i of e.getTracks())i.stop();this.prewarmed=!0,this.log("prewarmAudio: mic ready")}catch{this.warn("prewarmAudio: failed to get mic")}}emitStatus(t,e){if(this.statusCallback)try{this.statusCallback(t,e)}catch{this.error("VoiceProcessor: status callback error")}}}class j{constructor(){this.lastTap=0}setupDoubleTapListener(t){this.destroy(),this.dblClickListener=()=>{t()},document.addEventListener("dblclick",this.dblClickListener),this.touchEndListener=()=>{const e=new Date().getTime(),i=e-this.lastTap;i<300&&i>0&&t(),this.lastTap=e},document.addEventListener("touchend",this.touchEndListener)}destroy(){this.dblClickListener&&document.removeEventListener("dblclick",this.dblClickListener),this.touchEndListener&&document.removeEventListener("touchend",this.touchEndListener),this.dblClickListener=void 0,this.touchEndListener=void 0}}function $(){if(document.querySelector("#assistant-styles")){console.log("Styles already injected");return}const t=document.createElement("style");t.id="assistant-styles",t.innerHTML=`
|
|
1
|
+
"use strict";Object.defineProperty(exports,Symbol.toStringTag,{value:"Module"});const A=require("react/jsx-runtime"),C=require("react"),N={};function W(){return A.jsx("div",{className:N.container,children:A.jsx("h1",{children:"Welcome to ReactWrapper!"})})}class T{constructor(t){this.endpoint=t||"https://foisit-ninja.netlify.app/.netlify/functions/intent"}async determineIntent(t,e,i){try{const s={userInput:t,commands:e.map(r=>({id:r.id,command:r.command,description:r.description,parameters:r.parameters})),context:i},n=await fetch(this.endpoint,{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify(s)});if(!n.ok)throw new Error(`Proxy API Error: ${n.statusText}`);return await n.json()}catch(s){return console.error("OpenAIService Error:",s),{type:"unknown"}}}}class B{constructor(t=!0){if(this.commands=new Map,this.openAIService=null,this.context=null,this.pendingConfirmation=null,this.enableSmartIntent=!0,this.selectOptionsCache=new Map,typeof t=="boolean"){this.enableSmartIntent=t,this.enableSmartIntent&&(this.openAIService=new T);return}this.enableSmartIntent=t.enableSmartIntent??!0,this.enableSmartIntent&&(this.openAIService=new T(t.intentEndpoint))}addCommand(t,e){let i;if(typeof t=="string"){if(!e)throw new Error("Action required when adding command by string.");i={id:t.toLowerCase().replace(/\s+/g,"_"),command:t.toLowerCase(),action:e}}else i={...t},i.id||(i.id=i.command.toLowerCase().replace(/\s+/g,"_"));this.commands.set(i.command.toLowerCase(),i),i.id&&(i.id,i.command)}removeCommand(t){this.commands.delete(t.toLowerCase())}async executeCommand(t){if(typeof t=="object"&&t!==null){if(this.isStructured(t)){const c=String(t.commandId),f=t.params??{},a=this.getCommandById(c);if(!a)return{message:"That command is not available.",type:"error"};const p=this.sanitizeParamsForCommand(a,f),m=(a.parameters??[]).filter(S=>S.required).filter(S=>p[S.name]==null||p[S.name]==="");return m.length>0?(this.context={commandId:this.getCommandIdentifier(a),params:p},{message:`Please provide the required details for "${a.command}".`,type:"form",fields:m}):a.critical?(this.pendingConfirmation={commandId:this.getCommandIdentifier(a),params:p},this.buildConfirmResponse(a)):this.safeRunAction(a,p)}if(!this.context)return{message:"Session expired or invalid context.",type:"error"};const n=this.getCommandById(this.context.commandId);if(!n)return this.context=null,{message:"Session expired or invalid context.",type:"error"};if(Array.isArray(t))return{message:"Invalid form payload.",type:"error"};const o={...this.context.params,...t};if(n.critical)return this.context=null,this.pendingConfirmation={commandId:this.getCommandIdentifier(n),params:o},this.buildConfirmResponse(n);const r=await this.safeRunAction(n,o);return this.context=null,this.normalizeResponse(r)}const e=t.trim().toLowerCase();if(this.pendingConfirmation){const n=e;if(["yes","y","confirm","ok","okay"].includes(n)){const{commandId:o,params:r}=this.pendingConfirmation;this.pendingConfirmation=null;const c=this.getCommandById(o);return c?this.safeRunAction(c,r):{message:"That action is no longer available.",type:"error"}}return["no","n","cancel","stop"].includes(n)?(this.pendingConfirmation=null,{message:"Cancelled.",type:"success"}):{message:"Please confirm: Yes or No.",type:"confirm",options:[{label:"Yes",value:"yes"},{label:"No",value:"no"}]}}const i=this.commands.get(e);if(i){const n=i,o=(n.parameters??[]).filter(r=>r.required);return o.length>0?(this.context={commandId:this.getCommandIdentifier(n),params:{}},{message:`Please provide the required details for "${n.command}".`,type:"form",fields:o}):n.critical?(this.pendingConfirmation={commandId:this.getCommandIdentifier(n),params:{}},this.buildConfirmResponse(n)):this.safeRunAction(n,{})}const s=await this.tryDeterministicMatch(e);if(s)return s;if(this.enableSmartIntent&&this.openAIService){const n=await this.getCommandsForAI(),o=await this.openAIService.determineIntent(e,n,this.context);return this.handleAIResult(o)}return this.enableSmartIntent?this.listAllCommands():{message:"I'm not sure what you mean.",type:"error"}}async handleAIResult(t){if(t.type==="match"&&t.match){const e=this.getCommandById(t.match);if(!e)return{message:"I'm not sure what you mean.",type:"error"};const i=t.params??{},s=this.sanitizeParamsForCommand(e,i),n=e.allowAiParamExtraction===!1?{}:s,r=(e.parameters??[]).filter(f=>f.required).filter(f=>n[f.name]==null||n[f.name]==="");if(t.incomplete||r.length>0){if(this.context={commandId:this.getCommandIdentifier(e),params:n},!(e.collectRequiredViaForm!==!1)&&this.shouldAskSingleQuestion(r)){const p=r.map(g=>g.name).join(" and ");return{message:t.message||`Please provide ${p}.`,type:"question"}}return{message:t.message||`Please fill in the missing details for "${e.command}".`,type:"form",fields:r}}if(e.critical)return this.pendingConfirmation={commandId:this.getCommandIdentifier(e),params:n},this.buildConfirmResponse(e);const c=await e.action(n);return this.normalizeResponse(c)}return t.type==="ambiguous"&&t.options&&t.options.length?{message:t.message||"Did you mean one of these?",type:"ambiguous",options:t.options.map(e=>({label:e.label,value:e.commandId??e.label,commandId:e.commandId}))}:this.listAllCommands()}sanitizeParamsForCommand(t,e){const i={...e??{}};for(const s of t.parameters??[]){const n=i[s.name];if(s.type==="string"){if(typeof n!="string"){delete i[s.name];continue}const o=n.trim();if(!o){delete i[s.name];continue}i[s.name]=o}if(s.type==="number"){const o=typeof n=="number"?n:Number(n==null?void 0:n.toString().trim());if(Number.isNaN(o)){delete i[s.name];continue}if(typeof s.min=="number"&&o<s.min){delete i[s.name];continue}if(typeof s.max=="number"&&o>s.max){delete i[s.name];continue}i[s.name]=o}if(s.type==="date"){const o=i[s.name];if(typeof o=="string"){const r=o.trim();this.isIsoDateString(r)?i[s.name]=r:delete i[s.name]}else delete i[s.name]}if(s.type==="select"){const o=typeof n=="string"?n:n==null?void 0:n.toString();if(!o){delete i[s.name];continue}if(Array.isArray(s.options)&&s.options.length>0&&!s.options.some(c=>String(c.value)===String(o))){delete i[s.name];continue}i[s.name]=o}if(s.type==="file"){const o=i[s.name],r=o&&typeof o=="object"&&typeof o.name=="string"&&typeof o.size=="number",c=typeof o=="string"&&/^data:[^;]+;base64,/.test(o);(s.delivery??"file")==="base64"?!c&&!r&&delete i[s.name]:r||delete i[s.name]}}return i}isIsoDateString(t){if(!/^\d{4}-\d{2}-\d{2}$/.test(t))return!1;const e=new Date(`${t}T00:00:00Z`);return!Number.isNaN(e.getTime())}shouldAskSingleQuestion(t){if(t.length!==1)return!1;const e=t[0].type;return e==="string"||e==="number"||e==="date"}buildConfirmResponse(t){return{message:`Are you sure you want to run "${t.command}"?`,type:"confirm",options:[{label:"Yes",value:"yes"},{label:"No",value:"no"}]}}async tryDeterministicMatch(t){const e=[];for(const r of this.commands.values()){let c=0;const f=r.command.toLowerCase();t.includes(f)&&(c+=5);const a=r.keywords??[];for(const p of a){const g=p.toLowerCase().trim();g&&(t===g?c+=4:t.includes(g)&&(c+=3))}c>0&&e.push({cmd:r,score:c})}if(e.length===0)return null;e.sort((r,c)=>c.score-r.score);const i=e[0].score,s=e.filter(r=>r.score===i).slice(0,3);if(s.length>1)return{message:"I think you mean one of these. Which one should I run?",type:"ambiguous",options:s.map(r=>({label:r.cmd.command,value:r.cmd.command,commandId:r.cmd.id}))};const n=s[0].cmd,o=(n.parameters??[]).filter(r=>r.required);return o.length>0?(this.context={commandId:this.getCommandIdentifier(n),params:{}},{message:`Please provide the required details for "${n.command}".`,type:"form",fields:o}):n.critical?(this.pendingConfirmation={commandId:this.getCommandIdentifier(n),params:{}},this.buildConfirmResponse(n)):this.safeRunAction(n,{})}async safeRunAction(t,e){try{const i=await t.action(e??{});return this.normalizeResponse(i)}catch{return{message:"Something went wrong while running that command.",type:"error"}}}async getCommandsForAI(){const t=Array.from(this.commands.values()).map(e=>({...e,parameters:e.parameters?e.parameters.map(i=>({...i})):void 0}));return await Promise.all(t.map(async e=>{e.parameters&&await Promise.all(e.parameters.map(async i=>{if(i.type!=="select"||!i.getOptions||i.options&&i.options.length)return;const s=`${e.id??e.command}:${i.name}`,n=this.selectOptionsCache.get(s),o=Date.now();if(n&&o-n.ts<6e4){i.options=n.options;return}try{const r=await i.getOptions();this.selectOptionsCache.set(s,{options:r,ts:o}),i.options=r}catch{}}))})),t}getCommandById(t){for(const e of this.commands.values())if(e.id===t)return e}listAllCommands(){return{message:"Here are the available commands:",type:"ambiguous",options:Array.from(this.commands.values()).map(e=>({label:e.command,value:e.id??e.command,commandId:e.id??e.command}))}}normalizeResponse(t){return typeof t=="string"?{message:t,type:"success"}:t&&typeof t=="object"?t:{message:"Done",type:"success"}}isStructured(t){return typeof t.commandId=="string"}getCommandIdentifier(t){return t.id||(t.id=t.command.toLowerCase().replace(/\s+/g,"_")),t.id}getCommands(){return Array.from(this.commands.keys())}}class H{constructor(){this.synth=typeof window<"u"?window.speechSynthesis:null}speak(t,e){if(!this.synth){console.error("SpeechSynthesis API is not supported in this environment.");return}const i=new SpeechSynthesisUtterance(t);e&&(i.pitch=e.pitch||1,i.rate=e.rate||1,i.volume=e.volume||1),typeof window<"u"&&(i.onstart=()=>{window.dispatchEvent(new CustomEvent("foisit:tts-start"))},i.onend=()=>{console.log("Speech finished."),window.dispatchEvent(new CustomEvent("foisit:tts-end"))}),i.onerror=s=>{console.error("Error during speech synthesis:",s.error)},this.synth.speak(i)}stopSpeaking(){this.synth&&this.synth.cancel()}}class z{constructor(){this.fallbackMessage="Sorry, I didn’t understand that."}setFallbackMessage(t){this.fallbackMessage=t}handleFallback(t){t&&console.log(`Fallback triggered for: "${t}"`),console.log(this.fallbackMessage),new H().speak(this.fallbackMessage)}getFallbackMessage(){return this.fallbackMessage}}const P=()=>{if(typeof window>"u")return null;const d=window;return d.SpeechRecognition??d.webkitSpeechRecognition??null};class O{constructor(t="en-US",e={}){this.recognition=null,this.isListening=!1,this.engineActive=!1,this.intentionallyStopped=!1,this.restartAllowed=!0,this.lastStart=0,this.backoffMs=250,this.destroyed=!1,this.resultCallback=null,this.ttsSpeaking=!1,this.debugEnabled=!0,this.restartTimer=null,this.prewarmed=!1,this.hadResultThisSession=!1,this.onTTSStart=()=>{var s;this.ttsSpeaking=!0;try{(s=this.recognition)==null||s.stop()}catch{}this.isListening&&this.emitStatus("speaking")},this.onTTSEnd=()=>{this.ttsSpeaking=!1,this.isListening&&this.restartAllowed?this.safeRestart():this.emitStatus(this.isListening?"listening":"idle")};const i=P();if(i){this.recognition=new i,this.recognition.lang=t,this.recognition.interimResults=e.interimResults??!0,this.recognition.continuous=e.continuous??!0,this.recognition.onresult=n=>this.handleResult(n,e),this.recognition.onend=()=>this.handleEnd(),this.recognition.onstart=()=>{this.log("recognition onstart"),this.engineActive=!0,this.hadResultThisSession=!1,this.restartTimer&&(clearTimeout(this.restartTimer),this.restartTimer=null),this.backoffMs=250,this.isListening&&!this.ttsSpeaking&&this.emitStatus("listening")};const s=this.recognition;s.onaudiostart=()=>this.log("onaudiostart"),s.onsoundstart=()=>this.log("onsoundstart"),s.onspeechstart=()=>this.log("onspeechstart"),s.onspeechend=()=>this.log("onspeechend"),s.onsoundend=()=>this.log("onsoundend"),s.onaudioend=()=>this.log("onaudioend"),this.recognition.onerror=n=>this.handleError(n)}else this.recognition=null,this.emitStatus("unsupported");typeof window<"u"?(window.addEventListener("foisit:tts-start",this.onTTSStart),window.addEventListener("foisit:tts-end",this.onTTSEnd),this.visibilityHandler=()=>{var s;if(typeof document<"u"&&document.hidden){try{(s=this.recognition)==null||s.stop()}catch{}this.emitStatus(this.ttsSpeaking?"speaking":"idle")}else this.isListening&&!this.ttsSpeaking&&this.safeRestart()},typeof document<"u"&&document.addEventListener("visibilitychange",this.visibilityHandler)):this.visibilityHandler=void 0}log(t){this.debugEnabled&&t&&console.log("[VoiceProcessor]",t)}warn(t){this.debugEnabled&&t&&console.warn("[VoiceProcessor]",t)}error(t){this.debugEnabled&&t&&console.error("[VoiceProcessor]",t)}isSupported(){return P()!==null}onStatusChange(t){this.statusCallback=t}startListening(t){if(!this.isSupported()||!this.recognition){this.warn("VoiceProcessor: SpeechRecognition is not supported in this browser."),this.emitStatus("unsupported");return}if(this.isListening){this.warn("VoiceProcessor: Already listening."),this.resultCallback=t;return}this.resultCallback=t,this.intentionallyStopped=!1,this.restartAllowed=!0,this.isListening=!0,this.emitStatus("listening"),this.prewarmAudio().finally(()=>{this.safeRestart()})}stopListening(){var t;this.intentionallyStopped=!0,this.restartAllowed=!1,this.isListening=!1,this.emitStatus(this.ttsSpeaking?"speaking":"idle");try{(t=this.recognition)==null||t.stop()}catch{}}destroy(){this.destroyed=!0,this.stopListening(),this.resultCallback=null,window.removeEventListener("foisit:tts-start",this.onTTSStart),window.removeEventListener("foisit:tts-end",this.onTTSEnd),this.visibilityHandler&&(document.removeEventListener("visibilitychange",this.visibilityHandler),this.visibilityHandler=void 0)}handleResult(t,e){var s,n;if(!this.resultCallback)return;const i=e.confidenceThreshold??.6;for(let o=t.resultIndex;o<t.results.length;o++){const r=t.results[o],c=r&&r[0],f=((n=(s=c==null?void 0:c.transcript)==null?void 0:s.trim)==null?void 0:n.call(s))||"",a=(c==null?void 0:c.confidence)??0;if(f&&!(!r.isFinal&&e.interimResults===!1)&&!(r.isFinal&&a<i))try{this.hadResultThisSession=!0,this.resultCallback(f,!!r.isFinal)}catch{this.error("VoiceProcessor: result callback error")}}}handleEnd(){if(this.log("recognition onend"),this.engineActive=!1,this.destroyed||this.intentionallyStopped||!this.restartAllowed||this.ttsSpeaking){this.ttsSpeaking||(this.isListening=!1,this.emitStatus("idle"));return}this.isListening=!0,this.scheduleRestart()}handleError(t){const e=t==null?void 0:t.error;if(this.warn(`Error occurred: ${e??"unknown"}`),e&&["not-allowed","service-not-allowed","bad-grammar","language-not-supported"].includes(e)){this.intentionallyStopped=!0,this.restartAllowed=!1,this.isListening=!1,this.emitStatus("error",{error:e});return}this.scheduleRestart()}safeRestart(){if(!this.recognition)return;if(this.engineActive){this.log("safeRestart: engine already active, skipping start");return}const t=Date.now();if(t-this.lastStart<300){setTimeout(()=>this.safeRestart(),300);return}this.lastStart=t;try{this.log("calling recognition.start()"),this.recognition.start(),this.backoffMs=250,this.isListening&&!this.ttsSpeaking&&this.emitStatus("listening")}catch{this.error("recognition.start() threw; scheduling restart"),this.scheduleRestart()}}scheduleRestart(){if(this.destroyed||this.intentionallyStopped||!this.restartAllowed||this.ttsSpeaking)return;if(this.engineActive){this.log("scheduleRestart: engine active, not scheduling");return}const t=Math.min(this.backoffMs,2e3);if(this.log(`scheduleRestart in ${t}ms`),this.restartTimer){this.log("scheduleRestart: restart already scheduled");return}this.restartTimer=setTimeout(()=>{this.restartTimer=null,!(this.destroyed||this.intentionallyStopped||!this.restartAllowed||this.ttsSpeaking)&&this.safeRestart()},t),this.backoffMs=Math.min(this.backoffMs*2,2e3)}async prewarmAudio(){if(!this.prewarmed)try{if(typeof navigator>"u"||!("mediaDevices"in navigator))return;const t=navigator.mediaDevices;if(!(t!=null&&t.getUserMedia))return;this.log("prewarmAudio: requesting mic");const e=await t.getUserMedia({audio:!0});for(const i of e.getTracks())i.stop();this.prewarmed=!0,this.log("prewarmAudio: mic ready")}catch{this.warn("prewarmAudio: failed to get mic")}}emitStatus(t,e){if(this.statusCallback)try{this.statusCallback(t,e)}catch{this.error("VoiceProcessor: status callback error")}}}class j{constructor(){this.lastTap=0}setupDoubleTapListener(t){this.destroy(),this.dblClickListener=()=>{t()},document.addEventListener("dblclick",this.dblClickListener),this.touchEndListener=()=>{const e=new Date().getTime(),i=e-this.lastTap;i<300&&i>0&&t(),this.lastTap=e},document.addEventListener("touchend",this.touchEndListener)}destroy(){this.dblClickListener&&document.removeEventListener("dblclick",this.dblClickListener),this.touchEndListener&&document.removeEventListener("touchend",this.touchEndListener),this.dblClickListener=void 0,this.touchEndListener=void 0}}function U(){if(document.querySelector("#assistant-styles")){console.log("Styles already injected");return}const t=document.createElement("style");t.id="assistant-styles",t.innerHTML=`
|
|
2
2
|
/* Rounded shape with gradient animation */
|
|
3
3
|
.gradient-indicator {
|
|
4
4
|
position: fixed;
|
|
@@ -31,7 +31,7 @@
|
|
|
31
31
|
border-radius: 50%;
|
|
32
32
|
}
|
|
33
33
|
}
|
|
34
|
-
`,document.head.appendChild(t),console.log("Gradient styles injected")}function D(){if(document.querySelector("#gradient-indicator"))return;const d=document.createElement("div");d.id="gradient-indicator",$(),d.classList.add("gradient-indicator"),document.body.appendChild(d),console.log("Gradient indicator added to the DOM")}function U(){const d=document.querySelector("#gradient-indicator");d&&(d.remove(),console.log("Gradient indicator removed from the DOM"))}class V{constructor(){this.state="idle",this.subscribers=[]}getState(){return this.state}setState(t){this.state=t,this.notifySubscribers(),console.log("State updated:",t),t==="listening"?D():U()}subscribe(t){this.subscribers.push(t)}notifySubscribers(){this.subscribers.forEach(t=>t(this.state))}}class G{constructor(t){this.container=null,this.chatWindow=null,this.messagesContainer=null,this.input=null,this.isOpen=!1,this.loadingEl=null,this.config=t,this.init()}init(){var e,i;if(this.container)return;this.injectOverlayStyles();const t=document.getElementById("foisit-overlay-container");if(t&&t instanceof HTMLElement){this.container=t,this.chatWindow=t.querySelector(".foisit-chat"),this.messagesContainer=t.querySelector(".foisit-messages"),this.input=t.querySelector("input.foisit-input"),((e=this.config.floatingButton)==null?void 0:e.visible)!==!1&&!t.querySelector(".foisit-floating-btn")&&this.renderFloatingButton(),this.chatWindow||this.renderChatWindow();return}this.container=document.createElement("div"),this.container.id="foisit-overlay-container",this.container.className="foisit-overlay-container",document.body.appendChild(this.container),((i=this.config.floatingButton)==null?void 0:i.visible)!==!1&&this.renderFloatingButton(),this.renderChatWindow()}renderFloatingButton(){var s,n,a,r,c,f;const t=document.createElement("button");t.innerHTML=((s=this.config.floatingButton)==null?void 0:s.customHtml)||"🎙️";const e=((a=(n=this.config.floatingButton)==null?void 0:n.position)==null?void 0:a.bottom)||"20px",i=((c=(r=this.config.floatingButton)==null?void 0:r.position)==null?void 0:c.right)||"20px";t.className="foisit-floating-btn",t.style.bottom=e,t.style.right=i,t.onclick=()=>this.toggle(),t.onmouseenter=()=>t.style.transform="scale(1.05)",t.onmouseleave=()=>t.style.transform="scale(1)",(f=this.container)==null||f.appendChild(t)}renderChatWindow(){var n;if(this.chatWindow)return;this.chatWindow=document.createElement("div"),this.chatWindow.className="foisit-chat";const t=document.createElement("div");t.className="foisit-header";const e=document.createElement("span");e.className="foisit-title",e.textContent="Foisit";const i=document.createElement("button");i.type="button",i.className="foisit-close",i.setAttribute("aria-label","Close"),i.innerHTML="×",i.addEventListener("click",()=>this.toggle()),t.appendChild(e),t.appendChild(i),this.messagesContainer=document.createElement("div"),this.messagesContainer.className="foisit-messages";const s=document.createElement("div");s.className="foisit-input-area",this.input=document.createElement("input"),this.input.placeholder=this.config.inputPlaceholder||"Type a command...",this.input.className="foisit-input",this.input.addEventListener("keydown",a=>{var r;if(a.key==="Enter"&&((r=this.input)!=null&&r.value.trim())){const c=this.input.value.trim();this.input.value="",this.onSubmit&&this.onSubmit(c)}}),s.appendChild(this.input),this.chatWindow.appendChild(t),this.chatWindow.appendChild(this.messagesContainer),this.chatWindow.appendChild(s),(n=this.container)==null||n.appendChild(this.chatWindow)}registerCallbacks(t,e){this.onSubmit=t,this.onClose=e}toggle(t,e){t&&(this.onSubmit=t),e&&(this.onClose=e),this.isOpen=!this.isOpen,this.chatWindow&&(this.isOpen?(this.chatWindow.style.display="flex",requestAnimationFrame(()=>{this.chatWindow&&(this.chatWindow.style.opacity="1",this.chatWindow.style.transform="translateY(0) scale(1)")}),setTimeout(()=>{var i;return(i=this.input)==null?void 0:i.focus()},100)):(this.chatWindow.style.opacity="0",this.chatWindow.style.transform="translateY(20px) scale(0.95)",setTimeout(()=>{this.chatWindow&&!this.isOpen&&(this.chatWindow.style.display="none")},200),this.onClose&&this.onClose()))}addMessage(t,e){if(!this.messagesContainer)return;const i=document.createElement("div");i.textContent=t,i.className=e==="user"?"foisit-bubble user":"foisit-bubble system",this.messagesContainer.appendChild(i),this.scrollToBottom()}addOptions(t){if(!this.messagesContainer)return;const e=document.createElement("div");e.className="foisit-options-container",t.forEach(i=>{const s=document.createElement("button");s.textContent=i.label,s.className="foisit-option-chip",s.setAttribute("type","button"),s.setAttribute("aria-label",i.label);const n=()=>{if(i.commandId){this.onSubmit&&this.onSubmit({commandId:i.commandId});return}const a=i&&typeof i.value=="string"&&i.value.trim()?i.value:i.label;this.onSubmit&&this.onSubmit(a)};s.onclick=n,s.onkeydown=a=>{(a.key==="Enter"||a.key===" ")&&(a.preventDefault(),n())},e.appendChild(s)}),this.messagesContainer.appendChild(e),this.scrollToBottom()}addForm(t,e,i){if(!this.messagesContainer)return;this.addMessage(t,"system");const s=document.createElement("form");s.className="foisit-form";const n=[],a=(o,p)=>{const b=document.createElement("div");return b.className="foisit-form-label",b.innerHTML=o+(p?' <span class="foisit-req-star">*</span>':""),b},r=()=>{const o=document.createElement("div");return o.className="foisit-form-error",o.style.display="none",o};(e??[]).forEach(o=>{const p=document.createElement("div");p.className="foisit-form-group";const b=o.description||o.name;p.appendChild(a(b,o.required));let h;if(o.type==="select"){const l=document.createElement("select");l.className="foisit-form-input";const y=document.createElement("option");y.value="",y.textContent="Select...",l.appendChild(y);const x=m=>{(m??[]).forEach(w=>{const g=document.createElement("option");g.value=String(w.value??w.label??""),g.textContent=String(w.label??w.value??""),l.appendChild(g)})};if(Array.isArray(o.options)&&o.options.length)x(o.options);else if(typeof o.getOptions=="function"){const m=o.getOptions,w=document.createElement("option");w.value="",w.textContent="Loading...",l.appendChild(w),Promise.resolve().then(()=>m()).then(g=>{for(;l.options.length>1;)l.remove(1);x(g)}).catch(()=>{for(;l.options.length>1;)l.remove(1);const g=document.createElement("option");g.value="",g.textContent="Error loading options",l.appendChild(g)})}o.defaultValue!=null&&(l.value=String(o.defaultValue)),h=l}else if(o.type==="file"){const l=o,y=document.createElement("input");y.className="foisit-form-input",y.type="file",l.accept&&Array.isArray(l.accept)&&(y.accept=l.accept.join(",")),l.multiple&&(y.multiple=!0),l.capture&&(l.capture===!0?y.setAttribute("capture",""):y.setAttribute("capture",String(l.capture))),y.addEventListener("change",async()=>{const x=Array.from(y.files||[]),m=C;if(m.style.display="none",m.textContent="",x.length===0)return;const w=l.maxFiles??(l.multiple?10:1);if(x.length>w){m.textContent=`Please select at most ${w} file(s).`,m.style.display="block";return}const g=l.maxSizeBytes??1/0,u=x.reduce((v,E)=>v+E.size,0);if(x.some(v=>v.size>g)){m.textContent=`One or more files exceed the maximum size of ${Math.round(g/1024)} KB.`,m.style.display="block";return}const k=l.maxTotalBytes??1/0;if(u>k){m.textContent=`Total selected files exceed the maximum of ${Math.round(k/1024)} KB.`,m.style.display="block";return}if(l.accept&&Array.isArray(l.accept)){const v=l.accept;if(!x.every(L=>L.type?v.some(I=>I.startsWith(".")?L.name.toLowerCase().endsWith(I.toLowerCase()):L.type===I||L.type.startsWith(I.split("/")[0]+"/")):!0)){m.textContent="One or more files have an unsupported type.",m.style.display="block";return}}}),h=y}else{const l=document.createElement("input");l.className="foisit-form-input",o.type==="string"&&(l.placeholder=o.placeholder||"Type here..."),o.type==="number"?(l.type="number",typeof o.min=="number"&&(l.min=String(o.min)),typeof o.max=="number"&&(l.max=String(o.max)),typeof o.step=="number"&&(l.step=String(o.step)),o.defaultValue!=null&&(l.value=String(o.defaultValue))):o.type==="date"?(l.type="date",typeof o.min=="string"&&(l.min=o.min),typeof o.max=="string"&&(l.max=o.max),o.defaultValue!=null&&(l.value=String(o.defaultValue))):(l.type="text",o.defaultValue!=null&&(l.value=String(o.defaultValue))),h=l}const C=r();p.appendChild(h),p.appendChild(C),n.push({name:o.name,type:o.type,el:h,required:o.required}),s.appendChild(p)});const c=document.createElement("div");c.className="foisit-form-actions";const f=document.createElement("button");f.type="submit",f.textContent="Submit",f.className="foisit-option-chip",f.style.fontWeight="600",c.appendChild(f),s.appendChild(c),s.onsubmit=async o=>{o.preventDefault();const p={};let b=!1;s.querySelectorAll(".foisit-form-error").forEach(h=>{h.style.display="none",h.textContent=""}),s.querySelectorAll(".foisit-form-input").forEach(h=>{h.classList.remove("foisit-error-border")});for(const h of n){if(h.type==="file"){const x=h.el.parentElement,m=x==null?void 0:x.querySelector(".foisit-form-error"),w=h.el,g=Array.from(w.files||[]);if(h.required&&g.length===0){b=!0,w.classList.add("foisit-error-border"),m&&(m.textContent="This file is required",m.style.display="block");continue}if(g.length===0)continue;const u=(e??[]).find(v=>v.name===h.name),k=(u==null?void 0:u.delivery)??"file";if(u!=null&&u.maxWidth||u!=null&&u.maxHeight)try{const v=await this.getImageDimensions(g[0]);if(u.maxWidth&&v.width>u.maxWidth){b=!0,m&&(m.textContent=`Image width must be ≤ ${u.maxWidth}px`,m.style.display="block");continue}if(u.maxHeight&&v.height>u.maxHeight){b=!0,m&&(m.textContent=`Image height must be ≤ ${u.maxHeight}px`,m.style.display="block");continue}}catch{}if(u!=null&&u.maxDurationSec)try{const v=await this.getMediaDuration(g[0]);if(v&&v>u.maxDurationSec){b=!0,m&&(m.textContent=`Media duration must be ≤ ${u.maxDurationSec}s`,m.style.display="block");continue}}catch{}if(k==="file")p[h.name]=u!=null&&u.multiple?g:g[0];else if(k==="base64")try{const v=await Promise.all(g.map(E=>this.readFileAsDataURL(E)));p[h.name]=u!=null&&u.multiple?v:v[0]}catch{b=!0,m&&(m.textContent="Failed to encode file(s) to base64.",m.style.display="block");continue}continue}const C=(h.el.value??"").toString().trim(),l=h.el.parentElement,y=l==null?void 0:l.querySelector(".foisit-form-error");if(h.required&&(C==null||C==="")){b=!0,h.el.classList.add("foisit-error-border"),y&&(y.textContent="This field is required",y.style.display="block");continue}if(C!=="")if(h.type==="number"){const x=Number(C);Number.isNaN(x)||(p[h.name]=x)}else p[h.name]=C}if(b){s.classList.add("foisit-shake"),setTimeout(()=>s.classList.remove("foisit-shake"),400);return}f.disabled=!0,f.style.opacity="0.6",n.forEach(h=>{h.el.disabled=!0}),i(p)},this.messagesContainer.appendChild(s),this.scrollToBottom()}showLoading(){if(this.messagesContainer&&!this.loadingEl){this.loadingEl=document.createElement("div"),this.loadingEl.className="foisit-loading-dots foisit-bubble system";for(let t=0;t<3;t++){const e=document.createElement("div");e.className="foisit-dot",e.style.animation=`foisitPulse 1.4s infinite ease-in-out ${t*.2}s`,this.loadingEl.appendChild(e)}this.messagesContainer.appendChild(this.loadingEl),this.scrollToBottom()}}hideLoading(){var t;(t=this.loadingEl)==null||t.remove(),this.loadingEl=null}scrollToBottom(){this.messagesContainer&&(this.messagesContainer.scrollTop=this.messagesContainer.scrollHeight)}destroy(){var t;(t=this.container)==null||t.remove(),this.container=null,this.chatWindow=null,this.messagesContainer=null,this.input=null,this.isOpen=!1}readFileAsDataURL(t){return new Promise((e,i)=>{const s=new FileReader;s.onerror=()=>i(new Error("Failed to read file")),s.onload=()=>e(String(s.result)),s.readAsDataURL(t)})}getImageDimensions(t){return new Promise(e=>{try{const i=URL.createObjectURL(t),s=new Image;s.onload=()=>{const n={width:s.naturalWidth||s.width,height:s.naturalHeight||s.height};URL.revokeObjectURL(i),e(n)},s.onerror=()=>{URL.revokeObjectURL(i),e({width:0,height:0})},s.src=i}catch{e({width:0,height:0})}})}getMediaDuration(t){return new Promise(e=>{try{const i=URL.createObjectURL(t),s=t.type.startsWith("audio")?document.createElement("audio"):document.createElement("video");let n=!1;const a=setTimeout(()=>{n||(n=!0,URL.revokeObjectURL(i),e(0))},5e3);s.preload="metadata",s.onloadedmetadata=()=>{if(n)return;n=!0,clearTimeout(a);const c=s.duration||0;URL.revokeObjectURL(i),e(c)},s.onerror=()=>{n||(n=!0,clearTimeout(a),URL.revokeObjectURL(i),e(0))},s.src=i}catch{e(0)}})}injectOverlayStyles(){if(document.getElementById("foisit-overlay-styles"))return;const t=document.createElement("style");t.id="foisit-overlay-styles",t.textContent=`
|
|
34
|
+
`,document.head.appendChild(t),console.log("Gradient styles injected")}function D(){if(document.querySelector("#gradient-indicator"))return;const d=document.createElement("div");d.id="gradient-indicator",U(),d.classList.add("gradient-indicator"),document.body.appendChild(d),console.log("Gradient indicator added to the DOM")}function $(){const d=document.querySelector("#gradient-indicator");d&&(d.remove(),console.log("Gradient indicator removed from the DOM"))}function V(){return typeof window<"u"&&typeof document<"u"}class G{constructor(){this.state="idle",this.subscribers=[]}getState(){return this.state}setState(t){this.state=t,this.notifySubscribers(),console.log("State updated:",t),t==="listening"?D():$()}subscribe(t){this.subscribers.push(t)}notifySubscribers(){this.subscribers.forEach(t=>t(this.state))}}class Y{constructor(t){this.container=null,this.chatWindow=null,this.messagesContainer=null,this.input=null,this.isOpen=!1,this.loadingEl=null,this.active=V(),this.config=t,this.active&&this.init()}init(){var e,i;if(this.container)return;this.injectOverlayStyles();const t=document.getElementById("foisit-overlay-container");if(t&&t instanceof HTMLElement){this.container=t,this.chatWindow=t.querySelector(".foisit-chat"),this.messagesContainer=t.querySelector(".foisit-messages"),this.input=t.querySelector("input.foisit-input"),((e=this.config.floatingButton)==null?void 0:e.visible)!==!1&&!t.querySelector(".foisit-floating-btn")&&this.renderFloatingButton(),this.chatWindow||this.renderChatWindow();return}this.container=document.createElement("div"),this.container.id="foisit-overlay-container",this.container.className="foisit-overlay-container",document.body.appendChild(this.container),((i=this.config.floatingButton)==null?void 0:i.visible)!==!1&&this.renderFloatingButton(),this.renderChatWindow()}renderFloatingButton(){var s,n,o,r,c,f;const t=document.createElement("button");t.innerHTML=((s=this.config.floatingButton)==null?void 0:s.customHtml)||"🎙️";const e=((o=(n=this.config.floatingButton)==null?void 0:n.position)==null?void 0:o.bottom)||"20px",i=((c=(r=this.config.floatingButton)==null?void 0:r.position)==null?void 0:c.right)||"20px";t.className="foisit-floating-btn",t.style.bottom=e,t.style.right=i,t.onclick=()=>this.toggle(),t.onmouseenter=()=>t.style.transform="scale(1.05)",t.onmouseleave=()=>t.style.transform="scale(1)",(f=this.container)==null||f.appendChild(t)}renderChatWindow(){var n;if(this.chatWindow)return;this.chatWindow=document.createElement("div"),this.chatWindow.className="foisit-chat";const t=document.createElement("div");t.className="foisit-header";const e=document.createElement("span");e.className="foisit-title",e.textContent="Foisit";const i=document.createElement("button");i.type="button",i.className="foisit-close",i.setAttribute("aria-label","Close"),i.innerHTML="×",i.addEventListener("click",()=>this.toggle()),t.appendChild(e),t.appendChild(i),this.messagesContainer=document.createElement("div"),this.messagesContainer.className="foisit-messages";const s=document.createElement("div");s.className="foisit-input-area",this.input=document.createElement("input"),this.input.placeholder=this.config.inputPlaceholder||"Type a command...",this.input.className="foisit-input",this.input.addEventListener("keydown",o=>{var r;if(o.key==="Enter"&&((r=this.input)!=null&&r.value.trim())){const c=this.input.value.trim();this.input.value="",this.onSubmit&&this.onSubmit(c)}}),s.appendChild(this.input),this.chatWindow.appendChild(t),this.chatWindow.appendChild(this.messagesContainer),this.chatWindow.appendChild(s),(n=this.container)==null||n.appendChild(this.chatWindow)}registerCallbacks(t,e){this.active&&(this.onSubmit=t,this.onClose=e)}toggle(t,e){this.active&&(t&&(this.onSubmit=t),e&&(this.onClose=e),this.isOpen=!this.isOpen,this.chatWindow&&(this.isOpen?(this.chatWindow.style.display="flex",requestAnimationFrame(()=>{this.chatWindow&&(this.chatWindow.style.opacity="1",this.chatWindow.style.transform="translateY(0) scale(1)")}),setTimeout(()=>{var i;return(i=this.input)==null?void 0:i.focus()},100)):(this.chatWindow.style.opacity="0",this.chatWindow.style.transform="translateY(20px) scale(0.95)",setTimeout(()=>{this.chatWindow&&!this.isOpen&&(this.chatWindow.style.display="none")},200),this.onClose&&this.onClose())))}addMessage(t,e){if(!this.messagesContainer)return;const i=document.createElement("div");i.textContent=t,i.className=e==="user"?"foisit-bubble user":"foisit-bubble system",this.messagesContainer.appendChild(i),this.scrollToBottom()}addOptions(t){if(!this.messagesContainer)return;const e=document.createElement("div");e.className="foisit-options-container",t.forEach(i=>{const s=document.createElement("button");s.textContent=i.label,s.className="foisit-option-chip",s.setAttribute("type","button"),s.setAttribute("aria-label",i.label);const n=()=>{if(i.commandId){this.onSubmit&&this.onSubmit({commandId:i.commandId});return}const o=i&&typeof i.value=="string"&&i.value.trim()?i.value:i.label;this.onSubmit&&this.onSubmit(o)};s.onclick=n,s.onkeydown=o=>{(o.key==="Enter"||o.key===" ")&&(o.preventDefault(),n())},e.appendChild(s)}),this.messagesContainer.appendChild(e),this.scrollToBottom()}addForm(t,e,i){if(!this.messagesContainer)return;this.addMessage(t,"system");const s=document.createElement("form");s.className="foisit-form";const n=[],o=(a,p)=>{const g=document.createElement("div");return g.className="foisit-form-label",g.innerHTML=a+(p?' <span class="foisit-req-star">*</span>':""),g},r=()=>{const a=document.createElement("div");return a.className="foisit-form-error",a.style.display="none",a};(e??[]).forEach(a=>{const p=document.createElement("div");p.className="foisit-form-group";const g=a.description||a.name;p.appendChild(o(g,a.required));let m;if(a.type==="select"){const l=document.createElement("select");l.className="foisit-form-input";const b=document.createElement("option");b.value="",b.textContent="Select...",l.appendChild(b);const x=h=>{(h??[]).forEach(w=>{const y=document.createElement("option");y.value=String(w.value??w.label??""),y.textContent=String(w.label??w.value??""),l.appendChild(y)})};if(Array.isArray(a.options)&&a.options.length)x(a.options);else if(typeof a.getOptions=="function"){const h=a.getOptions,w=document.createElement("option");w.value="",w.textContent="Loading...",l.appendChild(w),Promise.resolve().then(()=>h()).then(y=>{for(;l.options.length>1;)l.remove(1);x(y)}).catch(()=>{for(;l.options.length>1;)l.remove(1);const y=document.createElement("option");y.value="",y.textContent="Error loading options",l.appendChild(y)})}a.defaultValue!=null&&(l.value=String(a.defaultValue)),m=l}else if(a.type==="file"){const l=a,b=document.createElement("input");b.className="foisit-form-input",b.type="file",l.accept&&Array.isArray(l.accept)&&(b.accept=l.accept.join(",")),l.multiple&&(b.multiple=!0),l.capture&&(l.capture===!0?b.setAttribute("capture",""):b.setAttribute("capture",String(l.capture))),b.addEventListener("change",async()=>{const x=Array.from(b.files||[]),h=S;if(h.style.display="none",h.textContent="",x.length===0)return;const w=l.maxFiles??(l.multiple?10:1);if(x.length>w){h.textContent=`Please select at most ${w} file(s).`,h.style.display="block";return}const y=l.maxSizeBytes??1/0,u=x.reduce((v,E)=>v+E.size,0);if(x.some(v=>v.size>y)){h.textContent=`One or more files exceed the maximum size of ${Math.round(y/1024)} KB.`,h.style.display="block";return}const k=l.maxTotalBytes??1/0;if(u>k){h.textContent=`Total selected files exceed the maximum of ${Math.round(k/1024)} KB.`,h.style.display="block";return}if(l.accept&&Array.isArray(l.accept)){const v=l.accept;if(!x.every(L=>L.type?v.some(I=>I.startsWith(".")?L.name.toLowerCase().endsWith(I.toLowerCase()):L.type===I||L.type.startsWith(I.split("/")[0]+"/")):!0)){h.textContent="One or more files have an unsupported type.",h.style.display="block";return}}}),m=b}else{const l=document.createElement("input");l.className="foisit-form-input",a.type==="string"&&(l.placeholder=a.placeholder||"Type here..."),a.type==="number"?(l.type="number",typeof a.min=="number"&&(l.min=String(a.min)),typeof a.max=="number"&&(l.max=String(a.max)),typeof a.step=="number"&&(l.step=String(a.step)),a.defaultValue!=null&&(l.value=String(a.defaultValue))):a.type==="date"?(l.type="date",typeof a.min=="string"&&(l.min=a.min),typeof a.max=="string"&&(l.max=a.max),a.defaultValue!=null&&(l.value=String(a.defaultValue))):(l.type="text",a.defaultValue!=null&&(l.value=String(a.defaultValue))),m=l}const S=r();p.appendChild(m),p.appendChild(S),n.push({name:a.name,type:a.type,el:m,required:a.required}),s.appendChild(p)});const c=document.createElement("div");c.className="foisit-form-actions";const f=document.createElement("button");f.type="submit",f.textContent="Submit",f.className="foisit-option-chip",f.style.fontWeight="600",c.appendChild(f),s.appendChild(c),s.onsubmit=async a=>{a.preventDefault();const p={};let g=!1;s.querySelectorAll(".foisit-form-error").forEach(m=>{m.style.display="none",m.textContent=""}),s.querySelectorAll(".foisit-form-input").forEach(m=>{m.classList.remove("foisit-error-border")});for(const m of n){if(m.type==="file"){const x=m.el.parentElement,h=x==null?void 0:x.querySelector(".foisit-form-error"),w=m.el,y=Array.from(w.files||[]);if(m.required&&y.length===0){g=!0,w.classList.add("foisit-error-border"),h&&(h.textContent="This file is required",h.style.display="block");continue}if(y.length===0)continue;const u=(e??[]).find(v=>v.name===m.name),k=(u==null?void 0:u.delivery)??"file";if(u!=null&&u.maxWidth||u!=null&&u.maxHeight)try{const v=await this.getImageDimensions(y[0]);if(u.maxWidth&&v.width>u.maxWidth){g=!0,h&&(h.textContent=`Image width must be ≤ ${u.maxWidth}px`,h.style.display="block");continue}if(u.maxHeight&&v.height>u.maxHeight){g=!0,h&&(h.textContent=`Image height must be ≤ ${u.maxHeight}px`,h.style.display="block");continue}}catch{}if(u!=null&&u.maxDurationSec)try{const v=await this.getMediaDuration(y[0]);if(v&&v>u.maxDurationSec){g=!0,h&&(h.textContent=`Media duration must be ≤ ${u.maxDurationSec}s`,h.style.display="block");continue}}catch{}if(k==="file")p[m.name]=u!=null&&u.multiple?y:y[0];else if(k==="base64")try{const v=await Promise.all(y.map(E=>this.readFileAsDataURL(E)));p[m.name]=u!=null&&u.multiple?v:v[0]}catch{g=!0,h&&(h.textContent="Failed to encode file(s) to base64.",h.style.display="block");continue}continue}const S=(m.el.value??"").toString().trim(),l=m.el.parentElement,b=l==null?void 0:l.querySelector(".foisit-form-error");if(m.required&&(S==null||S==="")){g=!0,m.el.classList.add("foisit-error-border"),b&&(b.textContent="This field is required",b.style.display="block");continue}if(S!=="")if(m.type==="number"){const x=Number(S);Number.isNaN(x)||(p[m.name]=x)}else p[m.name]=S}if(g){s.classList.add("foisit-shake"),setTimeout(()=>s.classList.remove("foisit-shake"),400);return}f.disabled=!0,f.style.opacity="0.6",n.forEach(m=>{m.el.disabled=!0}),i(p)},this.messagesContainer.appendChild(s),this.scrollToBottom()}showLoading(){if(this.messagesContainer&&!this.loadingEl){this.loadingEl=document.createElement("div"),this.loadingEl.className="foisit-loading-dots foisit-bubble system";for(let t=0;t<3;t++){const e=document.createElement("div");e.className="foisit-dot",e.style.animation=`foisitPulse 1.4s infinite ease-in-out ${t*.2}s`,this.loadingEl.appendChild(e)}this.messagesContainer.appendChild(this.loadingEl),this.scrollToBottom()}}hideLoading(){var t;(t=this.loadingEl)==null||t.remove(),this.loadingEl=null}scrollToBottom(){this.messagesContainer&&(this.messagesContainer.scrollTop=this.messagesContainer.scrollHeight)}destroy(){var t;(t=this.container)==null||t.remove(),this.container=null,this.chatWindow=null,this.messagesContainer=null,this.input=null,this.isOpen=!1}readFileAsDataURL(t){return new Promise((e,i)=>{const s=new FileReader;s.onerror=()=>i(new Error("Failed to read file")),s.onload=()=>e(String(s.result)),s.readAsDataURL(t)})}getImageDimensions(t){return new Promise(e=>{try{const i=URL.createObjectURL(t),s=new Image;s.onload=()=>{const n={width:s.naturalWidth||s.width,height:s.naturalHeight||s.height};URL.revokeObjectURL(i),e(n)},s.onerror=()=>{URL.revokeObjectURL(i),e({width:0,height:0})},s.src=i}catch{e({width:0,height:0})}})}getMediaDuration(t){return new Promise(e=>{try{const i=URL.createObjectURL(t),s=t.type.startsWith("audio")?document.createElement("audio"):document.createElement("video");let n=!1;const o=setTimeout(()=>{n||(n=!0,URL.revokeObjectURL(i),e(0))},5e3);s.preload="metadata",s.onloadedmetadata=()=>{if(n)return;n=!0,clearTimeout(o);const c=s.duration||0;URL.revokeObjectURL(i),e(c)},s.onerror=()=>{n||(n=!0,clearTimeout(o),URL.revokeObjectURL(i),e(0))},s.src=i}catch{e(0)}})}injectOverlayStyles(){if(document.getElementById("foisit-overlay-styles"))return;const t=document.createElement("style");t.id="foisit-overlay-styles",t.textContent=`
|
|
35
35
|
:root {
|
|
36
36
|
/* LIGHT MODE (Default) - Smoother gradient */
|
|
37
37
|
/* Changed: Softer, right-focused radial highlight to avoid a heavy white bottom */
|
|
@@ -352,4 +352,4 @@
|
|
|
352
352
|
transition: transform 0.2s;
|
|
353
353
|
}
|
|
354
354
|
.foisit-floating-btn:hover { transform: scale(1.05); }
|
|
355
|
-
`,document.head.appendChild(t)}}class
|
|
355
|
+
`,document.head.appendChild(t)}}class q{constructor(t){this.config=t,this.isActivated=!1,this.lastProcessedInput="",this.processingLock=!1,this.defaultIntroMessage="How can I help you?",this.commandHandler=new B({enableSmartIntent:this.config.enableSmartIntent!==!1,intentEndpoint:this.config.intentEndpoint}),this.fallbackHandler=new z,typeof window<"u"&&typeof document<"u"?(this.voiceProcessor=new O,this.textToSpeech=new H,this.stateManager=new G,this.gestureHandler=new j,this.overlayManager=new Y({floatingButton:this.config.floatingButton,inputPlaceholder:this.config.inputPlaceholder}),this.config.commands.forEach(e=>this.commandHandler.addCommand(e)),this.config.fallbackResponse&&this.fallbackHandler.setFallbackMessage(this.config.fallbackResponse),this.gestureHandler.setupDoubleTapListener(()=>this.toggle()),this.overlayManager.registerCallbacks(async e=>{if(typeof e=="string"){this.overlayManager.addMessage(e,"user"),await this.handleCommand(e);return}if(e&&typeof e=="object"){const i=e,s=i.label??i.commandId??"Selection";this.overlayManager.addMessage(String(s),"user"),this.overlayManager.showLoading();const n=await this.commandHandler.executeCommand(i);this.overlayManager.hideLoading(),this.processResponse(n)}},()=>console.log("AssistantService: Overlay closed."))):(this.voiceProcessor=void 0,this.textToSpeech=void 0,this.stateManager=void 0,this.gestureHandler=void 0,this.overlayManager=void 0,this.config.commands.forEach(e=>this.commandHandler.addCommand(e)),this.config.fallbackResponse&&this.fallbackHandler.setFallbackMessage(this.config.fallbackResponse))}startListening(){if(typeof window>"u"||!this.voiceProcessor){console.log("AssistantService: Voice is disabled or unavailable; startListening() is a no-op.");return}}stopListening(){if(typeof window>"u"||!this.voiceProcessor){console.log("AssistantService: Voice unavailable; stopListening() is a no-op."),this.isActivated=!1;return}this.voiceProcessor.stopListening(),this.isActivated=!1}reactivate(){console.log("AssistantService: Reactivating assistant..."),this.isActivated=!1;try{this.startListening()}catch{}}async processActivation(t){var i;const e=(i=this.config.activationCommand)==null?void 0:i.toLowerCase();e&&(t===e?(console.log("AssistantService: Activation matched."),this.isActivated=!0,this.textToSpeech.speak(this.config.introMessage||this.defaultIntroMessage)):console.log("AssistantService: Activation command not recognized."))}async handleCommand(t){this.overlayManager.showLoading();let e;try{e=await this.commandHandler.executeCommand(t)}finally{this.overlayManager.hideLoading()}if(e.type==="form"&&e.fields){this.overlayManager.addForm(e.message,e.fields,async i=>{this.overlayManager.showLoading();let s;try{s=await this.commandHandler.executeCommand(i)}finally{this.overlayManager.hideLoading()}this.processResponse(s)});return}if(e.type==="error"){this.fallbackHandler.handleFallback(t),this.overlayManager.addMessage(this.fallbackHandler.getFallbackMessage(),"system");return}if((e.type==="ambiguous"||e.type==="confirm")&&e.options){e.message&&this.overlayManager.addMessage(e.message,"system"),this.overlayManager.addOptions(e.options);return}e.message&&this.overlayManager.addMessage(e.message,"system")}destroy(){this.voiceProcessor.stopListening(),this.gestureHandler.destroy(),this.overlayManager.destroy()}processResponse(t){if(t){if(t.type==="form"&&t.fields){this.overlayManager.addForm(t.message,t.fields,async e=>{this.overlayManager.showLoading();let i;try{i=await this.commandHandler.executeCommand(e)}finally{this.overlayManager.hideLoading()}this.processResponse(i)});return}if((t.type==="ambiguous"||t.type==="confirm")&&t.options){t.message&&this.overlayManager.addMessage(t.message,"system"),this.overlayManager.addOptions(t.options);return}t.message&&this.overlayManager.addMessage(t.message,"system")}}addCommand(t,e){console.log(typeof t=="string"?`AssistantService: Adding command "${t}".`:`AssistantService: Adding rich command "${t.command}".`),this.commandHandler.addCommand(t,e)}removeCommand(t){console.log(`AssistantService: Removing command "${t}".`),this.commandHandler.removeCommand(t)}getCommands(){return this.commandHandler.getCommands()}toggle(t,e){console.log("AssistantService: Toggling overlay..."),this.overlayManager.toggle(async i=>{if(typeof i=="string"){this.overlayManager.addMessage(i,"user"),t&&t(i),await this.handleCommand(i);return}if(i&&typeof i=="object"){const s=i,n=s.label??s.commandId??"Selection";this.overlayManager.addMessage(String(n),"user"),this.overlayManager.showLoading();let o;try{o=await this.commandHandler.executeCommand(s)}finally{this.overlayManager.hideLoading()}this.processResponse(o)}},()=>{console.log("AssistantService: Overlay closed."),e&&e()})}}const M=C.createContext(null);let R=null;const K=({config:d,children:t})=>{const[e,i]=C.useState(null),[s,n]=C.useState(!1);return C.useEffect(()=>{R?console.warn("Multiple AssistantProvider instances detected. Reusing global AssistantService."):(console.log("Initializing global AssistantService..."),R=new q(d));const o=R;return i(o),n(!0),()=>{var r;console.log("Cleaning up AssistantService..."),(r=o.destroy)==null||r.call(o),R=null}},[d]),!s||!e?A.jsx("div",{children:"Loading Assistant..."}):A.jsx(M.Provider,{value:e,children:t})},F=()=>{const d=C.useContext(M);if(console.log("assistant",d),!d)throw new Error("useAssistant must be used within an AssistantProvider");return d},X=({label:d="Activate Assistant",onActivate:t})=>{const e=F(),i=()=>{t&&t(),e.reactivate()};return A.jsx("button",{onClick:i,className:"assistant-activator",children:d})},_=d=>{const[t,e]=C.useState(d.getState());return C.useEffect(()=>{const i=s=>{e(s)};return d.subscribe(i),()=>{d.subscribe(()=>{})}},[d]),t};exports.AssistantActivator=X;exports.AssistantContext=M;exports.AssistantProvider=K;exports.AssistantService=q;exports.ReactWrapper=W;exports.useAssistant=F;exports.useAssistantState=_;
|
package/index.mjs
CHANGED
|
@@ -66,14 +66,14 @@ class B {
|
|
|
66
66
|
async executeCommand(t) {
|
|
67
67
|
if (typeof t == "object" && t !== null) {
|
|
68
68
|
if (this.isStructured(t)) {
|
|
69
|
-
const c = String(t.commandId), f = t.params ?? {},
|
|
70
|
-
if (!
|
|
71
|
-
const p = this.sanitizeParamsForCommand(
|
|
72
|
-
return
|
|
73
|
-
message: `Please provide the required details for "${
|
|
69
|
+
const c = String(t.commandId), f = t.params ?? {}, a = this.getCommandById(c);
|
|
70
|
+
if (!a) return { message: "That command is not available.", type: "error" };
|
|
71
|
+
const p = this.sanitizeParamsForCommand(a, f), m = (a.parameters ?? []).filter((C) => C.required).filter((C) => p[C.name] == null || p[C.name] === "");
|
|
72
|
+
return m.length > 0 ? (this.context = { commandId: this.getCommandIdentifier(a), params: p }, {
|
|
73
|
+
message: `Please provide the required details for "${a.command}".`,
|
|
74
74
|
type: "form",
|
|
75
|
-
fields:
|
|
76
|
-
}) :
|
|
75
|
+
fields: m
|
|
76
|
+
}) : a.critical ? (this.pendingConfirmation = { commandId: this.getCommandIdentifier(a), params: p }, this.buildConfirmResponse(a)) : this.safeRunAction(a, p);
|
|
77
77
|
}
|
|
78
78
|
if (!this.context)
|
|
79
79
|
return { message: "Session expired or invalid context.", type: "error" };
|
|
@@ -82,28 +82,28 @@ class B {
|
|
|
82
82
|
return this.context = null, { message: "Session expired or invalid context.", type: "error" };
|
|
83
83
|
if (Array.isArray(t))
|
|
84
84
|
return { message: "Invalid form payload.", type: "error" };
|
|
85
|
-
const
|
|
85
|
+
const o = {
|
|
86
86
|
...this.context.params,
|
|
87
87
|
...t
|
|
88
88
|
};
|
|
89
89
|
if (n.critical)
|
|
90
90
|
return this.context = null, this.pendingConfirmation = {
|
|
91
91
|
commandId: this.getCommandIdentifier(n),
|
|
92
|
-
params:
|
|
92
|
+
params: o
|
|
93
93
|
}, this.buildConfirmResponse(n);
|
|
94
|
-
const r = await this.safeRunAction(n,
|
|
94
|
+
const r = await this.safeRunAction(n, o);
|
|
95
95
|
return this.context = null, this.normalizeResponse(r);
|
|
96
96
|
}
|
|
97
97
|
const e = t.trim().toLowerCase();
|
|
98
98
|
if (this.pendingConfirmation) {
|
|
99
99
|
const n = e;
|
|
100
100
|
if (["yes", "y", "confirm", "ok", "okay"].includes(n)) {
|
|
101
|
-
const { commandId:
|
|
101
|
+
const { commandId: o, params: r } = this.pendingConfirmation;
|
|
102
102
|
this.pendingConfirmation = null;
|
|
103
|
-
const c = this.getCommandById(
|
|
103
|
+
const c = this.getCommandById(o);
|
|
104
104
|
return c ? this.safeRunAction(c, r) : { message: "That action is no longer available.", type: "error" };
|
|
105
105
|
}
|
|
106
|
-
return ["no", "n", "cancel", "stop"].includes(n) ? (this.pendingConfirmation = null, { message: "
|
|
106
|
+
return ["no", "n", "cancel", "stop"].includes(n) ? (this.pendingConfirmation = null, { message: "Cancelled.", type: "success" }) : {
|
|
107
107
|
message: "Please confirm: Yes or No.",
|
|
108
108
|
type: "confirm",
|
|
109
109
|
options: [
|
|
@@ -114,22 +114,22 @@ class B {
|
|
|
114
114
|
}
|
|
115
115
|
const i = this.commands.get(e);
|
|
116
116
|
if (i) {
|
|
117
|
-
const n = i,
|
|
118
|
-
return
|
|
117
|
+
const n = i, o = (n.parameters ?? []).filter((r) => r.required);
|
|
118
|
+
return o.length > 0 ? (this.context = { commandId: this.getCommandIdentifier(n), params: {} }, {
|
|
119
119
|
message: `Please provide the required details for "${n.command}".`,
|
|
120
120
|
type: "form",
|
|
121
|
-
fields:
|
|
121
|
+
fields: o
|
|
122
122
|
}) : n.critical ? (this.pendingConfirmation = { commandId: this.getCommandIdentifier(n), params: {} }, this.buildConfirmResponse(n)) : this.safeRunAction(n, {});
|
|
123
123
|
}
|
|
124
124
|
const s = await this.tryDeterministicMatch(e);
|
|
125
125
|
if (s) return s;
|
|
126
126
|
if (this.enableSmartIntent && this.openAIService) {
|
|
127
|
-
const n = await this.getCommandsForAI(),
|
|
127
|
+
const n = await this.getCommandsForAI(), o = await this.openAIService.determineIntent(
|
|
128
128
|
e,
|
|
129
129
|
n,
|
|
130
130
|
this.context
|
|
131
131
|
);
|
|
132
|
-
return this.handleAIResult(
|
|
132
|
+
return this.handleAIResult(o);
|
|
133
133
|
}
|
|
134
134
|
return this.enableSmartIntent ? this.listAllCommands() : { message: "I'm not sure what you mean.", type: "error" };
|
|
135
135
|
}
|
|
@@ -138,30 +138,28 @@ class B {
|
|
|
138
138
|
const e = this.getCommandById(t.match);
|
|
139
139
|
if (!e)
|
|
140
140
|
return { message: "I'm not sure what you mean.", type: "error" };
|
|
141
|
-
const i = t.params ?? {}, s = this.sanitizeParamsForCommand(e, i),
|
|
142
|
-
if (t.incomplete ||
|
|
143
|
-
this.context = { commandId: this.getCommandIdentifier(e), params:
|
|
144
|
-
|
|
145
|
-
if (a.length <= 2 && !c) {
|
|
146
|
-
const f = a.map((o) => o.name).join(" and ");
|
|
141
|
+
const i = t.params ?? {}, s = this.sanitizeParamsForCommand(e, i), n = e.allowAiParamExtraction === !1 ? {} : s, r = (e.parameters ?? []).filter((f) => f.required).filter((f) => n[f.name] == null || n[f.name] === "");
|
|
142
|
+
if (t.incomplete || r.length > 0) {
|
|
143
|
+
if (this.context = { commandId: this.getCommandIdentifier(e), params: n }, !(e.collectRequiredViaForm !== !1) && this.shouldAskSingleQuestion(r)) {
|
|
144
|
+
const p = r.map((g) => g.name).join(" and ");
|
|
147
145
|
return {
|
|
148
|
-
message: t.message || `Please provide ${
|
|
146
|
+
message: t.message || `Please provide ${p}.`,
|
|
149
147
|
type: "question"
|
|
150
148
|
};
|
|
151
149
|
}
|
|
152
150
|
return {
|
|
153
151
|
message: t.message || `Please fill in the missing details for "${e.command}".`,
|
|
154
152
|
type: "form",
|
|
155
|
-
fields:
|
|
153
|
+
fields: r
|
|
156
154
|
};
|
|
157
155
|
}
|
|
158
156
|
if (e.critical)
|
|
159
157
|
return this.pendingConfirmation = {
|
|
160
158
|
commandId: this.getCommandIdentifier(e),
|
|
161
|
-
params:
|
|
159
|
+
params: n
|
|
162
160
|
}, this.buildConfirmResponse(e);
|
|
163
|
-
const
|
|
164
|
-
return this.normalizeResponse(
|
|
161
|
+
const c = await e.action(n);
|
|
162
|
+
return this.normalizeResponse(c);
|
|
165
163
|
}
|
|
166
164
|
return t.type === "ambiguous" && t.options && t.options.length ? {
|
|
167
165
|
message: t.message || "Did you mean one of these?",
|
|
@@ -175,14 +173,61 @@ class B {
|
|
|
175
173
|
}
|
|
176
174
|
sanitizeParamsForCommand(t, e) {
|
|
177
175
|
const i = { ...e ?? {} };
|
|
178
|
-
for (const s of t.parameters ?? [])
|
|
176
|
+
for (const s of t.parameters ?? []) {
|
|
177
|
+
const n = i[s.name];
|
|
178
|
+
if (s.type === "string") {
|
|
179
|
+
if (typeof n != "string") {
|
|
180
|
+
delete i[s.name];
|
|
181
|
+
continue;
|
|
182
|
+
}
|
|
183
|
+
const o = n.trim();
|
|
184
|
+
if (!o) {
|
|
185
|
+
delete i[s.name];
|
|
186
|
+
continue;
|
|
187
|
+
}
|
|
188
|
+
i[s.name] = o;
|
|
189
|
+
}
|
|
190
|
+
if (s.type === "number") {
|
|
191
|
+
const o = typeof n == "number" ? n : Number(n == null ? void 0 : n.toString().trim());
|
|
192
|
+
if (Number.isNaN(o)) {
|
|
193
|
+
delete i[s.name];
|
|
194
|
+
continue;
|
|
195
|
+
}
|
|
196
|
+
if (typeof s.min == "number" && o < s.min) {
|
|
197
|
+
delete i[s.name];
|
|
198
|
+
continue;
|
|
199
|
+
}
|
|
200
|
+
if (typeof s.max == "number" && o > s.max) {
|
|
201
|
+
delete i[s.name];
|
|
202
|
+
continue;
|
|
203
|
+
}
|
|
204
|
+
i[s.name] = o;
|
|
205
|
+
}
|
|
179
206
|
if (s.type === "date") {
|
|
180
|
-
const
|
|
181
|
-
if (typeof
|
|
182
|
-
const
|
|
183
|
-
this.isIsoDateString(
|
|
207
|
+
const o = i[s.name];
|
|
208
|
+
if (typeof o == "string") {
|
|
209
|
+
const r = o.trim();
|
|
210
|
+
this.isIsoDateString(r) ? i[s.name] = r : delete i[s.name];
|
|
211
|
+
} else
|
|
212
|
+
delete i[s.name];
|
|
213
|
+
}
|
|
214
|
+
if (s.type === "select") {
|
|
215
|
+
const o = typeof n == "string" ? n : n == null ? void 0 : n.toString();
|
|
216
|
+
if (!o) {
|
|
217
|
+
delete i[s.name];
|
|
218
|
+
continue;
|
|
184
219
|
}
|
|
220
|
+
if (Array.isArray(s.options) && s.options.length > 0 && !s.options.some((c) => String(c.value) === String(o))) {
|
|
221
|
+
delete i[s.name];
|
|
222
|
+
continue;
|
|
223
|
+
}
|
|
224
|
+
i[s.name] = o;
|
|
225
|
+
}
|
|
226
|
+
if (s.type === "file") {
|
|
227
|
+
const o = i[s.name], r = o && typeof o == "object" && typeof o.name == "string" && typeof o.size == "number", c = typeof o == "string" && /^data:[^;]+;base64,/.test(o);
|
|
228
|
+
(s.delivery ?? "file") === "base64" ? !c && !r && delete i[s.name] : r || delete i[s.name];
|
|
185
229
|
}
|
|
230
|
+
}
|
|
186
231
|
return i;
|
|
187
232
|
}
|
|
188
233
|
isIsoDateString(t) {
|
|
@@ -190,9 +235,14 @@ class B {
|
|
|
190
235
|
const e = /* @__PURE__ */ new Date(`${t}T00:00:00Z`);
|
|
191
236
|
return !Number.isNaN(e.getTime());
|
|
192
237
|
}
|
|
238
|
+
shouldAskSingleQuestion(t) {
|
|
239
|
+
if (t.length !== 1) return !1;
|
|
240
|
+
const e = t[0].type;
|
|
241
|
+
return e === "string" || e === "number" || e === "date";
|
|
242
|
+
}
|
|
193
243
|
buildConfirmResponse(t) {
|
|
194
244
|
return {
|
|
195
|
-
message:
|
|
245
|
+
message: `Are you sure you want to run "${t.command}"?`,
|
|
196
246
|
type: "confirm",
|
|
197
247
|
options: [
|
|
198
248
|
{ label: "Yes", value: "yes" },
|
|
@@ -206,10 +256,10 @@ class B {
|
|
|
206
256
|
let c = 0;
|
|
207
257
|
const f = r.command.toLowerCase();
|
|
208
258
|
t.includes(f) && (c += 5);
|
|
209
|
-
const
|
|
210
|
-
for (const p of
|
|
211
|
-
const
|
|
212
|
-
|
|
259
|
+
const a = r.keywords ?? [];
|
|
260
|
+
for (const p of a) {
|
|
261
|
+
const g = p.toLowerCase().trim();
|
|
262
|
+
g && (t === g ? c += 4 : t.includes(g) && (c += 3));
|
|
213
263
|
}
|
|
214
264
|
c > 0 && e.push({ cmd: r, score: c });
|
|
215
265
|
}
|
|
@@ -226,11 +276,11 @@ class B {
|
|
|
226
276
|
commandId: r.cmd.id
|
|
227
277
|
}))
|
|
228
278
|
};
|
|
229
|
-
const n = s[0].cmd,
|
|
230
|
-
return
|
|
279
|
+
const n = s[0].cmd, o = (n.parameters ?? []).filter((r) => r.required);
|
|
280
|
+
return o.length > 0 ? (this.context = { commandId: this.getCommandIdentifier(n), params: {} }, {
|
|
231
281
|
message: `Please provide the required details for "${n.command}".`,
|
|
232
282
|
type: "form",
|
|
233
|
-
fields:
|
|
283
|
+
fields: o
|
|
234
284
|
}) : n.critical ? (this.pendingConfirmation = { commandId: this.getCommandIdentifier(n), params: {} }, this.buildConfirmResponse(n)) : this.safeRunAction(n, {});
|
|
235
285
|
}
|
|
236
286
|
async safeRunAction(t, e) {
|
|
@@ -251,14 +301,14 @@ class B {
|
|
|
251
301
|
e.parameters && await Promise.all(
|
|
252
302
|
e.parameters.map(async (i) => {
|
|
253
303
|
if (i.type !== "select" || !i.getOptions || i.options && i.options.length) return;
|
|
254
|
-
const s = `${e.id ?? e.command}:${i.name}`, n = this.selectOptionsCache.get(s),
|
|
255
|
-
if (n &&
|
|
304
|
+
const s = `${e.id ?? e.command}:${i.name}`, n = this.selectOptionsCache.get(s), o = Date.now();
|
|
305
|
+
if (n && o - n.ts < 6e4) {
|
|
256
306
|
i.options = n.options;
|
|
257
307
|
return;
|
|
258
308
|
}
|
|
259
309
|
try {
|
|
260
310
|
const r = await i.getOptions();
|
|
261
|
-
this.selectOptionsCache.set(s, { options: r, ts:
|
|
311
|
+
this.selectOptionsCache.set(s, { options: r, ts: o }), i.options = r;
|
|
262
312
|
} catch {
|
|
263
313
|
}
|
|
264
314
|
})
|
|
@@ -297,19 +347,19 @@ class B {
|
|
|
297
347
|
}
|
|
298
348
|
class H {
|
|
299
349
|
constructor() {
|
|
300
|
-
this.synth = window.speechSynthesis;
|
|
350
|
+
this.synth = typeof window < "u" ? window.speechSynthesis : null;
|
|
301
351
|
}
|
|
302
352
|
speak(t, e) {
|
|
303
353
|
if (!this.synth) {
|
|
304
|
-
console.error("SpeechSynthesis API is not supported in this
|
|
354
|
+
console.error("SpeechSynthesis API is not supported in this environment.");
|
|
305
355
|
return;
|
|
306
356
|
}
|
|
307
357
|
const i = new SpeechSynthesisUtterance(t);
|
|
308
|
-
e && (i.pitch = e.pitch || 1, i.rate = e.rate || 1, i.volume = e.volume || 1), i.onstart = () => {
|
|
358
|
+
e && (i.pitch = e.pitch || 1, i.rate = e.rate || 1, i.volume = e.volume || 1), typeof window < "u" && (i.onstart = () => {
|
|
309
359
|
window.dispatchEvent(new CustomEvent("foisit:tts-start"));
|
|
310
360
|
}, i.onend = () => {
|
|
311
361
|
console.log("Speech finished."), window.dispatchEvent(new CustomEvent("foisit:tts-end"));
|
|
312
|
-
}, i.onerror = (s) => {
|
|
362
|
+
}), i.onerror = (s) => {
|
|
313
363
|
console.error("Error during speech synthesis:", s.error);
|
|
314
364
|
}, this.synth.speak(i);
|
|
315
365
|
}
|
|
@@ -317,7 +367,7 @@ class H {
|
|
|
317
367
|
this.synth && this.synth.cancel();
|
|
318
368
|
}
|
|
319
369
|
}
|
|
320
|
-
class
|
|
370
|
+
class z {
|
|
321
371
|
constructor() {
|
|
322
372
|
this.fallbackMessage = "Sorry, I didn’t understand that.";
|
|
323
373
|
}
|
|
@@ -332,10 +382,11 @@ class O {
|
|
|
332
382
|
}
|
|
333
383
|
}
|
|
334
384
|
const T = () => {
|
|
385
|
+
if (typeof window > "u") return null;
|
|
335
386
|
const d = window;
|
|
336
387
|
return d.SpeechRecognition ?? d.webkitSpeechRecognition ?? null;
|
|
337
388
|
};
|
|
338
|
-
class
|
|
389
|
+
class O {
|
|
339
390
|
constructor(t = "en-US", e = {}) {
|
|
340
391
|
this.recognition = null, this.isListening = !1, this.engineActive = !1, this.intentionallyStopped = !1, this.restartAllowed = !0, this.lastStart = 0, this.backoffMs = 250, this.destroyed = !1, this.resultCallback = null, this.ttsSpeaking = !1, this.debugEnabled = !0, this.restartTimer = null, this.prewarmed = !1, this.hadResultThisSession = !1, this.onTTSStart = () => {
|
|
341
392
|
var s;
|
|
@@ -357,16 +408,16 @@ class z {
|
|
|
357
408
|
s.onaudiostart = () => this.log("onaudiostart"), s.onsoundstart = () => this.log("onsoundstart"), s.onspeechstart = () => this.log("onspeechstart"), s.onspeechend = () => this.log("onspeechend"), s.onsoundend = () => this.log("onsoundend"), s.onaudioend = () => this.log("onaudioend"), this.recognition.onerror = (n) => this.handleError(n);
|
|
358
409
|
} else
|
|
359
410
|
this.recognition = null, this.emitStatus("unsupported");
|
|
360
|
-
window.addEventListener("foisit:tts-start", this.onTTSStart), window.addEventListener("foisit:tts-end", this.onTTSEnd), this.visibilityHandler = () => {
|
|
411
|
+
typeof window < "u" ? (window.addEventListener("foisit:tts-start", this.onTTSStart), window.addEventListener("foisit:tts-end", this.onTTSEnd), this.visibilityHandler = () => {
|
|
361
412
|
var s;
|
|
362
|
-
if (document.hidden) {
|
|
413
|
+
if (typeof document < "u" && document.hidden) {
|
|
363
414
|
try {
|
|
364
415
|
(s = this.recognition) == null || s.stop();
|
|
365
416
|
} catch {
|
|
366
417
|
}
|
|
367
418
|
this.emitStatus(this.ttsSpeaking ? "speaking" : "idle");
|
|
368
419
|
} else this.isListening && !this.ttsSpeaking && this.safeRestart();
|
|
369
|
-
}, document.addEventListener("visibilitychange", this.visibilityHandler);
|
|
420
|
+
}, typeof document < "u" && document.addEventListener("visibilitychange", this.visibilityHandler)) : this.visibilityHandler = void 0;
|
|
370
421
|
}
|
|
371
422
|
// Debug logger helpers
|
|
372
423
|
log(t) {
|
|
@@ -418,9 +469,9 @@ class z {
|
|
|
418
469
|
var s, n;
|
|
419
470
|
if (!this.resultCallback) return;
|
|
420
471
|
const i = e.confidenceThreshold ?? 0.6;
|
|
421
|
-
for (let
|
|
422
|
-
const r = t.results[
|
|
423
|
-
if (f && !(!r.isFinal && e.interimResults === !1) && !(r.isFinal &&
|
|
472
|
+
for (let o = t.resultIndex; o < t.results.length; o++) {
|
|
473
|
+
const r = t.results[o], c = r && r[0], f = ((n = (s = c == null ? void 0 : c.transcript) == null ? void 0 : s.trim) == null ? void 0 : n.call(s)) || "", a = (c == null ? void 0 : c.confidence) ?? 0;
|
|
474
|
+
if (f && !(!r.isFinal && e.interimResults === !1) && !(r.isFinal && a < i))
|
|
424
475
|
try {
|
|
425
476
|
this.hadResultThisSession = !0, this.resultCallback(f, !!r.isFinal);
|
|
426
477
|
} catch {
|
|
@@ -501,7 +552,7 @@ class z {
|
|
|
501
552
|
}
|
|
502
553
|
}
|
|
503
554
|
}
|
|
504
|
-
class
|
|
555
|
+
class U {
|
|
505
556
|
constructor() {
|
|
506
557
|
this.lastTap = 0;
|
|
507
558
|
}
|
|
@@ -562,17 +613,20 @@ function D() {
|
|
|
562
613
|
}
|
|
563
614
|
`, document.head.appendChild(t), console.log("Gradient styles injected");
|
|
564
615
|
}
|
|
565
|
-
function
|
|
616
|
+
function $() {
|
|
566
617
|
if (document.querySelector("#gradient-indicator"))
|
|
567
618
|
return;
|
|
568
619
|
const d = document.createElement("div");
|
|
569
620
|
d.id = "gradient-indicator", D(), d.classList.add("gradient-indicator"), document.body.appendChild(d), console.log("Gradient indicator added to the DOM");
|
|
570
621
|
}
|
|
571
|
-
function
|
|
622
|
+
function j() {
|
|
572
623
|
const d = document.querySelector("#gradient-indicator");
|
|
573
624
|
d && (d.remove(), console.log("Gradient indicator removed from the DOM"));
|
|
574
625
|
}
|
|
575
|
-
|
|
626
|
+
function V() {
|
|
627
|
+
return typeof window < "u" && typeof document < "u";
|
|
628
|
+
}
|
|
629
|
+
class G {
|
|
576
630
|
constructor() {
|
|
577
631
|
this.state = "idle", this.subscribers = [];
|
|
578
632
|
}
|
|
@@ -580,7 +634,7 @@ class V {
|
|
|
580
634
|
return this.state;
|
|
581
635
|
}
|
|
582
636
|
setState(t) {
|
|
583
|
-
this.state = t, this.notifySubscribers(), console.log("State updated:", t), t === "listening" ?
|
|
637
|
+
this.state = t, this.notifySubscribers(), console.log("State updated:", t), t === "listening" ? $() : j();
|
|
584
638
|
}
|
|
585
639
|
// eslint-disable-next-line no-unused-vars
|
|
586
640
|
subscribe(t) {
|
|
@@ -590,9 +644,9 @@ class V {
|
|
|
590
644
|
this.subscribers.forEach((t) => t(this.state));
|
|
591
645
|
}
|
|
592
646
|
}
|
|
593
|
-
class
|
|
647
|
+
class Y {
|
|
594
648
|
constructor(t) {
|
|
595
|
-
this.container = null, this.chatWindow = null, this.messagesContainer = null, this.input = null, this.isOpen = !1, this.loadingEl = null, this.config = t, this.init();
|
|
649
|
+
this.container = null, this.chatWindow = null, this.messagesContainer = null, this.input = null, this.isOpen = !1, this.loadingEl = null, this.active = V(), this.config = t, this.active && this.init();
|
|
596
650
|
}
|
|
597
651
|
init() {
|
|
598
652
|
var e, i;
|
|
@@ -606,10 +660,10 @@ class G {
|
|
|
606
660
|
this.container = document.createElement("div"), this.container.id = "foisit-overlay-container", this.container.className = "foisit-overlay-container", document.body.appendChild(this.container), ((i = this.config.floatingButton) == null ? void 0 : i.visible) !== !1 && this.renderFloatingButton(), this.renderChatWindow();
|
|
607
661
|
}
|
|
608
662
|
renderFloatingButton() {
|
|
609
|
-
var s, n,
|
|
663
|
+
var s, n, o, r, c, f;
|
|
610
664
|
const t = document.createElement("button");
|
|
611
665
|
t.innerHTML = ((s = this.config.floatingButton) == null ? void 0 : s.customHtml) || "🎙️";
|
|
612
|
-
const e = ((
|
|
666
|
+
const e = ((o = (n = this.config.floatingButton) == null ? void 0 : n.position) == null ? void 0 : o.bottom) || "20px", i = ((c = (r = this.config.floatingButton) == null ? void 0 : r.position) == null ? void 0 : c.right) || "20px";
|
|
613
667
|
t.className = "foisit-floating-btn", t.style.bottom = e, t.style.right = i, t.onclick = () => this.toggle(), t.onmouseenter = () => t.style.transform = "scale(1.05)", t.onmouseleave = () => t.style.transform = "scale(1)", (f = this.container) == null || f.appendChild(t);
|
|
614
668
|
}
|
|
615
669
|
renderChatWindow() {
|
|
@@ -623,26 +677,26 @@ class G {
|
|
|
623
677
|
const i = document.createElement("button");
|
|
624
678
|
i.type = "button", i.className = "foisit-close", i.setAttribute("aria-label", "Close"), i.innerHTML = "×", i.addEventListener("click", () => this.toggle()), t.appendChild(e), t.appendChild(i), this.messagesContainer = document.createElement("div"), this.messagesContainer.className = "foisit-messages";
|
|
625
679
|
const s = document.createElement("div");
|
|
626
|
-
s.className = "foisit-input-area", this.input = document.createElement("input"), this.input.placeholder = this.config.inputPlaceholder || "Type a command...", this.input.className = "foisit-input", this.input.addEventListener("keydown", (
|
|
680
|
+
s.className = "foisit-input-area", this.input = document.createElement("input"), this.input.placeholder = this.config.inputPlaceholder || "Type a command...", this.input.className = "foisit-input", this.input.addEventListener("keydown", (o) => {
|
|
627
681
|
var r;
|
|
628
|
-
if (
|
|
682
|
+
if (o.key === "Enter" && ((r = this.input) != null && r.value.trim())) {
|
|
629
683
|
const c = this.input.value.trim();
|
|
630
684
|
this.input.value = "", this.onSubmit && this.onSubmit(c);
|
|
631
685
|
}
|
|
632
686
|
}), s.appendChild(this.input), this.chatWindow.appendChild(t), this.chatWindow.appendChild(this.messagesContainer), this.chatWindow.appendChild(s), (n = this.container) == null || n.appendChild(this.chatWindow);
|
|
633
687
|
}
|
|
634
688
|
registerCallbacks(t, e) {
|
|
635
|
-
this.onSubmit = t, this.onClose = e;
|
|
689
|
+
this.active && (this.onSubmit = t, this.onClose = e);
|
|
636
690
|
}
|
|
637
691
|
toggle(t, e) {
|
|
638
|
-
t && (this.onSubmit = t), e && (this.onClose = e), this.isOpen = !this.isOpen, this.chatWindow && (this.isOpen ? (this.chatWindow.style.display = "flex", requestAnimationFrame(() => {
|
|
692
|
+
this.active && (t && (this.onSubmit = t), e && (this.onClose = e), this.isOpen = !this.isOpen, this.chatWindow && (this.isOpen ? (this.chatWindow.style.display = "flex", requestAnimationFrame(() => {
|
|
639
693
|
this.chatWindow && (this.chatWindow.style.opacity = "1", this.chatWindow.style.transform = "translateY(0) scale(1)");
|
|
640
694
|
}), setTimeout(() => {
|
|
641
695
|
var i;
|
|
642
696
|
return (i = this.input) == null ? void 0 : i.focus();
|
|
643
697
|
}, 100)) : (this.chatWindow.style.opacity = "0", this.chatWindow.style.transform = "translateY(20px) scale(0.95)", setTimeout(() => {
|
|
644
698
|
this.chatWindow && !this.isOpen && (this.chatWindow.style.display = "none");
|
|
645
|
-
}, 200), this.onClose && this.onClose()));
|
|
699
|
+
}, 200), this.onClose && this.onClose())));
|
|
646
700
|
}
|
|
647
701
|
addMessage(t, e) {
|
|
648
702
|
if (!this.messagesContainer) return;
|
|
@@ -660,11 +714,11 @@ class G {
|
|
|
660
714
|
this.onSubmit && this.onSubmit({ commandId: i.commandId });
|
|
661
715
|
return;
|
|
662
716
|
}
|
|
663
|
-
const
|
|
664
|
-
this.onSubmit && this.onSubmit(
|
|
717
|
+
const o = i && typeof i.value == "string" && i.value.trim() ? i.value : i.label;
|
|
718
|
+
this.onSubmit && this.onSubmit(o);
|
|
665
719
|
};
|
|
666
|
-
s.onclick = n, s.onkeydown = (
|
|
667
|
-
(
|
|
720
|
+
s.onclick = n, s.onkeydown = (o) => {
|
|
721
|
+
(o.key === "Enter" || o.key === " ") && (o.preventDefault(), n());
|
|
668
722
|
}, e.appendChild(s);
|
|
669
723
|
}), this.messagesContainer.appendChild(e), this.scrollToBottom();
|
|
670
724
|
}
|
|
@@ -673,157 +727,157 @@ class G {
|
|
|
673
727
|
this.addMessage(t, "system");
|
|
674
728
|
const s = document.createElement("form");
|
|
675
729
|
s.className = "foisit-form";
|
|
676
|
-
const n = [],
|
|
677
|
-
const
|
|
678
|
-
return
|
|
730
|
+
const n = [], o = (a, p) => {
|
|
731
|
+
const g = document.createElement("div");
|
|
732
|
+
return g.className = "foisit-form-label", g.innerHTML = a + (p ? ' <span class="foisit-req-star">*</span>' : ""), g;
|
|
679
733
|
}, r = () => {
|
|
680
|
-
const
|
|
681
|
-
return
|
|
734
|
+
const a = document.createElement("div");
|
|
735
|
+
return a.className = "foisit-form-error", a.style.display = "none", a;
|
|
682
736
|
};
|
|
683
|
-
(e ?? []).forEach((
|
|
737
|
+
(e ?? []).forEach((a) => {
|
|
684
738
|
const p = document.createElement("div");
|
|
685
739
|
p.className = "foisit-form-group";
|
|
686
|
-
const
|
|
687
|
-
p.appendChild(
|
|
688
|
-
let
|
|
689
|
-
if (
|
|
740
|
+
const g = a.description || a.name;
|
|
741
|
+
p.appendChild(o(g, a.required));
|
|
742
|
+
let m;
|
|
743
|
+
if (a.type === "select") {
|
|
690
744
|
const l = document.createElement("select");
|
|
691
745
|
l.className = "foisit-form-input";
|
|
692
|
-
const
|
|
693
|
-
|
|
694
|
-
const
|
|
695
|
-
(
|
|
696
|
-
const
|
|
697
|
-
|
|
746
|
+
const b = document.createElement("option");
|
|
747
|
+
b.value = "", b.textContent = "Select...", l.appendChild(b);
|
|
748
|
+
const w = (h) => {
|
|
749
|
+
(h ?? []).forEach((x) => {
|
|
750
|
+
const y = document.createElement("option");
|
|
751
|
+
y.value = String(x.value ?? x.label ?? ""), y.textContent = String(x.label ?? x.value ?? ""), l.appendChild(y);
|
|
698
752
|
});
|
|
699
753
|
};
|
|
700
|
-
if (Array.isArray(
|
|
701
|
-
|
|
702
|
-
else if (typeof
|
|
703
|
-
const
|
|
704
|
-
|
|
754
|
+
if (Array.isArray(a.options) && a.options.length)
|
|
755
|
+
w(a.options);
|
|
756
|
+
else if (typeof a.getOptions == "function") {
|
|
757
|
+
const h = a.getOptions, x = document.createElement("option");
|
|
758
|
+
x.value = "", x.textContent = "Loading...", l.appendChild(x), Promise.resolve().then(() => h()).then((y) => {
|
|
705
759
|
for (; l.options.length > 1; ) l.remove(1);
|
|
706
|
-
|
|
760
|
+
w(y);
|
|
707
761
|
}).catch(() => {
|
|
708
762
|
for (; l.options.length > 1; ) l.remove(1);
|
|
709
|
-
const
|
|
710
|
-
|
|
763
|
+
const y = document.createElement("option");
|
|
764
|
+
y.value = "", y.textContent = "Error loading options", l.appendChild(y);
|
|
711
765
|
});
|
|
712
766
|
}
|
|
713
|
-
|
|
714
|
-
} else if (
|
|
715
|
-
const l =
|
|
716
|
-
|
|
717
|
-
const
|
|
718
|
-
if (
|
|
719
|
-
const
|
|
720
|
-
if (
|
|
721
|
-
|
|
767
|
+
a.defaultValue != null && (l.value = String(a.defaultValue)), m = l;
|
|
768
|
+
} else if (a.type === "file") {
|
|
769
|
+
const l = a, b = document.createElement("input");
|
|
770
|
+
b.className = "foisit-form-input", b.type = "file", l.accept && Array.isArray(l.accept) && (b.accept = l.accept.join(",")), l.multiple && (b.multiple = !0), l.capture && (l.capture === !0 ? b.setAttribute("capture", "") : b.setAttribute("capture", String(l.capture))), b.addEventListener("change", async () => {
|
|
771
|
+
const w = Array.from(b.files || []), h = C;
|
|
772
|
+
if (h.style.display = "none", h.textContent = "", w.length === 0) return;
|
|
773
|
+
const x = l.maxFiles ?? (l.multiple ? 10 : 1);
|
|
774
|
+
if (w.length > x) {
|
|
775
|
+
h.textContent = `Please select at most ${x} file(s).`, h.style.display = "block";
|
|
722
776
|
return;
|
|
723
777
|
}
|
|
724
|
-
const
|
|
725
|
-
if (
|
|
726
|
-
|
|
778
|
+
const y = l.maxSizeBytes ?? 1 / 0, u = w.reduce((v, A) => v + A.size, 0);
|
|
779
|
+
if (w.some((v) => v.size > y)) {
|
|
780
|
+
h.textContent = `One or more files exceed the maximum size of ${Math.round(y / 1024)} KB.`, h.style.display = "block";
|
|
727
781
|
return;
|
|
728
782
|
}
|
|
729
783
|
const S = l.maxTotalBytes ?? 1 / 0;
|
|
730
784
|
if (u > S) {
|
|
731
|
-
|
|
785
|
+
h.textContent = `Total selected files exceed the maximum of ${Math.round(S / 1024)} KB.`, h.style.display = "block";
|
|
732
786
|
return;
|
|
733
787
|
}
|
|
734
788
|
if (l.accept && Array.isArray(l.accept)) {
|
|
735
789
|
const v = l.accept;
|
|
736
|
-
if (!
|
|
737
|
-
|
|
790
|
+
if (!w.every((E) => E.type ? v.some((L) => L.startsWith(".") ? E.name.toLowerCase().endsWith(L.toLowerCase()) : E.type === L || E.type.startsWith(L.split("/")[0] + "/")) : !0)) {
|
|
791
|
+
h.textContent = "One or more files have an unsupported type.", h.style.display = "block";
|
|
738
792
|
return;
|
|
739
793
|
}
|
|
740
794
|
}
|
|
741
|
-
}),
|
|
795
|
+
}), m = b;
|
|
742
796
|
} else {
|
|
743
797
|
const l = document.createElement("input");
|
|
744
|
-
l.className = "foisit-form-input",
|
|
798
|
+
l.className = "foisit-form-input", a.type === "string" && (l.placeholder = a.placeholder || "Type here..."), a.type === "number" ? (l.type = "number", typeof a.min == "number" && (l.min = String(a.min)), typeof a.max == "number" && (l.max = String(a.max)), typeof a.step == "number" && (l.step = String(a.step)), a.defaultValue != null && (l.value = String(a.defaultValue))) : a.type === "date" ? (l.type = "date", typeof a.min == "string" && (l.min = a.min), typeof a.max == "string" && (l.max = a.max), a.defaultValue != null && (l.value = String(a.defaultValue))) : (l.type = "text", a.defaultValue != null && (l.value = String(a.defaultValue))), m = l;
|
|
745
799
|
}
|
|
746
800
|
const C = r();
|
|
747
|
-
p.appendChild(
|
|
748
|
-
name:
|
|
749
|
-
type:
|
|
750
|
-
el:
|
|
751
|
-
required:
|
|
801
|
+
p.appendChild(m), p.appendChild(C), n.push({
|
|
802
|
+
name: a.name,
|
|
803
|
+
type: a.type,
|
|
804
|
+
el: m,
|
|
805
|
+
required: a.required
|
|
752
806
|
}), s.appendChild(p);
|
|
753
807
|
});
|
|
754
808
|
const c = document.createElement("div");
|
|
755
809
|
c.className = "foisit-form-actions";
|
|
756
810
|
const f = document.createElement("button");
|
|
757
|
-
f.type = "submit", f.textContent = "Submit", f.className = "foisit-option-chip", f.style.fontWeight = "600", c.appendChild(f), s.appendChild(c), s.onsubmit = async (
|
|
758
|
-
|
|
811
|
+
f.type = "submit", f.textContent = "Submit", f.className = "foisit-option-chip", f.style.fontWeight = "600", c.appendChild(f), s.appendChild(c), s.onsubmit = async (a) => {
|
|
812
|
+
a.preventDefault();
|
|
759
813
|
const p = {};
|
|
760
|
-
let
|
|
761
|
-
s.querySelectorAll(".foisit-form-error").forEach((
|
|
762
|
-
|
|
763
|
-
}), s.querySelectorAll(".foisit-form-input").forEach((
|
|
764
|
-
|
|
814
|
+
let g = !1;
|
|
815
|
+
s.querySelectorAll(".foisit-form-error").forEach((m) => {
|
|
816
|
+
m.style.display = "none", m.textContent = "";
|
|
817
|
+
}), s.querySelectorAll(".foisit-form-input").forEach((m) => {
|
|
818
|
+
m.classList.remove("foisit-error-border");
|
|
765
819
|
});
|
|
766
|
-
for (const
|
|
767
|
-
if (
|
|
768
|
-
const
|
|
769
|
-
if (
|
|
770
|
-
|
|
820
|
+
for (const m of n) {
|
|
821
|
+
if (m.type === "file") {
|
|
822
|
+
const w = m.el.parentElement, h = w == null ? void 0 : w.querySelector(".foisit-form-error"), x = m.el, y = Array.from(x.files || []);
|
|
823
|
+
if (m.required && y.length === 0) {
|
|
824
|
+
g = !0, x.classList.add("foisit-error-border"), h && (h.textContent = "This file is required", h.style.display = "block");
|
|
771
825
|
continue;
|
|
772
826
|
}
|
|
773
|
-
if (
|
|
774
|
-
const u = (e ?? []).find((v) => v.name ===
|
|
827
|
+
if (y.length === 0) continue;
|
|
828
|
+
const u = (e ?? []).find((v) => v.name === m.name), S = (u == null ? void 0 : u.delivery) ?? "file";
|
|
775
829
|
if (u != null && u.maxWidth || u != null && u.maxHeight)
|
|
776
830
|
try {
|
|
777
|
-
const v = await this.getImageDimensions(
|
|
831
|
+
const v = await this.getImageDimensions(y[0]);
|
|
778
832
|
if (u.maxWidth && v.width > u.maxWidth) {
|
|
779
|
-
|
|
833
|
+
g = !0, h && (h.textContent = `Image width must be ≤ ${u.maxWidth}px`, h.style.display = "block");
|
|
780
834
|
continue;
|
|
781
835
|
}
|
|
782
836
|
if (u.maxHeight && v.height > u.maxHeight) {
|
|
783
|
-
|
|
837
|
+
g = !0, h && (h.textContent = `Image height must be ≤ ${u.maxHeight}px`, h.style.display = "block");
|
|
784
838
|
continue;
|
|
785
839
|
}
|
|
786
840
|
} catch {
|
|
787
841
|
}
|
|
788
842
|
if (u != null && u.maxDurationSec)
|
|
789
843
|
try {
|
|
790
|
-
const v = await this.getMediaDuration(
|
|
844
|
+
const v = await this.getMediaDuration(y[0]);
|
|
791
845
|
if (v && v > u.maxDurationSec) {
|
|
792
|
-
|
|
846
|
+
g = !0, h && (h.textContent = `Media duration must be ≤ ${u.maxDurationSec}s`, h.style.display = "block");
|
|
793
847
|
continue;
|
|
794
848
|
}
|
|
795
849
|
} catch {
|
|
796
850
|
}
|
|
797
851
|
if (S === "file")
|
|
798
|
-
p[
|
|
852
|
+
p[m.name] = u != null && u.multiple ? y : y[0];
|
|
799
853
|
else if (S === "base64")
|
|
800
854
|
try {
|
|
801
|
-
const v = await Promise.all(
|
|
802
|
-
p[
|
|
855
|
+
const v = await Promise.all(y.map((A) => this.readFileAsDataURL(A)));
|
|
856
|
+
p[m.name] = u != null && u.multiple ? v : v[0];
|
|
803
857
|
} catch {
|
|
804
|
-
|
|
858
|
+
g = !0, h && (h.textContent = "Failed to encode file(s) to base64.", h.style.display = "block");
|
|
805
859
|
continue;
|
|
806
860
|
}
|
|
807
861
|
continue;
|
|
808
862
|
}
|
|
809
|
-
const C = (
|
|
810
|
-
if (
|
|
811
|
-
|
|
863
|
+
const C = (m.el.value ?? "").toString().trim(), l = m.el.parentElement, b = l == null ? void 0 : l.querySelector(".foisit-form-error");
|
|
864
|
+
if (m.required && (C == null || C === "")) {
|
|
865
|
+
g = !0, m.el.classList.add("foisit-error-border"), b && (b.textContent = "This field is required", b.style.display = "block");
|
|
812
866
|
continue;
|
|
813
867
|
}
|
|
814
868
|
if (C !== "")
|
|
815
|
-
if (
|
|
816
|
-
const
|
|
817
|
-
Number.isNaN(
|
|
869
|
+
if (m.type === "number") {
|
|
870
|
+
const w = Number(C);
|
|
871
|
+
Number.isNaN(w) || (p[m.name] = w);
|
|
818
872
|
} else
|
|
819
|
-
p[
|
|
873
|
+
p[m.name] = C;
|
|
820
874
|
}
|
|
821
|
-
if (
|
|
875
|
+
if (g) {
|
|
822
876
|
s.classList.add("foisit-shake"), setTimeout(() => s.classList.remove("foisit-shake"), 400);
|
|
823
877
|
return;
|
|
824
878
|
}
|
|
825
|
-
f.disabled = !0, f.style.opacity = "0.6", n.forEach((
|
|
826
|
-
|
|
879
|
+
f.disabled = !0, f.style.opacity = "0.6", n.forEach((m) => {
|
|
880
|
+
m.el.disabled = !0;
|
|
827
881
|
}), i(p);
|
|
828
882
|
}, this.messagesContainer.appendChild(s), this.scrollToBottom();
|
|
829
883
|
}
|
|
@@ -874,16 +928,16 @@ class G {
|
|
|
874
928
|
try {
|
|
875
929
|
const i = URL.createObjectURL(t), s = t.type.startsWith("audio") ? document.createElement("audio") : document.createElement("video");
|
|
876
930
|
let n = !1;
|
|
877
|
-
const
|
|
931
|
+
const o = setTimeout(() => {
|
|
878
932
|
n || (n = !0, URL.revokeObjectURL(i), e(0));
|
|
879
933
|
}, 5e3);
|
|
880
934
|
s.preload = "metadata", s.onloadedmetadata = () => {
|
|
881
935
|
if (n) return;
|
|
882
|
-
n = !0, clearTimeout(
|
|
936
|
+
n = !0, clearTimeout(o);
|
|
883
937
|
const c = s.duration || 0;
|
|
884
938
|
URL.revokeObjectURL(i), e(c);
|
|
885
939
|
}, s.onerror = () => {
|
|
886
|
-
n || (n = !0, clearTimeout(
|
|
940
|
+
n || (n = !0, clearTimeout(o), URL.revokeObjectURL(i), e(0));
|
|
887
941
|
}, s.src = i;
|
|
888
942
|
} catch {
|
|
889
943
|
e(0);
|
|
@@ -1217,12 +1271,12 @@ class G {
|
|
|
1217
1271
|
`, document.head.appendChild(t);
|
|
1218
1272
|
}
|
|
1219
1273
|
}
|
|
1220
|
-
class
|
|
1274
|
+
class K {
|
|
1221
1275
|
constructor(t) {
|
|
1222
1276
|
this.config = t, this.isActivated = !1, this.lastProcessedInput = "", this.processingLock = !1, this.defaultIntroMessage = "How can I help you?", this.commandHandler = new B({
|
|
1223
1277
|
enableSmartIntent: this.config.enableSmartIntent !== !1,
|
|
1224
1278
|
intentEndpoint: this.config.intentEndpoint
|
|
1225
|
-
}), this.fallbackHandler = new
|
|
1279
|
+
}), this.fallbackHandler = new z(), typeof window < "u" && typeof document < "u" ? (this.voiceProcessor = new O(), this.textToSpeech = new H(), this.stateManager = new G(), this.gestureHandler = new U(), this.overlayManager = new Y({
|
|
1226
1280
|
floatingButton: this.config.floatingButton,
|
|
1227
1281
|
inputPlaceholder: this.config.inputPlaceholder
|
|
1228
1282
|
}), this.config.commands.forEach((e) => this.commandHandler.addCommand(e)), this.config.fallbackResponse && this.fallbackHandler.setFallbackMessage(this.config.fallbackResponse), this.gestureHandler.setupDoubleTapListener(() => this.toggle()), this.overlayManager.registerCallbacks(
|
|
@@ -1239,15 +1293,22 @@ class Y {
|
|
|
1239
1293
|
}
|
|
1240
1294
|
},
|
|
1241
1295
|
() => console.log("AssistantService: Overlay closed.")
|
|
1242
|
-
);
|
|
1296
|
+
)) : (this.voiceProcessor = void 0, this.textToSpeech = void 0, this.stateManager = void 0, this.gestureHandler = void 0, this.overlayManager = void 0, this.config.commands.forEach((e) => this.commandHandler.addCommand(e)), this.config.fallbackResponse && this.fallbackHandler.setFallbackMessage(this.config.fallbackResponse));
|
|
1243
1297
|
}
|
|
1244
1298
|
/** Start listening for activation and commands */
|
|
1245
1299
|
startListening() {
|
|
1246
|
-
|
|
1300
|
+
if (typeof window > "u" || !this.voiceProcessor) {
|
|
1301
|
+
console.log("AssistantService: Voice is disabled or unavailable; startListening() is a no-op.");
|
|
1302
|
+
return;
|
|
1303
|
+
}
|
|
1247
1304
|
}
|
|
1248
1305
|
/** Stop listening */
|
|
1249
1306
|
stopListening() {
|
|
1250
|
-
|
|
1307
|
+
if (typeof window > "u" || !this.voiceProcessor) {
|
|
1308
|
+
console.log("AssistantService: Voice unavailable; stopListening() is a no-op."), this.isActivated = !1;
|
|
1309
|
+
return;
|
|
1310
|
+
}
|
|
1311
|
+
this.voiceProcessor.stopListening(), this.isActivated = !1;
|
|
1251
1312
|
}
|
|
1252
1313
|
/**
|
|
1253
1314
|
* Reset activation state so the next activation flow can occur.
|
|
@@ -1298,7 +1359,11 @@ class Y {
|
|
|
1298
1359
|
this.fallbackHandler.handleFallback(t), this.overlayManager.addMessage(this.fallbackHandler.getFallbackMessage(), "system");
|
|
1299
1360
|
return;
|
|
1300
1361
|
}
|
|
1301
|
-
|
|
1362
|
+
if ((e.type === "ambiguous" || e.type === "confirm") && e.options) {
|
|
1363
|
+
e.message && this.overlayManager.addMessage(e.message, "system"), this.overlayManager.addOptions(e.options);
|
|
1364
|
+
return;
|
|
1365
|
+
}
|
|
1366
|
+
e.message && this.overlayManager.addMessage(e.message, "system");
|
|
1302
1367
|
}
|
|
1303
1368
|
/**
|
|
1304
1369
|
* Cleanup resources
|
|
@@ -1356,13 +1421,13 @@ class Y {
|
|
|
1356
1421
|
if (i && typeof i == "object") {
|
|
1357
1422
|
const s = i, n = s.label ?? s.commandId ?? "Selection";
|
|
1358
1423
|
this.overlayManager.addMessage(String(n), "user"), this.overlayManager.showLoading();
|
|
1359
|
-
let
|
|
1424
|
+
let o;
|
|
1360
1425
|
try {
|
|
1361
|
-
|
|
1426
|
+
o = await this.commandHandler.executeCommand(s);
|
|
1362
1427
|
} finally {
|
|
1363
1428
|
this.overlayManager.hideLoading();
|
|
1364
1429
|
}
|
|
1365
|
-
this.processResponse(
|
|
1430
|
+
this.processResponse(o);
|
|
1366
1431
|
}
|
|
1367
1432
|
},
|
|
1368
1433
|
() => {
|
|
@@ -1378,27 +1443,27 @@ const Z = ({ config: d, children: t }) => {
|
|
|
1378
1443
|
return P(() => {
|
|
1379
1444
|
I ? console.warn(
|
|
1380
1445
|
"Multiple AssistantProvider instances detected. Reusing global AssistantService."
|
|
1381
|
-
) : (console.log("Initializing global AssistantService..."), I = new
|
|
1382
|
-
const
|
|
1383
|
-
return i(
|
|
1446
|
+
) : (console.log("Initializing global AssistantService..."), I = new K(d));
|
|
1447
|
+
const o = I;
|
|
1448
|
+
return i(o), n(!0), () => {
|
|
1384
1449
|
var r;
|
|
1385
|
-
console.log("Cleaning up AssistantService..."), (r =
|
|
1450
|
+
console.log("Cleaning up AssistantService..."), (r = o.destroy) == null || r.call(o), I = null;
|
|
1386
1451
|
};
|
|
1387
1452
|
}, [d]), !s || !e ? /* @__PURE__ */ k("div", { children: "Loading Assistant..." }) : /* @__PURE__ */ k(q.Provider, { value: e, children: t });
|
|
1388
|
-
},
|
|
1453
|
+
}, X = () => {
|
|
1389
1454
|
const d = N(q);
|
|
1390
1455
|
if (console.log("assistant", d), !d)
|
|
1391
1456
|
throw new Error("useAssistant must be used within an AssistantProvider");
|
|
1392
1457
|
return d;
|
|
1393
|
-
},
|
|
1458
|
+
}, tt = ({
|
|
1394
1459
|
label: d = "Activate Assistant",
|
|
1395
1460
|
onActivate: t
|
|
1396
1461
|
}) => {
|
|
1397
|
-
const e =
|
|
1462
|
+
const e = X();
|
|
1398
1463
|
return /* @__PURE__ */ k("button", { onClick: () => {
|
|
1399
1464
|
t && t(), e.reactivate();
|
|
1400
1465
|
}, className: "assistant-activator", children: d });
|
|
1401
|
-
},
|
|
1466
|
+
}, et = (d) => {
|
|
1402
1467
|
const [t, e] = R(d.getState());
|
|
1403
1468
|
return P(() => {
|
|
1404
1469
|
const i = (s) => {
|
|
@@ -1411,11 +1476,11 @@ const Z = ({ config: d, children: t }) => {
|
|
|
1411
1476
|
}, [d]), t;
|
|
1412
1477
|
};
|
|
1413
1478
|
export {
|
|
1414
|
-
|
|
1479
|
+
tt as AssistantActivator,
|
|
1415
1480
|
q as AssistantContext,
|
|
1416
1481
|
Z as AssistantProvider,
|
|
1417
|
-
|
|
1482
|
+
K as AssistantService,
|
|
1418
1483
|
J as ReactWrapper,
|
|
1419
|
-
|
|
1420
|
-
|
|
1484
|
+
X as useAssistant,
|
|
1485
|
+
et as useAssistantState
|
|
1421
1486
|
};
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@foisit/react-wrapper",
|
|
3
|
-
"version": "2.4.
|
|
3
|
+
"version": "2.4.4",
|
|
4
4
|
"main": "./index.js",
|
|
5
5
|
"types": "./index.d.ts",
|
|
6
6
|
"exports": {
|
|
@@ -19,7 +19,20 @@
|
|
|
19
19
|
"README.md"
|
|
20
20
|
],
|
|
21
21
|
"sideEffects": false,
|
|
22
|
-
"description": "
|
|
22
|
+
"description": "A powerful AI assistant library for React applications, providing seamless chatbot functionality and intelligent interactions for websites.",
|
|
23
|
+
"keywords": [
|
|
24
|
+
"ai-assistant",
|
|
25
|
+
"chatbot",
|
|
26
|
+
"react",
|
|
27
|
+
"ai",
|
|
28
|
+
"assistant",
|
|
29
|
+
"accessibility",
|
|
30
|
+
"website-integration"
|
|
31
|
+
],
|
|
32
|
+
"homepage": "https://github.com/boluwatifee4/foisit#readme",
|
|
33
|
+
"bugs": {
|
|
34
|
+
"url": "https://github.com/boluwatifee4/foisit/issues"
|
|
35
|
+
},
|
|
23
36
|
"repository": {
|
|
24
37
|
"type": "git",
|
|
25
38
|
"url": "git+https://github.com/boluwatifee4/foisit.git"
|