622 lines
28 KiB
Python
622 lines
28 KiB
Python
"""
|
|
YouTube Thumbnail Generator Module
|
|
|
|
This module provides functionality for generating YouTube video thumbnails.
|
|
"""
|
|
|
|
import streamlit as st
|
|
import time
|
|
import logging
|
|
import os
|
|
import traceback
|
|
from PIL import Image
|
|
from lib.gpt_providers.text_generation.main_text_generation import llm_text_gen
|
|
from lib.gpt_providers.text_to_image_generation.gen_gemini_images import generate_gemini_image, edit_image
|
|
|
|
# Configure logging
|
|
logging.basicConfig(
|
|
level=logging.INFO,
|
|
format='%(asctime)s - %(name)s - %(levelname)s - %(message)s'
|
|
)
|
|
logger = logging.getLogger('youtube_thumbnail_generator')
|
|
|
|
|
|
def generate_thumbnail_concepts(video_title, video_description, target_audience, content_type, style_preference, num_concepts=3):
|
|
"""Generate thumbnail concept ideas based on video content."""
|
|
logger.info(f"Generating thumbnail concepts for: '{video_title}'")
|
|
logger.info(f"Parameters: target_audience={target_audience}, content_type={content_type}, style_preference={style_preference}, num_concepts={num_concepts}")
|
|
|
|
# Create a system prompt for thumbnail concept generation
|
|
system_prompt = """You are a YouTube thumbnail expert specializing in creating engaging, click-worthy thumbnail concepts.
|
|
Your task is to generate thumbnail concept ideas based on the provided video information.
|
|
Focus ONLY on creating concepts that are optimized for YouTube, with proper visual hierarchy, text placement, and emotional triggers.
|
|
Return ONLY the concept descriptions, without any additional commentary or explanations.
|
|
Each concept should include:
|
|
1. A main visual element or scene
|
|
2. Text placement and content
|
|
3. Color scheme suggestions
|
|
4. Emotional trigger or hook
|
|
5. Brief explanation of why this concept would be effective"""
|
|
|
|
# Build the prompt
|
|
prompt = f"""
|
|
**Instructions:**
|
|
|
|
Please generate {num_concepts} thumbnail concept ideas for a YouTube video with the following information:
|
|
|
|
**Video Title:** {video_title}
|
|
**Video Description:** {video_description}
|
|
**Target Audience:** {target_audience}
|
|
**Content Type:** {content_type}
|
|
**Style Preference:** {style_preference}
|
|
|
|
**Specific Instructions:**
|
|
* Each concept should be clearly separated and numbered.
|
|
* Focus on creating thumbnails that stand out in search results and recommendations.
|
|
* Consider the target audience's interests and preferences.
|
|
* Include specific details about visual elements, text placement, and color schemes.
|
|
* Explain why each concept would be effective for this specific video.
|
|
"""
|
|
|
|
try:
|
|
logger.info("Sending request to LLM for thumbnail concepts")
|
|
response = llm_text_gen(prompt, system_prompt=system_prompt)
|
|
logger.info(f"Received response from LLM: {len(response)} characters")
|
|
return response
|
|
except Exception as err:
|
|
logger.error(f"Error generating thumbnail concepts: {err}")
|
|
logger.error(traceback.format_exc())
|
|
st.error(f"Error: Failed to generate thumbnail concepts: {err}")
|
|
return None
|
|
|
|
|
|
def generate_thumbnail_design(concept_description, style_preference, aspect_ratio="16:9", keywords=None, style=None, focus=None):
|
|
"""Generate a thumbnail image based on the concept description."""
|
|
logger.info(f"Generating thumbnail design for concept: '{concept_description[:50]}...'")
|
|
logger.info(f"Parameters: style_preference={style_preference}, aspect_ratio={aspect_ratio}, keywords={keywords}, style={style}, focus={focus}")
|
|
|
|
# Create a prompt for the image generation
|
|
image_prompt = f"""
|
|
Create a YouTube thumbnail image with the following specifications:
|
|
|
|
Concept: {concept_description}
|
|
Style: {style_preference}
|
|
Aspect Ratio: {aspect_ratio}
|
|
|
|
The image should be:
|
|
- High contrast and visually striking
|
|
- Suitable for a YouTube thumbnail
|
|
- Include the specified visual elements and text
|
|
- Follow the color scheme described
|
|
- Optimized for small display sizes
|
|
|
|
Make sure the text is large and readable, and the main subject is centered and prominent.
|
|
"""
|
|
|
|
try:
|
|
logger.info("Sending request to Gemini for thumbnail image")
|
|
# Generate the image using Gemini with enhanced prompt
|
|
img_path = generate_gemini_image(
|
|
image_prompt,
|
|
keywords=keywords,
|
|
style=style,
|
|
focus=focus,
|
|
enhance_prompt=True
|
|
)
|
|
logger.info(f"Received image from Gemini: {img_path}")
|
|
return img_path
|
|
except Exception as err:
|
|
logger.error(f"Error generating thumbnail image: {err}")
|
|
logger.error(traceback.format_exc())
|
|
st.error(f"Error: Failed to generate thumbnail image: {err}")
|
|
return None
|
|
|
|
|
|
def edit_thumbnail_image(img_path, edit_instructions):
|
|
"""Edit a thumbnail image based on user instructions."""
|
|
logger.info(f"Editing thumbnail image: '{img_path}'")
|
|
logger.info(f"Edit instructions: '{edit_instructions}'")
|
|
|
|
try:
|
|
logger.info("Sending request to Gemini for image editing")
|
|
# Edit the image using Gemini
|
|
edited_img_path = edit_image(img_path, edit_instructions)
|
|
logger.info(f"Image editing completed. Edited image path: {edited_img_path}")
|
|
|
|
# Return the path to the edited image
|
|
return edited_img_path
|
|
except Exception as err:
|
|
logger.error(f"Error editing thumbnail image: {err}")
|
|
logger.error(traceback.format_exc())
|
|
st.error(f"Error: Failed to edit thumbnail image: {err}")
|
|
return None
|
|
|
|
|
|
def analyze_thumbnail(thumbnail_path):
|
|
"""Analyze a thumbnail for effectiveness."""
|
|
logger.info(f"Analyzing thumbnail: '{thumbnail_path}'")
|
|
|
|
# This would typically involve image analysis, but for now we'll use AI to provide feedback
|
|
system_prompt = """You are a YouTube thumbnail expert specializing in analyzing and providing feedback on thumbnail designs.
|
|
Your task is to analyze the thumbnail and provide constructive feedback on its effectiveness.
|
|
Focus on aspects like visual hierarchy, text readability, emotional impact, and click-worthiness."""
|
|
|
|
# For now, we'll just return a placeholder analysis
|
|
# In a real implementation, we would analyze the actual image
|
|
logger.info("Generating thumbnail analysis")
|
|
return """
|
|
**Thumbnail Analysis:**
|
|
|
|
- **Visual Hierarchy:** The main subject is well-positioned and stands out against the background.
|
|
- **Text Readability:** The text is clear and readable, with good contrast against the background.
|
|
- **Emotional Impact:** The thumbnail creates curiosity and emotional connection with the target audience.
|
|
- **Click-worthiness:** The design is likely to attract clicks due to its visual appeal and clear value proposition.
|
|
|
|
**Suggestions for Improvement:**
|
|
- Consider adding a subtle border to make the thumbnail stand out more in search results.
|
|
- The text could be slightly larger for better readability on mobile devices.
|
|
- Adding a small icon or logo could help with brand recognition.
|
|
"""
|
|
|
|
|
|
def parse_concepts(concepts_text):
|
|
"""Parse the concepts text into a list of individual concepts."""
|
|
logger.info("Parsing concepts text into individual concepts")
|
|
|
|
concept_list = []
|
|
current_concept = ""
|
|
|
|
for line in concepts_text.split('\n'):
|
|
if line.strip().startswith(('1.', '2.', '3.', '4.', '5.')):
|
|
if current_concept:
|
|
concept_list.append(current_concept.strip())
|
|
current_concept = line
|
|
else:
|
|
current_concept += "\n" + line
|
|
|
|
if current_concept:
|
|
concept_list.append(current_concept.strip())
|
|
|
|
logger.info(f"Parsed {len(concept_list)} concepts from the response")
|
|
return concept_list
|
|
|
|
|
|
def write_yt_thumbnail():
|
|
"""Create a user interface for YouTube Thumbnail Generator."""
|
|
logger.info("Initializing YouTube Thumbnail Generator UI")
|
|
st.title("YouTube Thumbnail Generator")
|
|
st.write("Create engaging, click-worthy thumbnails for your YouTube videos.")
|
|
|
|
# Initialize session state for generated thumbnails if it doesn't exist
|
|
if "generated_thumbnails" not in st.session_state:
|
|
st.session_state.generated_thumbnails = []
|
|
if "thumbnail_concepts" not in st.session_state:
|
|
st.session_state.thumbnail_concepts = None
|
|
if "current_thumbnail_path" not in st.session_state:
|
|
st.session_state.current_thumbnail_path = None
|
|
if "concept_list" not in st.session_state:
|
|
st.session_state.concept_list = []
|
|
if "editing_thumbnail" not in st.session_state:
|
|
st.session_state.editing_thumbnail = False
|
|
if "edit_instructions" not in st.session_state:
|
|
st.session_state.edit_instructions = ""
|
|
if "edited_thumbnail_path" not in st.session_state:
|
|
st.session_state.edited_thumbnail_path = None
|
|
if "show_edit_form" not in st.session_state:
|
|
st.session_state.show_edit_form = False
|
|
|
|
# Create tabs for different sections
|
|
tab1, tab2 = st.tabs(["Basic Info", "Style & Generation"])
|
|
|
|
with tab1:
|
|
# Basic information inputs
|
|
video_title = st.text_input("Video Title",
|
|
placeholder="e.g., 10 Tips for Better Photography")
|
|
video_description = st.text_area("Video Description",
|
|
placeholder="Brief description of your video content")
|
|
target_audience = st.text_input("Target Audience",
|
|
placeholder="e.g., photography enthusiasts, beginners")
|
|
|
|
# Content type selection
|
|
content_type = st.selectbox("Content Type", [
|
|
"Tutorial/How-to",
|
|
"Vlog",
|
|
"Review",
|
|
"Educational",
|
|
"Entertainment",
|
|
"News/Update",
|
|
"Product Showcase",
|
|
"Challenge",
|
|
"Reaction",
|
|
"Comparison"
|
|
])
|
|
|
|
with tab2:
|
|
# Style preferences
|
|
st.subheader("Style Preferences")
|
|
|
|
# Create columns for style options
|
|
col1, col2 = st.columns(2)
|
|
|
|
with col1:
|
|
style_preference = st.selectbox("Thumbnail Style", [
|
|
"Bold and Dramatic",
|
|
"Clean and Minimal",
|
|
"Colorful and Vibrant",
|
|
"Dark and Moody",
|
|
"Professional and Corporate",
|
|
"Playful and Fun",
|
|
"Retro/Vintage",
|
|
"Modern and Sleek"
|
|
])
|
|
|
|
num_concepts = st.slider("Number of Concepts", 1, 5, 3)
|
|
|
|
with col2:
|
|
aspect_ratio = st.selectbox("Aspect Ratio", [
|
|
"16:9 (Standard)",
|
|
"1:1 (Square)",
|
|
"4:3 (Classic)",
|
|
"9:16 (Vertical)"
|
|
])
|
|
|
|
include_text = st.checkbox("Include Text Overlay", value=True)
|
|
if include_text:
|
|
text_style = st.selectbox("Text Style", [
|
|
"Bold and Impactful",
|
|
"Clean and Readable",
|
|
"Stylized and Thematic",
|
|
"Minimal and Subtle"
|
|
])
|
|
|
|
# Advanced AI Prompt Settings
|
|
st.subheader("Advanced AI Prompt Settings")
|
|
|
|
# Create columns for advanced settings
|
|
col3, col4 = st.columns(2)
|
|
|
|
with col3:
|
|
# Image style selection
|
|
image_style = st.selectbox("Image Style", [
|
|
"Auto (AI will choose best style)",
|
|
"Photorealistic",
|
|
"Artistic",
|
|
"Cartoon/Anime",
|
|
"Sketch/Drawing",
|
|
"Digital Art",
|
|
"3D Render"
|
|
])
|
|
|
|
# Extract style for the generate_gemini_image function
|
|
style = None
|
|
if image_style == "Photorealistic":
|
|
style = "photorealistic"
|
|
elif image_style == "Artistic":
|
|
style = "artistic"
|
|
elif image_style == "Cartoon/Anime":
|
|
style = "cartoon"
|
|
elif image_style == "Sketch/Drawing":
|
|
style = "sketch"
|
|
elif image_style == "Digital Art":
|
|
style = "digital_art"
|
|
elif image_style == "3D Render":
|
|
style = "3d_render"
|
|
|
|
with col4:
|
|
# Focus selection for photorealistic images
|
|
focus = None
|
|
if style == "photorealistic":
|
|
focus = st.selectbox("Image Focus", [
|
|
"Auto (AI will choose best focus)",
|
|
"Portraits",
|
|
"Objects",
|
|
"Motion",
|
|
"Wide-angle"
|
|
])
|
|
|
|
# Extract focus for the generate_gemini_image function
|
|
if focus == "Portraits":
|
|
focus = "portraits"
|
|
elif focus == "Objects":
|
|
focus = "objects"
|
|
elif focus == "Motion":
|
|
focus = "motion"
|
|
elif focus == "Wide-angle":
|
|
focus = "wide-angle"
|
|
elif focus == "Auto (AI will choose best focus)":
|
|
focus = None
|
|
|
|
# Keywords for enhanced prompt generation
|
|
st.subheader("Keywords for Enhanced Prompt")
|
|
st.write("Add keywords to enhance the AI prompt generation. These will help create more detailed and accurate thumbnails.")
|
|
|
|
# Create a text area for keywords
|
|
keywords_input = st.text_area(
|
|
"Keywords (comma-separated)",
|
|
placeholder="e.g., vibrant, energetic, bold, eye-catching, professional"
|
|
)
|
|
|
|
# Process keywords
|
|
keywords = None
|
|
if keywords_input:
|
|
keywords = [k.strip() for k in keywords_input.split(",") if k.strip()]
|
|
logger.info(f"User provided keywords: {keywords}")
|
|
|
|
# Generate button
|
|
if st.button("Generate Thumbnail Concepts"):
|
|
if not video_title:
|
|
st.error("Please enter a video title.")
|
|
return
|
|
|
|
with st.spinner("Generating thumbnail concepts..."):
|
|
logger.info("User clicked Generate Thumbnail Concepts button")
|
|
concepts = generate_thumbnail_concepts(
|
|
video_title,
|
|
video_description,
|
|
target_audience,
|
|
content_type,
|
|
style_preference,
|
|
num_concepts
|
|
)
|
|
|
|
if concepts:
|
|
# Store the concepts in session state
|
|
st.session_state.thumbnail_concepts = concepts
|
|
# Parse the concepts and store in session state
|
|
st.session_state.concept_list = parse_concepts(concepts)
|
|
logger.info("Stored thumbnail concepts in session state")
|
|
|
|
# Display the concepts in tabs
|
|
st.subheader("Thumbnail Concepts")
|
|
|
|
# Create tabs for each concept
|
|
concept_tabs = st.tabs([f"Concept {i+1}" for i in range(len(st.session_state.concept_list))])
|
|
|
|
for i, tab in enumerate(concept_tabs):
|
|
with tab:
|
|
st.markdown(st.session_state.concept_list[i])
|
|
|
|
# Add a button to generate image for this concept
|
|
if st.button(f"Generate Image for Concept {i+1}", key=f"gen_img_{i}"):
|
|
with st.spinner(f"Generating thumbnail image for concept {i+1}..."):
|
|
logger.info(f"User selected concept {i+1} for image generation")
|
|
# Get the selected concept
|
|
selected_concept = st.session_state.concept_list[i]
|
|
|
|
# Generate the thumbnail image with enhanced prompt
|
|
img_path = generate_thumbnail_design(
|
|
selected_concept,
|
|
style_preference,
|
|
aspect_ratio.split()[0], # Extract just the ratio part
|
|
keywords=keywords,
|
|
style=style,
|
|
focus=focus
|
|
)
|
|
|
|
if img_path:
|
|
# Store the current thumbnail path in session state
|
|
st.session_state.current_thumbnail_path = img_path
|
|
logger.info(f"Stored current thumbnail path in session state: {img_path}")
|
|
|
|
# Display the generated image
|
|
st.subheader("Generated Thumbnail")
|
|
st.image(img_path, use_container_width=True)
|
|
|
|
# Add download button
|
|
with open(img_path, "rb") as file:
|
|
st.download_button(
|
|
label="Download Thumbnail",
|
|
data=file,
|
|
file_name=f"youtube_thumbnail_{int(time.time())}.png",
|
|
mime="image/png"
|
|
)
|
|
|
|
# Add image editing section
|
|
st.subheader("Edit Thumbnail")
|
|
st.write("Make changes to your thumbnail by providing instructions below:")
|
|
|
|
# Create a text area for edit instructions
|
|
edit_instructions = st.text_area(
|
|
"Edit Instructions",
|
|
placeholder="e.g., Make the background darker, Add a red border, Change the text color to white",
|
|
key=f"edit_instructions_{i}"
|
|
)
|
|
|
|
# Store edit instructions in session state
|
|
st.session_state.edit_instructions = edit_instructions
|
|
|
|
# Add a button to apply edits
|
|
if st.button("Apply Edits", key=f"apply_edits_{i}"):
|
|
if not edit_instructions:
|
|
st.warning("Please provide edit instructions.")
|
|
else:
|
|
# Set editing flag
|
|
st.session_state.editing_thumbnail = True
|
|
st.session_state.show_edit_form = True
|
|
|
|
# Rerun to update the UI
|
|
st.rerun()
|
|
|
|
# Add analysis button
|
|
if st.button("Analyze Thumbnail", key=f"analyze_{i}"):
|
|
logger.info("User clicked Analyze Thumbnail button")
|
|
analysis = analyze_thumbnail(img_path)
|
|
st.subheader("Thumbnail Analysis")
|
|
st.markdown(analysis)
|
|
else:
|
|
st.error("Failed to generate thumbnail concepts. Please try again.")
|
|
|
|
# Display previously generated concepts if they exist in session state
|
|
elif st.session_state.thumbnail_concepts and st.session_state.concept_list:
|
|
logger.info("Displaying previously generated concepts from session state")
|
|
st.subheader("Thumbnail Concepts")
|
|
|
|
# Create tabs for each concept
|
|
concept_tabs = st.tabs([f"Concept {i+1}" for i in range(len(st.session_state.concept_list))])
|
|
|
|
for i, tab in enumerate(concept_tabs):
|
|
with tab:
|
|
st.markdown(st.session_state.concept_list[i])
|
|
|
|
# Add a button to generate image for this concept
|
|
if st.button(f"Generate Image for Concept {i+1}", key=f"gen_img_existing_{i}"):
|
|
with st.spinner(f"Generating thumbnail image for concept {i+1}..."):
|
|
logger.info(f"User selected concept {i+1} for image generation")
|
|
# Get the selected concept
|
|
selected_concept = st.session_state.concept_list[i]
|
|
|
|
# Generate the thumbnail image with enhanced prompt
|
|
img_path = generate_thumbnail_design(
|
|
selected_concept,
|
|
style_preference,
|
|
aspect_ratio.split()[0], # Extract just the ratio part
|
|
keywords=keywords,
|
|
style=style,
|
|
focus=focus
|
|
)
|
|
|
|
if img_path:
|
|
# Store the current thumbnail path in session state
|
|
st.session_state.current_thumbnail_path = img_path
|
|
logger.info(f"Stored current thumbnail path in session state: {img_path}")
|
|
|
|
# Display the generated image
|
|
st.subheader("Generated Thumbnail")
|
|
st.image(img_path, use_container_width=True)
|
|
|
|
# Add download button
|
|
with open(img_path, "rb") as file:
|
|
st.download_button(
|
|
label="Download Thumbnail",
|
|
data=file,
|
|
file_name=f"youtube_thumbnail_{int(time.time())}.png",
|
|
mime="image/png"
|
|
)
|
|
|
|
# Add image editing section
|
|
st.subheader("Edit Thumbnail")
|
|
st.write("Make changes to your thumbnail by providing instructions below:")
|
|
|
|
# Create a text area for edit instructions
|
|
edit_instructions = st.text_area(
|
|
"Edit Instructions",
|
|
placeholder="e.g., Make the background darker, Add a red border, Change the text color to white",
|
|
key=f"edit_instructions_existing_{i}"
|
|
)
|
|
|
|
# Store edit instructions in session state
|
|
st.session_state.edit_instructions = edit_instructions
|
|
|
|
# Add a button to apply edits
|
|
if st.button("Apply Edits", key=f"apply_edits_existing_{i}"):
|
|
if not edit_instructions:
|
|
st.warning("Please provide edit instructions.")
|
|
else:
|
|
# Set editing flag
|
|
st.session_state.editing_thumbnail = True
|
|
st.session_state.show_edit_form = True
|
|
|
|
# Rerun to update the UI
|
|
st.rerun()
|
|
|
|
# Add analysis button
|
|
if st.button("Analyze Thumbnail", key=f"analyze_existing_{i}"):
|
|
logger.info("User clicked Analyze Thumbnail button")
|
|
analysis = analyze_thumbnail(img_path)
|
|
st.subheader("Thumbnail Analysis")
|
|
st.markdown(analysis)
|
|
|
|
# Display current thumbnail if it exists in session state
|
|
elif st.session_state.current_thumbnail_path:
|
|
logger.info(f"Displaying current thumbnail from session state: {st.session_state.current_thumbnail_path}")
|
|
st.subheader("Current Thumbnail")
|
|
st.image(st.session_state.current_thumbnail_path, use_container_width=True)
|
|
|
|
# Add download button
|
|
with open(st.session_state.current_thumbnail_path, "rb") as file:
|
|
st.download_button(
|
|
label="Download Thumbnail",
|
|
data=file,
|
|
file_name=f"youtube_thumbnail_{int(time.time())}.png",
|
|
mime="image/png"
|
|
)
|
|
|
|
# Add image editing section
|
|
st.subheader("Edit Thumbnail")
|
|
st.write("Make changes to your thumbnail by providing instructions below:")
|
|
|
|
# Create a text area for edit instructions
|
|
edit_instructions = st.text_area(
|
|
"Edit Instructions",
|
|
placeholder="e.g., Make the background darker, Add a red border, Change the text color to white",
|
|
key="edit_instructions_current",
|
|
value=st.session_state.edit_instructions if st.session_state.edit_instructions else ""
|
|
)
|
|
|
|
# Store edit instructions in session state
|
|
st.session_state.edit_instructions = edit_instructions
|
|
|
|
# Add a button to apply edits
|
|
if st.button("Apply Edits", key="apply_edits_current"):
|
|
if not edit_instructions:
|
|
st.warning("Please provide edit instructions.")
|
|
else:
|
|
# Set editing flag
|
|
st.session_state.editing_thumbnail = True
|
|
st.session_state.show_edit_form = True
|
|
|
|
# Rerun to update the UI
|
|
st.rerun()
|
|
|
|
# Add analysis button
|
|
if st.button("Analyze Thumbnail", key="analyze_current"):
|
|
logger.info("User clicked Analyze Thumbnail button")
|
|
analysis = analyze_thumbnail(st.session_state.current_thumbnail_path)
|
|
st.subheader("Thumbnail Analysis")
|
|
st.markdown(analysis)
|
|
|
|
# Handle the editing process
|
|
if st.session_state.editing_thumbnail and st.session_state.show_edit_form:
|
|
st.subheader("Editing Thumbnail")
|
|
|
|
# Show a spinner while editing
|
|
with st.spinner("Editing thumbnail..."):
|
|
logger.info(f"User provided edit instructions: '{st.session_state.edit_instructions}'")
|
|
# Edit the thumbnail image
|
|
edited_img_path = edit_thumbnail_image(st.session_state.current_thumbnail_path, st.session_state.edit_instructions)
|
|
|
|
if edited_img_path:
|
|
# Update the current thumbnail path in session state
|
|
st.session_state.edited_thumbnail_path = edited_img_path
|
|
logger.info(f"Updated current thumbnail path in session state: {edited_img_path}")
|
|
|
|
# Reset editing flags
|
|
st.session_state.editing_thumbnail = False
|
|
st.session_state.show_edit_form = False
|
|
|
|
# Display the edited image
|
|
st.subheader("Edited Thumbnail")
|
|
st.image(edited_img_path, use_container_width=True)
|
|
|
|
# Add download button for the edited image
|
|
with open(edited_img_path, "rb") as file:
|
|
st.download_button(
|
|
label="Download Edited Thumbnail",
|
|
data=file,
|
|
file_name=f"youtube_thumbnail_edited_{int(time.time())}.png",
|
|
mime="image/png"
|
|
)
|
|
|
|
# Update the current thumbnail path to the edited one
|
|
st.session_state.current_thumbnail_path = edited_img_path
|
|
|
|
# Add a button to continue editing
|
|
if st.button("Continue Editing"):
|
|
st.session_state.show_edit_form = True
|
|
st.rerun()
|
|
else:
|
|
# Reset editing flags
|
|
st.session_state.editing_thumbnail = False
|
|
st.session_state.show_edit_form = False
|
|
|
|
st.error("Failed to edit the thumbnail. Please try again with different instructions.") |