User1342 commited on
Commit
abc6d3e
1 Parent(s): f7b8f12

Update app.py

Browse files
Files changed (1) hide show
  1. app.py +157 -223
app.py CHANGED
@@ -1,135 +1,23 @@
 
 
 
 
 
1
  import time
2
- from pprint import pprint
3
-
4
- from mastodon import Mastodon, MastodonNotFoundError # Mastodon.py
5
-
6
- list_of_servers = ['libretooth.gr',
7
- 'tilde.zone',
8
- 'hostux.social',
9
- 'social.linux.pizza',
10
- 'nerdculture.de',
11
- 'toot.wales',
12
- 'kolektiva.social',
13
- 'noc.social',
14
- 'seo.chat',
15
- 'ioc.exchange',
16
- 'glasgow.social',
17
- 'mindly.social',
18
- 'mstdn.party',
19
- 'universeodon.com',
20
- 'learningdisability.social',
21
- 'ravenation.club',
22
- 'home.social',
23
- 'techhub.social',
24
- 'mastodon.scot',
25
- 'sfba.social',
26
- 'mastodon.sdf.org',
27
- 'mastodon.lol',
28
- 'mstdn.social',
29
- 'mas.to',
30
- 'newsie.social']
31
-
32
- # A HTML blob of text used to define the 'login in with' button
33
- auth_button_text = '''<a href="{}"><button class="w3-button w3-light-grey w3-padding-large w3-section " onclick="document.getElementById('download').style.display='block'">
34
- <i class=""></i> Login with Mastodon! 🐘
35
- </button></a><br>'''
36
-
37
-
38
-
39
- def client_log_in(provided_server = None):
40
- '''
41
- Generates an authenticated Masterdon client for the admin user. Used for retireving the target website URL
42
- '''
43
-
44
- if provided_server == None:
45
- global slider_choice
46
- server = slider_choice
47
- else:
48
- server = provided_server
49
-
50
- if server != None:
51
- id = "WatchTower Ivory | Mastodon"
52
-
53
- secrets = json.loads(os.getenv('secrets_json'))
54
-
55
- client_id = secrets[server]["client_id"]
56
- client_secret = secrets[server]["client_secret"]
57
- password = secrets[server]["password"]
58
- username = os.getenv('username')
59
-
60
-
61
- mastodon = Mastodon(
62
- client_id=client_id,client_secret=client_secret,
63
- api_base_url='https://{}'.format(server)
64
- )
65
-
66
- access_token = mastodon.log_in(
67
- username=username,
68
- scopes=["write:blocks", "write:mutes","read:search","read:accounts"],
69
- password=password,
70
- redirect_uri="https://user1342-ivory.hf.space/"
71
- )
72
- else:
73
- mastodon = None
74
-
75
- return mastodon
76
-
77
-
78
- def get_auth_url(mastodon,provided_server = None):
79
- '''
80
- Retrieves a URL for the user to visit to auth them with WatchTower.
81
- :param mastodon: A admin masterdon instance.
82
- :return: The target URL.
83
- '''
84
 
85
- if provided_server == None:
86
- global slider_choice
87
- server = slider_choice
88
- else:
89
- server = provided_server
90
 
91
- secrets = json.loads(os.getenv('secrets_json'))
 
 
 
 
 
92
 
