Spaces:
Sleeping
Sleeping
Hakyung Sung
commited on
Commit
·
127d151
1
Parent(s):
fd84879
Correct app.py
Browse files
app.py
CHANGED
@@ -13,54 +13,202 @@ nlp = spacy.load(os.path.join(model_path, 'model-best'))
|
|
13 |
if 'parser' not in nlp.pipe_names and 'senter' not in nlp.pipe_names:
|
14 |
nlp.add_pipe('sentencizer')
|
15 |
|
16 |
-
# Define the inline color mapping for each ASC tag.
|
17 |
-
color_scheme = {
|
18 |
-
"ATTR": "#f6e9e9", # Light Red
|
19 |
-
"INTRAN_S": "#e7957f", # Light Blue
|
20 |
-
"INTRAN_MOT": "#f6f6aa", # Light Green
|
21 |
-
"INTRAN_RES": "#f0aed6", # Light Yellow
|
22 |
-
"CAUS_MOT": "#cdefb5", # Light Pink
|
23 |
-
"TRAN_S": "#a0d4f7", # Light Blue
|
24 |
-
"TRAN_RES": "#c7aefa", # Light Purple
|
25 |
-
"DITRAN": "#b3f0f7", # Light Teal
|
26 |
-
"PASSIVE": "#c3c0c0" # Light Gray
|
27 |
-
}
|
28 |
-
|
29 |
def get_highlighted_text(doc):
|
30 |
"""
|
31 |
-
Wraps detected ASCs in each sentence with a span tag
|
32 |
-
|
33 |
"""
|
34 |
highlighted_sentences = []
|
35 |
for sent in doc.sents:
|
36 |
-
|
37 |
-
# Find all entities fully contained within this sentence.
|
38 |
ents_in_sent = [ent for ent in doc.ents if ent.start_char >= sent.start_char and ent.end_char <= sent.end_char]
|
39 |
if ents_in_sent:
|
40 |
-
# Process entities in reverse order so
|
41 |
ents_in_sent = sorted(ents_in_sent, key=lambda x: x.start_char, reverse=True)
|
42 |
for ent in ents_in_sent:
|
43 |
ent_start = ent.start_char - sent.start_char
|
44 |
ent_end = ent.end_char - sent.start_char
|
45 |
-
#
|
46 |
-
|
47 |
-
|
48 |
-
|
49 |
-
|
50 |
-
+ f'<span style="background-color: {color}; font-weight: bold;" title="{ent.label_}">'
|
51 |
-
+ s[ent_start:ent_end]
|
52 |
-
+ f'<span style="display:inline-block; vertical-align: super; font-size: 0.8em; margin-left: 2px; color: black;">{ent.label_}</span>'
|
53 |
+ '</span>'
|
54 |
-
+
|
55 |
)
|
56 |
-
highlighted_sentences.append(
|
57 |
-
|
58 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
59 |
|
60 |
def process_text(input_text):
|
61 |
"""
|
62 |
Process input text to detect and tag ASCs.
|
63 |
-
Returns an HTML string with
|
64 |
"""
|
65 |
if not input_text.strip():
|
66 |
return "No text provided. Please enter some text."
|
@@ -75,55 +223,24 @@ def process_text(input_text):
|
|
75 |
|
76 |
return get_highlighted_text(doc)
|
77 |
|
78 |
-
# Define
|
79 |
-
sample_text =
|
80 |
-
"Once upon a time in a small, enchanted village nestled between towering mountains, there lived a baker named Oliver. "
|
81 |
-
"But this wasn't just any baker—Oliver had a magical secret. Every loaf of bread he baked had the power to grant a wish, "
|
82 |
-
"but only if it was made with true joy in his heart. The villagers adored Oliver’s bread, though they had no idea about its magic. "
|
83 |
-
"They just knew it tasted unlike anything else—warm, soft, and with a hint of something... extraordinary. Only a few people had ever discovered "
|
84 |
-
"its secret, and even fewer had made wishes, because the key was in asking for something truly selfless. "
|
85 |
-
"One crisp autumn morning, a traveling musician named Lyla passed through the village. She had a worn-out lute, tattered clothes, "
|
86 |
-
"and a bright spark of hope in her eyes despite her hardships. Drawn by the smell of freshly baked bread, she wandered into Oliver’s bakery. "
|
87 |
-
"Oliver, busy dusting flour off his hands, smiled warmly. “What can I do for you?” he asked. "
|
88 |
-
"Lyla’s stomach growled in response, and she laughed, a sound as melodic as her lute playing. “Just one loaf of bread, please,” she said, "
|
89 |
-
"placing a single coin on the counter, all she had left. "
|
90 |
-
"Oliver, feeling the joy in the simple act of serving someone in need, baked the loaf with care. As the bread came out of the oven, a golden glow "
|
91 |
-
"shimmered around it for just a moment. Lyla didn’t notice, but Oliver did, and he smiled to himself. "
|
92 |
-
"As Lyla took her first bite outside the shop, she felt warmth spread through her whole being. She thought of how she missed playing her lute to "
|
93 |
-
"cheer others up, but it was broken and beyond repair. Without knowing the magic at work, she whispered under her breath, 'I just wish I could bring "
|
94 |
-
"music to everyone again.' "
|
95 |
-
"That evening, as Lyla set up by the village fountain to play, something miraculous happened. Her old, broken lute began to transform, glowing just "
|
96 |
-
"like the bread had. In her hands now was the most beautiful lute she had ever seen, shimmering with gold and silver strings. When she strummed it, "
|
97 |
-
"the music that flowed out wasn’t just sound—it was pure joy. "
|
98 |
-
"The village gathered around her, drawn by the enchanting melodies that seemed to fill their hearts with warmth and happiness. People laughed, danced, "
|
99 |
-
"and even sang along, forgetting their worries. "
|
100 |
-
"Oliver watched from his bakery window, smiling to himself. He had no idea what Lyla had wished for, but he could see its magic at work. He knew his "
|
101 |
-
"bread had once again brought a little bit of magic to the world. "
|
102 |
-
"And so, every day after that, Lyla would play her magical lute in the village square, bringing joy to everyone who heard her music. People came from "
|
103 |
-
"distant lands just to hear her play, and with every note, the village grew a little brighter, a little happier. "
|
104 |
-
"As for Oliver, he continued to bake with joy in his heart, knowing that sometimes the smallest acts of kindness—like baking a loaf of bread—could "
|
105 |
-
"make the biggest difference in someone’s life. "
|
106 |
-
"And so, the village became known not just for its delicious bread, but for its music, magic, and the happiness that lingered in every corner. "
|
107 |
-
"(Generated by ChatGPT 4o 🤖)"
|
108 |
-
)
|
109 |
|
110 |
-
def fill_sample_text():
|
111 |
-
return sample_text
|
112 |
|
113 |
# Build the Gradio interface.
|
114 |
with gr.Blocks() as demo:
|
115 |
gr.Markdown("# ASC tagger demo")
|
116 |
-
gr.Markdown("
|
117 |
|
118 |
-
input_textbox = gr.Textbox(lines=
|
119 |
output_html = gr.HTML(label="Tagged Text")
|
120 |
-
tag_btn = gr.Button("Tag ASCs")
|
121 |
fill_btn = gr.Button("Fill Sample Text")
|
122 |
-
|
123 |
-
|
124 |
-
# When "Fill Sample Text" is clicked, populate the textbox.
|
125 |
fill_btn.click(fn=fill_sample_text, inputs=[], outputs=input_textbox)
|
126 |
-
|
127 |
|
128 |
if __name__ == "__main__":
|
129 |
demo.launch()
|
|
|
13 |
if 'parser' not in nlp.pipe_names and 'senter' not in nlp.pipe_names:
|
14 |
nlp.add_pipe('sentencizer')
|
15 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
16 |
def get_highlighted_text(doc):
|
17 |
"""
|
18 |
+
Wraps detected ASCs in each sentence with a <span> tag that carries the entity tag as a
|
19 |
+
data attribute. The output HTML is wrapped with a CSS <style> block that applies your desired styling.
|
20 |
"""
|
21 |
highlighted_sentences = []
|
22 |
for sent in doc.sents:
|
23 |
+
text = sent.text
|
24 |
+
# Find all entities that are fully contained within this sentence.
|
25 |
ents_in_sent = [ent for ent in doc.ents if ent.start_char >= sent.start_char and ent.end_char <= sent.end_char]
|
26 |
if ents_in_sent:
|
27 |
+
# Process entities in reverse order so that character offsets remain valid.
|
28 |
ents_in_sent = sorted(ents_in_sent, key=lambda x: x.start_char, reverse=True)
|
29 |
for ent in ents_in_sent:
|
30 |
ent_start = ent.start_char - sent.start_char
|
31 |
ent_end = ent.end_char - sent.start_char
|
32 |
+
# Wrap the detected entity with a span and include its tag via the data-entity attribute.
|
33 |
+
text = (
|
34 |
+
text[:ent_start]
|
35 |
+
+ f'<span class="entity" data-entity="{ent.label_}">'
|
36 |
+
+ text[ent_start:ent_end]
|
|
|
|
|
|
|
37 |
+ '</span>'
|
38 |
+
+ text[ent_end:]
|
39 |
)
|
40 |
+
highlighted_sentences.append(text)
|
41 |
+
result = "<br><br>".join(highlighted_sentences)
|
42 |
+
|
43 |
+
# Embed the provided CSS for styling.
|
44 |
+
style = """
|
45 |
+
<style>
|
46 |
+
body {
|
47 |
+
font-family: Arial, sans-serif;
|
48 |
+
margin: 0;
|
49 |
+
padding: 20px;
|
50 |
+
background-color: #f4f4f4;
|
51 |
+
}
|
52 |
+
.container {
|
53 |
+
max-width: 800px;
|
54 |
+
margin: 0 auto;
|
55 |
+
padding: 20px;
|
56 |
+
background-color: white;
|
57 |
+
border-radius: 8px;
|
58 |
+
box-shadow: 0 0 10px rgba(0, 0, 0, 0.1);
|
59 |
+
}
|
60 |
+
h1 {
|
61 |
+
font-size: 2rem;
|
62 |
+
font-weight: 700;
|
63 |
+
margin-bottom: 20px;
|
64 |
+
text-align: center;
|
65 |
+
}
|
66 |
+
p, textarea, input {
|
67 |
+
font-size: 0.9rem;
|
68 |
+
font-weight: 400;
|
69 |
+
}
|
70 |
+
.info {
|
71 |
+
font-size: 0.9rem;
|
72 |
+
color: #333;
|
73 |
+
}
|
74 |
+
.accuracy-highlight {
|
75 |
+
color: #007030;
|
76 |
+
font-weight: bold;
|
77 |
+
}
|
78 |
+
input[type="submit"], input[type="button"] {
|
79 |
+
font-size: 0.9rem;
|
80 |
+
}
|
81 |
+
textarea {
|
82 |
+
width: 95%;
|
83 |
+
max-width: 95%; /* Ensure textarea doesn't exceed the container */
|
84 |
+
padding: 20px;
|
85 |
+
margin-bottom: 10px;
|
86 |
+
border: 1px solid #ccc;
|
87 |
+
border-radius: 4px;
|
88 |
+
resize: vertical; /* Allow vertical resizing */
|
89 |
+
}
|
90 |
+
input[type="submit"], input[type="button"] {
|
91 |
+
background-color: #007030;
|
92 |
+
color: white;
|
93 |
+
padding: 10px 20px;
|
94 |
+
border: none;
|
95 |
+
border-radius: 4px;
|
96 |
+
cursor: pointer;
|
97 |
+
margin-right: 10px; /* Add some space between buttons */
|
98 |
+
}
|
99 |
+
input[type="submit"]:hover, input[type="button"]:hover {
|
100 |
+
background-color: #45a049;
|
101 |
+
}
|
102 |
+
.results {
|
103 |
+
margin-top: 20px;
|
104 |
+
line-height: 2.5;
|
105 |
+
}
|
106 |
+
.tag-counts {
|
107 |
+
margin-top: 2px;
|
108 |
+
text-align: center;
|
109 |
+
}
|
110 |
+
.tag-counts h2 {
|
111 |
+
margin-bottom: 5px;
|
112 |
+
text-align: left;
|
113 |
+
}
|
114 |
+
.entity {
|
115 |
+
display: inline-block;
|
116 |
+
border: none;
|
117 |
+
border-radius: 2px;
|
118 |
+
padding: 2px 5px;
|
119 |
+
margin: 0 4px;
|
120 |
+
position: relative;
|
121 |
+
white-space: nowrap;
|
122 |
+
line-height: 1.2;
|
123 |
+
font-size: 0.8em;
|
124 |
+
}
|
125 |
+
/* Highlight background colors for entity types */
|
126 |
+
.entity[data-entity="ATTR"] {
|
127 |
+
background-color: #f6e9e9; /* Light Red */
|
128 |
+
}
|
129 |
+
.entity[data-entity="INTRAN_S"] {
|
130 |
+
background-color: #e7957f; /* Light Blue */
|
131 |
+
}
|
132 |
+
.entity[data-entity="INTRAN_MOT"] {
|
133 |
+
background-color: #f6f6aa; /* Light Green */
|
134 |
+
}
|
135 |
+
.entity[data-entity="INTRAN_RES"] {
|
136 |
+
background-color: #f0aed6; /* Light Yellow */
|
137 |
+
}
|
138 |
+
.entity[data-entity="CAUS_MOT"] {
|
139 |
+
background-color: #cdefb5; /* Light Pink */
|
140 |
+
}
|
141 |
+
.entity[data-entity="TRAN_S"] {
|
142 |
+
background-color: #a0d4f7; /* Light Blue */
|
143 |
+
}
|
144 |
+
.entity[data-entity="TRAN_RES"] {
|
145 |
+
background-color: #c7aefa; /* Light Purple */
|
146 |
+
}
|
147 |
+
.entity[data-entity="DITRAN"] {
|
148 |
+
background-color: #b3f0f7; /* Light Teal */
|
149 |
+
}
|
150 |
+
.entity[data-entity="PASSIVE"] {
|
151 |
+
background-color: #c3c0c0; /* Light Gray */
|
152 |
+
}
|
153 |
+
/* Default style if the entity type is not specified */
|
154 |
+
.entity[data-entity=""] {
|
155 |
+
background-color: #cccccc; /* Light Gray */
|
156 |
+
}
|
157 |
+
/* Darker background colors for the entity label tooltips */
|
158 |
+
.entity[data-entity="ATTR"]::after {
|
159 |
+
background-color: #d29997; /* Darker Red */
|
160 |
+
}
|
161 |
+
.entity[data-entity="INTRAN_S"]::after {
|
162 |
+
background-color: #ec6161; /* Darker Orange */
|
163 |
+
}
|
164 |
+
.entity[data-entity="INTRAN_MOT"]::after {
|
165 |
+
background-color: #ebab22; /* Darker Green */
|
166 |
+
}
|
167 |
+
.entity[data-entity="INTRAN_RES"]::after {
|
168 |
+
background-color: #be5791; /* Darker Purple */
|
169 |
+
}
|
170 |
+
.entity[data-entity="CAUS_MOT"]::after {
|
171 |
+
background-color: #007030; /* Darker Green */
|
172 |
+
}
|
173 |
+
.entity[data-entity="TRAN_S"]::after {
|
174 |
+
background-color: #3085ce; /* Darker Blue */
|
175 |
+
}
|
176 |
+
.entity[data-entity="TRAN_RES"]::after {
|
177 |
+
background-color: #8268cf; /* Darker Purple */
|
178 |
+
}
|
179 |
+
.entity[data-entity="DITRAN"]::after {
|
180 |
+
background-color: #449cbb; /* Darker Teal */
|
181 |
+
}
|
182 |
+
.entity[data-entity="PASSIVE"]::after {
|
183 |
+
background-color: #6b6b6b; /* Darker Gray */
|
184 |
+
}
|
185 |
+
/* Default darker tooltip if the entity type is not specified */
|
186 |
+
.entity[data-entity=""]::after {
|
187 |
+
background-color: #888888; /* Darker Gray */
|
188 |
+
}
|
189 |
+
/* Styling for the entity label tooltip */
|
190 |
+
.entity::after {
|
191 |
+
content: attr(data-entity);
|
192 |
+
position: absolute;
|
193 |
+
bottom: -2em;
|
194 |
+
left: 0;
|
195 |
+
right: 0;
|
196 |
+
color: #fff; /* White text */
|
197 |
+
font-size: 0.7em;
|
198 |
+
padding: 2px 4px;
|
199 |
+
border-radius: 2px;
|
200 |
+
text-align: center;
|
201 |
+
min-width: 50px;
|
202 |
+
white-space: nowrap;
|
203 |
+
}
|
204 |
+
</style>
|
205 |
+
"""
|
206 |
+
return style + "<div class='container'>" + result + "</div>"
|
207 |
|
208 |
def process_text(input_text):
|
209 |
"""
|
210 |
Process input text to detect and tag ASCs.
|
211 |
+
Returns an HTML string with styles applied.
|
212 |
"""
|
213 |
if not input_text.strip():
|
214 |
return "No text provided. Please enter some text."
|
|
|
223 |
|
224 |
return get_highlighted_text(doc)
|
225 |
|
226 |
+
# Define sample text
|
227 |
+
sample_text = "Nancy sliced the tire open."
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
228 |
|
229 |
+
#def fill_sample_text():
|
230 |
+
# return sample_text
|
231 |
|
232 |
# Build the Gradio interface.
|
233 |
with gr.Blocks() as demo:
|
234 |
gr.Markdown("# ASC tagger demo")
|
235 |
+
gr.Markdown("This demo version of the Argument Structure Construction (ASC) tagger processes sentences and identifies nine types of ASCs. The identified ASCs are highlighted in the output text.")
|
236 |
|
237 |
+
input_textbox = gr.Textbox(lines=5, label="Input Text", placeholder="Enter text here...")
|
238 |
output_html = gr.HTML(label="Tagged Text")
|
|
|
239 |
fill_btn = gr.Button("Fill Sample Text")
|
240 |
+
tag_btn = gr.Button("Tag ASCs")
|
241 |
+
|
|
|
242 |
fill_btn.click(fn=fill_sample_text, inputs=[], outputs=input_textbox)
|
243 |
+
tag_btn.click(fn=process_text, inputs=input_textbox, outputs=output_html)
|
244 |
|
245 |
if __name__ == "__main__":
|
246 |
demo.launch()
|