yukee1992 commited on
Commit
a6956eb
Β·
verified Β·
1 Parent(s): ae00a18

Update app.py

Browse files
Files changed (1) hide show
  1. app.py +158 -104
app.py CHANGED
@@ -10,6 +10,8 @@ import re
10
  import tempfile
11
  import time
12
  import base64
 
 
13
 
14
  # External OCI API URL
15
  OCI_API_BASE_URL = "https://yukee1992-oci-story-book.hf.space"
@@ -25,13 +27,16 @@ except ImportError:
25
 
26
  # HIGH-QUALITY MODEL SELECTION
27
  MODEL_CHOICES = {
28
- "dreamshaper-8": "lykon/dreamshaper-8", # Excellent for fantasy/artistic
29
- "realistic-vision": "SG161222/Realistic_Vision_V5.1", # Photorealistic
30
- "anything-v5": "andite/anything-v5.0", # Anime/illustration style
31
- "openjourney": "prompthero/openjourney", # Artistic/Midjourney style
32
- "sd-2.1": "stabilityai/stable-diffusion-2-1", # General purpose
33
  }
34
 
 
 
 
35
  # Initialize the HIGH-QUALITY Stable Diffusion model
36
  def load_model(model_name="dreamshaper-8"):
37
  """Load and return a high-quality Stable Diffusion model"""
@@ -46,7 +51,6 @@ def load_model(model_name="dreamshaper-8"):
46
  requires_safety_checker=False
47
  )
48
 
49
- # Use better scheduler for quality
50
  pipe.scheduler = EulerAncestralDiscreteScheduler.from_config(pipe.scheduler.config)
51
  pipe = pipe.to("cpu")
52
 
@@ -54,7 +58,6 @@ def load_model(model_name="dreamshaper-8"):
54
  return pipe
55
  except Exception as e:
56
  print(f"❌ Model loading failed: {e}")
57
- # Fallback to SD 1.5
58
  return StableDiffusionPipeline.from_pretrained(
59
  "runwayml/stable-diffusion-v1-5",
60
  torch_dtype=torch.float32,
@@ -93,25 +96,20 @@ def enhance_prompt(prompt, style="childrens_book"):
93
  ]
94
  }
95
 
96
- # Choose style template
97
  templates = style_templates.get(style, style_templates["childrens_book"])
98
- style_prompt = templates[0] # Use the first template
99
 
100
- # Enhanced prompt construction
101
  enhanced = f"{style_prompt}, {prompt}"
102
 
103
- # Add quality boosters
104
  quality_boosters = [
105
  "intricate details", "beautiful composition", "perfect lighting",
106
  "professional artwork", "award winning", "trending on artstation"
107
  ]
108
 
109
- # Add 2-3 random quality boosters
110
  import random
111
  boosters = random.sample(quality_boosters, 2)
112
  enhanced += ", " + ", ".join(boosters)
113
 
