@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.
- package/CHANGELOG.md +51 -0
- package/dist/.tsbuildinfo +1 -1
- package/dist/cli/commands/create.d.ts.map +1 -1
- package/dist/cli/commands/create.js +6 -2
- package/dist/cli/commands/create.js.map +1 -1
- package/dist/cli/index.js +1 -1
- package/dist/cli/index.js.map +1 -1
- package/dist/generators/template-generator.d.ts.map +1 -1
- package/dist/generators/template-generator.js +13 -7
- package/dist/generators/template-generator.js.map +1 -1
- package/dist/templates/mobile/ui-auth-payments-ai-rag/template/README.md +655 -0
- package/dist/templates/mobile/ui-auth-payments-ai-rag/template/app/(tabs)/ai.tsx +683 -0
- package/dist/templates/mobile/ui-auth-payments-ai-rag/template/docs/MOBILE-SETUP.md +787 -0
- package/dist/templates/mobile/ui-auth-payments-ai-rag/template/hooks/useRAGSystem.ts +346 -0
- package/dist/templates/mobile/ui-auth-payments-ai-rag/template/lib/rag/config.ts +180 -0
- package/dist/templates/mobile/ui-auth-payments-ai-rag/template/package.json +113 -0
- package/dist/templates/mobile/ui-auth-payments-ai-rag/template/scripts/setup-rag.js +599 -0
- package/dist/templates/web/ui-auth-payments-ai-rag/template/README.md +434 -0
- package/dist/templates/web/ui-auth-payments-ai-rag/template/components/rag/KnowledgeManager.tsx +642 -0
- package/dist/templates/web/ui-auth-payments-ai-rag/template/components/rag/RAGAnalytics.tsx +466 -0
- package/dist/templates/web/ui-auth-payments-ai-rag/template/components/rag/RAGChatInterface.tsx +393 -0
- package/dist/templates/web/ui-auth-payments-ai-rag/template/docs/GETTING-STARTED.md +457 -0
- package/dist/templates/web/ui-auth-payments-ai-rag/template/hooks/useRAGSystem.ts +478 -0
- package/dist/templates/web/ui-auth-payments-ai-rag/template/lib/rag/config.ts +250 -0
- package/dist/templates/web/ui-auth-payments-ai-rag/template/package.json +74 -0
- package/dist/templates/web/ui-auth-payments-ai-rag/template/scripts/setup-rag.js +622 -0
- package/dist/templates/web/ui-auth-payments-ai-rag/template/src/app/ai/page.tsx +396 -0
- package/package.json +1 -1
- package/src/templates/mobile/ui-auth-payments-ai-rag/template/README.md +655 -0
- package/src/templates/mobile/ui-auth-payments-ai-rag/template/app/(tabs)/ai.tsx +683 -0
- package/src/templates/mobile/ui-auth-payments-ai-rag/template/docs/MOBILE-SETUP.md +787 -0
- package/src/templates/mobile/ui-auth-payments-ai-rag/template/hooks/useRAGSystem.ts +346 -0
- package/src/templates/mobile/ui-auth-payments-ai-rag/template/lib/rag/config.ts +180 -0
- package/src/templates/mobile/ui-auth-payments-ai-rag/template/package.json +113 -0
- package/src/templates/mobile/ui-auth-payments-ai-rag/template/scripts/setup-rag.js +599 -0
- package/src/templates/web/ui-auth-payments-ai-rag/template/README.md +434 -0
- package/src/templates/web/ui-auth-payments-ai-rag/template/components/rag/KnowledgeManager.tsx +642 -0
- package/src/templates/web/ui-auth-payments-ai-rag/template/components/rag/RAGAnalytics.tsx +466 -0
- package/src/templates/web/ui-auth-payments-ai-rag/template/components/rag/RAGChatInterface.tsx +393 -0
- package/src/templates/web/ui-auth-payments-ai-rag/template/docs/GETTING-STARTED.md +457 -0
- package/src/templates/web/ui-auth-payments-ai-rag/template/hooks/useRAGSystem.ts +478 -0
- package/src/templates/web/ui-auth-payments-ai-rag/template/lib/rag/config.ts +250 -0
- package/src/templates/web/ui-auth-payments-ai-rag/template/package.json +74 -0
- package/src/templates/web/ui-auth-payments-ai-rag/template/scripts/setup-rag.js +622 -0
- package/src/templates/web/ui-auth-payments-ai-rag/template/src/app/ai/page.tsx +396 -0
|
@@ -0,0 +1,655 @@
|
|
|
1
|
+
# Mobile AI Knowledge App with RAG v4.0.0
|
|
2
|
+
|
|
3
|
+
A powerful React Native/Expo application with AI-powered knowledge base using Retrieval-Augmented Generation (RAG), featuring offline support, voice input, and native mobile optimizations.
|
|
4
|
+
|
|
5
|
+
## 📱 Mobile-First Features
|
|
6
|
+
|
|
7
|
+
### AI & Knowledge Base
|
|
8
|
+
- **RAG-Powered Chat**: Intelligent conversations with your knowledge base
|
|
9
|
+
- **Voice Input**: Speak your queries with native speech recognition
|
|
10
|
+
- **Offline Mode**: Cached responses and queued queries for offline use
|
|
11
|
+
- **Touch-Optimized UI**: Native mobile interactions and gestures
|
|
12
|
+
- **Push Notifications**: Real-time updates for new knowledge
|
|
13
|
+
- **Haptic Feedback**: Enhanced tactile user experience
|
|
14
|
+
|
|
15
|
+
### Native Integrations
|
|
16
|
+
- **Camera Integration**: Scan documents to add to knowledge base
|
|
17
|
+
- **File System Access**: Import documents from device storage
|
|
18
|
+
- **Background Sync**: Knowledge updates while app is backgrounded
|
|
19
|
+
- **Biometric Auth**: Face ID/Touch ID for secure access
|
|
20
|
+
- **Deep Linking**: Share knowledge items with native URLs
|
|
21
|
+
|
|
22
|
+
### Performance Optimizations
|
|
23
|
+
- **Lazy Loading**: Efficient memory usage with virtualized lists
|
|
24
|
+
- **Image Caching**: Optimized asset loading and caching
|
|
25
|
+
- **Bundle Splitting**: Reduced initial app size
|
|
26
|
+
- **Native Performance**: 60fps animations and smooth scrolling
|
|
27
|
+
|
|
28
|
+
## 🏗️ Architecture
|
|
29
|
+
|
|
30
|
+
```
|
|
31
|
+
app/
|
|
32
|
+
├── (tabs)/ # Tab-based navigation
|
|
33
|
+
│ ├── ai.tsx # Main AI interface
|
|
34
|
+
│ ├── knowledge.tsx # Knowledge management
|
|
35
|
+
│ └── analytics.tsx # Usage analytics
|
|
36
|
+
├── auth/ # Authentication screens
|
|
37
|
+
│ ├── login.tsx
|
|
38
|
+
│ └── signup.tsx
|
|
39
|
+
├── onboarding/ # First-time user experience
|
|
40
|
+
hooks/
|
|
41
|
+
├── useRAGSystem.ts # Core RAG functionality
|
|
42
|
+
├── useOfflineSync.ts # Offline synchronization
|
|
43
|
+
└── useVoiceInput.ts # Voice recognition
|
|
44
|
+
lib/
|
|
45
|
+
├── rag/
|
|
46
|
+
│ ├── config.ts # Mobile-optimized RAG config
|
|
47
|
+
│ └── cache.ts # Offline caching strategy
|
|
48
|
+
├── supabase.ts # Mobile Supabase client
|
|
49
|
+
└── storage.ts # AsyncStorage utilities
|
|
50
|
+
```
|
|
51
|
+
|
|
52
|
+
## 🛠️ Quick Start
|
|
53
|
+
|
|
54
|
+
### 1. Installation
|
|
55
|
+
|
|
56
|
+
```bash
|
|
57
|
+
# Create new mobile project
|
|
58
|
+
npm create saas-app my-mobile-ai-app --template=mobile-ai-rag
|
|
59
|
+
|
|
60
|
+
# Navigate to project
|
|
61
|
+
cd my-mobile-ai-app
|
|
62
|
+
|
|
63
|
+
# Install dependencies
|
|
64
|
+
npx expo install
|
|
65
|
+
```
|
|
66
|
+
|
|
67
|
+
### 2. Environment Setup
|
|
68
|
+
|
|
69
|
+
Create `.env.local`:
|
|
70
|
+
|
|
71
|
+
```env
|
|
72
|
+
# Supabase Configuration
|
|
73
|
+
EXPO_PUBLIC_SUPABASE_URL=your_supabase_url
|
|
74
|
+
EXPO_PUBLIC_SUPABASE_ANON_KEY=your_supabase_anon_key
|
|
75
|
+
|
|
76
|
+
# OpenAI Configuration (client-side - use cautiously)
|
|
77
|
+
EXPO_PUBLIC_OPENAI_API_KEY=your_openai_api_key
|
|
78
|
+
|
|
79
|
+
# App Configuration
|
|
80
|
+
APP_VARIANT=development
|
|
81
|
+
EAS_PROJECT_ID=your_eas_project_id
|
|
82
|
+
```
|
|
83
|
+
|
|
84
|
+
**⚠️ Important**: Environment variables in React Native are embedded in the build. Use server-side API routes for sensitive operations in production.
|
|
85
|
+
|
|
86
|
+
### 3. Database Setup
|
|
87
|
+
|
|
88
|
+
```bash
|
|
89
|
+
# Setup RAG system
|
|
90
|
+
npm run setup:rag
|
|
91
|
+
|
|
92
|
+
# Seed with mobile-optimized knowledge
|
|
93
|
+
npm run seed:knowledge
|
|
94
|
+
```
|
|
95
|
+
|
|
96
|
+
### 4. Development
|
|
97
|
+
|
|
98
|
+
```bash
|
|
99
|
+
# Start Expo development server
|
|
100
|
+
npx expo start
|
|
101
|
+
|
|
102
|
+
# Run on iOS simulator
|
|
103
|
+
npx expo start --ios
|
|
104
|
+
|
|
105
|
+
# Run on Android emulator
|
|
106
|
+
npx expo start --android
|
|
107
|
+
|
|
108
|
+
# Open in Expo Go app
|
|
109
|
+
# Scan the QR code with your phone
|
|
110
|
+
```
|
|
111
|
+
|
|
112
|
+
## 📱 Mobile-Specific Usage
|
|
113
|
+
|
|
114
|
+
### Voice-Enabled Chat
|
|
115
|
+
|
|
116
|
+
```typescript
|
|
117
|
+
import { useRAGSystem } from '@/hooks/useRAGSystem'
|
|
118
|
+
import { RAGChatPanel } from '@digilogiclabs/saas-factory-ui/native'
|
|
119
|
+
|
|
120
|
+
export default function ChatScreen() {
|
|
121
|
+
const ragSystem = useRAGSystem({
|
|
122
|
+
domain: 'generic',
|
|
123
|
+
enableOffline: true,
|
|
124
|
+
enableVoice: true
|
|
125
|
+
})
|
|
126
|
+
|
|
127
|
+
return (
|
|
128
|
+
<RAGChatPanel
|
|
129
|
+
ragSystem={ragSystem.ragSystem}
|
|
130
|
+
enableVoiceInput={true}
|
|
131
|
+
enableOfflineMode={true}
|
|
132
|
+
mobileOptimized={true}
|
|
133
|
+
showSources={true}
|
|
134
|
+
showConfidenceScore={false} // Simplified for mobile
|
|
135
|
+
/>
|
|
136
|
+
)
|
|
137
|
+
}
|
|
138
|
+
```
|
|
139
|
+
|
|
140
|
+
### Offline-First Knowledge Management
|
|
141
|
+
|
|
142
|
+
```typescript
|
|
143
|
+
import { useOfflineSync } from '@/hooks/useOfflineSync'
|
|
144
|
+
|
|
145
|
+
export default function KnowledgeScreen() {
|
|
146
|
+
const ragSystem = useRAGSystem()
|
|
147
|
+
const offlineSync = useOfflineSync({
|
|
148
|
+
syncInterval: 300000, // 5 minutes
|
|
149
|
+
autoSync: true
|
|
150
|
+
})
|
|
151
|
+
|
|
152
|
+
return (
|
|
153
|
+
<KnowledgeManagementPanel
|
|
154
|
+
ragSystem={ragSystem.ragSystem}
|
|
155
|
+
offlineMode={!ragSystem.isOnline}
|
|
156
|
+
syncStatus={offlineSync.status}
|
|
157
|
+
onSync={offlineSync.syncNow}
|
|
158
|
+
/>
|
|
159
|
+
)
|
|
160
|
+
}
|
|
161
|
+
```
|
|
162
|
+
|
|
163
|
+
### Native UI Components
|
|
164
|
+
|
|
165
|
+
```typescript
|
|
166
|
+
import {
|
|
167
|
+
TabbedInterface,
|
|
168
|
+
SwipeableCard,
|
|
169
|
+
VirtualScrollList,
|
|
170
|
+
NativeFeatureHighlight
|
|
171
|
+
} from '@digilogiclabs/saas-factory-ui/native'
|
|
172
|
+
|
|
173
|
+
// Swipeable knowledge cards
|
|
174
|
+
<SwipeableCard
|
|
175
|
+
rightActions={[
|
|
176
|
+
{ label: 'Edit', color: '#3b82f6', onPress: handleEdit },
|
|
177
|
+
{ label: 'Delete', color: '#ef4444', onPress: handleDelete }
|
|
178
|
+
]}
|
|
179
|
+
>
|
|
180
|
+
<KnowledgeCard item={knowledge} />
|
|
181
|
+
</SwipeableCard>
|
|
182
|
+
|
|
183
|
+
// High-performance lists
|
|
184
|
+
<VirtualScrollList
|
|
185
|
+
data={knowledgeItems}
|
|
186
|
+
renderItem={renderKnowledgeItem}
|
|
187
|
+
estimatedItemSize={120}
|
|
188
|
+
onEndReached={loadMore}
|
|
189
|
+
/>
|
|
190
|
+
```
|
|
191
|
+
|
|
192
|
+
## 🔄 Offline Capabilities
|
|
193
|
+
|
|
194
|
+
### Caching Strategy
|
|
195
|
+
```typescript
|
|
196
|
+
// lib/rag/cache.ts
|
|
197
|
+
export class MobileRAGCache {
|
|
198
|
+
private cache = new Map<string, CachedResponse>()
|
|
199
|
+
private maxSize = 100 // Configurable cache size
|
|
200
|
+
|
|
201
|
+
async getCached(query: string): Promise<RAGResponse | null> {
|
|
202
|
+
const cached = this.cache.get(query)
|
|
203
|
+
if (cached && !this.isExpired(cached)) {
|
|
204
|
+
return cached.response
|
|
205
|
+
}
|
|
206
|
+
return null
|
|
207
|
+
}
|
|
208
|
+
|
|
209
|
+
async setCached(query: string, response: RAGResponse) {
|
|
210
|
+
if (this.cache.size >= this.maxSize) {
|
|
211
|
+
this.evictOldest()
|
|
212
|
+
}
|
|
213
|
+
this.cache.set(query, {
|
|
214
|
+
response,
|
|
215
|
+
timestamp: Date.now(),
|
|
216
|
+
expiresAt: Date.now() + (24 * 60 * 60 * 1000) // 24 hours
|
|
217
|
+
})
|
|
218
|
+
}
|
|
219
|
+
}
|
|
220
|
+
```
|
|
221
|
+
|
|
222
|
+
### Offline Queue Management
|
|
223
|
+
```typescript
|
|
224
|
+
// hooks/useOfflineSync.ts
|
|
225
|
+
export function useOfflineSync() {
|
|
226
|
+
const [offlineQueue, setOfflineQueue] = useState<OfflineQuery[]>([])
|
|
227
|
+
|
|
228
|
+
const queueQuery = async (query: string) => {
|
|
229
|
+
const offlineQuery: OfflineQuery = {
|
|
230
|
+
id: uuid(),
|
|
231
|
+
query,
|
|
232
|
+
timestamp: new Date(),
|
|
233
|
+
synced: false
|
|
234
|
+
}
|
|
235
|
+
|
|
236
|
+
setOfflineQueue(prev => [...prev, offlineQuery])
|
|
237
|
+
await AsyncStorage.setItem('offline_queue', JSON.stringify(offlineQueue))
|
|
238
|
+
}
|
|
239
|
+
|
|
240
|
+
const syncQueue = async () => {
|
|
241
|
+
// Process queued queries when online
|
|
242
|
+
for (const query of offlineQueue) {
|
|
243
|
+
try {
|
|
244
|
+
await ragSystem.query(query.query)
|
|
245
|
+
query.synced = true
|
|
246
|
+
} catch (error) {
|
|
247
|
+
console.error('Sync failed:', error)
|
|
248
|
+
}
|
|
249
|
+
}
|
|
250
|
+
}
|
|
251
|
+
}
|
|
252
|
+
```
|
|
253
|
+
|
|
254
|
+
## 🎤 Voice Integration
|
|
255
|
+
|
|
256
|
+
### Speech-to-Text
|
|
257
|
+
```typescript
|
|
258
|
+
import { useVoiceRecognition } from '@/hooks/useVoiceRecognition'
|
|
259
|
+
|
|
260
|
+
export function VoiceInput() {
|
|
261
|
+
const {
|
|
262
|
+
isListening,
|
|
263
|
+
transcript,
|
|
264
|
+
startListening,
|
|
265
|
+
stopListening,
|
|
266
|
+
clearTranscript
|
|
267
|
+
} = useVoiceRecognition({
|
|
268
|
+
language: 'en-US',
|
|
269
|
+
continuous: false,
|
|
270
|
+
interimResults: true
|
|
271
|
+
})
|
|
272
|
+
|
|
273
|
+
return (
|
|
274
|
+
<TouchableOpacity
|
|
275
|
+
onPress={isListening ? stopListening : startListening}
|
|
276
|
+
style={styles.voiceButton}
|
|
277
|
+
>
|
|
278
|
+
<Mic color={isListening ? '#ef4444' : '#3b82f6'} size={24} />
|
|
279
|
+
</TouchableOpacity>
|
|
280
|
+
)
|
|
281
|
+
}
|
|
282
|
+
```
|
|
283
|
+
|
|
284
|
+
### Text-to-Speech
|
|
285
|
+
```typescript
|
|
286
|
+
import * as Speech from 'expo-speech'
|
|
287
|
+
|
|
288
|
+
const speakResponse = (text: string) => {
|
|
289
|
+
Speech.speak(text, {
|
|
290
|
+
language: 'en-US',
|
|
291
|
+
pitch: 1.0,
|
|
292
|
+
rate: 0.8,
|
|
293
|
+
voice: 'com.apple.ttsbundle.Samantha-compact'
|
|
294
|
+
})
|
|
295
|
+
}
|
|
296
|
+
```
|
|
297
|
+
|
|
298
|
+
## 📊 Native Analytics
|
|
299
|
+
|
|
300
|
+
### Performance Monitoring
|
|
301
|
+
```typescript
|
|
302
|
+
import { useRAGAnalytics } from '@/hooks/useRAGAnalytics'
|
|
303
|
+
|
|
304
|
+
export function AnalyticsScreen() {
|
|
305
|
+
const analytics = useRAGAnalytics({
|
|
306
|
+
trackAppState: true,
|
|
307
|
+
trackMemoryUsage: true,
|
|
308
|
+
trackNetworkStatus: true
|
|
309
|
+
})
|
|
310
|
+
|
|
311
|
+
return (
|
|
312
|
+
<ScrollView>
|
|
313
|
+
<PerformanceMetrics
|
|
314
|
+
responseTime={analytics.averageResponseTime}
|
|
315
|
+
cacheHitRate={analytics.cacheHitRate}
|
|
316
|
+
offlineQueryRate={analytics.offlineQueryRate}
|
|
317
|
+
/>
|
|
318
|
+
|
|
319
|
+
<UsageCharts
|
|
320
|
+
queryVolume={analytics.queryVolume}
|
|
321
|
+
userSessions={analytics.sessionData}
|
|
322
|
+
knowledgeGrowth={analytics.knowledgeGrowth}
|
|
323
|
+
/>
|
|
324
|
+
</ScrollView>
|
|
325
|
+
)
|
|
326
|
+
}
|
|
327
|
+
```
|
|
328
|
+
|
|
329
|
+
## 🔐 Security & Privacy
|
|
330
|
+
|
|
331
|
+
### Secure Storage
|
|
332
|
+
```typescript
|
|
333
|
+
import * as SecureStore from 'expo-secure-store'
|
|
334
|
+
|
|
335
|
+
// Store sensitive data securely
|
|
336
|
+
await SecureStore.setItemAsync('user_token', authToken)
|
|
337
|
+
|
|
338
|
+
// Retrieve secure data
|
|
339
|
+
const token = await SecureStore.getItemAsync('user_token')
|
|
340
|
+
```
|
|
341
|
+
|
|
342
|
+
### Biometric Authentication
|
|
343
|
+
```typescript
|
|
344
|
+
import * as LocalAuthentication from 'expo-local-authentication'
|
|
345
|
+
|
|
346
|
+
const authenticateWithBiometrics = async () => {
|
|
347
|
+
const hasHardware = await LocalAuthentication.hasHardwareAsync()
|
|
348
|
+
const supportedTypes = await LocalAuthentication.supportedAuthenticationTypesAsync()
|
|
349
|
+
|
|
350
|
+
if (hasHardware && supportedTypes.length > 0) {
|
|
351
|
+
const result = await LocalAuthentication.authenticateAsync({
|
|
352
|
+
promptMessage: 'Authenticate to access your AI assistant',
|
|
353
|
+
fallbackLabel: 'Use passcode'
|
|
354
|
+
})
|
|
355
|
+
|
|
356
|
+
return result.success
|
|
357
|
+
}
|
|
358
|
+
|
|
359
|
+
return false
|
|
360
|
+
}
|
|
361
|
+
```
|
|
362
|
+
|
|
363
|
+
## 🚀 Build & Distribution
|
|
364
|
+
|
|
365
|
+
### EAS Build Configuration
|
|
366
|
+
```json
|
|
367
|
+
{
|
|
368
|
+
"expo": {
|
|
369
|
+
"name": "AI Knowledge Assistant",
|
|
370
|
+
"slug": "ai-knowledge-assistant",
|
|
371
|
+
"version": "1.0.0",
|
|
372
|
+
"orientation": "portrait",
|
|
373
|
+
"platforms": ["ios", "android"],
|
|
374
|
+
"assetBundlePatterns": ["**/*"]
|
|
375
|
+
},
|
|
376
|
+
"build": {
|
|
377
|
+
"preview": {
|
|
378
|
+
"android": {
|
|
379
|
+
"buildType": "apk"
|
|
380
|
+
}
|
|
381
|
+
},
|
|
382
|
+
"preview2": {
|
|
383
|
+
"android": {
|
|
384
|
+
"gradleCommand": ":app:assembleRelease"
|
|
385
|
+
}
|
|
386
|
+
},
|
|
387
|
+
"preview3": {
|
|
388
|
+
"developmentClient": true
|
|
389
|
+
},
|
|
390
|
+
"production": {}
|
|
391
|
+
},
|
|
392
|
+
"submit": {
|
|
393
|
+
"production": {}
|
|
394
|
+
}
|
|
395
|
+
}
|
|
396
|
+
```
|
|
397
|
+
|
|
398
|
+
### Building for Production
|
|
399
|
+
```bash
|
|
400
|
+
# Build for iOS
|
|
401
|
+
eas build --platform ios --profile production
|
|
402
|
+
|
|
403
|
+
# Build for Android
|
|
404
|
+
eas build --platform android --profile production
|
|
405
|
+
|
|
406
|
+
# Submit to app stores
|
|
407
|
+
eas submit --platform ios
|
|
408
|
+
eas submit --platform android
|
|
409
|
+
```
|
|
410
|
+
|
|
411
|
+
## 📱 Platform-Specific Features
|
|
412
|
+
|
|
413
|
+
### iOS Features
|
|
414
|
+
```typescript
|
|
415
|
+
// Push notifications
|
|
416
|
+
import * as Notifications from 'expo-notifications'
|
|
417
|
+
|
|
418
|
+
Notifications.setNotificationHandler({
|
|
419
|
+
handleNotification: async () => ({
|
|
420
|
+
shouldShowAlert: true,
|
|
421
|
+
shouldPlaySound: true,
|
|
422
|
+
shouldSetBadge: true,
|
|
423
|
+
}),
|
|
424
|
+
})
|
|
425
|
+
|
|
426
|
+
// Background app refresh
|
|
427
|
+
import * as BackgroundFetch from 'expo-background-fetch'
|
|
428
|
+
import * as TaskManager from 'expo-task-manager'
|
|
429
|
+
|
|
430
|
+
const BACKGROUND_SYNC_TASK = 'background-sync'
|
|
431
|
+
|
|
432
|
+
TaskManager.defineTask(BACKGROUND_SYNC_TASK, () => {
|
|
433
|
+
// Background sync logic
|
|
434
|
+
return BackgroundFetch.BackgroundFetchResult.NewData
|
|
435
|
+
})
|
|
436
|
+
```
|
|
437
|
+
|
|
438
|
+
### Android Features
|
|
439
|
+
```typescript
|
|
440
|
+
// File system access
|
|
441
|
+
import * as DocumentPicker from 'expo-document-picker'
|
|
442
|
+
|
|
443
|
+
const pickDocument = async () => {
|
|
444
|
+
const result = await DocumentPicker.getDocumentAsync({
|
|
445
|
+
type: ['text/plain', 'text/markdown', 'application/pdf'],
|
|
446
|
+
copyToCacheDirectory: true,
|
|
447
|
+
multiple: true
|
|
448
|
+
})
|
|
449
|
+
|
|
450
|
+
if (result.type === 'success') {
|
|
451
|
+
// Process selected documents
|
|
452
|
+
await addDocumentToKnowledge(result)
|
|
453
|
+
}
|
|
454
|
+
}
|
|
455
|
+
|
|
456
|
+
// Deep linking
|
|
457
|
+
import * as Linking from 'expo-linking'
|
|
458
|
+
|
|
459
|
+
const url = Linking.createURL('knowledge', {
|
|
460
|
+
queryParams: { id: 'doc123' }
|
|
461
|
+
})
|
|
462
|
+
// myapp://knowledge?id=doc123
|
|
463
|
+
```
|
|
464
|
+
|
|
465
|
+
## 🧪 Testing
|
|
466
|
+
|
|
467
|
+
### Unit Tests
|
|
468
|
+
```bash
|
|
469
|
+
npm run test
|
|
470
|
+
```
|
|
471
|
+
|
|
472
|
+
### Component Testing
|
|
473
|
+
```typescript
|
|
474
|
+
import { render, fireEvent } from '@testing-library/react-native'
|
|
475
|
+
import { RAGChatPanel } from '@/components/RAGChatPanel'
|
|
476
|
+
|
|
477
|
+
test('sends query on button press', () => {
|
|
478
|
+
const mockQuery = jest.fn()
|
|
479
|
+
const { getByTestId } = render(
|
|
480
|
+
<RAGChatPanel onQuery={mockQuery} />
|
|
481
|
+
)
|
|
482
|
+
|
|
483
|
+
fireEvent.press(getByTestId('send-button'))
|
|
484
|
+
expect(mockQuery).toHaveBeenCalled()
|
|
485
|
+
})
|
|
486
|
+
```
|
|
487
|
+
|
|
488
|
+
### E2E Testing with Detox
|
|
489
|
+
```javascript
|
|
490
|
+
describe('AI Chat Flow', () => {
|
|
491
|
+
beforeEach(async () => {
|
|
492
|
+
await device.reloadReactNative()
|
|
493
|
+
})
|
|
494
|
+
|
|
495
|
+
it('should navigate to chat and send message', async () => {
|
|
496
|
+
await element(by.id('ai-tab')).tap()
|
|
497
|
+
await element(by.id('chat-input')).typeText('Hello AI')
|
|
498
|
+
await element(by.id('send-button')).tap()
|
|
499
|
+
await expect(element(by.id('chat-message'))).toBeVisible()
|
|
500
|
+
})
|
|
501
|
+
})
|
|
502
|
+
```
|
|
503
|
+
|
|
504
|
+
## 🔧 Configuration
|
|
505
|
+
|
|
506
|
+
### Domain-Specific Mobile Configs
|
|
507
|
+
```typescript
|
|
508
|
+
// lib/rag/mobileConfig.ts
|
|
509
|
+
export const mobileRAGConfigs = {
|
|
510
|
+
plants: {
|
|
511
|
+
voice: {
|
|
512
|
+
plantNamesRecognition: true,
|
|
513
|
+
scientificNamesSupport: true
|
|
514
|
+
},
|
|
515
|
+
camera: {
|
|
516
|
+
plantIdentification: true,
|
|
517
|
+
diseaseDetection: true
|
|
518
|
+
},
|
|
519
|
+
notifications: {
|
|
520
|
+
wateringReminders: true,
|
|
521
|
+
seasonalTips: true
|
|
522
|
+
}
|
|
523
|
+
},
|
|
524
|
+
|
|
525
|
+
ecommerce: {
|
|
526
|
+
voice: {
|
|
527
|
+
productSearch: true,
|
|
528
|
+
priceQueries: true
|
|
529
|
+
},
|
|
530
|
+
camera: {
|
|
531
|
+
barcodeScanning: true,
|
|
532
|
+
visualSearch: true
|
|
533
|
+
},
|
|
534
|
+
notifications: {
|
|
535
|
+
priceAlerts: true,
|
|
536
|
+
stockUpdates: true
|
|
537
|
+
}
|
|
538
|
+
}
|
|
539
|
+
}
|
|
540
|
+
```
|
|
541
|
+
|
|
542
|
+
## 📈 Performance Best Practices
|
|
543
|
+
|
|
544
|
+
### Memory Management
|
|
545
|
+
```typescript
|
|
546
|
+
// Efficient list rendering
|
|
547
|
+
import { FlashList } from '@shopify/flash-list'
|
|
548
|
+
|
|
549
|
+
<FlashList
|
|
550
|
+
data={knowledge}
|
|
551
|
+
renderItem={renderKnowledgeItem}
|
|
552
|
+
estimatedItemSize={120}
|
|
553
|
+
getItemType={(item) => item.category}
|
|
554
|
+
removeClippedSubviews={true}
|
|
555
|
+
/>
|
|
556
|
+
|
|
557
|
+
// Image optimization
|
|
558
|
+
import { Image } from 'expo-image'
|
|
559
|
+
|
|
560
|
+
<Image
|
|
561
|
+
source={{ uri: imageUrl }}
|
|
562
|
+
placeholder={blurhash}
|
|
563
|
+
contentFit="cover"
|
|
564
|
+
transition={200}
|
|
565
|
+
/>
|
|
566
|
+
```
|
|
567
|
+
|
|
568
|
+
### Battery Optimization
|
|
569
|
+
```typescript
|
|
570
|
+
// Debounced search to reduce API calls
|
|
571
|
+
import { useDebouncedCallback } from 'use-debounce'
|
|
572
|
+
|
|
573
|
+
const debouncedSearch = useDebouncedCallback(
|
|
574
|
+
(query: string) => ragSystem.query(query),
|
|
575
|
+
500 // 500ms delay
|
|
576
|
+
)
|
|
577
|
+
|
|
578
|
+
// Background task limiting
|
|
579
|
+
import * as BackgroundFetch from 'expo-background-fetch'
|
|
580
|
+
|
|
581
|
+
await BackgroundFetch.setMinimumIntervalAsync(
|
|
582
|
+
BackgroundFetch.BackgroundFetchInterval.Never
|
|
583
|
+
)
|
|
584
|
+
```
|
|
585
|
+
|
|
586
|
+
## 🎯 Advanced Mobile Features
|
|
587
|
+
|
|
588
|
+
### Augmented Reality Integration
|
|
589
|
+
```typescript
|
|
590
|
+
// ARCore/ARKit for visual knowledge search
|
|
591
|
+
import { Camera } from 'expo-camera'
|
|
592
|
+
import { BarCodeScanner } from 'expo-barcode-scanner'
|
|
593
|
+
|
|
594
|
+
const ARKnowledgeScanner = () => {
|
|
595
|
+
const handleBarCodeScanned = ({ data }) => {
|
|
596
|
+
// Search knowledge base for scanned item
|
|
597
|
+
ragSystem.query(`Information about ${data}`)
|
|
598
|
+
}
|
|
599
|
+
|
|
600
|
+
return (
|
|
601
|
+
<Camera
|
|
602
|
+
style={styles.camera}
|
|
603
|
+
onBarCodeScanned={handleBarCodeScanned}
|
|
604
|
+
barCodeScannerSettings={{
|
|
605
|
+
barCodeTypes: [BarCodeScanner.Constants.BarCodeType.qr],
|
|
606
|
+
}}
|
|
607
|
+
/>
|
|
608
|
+
)
|
|
609
|
+
}
|
|
610
|
+
```
|
|
611
|
+
|
|
612
|
+
### Machine Learning Integration
|
|
613
|
+
```typescript
|
|
614
|
+
// On-device ML for enhanced privacy
|
|
615
|
+
import * as tf from '@tensorflow/tfjs-react-native'
|
|
616
|
+
|
|
617
|
+
const processImageLocally = async (imageUri: string) => {
|
|
618
|
+
// Load pre-trained model for image classification
|
|
619
|
+
const modelUrl = bundleResourceIO(modelJson, modelWeights)
|
|
620
|
+
const model = await tf.loadLayersModel(modelUrl)
|
|
621
|
+
|
|
622
|
+
// Process image and search knowledge
|
|
623
|
+
const predictions = await model.predict(processedImage)
|
|
624
|
+
const searchQuery = interpretPredictions(predictions)
|
|
625
|
+
|
|
626
|
+
return ragSystem.query(searchQuery)
|
|
627
|
+
}
|
|
628
|
+
```
|
|
629
|
+
|
|
630
|
+
## 🤝 Contributing
|
|
631
|
+
|
|
632
|
+
1. Fork the repository
|
|
633
|
+
2. Create a feature branch: `git checkout -b feature/amazing-feature`
|
|
634
|
+
3. Make your changes and test on both iOS and Android
|
|
635
|
+
4. Run tests: `npm run test`
|
|
636
|
+
5. Submit a pull request
|
|
637
|
+
|
|
638
|
+
## 📄 License
|
|
639
|
+
|
|
640
|
+
MIT License - see LICENSE file for details
|
|
641
|
+
|
|
642
|
+
## 🆘 Support
|
|
643
|
+
|
|
644
|
+
- 📖 [Mobile Documentation](https://docs.example.com/mobile-rag)
|
|
645
|
+
- 💬 [Discord Community](https://discord.gg/example)
|
|
646
|
+
- 🐛 [Issue Tracker](https://github.com/example/mobile-issues)
|
|
647
|
+
- 📱 [Mobile-Specific FAQ](https://docs.example.com/mobile-faq)
|
|
648
|
+
|
|
649
|
+
---
|
|
650
|
+
|
|
651
|
+
Built with ❤️ using Expo, React Native, Supabase, OpenAI, and RAG v4.0.0
|
|
652
|
+
|
|
653
|
+
**Download from:**
|
|
654
|
+
- 🍎 [App Store](https://apps.apple.com/app/example)
|
|
655
|
+
- 🤖 [Google Play](https://play.google.com/store/apps/example)
|