App

Tue 09 December 2025
import streamlit as st
import requests
from utils.youtube_api import extract_video_id, get_video_comments
from utils.sentiment_analysis import analyze_comment_sentiment
from dotenv import load_dotenv
import os
import time

load_dotenv()

# MCP Server URL
MCP_SERVER = "http://localhost:5000"

# Page config
st.set_page_config(
    page_title="YouTube Song Comment Analyzer",
    page_icon="🎵",
    layout="wide"
)

# Custom CSS
st.markdown("""
<style>
    .stProgress > div > div > div > div {
        background-color: #1DB954;
    }
    .stTextInput > div > div > input {
        color: #1DB954;
    }
    .positive {
        color: #1DB954;
        background-color: #f0fff4;
    }
    .negative {
        color: #FF0000;
        background-color: #fff0f0;
    }
    .neutral {
        color: #CCCCCC;
        background-color: #f8f9fa;
    }
    .comment-box {
        border-radius: 8px;
        padding: 12px;
        margin: 10px 0;
        box-shadow: 0 1px 3px rgba(0,0,0,0.1);
    }
    .rating-badge {
        padding: 3px 8px;
        border-radius: 12px;
        font-weight: bold;
        font-size: 0.8em;
    }
</style>
""", unsafe_allow_html=True)

