File size: 12,252 Bytes
c0ff9d9
 
 
 
 
 
642fbe6
c0ff9d9
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
2de99c3
c0ff9d9
 
 
 
 
650befd
c032773
c0ff9d9
 
45e9886
c0ff9d9
 
c032773
c0ff9d9
 
 
ab87761
 
 
c0ff9d9
 
 
 
 
650befd
c0ff9d9
 
ab87761
c0ff9d9
 
 
 
 
 
 
ab87761
c0ff9d9
 
 
 
 
 
 
 
 
 
 
 
 
 
ab87761
c0ff9d9
 
 
 
 
 
 
 
 
 
 
 
 
 
ab87761
c0ff9d9
 
 
 
 
 
 
 
 
 
 
 
 
ad0b044
c5718df
c0ff9d9
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
c5718df
c0ff9d9
c5718df
c0ff9d9
 
642fbe6
c0ff9d9
 
 
642fbe6
c0ff9d9
c032773
 
 
c0ff9d9
 
 
c032773
642fbe6
 
 
 
 
 
 
 
c0ff9d9
642fbe6
 
 
 
 
 
 
 
 
c0ff9d9
 
 
 
642fbe6
 
 
 
 
 
c0ff9d9
 
 
 
642fbe6
 
c0ff9d9
 
 
642fbe6
 
 
718ea84
642fbe6
 
 
 
ab87761
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
c0ff9d9
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
650befd
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
# streamlit run app.py
#------------------------------------------------------------------------------
#------------------------------------------------------------------------------
import streamlit as st 
import spacy 
import spacy_streamlit
from spacy import displacy
from io import StringIO
import pandas as pd

#Funktion, die eine Liste zu einem String umwandelt
def listToString(s):
    str1 = ""
    for ele in s:
        str1 += ele
    return str1

#Funktion, um einen Dataframe in einer csv zu speichern
def convert_df(df):
    return df.to_csv(index=False).encode('utf-8')

#------------------------------------------------------------------------------
#------------------------------------------------------------------------------

#Styling: Seitentitel, Favicon, etc. 
st.set_page_config(page_title='NerDH Visualisierer', page_icon='img/favicon.ico')
st.markdown(""" <style> 
        #MainMenu {visibility: hidden;} 
        footer {visibility: hidden;} 
        </style> """, unsafe_allow_html=True)
st.markdown('## NER-Visualisierer für (historische) deutsche Texte')

#------------------------------------------------------------------------------
#------------------------------------------------------------------------------

#Spacy-Modell auswählen 
model = "de_fnhd_nerdh"
model = st.sidebar.selectbox("Wähle ein Modell:", ["de_fnhd_nerdh", "de_core_news_sm", "de_core_news_md", "de_core_news_lg"], key="model")
with st.spinner('Modell wird geladen...'):
    nlp = spacy.load(model)
st.success('Modell ' + model + ' ist geladen!')

#Informationen über die verschiedenen Modelle
if model == "de_fnhd_nerdh":
    with st.sidebar.expander("Über das Modell"):
        st.write("""
            Das Modell basiert auf frühneuhochdeutschen Texten der digitalen Edition **Philipp Hainhofer: *Reiseberichte & Sammlungsbeschreibungen 1594-1636*** (https://hainhofer.hab.de/). 
            \n Trainiert wurde das Modell mit der Pipeline der Python Bibliothek [Spacy](https://spacy.io/) und dem Text [**München 1611**](https://hainhofer.hab.de/reiseberichte/muenchen1611?v={%22view%22:%22info%22}). 
            \n Das Modell kann [hier](https://huggingface.co/easyh/de_fnhd_nerdh/resolve/main/de_fnhd_nerdh-any-py3-none-any.whl) (586MB) heruntergeladen und als Python-Package installiert werden.
            \n F-Score: **0.92**. Dieser wurde getestet mit Texten aus der Edition.
            \n Mehr Informationen zum Prozess des Trainings etc. gibt es [hier](https://easyh.github.io/NerDH/tut/).
        """)
    with st.sidebar.expander("Named Entities Labels"):
        st.write("""
            **PERSON:** Einzelperson oder Familie
            \n**ORT:** Geographische Einheit, d. h. Länder, Städte, Staaten oder Flüsse.
            \n**ORGANISATION:** Institutionen,(Ordens-)Gemeinschaften, Verbindungen, etc.
            \n**OBJEKT:** Architektur, Gebäude, Kunst, etc.       
            \n**ZEIT:** Datum, Monat, Jahr, Uhrzeit etc.
            """)
