urltothumbainl / src /streamlit_app.py
Akshayram1's picture
Update src/streamlit_app.py
47d43fd verified
import streamlit as st
from openai import OpenAI
import requests
from PIL import Image
from io import BytesIO
import re
import urllib.parse
# Set up the page
st.set_page_config(
page_title="AI Thumbnail Generator",
page_icon="🎬",
layout="wide"
)
st.title("🎬 AI Video Thumbnail Generator")
st.write("Generate engaging thumbnails for your videos using OpenAI's DALL-E 3")
# Sidebar for API key
with st.sidebar:
st.header("πŸ”‘ Configuration")
openai_api_key = st.text_input("OpenAI API Key", type="password")
if openai_api_key:
client = OpenAI(api_key=openai_api_key)
st.success("API Key loaded!")
else:
st.warning("Enter your OpenAI API key to continue")
client = None
def extract_video_info(url):
"""Extract video information from URL using web scraping"""
video_info = {"platform": "unknown", "title": "", "id": "", "description": "", "extraction_success": False}
try:
# Identify platform first
if 'facebook.com' in url or 'fb.watch' in url:
video_info["platform"] = "facebook"
# Extract video ID from Facebook URL patterns
fb_patterns = [
r'facebook\.com/.*?/videos/(\d+)',
r'facebook\.com/watch/?\?v=(\d+)',
r'facebook\.com/share/v/([a-zA-Z0-9]+)',
r'fb\.watch/([a-zA-Z0-9_-]+)'
]
for pattern in fb_patterns:
match = re.search(pattern, url)
if match:
video_info["id"] = match.group(1)
break
st.warning("πŸ”’ Facebook videos require special handling. Please use **Manual Description mode** for best results.")
return video_info
elif 'instagram.com' in url:
video_info["platform"] = "instagram"
# Extract Instagram post/reel ID
ig_patterns = [
r'instagram\.com/p/([a-zA-Z0-9_-]+)',
r'instagram\.com/reel/([a-zA-Z0-9_-]+)',
r'instagram\.com/tv/([a-zA-Z0-9_-]+)'
]
for pattern in ig_patterns:
match = re.search(pattern, url)
if match:
video_info["id"] = match.group(1)
break
st.warning("πŸ”’ Instagram videos require login access. Please use **Manual Description mode** for best results.")
return video_info
elif 'tiktok.com' in url:
video_info["platform"] = "tiktok"
# Extract TikTok video ID
tiktok_match = re.search(r'tiktok\.com/.*?/video/(\d+)', url)
if tiktok_match:
video_info["id"] = tiktok_match.group(1)
st.warning("πŸ”’ TikTok videos have access restrictions. Please use **Manual Description mode** for best results.")
return video_info
elif 'twitter.com' in url or 'x.com' in url:
video_info["platform"] = "twitter"
# Extract tweet ID
twitter_patterns = [
r'twitter\.com/.*?/status/(\d+)',
r'x\.com/.*?/status/(\d+)'
]
for pattern in twitter_patterns:
match = re.search(pattern, url)
if match:
video_info["id"] = match.group(1)
break
st.warning("πŸ”’ Twitter/X videos have access restrictions. Please use **Manual Description mode** for best results.")
return video_info
# For supported platforms, continue with web scraping
headers = {
'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/91.0.4472.124 Safari/537.36'
}
response = requests.get(url, headers=headers, timeout=10)
html_content = response.text
# YouTube patterns
youtube_patterns = [
r'(?:youtube\.com/watch\?v=|youtu\.be/)([a-zA-Z0-9_-]+)',
r'youtube\.com/embed/([a-zA-Z0-9_-]+)'
]
for pattern in youtube_patterns:
match = re.search(pattern, url)
if match:
video_info["platform"] = "youtube"
video_info["id"] = match.group(1)
# Extract title from YouTube
title_patterns = [
r'<title>([^<]+)</title>',
r'"title":"([^"]+)"',
r'<meta property="og:title" content="([^"]+)"'
]
for title_pattern in title_patterns:
title_match = re.search(title_pattern, html_content)
if title_match:
video_info["title"] = title_match.group(1).replace(' - YouTube', '').replace('\\u0026', '&')
break
# Extract description from meta tags
desc_patterns = [
r'<meta name="description" content="([^"]+)"',
r'<meta property="og:description" content="([^"]+)"',
r'"description":"([^"]+)"'
]
for desc_pattern in desc_patterns:
desc_match = re.search(desc_pattern, html_content)
if desc_match:
video_info["description"] = desc_match.group(1).replace('\\n', ' ').replace('\\u0026', '&')
break
video_info["extraction_success"] = True
break
# Vimeo pattern
vimeo_match = re.search(r'vimeo\.com/(\d+)', url)
if vimeo_match:
video_info["platform"] = "vimeo"
video_info["id"] = vimeo_match.group(1)
# Extract title from Vimeo
title_patterns = [
r'<title>([^<]+)</title>',
r'<meta property="og:title" content="([^"]+)"'
]
for title_pattern in title_patterns:
title_match = re.search(title_pattern, html_content)
if title_match:
video_info["title"] = title_match.group(1).replace(' on Vimeo', '')
break
# Extract description
desc_patterns = [
r'<meta name="description" content="([^"]+)"',
r'<meta property="og:description" content="([^"]+)"'
]
for desc_pattern in desc_patterns:
desc_match = re.search(desc_pattern, html_content)
if desc_match:
video_info["description"] = desc_match.group(1)
break
video_info["extraction_success"] = True
# For other platforms, try to extract general info
if video_info["platform"] == "unknown":
# Try to get title from any webpage
title_patterns = [
r'<title>([^<]+)</title>',
r'<meta property="og:title" content="([^"]+)"'
]
for title_pattern in title_patterns:
title_match = re.search(title_pattern, html_content)
if title_match:
video_info["title"] = title_match.group(1)
break
# Try to get description from meta tags
desc_patterns = [
r'<meta name="description" content="([^"]+)"',
r'<meta property="og:description" content="([^"]+)"'
]
for desc_pattern in desc_patterns:
desc_match = re.search(desc_pattern, html_content)
if desc_match:
video_info["description"] = desc_match.group(1)
video_info["extraction_success"] = True
break
# Extract filename as fallback
from urllib.parse import urlparse
parsed_url = urlparse(url)
filename = parsed_url.path.split('/')[-1]
if not video_info["title"] and filename:
video_info["title"] = filename.replace('.mp4', '').replace('.avi', '').replace('.mov', '')
except Exception as e:
st.warning(f"⚠️ Could not automatically extract video information: {str(e)}")
st.info("πŸ’‘ **Tip:** Use **Manual Description mode** for better results with this URL.")
# Try to at least identify the platform for better guidance
if 'facebook.com' in url or 'fb.watch' in url:
video_info["platform"] = "facebook"
elif 'instagram.com' in url:
video_info["platform"] = "instagram"
elif 'tiktok.com' in url:
video_info["platform"] = "tiktok"
elif 'twitter.com' in url or 'x.com' in url:
video_info["platform"] = "twitter"
elif 'youtube.com' in url or 'youtu.be' in url:
video_info["platform"] = "youtube"
elif 'vimeo.com' in url:
video_info["platform"] = "vimeo"
# Fallback to basic URL parsing
from urllib.parse import urlparse
parsed_url = urlparse(url)
filename = parsed_url.path.split('/')[-1]
if filename:
video_info["title"] = filename.replace('.mp4', '').replace('.avi', '').replace('.mov', '')
return video_info
def analyze_video_content(url, custom_description=""):
"""Use GPT to analyze and create description for thumbnail generation"""
if not client:
return None
video_info = extract_video_info(url)
prompt = f"""
I need to create an engaging video thumbnail. Here's the video information I gathered:
URL: {url}
Platform: {video_info['platform']}
Video ID: {video_info['id']}
Title: {video_info['title']}
Description: {video_info['description']}
"""
if custom_description:
prompt += f"Additional User Description: {custom_description}\n"
prompt += """
Based on this video information, analyze the content and create a detailed description for generating an engaging thumbnail that would:
1. Grab viewers' attention and make them want to click
2. Accurately represent the video content based on the title and description
3. Look professional and suitable for the platform
4. Include specific visual elements, colors, mood, and composition suggestions
5. Consider what type of content this appears to be (educational, entertainment, tutorial, etc.)
Please provide:
- A clear, detailed description for the thumbnail image (2-3 sentences)
- Suggested visual style and mood
- Key elements that should be prominently featured
Focus on creating a thumbnail that would perform well and attract the target audience for this type of content.
"""
try:
response = client.chat.completions.create(
model="gpt-4",
messages=[{"role": "user", "content": prompt}],
max_tokens=300,
temperature=0.7
)
return response.choices[0].message.content.strip()
except Exception as e:
st.error(f"Error analyzing video: {str(e)}")
return None
def generate_thumbnail(description, style="professional", size="1024x1024"):
"""Generate thumbnail using DALL-E 3"""
if not client:
return None
style_prompts = {
"professional": "professional, clean, high-quality",
"creative": "creative, artistic, visually striking",
"minimalist": "minimalist, clean, simple design",
"colorful": "vibrant, colorful, eye-catching",
"dramatic": "dramatic lighting, cinematic, bold"
}
full_prompt = f"""
Create a {style_prompts[style]} YouTube-style thumbnail image: {description}
Requirements:
- 16:9 aspect ratio suitable for video thumbnails
- High contrast and bold visual elements
- Professional quality that would perform well on video platforms
- Engaging composition that draws the eye
"""
try:
response = client.images.generate(
model="dall-e-3",
prompt=full_prompt,
size=size,
quality="hd",
n=1
)
image_url = response.data[0].url
image_response = requests.get(image_url)
return Image.open(BytesIO(image_response.content))
except Exception as e:
st.error(f"Error generating thumbnail: {str(e)}")
return None
# Main interface
st.header("πŸ“₯ Input")
# Add mode selection
analysis_mode = st.radio(
"Choose input mode:",
["πŸ”— URL Analysis (Automatic)", "✍️ Manual Description (Custom)"],
help="Choose whether to analyze a video URL or create thumbnails from your own description"
)
if analysis_mode == "πŸ”— URL Analysis (Automatic)":
col1, col2 = st.columns([2, 1])
with col1:
video_url = st.text_input(
"Video URL:",
placeholder="https://youtube.com/watch?v=... or https://example.com/video.mp4",
help="Paste any video URL here"
)
with col2:
custom_description = st.text_area(
"Additional Description (Optional):",
placeholder="Add extra details about your video...",
height=100,
help="Supplement the automatic analysis with your own details"
)
else:
video_url = ""
custom_description = st.text_area(
"Describe your video content:",
placeholder="Describe what your video is about, the mood, target audience, key topics, etc. Be as detailed as possible for better thumbnails...",
height=150,
help="Provide a detailed description of your video content for AI thumbnail generation"
)
# Style and options
st.header("🎨 Customization")
col1, col2, col3 = st.columns(3)
with col1:
thumbnail_style = st.selectbox(
"Thumbnail Style:",
["professional", "creative", "minimalist", "colorful", "dramatic"],
help="Choose the visual style for your thumbnail"
)
with col2:
image_size = st.selectbox(
"Image Size:",
["1024x1024", "512x512"],
help="Higher resolution costs more but looks better"
)
with col3:
num_variations = st.slider(
"Number of Variations:",
min_value=1,
max_value=3,
value=1,
help="Generate multiple thumbnail options (DALL-E 3 generates one at a time)"
)
# Generate button
if st.button("πŸš€ Generate Thumbnail", type="primary", use_container_width=True):
if analysis_mode == "πŸ”— URL Analysis (Automatic)" and not video_url:
st.error("❌ Please enter a video URL or switch to Manual Description mode")
elif analysis_mode == "✍️ Manual Description (Custom)" and not custom_description:
st.error("❌ Please provide a description of your video content")
elif not client:
st.error("❌ Please enter your OpenAI API key in the sidebar")
else:
if analysis_mode == "πŸ”— URL Analysis (Automatic)":
# Step 1: Extract video information
with st.spinner("πŸ” Extracting video information..."):
video_info = extract_video_info(video_url)
# Display extracted information
if video_info['title'] or video_info['description'] or video_info['platform'] != 'unknown':
st.success("βœ… Video platform identified!")
with st.expander("πŸ“Š Extracted Video Information", expanded=True):
col1, col2 = st.columns(2)
with col1:
st.write("**Platform:**", video_info['platform'].title())
if video_info['id']:
st.write("**Video ID:**", video_info['id'])
if video_info['title']:
st.write("**Title:**", video_info['title'])
with col2:
if video_info['description']:
st.write("**Description:**")
st.write(video_info['description'][:200] + "..." if len(video_info['description']) > 200 else video_info['description'])
elif video_info['platform'] in ['facebook', 'instagram', 'tiktok', 'twitter']:
st.info(f"ℹ️ {video_info['platform'].title()} content detected. For best results, switch to **Manual Description mode** and describe your video content.")
# Check if we should continue with AI analysis or recommend manual mode
if video_info['platform'] in ['facebook', 'instagram', 'tiktok', 'twitter'] and not custom_description:
st.warning("πŸ”„ **Recommendation:** For social media videos, please either:")
st.write("1. Switch to **Manual Description mode** and describe your video content")
st.write("2. Or add a detailed description in the 'Additional Description' field above")
if st.button("πŸ”„ Switch to Manual Mode", key="switch_mode"):
st.rerun()
analysis = None
else:
# Step 2: Analyze video content with AI
with st.spinner("πŸ€– Analyzing video content with AI..."):
analysis = analyze_video_content(video_url, custom_description)
else:
# Manual mode - use custom description directly
st.success("βœ… Using your custom description!")
analysis_prompt = f"""
Create a detailed description for generating an engaging video thumbnail based on this video content:
{custom_description}
Please analyze this content and provide:
1. A clear, detailed description for the thumbnail image (2-3 sentences)
2. Suggested visual style and mood that matches the content
3. Key elements that should be prominently featured
4. Color palette and composition suggestions
Focus on creating a thumbnail that would grab attention and accurately represent this content.
"""
with st.spinner("πŸ€– Analyzing your description with AI..."):
try:
response = client.chat.completions.create(
model="gpt-4",
messages=[{"role": "user", "content": analysis_prompt}],
max_tokens=300,
temperature=0.7
)
analysis = response.choices[0].message.content.strip()
except Exception as e:
st.error(f"Error analyzing description: {str(e)}")
analysis = None
if analysis:
st.success("βœ… AI analysis complete!")
with st.expander("🧠 AI Content Analysis", expanded=True):
st.write(analysis)
# Step 3: Generate thumbnails
st.header("πŸ–ΌοΈ Generated Thumbnails")
for i in range(num_variations):
with st.spinner(f"🎨 Generating thumbnail {i+1}/{num_variations}..."):
# Add variation to prompt for multiple generations
varied_analysis = analysis
if num_variations > 1:
varied_analysis += f" (Create a unique visual variation #{i+1} with different composition, colors, or focus while maintaining the core message)"
thumbnail = generate_thumbnail(varied_analysis, thumbnail_style, image_size)
if thumbnail:
col1, col2 = st.columns([3, 1])
with col1:
st.image(
thumbnail,
caption=f"Thumbnail {i+1} - {thumbnail_style.title()} Style",
use_column_width=True
)
with col2:
# Download button
buffer = BytesIO()
thumbnail.save(buffer, format="PNG")
st.download_button(
label="πŸ“₯ Download",
data=buffer.getvalue(),
file_name=f"thumbnail_{i+1}_{thumbnail_style}.png",
mime="image/png",
key=f"download_{i}",
use_container_width=True
)
st.divider()
elif analysis_mode == "πŸ”— URL Analysis (Automatic)":
# Only show this error for URL mode, not when we're recommending manual mode
if not (video_info.get('platform') in ['facebook', 'instagram', 'tiktok', 'twitter'] and not custom_description):
st.error("❌ Failed to analyze content. Please try again or provide more details.")
# Information sections
st.header("ℹ️ How It Works")
col1, col2, col3 = st.columns(3)
with col1:
st.subheader("1️⃣ URL Analysis")
st.write("AI analyzes your video URL and description to understand the content")
with col2:
st.subheader("2️⃣ Content Description")
st.write("GPT-4 creates a detailed description optimized for thumbnail generation")
with col3:
st.subheader("3️⃣ Image Generation")
st.write("DALL-E 3 creates high-quality thumbnails with better prompt following")
# Supported platforms
st.header("🌐 Platform Support & Recommendations")
col1, col2 = st.columns(2)
with col1:
st.subheader("βœ… Automatic Analysis Works Well")
st.success("""
**YouTube** - Full title & description extraction
**Vimeo** - Complete metadata support
**Direct Video URLs** - Basic information extraction
**General Websites** - Title and meta description
""")
with col2:
st.subheader("πŸ”„ Use Manual Mode For")
st.info("""
**Facebook** - Requires login/blocked by anti-scraping
**Instagram** - Login required for video access
**TikTok** - Access restrictions and complex structure
**Twitter/X** - Limited public API access
**Private/Protected Videos** - Authentication required
""")
st.header("πŸ› οΈ Quick Fix for Facebook/Social Media Videos")
# Quick helper for social media users
if st.button("πŸ”„ I have a Facebook/Instagram/TikTok video - Help me!", type="secondary"):
st.balloons()
st.success("🎯 **Quick Solution for Social Media Videos:**")
st.write("1. Select **✍️ Manual Description (Custom)** mode above")
st.write("2. In the description box, tell us about your video:")
st.code("""Example template:
"[Video topic] - [what happens in video]
Target audience: [who watches this]
Mood: [fun/serious/educational/promotional]
Visual style: [colors you want/aesthetic]
Key elements: [people/objects/scenes]"
""")
st.write("3. Choose your preferred style and generate!")
st.info("πŸ’‘ This method often works **better** than automatic analysis because you know your content best!")
st.header("πŸ› οΈ How to Handle Facebook Videos")
with st.expander("πŸ“˜ Step-by-step guide for Facebook videos", expanded=True):
st.write("""
**For your Facebook video:** `https://www.facebook.com/share/v/16HtujeeH2/`
1. **Switch to Manual Description mode** (select the ✍️ option above)
2. **Describe your Facebook video content, for example:**
- What is the video about?
- What's the main topic or message?
- Who is the target audience?
- What's the mood/tone (educational, funny, serious, promotional)?
- Any key visual elements or people in the video?
3. **Example description:**
> "Educational video about sustainable farming techniques for small-scale farmers. Shows practical tips for organic gardening, water conservation, and crop rotation. Target audience is beginner gardeners and environmentally conscious people. Should have a clean, educational feel with earth tones."
4. **Generate thumbnail** - The AI will create perfect thumbnails based on your description!
""")
st.header("πŸ’‘ Pro Tips for Social Media Videos")
col1, col2 = st.columns(2)
with col1:
st.subheader("🎯 Better Descriptions")
st.info("""
**Include:**
- Video topic and main message
- Target audience (age, interests)
- Mood/tone (fun, serious, educational)
- Key visual elements or people
- Desired colors or style
""")
with col2:
st.subheader("πŸš€ Platform-Specific Styles")
st.info("""
**Facebook**: Professional or colorful styles work well
**Instagram**: Creative and colorful for better engagement
**TikTok**: Dramatic and colorful for younger audience
**Twitter**: Clean, minimalist for news/discussion content
""")
# DALL-E 3 Benefits section
st.header("🎨 DALL-E 3 Advantages")
col1, col2 = st.columns(2)
with col1:
st.info("""
βœ… **Higher Quality:** Superior image generation
βœ… **Better Prompt Following:** More accurate to descriptions
βœ… **Enhanced Details:** Sharper, more professional results
""")
with col2:
st.info("""
βœ… **HD Quality:** Crystal clear thumbnails
βœ… **Better Composition:** Superior layout and visual balance
βœ… **Text Integration:** Can include readable text elements
""")
# Pricing info
st.header("πŸ’° Cost Information")
cost_info = f"""
**OpenAI API Costs (approximate):**
- GPT-4 Analysis: ~$0.001 per video
- DALL-E 3 Image Generation: ~$0.08 per {image_size} HD image
- **Total per thumbnail:** ~$0.081 USD
*Costs may vary based on current OpenAI pricing*
"""
st.info(cost_info)
# Tips
st.header("πŸ’‘ Tips for Best Results")
col1, col2 = st.columns(2)
with col1:
st.subheader("🎯 For Better Analysis")
st.info("""
**URL Tips:**
- Use direct YouTube/Vimeo links for best results
- Make sure the video is publicly accessible
- For private videos, provide detailed descriptions
**Description Tips:**
- Include the video topic and target audience
- Mention the mood/tone (serious, fun, educational)
- Specify any key visual elements or themes
""")
with col2:
st.subheader("πŸš€ For Better Thumbnails")
st.info("""
**Style Selection:**
- **Professional**: Business, tutorials, serious content
- **Creative**: Art, design, entertainment content
- **Colorful**: Kids content, fun videos, gaming
- **Dramatic**: Action, movie trailers, intense content
- **Minimalist**: Tech, educational, clean aesthetic
""")
# Troubleshooting section
st.header("πŸ”§ Troubleshooting Common Issues")
with st.expander("❓ Why doesn't automatic analysis work for my video?"):
st.write("""
**Social Media Platforms (Facebook, Instagram, TikTok, Twitter):**
- These platforms block automated content extraction
- They require login/authentication for video access
- **Solution:** Use **Manual Description mode** instead
**YouTube/Vimeo Issues:**
- Video might be private or region-locked
- Some videos have restricted metadata
- **Solution:** Add custom description for better context
**General Website Videos:**
- Some sites block automated requests
- Limited metadata available
- **Solution:** Describe the video content manually
""")
with st.expander("πŸš€ How to get the best thumbnails?"):
st.write("""
**For Manual Descriptions:**
1. **Be Specific:** Instead of "cooking video" β†’ "Italian pasta making tutorial showing step-by-step homemade fettuccine preparation"
2. **Include Visual Details:** "Close-up shots of hands kneading dough, flour dust, kitchen setting with warm lighting"
3. **Mention Target Audience:** "For beginner home cooks and food enthusiasts"
4. **Specify Mood/Style:** "Cozy, warm atmosphere with rustic kitchen aesthetic"
5. **Color Preferences:** "Earth tones, warm yellows and browns, natural lighting"
""")
with st.expander("πŸ’° Cost concerns?"):
st.write("""
**Cost Breakdown:**
- GPT-4 Analysis: ~$0.001 per video
- DALL-E 3 Generation: ~$0.08 per HD thumbnail
- **Total:** ~$0.081 per thumbnail
**Tips to Save:**
- Generate fewer variations (1-2 instead of 3)
- Use 512x512 size if budget is tight
- Perfect your description before generating to avoid re-dos
""")
with st.expander("πŸ”’ Privacy and social media videos"):
st.write("""
**Why Manual Mode is Better for Social Media:**
- **Privacy:** No need to access private content
- **Accuracy:** You know your video better than any algorithm
- **Control:** Full control over thumbnail style and messaging
- **Speed:** No need to wait for extraction attempts
**Security:** Your video content stays private - only your description is sent to OpenAI.
""")
# Footer
st.divider()
st.markdown("""
<div style='text-align: center; color: #666;'>
<p>Built with ❀️ using Streamlit and OpenAI API (GPT-4 + DALL-E 3)</p>
</div>
""", unsafe_allow_html=True)