@digilogiclabs/create-saas-app 1.17.1 → 1.18.0

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.
Files changed (45) hide show
  1. package/CHANGELOG.md +51 -0
  2. package/dist/.tsbuildinfo +1 -1
  3. package/dist/cli/commands/create.d.ts.map +1 -1
  4. package/dist/cli/commands/create.js +6 -2
  5. package/dist/cli/commands/create.js.map +1 -1
  6. package/dist/cli/index.js +1 -1
  7. package/dist/cli/index.js.map +1 -1
  8. package/dist/generators/template-generator.d.ts.map +1 -1
  9. package/dist/generators/template-generator.js +13 -7
  10. package/dist/generators/template-generator.js.map +1 -1
  11. package/dist/templates/mobile/ui-auth-payments-ai-rag/template/README.md +655 -0
  12. package/dist/templates/mobile/ui-auth-payments-ai-rag/template/app/(tabs)/ai.tsx +683 -0
  13. package/dist/templates/mobile/ui-auth-payments-ai-rag/template/docs/MOBILE-SETUP.md +787 -0
  14. package/dist/templates/mobile/ui-auth-payments-ai-rag/template/hooks/useRAGSystem.ts +346 -0
  15. package/dist/templates/mobile/ui-auth-payments-ai-rag/template/lib/rag/config.ts +180 -0
  16. package/dist/templates/mobile/ui-auth-payments-ai-rag/template/package.json +113 -0
  17. package/dist/templates/mobile/ui-auth-payments-ai-rag/template/scripts/setup-rag.js +599 -0
  18. package/dist/templates/web/ui-auth-payments-ai-rag/template/README.md +434 -0
  19. package/dist/templates/web/ui-auth-payments-ai-rag/template/components/rag/KnowledgeManager.tsx +642 -0
  20. package/dist/templates/web/ui-auth-payments-ai-rag/template/components/rag/RAGAnalytics.tsx +466 -0
  21. package/dist/templates/web/ui-auth-payments-ai-rag/template/components/rag/RAGChatInterface.tsx +393 -0
  22. package/dist/templates/web/ui-auth-payments-ai-rag/template/docs/GETTING-STARTED.md +457 -0
  23. package/dist/templates/web/ui-auth-payments-ai-rag/template/hooks/useRAGSystem.ts +478 -0
  24. package/dist/templates/web/ui-auth-payments-ai-rag/template/lib/rag/config.ts +250 -0
  25. package/dist/templates/web/ui-auth-payments-ai-rag/template/package.json +74 -0
  26. package/dist/templates/web/ui-auth-payments-ai-rag/template/scripts/setup-rag.js +622 -0
  27. package/dist/templates/web/ui-auth-payments-ai-rag/template/src/app/ai/page.tsx +396 -0
  28. package/package.json +1 -1
  29. package/src/templates/mobile/ui-auth-payments-ai-rag/template/README.md +655 -0
  30. package/src/templates/mobile/ui-auth-payments-ai-rag/template/app/(tabs)/ai.tsx +683 -0
  31. package/src/templates/mobile/ui-auth-payments-ai-rag/template/docs/MOBILE-SETUP.md +787 -0
  32. package/src/templates/mobile/ui-auth-payments-ai-rag/template/hooks/useRAGSystem.ts +346 -0
  33. package/src/templates/mobile/ui-auth-payments-ai-rag/template/lib/rag/config.ts +180 -0
  34. package/src/templates/mobile/ui-auth-payments-ai-rag/template/package.json +113 -0
  35. package/src/templates/mobile/ui-auth-payments-ai-rag/template/scripts/setup-rag.js +599 -0
  36. package/src/templates/web/ui-auth-payments-ai-rag/template/README.md +434 -0
  37. package/src/templates/web/ui-auth-payments-ai-rag/template/components/rag/KnowledgeManager.tsx +642 -0
  38. package/src/templates/web/ui-auth-payments-ai-rag/template/components/rag/RAGAnalytics.tsx +466 -0
  39. package/src/templates/web/ui-auth-payments-ai-rag/template/components/rag/RAGChatInterface.tsx +393 -0
  40. package/src/templates/web/ui-auth-payments-ai-rag/template/docs/GETTING-STARTED.md +457 -0
  41. package/src/templates/web/ui-auth-payments-ai-rag/template/hooks/useRAGSystem.ts +478 -0
  42. package/src/templates/web/ui-auth-payments-ai-rag/template/lib/rag/config.ts +250 -0
  43. package/src/templates/web/ui-auth-payments-ai-rag/template/package.json +74 -0
  44. package/src/templates/web/ui-auth-payments-ai-rag/template/scripts/setup-rag.js +622 -0
  45. package/src/templates/web/ui-auth-payments-ai-rag/template/src/app/ai/page.tsx +396 -0