93
- client_id = secrets[server]["client_id"]
94
- client_secret = secrets[server]["client_secret"]
95
-
96
- return mastodon.auth_request_url(client_id=client_id, scopes=["write:blocks", "write:mutes","read:search","read:accounts"],
97
- redirect_uris="https://user1342-ivory.hf.space/")
98
-
99
-
100
- def login_from_code(code):
101
- '''
102
- Used to create a masterdon client instance based on an authenticated user code (retrieved from the URL).
103
- :param code: The code which will authenticate the user/ WatchTower.
104
- :return: A masterdon client instance signed in as the user.
105
- '''
106
-
107
- global slider_choice
108
- server = slider_choice
109
-
110
- if server != None:
111
- secrets = json.loads(os.getenv('secrets_json'))
112
- client_id = secrets[server]["client_id"]
113
- client_secret = secrets[server]["client_secret"]
114
-
115
- mastodon = Mastodon(
116
- client_id=client_id, client_secret=client_secret,
117
- api_base_url='https://{}'.format(server)
118
- )
119
-
120
- mastodon.log_in(code=code,
121
- scopes=["write:blocks", "write:mutes","read:search","read:accounts"],
122
- redirect_uri="https://user1342-ivory.hf.space/")
123
- else:
124
- mastodon = None
125
-
126
- return mastodon
127
-
128
-
129
- # !/usr/bin/env python
130
- # coding: utf-8
131
-
132
- html_data = '''
133
  <!DOCTYPE html>
134
  <html>
135
  <head>
@@ -152,22 +40,23 @@ img {margin-bottom: -8px;}
152
  <div class="w3-padding-large w3-white">
153
  <div class="w3-row-padding-large">
154
  <div class="w3-col">
155
- <h1 class="w3-jumbo"><b>WatchTower 🐘🚧</b></h1>
156
- <h1 class="w3-xxxlarge w3-text-purple"><b>Remove Unfavorable Messages From Your Mastodon Feed </b></h1>
157
- <p><span class="w3-xlarge">Scroll down to use WatchTower Ivory. ⬇ </span> WatchTower is a tool that identifies hate speech, misinformation, and extremist content and blocks/ mutes it from your feed. WatchTower Ivory is the second iteration of WatchTower, designed specifically for Mastodon. 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 Mastodon logo below, then you'll be taken to the Mastodon 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>
158
  <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'">
159
  <i class=""></i> Find Out More! 💬
160
  </button></a>
161
  <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'">
162
  <i class=""></i> Support The Creator! ❤
163
  </button></a>
164
- <a href="https://infosec.exchange/@JamesStevenson"><button class="w3-button w3-light-grey w3-padding-large w3-section " onclick="document.getElementById('download').style.display='block'">
165
  <i class=""></i> Follow Us! 🐦
166
  </button></a>
167
  </div>
168
  </div>
169
  </div>
170
 
 
171
  <script>
172
  // Slideshow
173
  var slideIndex = 1;
@@ -189,8 +78,6 @@ function showDivs(n) {
189
  }
190
  </script>
191
  <br>
192
- <br>
193
- <br>
194
  </body>
195
  </html>
196
 
@@ -199,50 +86,99 @@ function showDivs(n) {
199
  # Imports
200
  import json
201
  import os
 
202
  import gradio as gr
 
203
 
204
  # Setup the gradio block and add some generic CSS
205
- block = gr.Blocks(
206
- 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;}",
207
- title="WatchTower")
208
 
209
  # Chat history variable used for the chatbot prompt on the 'getting started' page.
210
  chat_history = []
211
 
212
 
213
- def get_client_from_tokens(code):
214
  '''
215
- This function is used for generating a masterdon client object based on the code URL paramiters
216
- :param code
217
- :return: A Masterdon client object
 
218
  '''
 
 
 
 
 
 
 
 
219
 
220
- return login_from_code(code)
 
 
221
 
 
 
 
 
 
 
 
 
 
 
 
 
 
222
 
223
  def block_user(user_id, user, reason):
224
  finished = False
225
  blocked = True
226
  attempts = 0
227
  while not finished:
228
-
229
  try:
230
- user ="alcinnz@floss.social"
231
- user_dict = client.account_search(user)
232
- pprint(user_dict)
233
-
234
- client.account_block(user_dict[0]["id"])
235
- print("Blocked {} for {}".format(user, reason))
236
- except MastodonNotFoundError as e:
237
- if "Record not found" in str(e):
238
- print("Record not found...")
239
- return False
240
-
241
-
242
- print("Blocked {}, for {}".format(user, reason))
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
243
  return blocked
244
 
245
-
246
  def block_users(client, threshold, dataset):
247
  '''
