Spaces:
Runtime error
Runtime error
Update app.py
Browse files
app.py
CHANGED
@@ -8,99 +8,6 @@ import time
|
|
8 |
import gradio as gr
|
9 |
import tweepy
|
10 |
|
11 |
-
# The HTML body used for the WatchTower page
|
12 |
-
html_body = '''
|
13 |
-
<!-- Header -->
|
14 |
-
<header class="w3-display-container w3-content w3-wide" style="max-width:1500px;" id="home">
|
15 |
-
<img class="w3-image" src="https://www.jamesstevenson.me/wp-content/uploads/2022/08/Copy-of-WatchTower-1.png" alt="Architecture" width="1500" height="800">
|
16 |
-
<div class="w3-display-middle w3-margin-top w3-center">
|
17 |
-
<h1 class="w3-xxlarge w3-text-white"><span class="w3-padding w3-black w3-opacity-min"><b>WATCH</b></span> <span class="w3-hide-small w3-text-dark-grey">Tower</span></h1>
|
18 |
-
</div>
|
19 |
-
</header>
|
20 |
-
<!-- Container (About Section) -->
|
21 |
-
<div class="w3-content w3-container w3-padding-64" id="about">
|
22 |
-
<p class="w3-center"><em>To get started using WatchTower go to the 'Getting Started' tab, authenticate with Twitter, customise your confidence tolerance (the lower the score the less confident WatchTower is that the users will be extremist), and run WatchTower.</p><br><br>
|
23 |
-
<h3 class="w3-center">Block Violent Content Before It Reaches Your Feed</h3>
|
24 |
-
<p class="w3-center"><em>WatchTower identifies, blocks, and filters out violent and radical content before it reaches your Twitter feed.
|
25 |
-
</em></p>
|
26 |
-
<br>
|
27 |
-
<p>WatchTower works to protect you from violent, misinformation, hate speech and other malicious communication by using a suite of machine learning models to identify user accounts that post content that commonly falls into these categories. WatchTower is broken down into two components, the first utilises the Twitter streaming API and applies a suite of machine learning models to identify users that commonly post malicious information, while the second element provides a web UI where users can authenticaate with Twitter and tailor the types and thresholds for the accounts they block. </p>
|
28 |
-
<br>
|
29 |
-
<p> WatchTower was developed solely by James Stevenson and uses Pinpoint, a machine learning model also developed by James. The future roadmap sees WatchTower incorporate other models for identifying content such as misinformation and hate speech. More on Pinpoint and the model WatchTower uses to identify violent extremism can be seen below. To get started using WatchTower go to the 'Getting Started' tab, authenticate with Twitter, customise your confidence tolerance (the lower the score the less confident WatchTower is that the users will be extremist), and run WatchTower.</p>
|
30 |
-
<p class="w3-large w3-center w3-padding-16">Model Accuracy:</p>
|
31 |
-
<p class="w3-center"><em>Machine learning models can be validated based on several statistics. These statistics for Pinpoint the main ML model used by WatchTower can be seen below. </p>
|
32 |
-
<br>
|
33 |
-
<p class="w3-wide"><i class="fa fa-camera"></i>Accuracy</p>
|
34 |
-
<div class="w3-light-grey">
|
35 |
-
<div class="w3-container w3-padding-small w3-dark-grey w3-center" style="width:82%">82%</div>
|
36 |
-
</div>
|
37 |
-
<p class="w3-wide"><i class="fa fa-laptop"></i>Recall</p>
|
38 |
-
<div class="w3-light-grey">
|
39 |
-
<div class="w3-container w3-padding-small w3-dark-grey w3-center" style="width:67%">67%</div>
|
40 |
-
</div>
|
41 |
-
<p class="w3-wide"><i class="fa fa-photo"></i>Precision</p>
|
42 |
-
<div class="w3-light-grey">
|
43 |
-
<div class="w3-container w3-padding-small w3-dark-grey w3-center" style="width:73%">73%</div>
|
44 |
-
</div>
|
45 |
-
<p class="w3-wide"><i class="fa fa-photo"></i>F-Measure</p>
|
46 |
-
<div class="w3-light-grey">
|
47 |
-
<div class="w3-container w3-padding-small w3-dark-grey w3-center" style="width:70%">70%</div>
|
48 |
-
</div>
|
49 |
-
</div>
|
50 |
-
<div class="w3-row w3-center w3-dark-grey w3-padding-16">
|
51 |
-
<div class="w3-quarter w3-section">
|
52 |
-
</div>
|
53 |
-
</div>
|
54 |
-
<br>
|
55 |
-
<!-- Container (Portfolio Section) -->
|
56 |
-
<div class="w3-content w3-container w3-padding-64" id="portfolio">
|
57 |
-
<h3 class="w3-center">Chirp Development Challenge 2022</h3>
|
58 |
-
<p class="w3-center"><em>WatchTower was developed for the Chirp 2022 Twitter API Developer Challenge</em></p>
|
59 |
-
</div><p> Watchtower was developed solely by James Stevenson for the Chirp 2022 Twitter API Developer Challenge. More infomration of this can be found below.</p>
|
60 |
-
<br>
|
61 |
-
<img class="w3-image" src="https://cdn.cms-twdigitalassets.com/content/dam/developer-twitter/redesign-2021-images/blog2022/chirp/Dev-challenge.jpg.twimg.1920.jpg" alt="Architecture" width="1500" height="800">
|
62 |
-
<br>
|
63 |
-
<!-- Modal for full size images on click-->
|
64 |
-
<div id="modal01" class="w3-modal w3-black" onclick="this.style.display='none'">
|
65 |
-
<span class="w3-button w3-large w3-black w3-display-topright" title="Close Modal Image"><i class="fa fa-remove"></i></span>
|
66 |
-
<div class="w3-modal-content w3-animate-zoom w3-center w3-transparent w3-padding-64">
|
67 |
-
<img id="img01" class="w3-image">
|
68 |
-
<p id="caption" class="w3-opacity w3-large"></p>
|
69 |
-
</div>
|
70 |
-
</div>
|
71 |
-
|
72 |
-
<script>
|
73 |
-
// Modal Image Gallery
|
74 |
-
function onClick(element) {
|
75 |
-
document.getElementById("img01").src = element.src;
|
76 |
-
document.getElementById("modal01").style.display = "block";
|
77 |
-
var captionText = document.getElementById("caption");
|
78 |
-
captionText.innerHTML = element.alt;
|
79 |
-
}
|
80 |
-
// Change style of navbar on scroll
|
81 |
-
window.onscroll = function() {myFunction()};
|
82 |
-
function myFunction() {
|
83 |
-
var navbar = document.getElementById("myNavbar");
|
84 |
-
if (document.body.scrollTop > 100 || document.documentElement.scrollTop > 100) {
|
85 |
-
navbar.className = "w3-bar" + " w3-card" + " w3-animate-top" + " w3-white";
|
86 |
-
} else {
|
87 |
-
navbar.className = navbar.className.replace(" w3-card w3-animate-top w3-white", "");
|
88 |
-
}
|
89 |
-
}
|
90 |
-
// Used to toggle the menu on small screens when clicking on the menu button
|
91 |
-
function toggleFunction() {
|
92 |
-
var x = document.getElementById("navDemo");
|
93 |
-
if (x.className.indexOf("w3-show") == -1) {
|
94 |
-
x.className += " w3-show";
|
95 |
-
} else {
|
96 |
-
x.className = x.className.replace(" w3-show", "");
|
97 |
-
}
|
98 |
-
}
|
99 |
-
</script>
|
100 |
-
</body>
|
101 |
-
</html>
|
102 |
-
'''
|
103 |
-
|
104 |
# Twitter keys
|
105 |
consumer_token = os.getenv('CONSUMER_TOKEN')
|
106 |
consumer_secret = os.getenv('CONSUMER_SECRET')
|
@@ -108,12 +15,20 @@ my_access_token = os.getenv('ACCESS_TOKEN')
|
|
108 |
my_access_secret = os.getenv('ACCESS_SECRET')
|
109 |
bearer = os.getenv('BEARER')
|
110 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
111 |
# Setup the gradio block and add some generic CSS
|
112 |
-
block = gr.Blocks(css="
|
113 |
|
114 |
# Chat history variable used for the chatbot prompt on the 'getting started' page.
|
115 |
chat_history = []
|
116 |
|
|
|
117 |
def get_client_from_tokens(oauth_verifier, oauth_token):
|
118 |
'''
|
119 |
This function is used for generating a Tweepy client object based on Oauth verifier and token paramiters
|
@@ -123,7 +38,7 @@ def get_client_from_tokens(oauth_verifier, oauth_token):
|
|
123 |
'''
|
124 |
new_oauth1_user_handler = tweepy.OAuth1UserHandler(
|
125 |
consumer_token, consumer_secret,
|
126 |
-
callback="https://hf.space/embed/User1342/WatchTower/"
|
127 |
)
|
128 |
new_oauth1_user_handler.request_token = {
|
129 |
"oauth_token": oauth_token,
|
@@ -174,7 +89,7 @@ def block_users(client, threshold, dataset):
|
|
174 |
|
175 |
finished = False
|
176 |
while not finished:
|
177 |
-
|
178 |
try:
|
179 |
print("preparing to block {}".format(user_id))
|
180 |
client.block(target_user_id=user_id)
|
@@ -183,7 +98,7 @@ def block_users(client, threshold, dataset):
|
|
183 |
print("time out error")
|
184 |
print(e)
|
185 |
finished = True
|
186 |
-
#time.sleep(240)
|
187 |
continue
|
188 |
except tweepy.errors.BadRequest as e:
|
189 |
print("bad request error")
|
@@ -192,7 +107,7 @@ def block_users(client, threshold, dataset):
|
|
192 |
continue
|
193 |
except:
|
194 |
time.sleep(240)
|
195 |
-
continue
|
196 |
time.sleep(1)
|
197 |
finished = True
|
198 |
me = client.get_me()
|
@@ -247,12 +162,14 @@ name = None
|
|
247 |
|
248 |
|
249 |
def button_pressed(slider_value, url_params):
|
250 |
-
#print(url_params)
|
251 |
return [None, chat(radio.value, slider_value, url_params)]
|
252 |
|
|
|
253 |
# The website that the user will visit to authenticate WatchTower.
|
254 |
target_website = None
|
255 |
|
|
|
256 |
def update_target_website():
|
257 |
'''
|
258 |
Updates the URL used to authenticate WatchTower with Twitter.
|
@@ -264,7 +181,7 @@ def update_target_website():
|
|
264 |
global chat_history
|
265 |
global client
|
266 |
global name
|
267 |
-
|
268 |
client = None
|
269 |
name = "no username"
|
270 |
|
@@ -283,7 +200,8 @@ def update_target_website():
|
|
283 |
return '<a href={}><img src="https://cdn.cms-twdigitalassets.com/content/dam/developer-twitter/auth-docs/sign-in-with-twitter-gray.png.twimg.1920.png" alt="Log In With Twitter"></a><br>'.format(
|
284 |
get_target_website())
|
285 |
|
286 |
-
|
|
|
287 |
# Thanks to here: https://discuss.huggingface.co/t/hugging-face-and-gradio-url-paramiters/21110/2
|
288 |
get_window_url_params = """
|
289 |
function(text_input, url_params) {
|
@@ -294,35 +212,30 @@ get_window_url_params = """
|
|
294 |
}
|
295 |
"""
|
296 |
|
|
|
297 |
def get_target_website():
|
298 |
'''
|
299 |
A wrapper function used for retrieving the URL a user will use to authenticate WatchTower with Twitter.
|
300 |
-
:return:
|
301 |
'''
|
302 |
oauth1_user_handler = tweepy.OAuth1UserHandler(
|
303 |
consumer_token, consumer_secret,
|
304 |
-
callback="https://hf.space/embed/User1342/WatchTower/"
|
305 |
)
|
306 |
target_website = oauth1_user_handler.get_authorization_url(signin_with_twitter=True)
|
307 |
|
308 |
return target_website
|
309 |
|
|
|
310 |
# The Gradio HTML component used for the 'sign in with Twitter' button
|
311 |
-
twitter_auth_button = gr.HTML(
|
312 |
-
value='<a href={}><img src="https://cdn.cms-twdigitalassets.com/content/dam/developer-twitter/auth-docs/sign-in-with-twitter-gray.png.twimg.1920.png" alt="Log In With Twitter"></a><br>'.format(
|
313 |
-
get_target_website()))
|
314 |
|
315 |
# The main chunk of code that uses Gradio blocks to create the UI
|
316 |
with block:
|
|
|
|
|
317 |
gr.HTML('''
|
318 |
<meta name="viewport" content="width=device-width, initial-scale=1">
|
319 |
<link rel="stylesheet" href="https://www.w3schools.com/w3css/4/w3.css">
|
320 |
-
<!-- Navbar (sit on top) -->
|
321 |
-
<div class="w3-top">
|
322 |
-
<div class="w3-bar w3-white w3-wide w3-padding w3-card">
|
323 |
-
<p class="w3-bar-item w3-button"><b>WATCH</b> Tower</p>
|
324 |
-
</div>
|
325 |
-
</div>
|
326 |
''')
|
327 |
gr.HTML("<center><p><br></p></center>")
|
328 |
|
@@ -331,40 +244,42 @@ with block:
|
|
331 |
user_message = "Log in via Twitter and configure your blocking options above."
|
332 |
|
333 |
chat_history.append(["Welcome to Watchtower.", user_message])
|
334 |
-
|
335 |
-
with
|
336 |
-
|
337 |
-
|
338 |
-
|
339 |
-
|
340 |
-
|
341 |
-
|
342 |
-
|
343 |
-
|
344 |
-
|
345 |
-
|
346 |
-
|
347 |
-
|
348 |
-
|
349 |
-
|
350 |
-
|
351 |
-
|
352 |
-
|
353 |
-
|
354 |
-
|
355 |
-
|
356 |
-
|
357 |
-
|
358 |
-
|
359 |
-
|
360 |
-
|
361 |
-
|
362 |
-
|
363 |
-
|
364 |
-
|
365 |
-
|
366 |
-
|
367 |
-
|
|
|
|
|
368 |
gr.Markdown(
|
369 |
"""___
|
370 |
<p style='text-align: center'>
|
@@ -377,8 +292,9 @@ with block:
|
|
377 |
# Setup callback for when page loads (used to set a new Twitter auth target webspage)
|
378 |
block.__enter__()
|
379 |
block.set_event_trigger(
|
380 |
-
event_name="load", fn=update_target_website, inputs=None, outputs=[
|
381 |
)
|
382 |
|
383 |
# Launcg the page
|
384 |
-
block.launch(enable_queue=False,
|
|
|
|
8 |
import gradio as gr
|
9 |
import tweepy
|
10 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
11 |
# Twitter keys
|
12 |
consumer_token = os.getenv('CONSUMER_TOKEN')
|
13 |
consumer_secret = os.getenv('CONSUMER_SECRET')
|
|
|
15 |
my_access_secret = os.getenv('ACCESS_SECRET')
|
16 |
bearer = os.getenv('BEARER')
|
17 |
|
18 |
+
# Imports
|
19 |
+
import json
|
20 |
+
import os
|
21 |
+
import time
|
22 |
+
import gradio as gr
|
23 |
+
import tweepy
|
24 |
+
|
25 |
# Setup the gradio block and add some generic CSS
|
26 |
+
block = gr.Blocks(css="", title="WatchTower")
|
27 |
|
28 |
# Chat history variable used for the chatbot prompt on the 'getting started' page.
|
29 |
chat_history = []
|
30 |
|
31 |
+
|
32 |
def get_client_from_tokens(oauth_verifier, oauth_token):
|
33 |
'''
|
34 |
This function is used for generating a Tweepy client object based on Oauth verifier and token paramiters
|
|
|
38 |
'''
|
39 |
new_oauth1_user_handler = tweepy.OAuth1UserHandler(
|
40 |
consumer_token, consumer_secret,
|
41 |
+
callback="http://127.0.0.1:7860/'#https://hf.space/embed/User1342/WatchTower/"
|
42 |
)
|
43 |
new_oauth1_user_handler.request_token = {
|
44 |
"oauth_token": oauth_token,
|
|
|
89 |
|
90 |
finished = False
|
91 |
while not finished:
|
92 |
+
|
93 |
try:
|
94 |
print("preparing to block {}".format(user_id))
|
95 |
client.block(target_user_id=user_id)
|
|
|
98 |
print("time out error")
|
99 |
print(e)
|
100 |
finished = True
|
101 |
+
# time.sleep(240)
|
102 |
continue
|
103 |
except tweepy.errors.BadRequest as e:
|
104 |
print("bad request error")
|
|
|
107 |
continue
|
108 |
except:
|
109 |
time.sleep(240)
|
110 |
+
continue
|
111 |
time.sleep(1)
|
112 |
finished = True
|
113 |
me = client.get_me()
|
|
|
162 |
|
163 |
|
164 |
def button_pressed(slider_value, url_params):
|
165 |
+
# print(url_params)
|
166 |
return [None, chat(radio.value, slider_value, url_params)]
|
167 |
|
168 |
+
|
169 |
# The website that the user will visit to authenticate WatchTower.
|
170 |
target_website = None
|
171 |
|
172 |
+
|
173 |
def update_target_website():
|
174 |
'''
|
175 |
Updates the URL used to authenticate WatchTower with Twitter.
|
|
|
181 |
global chat_history
|
182 |
global client
|
183 |
global name
|
184 |
+
|
185 |
client = None
|
186 |
name = "no username"
|
187 |
|
|
|
200 |
return '<a href={}><img src="https://cdn.cms-twdigitalassets.com/content/dam/developer-twitter/auth-docs/sign-in-with-twitter-gray.png.twimg.1920.png" alt="Log In With Twitter"></a><br>'.format(
|
201 |
get_target_website())
|
202 |
|
203 |
+
|
204 |
+
# The below is a JS blob used to retrieve the URL params.
|
205 |
# Thanks to here: https://discuss.huggingface.co/t/hugging-face-and-gradio-url-paramiters/21110/2
|
206 |
get_window_url_params = """
|
207 |
function(text_input, url_params) {
|
|
|
212 |
}
|
213 |
"""
|
214 |
|
215 |
+
|
216 |
def get_target_website():
|
217 |
'''
|
218 |
A wrapper function used for retrieving the URL a user will use to authenticate WatchTower with Twitter.
|
219 |
+
:return:
|
220 |
'''
|
221 |
oauth1_user_handler = tweepy.OAuth1UserHandler(
|
222 |
consumer_token, consumer_secret,
|
223 |
+
callback="http://127.0.0.1:7860/"#"https://hf.space/embed/User1342/WatchTower/"
|
224 |
)
|
225 |
target_website = oauth1_user_handler.get_authorization_url(signin_with_twitter=True)
|
226 |
|
227 |
return target_website
|
228 |
|
229 |
+
|
230 |
# The Gradio HTML component used for the 'sign in with Twitter' button
|
|
|
|
|
|
|
231 |
|
232 |
# The main chunk of code that uses Gradio blocks to create the UI
|
233 |
with block:
|
234 |
+
|
235 |
+
|
236 |
gr.HTML('''
|
237 |
<meta name="viewport" content="width=device-width, initial-scale=1">
|
238 |
<link rel="stylesheet" href="https://www.w3schools.com/w3css/4/w3.css">
|
|
|
|
|
|
|
|
|
|
|
|
|
239 |
''')
|
240 |
gr.HTML("<center><p><br></p></center>")
|
241 |
|
|
|
244 |
user_message = "Log in via Twitter and configure your blocking options above."
|
245 |
|
246 |
chat_history.append(["Welcome to Watchtower.", user_message])
|
247 |
+
|
248 |
+
with gr.Group():
|
249 |
+
with gr.Row().style(mobile_collapse=False, equal_height=True):
|
250 |
+
gr.HTML(value=r'<img src="https://www.watchtower.cartographer.one/wp-content/uploads/2022/10/Blocking-Unfavorable-Content.png" alt="Markdown Monster icon" style="float: left; margin-right: 10px;" width="350"/>').style(
|
251 |
+
)
|
252 |
+
with gr.Box():
|
253 |
+
#gr.Label(value="WatchTower", visible=True, interactive=False)
|
254 |
+
url_params = gr.JSON({}, visible=False, label="URL Params").style(
|
255 |
+
)
|
256 |
+
text_input = gr.Text(label="Input", visible=False).style(
|
257 |
+
rounded=(False, True, True, False),
|
258 |
+
)
|
259 |
+
text_output = gr.Text(label="Output", visible=False).style(
|
260 |
+
rounded=(False, True, True, False),
|
261 |
+
)
|
262 |
+
twitter_auth_button = gr.HTML(
|
263 |
+
value='<a href={}><img src="https://cdn.cms-twdigitalassets.com/content/dam/developer-twitter/auth-docs/sign-in-with-twitter-gray.png.twimg.1920.png" alt="Log In With Twitter"></a><br>'.format(
|
264 |
+
get_target_website())).style(
|
265 |
+
)
|
266 |
+
with gr.Row().style(mobile_collapse=True, equal_height=True):
|
267 |
+
radio = gr.CheckboxGroup(value="Violent", choices=["Violent", "Hate Speech", "Misinformation"],
|
268 |
+
interactive=False, label="Behaviour To Block").style(
|
269 |
+
rounded=(False, True, True, False),
|
270 |
+
)
|
271 |
+
|
272 |
+
slider = gr.Slider(value=10, interactive=True, label="Threshold Confidence Tolerance")
|
273 |
+
|
274 |
+
chatbot = gr.Chatbot(value=chat_history, label="Watchtower Output").style(
|
275 |
+
rounded=(False, True, True, False),
|
276 |
+
)
|
277 |
+
btn = gr.Button("Run WatchTower").style(
|
278 |
+
margin=False,
|
279 |
+
rounded=(False, True, True, False), full_width=True
|
280 |
+
)
|
281 |
+
btn.click(fn=button_pressed, inputs=[slider, url_params],
|
282 |
+
outputs=[text_output, chatbot], _js=get_window_url_params)
|
283 |
gr.Markdown(
|
284 |
"""___
|
285 |
<p style='text-align: center'>
|
|
|
292 |
# Setup callback for when page loads (used to set a new Twitter auth target webspage)
|
293 |
block.__enter__()
|
294 |
block.set_event_trigger(
|
295 |
+
event_name="load", fn=update_target_website, inputs=None, outputs=[], no_target=True
|
296 |
)
|
297 |
|
298 |
# Launcg the page
|
299 |
+
block.launch(enable_queue=False,
|
300 |
+
favicon_path="https://www.jamesstevenson.me/wp-content/uploads/2022/08/Untitled-design-32.png")
|