# SPDX-FileCopyrightText: 2016-2026 PyThaiNLP Project
# SPDX-FileType: SOURCE
# SPDX-License-Identifier: Apache-2.0
"""Dependency parsing for Thai text."""
from __future__ import annotations
from typing import Any, Optional, Union
_tagger: Optional[Any] = None
_tagger_name: str = ""
[docs]
def dependency_parsing(
text: str,
model: Optional[str] = None,
tag: str = "str",
engine: str = "esupar",
) -> Union[list[list[str]], str]:
"""
Parse the dependency structure of a text.
:param str text: text to be parsed
:param Optional[str] model: model to use with the engine
(for esupar, transformers_ud, and ud_goeswith)
:param str tag: output type, ``"str"`` (CoNLL-U text, default)
or ``"list"``
:param str engine: engine to use for parsing. Options are:
* *esupar* (default) - tokenizer, POS tagger, and dependency
parser using BERT/RoBERTa/DeBERTa models.
`GitHub <https://github.com/KoichiYasuoka/esupar>`_
* *spacy_thai* - tokenizer, POS tagger, and dependency parser
for the Thai language, using Universal Dependencies.
`GitHub <https://github.com/KoichiYasuoka/spacy-thai>`_
* *transformers_ud* - TransformersUD.
`GitHub <https://github.com/KoichiYasuoka/>`_
* *ud_goeswith* - POS tagger and dependency parser
using ``goeswith`` for subwords
* *attaparse* - Thai dependency parser using Stanza and
PhayaThaiBERT.
`GitHub <https://github.com/nlp-chula/attaparse>`_
:return: CoNLL-U text if ``tag`` is ``"str"``, otherwise a list of
lists of fields
:rtype: Union[list[list[str]], str]
:raises NotImplementedError: if the engine is not supported
Options for ``model`` with the esupar engine:
* *th* (default) - KoichiYasuoka/roberta-base-thai-spm-upos model.
`Hugging Face
<https://huggingface.co/KoichiYasuoka/roberta-base-thai-spm-upos>`_
* *KoichiYasuoka/deberta-base-thai-upos* - DeBERTa(V2) model
pre-trained on Thai Wikipedia texts for POS tagging and
dependency parsing.
`Hugging Face
<https://huggingface.co/KoichiYasuoka/deberta-base-thai-upos>`_
* *KoichiYasuoka/roberta-base-thai-syllable-upos* - RoBERTa model
pre-trained on Thai Wikipedia texts for POS tagging and
dependency parsing (syllable level).
`Hugging Face
<https://huggingface.co/KoichiYasuoka/roberta-base-thai-syllable-upos>`_
* *KoichiYasuoka/roberta-base-thai-char-upos* - RoBERTa model
pre-trained on Thai Wikipedia texts for POS tagging and
dependency parsing (character level).
`Hugging Face
<https://huggingface.co/KoichiYasuoka/roberta-base-thai-char-upos>`_
To train models for esupar, see the
`esupar GitHub repository <https://github.com/KoichiYasuoka/esupar>`_.
Options for ``model`` with the transformers_ud engine:
* *KoichiYasuoka/deberta-base-thai-ud-head* (default) - DeBERTa(V2)
model pre-trained on Thai Wikipedia texts for dependency parsing
(head detection using Universal Dependencies) and question
answering, derived from deberta-base-thai and trained on
th_blackboard.conll.
`Hugging Face
<https://huggingface.co/KoichiYasuoka/deberta-base-thai-ud-head>`_
* *KoichiYasuoka/roberta-base-thai-spm-ud-head* - RoBERTa model
pre-trained on Thai Wikipedia texts for dependency parsing.
`Hugging Face
<https://huggingface.co/KoichiYasuoka/roberta-base-thai-spm-ud-head>`_
Options for ``model`` with the ud_goeswith engine:
* *KoichiYasuoka/deberta-base-thai-ud-goeswith* (default) -
DeBERTa(V2) model pre-trained on Thai Wikipedia texts for POS
tagging and dependency parsing (using ``goeswith`` for subwords).
`Hugging Face
<https://huggingface.co/KoichiYasuoka/deberta-base-thai-ud-goeswith>`_
:Example:
>>> from pythainlp.parse import dependency_parsing # doctest: +SKIP
>>> print(
... dependency_parsing("ผมเป็นคนดี", engine="esupar")
... ) # doctest: +SKIP
1 ผม _ PRON _ _ 3 nsubj _ SpaceAfter=No
2 เป็น _ VERB _ _ 3 cop _ SpaceAfter=No
3 คน _ NOUN _ _ 0 root _ SpaceAfter=No
4 ดี _ VERB _ _ 3 acl _ SpaceAfter=No
>>> print(
... dependency_parsing("ผมเป็นคนดี", engine="spacy_thai")
... ) # doctest: +SKIP
1 ผม PRON PPRS _ 2 nsubj _ SpaceAfter=No
2 เป็น VERB VSTA _ 0 ROOT _ SpaceAfter=No
3 คนดี NOUN NCMN _ 2 obj _ SpaceAfter=No
"""
global _tagger, _tagger_name
if _tagger is None or _tagger_name != engine:
if engine == "esupar":
from pythainlp.parse.esupar_engine import Parse
_tagger = Parse(model=model or "th")
elif engine == "transformers_ud":
from pythainlp.parse.transformers_ud import Parse # type: ignore[assignment] # noqa: I001
_tagger = Parse(
model=model or "KoichiYasuoka/deberta-base-thai-ud-head"
)
elif engine == "spacy_thai":
from pythainlp.parse.spacy_thai_engine import Parse # type: ignore[assignment] # noqa: I001
_tagger = Parse()
elif engine == "ud_goeswith":
from pythainlp.parse.ud_goeswith import Parse # type: ignore[assignment] # noqa: I001
_tagger = Parse(
model=model or "KoichiYasuoka/deberta-base-thai-ud-goeswith"
)
elif engine == "attaparse":
from pythainlp.parse.attaparse_engine import Parse # type: ignore[assignment] # noqa: I001
_tagger = Parse()
else:
raise NotImplementedError("The engine doesn't support.")
_tagger_name = engine
return _tagger(text, tag=tag)