Maria Tsilimos commited on
Commit
57df577
·
unverified ·
1 Parent(s): 701fd8d

Update app.py

Browse files
Files changed (1) hide show
  1. app.py +99 -95
app.py CHANGED
@@ -6,76 +6,69 @@ from transformers import pipeline
6
  from streamlit_extras.stylable_container import stylable_container
7
  import plotly.express as px
8
  import zipfile
9
-
10
  from PyPDF2 import PdfReader
11
  import docx
12
-
13
-
14
  import os
15
  from comet_ml import Experiment
16
  import re
17
- import numpy as np
18
-
19
-
20
-
21
 
22
- st.subheader("4-Named Entity Recognition Web App", divider = "rainbow")
23
- st.link_button("by nlpblogs", "https://nlpblogs.com", type = "tertiary")
24
 
25
- expander = st.expander("**Important notes on the 4-Named Entity Recognition Web App**")
26
- expander.write('''
27
-
28
- **Named Entities:**
29
- This 4-Named Entity Recognition Web App predicts four (4) labels (“PER: person”, “LOC: location”, “ORG: organization”, “MISC: miscellaneous”). 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.
30
-
31
- **How to Use:**
32
- Upload your .pdf or .docx file. Then, click the 'Results' button to extract and tag entities in your text data.
33
-
34
- **Usage Limits:**
35
- You can request results up to 10 times.
36
-
37
- **Customization:**
38
- 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.
39
-
40
- **Technical issues:**
41
- If your connection times out, please refresh the page or reopen the app's URL.
42
-
43
- For any errors or inquiries, please contact us at [email protected]
44
-
45
- ''')
46
-
47
-
48
- with st.sidebar:
49
- container = st.container(border=True)
50
- 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.")
51
- st.subheader("Related NLP Web Apps", divider = "rainbow")
52
- 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")
53
 
54
 
 
55
  COMET_API_KEY = os.environ.get("COMET_API_KEY")
56
  COMET_WORKSPACE = os.environ.get("COMET_WORKSPACE")
57
  COMET_PROJECT_NAME = os.environ.get("COMET_PROJECT_NAME")
58
 
 
59
  if COMET_API_KEY and COMET_WORKSPACE and COMET_PROJECT_NAME:
60
  comet_initialized = True
61
- else:
62
- comet_initialized = False
63
- st.warning("Comet ML not initialized. Check environment variables.")
64
-
65
-
66
 
 
67
  if 'file_upload_attempts' not in st.session_state:
68
  st.session_state['file_upload_attempts'] = 0
69
 
70
  max_attempts = 10
71
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
72
 
 
73
  upload_file = st.file_uploader("Upload your file. Accepted file formats include: .pdf, .docx", type=['pdf', 'docx'])
74
  text = None
75
  df = None
76
 
77
  if upload_file is not None:
78
-
79
  file_extension = upload_file.name.split('.')[-1].lower()
80
  if file_extension == 'pdf':
81
  try:
@@ -83,47 +76,53 @@ if upload_file is not None:
83
  text = ""
84
  for page in pdf_reader.pages:
85
  text += page.extract_text()
86
- st.write("Due to security protocols, the file content is hidden.")
87
  except Exception as e:
88
  st.error(f"An error occurred while reading PDF: {e}")
 
89
  elif file_extension == 'docx':
90
  try:
91
  doc = docx.Document(upload_file)
92
  text = "\n".join([para.text for para in doc.paragraphs])
93
- st.write("Due to security protocols, the file content is hidden.")
94
  except Exception as e:
95
  st.error(f"An error occurred while reading docx: {e}")
 
96
  else:
97
  st.warning("Unsupported file type.")
98
-
99
- st.stop()
100
-
101
 
102
  st.divider()
103
 
 
104
  if st.button("Results"):
 
 
 
105
  if st.session_state['file_upload_attempts'] >= max_attempts:
106
  st.error(f"You have requested results {max_attempts} times. You have reached your daily request limit.")
107
  st.stop()
 
 
 
 
 
108
  st.session_state['file_upload_attempts'] += 1