248
  Used for blocking a series of users based on the threshold and datasets provided. Here the users folder is used.
@@ -253,7 +189,6 @@ def block_users(client, threshold, dataset):
253
  '''
254
  num_users_blocked = 0
255
 
256
-
257
  for filename in os.listdir("users"):
258
  filename = os.path.join("users", filename)
259
  print("File {} open".format(filename))
@@ -262,27 +197,37 @@ def block_users(client, threshold, dataset):
262
 
263
  for user in users:
264
  print("Reviewing user {}".format(user))
265
- if "Violent" in dataset:
266
- # Due to the low number of posts used to aggregate the initial dataset and unreliability of this model,
267
- # the weight has been lowered to represent this.
268
- if user["violence-threshold"]/2 >= threshold:
269
- user_id = str(user["acct"])
270
- if block_user(user_id, user, "Violent"):
271
- num_users_blocked = num_users_blocked + 1
272
- continue
273
- if "Hate Speech" in dataset:
274
- if user["toxicity-threshold"] >= threshold:
275
- user_id = str(user["acct"])
276
- if block_user(user_id, user, "Hate Speech"):
277
- num_users_blocked = num_users_blocked + 1
278
- continue
 
 
 
 
 
 
 
 
 
 
279
 
280
  return num_users_blocked
281
 
282
 
283
  def chat(selected_option=None, radio_score=None, url_params=None):
284
  '''
285
- This function is used to initialise blocking users once the user has authenticated with Mastodon.
286
  :param selected_option:
287
  :param radio_score:
288
  :param url_params:
@@ -294,8 +239,8 @@ def chat(selected_option=None, radio_score=None, url_params=None):
294
  history = []
295
 
296
  # app id
297
- if "code" in url_params and client is None:
298
- client = get_client_from_tokens(url_params["code"])
299
  if radio_score != None and selected_option != None:
300
 
301
  if client != None:
@@ -311,8 +256,7 @@ def chat(selected_option=None, radio_score=None, url_params=None):
311
 
312
  # Display to user, set options
313
  history.append(
314
- ["Model tuned to a '{}%' threshold and is using the {} dataset.".format(radio_score,
315
- block_type.capitalize()),
316
  "{} Account blocking initialised".format(block_type.capitalize())])
317
  num_users_blocked = block_users(client, radio_score, selected_option)
