import streamlit as st import pandas as pd import matplotlib.pyplot as plt from transformers import pipeline from youtube_comment_downloader import YoutubeCommentDownloader from wordcloud import WordCloud from langdetect import detect import re import yt_dlp # para futuros metadatos, pero ya no se usa aquí st.set_page_config(page_title="Análisis de Sentimientos en YouTube", layout="wide") st.markdown("## 🤖 Análisis con IA de Comentarios de YouTube") st.markdown("Descubre qué opina la gente sobre cualquier video al instante 🎯") video_url = st.text_input("🔗 Ingresa el link de un video de YouTube:") max_comments = st.slider("💬 ¿Cuántos comentarios deseas analizar?", 10, 500, 100, step=10) def extract_video_id(url): match = re.search(r"v=([a-zA-Z0-9_-]{11})", url) return match.group(1) if match else None @st.cache_data(show_spinner=False) def get_comments(video_id, max_comments=50): downloader = YoutubeCommentDownloader() comments = downloader.get_comments_from_url( f"https://www.youtube.com/watch?v={video_id}", sort_by=0 ) texts = [] for i, comment in enumerate(comments): if i >= max_comments: break texts.append(comment['text']) return texts @st.cache_resource def load_model(language): return pipeline("sentiment-analysis", model="nlptown/bert-base-multilingual-uncased-sentiment") if video_url: video_id = extract_video_id(video_url) if video_id: # ✅ Mostrar solo la miniatura y botón al video, sin el título st.image(f"https://img.youtube.com/vi/{video_id}/0.jpg", caption="Miniatura del video", width=480) st.markdown(f"[🔗 Ver en YouTube](https://www.youtube.com/watch?v={video_id})") with st.spinner("🔍 Extrayendo comentarios..."): comments = get_comments(video_id, max_comments=max_comments) st.write(f"💬 Se extrajeron **{len(comments)}** comentarios") if comments: try: idioma = detect(comments[0]) except: idioma = "desconocido" st.markdown(f"🌐 **Idioma detectado:** `{idioma}`") model = load_model(idioma) with st.spinner("🧠 Analizando sentimientos..."): results = model(comments) sentiments = [] for r in results: label = r['label'] if label in ["1 star", "2 stars"]: sentiments.append("Negativo") elif label == "3 stars": sentiments.append("Neutral") else: sentiments.append("Positivo") df = pd.DataFrame({"Comentario": comments, "Sentimiento": sentiments}) sentiment_counts = df["Sentimiento"].value_counts() total = sentiment_counts.sum() dominant = sentiment_counts.idxmax() pos = sentiment_counts.get("Positivo", 0) neutro = sentiment_counts.get("Neutral", 0) neg = sentiment_counts.get("Negativo", 0) score = (pos + 0.5 * neutro) / total st.metric("🎯 Probabilidad de éxito del video", f"{score*100:.1f} %") if score > 0.75: st.success("🚀 ¡Este video tiene alto potencial de viralidad!") elif score > 0.5: st.info("📈 Este video tiene una recepción mayormente positiva.") else: st.warning("😐 El video podría no estar siendo bien recibido.") tab1, tab2, tab3 = st.tabs(["📊 Análisis", "☁️ Palabras", "📌 Comentarios clave"]) with tab1: st.dataframe(df) fig1, ax1 = plt.subplots() sentiment_counts.plot(kind='pie', autopct='%1.1f%%', ax=ax1, ylabel="") ax1.set_title("Distribución de Sentimientos") st.pyplot(fig1) with tab2: all_text = " ".join(df["Comentario"]) wordcloud = WordCloud(width=800, height=400, background_color="white").generate(all_text) fig_wc, ax_wc = plt.subplots() ax_wc.imshow(wordcloud, interpolation='bilinear') ax_wc.axis("off") st.pyplot(fig_wc) with tab3: for tipo in ["Positivo", "Neutral", "Negativo"]: ejemplo = df[df["Sentimiento"] == tipo].head(1) if not ejemplo.empty: st.markdown(f"**{tipo}**: _{ejemplo['Comentario'].values[0]}_") csv = df.to_csv(index=False).encode('utf-8') st.download_button( label="📥 Descargar resultados como CSV", data=csv, file_name='sentimientos_youtube.csv', mime='text/csv', ) else: st.warning("No se pudieron extraer comentarios.") else: st.error("❌ El link no es válido. Asegúrate de que sea un enlace de YouTube con el parámetro `v=`.")