Brunohdez commited on
Commit
e4586df
·
verified ·
1 Parent(s): 4781423

Update app.py

Browse files
Files changed (1) hide show
  1. app.py +56 -45
app.py CHANGED
@@ -6,6 +6,8 @@ from youtube_comment_downloader import YoutubeCommentDownloader
6
  from wordcloud import WordCloud
7
  from langdetect import detect
8
  import re
 
 
9
 
10
  st.set_page_config(page_title="Análisis de Sentimientos en YouTube", layout="wide")
11
 
@@ -36,21 +38,33 @@ def get_comments(video_id, max_comments=50):
36
 
37
  @st.cache_resource
38
  def load_model(language):
39
- if language == "es":
40
- return pipeline("sentiment-analysis", model="nlptown/bert-base-multilingual-uncased-sentiment") # multilingüe
41
- else:
42
- return pipeline("sentiment-analysis", model="nlptown/bert-base-multilingual-uncased-sentiment") # fallback
 
 
 
 
 
 
 
 
 
 
43
 
44
  if video_url:
45
  video_id = extract_video_id(video_url)
46
 
47
  if video_id:
48
- # 🎞️ Miniatura del video
49
  st.image(f"https://img.youtube.com/vi/{video_id}/0.jpg", caption="Miniatura del video", width=480)
 
 
50
 
51
  with st.spinner("🔍 Extrayendo comentarios..."):
52
  comments = get_comments(video_id, max_comments=max_comments)
53
-
54
  st.write(f"💬 Se extrajeron **{len(comments)}** comentarios")
55
 
56
  if comments:
@@ -61,7 +75,7 @@ if video_url:
61
  idioma = "desconocido"
62
  st.markdown(f"🌐 **Idioma detectado:** `{idioma}`")
63
 
64
- # Cargar modelo adecuado
65
  model = load_model(idioma)
66
 
67
  with st.spinner("🧠 Analizando sentimientos..."):
@@ -79,25 +93,15 @@ if video_url:
79
 
80
  df = pd.DataFrame({"Comentario": comments, "Sentimiento": sentiments})
81
 
82
- # Mostrar resumen
83
- st.subheader("📊 Resumen de Resultados")
84
  sentiment_counts = df["Sentimiento"].value_counts()
85
  total = sentiment_counts.sum()
86
  dominant = sentiment_counts.idxmax()
87
- st.markdown(f"**Sentimiento predominante:** `{dominant}`")
88
-
89
- if dominant == "Positivo":
90
- st.balloons()
91
- elif dominant == "Negativo":
92
- st.error("⚠️ Hay una gran cantidad de comentarios negativos.")
93
- else:
94
- st.info("🟡 Los comentarios son mayormente neutros.")
95
-
96
- # 🎯 Predicción de éxito del video
97
  pos = sentiment_counts.get("Positivo", 0)
98
  neutro = sentiment_counts.get("Neutral", 0)
99
  neg = sentiment_counts.get("Negativo", 0)
100
  score = (pos + 0.5 * neutro) / total
 
101
  st.metric("🎯 Probabilidad de éxito del video", f"{score*100:.1f} %")
102
  if score > 0.75:
103
  st.success("🚀 ¡Este video tiene alto potencial de viralidad!")
@@ -106,32 +110,39 @@ if video_url:
106
  else:
107
  st.warning("😐 El video podría no estar siendo bien recibido.")
108
 
109
- # Mostrar tabla
110
- st.dataframe(df)
111
-
112
- # Gráfico de pastel
113
- fig1, ax1 = plt.subplots()
114
- sentiment_counts.plot(kind='pie', autopct='%1.1f%%', ax=ax1, ylabel="")
115
- ax1.set_title("Distribución de Sentimientos")
116
- st.pyplot(fig1)
117
-
118
- # Wordcloud
119
- st.subheader("☁️ Palabras más frecuentes")
120
- all_text = " ".join(df["Comentario"])
121
- wordcloud = WordCloud(width=800, height=400, background_color="white").generate(all_text)
122
- fig_wc, ax_wc = plt.subplots()
123
- ax_wc.imshow(wordcloud, interpolation='bilinear')
124
- ax_wc.axis("off")
125
- st.pyplot(fig_wc)
126
-
127
- # Comentarios destacados
128
- st.subheader("📌 Comentarios representativos")
129
- for tipo in ["Positivo", "Neutral", "Negativo"]:
130
- ejemplo = df[df["Sentimiento"] == tipo].head(1)
131
- if not ejemplo.empty:
132
- st.markdown(f"**{tipo}**: _{ejemplo['Comentario'].values[0]}_")
133
-
134
- # Botón para descargar CSV
 
 
 
 
 
 
 
135
  csv = df.to_csv(index=False).encode('utf-8')
