fizzarif7 commited on
Commit
ca4cae7
·
verified ·
1 Parent(s): 2b3fd90

Update app.py

Browse files
Files changed (1) hide show
  1. app.py +89 -71
app.py CHANGED
@@ -6,7 +6,6 @@ from dotenv import load_dotenv
6
  from gtts import gTTS
7
  import tempfile
8
  import traceback
9
- from moviepy.editor import ImageClip, concatenate_videoclips, AudioFileClip
10
 
11
  from reportlab.platypus import SimpleDocTemplate, Paragraph, Spacer, Image as RLImage
12
  from reportlab.lib.pagesizes import letter
@@ -32,7 +31,8 @@ image_model = genai.GenerativeModel(
32
  )
33
  hf_client = InferenceClient(token=hf_token)
34
 
35
- # Utilities
 
36
  def generate_image_from_text(prompt):
37
  try:
38
  response = image_model.generate_content(prompt)
@@ -40,14 +40,15 @@ def generate_image_from_text(prompt):
40
  if hasattr(part, 'inline_data') and part.inline_data.mime_type.startswith("image/"):
41
  return Image.open(BytesIO(part.inline_data.data))
42
  except Exception as e:
43
- print("Image gen error:", e)
44
  return None
45
 
46
  def summarize_scene(scene_text):
47
  try:
48
  response = text_model.generate_content(f"Summarize this scene in one sentence: {scene_text}")
49
  return response.text.strip()
50
- except:
 
51
  return "Summary unavailable."
52
 
53
  def explain_scene(image):
@@ -59,8 +60,10 @@ def explain_scene(image):
59
  buffered = BytesIO()
60
  image.save(buffered, format="PNG")
61
  buffered.seek(0)
62
- return hf_client.image_to_text("Salesforce/blip-image-captioning-base", image=buffered).strip()
 
63
  except:
 
64
  return "Explanation unavailable."
65
 
66
  def text_to_speech(text):
@@ -69,7 +72,8 @@ def text_to_speech(text):
69
  tmp = tempfile.NamedTemporaryFile(delete=False, suffix=".mp3")
70
  tts.save(tmp.name)
71
  return tmp.name
72
- except:
 
73
  return None
74
 
75
  def generate_pdf(images, explanations):
@@ -85,95 +89,109 @@ def generate_pdf(images, explanations):
85
  story += [
86
  RLImage(img_tmp.name, width=400, height=300),
87
  Spacer(1, 12),
88
- Paragraph(f"Scene {i+1} Explanation", styles["Heading3"]),
89
  Paragraph(explanations[i], styles["BodyText"]),
90
  Spacer(1, 24),
91
  ]
92
  doc.build(story)
93
  return tmp.name
94
 
95
- def generate_video(images, explanations):
96
- clips = []
97
- for img, explanation in zip(images, explanations):
98
- if img and explanation:
99
- audio_path = text_to_speech(explanation)
100
- if audio_path:
101
- audio = AudioFileClip(audio_path)
102
- img_path = tempfile.NamedTemporaryFile(delete=False, suffix=".png").name
103
- img.save(img_path)
104
- clip = ImageClip(img_path).set_duration(audio.duration).set_audio(audio)
105
- clips.append(clip)
106
- if clips:
107
- final_video = concatenate_videoclips(clips)
108
- out_path = tempfile.NamedTemporaryFile(delete=False, suffix=".mp4").name
109
- final_video.write_videofile(out_path, codec="libx264", audio_codec="aac")
110
- return out_path
111
- return None
112
 
113
- def remove_scene(index, images, summaries, explanations):
114
- try:
115
- index = int(index)
116
- if 0 <= index < len(images):
117
- del images[index]
118
- del summaries[index]
119
- del explanations[index]
120
- except:
121
- pass
122
  return images, summaries, explanations
123
 
124
- def get_thumbnails(images):
125
- return images
 
 
 
126
 
127
- # UI Placeholder
128
- with gr.Blocks() as demo:
129
- gr.Markdown("## 🎬 AI Story Builder with Scene Editing & Video Export")
130
 
131
- theme = gr.Textbox(label="Theme")
132
- characters = gr.Textbox(label="Characters")
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
133
  dialogue = gr.Textbox(label="Dialogue")
134
 
135
  generate_btn = gr.Button("Generate Scene")
136
- delete_index = gr.Number(label="Delete Scene Index (0-based)")
137
- delete_btn = gr.Button("Delete Scene")
 
 
 
