@umituz/react-native-ai-fal-provider 3.1.6 → 3.2.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 (36) hide show
  1. package/package.json +1 -1
  2. package/src/exports/infrastructure.ts +0 -45
  3. package/src/exports/presentation.ts +2 -11
  4. package/src/index.ts +2 -3
  5. package/src/infrastructure/services/fal-queue-operations.ts +1 -1
  6. package/src/infrastructure/services/index.ts +0 -2
  7. package/src/infrastructure/utils/index.ts +7 -53
  8. package/src/infrastructure/utils/input-validator.util.ts +1 -1
  9. package/src/infrastructure/utils/parsers/index.ts +1 -4
  10. package/src/init/createAiProviderInitModule.ts +0 -56
  11. package/src/init/initializeFalProvider.ts +34 -0
  12. package/src/presentation/hooks/index.ts +0 -3
  13. package/src/infrastructure/services/fal-models.service.ts +0 -40
  14. package/src/infrastructure/utils/base-builders.util.ts +0 -28
  15. package/src/infrastructure/utils/collections/array-filters.util.ts +0 -63
  16. package/src/infrastructure/utils/collections/array-sorters.util.ts +0 -94
  17. package/src/infrastructure/utils/collections/index.ts +0 -7
  18. package/src/infrastructure/utils/date-format.util.ts +0 -30
  19. package/src/infrastructure/utils/error-categorizer.ts +0 -9
  20. package/src/infrastructure/utils/job-metadata/index.ts +0 -26
  21. package/src/infrastructure/utils/job-metadata/job-metadata-format.util.ts +0 -78
  22. package/src/infrastructure/utils/job-metadata/job-metadata-lifecycle.util.ts +0 -66
  23. package/src/infrastructure/utils/job-metadata/job-metadata-queries.util.ts +0 -57
  24. package/src/infrastructure/utils/job-metadata/job-metadata.types.ts +0 -19
  25. package/src/infrastructure/utils/job-storage/index.ts +0 -19
  26. package/src/infrastructure/utils/job-storage/job-storage-crud.util.ts +0 -64
  27. package/src/infrastructure/utils/job-storage/job-storage-interface.ts +0 -44
  28. package/src/infrastructure/utils/job-storage/job-storage-queries.util.ts +0 -81
  29. package/src/infrastructure/utils/number-format.util.ts +0 -86
  30. package/src/infrastructure/utils/parsers/object-validators.util.ts +0 -38
  31. package/src/infrastructure/utils/parsers/value-parsers.util.ts +0 -45
  32. package/src/infrastructure/utils/string-format.util.ts +0 -72
  33. package/src/infrastructure/validators/README.md +0 -290
  34. package/src/init/registerWithWizard.ts +0 -28
  35. package/src/presentation/hooks/README.md +0 -626
  36. package/src/presentation/hooks/use-models.ts +0 -56
