Spaces:
Sleeping
Sleeping
import streamlit as st | |
import googleapiclient.discovery | |
import google.generativeai as genai | |
from datetime import datetime, timedelta | |
# Configure page | |
st.set_page_config( | |
page_title="YouTube Content Strategist", | |
page_icon="π", | |
layout="wide", | |
initial_sidebar_state="expanded" | |
) | |
# Custom CSS styling | |
st.markdown(r""" | |
<style> | |
.header { | |
font-size: 2.5em !important; | |
color: #FF4B4B !important; | |
margin-bottom: 30px !important; | |
} | |
.sidebar .sidebar-content { | |
background-color: #F0F2F6; | |
} | |
.stProgress > div > div > div > div { | |
background-color: #FF4B4B; | |
} | |
.day-card { | |
padding: 20px; | |
border-radius: 10px; | |
box-shadow: 0 4px 6px rgba(0, 0, 0, 0.1); | |
margin-bottom: 20px; | |
background-color: white; | |
} | |
body { | |
background-image: url('https://images.unsplash.com/photo-7NT4EDSI5Ok'); | |
background-size: cover; | |
background-position: center; | |
background-repeat: no-repeat; | |
background-attachment: fixed; | |
} | |
.main > div { | |
background-color: rgba(255, 255, 255, 0.9); | |
padding: 20px; | |
border-radius: 10px; | |
} | |
</style> | |
""", unsafe_allow_html=True) | |
# Initialize session state | |
if 'content_plan' not in st.session_state: | |
st.session_state.content_plan = None | |
# Sidebar configuration | |
with st.sidebar: | |
st.header("Configuration βοΈ") | |
YOUTUBE_API_KEY = st.text_input("YouTube API Key", type="password") | |
GEMINI_API_KEY = st.text_input("Gemini API Key", type="password") | |
MAX_VIDEOS = st.slider("Max Videos to Analyze", 1, 20, 10) | |
COMMENTS_PER_VIDEO = st.slider("Comments per Video", 10, 100, 50) | |
# Main content | |
st.markdown('<div class="header">π₯ YouTube Content Strategist</div>', unsafe_allow_html=True) | |
st.write("Generate data-driven content plans using YouTube audience insights") | |
# Helper functions | |
def get_channel_id(channel_url): | |
"""Extract channel ID from URL.""" | |
if "@" in channel_url: | |
return channel_url.split("@")[-1] | |
elif "channel/" in channel_url: | |
return channel_url.split("channel/")[-1] | |
return None | |
def get_channel_videos(channel_id): | |
"""Fetch recent video IDs from the channel.""" | |
youtube = googleapiclient.discovery.build("youtube", "v3", developerKey=YOUTUBE_API_KEY) | |
request = youtube.search().list( | |
part="id", | |
channelId=channel_id, | |
maxResults=MAX_VIDEOS, | |
order="date", | |
type="video" | |
) | |
response = request.execute() | |
return [item['id']['videoId'] for item in response['items']] | |
def get_video_comments(video_id): | |
"""Fetch comments from a video.""" | |
youtube = googleapiclient.discovery.build("youtube", "v3", developerKey=YOUTUBE_API_KEY) | |
request = youtube.commentThreads().list( | |
part="snippet", | |
videoId=video_id, | |
maxResults=COMMENTS_PER_VIDEO, | |
textFormat="plainText" | |
) | |
response = request.execute() | |
return [item['snippet']['topLevelComment']['snippet']['textDisplay'] for item in response['items']] | |
def analyze_comments(comments): | |
"""Analyze comments using Gemini API and generate a content plan.""" | |
genai.configure(api_key=GEMINI_API_KEY) | |
model = genai.GenerativeModel('gemini-1.5-pro') | |
prompt = f""" | |
Analyze the following YouTube comments and generate a 10-day content plan. | |
Each day should include: | |
1. Content Topic | |
2. Objective | |
3. Format | |
4. Engagement Strategy | |
5. Success Metrics | |
Comments: | |
{comments} | |
""" | |
response = model.generate_content(prompt) | |
return response.text | |
# Analysis execution | |
channel_url = st.text_input("Enter YouTube Channel URL:", placeholder="https://www.youtube.com/@ChannelName") | |
if st.button("Generate Content Plan π"): | |
if not all([YOUTUBE_API_KEY, GEMINI_API_KEY, channel_url]): | |
st.error("Please fill all required fields!") | |
else: | |
try: | |
# Initialize APIs | |
youtube = googleapiclient.discovery.build("youtube", "v3", developerKey=YOUTUBE_API_KEY) | |
genai.configure(api_key=GEMINI_API_KEY) | |
model = genai.GenerativeModel('gemini-1.5-pro') | |
# Get channel data | |
with st.spinner("π Analyzing channel..."): | |
channel_id = get_channel_id(channel_url) | |
if not channel_id: | |
st.error("Invalid channel URL") | |
st.stop() | |
video_ids = get_channel_videos(channel_id) | |
# Get comments | |
all_comments = [] | |
progress_bar = st.progress(0) | |
for idx, video_id in enumerate(video_ids): | |
progress = (idx + 1) / len(video_ids) | |
progress_bar.progress(progress, text=f"π₯ Collecting comments from video {idx+1}/{len(video_ids)}...") | |
all_comments.extend(get_video_comments(video_id)) | |
# Generate content plan | |
with st.spinner("π§ Analyzing comments and generating plan..."): | |
content_plan = analyze_comments(all_comments) | |
st.session_state.content_plan = content_plan | |
progress_bar.empty() | |
except Exception as e: | |
st.error(f"Error: {str(e)}") | |
# Display results | |
if st.session_state.content_plan: | |
st.markdown("## π 10-Day Content Plan") | |
st.success("Here's your personalized content strategy based on audience insights!") | |
# Create date cards | |
start_date = datetime.now() | |
for day in range(10): | |
current_date = start_date + timedelta(days=day) | |
with st.expander(f"Day {day+1} - {current_date.strftime('%b %d')}", expanded=True if day==0 else False): | |
# Use .split('\n') instead of f-string splitting | |
plan_lines = st.session_state.content_plan.split('\n') | |
# Calculate start index, accounting for potential inconsistent line counts | |
start_index = day * 5 | |
if start_index + 4 < len(plan_lines): | |
st.markdown(f""" | |
<div class="day-card"> | |
<h3>{plan_lines[start_index] if start_index < len(plan_lines) else 'No Topic'}</h3> | |
<p>π― Objective: {plan_lines[start_index+1] if start_index+1 < len(plan_lines) else 'N/A'}</p> | |
<p>πΉ Format: {plan_lines[start_index+2] if start_index+2 < len(plan_lines) else 'N/A'}</p> | |
<p>π‘ Engagement Strategy: {plan_lines[start_index+3] if start_index+3 < len(plan_lines) else 'N/A'}</p> | |
<p>π Success Metrics: {plan_lines[start_index+4] if start_index+4 < len(plan_lines) else 'N/A'}</p> | |
</div> | |
""", unsafe_allow_html=True) | |
# Download button | |
st.download_button( | |
label="π₯ Download Full Plan", | |
data=st.session_state.content_plan, | |
file_name=f"content_plan_{datetime.now().strftime('%Y%m%d')}.txt", | |
mime="text/plain" | |
) | |
# Instructions | |
with st.expander("βΉοΈ How to use this tool"): | |
st.markdown(""" | |
1. **Get API Keys**: | |
- YouTube Data API: [Get it here](https://console.cloud.google.com/) | |
- Gemini API: [Get it here](https://makersuite.google.com/) | |
2. **Enter Channel URL**: | |
- Supports both channel IDs (@ChannelName) and custom URLs | |
3. **Adjust Settings**: | |
- Control number of videos/comments analyzed in sidebar | |
4. **Generate Plan**: | |
- Click the rocket button to create your strategy | |
5. **Implement & Track**: | |
- Download the plan and track performance in YouTube Analytics | |
""") |