114
- # Negative prompt to avoid bad quality
115
  negative_prompt = (
116
  "blurry, low quality, low resolution, ugly, deformed, poorly drawn, "
117
  "bad anatomy, wrong anatomy, extra limb, missing limb, floating limbs, "
@@ -121,23 +119,37 @@ def enhance_prompt(prompt, style="childrens_book"):
121
 
122
  return enhanced, negative_prompt
123
 
124
- def save_to_oci_via_api(image, prompt):
125
- """Save image using the EXTERNAL OCI API endpoint"""
 
 
 
 
 
 
 
 
 
 
 
126
  try:
127
  # Convert image to bytes
128
  img_bytes = io.BytesIO()
129
  image.save(img_bytes, format='PNG')
130
  img_data = img_bytes.getvalue()
131
 
132
- # Create filename
133
- timestamp = datetime.now().strftime("%Y%m%d_%H%M%S")
134
- safe_prompt = "".join(c for c in prompt[:30] if c.isalnum() or c in (' ', '-', '_')).rstrip()
135
- filename = f"hq_story_{timestamp}_{safe_prompt}.png"
 
 
 
136
 
137
  # Use the EXTERNAL API URL
138
  api_url = f"{OCI_API_BASE_URL}/api/upload"
139
 
140
- print(f"🌐 Calling EXTERNAL OCI API: {api_url}")
141
 
142
  # Prepare form data for API request
143
  files = {
@@ -145,162 +157,204 @@ def save_to_oci_via_api(image, prompt):
145
  }
146
 
147
  data = {
148
- 'project_id': 'storybook-generator',
149
- 'subfolder': 'high-quality-books'
150
  }
151
 
152
- # Make the API request with timeout
153
  response = requests.post(api_url, files=files, data=data, timeout=30)
154
 
155
- print(f"πŸ“¨ API Response: {response.status_code}")
156
-
157
  if response.status_code == 200:
158
  result = response.json()
159
  if result['status'] == 'success':
160
- return f"βœ… {result['message']}"
161
  else:
162
  return f"❌ API Error: {result.get('message', 'Unknown error')}"
163
  else:
164
- return f"❌ HTTP Error: {response.status_code} - {response.text}"
165
 
166
  except Exception as e:
167
- return f"❌ API upload failed: {str(e)}"
168
 
169
- def generate_high_quality_image(prompt, model_choice="dreamshaper-8", style="childrens_book"):
170
- """Generate HIGH-QUALITY image from text prompt"""
171
  try:
172
  if not prompt or not prompt.strip():
173
  return None, "❌ Please enter a scene description"
174
 
 
 
 
175
  # Reload model if different choice
176
  global pipe
177
- if model_choice != "dreamshaper-8": # Default already loaded
178
  pipe = load_model(model_choice)
179
 
180
- # PROFESSIONAL PROMPT ENHANCEMENT
181
  enhanced_prompt, negative_prompt = enhance_prompt(prompt, style)
182
 
183
- print(f"🎨 Generating HQ image for prompt: {enhanced_prompt}")
184
- print(f"🚫 Negative prompt: {negative_prompt[:100]}...")
185
 
186
- # Generate HIGH-QUALITY image with better settings
187
  image = pipe(
188
  prompt=enhanced_prompt,
189
  negative_prompt=negative_prompt,
190
- num_inference_steps=30, # More steps = better quality
191
- guidance_scale=8.5, # Higher guidance = better prompt following
192
- width=768, # Higher resolution
193
  height=768,
194
- generator=torch.Generator(device="cpu").manual_seed(int(time.time())) # Random seed
195
  ).images[0]
196
 
197
- print("βœ… HQ Image generated successfully!")
198
 
199
- # Save to OCI
200
- print("πŸ’Ύ Saving HQ image to OCI storage...")
201
- save_status = save_to_oci_via_api(image, prompt)
202
- print(f"Save status: {save_status}")
203
 
204
  return image, save_status
205
 
206
  except Exception as e:
207
- error_msg = f"❌ HQ Generation failed: {str(e)}"
208
  print(error_msg)
209
- import traceback
210
- print(f"Traceback: {traceback.format_exc()}")
211
  return None, error_msg
212
 
213
- # Create the Gradio interface with QUALITY OPTIONS
214
- with gr.Blocks(title="Premium Children's Book Illustrator", theme="soft") as demo:
215
- gr.Markdown("# 🎨 Premium Children's Book Illustrator")
216
- gr.Markdown("Generate **studio-quality** storybook images with professional results")
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
217
 
218
  with gr.Row():
219
  with gr.Column(scale=1):
 
 
 
 
 
 
 
 
220
  gr.Markdown("### 🎯 Quality Settings")
221
 
222
  model_choice = gr.Dropdown(
223
  label="AI Model",
224
  choices=list(MODEL_CHOICES.keys()),
225
- value="dreamshaper-8",
226
- info="Choose the best model for your style"
227
  )
228
 
229
  style_choice = gr.Dropdown(
230
  label="Art Style",
231
  choices=["childrens_book", "realistic", "fantasy", "anime"],
232
- value="childrens_book",
233
- info="Select the artistic style"
234
  )
 
 
 
235
 
236
  prompt_input = gr.Textbox(
237
- label="Scene Description",
238
- placeholder="Describe your scene in detail...\nExample: A friendly dragon reading a giant book under a magical tree with glowing fairies",
239
- lines=3
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
240
  )
241
 
242
- generate_btn = gr.Button("✨ Generate Premium Image", variant="primary")
243
 
244
- with gr.Column(scale=2):
245
- image_output = gr.Image(label="Generated Image", height=500, show_download_button=True)
246
- status_output = gr.Textbox(label="Status", interactive=False, lines=3)
247
 
248
- # Examples section
249
- with gr.Accordion("πŸ’‘ Prompt Examples & Tips", open=False):
250
  gr.Markdown("""
251
- ## 🎨 Professional Prompt Examples:
252
-
253
- **Best Results:**
254
- - "A cute baby dragon learning to read with an old wise turtle in a magical forest"
255
- - "Group of animal friends having a picnic under a giant glowing mushroom"
256
- - "Little girl exploring a castle made of candy with talking animals"
257
- - "Space adventure with friendly robots and colorful aliens"
 
 
 
258
 
259
- ## 🚫 Avoid:
260
- - "dragon" β†’ **"friendly cartoon dragon reading book"**
261
- - "cat" β†’ **"cute kitten playing with yarn ball"**
262
- - "tree" β†’ **"magical tree with glowing fairies"**
263
-
264
- ## ⚑ Pro Tips:
265
- 1. **Be descriptive** - Add colors, emotions, settings
266
- 2. **Specify style** - "watercolor", "cartoon", "realistic"
267
- 3. **Add details** - "with glowing effects", "in a magical forest"
268
- 4. **Use positive language** - "happy", "friendly", "colorful"
269
  """)
270
 
271
- # Debug section
272
- with gr.Accordion("πŸ”§ Advanced Settings", open=False):
273
- debug_btn = gr.Button("πŸ”„ Check System Status", variant="secondary")
274
- debug_output = gr.Textbox(label="System Info", interactive=False, lines=4)
275
-
276
- def check_system_status():
277
- """Check system status"""
278
- return f"""**System Status:**
279
- - Model: {model_choice.value}
280
- - Style: {style_choice.value}
281
- - OCI API: {OCI_API_BASE_URL}
282
- - Ready for premium image generation!"""
 
 
 
 
 
283
 
284
  # Connect buttons to functions
285
  generate_btn.click(
286
- fn=generate_high_quality_image,
287
- inputs=[prompt_input, model_choice, style_choice],
288
  outputs=[image_output, status_output]
289
  )
290
 
291
- debug_btn.click(
292
- fn=check_system_status,
293
- inputs=None,
294
- outputs=debug_output
295
  )
296
 
297
- # For Hugging Face Spaces deployment
298
  def get_app():
299
  return demo
300
 
301
  if __name__ == "__main__":
302
- print("πŸš€ Starting Premium Children's Book Illustrator...")
303
- print("🎨 Loaded with HIGH-QUALITY models:")
304
- for model in MODEL_CHOICES:
305
- print(f" - {model}")
306
  demo.launch(server_name="0.0.0.0", server_port=7860)
 
10
  import tempfile
11
  import time
12
  import base64
13
+ import json
14
+ from typing import Dict, List, Tuple
15
 
16
  # External OCI API URL
17
  OCI_API_BASE_URL = "https://yukee1992-oci-story-book.hf.space"
 
27
 
28
  # HIGH-QUALITY MODEL SELECTION
29
  MODEL_CHOICES = {
30
+ "dreamshaper-8": "lykon/dreamshaper-8",
31
+ "realistic-vision": "SG161222/Realistic_Vision_V5.1",
32
+ "anything-v5": "andite/anything-v5.0",
33
+ "openjourney": "prompthero/openjourney",
34
+ "sd-2.1": "stabilityai/stable-diffusion-2-1",
35
  }
36
 
37
+ # Story tracking for sequence numbering
38
+ story_registry: Dict[str, int] = {} # {story_title: current_sequence}
39
+
40
  # Initialize the HIGH-QUALITY Stable Diffusion model
41
  def load_model(model_name="dreamshaper-8"):
42
  """Load and return a high-quality Stable Diffusion model"""
 
51
  requires_safety_checker=False
52
  )