@@ -0,0 +1,478 @@
1
+ 'use client'
2
+
3
+ import { useState, useEffect, useCallback, useRef, useMemo } from 'react';
4
+ import { RAGSystem } from '@digilogiclabs/saas-factory-ai';
5
+ import type {
6
+ RAGQuery,
7
+ RAGResponse,
8
+ RAGDocument,
9
+ RAGSearchResult,
10
+ RAGDocumentSchema
11
+ } from '@digilogiclabs/saas-factory-ai-types';
12
+ import { getRAGConfigForDomain, webRAGOptions } from '../lib/rag/config';
13
+ import { toast } from 'sonner';
14
+
15
+ interface UseRAGSystemOptions {
16
+ domain?: string;
17
+ enableStreaming?: boolean;
18
+ enableCache?: boolean;
19
+ autoInitialize?: boolean;
20
+ }
21
+
22
+ interface RAGState {
23
+ isInitialized: boolean;
24
+ isLoading: boolean;
25
+ isStreaming: boolean;
26
+ lastSyncAt: Date | null;
27
+ totalQueries: number;
28
+ totalDocuments: number;
29
+ error: string | null;
30
+ health: 'healthy' | 'degraded' | 'down';
31
+ }
32
+
33
+ interface StreamingState {
34
+ isStreaming: boolean;
35
+ currentResponse: string;
36
+ sources: RAGSearchResult[];
37
+ confidence: number;
38
+ }
39
+
40
+ export function useRAGSystem<TSchema extends RAGDocumentSchema>(
41
+ options: UseRAGSystemOptions = {}
42
+ ) {
43
+ const {
44
+ domain = 'generic',
45
+ enableStreaming = true,
46
+ enableCache = true,
47
+ autoInitialize = true
48
+ } = options;
49
+
50
+ const [ragSystem, setRAGSystem] = useState<RAGSystem<TSchema> | null>(null);
51
+ const [state, setState] = useState<RAGState>({
52
+ isInitialized: false,
53
+ isLoading: false,
54
+ isStreaming: false,
55
+ lastSyncAt: null,
56
+ totalQueries: 0,
57
+ totalDocuments: 0,
58
+ error: null,
59
+ health: 'down'
60
+ });
61
+
62
+ const [streamingState, setStreamingState] = useState<StreamingState>({
63
+ isStreaming: false,
64
+ currentResponse: '',
65
+ sources: [],
66
+ confidence: 0
67
+ });
68
+
69
+ const [queryHistory, setQueryHistory] = useState<RAGQuery[]>([]);
70
+ const [responseCache, setResponseCache] = useState<Map<string, RAGResponse>>(new Map());
71
+
72
+ const abortControllerRef = useRef<AbortController | null>(null);
73
+ const statsRef = useRef({ queries: 0, documents: 0, lastSync: null as Date | null });
74
+
75
+ // Memoized configuration
76
+ const ragConfig = useMemo(() => getRAGConfigForDomain(domain), [domain]);
77
+
78
+ // Initialize RAG system
79
+ useEffect(() => {
80
+ if (!autoInitialize) return;
81
+
82
+ const initRAG = async () => {
83
+ try {
84
+ setState(prev => ({ ...prev, isLoading: true, error: null }));
85
+
86
+ const system = new RAGSystem<TSchema>(ragConfig);
87
+ await system.initialize();
88
+
89
+ setRAGSystem(system);
90
+
91
+ // Load initial stats
92
+ const stats = await system.getStats();
93
+ statsRef.current = {
94
+ queries: stats.totalQueries || 0,
95
+ documents: stats.totalDocuments || 0,
96
+ lastSync: stats.lastSync ? new Date(stats.lastSync) : null
97
+ };
98
+
99
+ setState(prev => ({
100
+ ...prev,
101
+ isInitialized: true,
102
+ isLoading: false,
103
+ totalQueries: statsRef.current.queries,
104
+ totalDocuments: statsRef.current.documents,
105
+ lastSyncAt: statsRef.current.lastSync,
106
+ health: 'healthy'
107
+ }));
108
+
109
+ toast.success('AI Knowledge System initialized');
110
+
111
+ } catch (error) {
112
+ console.error('RAG initialization error:', error);
113
+ const errorMessage = error instanceof Error ? error.message : 'Initialization failed';
114
+
115
+ setState(prev => ({
116
+ ...prev,
117
+ error: errorMessage,
118
+ isLoading: false,
119
+ health: 'down'
120
+ }));
121
+
122
+ toast.error(`Failed to initialize AI system: ${errorMessage}`);
123
+ }
124
+ };
125
+
126
+ initRAG();
127
+ }, [ragConfig, autoInitialize]);
128
+
129
+ // Cleanup on unmount
130
+ useEffect(() => {
131
+ return () => {
132
+ if (abortControllerRef.current) {
133
+ abortControllerRef.current.abort();
134
+ }
135
+ };
136
+ }, []);
137
+
138
+ // Query function with streaming support
139
+ const query = useCallback(async (
140
+ queryText: string,
141
+ options?: {
142
+ category?: string;
143
+ maxResults?: number;
144
+ includeMetadata?: boolean;
145
+ stream?: boolean;
146
+ }
147
+ ): Promise<RAGResponse> => {
148
+ if (!ragSystem) {
149
+ throw new Error('RAG system not initialized');
150
+ }
151
+
152
+ // Cancel any ongoing request
153
+ if (abortControllerRef.current) {
154
+ abortControllerRef.current.abort();
155
+ }
156
+
157
+ abortControllerRef.current = new AbortController();
158
+
159
+ const ragQuery: RAGQuery = {
160
+ query: queryText,
161
+ category: options?.category,
162
+ maxResults: options?.maxResults || 6,
163
+ includeMetadata: options?.includeMetadata ?? true,
164
+ timestamp: new Date()
165
+ };
166
+
167
+ const cacheKey = getCacheKey(ragQuery);
168
+ const shouldStream = enableStreaming && (options?.stream !== false);
169
+
170
+ // Check cache first
171
+ if (enableCache && responseCache.has(cacheKey)) {
172
+ const cached = responseCache.get(cacheKey)!;
173
+ toast.success('Retrieved from cache');
174
+ return { ...cached, fromCache: true };
175
+ }
176
+
177
+ try {
178
+ setState(prev => ({ ...prev, isLoading: true, error: null }));
179
+
180
+ if (shouldStream) {
181
+ // Initialize streaming state
182
+ setStreamingState({
183
+ isStreaming: true,
184
+ currentResponse: '',
185
+ sources: [],
186
+ confidence: 0
187
+ });
188
+
189
+ // Handle streaming response
190
+ const response = await ragSystem.queryStream(
191
+ ragQuery,
192
+ {
193
+ onChunk: (chunk) => {
194
+ setStreamingState(prev => ({
195
+ ...prev,
196
+ currentResponse: prev.currentResponse + chunk.text,
197
+ confidence: chunk.confidence || prev.confidence
198
+ }));
199
+ },
200
+ onSources: (sources) => {
201
+ setStreamingState(prev => ({
202
+ ...prev,
203
+ sources
204
+ }));
205
+ },
206
+ signal: abortControllerRef.current?.signal
207
+ }
208
+ );
209
+
210
+ // Finalize streaming
211
+ setStreamingState(prev => ({ ...prev, isStreaming: false }));
212
+
213
+ return response;
214
+
215
+ } else {
216
+ // Regular non-streaming query
217
+ const response = await ragSystem.query(ragQuery, {
218
+ signal: abortControllerRef.current?.signal
219
+ });
220
+
221
+ // Cache successful responses
222
+ if (enableCache && response.confidence > 0.6) {
223
+ const newCache = new Map(responseCache);
224
+ newCache.set(cacheKey, response);
225
+
226
+ // Limit cache size
227
+ if (newCache.size > 100) {
228
+ const firstKey = newCache.keys().next().value;
229
+ newCache.delete(firstKey);
230
+ }
231
+
232
+ setResponseCache(newCache);
233
+ }
234
+
235
+ return response;
236
+ }
237
+
238
+ } catch (error: any) {
239
+ if (error.name === 'AbortError') {
240
+ throw new Error('Query cancelled');
241
+ }
242
+
243
+ setState(prev => ({ ...prev, error: error.message, health: 'degraded' }));
244
+ toast.error(`Query failed: ${error.message}`);
245
+ throw error;
246
+
247
+ } finally {
248
+ setState(prev => ({
249
+ ...prev,
250
+ isLoading: false,
251
+ totalQueries: prev.totalQueries + 1
252
+ }));
253
+
254
+ // Update query history
255
+ setQueryHistory(prev => [ragQuery, ...prev.slice(0, 19)]);
256
+
257
+ // Reset streaming state if not streaming
258
+ if (!shouldStream) {
259
+ setStreamingState({
260
+ isStreaming: false,
261
+ currentResponse: '',
262
+ sources: [],
263
+ confidence: 0
264
+ });
265
+ }
266
+ }
267
+ }, [ragSystem, enableStreaming, enableCache, responseCache]);
268
+
269
+ // Search knowledge base
270
+ const searchKnowledge = useCallback(async (
271
+ searchText: string,
272
+ filters?: {
273
+ category?: string;
274
+ limit?: number;
275
+ sort?: 'relevance' | 'date' | 'popularity';
276
+ includeMetadata?: boolean;
277
+ }
278
+ ): Promise<RAGSearchResult[]> => {
279
+ if (!ragSystem) return [];
280
+
281
+ try {
282
+ return await ragSystem.searchDocuments(searchText, {
283
+ ...filters,
284
+ limit: filters?.limit || 20
285
+ });
286
+ } catch (error) {
287
+ console.error('Knowledge search error:', error);
288
+ toast.error('Search failed');
289
+ return [];
290
+ }
291
+ }, [ragSystem]);
292
+
293
+ // Add document to knowledge base
294
+ const addKnowledge = useCallback(async (
295
+ document: Omit<RAGDocument<TSchema>, 'id' | 'createdAt' | 'updatedAt'>
296
+ ): Promise<string | null> => {
297
+ if (!ragSystem) return null;
298
+
299
+ try {
300
+ const id = await ragSystem.addDocument(document as RAGDocument<TSchema>);
301
+
302
+ setState(prev => ({
303
+ ...prev,
304
+ totalDocuments: prev.totalDocuments + 1
305
+ }));
306
+
307
+ toast.success('Knowledge added successfully');
308
+ return id;
309
+
310
+ } catch (error) {
311
+ console.error('Add knowledge error:', error);
312
+ toast.error('Failed to add knowledge');
313
+ return null;
314
+ }
315
+ }, [ragSystem]);
316
+
317
+ // Update document
318
+ const updateKnowledge = useCallback(async (
319
+ id: string,
320
+ updates: Partial<RAGDocument<TSchema>>
321
+ ): Promise<boolean> => {
322
+ if (!ragSystem) return false;
323
+
324
+ try {
325
+ await ragSystem.updateDocument(id, updates);
326
+ toast.success('Knowledge updated successfully');
327
+ return true;
328
+
329
+ } catch (error) {
330
+ console.error('Update knowledge error:', error);
331
+ toast.error('Failed to update knowledge');
332
+ return false;
333
+ }
334
+ }, [ragSystem]);
335
+
336
+ // Delete document
337
+ const deleteKnowledge = useCallback(async (id: string): Promise<boolean> => {
338
+ if (!ragSystem) return false;
339
+
340
+ try {
341
+ await ragSystem.deleteDocument(id);
342
+
343
+ setState(prev => ({
344
+ ...prev,
345
+ totalDocuments: Math.max(0, prev.totalDocuments - 1)
346
+ }));
347
+
348
+ toast.success('Knowledge deleted successfully');
349
+ return true;
350
+
351
+ } catch (error) {
352
+ console.error('Delete knowledge error:', error);
353
+ toast.error('Failed to delete knowledge');
354
+ return false;
355
+ }
356
+ }, [ragSystem]);
357
+
358
+ // Bulk operations
359
+ const bulkAddKnowledge = useCallback(async (
360
+ documents: Omit<RAGDocument<TSchema>, 'id' | 'createdAt' | 'updatedAt'>[]
361
+ ): Promise<string[]> => {
362
+ if (!ragSystem) return [];
363
+
364
+ try {
365
+ setState(prev => ({ ...prev, isLoading: true }));
366
+
367
+ const ids = await ragSystem.bulkAddDocuments(documents as RAGDocument<TSchema>[]);
368
+
369
+ setState(prev => ({
370
+ ...prev,
371
+ totalDocuments: prev.totalDocuments + ids.length,
372
+ isLoading: false
373
+ }));
374
+
375
+ toast.success(`Added ${ids.length} knowledge documents`);
376
+ return ids;
377
+
378
+ } catch (error) {
379
+ setState(prev => ({ ...prev, isLoading: false }));
380
+ console.error('Bulk add error:', error);
381
+ toast.error('Bulk add operation failed');
382
+ return [];
383
+ }
384
+ }, [ragSystem]);
385
+
386
+ // Sync knowledge base
387
+ const syncKnowledgeBase = useCallback(async (): Promise<void> => {
388
+ if (!ragSystem) return;
389
+
390
+ try {
391
+ setState(prev => ({ ...prev, isLoading: true }));
392
+
393
+ await ragSystem.sync(state.lastSyncAt);
394
+
395
+ const stats = await ragSystem.getStats();
396
+
397
+ setState(prev => ({
398
+ ...prev,
399
+ lastSyncAt: new Date(),
400
+ totalDocuments: stats.totalDocuments || prev.totalDocuments,
401
+ isLoading: false,
402
+ health: 'healthy'
403
+ }));
404
+
405
+ toast.success('Knowledge base synchronized');
406
+
407
+ } catch (error) {
408
+ setState(prev => ({ ...prev, isLoading: false, health: 'degraded' }));
409
+ console.error('Sync error:', error);
410
+ toast.error('Synchronization failed');
411
+ }
412
+ }, [ragSystem, state.lastSyncAt]);
413
+
414
+ // Cancel current operation
415
+ const cancelOperation = useCallback(() => {
416
+ if (abortControllerRef.current) {
417
+ abortControllerRef.current.abort();
418
+ setStreamingState({
419
+ isStreaming: false,
420
+ currentResponse: '',
421
+ sources: [],
422
+ confidence: 0
423
+ });
424
+ setState(prev => ({ ...prev, isLoading: false }));
425
+ toast.info('Operation cancelled');
426
+ }
427
+ }, []);
428
+
429
+ // Clear cache
430
+ const clearCache = useCallback(() => {
431
+ setResponseCache(new Map());
432
+ setQueryHistory([]);
433
+ toast.success('Cache cleared');
434
+ }, []);
435
+
436
+ // Get analytics data
437
+ const getAnalytics = useCallback(async (timeRange: string = '7d') => {
438
+ if (!ragSystem) return null;
439
+
440
+ try {
441
+ return await ragSystem.getAnalytics(timeRange);
442
+ } catch (error) {
443
+ console.error('Analytics error:', error);
444
+ return null;
445
+ }
446
+ }, [ragSystem]);
447
+
448
+ // Helper functions
449
+ const getCacheKey = (query: RAGQuery): string => {
450
+ return `${query.query}:${query.category || 'all'}:${query.maxResults}`;
451
+ };
452
+
453
+ return {
454
+ // State
455
+ ...state,
456
+ ragSystem,
457
+ queryHistory,
458
+ streamingState,
459
+ cacheSize: responseCache.size,
460
+
461
+ // Actions
462
+ query,
463
+ searchKnowledge,
464
+ addKnowledge,
465
+ updateKnowledge,
466
+ deleteKnowledge,
467
+ bulkAddKnowledge,
468
+ syncKnowledgeBase,
469
+ cancelOperation,
470
+ clearCache,
471
+ getAnalytics,
472
+
473
+ // Utilities
474
+ isReady: state.isInitialized && !state.isLoading && state.health !== 'down',
475
+ canQuery: state.isInitialized && state.health !== 'down',
476
+ hasError: !!state.error,
477
+ };
478
+ }