138
 
139
- images_state = gr.State([])
140
- summaries_state = gr.State([])
141
- explanations_state = gr.State([])
142
 
143
- thumbnails = gr.Gallery(label="Scene Previews").style(grid=[4], height="auto")
144
- explanation_box = gr.Textbox(label="Last Scene Explanation", lines=5)
145
- summary_box = gr.Textbox(label="Last Scene Summary")
146
 
147
- pdf_file = gr.File(label="Download PDF")
148
- video_file = gr.File(label="Download Video")
149
- export_btn = gr.Button("Export PDF and Video")
150
 
151
  generate_btn.click(
152
- fn=lambda theme, characters, dialogue, images, summaries, explanations: (
153
- img := generate_image_from_text(f"Theme: {theme}, Characters: {characters}, Dialogue: {dialogue}"),
154
- summ := summarize_scene(theme),
155
- expl := explain_scene(img),
156
- images + [img], summaries + [summ], explanations + [expl],
157
- f"{expl}", f"{summ}", get_thumbnails(images + [img])
158
  ),
159
- inputs=[theme, characters, dialogue, images_state, summaries_state, explanations_state],
160
- outputs=[images_state, summaries_state, explanations_state, explanation_box, summary_box, thumbnails]
 
 
 
 
 
 
161
  )
162
 
163
  delete_btn.click(
164
- fn=remove_scene,
165
- inputs=[delete_index, images_state, summaries_state, explanations_state],
166
- outputs=[images_state, summaries_state, explanations_state]
167
- ).then(
168
- fn=get_thumbnails,
169
- inputs=images_state,
170
- outputs=thumbnails
171
  )
172
 
173
- export_btn.click(
174
- fn=lambda images, explanations: (generate_pdf(images, explanations), generate_video(images, explanations)),
175
- inputs=[images_state, explanations_state],
176
- outputs=[pdf_file, video_file]
177
  )
178
 
179
- demo.launch()
 
6
  from gtts import gTTS
7
  import tempfile
8
  import traceback
 
9
 
10
  from reportlab.platypus import SimpleDocTemplate, Paragraph, Spacer, Image as RLImage
11
  from reportlab.lib.pagesizes import letter
 
31
  )
32
  hf_client = InferenceClient(token=hf_token)
33
 
34
+ # -------------------- Utility Functions --------------------
35
+
36
  def generate_image_from_text(prompt):
37
  try:
38
  response = image_model.generate_content(prompt)
 
40
  if hasattr(part, 'inline_data') and part.inline_data.mime_type.startswith("image/"):
41
  return Image.open(BytesIO(part.inline_data.data))
42
  except Exception as e:
43
+ print("Image generation error:", e)
44
  return None
45
 
46
  def summarize_scene(scene_text):
47
  try:
48
  response = text_model.generate_content(f"Summarize this scene in one sentence: {scene_text}")
49
  return response.text.strip()
50
+ except Exception as e:
51
+ print("Summary error:", e)
52
  return "Summary unavailable."
53
 
54
  def explain_scene(image):
 
60
  buffered = BytesIO()
61
  image.save(buffered, format="PNG")
62
  buffered.seek(0)
63
+ result = hf_client.image_to_text("Salesforce/blip-image-captioning-base", image=buffered)
64
+ return result.strip()
65
  except:
66
+ traceback.print_exc()
67
  return "Explanation unavailable."
68
 
69
  def text_to_speech(text):
 
72
  tmp = tempfile.NamedTemporaryFile(delete=False, suffix=".mp3")
73
  tts.save(tmp.name)
74
  return tmp.name
75
+ except Exception as e:
76
+ print("TTS error:", e)
77
  return None
78
 
79
  def generate_pdf(images, explanations):
 
89
  story += [
90
  RLImage(img_tmp.name, width=400, height=300),
91
  Spacer(1, 12),
92
+ Paragraph(f"Scene {i + 1} Explanation", styles["Heading3"]),
93
  Paragraph(explanations[i], styles["BodyText"]),
94
  Spacer(1, 24),
95
  ]
96
  doc.build(story)
97
  return tmp.name
98
 
99
+ # -------------------- Scene Management --------------------
100
+
101
+ def generate_scene(prompt, images, summaries, explanations):
102
+ image = generate_image_from_text(prompt)
103
+ summary = summarize_scene(prompt)
104
+ explanation = explain_scene(image) if image else "Explanation unavailable."
105
+
106
+ images.append(image)
107
+ summaries.append(summary)
108
+ explanations.append(explanation)
 
 
 
 
 
 
 
