cal commited on
Commit
cf93474
·
1 Parent(s): 3c9f5a5

new app file

Browse files
Files changed (1) hide show
  1. src/streamlit_app.py +135 -38
src/streamlit_app.py CHANGED
@@ -1,40 +1,137 @@
1
- import altair as alt
2
- import numpy as np
3
- import pandas as pd
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
4
  import streamlit as st
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
5
 
6
- """
7
- # Welcome to Streamlit!
8
-
9
- Edit `/streamlit_app.py` to customize this app to your heart's desire :heart:.
10
- If you have any questions, checkout our [documentation](https://docs.streamlit.io) and [community
11
- forums](https://discuss.streamlit.io).
12
-
13
- In the meantime, below is an example of what you can do with just a few lines of code:
14
- """
15
-
16
- num_points = st.slider("Number of points in spiral", 1, 10000, 1100)
17
- num_turns = st.slider("Number of turns in spiral", 1, 300, 31)
18
-
19
- indices = np.linspace(0, 1, num_points)
20
- theta = 2 * np.pi * num_turns * indices
21
- radius = indices
22
-
23
- x = radius * np.cos(theta)
24
- y = radius * np.sin(theta)
25
-
26
- df = pd.DataFrame({
27
- "x": x,
28
- "y": y,
29
- "idx": indices,
30
- "rand": np.random.randn(num_points),
31
- })
32
-
33
- st.altair_chart(alt.Chart(df, height=700, width=700)
34
- .mark_point(filled=True)
35
- .encode(
36
- x=alt.X("x", axis=None),
37
- y=alt.Y("y", axis=None),
38
- color=alt.Color("idx", legend=None, scale=alt.Scale()),
39
- size=alt.Size("rand", legend=None, scale=alt.Scale(range=[1, 150])),
40
- ))
 
1
+ # app.py
2
+ import os
3
+ os.environ["CUDA_VISIBLE_DEVICES"] = "-1"
4
+ os.environ['HUGGINGFACE_HUB_CACHE'] = '/data/.cache/huggingface'
5
+ # 2. For Streamlit's own cache/config directory
6
+ # This tells Streamlit to put its internal cache and config files here.
7
+ os.environ['STREAMLIT_SERVER_BROWSER_CACHE_PATH'] = '/tmp/.streamlit_cache'
8
+ # You might also consider setting these if the above is not enough:
9
+ # os.environ['STREAMLIT_SERVER_LIB_CACHE_PATH'] = '/tmp/.streamlit_lib_cache'
10
+ # os.environ['STREAMLIT_SERVER_STATIC_CACHE_PATH'] = '/tmp/.streamlit_static_cache'
11
+
12
+ # 3. For Matplotlib configuration/cache
13
+ # This tells Matplotlib to put its config and cache in a writable /tmp subfolder.
14
+ os.environ['MPLCONFIGDIR'] = '/data/.config/matplotlib'
15
+
16
+ # 4. Optional: To silence the TensorFlow oneDNN warnings if you don't need them
17
+ # This doesn't fix a core error, but cleans up logs.
18
+ os.environ['TF_ENABLE_ONEDNN_OPTS'] = '0'
19
+
20
  import streamlit as st
