Simon Clematide
Add morphological features toggle, hover tooltip, and UD documentation links
ae56e3f
Raw History Blame Contribute Delete
3.69 kB
"""
Client wrapper for LINDAT UDPipe 2 REST API.
API Reference: https://lindat.mff.cuni.cz/services/udpipe/api/
"""
import requests
from typing import Dict, Any, Optional
UDPIPE_API_URL = "https://lindat.mff.cuni.cz/services/udpipe/api/process"
class UDPipeClient:
def __init__(self, timeout: int = 15):
self.timeout = timeout
self.session = requests.Session()
def parse_sentence(
self,
text: str,
model: str,
strip_morphology: bool = True,
cache: Optional[Any] = None
) -> Dict[str, Any]:
"""
Parses a single sentence with UDPipe 2.
Args:
text: Sentence text (single sentence).
model: Model identifier (e.g. 'english-ewt-ud-2.17-251125').
strip_morphology: If True, sets FEATS column to '_' so the visualizer
and parser focus strictly on POS tags and dependencies.
cache: Optional BoundedParseCache or mapping with .get(model, text) and
.set(model, text, conllu).
Returns:
Dictionary with { "conllu": str, "model": str, "error": Optional[str] }
"""
clean_text = text.strip()
# Enforce single sentence processing (first sentence line)
if "\n" in clean_text:
clean_text = clean_text.split("\n")[0].strip()
if not clean_text:
return {"conllu": "", "model": model, "error": "Empty input text."}
if cache is not None:
cached_conllu = cache.get(model, clean_text, strip_morphology=strip_morphology)
if cached_conllu is not None:
return {
"conllu": cached_conllu,
"model": model,
"error": None
}
data = {
"data": clean_text,
"model": model,
"tokenizer": "",
"tagger": "",
"parser": "",
}
try:
resp = self.session.post(UDPIPE_API_URL, data=data, timeout=self.timeout)
resp.raise_for_status()
res_json = resp.json()
conllu_raw = res_json.get("result", "")
if strip_morphology:
conllu_processed = self._strip_feats_column(conllu_raw)
else:
conllu_processed = conllu_raw
if cache is not None and conllu_processed:
cache.set(model, clean_text, conllu_processed, strip_morphology=strip_morphology)
return {
"conllu": conllu_processed,
"model": model,
"error": None
}
except requests.exceptions.RequestException as e:
return {
"conllu": "",
"model": model,
"error": f"UDPipe API Request Error: {e}"
}
@staticmethod
def _strip_feats_column(conllu_text: str) -> str:
"""
Replaces column 6 (FEATS) with '_' to keep focus on POS tags and dependency relations.
CoNLL-U columns: 1:ID, 2:FORM, 3:LEMMA, 4:UPOS, 5:XPOS, 6:FEATS, 7:HEAD, 8:DEPREL, 9:DEPS, 10:MISC
"""
out_lines = []
for line in conllu_text.splitlines():
line_str = line.strip()
if not line_str or line_str.startswith("#"):
out_lines.append(line)
continue
cols = line.split("\t")
if len(cols) == 10:
cols[5] = "_" # Blank morphological features
out_lines.append("\t".join(cols))
else:
out_lines.append(line)
return "\n".join(out_lines) + "\n"