File size: 6,945 Bytes
c8c0b31
 
 
 
 
 
 
 
 
 
 
 
 
98dd4d1
 
c8c0b31
98dd4d1
 
 
 
 
 
c8c0b31
 
 
98dd4d1
c8c0b31
 
 
 
 
 
 
 
 
 
 
 
 
98dd4d1
c8c0b31
78c326c
98dd4d1
 
78c326c
98dd4d1
 
78c326c
 
98dd4d1
 
 
 
 
 
78c326c
 
98dd4d1
78c326c
 
 
 
98dd4d1
78c326c
 
 
 
98dd4d1
78c326c
98dd4d1
78c326c
 
 
 
98dd4d1
78c326c
 
 
98dd4d1
78c326c
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
c8c0b31
98dd4d1
c8c0b31
 
 
 
 
 
 
 
 
 
 
98dd4d1
c8c0b31
98dd4d1
c8c0b31
98dd4d1
 
c8c0b31
 
 
 
 
 
98dd4d1
 
c8c0b31
 
 
 
 
 
 
 
 
 
 
 
98dd4d1
c8c0b31
 
 
98dd4d1
 
6c08b31
 
98dd4d1
 
 
 
 
 
 
 
 
c92bdd2
c556d1c
 
 
 
 
 
 
 
 
 
 
 
 
 
 
98dd4d1
 
 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
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**.
    """)