sushilideaclan01 commited on
Commit
4c17c06
·
1 Parent(s): bf8e54b

added custom user instructions in the creative modifier

Browse files
frontend/app/creative/modify/page.tsx CHANGED
@@ -39,6 +39,7 @@ export default function CreativeModifyPage() {
39
  const [concept, setConcept] = useState("");
40
  const [mode, setMode] = useState<ModificationMode>("modify");
41
  const [imageModel, setImageModel] = useState<string | null>(null);
 
42
 
43
  // Result state
44
  const [result, setResult] = useState<ModifiedImageResult | null>(null);
@@ -104,6 +105,7 @@ export default function CreativeModifyPage() {
104
  concept: concept.trim() || undefined,
105
  mode,
106
  image_model: imageModel,
 
107
  });
108
 
109
  if (response.status !== "success" || !response.image) {
@@ -118,7 +120,7 @@ export default function CreativeModifyPage() {
118
  } finally {
119
  setIsLoading(false);
120
  }
121
- }, [originalImageUrl, analysis, angle, concept, mode, imageModel]);
122
 
123
  // Reset to start over
124
  const handleStartOver = useCallback(() => {
@@ -130,6 +132,7 @@ export default function CreativeModifyPage() {
130
  setConcept("");
131
  setMode("modify");
132
  setImageModel(null);
 
133
  setResult(null);
134
  setGeneratedPrompt(null);
135
  setError(null);
@@ -352,10 +355,12 @@ export default function CreativeModifyPage() {
352
  concept={concept}
353
  mode={mode}
354
  imageModel={imageModel}
 
355
  onAngleChange={setAngle}
356
  onConceptChange={setConcept}
357
  onModeChange={setMode}
358
  onImageModelChange={setImageModel}
 
359
  onSubmit={handleModify}
360
  isLoading={isLoading}
361
  />
 
39
  const [concept, setConcept] = useState("");
40
  const [mode, setMode] = useState<ModificationMode>("modify");
41
  const [imageModel, setImageModel] = useState<string | null>(null);
42
+ const [userPrompt, setUserPrompt] = useState("");
43
 
44
  // Result state
45
  const [result, setResult] = useState<ModifiedImageResult | null>(null);
 
105
  concept: concept.trim() || undefined,
106
  mode,
107
  image_model: imageModel,
108
+ user_prompt: userPrompt.trim() || undefined,
109
  });
110
 
111
  if (response.status !== "success" || !response.image) {
 
120
  } finally {
121
  setIsLoading(false);
122
  }
123
+ }, [originalImageUrl, analysis, angle, concept, mode, imageModel, userPrompt]);
124
 
125
  // Reset to start over
