@umituz/react-native-ai-generation-content 1.12.25 → 1.12.29

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 (57) hide show
  1. package/package.json +3 -2
  2. package/src/domains/creations/application/services/CreationsService.ts +73 -0
  3. package/src/domains/creations/domain/entities/Creation.ts +60 -0
  4. package/src/domains/creations/domain/entities/index.ts +6 -0
  5. package/src/domains/creations/domain/repositories/ICreationsRepository.ts +23 -0
  6. package/src/domains/creations/domain/repositories/index.ts +5 -0
  7. package/src/domains/creations/domain/services/ICreationsStorageService.ts +13 -0
  8. package/src/domains/creations/domain/value-objects/CreationsConfig.ts +75 -0
  9. package/src/domains/creations/domain/value-objects/index.ts +12 -0
  10. package/src/domains/creations/index.ts +84 -0
  11. package/src/domains/creations/infrastructure/adapters/createRepository.ts +54 -0
  12. package/src/domains/creations/infrastructure/adapters/index.ts +5 -0
  13. package/src/domains/creations/infrastructure/repositories/CreationsRepository.ts +241 -0
  14. package/src/domains/creations/infrastructure/repositories/index.ts +8 -0
  15. package/src/domains/creations/infrastructure/services/CreationsStorageService.ts +49 -0
  16. package/src/domains/creations/presentation/components/CreationCard.tsx +136 -0
  17. package/src/domains/creations/presentation/components/CreationDetail/DetailActions.tsx +76 -0
  18. package/src/domains/creations/presentation/components/CreationDetail/DetailHeader.tsx +81 -0
  19. package/src/domains/creations/presentation/components/CreationDetail/DetailImage.tsx +41 -0
  20. package/src/domains/creations/presentation/components/CreationDetail/DetailStory.tsx +67 -0
  21. package/src/domains/creations/presentation/components/CreationDetail/index.ts +4 -0
  22. package/src/domains/creations/presentation/components/CreationImageViewer.tsx +43 -0
  23. package/src/domains/creations/presentation/components/CreationThumbnail.tsx +63 -0
  24. package/src/domains/creations/presentation/components/CreationsGrid.tsx +75 -0
  25. package/src/domains/creations/presentation/components/CreationsHomeCard.tsx +176 -0
  26. package/src/domains/creations/presentation/components/EmptyState.tsx +82 -0
  27. package/src/domains/creations/presentation/components/FilterBottomSheet.tsx +160 -0
  28. package/src/domains/creations/presentation/components/FilterChips.tsx +105 -0
  29. package/src/domains/creations/presentation/components/GalleryEmptyStates.tsx +87 -0
  30. package/src/domains/creations/presentation/components/GalleryHeader.tsx +106 -0
  31. package/src/domains/creations/presentation/components/index.ts +20 -0
  32. package/src/domains/creations/presentation/hooks/index.ts +7 -0
  33. package/src/domains/creations/presentation/hooks/useCreations.ts +38 -0
  34. package/src/domains/creations/presentation/hooks/useCreationsFilter.ts +77 -0
  35. package/src/domains/creations/presentation/hooks/useDeleteCreation.ts +51 -0
  36. package/src/domains/creations/presentation/screens/CreationDetailScreen.tsx +78 -0
  37. package/src/domains/creations/presentation/screens/CreationsGalleryScreen.tsx +194 -0
  38. package/src/domains/creations/presentation/screens/index.ts +5 -0
  39. package/src/domains/creations/presentation/utils/filterUtils.ts +52 -0
  40. package/src/domains/creations/types.d.ts +42 -0
  41. package/src/domains/prompts/infrastructure/services/AIServiceProcessor.ts +142 -0
  42. package/src/domains/prompts/presentation/hooks/useAIServices.ts +15 -132
  43. package/src/features/background/presentation/components/ComparisonSlider.tsx +2 -2
  44. package/src/features/background/presentation/components/ErrorDisplay.tsx +2 -2
  45. package/src/features/background/presentation/components/GenerateButton.tsx +0 -2
  46. package/src/features/background/presentation/components/ImagePicker.tsx +2 -2
  47. package/src/features/background/presentation/components/ResultDisplay.tsx +2 -2
  48. package/src/index.ts +6 -0
  49. package/src/infrastructure/services/generation-orchestrator.service.ts +25 -162
  50. package/src/infrastructure/services/job-poller.ts +103 -0
  51. package/src/infrastructure/services/progress-manager.ts +58 -0
  52. package/src/infrastructure/services/provider-validator.ts +52 -0
  53. package/src/presentation/components/GenerationProgressContent.tsx +4 -4
  54. package/src/presentation/components/PendingJobCard.tsx +2 -2
  55. package/src/presentation/components/PendingJobCardActions.tsx +2 -2
  56. package/src/presentation/components/result/GenerationResultContent.tsx +2 -3
  57. package/src/presentation/hooks/usePhotoGeneration.ts +7 -5