53
 
 
54
  pipe.scheduler = EulerAncestralDiscreteScheduler.from_config(pipe.scheduler.config)
55
  pipe = pipe.to("cpu")
56
 
 
58
  return pipe
59
  except Exception as e:
60
  print(f"❌ Model loading failed: {e}")
 
61
  return StableDiffusionPipeline.from_pretrained(
62
  "runwayml/stable-diffusion-v1-5",
63
  torch_dtype=torch.float32,
 
96
  ]
97
  }
98
 
 
99
  templates = style_templates.get(style, style_templates["childrens_book"])
100
+ style_prompt = templates[0]
101
 
 
102
  enhanced = f"{style_prompt}, {prompt}"
103
 
 
104
  quality_boosters = [
105
  "intricate details", "beautiful composition", "perfect lighting",
106
  "professional artwork", "award winning", "trending on artstation"
107
  ]
108
 
 
109
  import random
110
  boosters = random.sample(quality_boosters, 2)
111
  enhanced += ", " + ", ".join(boosters)
112
 
 
113
  negative_prompt = (
114
  "blurry, low quality, low resolution, ugly, deformed, poorly drawn, "
115
  "bad anatomy, wrong anatomy, extra limb, missing limb, floating limbs, "
 
119
 
120
  return enhanced, negative_prompt
121
 
122
+ def get_next_sequence_number(story_title: str) -> int:
123
+ """Get the next sequence number for a story"""
124
+ # Clean the story title for use in filenames
125
+ clean_title = re.sub(r'[^a-zA-Z0-9_\-]', '', story_title.strip().replace(' ', '_'))
126
+
127
+ if clean_title not in story_registry:
128
+ story_registry[clean_title] = 0
129
+
130
+ story_registry[clean_title] += 1
131
+ return story_registry[clean_title], clean_title
132
+
133
+ def save_to_oci_via_api(image, prompt, story_title, sequence_number):
134
+ """Save image with organized storybook structure"""
135
  try:
136
  # Convert image to bytes
137
  img_bytes = io.BytesIO()
138
  image.save(img_bytes, format='PNG')
139
  img_data = img_bytes.getvalue()
140
 
141
+ # Get sequence number and clean title
142
+ seq_num, clean_title = get_next_sequence_number(story_title)
143
+ if sequence_number is not None:
144
+ seq_num = sequence_number # Use provided sequence number if available
145
+
146
+ # Create organized filename with sequence
147
+ filename = f"page_{seq_num:03d}_{clean_title}.png"
148
 
149
  # Use the EXTERNAL API URL
150
  api_url = f"{OCI_API_BASE_URL}/api/upload"
151
 
152
+ print(f"πŸ“ Saving to: stories/{clean_title}/{filename}")
153
 
154
  # Prepare form data for API request
155
  files = {
 
157
  }
158
 
159
  data = {
160
+ 'project_id': 'storybook-library',
161
+ 'subfolder': f'stories/{clean_title}'
162
  }
163
 
164
+ # Make the API request
165
  response = requests.post(api_url, files=files, data=data, timeout=30)
166
 
 
 
167
  if response.status_code == 200:
168
  result = response.json()
169
  if result['status'] == 'success':
170
+ return f"βœ… Saved: {filename} | Story: {clean_title}"
171
  else:
172
  return f"❌ API Error: {result.get('message', 'Unknown error')}"
173
  else:
174
+ return f"❌ HTTP Error: {response.status_code}"
175
 
176
  except Exception as e:
177
+ return f"❌ Upload failed: {str(e)}"
178
 
179
+ def generate_storybook_page(prompt, story_title, sequence_number=None, model_choice="dreamshaper-8", style="childrens_book"):
180
+ """Generate a storybook page with organized naming"""
181
  try:
182
  if not prompt or not prompt.strip():
183
  return None, "❌ Please enter a scene description"
184
 
185
+ if not story_title or not story_title.strip():
186
+ return None, "❌ Please enter a story title"
187
+
188
  # Reload model if different choice
189
  global pipe
190
+ if model_choice != "dreamshaper-8":
191
  pipe = load_model(model_choice)
192
 
193
+ # Professional prompt enhancement
194
  enhanced_prompt, negative_prompt = enhance_prompt(prompt, style)
195
 
196
+ print(f"πŸ“– Generating page for: {story_title}")
197
+ print(f"🎨 Prompt: {enhanced_prompt}")
198
 
199
+ # Generate high-quality image
200
  image = pipe(
201
  prompt=enhanced_prompt,
202
  negative_prompt=negative_prompt,
203
+ num_inference_steps=30,
204
+ guidance_scale=8.5,
205
+ width=768,
206
  height=768,
207
+ generator=torch.Generator(device="cpu").manual_seed(int(time.time()))
208
  ).images[0]
209
 
210
+ print("βœ… Page generated successfully!")
211
 
212
+ # Save with organized structure
213
+ save_status = save_to_oci_via_api(image, prompt, story_title, sequence_number)
214
+ print(f"πŸ’Ύ {save_status}")
 
215
 
216
  return image, save_status
217
 
218
  except Exception as e:
219
+ error_msg = f"❌ Generation failed: {str(e)}"
220
  print(error_msg)
 
 
221
  return None, error_msg
222
 
223
+ def batch_generate_storybook(story_title, scenes_text, model_choice="dreamshaper-8", style="childrens_book"):
224
+ """Generate multiple pages for a complete storybook"""
225
+ if not story_title or not scenes_text:
226
+ return [], "❌ Please provide story title and scenes"
227
+
228
+ scenes = [scene.strip() for scene in scenes_text.split('\n') if scene.strip()]
229
+ results = []
230
+ status_messages = []
231
+
232
+ for i, scene in enumerate(scenes, 1):
233
+ print(f"πŸ“– Generating page {i}/{len(scenes)} for: {story_title}")
234
+ image, status = generate_storybook_page(
235
+ scene, story_title, i, model_choice, style
236
+ )
237
+
238
+ if image:
239
+ results.append((f"Page {i}: {scene}", image))
240
+ status_messages.append(f"Page {i}: {status}")
241
+
242
+ return results, "\n".join(status_messages)
243
+
244
+ # Create the enhanced Gradio interface
245
+ with gr.Blocks(title="Professional Storybook Generator", theme="soft") as demo:
246
+ gr.Markdown("# πŸ“š Professional Storybook Generator")
247
+ gr.Markdown("Create organized storybooks with sequential page numbering")
248
 
249
  with gr.Row():
250
  with gr.Column(scale=1):
251
+ gr.Markdown("### πŸ“– Story Information")
252
+
253
+ story_title = gr.Textbox(
254
+ label="Story Title",
255
+ placeholder="Enter your story title...\nExample: The Dragon's Reading Adventure",
256
+ lines=1
257
+ )
258
+
259
  gr.Markdown("### 🎯 Quality Settings")
260
 
261
  model_choice = gr.Dropdown(
262
  label="AI Model",
263
  choices=list(MODEL_CHOICES.keys()),
264
+ value="dreamshaper-8"
 
265
  )
266
 
267
  style_choice = gr.Dropdown(
268
  label="Art Style",
269
  choices=["childrens_book", "realistic", "fantasy", "anime"],
270
+ value="childrens_book"
 
271
  )
272
+
273
+ with gr.Column(scale=2):
274
+ gr.Markdown("### 🎨 Single Page Generation")
275
 
276
  prompt_input = gr.Textbox(
277
+ label="Page Description",
278
+ placeholder="Describe this page's scene...\nExample: The dragon discovers a magical library in the forest",
279
+ lines=2
280
+ )
281
+
282
+ generate_btn = gr.Button("✨ Generate Single Page", variant="primary")
283
+ image_output = gr.Image(label="Generated Page", height=400, show_download_button=True)
284
+ status_output = gr.Textbox(label="Status", interactive=False, lines=2)
285
+
286
+ with gr.Row():
287
+ gr.Markdown("### πŸ“š Complete Storybook Generation")
288
+
289
+ with gr.Row():
290
+ with gr.Column():
291
+ scenes_input = gr.Textbox(
292
+ label="Story Scenes (One per line = One per page)",
293
+ placeholder="Enter each page's scene on a separate line...\nExample:\nThe dragon finds a mysterious book\nHe learns to read with owl friend\nThey discover hidden treasure map\nFriends celebrate with magical feast",
294
+ lines=6
295
  )
296
 
297
+ batch_btn = gr.Button("πŸ“– Generate Complete Storybook", variant="primary")
298
 
299
+ with gr.Column():
300
+ batch_status = gr.Textbox(label="Generation Status", interactive=False, lines=8)
301
+ batch_gallery = gr.Gallery(label="Storybook Pages", columns=2, height=600)
302
 
303
+ with gr.Accordion("πŸ“ Folder Structure Preview", open=True):
 
304
  gr.Markdown("""
305
+ **Your story will be organized as:**
306
+ ```
307
+ storybook-library/
308
+ └── stories/
309
+ └── The_Dragons_Reading_Adventure/
310
+ β”œβ”€β”€ page_001_The_Dragons_Reading_Adventure.png
311
+ β”œβ”€β”€ page_002_The_Dragons_Reading_Adventure.png
312
+ β”œβ”€β”€ page_003_The_Dragons_Reading_Adventure.png
313
+ └── page_004_The_Dragons_Reading_Adventure.png
314
+ ```
315
 
316
+ **Perfect for:**
317
+ - βœ… Easy PDF compilation later
318
+ - βœ… Automatic sequencing
319
+ - βœ… Organized by story title
320
+ - βœ… Ready for n8n automation
 
 
 
 
 
321
  """)
322
 
323
+ with gr.Accordion("πŸ’‘ API Usage for n8n", open=False):
324
+ gr.Markdown("""
325
+ **For n8n automation, use this JSON format:**
326
+ ```json
327
+ {
328
+ "story_title": "The Dragon's Reading Adventure",
329
+ "scenes": [
330
+ "The dragon finds a mysterious old book in the forest",
331
+ "He meets an owl who teaches him to read",
332
+ "They discover a hidden treasure map in the book",
333
+ "All animal friends celebrate with a magical feast"
334
+ ],
335
+ "model_choice": "dreamshaper-8",
336
+ "style": "childrens_book"
337
+ }
338
+ ```
339
+ """)
340
 
341
  # Connect buttons to functions
342
  generate_btn.click(
343
+ fn=generate_storybook_page,
344
+ inputs=[prompt_input, story_title, gr.Number(visible=False), model_choice, style_choice],
345
  outputs=[image_output, status_output]
346
  )
347
 
348
+ batch_btn.click(
349
+ fn=batch_generate_storybook,
350
+ inputs=[story_title, scenes_input, model_choice, style_choice],
351
+ outputs=[batch_gallery, batch_status]
352
  )
353
 
 
354
  def get_app():
355
  return demo
356
 
357
  if __name__ == "__main__":
358
+ print("πŸš€ Starting Professional Storybook Generator...")
359
+ print("πŸ“ Feature: Organized story sequencing enabled")
 
 
360
  demo.launch(server_name="0.0.0.0", server_port=7860)