Iker commited on
Commit
0f36bab
1 Parent(s): 21a2d13
Files changed (4) hide show
  1. README.md +3 -3
  2. app.py +253 -0
  3. guidelines.py +81 -0
  4. requirements.txt +4 -0
README.md CHANGED
@@ -1,8 +1,8 @@
1
  ---
2
- title: ClickbaitAnnotation
3
- emoji: 🚀
4
  colorFrom: green
5
- colorTo: blue
6
  sdk: gradio
7
  sdk_version: 4.19.2
8
  app_file: app.py
 
1
  ---
2
+ title: 🖱️ Clickbait Annotation Platform
3
+ emoji: 🖱️
4
  colorFrom: green
5
+ colorTo: red
6
  sdk: gradio
7
  sdk_version: 4.19.2
8
  app_file: app.py
app.py ADDED
@@ -0,0 +1,253 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import json
2
+ import os
3
+ import random
4
+ import string
5
+
6
+ import gradio as gr
7
+ import huggingface_hub
8
+ from datasets import load_dataset
9
+ from evaluate import load
10
+
11
+ from guidelines import guidelines
12
+
13
+ human2_annotation_file = "human2/test-human2.jsonl"
14
+ space = "Iker/ClickbaitAnnotation"
15
+
16
+
17
+ def clean_text(text: str) -> str:
18
+ # Remove punctuation
19
+ text = text.translate(str.maketrans("", "", string.punctuation))
20
+
21
+ # Remove newlines and multiple spaces
22
+ text = text.replace("\n", " ").strip()
23
+ text = " ".join(text.split()).strip()
24
+
25
+ # lowercase
26
+ text = text.lower()
27
+
28
+ return text
29
+
30
+
31
+ def html_progress_bar(completed_steps, total_steps):
32
+ percentage = (completed_steps / total_steps) * 100
33
+ return f"""
34
+ <!DOCTYPE html>
35
+ <html lang="en">
36
+ <head>
37
+ <meta charset="UTF-8">
38
+ <meta name="viewport" content="width=device-width, initial-scale=1.0">
39
+ <title>Progress Bar</title>
40
+ <style>
41
+ .progress-container {{
42
+ width: 100%;
43
+ background-color: #ffffff;
44
+ }}
45
+
46
+ .progress-bar {{
47
+ width: {percentage}%;
48
+ height: 30px;
49
+ background-color: #d1fae5;
50
+ text-align: center;
51
+ line-height: 30px;
52
+ color: white;
53
+ }}
54
+ </style>
55
+ </head>
56
+ <body>
57
+
58
+ <div class="progress-container">
59
+ <div class="progress-bar">{percentage:.0f}%</div>
60
+ </div>
61
+
62
+ </body>
63
+ </html>
64
+ """
65
+
66
+
67
+ class AnnotationManager:
68
+ def __init__(self):
69
+ self.dataset = list(
70
+ load_dataset(
71
+ "Iker/NoticIA", token=os.environ.get("TOKEN") or True, split="test"
72
+ )
73
+ )
74
+
75
+ self.total = len(self.dataset)
76
+ self.predictions = []
77
+ self.references = []
78
+
79
+ print(f"Total examples: {self.total}")
80
+
81
+ try:
82
+ huggingface_hub.hf_hub_download(
83
+ repo_id=space,
84
+ repo_type="space",
85
+ token=os.environ.get("TOKEN") or True,
86
+ filename=human2_annotation_file,
87
+ local_dir=os.getcwd(),
88
+ )
89
+
90
+ with open(human2_annotation_file, "r") as f:
91
+ annotations = f.readlines()
92
+
93
+ annotations = [json.loads(a) for a in annotations]
94
+ for a in annotations:
95
+ self.predictions.append(clean_text(a["summary2"]))
96
+ self.references.append([clean_text(a["summary"])])
97
+
98
+ self.dataset = self.dataset[len(annotations) :]
99
+ except Exception:
100
+ print("Unable to download annotations. Starting from the beginning.")
101
+
102
+ self.current = None
103
+
104
+ def get_next(self):
105
+ if len(self.dataset) == 0:
106
+ return "🎉 Anotación Finalizada 🎉", "🎉 Anotación Finalizada 🎉"
107
+ self.current = self.dataset.pop(0)
108
+ return self.current["web_headline"], self.current["web_text"]
109
+
110
+ def save_annotation(self, annotation):
111
+ if len(annotation) > 0:
112
+ example = {
113
+ "web_url": self.current["web_url"],
114
+ "web_headline": self.current["web_headline"],
115
+ "summary": self.current["summary"],
116
+ "summary2": annotation,
117
+ "web_text": self.current["web_text"],
118
+ "clean_web_text": self.current["clean_web_text"],
119
+ }
120
+
121
+ if not os.path.exists(human2_annotation_file):
122
+ os.makedirs(os.path.dirname(human2_annotation_file), exist_ok=True)
123
+ with open(human2_annotation_file, "w", encoding="utf8") as f:
124
+ print(json.dumps(example, ensure_ascii=False), file=f)
125
+ else:
126
+ with open(human2_annotation_file, "a", encoding="utf8") as f:
127
+ print(json.dumps(example, ensure_ascii=False), file=f)
128
+
129
+ self.predictions.append(clean_text(annotation))
130
+ self.references.append([clean_text(example["summary"])])
131
+
132
+ huggingface_hub.upload_file(
133
+ repo_id=space,
134
+ repo_type="space",
135
+ token=os.environ.get("TOKEN") or True,
136
+ path_in_repo=human2_annotation_file,
137
+ path_or_fileobj=human2_annotation_file,
138
+ )
139
+
140
+ next_headline, next_text = self.get_next()
141
+
142
+ return next_headline, next_text, self.get_rouge(), self.progress(), ""
143
+
144
+ def get_rouge(self):
145
+ try:
146
+ experiment_id = "".join(
147
+ random.choice(string.ascii_uppercase + string.digits) for _ in range(6)
148
+ )
149
+ rouge = load("rouge", experiment_id=experiment_id)
150
+
151
+ return rouge.compute(
152
+ predictions=self.predictions,
153
+ references=self.references,
154
+ use_aggregator=True,
155
+ rouge_types=["rouge1"],
156
+ )["rouge1"]
157
+ except Exception:
158
+ return "N/A"
159
+
160
+ def progress(self):
161
+ # Return first number represents steps completed, and second value represents total steps
162
+ return html_progress_bar(self.total - len(self.dataset), self.total)
163
+
164
+ def gr_start(self):
165
+ if self.current is not None:
166
+ return (
167
+ self.current["web_headline"],
168
+ self.current["web_text"],
169
+ self.get_rouge(),
170
+ self.progress(),
171
+ "",
172
+ )
173
+ headline, text = self.get_next()
174
+ return headline, text, self.get_rouge(), self.progress(), ""
175
+
176
+
177
+ theme = gr.themes.Soft(
178
+ primary_hue="emerald",
179
+ secondary_hue="red",
180
+ text_size="sm",
181
+ spacing_size="sm",
182
+ font=[
183
+ gr.themes.GoogleFont("Poppins"),
184
+ gr.themes.GoogleFont("Poppins"),
185
+ gr.themes.GoogleFont("Poppins"),
186
+ gr.themes.GoogleFont("Poppins"),
187
+ ],
188
+ ).set(block_background_fill="*neutral_50", block_background_fill_dark="*neutral_950")
189
+
190
+ manager = AnnotationManager()
191
+
192
+
193
+ with gr.Blocks(
194
+ theme=theme, title="🖱️ Resumen de noticias Clickbait 🖱️", analytics_enabled=False
195
+ ) as demo:
196
+ with gr.Tab("Guidelines") as tab_guidelines:
197
+ gr.Markdown(guidelines)
198
+
199
+ with gr.Tab("Anotación") as tab_annotation:
200
+ gr_play = gr.Button("▶️ Empieza a anotar")
201
+
202
+ gr_progress = gr.HTML(value=manager.progress(), label="Progreso")
203
+
204
+ gr_rouge = gr.Textbox(
205
+ value="Pulsa ▶️",
206
+ label="Rouge-1",
207
+ info="Rouge Score actual entre las anotaciones y los resúmenes de referencia.",
208
+ lines=1,
209
+ interactive=False,
210
+ )
211
+
212
+ gr_headline = gr.Textbox(
213
+ value="Pulsa ▶️",
214
+ label="Titular",
215
+ info="El titular del artículo.",
216
+ lines=2,
217
+ interactive=False,
218
+ )
219
+
220
+ gr_body = gr.Textbox(
221
+ value="Pulsa ▶️",
222
+ label="Artículo",
223
+ info="El cuerpo del artículo/noticia.",
224
+ lines=10,
225
+ interactive=False,
226
+ )
227
+
228
+ gr_summary = gr.Textbox(
229
+ value="",
230
+ label="Resumen",
231
+ info="Escribe aquí el resumen del artículo. Recuerda leer las guidelines antes de empezar.",
232
+ lines=2,
233
+ interactive=True,
234
+ )
235
+
236
+ save = gr.Button(
237
+ "💾 Guardar",
238
+ )
239
+
240
+ save.click(
241
+ fn=manager.save_annotation,
242
+ inputs=[gr_summary],
243
+ outputs=[gr_headline, gr_body, gr_rouge, gr_progress, gr_summary],
244
+ )
245
+
246
+ gr_play.click(
247
+ fn=manager.gr_start,
248
+ inputs=None,
249
+ outputs=[gr_headline, gr_body, gr_rouge, gr_progress, gr_summary],
250
+ )
251
+
252
+
253
+ demo.launch()
guidelines.py ADDED
@@ -0,0 +1,81 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ guidelines = """
2
+ ## Guidelines
3
+ ### ¿Que es un artículo clickbait?
4
+ Definimos un artículo clickbait como un artículo que busca atraer la atención del lector a través de la curiosidad. Para ello, el titular
5
+ plantea una pregunta o una afirmación incompleta, sansacionalista, exagerada o engañosa. La respuesta a la pregunta generada en el titular,
6
+ no suele aparecer hasta el final del artículo, la cual es precedida por una gran cantidad de contenido irrelevante.
7
+ El objetivo es que el usuario entre en la web a través del titular y después haga scroll hasta el final del artículo haciendole ver la mayor
8
+ cantidad de publicidad posible. Los artículos clickbait suelen ser de baja calidad y no aportan valor al lector, más allá de la curiosidad inicial.
9
+
10
+ ```
11
+ # La impactante predicción del tiempo de Jorge Rey para el puente de diciembre
12
+ En el mundo de la meteorología, hay nombres que resuenan con autoridad y precisión.
13
+ Uno de ellos es Jorge Rey, el joven burgalés que, a sus dieciséis años, ha sorprendido a España
14
+ con sus predicciones climáticas. Sus métodos [...]
15
+ Refiriéndose a un refrán popular: "Año de bellotas, año de nieve hasta las pelotas".
16
+ Esto sugiere una ola de frío invernal que podría coincidir con el inicio de diciembre.
17
+ ```
18
+ Resumen del artículo:
19
+ ```
20
+ El inicio de un periodo frío intenso.
21
+ ```
22
+
23
+ ### Dataset
24
+ En nuestro dataset, cada ejemplo contiene un titular de un artículo y el contenido del artículo. El objetivo es generar un resumen del artículo
25
+ que responda a la pregunta o afirmación planteada en el titular.
26
+
27
+ ### Anotación
28
+ Para cada ejemplo, se proporciona un titular y el cuerpo del artículo. El obejetivo es generar un resumen del artículo que responda a la pregunta
29
+ - Debes buscar en el cuerpo del artículo una frase que responda la pregunta que plantea el titular.
30
+ - Si es posible, el resumen debe parafrasear el texto original. Si parafraseas el texto original, añade "comillas" al texto parafraseado.
31
+ - El resumen debe tener las mínimas palabras posibles.
32
+ - No nos interesa ninguna información extra o aclaración adicional. El resumen debe una respuesta lo más consisa posible.
33
+
34
+ #### Ejemplos de anotación
35
+
36
+ ```
37
+ # El cambio en las matrículas que se espera para el mes de septiembre
38
+ Si eres de los que sigues el avance de las matriculaciones (como nosotros que, cada día,
39
+ buscamos cuál ha sido la última combinación asignada) es posible que estés pendiente del [...]
40
+ será en septiembre cuando se dé el salto a la M.
41
+
42
+ - Resumen del artículo: Se dará el salto a la letra M.
43
+ ```
44
+
45
+ ```
46
+ # Estos serán los lenguajes de programación con más salida en 2024. Puedes empezar a aprenderlos gratis
47
+ Si con el año nuevo te has propuesto aumentar tu empleabilidad aprendiendo un nuevo lenguaje de programación o [...]
48
+ Que JavaScript sea el número 1 de Stack Overflow no es una sorpresa, considerando que es su undécimo año consecutivo
49
+ mandando en la lista. No obstante, cabe destacar la subida de Python hasta el tercer puesto,
50
+ que ojo se coloca en el primer puesto para quienes no se dedican profesionalmente al desarrollo.
51
+
52
+ - Resumen del artículo: Python y JavaScript.
53
+ ```
54
+
55
+ ```
56
+ # TIKTOK: Una azafata destapa la razón por la que no deberías tomar café en los aviones
57
+ Un pasajero se toma un café a bordo de un avión Chalabala Nadie [...]
58
+ Una pasajera almuerza en un avión Astakhovyaroslav "El agua que usamos para el café y el
59
+ té proviene del mismo lugar, ¿y adivinen qué? Nunca se limpia" asegura en la publicación.
60
+
61
+ - Resumen del artículo: "El agua que usamos para el café y el té proviene del mismo lugar, ¿y adivinen qué? Nunca se limpia".
62
+ ```
63
+
64
+ ```
65
+ # Canción de Iron Maiden más difícil de cantar para Bruce Dickinson
66
+ Iron Maiden es una legendaria banda de heavy metal, fundada por Steve Harris en 1975, [...]
67
+ «La canción que encuentro más difícil de cantar en el repertorio de Maiden es ‘Aces High’.
68
+
69
+ - Resumen del artículo: "Aces High".
70
+ ```
71
+
72
+ ```
73
+ # La bonita causa a la que Guillermo dona 6.287 euros tras resolver el Panel final en La ruleta
74
+ El concursante ha puesto el broche de oro a un concurso perfecto. ¡Jorge Fernández ha [...]
75
+ Un dinero que será destinado a la lucha contra el maltrato y el abandono animal.
76
+
77
+ - Resumen del artículo: Será destinado a la lucha contra el maltrato y el abandono animal.
78
+
79
+ ```
80
+
81
+ """.strip()
requirements.txt ADDED
@@ -0,0 +1,4 @@
 
 
 
 
 
1
+ gradio
2
+ setuptools
3
+ huggingface_hub
4
+ rouge_score