@umituz/react-native-ai-generation-content 1.6.0 → 1.8.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/package.json
CHANGED
|
@@ -42,7 +42,10 @@ export interface JobExecutorConfig<TInput = unknown, TResult = unknown> {
|
|
|
42
42
|
readonly timeoutMs?: number;
|
|
43
43
|
}
|
|
44
44
|
|
|
45
|
+
export type GenerationMode = "direct" | "queued";
|
|
46
|
+
|
|
45
47
|
export interface BackgroundQueueConfig {
|
|
48
|
+
readonly mode?: GenerationMode;
|
|
46
49
|
readonly maxConcurrent?: number;
|
|
47
50
|
readonly retryCount?: number;
|
|
48
51
|
readonly retryDelayMs?: number;
|
|
@@ -50,6 +53,7 @@ export interface BackgroundQueueConfig {
|
|
|
50
53
|
}
|
|
51
54
|
|
|
52
55
|
export const DEFAULT_QUEUE_CONFIG: Required<BackgroundQueueConfig> = {
|
|
56
|
+
mode: "queued",
|
|
53
57
|
maxConcurrent: 1,
|
|
54
58
|
retryCount: 2,
|
|
55
59
|
retryDelayMs: 2000,
|
package/src/index.ts
CHANGED
|
@@ -55,6 +55,7 @@ export type {
|
|
|
55
55
|
UpdateJobInput,
|
|
56
56
|
JobExecutorConfig,
|
|
57
57
|
BackgroundQueueConfig,
|
|
58
|
+
GenerationMode,
|
|
58
59
|
} from "./domain/entities";
|
|
59
60
|
|
|
60
61
|
export { DEFAULT_POLLING_CONFIG, DEFAULT_PROGRESS_STAGES, DEFAULT_QUEUE_CONFIG } from "./domain/entities";
|
|
@@ -146,6 +147,7 @@ export type {
|
|
|
146
147
|
UsePendingJobsReturn,
|
|
147
148
|
UseBackgroundGenerationOptions,
|
|
148
149
|
UseBackgroundGenerationReturn,
|
|
150
|
+
DirectExecutionResult,
|
|
149
151
|
} from "./presentation/hooks";
|
|
150
152
|
|
|
151
153
|
// =============================================================================
|
|
@@ -4,7 +4,13 @@
|
|
|
4
4
|
*/
|
|
5
5
|
|
|
6
6
|
import React from "react";
|
|
7
|
-
import {
|
|
7
|
+
import {
|
|
8
|
+
Modal,
|
|
9
|
+
View,
|
|
10
|
+
Text,
|
|
11
|
+
TouchableOpacity,
|
|
12
|
+
StyleSheet,
|
|
13
|
+
} from "react-native";
|
|
8
14
|
|
|
9
15
|
export interface GenerationProgressModalProps {
|
|
10
16
|
visible: boolean;
|
|
@@ -12,11 +18,14 @@ export interface GenerationProgressModalProps {
|
|
|
12
18
|
title?: string;
|
|
13
19
|
message?: string;
|
|
14
20
|
hint?: string;
|
|
21
|
+
dismissLabel?: string;
|
|
22
|
+
onDismiss?: () => void;
|
|
15
23
|
overlayColor?: string;
|
|
16
24
|
modalBackgroundColor?: string;
|
|
17
25
|
textColor?: string;
|
|
18
26
|
progressColor?: string;
|
|
19
27
|
progressBackgroundColor?: string;
|
|
28
|
+
dismissButtonColor?: string;
|
|
20
29
|
renderContent?: (props: GenerationProgressRenderProps) => React.ReactNode;
|
|
21
30
|
}
|
|
22
31
|
|
|
@@ -25,6 +34,7 @@ export interface GenerationProgressRenderProps {
|
|
|
25
34
|
title?: string;
|
|
26
35
|
message?: string;
|
|
27
36
|
hint?: string;
|
|
37
|
+
onDismiss?: () => void;
|
|
28
38
|
}
|
|
29
39
|
|
|
30
40
|
export const GenerationProgressModal: React.FC<
|
|
@@ -35,11 +45,14 @@ export const GenerationProgressModal: React.FC<
|
|
|
35
45
|
title,
|
|
36
46
|
message,
|
|
37
47
|
hint,
|
|
48
|
+
dismissLabel = "Got it",
|
|
49
|
+
onDismiss,
|
|
38
50
|
overlayColor = "rgba(0, 0, 0, 0.7)",
|
|
39
51
|
modalBackgroundColor = "#1C1C1E",
|
|
40
52
|
textColor = "#FFFFFF",
|
|
41
53
|
progressColor = "#007AFF",
|
|
42
54
|
progressBackgroundColor = "#3A3A3C",
|
|
55
|
+
dismissButtonColor = "#007AFF",
|
|
43
56
|
renderContent,
|
|
44
57
|
}) => {
|
|
45
58
|
const clampedProgress = Math.max(0, Math.min(100, progress));
|
|
@@ -53,7 +66,13 @@ export const GenerationProgressModal: React.FC<
|
|
|
53
66
|
statusBarTranslucent
|
|
54
67
|
>
|
|
55
68
|
<View style={[styles.overlay, { backgroundColor: overlayColor }]}>
|
|
56
|
-
{renderContent({
|
|
69
|
+
{renderContent({
|
|
70
|
+
progress: clampedProgress,
|
|
71
|
+
title,
|
|
72
|
+
message,
|
|
73
|
+
hint,
|
|
74
|
+
onDismiss,
|
|
75
|
+
})}
|
|
57
76
|
</View>
|
|
58
77
|
</Modal>
|
|
59
78
|
);
|
|
@@ -105,6 +124,18 @@ export const GenerationProgressModal: React.FC<
|
|
|
105
124
|
{hint && (
|
|
106
125
|
<Text style={[styles.hint, { color: textColor }]}>{hint}</Text>
|
|
107
126
|
)}
|
|
127
|
+
|
|
128
|
+
{onDismiss && (
|
|
129
|
+
<TouchableOpacity
|
|
130
|
+
style={[
|
|
131
|
+
styles.dismissButton,
|
|
132
|
+
{ backgroundColor: dismissButtonColor },
|
|
133
|
+
]}
|
|
134
|
+
onPress={onDismiss}
|
|
135
|
+
>
|
|
136
|
+
<Text style={styles.dismissText}>{dismissLabel}</Text>
|
|
137
|
+
</TouchableOpacity>
|
|
138
|
+
)}
|
|
108
139
|
</View>
|
|
109
140
|
</View>
|
|
110
141
|
</Modal>
|
|
@@ -162,5 +193,19 @@ const styles = StyleSheet.create({
|
|
|
162
193
|
textAlign: "center",
|
|
163
194
|
fontStyle: "italic",
|
|
164
195
|
opacity: 0.6,
|
|
196
|
+
marginBottom: 16,
|
|
197
|
+
},
|
|
198
|
+
dismissButton: {
|
|
199
|
+
marginTop: 8,
|
|
200
|
+
paddingVertical: 14,
|
|
201
|
+
paddingHorizontal: 32,
|
|
202
|
+
borderRadius: 12,
|
|
203
|
+
minWidth: 140,
|
|
204
|
+
alignItems: "center",
|
|
205
|
+
},
|
|
206
|
+
dismissText: {
|
|
207
|
+
color: "#FFFFFF",
|
|
208
|
+
fontSize: 16,
|
|
209
|
+
fontWeight: "600",
|
|
165
210
|
},
|
|
166
211
|
});
|
|
@@ -1,9 +1,11 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* useBackgroundGeneration Hook
|
|
3
|
-
* Executes AI generation tasks
|
|
3
|
+
* Executes AI generation tasks with optional queue management
|
|
4
|
+
* - mode: 'direct' - Execute immediately, no queue UI (for images)
|
|
5
|
+
* - mode: 'queued' - Use pending jobs queue with UI (for videos)
|
|
4
6
|
*/
|
|
5
7
|
|
|
6
|
-
import { useCallback, useRef } from "react";
|
|
8
|
+
import { useCallback, useRef, useState } from "react";
|
|
7
9
|
import { usePendingJobs } from "./use-pending-jobs";
|
|
8
10
|
import type {
|
|
9
11
|
BackgroundJob,
|
|
@@ -18,15 +20,27 @@ export interface UseBackgroundGenerationOptions<TInput, TResult>
|
|
|
18
20
|
readonly onJobComplete?: (job: BackgroundJob<TInput, TResult>) => void;
|
|
19
21
|
readonly onJobError?: (job: BackgroundJob<TInput, TResult>) => void;
|
|
20
22
|
readonly onAllComplete?: () => void;
|
|
23
|
+
readonly onProgress?: (progress: number) => void;
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
export interface DirectExecutionResult<TResult> {
|
|
27
|
+
readonly success: boolean;
|
|
28
|
+
readonly result?: TResult;
|
|
29
|
+
readonly error?: string;
|
|
21
30
|
}
|
|
22
31
|
|
|
23
32
|
export interface UseBackgroundGenerationReturn<TInput, TResult> {
|
|
24
33
|
readonly startJob: (input: TInput, type: string) => Promise<string>;
|
|
34
|
+
readonly executeDirectly: (
|
|
35
|
+
input: TInput,
|
|
36
|
+
) => Promise<DirectExecutionResult<TResult>>;
|
|
25
37
|
readonly cancelJob: (id: string) => void;
|
|
26
38
|
readonly retryJob: (id: string) => void;
|
|
27
39
|
readonly pendingJobs: BackgroundJob<TInput, TResult>[];
|
|
28
40
|
readonly activeJobCount: number;
|
|
29
41
|
readonly hasActiveJobs: boolean;
|
|
42
|
+
readonly isProcessing: boolean;
|
|
43
|
+
readonly progress: number;
|
|
30
44
|
}
|
|
31
45
|
|
|
32
46
|
export function useBackgroundGeneration<TInput = unknown, TResult = unknown>(
|
|
@@ -38,16 +52,41 @@ export function useBackgroundGeneration<TInput = unknown, TResult = unknown>(
|
|
|
38
52
|
new Map(),
|
|
39
53
|
);
|
|
40
54
|
|
|
41
|
-
const
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
55
|
+
const [isProcessing, setIsProcessing] = useState(false);
|
|
56
|
+
const [progress, setProgress] = useState(0);
|
|
57
|
+
|
|
58
|
+
const { jobs, addJobAsync, updateJob, removeJob, getJob } = usePendingJobs<
|
|
59
|
+
TInput,
|
|
60
|
+
TResult
|
|
61
|
+
>({
|
|
48
62
|
queryKey: config.queryKey,
|
|
49
63
|
});
|
|
50
64
|
|
|
65
|
+
const executeDirectly = useCallback(
|
|
66
|
+
async (input: TInput): Promise<DirectExecutionResult<TResult>> => {
|
|
67
|
+
const { executor } = options;
|
|
68
|
+
|
|
69
|
+
setIsProcessing(true);
|
|
70
|
+
setProgress(0);
|
|
71
|
+
|
|
72
|
+
try {
|
|
73
|
+
const result = await executor.execute(input, (p) => {
|
|
74
|
+
setProgress(p);
|
|
75
|
+
options.onProgress?.(p);
|
|
76
|
+
});
|
|
77
|
+
|
|
78
|
+
setProgress(100);
|
|
79
|
+
return { success: true, result };
|
|
80
|
+
} catch (error) {
|
|
81
|
+
const errorMsg = error instanceof Error ? error.message : String(error);
|
|
82
|
+
return { success: false, error: errorMsg };
|
|
83
|
+
} finally {
|
|
84
|
+
setIsProcessing(false);
|
|
85
|
+
}
|
|
86
|
+
},
|
|
87
|
+
[options],
|
|
88
|
+
);
|
|
89
|
+
|
|
51
90
|
const executeJob = useCallback(
|
|
52
91
|
async (jobId: string, input: TInput) => {
|
|
53
92
|
const { executor } = options;
|
|
@@ -58,8 +97,8 @@ export function useBackgroundGeneration<TInput = unknown, TResult = unknown>(
|
|
|
58
97
|
updates: { status: "processing", progress: 10 },
|
|
59
98
|
});
|
|
60
99
|
|
|
61
|
-
const result = await executor.execute(input, (
|
|
62
|
-
updateJob({ id: jobId, updates: { progress } });
|
|
100
|
+
const result = await executor.execute(input, (p) => {
|
|
101
|
+
updateJob({ id: jobId, updates: { progress: p } });
|
|
63
102
|
});
|
|
64
103
|
|
|
65
104
|
updateJob({
|
|
@@ -84,11 +123,7 @@ export function useBackgroundGeneration<TInput = unknown, TResult = unknown>(
|
|
|
84
123
|
|
|
85
124
|
updateJob({
|
|
86
125
|
id: jobId,
|
|
87
|
-
updates: {
|
|
88
|
-
status: "failed",
|
|
89
|
-
error: errorMsg,
|
|
90
|
-
progress: 0,
|
|
91
|
-
},
|
|
126
|
+
updates: { status: "failed", error: errorMsg, progress: 0 },
|
|
92
127
|
});
|
|
93
128
|
|
|
94
129
|
const failedJob = getJob(jobId);
|
|
@@ -101,7 +136,6 @@ export function useBackgroundGeneration<TInput = unknown, TResult = unknown>(
|
|
|
101
136
|
}
|
|
102
137
|
} finally {
|
|
103
138
|
activeJobsRef.current.delete(jobId);
|
|
104
|
-
|
|
105
139
|
if (activeJobsRef.current.size === 0) {
|
|
106
140
|
options.onAllComplete?.();
|
|
107
141
|
}
|
|
@@ -125,7 +159,6 @@ export function useBackgroundGeneration<TInput = unknown, TResult = unknown>(
|
|
|
125
159
|
});
|
|
126
160
|
|
|
127
161
|
activeJobsRef.current.add(jobId);
|
|
128
|
-
|
|
129
162
|
executeJob(jobId, input);
|
|
130
163
|
|
|
131
164
|
return jobId;
|
|
@@ -146,7 +179,6 @@ export function useBackgroundGeneration<TInput = unknown, TResult = unknown>(
|
|
|
146
179
|
(id: string) => {
|
|
147
180
|
const jobData = jobInputsRef.current.get(id);
|
|
148
181
|
if (!jobData) return;
|
|
149
|
-
|
|
150
182
|
removeJob(id);
|
|
151
183
|
startJob(jobData.input, jobData.type);
|
|
152
184
|
},
|
|
@@ -155,10 +187,13 @@ export function useBackgroundGeneration<TInput = unknown, TResult = unknown>(
|
|
|
155
187
|
|
|
156
188
|
return {
|
|
157
189
|
startJob,
|
|
190
|
+
executeDirectly,
|
|
158
191
|
cancelJob,
|
|
159
192
|
retryJob,
|
|
160
193
|
pendingJobs: jobs,
|
|
161
194
|
activeJobCount: activeJobsRef.current.size,
|
|
162
195
|
hasActiveJobs: activeJobsRef.current.size > 0,
|
|
196
|
+
isProcessing,
|
|
197
|
+
progress,
|
|
163
198
|
};
|
|
164
199
|
}
|