@courseecho/ai-widget-react 1.0.24 → 1.0.25

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.
@@ -1,226 +0,0 @@
1
- import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
2
- /**
3
- * AI Chat Widget - React Component (Modern Redesign)
4
- * Usage: <AiChatWidget config={...} apiKey="..." />
5
- */
6
- import { useRef, useEffect, useState, useCallback } from 'react';
7
- import { useAiWidget } from './hooks';
8
- import { ShadowWrapper } from './ShadowWrapper';
9
- // Chat sound — Web Audio API (no external files)
10
- function playSound(type) {
11
- try {
12
- const AudioCtx = window.AudioContext || window.webkitAudioContext;
13
- if (!AudioCtx)
14
- return;
15
- const ctx = new AudioCtx();
16
- if (type === 'send') {
17
- const osc = ctx.createOscillator();
18
- const gain = ctx.createGain();
19
- osc.connect(gain);
20
- gain.connect(ctx.destination);
21
- osc.type = 'sine';
22
- osc.frequency.setValueAtTime(880, ctx.currentTime);
23
- osc.frequency.exponentialRampToValueAtTime(440, ctx.currentTime + 0.08);
24
- gain.gain.setValueAtTime(0.18, ctx.currentTime);
25
- gain.gain.exponentialRampToValueAtTime(0.0001, ctx.currentTime + 0.12);
26
- osc.start(ctx.currentTime);
27
- osc.stop(ctx.currentTime + 0.12);
28
- osc.onended = () => ctx.close();
29
- }
30
- else {
31
- const playTone = (freq, startTime, duration) => {
32
- const osc = ctx.createOscillator();
33
- const gain = ctx.createGain();
34
- osc.connect(gain);
35
- gain.connect(ctx.destination);
36
- osc.type = 'sine';
37
- osc.frequency.setValueAtTime(freq, startTime);
38
- gain.gain.setValueAtTime(0.0001, startTime);
39
- gain.gain.linearRampToValueAtTime(0.22, startTime + 0.02);
40
- gain.gain.exponentialRampToValueAtTime(0.0001, startTime + duration);
41
- osc.start(startTime);
42
- osc.stop(startTime + duration);
43
- };
44
- playTone(880, ctx.currentTime, 0.18);
45
- playTone(1100, ctx.currentTime + 0.13, 0.22);
46
- setTimeout(() => ctx.close(), 500);
47
- }
48
- }
49
- catch (_) { /* silently ignore audio errors */ }
50
- }
51
- // Lightweight markdown renderer (no external deps)
52
- function renderMarkdown(text) {
53
- const lines = text.split('\n');
54
- const nodes = [];
55
- let olItems = [];
56
- let ulItems = [];
57
- let key = 0;
58
- const inlineFormat = (s) => s.replace(/&/g, '&amp;').replace(/</g, '&lt;').replace(/>/g, '&gt;')
59
- .replace(/\*\*(.+?)\*\*/g, '<strong>$1</strong>')
60
- .replace(/\*(.+?)\*/g, '<em>$1</em>')
61
- .replace(/`(.+?)`/g, '<code>$1</code>');
62
- const flushLists = () => {
63
- if (olItems.length) {
64
- nodes.push(_jsx("ol", { children: olItems.map((t, i) => _jsx("li", { dangerouslySetInnerHTML: { __html: inlineFormat(t) } }, i)) }, key++));
65
- olItems = [];
66
- }
67
- if (ulItems.length) {
68
- nodes.push(_jsx("ul", { children: ulItems.map((t, i) => _jsx("li", { dangerouslySetInnerHTML: { __html: inlineFormat(t) } }, i)) }, key++));
69
- ulItems = [];
70
- }
71
- };
72
- lines.forEach((line) => {
73
- const olMatch = line.match(/^\d+\.\s+(.*)/);
74
- const ulMatch = line.match(/^[-*]\s+(.*)/);
75
- const h3Match = line.match(/^###\s+(.*)/);
76
- const h2Match = line.match(/^##\s+(.*)/);
77
- if (h3Match || h2Match) {
78
- flushLists();
79
- const content = (h3Match || h2Match)[1];
80
- nodes.push(h3Match
81
- ? _jsx("h4", { dangerouslySetInnerHTML: { __html: inlineFormat(content) } }, key++)
82
- : _jsx("h3", { dangerouslySetInnerHTML: { __html: inlineFormat(content) } }, key++));
83
- }
84
- else if (olMatch) {
85
- if (ulItems.length)
86
- flushLists();
87
- olItems.push(olMatch[1]);
88
- }
89
- else if (ulMatch) {
90
- if (olItems.length)
91
- flushLists();
92
- ulItems.push(ulMatch[1]);
93
- }
94
- else if (line.trim() === '') {
95
- flushLists();
96
- nodes.push(_jsx("br", {}, key++));
97
- }
98
- else {
99
- flushLists();
100
- nodes.push(_jsx("p", { dangerouslySetInnerHTML: { __html: inlineFormat(line) } }, key++));
101
- }
102
- });
103
- flushLists();
104
- return nodes;
105
- }
106
- function autoDetectPageContext() {
107
- if (typeof document === 'undefined')
108
- return {};
109
- const get = (attr) => document.querySelector(`[data-${attr}]`)?.getAttribute(`data-${attr}`) ||
110
- document.querySelector(`meta[name="${attr}"]`)?.getAttribute('content') || null;
111
- let pageType = get('page-type') || get('pagetype');
112
- let entityId = get('entity-id') || get('entityid');
113
- if (!pageType) {
114
- const seg = window.location.pathname.replace(/\/+$/, '').split('/').filter(Boolean);
115
- const known = { course: 'course', courses: 'course', lesson: 'lesson', blog: 'blog', product: 'product', checkout: 'checkout', dashboard: 'dashboard', docs: 'documentation', doc: 'documentation' };
116
- for (const s of seg) {
117
- if (known[s]) {
118
- pageType = known[s];
119
- break;
120
- }
121
- }
122
- }
123
- if (!entityId) {
124
- const p = new URLSearchParams(window.location.search);
125
- entityId = p.get('id') || p.get('courseId') || p.get('productId') || null;
126
- }
127
- return { pageType: pageType || undefined, entityId: entityId || undefined };
128
- }
129
- const DEFAULT_SUGGESTIONS = [
130
- { id: 'd1', text: 'What can you do for me?', icon: '', category: 'Getting started', description: 'Learn about my capabilities' },
131
- { id: 'd2', text: 'How do I get started?', icon: '', category: 'Getting started', description: 'Quick onboarding guide' },
132
- { id: 'd3', text: 'Show me the documentation', icon: '', category: 'Resources', description: 'Browse guides' },
133
- { id: 'd4', text: 'I need help with a problem', icon: '', category: 'Support', description: 'Troubleshoot an issue' },
134
- { id: 'd5', text: 'What are the pricing options?', icon: '', category: 'Billing', description: 'Plans and pricing' },
135
- { id: 'd6', text: 'Contact support team', icon: '', category: 'Support', description: 'Talk to a human' },
136
- ];
137
- export const AiChatWidget = ({ config, apiKey, jwtToken, title = 'AI Assistant', subtitle = 'Online Ready to help', placeholder = 'Type a message', poweredBy, poweredByUrl = 'https://courseecho.com', onError, onMessageReceived, className, defaultMinimized = false, expandedHeight = '580px', }) => {
138
- const [mergedConfig] = useState(() => {
139
- const auto = autoDetectPageContext();
140
- return { ...config, context: { ...auto, ...config.context } };
141
- });
142
- const { messages, isLoading, error, sendQuery, initialized, suggestions } = useAiWidget(mergedConfig, jwtToken);
143
- const [isMinimized, setIsMinimized] = useState(defaultMinimized);
144
- const [userInput, setUserInput] = useState('');
145
- const [showSuggestions, setShowSuggestions] = useState(false);
146
- const [filteredSugs, setFilteredSugs] = useState([]);
147
- const [activeIdx, setActiveIdx] = useState(-1);
148
- const [chipsVisible, setChipsVisible] = useState(true);
149
- const messagesEndRef = useRef(null);
150
- const inputRef = useRef(null);
151
- const allSugs = (suggestions && suggestions.length > 0) ? suggestions : DEFAULT_SUGGESTIONS;
152
- useEffect(() => { messagesEndRef.current?.scrollIntoView({ behavior: 'smooth' }); }, [messages]);
153
- useEffect(() => {
154
- if (messages.length > 0) {
155
- const last = messages[messages.length - 1];
156
- if (last.role === 'assistant') {
157
- playSound('receive');
158
- if (onMessageReceived)
159
- onMessageReceived(last);
160
- }
161
- }
162
- }, [messages, onMessageReceived]);
163
- useEffect(() => { if (error && onError)
164
- onError(error); }, [error, onError]);
165
- const filterSugs = (q) => {
166
- const lq = q.toLowerCase();
167
- const filtered = q.trim()
168
- ? allSugs.filter(s => s.text.toLowerCase().includes(lq) || s.category?.toLowerCase().includes(lq) || s.description?.toLowerCase().includes(lq))
169
- : allSugs;
170
- setFilteredSugs(filtered.slice(0, 6));
171
- setShowSuggestions(true);
172
- setActiveIdx(-1);
173
- };
174
- const doSend = useCallback(async (text) => {
175
- if (!text.trim() || isLoading)
176
- return;
177
- setUserInput('');
178
- setShowSuggestions(false);
179
- setChipsVisible(false);
180
- if (inputRef.current)
181
- inputRef.current.style.height = 'auto';
182
- playSound('send');
183
- await sendQuery(text);
184
- // eslint-disable-next-line react-hooks/exhaustive-deps
185
- }, [isLoading, sendQuery]);
186
- const selectSuggestion = (text) => doSend(text);
187
- const handleInputChange = (e) => {
188
- const val = e.target.value;
189
- setUserInput(val);
190
- const el = e.target;
191
- el.style.height = 'auto';
192
- el.style.height = Math.min(el.scrollHeight, 120) + 'px';
193
- filterSugs(val);
194
- };
195
- const handleKeyDown = (e) => {
196
- if (e.key === 'ArrowDown') {
197
- e.preventDefault();
198
- setActiveIdx(i => Math.min(i + 1, filteredSugs.length - 1));
199
- }
200
- else if (e.key === 'ArrowUp') {
201
- e.preventDefault();
202
- setActiveIdx(i => Math.max(i - 1, 0));
203
- }
204
- else if (e.key === 'Enter' && !e.shiftKey) {
205
- e.preventDefault();
206
- if (showSuggestions && activeIdx >= 0)
207
- selectSuggestion(filteredSugs[activeIdx].text);
208
- else
209
- doSend(userInput);
210
- }
211
- else if (e.key === 'Escape') {
212
- setShowSuggestions(false);
213
- }
214
- };
215
- if (!initialized)
216
- return _jsx(ShadowWrapper, { children: _jsx("div", { className: "aiwg-root", style: { padding: 20, textAlign: 'center' }, children: "Initializing" }) });
217
- const themeClass = mergedConfig.theme === 'dark' ? 'aiwg-dark' : '';
218
- const minimizedClass = isMinimized ? 'aiwg-minimized' : '';
219
- const poweredByLabel = poweredBy || 'CourseEcho.com';
220
- return (_jsx(ShadowWrapper, { children: _jsxs("div", { className: `aiwg-root ${themeClass} ${minimizedClass} ${className || ''}`, style: { height: isMinimized ? '72px' : expandedHeight }, children: [_jsxs("div", { className: "aiwg-header", onClick: () => isMinimized && setIsMinimized(false), children: [_jsx("div", { className: "aiwg-avatar" }), _jsxs("div", { className: "aiwg-header-info", children: [_jsx("div", { className: "aiwg-title", children: title }), _jsxs("div", { className: "aiwg-subtitle", children: [_jsx("span", { className: "aiwg-online-dot" }), subtitle] })] }), _jsx("button", { className: "aiwg-minimize-btn", "aria-label": "Minimize", onClick: (e) => { e.stopPropagation(); setIsMinimized(true); }, children: "\u2715" })] }), _jsxs("div", { className: "aiwg-messages", children: [messages.length === 0 && (_jsxs("div", { className: "aiwg-welcome", children: [_jsx("div", { className: "aiwg-welcome-icon" }), _jsx("h4", { children: "Hi there! I'm your AI assistant." }), _jsx("p", { children: "Ask me anything or pick a suggestion below." })] })), messages.map((msg) => {
221
- const isUser = msg.role === 'user';
222
- const time = new Date(msg.timestamp).toLocaleTimeString([], { hour: '2-digit', minute: '2-digit' });
223
- return (_jsxs("div", { className: `aiwg-msg ${isUser ? 'aiwg-msg--user' : 'aiwg-msg--bot'}`, children: [_jsx("div", { className: "aiwg-msg-avatar", children: isUser ? '' : '' }), _jsxs("div", { className: "aiwg-msg-body", children: [_jsx("div", { className: "aiwg-msg-bubble", children: isUser ? msg.content : renderMarkdown(msg.content) }), _jsx("div", { className: "aiwg-msg-time", children: time })] })] }, msg.id));
224
- }), isLoading && (_jsxs("div", { className: "aiwg-msg aiwg-msg--bot", children: [_jsx("div", { className: "aiwg-msg-avatar" }), _jsx("div", { className: "aiwg-msg-body", children: _jsx("div", { className: "aiwg-msg-bubble aiwg-typing", children: _jsxs("div", { className: "aiwg-typing-dots", children: [_jsx("span", {}), _jsx("span", {}), _jsx("span", {})] }) }) })] })), error && _jsxs("div", { className: "aiwg-error", style: { display: 'block' }, children: [" ", error] }), _jsx("div", { ref: messagesEndRef })] }), chipsVisible && messages.length === 0 && (_jsx("div", { className: "aiwg-chip-row", children: allSugs.slice(0, 4).map(s => (_jsxs("button", { className: "aiwg-chip", onClick: () => selectSuggestion(s.text), children: [s.icon, " ", s.text] }, s.id))) })), _jsxs("div", { className: "aiwg-input-area", children: [showSuggestions && filteredSugs.length > 0 && (_jsxs("div", { className: "aiwg-suggestions", children: [_jsx("div", { className: "aiwg-suggestions-header", children: "Suggestions" }), _jsx("div", { className: "aiwg-suggestions-list", children: filteredSugs.map((s, i) => (_jsxs("div", { className: `aiwg-suggestion-item${i === activeIdx ? ' aiwg-active' : ''}`, onMouseEnter: () => setActiveIdx(i), onClick: () => selectSuggestion(s.text), children: [s.icon && _jsx("span", { className: "aiwg-suggestion-icon", children: s.icon }), _jsxs("div", { className: "aiwg-suggestion-main", children: [_jsx("div", { className: "aiwg-suggestion-text", children: s.text }), s.description && _jsx("div", { className: "aiwg-suggestion-desc", children: s.description })] }), s.category && _jsx("span", { className: "aiwg-suggestion-badge", children: s.category })] }, s.id))) }), _jsxs("div", { className: "aiwg-kbd-hint", children: [_jsxs("span", { children: [_jsx("kbd", {}), " navigate"] }), _jsxs("span", { children: [_jsx("kbd", {}), " select"] }), _jsxs("span", { children: [_jsx("kbd", { children: "Esc" }), " close"] })] })] })), _jsxs("div", { className: "aiwg-input-row", children: [_jsx("textarea", { ref: inputRef, className: "aiwg-input", placeholder: placeholder, value: userInput, rows: 1, onChange: handleInputChange, onFocus: () => filterSugs(userInput), onKeyDown: handleKeyDown, disabled: isLoading, "aria-label": "Chat message input" }), _jsx("button", { className: "aiwg-send-btn", type: "button", disabled: isLoading || !userInput.trim(), onClick: () => doSend(userInput), "aria-label": "Send", children: _jsxs("svg", { viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "2.5", strokeLinecap: "round", strokeLinejoin: "round", children: [_jsx("line", { x1: "22", y1: "2", x2: "11", y2: "13" }), _jsx("polygon", { points: "22 2 15 22 11 13 2 9 22 2" })] }) })] })] }), _jsxs("div", { className: "aiwg-powered", children: ["Powered by", ' ', _jsx("a", { href: poweredByUrl, target: "_blank", rel: "noopener noreferrer", children: poweredByLabel })] })] }) }));
225
- };
226
- export default AiChatWidget;
@@ -1,64 +0,0 @@
1
- /**
2
- * AI Widget React - Custom Hooks
3
- * useAiChat, useAiContext, useAiMessages
4
- */
5
- import { AiWidgetSDK, AiContextConfig, AiMessage, AiContext, AiSuggestion } from '@courseecho/ai-core-sdk';
6
- /**
7
- * Hook to initialize and use the AI SDK
8
- * @param config Configuration for the SDK
9
- * @param jwtToken Optional JWT token for authentication
10
- * @returns SDK instance and utility functions
11
- */
12
- export declare function useAiChat(config: AiContextConfig, jwtToken?: string): {
13
- sdk: AiWidgetSDK;
14
- sendQuery: (query: string) => Promise<AiMessage>;
15
- setJwt: (token: string) => void;
16
- checkHealth: () => Promise<boolean>;
17
- exportChats: (format?: "json" | "csv") => string;
18
- initialized: boolean;
19
- error: string | null;
20
- };
21
- /**
22
- * Hook to subscribe to messages
23
- */
24
- export declare function useAiMessages(sdk: AiWidgetSDK): AiMessage[];
25
- /**
26
- * Hook to subscribe to loading state
27
- */
28
- export declare function useAiLoading(sdk: AiWidgetSDK): boolean;
29
- /**
30
- * Hook to subscribe to error state
31
- */
32
- export declare function useAiError(sdk: AiWidgetSDK): string | null;
33
- /**
34
- * Hook to manage context
35
- */
36
- export declare function useAiContext(sdk: AiWidgetSDK): {
37
- context: AiContext;
38
- updateContext: (newContext: Partial<AiContext>) => void;
39
- updateContextProperty: (key: string, value: any) => void;
40
- };
41
- /**
42
- * Hook to subscribe to suggestions
43
- */
44
- export declare function useAiSuggestions(sdk: AiWidgetSDK): {
45
- suggestions: AiSuggestion[];
46
- filterSuggestions: (query: string) => AiSuggestion[];
47
- };
48
- /**
49
- * Combined hook for common use cases
50
- */
51
- export declare function useAiWidget(config: AiContextConfig, jwtToken?: string): {
52
- sdk: AiWidgetSDK;
53
- messages: AiMessage[];
54
- isLoading: boolean;
55
- error: string | null;
56
- context: AiContext;
57
- sendQuery: (query: string) => Promise<AiMessage>;
58
- updateContext: (newContext: Partial<AiContext>) => void;
59
- updateContextProperty: (key: string, value: any) => void;
60
- initialized: boolean;
61
- initError: string | null;
62
- suggestions: AiSuggestion[];
63
- filterSuggestions: (query: string) => AiSuggestion[];
64
- };
@@ -1,181 +0,0 @@
1
- /**
2
- * AI Widget React - Custom Hooks
3
- * useAiChat, useAiContext, useAiMessages
4
- */
5
- import { useEffect, useState, useRef, useCallback } from 'react';
6
- import { AiWidgetSDK, } from '@courseecho/ai-core-sdk';
7
- /**
8
- * Hook to initialize and use the AI SDK
9
- * @param config Configuration for the SDK
10
- * @param jwtToken Optional JWT token for authentication
11
- * @returns SDK instance and utility functions
12
- */
13
- export function useAiChat(config, jwtToken) {
14
- // Initialize synchronously on first render so the SDK is never null.
15
- const sdkRef = useRef(null);
16
- if (sdkRef.current === null) {
17
- sdkRef.current = new AiWidgetSDK(config);
18
- }
19
- const [initialized, setInitialized] = useState(false);
20
- const [error, setError] = useState(null);
21
- // Apply JWT and side-effects after mount / when token changes.
22
- useEffect(() => {
23
- const sdk = sdkRef.current;
24
- try {
25
- if (jwtToken) {
26
- sdk.setJwtToken(jwtToken);
27
- }
28
- // Initialize auto-suggestions if enabled
29
- if (config.suggestionConfig?.autoGenerate !== false) {
30
- sdk.initializeAutoSuggestions().catch((err) => {
31
- console.warn('Auto-suggestions initialization failed:', err);
32
- });
33
- }
34
- setInitialized(true);
35
- }
36
- catch (err) {
37
- setError(String(err));
38
- }
39
- // eslint-disable-next-line react-hooks/exhaustive-deps
40
- }, [jwtToken]);
41
- const sdk = sdkRef.current;
42
- const sendQuery = useCallback(async (query) => {
43
- if (!sdk)
44
- throw new Error('SDK not initialized');
45
- try {
46
- setError(null);
47
- return await sdk.sendQuery(query);
48
- }
49
- catch (err) {
50
- setError(String(err));
51
- throw err;
52
- }
53
- }, [sdk]);
54
- const setJwt = useCallback((token) => {
55
- if (!sdk)
56
- throw new Error('SDK not initialized');
57
- sdk.setJwtToken(token);
58
- }, [sdk]);
59
- const checkHealth = useCallback(async () => {
60
- if (!sdk)
61
- throw new Error('SDK not initialized');
62
- return sdk.checkHealth();
63
- }, [sdk]);
64
- const exportChats = useCallback((format = 'json') => {
65
- if (!sdk)
66
- throw new Error('SDK not initialized');
67
- return sdk.exportChats(format);
68
- }, [sdk]);
69
- return {
70
- sdk,
71
- sendQuery,
72
- setJwt,
73
- checkHealth,
74
- exportChats,
75
- initialized,
76
- error,
77
- };
78
- }
79
- /**
80
- * Hook to subscribe to messages
81
- */
82
- export function useAiMessages(sdk) {
83
- const [messages, setMessages] = useState(() => sdk.getMessages());
84
- useEffect(() => {
85
- const unsubscribe = sdk.onMessagesChange((msgs) => {
86
- setMessages([...msgs]);
87
- });
88
- return unsubscribe;
89
- }, [sdk]);
90
- return messages;
91
- }
92
- /**
93
- * Hook to subscribe to loading state
94
- */
95
- export function useAiLoading(sdk) {
96
- const [isLoading, setIsLoading] = useState(() => sdk.isLoading());
97
- useEffect(() => {
98
- const unsubscribe = sdk.onLoadingChange((loading) => {
99
- setIsLoading(loading);
100
- });
101
- return unsubscribe;
102
- }, [sdk]);
103
- return isLoading;
104
- }
105
- /**
106
- * Hook to subscribe to error state
107
- */
108
- export function useAiError(sdk) {
109
- const [error, setError] = useState(() => sdk.getError());
110
- useEffect(() => {
111
- const unsubscribe = sdk.onErrorChange((err) => {
112
- setError(err);
113
- });
114
- return unsubscribe;
115
- }, [sdk]);
116
- return error;
117
- }
118
- /**
119
- * Hook to manage context
120
- */
121
- export function useAiContext(sdk) {
122
- const [context, setContext] = useState(() => sdk.getContext());
123
- useEffect(() => {
124
- const unsubscribe = sdk.onContextChange((ctx) => {
125
- setContext({ ...ctx });
126
- });
127
- return unsubscribe;
128
- }, [sdk]);
129
- const updateContext = useCallback((newContext) => {
130
- sdk.setContext(newContext);
131
- }, [sdk]);
132
- const updateContextProperty = useCallback((key, value) => {
133
- sdk.updateContextProperty(key, value);
134
- }, [sdk]);
135
- return {
136
- context,
137
- updateContext,
138
- updateContextProperty,
139
- };
140
- }
141
- /**
142
- * Hook to subscribe to suggestions
143
- */
144
- export function useAiSuggestions(sdk) {
145
- const [suggestions, setSuggestions] = useState(() => sdk.getSuggestions());
146
- useEffect(() => {
147
- const unsubscribe = sdk.onSuggestionsChange((sugg) => {
148
- setSuggestions([...sugg]);
149
- });
150
- return unsubscribe;
151
- }, [sdk]);
152
- const filterSuggestions = useCallback((query) => {
153
- return sdk.filterSuggestions(query);
154
- }, [sdk]);
155
- return { suggestions, filterSuggestions };
156
- }
157
- /**
158
- * Combined hook for common use cases
159
- */
160
- export function useAiWidget(config, jwtToken) {
161
- const { sdk, sendQuery, initialized, error: initError } = useAiChat(config, jwtToken);
162
- const messages = useAiMessages(sdk);
163
- const isLoading = useAiLoading(sdk);
164
- const error = useAiError(sdk);
165
- const { context, updateContext, updateContextProperty } = useAiContext(sdk);
166
- const { suggestions, filterSuggestions } = useAiSuggestions(sdk);
167
- return {
168
- sdk,
169
- messages,
170
- isLoading,
171
- error,
172
- context,
173
- sendQuery,
174
- updateContext,
175
- updateContextProperty,
176
- initialized,
177
- initError,
178
- suggestions,
179
- filterSuggestions,
180
- };
181
- }
@@ -1,7 +0,0 @@
1
- /**
2
- * AI Widget React - Public API
3
- */
4
- export { AiChatWidget } from './components';
5
- export type { AiChatWidgetProps } from './components';
6
- export { useAiChat, useAiMessages, useAiLoading, useAiError, useAiContext, useAiWidget, } from './hooks';
7
- export type { AiContextConfig, AiContext, AiMessage, AiChart, AiQueryResponse, } from '@courseecho/ai-core-sdk';
@@ -1,5 +0,0 @@
1
- /**
2
- * AI Widget React - Public API
3
- */
4
- export { AiChatWidget } from './components';
5
- export { useAiChat, useAiMessages, useAiLoading, useAiError, useAiContext, useAiWidget, } from './hooks';