elif model == "de_core_news_sm":
    with st.sidebar.expander("Über das Modell"):
            st.write("""
                Das kleinste deutsche Spacy Modell mit nur 13MB. Grund dafür sind die fehlenden Worteinbettungen (Word-Vectors). Trainiert wurde das Modell mit folgenden Quellen: [Tiger Corpus](), [Tiger2Dep]() und [WikiNER]().
                Anwendungsbereich für das Modell sind haupsächtliche moderne Texte und News-Berichte (F-Score: 0.82).
                Daher wird dieses Modell mit historischen Texten nicht wirklich gut abschneiden.
                \n Mehr Informationen zum Modell gibts hier [hier](https://spacy.io/models/de#de_core_news_sm).
            """)
    with st.sidebar.expander("Named Entities Labels"):
            st.write("""
                **PER:** Einzelperson oder Familie
                \n**LOC:** Geographische Einheit, d. h. Länder, Städte, Staaten.
                \n**ORG:** Unternehmen, Agenturen, Institutionen, Regierungseinrichtungen
                \n**MISC:** Gemischte Kategorie (Ereignisse, Nationalitäten, Kunstgegenstände)
            """)
elif model == "de_core_news_md":
    with st.sidebar.expander("Über das Modell"):
            st.write("""
                Das mittlere deutsche Spacy Modell mit 42MB und 20.000 Worteinbettungen. Trainiert wurde das Modell mit folgenden Quellen: [Tiger Corpus](), [Tiger2Dep]() und [WikiNER]().
                Anwendungsbereich für das Modell sind haupsächtliche moderne Texte und News-Berichte (F-Score: 0.84).
                Daher wird dieses Modell mit historischen Texten nicht wirklich gut abschneiden.
                \n Mehr Informationen zum Modell gibts hier [hier](https://spacy.io/models/de#de_core_news_md).
            """)
    with st.sidebar.expander("Named Entities Labels"):
            st.write("""
                 **PER:** Einzelperson oder Familie
                \n**LOC:** Geographische Einheit, d. h. Länder, Städte, Staaten.
                \n**ORG:** Unternehmen, Agenturen, Institutionen, Regierungseinrichtungen
                \n**MISC:** Gemischte Kategorie (Ereignisse, Nationalitäten, Kunstgegenstände)
            """)
else: 
    with st.sidebar.expander("Über das Modell"):
        st.write("""
        Das Größte von den drei deutschen Spacy Modellen mit 541MB und 500.000 Worteinbettungen. Trainiert wurde das Modell mit folgenden Quellen: [Tiger Corpus](), [Tiger2Dep]() und [WikiNER]().
        Anwendungsbereich für das Modell sind haupsächtliche moderne Texte und News-Berichte (F-Score: 0.85).
        Daher wird dieses Modell mit historischen Texten nicht wirklich gut abschneiden.
        \n Mehr Informationen zum Modell gibts hier [hier](https://spacy.io/models/de#de_core_news_lg).
        """)
    with st.sidebar.expander("Named Entities Labels"):
            st.write("""
                 **PER:** Einzelperson oder Familie
                \n**LOC:** Geographische Einheit, d. h. Länder, Städte, Staaten.
                \n**ORG:** Unternehmen, Agenturen, Institutionen, Regierungseinrichtungen
                \n**MISC:** Gemischte Kategorie (Ereignisse, Nationalitäten, Kunstgegenstände)
            """)

#------------------------------------------------------------------------------
#------------------------------------------------------------------------------

#Text hochladen 
st.markdown('### Text hochladen **oder** direkt ins Textfeld einfügen.')
uploaded_file = st.file_uploader("Texte nur im .txt-Format und utf-8- oder utf-16 Kodierung hochladen.")
#Standardtext im Textfeld
DEFAULT_TEXT = """Vmb 12 Vhr bin Jch von Dachaw wider hinweck geritten, vnd vmb 3 Vhr zu Adelshausen, beÿ dem Hannß Wilhalm Hund, Jhrer Durchleucht Rath vnd Cammerer, eingekheret, welcher vermaint, mich v̈ber nacht zu behalten, Habe mich aber entschuldiget, vnd Jhme vnd seiner frawen versprochen, ainmal zu bequemberer zeit, mit meiner haußfrawen zu Jhm zu spatzirn. Jetzt allain ainen trunckh mit Jhme gethan, vnd vmb 4 Vhren wider fort auf Augspurg noch in die Vier meil geritten, vnd zu Abents nach 9 Vhr, Gott lob vnd danckh, glücklich vnd wol, vnd, obwol noch vnuerdienter, mit vil empfangener ehr zu Hauß ankommen."""

#Einlesen des Textes
with st.spinner("Text wird eingelesen..."):
    UPLOADED_TEXT_list = []
    if uploaded_file:
        # To convert to a string based IO:
        try:
            stringio = StringIO(uploaded_file.getvalue().decode("utf-8"))
        except:
            stringio = StringIO(uploaded_file.getvalue().decode("utf-16"))
        for line in stringio:       
            read_text = str(line)
            clean_text = read_text.replace("\n", " ")
            UPLOADED_TEXT_list.append(clean_text)
        UPLOADED_TEXT = listToString(UPLOADED_TEXT_list)    
        text = st.text_area(" ", UPLOADED_TEXT, height=200)
    else:
        text = st.text_area(" ", DEFAULT_TEXT, height=200)
