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 | |
st.markdown(""" | |
<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-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) | |
# Session state for content plan | |
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_actual_channel_id(youtube, channel_url): | |
"""Extract real channel ID from a handle (@username) or custom URL.""" | |
if "@" in channel_url: | |
username = channel_url.split("@")[-1] | |
request = youtube.channels().list(part="id", forHandle=username) | |
elif "channel/" in channel_url: | |
return channel_url.split("channel/")[-1] | |
else: | |
return None | |
response = request.execute() | |
if "items" in response and response["items"]: | |
return response["items"][0]["id"] | |
return None | |
def get_channel_videos(youtube, channel_id): | |
"""Fetch recent video IDs from the channel.""" | |
request = youtube.search().list( | |
part="id", | |
channelId=channel_id, | |
maxResults=min(MAX_VIDEOS, 50), # Ensure within API limit | |
order="date", | |
type="video" | |
) | |
response = request.execute() | |
return [item['id']['videoId'] for item in response.get("items", [])] | |
def get_video_comments(youtube, video_id): | |
"""Fetch comments from a video.""" | |
request = youtube.commentThreads().list( | |
part="snippet", | |
videoId=video_id, | |
maxResults=min(COMMENTS_PER_VIDEO, 100), # Ensure within API limit | |
textFormat="plainText" | |
) | |
response = request.execute() | |
return [item['snippet']['topLevelComment']['snippet']['textDisplay'] for item in response.get("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 | |
# Get channel URL | |
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: | |
youtube = googleapiclient.discovery.build("youtube", "v3", developerKey=YOUTUBE_API_KEY) | |
genai.configure(api_key=GEMINI_API_KEY) | |
with st.spinner("π Analyzing channel..."): | |
channel_id = get_actual_channel_id(youtube, channel_url) | |
if not channel_id: | |
st.error("Invalid channel URL!") | |
st.stop() | |
video_ids = get_channel_videos(youtube, channel_id) | |
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(youtube, video_id)) | |
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!") | |
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): | |
plan_lines = st.session_state.content_plan.split("\n") | |
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) | |
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" | |
) | |
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**: | |
3. **Adjust Settings**: | |
4. **Generate Plan**: | |
5. **Download & Track Results**. | |
""") | |