Spaces:
Sleeping
Sleeping
File size: 9,791 Bytes
15634f7 b563b79 15634f7 2d7589c b563b79 2d7589c 15634f7 2d7589c | 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 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 | """
NLP Text Lab - Gradio app for Hugging Face Spaces
Tasks: Tokenization, Stop-word removal, Stemming, Lemmatization,
POS tagging + word frequency, Full preprocessing pipeline.
"""
# NOTE: `spaces` must be imported FIRST (before spacy/torch), otherwise ZeroGPU
# raises "CUDA has been initialized before importing the spaces package".
try:
import spaces
except ImportError: # running locally / on CPU hardware
spaces = None
import string
from collections import Counter
import gradio as gr
import nltk
import pandas as pd
import spacy
from nltk.corpus import stopwords, wordnet
from nltk.stem import (LancasterStemmer, PorterStemmer, SnowballStemmer,
WordNetLemmatizer)
from nltk.tokenize import sent_tokenize, word_tokenize
# ------------------------------------------------- ZeroGPU compatibility ----
# ZeroGPU needs at least one @spaces.GPU function. The app does not use a GPU,
# so this is only a harmless placeholder.
if spaces is not None:
@spaces.GPU
def _gpu_placeholder():
return "ok"
# ---------------------------------------------------------------- setup ----
for pkg in ["punkt", "punkt_tab", "stopwords", "wordnet", "omw-1.4",
"averaged_perceptron_tagger", "averaged_perceptron_tagger_eng"]:
nltk.download(pkg, quiet=True)
def load_spacy():
try:
return spacy.load("en_core_web_sm")
except OSError:
from spacy.cli import download
download("en_core_web_sm")
return spacy.load("en_core_web_sm")
nlp = load_spacy()
STOP_WORDS = set(stopwords.words("english"))
porter, lancaster = PorterStemmer(), LancasterStemmer()
snowball = SnowballStemmer("english")
wnl = WordNetLemmatizer()
DEFAULT_TEXT = (
"Consistency is the key to success.\n"
"Every small step we take today brings us closer to the future we dream of.\n"
"The journey may be difficult, and sometimes we may feel tired or lost,\n"
"but we must keep moving forward. Growth takes time, patience, and courage."
)
# -------------------------------------------------------------- helpers ----
def _clean(text):
return (text or "").strip()
def _is_punct(tok):
return all(ch in string.punctuation for ch in tok)
def _wn_pos(tag):
"""Convert Penn Treebank tag to WordNet POS."""
if tag.startswith("J"):
return wordnet.ADJ
if tag.startswith("V"):
return wordnet.VERB
if tag.startswith("R"):
return wordnet.ADV
return wordnet.NOUN
# ---------------------------------------------------------------- tasks ----
def task_tokenize(text):
text = _clean(text)
if not text:
return "Please enter a sentence.", "", "", ""
words = word_tokenize(text)
sents = sent_tokenize(text)
doc = nlp(text)
spacy_tokens = [t.text for t in doc if not t.is_space]
spacy_sents = [s.text.strip() for s in doc.sents]
nltk_out = (f"WORD TOKENS ({len(words)}):\n{words}\n\n"
f"SENTENCES ({len(sents)}):\n" +
"\n".join(f"{i+1}. {s}" for i, s in enumerate(sents)))
spacy_out = (f"WORD TOKENS ({len(spacy_tokens)}):\n{spacy_tokens}\n\n"
f"SENTENCES ({len(spacy_sents)}):\n" +
"\n".join(f"{i+1}. {s}" for i, s in enumerate(spacy_sents)))
summary = (f"No. of tokens (NLTK): {len(words)} | "
f"No. of sentences (NLTK): {len(sents)}")
return summary, nltk_out, spacy_out, ""
def task_stopwords(text, remove_punct, lowercase):
text = _clean(text)
if not text:
return "Please enter a sentence.", "", "", ""
tokens = word_tokenize(text)
kept, removed = [], []
for tok in tokens:
if remove_punct and _is_punct(tok):
removed.append(tok)
continue
if tok.lower() in STOP_WORDS: # case-insensitive match
removed.append(tok)
else:
kept.append(tok.lower() if lowercase else tok)
summary = (f"Original tokens: {len(tokens)} | Removed: {len(removed)} | "
f"Remaining: {len(kept)}")
return summary, str(tokens), str(removed), " ".join(kept)
def task_stemming(text):
text = _clean(text)
if not text:
return pd.DataFrame(columns=["Word", "Porter", "Lancaster", "Snowball"])
toks = [t for t in word_tokenize(text) if not _is_punct(t)]
rows = [[t, porter.stem(t), lancaster.stem(t), snowball.stem(t)] for t in toks]
return pd.DataFrame(rows, columns=["Word", "Porter", "Lancaster", "Snowball"])
def task_lemmatize(text):
text = _clean(text)
empty1 = pd.DataFrame(columns=["Word", "POS tag", "Lemma (default=noun)",
"Lemma (POS-aware)"])
empty2 = pd.DataFrame(columns=["Word", "POS", "spaCy Lemma"])
if not text:
return empty1, empty2
toks = [t for t in word_tokenize(text) if not _is_punct(t)]
rows = []
for tok, tag in nltk.pos_tag(toks):
rows.append([tok, tag, wnl.lemmatize(tok.lower()),
wnl.lemmatize(tok.lower(), _wn_pos(tag))])
doc = nlp(text)
rows2 = [[t.text, t.pos_, t.lemma_] for t in doc
if not t.is_space and not t.is_punct]
return (pd.DataFrame(rows, columns=empty1.columns),
pd.DataFrame(rows2, columns=empty2.columns))
def task_pos_freq(text):
text = _clean(text)
if not text:
return (pd.DataFrame(columns=["Word", "POS tag"]),
pd.DataFrame(columns=["Word", "Count"]))
toks = [t for t in word_tokenize(text) if not _is_punct(t)]
pos_df = pd.DataFrame(nltk.pos_tag(toks), columns=["Word", "POS tag"])
words = [t.lower() for t in toks if t.lower() not in STOP_WORDS]
freq_df = pd.DataFrame(Counter(words).most_common(),
columns=["Word", "Count"])
return pos_df, freq_df
def task_pipeline(text):
text = _clean(text)
if not text:
return ["Please enter a sentence."] + [""] * 5
tokens = word_tokenize(text.lower())
no_punct = [t for t in tokens if not _is_punct(t)]
no_stop = [t for t in no_punct if t not in STOP_WORDS]
stems = [porter.stem(t) for t in no_stop]
lemmas = [wnl.lemmatize(t, _wn_pos(tag)) for t, tag in nltk.pos_tag(no_stop)]
return (f"1. Lowercase + Tokenize\n{tokens}", f"2. Remove punctuation\n{no_punct}",
f"3. Remove stop words\n{no_stop}", f"4. Stemming (Porter)\n{stems}",
f"5. Lemmatization (POS-aware)\n{lemmas}",
" ".join(lemmas))
LEARN_MD = """
## Stemming ("trimming") vs Lemmatization
**Stemming** chops the ending (suffix) off a word using simple rules, so the
result may *not* be a real word. It is fast but rough.
| Word | Stem (Porter) |
|---|---|
| studies | studi |
| running | run |
| difficult | difficult |
| happily | happili |
**Lemmatization** uses a dictionary (WordNet) and the word's part of speech to
return the real base form (the *lemma*). Slower but accurate.
| Word | POS | Lemma |
|---|---|---|
| studies | noun/verb | study |
| running | verb | run |
| better | adjective | good |
| mice | noun | mouse |
**When to use what?** Stemming for search engines/speed, lemmatization when
meaning matters (chatbots, sentiment analysis, NLP models).
## Stop words
Very common words (the, is, to, we ...) that carry little meaning. They are
removed to keep only the useful words.
"""
# ------------------------------------------------------------------- UI ----
with gr.Blocks(title="NLP Text Lab") as demo:
gr.Markdown("# 🧪 NLP Text Lab\nType a sentence/paragraph, then open any "
"tab and press the button.")
text_in = gr.Textbox(label="Your text", lines=5, value=DEFAULT_TEXT)
with gr.Tab("1. Tokenization"):
b1 = gr.Button("Tokenize", variant="primary")
s1 = gr.Textbox(label="Summary")
with gr.Row():
n1 = gr.Textbox(label="NLTK", lines=12)
sp1 = gr.Textbox(label="spaCy", lines=12)
hid = gr.Textbox(visible=False)
b1.click(task_tokenize, text_in, [s1, n1, sp1, hid])
with gr.Tab("2. Stop Words Removal"):
with gr.Row():
rp = gr.Checkbox(True, label="Also remove punctuation")
lc = gr.Checkbox(False, label="Lowercase result")
b2 = gr.Button("Remove stop words", variant="primary")
s2 = gr.Textbox(label="Summary")
t2 = gr.Textbox(label="All tokens", lines=3)
r2 = gr.Textbox(label="Removed (stop words / punctuation)", lines=3)
f2 = gr.Textbox(label="Filtered sentence", lines=3)
b2.click(task_stopwords, [text_in, rp, lc], [s2, t2, r2, f2])
with gr.Tab("3. Stemming"):
b3 = gr.Button("Apply stemming", variant="primary")
o3 = gr.Dataframe(label="Stemming results (Porter / Lancaster / Snowball)")
b3.click(task_stemming, text_in, o3)
with gr.Tab("4. Lemmatization"):
b4 = gr.Button("Apply lemmatization", variant="primary")
o4a = gr.Dataframe(label="NLTK WordNet Lemmatizer")
o4b = gr.Dataframe(label="spaCy Lemmatizer")
b4.click(task_lemmatize, text_in, [o4a, o4b])
with gr.Tab("5. POS Tags + Word Frequency"):
b5 = gr.Button("Analyse", variant="primary")
with gr.Row():
o5a = gr.Dataframe(label="Part-of-speech tags")
o5b = gr.Dataframe(label="Word frequency (without stop words)")
b5.click(task_pos_freq, text_in, [o5a, o5b])
with gr.Tab("6. Full Pipeline"):
b6 = gr.Button("Run full pipeline", variant="primary")
p = [gr.Textbox(lines=3, show_label=False) for _ in range(5)]
final = gr.Textbox(label="Final cleaned text", lines=2)
b6.click(task_pipeline, text_in, p + [final])
with gr.Tab("📖 Learn"):
gr.Markdown(LEARN_MD)
if __name__ == "__main__":
demo.launch() |