S-Dreamer commited on
Commit
39431ec
·
verified ·
1 Parent(s): e81a8a7

Update app.py

Browse files
Files changed (1) hide show
  1. app.py +193 -415
app.py CHANGED
@@ -11,17 +11,14 @@ except ImportError:
11
  InferenceClient = None
12
 
13
 
14
- # =============================================================================
15
- # CONFIGURATION
16
- # =============================================================================
17
-
18
  APP_TITLE = "Free Image Prompt Generator"
19
 
20
- DEFAULT_MODEL = os.getenv(
21
  "PROMPT_MODEL",
22
  "Qwen/Qwen2.5-7B-Instruct",
23
  )
24
 
 
25
  STYLES = [
26
  "Cinematic",
27
  "Photorealistic",
@@ -78,7 +75,8 @@ CAMERAS = [
78
  "Dynamic action perspective",
79
  ]
80
 
81
- DEFAULT_NEGATIVE = (
 
82
  "text, captions, subtitles, logos, watermarks, signatures, "
83
  "malformed anatomy, extra limbs, duplicated objects, distorted faces, "
84
  "bad hands, inconsistent perspective, floating objects, visual artifacts, "
@@ -86,33 +84,25 @@ DEFAULT_NEGATIVE = (
86
  )
87
 
88
 
89
- # =============================================================================
90
- # TEXT HELPERS
91
- # =============================================================================
92
-
93
  def clean_text(text: str) -> str:
94
- """Normalize whitespace while preserving paragraph breaks."""
95
  if not text:
96
  return ""
97
 
98
  text = str(text)
99
  text = text.replace("\r\n", "\n")
100
  text = text.replace("\r", "\n")
101
-
102
  text = re.sub(r"[ \t]+", " ", text)
103
  text = re.sub(r"\n{3,}", "\n\n", text)
104
 
105
  return text.strip()
106
 
107
 
108
- def extract_prompt_text(text: str) -> str:
109
- """Clean common formatting accidentally returned by language models."""
110
  if not text:
111
  return ""
112
 
113
  text = str(text).strip()
114
 
115
- # Remove Markdown code fences.
116
  text = re.sub(
117
  r"^```(?:text|prompt|markdown)?\s*",
118
  "",
@@ -122,25 +112,17 @@ def extract_prompt_text(text: str) -> str:
122
 
123
  text = re.sub(r"\s*```$", "", text)
124
 
125
- # Remove accidental surrounding quotation marks.
126
  if len(text) >= 2:
127
- if (
128
- (text.startswith('"') and text.endswith('"'))
129
- or
130
- (text.startswith("'") and text.endswith("'"))
131
- ):
132
- text = text[1:-1].strip()
133
 
134
- return clean_text(text)
 
135
 
 
136
 
137
- # =============================================================================
138
- # HUGGING FACE CLIENT
139
- # =============================================================================
140
 
141
  def get_client() -> Optional["InferenceClient"]:
142
- """Return a configured Hugging Face client if available."""
143
-
144
  token = os.getenv("HF_TOKEN")
145
 
146
  if not token:
@@ -151,20 +133,18 @@ def get_client() -> Optional["InferenceClient"]:
151
 
152
  try:
153
  return InferenceClient(
154
- model=DEFAULT_MODEL,
155
  token=token,
156
  )
157
  except Exception as exc:
158
  print(
159
- f"[HF CLIENT ERROR] {type(exc).__name__}: {exc}"
 
 
160
  )
161
  return None
162
 
163
 
164
- # =============================================================================
165
- # LOCAL PROMPT ENGINE
166
- # =============================================================================
167
-
168
  def build_local_prompt(
169
  idea: str,
170
  style: str,
@@ -172,7 +152,7 @@ def build_local_prompt(
172
  mood: str,
173
  detail: str,
174
  camera: str,
175
- ) -> Tuple[str, str]:
176
 
177
  idea = clean_text(idea)
178
 
@@ -184,77 +164,54 @@ def build_local_prompt(
184
 
185
  prompt = (
186
  f"{style} image of {idea}. "
187
- f"Use a {camera.lower()} with intentional framing, strong visual "
188
- f"hierarchy, convincing depth, natural perspective, and balanced "
189
- f"negative space. "
190
  f"Create a coherent environment with meaningful foreground, "
191
- f"midground, and background elements that support the subject. "
192
- f"Use {mood.lower()} lighting and atmosphere with believable light "
193
- f"falloff, dimensional shadows, subtle highlights, and atmospheric "
194
- f"depth. "
195
  f"Apply a consistent {style.lower()} aesthetic with "
196
  f"{detail.lower()}, refined textures, coherent materials, "
197
  f"realistic surface response, and controlled visual complexity. "
198
- f"Use a deliberate color palette appropriate to the subject, "
199
- f"environment, lighting, and mood. "
200
- f"High visual fidelity, crisp focal detail, clean edges, nuanced "
201
- f"textures, realistic spatial relationships, polished professional "
202
- f"finish, and cinematic visual storytelling. "
203
  f"Aspect ratio {aspect}."
204
  )
205
 
206
- return clean_text(prompt), DEFAULT_NEGATIVE
207
-
208
 
209
- # =============================================================================
210
- # AI PROMPT ENGINE
211
- # =============================================================================
212
 
213
- AI_SYSTEM_PROMPT = """
214
  You are an expert image-prompt architect.
215
 
216
- Transform a user's image idea into a production-ready prompt for an
217
- image-generation model.
218
-
219
- CORE PRINCIPLES:
220
-
221
- 1. Preserve the user's core idea, subject, intent, and important details.
222
- 2. Never radically alter the user's concept.
223
- 3. Add useful visual specificity rather than random decoration.
224
- 4. Resolve reasonable ambiguity intelligently.
225
- 5. Prefer concrete visual information over generic adjectives.
226
- 6. Avoid unnecessary repetition.
227
- 7. Every added detail must support the user's concept.
228
- 8. Do not invent named people, brands, locations, products, or story elements
229
- unless requested or clearly implied.
230
- 9. Avoid contradictory attributes.
231
- 10. Use useful camera, composition, lighting, spatial, material, texture,
232
- environmental, color, and depth information.
233
- 11. Avoid generic AI filler such as "masterpiece", "stunning", "breathtaking",
234
- and repeated "ultra-realistic" language unless it genuinely adds meaning.
235
- 12. Do not over-engineer simple concepts.
236
- 13. Make the result directly usable in an image-generation model.
237
- 14. Do not explain your choices.
238
- 15. Do not mention that you are an AI.
239
- 16. Return ONLY the finished image prompt.
240
- 17. Do not wrap the prompt in quotation marks.
241
-
242
- A strong prompt should naturally communicate:
243
-
244
- - subject
245
- - environment
246
- - composition
247
- - camera language where useful
248
- - lighting
249
- - atmosphere
250
- - materials and textures where useful
251
- - visual style
252
- - color
253
- - depth
254
- - image quality
255
- - aspect ratio
256
-
257
- Use natural prose rather than unnecessary section headings.
258
  """
259
 
260
 
@@ -272,10 +229,10 @@ def build_ai_prompt(
272
  if client is None:
273
  return (
274
  "",
275
- "Smart AI is unavailable; using the built-in prompt engine.",
276
  )
277
 
278
- user_prompt = f"""
279
  USER IDEA:
280
  {idea}
281
 
@@ -285,7 +242,7 @@ STYLE:
285
  ASPECT RATIO:
286
  {aspect}
287
 
288
- MOOD / ATMOSPHERE:
289
  {mood}
290
 
291
  DETAIL LEVEL:
@@ -300,11 +257,11 @@ CAMERA / COMPOSITION:
300
  messages=[
301
  {
302
  "role": "system",
303
- "content": AI_SYSTEM_PROMPT,
304
  },
305
  {
306
  "role": "user",
307
- "content": user_prompt,
308
  },
309
  ],
310
  max_tokens=1200,
@@ -312,43 +269,42 @@ CAMERA / COMPOSITION:
312
  )
313
 
314
  if not response:
315
- return "", "Smart AI returned no response."
316
 
317
  if not response.choices:
318
- return "", "Smart AI returned no usable response."
319
 
320
  message = response.choices[0].message
321
 
322
  if not message:
323
- return "", "Smart AI returned an empty message."
324
 
325
  content = message.content
326
 
327
  if not content:
328
- return "", "Smart AI returned an empty prompt."
329
 
330
- content = extract_prompt_text(content)
331
 
332
  if not content:
333
- return "", "Smart AI returned no usable prompt."
334
 
335
  return content, None
336
 
337
  except Exception as exc:
 
338
  print(
339
- f"[HF AI ERROR] {type(exc).__name__}: {exc}"
 
 
340
  )
341
 
342
  return (
343
  "",
344
- "Smart AI was unavailable; using the built-in prompt engine.",
345
  )
346
 
347
 
348
- # =============================================================================
349
- # MAIN GENERATION
350
- # =============================================================================
351
-
352
  def generate_prompt(
353
  idea: str,
354
  style: str,
@@ -357,187 +313,113 @@ def generate_prompt(
357
  detail: str,
358
  camera: str,
359
  use_ai: bool,
360
- ) -> Tuple[str, str, str]:
361
 
362
  if not idea or not idea.strip():
 
363
  return (
364
  "",
365
- DEFAULT_NEGATIVE,
366
  "⚠️ Enter an image idea first.",
367
  )
368
 
369
  idea = clean_text(idea)
370
 
371
  if use_ai:
 
372
  ai_prompt, error = build_ai_prompt(
373
- idea=idea,
374
- style=style,
375
- aspect=aspect,
376
- mood=mood,
377
- detail=detail,
378
- camera=camera,
379
  )
380
 
381
  if ai_prompt:
 
382
  return (
383
  ai_prompt,
384
- DEFAULT_NEGATIVE,
385
- "✓ Prompt created with Smart AI",
386
  )
387
 
388
- local_prompt, negative = build_local_prompt(
389
- idea=idea,
390
- style=style,
391
- aspect=aspect,
392
- mood=mood,
393
- detail=detail,
394
- camera=camera,
395
  )
396
 
397
  return (
398
  local_prompt,
399
- negative,
400
- f"✓ Prompt created with the built-in engine • {error}",
401
  )
402
 
403
- local_prompt, negative = build_local_prompt(
404
- idea=idea,
405
- style=style,
406
- aspect=aspect,
407
- mood=mood,
408
- detail=detail,
409
- camera=camera,
410
  )
411
 
412
  return (
413
  local_prompt,
414
- negative,
415
- "✓ Prompt created with the built-in engine",
416
  )
417
 
418
 
419
- # =============================================================================
420
- # PROMPT TRANSFORMATION
421
- # =============================================================================
422
 
423
- TRANSFORMATION_INSTRUCTIONS = {
424
  "Improve": """
425
- Improve this image prompt.
426
 
427
  Preserve the exact core subject and concept.
428
 
429
- Increase useful visual specificity where it genuinely improves the image.
430
- Strengthen composition, lighting, depth, materials, atmosphere, spatial
431
- relationships, and camera language where appropriate.
432
 
433
- Remove generic filler and repetition.
434
 
435
  Do not radically change the concept.
436
 
437
- Return ONLY the improved image prompt.
438
  """,
439
 
440
  "Remix": """
441
- Remix this image prompt.
442
 
443
  Preserve the core subject and concept.
444
 
445
- Create a fresh creative interpretation by changing appropriate elements such
446
- as environment, composition, lighting, atmosphere, color, camera perspective,
447
- or visual treatment.
448
 
449
  Do not replace the main subject.
450
 
451
- Do not turn the concept into something unrelated.
452
-
453
- Return ONLY the remixed image prompt.
454
  """,
455
 
456
  "Simplify": """
457
- Simplify this image prompt.
458
 
459
- Preserve the important subject, environment, style, mood, and visual intent.
460
 
461
- Remove unnecessary adjectives, repetition, generic AI language, and
462
- over-engineered descriptions.
463
 
464
- Make the prompt concise while retaining the information that matters.
465
 
466
- Return ONLY the simplified image prompt.
467
  """,
468
  }
469
 
470
 
471
- def transform_prompt(
472
- prompt: str,
473
- action: str,
474
- ) -> Tuple[str, str]:
475
-
476
- if not prompt or not prompt.strip():
477
- return (
478
- "",
479
- "⚠️ Generate a prompt first.",
480
- )
481
-
482
- prompt = clean_text(prompt)
483
-
484
- instruction = TRANSFORMATION_INSTRUCTIONS.get(action)
485
-
486
- if not instruction:
487
- return (
488
- prompt,
489
- "✓ Prompt ready.",
490
- )
491
-
492
- client = get_client()
493
-
494
- if client is not None:
495
- try:
496
- response = client.chat_completion(
497
- messages=[
498
- {
499
- "role": "system",
500
- "content": (
501
- "You are an expert image prompt editor. "
502
- "Return only the requested image prompt."
503
- ),
504
- },
505
- {
506
- "role": "user",
507
- "content": (
508
- f"{instruction}\n\n"
509
- f"CURRENT PROMPT:\n{prompt}"
510
- ),
511
- },
512
- ],
513
- max_tokens=1200,
514
- temperature=(
515
- 0.8
516
- if action == "Remix"
517
- else 0.5
518
- ),
519
- )
520
-
521
- if response and response.choices:
522
- content = response.choices[0].message.content
523
-
524
- if content:
525
- content = extract_prompt_text(content)
526
-
527
- if content:
528
- return (
529
- content,
530
- f"✓ Prompt {action.lower()}ed with Smart AI",
531
- )
532
-
533
- except Exception as exc:
534
- print(
535
- f"[HF TRANSFORM ERROR] {type(exc).__name__}: {exc}"
536
- )
537
-
538
- return local_transform(prompt, action)
539
-
540
-
541
  def local_transform(
542
  prompt: str,
543
  action: str,
@@ -547,17 +429,15 @@ def local_transform(
547
 
548
  if action == "Improve":
549
 
550
- prompt = prompt.rstrip(". ")
551
-
552
  addition = (
553
- " Enhance the scene with coherent depth, intentional composition, "
554
  "natural lighting, refined textures, believable materials, "
555
  "and strong focal detail."
556
  )
557
 
558
  return (
559
- f"{prompt}.{addition}",
560
- "✓ Prompt improved with the built-in engine",
561
  )
562
 
563
  if action == "Simplify":
@@ -572,225 +452,123 @@ def local_transform(
572
 
573
  return (
574
  clean_text(prompt),
575
- "✓ Prompt simplified with the built-in engine",
576
  )
577
 
578
  if action == "Remix":
579
 
580
- remix_phrases = [
581
  "with dramatic atmospheric depth",
582
  "under cinematic environmental lighting",
583
  "with a striking editorial composition",
584
  "with subtle surreal visual elements",
585
  "during a visually dramatic transitional moment",
586
- "with strong foreground-to-background depth",
587
  "using an unconventional cinematic perspective",
588
  ]
589
 
590
- addition = random.choice(remix_phrases)
591
-
592
- prompt = prompt.rstrip(". ")
593
 
594
  return (
595
- f"{prompt}, {addition}.",
596
- "✓ Prompt remixed with the built-in engine",
597
  )
598
 
599
  return (
600
  prompt,
601
- "✓ Prompt ready.",
602
- )
603
-
604
-
605
- def improve_prompt(prompt: str):
606
- return transform_prompt(prompt, "Improve")
607
-
608
-
609
- def remix_prompt(prompt: str):
610
- return transform_prompt(prompt, "Remix")
611
-
612
-
613
- def simplify_prompt(prompt: str):
614
- return transform_prompt(prompt, "Simplify")
615
-
616
-
617
- # =============================================================================
618
- # SURPRISE ME
619
- # =============================================================================
620
-
621
- SURPRISE_IDEAS = [
622
- "a tiny astronaut exploring an enormous abandoned greenhouse",
623
- "a fox sitting inside an ancient observatory beneath a meteor shower",
624
- "a futuristic Brisbane street transformed by bioluminescent plants",
625
- "a mechanical whale swimming through a flooded cathedral",
626
- "a lone explorer discovering a hidden city beneath the ocean",
627
- "a tiny robot repairing a gigantic antique clock",
628
- "a medieval library built inside the hollow trunk of an enormous tree",
629
- "an abandoned space station slowly being reclaimed by vegetation",
630
- "a cyberpunk night market during a tropical storm",
631
- "a mysterious train crossing an impossible landscape at sunrise",
632
- "an ancient temple hidden beneath a frozen ocean",
633
- "a giant botanical garden growing inside an abandoned spacecraft",
634
- ]
635
-
636
-
637
- def surprise_me():
638
- idea = random.choice(SURPRISE_IDEAS)
639
- style = random.choice(STYLES)
640
- aspect = random.choice(ASPECT_RATIOS)
641
- mood = random.choice(MOODS)
642
- detail = random.choice(DETAIL_LEVELS)
643
- camera = random.choice(CAMERAS)
644
-
645
- return (
646
- idea,
647
- style,
648
- aspect,
649
- mood,
650
- detail,
651
- camera,
652
- "🎲 Surprise idea created — hit Generate Prompt.",
653
  )
654
 
655
 
656
- # =============================================================================
657
- # EXAMPLES
658
- # =============================================================================
659
-
660
- EXAMPLES = [
661
- [
662
- "A futuristic Brisbane skyline after a tropical storm",
663
- "Cinematic",
664
- "16:9",
665
- "Moody",
666
- "Highly detailed",
667
- "Wide establishing shot",
668
- ],
669
- [
670
- "A tiny robot repairing an antique mechanical clock",
671
- "3D Render",
672
- "1:1",
673
- "Whimsical",
674
- "Extremely detailed",
675
- "Macro composition",
676
- ],
677
- [
678
- "A medieval library hidden inside a giant tree",
679
- "Fantasy",
680
- "4:5",
681
- "Serene",
682
- "Highly detailed",
683
- "Symmetrical composition",
684
- ],
685
- [
686
- "A lone astronaut exploring an abandoned underwater city",
687
- "Concept Art",
688
- "21:9",
689
- "Mysterious",
690
- "Extremely detailed",
691
- "Wide establishing shot",
692
- ],
693
- ]
694
-
695
-
696
- # =============================================================================
697
- # CUSTOM CSS
698
- # =============================================================================
699
-
700
- CUSTOM_CSS = """
701
- .gradio-container {
702
- max-width: 1100px !important;
703
- margin: auto !important;
704
- }
705
 
706
- .hero {
707
- text-align: center;
708
- padding: 18px 10px 8px 10px;
709
- }
710
 
711
- .hero h1 {
712
- font-size: 2.4rem;
713
- margin-bottom: 8px;
714
- }
715
 
716
- .hero p {
717
- font-size: 1.05rem;
718
- opacity: 0.8;
719
- }
720
 
721
- .output-actions {
722
- margin-top: 8px;
723
- }
724
 
725
- .status {
726
- text-align: center;
727
- font-size: 0.9rem;
728
- }
729
 
730
- .primary-button {
731
- min-height: 52px;
732
- font-size: 1.05rem !important;
733
- font-weight: 600 !important;
734
- }
735
 
736
- footer {
737
- display: none !important;
738
- }
739
- """
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
740
 
 
741
 
742
- # =============================================================================
743
- # GRADIO APPLICATION
744
- # =============================================================================
745
 
746
- with gr.Blocks(
747
- title=APP_TITLE,
748
- css=CUSTOM_CSS,
749
- ) as demo:
750
 
751
- # -------------------------------------------------------------------------
752
- # HERO
753
- # -------------------------------------------------------------------------
754
 
755
- gr.Markdown(
756
- """
757
- <div class="hero">
758
 
759
- # 🫂 Free Image Prompt Generator
 
 
 
760
 
761
- ### Turn what's in your head into a production-ready image prompt.
762
 
763
- Describe your idea. I'll handle the visual details.
 
 
 
 
764
 
765
- </div>
766
- """
 
767
  )
768
 
769
- # -------------------------------------------------------------------------
770
- # MAIN WORKSPACE
771
- # -------------------------------------------------------------------------
772
 
773
- with gr.Row():
 
774
 
775
- # =====================================================================
776
- # INPUT PANEL
777
- # =====================================================================
778
 
779
- with gr.Column(scale=1):
 
780
 
781
- idea = gr.Textbox(
782
- label="What do you want to create?",
783
- placeholder=(
784
- "Example: A lone astronaut exploring an abandoned "
785
- "underwater city"
786
- ),
787
- lines=5,
788
- max_lines=10,
789
- )
790
 
791
- surprise_button = gr.Button(
792
- "🎲 Surprise Me",
793
- variant="secondary",
794
- )
795
 
796
- with gr.Accor
 
 
 
 
 
 
11
  InferenceClient = None
12
 
13
 
 
 
 
 
14
  APP_TITLE = "Free Image Prompt Generator"
15
 
16
+ MODEL = os.getenv(
17
  "PROMPT_MODEL",
18
  "Qwen/Qwen2.5-7B-Instruct",
19
  )
20
 
21
+
22
  STYLES = [
23
  "Cinematic",
24
  "Photorealistic",
 
75
  "Dynamic action perspective",
76
  ]
77
 
78
+
79
+ NEGATIVE_PROMPT = (
80
  "text, captions, subtitles, logos, watermarks, signatures, "
81
  "malformed anatomy, extra limbs, duplicated objects, distorted faces, "
82
  "bad hands, inconsistent perspective, floating objects, visual artifacts, "
 
84
  )
85
 
86
 
 
 
 
 
87
  def clean_text(text: str) -> str:
 
88
  if not text:
89
  return ""
90
 
91
  text = str(text)
92
  text = text.replace("\r\n", "\n")
93
  text = text.replace("\r", "\n")
 
94
  text = re.sub(r"[ \t]+", " ", text)
95
  text = re.sub(r"\n{3,}", "\n\n", text)
96
 
97
  return text.strip()
98
 
99
 
100
+ def clean_ai_response(text: str) -> str:
 
101
  if not text:
102
  return ""
103
 
104
  text = str(text).strip()
105
 
 
106
  text = re.sub(
107
  r"^```(?:text|prompt|markdown)?\s*",
108
  "",
 
112
 
113
  text = re.sub(r"\s*```$", "", text)
114
 
 
115
  if len(text) >= 2:
116
+ if text[0] == '"' and text[-1] == '"':
117
+ text = text[1:-1]
 
 
 
 
118
 
119
+ elif text[0] == "'" and text[-1] == "'":
120
+ text = text[1:-1]
121
 
122
+ return clean_text(text)
123
 
 
 
 
124
 
125
  def get_client() -> Optional["InferenceClient"]:
 
 
126
  token = os.getenv("HF_TOKEN")
127
 
128
  if not token:
 
133
 
134
  try:
135
  return InferenceClient(
136
+ model=MODEL,
137
  token=token,
138
  )
139
  except Exception as exc:
140
  print(
141
+ "[CLIENT ERROR]",
142
+ type(exc).__name__,
143
+ str(exc),
144
  )
145
  return None
146
 
147
 
 
 
 
 
148
  def build_local_prompt(
149
  idea: str,
150
  style: str,
 
152
  mood: str,
153
  detail: str,
154
  camera: str,
155
+ ) -> str:
156
 
157
  idea = clean_text(idea)
158
 
 
164
 
165
  prompt = (
166
  f"{style} image of {idea}. "
167
+ f"Use a {camera.lower()} with intentional framing, "
168
+ f"strong visual hierarchy, convincing depth, natural perspective, "
169
+ f"and balanced negative space. "
170
  f"Create a coherent environment with meaningful foreground, "
171
+ f"midground, and background elements supporting the subject. "
172
+ f"Use {mood.lower()} lighting and atmosphere with believable "
173
+ f"light falloff, dimensional shadows, subtle highlights, "
174
+ f"and atmospheric depth. "
175
  f"Apply a consistent {style.lower()} aesthetic with "
176
  f"{detail.lower()}, refined textures, coherent materials, "
177
  f"realistic surface response, and controlled visual complexity. "
178
+ f"Use a deliberate color palette appropriate to the scene. "
179
+ f"High visual fidelity, crisp focal detail, clean edges, "
180
+ f"nuanced textures, realistic spatial relationships, "
181
+ f"polished professional finish, cinematic visual storytelling. "
 
182
  f"Aspect ratio {aspect}."
183
  )
184
 
185
+ return clean_text(prompt)
 
186
 
 
 
 
187
 
188
+ AI_SYSTEM = """
189
  You are an expert image-prompt architect.
190
 
191
+ Transform the user's idea into a production-ready image-generation prompt.
192
+
193
+ Preserve the user's core concept, subject and intent.
194
+
195
+ Add useful visual specificity involving:
196
+ subject, environment, composition, camera, lighting, atmosphere, materials,
197
+ textures, color, depth and visual style.
198
+
199
+ Resolve reasonable ambiguity intelligently.
200
+
201
+ Do not invent unrelated story elements, people, brands or locations.
202
+
203
+ Avoid generic filler such as:
204
+ masterpiece, stunning, breathtaking, amazing, incredible.
205
+
206
+ Avoid repetition and contradictory attributes.
207
+
208
+ Do not radically change the user's concept.
209
+
210
+ Return ONLY the finished image prompt.
211
+
212
+ Do not explain your choices.
213
+ Do not mention being an AI.
214
+ Do not use quotation marks around the answer.
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
215
  """
216
 
217
 
 
229
  if client is None:
230
  return (
231
  "",
232
+ "Hugging Face AI unavailable.",
233
  )
234
 
235
+ request = f"""
236
  USER IDEA:
237
  {idea}
238
 
 
242
  ASPECT RATIO:
243
  {aspect}
244
 
245
+ MOOD:
246
  {mood}
247
 
248
  DETAIL LEVEL:
 
257
  messages=[
258
  {
259
  "role": "system",
260
+ "content": AI_SYSTEM,
261
  },
262
  {
263
  "role": "user",
264
+ "content": request,
265
  },
266
  ],
267
  max_tokens=1200,
 
269
  )
270
 
271
  if not response:
272
+ return "", "AI returned no response."
273
 
274
  if not response.choices:
275
+ return "", "AI returned no choices."
276
 
277
  message = response.choices[0].message
278
 
279
  if not message:
280
+ return "", "AI returned no message."
281
 
282
  content = message.content
283
 
284
  if not content:
285
+ return "", "AI returned empty content."
286
 
287
+ content = clean_ai_response(content)
288
 
289
  if not content:
290
+ return "", "AI returned an empty prompt."
291
 
292
  return content, None
293
 
294
  except Exception as exc:
295
+
296
  print(
297
+ "[HF ERROR]",
298
+ type(exc).__name__,
299
+ str(exc),
300
  )
301
 
302
  return (
303
  "",
304
+ "Hugging Face request failed.",
305
  )
306
 
307
 
 
 
 
 
308
  def generate_prompt(
309
  idea: str,
310
  style: str,
 
313
  detail: str,
314
  camera: str,
315
  use_ai: bool,
316
+ ):
317
 
318
  if not idea or not idea.strip():
319
+
320
  return (
321
  "",
322
+ NEGATIVE_PROMPT,
323
  "⚠️ Enter an image idea first.",
324
  )
325
 
326
  idea = clean_text(idea)
327
 
328
  if use_ai:
329
+
330
  ai_prompt, error = build_ai_prompt(
331
+ idea,
332
+ style,
333
+ aspect,
334
+ mood,
335
+ detail,
336
+ camera,
337
  )
338
 
339
  if ai_prompt:
340
+
341
  return (
342
  ai_prompt,
343
+ NEGATIVE_PROMPT,
344
+ f"✓ Generated with {MODEL}",
345
  )
346
 
347
+ local_prompt = build_local_prompt(
348
+ idea,
349
+ style,
350
+ aspect,
351
+ mood,
352
+ detail,
353
+ camera,
354
  )
355
 
356
  return (
357
  local_prompt,
358
+ NEGATIVE_PROMPT,
359
+ f"✓ Built-in engine used • {error}",
360
  )
361
 
362
+ local_prompt = build_local_prompt(
363
+ idea,
364
+ style,
365
+ aspect,
366
+ mood,
367
+ detail,
368
+ camera,
369
  )
370
 
371
  return (
372
  local_prompt,
373
+ NEGATIVE_PROMPT,
374
+ "✓ Generated with built-in engine",
375
  )
376
 
377
 
378
+ TRANSFORM_INSTRUCTIONS = {
 
 
379
 
 
380
  "Improve": """
381
+ Improve this image-generation prompt.
382
 
383
  Preserve the exact core subject and concept.
384
 
385
+ Increase useful visual specificity.
386
+ Strengthen composition, lighting, depth, atmosphere, materials and camera
387
+ language where appropriate.
388
 
389
+ Remove repetition and generic filler.
390
 
391
  Do not radically change the concept.
392
 
393
+ Return ONLY the improved prompt.
394
  """,
395
 
396
  "Remix": """
397
+ Remix this image-generation prompt.
398
 
399
  Preserve the core subject and concept.
400
 
401
+ Create a fresh interpretation by intelligently changing elements such as
402
+ environment, composition, lighting, atmosphere, color or camera perspective.
 
403
 
404
  Do not replace the main subject.
405
 
406
+ Return ONLY the remixed prompt.
 
 
407
  """,
408
 
409
  "Simplify": """
410
+ Simplify this image-generation prompt.
411
 
412
+ Preserve the important subject, environment, style, mood and visual intent.
413
 
414
+ Remove unnecessary adjectives, repetition and generic AI language.
 
415
 
416
+ Make the prompt concise and effective.
417
 
418
+ Return ONLY the simplified prompt.
419
  """,
420
  }
421
 
422
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
423
  def local_transform(
424
  prompt: str,
425
  action: str,
 
429
 
430
  if action == "Improve":
431
 
 
 
432
  addition = (
433
+ " Enhance coherent depth, intentional composition, "
434
  "natural lighting, refined textures, believable materials, "
435
  "and strong focal detail."
436
  )
437
 
438
  return (
439
+ prompt.rstrip(".") + "." + addition,
440
+ "✓ Improved locally",
441
  )
442
 
443
  if action == "Simplify":
 
452
 
453
  return (
454
  clean_text(prompt),
455
+ "✓ Simplified locally",
456
  )
457
 
458
  if action == "Remix":
459
 
460
+ choices = [
461
  "with dramatic atmospheric depth",
462
  "under cinematic environmental lighting",
463
  "with a striking editorial composition",
464
  "with subtle surreal visual elements",
465
  "during a visually dramatic transitional moment",
 
466
  "using an unconventional cinematic perspective",
467
  ]
468
 
469
+ addition = random.choice(choices)
 
 
470
 
471
  return (
472
+ prompt.rstrip(".") + ", " + addition + ".",
473
+ "✓ Remixed locally",
474
  )
475
 
476
  return (
477
  prompt,
478
+ "✓ Prompt ready",
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
479
  )
480
 
481
 
482
+ def transform_prompt(
483
+ prompt: str,
484
+ action: str,
485
+ ) -> Tuple[str, str]:
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
486
 
487
+ if not prompt or not prompt.strip():
 
 
 
488
 
489
+ return (
490
+ "",
491
+ "⚠️ Generate a prompt first.",
492
+ )
493
 
494
+ prompt = clean_text(prompt)
 
 
 
495
 
496
+ client = get_client()
497
+ instruction = TRANSFORM_INSTRUCTIONS.get(action)
 
498
 
499
+ if client is not None and instruction:
 
 
 
500
 
501
+ try:
 
 
 
 
502
 
503
+ response = client.chat_completion(
504
+ messages=[
505
+ {
506
+ "role": "system",
507
+ "content": (
508
+ "You are an expert image prompt editor. "
509
+ "Return only the requested prompt."
510
+ ),
511
+ },
512
+ {
513
+ "role": "user",
514
+ "content": (
515
+ instruction
516
+ + "\n\nCURRENT PROMPT:\n"
517
+ + prompt
518
+ ),
519
+ },
520
+ ],
521
+ max_tokens=1200,
522
+ temperature=(
523
+ 0.8
524
+ if action == "Remix"
525
+ else 0.5
526
+ ),
527
+ )
528
 
529
+ if response and response.choices:
530
 
531
+ content = response.choices[0].message.content
 
 
532
 
533
+ if content:
 
 
 
534
 
535
+ content = clean_ai_response(content)
 
 
536
 
537
+ if content:
 
 
538
 
539
+ return (
540
+ content,
541
+ f"✓ {action} completed with Smart AI",
542
+ )
543
 
544
+ except Exception as exc:
545
 
546
+ print(
547
+ "[TRANSFORM ERROR]",
548
+ type(exc).__name__,
549
+ str(exc),
550
+ )
551
 
552
+ return local_transform(
553
+ prompt,
554
+ action,
555
  )
556
 
 
 
 
557
 
558
+ def improve_prompt(prompt):
559
+ return transform_prompt(prompt, "Improve")
560
 
 
 
 
561
 
562
+ def remix_prompt(prompt):
563
+ return transform_prompt(prompt, "Remix")
564
 
 
 
 
 
 
 
 
 
 
565
 
566
+ def simplify_prompt(prompt):
567
+ return transform_prompt(prompt, "Simplify")
 
 
568
 
569
+
570
+ SURPRISE_IDEAS = [
571
+ "a tiny astronaut exploring an enormous abandoned greenhouse",
572
+ "a fox sitting inside an ancient observatory beneath a meteor shower",
573
+ "a futuristic Brisbane street transformed by bioluminescent plants",
574
+ "a mechanical