Spaces:
Sleeping
Sleeping
Major Speed update
#1
by dev-immersfy - opened
- .gitignore +3 -2
- app.py +131 -98
- aws_utils.py +2 -2
- core.py +279 -393
- parameters.py +5 -3
- script_gen.py +22 -15
.gitignore
CHANGED
|
@@ -1,2 +1,3 @@
|
|
| 1 |
-
.env
|
| 2 |
-
__pycache__
|
|
|
|
|
|
| 1 |
+
*.env
|
| 2 |
+
__pycache__/
|
| 3 |
+
.gradio/
|
app.py
CHANGED
|
@@ -11,10 +11,10 @@ with gr.Blocks() as demo:
|
|
| 11 |
current_episode = gr.State(-1)
|
| 12 |
current_scene = gr.State(-1)
|
| 13 |
current_frame = gr.State(-1)
|
| 14 |
-
|
| 15 |
character_data = gr.State({})
|
| 16 |
current_frame_data = gr.State(None)
|
| 17 |
-
|
| 18 |
image_data_b64 = gr.State([])
|
| 19 |
choice = gr.State([])
|
| 20 |
|
|
@@ -34,11 +34,11 @@ with gr.Blocks() as demo:
|
|
| 34 |
with gr.Column():
|
| 35 |
load_images = gr.Button("Load Images")
|
| 36 |
developer = gr.Checkbox(
|
| 37 |
-
value=False, label="Enable Developer Mode"
|
| 38 |
)
|
| 39 |
|
| 40 |
images = gr.Gallery(
|
| 41 |
-
label="Select an Image", elem_id="image_select", columns=4, height=
|
| 42 |
)
|
| 43 |
|
| 44 |
with gr.Row():
|
|
@@ -58,43 +58,46 @@ with gr.Blocks() as demo:
|
|
| 58 |
|
| 59 |
with gr.Column(visible=False) as developer_options:
|
| 60 |
with gr.Column():
|
| 61 |
-
setting = gr.Textbox(label="Frame Setting")
|
| 62 |
with gr.Row():
|
| 63 |
with gr.Column():
|
| 64 |
gr.Markdown("## Composition #1")
|
| 65 |
-
prompt_1 = gr.TextArea(label="Image Prompt")
|
| 66 |
seed_1 = gr.Textbox(label="Generation Seed")
|
| 67 |
with gr.Column():
|
| 68 |
gr.Markdown("## Composition #2")
|
| 69 |
-
prompt_2 = gr.TextArea(label="Image Prompt")
|
| 70 |
seed_2 = gr.Textbox(label="Generation Seed")
|
| 71 |
with gr.Row():
|
| 72 |
with gr.Column():
|
| 73 |
gr.Markdown("## Composition #3")
|
| 74 |
-
prompt_3 = gr.TextArea(label="Image Prompt")
|
| 75 |
seed_3 = gr.Textbox(label="Generation Seed")
|
| 76 |
with gr.Column():
|
| 77 |
gr.Markdown("## Composition #4")
|
| 78 |
-
prompt_4 = gr.TextArea(label="Image Prompt")
|
| 79 |
seed_4 = gr.Textbox(label="Generation Seed")
|
| 80 |
|
| 81 |
with gr.Row():
|
| 82 |
regenerate_comps_btn = gr.Button(value="Regenerate Compositions")
|
| 83 |
-
save_components_btn = gr.Button(value="Save Compositions")
|
| 84 |
|
| 85 |
with gr.Column():
|
| 86 |
negative_prompt = gr.TextArea(
|
| 87 |
value="",
|
| 88 |
label="Negative Prompt",
|
|
|
|
| 89 |
)
|
| 90 |
-
|
| 91 |
-
chars = gr.CheckboxGroup(
|
| 92 |
choices=[], value=[], label="Related Characters", interactive=True
|
| 93 |
)
|
| 94 |
|
| 95 |
with gr.Row():
|
| 96 |
-
height = gr.Textbox(
|
| 97 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
| 98 |
visual_style = gr.Dropdown(
|
| 99 |
choices=parameters.VISUAL_CHOICES,
|
| 100 |
label="Current Visual Style",
|
|
@@ -106,57 +109,65 @@ with gr.Blocks() as demo:
|
|
| 106 |
save_btn = gr.Button("Save")
|
| 107 |
|
| 108 |
############################################ EVENTS ############################################
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 109 |
load_metadata.click(
|
| 110 |
core.load_metadata_fn,
|
| 111 |
inputs=[comic_id],
|
|
|
|
|
|
|
|
|
|
|
|
|
| 112 |
outputs=[
|
| 113 |
-
episode_dropdown,
|
| 114 |
frame_dropdown,
|
| 115 |
current_episode,
|
| 116 |
current_frame,
|
| 117 |
-
|
| 118 |
-
|
| 119 |
-
details,
|
| 120 |
-
developer,
|
| 121 |
],
|
| 122 |
)
|
| 123 |
|
| 124 |
episode_dropdown.input(
|
| 125 |
-
core.
|
| 126 |
-
inputs=[episode_dropdown],
|
| 127 |
outputs=[
|
| 128 |
-
episode_dropdown,
|
| 129 |
frame_dropdown,
|
| 130 |
current_episode,
|
| 131 |
current_frame,
|
|
|
|
|
|
|
| 132 |
],
|
| 133 |
)
|
| 134 |
|
| 135 |
frame_dropdown.input(
|
| 136 |
-
|
| 137 |
inputs=[frame_dropdown],
|
| 138 |
-
outputs=[
|
| 139 |
-
current_frame,
|
| 140 |
-
],
|
| 141 |
)
|
| 142 |
|
| 143 |
load_images.click(
|
| 144 |
-
core.
|
| 145 |
inputs=[
|
| 146 |
-
|
| 147 |
-
current_episode,
|
| 148 |
current_frame,
|
| 149 |
-
|
| 150 |
-
character_data,
|
| 151 |
],
|
| 152 |
outputs=[
|
| 153 |
-
episode_dropdown,
|
| 154 |
-
frame_dropdown,
|
| 155 |
-
# Textual data returned from load_text_data()
|
| 156 |
images,
|
| 157 |
-
episodes_data,
|
| 158 |
-
current_episode,
|
| 159 |
-
current_frame,
|
| 160 |
image_description,
|
| 161 |
narration,
|
| 162 |
character,
|
|
@@ -171,33 +182,44 @@ with gr.Blocks() as demo:
|
|
| 171 |
seed_3,
|
| 172 |
prompt_4,
|
| 173 |
seed_4,
|
| 174 |
-
chars,
|
| 175 |
],
|
|
|
|
|
|
|
|
|
|
|
|
|
| 176 |
)
|
| 177 |
|
| 178 |
# When an image is clicked
|
| 179 |
def get_select_index(evt: gr.SelectData, images):
|
| 180 |
return images[evt.index]
|
| 181 |
-
|
| 182 |
images.select(get_select_index, images, selected_image)
|
| 183 |
|
| 184 |
next_button.click(
|
| 185 |
core.load_data_next,
|
| 186 |
inputs=[
|
| 187 |
-
|
| 188 |
current_episode,
|
| 189 |
current_frame,
|
| 190 |
-
|
| 191 |
-
|
| 192 |
],
|
| 193 |
outputs=[
|
| 194 |
episode_dropdown,
|
| 195 |
frame_dropdown,
|
| 196 |
-
# Textual data returned from load_text_data()
|
| 197 |
-
images,
|
| 198 |
-
episodes_data,
|
| 199 |
current_episode,
|
| 200 |
current_frame,
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 201 |
image_description,
|
| 202 |
narration,
|
| 203 |
character,
|
|
@@ -212,27 +234,43 @@ with gr.Blocks() as demo:
|
|
| 212 |
seed_3,
|
| 213 |
prompt_4,
|
| 214 |
seed_4,
|
| 215 |
-
chars,
|
| 216 |
],
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 217 |
)
|
| 218 |
|
| 219 |
prev_button.click(
|
| 220 |
core.load_data_prev,
|
| 221 |
inputs=[
|
| 222 |
-
|
| 223 |
current_episode,
|
| 224 |
current_frame,
|
| 225 |
-
|
| 226 |
-
|
| 227 |
],
|
| 228 |
outputs=[
|
| 229 |
episode_dropdown,
|
| 230 |
frame_dropdown,
|
| 231 |
-
# Textual data returned from load_text_data()
|
| 232 |
-
images,
|
| 233 |
-
episodes_data,
|
| 234 |
current_episode,
|
| 235 |
current_frame,
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 236 |
image_description,
|
| 237 |
narration,
|
| 238 |
character,
|
|
@@ -247,8 +285,15 @@ with gr.Blocks() as demo:
|
|
| 247 |
seed_3,
|
| 248 |
prompt_4,
|
| 249 |
seed_4,
|
| 250 |
-
chars,
|
| 251 |
],
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 252 |
)
|
| 253 |
|
| 254 |
save_button.click(
|
|
@@ -262,23 +307,8 @@ with gr.Blocks() as demo:
|
|
| 262 |
outputs=[],
|
| 263 |
)
|
| 264 |
|
| 265 |
-
developer.change(
|
| 266 |
-
core.toggle_developer_options,
|
| 267 |
-
inputs=[developer, prompt_1, prompt_2, prompt_3, prompt_4, setting],
|
| 268 |
-
outputs=[developer_options, prompt_1, prompt_2, prompt_3, prompt_4, setting],
|
| 269 |
-
).then(
|
| 270 |
-
lambda: (
|
| 271 |
-
gr.update(interactive=True),
|
| 272 |
-
gr.update(interactive=True),
|
| 273 |
-
gr.update(interactive=True),
|
| 274 |
-
gr.update(interactive=True),
|
| 275 |
-
gr.update(interactive=True),
|
| 276 |
-
),
|
| 277 |
-
outputs=[prompt_1, prompt_2, prompt_3, prompt_4, setting],
|
| 278 |
-
)
|
| 279 |
-
|
| 280 |
regenerate_comps_btn.click(
|
| 281 |
-
core.
|
| 282 |
inputs=[
|
| 283 |
image_description,
|
| 284 |
narration,
|
|
@@ -286,12 +316,31 @@ with gr.Blocks() as demo:
|
|
| 286 |
dialouge,
|
| 287 |
location,
|
| 288 |
setting,
|
| 289 |
-
|
| 290 |
current_episode,
|
| 291 |
current_frame,
|
| 292 |
-
|
|
|
|
|
|
|
| 293 |
],
|
| 294 |
outputs=[
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 295 |
prompt_1,
|
| 296 |
seed_1,
|
| 297 |
prompt_2,
|
|
@@ -299,16 +348,17 @@ with gr.Blocks() as demo:
|
|
| 299 |
prompt_3,
|
| 300 |
seed_3,
|
| 301 |
prompt_4,
|
| 302 |
-
seed_4
|
| 303 |
],
|
|
|
|
| 304 |
)
|
| 305 |
|
| 306 |
-
|
| 307 |
-
core.
|
| 308 |
inputs=[
|
| 309 |
current_episode,
|
| 310 |
current_frame,
|
| 311 |
-
|
| 312 |
comic_id,
|
| 313 |
image_description,
|
| 314 |
narration,
|
|
@@ -316,36 +366,19 @@ with gr.Blocks() as demo:
|
|
| 316 |
dialouge,
|
| 317 |
location,
|
| 318 |
setting,
|
| 319 |
-
chars,
|
| 320 |
prompt_1,
|
| 321 |
prompt_2,
|
| 322 |
prompt_3,
|
| 323 |
prompt_4,
|
| 324 |
-
|
| 325 |
-
|
| 326 |
-
)
|
| 327 |
-
regenerate_btn.click(
|
| 328 |
-
core.regenerate_data,
|
| 329 |
-
inputs=[
|
| 330 |
-
comic_id,
|
| 331 |
-
current_episode,
|
| 332 |
-
current_frame,
|
| 333 |
-
episodes_data,
|
| 334 |
character_data,
|
| 335 |
-
|
| 336 |
-
|
| 337 |
-
width,
|
| 338 |
-
details,
|
| 339 |
-
chars,
|
| 340 |
-
],
|
| 341 |
-
outputs=[images, image_data_b64],
|
| 342 |
)
|
| 343 |
|
| 344 |
-
save_btn.click(
|
| 345 |
-
core.save_images,
|
| 346 |
-
inputs=[image_data_b64, current_episode, current_frame, comic_id, details],
|
| 347 |
-
)
|
| 348 |
demo.launch(
|
| 349 |
-
auth=("admin", "Qrt@12*34#immersfy"), share=True, ssr_mode=False, debug=True
|
|
|
|
| 350 |
)
|
| 351 |
# demo.launch(share=True, ssr_mode=False, debug=True)
|
|
|
|
| 11 |
current_episode = gr.State(-1)
|
| 12 |
current_scene = gr.State(-1)
|
| 13 |
current_frame = gr.State(-1)
|
| 14 |
+
episode_data = gr.State({})
|
| 15 |
character_data = gr.State({})
|
| 16 |
current_frame_data = gr.State(None)
|
| 17 |
+
frame_hash_map = gr.State({})
|
| 18 |
image_data_b64 = gr.State([])
|
| 19 |
choice = gr.State([])
|
| 20 |
|
|
|
|
| 34 |
with gr.Column():
|
| 35 |
load_images = gr.Button("Load Images")
|
| 36 |
developer = gr.Checkbox(
|
| 37 |
+
value=False, label="Enable Developer Mode"
|
| 38 |
)
|
| 39 |
|
| 40 |
images = gr.Gallery(
|
| 41 |
+
label="Select an Image", elem_id="image_select", columns=4, height=320, object_fit="contain"
|
| 42 |
)
|
| 43 |
|
| 44 |
with gr.Row():
|
|
|
|
| 58 |
|
| 59 |
with gr.Column(visible=False) as developer_options:
|
| 60 |
with gr.Column():
|
| 61 |
+
setting = gr.Textbox(label="Frame Setting", interactive=True)
|
| 62 |
with gr.Row():
|
| 63 |
with gr.Column():
|
| 64 |
gr.Markdown("## Composition #1")
|
| 65 |
+
prompt_1 = gr.TextArea(label="Image Prompt", interactive=True)
|
| 66 |
seed_1 = gr.Textbox(label="Generation Seed")
|
| 67 |
with gr.Column():
|
| 68 |
gr.Markdown("## Composition #2")
|
| 69 |
+
prompt_2 = gr.TextArea(label="Image Prompt", interactive=True)
|
| 70 |
seed_2 = gr.Textbox(label="Generation Seed")
|
| 71 |
with gr.Row():
|
| 72 |
with gr.Column():
|
| 73 |
gr.Markdown("## Composition #3")
|
| 74 |
+
prompt_3 = gr.TextArea(label="Image Prompt", interactive=True)
|
| 75 |
seed_3 = gr.Textbox(label="Generation Seed")
|
| 76 |
with gr.Column():
|
| 77 |
gr.Markdown("## Composition #4")
|
| 78 |
+
prompt_4 = gr.TextArea(label="Image Prompt", interactive=True)
|
| 79 |
seed_4 = gr.Textbox(label="Generation Seed")
|
| 80 |
|
| 81 |
with gr.Row():
|
| 82 |
regenerate_comps_btn = gr.Button(value="Regenerate Compositions")
|
|
|
|
| 83 |
|
| 84 |
with gr.Column():
|
| 85 |
negative_prompt = gr.TextArea(
|
| 86 |
value="",
|
| 87 |
label="Negative Prompt",
|
| 88 |
+
interactive=True,
|
| 89 |
)
|
| 90 |
+
related_chars = gr.CheckboxGroup(
|
|
|
|
| 91 |
choices=[], value=[], label="Related Characters", interactive=True
|
| 92 |
)
|
| 93 |
|
| 94 |
with gr.Row():
|
| 95 |
+
height = gr.Textbox(
|
| 96 |
+
value=parameters.IMG_HEIGHT, label="Image Height", interactive=True
|
| 97 |
+
)
|
| 98 |
+
width = gr.Textbox(
|
| 99 |
+
value=parameters.IMG_WIDTH, label="Image Width", interactive=True
|
| 100 |
+
)
|
| 101 |
visual_style = gr.Dropdown(
|
| 102 |
choices=parameters.VISUAL_CHOICES,
|
| 103 |
label="Current Visual Style",
|
|
|
|
| 109 |
save_btn = gr.Button("Save")
|
| 110 |
|
| 111 |
############################################ EVENTS ############################################
|
| 112 |
+
developer.change(
|
| 113 |
+
core.toggle_developer_options,
|
| 114 |
+
inputs=[developer],
|
| 115 |
+
outputs=[developer_options],
|
| 116 |
+
).then(
|
| 117 |
+
lambda is_developer: (
|
| 118 |
+
gr.update(interactive=is_developer),
|
| 119 |
+
gr.update(interactive=is_developer),
|
| 120 |
+
gr.update(interactive=is_developer),
|
| 121 |
+
gr.update(interactive=is_developer),
|
| 122 |
+
gr.update(interactive=is_developer),
|
| 123 |
+
),
|
| 124 |
+
inputs=[developer],
|
| 125 |
+
outputs=[image_description, narration, character, dialouge, location],
|
| 126 |
+
)
|
| 127 |
+
|
| 128 |
load_metadata.click(
|
| 129 |
core.load_metadata_fn,
|
| 130 |
inputs=[comic_id],
|
| 131 |
+
outputs=[episode_dropdown, current_episode, character_data],
|
| 132 |
+
).then( # This ensures `load_dropdown_fn` runs after `load_metadata_fn`
|
| 133 |
+
core.episode_dropdown_effect,
|
| 134 |
+
inputs=[comic_id, episode_dropdown],
|
| 135 |
outputs=[
|
|
|
|
| 136 |
frame_dropdown,
|
| 137 |
current_episode,
|
| 138 |
current_frame,
|
| 139 |
+
episode_data,
|
| 140 |
+
frame_hash_map,
|
|
|
|
|
|
|
| 141 |
],
|
| 142 |
)
|
| 143 |
|
| 144 |
episode_dropdown.input(
|
| 145 |
+
core.episode_dropdown_effect,
|
| 146 |
+
inputs=[comic_id, episode_dropdown],
|
| 147 |
outputs=[
|
|
|
|
| 148 |
frame_dropdown,
|
| 149 |
current_episode,
|
| 150 |
current_frame,
|
| 151 |
+
episode_data,
|
| 152 |
+
frame_hash_map,
|
| 153 |
],
|
| 154 |
)
|
| 155 |
|
| 156 |
frame_dropdown.input(
|
| 157 |
+
lambda frame: frame,
|
| 158 |
inputs=[frame_dropdown],
|
| 159 |
+
outputs=[current_frame],
|
|
|
|
|
|
|
| 160 |
)
|
| 161 |
|
| 162 |
load_images.click(
|
| 163 |
+
core.load_data,
|
| 164 |
inputs=[
|
| 165 |
+
episode_data,
|
|
|
|
| 166 |
current_frame,
|
| 167 |
+
frame_hash_map,
|
|
|
|
| 168 |
],
|
| 169 |
outputs=[
|
|
|
|
|
|
|
|
|
|
| 170 |
images,
|
|
|
|
|
|
|
|
|
|
| 171 |
image_description,
|
| 172 |
narration,
|
| 173 |
character,
|
|
|
|
| 182 |
seed_3,
|
| 183 |
prompt_4,
|
| 184 |
seed_4,
|
|
|
|
| 185 |
],
|
| 186 |
+
).then(
|
| 187 |
+
core.update_characters,
|
| 188 |
+
inputs=[character_data, current_frame, frame_hash_map, episode_data],
|
| 189 |
+
outputs=[related_chars],
|
| 190 |
)
|
| 191 |
|
| 192 |
# When an image is clicked
|
| 193 |
def get_select_index(evt: gr.SelectData, images):
|
| 194 |
return images[evt.index]
|
|
|
|
| 195 |
images.select(get_select_index, images, selected_image)
|
| 196 |
|
| 197 |
next_button.click(
|
| 198 |
core.load_data_next,
|
| 199 |
inputs=[
|
| 200 |
+
comic_id,
|
| 201 |
current_episode,
|
| 202 |
current_frame,
|
| 203 |
+
frame_hash_map,
|
| 204 |
+
episode_data,
|
| 205 |
],
|
| 206 |
outputs=[
|
| 207 |
episode_dropdown,
|
| 208 |
frame_dropdown,
|
|
|
|
|
|
|
|
|
|
| 209 |
current_episode,
|
| 210 |
current_frame,
|
| 211 |
+
episode_data,
|
| 212 |
+
frame_hash_map,
|
| 213 |
+
],
|
| 214 |
+
).then(
|
| 215 |
+
core.load_data,
|
| 216 |
+
inputs=[
|
| 217 |
+
episode_data,
|
| 218 |
+
current_frame,
|
| 219 |
+
frame_hash_map,
|
| 220 |
+
],
|
| 221 |
+
outputs=[
|
| 222 |
+
images,
|
| 223 |
image_description,
|
| 224 |
narration,
|
| 225 |
character,
|
|
|
|
| 234 |
seed_3,
|
| 235 |
prompt_4,
|
| 236 |
seed_4,
|
|
|
|
| 237 |
],
|
| 238 |
+
).then(
|
| 239 |
+
core.update_characters,
|
| 240 |
+
inputs=[character_data, current_frame, frame_hash_map, episode_data],
|
| 241 |
+
outputs=[related_chars],
|
| 242 |
+
).then(
|
| 243 |
+
lambda a, b: (a, b),
|
| 244 |
+
inputs=[current_episode, current_frame],
|
| 245 |
+
outputs=[current_episode, current_frame],
|
| 246 |
)
|
| 247 |
|
| 248 |
prev_button.click(
|
| 249 |
core.load_data_prev,
|
| 250 |
inputs=[
|
| 251 |
+
comic_id,
|
| 252 |
current_episode,
|
| 253 |
current_frame,
|
| 254 |
+
frame_hash_map,
|
| 255 |
+
episode_data,
|
| 256 |
],
|
| 257 |
outputs=[
|
| 258 |
episode_dropdown,
|
| 259 |
frame_dropdown,
|
|
|
|
|
|
|
|
|
|
| 260 |
current_episode,
|
| 261 |
current_frame,
|
| 262 |
+
episode_data,
|
| 263 |
+
frame_hash_map,
|
| 264 |
+
],
|
| 265 |
+
).then(
|
| 266 |
+
core.load_data,
|
| 267 |
+
inputs=[
|
| 268 |
+
episode_data,
|
| 269 |
+
current_frame,
|
| 270 |
+
frame_hash_map,
|
| 271 |
+
],
|
| 272 |
+
outputs=[
|
| 273 |
+
images,
|
| 274 |
image_description,
|
| 275 |
narration,
|
| 276 |
character,
|
|
|
|
| 285 |
seed_3,
|
| 286 |
prompt_4,
|
| 287 |
seed_4,
|
|
|
|
| 288 |
],
|
| 289 |
+
).then(
|
| 290 |
+
core.update_characters,
|
| 291 |
+
inputs=[character_data, current_frame, frame_hash_map, episode_data],
|
| 292 |
+
outputs=[related_chars],
|
| 293 |
+
).then(
|
| 294 |
+
lambda a, b: (a, b),
|
| 295 |
+
inputs=[current_episode, current_frame],
|
| 296 |
+
outputs=[current_episode, current_frame],
|
| 297 |
)
|
| 298 |
|
| 299 |
save_button.click(
|
|
|
|
| 307 |
outputs=[],
|
| 308 |
)
|
| 309 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 310 |
regenerate_comps_btn.click(
|
| 311 |
+
core.regenerate_compositions,
|
| 312 |
inputs=[
|
| 313 |
image_description,
|
| 314 |
narration,
|
|
|
|
| 316 |
dialouge,
|
| 317 |
location,
|
| 318 |
setting,
|
| 319 |
+
related_chars,
|
| 320 |
current_episode,
|
| 321 |
current_frame,
|
| 322 |
+
episode_data,
|
| 323 |
+
frame_hash_map,
|
| 324 |
+
character_data,
|
| 325 |
],
|
| 326 |
outputs=[
|
| 327 |
+
prompt_1,
|
| 328 |
+
prompt_2,
|
| 329 |
+
prompt_3,
|
| 330 |
+
prompt_4,
|
| 331 |
+
],
|
| 332 |
+
)
|
| 333 |
+
|
| 334 |
+
regenerate_btn.click(
|
| 335 |
+
core.regenerate_images,
|
| 336 |
+
inputs=[
|
| 337 |
+
current_episode,
|
| 338 |
+
current_frame,
|
| 339 |
+
visual_style,
|
| 340 |
+
height,
|
| 341 |
+
width,
|
| 342 |
+
character_data,
|
| 343 |
+
related_chars,
|
| 344 |
prompt_1,
|
| 345 |
seed_1,
|
| 346 |
prompt_2,
|
|
|
|
| 348 |
prompt_3,
|
| 349 |
seed_3,
|
| 350 |
prompt_4,
|
| 351 |
+
seed_4
|
| 352 |
],
|
| 353 |
+
outputs=[images],
|
| 354 |
)
|
| 355 |
|
| 356 |
+
save_btn.click(
|
| 357 |
+
core.save_comic_data,
|
| 358 |
inputs=[
|
| 359 |
current_episode,
|
| 360 |
current_frame,
|
| 361 |
+
episode_data,
|
| 362 |
comic_id,
|
| 363 |
image_description,
|
| 364 |
narration,
|
|
|
|
| 366 |
dialouge,
|
| 367 |
location,
|
| 368 |
setting,
|
|
|
|
| 369 |
prompt_1,
|
| 370 |
prompt_2,
|
| 371 |
prompt_3,
|
| 372 |
prompt_4,
|
| 373 |
+
frame_hash_map,
|
| 374 |
+
related_chars,
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 375 |
character_data,
|
| 376 |
+
images,
|
| 377 |
+
]
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 378 |
)
|
| 379 |
|
|
|
|
|
|
|
|
|
|
|
|
|
| 380 |
demo.launch(
|
| 381 |
+
# auth=("admin", "Qrt@12*34#immersfy"), share=True, ssr_mode=False, debug=True
|
| 382 |
+
share=False,
|
| 383 |
)
|
| 384 |
# demo.launch(share=True, ssr_mode=False, debug=True)
|
aws_utils.py
CHANGED
|
@@ -84,7 +84,7 @@ def fetch_from_s3(source: Union[str, dict], region_name: str = "ap-south-1") ->
|
|
| 84 |
Returns:
|
| 85 |
bytes: The content of the file fetched from S3.
|
| 86 |
"""
|
| 87 |
-
print(f"Fetching file from S3. Source: {source}")
|
| 88 |
s3_client = boto3.client("s3", region_name=region_name)
|
| 89 |
|
| 90 |
# Parse the source depending on its type
|
|
@@ -104,7 +104,7 @@ def fetch_from_s3(source: Union[str, dict], region_name: str = "ap-south-1") ->
|
|
| 104 |
print("Source must be a string URL or a dictionary.")
|
| 105 |
raise ValueError("Source must be a string URL or a dictionary.")
|
| 106 |
|
| 107 |
-
print(f"Attempting to download from bucket: {bucket_name}, path: {file_path}")
|
| 108 |
try:
|
| 109 |
response = s3_client.get_object(Bucket=bucket_name, Key=file_path)
|
| 110 |
file_content = response["Body"].read()
|
|
|
|
| 84 |
Returns:
|
| 85 |
bytes: The content of the file fetched from S3.
|
| 86 |
"""
|
| 87 |
+
# print(f"Fetching file from S3. Source: {source}")
|
| 88 |
s3_client = boto3.client("s3", region_name=region_name)
|
| 89 |
|
| 90 |
# Parse the source depending on its type
|
|
|
|
| 104 |
print("Source must be a string URL or a dictionary.")
|
| 105 |
raise ValueError("Source must be a string URL or a dictionary.")
|
| 106 |
|
| 107 |
+
# print(f"Attempting to download from bucket: {bucket_name}, path: {file_path}")
|
| 108 |
try:
|
| 109 |
response = s3_client.get_object(Bucket=bucket_name, Key=file_path)
|
| 110 |
file_content = response["Body"].read()
|
core.py
CHANGED
|
@@ -1,7 +1,7 @@
|
|
| 1 |
from typing import List
|
| 2 |
from PIL import Image
|
|
|
|
| 3 |
import gradio as gr
|
| 4 |
-
import dataclasses
|
| 5 |
import io
|
| 6 |
import jinja2
|
| 7 |
import base64
|
|
@@ -11,38 +11,20 @@ import script_gen
|
|
| 11 |
import inout as iowrapper
|
| 12 |
import openai_wrapper
|
| 13 |
import json
|
| 14 |
-
from dataclasses import asdict
|
| 15 |
import base64
|
| 16 |
-
import io
|
| 17 |
|
| 18 |
AWS_BUCKET = parameters.AWS_BUCKET
|
| 19 |
llm = openai_wrapper.GPT_4O_MINI
|
| 20 |
|
| 21 |
|
| 22 |
-
|
| 23 |
-
|
| 24 |
-
|
| 25 |
-
|
| 26 |
-
|
| 27 |
-
|
| 28 |
-
|
| 29 |
-
|
| 30 |
-
@dataclasses.dataclass
|
| 31 |
-
class ComicFrame:
|
| 32 |
-
description: str
|
| 33 |
-
narration: str
|
| 34 |
-
character_dilouge: str
|
| 35 |
-
character: str
|
| 36 |
-
location: str
|
| 37 |
-
setting: str
|
| 38 |
-
all_characters: list
|
| 39 |
-
compositions: List[Composition] = dataclasses.field(default_factory=list)
|
| 40 |
-
|
| 41 |
-
|
| 42 |
-
def update_characters(character_data, curr_frame):
|
| 43 |
-
return gr.CheckboxGroup(
|
| 44 |
-
choices=list(character_data.keys()), value=curr_frame.all_characters
|
| 45 |
-
)
|
| 46 |
|
| 47 |
|
| 48 |
def list_current_dir(bucket_name: str, folder_path: str = "") -> list:
|
|
@@ -59,227 +41,183 @@ def list_current_dir(bucket_name: str, folder_path: str = "") -> list:
|
|
| 59 |
return []
|
| 60 |
|
| 61 |
|
| 62 |
-
def
|
| 63 |
-
episodes_data: list,
|
| 64 |
-
current_episode: int,
|
| 65 |
-
current_frame: int,
|
| 66 |
-
is_developer: bool,
|
| 67 |
-
character_data,
|
| 68 |
-
):
|
| 69 |
try:
|
| 70 |
-
|
| 71 |
-
|
| 72 |
-
|
| 73 |
-
|
| 74 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 75 |
return (
|
| 76 |
-
|
| 77 |
-
|
| 78 |
-
|
| 79 |
-
current_frame,
|
| 80 |
-
gr.Textbox(value=curr_frame.description, interactive=is_developer),
|
| 81 |
-
gr.Textbox(value=curr_frame.narration, interactive=is_developer),
|
| 82 |
-
gr.Textbox(value=curr_frame.character, interactive=is_developer),
|
| 83 |
-
gr.Textbox(value=curr_frame.character_dilouge, interactive=is_developer),
|
| 84 |
-
gr.Textbox(value=curr_frame.location, interactive=is_developer),
|
| 85 |
-
curr_frame.setting,
|
| 86 |
-
curr_frame.compositions[0].prompt,
|
| 87 |
-
curr_frame.compositions[0].seed,
|
| 88 |
-
curr_frame.compositions[1].prompt,
|
| 89 |
-
curr_frame.compositions[1].seed,
|
| 90 |
-
curr_frame.compositions[2].prompt,
|
| 91 |
-
curr_frame.compositions[2].seed,
|
| 92 |
-
curr_frame.compositions[3].prompt,
|
| 93 |
-
curr_frame.compositions[3].seed,
|
| 94 |
-
update_characters(character_data, curr_frame),
|
| 95 |
)
|
| 96 |
except Exception as e:
|
| 97 |
-
|
| 98 |
-
|
| 99 |
-
|
| 100 |
-
|
| 101 |
-
|
| 102 |
-
|
| 103 |
-
|
| 104 |
-
|
| 105 |
-
|
| 106 |
-
|
| 107 |
-
|
| 108 |
-
|
| 109 |
-
|
| 110 |
-
|
| 111 |
-
""
|
| 112 |
-
|
| 113 |
-
|
| 114 |
-
|
| 115 |
-
|
| 116 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
| 117 |
)
|
|
|
|
|
|
|
|
|
|
| 118 |
|
| 119 |
|
| 120 |
-
def
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 121 |
try:
|
| 122 |
-
|
| 123 |
-
|
| 124 |
-
|
| 125 |
-
|
| 126 |
-
|
| 127 |
-
|
| 128 |
|
| 129 |
-
for
|
| 130 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 131 |
|
| 132 |
-
for folder in list_current_dir(AWS_BUCKET, f"{comic_id}/episodes/"):
|
| 133 |
-
if "episode" in folder:
|
| 134 |
-
json_path = f"s3://{AWS_BUCKET}/{folder}episode.json"
|
| 135 |
-
idx = int(folder.split("/")[2].split("-")[-1])
|
| 136 |
-
episode_idx.append(idx)
|
| 137 |
-
data = eval(aws_utils.fetch_from_s3(source=json_path).decode("utf-8"))
|
| 138 |
-
comic_frames = []
|
| 139 |
-
details[idx] = {}
|
| 140 |
-
cumulative_frame_count = 0
|
| 141 |
-
|
| 142 |
-
for scene_num, scene in enumerate(data["scenes"]):
|
| 143 |
-
scene_frame_count = len(scene["frames"])
|
| 144 |
-
cumulative_frame_count += scene_frame_count
|
| 145 |
-
details[idx][scene_num] = cumulative_frame_count
|
| 146 |
-
|
| 147 |
-
for frame in scene["frames"]:
|
| 148 |
-
comic_frames.append(
|
| 149 |
-
ComicFrame(
|
| 150 |
-
description=frame["description"],
|
| 151 |
-
narration=frame["narration"],
|
| 152 |
-
character=frame["audio_cue_character"],
|
| 153 |
-
character_dilouge=frame["audio_cue_text"],
|
| 154 |
-
compositions=[
|
| 155 |
-
Composition(**comp)
|
| 156 |
-
for comp in frame["compositions"]
|
| 157 |
-
],
|
| 158 |
-
location=frame["location"],
|
| 159 |
-
setting=frame["frame_setting"],
|
| 160 |
-
all_characters=[
|
| 161 |
-
char["name"] for char in frame["characters"]
|
| 162 |
-
],
|
| 163 |
-
)
|
| 164 |
-
)
|
| 165 |
-
episodes_data[idx] = comic_frames
|
| 166 |
-
|
| 167 |
-
current_episode, current_frame = min(episode_idx), 0
|
| 168 |
return (
|
| 169 |
-
|
| 170 |
-
|
| 171 |
-
|
| 172 |
-
|
| 173 |
-
|
| 174 |
-
|
| 175 |
-
|
| 176 |
-
|
| 177 |
-
|
| 178 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 179 |
)
|
| 180 |
except Exception as e:
|
| 181 |
-
|
| 182 |
-
|
| 183 |
-
|
| 184 |
-
|
| 185 |
-
|
| 186 |
-
|
| 187 |
-
|
| 188 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 189 |
|
| 190 |
|
| 191 |
def load_data_next(
|
| 192 |
-
|
| 193 |
current_episode: int,
|
| 194 |
current_frame: int,
|
| 195 |
-
|
| 196 |
-
|
| 197 |
):
|
| 198 |
-
if current_frame + 1 <
|
| 199 |
current_frame += 1
|
| 200 |
-
elif current_episode + 1 < len(episodes_data):
|
| 201 |
-
current_episode += 1
|
| 202 |
-
current_frame = 0
|
| 203 |
else:
|
| 204 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 205 |
return (
|
| 206 |
gr.update(value=current_episode),
|
| 207 |
-
gr.update(value=current_frame),
|
| 208 |
-
|
| 209 |
-
|
| 210 |
-
|
|
|
|
| 211 |
)
|
| 212 |
|
| 213 |
|
| 214 |
def load_data_prev(
|
| 215 |
-
|
| 216 |
current_episode: int,
|
| 217 |
current_frame: int,
|
| 218 |
-
|
| 219 |
-
|
| 220 |
):
|
| 221 |
-
if current_frame - 1 >= 0:
|
| 222 |
current_frame -= 1
|
| 223 |
-
elif current_episode - 1 > min(list(episodes_data.keys())):
|
| 224 |
-
current_episode -= 1
|
| 225 |
-
current_frame = 0
|
| 226 |
else:
|
| 227 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 228 |
return (
|
| 229 |
gr.update(value=current_episode),
|
| 230 |
-
gr.update(value=current_frame),
|
| 231 |
-
|
| 232 |
-
|
| 233 |
-
|
|
|
|
| 234 |
)
|
| 235 |
|
| 236 |
|
| 237 |
-
def
|
| 238 |
-
|
| 239 |
-
selected_episode: int,
|
| 240 |
-
selected_frame: int,
|
| 241 |
-
is_developer: bool,
|
| 242 |
-
character_data,
|
| 243 |
):
|
| 244 |
-
return (
|
| 245 |
-
gr.update(value=selected_episode),
|
| 246 |
-
gr.update(value=selected_frame),
|
| 247 |
-
*load_data_inner(
|
| 248 |
-
episodes_data,
|
| 249 |
-
selected_episode,
|
| 250 |
-
selected_frame,
|
| 251 |
-
is_developer,
|
| 252 |
-
character_data,
|
| 253 |
-
),
|
| 254 |
-
# update_characters(character_data)
|
| 255 |
-
)
|
| 256 |
-
|
| 257 |
-
|
| 258 |
-
def get_scene_number(details, current_episode, current_frame):
|
| 259 |
-
episode_details = details.get(current_episode)
|
| 260 |
-
if not episode_details:
|
| 261 |
-
print(f"Episode {current_episode} not found!")
|
| 262 |
-
return None
|
| 263 |
-
|
| 264 |
-
# Determine scene number and frame number within the scene
|
| 265 |
-
scene_num, frame_num_in_scene = None, 0
|
| 266 |
-
for scene_idx, cumulative_frame_count in enumerate(episode_details.items()):
|
| 267 |
-
if current_frame < cumulative_frame_count[1]:
|
| 268 |
-
scene_num = cumulative_frame_count[0]
|
| 269 |
-
frame_num_in_scene = current_frame - (episode_details.get(scene_num - 1, 0))
|
| 270 |
-
break
|
| 271 |
-
return scene_num, frame_num_in_scene
|
| 272 |
-
|
| 273 |
-
|
| 274 |
-
def load_dropdown_fn(selected_episode):
|
| 275 |
-
return (gr.update(value=selected_episode), gr.update(value=0), selected_episode, 0)
|
| 276 |
-
|
| 277 |
-
|
| 278 |
-
def load_dropdown_fn_v2(selected_frame):
|
| 279 |
-
return selected_frame
|
| 280 |
-
|
| 281 |
-
|
| 282 |
-
def save_image(selected_image, comic_id: str, current_episode: int, current_frame: int):
|
| 283 |
with Image.open(selected_image[0]) as img:
|
| 284 |
img_bytes = io.BytesIO()
|
| 285 |
img.convert("RGB").save(img_bytes, "JPEG")
|
|
@@ -293,224 +231,201 @@ def save_image(selected_image, comic_id: str, current_episode: int, current_fram
|
|
| 293 |
gr.Info("Saved Image successfully!")
|
| 294 |
|
| 295 |
|
| 296 |
-
def
|
| 297 |
-
|
| 298 |
-
|
| 299 |
-
|
| 300 |
-
|
| 301 |
-
|
| 302 |
-
|
| 303 |
-
|
| 304 |
-
return gr.update(visible=False), prompt_1, prompt_2, prompt_3, prompt_4, setting
|
| 305 |
-
|
| 306 |
-
|
| 307 |
-
def regenerate_composition_data(
|
| 308 |
-
image_description,
|
| 309 |
-
narration,
|
| 310 |
-
character,
|
| 311 |
-
dialouge,
|
| 312 |
-
location,
|
| 313 |
-
setting,
|
| 314 |
-
chars,
|
| 315 |
current_episode: int,
|
| 316 |
current_frame: int,
|
| 317 |
episodes_data: dict,
|
|
|
|
|
|
|
| 318 |
):
|
| 319 |
try:
|
| 320 |
print(
|
| 321 |
f"Regenerating composition data for episode {current_episode}, frame {current_frame}"
|
| 322 |
)
|
| 323 |
-
|
| 324 |
-
|
| 325 |
-
|
| 326 |
-
|
| 327 |
-
|
| 328 |
-
|
| 329 |
-
|
| 330 |
-
except Exception as e:
|
| 331 |
-
print(f"Error creating prompt template: {e}")
|
| 332 |
-
raise
|
| 333 |
|
| 334 |
try:
|
| 335 |
-
|
| 336 |
prompt_dict = {
|
| 337 |
"system": script_gen.generate_image_compositions_instruction,
|
| 338 |
-
"user":
|
|
|
|
|
|
|
| 339 |
{
|
| 340 |
"FRAME": {
|
| 341 |
"description": image_description,
|
| 342 |
"narration": narration,
|
| 343 |
-
"
|
| 344 |
-
"
|
| 345 |
"location": location,
|
| 346 |
-
"
|
| 347 |
-
"
|
| 348 |
-
}
|
|
|
|
|
|
|
| 349 |
}
|
| 350 |
),
|
| 351 |
}
|
| 352 |
-
except Exception as e:
|
| 353 |
-
print(f"Error rendering prompt: {e}")
|
| 354 |
-
raise
|
| 355 |
|
| 356 |
-
try:
|
| 357 |
print("Generating compositions using LLM")
|
| 358 |
compositions = llm.generate_valid_json_response(prompt_dict)
|
| 359 |
-
|
| 360 |
-
print(f"Error generating compositions: {e}")
|
| 361 |
-
raise
|
| 362 |
-
|
| 363 |
-
try:
|
| 364 |
-
print("Updating frame compositions")
|
| 365 |
-
frame.compositions = [
|
| 366 |
-
Composition(
|
| 367 |
-
**comp,
|
| 368 |
-
seed=(
|
| 369 |
-
frame.compositions[idx].seed
|
| 370 |
-
if idx < len(frame.compositions)
|
| 371 |
-
else ""
|
| 372 |
-
),
|
| 373 |
-
image=(
|
| 374 |
-
frame.compositions[idx].image
|
| 375 |
-
if idx < len(frame.compositions)
|
| 376 |
-
else ""
|
| 377 |
-
),
|
| 378 |
-
)
|
| 379 |
-
for idx, comp in enumerate(compositions["compositions"])
|
| 380 |
-
]
|
| 381 |
except Exception as e:
|
| 382 |
print(f"Error updating frame compositions: {e}")
|
| 383 |
raise
|
| 384 |
|
| 385 |
print("Composition data regenerated successfully.")
|
| 386 |
return [
|
| 387 |
-
|
| 388 |
-
|
| 389 |
-
|
| 390 |
-
|
| 391 |
-
frame.compositions[2].prompt,
|
| 392 |
-
frame.compositions[2].seed,
|
| 393 |
-
frame.compositions[3].prompt,
|
| 394 |
-
frame.compositions[3].seed,
|
| 395 |
]
|
| 396 |
except Exception as e:
|
| 397 |
print(f"Error in regenerate_composition_data: {e}")
|
| 398 |
return [""] * 8
|
| 399 |
|
| 400 |
|
| 401 |
-
def
|
| 402 |
-
|
| 403 |
-
|
| 404 |
-
|
| 405 |
-
|
| 406 |
-
|
| 407 |
-
|
| 408 |
-
|
| 409 |
-
|
| 410 |
-
|
| 411 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 412 |
):
|
| 413 |
-
|
| 414 |
-
|
| 415 |
-
print(chars)
|
| 416 |
-
try:
|
| 417 |
-
current_scene, frame_num_in_scene = get_scene_number(
|
| 418 |
-
details, current_episode, current_frame
|
| 419 |
-
)
|
| 420 |
print(
|
| 421 |
-
f"Regenerating data for episode {current_episode},
|
| 422 |
)
|
| 423 |
-
|
| 424 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 425 |
|
| 426 |
-
for i, composition in enumerate(
|
| 427 |
try:
|
| 428 |
print(f"Generating image for composition {i}")
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 429 |
payload = {
|
| 430 |
-
"prompt":
|
| 431 |
"characters": related_chars,
|
| 432 |
"parameters": {
|
| 433 |
"height": height,
|
| 434 |
"width": width,
|
| 435 |
"visual_style": visual_style,
|
| 436 |
-
"seed": composition
|
| 437 |
},
|
| 438 |
}
|
| 439 |
|
| 440 |
-
|
| 441 |
-
|
| 442 |
-
|
| 443 |
-
|
| 444 |
-
|
| 445 |
-
)
|
| 446 |
-
print(f"Image generated for composition {i}. Decoding image data.")
|
| 447 |
-
image_data = io.BytesIO(base64.b64decode(data["image"]))
|
| 448 |
-
image_data_b64.append(data["image"])
|
| 449 |
-
images.append(Image.open(image_data))
|
| 450 |
-
except Exception as e:
|
| 451 |
-
print(f"Error generating image for composition {i}: {e}")
|
| 452 |
-
continue
|
| 453 |
except Exception as e:
|
| 454 |
print(f"Error processing composition {i}: {e}")
|
| 455 |
continue
|
| 456 |
|
| 457 |
-
print("
|
| 458 |
-
|
|
|
|
| 459 |
except Exception as e:
|
| 460 |
print(f"Error in regenerate_data: {e}")
|
| 461 |
-
|
|
|
|
| 462 |
|
| 463 |
|
| 464 |
-
def
|
| 465 |
current_episode: int,
|
| 466 |
current_frame: int,
|
| 467 |
-
|
| 468 |
comic_id: str,
|
| 469 |
-
image_description,
|
| 470 |
-
narration,
|
| 471 |
-
character,
|
| 472 |
-
dialogue
|
| 473 |
-
location,
|
| 474 |
-
setting,
|
| 475 |
-
|
| 476 |
-
|
| 477 |
-
|
| 478 |
-
|
| 479 |
-
|
|
|
|
|
|
|
|
|
|
| 480 |
):
|
| 481 |
try:
|
| 482 |
-
|
| 483 |
-
|
|
|
|
| 484 |
)
|
|
|
|
| 485 |
print(
|
| 486 |
-
f"Saving
|
| 487 |
-
)
|
| 488 |
-
|
| 489 |
-
# Fetch episode data from S3
|
| 490 |
-
episode_path = f"s3://blix-demo-v0/{comic_id}/episodes/episode-{current_episode}/episode.json"
|
| 491 |
-
print(f"Fetching episode from S3: {episode_path}")
|
| 492 |
-
episode_json = aws_utils.fetch_from_s3(episode_path).decode("utf-8")
|
| 493 |
-
episode = json.loads(episode_json)
|
| 494 |
-
|
| 495 |
-
frame_data = episode["scenes"][current_scene]["frames"][frame_num_in_scene]
|
| 496 |
-
print(
|
| 497 |
-
f"Updating compositions for scene {current_scene}, frame {frame_num_in_scene}"
|
| 498 |
)
|
| 499 |
|
| 500 |
# Update compositions with prompts
|
| 501 |
prompts_list = [prompt_1, prompt_2, prompt_3, prompt_4]
|
| 502 |
-
|
| 503 |
-
|
| 504 |
-
|
| 505 |
-
|
| 506 |
-
|
| 507 |
-
"
|
| 508 |
-
|
| 509 |
-
|
| 510 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
| 511 |
|
| 512 |
-
#
|
| 513 |
-
|
| 514 |
{
|
| 515 |
"description": image_description,
|
| 516 |
"narration": narration,
|
|
@@ -518,48 +433,19 @@ def save_image_compositions(
|
|
| 518 |
"location": location,
|
| 519 |
"setting": setting,
|
| 520 |
"audio_cue_character": character,
|
|
|
|
| 521 |
}
|
| 522 |
)
|
| 523 |
|
| 524 |
# Save the updated episode back to S3
|
| 525 |
-
print(f"Saving updated episode to S3
|
| 526 |
aws_utils.save_to_s3(
|
| 527 |
bucket_name=parameters.AWS_BUCKET,
|
| 528 |
folder_name=f"{comic_id}/episodes/episode-{current_episode}",
|
| 529 |
-
content=
|
| 530 |
file_name="episode.json",
|
| 531 |
)
|
| 532 |
-
|
| 533 |
-
gr.Info("Compositions saved successfully!")
|
| 534 |
-
print(current_scene)
|
| 535 |
-
return current_scene
|
| 536 |
-
|
| 537 |
-
except Exception as e:
|
| 538 |
-
print(f"Error in save_image_compositions: {e}")
|
| 539 |
-
return None
|
| 540 |
-
|
| 541 |
-
|
| 542 |
-
def save_images(image_data_b64, current_episode, current_frame, comic_id, details):
|
| 543 |
-
try:
|
| 544 |
-
current_scene, frame_num_in_scene = get_scene_number(
|
| 545 |
-
details, current_episode, current_frame
|
| 546 |
-
)
|
| 547 |
-
print(
|
| 548 |
-
f"Saving images for episode {current_episode}, Scene {current_scene} ,frame {frame_num_in_scene}."
|
| 549 |
-
)
|
| 550 |
-
for i, image_data in enumerate(image_data_b64):
|
| 551 |
-
try:
|
| 552 |
-
print(f"Saving image {i} to S3")
|
| 553 |
-
aws_utils.save_to_s3(
|
| 554 |
-
parameters.AWS_BUCKET,
|
| 555 |
-
f"{comic_id}/episodes/episode-{current_episode}/compositions/scene-{current_scene}/frame-{frame_num_in_scene}",
|
| 556 |
-
io.BytesIO(base64.b64decode(image_data)),
|
| 557 |
-
f"{i}.jpg",
|
| 558 |
-
)
|
| 559 |
-
except Exception as e:
|
| 560 |
-
print(f"Error saving image {i} to S3: {e}")
|
| 561 |
-
continue
|
| 562 |
-
print("All images saved successfully!")
|
| 563 |
-
gr.Info("All images saved successfully!")
|
| 564 |
except Exception as e:
|
| 565 |
-
print(f"Error in
|
|
|
|
|
|
| 1 |
from typing import List
|
| 2 |
from PIL import Image
|
| 3 |
+
import json
|
| 4 |
import gradio as gr
|
|
|
|
| 5 |
import io
|
| 6 |
import jinja2
|
| 7 |
import base64
|
|
|
|
| 11 |
import inout as iowrapper
|
| 12 |
import openai_wrapper
|
| 13 |
import json
|
|
|
|
| 14 |
import base64
|
|
|
|
| 15 |
|
| 16 |
AWS_BUCKET = parameters.AWS_BUCKET
|
| 17 |
llm = openai_wrapper.GPT_4O_MINI
|
| 18 |
|
| 19 |
|
| 20 |
+
#### Functions ordered by their order of developement.
|
| 21 |
+
def toggle_developer_options(is_developer: bool):
|
| 22 |
+
if is_developer:
|
| 23 |
+
# Return visibility updates for the developer options along with the values
|
| 24 |
+
return gr.update(visible=True)
|
| 25 |
+
else:
|
| 26 |
+
# Hide the developer options and return only the updated visibility
|
| 27 |
+
return gr.update(visible=False)
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 28 |
|
| 29 |
|
| 30 |
def list_current_dir(bucket_name: str, folder_path: str = "") -> list:
|
|
|
|
| 41 |
return []
|
| 42 |
|
| 43 |
|
| 44 |
+
def load_metadata_fn(comic_id: str):
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 45 |
try:
|
| 46 |
+
# Load character data
|
| 47 |
+
character_data = {}
|
| 48 |
+
character_path = f"s3://blix-demo-v0/{comic_id}/characters/characters.json"
|
| 49 |
+
char_data = json.loads(aws_utils.fetch_from_s3(character_path).decode("utf-8"))
|
| 50 |
+
character_data = {
|
| 51 |
+
name: char for name, char in char_data.items()
|
| 52 |
+
}
|
| 53 |
+
|
| 54 |
+
# Load episode data
|
| 55 |
+
episode_folders = list_current_dir(AWS_BUCKET, f"{comic_id}/episodes/")
|
| 56 |
+
episode_indices = []
|
| 57 |
+
for folder in episode_folders:
|
| 58 |
+
if "episode" in folder:
|
| 59 |
+
idx = int(folder.split("/")[2].split("-")[-1])
|
| 60 |
+
episode_indices.append(idx)
|
| 61 |
+
if not episode_indices:
|
| 62 |
+
return (gr.update(choices=[]), None, {})
|
| 63 |
+
|
| 64 |
+
# Return the values
|
| 65 |
+
min_episode = min(episode_indices)
|
| 66 |
return (
|
| 67 |
+
gr.update(choices=episode_indices, value=min_episode),
|
| 68 |
+
min_episode,
|
| 69 |
+
character_data,
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 70 |
)
|
| 71 |
except Exception as e:
|
| 72 |
+
gr.Warning(f"Error loading metadata: {e}")
|
| 73 |
+
return (gr.update(choices=[]), None, {})
|
| 74 |
+
|
| 75 |
+
|
| 76 |
+
def load_episode_data(comic_id: str, episode_num: int):
|
| 77 |
+
try:
|
| 78 |
+
print(f"For episode: {episode_num}")
|
| 79 |
+
json_path = (
|
| 80 |
+
f"s3://{AWS_BUCKET}/{comic_id}/episodes/episode-{episode_num}/episode.json"
|
| 81 |
+
)
|
| 82 |
+
episode_data = json.loads(aws_utils.fetch_from_s3(json_path).decode("utf-8"))
|
| 83 |
+
frame_hash_map = {}
|
| 84 |
+
count = 1
|
| 85 |
+
for scene_idx, scene in enumerate(episode_data["scenes"]):
|
| 86 |
+
for frame_idx, _ in enumerate(scene["frames"]):
|
| 87 |
+
frame_hash_map[count] = {
|
| 88 |
+
"scene": scene_idx,
|
| 89 |
+
"frame": frame_idx,
|
| 90 |
+
}
|
| 91 |
+
count += 1
|
| 92 |
+
return (episode_data, frame_hash_map)
|
| 93 |
+
except Exception as e:
|
| 94 |
+
print(
|
| 95 |
+
f"Failed to load json dictionary for episode: {episode_num} at path: {json_path}"
|
| 96 |
)
|
| 97 |
+
import traceback as tc
|
| 98 |
+
print(tc.format_exc())
|
| 99 |
+
return {}, {}
|
| 100 |
|
| 101 |
|
| 102 |
+
def episode_dropdown_effect(comic_id, selected_episode):
|
| 103 |
+
episode_data, frame_hash_map = load_episode_data(comic_id, selected_episode)
|
| 104 |
+
current_frame = min(list(frame_hash_map.keys()))
|
| 105 |
+
return (
|
| 106 |
+
gr.update(choices=list(frame_hash_map.keys()), value=current_frame),
|
| 107 |
+
selected_episode,
|
| 108 |
+
current_frame,
|
| 109 |
+
episode_data,
|
| 110 |
+
frame_hash_map,
|
| 111 |
+
)
|
| 112 |
+
|
| 113 |
+
|
| 114 |
+
def load_data(episodes_data: dict, current_frame: int, frame_hash_map: dict):
|
| 115 |
try:
|
| 116 |
+
image_list = []
|
| 117 |
+
scene_num, frame_num = (
|
| 118 |
+
frame_hash_map[current_frame]["scene"],
|
| 119 |
+
frame_hash_map[current_frame]["frame"],
|
| 120 |
+
)
|
| 121 |
+
curr_frame = episodes_data["scenes"][scene_num]["frames"][frame_num]
|
| 122 |
|
| 123 |
+
for comp in curr_frame["compositions"]:
|
| 124 |
+
# Fetch image from S3
|
| 125 |
+
data = aws_utils.fetch_from_s3(comp["image"])
|
| 126 |
+
if data:
|
| 127 |
+
image = Image.open(io.BytesIO(data))
|
| 128 |
+
image_list.append(image)
|
| 129 |
+
else:
|
| 130 |
+
print(f"Failed to load image from: {comp['image']}")
|
| 131 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 132 |
return (
|
| 133 |
+
image_list, # Return the image list to be displayed in the gallery
|
| 134 |
+
curr_frame["description"],
|
| 135 |
+
curr_frame["narration"],
|
| 136 |
+
curr_frame["audio_cue_character"],
|
| 137 |
+
curr_frame["audio_cue_text"],
|
| 138 |
+
curr_frame["location"],
|
| 139 |
+
curr_frame["frame_setting"],
|
| 140 |
+
curr_frame["compositions"][0]["prompt"],
|
| 141 |
+
curr_frame["compositions"][0]["seed"],
|
| 142 |
+
curr_frame["compositions"][1]["prompt"],
|
| 143 |
+
curr_frame["compositions"][1]["seed"],
|
| 144 |
+
curr_frame["compositions"][2]["prompt"],
|
| 145 |
+
curr_frame["compositions"][2]["seed"],
|
| 146 |
+
curr_frame["compositions"][3]["prompt"],
|
| 147 |
+
curr_frame["compositions"][3]["seed"],
|
| 148 |
)
|
| 149 |
except Exception as e:
|
| 150 |
+
print("Error in load_data:", str(e)) # Debugging the error
|
| 151 |
+
gr.Warning("Failed to load data. Check logs!")
|
| 152 |
+
|
| 153 |
+
|
| 154 |
+
def update_characters(character_data: dict, current_frame: int, frame_hash_map: dict, episode_data: dict):
|
| 155 |
+
scene_num, frame_num = (
|
| 156 |
+
frame_hash_map[current_frame]["scene"],
|
| 157 |
+
frame_hash_map[current_frame]["frame"],
|
| 158 |
+
)
|
| 159 |
+
curr_frame = episode_data["scenes"][scene_num]["frames"][frame_num]
|
| 160 |
+
return gr.CheckboxGroup(
|
| 161 |
+
choices=list(character_data.keys()),
|
| 162 |
+
value=[char["name"] for char in curr_frame["characters"]],
|
| 163 |
+
)
|
| 164 |
|
| 165 |
|
| 166 |
def load_data_next(
|
| 167 |
+
comic_id: str,
|
| 168 |
current_episode: int,
|
| 169 |
current_frame: int,
|
| 170 |
+
frame_hash_map: dict,
|
| 171 |
+
episode_data: dict,
|
| 172 |
):
|
| 173 |
+
if current_frame + 1 < list(frame_hash_map.keys())[-1]:
|
| 174 |
current_frame += 1
|
|
|
|
|
|
|
|
|
|
| 175 |
else:
|
| 176 |
+
current_episode += 1
|
| 177 |
+
episode_data, frame_hash_map = load_episode_data(comic_id, current_episode)
|
| 178 |
+
if len(episode_data) < 1:
|
| 179 |
+
gr.Warning("All episodes finished.")
|
| 180 |
+
return
|
| 181 |
+
current_frame = min(list(frame_hash_map.keys()))
|
| 182 |
return (
|
| 183 |
gr.update(value=current_episode),
|
| 184 |
+
gr.update(choices=list(frame_hash_map.keys()), value=current_frame),
|
| 185 |
+
current_episode,
|
| 186 |
+
current_frame,
|
| 187 |
+
episode_data,
|
| 188 |
+
frame_hash_map,
|
| 189 |
)
|
| 190 |
|
| 191 |
|
| 192 |
def load_data_prev(
|
| 193 |
+
comic_id: str,
|
| 194 |
current_episode: int,
|
| 195 |
current_frame: int,
|
| 196 |
+
frame_hash_map: dict,
|
| 197 |
+
episode_data: dict,
|
| 198 |
):
|
| 199 |
+
if current_frame - 1 >= list(frame_hash_map.keys())[0]:
|
| 200 |
current_frame -= 1
|
|
|
|
|
|
|
|
|
|
| 201 |
else:
|
| 202 |
+
current_episode -= 1
|
| 203 |
+
episode_data, frame_hash_map = load_episode_data(comic_id, current_episode)
|
| 204 |
+
if len(episode_data) < 1:
|
| 205 |
+
gr.Warning("No previous episode found.")
|
| 206 |
+
return
|
| 207 |
+
current_frame = min(list(frame_hash_map.keys()))
|
| 208 |
return (
|
| 209 |
gr.update(value=current_episode),
|
| 210 |
+
gr.update(choices=list(frame_hash_map.keys()), value=current_frame),
|
| 211 |
+
current_episode,
|
| 212 |
+
current_frame,
|
| 213 |
+
episode_data,
|
| 214 |
+
frame_hash_map,
|
| 215 |
)
|
| 216 |
|
| 217 |
|
| 218 |
+
def save_image(
|
| 219 |
+
selected_image: ..., comic_id: str, current_episode: int, current_frame: int
|
|
|
|
|
|
|
|
|
|
|
|
|
| 220 |
):
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 221 |
with Image.open(selected_image[0]) as img:
|
| 222 |
img_bytes = io.BytesIO()
|
| 223 |
img.convert("RGB").save(img_bytes, "JPEG")
|
|
|
|
| 231 |
gr.Info("Saved Image successfully!")
|
| 232 |
|
| 233 |
|
| 234 |
+
def regenerate_compositions(
|
| 235 |
+
image_description: str,
|
| 236 |
+
narration: str,
|
| 237 |
+
character: str,
|
| 238 |
+
dialouge: str,
|
| 239 |
+
location: str,
|
| 240 |
+
setting: str,
|
| 241 |
+
rel_chars: list,
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 242 |
current_episode: int,
|
| 243 |
current_frame: int,
|
| 244 |
episodes_data: dict,
|
| 245 |
+
frame_hash_map: dict,
|
| 246 |
+
character_data: dict,
|
| 247 |
):
|
| 248 |
try:
|
| 249 |
print(
|
| 250 |
f"Regenerating composition data for episode {current_episode}, frame {current_frame}"
|
| 251 |
)
|
| 252 |
+
scene_num, frame_num = (
|
| 253 |
+
frame_hash_map[current_frame]["scene"],
|
| 254 |
+
frame_hash_map[current_frame]["frame"],
|
| 255 |
+
)
|
| 256 |
+
prev_frame = {}
|
| 257 |
+
if frame_num-1 > 0:
|
| 258 |
+
prev_frame = episodes_data["scenes"][scene_num]["frames"][frame_num-1]
|
|
|
|
|
|
|
|
|
|
| 259 |
|
| 260 |
try:
|
| 261 |
+
related_chars = [character_data[char] for char in rel_chars]
|
| 262 |
prompt_dict = {
|
| 263 |
"system": script_gen.generate_image_compositions_instruction,
|
| 264 |
+
"user": jinja2.Template(
|
| 265 |
+
script_gen.generate_image_compositions_user_prompt
|
| 266 |
+
).render(
|
| 267 |
{
|
| 268 |
"FRAME": {
|
| 269 |
"description": image_description,
|
| 270 |
"narration": narration,
|
| 271 |
+
"audio_cue_text": dialouge,
|
| 272 |
+
"audio_cue_character": character,
|
| 273 |
"location": location,
|
| 274 |
+
"frame_setting": setting,
|
| 275 |
+
"characters": json.dumps(related_chars),
|
| 276 |
+
},
|
| 277 |
+
"LOCATION_DESCRIPTION": prev_frame.get("location", ""),
|
| 278 |
+
"frame_settings": prev_frame.get("frame_setting", ""),
|
| 279 |
}
|
| 280 |
),
|
| 281 |
}
|
|
|
|
|
|
|
|
|
|
| 282 |
|
|
|
|
| 283 |
print("Generating compositions using LLM")
|
| 284 |
compositions = llm.generate_valid_json_response(prompt_dict)
|
| 285 |
+
comps = compositions["compositions"]
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 286 |
except Exception as e:
|
| 287 |
print(f"Error updating frame compositions: {e}")
|
| 288 |
raise
|
| 289 |
|
| 290 |
print("Composition data regenerated successfully.")
|
| 291 |
return [
|
| 292 |
+
comps[0]["prompt"],
|
| 293 |
+
comps[1]["prompt"],
|
| 294 |
+
comps[2]["prompt"],
|
| 295 |
+
comps[3]["prompt"],
|
|
|
|
|
|
|
|
|
|
|
|
|
| 296 |
]
|
| 297 |
except Exception as e:
|
| 298 |
print(f"Error in regenerate_composition_data: {e}")
|
| 299 |
return [""] * 8
|
| 300 |
|
| 301 |
|
| 302 |
+
def regenerate_images(
|
| 303 |
+
current_episode: int,
|
| 304 |
+
current_frame: int,
|
| 305 |
+
visual_style: str,
|
| 306 |
+
height: int,
|
| 307 |
+
width: int,
|
| 308 |
+
character_data: dict,
|
| 309 |
+
rel_chars: dict,
|
| 310 |
+
prompt_1: str,
|
| 311 |
+
seed_1: str,
|
| 312 |
+
prompt_2: str,
|
| 313 |
+
seed_2: str,
|
| 314 |
+
prompt_3: str,
|
| 315 |
+
seed_3: str,
|
| 316 |
+
prompt_4: str,
|
| 317 |
+
seed_4: str,
|
| 318 |
):
|
| 319 |
+
image_list = []
|
| 320 |
+
try:
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 321 |
print(
|
| 322 |
+
f"Regenerating data for episode {current_episode}, and frame {current_frame}"
|
| 323 |
)
|
| 324 |
+
related_chars = [character_data[ch]["profile_image"] for ch in rel_chars]
|
| 325 |
+
new_compositions = [
|
| 326 |
+
{
|
| 327 |
+
"prompt": prompt_1,
|
| 328 |
+
"seed": seed_1,
|
| 329 |
+
},
|
| 330 |
+
{
|
| 331 |
+
"prompt": prompt_2,
|
| 332 |
+
"seed": seed_2,
|
| 333 |
+
},
|
| 334 |
+
{
|
| 335 |
+
"prompt": prompt_3,
|
| 336 |
+
"seed": seed_3,
|
| 337 |
+
},
|
| 338 |
+
{
|
| 339 |
+
"prompt": prompt_4,
|
| 340 |
+
"seed": seed_4,
|
| 341 |
+
},
|
| 342 |
+
]
|
| 343 |
|
| 344 |
+
for i, composition in enumerate(new_compositions):
|
| 345 |
try:
|
| 346 |
print(f"Generating image for composition {i}")
|
| 347 |
+
prompt = composition["prompt"]
|
| 348 |
+
if "NOCHAR" in prompt:
|
| 349 |
+
prompt = prompt.replace(
|
| 350 |
+
"NOCHAR", ""
|
| 351 |
+
)
|
| 352 |
payload = {
|
| 353 |
+
"prompt": prompt,
|
| 354 |
"characters": related_chars,
|
| 355 |
"parameters": {
|
| 356 |
"height": height,
|
| 357 |
"width": width,
|
| 358 |
"visual_style": visual_style,
|
| 359 |
+
"seed": composition["seed"],
|
| 360 |
},
|
| 361 |
}
|
| 362 |
|
| 363 |
+
data = iowrapper.get_valid_post_response(
|
| 364 |
+
url=f"{parameters.MODEL_SERVER_URL}generate_image",
|
| 365 |
+
payload=payload,
|
| 366 |
+
)
|
| 367 |
+
image_list.append(Image.open(io.BytesIO(base64.b64decode(data["image"]))))
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 368 |
except Exception as e:
|
| 369 |
print(f"Error processing composition {i}: {e}")
|
| 370 |
continue
|
| 371 |
|
| 372 |
+
print(f"Generated new images for episode: {current_episode} and frame: {current_frame}")
|
| 373 |
+
print(f"Length of image list: {len(image_list)}")
|
| 374 |
+
return image_list
|
| 375 |
except Exception as e:
|
| 376 |
print(f"Error in regenerate_data: {e}")
|
| 377 |
+
gr.Warning("Failed to generate new images!")
|
| 378 |
+
return []
|
| 379 |
|
| 380 |
|
| 381 |
+
def save_comic_data(
|
| 382 |
current_episode: int,
|
| 383 |
current_frame: int,
|
| 384 |
+
episode_data: dict,
|
| 385 |
comic_id: str,
|
| 386 |
+
image_description: str,
|
| 387 |
+
narration: str,
|
| 388 |
+
character: str,
|
| 389 |
+
dialogue: str,
|
| 390 |
+
location: str,
|
| 391 |
+
setting: str,
|
| 392 |
+
prompt_1: str,
|
| 393 |
+
prompt_2: str,
|
| 394 |
+
prompt_3: str,
|
| 395 |
+
prompt_4: str,
|
| 396 |
+
frame_hash_map: dict,
|
| 397 |
+
rel_chars: list,
|
| 398 |
+
character_data: dict,
|
| 399 |
+
images: list
|
| 400 |
):
|
| 401 |
try:
|
| 402 |
+
scene_num, frame_num = (
|
| 403 |
+
frame_hash_map[current_frame]["scene"],
|
| 404 |
+
frame_hash_map[current_frame]["frame"],
|
| 405 |
)
|
| 406 |
+
curr_frame = episode_data["scenes"][scene_num]["frames"][frame_num]
|
| 407 |
print(
|
| 408 |
+
f"Saving comic data for episode {current_episode}, frame {frame_num}"
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 409 |
)
|
| 410 |
|
| 411 |
# Update compositions with prompts
|
| 412 |
prompts_list = [prompt_1, prompt_2, prompt_3, prompt_4]
|
| 413 |
+
for i, comp in enumerate(curr_frame["compositions"]):
|
| 414 |
+
comp["prompt"] = prompts_list[i]
|
| 415 |
+
# Save new images to S3
|
| 416 |
+
with Image.open(images[i][0]) as img:
|
| 417 |
+
img_bytes = io.BytesIO()
|
| 418 |
+
img.convert("RGB").save(img_bytes, "JPEG")
|
| 419 |
+
img_bytes.seek(0)
|
| 420 |
+
aws_utils.save_to_s3(
|
| 421 |
+
parameters.AWS_BUCKET,
|
| 422 |
+
f"{comic_id}/episodes/episode-{current_episode}/compositions/scene-{scene_num}/frame-{frame_num}",
|
| 423 |
+
img_bytes,
|
| 424 |
+
f"{i}.jpg",
|
| 425 |
+
)
|
| 426 |
|
| 427 |
+
# Update frame data
|
| 428 |
+
curr_frame.update(
|
| 429 |
{
|
| 430 |
"description": image_description,
|
| 431 |
"narration": narration,
|
|
|
|
| 433 |
"location": location,
|
| 434 |
"setting": setting,
|
| 435 |
"audio_cue_character": character,
|
| 436 |
+
"characters": [character_data[char] for char in rel_chars],
|
| 437 |
}
|
| 438 |
)
|
| 439 |
|
| 440 |
# Save the updated episode back to S3
|
| 441 |
+
print(f"Saving updated episode {current_episode} to S3")
|
| 442 |
aws_utils.save_to_s3(
|
| 443 |
bucket_name=parameters.AWS_BUCKET,
|
| 444 |
folder_name=f"{comic_id}/episodes/episode-{current_episode}",
|
| 445 |
+
content=episode_data,
|
| 446 |
file_name="episode.json",
|
| 447 |
)
|
| 448 |
+
gr.Info("Comic data saved successfully!")
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 449 |
except Exception as e:
|
| 450 |
+
print(f"Error in saving comic data: {e}")
|
| 451 |
+
gr.Warning("Failed to save data for the comic!")
|
parameters.py
CHANGED
|
@@ -1,7 +1,7 @@
|
|
| 1 |
import os
|
| 2 |
-
|
| 3 |
|
| 4 |
-
|
| 5 |
|
| 6 |
|
| 7 |
AWS_BUCKET = os.getenv("AWS_BUCKET")
|
|
@@ -11,4 +11,6 @@ os.environ["S3_BUCKET_NAME"] = os.getenv("AWS_BUCKET")
|
|
| 11 |
VISUAL_CHOICES = ["DARK", "FLUX_COMIC", "GHIBLI_COMIC"]
|
| 12 |
MAX_TRIES = os.getenv("MAX_TRIES")
|
| 13 |
OPEN_AI_API_KEY = os.getenv("OPEN_AI_KEY")
|
| 14 |
-
MODEL_SERVER_URL = os.getenv("MODEL_SERVER_URL")
|
|
|
|
|
|
|
|
|
| 1 |
import os
|
| 2 |
+
from dotenv import load_dotenv
|
| 3 |
|
| 4 |
+
load_dotenv()
|
| 5 |
|
| 6 |
|
| 7 |
AWS_BUCKET = os.getenv("AWS_BUCKET")
|
|
|
|
| 11 |
VISUAL_CHOICES = ["DARK", "FLUX_COMIC", "GHIBLI_COMIC"]
|
| 12 |
MAX_TRIES = os.getenv("MAX_TRIES")
|
| 13 |
OPEN_AI_API_KEY = os.getenv("OPEN_AI_KEY")
|
| 14 |
+
MODEL_SERVER_URL = os.getenv("MODEL_SERVER_URL")
|
| 15 |
+
IMG_HEIGHT=os.getenv("IMG_HEIGHT")
|
| 16 |
+
IMG_WIDTH=os.getenv("IMG_WIDTH")
|
script_gen.py
CHANGED
|
@@ -1,53 +1,60 @@
|
|
| 1 |
generate_image_compositions_instruction = """\
|
| 2 |
-
As a visual artist and cinematographer with extensive knowledge of different camera angles, visual styles, and aesthetics, your task is to analyze the provided frame details and create four distinct compositions. Each composition should follow a specific narrative structure in its prompt construction:
|
| 3 |
|
| 4 |
1) Output Requirements in json:
|
| 5 |
{
|
| 6 |
"compositions": [
|
| 7 |
{
|
| 8 |
"prompt": "Detailed visual description following the structure below (max 77 tokens)",
|
| 9 |
-
"shot_type": "Optimal cinematographic shot"
|
| 10 |
}
|
| 11 |
]
|
| 12 |
}
|
| 13 |
|
| 14 |
2) Prompt Structure (in this specific order):
|
| 15 |
a) Begin with the environment and setting:
|
| 16 |
-
- Establish the broader landscape/location first
|
| 17 |
-
- Describe key environmental elements
|
| 18 |
-
- Set the atmospheric conditions
|
| 19 |
-
- Define the lighting and mood
|
| 20 |
-
|
| 21 |
b) Then layer in the scene elements:
|
| 22 |
- How different parts of the environment interact
|
| 23 |
- Spatial relationships and depth
|
| 24 |
-
- Textures and materials
|
| 25 |
- Any dynamic elements (movement, weather effects)
|
| 26 |
-
|
| 27 |
c) Finally, integrate characters (if applicable):
|
| 28 |
- Their position within the established environment
|
| 29 |
- How they interact with the space
|
| 30 |
- Their expressions and actions as part of the scene
|
| 31 |
-
|
| 32 |
3) Each composition should:
|
| 33 |
- Flow naturally like a single, cohesive description
|
| 34 |
- Prioritize environmental storytelling
|
| 35 |
- Build the scene progressively from background to foreground
|
| 36 |
- Maintain consistent atmosphere throughout
|
|
|
|
| 37 |
|
| 38 |
4) For NO-CHAR compositions:
|
| 39 |
Focus entirely on a and b of the prompt structure, with extra emphasis on:
|
| 40 |
-
- Environmental details and patterns
|
| 41 |
-
- Architectural elements
|
| 42 |
- Natural phenomena
|
| 43 |
-
- Atmospheric qualities
|
| 44 |
|
| 45 |
-
Note: Avoid jumping between environment and character descriptions. Each element should flow naturally into the next, creating a unified visual narrative.
|
| 46 |
"""
|
| 47 |
|
| 48 |
generate_image_compositions_user_prompt = """\
|
| 49 |
Here's are the details:
|
| 50 |
|
| 51 |
-
##
|
| 52 |
{{FRAME}}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 53 |
"""
|
|
|
|
| 1 |
generate_image_compositions_instruction = """\
|
| 2 |
+
As a visual artist and cinematographer with extensive knowledge of different camera angles, visual styles, and aesthetics, your task is to analyze the provided frame details and create four distinct compositions, maintaining consistency with previous frame's location and settings. Each composition should follow a specific narrative structure in its prompt construction:
|
| 3 |
|
| 4 |
1) Output Requirements in json:
|
| 5 |
{
|
| 6 |
"compositions": [
|
| 7 |
{
|
| 8 |
"prompt": "Detailed visual description following the structure below (max 77 tokens)",
|
| 9 |
+
"shot_type": "Optimal cinematographic shot",
|
| 10 |
}
|
| 11 |
]
|
| 12 |
}
|
| 13 |
|
| 14 |
2) Prompt Structure (in this specific order):
|
| 15 |
a) Begin with the environment and setting:
|
| 16 |
+
- Establish the broader landscape/location first, maintaining consistency with previous frame
|
| 17 |
+
- Describe key environmental elements that persist from previous frame
|
| 18 |
+
- Set the atmospheric conditions aligned with previous settings
|
| 19 |
+
- Define the lighting and mood that follows from previous frame
|
| 20 |
+
|
| 21 |
b) Then layer in the scene elements:
|
| 22 |
- How different parts of the environment interact
|
| 23 |
- Spatial relationships and depth
|
| 24 |
+
- Textures and materials consistent with previous frame
|
| 25 |
- Any dynamic elements (movement, weather effects)
|
| 26 |
+
|
| 27 |
c) Finally, integrate characters (if applicable):
|
| 28 |
- Their position within the established environment
|
| 29 |
- How they interact with the space
|
| 30 |
- Their expressions and actions as part of the scene
|
| 31 |
+
|
| 32 |
3) Each composition should:
|
| 33 |
- Flow naturally like a single, cohesive description
|
| 34 |
- Prioritize environmental storytelling
|
| 35 |
- Build the scene progressively from background to foreground
|
| 36 |
- Maintain consistent atmosphere throughout
|
| 37 |
+
- Ensure visual continuity with previous frame's location and settings
|
| 38 |
|
| 39 |
4) For NO-CHAR compositions:
|
| 40 |
Focus entirely on a and b of the prompt structure, with extra emphasis on:
|
| 41 |
+
- Environmental details and patterns that match previous frame
|
| 42 |
+
- Architectural elements maintaining previous frame's style
|
| 43 |
- Natural phenomena
|
| 44 |
+
- Atmospheric qualities aligned with previous settings
|
| 45 |
|
| 46 |
+
Note: Avoid jumping between environment and character descriptions. Each element should flow naturally into the next, creating a unified visual narrative while maintaining consistency with previous frame's location and settings.\
|
| 47 |
"""
|
| 48 |
|
| 49 |
generate_image_compositions_user_prompt = """\
|
| 50 |
Here's are the details:
|
| 51 |
|
| 52 |
+
## Current Frame:
|
| 53 |
{{FRAME}}
|
| 54 |
+
|
| 55 |
+
Previous Frame location:
|
| 56 |
+
{{LOCATION_DESCRIPTION}}
|
| 57 |
+
|
| 58 |
+
Previous Frame settings:
|
| 59 |
+
{{frame_settings}}
|
| 60 |
"""
|