Spaces:
Sleeping
Sleeping
Upload 48 files
Browse files- app.py +13 -0
- final_dataset_text_processed.csv +0 -0
- helper.py +57 -0
- home.py +48 -0
- images/.DS_Store +0 -0
- images/ASUS Zenfone 11 Ultra.jpg +0 -0
- images/Galaxy A06.jpg +0 -0
- images/Galaxy S24 Ultra.png +0 -0
- images/Galaxy S24+.jpeg +0 -0
- images/Galaxy S24.jpg +0 -0
- images/Galaxy S25 Slim.png +0 -0
- images/Galaxy S25 Ultra.png +0 -0
- images/Galaxy S25.png +0 -0
- images/Google Pixel 9.jpeg +0 -0
- images/Huawei Mate XT Ultimate.jpg +0 -0
- images/Huawei Nova Flip.png +0 -0
- images/Huawei Pura 70 Pro.png +0 -0
- images/Huawei Pura 70 Ultra.jpg +0 -0
- images/Huawei Pura 70.jpeg +0 -0
- images/Huawei Pura 80 Ultra.jpg +0 -0
- images/Infinix Zero 30.jpeg +0 -0
- images/OPPO A3x.jpg +0 -0
- images/OPPO Find X7.jpg +0 -0
- images/POCO M7 Pro 5G.png +0 -0
- images/Pixel 10 Pro.jpeg +0 -0
- images/Pixel 10.jpg +0 -0
- images/Pixel 9a.jpg +0 -0
- images/Realme 12 5G.jpg +0 -0
- images/Realme 12 Pro 5G.jpg +0 -0
- images/Realme 13 Series.jpg +0 -0
- images/Realme C61.jpeg +0 -0
- images/Redmi Note 13 5G.jpg +0 -0
- images/Redmi Note 13 Pro 5G.jpg +0 -0
- images/Redmi Note 14 Series.png +0 -0
- images/Sharp Aquos Sense 8.jpg +0 -0
- images/Tecno Spark 20c.png +0 -0
- images/Vivo V40.jpeg +0 -0
- images/Vivo X100 Pro.jpg +0 -0
- images/Xiaomi 14T Pro.jpg +0 -0
- images/Xiaomi 14T.png +0 -0
- images/Xiaomi 15 Pro.jpg +0 -0
- images/Xiaomi 15.png +0 -0
- images/iPhone 16.jpeg +0 -0
- images/iPhone 17 Air.jpg +0 -0
- images/iPhone 17.jpeg +0 -0
- images/iQOO Z8.jpeg +0 -0
- requirements.txt +13 -0
- youtube.py +22 -0
app.py
ADDED
|
@@ -0,0 +1,13 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
import streamlit as st
|
| 2 |
+
import home
|
| 3 |
+
import youtube
|
| 4 |
+
|
| 5 |
+
PAGES = {
|
| 6 |
+
"Home": home,
|
| 7 |
+
"Youtube": youtube
|
| 8 |
+
}
|
| 9 |
+
st.sidebar.title('Navigation')
|
| 10 |
+
|
| 11 |
+
selection = st.sidebar.selectbox("Go to", list(PAGES.keys()))
|
| 12 |
+
page = PAGES[selection]
|
| 13 |
+
page.app()
|
final_dataset_text_processed.csv
ADDED
|
The diff for this file is too large to render.
See raw diff
|
|
|
helper.py
ADDED
|
@@ -0,0 +1,57 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
import re
|
| 2 |
+
from dotenv import load_dotenv
|
| 3 |
+
import os
|
| 4 |
+
from googleapiclient.discovery import build
|
| 5 |
+
|
| 6 |
+
load_dotenv()
|
| 7 |
+
|
| 8 |
+
api_key = os.getenv('API_KEY')
|
| 9 |
+
youtube = build('youtube', 'v3', developerKey=api_key)
|
| 10 |
+
|
| 11 |
+
def get_all_comments(video_id):
|
| 12 |
+
comments = []
|
| 13 |
+
next_page_token = None
|
| 14 |
+
|
| 15 |
+
while True:
|
| 16 |
+
# Make API call to get comments
|
| 17 |
+
request = youtube.commentThreads().list(
|
| 18 |
+
part='snippet',
|
| 19 |
+
videoId=video_id,
|
| 20 |
+
textFormat='plainText',
|
| 21 |
+
pageToken=next_page_token # Use pagination token for next set of comments
|
| 22 |
+
)
|
| 23 |
+
|
| 24 |
+
# Execute the request
|
| 25 |
+
response = request.execute()
|
| 26 |
+
|
| 27 |
+
# Loop through the comments in the response
|
| 28 |
+
for item in response['items']:
|
| 29 |
+
comment = item['snippet']['topLevelComment']['snippet']['textDisplay']
|
| 30 |
+
author = item['snippet']['topLevelComment']['snippet']['authorDisplayName']
|
| 31 |
+
timestamp = item['snippet']['topLevelComment']['snippet']['publishedAt']
|
| 32 |
+
like_count = item['snippet']['topLevelComment']['snippet']['likeCount']
|
| 33 |
+
comments.append({
|
| 34 |
+
'author': author.strip(),
|
| 35 |
+
'comment': comment.strip(),
|
| 36 |
+
'timestamp': timestamp.strip(),
|
| 37 |
+
'like_count': like_count,
|
| 38 |
+
})
|
| 39 |
+
|
| 40 |
+
# Check if there's another page of comments (pagination)
|
| 41 |
+
next_page_token = response.get('nextPageToken')
|
| 42 |
+
|
| 43 |
+
if not next_page_token or len(comments) >= 100: # If no more pages, break the loop
|
| 44 |
+
break
|
| 45 |
+
|
| 46 |
+
return comments
|
| 47 |
+
|
| 48 |
+
def extract_youtube_id(url_or_id):
|
| 49 |
+
pattern = r'(?:v=|\/)([a-zA-Z0-9_-]{11})(?:&|$)?'
|
| 50 |
+
|
| 51 |
+
if re.fullmatch(r'[a-zA-Z0-9_-]{11}', url_or_id):
|
| 52 |
+
return url_or_id
|
| 53 |
+
|
| 54 |
+
match = re.search(pattern, url_or_id)
|
| 55 |
+
if match:
|
| 56 |
+
return match.group(1)
|
| 57 |
+
return None
|
home.py
ADDED
|
@@ -0,0 +1,48 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
import streamlit as st
|
| 2 |
+
from wordcloud import WordCloud
|
| 3 |
+
import pandas as pd
|
| 4 |
+
import matplotlib.pyplot as plt
|
| 5 |
+
from PIL import Image
|
| 6 |
+
import os
|
| 7 |
+
import re
|
| 8 |
+
import pkg_resources
|
| 9 |
+
import streamlit as st
|
| 10 |
+
|
| 11 |
+
# Get all installed packages and their versions
|
| 12 |
+
packages = {dist.project_name: dist.version for dist in pkg_resources.working_set}
|
| 13 |
+
|
| 14 |
+
# Display the packages in Streamlit
|
| 15 |
+
|
| 16 |
+
|
| 17 |
+
def app():
|
| 18 |
+
st.header('Phone Brands Sentiment Analysis', divider='rainbow')
|
| 19 |
+
data = pd.read_csv("final_dataset_text_processed.csv")
|
| 20 |
+
data.dropna(inplace=True)
|
| 21 |
+
val = st.sidebar.pills("Choose Phone Word Cloud To Show", data["tipe_produk"].unique(), selection_mode="multi")
|
| 22 |
+
st.write("Installed Packages and Versions:")
|
| 23 |
+
st.json(packages)
|
| 24 |
+
for the_value in val:
|
| 25 |
+
the_product = data[data["tipe_produk"] == the_value]
|
| 26 |
+
if not the_product.empty:
|
| 27 |
+
text_data = " ".join(data["text_processed"])
|
| 28 |
+
wordcloud = WordCloud(width=800, height=400, background_color='white').generate(text_data)
|
| 29 |
+
regex = re.compile(r"^(.*)\.[^.]+$")
|
| 30 |
+
col1, col2 = st.columns([3, 7])
|
| 31 |
+
image = None
|
| 32 |
+
|
| 33 |
+
for item in os.listdir("images"):
|
| 34 |
+
item_cleaned = regex.match(item).group(1)
|
| 35 |
+
if item_cleaned.lower().strip() == the_value.lower().strip():
|
| 36 |
+
image = Image.open(f"./images/{item}")
|
| 37 |
+
break
|
| 38 |
+
with col1:
|
| 39 |
+
if image:
|
| 40 |
+
st.write(the_value)
|
| 41 |
+
st.image(image)
|
| 42 |
+
plt.title(f"Wordcloud for phone {the_value}")
|
| 43 |
+
plt.figure(figsize=(10, 5))
|
| 44 |
+
plt.imshow(wordcloud, interpolation='bilinear')
|
| 45 |
+
plt.axis("off")
|
| 46 |
+
with col2:
|
| 47 |
+
st.write('<p style="visibility: hidden;">This is some text.</p>', unsafe_allow_html=True)
|
| 48 |
+
st.pyplot(plt)
|
images/.DS_Store
ADDED
|
Binary file (6.15 kB). View file
|
|
|
images/ASUS Zenfone 11 Ultra.jpg
ADDED
|
images/Galaxy A06.jpg
ADDED
|
images/Galaxy S24 Ultra.png
ADDED
|
images/Galaxy S24+.jpeg
ADDED
|
images/Galaxy S24.jpg
ADDED
|
images/Galaxy S25 Slim.png
ADDED
|
images/Galaxy S25 Ultra.png
ADDED
|
images/Galaxy S25.png
ADDED
|
images/Google Pixel 9.jpeg
ADDED
|
|
images/Huawei Mate XT Ultimate.jpg
ADDED
|
images/Huawei Nova Flip.png
ADDED
|
images/Huawei Pura 70 Pro.png
ADDED
|
images/Huawei Pura 70 Ultra.jpg
ADDED
|
images/Huawei Pura 70.jpeg
ADDED
|
images/Huawei Pura 80 Ultra.jpg
ADDED
|
images/Infinix Zero 30.jpeg
ADDED
|
images/OPPO A3x.jpg
ADDED
|
images/OPPO Find X7.jpg
ADDED
|
images/POCO M7 Pro 5G.png
ADDED
|
images/Pixel 10 Pro.jpeg
ADDED
|
|
images/Pixel 10.jpg
ADDED
|
|
images/Pixel 9a.jpg
ADDED
|
|
images/Realme 12 5G.jpg
ADDED
|
images/Realme 12 Pro 5G.jpg
ADDED
|
images/Realme 13 Series.jpg
ADDED
|
images/Realme C61.jpeg
ADDED
|
images/Redmi Note 13 5G.jpg
ADDED
|
images/Redmi Note 13 Pro 5G.jpg
ADDED
|
images/Redmi Note 14 Series.png
ADDED
|
images/Sharp Aquos Sense 8.jpg
ADDED
|
images/Tecno Spark 20c.png
ADDED
|
images/Vivo V40.jpeg
ADDED
|
images/Vivo X100 Pro.jpg
ADDED
|
images/Xiaomi 14T Pro.jpg
ADDED
|
images/Xiaomi 14T.png
ADDED
|
images/Xiaomi 15 Pro.jpg
ADDED
|
images/Xiaomi 15.png
ADDED
|
images/iPhone 16.jpeg
ADDED
|
images/iPhone 17 Air.jpg
ADDED
|
images/iPhone 17.jpeg
ADDED
|
images/iQOO Z8.jpeg
ADDED
|
requirements.txt
ADDED
|
@@ -0,0 +1,13 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
wordcloud==1.9.4
|
| 2 |
+
streamlit==1.40.1
|
| 3 |
+
seaborn==0.13.2
|
| 4 |
+
scikit-learn==1.5.2
|
| 5 |
+
numpy==1.26.4
|
| 6 |
+
nltk==3.9.1
|
| 7 |
+
matplotlib==3.9.2
|
| 8 |
+
joblib==1.4.2
|
| 9 |
+
google-api-python-client==2.153.0
|
| 10 |
+
google-auth==2.36.0
|
| 11 |
+
google-auth-httplib2==0.2.0
|
| 12 |
+
google-api-core==2.23.0
|
| 13 |
+
googleapis-common-protos==1.66.0
|
youtube.py
ADDED
|
@@ -0,0 +1,22 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
from helper import extract_youtube_id, get_all_comments
|
| 2 |
+
import streamlit as st
|
| 3 |
+
|
| 4 |
+
def app():
|
| 5 |
+
st.header('Phone Brands Sentiment Analysis', divider='rainbow')
|
| 6 |
+
user_input = st.text_input("Enter a youtube link for sentiment analysis")
|
| 7 |
+
if st.button('Submit', type="secondary"):
|
| 8 |
+
try:
|
| 9 |
+
the_youtube_id = extract_youtube_id(user_input)
|
| 10 |
+
if the_youtube_id:
|
| 11 |
+
with st.spinner("Please wait while we're loading the data..."):
|
| 12 |
+
the_data = get_all_comments(the_youtube_id)
|
| 13 |
+
st.write(f"Total Comments: {len(the_data)}")
|
| 14 |
+
for data in the_data:
|
| 15 |
+
st.write(data["comment"])
|
| 16 |
+
else:
|
| 17 |
+
st.write("Invalid youtube link.")
|
| 18 |
+
except:
|
| 19 |
+
st.write("Invalid youtube link.")
|
| 20 |
+
else:
|
| 21 |
+
st.write("Click the button to submit your link!")
|
| 22 |
+
|