#10. YouTube Summariser AI Workshop
Learn how to use GenAI to summarise YouTube videos released by your favourite channels over the last week, month or quarter! Send them as a recurring email too!
Forwarded this email? Subscribe here for more β¨
Welcome to the 10th edition of the 100 GenAI MVPs newsletter, a journey all about shipping 100 happy and helpful GenAI solutions, and how to build them! ππ©βπ»β¨ Together, we built a robot panda you can chat with (π award winner), a member finder for online communities (π competition winner), and many more!
Hellooo AI Alchemists! π€π§ͺβ¨
Last night, I ran my first ever AI workshop at the University of Technology Sydney as part of the Sydney AI Happy Hour Meetup run by Timothy Yang. It went so, unbelievably well.
Today, I got this email from an attendee who followed all of the exercises in the workshop to create what you see below. It was their first ever AI app:
Every time I received one of these emails last night and today, I got this deep sense that this is my why for producing these deep dives.
The way that your mind works to adapt and extend these projects is utter magic to me. I LOVE seeing what you do with them.
So thank you for sharing, all of you, truly π₯°
Are you ready to summarise YouTube videos!??
Letβs get building!
β Becca π
This is a demo of the YouTube Summariser in action. I used Streamlit to create the front-end to show the generation process, but the end product is actually the email.
Why YouTube Digests Are So Magical
YouTube is an incredible place for both learning and entertainment. But.
One minute youβre watching a video about Autonomous AI Agents, the next youβre watching a Mr Beast video about surviving 7 days in an abandoned city π
A YouTube Digest helps you deal with information overwhelm by sending yourself a curated list of videos from your favourite channels. The custom GenAI summaries lets you extract the most value from the content, by making it work for you:
π Intentional: Summarise the key points of each video so you can decide which you most want to watch.
β Actionable: Distill the video into action steps so you can apply the ideas to your life right now.
π― Applicable: Extract key ideas from a video and apply them to your personal goals.
π€― Next-Level: Convert a music video into a step-by-step choreographed routine that breaks down each dance move.
This deep dive will teach you how to achieve the first three, but do keep in mind that the last one is possible right now with the same building blocks (you just need to add one more, GPT-vision).
What you will be able to make from this deep dive
After the hour long workshop last night, one of the attendees who had never built an AI app before, generated this email by following the exercises:
You can do this too!
How to build your own GenAI YouTube Digest
I have created a Google CoLab notebook with every single step of the project broken down into small bite-sized building blocks.
You donβt need to install anything outside of the notebook. Just click the play button to run the code snippets and see the results.
You can also change the snippets, so itβs a great place to experiment. If you mess something up, just re-download the original and start again π
π Google CoLab YouTube Summariser Notebook
Iβll include all of the steps below too.
Because I love seeing what you build so much, and because I want to learn from you too, I have setup this competition:
To enter, reply to this newsletter with a link to your tutorial (or DM me on LinkedIn).
𧩠Step 1: Retrieve videos from a single YouTube Channel
If any of the code snippets below are confusing, paste them into ChatGPT and ask it to explain whatβs going on line-by-line.
1.1. Install dependencies
pip install isodate
pip install youtube-transcript-api
pip install markdown2
pip install openai
1.2. Setup your API keys
π YouTube API Key:
Log into Google Developer Cloud console.
Create a new project.
On new project dashboard, click Explore & Enable APIs.
Search for YouTube Data v3 under YouTube APIs and enable it.
Create a credential (your API key).
π OpenAI API key:
Create an OpenAI account and log in.
Click on 'API Keys' in the sidebar.
Click 'Create new secret key' and copy your API key.
π App Password:
Lets you send emails securely from your account using an app-specific password.
Log-in to your google account.
Click on 'Security'.
Click on '2-Step Verification'.
Scroll to bottom and click 'App passwords'.
Create a new app password.
youtube_api_key = "YOUR youtube_api_key"
smtp_app_password = "YOUR smtp_app_password"
openai_api_key = "YOUR openai_api_key"
1.3. Get channel ID from username
Itβs easier to get a channelβs username than the ID, and easier for humans to understand at a glance. E.g. βtimferrissβ is easier to understand than βUCznv7Vf9nBdJYvBagFdAHWwβ
from googleapiclient.discovery import build
def get_channel_id_from_username(username="timferriss"):
youtube_client = build('youtube', 'v3', developerKey=youtube_api_key)
search_response = youtube_client.search().list(
q=username,
part='snippet',
type='channel',
maxResults=1
).execute()
channel_id = search_response['items'][0]['id']['channelId']
return channel_id
channel_id = get_channel_id_from_username()
print(channel_id)
# => "UCznv7Vf9nBdJYvBagFdAHWw"
1.4. Get YouTuber details
def get_youtuber_details(username="timferriss"):
youtube_client = build('youtube', 'v3', developerKey=youtube_api_key)
channel_id = get_channel_id_from_username()
channel_response = youtube_client.channels().list(
id=channel_id,
part='snippet,contentDetails,statistics'
).execute()
channel_details = channel_response['items'][0]
return {
"channel_id": channel_id,
"channel_username": username.strip(),
"channel_name": channel_details['snippet']['title'],
"channel_description": channel_details['snippet']['description'],
"thumbnail": channel_details['snippet']['thumbnails']['medium']['url'],
"uploads_playlist_id": channel_details['contentDetails']['relatedPlaylists']['uploads']
}
get_youtuber_details()
1.5. Get the transcript for a single YouTube video
You can return the βtranscript_with_timestampsβ or the βtranscriptβ (plain text version).
from youtube_transcript_api import YouTubeTranscriptApi
def get_video_transcript(video_id):
transcript_with_timestamps = YouTubeTranscriptApi.get_transcript(video_id)
transcript = ' '.join([t['text'] for t in transcript_with_timestamps])
return transcript
print(get_video_transcript(video_id)) # A recent Tim Ferriss video transcript
1.6. Get videos published by channel over last x days
from datetime import datetime, timedelta
from isodate import parse_duration
import requests
def get_videos_from_playlist(playlist_id="UUznv7Vf9nBdJYvBagFdAHWw", days=30):
# Get the uploads playlist items
response = requests.get(f'https://www.googleapis.com/youtube/v3/playlistItems?part=snippet&playlistId={playlist_id}&maxResults=50&key={youtube_api_key}')
videos = response.json()['items']
# Filter videos from the last 'x' days and get video IDs
cutoff_date = datetime.now() - timedelta(days=days)
recent_videos = []
video_ids = []
for video in videos:
if datetime.strptime(video['snippet']['publishedAt'], '%Y-%m-%dT%H:%M:%SZ') > cutoff_date:
recent_videos.append(video)
video_ids.append(video['snippet']['resourceId']['videoId'])
# Get video durations
response = requests.get(f'https://www.googleapis.com/youtube/v3/videos?part=contentDetails&id={",".join(video_ids)}&key={youtube_api_key}')
video_durations = {video['id']: parse_duration(video['contentDetails']['duration']).total_seconds() for video in response.json()['items']}
videos = [
{
'video_id': video['snippet']['resourceId']['videoId'],
'title': video['snippet']['title'],
'description': video['snippet']['description'],
'thumbnail': video['snippet']['thumbnails']['high']['url'],
'publishedAt': video['snippet']['publishedAt'],
'transcript': get_video_transcript(video['snippet']['resourceId']['videoId']),
'duration': f"{int(video_durations[video['snippet']['resourceId']['videoId']] // 60)}m {int(video_durations[video['snippet']['resourceId']['videoId']] % 60)}s"
}
# Filter out YouTube Shorts (60 seconds or less)
for video in recent_videos
if video_durations[video['snippet']['resourceId']['videoId']] > 60
]
return videos
videos = get_videos_from_playlist()
𧩠Step 2: Summarise transcripts using GenAI
2.1. Write a prompt for summarising a transcript
πPrompt writing tips:
Prompt writing tips from OpenAI's Prompt Engineering Guide:
Write clear instructions: Describe the steps needed to complete a task. If outputs are too long, ask for brief replies and specify the format you want.
Give good examples: Find a transcript summary you really like and ask an LLM to write a prompt for recreating it. Or just paste in examples directly.
Split tasks into simpler subtasks: For example, if you want both a long and short bio to be used on different parts of the site, create a long bio first and then use that long bio to create the short one in two separate tasks.
Adopt a persona: If youβre writing AI trend summaries, tell the LLM to act as if it is an expert trends reporter.
Follow-ups: If you find yourself adding follow-up prompts to modify some part of the output, that might be a good candidate to add back into the original prompt.
You can also get good results by keeping your prompts simple and straightforward:
prompt = """
Distill the following transcript down into 5 actions you can mark as complete, as a numbered list, no other content. Please make each one practical and specific.
"""
2.2. Summarise a single transcript using your prompt and OpenAI GPT-3.5
from openai import OpenAI
def summarise_transcript(prompt, transcript):
client = OpenAI(api_key=openai_api_key)
response = client.chat.completions.create(
model="gpt-3.5-turbo-16k",
messages=[
{"role": "system", "content": prompt},
{"role": "user", "content": transcript[:70000]}
]
)
return response.choices[0].message.content
transcript = "<YOUR_TRANSCRIPT>"
print(summarise_transcript(prompt, transcript))
2.3. Summarise all of the video transcripts with your custom summary
If your transcripts are longer than the 16,000 token limit, then you might need to split them into smaller chunks before summarising. Iβve just truncated each transcript so it is about 70,000 characters, which is about 75% of the token limit give or take, just to keep this simple.
for video in videos:
print("Summarised video:")
print(summarise_transcript(prompt, video['transcript'][:70000]))
print("")
𧩠Step 3: Send an email to yourself
3.1. Create a HTML template for a single YouTube video summary
import markdown2
def generate_summarised_video_section(video, summary):
section_html = f"""
<td style="width: 50%; padding: 10px; box-sizing: border-box; vertical-align: top;">
<img src="{video['thumbnail']}" alt="thumbnail" style="width: 100%;">
<h3>π <a href="#" target="_blank">{video['title']}</a></h3>
<p>π€ AI-Generated actionables from video:</p>
<div style="font-size: 10px;">
{markdown2.markdown(summary)}
</div>
<a href="https://www.youtube.com/watch?v={video['video_id']}" target="_blank">π Watch original Video</a>
</td>
"""
return section_html
3.2. Create a list of HTML templates for all video summaries
summarised_html_sections = []
for video in videos:
summary = summarise_transcript(prompt, video['transcript'])
summarised_html_sections.append(generate_summarised_video_section(video, summary))
print(summarised_html_sections)
3.3. Create a full email template including header, banner image, summary sections and CTA
import smtplib
from email.mime.multipart import MIMEMultipart
from email.mime.text import MIMEText
sender_email = "<YOUR_EMAIL>"
subject = "π€ YouTube Video Summaries!"
def generate_email_template(sender_email, subject, summarised_sections):
# Image URL saved on Imgur
banner_url = "https://i.imgur.com/wUoeb87.gif"
rows = []
for i in range(0, len(summarised_sections), 2):
row_sections = summarised_sections[i:i+2]
row_html = '<tr>' + ''.join(row_sections) + '</tr>'
rows.append(row_html)
all_rows = ''.join(rows)
html_body = f"""
<html>
<body style="font-family: 'Roboto', sans-serif; font-size: 16px;">
<img src="{banner_url}" alt="Banner Image" style="width: 100%;"><br>
<p>These are the summaries of videos published by your fave channels this month!</p>
<table width="100%" cellspacing="0" cellpadding="0" style="border-collapse: collapse;">
{all_rows}
</table>
<footer>
<p>Sign up to <a href="fairylightsai.substack.com" target="_blank">100GenAI project newsletter</a> to learn how to build AI projects like this! β¨π€π§ͺ</p>
</footer>
</body>
</html>
"""
# Create the MIMEMultipart message
message = MIMEMultipart('related')
message['From'] = sender_email
message['Subject'] = subject
message.attach(MIMEText(html_body, 'html'))
return message
email_content = generate_email_template(sender_email, subject, summarised_html_sections)
3.4. Send the email to yourself
def send_email(sender_email, password, subscribers, subject, content):
smtp_server = "smtp.gmail.com"
smtp_port = 587 # For TLS
server = smtplib.SMTP(smtp_server, smtp_port)
server.starttls() # Start TLS encryption
try:
server.login(sender_email, password)
for receiver_email in subscribers:
# Generate a new email content for each subscriber
content['To'] = receiver_email
server.sendmail(sender_email, receiver_email, content.as_string())
print(f"Email sent successfully to {receiver_email}")
except Exception as e:
print(f"An error occurred: {e}")
finally:
server.quit()
sender_email = "<YOUR_EMAIL>"
password = smtp_app_password
subscribers = [
"<SUBSCRIBER_EMAIL>",
]
subject = "π€ AI YouTube Video Summaries!!!"
content = email_content
send_email(sender_email, password, subscribers, subject, content)
3.5. Send a recurring email to yourself
A cron job is a scheduled task that you can set up on a Unix-like operating system (such as Linux or macOS) to run commands or scripts at specified times or intervals.
To send yourself a recurring email every x number of days using a cron job, you first need to create a script or command that sends the email. Once you have the script ready, you can set up a cron job to run the script at the desired interval. For example, to send an email every 30 days, you would set up a cron job like this:
1. Open your terminal.
2. Type crontab -e
and press Enter.
3. Add the following line to the crontab file, replacing /path/to/send_email_script.py
with the actual path to your script:
0 0 */30 * * /usr/bin/python3 /path/to/send_email_script.py
This cron job will run the script at midnight on the 1st, 31st, and so on, of every month, effectively sending the email every 30 days.
Save your changes and exit the editor.
If youβve gotten this far, well done! Youβre absolutely amazing. Please send me the email you generated via LinkedIn DM. I ADORE seeing them!
Until next time,
π
To enter, reply to this newsletter with a link to your tutorial (or DM me on LinkedIn).
Moar GenAI Projects! π€π§ͺβ¨
π Here are some more projects to check out if you loved this one!