Spaces:
Runtime error
Runtime error
File size: 15,507 Bytes
abc6d3e fd1b24a abc6d3e fd1b24a abc6d3e 06188f8 abc6d3e f7b8f12 927c4f3 3d7ef93 9dd1fca 1566af8 abc6d3e 3d7ef93 abc6d3e 3d7ef93 abc6d3e 3d7ef93 1a124d9 82e6b2b abc6d3e 82e6b2b abc6d3e 82e6b2b 9414e21 abc6d3e fd1b24a 9414e21 fd1b24a 1a124d9 abc6d3e 9414e21 abc6d3e 9414e21 abc6d3e fd1b24a abc6d3e 563d741 abc6d3e 1cd7d07 06188f8 a9f3875 22704b7 06188f8 abc6d3e b15d357 abc6d3e a9f3875 9414e21 fd1b24a 9414e21 fd1b24a 1cd7d07 fd1b24a 62858ef fd1b24a 1cd7d07 fd1b24a 62858ef abc6d3e f26110a abc6d3e f26110a abc6d3e 1cd7d07 fd1b24a 1cd7d07 723c207 9414e21 abc6d3e 9414e21 1cd7d07 723c207 abc6d3e fd1b24a 723c207 768a35d 06188f8 723c207 abc6d3e 06188f8 723c207 fd1b24a 723c207 8ef1d8a 723c207 1cd7d07 fd1b24a 1cd7d07 723c207 fd1b24a 1cd7d07 723c207 9414e21 1a124d9 9414e21 1a124d9 9414e21 768a35d 9414e21 1a124d9 9414e21 abc6d3e 9414e21 fd1b24a 1a124d9 8ef1d8a fd1b24a 1cd7d07 723c207 abc6d3e 1cd7d07 723c207 7e78c4e abc6d3e 9414e21 abc6d3e 9414e21 abc6d3e 768a35d 1a124d9 9414e21 723c207 16e7310 3d2f56d abc6d3e 1a124d9 abc6d3e 9414e21 abc6d3e 9414e21 abc6d3e c1493db abc6d3e c1493db 1a124d9 abc6d3e 7e78c4e 9414e21 82e6b2b fd1b24a abc6d3e fd1b24a 723c207 fd1b24a abc6d3e 3d7ef93 9dd1fca 1a124d9 abc6d3e 1a124d9 9dd1fca abc6d3e 9dd1fca abc6d3e 1a124d9 abc6d3e 7cb6d47 01b9d96 9dd1fca 1a124d9 768a35d abc6d3e 768a35d abc6d3e f6ab2d7 95cefa6 ec5258e 95cefa6 3d2f56d 9dd1fca abc6d3e 9dd1fca 3fb64c6 abc6d3e |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 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 369 370 371 372 373 374 375 376 377 378 379 380 381 382 383 384 385 386 387 388 389 390 391 392 393 394 395 396 397 398 399 400 401 402 403 404 405 406 407 408 409 410 411 412 |
#!/usr/bin/env python
# coding: utf-8
import json
import os
import re
import time
from random import random
import socket
from threading import Thread
from time import sleep
# Twitter keys
consumer_token = os.getenv('CONSUMER_TOKEN')
consumer_secret = os.getenv('CONSUMER_SECRET')
my_access_token = os.getenv('ACCESS_TOKEN')
my_access_secret = os.getenv('ACCESS_SECRET')
bearer = os.getenv('BEARER')
html_data = '''
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<link rel="stylesheet" href="https://www.w3schools.com/w3css/4/w3.css">
<link rel="stylesheet" href="https://fonts.googleapis.com/css?family=Poppins">
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/4.7.0/css/font-awesome.min.css">
<style>
body,h1,h2,h3,h4,h5 {font-family: "Poppins", sans-serif}
body {font-size: 16px;}
img {margin-bottom: -8px;}
.mySlides {display: none;}
</style>
</head>
<body class="w3-content w3-black" style="max-width:1500px;">
<!-- The App Section -->
<div class="w3-padding-large w3-white">
<div class="w3-row-padding-large">
<div class="w3-col">
<h1 class="w3-jumbo"><b>WatchTower 🐦🚧</b></h1>
<h1 class="w3-xxxlarge w3-text-blue"><b>Remove Unfavorable Tweets From Your Feed </b></h1>
<p><span class="w3-xlarge">Scroll down to use WatchTower 1.0. ⬇ </span> WatchTower is a tool that identifies hate speech, misinformation, and extremist content and blocks/ mutes it from your Twitter feed. WatchTower blocks content based on it's current database, so make sure to come back regularly to ensure you're up to date! We use a queue system, which means <b> you may need to wait your turn to run WatchTower</b> - however, once you've clicked run, you can close the tab as WatchTower will continue in the background. WatchTower is simple to use: first scroll down the page and click the 'sign in with Twitter' button, then you'll be taken to the Twitter website and asked to verify yourself, after this you'll be taken back here, then simply scroll down to the bottom of the page and click run!</p>
<a href="https://www.watchtower.cartographer.one/"><button class="w3-button w3-light-grey w3-padding-large w3-section " onclick="document.getElementById('download').style.display='block'">
<i class=""></i> Find Out More! 💬
</button></a>
<a href="https://ko-fi.com/jamesstevenson"><button class="w3-button w3-light-grey w3-padding-large w3-section " onclick="document.getElementById('download').style.display='block'">
<i class=""></i> Support The Creator! ❤
</button></a>
<a href="https://twitter.com/WATCHTOWER_WEB"><button class="w3-button w3-light-grey w3-padding-large w3-section " onclick="document.getElementById('download').style.display='block'">
<i class=""></i> Follow Us! 🐦
</button></a>
</div>
</div>
</div>
<!-- Modal -->
<script>
// Slideshow
var slideIndex = 1;
showDivs(slideIndex);
function plusDivs(n) {
showDivs(slideIndex += n);
}
function showDivs(n) {
var i;
var x = document.getElementsByClassName("mySlides");
if (n > x.length) {slideIndex = 1}
if (n < 1) {slideIndex = x.length}
for (i = 0; i < x.length; i++) {
x[i].style.display = "none";
}
x[slideIndex-1].style.display = "block";
}
</script>
<br>
</body>
</html>
'''
# Imports
import json
import os
import time
import gradio as gr
import tweepy
# Setup the gradio block and add some generic CSS
block = gr.Blocks(css=".container { max-width: 800px; margin: auto; } h1 { margin: 0px; padding: 5px 0; line-height: 50px; font-size: 60pt; }.close-heading {margin: 0px; padding: 0px;} .close-heading p { margin: 0px; padding: 0px;}", title="WatchTower")
# Chat history variable used for the chatbot prompt on the 'getting started' page.
chat_history = []
def get_client_from_tokens(oauth_verifier, oauth_token):
'''
This function is used for generating a Tweepy client object based on Oauth verifier and token paramiters
:param oauth_verifier:
:param oauth_token:
:return: A Tweepy client object
'''
new_oauth1_user_handler = tweepy.OAuth1UserHandler(
consumer_token, consumer_secret,
callback="https://hf.space/embed/User1342/WatchTower/"
)
new_oauth1_user_handler.request_token = {
"oauth_token": oauth_token,
"oauth_token_secret": consumer_secret
}
access_token, access_token_secret = new_oauth1_user_handler.get_access_token(
oauth_verifier
)
their_client = tweepy.Client(
bearer_token=bearer,
consumer_key=consumer_token,
consumer_secret=consumer_secret,
access_token=access_token,
access_token_secret=access_token_secret
)
# TODO: The below is not necessary and can be removed.
global client
client = their_client
return their_client
def block_user(user_id, user, reason):
finished = False
blocked = True
attempts = 0
while not finished:
try:
print("preparing to block {}".format(user_id))
client.block(target_user_id=user_id)
print("User blocked")
except tweepy.errors.TooManyRequests as e:
try:
client.mute(target_user_id=user_id)
print("Could not block, so muted")
except tweepy.errors.TooManyRequests as e:
if attempts == 0:
print("waiting 15 minutes for rate limit to finish")
time.sleep(900)
attempts = attempts + 1
continue
else:
finished = True
blocked = False
continue
except tweepy.errors.BadRequest as e:
print("bad request error")
print(e)
finished = True
blocked = False
continue
except tweepy.errors.BadRequest as e:
print("bad request error")
print(e)
finished = True
blocked = False
continue
except:
time.sleep(240)
continue
#time.sleep(1)
finished = True
try:
me = client.get_me()
print("{} blocked {}, for {}".format(me.data["username"], user, reason))
except tweepy.errors.TooManyRequests as e:
print("Blocked {}, for {}".format(user, reason))
return blocked
def block_users(client, threshold, dataset):
'''
Used for blocking a series of users based on the threshold and datasets provided. Here the users folder is used.
:param client:
:param threshold:
:param dataset:
:return: The number of blocked users.
'''
num_users_blocked = 0
for filename in os.listdir("users"):
filename = os.path.join("users", filename)
print("File {} open".format(filename))
user_file = open(filename, "r")
users = json.load(user_file)
for user in users:
print("Reviewing user {}".format(user))
if "threshold" in user:
# old type of dataset being used, only 'violent' data available
if "Violent" in dataset:
if user["threshold"]/2 >= threshold:
user_id = str(user["username"])
if block_user(user_id, user, "Violent - old dataset"):
num_users_blocked = num_users_blocked + 1
else:
# modern dataset being used
if "Violent" in dataset:
if user["violence-threshold"]/2 >= threshold:
user_id = str(user["username"])
if block_user(user_id, user, "Violent"):
num_users_blocked = num_users_blocked + 1
continue
if "Hate Speech" in dataset:
if user["toxicity-threshold"] >= threshold:
user_id = str(user["username"])
if block_user(user_id, user, "Hate Speech"):
num_users_blocked = num_users_blocked + 1
continue
return num_users_blocked
def chat(selected_option=None, radio_score=None, url_params=None):
'''
This function is used to initialise blocking users once the user has authenticated with Twitter.
:param selected_option:
:param radio_score:
:param url_params:
:return: the chatbot history is returned (including information on blocked accounts).
'''
global client
global chat_history
history = []
# app id
if "oauth_verifier" in url_params and "oauth_token" in url_params and client is None:
client = get_client_from_tokens(url_params["oauth_verifier"], url_params["oauth_token"])
if radio_score != None and selected_option != None:
if client != None:
# Extract the list to a string representation
if type(selected_option) is list:
block_type = ""
for b_type in selected_option:
block_type = block_type + " + " + b_type.capitalize()
block_type = "'" + block_type[3:] + "'"
else:
block_type = selected_option
# Display to user, set options
history.append(
["Model tuned to a '{}%' threshold and is using the {} dataset.".format(radio_score, block_type.capitalize()),
"{} Account blocking initialised".format(block_type.capitalize())])
num_users_blocked = block_users(client, radio_score, selected_option)
history.append(
["Blocked {} user account(s).".format(num_users_blocked), "Thank you for using Watchtower."])
elif radio_score != None or selected_option != None:
chat_history.append(["Initialisation error!", "Please tune the model by using the above options"])
history = chat_history + history
chatbot.value = history
chatbot.update(value=history)
client = None
return history
def infer(prompt):
pass
have_initialised = False
client = None
name = None
def button_pressed(slider_value, url_params):
# print(url_params)
return [None, chat(radio.value, slider_value, url_params)]
# The website that the user will visit to authenticate WatchTower.
target_website = None
def update_target_website():
'''
Updates the URL used to authenticate WatchTower with Twitter.
#TODO this function is full of old code and can be optimised.
:return:
'''
global have_initialised
global chatbot
global chat_history
global client
global name
client = None
name = "no username"
chat_history = [
["Welcome to Watchtower.".format(name), "Log in via Twitter and configure your blocking options above."]]
chatbot.value = chat_history
chatbot.update(value=chat_history)
twitter_auth_button.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(
get_target_website())
twitter_auth_button.update(
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(
get_target_website()))
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(
get_target_website())
# The below is a JS blob used to retrieve the URL params.
# Thanks to here: https://discuss.huggingface.co/t/hugging-face-and-gradio-url-paramiters/21110/2
get_window_url_params = """
function(text_input, url_params) {
console.log(text_input, url_params);
const params = new URLSearchParams(window.location.search);
url_params = Object.fromEntries(params);
return [text_input, url_params];
}
"""
def get_chatbot_text():
return [('Welcome to Watchtower.', 'Log in via Twitter and configure your blocking options above.')]
def get_target_website():
'''
A wrapper function used for retrieving the URL a user will use to authenticate WatchTower with Twitter.
:return:
'''
oauth1_user_handler = tweepy.OAuth1UserHandler(
consumer_token, consumer_secret,
callback="https://hf.space/embed/User1342/WatchTower/"
)
target_website = oauth1_user_handler.get_authorization_url(signin_with_twitter=True)
return target_website
# The Gradio HTML component used for the 'sign in with Twitter' button
# The main chunk of code that uses Gradio blocks to create the UI
html_button = None
with block:
gr.HTML('''
<meta name="viewport" content="width=device-width, initial-scale=1">
<link rel="stylesheet" href="https://www.w3schools.com/w3css/4/w3.css">
''')
# todo check if user signed in
user_message = "Log in via Twitter and configure your blocking options above."
chat_history.append(["Welcome to Watchtower.", user_message])
gr.HTML(value=html_data)
with gr.Group():
with gr.Row().style(equal_height=True):
with gr.Box():
#gr.Label(value="WatchTower", visible=True, interactive=False)
url_params = gr.JSON({}, visible=False, label="URL Params").style(
)
text_input = gr.Text(label="Input", visible=False).style()
text_output = gr.Text(label="Output", visible=False).style()
html_button = twitter_auth_button = gr.HTML(
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(
get_target_website())).style(
)
with gr.Row().style(equal_height=True):
radio = gr.CheckboxGroup(value=["Violent", "Hate Speech"], choices=["Violent", "Hate Speech", "Misinformation"],
interactive=False, label="Behaviour To Block").style()
slider = gr.Slider(value=30, interactive=True, label="Threshold Confidence Tolerance")
chatbot = gr.Chatbot(label="Watchtower Output", value=get_chatbot_text()).style(color_map=["blue","grey"])
btn = gr.Button("Run WatchTower").style(full_width=True).style()
btn.click(fn=button_pressed, inputs=[slider, url_params],
outputs=[text_output, chatbot], _js=get_window_url_params)
gr.Markdown(
"""___
<p style='text-align: center'>
Created by <a href="https://twitter.com/_JamesStevenson" target="_blank"</a> James Stevenson
<br/>
</p>"""
)
# Setup callback for when page loads (used to set a new Twitter auth target webspage)
block.__enter__()
block.set_event_trigger(
event_name="load", fn=update_target_website, inputs=None, outputs=[html_button], no_target=True
)
block.set_event_trigger(
event_name="load", fn=get_chatbot_text, inputs=None, outputs=[chatbot], no_target=True
)
#block.attach_load_events()
# Launcg the page
block.launch(enable_queue = True) |