21
+ from googleapiclient.discovery import build
22
+ from transformers import pipeline
23
+ import pandas as pd
24
+
25
+ st.set_page_config(page_title="YouTube Comment Sentiment Analyzer", layout="wide")
26
+
27
+ # --- Configuration ---
28
+ # Get API Key from Hugging Face Space Secrets
29
+ YOUTUBE_API_KEY = os.environ.get("YOUTUBE_API_KEY")
30
+
31
+ if not YOUTUBE_API_KEY:
32
+ st.error("YouTube API Key not found. Please set it as a secret in your Hugging Face Space settings.")
33
+ st.stop()
34
+
35
+ # Initialize YouTube Data API client
36
+ youtube = build('youtube', 'v3', developerKey=YOUTUBE_API_KEY)
37
+
38
+ # Initialize sentiment analysis pipeline
39
+ # You can choose other models, e.g., "cardiffnlp/twitter-roberta-base-sentiment-latest"
40
+ @st.cache_resource
41
+ def load_sentiment_model():
42
+ return pipeline("sentiment-analysis", model="sshleifer/tiny-distilbert-base-uncased-finetuned-sst-2-english")
43
+ truncation=True
44
+
45
+ sentiment_analyzer = load_sentiment_model()
46
+
47
+ def get_video_id(youtube_url):
48
+ """Extracts video ID from a YouTube URL."""
49
+ # ... your implementation ...
50
+ if "youtube.com/watch?v=" in youtube_url:
51
+ return youtube_url.split("v=")[1].split("&")[0]
52
+ elif "youtu.be/" in youtube_url:
53
+ return youtube_url.split("youtu.be/")[1].split("?")[0]
54
+ return None
55
+
56
+
57
+ def get_comments(video_id, max_results=100):
58
+ """Fetches comments for a given video ID."""
59
+ comments = []
60
+ # ... your implementation ...
61
+ try:
62
+ request = youtube.commentThreads().list(
63
+ part="snippet",
64
+ videoId=video_id,
65
+ textFormat="plainText",
66
+ maxResults=min(100, max_results)
67
+ )
68
+ response = request.execute()
69
+ for item in response['items']:
70
+ comment = item['snippet']['topLevelComment']['snippet']['textDisplay']
71
+ comments.append(comment)
72
+ # Add pagination logic if needed for > 100 comments
73
+ except Exception as e:
74
+ st.error(f"Error fetching comments: {e}")
75
+ return []
76
+ return comments
77
+
78
+ # --- Streamlit UI (Uncomment/Reintroduce these) ---
79
+
80
+ st.title("📹 YouTube Comment Sentiment Analyzer")
81
+ st.markdown("Enter a YouTube video link to analyze the sentiment of its comments.")
82
+
83
+ youtube_link = st.text_input("YouTube Video Link:", placeholder="e.g., https://www.youtube.com/watch?v=dQw4w9WgXcQ")
84
+
85
+ if st.button("Analyze Comments"):
86
+ if not youtube_link:
87
+ st.warning("Please enter a YouTube video link.")
88
+ else:
89
+ video_id = get_video_id(youtube_link)
90
+ if not video_id:
91
+ st.error("Invalid YouTube link. Please ensure it's a valid video URL.")
92
+ else:
93
+ with st.spinner("Fetching comments and analyzing sentiment..."):
94
+ try:
95
+ # Fetch up to 200 comments, adjust as needed
96
+ comments = get_comments(video_id, max_results=200)
97
+ if not comments:
98
+ st.info("No comments found for this video, or comments are disabled.")
99
+ else:
100
+ st.subheader(f"Analyzing {len(comments)} comments:")
101
+ sentiments = []
102
+ for i, comment in enumerate(comments):
103
+ result = sentiment_analyzer(comment)[0]
104
+ label = result['label']
105
+ score = result['score']
106
+ sentiments.append({"Comment": comment, "Sentiment": label, "Score": f"{score:.2f}"})
107
+
108
+ df = pd.DataFrame(sentiments)
109
+ st.dataframe(df, height=300)
110
+
111
+ st.write("Unique Sentiment Labels found:")
112
+ st.write(df['Sentiment'].unique())
113
+ st.write("First 5 rows of sentiments DataFrame:")
114
+ st.dataframe(df.head())
115
+
116
+ pos_count = df[df['Sentiment'] == 'LABEL_1'].shape[0]
117
+ neg_count = df[df['Sentiment'] == 'LABEL_0'].shape[0]
118
+
119
+ total_analyzed = len(comments)
120
+ if total_analyzed > 0:
121
+ st.subheader("Overall Sentiment Breakdown:")
122
+ col1, col2, col3 = st.columns(3)
123
+ with col1:
124
+ st.metric("Positive Comments", f"{pos_count} ({pos_count/total_analyzed:.1%})")
125
+ with col2:
126
+ st.metric("Negative Comments", f"{neg_count} ({neg_count/total_analyzed:.1%})")
127
+ with col3:
128
+ st.metric("Total Comments Analyzed", total_analyzed)
129
+
130
+ st.success("Analysis complete!")
131
 
132
+ except Exception as e:
133
+ st.error(f"An error occurred during analysis: {e}. Please check the video link or your API key.")
134
+ if "disabled comments" in str(e).lower():
135
+ st.info("Comments might be disabled for this video.")
136
+ elif "quota" in str(e).lower():
137
+ st.info("You might have hit your YouTube Data API daily quota.")