109
-
110
-
111
- with st.spinner("Wait for it...", show_time=True):
112
- time.sleep(5)
113
- model = pipeline("token-classification", model="dslim/distilbert-NER", aggregation_strategy = "max")
114
- text1 = model(text)
115
-
116
- df1 = pd.DataFrame(text1)
117
- pattern = r'[^\w\s]'
118
- df1['word'] = df1['word'].replace(pattern, '', regex=True)
119
 
120
- df2 = df1.replace('', 'Unknown')
121
- df = df2.dropna()
 
 
 
122
 
123
-
124
-
 
 
125
 
126
-
 
 
127
 
128
  if comet_initialized:
129
  experiment = Experiment(
@@ -131,12 +130,13 @@ if st.button("Results"):
131
  workspace=COMET_WORKSPACE,
132
  project_name=COMET_PROJECT_NAME,
133
  )
134
- experiment.log_parameter("input_text", text)
135
  experiment.log_table("predicted_entities", df)
136
 
 
137
  properties = {"border": "2px solid gray", "color": "blue", "font-size": "16px"}
138
  df_styled = df.style.set_properties(**properties)
139
- st.dataframe(df_styled)
140
 
141
  with st.expander("See Glossary of tags"):
142
  st.write('''
@@ -151,45 +151,48 @@ if st.button("Results"):
151
  '**end**': ['index of the end of the corresponding entity']
152
  ''')
153
 
154
- if df is not None:
155
- fig = px.treemap(df, path=[px.Constant("all"), 'word', 'entity_group'],
 
156
  values='score', color='entity_group')
157
- fig.update_layout(margin = dict(t=50, l=25, r=25, b=25))
158
- st.subheader("Tree map", divider = "rainbow")
159
- st.plotly_chart(fig)
 
 
 
 
 
 
 
 
 
 
 
160
  if comet_initialized:
161
- experiment.log_figure(figure=fig, figure_name="entity_treemap")
162
-
163
- if df is not None:
164
- value_counts1 = df['entity_group'].value_counts()
165
- df1 = pd.DataFrame(value_counts1)
166
- final_df = df1.reset_index().rename(columns={"index": "entity_group"})
167
- col1, col2 = st.columns(2)
168
- with col1:
169
- fig1 = px.pie(final_df, values='count', names='entity_group', hover_data=['count'], labels={'count': 'count'}, title='Percentage of predicted labels')
170
- fig1.update_traces(textposition='inside', textinfo='percent+label')
171
- st.subheader("Pie Chart", divider = "rainbow")
172
- st.plotly_chart(fig1)
173
- if comet_initialized:
174
- experiment.log_figure(figure=fig1, figure_name="label_pie_chart")
175
- with col2:
176
- fig2 = px.bar(final_df, x="count", y="entity_group", color="entity_group", text_auto=True, title='Occurrences of predicted labels')
177
- st.subheader("Bar Chart", divider = "rainbow")
178
- st.plotly_chart(fig2)
179
- if comet_initialized:
180
- experiment.log_figure(figure=fig2, figure_name="label_bar_chart")
181
 
 
 
 
 
 
 
 
 
182
  dfa = pd.DataFrame(
183
  data={
184
- 'word': ['entity extracted from your text data'], 'score': ['accuracy score; how accurately a tag has been assigned to a given entity'], 'entity_group': ['label (tag) assigned to a given extracted entity'],
 
 
185
  'start': ['index of the start of the corresponding entity'],
186
  'end': ['index of the end of the corresponding entity'],
187
- })
 
188
  buf = io.BytesIO()
189
  with zipfile.ZipFile(buf, "w") as myzip:
190
  myzip.writestr("Summary of the results.csv", df.to_csv(index=False))
191
  myzip.writestr("Glossary of tags.csv", dfa.to_csv(index=False))
192
-
193
 