@@ -0,0 +1,142 @@
1
+ /**
2
+ * AI Service Processor
3
+ * Handles processing of different AI service types
4
+ */
5
+
6
+ import type { FaceSwapConfig } from '../../domain/entities/FaceSwapConfig';
7
+ import type { PhotoRestorationConfig } from '../../domain/entities/PhotoRestorationConfig';
8
+ import type { ImageEnhancementConfig } from '../../domain/entities/ImageEnhancementConfig';
9
+ import type { StyleTransferConfig } from '../../domain/entities/StyleTransferConfig';
10
+ import type { BackgroundRemovalConfig } from '../../domain/entities/BackgroundRemovalConfig';
11
+ import type { TextGenerationConfig } from '../../domain/entities/TextGenerationConfig';
12
+ import type { ColorizationConfig } from '../../domain/entities/ColorizationConfig';
13
+ import type {
14
+ IFaceSwapService,
15
+ IPhotoRestorationService,
16
+ IImageEnhancementService,
17
+ IStyleTransferService,
18
+ IBackgroundRemovalService,
19
+ ITextGenerationService,
20
+ IColorizationService,
21
+ } from '../../domain/repositories/IAIPromptServices';
22
+ import type { AIPromptResult } from '../../domain/entities/types';
23
+ import type { AIPromptTemplate } from '../../domain/entities/AIPromptTemplate';
24
+
25
+ export type AIConfig =
26
+ | { type: 'face-swap'; config: FaceSwapConfig }
27
+ | { type: 'photo-restoration'; config: PhotoRestorationConfig }
28
+ | { type: 'image-enhancement'; config: ImageEnhancementConfig }
29
+ | { type: 'style-transfer'; config: StyleTransferConfig }
30
+ | { type: 'background-removal'; config: BackgroundRemovalConfig }
31
+ | { type: 'text-generation'; config: TextGenerationConfig }
32
+ | { type: 'colorization'; config: ColorizationConfig };
33
+
34
+ export interface AIServices {
35
+ faceSwap: IFaceSwapService;
36
+ photoRestoration: IPhotoRestorationService;
37
+ imageEnhancement: IImageEnhancementService;
38
+ styleTransfer: IStyleTransferService;
39
+ backgroundRemoval: IBackgroundRemovalService;
40
+ textGeneration: ITextGenerationService;
41
+ colorization: IColorizationService;
42
+ }
43
+
44
+ export interface ProcessResult {
45
+ template: AIPromptTemplate;
46
+ prompt: string;
47
+ config: Record<string, unknown>;
48
+ }
49
+
50
+ export class AIServiceProcessor {
51
+ constructor(private services: AIServices) { }
52
+
53
+ async process(aiConfig: AIConfig): Promise<ProcessResult> {
54
+ const { templateResult, promptResult } = await this.executeService(aiConfig);
55
+
56
+ if (!templateResult?.success || !templateResult.data) {
57
+ throw new Error('Failed to generate template');
58
+ }
59
+
60
+ if (!promptResult?.success || !promptResult.data) {
61
+ throw new Error('Failed to generate prompt');
62
+ }
63
+
64
+ return {
65
+ template: templateResult.data,
66
+ prompt: promptResult.data,
67
+ config: aiConfig.config as unknown as Record<string, unknown>,
68
+ };
69
+ }
70
+
71
+ async getAvailableStyles(serviceType: string): Promise<string[]> {
72
+ switch (serviceType) {
73
+ case 'face-swap':
74
+ return await this.services.faceSwap.getAvailableStyles();
75
+ case 'style-transfer':
76
+ return await this.services.styleTransfer.getAvailableStyles();
77
+ default:
78
+ return [];
79
+ }
80
+ }
81
+
82
+ private async executeService(aiConfig: AIConfig): Promise<{
83
+ templateResult: AIPromptResult<AIPromptTemplate> | undefined;
84
+ promptResult: AIPromptResult<string> | undefined;
85
+ }> {
86
+ let templateResult: AIPromptResult<AIPromptTemplate> | undefined;
87
+ let promptResult: AIPromptResult<string> | undefined;
88
+
89
+ switch (aiConfig.type) {
90
+ case 'face-swap':
91
+ templateResult = await this.services.faceSwap.generateTemplate(aiConfig.config);
92
+ if (templateResult.success && templateResult.data) {
93
+ promptResult = await this.services.faceSwap.generatePrompt(templateResult.data, aiConfig.config);
94
+ }
95
+ break;
96
+
97
+ case 'photo-restoration':
98
+ templateResult = await this.services.photoRestoration.generateTemplate(aiConfig.config);
99
+ if (templateResult.success && templateResult.data) {
100
+ promptResult = await this.services.photoRestoration.generatePrompt(templateResult.data, aiConfig.config);
101
+ }
102
+ break;
103
+
104
+ case 'image-enhancement':
105
+ templateResult = await this.services.imageEnhancement.generateTemplate(aiConfig.config);
106
+ if (templateResult.success && templateResult.data) {
107
+ promptResult = await this.services.imageEnhancement.generatePrompt(templateResult.data, aiConfig.config);
108
+ }
109
+ break;
110
+
111
+ case 'style-transfer':
112
+ templateResult = await this.services.styleTransfer.generateTemplate(aiConfig.config);
113
+ if (templateResult.success && templateResult.data) {
114
+ promptResult = await this.services.styleTransfer.generatePrompt(templateResult.data, aiConfig.config);
115
+ }
116
+ break;
117
+
118
+ case 'background-removal':
119
+ templateResult = await this.services.backgroundRemoval.generateTemplate(aiConfig.config);
120
+ if (templateResult.success && templateResult.data) {
121
+ promptResult = await this.services.backgroundRemoval.generatePrompt(templateResult.data, aiConfig.config);
122
+ }
123
+ break;
124
+
125
+ case 'text-generation':
126
+ templateResult = await this.services.textGeneration.generateTemplate(aiConfig.config);
127
+ if (templateResult.success && templateResult.data) {
128
+ promptResult = await this.services.textGeneration.generatePrompt(templateResult.data, aiConfig.config);
129
+ }
130
+ break;
131
+
132
+ case 'colorization':
133
+ templateResult = await this.services.colorization.generateTemplate(aiConfig.config);
134
+ if (templateResult.success && templateResult.data) {
135
+ promptResult = await this.services.colorization.generatePrompt(templateResult.data, aiConfig.config);
136
+ }
137
+ break;
138
+ }
139
+
140
+ return { templateResult, promptResult };
141
+ }
142
+ }
@@ -1,50 +1,12 @@
1
- import { useState, useCallback } from 'react';
2
- import type {
3
- FaceSwapConfig
4
- } from '../../domain/entities/FaceSwapConfig';
5
- import type {
6
- PhotoRestorationConfig
7
- } from '../../domain/entities/PhotoRestorationConfig';
8
- import type {
9
- ImageEnhancementConfig
10
- } from '../../domain/entities/ImageEnhancementConfig';
11
- import type {
12
- StyleTransferConfig
13
- } from '../../domain/entities/StyleTransferConfig';
14
- import type {
15
- BackgroundRemovalConfig
16
- } from '../../domain/entities/BackgroundRemovalConfig';
17
- import type {
18
- TextGenerationConfig
19
- } from '../../domain/entities/TextGenerationConfig';
20
- import type {
21
- ColorizationConfig
22
- } from '../../domain/entities/ColorizationConfig';
23
- import type {
24
- IFaceSwapService,
25
- IPhotoRestorationService,
26
- IImageEnhancementService,
27
- IStyleTransferService,
28
- IBackgroundRemovalService,
29
- ITextGenerationService,
30
- IColorizationService
31
- } from '../../domain/repositories/IAIPromptServices';
1
+ import { useState, useCallback, useMemo } from 'react';
32
2
  import type { ITemplateRepository } from '../../domain/repositories/ITemplateRepository';
