esap-aiui-react 1.0.1 → 1.0.2

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 CHANGED
@@ -6,10 +6,17 @@
6
6
  [![TypeScript](https://img.shields.io/badge/TypeScript-5.3-blue.svg?style=flat-square)](https://www.typescriptlang.org/)
7
7
  [![PRs Welcome](https://img.shields.io/badge/PRs-welcome-brightgreen.svg?style=flat-square)](https://github.com/espai/aiui-react/pulls)
8
8
 
9
- **Zero-configuration voice and chat control for React applications through autonomous semantic UI discovery.**
9
+ **Zero-configuration voice and chat control for any React applications through autonomous semantic UI discovery.**
10
10
 
11
11
  AIUI React SDK enables natural language interaction with any React application through both voice commands and text chat, without manual UI annotation or intent mapping. The framework employs real-time DOM observation and semantic element discovery to automatically understand your application's interface, allowing users to control your app through conversational voice or text-based commands.
12
12
 
13
+ ### Enterprise features at a glance
14
+
15
+ - Security: API-key protected WebSocket channels and safety-rule gates
16
+ - Privacy: client-side redaction and sensitive-field filtering
17
+ - Auditability: server-side action logs and context update tracing
18
+ - Deployment: cloud, private VPC, or fully on-prem
19
+
13
20
  ## Overview
14
21
 
15
22
  Traditional voice control solutions require extensive manual configuration, predefined intent schemas, or explicit UI element annotation. AIUI eliminates this overhead through a novel semantic discovery architecture that automatically maps UI elements to their contextual meaning, enabling immediate voice interaction with zero setup.
@@ -29,7 +36,7 @@ The SDK implements a **hybrid discovery engine** combining MutationObserver-base
29
36
 
30
37
  ## Architecture
31
38
 
32
- ![AIUI Architecture](./assets/architecture-diagram.png)
39
+ ![AIUI Architecture](https://i.imgur.com/Pvmi0Aq.png)
33
40
 
34
41
  ### Protocol Design
35
42
 
@@ -1026,208 +1033,6 @@ The SDK communicates with a backend server implementing the AIUI protocol. The s
1026
1033
  }
1027
1034
  ```
1028
1035
 
1029
- ### Reference Server Implementation
1030
-
1031
- ```javascript
1032
- const WebSocket = require('ws');
1033
-
1034
- // Create WebSocket server with three endpoints
1035
- const contextServer = new WebSocket.Server({ port: 8080, path: '/context' });
1036
- const audioServer = new WebSocket.Server({ port: 8080, path: '/audio' });
1037
- const chatServer = new WebSocket.Server({ port: 8080, path: '/chat' });
1038
-
1039
- // Session management
1040
- const sessions = new Map();
1041
-
1042
- // Context channel handler
1043
- contextServer.on('connection', (ws, req) => {
1044
- const url = new URL(req.url, 'ws://localhost');
1045
- const applicationId = url.searchParams.get('applicationId');
1046
- const apiKey = url.searchParams.get('apiKey');
1047
-
1048
- // Validate API key
1049
- if (!validateApiKey(apiKey)) {
1050
- ws.close(1008, 'Invalid API key');
1051
- return;
1052
- }
1053
-
1054
- console.log(`Context connected: ${applicationId}`);
1055
-
1056
- // Store session
1057
- if (!sessions.has(applicationId)) {
1058
- sessions.set(applicationId, {});
1059
- }
1060
- sessions.get(applicationId).contextWs = ws;
1061
-
1062
- ws.on('message', async (data) => {
1063
- const message = JSON.parse(data.toString());
1064
-
1065
- if (message.type === 'context_update' || message.type === 'context_append') {
1066
- // Store UI context for LLM
1067
- const session = sessions.get(applicationId);
1068
- session.uiContext = message.context || message.elements;
1069
-
1070
- console.log(`UI context updated: ${session.uiContext.elements?.length || 0} elements`);
1071
- }
1072
- });
1073
-
1074
- ws.on('close', () => {
1075
- console.log(`Context disconnected: ${applicationId}`);
1076
- });
1077
- });
1078
-
1079
- // Audio channel handler (for voice mode)
1080
- audioServer.on('connection', (ws, req) => {
1081
- const url = new URL(req.url, 'ws://localhost');
1082
- const applicationId = url.searchParams.get('applicationId');
1083
-
1084
- console.log(`Audio connected: ${applicationId}`);
1085
-
1086
- const session = sessions.get(applicationId);
1087
- if (session) {
1088
- session.audioWs = ws;
1089
- }
1090
-
1091
- let audioBuffer = [];
1092
-
1093
- ws.on('message', async (data) => {
1094
- if (data instanceof Buffer) {
1095
- // Accumulate audio chunks
1096
- audioBuffer.push(data);
1097
-
1098
- // Process when sufficient audio accumulated (e.g., 1 second)
1099
- if (audioBuffer.length >= 50) { // 50 * 20ms = 1 second
1100
- const audioData = Buffer.concat(audioBuffer);
1101
- audioBuffer = [];
1102
-
1103
- // Send to Speech-to-Text service
1104
- const transcript = await speechToText(audioData);
1105
-
1106
- if (transcript && session?.uiContext) {
1107
- // Process with LLM
1108
- const action = await processWithLLM(transcript, session.uiContext);
1109
-
1110
- // Send action command via context channel
1111
- session.contextWs?.send(JSON.stringify({
1112
- type: 'action',
1113
- action: action.type,
1114
- params: action.params,
1115
- timestamp: new Date().toISOString()
1116
- }));
1117
-
1118
- // Generate TTS response
1119
- const audioResponse = await textToSpeech(action.response);
1120
-
1121
- // Send audio response
1122
- ws.send(audioResponse);
1123
- }
1124
- }
1125
- }
1126
- });
1127
-
1128
- ws.on('close', () => {
1129
- console.log(`Audio disconnected: ${applicationId}`);
1130
- });
1131
- });
1132
-
1133
- // Chat channel handler (for text mode)
1134
- chatServer.on('connection', (ws, req) => {
1135
- const url = new URL(req.url, 'ws://localhost');
1136
- const applicationId = url.searchParams.get('applicationId');
1137
-
1138
- console.log(`Chat connected: ${applicationId}`);
1139
-
1140
- const session = sessions.get(applicationId);
1141
- if (session) {
1142
- session.chatWs = ws;
1143
- }
1144
-
1145
- // Confirm connection
1146
- ws.send(JSON.stringify({ type: 'chat_connected' }));
1147
-
1148
- ws.on('message', async (data) => {
1149
- const message = JSON.parse(data.toString());
1150
-
1151
- if (message.type === 'chat_message') {
1152
- const userMessage = message.content;
1153
- console.log(`Chat message from ${applicationId}: ${userMessage}`);
1154
-
1155
- // Send typing indicator
1156
- ws.send(JSON.stringify({ type: 'chat_typing', typing: true }));
1157
-
1158
- if (session?.uiContext) {
1159
- // Process with LLM
1160
- const response = await processWithLLM(userMessage, session.uiContext);
1161
-
1162
- // Stop typing indicator
1163
- ws.send(JSON.stringify({ type: 'chat_typing', typing: false }));
1164
-
1165
- // If action required, send to context channel
1166
- if (response.action) {
1167
- session.contextWs?.send(JSON.stringify({
1168
- type: 'action',
1169
- action: response.type,
1170
- params: response.params,
1171
- timestamp: new Date().toISOString()
1172
- }));
1173
- }
1174
-
1175
- // Send chat response
1176
- ws.send(JSON.stringify({
1177
- type: 'chat_message',
1178
- role: 'assistant',
1179
- content: response.message,
1180
- timestamp: new Date().toISOString()
1181
- }));
1182
- } else {
1183
- ws.send(JSON.stringify({
1184
- type: 'chat_message',
1185
- role: 'assistant',
1186
- content: 'I don\'t have access to the UI context yet. Please ensure the page is loaded.',
1187
- timestamp: new Date().toISOString()
1188
- }));
1189
- }
1190
- }
1191
- });
1192
-
1193
- ws.on('close', () => {
1194
- console.log(`Chat disconnected: ${applicationId}`);
1195
- if (session) {
1196
- session.chatWs = null;
1197
- }
1198
- });
1199
- });
1200
-
1201
- async function processWithLLM(userInput, uiContext) {
1202
- const prompt = `
1203
- You are controlling a web application via ${typeof userInput === 'string' ? 'chat' : 'voice'}.
1204
-
1205
- Current UI Context:
1206
- ${JSON.stringify(uiContext, null, 2)}
1207
-
1208
- User input: "${userInput}"
1209
-
1210
- Determine if an action is needed and respond in JSON format:
1211
- {
1212
- "action": true/false,
1213
- "type": "click" | "set_value" | "select_from_dropdown" | "navigate",
1214
- "params": { "semantic": "element description", "value": "..." },
1215
- "message": "Response to user (what you did or information about the UI)"
1216
- }
1217
-
1218
- If the user is just asking for information about the UI, set action to false and provide the information in message.
1219
- `;
1220
-
1221
- const response = await openai.chat.completions.create({
1222
- model: "gpt-4",
1223
- messages: [{ role: "user", content: prompt }],
1224
- response_format: { type: "json_object" }
1225
- });
1226
-
1227
- return JSON.parse(response.choices[0].message.content);
1228
- }
1229
- ```
1230
-
1231
1036
  ### Production Deployment Considerations
1232
1037
 
1233
1038
  **Security:**
@@ -1481,4 +1286,4 @@ Special thanks to early adopters who provided production feedback and contribute
1481
1286
 
1482
1287
  ---
1483
1288
 
1484
- **Built with precision for voice-first web experiences.**
1289
+ **Built with precision for voice-first web experiences.**
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "esap-aiui-react",
3
- "version": "1.0.1",
3
+ "version": "1.0.2",
4
4
  "type": "module",
5
5
  "description": "Zero-configuration voice and chat control for React applications through autonomous semantic UI discovery",
6
6
  "main": "dist/index.js",
@@ -1,57 +0,0 @@
1
- import * as React from 'react';
2
- import type { ReactNode } from 'react';
3
- export interface AIUIConfig {
4
- applicationId: string;
5
- serverUrl: string;
6
- apiKey?: string;
7
- pages: MinimalPageConfig[];
8
- safetyRules?: SafetyRules;
9
- privacy?: PrivacyConfig;
10
- onNavigate?: (route: string) => void | Promise<void>;
11
- }
12
- export interface MinimalPageConfig {
13
- route: string;
14
- title?: string;
15
- safeActions?: string[];
16
- dangerousActions?: string[];
17
- }
18
- export interface SafetyRules {
19
- requireConfirmation?: string[];
20
- blockedSelectors?: string[];
21
- allowedDomains?: string[];
22
- }
23
- export interface PrivacyConfig {
24
- redactPatterns?: string[];
25
- exposePasswords?: boolean;
26
- exposeCreditCards?: boolean;
27
- }
28
- interface AIUIContextValue {
29
- config: AIUIConfig;
30
- isConnected: boolean;
31
- isListening: boolean;
32
- currentPage: string | null;
33
- connect: () => void;
34
- disconnect: () => void;
35
- startListening: () => Promise<void>;
36
- stopListening: () => void;
37
- sendChatMessage: (message: string) => Promise<void>;
38
- chatMessages: ChatMessage[];
39
- isChatConnected: boolean;
40
- executeAction: (action: string, params: any) => Promise<any>;
41
- getComponentValue: (selector: string) => any;
42
- registerComponent: (componentId: string, element: HTMLElement) => void;
43
- unregisterComponent: (componentId: string) => void;
44
- }
45
- export interface ChatMessage {
46
- role: 'user' | 'assistant';
47
- content: string;
48
- timestamp: string;
49
- }
50
- export declare const useAIUI: () => AIUIContextValue;
51
- export interface AIUIProviderProps {
52
- config: AIUIConfig;
53
- children: ReactNode;
54
- }
55
- export declare const AIUIProvider: React.FC<AIUIProviderProps>;
56
- export default AIUIProvider;
57
- //# sourceMappingURL=auuichat.d.ts.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"auuichat.d.ts","sourceRoot":"","sources":["../src/auuichat.tsx"],"names":[],"mappings":"AACA,OAAO,KAAK,KAAK,MAAM,OAAO,CAAC;AAE/B,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,OAAO,CAAC;AAOvC,MAAM,WAAW,UAAU;IACvB,aAAa,EAAE,MAAM,CAAC;IACtB,SAAS,EAAE,MAAM,CAAC;IAClB,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,KAAK,EAAE,iBAAiB,EAAE,CAAC;IAC3B,WAAW,CAAC,EAAE,WAAW,CAAC;IAC1B,OAAO,CAAC,EAAE,aAAa,CAAC;IACxB,UAAU,CAAC,EAAE,CAAC,KAAK,EAAE,MAAM,KAAK,IAAI,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;CACxD;AAED,MAAM,WAAW,iBAAiB;IAC9B,KAAK,EAAE,MAAM,CAAC;IACd,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,WAAW,CAAC,EAAE,MAAM,EAAE,CAAC;IACvB,gBAAgB,CAAC,EAAE,MAAM,EAAE,CAAC;CAC/B;AAED,MAAM,WAAW,WAAW;IACxB,mBAAmB,CAAC,EAAE,MAAM,EAAE,CAAC;IAC/B,gBAAgB,CAAC,EAAE,MAAM,EAAE,CAAC;IAC5B,cAAc,CAAC,EAAE,MAAM,EAAE,CAAC;CAC7B;AAED,MAAM,WAAW,aAAa;IAC1B,cAAc,CAAC,EAAE,MAAM,EAAE,CAAC;IAC1B,eAAe,CAAC,EAAE,OAAO,CAAC;IAC1B,iBAAiB,CAAC,EAAE,OAAO,CAAC;CAC/B;AAED,UAAU,gBAAgB;IACtB,MAAM,EAAE,UAAU,CAAC;IACnB,WAAW,EAAE,OAAO,CAAC;IACrB,WAAW,EAAE,OAAO,CAAC;IACrB,WAAW,EAAE,MAAM,GAAG,IAAI,CAAC;IAE3B,OAAO,EAAE,MAAM,IAAI,CAAC;IACpB,UAAU,EAAE,MAAM,IAAI,CAAC;IACvB,cAAc,EAAE,MAAM,OAAO,CAAC,IAAI,CAAC,CAAC;IACpC,aAAa,EAAE,MAAM,IAAI,CAAC;IAE1B,eAAe,EAAE,CAAC,OAAO,EAAE,MAAM,KAAK,OAAO,CAAC,IAAI,CAAC,CAAC;IACpD,YAAY,EAAE,WAAW,EAAE,CAAC;IAC5B,eAAe,EAAE,OAAO,CAAC;IAEzB,aAAa,EAAE,CAAC,MAAM,EAAE,MAAM,EAAE,MAAM,EAAE,GAAG,KAAK,OAAO,CAAC,GAAG,CAAC,CAAC;IAC7D,iBAAiB,EAAE,CAAC,QAAQ,EAAE,MAAM,KAAK,GAAG,CAAC;IAC7C,iBAAiB,EAAE,CAAC,WAAW,EAAE,MAAM,EAAE,OAAO,EAAE,WAAW,KAAK,IAAI,CAAC;IACvE,mBAAmB,EAAE,CAAC,WAAW,EAAE,MAAM,KAAK,IAAI,CAAC;CACtD;AAED,MAAM,WAAW,WAAW;IACxB,IAAI,EAAE,MAAM,GAAG,WAAW,CAAC;IAC3B,OAAO,EAAE,MAAM,CAAC;IAChB,SAAS,EAAE,MAAM,CAAC;CACrB;AAID,eAAO,MAAM,OAAO,QAAO,gBAM1B,CAAC;AAu3DF,MAAM,WAAW,iBAAiB;IAC9B,MAAM,EAAE,UAAU,CAAC;IACnB,QAAQ,EAAE,SAAS,CAAC;CACvB;AAED,eAAO,MAAM,YAAY,EAAE,KAAK,CAAC,EAAE,CAAC,iBAAiB,CA6RpD,CAAC;AA6BF,eAAe,YAAY,CAAC"}