136
  st.download_button(
137
  label="📥 Descargar resultados como CSV",
 
6
  from wordcloud import WordCloud
7
  from langdetect import detect
8
  import re
9
+ import requests
10
+ from bs4 import BeautifulSoup
11
 
12
  st.set_page_config(page_title="Análisis de Sentimientos en YouTube", layout="wide")
13
 
 
38
 
39
  @st.cache_resource
40
  def load_model(language):
41
+ return pipeline("sentiment-analysis", model="nlptown/bert-base-multilingual-uncased-sentiment")
42
+
43
+ @st.cache_resource
44
+ def load_summarizer():
45
+ return pipeline("summarization", model="sshleifer/distilbart-cnn-12-6")
46
+
47
+ def get_video_title(video_id):
48
+ url = f"https://www.youtube.com/watch?v={video_id}"
49
+ response = requests.get(url)
50
+ soup = BeautifulSoup(response.text, "html.parser")
51
+ title_tag = soup.find("title")
52
+ if title_tag:
53
+ return title_tag.text.replace("- YouTube", "").strip()
54
+ return "Título no encontrado"
55
 
56
  if video_url:
57
  video_id = extract_video_id(video_url)
58
 
59
  if video_id:
60
+ title = get_video_title(video_id)
61
  st.image(f"https://img.youtube.com/vi/{video_id}/0.jpg", caption="Miniatura del video", width=480)
62
+ st.markdown(f"### 📺 {title}")
63
+ st.markdown(f"[🔗 Ver en YouTube](https://www.youtube.com/watch?v={video_id})")
64
 
65
  with st.spinner("🔍 Extrayendo comentarios..."):
66
  comments = get_comments(video_id, max_comments=max_comments)
67
+
68
  st.write(f"💬 Se extrajeron **{len(comments)}** comentarios")
69
 
70
  if comments:
 
75
  idioma = "desconocido"
76
  st.markdown(f"🌐 **Idioma detectado:** `{idioma}`")
77
 
78
+ # Modelo de sentimiento
79
  model = load_model(idioma)
80
 
81
  with st.spinner("🧠 Analizando sentimientos..."):
 
93
 
94
  df = pd.DataFrame({"Comentario": comments, "Sentimiento": sentiments})
95
 
96
+ # 🎯 Predicción de éxito del video
 
97
  sentiment_counts = df["Sentimiento"].value_counts()
98
  total = sentiment_counts.sum()
99
  dominant = sentiment_counts.idxmax()
 
 
 
 
 
 
 
 
 
 
100
  pos = sentiment_counts.get("Positivo", 0)
101
  neutro = sentiment_counts.get("Neutral", 0)
102
  neg = sentiment_counts.get("Negativo", 0)
103
  score = (pos + 0.5 * neutro) / total
104
+
105
  st.metric("🎯 Probabilidad de éxito del video", f"{score*100:.1f} %")
106
  if score > 0.75:
107
  st.success("🚀 ¡Este video tiene alto potencial de viralidad!")
 
110
  else:
111
  st.warning("😐 El video podría no estar siendo bien recibido.")
112
 
113
+ # 🧠 Resumen automático (usando comentarios)
114
+ with st.spinner("📝 Generando resumen..."):
115
+ summarizer = load_summarizer()
116
+ resumen_input = " ".join(df["Comentario"].tolist())[:1000] # limit input size
117
+ resumen = summarizer(resumen_input, max_length=60, min_length=15, do_sample=False)[0]['summary_text']
118
+ st.subheader("🧠 Resumen automático de los comentarios")
119
+ st.markdown(f"_{resumen}_")
120
+
121
+ # 🧱 Organización con pestañas
122
+ tab1, tab2, tab3 = st.tabs(["📊 Análisis", "☁️ Palabras", "📌 Comentarios clave"])
123
+
124
+ with tab1:
125
+ st.dataframe(df)
126
+ fig1, ax1 = plt.subplots()
127
+ sentiment_counts.plot(kind='pie', autopct='%1.1f%%', ax=ax1, ylabel="")
128
+ ax1.set_title("Distribución de Sentimientos")
129
+ st.pyplot(fig1)
130
+
131
+ with tab2:
132
+ all_text = " ".join(df["Comentario"])
133
+ wordcloud = WordCloud(width=800, height=400, background_color="white").generate(all_text)
134
+ fig_wc, ax_wc = plt.subplots()
135
+ ax_wc.imshow(wordcloud, interpolation='bilinear')
136
+ ax_wc.axis("off")
137
+ st.pyplot(fig_wc)
138
+
139
+ with tab3:
140
+ for tipo in ["Positivo", "Neutral", "Negativo"]:
141
+ ejemplo = df[df["Sentimiento"] == tipo].head(1)
142
+ if not ejemplo.empty:
143
+ st.markdown(f"**{tipo}**: _{ejemplo['Comentario'].values[0]}_")
144
+
145
+ # Descargar CSV
146
  csv = df.to_csv(index=False).encode('utf-8')
147
  st.download_button(
148
  label="📥 Descargar resultados como CSV",