st.success("Text ist eingelesen!")

st.markdown("---")
#------------------------------------------------------------------------------
#------------------------------------------------------------------------------

st.markdown("### Named Entities")
#Farben für die verschiedenen Entitäten 
colors = {"PER": "#fdec3e", "PERSON": "#fdec3e", "LOC": "#7e56c2", "ORT": "#7e56c2", "ORG": "#209485" , "ORGANISATION": "#209485" , "MISC": "#eb4034",  "ZEIT": "#4c9c4b", "OBJEKT": "#7e56c2"}

#Spacy-Streamlit NER Visualizer
#NER-Prozess wird gestartet, je nach Model werden hier die entsprechenden Entitäten gewechselt.
with st.spinner('Named Entities werden gesucht...'):
    doc = nlp(text)
    if model == "de_fnhd_nerdh":    
        entities = st.multiselect('Entitäten auswählen', ['PERSON', 'ORT', 'ORGANISATION', 'OBJEKT', 'ZEIT', 'Alle Entitäten'], default= ['Alle Entitäten'])
        if 'Alle Entitäten' in entities:
            entities = ['PERSON', 'ORT', 'ORGANISATION', 'OBJEKT', 'ZEIT']

        options = {"ents": entities,"colors": colors}
        ent_html = displacy.render(doc, style="ent", options=options, jupyter=False)
        st.markdown(ent_html, unsafe_allow_html=True)
        #spacy_streamlit.visualize_ner(doc, labels = ["PERSON", "ORT", "ORGANISATION", "OBJEKT", "ZEIT",], show_table=False,    colors = colors)
    else: 
        entities = st.multiselect('Entitäten auswählen', ["PER", "LOC", "ORG", "MISC", 'Alle Entitäten'], default= ['Alle Entitäten'])
        if 'Alle Entitäten' in entities:
            entities = ["PER", "LOC", "ORG", "MISC"]

        options = {"ents": entities,"colors": colors}
        ent_html = displacy.render(doc, style="ent", options=options, jupyter=False)
        st.markdown(ent_html, unsafe_allow_html=True)
        #spacy_streamlit.visualize_ner(doc, labels = ["PER", "LOC", "ORG", "MISC"], show_table=False,    colors = colors)
st.markdown(' ')
st.success('Suchprozess ist abgeschlossen!')

#------------------------------------------------------------------------------
#------------------------------------------------------------------------------
#Download-Funktion der Entitäten
st.sidebar.markdown('\n\n')
st.sidebar.markdown('''
### NER-Ergebnnisse in einer .csv-Datei downloaden.
Die Datei enthält die ausgewählten Entitäten.
''')

#Um die NER-Ergebnisse downloaden zu können, werden die Entitäten in einer csv gespeichert
results = []
for ent in doc.ents:
    if ent.label_ in entities:
        results.append([ent.text,ent.label_])
df_results = pd.DataFrame(results, columns = ['text', 'label'])
csv = convert_df(df_results)

st.sidebar.download_button( 
    "Ergebnisse downloaden",
   csv,
     model + '_' + str(entities) + ".csv",
   "text/csv",
   key='download-csv'
)


#------------------------------------------------------------------------------
#------------------------------------------------------------------------------

#Modell in Python Umgebung installieren 

if model == "de_fnhd_nerdh":
    st.markdown('---') #### Modell in Python installieren und laden')
    st.markdown('#### Modell in Python installieren und laden')
    st.markdown('''
    ```py
    !pip install https://huggingface.co/easyh/de_fnhd_nerdh/resolve/main/de_fnhd_nerdh-any-py3-none-any.whl

    import spacy
    nlp = spacy.load("de_fnhd_nerdh")
    ```
    ''')


#------------------------------------------------------------------------------
#------------------------------------------------------------------------------

#Referenzen über das Projekt
st.sidebar.markdown('\n\n')
st.sidebar.markdown('\n\n')
with st.sidebar.expander("Referenzen"):
    st.write('''
    Github: https://github.com/easyh/NerDH\n
    Spacy: https://spacy.io/\n
    NerDH-Tutorial: https://easyh.github.io/NerDH/\n
    Trainingsdaten: https://hainhofer.hab.de/
    ''')

#------------------------------------------------------------------------------
#------------------------------------------------------------------------------

#Button zurück zum NerDH Tutorial
st.sidebar.markdown('\n\n')
st.sidebar.write(f'''
    <a target="_blank" href="https://easyh.github.io/NerDH/">
        <button style="color:white;background-color: #209485;  border: none; display: inline-block; border-radius: 8px; padding: 10px 22px;">
           Zurück zum Tutorial
        </button>
    </a>
    ''',
    unsafe_allow_html=True
)