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'
([^<]+)',
r'"title":"([^"]+)"',
r'([^<]+)',
r'([^<]+)',
r' 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("""
Built with â¤ī¸ using Streamlit and OpenAI API (GPT-4 + DALL-E 3)
""", unsafe_allow_html=True)