Spaces:
Sleeping
Sleeping
Commit
·
f3007f9
0
Parent(s):
streamlit app
Browse files- .github/workflows/check.yml +16 -0
- .github/workflows/main.yml +23 -0
- .gitignore +4 -0
- .streamlit/config.toml +2 -0
- README.md +120 -0
- app.py +205 -0
- assets/Acceptable.jpg +0 -0
- assets/Inappropriate.jpg +0 -0
- assets/Not Sexist.jpg +0 -0
- assets/Offensive.jpg +0 -0
- assets/Sexist.jpg +0 -0
- assets/Violent.jpg +0 -0
- requirements.txt +6 -0
.github/workflows/check.yml
ADDED
@@ -0,0 +1,16 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
name: Check file size
|
2 |
+
on: # or directly `on: [push]` to run the action on every push on any branch
|
3 |
+
pull_request:
|
4 |
+
branches: [main]
|
5 |
+
|
6 |
+
# to run this workflow manually from the Actions tab
|
7 |
+
workflow_dispatch:
|
8 |
+
|
9 |
+
jobs:
|
10 |
+
sync-to-hub:
|
11 |
+
runs-on: ubuntu-latest
|
12 |
+
steps:
|
13 |
+
- name: Check large files
|
14 |
+
uses: ActionsDesk/[email protected]
|
15 |
+
with:
|
16 |
+
filesizelimit: 10485760 # this is 10MB so we can sync to HF Spaces
|
.github/workflows/main.yml
ADDED
@@ -0,0 +1,23 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
name: Sync to Hugging Face hub
|
2 |
+
on:
|
3 |
+
push:
|
4 |
+
pull_request:
|
5 |
+
branches: [main]
|
6 |
+
|
7 |
+
# to run this workflow manually from the Actions tab
|
8 |
+
workflow_dispatch:
|
9 |
+
|
10 |
+
jobs:
|
11 |
+
sync-to-hub:
|
12 |
+
runs-on: ubuntu-latest
|
13 |
+
steps:
|
14 |
+
- uses: actions/checkout@v3
|
15 |
+
with:
|
16 |
+
fetch-depth: 0
|
17 |
+
lfs: true
|
18 |
+
- name: Push to hub
|
19 |
+
env:
|
20 |
+
HF_TOKEN: ${{ secrets.HF_TOKEN }}
|
21 |
+
HF_username: devanshsrivastav # your huggingface.co username here (check your profile page)
|
22 |
+
HF_space_name: GoEmotions # name of the hub space to which you want to push the model
|
23 |
+
run: git push https://$HF_username:[email protected]/spaces/$HF_username/$HF_space_name main
|
.gitignore
ADDED
@@ -0,0 +1,4 @@
|
|
|
|
|
|
|
|
|
|
|
1 |
+
.env
|
2 |
+
.DS_Store
|
3 |
+
tumai
|
4 |
+
venv
|
.streamlit/config.toml
ADDED
@@ -0,0 +1,2 @@
|
|
|
|
|
|
|
1 |
+
[theme]
|
2 |
+
base="light"
|
README.md
ADDED
@@ -0,0 +1,120 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
---
|
2 |
+
license: apache-2.0
|
3 |
+
title: GoEmotions Dashboard
|
4 |
+
sdk: streamlit
|
5 |
+
sdk_version: "1.22.0"
|
6 |
+
app_file: app.py
|
7 |
+
---
|
8 |
+
|
9 |
+
# GoEmotions Dashboard - Analyzing Emotions in Text
|
10 |
+
|
11 |
+
This is a Python script that uses Streamlit, Plotly, and the Hugging Face Inference API to create a web-based dashboard for analyzing emotions in text. Finally this dashboard is deployed on Hugging Face Spaces using GitHub Actions.
|
12 |
+
|
13 |
+
## Pre-requisites:
|
14 |
+
|
15 |
+
- Python 3.7 or higher
|
16 |
+
|
17 |
+
## Project Structure:
|
18 |
+
```dir
|
19 |
+
GoEmotions/
|
20 |
+
├── app.py
|
21 |
+
├── requirements.txt
|
22 |
+
├── .env
|
23 |
+
├── README.md
|
24 |
+
├── assets/
|
25 |
+
└── .github/workflows
|
26 |
+
```
|
27 |
+
|
28 |
+
## Setup
|
29 |
+
|
30 |
+
`Step 1` - Clone this repository to your local machine using the following command, or open the repository in GitHub Codespaces.
|
31 |
+
|
32 |
+
```bash
|
33 |
+
git clone https://github.com/devansh-srivastav/GoEmotions.git
|
34 |
+
```
|
35 |
+
|
36 |
+
`Step 2` - Navigate to the root directory of the project.
|
37 |
+
|
38 |
+
```bash
|
39 |
+
cd GoEmotions
|
40 |
+
```
|
41 |
+
|
42 |
+
`Step 3` - Create and activate a new python virtual environment: (This step can be skipped if working on GitHub Codespaces!)
|
43 |
+
|
44 |
+
```bash
|
45 |
+
python -m venv venv
|
46 |
+
```
|
47 |
+
|
48 |
+
For Windows
|
49 |
+
```bash
|
50 |
+
venv\Scripts\activate
|
51 |
+
```
|
52 |
+
|
53 |
+
For Linux/MacOS
|
54 |
+
|
55 |
+
```bash
|
56 |
+
source venv/bin/activate
|
57 |
+
```
|
58 |
+
|
59 |
+
`Step 4` - Install the required packages using pip: (This step can be skipped if working on GitHub Codespaces as it automatically installs the requirements!)
|
60 |
+
|
61 |
+
```bash
|
62 |
+
pip install -r requirements.txt
|
63 |
+
```
|
64 |
+
|
65 |
+
`Step 5`- Create a free account on the [Hugging Face website](https://huggingface.co/) and generate an API key (read).
|
66 |
+
|
67 |
+
`Step 6`
|
68 |
+
|
69 |
+
- Create a `.env` file in the root directory of the project and add your
|
70 |
+
- Hugging Face API key like this: `HF_API_KEY=<your_api_key_here>`
|
71 |
+
|
72 |
+
`Step 7` - Run the Streamlit app.
|
73 |
+
|
74 |
+
```bash
|
75 |
+
streamlit run app.py
|
76 |
+
```
|
77 |
+
|
78 |
+
or
|
79 |
+
|
80 |
+
```bash
|
81 |
+
python -m streamlit run app.py
|
82 |
+
```
|
83 |
+
|
84 |
+
- If you want to run this application on GitHub Codespaces, you will need to add the following flags to the `streamlit run` command:
|
85 |
+
|
86 |
+
```bash
|
87 |
+
python -m streamlit run app.py --server.enableCORS false --server.enableXsrfProtection false
|
88 |
+
```
|
89 |
+
|
90 |
+
## Deployment to Spaces (CI/CD)
|
91 |
+
|
92 |
+
`Step 1`
|
93 |
+
Commit your code and push it to your GitHub repository
|
94 |
+
|
95 |
+
`Step 2`
|
96 |
+
Create a new Space on Hugging Face, add it as an additional remote to git and force push your code on Spaces:
|
97 |
+
|
98 |
+
```bash
|
99 |
+
git remote add space https://huggingface.co/spaces/HF_USERNAME/SPACE_NAME
|
100 |
+
```
|
101 |
+
|
102 |
+
```bash
|
103 |
+
git push --force space main
|
104 |
+
```
|
105 |
+
|
106 |
+
`Step 3`
|
107 |
+
In the main.yml, add your Hugging Face username and Space name to the variables 'HF_username' and 'HF_space_name'
|
108 |
+
|
109 |
+
`Step 4`
|
110 |
+
Create a new API key on Hugging Face (write) and add it as a secret to your GitHub Repository naming it as 'HF_TOKEN'.
|
111 |
+
|
112 |
+
`Step 5`
|
113 |
+
Trigger the CI/CD pipeline by a push or a pull request to your main branch.
|
114 |
+
|
115 |
+
## Usage:
|
116 |
+
|
117 |
+
- A web-based dashboard will open in your default browser.
|
118 |
+
- Type or paste a text input in the text box provided.
|
119 |
+
- The dashboard will visualise the detected emotions in a set of gauges, with each gauge representing the intensity of a specific emotion category. The gauge colors are based on a predefined color map for each emotion category.
|
120 |
+
- Moreover, the dashboard will display the results from Hate Speech Analysis and Sexism Detection models.
|
app.py
ADDED
@@ -0,0 +1,205 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
import plotly.graph_objects as go
|
2 |
+
from plotly.subplots import make_subplots
|
3 |
+
import streamlit as st
|
4 |
+
import requests
|
5 |
+
import json
|
6 |
+
import os
|
7 |
+
from dotenv import load_dotenv
|
8 |
+
load_dotenv()
|
9 |
+
|
10 |
+
# AI model code
|
11 |
+
HF_API_KEY = os.getenv("HF_API_KEY")
|
12 |
+
|
13 |
+
# API_URL_ED = "https://api-inference.huggingface.co/models/j-hartmann/emotion-english-distilroberta-base" #alternate ED model(slow loading on first run)
|
14 |
+
API_URL_ED = "https://api-inference.huggingface.co/models/bhadresh-savani/bert-base-go-emotion"
|
15 |
+
API_URL_HS = "https://api-inference.huggingface.co/models/IMSyPP/hate_speech_en"
|
16 |
+
API_URL_SD = "https://api-inference.huggingface.co/models/NLP-LTU/bertweet-large-sexism-detector"
|
17 |
+
|
18 |
+
headers = {"Authorization": f"Bearer {HF_API_KEY}"}
|
19 |
+
|
20 |
+
def query(payload):
|
21 |
+
response_ED = requests.request("POST", API_URL_ED, headers=headers, json=payload)
|
22 |
+
response_HS = requests.request("POST", API_URL_HS, headers=headers, json=payload)
|
23 |
+
response_SD = requests.request("POST", API_URL_SD, headers=headers, json=payload)
|
24 |
+
return (json.loads(response_ED.content.decode("utf-8")),json.loads(response_HS.content.decode("utf-8")),json.loads(response_SD.content.decode("utf-8")))
|
25 |
+
|
26 |
+
st.set_page_config(
|
27 |
+
page_title="GoEmotions Dashboard",
|
28 |
+
layout="wide"
|
29 |
+
)
|
30 |
+
|
31 |
+
# Set page title
|
32 |
+
st.title("GoEmotions Dashboard - Analyzing Emotions in Text")
|
33 |
+
|
34 |
+
# Define color map for each emotion category
|
35 |
+
color_map = {
|
36 |
+
'admiration': ['#1f77b4', '#98df8a', '#2ca02c', '#d62728'],
|
37 |
+
'amusement': ['#ff7f0e', '#98df8a', '#2ca02c', '#d62728'],
|
38 |
+
'anger': ['#ffbb78', '#ff7f0e', '#d62728', '#bcbd22'],
|
39 |
+
'annoyance': ['#ffbb78', '#ff7f0e', '#d62728', '#bcbd22'],
|
40 |
+
'approval': ['#1f77b4', '#98df8a', '#2ca02c', '#d62728'],
|
41 |
+
'caring': ['#98df8a', '#2ca02c', '#FF69B4', '#d62728'],
|
42 |
+
'confusion': ['#ffbb78', '#ff7f0e', '#9467bd', '#d62728'],
|
43 |
+
'curiosity': ['#ffbb78', '#ff7f0e', '#9467bd', '#d62728'],
|
44 |
+
'desire': ['#2ca02c', '#ff7f0e', '#98df8a', '#d62728'],
|
45 |
+
'disappointment': ['#ffbb78', '#ff7f0e', '#d62728', '#bcbd22'],
|
46 |
+
'disapproval': ['#ffbb78', '#ff7f0e', '#d62728', '#bcbd22'],
|
47 |
+
'disgust': ['#ffbb78', '#ff7f0e', '#d62728', '#bcbd22'],
|
48 |
+
'embarrassment': ['#ffbb78', '#ff7f0e', '#9467bd', '#d62728'],
|
49 |
+
'excitement': ['#ff7f0e', '#2ca02c', '#98df8a', '#d62728'],
|
50 |
+
'fear': ['#ffbb78', '#ff7f0e', '#d62728', '#bcbd22'],
|
51 |
+
'gratitude': ['#98df8a', '#2ca02c', '#1f77b4', '#d62728'],
|
52 |
+
'grief': ['#ffbb78', '#d62728', '#bcbd22', '#ff7f0e'],
|
53 |
+
'joy': ['#ff7f0e', '#98df8a', '#2ca02c', '#d62728'],
|
54 |
+
'love': ['#FF69B4', '#98df8a', '#2ca02c', '#d62728'],
|
55 |
+
'nervousness': ['#ffbb78', '#ff7f0e', '#9467bd', '#d62728'],
|
56 |
+
'optimism': ['#98df8a', '#2ca02c', '#1f77b4', '#d62728'],
|
57 |
+
'pride': ['#98df8a', '#ff7f0e', '#1f77b4', '#d62728'],
|
58 |
+
'realization': ['#9467bd', '#ff7f0e', '#ffbb78', '#d62728'],
|
59 |
+
'relief': ['#1f77b4', '#98df8a', '#2ca02c', '#d62728'],
|
60 |
+
'remorse': ['#ffbb78', '#ff7f0e', '#d62728', '#bcbd22'],
|
61 |
+
'sadness': ['#ffbb78', '#ff7f0e', '#d62728', '#bcbd22'],
|
62 |
+
'surprise': ['#ff7f0e', '#ffbb78', '#9467bd', '#d62728'],
|
63 |
+
'neutral': ['#2ca02c', '#98df8a', '#1f77b4', '#d62728']
|
64 |
+
}
|
65 |
+
|
66 |
+
|
67 |
+
# Labels for Hate Speech Classification
|
68 |
+
label_hs = {"LABEL_0": "Acceptable", "LABEL_1": "Inappropriate", "LABEL_2": "Offensive", "LABEL_3": "Violent"}
|
69 |
+
|
70 |
+
|
71 |
+
# Define default options
|
72 |
+
|
73 |
+
default_options = [
|
74 |
+
"I'm so excited for my vacation next week!",
|
75 |
+
"I'm feeling so stressed about work.",
|
76 |
+
"I just received great news from my doctor!",
|
77 |
+
"I can't wait to see my best friend tomorrow.",
|
78 |
+
"I'm feeling so lonely and sad today."
|
79 |
+
"I'm so angry at my neighbor for being so rude.",
|
80 |
+
"You are so annoying!",
|
81 |
+
"You people from small towns are so dumb.",
|
82 |
+
"If you don't agree with me, you are a moron.",
|
83 |
+
"I hate you so much!",
|
84 |
+
"If you don't listen to me, I'll beat you up!",
|
85 |
+
]
|
86 |
+
|
87 |
+
with st.sidebar:
|
88 |
+
|
89 |
+
# Create dropdown with default options
|
90 |
+
selected_option = st.selectbox("Select a default option or enter your own text:", default_options)
|
91 |
+
|
92 |
+
# Display text input with selected option as default value
|
93 |
+
text_input = st.text_area("Enter text to analyze emotions:", value = selected_option, height=100)
|
94 |
+
|
95 |
+
# Add submit button
|
96 |
+
submit = st.button("Submit")
|
97 |
+
|
98 |
+
# If submit button is clicked
|
99 |
+
if submit:
|
100 |
+
|
101 |
+
# Call API and get predicted probabilities for each emotion category and hate speech classification
|
102 |
+
payload = {"inputs": text_input, "options": {"wait_for_model": True, "use_cache": True}}
|
103 |
+
response_ED, response_HS, response_SD = query(payload)
|
104 |
+
predicted_probabilities_ED = response_ED[0]
|
105 |
+
predicted_probabilities_HS = response_HS[0]
|
106 |
+
predicted_probabilities_SD = response_SD[0]
|
107 |
+
|
108 |
+
# Creating columns to visualize the results
|
109 |
+
ED, _, HS, __, SD = st.columns([4,1,2,1,2])
|
110 |
+
|
111 |
+
with ED:
|
112 |
+
# Get the top 4 emotion categories and their scores
|
113 |
+
top_emotions = predicted_probabilities_ED[:4]
|
114 |
+
top_scores = [e['score'] for e in top_emotions]
|
115 |
+
|
116 |
+
# Create the gauge charts for the top 4 emotion categories
|
117 |
+
fig = make_subplots(rows=2, cols=2, specs=[[{'type': 'indicator'}, {'type': 'indicator'}],
|
118 |
+
[{'type': 'indicator'}, {'type': 'indicator'}]],
|
119 |
+
vertical_spacing=0.4)
|
120 |
+
|
121 |
+
for i, emotion in enumerate(top_emotions):
|
122 |
+
# Get the emotion category, color, and normalized score for the current emotion
|
123 |
+
category = emotion['label']
|
124 |
+
color = color_map[category]
|
125 |
+
value = top_scores[i] * 100
|
126 |
+
|
127 |
+
# Calculate the row and column position for adding the trace to the subplots
|
128 |
+
row = i // 2 + 1
|
129 |
+
col = i % 2 + 1
|
130 |
+
|
131 |
+
# Add a gauge chart trace for the current emotion category
|
132 |
+
fig.add_trace(go.Indicator(
|
133 |
+
domain={'x': [0, 1], 'y': [0, 1]},
|
134 |
+
value=value,
|
135 |
+
mode="gauge+number",
|
136 |
+
title={'text': category.capitalize()},
|
137 |
+
gauge={'axis': {'range': [None, 100]},
|
138 |
+
'bar': {'color': color[3]},
|
139 |
+
'bgcolor': 'white',
|
140 |
+
'borderwidth': 2,
|
141 |
+
'bordercolor': color[1],
|
142 |
+
'steps': [{'range': [0, 33], 'color': color[0]},
|
143 |
+
{'range': [33, 66], 'color': color[1]},
|
144 |
+
{'range': [66, 100], 'color': color[2]}],
|
145 |
+
'threshold': {'line': {'color': "black", 'width': 4},
|
146 |
+
'thickness': 0.5,
|
147 |
+
'value': 50}}), row=row, col=col)
|
148 |
+
|
149 |
+
# Update the layout of the figure
|
150 |
+
fig.update_layout(height=400, margin=dict(t=50, b=5, l=0, r=0))
|
151 |
+
|
152 |
+
|
153 |
+
# Display gauge charts
|
154 |
+
st.text("")
|
155 |
+
st.text("")
|
156 |
+
st.text("")
|
157 |
+
st.subheader("Emotion Detection")
|
158 |
+
st.text("")
|
159 |
+
st.plotly_chart(fig, use_container_width=True)
|
160 |
+
|
161 |
+
with _:
|
162 |
+
st.text("")
|
163 |
+
|
164 |
+
|
165 |
+
with HS:
|
166 |
+
# Display Hate Speech Classification
|
167 |
+
hate_detection = label_hs[predicted_probabilities_HS[0]['label']]
|
168 |
+
st.text("")
|
169 |
+
st.text("")
|
170 |
+
st.text("")
|
171 |
+
st.subheader("Hate Speech Analysis")
|
172 |
+
st.text("")
|
173 |
+
st.image(f"assets/{hate_detection}.jpg", width=200)
|
174 |
+
st.text("")
|
175 |
+
st.text("")
|
176 |
+
st.markdown(f"#### The given text is: {hate_detection}")
|
177 |
+
|
178 |
+
with __:
|
179 |
+
st.text("")
|
180 |
+
|
181 |
+
with SD:
|
182 |
+
label_SD = predicted_probabilities_SD[0]['label'].title()
|
183 |
+
st.text("")
|
184 |
+
st.text("")
|
185 |
+
st.text("")
|
186 |
+
st.subheader("Sexism Detection")
|
187 |
+
st.text("")
|
188 |
+
st.image(f"assets/{label_SD}.jpg", width=200)
|
189 |
+
st.text("")
|
190 |
+
st.text("")
|
191 |
+
st.markdown(f"#### The given text is: {label_SD}")
|
192 |
+
|
193 |
+
|
194 |
+
|
195 |
+
|
196 |
+
|
197 |
+
|
198 |
+
|
199 |
+
hide_st_style = """
|
200 |
+
<style>
|
201 |
+
#MainMenu {visibility: hidden;}
|
202 |
+
footer {visibility: hidden;}
|
203 |
+
</style>
|
204 |
+
"""
|
205 |
+
st.markdown(hide_st_style, unsafe_allow_html=True)
|
assets/Acceptable.jpg
ADDED
![]() |
assets/Inappropriate.jpg
ADDED
![]() |
assets/Not Sexist.jpg
ADDED
![]() |
assets/Offensive.jpg
ADDED
![]() |
assets/Sexist.jpg
ADDED
![]() |
assets/Violent.jpg
ADDED
![]() |
requirements.txt
ADDED
@@ -0,0 +1,6 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
plotly==5.3.1
|
2 |
+
streamlit==1.22.0
|
3 |
+
requests==2.26.0
|
4 |
+
python-dotenv==0.19.1
|
5 |
+
protobuf==3.20.*
|
6 |
+
altair<5
|