|
|
import torch |
|
|
import gradio as gr |
|
|
import pandas as pd |
|
|
import matplotlib.pyplot as plt |
|
|
from transformers import pipeline |
|
|
from youtube_comment_downloader import YoutubeCommentDownloader |
|
|
import re |
|
|
|
|
|
analyzer = pipeline("text-classification", model="distilbert/distilbert-base-uncased-finetuned-sst-2-english") |
|
|
|
|
|
|
|
|
def extract_video_id(url): |
|
|
|
|
|
patterns = [ |
|
|
r'(?:https?://)?(?:www\.)?youtube\.com/watch\?v=([a-zA-Z0-9_-]{11})', |
|
|
r'(?:https?://)?(?:www\.)?youtube\.com/embed/([a-zA-Z0-9_-]{11})', |
|
|
r'(?:https?://)?youtu\.be/([a-zA-Z0-9_-]{11})' |
|
|
] |
|
|
|
|
|
for pattern in patterns: |
|
|
match = re.search(pattern, url) |
|
|
if match: |
|
|
return match.group(1) |
|
|
|
|
|
return None |
|
|
|
|
|
|
|
|
def fetch_comments(url, max_comments=100): |
|
|
|
|
|
video_id = extract_video_id(url) |
|
|
if not video_id: |
|
|
return None, "Invalid YouTube URL" |
|
|
|
|
|
|
|
|
downloader = YoutubeCommentDownloader() |
|
|
|
|
|
|
|
|
try: |
|
|
comments = [] |
|
|
for comment in downloader.get_comments(video_id): |
|
|
comments.append(comment["text"]) |
|
|
if len(comments) >= max_comments: |
|
|
break |
|
|
|
|
|
df = pd.DataFrame(comments, columns=["comments"]) |
|
|
return df |
|
|
|
|
|
except Exception as e: |
|
|
return None, f"Error: {str(e)}" |
|
|
|
|
|
|
|
|
def analyze_comments(video_url): |
|
|
comments_df = fetch_comments(video_url) |
|
|
|
|
|
if comments_df.empty: |
|
|
return "No comments found.", None, None |
|
|
|
|
|
|
|
|
comments_df["sentiment"] = comments_df["comments"].apply(lambda x: analyzer(x)[0]["label"]) |
|
|
|
|
|
positive_count = comments_df["sentiment"].value_counts().get("POSITIVE", 0) |
|
|
negative_count = comments_df["sentiment"].value_counts().get("NEGATIVE", 0) |
|
|
|
|
|
|
|
|
total_comments = len(comments_df) |
|
|
if total_comments > 0: |
|
|
if positive_count > negative_count: |
|
|
avg_sentiment = "Positive" |
|
|
elif negative_count > positive_count: |
|
|
avg_sentiment = "Negative" |
|
|
else: |
|
|
avg_sentiment = "Neutral" |
|
|
else: |
|
|
avg_sentiment = "Neutral" |
|
|
|
|
|
|
|
|
fig, ax = plt.subplots(figsize=(6, 6)) |
|
|
ax.pie( |
|
|
[positive_count, negative_count], |
|
|
labels=["Positive", "Negative"], |
|
|
autopct='%1.1f%%', |
|
|
colors=['#4CAF50', '#F44336'] |
|
|
) |
|
|
ax.set_title("Sentiment Distribution") |
|
|
|
|
|
|
|
|
sentiment_summary = f"Total Positive Comments: {positive_count}\nTotal Negative Comments: {negative_count}\nAverage Sentiment: {avg_sentiment}" |
|
|
|
|
|
return sentiment_summary, fig |
|
|
|
|
|
|
|
|
|
|
|
gr.close_all() |
|
|
|
|
|
demo = gr.Interface( |
|
|
fn=analyze_comments, |
|
|
inputs=[gr.Textbox(label="YouTube Video URL", placeholder="Enter YouTube video URL")], |
|
|
outputs=[ |
|
|
gr.Textbox(label="Sentiment Summary"), |
|
|
gr.Plot(label="Sentiment Pie Chart") |
|
|
], |
|
|
title="YouTube Comment Sentiment Analyzer", |
|
|
description="Analyze the sentiments of YouTube video comments and view detailed analysis." |
|
|
) |
|
|
|
|
|
demo.launch() |