33
3
  import type { IPromptHistoryRepository } from '../../domain/repositories/IPromptHistoryRepository';
34
4
  import type { GeneratedPrompt } from '../../domain/entities/GeneratedPrompt';
35
5
  import { createGeneratedPrompt } from '../../domain/entities/GeneratedPrompt';
36
6
  import { useAsyncState } from './useAsyncState';
37
- import type { AIPromptResult } from '../../domain/entities/types';
38
- import type { AIPromptTemplate } from '../../domain/entities/AIPromptTemplate';
7
+ import { AIServiceProcessor, type AIConfig, type AIServices } from '../../infrastructure/services/AIServiceProcessor';
39
8
 
40
- export type AIConfig =
41
- | { type: 'face-swap'; config: FaceSwapConfig }
42
- | { type: 'photo-restoration'; config: PhotoRestorationConfig }
43
- | { type: 'image-enhancement'; config: ImageEnhancementConfig }
44
- | { type: 'style-transfer'; config: StyleTransferConfig }
45
- | { type: 'background-removal'; config: BackgroundRemovalConfig }
46
- | { type: 'text-generation'; config: TextGenerationConfig }
47
- | { type: 'colorization'; config: ColorizationConfig };
9
+ export type { AIConfig };
48
10
 
49
11
  export interface UseAIServicesState {
50
12
  generatedPrompt: GeneratedPrompt | null;
@@ -60,15 +22,7 @@ export interface UseAIServicesActions {
60
22
  }
61
23
 
62
24
  export const useAIServices = (
63
- services: {
64
- faceSwap: IFaceSwapService;
65
- photoRestoration: IPhotoRestorationService;
66
- imageEnhancement: IImageEnhancementService;
67
- styleTransfer: IStyleTransferService;
68
- backgroundRemoval: IBackgroundRemovalService;
69
- textGeneration: ITextGenerationService;
70
- colorization: IColorizationService;
71
- },
25
+ services: AIServices,
72
26
  repositories: {
73
27
  template: ITemplateRepository;
74
28
  history: IPromptHistoryRepository;
@@ -85,110 +39,39 @@ export const useAIServices = (
85
39
 
86
40
  const [currentService, setCurrentService] = useState<string | null>(null);
87
41
 
42
+ const processor = useMemo(() => new AIServiceProcessor(services), [services]);
43
+
88
44
  const processRequest = useCallback(async (aiConfig: AIConfig): Promise<void> => {
89
45
  clearError();
90
46
  setCurrentService(aiConfig.type);
91
47
 
92
48
  try {
93
- let templateResult: AIPromptResult<AIPromptTemplate> | undefined;
94
- let promptResult: AIPromptResult<string> | undefined;
95
-
96
- switch (aiConfig.type) {
97
- case 'face-swap':
98
- templateResult = await services.faceSwap.generateTemplate(aiConfig.config);
99
- if (templateResult.success && templateResult.data) {
100
- promptResult = await services.faceSwap.generatePrompt(templateResult.data, aiConfig.config);
101
- }
102
- break;
103
-
104
- case 'photo-restoration':
105
- templateResult = await services.photoRestoration.generateTemplate(aiConfig.config);
106
- if (templateResult.success && templateResult.data) {
107
- promptResult = await services.photoRestoration.generatePrompt(templateResult.data, aiConfig.config);
108
- }
109
- break;
110
-
111
- case 'image-enhancement':
112
- templateResult = await services.imageEnhancement.generateTemplate(aiConfig.config);
113
- if (templateResult.success && templateResult.data) {
114
- promptResult = await services.imageEnhancement.generatePrompt(templateResult.data, aiConfig.config);
115
- }
116
- break;
117
-
118
- case 'style-transfer':
119
- templateResult = await services.styleTransfer.generateTemplate(aiConfig.config);
120
- if (templateResult.success && templateResult.data) {
121
- promptResult = await services.styleTransfer.generatePrompt(templateResult.data, aiConfig.config);
122
- }
123
- break;
124
-
125
- case 'background-removal':
126
- templateResult = await services.backgroundRemoval.generateTemplate(aiConfig.config);
127
- if (templateResult.success && templateResult.data) {
128
- promptResult = await services.backgroundRemoval.generatePrompt(templateResult.data, aiConfig.config);
129
- }
130
- break;
131
-
132
- case 'text-generation':
133
- templateResult = await services.textGeneration.generateTemplate(aiConfig.config);
134
- if (templateResult.success && templateResult.data) {
135
- promptResult = await services.textGeneration.generatePrompt(templateResult.data, aiConfig.config);
136
- }
137
- break;
138
-
139
- case 'colorization':
140
- templateResult = await services.colorization.generateTemplate(aiConfig.config);
141
- if (templateResult.success && templateResult.data) {
142
- promptResult = await services.colorization.generatePrompt(templateResult.data, aiConfig.config);
143
- }
144
- break;
145
-
146
- default:
147
- setError('Unknown AI service type');
148
- return;
149
- }
150
-
151
- if (!templateResult?.success || !templateResult.data) {
152
- setError('Failed to generate template');
153
- return;
154
- }
155
-
156
- if (!promptResult?.success || !promptResult.data) {
157
- setError('Failed to generate prompt');
158
- return;
159
- }
49
+ const result = await processor.process(aiConfig);
160
50
 
161
51
  const newPrompt = createGeneratedPrompt({
162
- templateId: templateResult.data.id,
163
- generatedText: promptResult.data,
164
- variables: aiConfig.config as unknown as Record<string, unknown>,
52
+ templateId: result.template.id,
53
+ generatedText: result.prompt,
54
+ variables: result.config,
165
55
  });
166
56
 
167
57
  await repositories.history.save(newPrompt);
168
58
  setGeneratedPrompt(newPrompt);
169
59
 
170
- } catch {
171
- setError('An unexpected error occurred');
60
+ } catch (err) {
61
+ setError(err instanceof Error ? err.message : 'An unexpected error occurred');
172
62
  } finally {
173
63
  setCurrentService(null);
174
64
  }
175
- }, [services, repositories, setError, setGeneratedPrompt, clearError]);
65
+ }, [processor, repositories, setError, setGeneratedPrompt, clearError]);
176
66
 
177
67
  const getAvailableStyles = useCallback(async (serviceType: string): Promise<string[]> => {
178
68
  try {
179
- switch (serviceType) {
180
- case 'face-swap':
181
- return await services.faceSwap.getAvailableStyles();
182
- case 'style-transfer':
183
- return await services.styleTransfer.getAvailableStyles();
184
- default:
185
- return [];
186
- }
69
+ return await processor.getAvailableStyles(serviceType);
187
70
  } catch {
188
71
  setError('Failed to load available styles');
189
72
  return [];
190
73
  }
191
- }, [services, setError]);
74
+ }, [processor, setError]);
192
75
 
