sushilideaclan01 commited on
Commit
9de719c
Β·
1 Parent(s): addcf34

Refactor extensive ad generation to support batch responses

Browse files

- Updated the API endpoint to return all generated ads instead of just the first one, enhancing the batch generation feature.
- Modified the frontend components to handle and display batch results, including updates to the GeneratePage and ExtensiveForm for better user feedback.
- Changed variable names and comments for clarity, ensuring consistency in terminology related to ad images and variations.
- Improved error handling and logging in the generator service to accommodate the new batch processing logic.

frontend/app/generate/matrix/page.tsx CHANGED
@@ -170,7 +170,7 @@ export default function MatrixGeneratePage() {
170
 
171
  <div>
172
  <label className="block text-sm font-semibold text-gray-700 mb-2">
173
- Number of Images: <span className="text-cyan-600 font-bold">{numImages}</span>
174
  </label>
175
  <input
176
  type="range"
 
170
 
171
  <div>
172
  <label className="block text-sm font-semibold text-gray-700 mb-2">
173
+ Number of Ad Images: <span className="text-cyan-600 font-bold">{numImages}</span>
174
  </label>
175
  <input
176
  type="range"
frontend/app/generate/page.tsx CHANGED
@@ -491,7 +491,7 @@ export default function GeneratePage() {
491
  message: progressSteps[0].message,
492
  });
493
 
494
- // Generate ad using extensive
495
  const result = await generateExtensiveAd(data);
496
 
497
  // Clear progress interval
@@ -500,12 +500,9 @@ export default function GeneratePage() {
500
  progressInterval = null;
501
  }
502
 
503
- // Verify all images are included
504
- if (result.images && result.images.length > 0) {
505
- console.log(`βœ“ Extensive generation completed with ${result.images.length} image(s)`);
506
- console.log(`πŸ“… Generated at: ${result.created_at || 'N/A'}`);
507
- console.log(`πŸ“Š Note: Generate page shows images from the first strategy only. All strategies are saved separately in the database and appear on the Dashboard.`);
508
- }
509
 