@@ -1,626 +0,0 @@
1
- # React Hooks
2
-
3
- FAL AI işlemleri için React Hook'ları.
4
-
5
- ## useFalGeneration
6
-
7
- AI içerik oluşturma işlemleri için React hook'u.
8
-
9
- ### Parametreler
10
-
11
- ```typescript
12
- interface UseFalGenerationOptions {
13
- timeoutMs?: number; // Zaman aşımı (ms)
14
- onProgress?: (status: FalQueueStatus) => void; // İlerleme callback
15
- onError?: (error: FalErrorInfo) => void; // Hata callback
16
- }
17
- ```
18
-
19
- ### Dönüş Değeri
20
-
21
- ```typescript
22
- interface UseFalGenerationResult<T> {
23
- data: T | null; // Oluşturulan veri
24
- error: FalErrorInfo | null; // Hata bilgisi
25
- isLoading: boolean; // Yükleme durumu
26
- isRetryable: boolean; // Retry edilebilir mi?
27
- requestId: string | null; // İstek ID'si
28
- isCancelling: boolean; // İptal ediliyor mu?
29
-
30
- generate: (modelEndpoint: string, input: FalJobInput) => Promise<T | null>;
31
- retry: () => Promise<T | null>;
32
- cancel: () => void;
33
- reset: () => void;
34
- }
35
- ```
36
-
37
- ### Temel Kullanım
38
-
39
- ```typescript
40
- import { useFalGeneration } from '@umituz/react-native-ai-fal-provider';
41
-
42
- function ImageGenerator() {
43
- const { data, error, isLoading, generate, retry, cancel } = useFalGeneration({
44
- timeoutMs: 120000,
45
- onProgress: (status) => {
46
- console.log('Durum:', status.status);
47
- console.log('Sıra:', status.queuePosition);
48
- },
49
- onError: (error) => {
50
- console.error('Hata:', error.messageKey);
51
- },
52
- });
53
-
54
- const handleGenerate = async () => {
55
- await generate('fal-ai/flux/schnell', {
56
- prompt: 'Güneş batımında sahil kenarında yürüyen iki kişi',
57
- image_size: 'landscape_16_9',
58
- });
59
- };
60
-
61
- return (
62
- <View>
63
- <Button onPress={handleGenerate} disabled={isLoading} />
64
- {isLoading && (
65
- <>
66
- <ActivityIndicator />
67
- <Button title="İptal" onPress={cancel} />
68
- </>
69
- )}
70
- {error && (
71
- <>
72
- <Text>Hata: {error.messageKey}</Text>
73
- {error.retryable && <Button title="Tekrar Dene" onPress={retry} />}
74
- </>
75
- )}
76
- {data?.images?.[0]?.url && (
77
- <Image source={{ uri: data.images[0].url }} />
78
- )}
79
- </View>
80
- );
81
- }
82
- ```
83
-
84
- ### Video Oluşturma
85
-
86
- ```typescript
87
- function VideoGenerator() {
88
- const { data, isLoading, generate } = useFalGeneration({
89
- timeoutMs: 300000, // 5 dakika
90
- onProgress: (status) => {
91
- console.log(`İlerleme: ${status.status}`);
92
- if (status.queuePosition) {
93
- console.log(`Sırada: ${status.queuePosition}`);
94
- }
95
- },
96
- });
97
-
98
- const handleGenerate = async () => {
99
- await generate('fal-ai/minimax-video', {
100
- prompt: 'Yağmurlu bir Tokyo sokakta yürüyen insanlar',
101
- aspect_ratio: '16:9',
102
- });
103
- };
104
-
105
- return (
106
- <View>
107
- <Button onPress={handleGenerate} disabled={isLoading} />
108
- {isLoading && <ActivityIndicator />}
109
- {data?.video?.url && <Video source={{ uri: data.video.url }} />}
110
- </View>
111
- );
112
- }
113
- ```
114
-
115
- ### İptal Edilebilir İşlem
116
-
117
- ```typescript
118
- function CancellableGeneration() {
119
- const { data, isLoading, isCancelling, generate, cancel, reset } = useFalGeneration();
120
-
121
- const handleGenerate = async () => {
122
- await generate('fal-ai/flux/dev', {
123
- prompt: 'Profesyonel bir iş ortamı',
124
- });
125
- };
126
-
127
- return (
128
- <View>
129
- <Button onPress={handleGenerate} disabled={isLoading} />
130
- {isLoading && !isCancelling && (
131
- <Button title="İptal Et" onPress={cancel} color="red" />
132
- )}
133
- {isCancelling && <Text>İptal ediliyor...</Text>}
134
- <Button title="Sıfırla" onPress={reset} />
135
- {data && <Image source={{ uri: data.images[0].url }} />}
136
- </View>
137
- );
138
- }
139
- ```
140
-
141
- ### İlerleme Göstergesi
142
-
143
- ```typescript
144
- function ProgressIndicator() {
145
- const { isLoading, generate } = useFalGeneration({
146
- onProgress: (status) => {
147
- switch (status.status) {
148
- case 'IN_QUEUE':
149
- console.log(`Sırada: ${status.queuePosition ?? 'bilinmiyor'}`);
150
- break;
151
- case 'IN_PROGRESS':
152
- console.log('İşleniyor...');
153
- break;
154
- case 'COMPLETED':
155
- console.log('Tamamlandı!');
156
- break;
157
- }
158
-
159
- // Logları göster
160
- status.logs?.forEach((log) => {
161
- console.log(`[${log.level}] ${log.message}`);
162
- });
163
- },
164
- });
165
-
166
- return (
167
- <View>
168
- <Button onPress={() => generate(...)} />
169
- {isLoading && <ActivityIndicator />}
170
- </View>
171
- );
172
- }
173
- ```
174
-
175
- ## useModels
176
-
177
- Model seçimi ve yönetimi için React hook'u.
178
-
179
- ### Parametreler
180
-
181
- ```typescript
182
- interface UseModelsProps {
183
- readonly type: ModelType; // Model tipi
184
- readonly config?: ModelSelectionConfig; // Opsiyonel yapılandırma
185
- }
186
-
187
- interface ModelSelectionConfig {
188
- readonly initialModelId?: string; // Başlangıç modeli
189
- readonly defaultModelId?: string; // Varsayılan model ID
190
- readonly defaultCreditCost?: number; // Varsayılan kredi maliyeti
191
- }
192
- ```
193
-
194
- ### Dönüş Değeri
195
-
196
- ```typescript
197
- interface UseModelsReturn {
198
- models: FalModelConfig[]; // Mevcut modeller
199
- selectedModel: FalModelConfig | null; // Seçili model
200
- selectModel: (id: string) => void; // Model seçme fonksiyonu
201
- creditCost: number; // Seçili modelin maliyeti
202
- modelId: string; // Seçili modelin ID'si
203
- isLoading: boolean; // Yükleme durumu
204
- error: string | null; // Hata mesajı
205
- refreshModels: () => void; // Modelleri yenile
206
- }
207
- ```
208
-
209
- ### Model Seçimi
210
-
211
- ```typescript
212
- function ModelSelector() {
213
- const {
214
- models,
215
- selectedModel,
216
- selectModel,
217
- creditCost,
218
- modelId,
219
- isLoading,
220
- } = useModels({
221
- type: 'text-to-image',
222
- config: {
223
- defaultCreditCost: 2,
224
- defaultModelId: 'fal-ai/flux/schnell',
225
- initialModelId: 'fal-ai/flux/dev',
226
- },
227
- });
228
-
229
- if (isLoading) return <ActivityIndicator />;
230
-
231
- return (
232
- <View>
233
- <Text>Model Seçin:</Text>
234
- <Picker selectedValue={modelId} onValueChange={selectModel}>
235
- {models.map((model) => (
236
- <Picker.Item
237
- key={model.id}
238
- label={`${model.name} (${model.pricing?.freeUserCost} kredi)`}
239
- value={model.id}
240
- />
241
- ))}
242
- </Picker>
243
-
244
- <Text>Seçili: {selectedModel?.name}</Text>
245
- <Text>Maliyet: {creditCost} kredi</Text>
246
- <Text>{selectedModel?.description}</Text>
247
- </View>
248
- );
249
- }
250
- ```
251
-
252
- ### Model Karşılaştırma
253
-
254
- ```typescript
255
- function ModelComparison() {
256
- const { models, selectModel, modelId } = useModels({
257
- type: 'text-to-video',
258
- });
259
-
260
- return (
261
- <View>
262
- <Text>Modelleri Karşılaştırın:</Text>
263
- {models.map((model) => (
264
- <TouchableOpacity
265
- key={model.id}
266
- onPress={() => selectModel(model.id)}
267
- style={[
268
- styles.modelCard,
269
- model.id === modelId && styles.selected,
270
- ]}
271
- >
272
- <Text style={styles.name}>{model.name}</Text>
273
- <Text style={styles.cost}>
274
- Ücretsiz: {model.pricing?.freeUserCost} kredi
275
- </Text>
276
- <Text style={styles.cost}>
277
- Premium: {model.pricing?.premiumUserCost} kredi
278
- </Text>
279
- <Text style={styles.description}>{model.description}</Text>
280
- </TouchableOpacity>
281
- ))}
282
- </View>
283
- );
284
- }
285
- ```
286
-
287
- ## Birlikte Kullanım
288
-
289
- ### useFalGeneration + useModels
290
-
291
- ```typescript
292
- function AIImageGenerator() {
293
- // Model seçimi
294
- const {
295
- models,
296
- selectedModel,
297
- selectModel,
298
- creditCost,
299
- modelId,
300
- } = useModels({
301
- type: 'text-to-image',
302
- config: {
303
- defaultCreditCost: 2,
304
- initialModelId: 'fal-ai/flux/schnell',
305
- },
306
- });
307
-
308
- // Görsel oluşturma
309
- const { data, error, isLoading, generate, retry } = useFalGeneration({
310
- onError: (error) => {
311
- Alert.alert('Hata', error.messageKey);
312
- },
313
- });
314
-
315
- const handleGenerate = async (prompt: string) => {
316
- await generate(modelId, {
317
- prompt,
318
- image_size: 'landscape_16_9',
319
- });
320
- };
321
-
322
- return (
323
- <View>
324
- {/* Model Seçimi */}
325
- <Text>Model: {selectedModel?.name}</Text>
326
- <Text>Maliyet: {creditCost} kredi</Text>
327
-
328
- <Picker selectedValue={modelId} onValueChange={selectModel}>
329
- {models.map((model) => (
330
- <Picker.Item
331
- key={model.id}
332
- label={`${model.name} - ${model.pricing?.freeUserCost} kredi`}
333
- value={model.id}
334
- />
335
- ))}
336
- </Picker>
337
-
338
- {/* Prompt Girişi */}
339
- <TextInput
340
- placeholder="Görsel açıklaması girin..."
341
- onChangeText={setPrompt}
342
- />
343
-
344
- {/* Oluştur Butonu */}
345
- <Button
346
- title="Oluştur"
347
- onPress={() => handleGenerate(prompt)}
348
- disabled={isLoading || !prompt}
349
- />
350
-
351
- {/* Sonuç */}
352
- {isLoading && <ActivityIndicator />}
353
- {error && error.retryable && (
354
- <Button title="Tekrar Dene" onPress={retry} />
355
- )}
356
- {data?.images?.[0]?.url && (
357
- <Image source={{ uri: data.images[0].url }} style={{ width: '100%', height: 300 }} />
358
- )}
359
- </View>
360
- );
361
- }
362
- ```
363
-
364
- ## Örnek Uygulama
365
-
366
- ### Tam Özellikli AI Oluşturucu
367
-
368
- ```typescript
369
- import React, { useState } from 'react';
370
- import {
371
- View,
372
- Text,
373
- TextInput,
374
- Button,
375
- ActivityIndicator,
376
- Image,
377
- Picker,
378
- Alert,
379
- } from 'react-native';
380
- import { useFalGeneration, useModels } from '@umituz/react-native-ai-fal-provider';
381
-
382
- function AIGenerator() {
383
- const [prompt, setPrompt] = useState('');
384
- const [imageSize, setImageSize] = useState('landscape_16_9');
385
-
386
- const {
387
- models,
388
- selectedModel,
389
- selectModel,
390
- creditCost,
391
- modelId,
392
- } = useModels({
393
- type: 'text-to-image',
394
- config: {
395
- defaultCreditCost: 2,
396
- initialModelId: 'fal-ai/flux/schnell',
397
- },
398
- });
399
-
400
- const {
401
- data,
402
- error,
403
- isLoading,
404
- isRetryable,
405
- generate,
406
- retry,
407
- cancel,
408
- reset,
409
- } = useFalGeneration({
410
- timeoutMs: 120000,
411
- onProgress: (status) => {
412
- console.log('Durum:', status.status);
413
- if (status.queuePosition) {
414
- console.log('Sırada:', status.queuePosition);
415
- }
416
- },
417
- onError: (error) => {
418
- Alert.alert('Hata', error.messageKey);
419
- },
420
- });
421
-
422
- const handleGenerate = async () => {
423
- if (!prompt.trim()) {
424
- Alert.alert('Uyarı', 'Lütfen bir prompt girin');
425
- return;
426
- }
427
-
428
- await generate(modelId, {
429
- prompt: prompt.trim(),
430
- image_size: imageSize,
431
- num_inference_steps: 4,
432
- });
433
- };
434
-
435
- return (
436
- <View style={{ padding: 20 }}>
437
- <Text style={{ fontSize: 24, fontWeight: 'bold', marginBottom: 20 }}>
438
- AI Görsel Oluşturucu
439
- </Text>
440
-
441
- {/* Model Seçimi */}
442
- <View style={{ marginBottom: 20 }}>
443
- <Text>Model Seçin:</Text>
444
- <Picker
445
- selectedValue={modelId}
446
- onValueChange={selectModel}
447
- enabled={!isLoading}
448
- >
449
- {models.map((model) => (
450
- <Picker.Item
451
- key={model.id}
452
- label={`${model.name} (${model.pricing?.freeUserCost} kredi)`}
453
- value={model.id}
454
- />
455
- ))}
456
- </Picker>
457
- <Text>Seçili: {selectedModel?.name}</Text>
458
- <Text>Maliyet: {creditCost} kredi</Text>
459
- </View>
460
-
461
- {/* Image Size Seçimi */}
462
- <View style={{ marginBottom: 20 }}>
463
- <Text>Boyut:</Text>
464
- <Picker
465
- selectedValue={imageSize}
466
- onValueChange={setImageSize}
467
- enabled={!isLoading}
468
- >
469
- <Picker.Item label="Kare (1:1)" value="square_hd" />
470
- <Picker.Item label="Yatay (16:9)" value="landscape_16_9" />
471
- <Picker.Item label="Dikey (9:16)" value="portrait_9_16" />
472
- </Picker>
473
- </View>
474
-
475
- {/* Prompt Girişi */}
476
- <TextInput
477
- style={{
478
- borderWidth: 1,
479
- borderColor: '#ccc',
480
- borderRadius: 8,
481
- padding: 12,
482
- marginBottom: 20,
483
- minHeight: 100,
484
- }}
485
- placeholder="Oluşturmak istediğiniz görseli açıklayın..."
486
- value={prompt}
487
- onChangeText={setPrompt}
488
- multiline
489
- editable={!isLoading}
490
- maxLength: 1000
491
- />
492
-
493
- {/* Butonlar */}
494
- <View style={{ flexDirection: 'row', marginBottom: 20 }}>
495
- <View style={{ flex: 1, marginRight: 10 }}>
496
- <Button
497
- title="Oluştur"
498
- onPress={handleGenerate}
499
- disabled={isLoading || !prompt.trim()}
500
- />
501
- </View>
502
- {isLoading && (
503
- <View style={{ flex: 1 }}>
504
- <Button title="İptal" onPress={cancel} color="red" />
505
- </View>
506
- )}
507
- {error && isRetryable && (
508
- <View style={{ flex: 1 }}>
509
- <Button title="Tekrar Dene" onPress={retry} color="orange" />
510
- </View>
511
- )}
512
- {data && (
513
- <View style={{ flex: 1 }}>
514
- <Button title="Sıfırla" onPress={reset} color="gray" />
515
- </View>
516
- )}
517
- </View>
518
-
519
- {/* Durum */}
520
- {isLoading && (
521
- <View style={{ alignItems: 'center', marginBottom: 20 }}>
522
- <ActivityIndicator size="large" />
523
- <Text style={{ marginTop: 10 }}>
524
- Görsel oluşturuluyor...
525
- </Text>
526
- </View>
527
- )}
528
-
529
- {/* Sonuç */}
530
- {data?.images?.[0]?.url && (
531
- <View>
532
- <Text style={{ marginBottom: 10 }}>Sonuç:</Text>
533
- <Image
534
- source={{ uri: data.images[0].url }}
535
- style={{ width: '100%', height: 300, borderRadius: 8 }}
536
- resizeMode="contain"
537
- />
538
- </View>
539
- )}
540
- </View>
541
- );
542
- }
543
- ```
544
-
545
- ## İpuçları
546
-
547
- ### 1. Prompt Doğrulama
548
-
549
- ```typescript
550
- const isValidPrompt = (prompt: string) => {
551
- return prompt.trim().length >= 10 && prompt.trim().length <= 1000;
552
- };
553
- ```
554
-
555
- ### 2. Debounced Generate
556
-
557
- ```typescript
558
- import { debounce } from '@umituz/react-native-ai-fal-provider';
559
-
560
- const debouncedGenerate = debounce(
561
- (prompt) => generate(modelId, { prompt }),
562
- 1000
563
- );
564
- ```
565
-
566
- ### 3. Kredi Bakiyesi Kontrolü
567
-
568
- ```typescript
569
- const handleGenerate = async () => {
570
- const userCredits = await getUserCredits();
571
-
572
- if (userCredits < creditCost) {
573
- Alert.alert(
574
- 'Yetersiz Bakiye',
575
- `Bu işlem ${creditCost} kredi gerektirir. Sizin bakiyeniz: ${userCredits}`
576
- );
577
- return;
578
- }
579
-
580
- await generate(modelId, { prompt });
581
- };
582
- ```
583
-
584
- ### 4. Multiple Generations
585
-
586
- ```typescript
587
- const [generatedImages, setGeneratedImages] = useState<string[]>([]);
588
-
589
- const handleGenerate = async () => {
590
- const result = await generate(modelId, { prompt });
591
-
592
- if (result?.images) {
593
- setGeneratedImages(prev => [
594
- ...prev,
595
- ...result.images.map((img: any) => img.url)
596
- ]);
597
- }
598
- };
599
- ```
600
-
601
- ## TypeScript Desteği
602
-
603
- ```typescript
604
- import type {
605
- UseFalGenerationOptions,
606
- UseFalGenerationResult,
607
- UseModelsProps,
608
- UseModelsReturn,
609
- } from '@umituz/react-native-ai-fal-provider';
610
-
611
- // Tip tanımları
612
- interface ImageGenerationResult {
613
- images: Array<{ url: string }>;
614
- }
615
-
616
- const { data } = useFalGeneration<ImageGenerationResult>({
617
- timeoutMs: 120000,
618
- });
619
-
620
- // data artık ImageGenerationResult tipinde
621
- ```
622
-
623
- ## Daha Fazla Bilgi
624
-
625
- - [React Hooks Documentation](https://react.dev/reference/react)
626
- - [FAL AI Documentation](https://fal.ai/docs)
@@ -1,56 +0,0 @@
1
- /**
2
- * useModels Hook - Model selection management
3
- */
4
-
5
- import { useState, useCallback, useMemo, useEffect } from "react";
6
- import { falModelsService, type FalModelConfig } from "../../infrastructure/services/fal-models.service";
7
-
8
- export interface UseModelsProps {
9
- readonly models: FalModelConfig[];
10
- readonly initialModelId?: string;
11
- }
12
-
13
- export interface UseModelsReturn {
14
- readonly models: FalModelConfig[];
15
- readonly selectedModel: FalModelConfig | null;
16
- readonly selectModel: (modelId: string) => void;
17
- readonly modelId: string;
18
- }
19
-
20
- export function useModels(props: UseModelsProps): UseModelsReturn {
21
- const { models, initialModelId } = props;
22
-
23
- const sortedModels = useMemo(() => falModelsService.sortModels(models), [models]);
24
-
25
- const [selectedModel, setSelectedModel] = useState<FalModelConfig | null>(() => {
26
- if (initialModelId) {
27
- const initial = falModelsService.findById(initialModelId, sortedModels);
28
- if (initial) return initial;
29
- }
30
- return falModelsService.getDefaultModel(sortedModels) ?? null;
31
- });
32
-
33
- useEffect(() => {
34
- if (initialModelId) {
35
- const model = falModelsService.findById(initialModelId, sortedModels);
36
- if (model) setSelectedModel(model);
37
- }
38
- }, [initialModelId, sortedModels]);
39
-
40
- const selectModel = useCallback(
41
- (modelId: string) => {
42
- const model = falModelsService.findById(modelId, sortedModels);
43
- if (model) setSelectedModel(model);
44
- },
45
- [sortedModels]
46
- );
47
-
48
- const modelId = useMemo(() => selectedModel?.id ?? "", [selectedModel]);
49
-
50
- return {
51
- models: sortedModels,
52
- selectedModel,
53
- selectModel,
54
- modelId,
55
- };
56
- }