def main():
    st.title("🎵 YouTube Song Comment Analyzer")
    st.markdown("Analyze sentiment of comments on any YouTube song")

    # Initialize session state for comments if not exists
    if 'analyzed_comments' not in st.session_state:
        st.session_state.analyzed_comments = []

    if 'video_id' not in st.session_state:
        st.session_state.video_id = ""

    # Input section
    with st.form("input_form"):
        youtube_url = st.text_input("Enter YouTube Song URL", placeholder="https://www.youtube.com/watch?v=...")
        comment_limit = st.slider("Number of comments to analyze", 10, 200, 50)
        submit_button = st.form_submit_button("Analyze Comments")

    if submit_button and youtube_url:
        video_id = extract_video_id(youtube_url)

        if not video_id:
            st.error("Invalid YouTube URL. Please enter a valid YouTube video URL.")
            return

        with st.spinner("Fetching and analyzing comments..."):
            progress_bar = st.progress(0)

            # Step 1: Get comments from YouTube
            comments, error = get_video_comments(video_id, comment_limit)
            if error:
                st.error(f"Error fetching comments: {error}")
                return

            progress_bar.progress(30)

            # Step 2: Analyze sentiment
            analyzed_comments = []
            for i, comment in enumerate(comments):
                sentiment = analyze_comment_sentiment(comment['text'])
                analyzed_comments.append({
                    'song_id': video_id,
                    'author': comment['author'],
                    'comment': comment['text'],
                    'likes': comment['likes'],
                    'published_at': comment['published_at'],
                    'sentiment': sentiment['sentiment'],
                    'rating': sentiment['rating'],
                    'label': sentiment['label']
                })
                progress_bar.progress(30 + int(40 * (i + 1) / len(comments)))

            progress_bar.progress(80)

            # Step 3: Store in MongoDB via MCP
            try:
                response = requests.post(
                    f"{MCP_SERVER}/store_comments",
                    json={"comments": analyzed_comments}
                )
                if response.status_code != 200:
                    st.warning(f"Comments couldn't be saved to database: {response.json().get('message')}")
            except Exception as e:
                st.warning(f"Couldn't connect to database: {str(e)}")

            progress_bar.progress(100)
            time.sleep(0.5)
            progress_bar.empty()

            # Store in session state
            st.session_state.analyzed_comments = analyzed_comments
            st.session_state.video_id = video_id

            st.success(f"Analyzed {len(analyzed_comments)} comments for video ID: {video_id}")

    # Only show sorting and results if we have comments
    if st.session_state.analyzed_comments:
        # Sorting options - using columns for better layout
        col1, col2 = st.columns([1, 1])

        with col1:
            sort_option = st.selectbox(
                "Sort comments by",
                ["Highest Rating", "Most Positive", "Most Negative", "Most Likes", "Newest First"],
                key="sort_option"
            )

        with col2:
            display_limit = st.slider(
                "Number of comments to display",
                5, min(50, len(st.session_state.analyzed_comments)), 
                10,
                key="display_limit"
            )

        # Sort comments based on selection - doesn't trigger rerun
        if st.session_state.analyzed_comments:
            comments_to_display = st.session_state.analyzed_comments.copy()

            if sort_option == "Highest Rating":
                comments_to_display.sort(key=lambda x: x['rating'], reverse=True)
            elif sort_option == "Most Positive":
                comments_to_display.sort(key=lambda x: x['sentiment'], reverse=True)
            elif sort_option == "Most Negative":
                comments_to_display.sort(key=lambda x: x['sentiment'])
            elif sort_option == "Most Likes":
                comments_to_display.sort(key=lambda x: x['likes'], reverse=True)
            elif sort_option == "Newest First":
                comments_to_display.sort(key=lambda x: x['published_at'], reverse=True)

        # Display comments
        st.subheader("Comment Analysis Results")

        for comment in comments_to_display[:display_limit]:
            sentiment_class = comment['label']
            rating_color = "#1DB954" if comment['rating'] >= 7 else "#FF0000" if comment['rating'] <= 4 else "#FFA500"

            st.markdown(f"""
            <div class="comment-box {sentiment_class}">
                <div style="display: flex; justify-content: space-between; align-items: center; margin-bottom: 8px;">
                    <div style="font-weight: bold; font-size: 1.1em;">{comment['author']}</div>
                    <div class="rating-badge" style="background-color: {rating_color}; color: white;">
                        {comment['rating']}/10
                    </div>
                </div>
                <p style="margin: 8px 0; font-size: 0.95em;">{comment['comment']}</p>
                <div style="display: flex; justify-content: space-between; font-size: 0.8em; color: #666;">
                    <span>👍 {comment['likes']} likes</span>
                    <span class="{sentiment_class}" style="font-weight: bold;">{sentiment_class.capitalize()} sentiment ({comment['sentiment']:.2f})</span>
                    <span>{comment['published_at'][:10]}</span>
                </div>
            </div>
            """, unsafe_allow_html=True)

        # Show statistics
        positive_count = sum(1 for c in st.session_state.analyzed_comments if c['label'] == 'positive')
        negative_count = sum(1 for c in st.session_state.analyzed_comments if c['label'] == 'negative')
        neutral_count = sum(1 for c in st.session_state.analyzed_comments if c['label'] == 'neutral')

        st.markdown(f"""
        <div style="margin-top: 20px; padding: 15px; background-color: #f8f9fa; border-radius: 8px;">
            <h4 style="margin-top: 0;">Overall Sentiment Distribution</h4>
            <div style="display: flex; justify-content: space-between;">
                <span class="positive">Positive: {positive_count} ({positive_count/len(st.session_state.analyzed_comments)*100:.1f}%)</span>
                <span class="neutral">Neutral: {neutral_count} ({neutral_count/len(st.session_state.analyzed_comments)*100:.1f}%)</span>
                <span class="negative">Negative: {negative_count} ({negative_count/len(st.session_state.analyzed_comments)*100:.1f}%)</span>
            </div>
        </div>
        """, unsafe_allow_html=True)

if __name__ == '__main__':
    main()
---------------------------------------------------------------------------

ModuleNotFoundError                       Traceback (most recent call last)

Cell In[1], line 3
      1 import streamlit as st
      2 import requests
----> 3 from utils.youtube_api import extract_video_id, get_video_comments
      4 from utils.sentiment_analysis import analyze_comment_sentiment
      5 from dotenv import load_dotenv


ModuleNotFoundError: No module named 'utils'


Score: 0

Category: song comment emmiter


Mcp Server

Tue 09 December 2025
from flask import Flask, request, jsonify
from flask_cors import CORS
from pymongo import MongoClient
from dotenv import load_dotenv
import os

load_dotenv()

app = Flask(__name__)
CORS(app)

# MongoDB connection
client = MongoClient(
    os.getenv("MONGODB_URI"),
    serverSelectionTimeoutMS=5000,  # 5 second timeout
    socketTimeoutMS=30000,  # 30 second socket timeout
    connectTimeoutMS=30000  # 30 second connection timeout …

Category: song comment emmiter

Read More
Page 1 of 1