318
  history.append(
@@ -347,7 +291,7 @@ target_website = None
347
 
348
  def update_target_website():
349
  '''
350
- Updates the URL used to authenticate WatchTower with Mastodon.
351
  #TODO this function is full of old code and can be optimised.
352
  :return:
353
  '''
@@ -361,18 +305,19 @@ def update_target_website():
361
  name = "no username"
362
 
363
  chat_history = [
364
- ["Welcome to Watchtower.".format(name), "Log in via Mastodon and configure your blocking options above."]]
365
 
366
  chatbot.value = chat_history
367
  chatbot.update(value=chat_history)
368
 
369
- mastodon_auth_button.value = auth_button_text.format(
370
  get_target_website())
371
- mastodon_auth_button.update(
372
- value=auth_button_text.format(
373
  get_target_website()))
374
 
375
- return auth_button_text.format(get_target_website(list_of_servers[0]))
 
376
 
377
 
378
  # The below is a JS blob used to retrieve the URL params.
@@ -385,36 +330,31 @@ get_window_url_params = """
385
  return [text_input, url_params];
386
  }
387
  """
388
- slider_choice = list_of_servers[0]
389
- def update_server(choice):
390
- print("In change server")
391
- global slider_choice
392
- slider_choice = choice
393
-
394
- get_target_website()
395
-
396
- return auth_button_text.format(get_target_website())
397
 
398
  def get_chatbot_text():
399
- return [('Welcome to Watchtower.', 'Log in via Mastodon and configure your blocking options above.')]
400
 
401
-
402
- def get_target_website(provided_server = None):
403
  '''
404
- A wrapper function used for retrieving the URL a user will use to authenticate WatchTower with Mastodon.
405
- :return: auth url
406
  '''
 
 
 
 
 
407
 
408
- mastodon = client_log_in(provided_server)
409
- return get_auth_url(mastodon, provided_server)
410
 
411
 
412
- # The Gradio HTML component used for the 'sign in with Mastodon' button
413
 
414
  # The main chunk of code that uses Gradio blocks to create the UI
415
  html_button = None
416
- dropdown = None
417
  with block:
 
 
418
  gr.HTML('''
419
  <meta name="viewport" content="width=device-width, initial-scale=1">
420
  <link rel="stylesheet" href="https://www.w3schools.com/w3css/4/w3.css">
@@ -422,57 +362,51 @@ with block:
422
 
423
  # todo check if user signed in
424
 
425
- user_message = "Log in via Mastodon and configure your blocking options above."
426
- chat_history.append(["WelcoMe to Watchtower.", user_message])
427
  gr.HTML(value=html_data)
428
  with gr.Group():
429
  with gr.Row().style(equal_height=True):
430
  with gr.Box():
431
- # gr.Label(value="WatchTower", visible=True, interactive=False)
432
  url_params = gr.JSON({}, visible=False, label="URL Params").style(
433
  )
434
  text_input = gr.Text(label="Input", visible=False).style()
435
  text_output = gr.Text(label="Output", visible=False).style()
436
- with gr.Row().style():
437
- dropdown = gr.Dropdown(choices=list_of_servers, label="Server", value=list_of_servers[0])
438
- html_button = mastodon_auth_button = gr.HTML(
439
- value=auth_button_text.format(
440
- get_target_website())).style(
441
- )
442
  with gr.Row().style(equal_height=True):
443
- radio = gr.CheckboxGroup(value=["Violent", "Hate Speech"],
444
- choices=["Violent", "Hate Speech", "Misinformation"],
445
- interactive=False, label="Behaviour To Block").style()
446
 
447
- slider = gr.Slider(value=30, interactive=True, label="Threshold Confidence Tolerance").style()
 
 
448
 
449
- chatbot = gr.Chatbot(label="Watchtower Output", value=[('Welcome to Watchtower.',
450
- 'Log in via Mastodon and configure your blocking options above.')]).style(
451
- color_map=["grey", "purple"])
452
 
453
  btn = gr.Button("Run WatchTower").style(full_width=True).style()
454
- dropdown.change(fn=update_server, inputs=[dropdown], outputs=html_button)
455
  btn.click(fn=button_pressed, inputs=[slider, url_params],
456
  outputs=[text_output, chatbot], _js=get_window_url_params)
457
  gr.Markdown(
458
  """___
459
  <p style='text-align: center'>
460
- Created by <a href="https://JamesStevenson.me" target="_blank"</a> James Stevenson
461
  <br/>
462
  </p>"""
463
  )
464
 
465
- # Setup callback for when page loads (used to set a new Mastodon auth target webspage)
466
  block.__enter__()
467
  block.set_event_trigger(
468
  event_name="load", fn=update_target_website, inputs=None, outputs=[html_button], no_target=True
469
  )
470
-
471
  block.set_event_trigger(
472
  event_name="load", fn=get_chatbot_text, inputs=None, outputs=[chatbot], no_target=True
473
  )
474
 
475
- block.attach_load_events()
476
 
477
  # Launcg the page
478
- block.launch(enable_queue=True)
 
1
+ #!/usr/bin/env python
2
+ # coding: utf-8
3
+ import json
4
+ import os
5
+ import re
6
  import time
7
+ from random import random
8
+ import socket
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
9
 
10
+ from threading import Thread
11
+ from time import sleep
 
 
 
12
 
13
+ # Twitter keys
14
+ consumer_token = os.getenv('CONSUMER_TOKEN')
15
+ consumer_secret = os.getenv('CONSUMER_SECRET')
16
+ my_access_token = os.getenv('ACCESS_TOKEN')
17
+ my_access_secret = os.getenv('ACCESS_SECRET')
18
+ bearer = os.getenv('BEARER')
19
 
20
+ html_data = '''a
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
21
  <!DOCTYPE html>
22
  <html>
23
  <head>
 
40
  <div class="w3-padding-large w3-white">
41
  <div class="w3-row-padding-large">
42
  <div class="w3-col">
43
+ <h1 class="w3-jumbo"><b>WatchTower 🐦🚧</b></h1>
44
+ <h1 class="w3-xxxlarge w3-text-blue"><b>Remove Unfavorable Tweets From Your Feed </b></h1>
45
+ <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>
46
  <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'">
47
  <i class=""></i> Find Out More! 💬
48
  </button></a>
49
  <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'">
50
  <i class=""></i> Support The Creator! ❤
51
  </button></a>
52
+ <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'">
53
  <i class=""></i> Follow Us! 🐦
54
  </button></a>
55
  </div>
56
  </div>
57
  </div>
58
 
59
+ <!-- Modal -->
60
  <script>
61
  // Slideshow
62
  var slideIndex = 1;
 
78
  }
79
  </script>
80
  <br>
 
 
81
  </body>
82
  </html>
83
 
 
86
  # Imports
87
  import json
88
  import os
89
+ import time
90
  import gradio as gr
91
+ import tweepy
92
 
93
  # Setup the gradio block and add some generic CSS
94
+ 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")
 
 
95
 
96
  # Chat history variable used for the chatbot prompt on the 'getting started' page.
97
  chat_history = []
98
 
99
 
100
+ def get_client_from_tokens(oauth_verifier, oauth_token):
101
  '''
102
+ This function is used for generating a Tweepy client object based on Oauth verifier and token paramiters
103
+ :param oauth_verifier:
104
+ :param oauth_token:
105
+ :return: A Tweepy client object
106
  '''
107
+ new_oauth1_user_handler = tweepy.OAuth1UserHandler(
108
+ consumer_token, consumer_secret,
109
+ callback="https://hf.space/embed/User1342/WatchTower/"
110
+ )
111
+ new_oauth1_user_handler.request_token = {
112
+ "oauth_token": oauth_token,
113
+ "oauth_token_secret": consumer_secret
114
+ }
115
 
116
+ access_token, access_token_secret = new_oauth1_user_handler.get_access_token(
117
+ oauth_verifier
118
+ )
119
 
120
+ their_client = tweepy.Client(
121
+ bearer_token=bearer,
122
+ consumer_key=consumer_token,
123
+ consumer_secret=consumer_secret,
124
+ access_token=access_token,
125
+ access_token_secret=access_token_secret
126
+ )
127
+
128
+ # TODO: The below is not necessary and can be removed.
129
+ global client
130
+ client = their_client
131
+
132
+ return their_client
133
 
134
  def block_user(user_id, user, reason):
135
  finished = False
136
  blocked = True
137
  attempts = 0
138
  while not finished:
139
+
140
  try:
141
+ print("preparing to block {}".format(user_id))
142
+ client.block(target_user_id=user_id)
143
+ print("User blocked")
144
+ except tweepy.errors.TooManyRequests as e:
145
+ try:
146
+ client.mute(target_user_id=user_id)
147
+ print("Could not block, so muted")
148
+ except tweepy.errors.TooManyRequests as e:
149
+ if attempts == 0:
150
+ print("waiting 15 minutes for rate limit to finish")
151
+ time.sleep(900)
152
+ attempts = attempts + 1
153
+ continue
154
+ else:
155
+ finished = True
156
+ blocked = False
157
+ continue
158
+ except tweepy.errors.BadRequest as e:
159
+ print("bad request error")
160
+ print(e)
161
+ finished = True
162
+ blocked = False
163
+ continue
164
+ except tweepy.errors.BadRequest as e:
165
+ print("bad request error")
166
+ print(e)
167
+ finished = True
168
+ blocked = False
169
+ continue
170
+ except:
171
+ time.sleep(240)
172
+ continue
173
+ #time.sleep(1)
174
+ finished = True
175
+ try:
176
+ me = client.get_me()
177
+ print("{} blocked {}, for {}".format(me.data["username"], user, reason))
178
+ except tweepy.errors.TooManyRequests as e:
179
+ print("Blocked {}, for {}".format(user, reason))
180
  return blocked
181
 
 
182
  def block_users(client, threshold, dataset):
183
  '''
184
  Used for blocking a series of users based on the threshold and datasets provided. Here the users folder is used.
 
189
  '''
190
  num_users_blocked = 0
191
 
 
192
  for filename in os.listdir("users"):
193
  filename = os.path.join("users", filename)
194
  print("File {} open".format(filename))
 
197
 
198
  for user in users:
199
  print("Reviewing user {}".format(user))
200
+
201
+ if "threshold" in user:
202
+ # old type of dataset being used, only 'violent' data available
203
+ if "Violent" in dataset:
204
+ if user["threshold"] >= threshold:
205
+
206
+ user_id = str(user["username"])
207
+ if block_user(user_id, user, "Violent - old dataset"):
208
+ num_users_blocked = num_users_blocked + 1
209
+ else:
210
+ # modern dataset being used
211
+ if "Violent" in dataset:
212
+ if user["violence-threshold"] >= threshold:
213
+ user_id = str(user["username"])
214
+ if block_user(user_id, user, "Violent"):
215
+ num_users_blocked = num_users_blocked + 1
216
+ continue
217
+ if "Hate Speech" in dataset:
218
+ if user["toxicity-threshold"] >= threshold:
219
+ user_id = str(user["username"])
220
+ if block_user(user_id, user, "Hate Speech"):
221
+ num_users_blocked = num_users_blocked + 1
222
+ continue
223
+
224
 
225
  return num_users_blocked
226
 
227
 
228
  def chat(selected_option=None, radio_score=None, url_params=None):
229
  '''
230
+ This function is used to initialise blocking users once the user has authenticated with Twitter.
231
  :param selected_option:
232
  :param radio_score:
233
  :param url_params:
 
239
  history = []
240
 
241
  # app id
242
+ if "oauth_verifier" in url_params and "oauth_token" in url_params and client is None:
243
+ client = get_client_from_tokens(url_params["oauth_verifier"], url_params["oauth_token"])
244
  if radio_score != None and selected_option != None:
245
 
246
  if client != None:
 
256
 
257
  # Display to user, set options
258
  history.append(
259
+ ["Model tuned to a '{}%' threshold and is using the {} dataset.".format(radio_score, block_type.capitalize()),
 
260
  "{} Account blocking initialised".format(block_type.capitalize())])
261
  num_users_blocked = block_users(client, radio_score, selected_option)
262
  history.append(
 
291
 
292
  def update_target_website():
293
  '''
294
+ Updates the URL used to authenticate WatchTower with Twitter.
295
  #TODO this function is full of old code and can be optimised.
296
  :return:
297
  '''
 
305
  name = "no username"
306
 
307
  chat_history = [
308
+ ["Welcome to Watchtower.".format(name), "Log in via Twitter and configure your blocking options above."]]
309
 
310
  chatbot.value = chat_history
311
  chatbot.update(value=chat_history)
312
 
313
+ 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(
314
  get_target_website())
315
+ twitter_auth_button.update(
316
+ 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(
317
  get_target_website()))
318
 
319
+ 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(
320
+ get_target_website())
321
 
322
 
323
  # The below is a JS blob used to retrieve the URL params.
 
330
  return [text_input, url_params];
331
  }
332
  """
 
 
 
 
 
 
 
 
 
333
 
334
  def get_chatbot_text():
335
+ return [('Welcome to Watchtower.', 'Log in via Twitter and configure your blocking options above.')]
336
 
337
+ def get_target_website():
 
338
  '''
339
+ A wrapper function used for retrieving the URL a user will use to authenticate WatchTower with Twitter.
340
+ :return:
341
  '''
342
+ oauth1_user_handler = tweepy.OAuth1UserHandler(
343
+ consumer_token, consumer_secret,
344
+ callback="https://hf.space/embed/User1342/WatchTower/"
345
+ )
346
+ target_website = oauth1_user_handler.get_authorization_url(signin_with_twitter=True)
347
 
348
+ return target_website
 
349
 
350
 
351
+ # The Gradio HTML component used for the 'sign in with Twitter' button
352
 
353
  # The main chunk of code that uses Gradio blocks to create the UI
354
  html_button = None
 
355
  with block:
356
+
357
+
358
  gr.HTML('''
359
  <meta name="viewport" content="width=device-width, initial-scale=1">
360
  <link rel="stylesheet" href="https://www.w3schools.com/w3css/4/w3.css">
 
362
 
363
  # todo check if user signed in
364
 
365
+ user_message = "Log in via Twitter and configure your blocking options above."
366
+ chat_history.append(["Welcome to Watchtower.", user_message])
367
  gr.HTML(value=html_data)
368
  with gr.Group():
369
  with gr.Row().style(equal_height=True):
370
  with gr.Box():
371
+ #gr.Label(value="WatchTower", visible=True, interactive=False)
372
  url_params = gr.JSON({}, visible=False, label="URL Params").style(
373
  )
374
  text_input = gr.Text(label="Input", visible=False).style()
375
  text_output = gr.Text(label="Output", visible=False).style()
376
+ html_button = twitter_auth_button = gr.HTML(
377
+ 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(
378
+ get_target_website())).style(
379
+ )
 
 
380
  with gr.Row().style(equal_height=True):
381
+ radio = gr.CheckboxGroup(value=["Violent", "Hate Speech"], choices=["Violent", "Hate Speech", "Misinformation"],
382
+ interactive=False, label="Behaviour To Block").style()
 
383
 
384
+ slider = gr.Slider(value=30, interactive=True, label="Threshold Confidence Tolerance")
385
+
386
+ chatbot = gr.Chatbot(label="Watchtower Output", value=get_chatbot_text()).style(color_map=["blue","grey"])
387
 
 
 
 
388
 
389
  btn = gr.Button("Run WatchTower").style(full_width=True).style()
 
390
  btn.click(fn=button_pressed, inputs=[slider, url_params],
391
  outputs=[text_output, chatbot], _js=get_window_url_params)
392
  gr.Markdown(
393
  """___
394
  <p style='text-align: center'>
395
+ Created by <a href="https://twitter.com/_JamesStevenson" target="_blank"</a> James Stevenson
396
  <br/>
397
  </p>"""
398
  )
399
 
400
+ # Setup callback for when page loads (used to set a new Twitter auth target webspage)
401
  block.__enter__()
402
  block.set_event_trigger(
403
  event_name="load", fn=update_target_website, inputs=None, outputs=[html_button], no_target=True
404
  )
 
405
  block.set_event_trigger(
406
  event_name="load", fn=get_chatbot_text, inputs=None, outputs=[chatbot], no_target=True
407
  )
408
 
409
+ #block.attach_load_events()
410
 
411
  # Launcg the page
412
+ block.launch(enable_queue = True)