510
  setProgress({
511
  step: "saving",
@@ -516,14 +513,18 @@ export default function GeneratePage() {
516
  // Small delay to show saving step
517
  await new Promise(resolve => setTimeout(resolve, 500));
518
 
519
- setCurrentGeneration(result);
 
 
 
 
520
  setProgress({
521
  step: "complete",
522
  progress: 100,
523
  message: "Ad generated successfully!",
524
  });
525
 
526
- toast.success("Ad generated successfully using Extensive!");
527
  } catch (error: any) {
528
  // Clear progress interval on error
529
  if (progressInterval) {
@@ -701,7 +702,7 @@ export default function GeneratePage() {
701
 
702
  <div>
703
  <label className="block text-sm font-semibold text-gray-700 mb-2">
704
- Number of Images: <span className="text-blue-600 font-bold">{numImages}</span>
705
  </label>
706
  <input
707
  type="range"
 
491
  message: progressSteps[0].message,
492
  });
493
 
494
+ // Generate ad using extensive - returns BatchResponse like batch flow
495
  const result = await generateExtensiveAd(data);
496
 
497
  // Clear progress interval
 
500
  progressInterval = null;
501
  }
502
 
503
+ // Store results like batch generation
504
+ setBatchResults(result.ads);
505
+ setCurrentBatchIndex(0);
 
 
 
506
 
507
  setProgress({
508
  step: "saving",
 
513
  // Small delay to show saving step
514
  await new Promise(resolve => setTimeout(resolve, 500));
515
 
516
+ // Show first result
517
+ if (result.ads.length > 0) {
518
+ setCurrentGeneration(result.ads[0]);
519
+ }
520
+
521
  setProgress({
522
  step: "complete",
523
  progress: 100,
524
  message: "Ad generated successfully!",
525
  });
526
 
527
+ toast.success(`Generated ${result.count} ad(s) successfully using Extensive!`);
528
  } catch (error: any) {
529
  // Clear progress interval on error
530
  if (progressInterval) {
 
702
 
703
  <div>
704
  <label className="block text-sm font-semibold text-gray-700 mb-2">
705
+ Number of Ad Images: <span className="text-blue-600 font-bold">{numImages}</span>
706
  </label>
707
  <input
708
  type="range"
frontend/components/generation/AdPreview.tsx CHANGED
@@ -238,29 +238,6 @@ export const AdPreview: React.FC<AdPreviewProps> = ({ ad }) => {
238
  </div>
239
  )}
240
 
241
- {/* Headline */}
242
- <div className="bg-white rounded-2xl shadow-lg shadow-blue-100/30 p-6 border-l-4 border-blue-500">
243
- <div className="flex items-start justify-between gap-4 mb-3">
244
- <h3 className="text-xs font-bold text-blue-600 uppercase tracking-wider">Headline</h3>
245
- <div className="relative group">
246
- <Button
247
- variant="ghost"
248
- size="sm"
249
- onClick={() => handleCopyText(ad.headline, "Headline")}
250
- className="text-blue-500 hover:bg-blue-50"
251
- >
252
- <Copy className="h-4 w-4" />
253
- </Button>
254
- <span className="absolute -bottom-8 left-1/2 -translate-x-1/2 px-2 py-1 bg-blue-600 text-white text-xs rounded opacity-0 group-hover:opacity-100 transition-opacity whitespace-nowrap pointer-events-none z-10">
255
- Copy Headline
256
- </span>
257
- </div>
258
- </div>
259
- <h1 className="text-2xl font-bold bg-gradient-to-r from-gray-900 to-gray-700 bg-clip-text text-transparent leading-tight">
260
- {ad.headline}
261
- </h1>
262
- </div>
263
-
264
  {/* Description */}
265
  {ad.description && (
266
  <div className="bg-white rounded-2xl shadow-md p-6 border-l-4 border-violet-500">
@@ -283,10 +260,7 @@ export const AdPreview: React.FC<AdPreviewProps> = ({ ad }) => {
283
  <p className="text-gray-700 leading-relaxed">{ad.description}</p>
284
  </div>
285
  )}
286
- </div>
287
 
288
- {/* Right Column - Additional Info */}
289
- <div className="space-y-5">
290
  {/* Body Story */}
291
  {ad.body_story && (
292
  <div className="bg-white rounded-2xl shadow-md p-6 border-l-4 border-amber-500">
@@ -337,7 +311,10 @@ export const AdPreview: React.FC<AdPreviewProps> = ({ ad }) => {
337
  </div>
338
  </div>
339
  )}
 
340
 
 
 
341
  {/* CTA */}
342
  {ad.cta && (
343
  <div className="bg-gradient-to-r from-emerald-50 to-teal-50 rounded-2xl shadow-md p-6 border border-emerald-200">
 
238
  </div>
239
  )}
240
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
241
  {/* Description */}
242
  {ad.description && (
243
  <div className="bg-white rounded-2xl shadow-md p-6 border-l-4 border-violet-500">
 
260
  <p className="text-gray-700 leading-relaxed">{ad.description}</p>
261
  </div>
262
  )}
 
263
 
 
 
264
  {/* Body Story */}
265
  {ad.body_story && (
266
  <div className="bg-white rounded-2xl shadow-md p-6 border-l-4 border-amber-500">
 
311
  </div>
312
  </div>
313
  )}
314
+ </div>
315
 
316
+ {/* Right Column - CTA and Strategy */}
317
+ <div className="space-y-5">
318
  {/* CTA */}
319
  {ad.cta && (
320
  <div className="bg-gradient-to-r from-emerald-50 to-teal-50 rounded-2xl shadow-md p-6 border border-emerald-200">
frontend/components/generation/ExtensiveForm.tsx CHANGED
@@ -115,7 +115,7 @@ export const ExtensiveForm: React.FC<ExtensiveFormProps> = ({
115
 
116
  <div>
117
  <label className="block text-sm font-semibold text-gray-700 mb-2">
118
- Images per Strategy: <span className="text-blue-600 font-bold">{numImages}</span>
119
  </label>
120
  <input
121
  type="range"
@@ -129,6 +129,9 @@ export const ExtensiveForm: React.FC<ExtensiveFormProps> = ({
129
  <span>1</span>
130
  <span>3</span>
131
  </div>
 
 
 
132
  </div>
133
 
134
  <div>
@@ -152,6 +155,15 @@ export const ExtensiveForm: React.FC<ExtensiveFormProps> = ({
152
  </p>
153
  </div>
154
 
 
 
 
 
 
 
 
 
 
155
  <button
156
  type="submit"
157
  disabled={isLoading}
 
115
 
116
  <div>
117
  <label className="block text-sm font-semibold text-gray-700 mb-2">
118
+ Variations per Strategy: <span className="text-blue-600 font-bold">{numImages}</span>
119
  </label>
120
  <input
121
  type="range"
 
129
  <span>1</span>
130
  <span>3</span>
131
  </div>
132
+ <p className="text-xs text-gray-500 mt-1">
133
+ Each variation will have a unique image and slight copy variations
134
+ </p>
135
  </div>
136
 
137
  <div>
 
155
  </p>
156
  </div>
157
 
158
+ <div className="bg-gradient-to-r from-blue-50 to-cyan-50 border border-blue-200 rounded-xl p-4">
159
+ <p className="text-sm font-semibold text-gray-800">
160
+ <strong>Estimated:</strong> {numStrategies} ads Γ— {numImages} variation(s) = {numStrategies * numImages} total variations
161
+ </p>
162
+ <p className="text-xs text-gray-600 mt-1">
163
+ This may take several minutes to complete
164
+ </p>
165
+ </div>
166
+
167
  <button
168
  type="submit"
169
  disabled={isLoading}
frontend/components/generation/GenerationForm.tsx CHANGED
@@ -97,7 +97,7 @@ export const GenerationForm: React.FC<GenerationFormProps> = ({
97
 
98
  <div>
99
  <label className="block text-sm font-semibold text-gray-700 mb-2">
100
- Number of Images: <span className="text-blue-600 font-bold">{numImages}</span>
101
  </label>
102
  <input
103
  type="range"
 
97
 
98
  <div>
99
  <label className="block text-sm font-semibold text-gray-700 mb-2">
100
+ Number of Ad Images: <span className="text-blue-600 font-bold">{numImages}</span>
101
  </label>
102
  <input
103
  type="range"
frontend/lib/api/endpoints.ts CHANGED
@@ -77,7 +77,7 @@ export const generateExtensiveAd = async (params: {
77
  num_images: number;
78
  image_model?: string | null;
79
  num_strategies: number;
80
- }): Promise<GenerateResponse> => {
81
  // Ensure required parameters are always sent
82
  const requestParams = {
83
  niche: params.niche,
@@ -87,7 +87,7 @@ export const generateExtensiveAd = async (params: {
87
  ...(params.offer && { offer: params.offer }),
88
  ...(params.image_model && { image_model: params.image_model }),
89
  };
90
- const response = await apiClient.post<GenerateResponse>("/extensive/generate", requestParams);
91
  return response.data;
92
  };
93
 
 
77
  num_images: number;
78
  image_model?: string | null;
79
  num_strategies: number;
80
+ }): Promise<BatchResponse> => {
81
  // Ensure required parameters are always sent
82
  const requestParams = {
83
  niche: params.niche,
 
87
  ...(params.offer && { offer: params.offer }),
88
  ...(params.image_model && { image_model: params.image_model }),
89
  };
90
+ const response = await apiClient.post<BatchResponse>("/extensive/generate", requestParams);
91
  return response.data;
92
  };
93
 
main.py CHANGED
@@ -1133,7 +1133,7 @@ class ExtensiveGenerateRequest(BaseModel):
1133
  )
1134
 
1135
 
1136
- @app.post("/extensive/generate", response_model=GenerateResponse)
1137
  async def generate_extensive(
1138
  request: ExtensiveGenerateRequest,
1139
  username: str = Depends(get_current_user)
@@ -1150,10 +1150,10 @@ async def generate_extensive(
1150
  4. Generates image prompts and ad copy in parallel
1151
  5. Generates images for each strategy
1152
 
1153
- Returns the first generated ad from the strategies.
1154
  """
1155
  try:
1156
- result = await ad_generator.generate_ad_extensive(
1157
  niche=request.niche,
1158
  target_audience=request.target_audience,
1159
  offer=request.offer,
@@ -1162,7 +1162,11 @@ async def generate_extensive(
1162
  num_strategies=request.num_strategies,
1163
  username=username, # Pass current user
1164
  )
1165
- return result
 
 
 
 
1166
  except Exception as e:
1167
  raise HTTPException(status_code=500, detail=str(e))
1168
 
 
1133
  )
1134
 
1135
 
1136
+ @app.post("/extensive/generate", response_model=BatchResponse)
1137
  async def generate_extensive(
1138
  request: ExtensiveGenerateRequest,
1139
  username: str = Depends(get_current_user)
 
1150
  4. Generates image prompts and ad copy in parallel
1151
  5. Generates images for each strategy
1152
 
1153
+ Returns all generated ads from all strategies (like batch generation).
1154
  """
1155
  try:
1156
+ results = await ad_generator.generate_ad_extensive(
1157
  niche=request.niche,
1158
  target_audience=request.target_audience,
1159
  offer=request.offer,
 
1162
  num_strategies=request.num_strategies,
1163
  username=username, # Pass current user
1164
  )
1165
+ # Return as BatchResponse format
1166
+ return BatchResponse(
1167
+ count=len(results),
1168
+ ads=results
1169
+ )
1170
  except Exception as e:
1171
  raise HTTPException(status_code=500, detail=str(e))
1172
 
services/generator.py CHANGED
@@ -2152,11 +2152,10 @@ CONCEPT: {concept['name']}
2152
  })
2153
  print(f"βœ“ Strategy {idx + 1} completed with {len(generated_images)} image(s)")
2154
 
2155
- # Return first result (or all if needed)
2156
  if all_results:
2157
- result = all_results[0]
2158
- print(f"πŸ“€ Returning result with {len(result.get('images', []))} image(s)")
2159
- return result # Return first strategy result with all its images
2160
  else:
2161
  raise ValueError("No ads generated from extensive")
2162
 
 
2152
  })
2153
  print(f"βœ“ Strategy {idx + 1} completed with {len(generated_images)} image(s)")
2154
 
2155
+ # Return all results (like batch generation)
2156
  if all_results:
2157
+ print(f"πŸ“€ Returning {len(all_results)} strategy result(s)")
2158
+ return all_results
 
2159
  else:
2160
  raise ValueError("No ads generated from extensive")
2161