194
  with stylable_container(
195
  key="download_button",
@@ -198,7 +201,7 @@ if st.button("Results"):
198
  st.download_button(
199
  label="Download zip file",
200
  data=buf.getvalue(),
201
- file_name="zip file.zip",
202
  mime="application/zip",
203
  )
204
  if comet_initialized:
@@ -207,5 +210,6 @@ if st.button("Results"):
207
  st.divider()
208
  if comet_initialized:
209
  experiment.end()
210
- st.write(f"Number of times you requested results: {st.session_state['file_upload_attempts']}/{max_attempts}")
 
211
 
 
6
  from streamlit_extras.stylable_container import stylable_container
7
  import plotly.express as px
8
  import zipfile
 
9
  from PyPDF2 import PdfReader
10
  import docx
 
 
11
  import os
12
  from comet_ml import Experiment
13
  import re
14
+ import numpy as np
 
 
 
15
 
16
+ st.set_page_config(layout="wide", page_title="Named Entity Recognition App")
 
17
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
18
 
19
 
20
+ # --- Configuration ---
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
+ # --- Initialize session state ---
30
  if 'file_upload_attempts' not in st.session_state:
31
  st.session_state['file_upload_attempts'] = 0
32
 
33
  max_attempts = 10
34
 
35
+ # --- Helper function for model loading ---
36
+ @st.cache_resource
37
+ def load_ner_model():
38
+ """Loads the pre-trained NER model and caches it."""
39
+ return pipeline("token-classification", model="dslim/distilbert-NER", aggregation_strategy="max")
40
+
41
+ # --- UI Elements ---
42
+ st.subheader("4-English Named Entity Recognition Web App", divider="rainbow")
43
+ st.link_button("by nlpblogs", "https://nlpblogs.com", type="tertiary")
44
+
45
+ expander = st.expander("**Important notes on the 4-English Named Entity Recognition Web App**")
46
+ expander.write('''
47
+ **Named Entities:** This 4-English Named Entity Recognition Web App predicts four (4) labels (“PER: person”, “LOC: location”, “ORG: organization”, “MISC: miscellaneous”). 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.
48
+
49
+ **How to Use:** Upload your .pdf or .docx file. Then, click the 'Results' button to extract and tag entities in your text data.
50
+
51
+ **Usage Limits:** You can request results up to 10 times.
52
+
53
+ **Customization:** 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.
54
+
55
+ **Technical issues:** If your connection times out, please refresh the page or reopen the app's URL.
56
+
57
+ For any errors or inquiries, please contact us at [email protected]
58
+ ''')
59
+
60
+ with st.sidebar:
61
+ container = st.container(border=True)
62
+ 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.")
63
+ st.subheader("Related NLP Web Apps", divider="rainbow")
64
+ 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")
65
 
66
+ # --- File Upload ---
67
  upload_file = st.file_uploader("Upload your file. Accepted file formats include: .pdf, .docx", type=['pdf', 'docx'])
68
  text = None
69
  df = None
70
 
71
  if upload_file is not None:
 
72
  file_extension = upload_file.name.split('.')[-1].lower()
73
  if file_extension == 'pdf':
74
  try:
 
76
  text = ""
77
  for page in pdf_reader.pages:
78
  text += page.extract_text()
79
+ st.write("File uploaded successfully. Due to security protocols, the file content is hidden.")
80
  except Exception as e:
81
  st.error(f"An error occurred while reading PDF: {e}")
82
+ text = None
83
  elif file_extension == 'docx':
84
  try:
85
  doc = docx.Document(upload_file)
86
  text = "\n".join([para.text for para in doc.paragraphs])
87
+ st.write("File uploaded successfully. Due to security protocols, the file content is hidden.")
88
  except Exception as e:
89
  st.error(f"An error occurred while reading docx: {e}")
90
+ text = None
91
  else:
92
  st.warning("Unsupported file type.")
93
+ text = None
 
 
94
 
95
  st.divider()
96
 
97
+ # --- Results Button and Processing Logic ---
98
  if st.button("Results"):
99
+ if not comet_initialized:
100
+ st.warning("Comet ML not initialized. Check environment variables if you wish to log data.")
101
+
102
  if st.session_state['file_upload_attempts'] >= max_attempts:
103
  st.error(f"You have requested results {max_attempts} times. You have reached your daily request limit.")
104
  st.stop()
105
+
106
+ if text is None:
107
+ st.warning("Please upload a supported file (.pdf or .docx) before requesting results.")
108
+ st.stop()
109
+
110
  st.session_state['file_upload_attempts'] += 1
 
 
 
 
 
 
 
 
 
 
111
 
112
+ with st.spinner("Analyzing text...", show_time=True):
113
+ # Load model (cached)
114
+ model = load_ner_model()
115
+ text_entities = model(text)
116
+ df = pd.DataFrame(text_entities)
117
 
118
+ # Clean and filter DataFrame
119
+ pattern = r'[^\w\s]'
120
+ df['word'] = df['word'].replace(pattern, '', regex=True)
121
+ df = df.replace('', 'Unknown').dropna()
122
 
123
+ if df.empty:
124
+ st.warning("No entities were extracted from the uploaded text.")
125
+ st.stop()
126
 
127
  if comet_initialized:
128
  experiment = Experiment(
 
130
  workspace=COMET_WORKSPACE,
131
  project_name=COMET_PROJECT_NAME,
132
  )
133
+ experiment.log_parameter("input_text_length", len(text))
134
  experiment.log_table("predicted_entities", df)
135
 
136
+ # --- Display Results ---
137
  properties = {"border": "2px solid gray", "color": "blue", "font-size": "16px"}
138
  df_styled = df.style.set_properties(**properties)
139
+ st.dataframe(df_styled, use_container_width=True)
140
 
141
  with st.expander("See Glossary of tags"):
142
  st.write('''
 
151
  '**end**': ['index of the end of the corresponding entity']
152
  ''')
153
 
154
+ # --- Visualizations ---
155
+ st.subheader("Tree map", divider="rainbow")
156
+ fig_treemap = px.treemap(df, path=[px.Constant("all"), 'word', 'entity_group'],
157
  values='score', color='entity_group')
158
+ fig_treemap.update_layout(margin=dict(t=50, l=25, r=25, b=25))
159
+ st.plotly_chart(fig_treemap)
160
+ if comet_initialized:
161
+ experiment.log_figure(figure=fig_treemap, figure_name="entity_treemap")
162
+
163
+ value_counts1 = df['entity_group'].value_counts()
164
+ final_df_counts = value_counts1.reset_index().rename(columns={"index": "entity_group"})
165
+
166
+ col1, col2 = st.columns(2)
167
+ with col1:
168
+ st.subheader("Pie Chart", divider="rainbow")
169
+ fig_pie = px.pie(final_df_counts, values='count', names='entity_group', hover_data=['count'], labels={'count': 'count'}, title='Percentage of predicted labels')
170
+ fig_pie.update_traces(textposition='inside', textinfo='percent+label')
171
+ st.plotly_chart(fig_pie)
172
  if comet_initialized:
173
+ experiment.log_figure(figure=fig_pie, figure_name="label_pie_chart")
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
174
 
175
+ with col2:
176
+ st.subheader("Bar Chart", divider="rainbow")
177
+ fig_bar = px.bar(final_df_counts, x="count", y="entity_group", color="entity_group", text_auto=True, title='Occurrences of predicted labels')
178
+ st.plotly_chart(fig_bar)
179
+ if comet_initialized:
180
+ experiment.log_figure(figure=fig_bar, figure_name="label_bar_chart")
181
+
182
+ # --- Downloadable Content ---
183
  dfa = pd.DataFrame(
184
  data={
185
+ 'word': ['entity extracted from your text data'],
186
+ 'score': ['accuracy score; how accurately a tag has been assigned to a given entity'],
187
+ 'entity_group': ['label (tag) assigned to a given extracted entity'],
188
  'start': ['index of the start of the corresponding entity'],
189
  'end': ['index of the end of the corresponding entity'],
190
+ })
191
+
192
  buf = io.BytesIO()
193
  with zipfile.ZipFile(buf, "w") as myzip:
194
  myzip.writestr("Summary of the results.csv", df.to_csv(index=False))
195
  myzip.writestr("Glossary of tags.csv", dfa.to_csv(index=False))
 
196
 
197
  with stylable_container(
198
  key="download_button",
 
201
  st.download_button(
202
  label="Download zip file",
203
  data=buf.getvalue(),
204
+ file_name="nlpblogs_ner_results.zip",
205
  mime="application/zip",
206
  )
207
  if comet_initialized:
 
210
  st.divider()
211
  if comet_initialized:
212
  experiment.end()
213
+
214
+ st.write(f"Number of times you requested results: **{st.session_state['file_upload_attempts']}/{max_attempts}**")
215