Maria Tsilimos commited on
Commit
190c620
·
unverified ·
1 Parent(s): 00afd19

Create app.py

Browse files
Files changed (1) hide show
  1. app.py +386 -0
app.py ADDED
@@ -0,0 +1,386 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import requests
2
+ import streamlit as st
3
+ from bs4 import BeautifulSoup
4
+ import pandas as pd
5
+ from transformers import pipeline
6
+ import plotly.express as px
7
+ import time
8
+ import io
9
+ import os
10
+ from comet_ml import Experiment
11
+ import zipfile
12
+ import re
13
+ from streamlit_extras.stylable_container import stylable_container
14
+
15
+
16
+ st.set_page_config(layout="wide", page_title="Named Entity Recognition App")
17
+
18
+
19
+
20
+
21
+ COMET_API_KEY = os.environ.get("COMET_API_KEY")
22
+ COMET_WORKSPACE = os.environ.get("COMET_WORKSPACE")
23
+ COMET_PROJECT_NAME = os.environ.get("COMET_PROJECT_NAME")
24
+
25
+ comet_initialized = False
26
+ if COMET_API_KEY and COMET_WORKSPACE and COMET_PROJECT_NAME:
27
+ comet_initialized = True
28
+
29
+
30
+
31
+ st.subheader("58-Italian Named Entity Recognition Web App", divider="rainbow")
32
+ st.link_button("by nlpblogs", "https://nlpblogs.com", type="tertiary")
33
+
34
+ expander = st.expander("**Important notes on the 58-Italian-Named Entity Recognition Web App**")
35
+ expander.write('''
36
+
37
+ **Named Entities:**
38
+ This 58-Italian-Named Entity Recognition Web App predicts fifty-eight (58) labels
39
+
40
+ ("**INDIRIZZO**: Identifica un indirizzo fisico.
41
+
42
+ **VALUTA**: Rappresenta una valuta.
43
+
44
+ **CVV**: Codice di sicurezza della carta di credito.
45
+
46
+ **NUMERO_CONTO**: Numero di un conto bancario.
47
+
48
+ **BIC**: Codice identificativo di una banca (Bank Identifier Code).
49
+
50
+ **IBAN**: Numero di conto bancario internazionale.
51
+
52
+ **STATO**: Identifica un paese o una nazione.
53
+
54
+ **NOME**: Riferito al nome di una persona.
55
+
56
+ **COGNOME**: Riferito al cognome di una persona.
57
+
58
+ **CODICE_POSTALE**: Codice postale di un'area geografica.
59
+
60
+ **IP**: Indirizzo IP di un dispositivo in rete.
61
+
62
+ **ORARIO**: Riferito a un orario specifico.
63
+
64
+ **URL**: Indirizzo web (Uniform Resource Locator).
65
+
66
+ **LUOGO**: Identifica un luogo geografico.
67
+
68
+ **IMPORTO**: Riferito a una somma di denaro.
69
+
70
+ **EMAIL**: Indirizzo di posta elettronica.
71
+
72
+ **PASSWORD**: Parola chiave per l'accesso a sistemi protetti.
73
+
74
+ **NUMERO_CARTA**: Numero di una carta di credito o debito.
75
+
76
+ **TARGA_VEICOLO**: Numero di targa di un veicolo.
77
+
78
+ **DATA_NASCITA**: Data di nascita di una persona.
79
+
80
+ **DATA_MORTE**: Data di decesso di una persona.
81
+
82
+ **RAGIONE_SOCIALE**: Nome legale di un'azienda o entità commerciale.
83
+
84
+ **ETA**: Età di una persona.
85
+
86
+ **DATA**: Riferita a una data generica.
87
+
88
+ **PROFESSIONE**: Occupazione o lavoro di una persona.
89
+
90
+ **PIN**: Numero di identificazione personale.
91
+
92
+ **NUMERO_TELEFONO**: Numero telefonico.
93
+
94
+ **FOGLIO**: Riferito a un foglio di documentazione.
95
+
96
+ **PARTICELLA**: Riferito a una particella catastale.
97
+
98
+ **CARTELLA_CLINICA**: Documentazione medica di un paziente.
99
+
100
+ **MALATTIA**: Identifica una malattia o condizione medica.
101
+
102
+ **MEDICINA**: Riferito a un farmaco o trattamento medico.
103
+
104
+ **CODICE_FISCALE**: Codice fiscale personale o aziendale.
105
+
106
+ **NUMERO_DOCUMENTO**: Numero di un documento ufficiale.
107
+
108
+ **STORIA_CLINICA**: Registro delle condizioni mediche di un paziente.
109
+
110
+ **AVV_NOTAIO**: Identifica un avvocato o notaio.
111
+
112
+ **P_IVA**: Partita IVA di un'azienda o professionista.
113
+
114
+ **LEGGE**: Riferito a una legge specifica.
115
+
116
+ **TASSO_MUTUO**: Tasso di interesse di un mutuo.
117
+
118
+ **N_SENTENZA**: Numero di una sentenza legale.
119
+
120
+ **MAPPALE**: Riferito a un mappale catastale.
121
+
122
+ **SUBALTERNO**: Riferito a un subalterno catastale.
123
+
124
+ **REGIME_PATRIMONIALE**: Stato patrimoniale in ambito legale.
125
+
126
+ **STATO_CIVILE**: Stato civile di una persona.
127
+
128
+ **BANCA**: Identifica una banca o istituto di credito.
129
+
130
+ **BRAND**: Marchio o brand commerciale.
131
+
132
+ **NUM_ASSEGNO_BANCARIO**: Numero di un assegno bancario.
133
+
134
+ **IMEI**: Numero di identificazione internazionale di un dispositivo mobile.
135
+
136
+ **N_LICENZA**: Numero di una licenza specifica.
137
+
138
+ **IPV6_1**: Indirizzo IP versione 6.
139
+
140
+ **MAC**: Indirizzo MAC di un dispositivo di rete.
141
+
142
+ **USER_AGENT**: Identifica il software usato per accedere a una rete.
143
+
144
+ **TRIBUNALE**: Identifica un tribunale specifico.
145
+
146
+ **STRENGTH**: Riferito alla forza o intensità di del medicinale.
147
+
148
+ **FREQUENZA**: Riferito alla frequenza di un trattamento medico.
149
+
150
+ **DURATION**: Durata di un evento o trattamento.
151
+
152
+ **DOSAGGIO**: Quantità di un medicinale da assumere.
153
+
154
+ **FORM**: Forma del medicinale, ad esempio compresse").
155
+
156
+ Results are presented in an easy-to-read table, visualized in an interactive tree map, pie chart, and bar chart, and are available for download along with a Glossary of tags.
157
+
158
+ **How to Use:**
159
+ Paste a URL, and then press Enter. If you type or paste text, just press Ctrl + Enter.
160
+
161
+ **Usage Limits:**
162
+ You can request results up to 10 times.
163
+
164
+ **Customization:**
165
+ To change the app's background color to white or black, click the three-dot menu on the right-hand side of your app, go to Settings and then Choose app theme, colors and fonts.
166
+
167
+ **Technical issues:**
168
+ If your connection times out, please refresh the page or reopen the app's URL.
169
+
170
+ For any errors or inquiries, please contact us at [email protected]
171
+
172
+ ''')
173
+
174
+
175
+
176
+
177
+
178
+
179
+ with st.sidebar:
180
+ container = st.container(border=True)
181
+ container.write("**Named Entity Recognition (NER)** is the task of extracting and tagging entities in text data. Entities can be persons, organizations, locations, countries, products, events etc.")
182
+ st.subheader("Related NLP Web Apps", divider="rainbow")
183
+ st.link_button("8-Named Entity Recognition Web App", "https://nlpblogs.com/shop/named-entity-recognition-ner/8-named-entity-recognition-web-app/", type="primary")
184
+
185
+
186
+ if 'source_type_attempts' not in st.session_state:
187
+ st.session_state['source_type_attempts'] = 0
188
+ max_attempts = 10
189
+
190
+ def clear_url_input():
191
+
192
+ st.session_state.url = ""
193
+
194
+ def clear_text_input():
195
+
196
+ st.session_state.my_text_area = ""
197
+
198
+ url = st.text_input("Enter URL from the internet, and then press Enter:", key="url")
199
+ st.button("Clear URL", on_click=clear_url_input)
200
+
201
+ text = st.text_area("Type or paste your text below, and then press Ctrl + Enter", key='my_text_area')
202
+ st.button("Clear Text", on_click=clear_text_input)
203
+
204
+
205
+ source_type = None
206
+ input_content = None
207
+ text_to_process = None
208
+
209
+ if url:
210
+ source_type = 'url'
211
+ input_content = url
212
+ elif text:
213
+ source_type = 'text'
214
+ input_content = text
215
+
216
+ if source_type:
217
+
218
+ st.subheader("Results", divider = "rainbow")
219
+
220
+
221
+ if st.session_state['source_type_attempts'] >= max_attempts:
222
+ st.error(f"You have requested results {max_attempts} times. You have reached your daily request limit.")
223
+ st.stop()
224
+
225
+ st.session_state['source_type_attempts'] += 1
226
+
227
+
228
+ @st.cache_resource
229
+ def load_ner_model():
230
+
231
+ return pipeline("token-classification", model="DeepMount00/Italian_NER_XXL", aggregation_strategy="max")
232
+
233
+ model = load_ner_model()
234
+ experiment = None
235
+
236
+ try:
237
+ if source_type == 'url':
238
+ if not url.startswith(("http://", "https://")):
239
+ st.error("Please enter a valid URL starting with 'http://' or 'https://'.")
240
+ else:
241
+ with st.spinner(f"Fetching and parsing content from **{url}**...", show_time=True):
242
+ f = requests.get(url, timeout=10)
243
+ f.raise_for_status() # Raise an HTTPError for bad responses (4xx or 5xx)
244
+ soup = BeautifulSoup(f.text, 'html.parser')
245
+ text_to_process = soup.get_text(separator=' ', strip=True)
246
+ st.divider()
247
+ st.write("**Input text content**")
248
+ st.write(text_to_process[:500] + "..." if len(text_to_process) > 500 else text_to_process)
249
+
250
+
251
+
252
+ elif source_type == 'text':
253
+ text_to_process = text
254
+ st.divider()
255
+ st.write("**Input text content**")
256
+
257
+ st.write(text_to_process[:500] + "..." if len(text_to_process) > 500 else text_to_process)
258
+
259
+ if text_to_process and len(text_to_process.strip()) > 0:
260
+ with st.spinner("Analyzing text...", show_time=True):
261
+ entities = model(text_to_process)
262
+ data = []
263
+ for entity in entities:
264
+ data.append({
265
+ 'word': entity['word'],
266
+ 'entity_group': entity['entity_group'],
267
+ 'score': entity['score'],
268
+ 'start': entity['start'], # Include start and end for download
269
+ 'end': entity['end']
270
+ })
271
+ df = pd.DataFrame(data)
272
+
273
+
274
+ pattern = r'[^\w\s]'
275
+ df['word'] = df['word'].replace(pattern, '', regex=True)
276
+
277
+ df = df.replace('', 'Unknown')
278
+ st.dataframe(df)
279
+
280
+
281
+ if comet_initialized:
282
+ experiment = Experiment(
283
+ api_key=COMET_API_KEY,
284
+ workspace=COMET_WORKSPACE,
285
+ project_name=COMET_PROJECT_NAME,
286
+ )
287
+ experiment.log_parameter("input_source_type", source_type)
288
+ experiment.log_parameter("input_content_length", len(input_content))
289
+ experiment.log_table("predicted_entities", df)
290
+
291
+ with st.expander("See Glossary of tags"):
292
+ st.write('''
293
+ '**word**': ['entity extracted from your text data']
294
+
295
+ '**score**': ['accuracy score; how accurately a tag has been assigned to a given entity']
296
+
297
+ '**entity_group**': ['label (tag) assigned to a given extracted entity']
298
+
299
+ '**start**': ['index of the start of the corresponding entity']
300
+
301
+ '**end**': ['index of the end of the corresponding entity']
302
+
303
+ ''')
304
+
305
+
306
+ if not df.empty:
307
+
308
+ st.markdown("---")
309
+ st.subheader("Treemap", divider="rainbow")
310
+ fig = px.treemap(df, path=[px.Constant("all"), 'entity_group', 'word'],
311
+ values='score', color='entity_group',
312
+ )
313
+ fig.update_layout(margin=dict(t=50, l=25, r=25, b=25))
314
+ st.plotly_chart(fig, use_container_width=True)
315
+ if comet_initialized and experiment:
316
+ experiment.log_figure(figure=fig, figure_name="entity_treemap")
317
+
318
+
319
+
320
+ value_counts = df['entity_group'].value_counts().reset_index()
321
+ value_counts.columns = ['entity_group', 'count']
322
+
323
+ col1, col2 = st.columns(2)
324
+ with col1:
325
+ st.subheader("Pie Chart", divider="rainbow")
326
+ fig1 = px.pie(value_counts, values='count', names='entity_group',
327
+ hover_data=['count'], labels={'count': 'count'},
328
+ title='Percentage of Predicted Labels')
329
+ fig1.update_traces(textposition='inside', textinfo='percent+label')
330
+ st.plotly_chart(fig1, use_container_width=True)
331
+ if comet_initialized and experiment: # Check if experiment is initialized
332
+ experiment.log_figure(figure=fig1, figure_name="label_pie_chart")
333
+
334
+ with col2:
335
+ st.subheader("Bar Chart", divider="rainbow")
336
+ fig2 = px.bar(value_counts, x="count", y="entity_group", color="entity_group",
337
+ text_auto=True, title='Occurrences of Predicted Labels')
338
+ st.plotly_chart(fig2, use_container_width=True)
339
+ if comet_initialized and experiment: # Check if experiment is initialized
340
+ experiment.log_figure(figure=fig2, figure_name="label_bar_chart")
341
+ else:
342
+ st.warning("No entities were extracted from the provided text.")
343
+
344
+
345
+
346
+ dfa = pd.DataFrame(
347
+ data={
348
+ 'word': ['entity extracted from your text data'],
349
+ 'score': ['accuracy score; how accurately a tag has been assigned to a given entity'],
350
+ 'entity_group': ['label (tag) assigned to a given extracted entity'],
351
+ 'start': ['index of the start of the corresponding entity'],
352
+ 'end': ['index of the end of the corresponding entity'],
353
+
354
+
355
+ }
356
+ )
357
+ buf = io.BytesIO()
358
+ with zipfile.ZipFile(buf, "w") as myzip:
359
+ if not df.empty:
360
+ myzip.writestr("Summary_of_results.csv", df.to_csv(index=False))
361
+ myzip.writestr("Glossary_of_tags.csv", dfa.to_csv(index=False))
362
+
363
+ with stylable_container(
364
+ key="download_button",
365
+ css_styles="""button { background-color: yellow; border: 1px solid black; padding: 5px; color: black; }""",
366
+ ):
367
+ st.download_button(
368
+ label="Download zip file",
369
+ data=buf.getvalue(),
370
+ file_name="nlpblogs_ner_results.zip",
371
+ mime="application/zip",)
372
+
373
+
374
+
375
+ st.divider()
376
+ else:
377
+ st.warning("No meaningful text found to process. Please enter a URL or text.")
378
+
379
+
380
+ except Exception as e:
381
+ st.error(f"An unexpected error occurred: {e}")
382
+ finally:
383
+ if comet_initialized and experiment:
384
+ experiment.end()
385
+
386
+ st.write(f"Number of times you requested results: **{st.session_state['source_type_attempts']}/{max_attempts}**")