@courseecho/ai-widget-react 1.0.23 → 1.0.24
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/core/src/auto-suggestion-generator.d.ts +118 -0
- package/dist/core/src/auto-suggestion-generator.js +538 -0
- package/dist/core/src/communication-service.d.ts +47 -0
- package/dist/core/src/communication-service.js +124 -0
- package/dist/core/src/index.d.ts +11 -0
- package/dist/core/src/index.js +15 -0
- package/dist/core/src/models.d.ts +137 -0
- package/dist/core/src/models.js +5 -0
- package/dist/core/src/sdk.d.ts +166 -0
- package/dist/core/src/sdk.js +387 -0
- package/dist/core/src/state-manager.d.ts +200 -0
- package/dist/core/src/state-manager.js +368 -0
- package/dist/core/src/widget-css.d.ts +14 -0
- package/dist/core/src/widget-css.js +389 -0
- package/dist/react/src/ShadowWrapper.d.ts +12 -0
- package/dist/react/src/ShadowWrapper.js +44 -0
- package/dist/react/src/components.d.ts +25 -0
- package/dist/react/src/components.js +226 -0
- package/dist/react/src/hooks.d.ts +64 -0
- package/dist/react/src/hooks.js +181 -0
- package/dist/react/src/index.d.ts +7 -0
- package/dist/react/src/index.js +5 -0
- package/package.json +1 -1
|
@@ -0,0 +1,124 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* AI Widget SDK - Core Communication Service
|
|
3
|
+
* Handle HTTP requests to backend API
|
|
4
|
+
*/
|
|
5
|
+
/** Safely parse a Response body as JSON — returns null for empty/non-JSON bodies instead of throwing. */
|
|
6
|
+
async function safeJson(res) {
|
|
7
|
+
const text = await res.text();
|
|
8
|
+
if (!text || !text.trim())
|
|
9
|
+
return null;
|
|
10
|
+
try {
|
|
11
|
+
return JSON.parse(text);
|
|
12
|
+
}
|
|
13
|
+
catch {
|
|
14
|
+
return null;
|
|
15
|
+
}
|
|
16
|
+
}
|
|
17
|
+
export class AiCommunicationService {
|
|
18
|
+
constructor(apiEndpoint, apiKey) {
|
|
19
|
+
if (!apiEndpoint) {
|
|
20
|
+
throw new Error('apiEndpoint is required');
|
|
21
|
+
}
|
|
22
|
+
this.apiEndpoint = apiEndpoint.replace(/\/$/, ''); // Remove trailing slash
|
|
23
|
+
this.apiKey = apiKey;
|
|
24
|
+
}
|
|
25
|
+
/**
|
|
26
|
+
* Set JWT token for authentication
|
|
27
|
+
*/
|
|
28
|
+
setJwtToken(token) {
|
|
29
|
+
this.jwtToken = token;
|
|
30
|
+
}
|
|
31
|
+
/**
|
|
32
|
+
* Get current JWT token
|
|
33
|
+
*/
|
|
34
|
+
getJwtToken() {
|
|
35
|
+
return this.jwtToken;
|
|
36
|
+
}
|
|
37
|
+
/**
|
|
38
|
+
* Check if JWT token is set
|
|
39
|
+
*/
|
|
40
|
+
isAuthenticated() {
|
|
41
|
+
return !!this.jwtToken;
|
|
42
|
+
}
|
|
43
|
+
/**
|
|
44
|
+
* Send query to backend API
|
|
45
|
+
*/
|
|
46
|
+
async sendQuery(request) {
|
|
47
|
+
if (!this.jwtToken && !this.apiKey) {
|
|
48
|
+
throw new Error('Authentication required: Set JWT token or API key. Call setJwtToken() first.');
|
|
49
|
+
}
|
|
50
|
+
const headers = {
|
|
51
|
+
'Content-Type': 'application/json',
|
|
52
|
+
};
|
|
53
|
+
if (this.jwtToken) {
|
|
54
|
+
headers['Authorization'] = `Bearer ${this.jwtToken}`;
|
|
55
|
+
}
|
|
56
|
+
else if (this.apiKey) {
|
|
57
|
+
headers['X-API-Key'] = this.apiKey;
|
|
58
|
+
}
|
|
59
|
+
try {
|
|
60
|
+
const response = await fetch(`${this.apiEndpoint}/api/aiorchestrator/query`, {
|
|
61
|
+
method: 'POST',
|
|
62
|
+
headers,
|
|
63
|
+
body: JSON.stringify(request),
|
|
64
|
+
});
|
|
65
|
+
if (!response.ok) {
|
|
66
|
+
const errorData = await safeJson(response);
|
|
67
|
+
throw new ApiError(errorData?.message || `HTTP ${response.status}`, response.status, errorData);
|
|
68
|
+
}
|
|
69
|
+
const data = (await safeJson(response));
|
|
70
|
+
if (!data)
|
|
71
|
+
throw new ApiError('Empty response from server', 500);
|
|
72
|
+
// Ensure timestamp is a Date object
|
|
73
|
+
data.timestamp = new Date(data.timestamp);
|
|
74
|
+
return data;
|
|
75
|
+
}
|
|
76
|
+
catch (error) {
|
|
77
|
+
if (error instanceof ApiError) {
|
|
78
|
+
throw error;
|
|
79
|
+
}
|
|
80
|
+
throw new ApiError(`Failed to send query: ${String(error)}`, 500);
|
|
81
|
+
}
|
|
82
|
+
}
|
|
83
|
+
/**
|
|
84
|
+
* Check backend health
|
|
85
|
+
*/
|
|
86
|
+
async checkHealth() {
|
|
87
|
+
try {
|
|
88
|
+
const response = await fetch(`${this.apiEndpoint}/health`);
|
|
89
|
+
return response.ok;
|
|
90
|
+
}
|
|
91
|
+
catch {
|
|
92
|
+
return false;
|
|
93
|
+
}
|
|
94
|
+
}
|
|
95
|
+
/**
|
|
96
|
+
* Get API endpoint
|
|
97
|
+
*/
|
|
98
|
+
getApiEndpoint() {
|
|
99
|
+
return this.apiEndpoint;
|
|
100
|
+
}
|
|
101
|
+
}
|
|
102
|
+
/**
|
|
103
|
+
* Custom API Error class
|
|
104
|
+
*/
|
|
105
|
+
export class ApiError extends Error {
|
|
106
|
+
constructor(message, statusCode, responseData) {
|
|
107
|
+
super(message);
|
|
108
|
+
this.statusCode = statusCode;
|
|
109
|
+
this.responseData = responseData;
|
|
110
|
+
this.name = 'ApiError';
|
|
111
|
+
}
|
|
112
|
+
isRateLimited() {
|
|
113
|
+
return this.statusCode === 429;
|
|
114
|
+
}
|
|
115
|
+
isUnauthorized() {
|
|
116
|
+
return this.statusCode === 401;
|
|
117
|
+
}
|
|
118
|
+
isBadRequest() {
|
|
119
|
+
return this.statusCode === 400;
|
|
120
|
+
}
|
|
121
|
+
isServerError() {
|
|
122
|
+
return this.statusCode >= 500;
|
|
123
|
+
}
|
|
124
|
+
}
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* AI Widget Core SDK - Public API
|
|
3
|
+
* Framework-agnostic core library
|
|
4
|
+
*/
|
|
5
|
+
export * from './models';
|
|
6
|
+
export { AiCommunicationService, ApiError } from './communication-service';
|
|
7
|
+
export { ChatStateManager, ContextStateManager, ChartManager, SuggestionManager, } from './state-manager';
|
|
8
|
+
export { PageContentScanner, AiSuggestionGenerator, type PageContent, } from './auto-suggestion-generator';
|
|
9
|
+
export { AiWidgetSDK } from './sdk';
|
|
10
|
+
export type { StateListener } from './state-manager';
|
|
11
|
+
export { WIDGET_CSS } from './widget-css';
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* AI Widget Core SDK - Public API
|
|
3
|
+
* Framework-agnostic core library
|
|
4
|
+
*/
|
|
5
|
+
// Models
|
|
6
|
+
export * from './models';
|
|
7
|
+
// Services
|
|
8
|
+
export { AiCommunicationService, ApiError } from './communication-service';
|
|
9
|
+
export { ChatStateManager, ContextStateManager, ChartManager, SuggestionManager, } from './state-manager';
|
|
10
|
+
// Auto-suggestion & page scanning
|
|
11
|
+
export { PageContentScanner, AiSuggestionGenerator, } from './auto-suggestion-generator';
|
|
12
|
+
// Main SDK
|
|
13
|
+
export { AiWidgetSDK } from './sdk';
|
|
14
|
+
// Canonical widget CSS (used by all framework packages)
|
|
15
|
+
export { WIDGET_CSS } from './widget-css';
|
|
@@ -0,0 +1,137 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* AI Widget SDK - Shared Models
|
|
3
|
+
* Framework-agnostic type definitions used across all implementations
|
|
4
|
+
*/
|
|
5
|
+
export interface AiMessage {
|
|
6
|
+
id: string;
|
|
7
|
+
role: 'user' | 'assistant';
|
|
8
|
+
content: string;
|
|
9
|
+
timestamp: Date;
|
|
10
|
+
metadata?: {
|
|
11
|
+
hasChart: boolean;
|
|
12
|
+
charts?: AiChart[];
|
|
13
|
+
suggestedFollowUps?: string[];
|
|
14
|
+
};
|
|
15
|
+
}
|
|
16
|
+
export interface AiChart {
|
|
17
|
+
type: 'bar' | 'line' | 'pie' | 'doughnut' | 'radar';
|
|
18
|
+
title: string;
|
|
19
|
+
labels: string[];
|
|
20
|
+
datasets: ChartDataset[];
|
|
21
|
+
options?: ChartOptions;
|
|
22
|
+
}
|
|
23
|
+
export interface ChartDataset {
|
|
24
|
+
label: string;
|
|
25
|
+
data: number[];
|
|
26
|
+
backgroundColor?: string | string[];
|
|
27
|
+
borderColor?: string | string[];
|
|
28
|
+
tension?: number;
|
|
29
|
+
fill?: boolean;
|
|
30
|
+
}
|
|
31
|
+
export interface ChartOptions {
|
|
32
|
+
responsive?: boolean;
|
|
33
|
+
maintainAspectRatio?: boolean;
|
|
34
|
+
plugins?: {
|
|
35
|
+
legend?: {
|
|
36
|
+
display?: boolean;
|
|
37
|
+
position?: 'top' | 'bottom' | 'left' | 'right';
|
|
38
|
+
};
|
|
39
|
+
tooltip?: {
|
|
40
|
+
enabled?: boolean;
|
|
41
|
+
};
|
|
42
|
+
};
|
|
43
|
+
scales?: Record<string, any>;
|
|
44
|
+
}
|
|
45
|
+
export interface AiContext {
|
|
46
|
+
pageType: string;
|
|
47
|
+
entityId?: string;
|
|
48
|
+
userId?: string;
|
|
49
|
+
customData?: Record<string, any>;
|
|
50
|
+
}
|
|
51
|
+
export interface AiContextConfig {
|
|
52
|
+
context: AiContext;
|
|
53
|
+
apiEndpoint?: string;
|
|
54
|
+
apiKey?: string;
|
|
55
|
+
maxChatHistory?: number;
|
|
56
|
+
theme?: 'light' | 'dark';
|
|
57
|
+
position?: 'bottom-right' | 'bottom-left' | 'top-right' | 'top-left';
|
|
58
|
+
enableCharts?: boolean;
|
|
59
|
+
enableExport?: boolean;
|
|
60
|
+
suggestionConfig?: SuggestionConfig;
|
|
61
|
+
}
|
|
62
|
+
export interface AiQueryRequest {
|
|
63
|
+
userQuery: string;
|
|
64
|
+
pageType: string;
|
|
65
|
+
entityId?: string;
|
|
66
|
+
contextData?: Record<string, any>;
|
|
67
|
+
[key: string]: any;
|
|
68
|
+
}
|
|
69
|
+
export interface AiQueryResponse {
|
|
70
|
+
sessionId: string;
|
|
71
|
+
response: string;
|
|
72
|
+
toolsUsed: string[];
|
|
73
|
+
tokensUsed: number;
|
|
74
|
+
cost: number;
|
|
75
|
+
timestamp: Date;
|
|
76
|
+
}
|
|
77
|
+
export interface AiErrorResponse {
|
|
78
|
+
error: string;
|
|
79
|
+
message: string;
|
|
80
|
+
statusCode: number;
|
|
81
|
+
timestamp: Date;
|
|
82
|
+
}
|
|
83
|
+
export interface ChartExportOptions {
|
|
84
|
+
format: 'csv' | 'json';
|
|
85
|
+
filename?: string;
|
|
86
|
+
}
|
|
87
|
+
export interface ChatExportData {
|
|
88
|
+
sessionId: string;
|
|
89
|
+
messages: AiMessage[];
|
|
90
|
+
charts: AiChart[];
|
|
91
|
+
exportedAt: Date;
|
|
92
|
+
}
|
|
93
|
+
/**
|
|
94
|
+
* Suggestion Models for Auto-suggestion Feature
|
|
95
|
+
*/
|
|
96
|
+
export interface AiSuggestion {
|
|
97
|
+
id: string;
|
|
98
|
+
text: string;
|
|
99
|
+
category?: string;
|
|
100
|
+
icon?: string;
|
|
101
|
+
description?: string;
|
|
102
|
+
metadata?: Record<string, any>;
|
|
103
|
+
}
|
|
104
|
+
export interface SuggestionGroup {
|
|
105
|
+
category: string;
|
|
106
|
+
suggestions: AiSuggestion[];
|
|
107
|
+
icon?: string;
|
|
108
|
+
}
|
|
109
|
+
export interface PageScanConfig {
|
|
110
|
+
enabled?: boolean;
|
|
111
|
+
autoScan?: boolean;
|
|
112
|
+
scanInterval?: number;
|
|
113
|
+
maxTextLength?: number;
|
|
114
|
+
excludeSelectors?: string[];
|
|
115
|
+
cacheDuration?: number;
|
|
116
|
+
mergeWithUserSuggestions?: boolean;
|
|
117
|
+
}
|
|
118
|
+
export interface AiSuggestionGeneratorConfig {
|
|
119
|
+
enabled?: boolean;
|
|
120
|
+
tier?: 'free' | 'premium';
|
|
121
|
+
backendUrl?: string;
|
|
122
|
+
apiKey?: string;
|
|
123
|
+
timeoutMs?: number;
|
|
124
|
+
}
|
|
125
|
+
export interface SuggestionConfig {
|
|
126
|
+
enabled: boolean;
|
|
127
|
+
suggestions?: AiSuggestion[];
|
|
128
|
+
categories?: SuggestionGroup[];
|
|
129
|
+
maxVisibleSuggestions?: number;
|
|
130
|
+
showOnFocus?: boolean;
|
|
131
|
+
showOnClick?: boolean;
|
|
132
|
+
customSuggestions?: (query: string) => Promise<AiSuggestion[]>;
|
|
133
|
+
autoGenerate?: boolean;
|
|
134
|
+
autoGenerateFreeTier?: boolean;
|
|
135
|
+
pageScanning?: PageScanConfig;
|
|
136
|
+
aiConfig?: AiSuggestionGeneratorConfig;
|
|
137
|
+
}
|
|
@@ -0,0 +1,166 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* AI Widget SDK - Core SDK
|
|
3
|
+
* Main orchestrator that ties everything together
|
|
4
|
+
*/
|
|
5
|
+
import { AiCommunicationService } from './communication-service';
|
|
6
|
+
import { ChatStateManager, ContextStateManager, ChartManager, SuggestionManager } from './state-manager';
|
|
7
|
+
import { AiContextConfig, AiMessage, AiSuggestion } from './models';
|
|
8
|
+
import { PageContentScanner, AiSuggestionGenerator } from './auto-suggestion-generator';
|
|
9
|
+
export declare class AiWidgetSDK {
|
|
10
|
+
private communicationService;
|
|
11
|
+
private chatStateManager;
|
|
12
|
+
private contextStateManager;
|
|
13
|
+
private chartManager;
|
|
14
|
+
private suggestionManager;
|
|
15
|
+
private pageContentScanner;
|
|
16
|
+
private suggestionGenerator;
|
|
17
|
+
private config;
|
|
18
|
+
private autoSuggestionInterval?;
|
|
19
|
+
constructor(config: AiContextConfig);
|
|
20
|
+
/**
|
|
21
|
+
* Initialize auto-suggestions based on page content
|
|
22
|
+
*/
|
|
23
|
+
initializeAutoSuggestions(): Promise<void>;
|
|
24
|
+
/**
|
|
25
|
+
* Validate configuration
|
|
26
|
+
*/
|
|
27
|
+
private validateConfig;
|
|
28
|
+
/**
|
|
29
|
+
* Set JWT token for authentication
|
|
30
|
+
*/
|
|
31
|
+
setJwtToken(token: string): void;
|
|
32
|
+
/**
|
|
33
|
+
* Send a query to the AI backend
|
|
34
|
+
*/
|
|
35
|
+
sendQuery(userQuery: string): Promise<AiMessage>;
|
|
36
|
+
/**
|
|
37
|
+
* Update context
|
|
38
|
+
*/
|
|
39
|
+
setContext(context: Partial<AiContextConfig['context']>): void;
|
|
40
|
+
/**
|
|
41
|
+
* Update single context property
|
|
42
|
+
*/
|
|
43
|
+
updateContextProperty(key: string, value: any): void;
|
|
44
|
+
/**
|
|
45
|
+
* Get current context
|
|
46
|
+
*/
|
|
47
|
+
getContext(): import("src").AiContext;
|
|
48
|
+
/**
|
|
49
|
+
* Clear chat history
|
|
50
|
+
*/
|
|
51
|
+
clearChatHistory(): void;
|
|
52
|
+
/**
|
|
53
|
+
* Get chat messages
|
|
54
|
+
*/
|
|
55
|
+
getMessages(): AiMessage[];
|
|
56
|
+
/**
|
|
57
|
+
* Get current error
|
|
58
|
+
*/
|
|
59
|
+
getError(): string | null;
|
|
60
|
+
/**
|
|
61
|
+
* Check if loading
|
|
62
|
+
*/
|
|
63
|
+
isLoading(): boolean;
|
|
64
|
+
/**
|
|
65
|
+
* Export chat history
|
|
66
|
+
*/
|
|
67
|
+
exportChats(format?: 'json' | 'csv'): string;
|
|
68
|
+
/**
|
|
69
|
+
* Export charts
|
|
70
|
+
*/
|
|
71
|
+
exportCharts(format?: 'json' | 'csv'): string;
|
|
72
|
+
/**
|
|
73
|
+
* Check backend health
|
|
74
|
+
*/
|
|
75
|
+
checkHealth(): Promise<boolean>;
|
|
76
|
+
/**
|
|
77
|
+
* Subscribe to message changes
|
|
78
|
+
*/
|
|
79
|
+
onMessagesChange(listener: (messages: AiMessage[]) => void): () => void;
|
|
80
|
+
/**
|
|
81
|
+
* Subscribe to loading changes
|
|
82
|
+
*/
|
|
83
|
+
onLoadingChange(listener: (isLoading: boolean) => void): () => void;
|
|
84
|
+
/**
|
|
85
|
+
* Subscribe to error changes
|
|
86
|
+
*/
|
|
87
|
+
onErrorChange(listener: (error: string | null) => void): () => void;
|
|
88
|
+
/**
|
|
89
|
+
* Subscribe to context changes
|
|
90
|
+
*/
|
|
91
|
+
onContextChange(listener: (context: any) => void): () => void;
|
|
92
|
+
/**
|
|
93
|
+
* Get all suggestions
|
|
94
|
+
*/
|
|
95
|
+
getSuggestions(): AiSuggestion[];
|
|
96
|
+
/**
|
|
97
|
+
* Filter suggestions based on query
|
|
98
|
+
*/
|
|
99
|
+
filterSuggestions(query: string): AiSuggestion[];
|
|
100
|
+
/**
|
|
101
|
+
* Get suggestions by category
|
|
102
|
+
*/
|
|
103
|
+
getSuggestionsByCategory(category: string): AiSuggestion[];
|
|
104
|
+
/**
|
|
105
|
+
* Add a suggestion
|
|
106
|
+
*/
|
|
107
|
+
addSuggestion(suggestion: AiSuggestion): void;
|
|
108
|
+
/**
|
|
109
|
+
* Add multiple suggestions
|
|
110
|
+
*/
|
|
111
|
+
addSuggestions(suggestions: AiSuggestion[]): void;
|
|
112
|
+
/**
|
|
113
|
+
* Remove a suggestion by id
|
|
114
|
+
*/
|
|
115
|
+
removeSuggestion(id: string): void;
|
|
116
|
+
/**
|
|
117
|
+
* Clear all suggestions
|
|
118
|
+
*/
|
|
119
|
+
clearSuggestions(): void;
|
|
120
|
+
/**
|
|
121
|
+
* Update suggestion
|
|
122
|
+
*/
|
|
123
|
+
updateSuggestion(id: string, updates: Partial<AiSuggestion>): void;
|
|
124
|
+
/**
|
|
125
|
+
* Subscribe to suggestion changes
|
|
126
|
+
*/
|
|
127
|
+
onSuggestionsChange(listener: (suggestions: AiSuggestion[]) => void): () => void;
|
|
128
|
+
/**
|
|
129
|
+
* Get suggestion manager for advanced use
|
|
130
|
+
*/
|
|
131
|
+
getSuggestionManager(): SuggestionManager;
|
|
132
|
+
/**
|
|
133
|
+
* Get internal services (for advanced use)
|
|
134
|
+
*/
|
|
135
|
+
getServices(): {
|
|
136
|
+
communication: AiCommunicationService;
|
|
137
|
+
chatState: ChatStateManager;
|
|
138
|
+
contextState: ContextStateManager;
|
|
139
|
+
charts: ChartManager;
|
|
140
|
+
suggestions: SuggestionManager;
|
|
141
|
+
};
|
|
142
|
+
/**
|
|
143
|
+
* Trigger manual page scan for auto-suggestions
|
|
144
|
+
*/
|
|
145
|
+
triggerAutoSuggestions(): Promise<void>;
|
|
146
|
+
/**
|
|
147
|
+
* Get page content scanner
|
|
148
|
+
*/
|
|
149
|
+
getPageContentScanner(): PageContentScanner;
|
|
150
|
+
/**
|
|
151
|
+
* Get suggestion generator
|
|
152
|
+
*/
|
|
153
|
+
getSuggestionGenerator(): AiSuggestionGenerator;
|
|
154
|
+
/**
|
|
155
|
+
* Stop auto-suggestion scanning
|
|
156
|
+
*/
|
|
157
|
+
stopAutoSuggestions(): void;
|
|
158
|
+
/**
|
|
159
|
+
* Private helper to generate unique IDs
|
|
160
|
+
*/
|
|
161
|
+
private generateId;
|
|
162
|
+
/**
|
|
163
|
+
* Private helper to extract error message
|
|
164
|
+
*/
|
|
165
|
+
private getErrorMessage;
|
|
166
|
+
}
|