126
  const handleStartOver = useCallback(() => {
 
132
  setConcept("");
133
  setMode("modify");
134
  setImageModel(null);
135
+ setUserPrompt("");
136
  setResult(null);
137
  setGeneratedPrompt(null);
138
  setError(null);
 
355
  concept={concept}
356
  mode={mode}
357
  imageModel={imageModel}
358
+ userPrompt={userPrompt}
359
  onAngleChange={setAngle}
360
  onConceptChange={setConcept}
361
  onModeChange={setMode}
362
  onImageModelChange={setImageModel}
363
+ onUserPromptChange={setUserPrompt}
364
  onSubmit={handleModify}
365
  isLoading={isLoading}
366
  />
frontend/components/creative/ModificationForm.tsx CHANGED
@@ -26,10 +26,12 @@ interface ModificationFormProps {
26
  concept: string;
27
  mode: ModificationMode;
28
  imageModel: string | null;
 
29
  onAngleChange: (value: string) => void;
30
  onConceptChange: (value: string) => void;
31
  onModeChange: (mode: ModificationMode) => void;
32
  onImageModelChange: (model: string | null) => void;
 
33
  onSubmit: () => void;
34
  isLoading: boolean;
35
  }
@@ -41,10 +43,12 @@ export const ModificationForm: React.FC<ModificationFormProps> = ({
41
  concept,
42
  mode,
43
  imageModel,
 
44
  onAngleChange,
45
  onConceptChange,
46
  onModeChange,
47
  onImageModelChange,
 
48
  onSubmit,
49
  isLoading,
50
  }) => {
@@ -99,7 +103,7 @@ export const ModificationForm: React.FC<ModificationFormProps> = ({
99
  fetchOptions();
100
  }, []);
101
 
102
- const isValid = angle.trim() || concept.trim();
103
 
104
  const groupedAngles = angleOptions.reduce((acc, angle) => {
105
  if (!acc[angle.category]) acc[angle.category] = [];
@@ -314,6 +318,26 @@ export const ModificationForm: React.FC<ModificationFormProps> = ({
314
  </div>
315
  </div>
316
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
317
  {/* Image Model Selection */}
318
  <div className="space-y-4 pt-4 border-t border-gray-100">
319
  <label className="text-sm font-bold text-gray-700 uppercase tracking-wider block">
@@ -360,12 +384,12 @@ export const ModificationForm: React.FC<ModificationFormProps> = ({
360
  </span>
361
  </button>
362
 
363
- {!isValid && (
364
- <div className="mt-4 flex items-center justify-center gap-2 text-amber-600 animate-pulse">
365
- <Info className="w-4 h-4" />
366
- <p className="text-sm font-bold">Please select or enter at least one angle or concept</p>
367
- </div>
368
- )}
369
  </div>
370
  </CardContent>
371
  </Card>
 
26
  concept: string;
27
  mode: ModificationMode;
28
  imageModel: string | null;
29
+ userPrompt: string;
30
  onAngleChange: (value: string) => void;
31
  onConceptChange: (value: string) => void;
32
  onModeChange: (mode: ModificationMode) => void;
33
  onImageModelChange: (model: string | null) => void;
34
+ onUserPromptChange: (value: string) => void;
35
  onSubmit: () => void;
36
  isLoading: boolean;
37
  }
 
43
  concept,
44
  mode,
45
  imageModel,
46
+ userPrompt,
47
  onAngleChange,
48
  onConceptChange,
49
  onModeChange,
50
  onImageModelChange,
51
+ onUserPromptChange,
52
  onSubmit,
53
  isLoading,
54
  }) => {
 
103
  fetchOptions();
104
  }, []);
105
 
106
+ const isValid = angle.trim() || concept.trim() || userPrompt.trim();
107
 
108
  const groupedAngles = angleOptions.reduce((acc, angle) => {
109
  if (!acc[angle.category]) acc[angle.category] = [];
 
318
  </div>
319
  </div>
320
 
321
+ {/* User Prompt (Optional) */}
322
+ <div className="space-y-4 pt-4 border-t border-gray-100">
323
+ <div className="flex items-center gap-2">
324
+ <Lightbulb className="w-4 h-4 text-purple-500" />
325
+ <label className="text-sm font-bold text-gray-700 uppercase tracking-wider">
326
+ Custom Instructions (Optional)
327
+ </label>
328
+ </div>
329
+ <textarea
330
+ value={userPrompt}
331
+ onChange={(e) => onUserPromptChange(e.target.value)}
332
+ placeholder="e.g., Make the image more vibrant, add a sense of urgency, change the background to blue..."
333
+ className="w-full px-4 py-3 rounded-xl border-2 border-gray-100 bg-gray-50/50 hover:bg-white focus:bg-white focus:border-purple-500 focus:ring-4 focus:ring-purple-500/10 transition-all font-medium text-gray-900 min-h-[100px] resize-y"
334
+ />
335
+ <p className="text-xs text-gray-500 flex items-center gap-1.5 px-1">
336
+ <Info className="w-3 h-3" />
337
+ Provide specific instructions for how you want the image modified.
338
+ </p>
339
+ </div>
340
+
341
  {/* Image Model Selection */}
342
  <div className="space-y-4 pt-4 border-t border-gray-100">
343
  <label className="text-sm font-bold text-gray-700 uppercase tracking-wider block">
 
384
  </span>
385
  </button>
386
 
387
+ {!isValid && (
388
+ <div className="mt-4 flex items-center justify-center gap-2 text-amber-600 animate-pulse">
389
+ <Info className="w-4 h-4" />
390
+ <p className="text-sm font-bold">Please provide at least one: angle, concept, or custom instructions</p>
391
+ </div>
392
+ )}
393
  </div>
394
  </CardContent>
395
  </Card>
frontend/lib/api/endpoints.ts CHANGED
@@ -329,6 +329,7 @@ export const modifyCreative = async (params: {
329
  concept?: string;
330
  mode: ModificationMode;
331
  image_model?: string | null;
 
332
  }): Promise<CreativeModifyResponse> => {
333
  const response = await apiClient.post<CreativeModifyResponse>(
334
  "/api/creative/modify",
 
329
  concept?: string;
330
  mode: ModificationMode;
331
  image_model?: string | null;
332
+ user_prompt?: string;
333
  }): Promise<CreativeModifyResponse> => {
334
  const response = await apiClient.post<CreativeModifyResponse>(
335
  "/api/creative/modify",
main.py CHANGED
@@ -1967,6 +1967,10 @@ class CreativeModifyRequest(BaseModel):
1967
  default=None,
1968
  description="Image generation model to use"
1969
  )
 
 
 
 
1970
 
1971
 
1972
  class ModifiedImageResult(BaseModel):
@@ -2207,6 +2211,7 @@ async def modify_creative(
2207
  user_concept=request.concept,
2208
  mode=request.mode,
2209
  image_model=request.image_model,
 
2210
  )
2211
 
2212
  if result["status"] != "success":
 
1967
  default=None,
1968
  description="Image generation model to use"
1969
  )
1970
+ user_prompt: Optional[str] = Field(
1971
+ default=None,
1972
+ description="Optional custom user prompt/instructions for modification"
1973
+ )
1974
 
1975
 
1976
  class ModifiedImageResult(BaseModel):
 
2211
  user_concept=request.concept,
2212
  mode=request.mode,
2213
  image_model=request.image_model,
2214
+ user_prompt=request.user_prompt,
2215
  )
2216
 
2217
  if result["status"] != "success":
services/creative_modifier.py CHANGED
@@ -231,6 +231,7 @@ Be specific and detailed in your analysis. If you cannot determine something wit
231
  user_angle: Optional[str] = None,
232
  user_concept: Optional[str] = None,
233
  mode: str = "modify",
 
234
  ) -> str:
235
  """
236
  Generate a prompt for modifying the creative based on analysis and user input.
@@ -240,6 +241,7 @@ Be specific and detailed in your analysis. If you cannot determine something wit
240
  user_angle: User-provided angle to apply
241
  user_concept: User-provided concept to apply
242
  mode: "modify" for image-to-image, "inspired" for new generation
 
243
 
244
  Returns:
245
  Generated prompt string
@@ -247,6 +249,12 @@ Be specific and detailed in your analysis. If you cannot determine something wit
247
  logger.info(f"Generating modification prompt (mode: {mode})")
248
  logger.info(f"User angle: {user_angle}")
249
  logger.info(f"User concept: {user_concept}")
 
 
 
 
 
 
250
 
251
  system_prompt = """You are an expert advertising creative director with 20+ years experience.
252
  Your task is to create seamless, organic modifications that enhance existing creatives without appearing forced.
@@ -399,6 +407,7 @@ Be specific and detailed in your analysis. If you cannot determine something wit
399
  user_concept: Optional[str] = None,
400
  mode: str = "modify",
401
  image_model: Optional[str] = None,
 
402
  width: int = 1024,
403
  height: int = 1024,
404
  ) -> Dict[str, Any]:
@@ -412,6 +421,7 @@ Be specific and detailed in your analysis. If you cannot determine something wit
412
  user_concept: User-provided concept
413
  mode: "modify" for image-to-image, "inspired" for new generation
414
  image_model: Model to use for generation
 
415
  width: Output width
416
  height: Output height
417
 
@@ -425,6 +435,7 @@ Be specific and detailed in your analysis. If you cannot determine something wit
425
  logger.info(f"Image URL: {image_url}")
426
  logger.info(f"User angle: {user_angle}")
427
  logger.info(f"User concept: {user_concept}")
 
428
  logger.info(f"Image model: {image_model}")
429
  logger.info("=" * 80)
430
 
@@ -442,6 +453,7 @@ Be specific and detailed in your analysis. If you cannot determine something wit
442
  user_angle=user_angle,
443
  user_concept=user_concept,
444
  mode=mode,
 
445
  )
446
  result["prompt"] = prompt
447
  logger.info(f"✓ Generated prompt: {prompt}")
 
231
  user_angle: Optional[str] = None,
232
  user_concept: Optional[str] = None,
233
  mode: str = "modify",
234
+ user_prompt: Optional[str] = None,
235
  ) -> str:
236
  """
237
  Generate a prompt for modifying the creative based on analysis and user input.
 
241
  user_angle: User-provided angle to apply
242
  user_concept: User-provided concept to apply
243
  mode: "modify" for image-to-image, "inspired" for new generation
244
+ user_prompt: Custom user instructions for modification
245
 
246
  Returns:
247
  Generated prompt string
 
249
  logger.info(f"Generating modification prompt (mode: {mode})")
250
  logger.info(f"User angle: {user_angle}")
251
  logger.info(f"User concept: {user_concept}")
252
+ logger.info(f"User prompt: {user_prompt}")
253
+
254
+ # If user provided a custom prompt, use it directly
255
+ if user_prompt and user_prompt.strip():
256
+ logger.info("Using custom user prompt directly")
257
+ return user_prompt.strip()
258
 
259
  system_prompt = """You are an expert advertising creative director with 20+ years experience.
260
  Your task is to create seamless, organic modifications that enhance existing creatives without appearing forced.
 
407
  user_concept: Optional[str] = None,
408
  mode: str = "modify",
409
  image_model: Optional[str] = None,
410
+ user_prompt: Optional[str] = None,
411
  width: int = 1024,
412
  height: int = 1024,
413
  ) -> Dict[str, Any]:
 
421
  user_concept: User-provided concept
422
  mode: "modify" for image-to-image, "inspired" for new generation
423
  image_model: Model to use for generation
424
+ user_prompt: Custom user instructions for modification
425
  width: Output width
426
  height: Output height
427
 
 
435
  logger.info(f"Image URL: {image_url}")
436
  logger.info(f"User angle: {user_angle}")
437
  logger.info(f"User concept: {user_concept}")
438
+ logger.info(f"User prompt: {user_prompt}")
439
  logger.info(f"Image model: {image_model}")
440
  logger.info("=" * 80)
441
 
 
453
  user_angle=user_angle,
454
  user_concept=user_concept,
455
  mode=mode,
456
+ user_prompt=user_prompt,
457
  )
458
  result["prompt"] = prompt
459
  logger.info(f"✓ Generated prompt: {prompt}")