109
 
 
 
 
 
 
 
 
 
 
110
  return images, summaries, explanations
111
 
112
+ def edit_scene(index, theme, char_count, character_names, dialogue, images, summaries, explanations):
113
+ prompt = f"Scene {index+1} set in {theme}. Characters: {character_names}. Dialogue: '{dialogue}'"
114
+ image = generate_image_from_text(prompt)
115
+ summary = summarize_scene(prompt)
116
+ explanation = explain_scene(image)
117
 
118
+ images[index] = image
119
+ summaries[index] = summary
120
+ explanations[index] = explanation
121
 
122
+ return images, summaries, explanations
123
+
124
+ def delete_scene(index, images, summaries, explanations):
125
+ if 0 <= index < len(images):
126
+ del images[index]
127
+ del summaries[index]
128
+ del explanations[index]
129
+ return images, summaries, explanations
130
+
131
+ def finalize_story(images, explanations):
132
+ if not images or not explanations:
133
+ return None, None
134
+ pdf = generate_pdf(images, explanations)
135
+ with tempfile.NamedTemporaryFile(delete=False, suffix=".txt", mode="w", encoding="utf-8") as txt:
136
+ for i, exp in enumerate(explanations):
137
+ txt.write(f"Scene {i+1}:\n{exp}\n\n")
138
+ txt_path = txt.name
139
+ return txt_path, pdf
140
+
141
+ # -------------------- UI Logic --------------------
142
+
143
+ with gr.Blocks(title="AI Scene Builder with Preview & Editing") as demo:
144
+ gr.Markdown("## 🎬 AI Story Scene Generator with Editing and Previews")
145
+
146
+ scene_count = gr.Number(label="Number of Scenes", precision=0)
147
+ theme = gr.Textbox(label="Global Theme")
148
+
149
+ char_count = gr.Number(label="Number of Characters", precision=0)
150
+ character_names = gr.Textbox(label="Character Names")
151
  dialogue = gr.Textbox(label="Dialogue")
152
 
153
  generate_btn = gr.Button("Generate Scene")
154
+ index_to_edit = gr.Number(label="Scene Index to Edit/Delete (0-based)", value=0)
155
+ edit_btn = gr.Button("✏️ Edit Scene")
156
+ delete_btn = gr.Button("🗑️ Delete Scene")
157
+
158
+ thumbnail_gallery = gr.Gallery(label="Scene Previews").style(grid=[4], height="auto")
159
 
160
+ finalize_btn = gr.Button("✅ Finalize & Export")
161
+ txt_file = gr.File()
162
+ pdf_file = gr.File()
163
 
164
+ scene_images = gr.State([])
165
+ scene_explanations = gr.State([])
166
+ scene_summaries = gr.State([])
167
 
168
+ def build_prompt(index, theme, character_names, dialogue):
169
+ return f"Scene {index+1} set in {theme}. Characters: {character_names}. Dialogue: '{dialogue}'"
 
170
 
171
  generate_btn.click(
172
+ lambda sc, th, cc, names, dlg, imgs, sums, expls: generate_scene(
173
+ build_prompt(len(imgs), th, names, dlg), imgs, sums, expls
 
 
 
 
174
  ),
175
+ inputs=[scene_count, theme, char_count, character_names, dialogue, scene_images, scene_summaries, scene_explanations],
176
+ outputs=[scene_images, scene_summaries, scene_explanations, thumbnail_gallery]
177
+ )
178
+
179
+ edit_btn.click(
180
+ edit_scene,
181
+ inputs=[index_to_edit, theme, char_count, character_names, dialogue, scene_images, scene_summaries, scene_explanations],
182
+ outputs=[scene_images, scene_summaries, scene_explanations, thumbnail_gallery]
183
  )
184
 
185
  delete_btn.click(
186
+ delete_scene,
187
+ inputs=[index_to_edit, scene_images, scene_summaries, scene_explanations],
188
+ outputs=[scene_images, scene_summaries, scene_explanations, thumbnail_gallery]
 
 
 
 
189
  )
190
 
191
+ finalize_btn.click(
192
+ finalize_story,
193
+ inputs=[scene_images, scene_explanations],
194
+ outputs=[txt_file, pdf_file]
195
  )
196
 
197
+ demo.launch()