193
76
  const clearPrompt = useCallback(() => {
194
77
  setGeneratedPrompt(null);
@@ -129,7 +129,7 @@ export const ComparisonSlider: React.FC<ComparisonSliderProps> = memo(
129
129
  <View style={[styles.label, styles.labelLeft, themedStyles.labelLeft]}>
130
130
  <AtomicText
131
131
 
132
- color="textPrimary"
132
+
133
133
  >
134
134
  {beforeLabel}
135
135
  </AtomicText>
@@ -140,7 +140,7 @@ export const ComparisonSlider: React.FC<ComparisonSliderProps> = memo(
140
140
  <View style={[styles.label, styles.labelRight, themedStyles.labelRight]}>
141
141
  <AtomicText
142
142
 
143
- color="backgroundPrimary"
143
+
144
144
  >
145
145
  {afterLabel}
146
146
  </AtomicText>
@@ -31,11 +31,11 @@ export const ErrorDisplay: React.FC<ErrorDisplayProps> = memo(
31
31
  <AtomicIcon
32
32
  name="alert-circle"
33
33
  size="sm"
34
- color="error"
34
+
35
35
  />
36
36
  <AtomicText
37
37
 
38
- color="error"
38
+
39
39
  style={styles.errorText}
40
40
  >
41
41
  {error}
@@ -45,10 +45,8 @@ export const GenerateButton: React.FC<GenerateButtonProps> = memo(
45
45
  name="sparkles"
46
46
  size="md"
47
47
  color={disabled ? "surfaceVariant" : "onPrimary"}
48
- style={styles.icon}
49
48
  />
50
49
  <AtomicText
51
-
52
50
  style={[
53
51
  styles.text,
54
52
  {
@@ -45,7 +45,7 @@ export const ImagePicker: React.FC<ImagePickerProps> = memo(
45
45
  <AtomicIcon
46
46
  name="image-plus"
47
47
  size="md"
48
- color="onPrimary"
48
+
49
49
  />
50
50
  </View>
51
51
  </View>
@@ -66,7 +66,7 @@ export const ImagePicker: React.FC<ImagePickerProps> = memo(
66
66
  <AtomicIcon
67
67
  name="upload"
68
68
  size="lg"
69
- color="primary"
69
+
70
70
  />
71
71
  </View>
72
72
  <AtomicText
@@ -48,7 +48,7 @@ export const ResultDisplay: React.FC<ResultDisplayProps> = memo(
48
48
  <AtomicIcon
49
49
  name="refresh-cw"
50
50
  size="md"
51
- color="onSurface"
51
+
52
52
  />
53
53
  <AtomicText
54
54
 
@@ -68,7 +68,7 @@ export const ResultDisplay: React.FC<ResultDisplayProps> = memo(
68
68
  <AtomicIcon
69
69
  name="download"
70
70
  size="md"
71
- color="onPrimary"
71
+
72
72
  />
73
73
  <AtomicText
74
74
 
package/src/index.ts CHANGED
@@ -234,6 +234,12 @@ export * from "./domains/prompts";
234
234
 
235
235
  export * from "./domains/content-moderation";
236
236
 
237
+ // =============================================================================
238
+ // DOMAINS - Creations
239
+ // =============================================================================
240
+
241
+ export * from "./domains/creations";
242
+
237
243
  // =============================================================================
238
244
  // DOMAINS - Face Detection
239
245
  // =============================================================================
@@ -9,15 +9,10 @@ import type {
9
9
  GenerationProgress,
10
10
  PollingConfig,
11
11
  } from "../../domain/entities";
12
- import { DEFAULT_POLLING_CONFIG } from "../../domain/entities";
13
- import type { IAIProvider, JobStatus } from "../../domain/interfaces";
14
- import { providerRegistry } from "./provider-registry.service";
15
- import {
16
- classifyError,
17
- isTransientError,
18
- } from "../utils/error-classifier.util";
19
- import { createPollingDelay } from "../utils/polling-interval.util";
20
- import { createProgressTracker } from "../utils/progress-calculator.util";
12
+ import { classifyError } from "../utils/error-classifier.util";
13
+ import { ProgressManager } from "./progress-manager";
14
+ import { JobPoller, type PollerConfig } from "./job-poller";
15
+ import { ProviderValidator } from "./provider-validator";
21
16
 
22
17
  declare const __DEV__: boolean;
23
18
 
@@ -27,7 +22,9 @@ export interface OrchestratorConfig {
27
22
  }
28
23
 
29
24
  class GenerationOrchestratorService {
30
- private config: OrchestratorConfig = {};
25
+ private progressManager = new ProgressManager();
26
+ private jobPoller = new JobPoller();
27
+ private providerValidator = new ProviderValidator();
31
28
 
32
29
  configure(config: OrchestratorConfig): void {
33
30
  if (typeof __DEV__ !== "undefined" && __DEV__) {
@@ -37,14 +34,19 @@ class GenerationOrchestratorService {
37
34
  hasStatusUpdate: !!config.onStatusUpdate,
38
35
  });
39
36
  }
40
- this.config = { ...this.config, ...config };
37
+
38
+ const pollerConfig: PollerConfig = {
39
+ polling: config.polling,
40
+ onStatusUpdate: config.onStatusUpdate,
41
+ };
42
+
43
+ this.jobPoller.configure(pollerConfig);
41
44
  }
42
45
 
43
46
  async generate<T = unknown>(
44
47
  request: GenerationRequest,
45
48
  ): Promise<GenerationResult<T>> {
46
- const provider = this.getProvider();
47
- const progressTracker = createProgressTracker();
49
+ const provider = this.providerValidator.getProvider();
48
50
  const startTime = Date.now();
49
51
 
50
52
  if (typeof __DEV__ !== "undefined" && __DEV__) {
@@ -60,11 +62,7 @@ class GenerationOrchestratorService {
60
62
  stage: GenerationProgress["stage"],
61
63
  subProgress = 0,
62
64
  ) => {
63
- const progress = progressTracker.setStatus(stage);
64
- request.onProgress?.({
65
- stage,
66
- progress: progress + subProgress,
67
- });
65
+ this.progressManager.updateProgress(stage, subProgress, request.onProgress);
68
66
  };
69
67
 
70
68
  try {
@@ -84,11 +82,19 @@ class GenerationOrchestratorService {
84
82
 
85
83
  updateProgress("generating");
86
84
 
87
- const result = await this.pollForResult<T>(
85
+ const result = await this.jobPoller.pollForResult<T>(
88
86
  provider,
89
87
  request.model,
90
88
  submission.requestId,
91
89
  request.onProgress,
90
+ (status, attempt, config) => {
91
+ this.progressManager.updateProgressFromStatus(
92
+ status,
93
+ attempt,
94
+ config,
95
+ request.onProgress,
96
+ );
97
+ },
92
98
  );
93
99
 
94
100
  updateProgress("completed");
@@ -139,149 +145,6 @@ class GenerationOrchestratorService {
139
145
  };
140
146
  }
141
147
  }
142
-
143
- private async pollForResult<T>(
144
- provider: IAIProvider,
145
- model: string,
146
- requestId: string,
147
- onProgress?: (progress: GenerationProgress) => void,
148
- ): Promise<T> {
149
- if (typeof __DEV__ !== "undefined" && __DEV__) {
150
- // eslint-disable-next-line no-console
151
- console.log("[Orchestrator] pollForResult() started", {
152
- provider: provider.providerId,
153
- model,
154
- requestId,
155
- });
156
- }
157
-
158
- const config = {
159
- ...DEFAULT_POLLING_CONFIG,
160
- ...this.config.polling,
161
- };
162
-
163
- let consecutiveErrors = 0;
164
-
165
- for (let attempt = 0; attempt < config.maxAttempts; attempt++) {
166
- await createPollingDelay(attempt, config);
167
-
168
- if (typeof __DEV__ !== "undefined" && __DEV__ && attempt % 5 === 0) {
169
- // eslint-disable-next-line no-console
170
- console.log("[Orchestrator] pollForResult() attempt", {
171
- attempt,
172
- maxAttempts: config.maxAttempts,
173
- });
174
- }
175
-
176
- try {
177
- const status = await provider.getJobStatus(model, requestId);
178
-
179
- consecutiveErrors = 0;
180
-
181
- this.updateProgressFromStatus(status, attempt, config, onProgress);
182
-
183
- if (status.status === "COMPLETED") {
184
- if (typeof __DEV__ !== "undefined" && __DEV__) {
185
- // eslint-disable-next-line no-console
186
- console.log("[Orchestrator] pollForResult() job COMPLETED", {
187
- requestId,
188
- attempt,
189
- });
190
- }
191
- return provider.getJobResult<T>(model, requestId);
192
- }
193
-
194
- if (status.status === "FAILED") {
195
- throw new Error("Job failed on provider");
196
- }
197
-
198
- await this.config.onStatusUpdate?.(requestId, status.status);
199
- } catch (error) {
200
- if (isTransientError(error)) {
201
- consecutiveErrors++;
202
-
203
- if (consecutiveErrors >= config.maxConsecutiveErrors) {
204
- throw error;
205
- }
206
-
207
- continue;
208
- }
209
-
210
- throw error;
211
- }
212
- }
213
-
214
- throw new Error(
215
- `Polling timeout after ${config.maxAttempts} attempts`,
216
- );
217
- }
218
-
219
- private updateProgressFromStatus(
220
- status: JobStatus,
221
- attempt: number,
222
- config: PollingConfig,
223
- onProgress?: (progress: GenerationProgress) => void,
224
- ): void {
225
- const baseProgress = 25;
226
- const maxProgress = 85;
227
- const range = maxProgress - baseProgress;
228
-
229
- let progress: number;
230
-
231
- if (status.status === "IN_QUEUE") {
232
- progress = baseProgress + range * 0.2;
233
- } else if (status.status === "IN_PROGRESS") {
234
- const ratio = Math.min(attempt / (config.maxAttempts * 0.7), 1);
235
- progress = baseProgress + range * (0.2 + 0.6 * ratio);
236
- } else {
237
- progress = baseProgress;
238
- }
239
-
240
- onProgress?.({
241
- stage: "generating",
242
- progress: Math.round(progress),
243
- eta: status.eta,
244
- });
245
- }
246
-
247
- private getProvider(): IAIProvider {
248
- if (typeof __DEV__ !== "undefined" && __DEV__) {
249
- // eslint-disable-next-line no-console
250
- console.log("[Orchestrator] getProvider() called");
251
- }
252
-
253
- const provider = providerRegistry.getActiveProvider();
254
-
255
- if (!provider) {
256
- if (typeof __DEV__ !== "undefined" && __DEV__) {
257
- // eslint-disable-next-line no-console
258
- console.error("[Orchestrator] No active provider found!");
259
- }
260
- throw new Error(
261
- "No active AI provider. Register and set a provider first.",
262
- );
263
- }
264
-
265
- if (!provider.isInitialized()) {
266
- if (typeof __DEV__ !== "undefined" && __DEV__) {
267
- // eslint-disable-next-line no-console
268
- console.error("[Orchestrator] Provider not initialized:", provider.providerId);
269
- }
270
- throw new Error(
271
- `Provider ${provider.providerId} is not initialized.`,
272
- );
273
- }
274
-
275
- if (typeof __DEV__ !== "undefined" && __DEV__) {
276
- // eslint-disable-next-line no-console
277
- console.log("[Orchestrator] getProvider() returning:", {
278
- providerId: provider.providerId,
279
- isInitialized: provider.isInitialized(),
280
- });
281
- }
282
-
283
- return provider;
284
- }
285
148
  }
286
149
 
287
150
  export const generationOrchestrator = new GenerationOrchestratorService();