File size: 6,855 Bytes
079430a e21f6d3 a2632d3 079430a a2632d3 e21f6d3 a2632d3 e21f6d3 a2632d3 e21f6d3 a2632d3 e21f6d3 079430a e21f6d3 a2632d3 e21f6d3 079430a e21f6d3 a2632d3 e21f6d3 a2632d3 e21f6d3 a2632d3 e21f6d3 a2632d3 e21f6d3 a2632d3 e21f6d3 a2632d3 e21f6d3 a2632d3 e21f6d3 a2632d3 079430a |
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 174 175 176 |
import gradio as gr
import pandas as pd
import yt_dlp
import os
from semantic_chunkers import StatisticalChunker
from semantic_router.encoders import HuggingFaceEncoder
from faster_whisper import WhisperModel
import spaces
# Function to download YouTube audio
def download_youtube_audio(url, output_path, preferred_quality="192"):
ydl_opts = {
'format': 'bestaudio/best', # Select best audio quality
'postprocessors': [{
'key': 'FFmpegExtractAudio',
'preferredcodec': 'mp3',
'preferredquality': preferred_quality,
}],
'outtmpl': output_path, # Specify the output path and file name
}
try:
with yt_dlp.YoutubeDL(ydl_opts) as ydl:
info_dict = ydl.extract_info(url, download=False)
video_title = info_dict.get('title', None)
print(f"Downloading audio for: {video_title}")
ydl.download([url])
print(f"Audio file saved as: {output_path}")
return output_path
except yt_dlp.utils.DownloadError as e:
print(f"Error downloading audio: {e}")
return None # Indicate failure
# Function to transcribe audio using WhisperModel
def transcribe(path, model_name):
model = WhisperModel(model_name)
print(f"Reading {path}")
segments, info = model.transcribe(path)
return segments
# Function to process segments and convert them into a DataFrame
@spaces.GPU
def process_segments(segments):
result = {}
print("Processing...")
for i, segment in enumerate(segments):
chunk_id = f"chunk_{i}"
result[chunk_id] = {
'chunk_id': segment.id,
'chunk_length': segment.end - segment.start,
'text': segment.text,
'start_time': segment.start,
'end_time': segment.end
}
df = pd.DataFrame.from_dict(result, orient='index')
df.to_csv('final.csv') # Save DataFrame to final.csv
return df
# Gradio interface functions
@spaces.GPU
def generate_transcript(youtube_url, model_name="distil-large-v3"):
path = "downloaded_audio.mp3"
download_youtube_audio(youtube_url, path)
segments = transcribe(path, model_name)
df = process_segments(segments)
lis = list(df['text'])
encoder = HuggingFaceEncoder(name="sentence-transformers/all-MiniLM-L6-v2")
chunker = StatisticalChunker(encoder=encoder, dynamic_threshold=True, min_split_tokens=30, max_split_tokens=40, window_size=2, enable_statistics=False)
chunks = chunker._chunk(lis)
row_index = 0
for i in range(len(chunks)):
for j in range(len(chunks[i].splits)):
df.at[row_index, 'chunk_id2'] = f'chunk_{i}'
row_index += 1
grouped = df.groupby('chunk_id2').agg({
'start_time': 'min',
'end_time': 'max',
'text': lambda x: ' '.join(x),
'chunk_id': list
}).reset_index()
grouped = grouped.rename(columns={'chunk_id': 'chunk_ids'})
grouped['chunk_length'] = grouped['end_time'] - grouped['start_time']
grouped['chunk_id'] = grouped['chunk_id2']
grouped = grouped.drop(columns=['chunk_id2', 'chunk_ids'])
grouped.to_csv('final.csv')
df = pd.read_csv("final.csv")
transcripts = df.to_dict(orient='records')
return transcripts
# Function to download video using yt-dlp and generate transcript HTML
def download_video(youtube_url):
# Define download options
ydl_opts = {
'format': 'mp4',
'outtmpl': 'downloaded_video.%(ext)s',
'quiet': True
}
# Extract video ID to check if already downloaded
with yt_dlp.YoutubeDL({'quiet': True}) as ydl:
info_dict = ydl.extract_info(youtube_url, download=False)
video_ext = info_dict.get('ext')
video_path = f'downloaded_video.mp4'
# Check if video already downloaded
if not os.path.exists(video_path):
# Download the video
with yt_dlp.YoutubeDL(ydl_opts) as ydl:
ydl.download([youtube_url])
# Generate HTML for the transcript
transcripts = generate_transcript(youtube_url)
transcript_html = ""
for t in transcripts:
transcript_html += f'<div class="transcript-block"><a href="#" onclick="var video = document.getElementById(\'video-player\').querySelector(\'video\'); video.currentTime={t["start_time"]}; return false;">' \
f'[{t["start_time"]:.2f} - {t["end_time"]:.2f}]<br>{t["text"]}</a></div>'
return video_path, transcript_html
# Function to search the transcript
def search_transcript(keyword):
transcripts = pd.read_csv("final.csv").to_dict(orient='records')
search_results = ""
for t in transcripts:
if keyword.lower() in t['text'].lower():
search_results += f'<div class="transcript-block"><a href="#" onclick="var video = document.getElementById(\'video-player\').querySelector(\'video\'); video.currentTime={t["start_time"]}; return false;">' \
f'[{t["start_time"]:.2f} - {t["end_time"]:.2f}]<br>{t["text"]}</a></div>'
return search_results
# CSS for styling
css = """
.fixed-video { width: 480px !important; height: 270px !important; }
.fixed-transcript { width: 480px !important; height: 270px !important; overflow-y: auto; }
.transcript-block { margin: 10px 0; padding: 10px; border: 1px solid #ddd; border-radius: 5px; background-color: #f9f9f9; }
.transcript-block a { text-decoration: none; color: #007bff; }
.transcript-block a:hover { text-decoration: underline; }
"""
# Gradio interface
with gr.Blocks(css=css) as demo:
gr.Markdown("# YouTube Video Player with Clickable Transcript")
with gr.Row():
youtube_url = gr.Textbox(label="YouTube URL", placeholder="Enter YouTube video link here")
download_button = gr.Button("Download and Display Transcript")
with gr.Row():
video = gr.Video(label="Video Player", elem_id="video-player", elem_classes="fixed-video")
transcript_display = gr.HTML(label="Transcript", elem_classes="fixed-transcript")
with gr.Row():
search_box = gr.Textbox(label="Search Transcript", placeholder="Enter keyword to search")
search_button = gr.Button("Search")
search_results_display = gr.HTML(label="Search Results", elem_classes="fixed-transcript")
# On button click, download the video and display the transcript
def display_transcript(youtube_url):
video_path, transcript_html = download_video(youtube_url)
return video_path, transcript_html
download_button.click(fn=display_transcript, inputs=youtube_url, outputs=[video, transcript_display])
# On search button click, search the transcript and display results
search_button.click(fn=search_transcript, inputs=search_box, outputs=search_results_display)
# Launch the interface
demo.launch()
|