Python client bareunpy
bareunpy is the official client library that wraps the Bareun server so you can use it easily from Python.
It provides four features: morphological analysis (Tagger), segmentation (Tokenizer), spelling and grammar correction (Corrector), and custom dictionary management (CustomDict).
bareunpy 2.1: homonym sense disambiguation (beta)
Version 2.1.0 adds the homonym sense disambiguation (WSD) API.
Whether 다리 is a bridge (橋) to cross or a leg (脚) of the body is not decided by POS (NNG),
and with this feature on, the meaning is chosen from context and you receive the sense number (the dictionary's meaning number) and the definition together.
pip install --upgrade "bareunpy>=2.1"
This is a beta feature
This feature is in beta and requires a server of Bareun 3.1.0 or higher. During the beta, it can be used on api.bareun.ai (the cloud), and on a self-installed server after upgrading to 3.1.0. For accuracy and limits, see the Homonym sense disambiguation API.
Getting just the senses: senses()
from bareunpy import Tagger
tagger = Tagger(apikey="koba-XXXX-...")
for s in tagger.senses("다리를 건넜다."):
print(s.content, s.tag, s.sense_no, s.meaning)
# 다리 NNG 5 물을 건너거나 … 건너다닐 수 있도록 만든 시설물.
# 건너 VV 1 무엇을 사이에 두고 한편에서 맞은편으로 가다.
for s in tagger.senses("다리가 저리다."):
print(s.content, s.sense_no, s.meaning)
# 다리 1 사람이나 동물의 몸통 아래 붙어 있는 신체의 부분. …
senses() returns only the morphemes that were given a sense. Morphemes with no dictionary sense number, such as particles and endings,
are left out, so it is normal for the result to be shorter than the morpheme list.
Each item is a SenseInfo and holds the following values.
| Field | Description |
|---|---|
content / tag | The surface form and POS of the morpheme |
sense_no | Sense number (the meaning number in Urimalsaem, the NIKL Open Korean Dictionary). In dictionary notation it is zero-padded to 3 digits (005) |
meaning | Definition in Korean. It can be an empty string (under 1%, where Urimalsaem has no headword) |
urimal_target_id | Unique number of the Urimalsaem headword (0 if none) |
urimal_url | Address of the Urimalsaem dictionary page (an empty string if there is no number) |
probability | Probability [0,1] that this sense was chosen among the candidate senses. Always 1.0 if there is only one candidate |
Getting it together with the analysis result: with_sense
res = tagger.tag("다리를 건넜다.", with_sense=True)
res.senses() # list of SenseInfo
res.pos(join=True, sense=True) # ['다리__005/NNG', '를/JKO', '건너__001/VV', ...]
res.pos(sense=True) # [('다리', 'NNG', 5), ('를', 'JKO', 0), ...]
# The same option works for multiple sentences and raw analysis.
tagger.tags(["다리를 건넜다.", "다리가 저리다."], with_sense=True)
tagger.taglist(["다리를 건넜다."], with_sense=True)
tagger.tag_raw("다리를건넜다", with_sense=True)
Nothing changes unless you turn it on
with_sense and sense both default to False. A call without them has the same response contents and
processing time as before, and the tuple shape of the pos() result stays the same. Turning it on makes the server run
one more inference, so it is best to turn it on only where needed.
bareunpy 2.0
What changed
Version 2.0 switches the internal communication method to Connect RPC. The client was adapted to match the server's change to handling gRPC, Connect, and REST all on one port.
Key improvements in 2.0
Much lighter
1.x needed several packages, such as grpcio (a C extension, 50MB+), bareun-apis, googleapis-common-protos, certifi, and cryptography.
2.0 has only two runtime dependencies: connectrpc and protobuf.
The install size drops a lot, and you no longer have to worry about dependency conflicts.
Bug fixes
We fixed several known problems in 1.x.
| Problem | 1.x | 2.0 |
|---|---|---|
TypeError when calling set_domain() | ❌ Broken | ✅ Works properly, with a DeprecationWarning |
| CA certificate error (TLS) | ❌ Connecting to api.bareun.ai could fail | ✅ Fixed |
grpcio ↔ protobuf version conflict | ❌ Install could fail depending on the environment | ✅ A single protobuf 7.35+ |
Dependence on the unofficial connecpy library | ❌ Maintenance risk | ✅ Official connectrpc |
| Python 3.6–3.9 support (EOL) | (supported) | Streamlined to Python 3.10+ |
Streaming correction API added
Corrector.correct_error_stream() was added, which streams spelling and grammar correction results in real time.
Installation
pip install "bareunpy>=2.0"
Python 3.10 or higher is required.
Versions supported by pyqwest (Rust-based HTTP)
pyqwest, the HTTP transport layer of connectrpc, provides binaries for Python 3.10, 3.12, and 3.13.
Python 3.11 is not supported yet, so 3.12 or 3.13 is recommended.
bareunpy 1.x
This is the earlier grpcio-based version. Environments already using 1.x keep working.
pip install "bareunpy<2.0"
Notice on long-term support for 1.x
1.x currently receives no new features beyond security and urgent fixes. For new environments, we recommend 2.0.
API key and server address
An API key is a value that starts with koba-, issued on the Bareun portal.
| Environment | host | port |
|---|---|---|
Cloud (api.bareun.ai) | "api.bareun.ai" | 443 (TLS) |
| Self-installed or Docker | "localhost" | 5656 |
If you omit host, the default is api.bareun.ai:443.
Morphological analysis: Tagger
from bareunpy import Tagger
tagger = Tagger(apikey="koba-XXXX-...")
# or explicitly
tagger = Tagger(apikey="koba-XXXX-...", host="api.bareun.ai", port=443)
result = tagger.tag("나비 허리에 새파란 초생달이 시리다.")
print(result.pos())
# [('나비', 'NNG'), ('허리', 'NNG'), ('에', 'JKB'), ...]
print(result.nouns()) # ['나비', '허리', '초생달']
from bareunpy import Tagger
tagger = Tagger(apikey="koba-XXXX-...", host="localhost", port=5656)
result = tagger.tag("나비 허리에 새파란 초생달이 시리다.")
print(result.pos())
# [('나비', 'NNG'), ('허리', 'NNG'), ('에', 'JKB'), ...]
print(result.nouns()) # ['나비', '허리', '초생달']
Analyzing multiple sentences
# Multiple sentences as a list: joined with newlines and analyzed
result = tagger.tags(["첫 번째 문장.", "두 번째 문장."])
# The list as is, without sentence splitting
result = tagger.taglist(["첫 번째 문장.", "두 번째 문장."])
print(result.morphs())
tagger = Tagger(apikey="koba-XXXX-...", host="localhost", port=5656)
result = tagger.tags(["첫 번째 문장.", "두 번째 문장."])
result = tagger.taglist(["첫 번째 문장.", "두 번째 문장."])
print(result.morphs())
Working with the Tagged result
result = tagger.tag("햇빛이 선명하게 나뭇잎을 핥고 있었다.")
result.pos() # [(morpheme, POS), ...]
result.pos(join=True) # ['햇빛/NNG', '이/JKS', ...]
result.pos(detail=True) # (morpheme, POS, OOV flag, probability)
result.pos(sense=True) # (morpheme, POS, sense number): 2.1, when analyzed with with_sense=True
result.senses() # list of homonym senses: 2.1, when analyzed with with_sense=True
result.morphs() # ['햇빛', '이', '선명', ...]
result.nouns() # ['햇빛', '나뭇잎']
result.verbs() # ['핥']
result.as_json() # dict
result.as_json_str() # JSON string
Main methods
| Method | Returns | Description |
|---|---|---|
tag(text) | Tagged | Morphological analysis of a string. Splits sentences internally |
tags(sentences) | Tagged | A list of strings, joined with newlines and analyzed |
taglist(sentences) | Tagged | Analyzes the list as is, sentence by sentence (no splitting) |
pos(text) | list | Shorthand for tag() + .pos() |
morphs(text) | list | Shorthand for tag() + .morphs() |
nouns(text) | list | Shorthand for tag() + .nouns() |
senses(text) | list | Homonym sense disambiguation result (a list of SenseInfo). 2.1 or higher, beta |
tag_raw(text) | Tagged | Raw model analysis without post-processing. 2.0.1 or higher |
Segmentation: Tokenizer
Returns the result of segmentation, the stage before morphological analysis.
from bareunpy import Tokenizer
tokenizer = Tokenizer(apikey="koba-XXXX-...")
result = tokenizer.tokenize("안녕하세요, 반가워요.")
print(result.seg()) # list of segmentation results
print(result.nouns()) # nouns only
from bareunpy import Tokenizer
tokenizer = Tokenizer(apikey="koba-XXXX-...", host="localhost", port=5656)
result = tokenizer.tokenize("안녕하세요, 반가워요.")
print(result.seg()) # list of segmentation results
print(result.nouns()) # nouns only
Spelling and grammar correction: Corrector
Cloud-only feature
Spelling and grammar correction (Corrector) is available only on the api.bareun.ai cloud service.
Self-installed (on-premises) servers do not include the correction feature.
from bareunpy import Corrector
corrector = Corrector(apikey="koba-XXXX-...") # defaults to api.bareun.ai:443
resp = corrector.correct_error("영수 도 줄기가 얇어서 고은 꽃이 피었다.")
print(resp.revised) # the corrected sentence
corrector.print_results(resp)
Streaming correction (new in 2.0)
For long sentences or when you need real-time feedback, you can use the streaming mode, in which the server sends correction results in pieces.
corrector = Corrector(apikey="koba-XXXX-...") # cloud only
for resp in corrector.correct_error_stream("긴 텍스트를 여기에 넣습니다..."):
kind = resp.WhichOneof("res")
if kind == "first":
print("Original:", resp.first.origin)
elif kind == "progress":
print("Correcting...", resp.progress)
elif kind == "post":
print("Final:", resp.post.revised)
Streaming is 2.0 only
correct_error_stream() uses Connect RPC's server-streaming.
It is not supported in 1.x.
Custom dictionary: CustomDict
from bareunpy import Tagger
tagger = Tagger(apikey="koba-XXXX-...")
cd = tagger.custom_dict("my-domain")
cd.copy_np_set({"바이칼AI", "바른NLP"}) # proper nouns
cd.update() # apply to the server
tagger.set_custom_dicts(["my-domain"])
result = tagger.tag("바이칼AI의 바른NLP 엔진")
from bareunpy import Tagger
tagger = Tagger(apikey="koba-XXXX-...", host="localhost", port=5656)
cd = tagger.custom_dict("my-domain")
cd.copy_np_set({"바이칼AI", "바른NLP"})
cd.update()
tagger.set_custom_dicts(["my-domain"])
result = tagger.tag("바이칼AI의 바른NLP 엔진")
For more on operating a custom dictionary, see Using the custom dictionary in depth.
Migrating from 1.x to 2.0
The basic API is the same, so most code can be used as is.
pip install "bareunpy>=2.0"
Things to note:
- The
grpciodependency is gone. If you have code that usedgrpciodirectly, you have to keep it installed separately. set_domain()is kept only as an alias ofset_custom_dicts(). It raises aDeprecationWarningand will be removed in the future.correct_error_list()has been retired. Usecorrect_error().- Python 3.6–3.9 is not supported.
Frequently asked questions
Q. How do I install bareunpy 2.0?
Install it with pip install "bareunpy>=2.0". Python 3.10 or higher is required, and 3.12 or 3.13 is recommended.
Q. Do I have to change a lot of code to move from 1.x to 2.0?
The basic API of Tagger, Tokenizer, Corrector, and CustomDict is the same. If you upgrade with pip install "bareunpy>=2.0", most things work as they are.
Q. What happens in 2.0 to code that used grpcio directly?
bareunpy itself no longer needs grpcio. If your existing code imported and used grpcio directly, you have to install it separately.
Q. I'm using Python 3.11. Can I install 2.0?
pyqwest, the HTTP transport layer, does not yet provide a binary for 3.11. Please use 3.10, 3.12, or 3.13.
Q. Can I use spelling and grammar correction on a self-installed server?
Spelling and grammar correction (Corrector) is available only on the api.bareun.ai cloud service. On a self-installed server, only morphological analysis and segmentation are available.
Q. Can I get the senses of homonyms distinguished?
With bareunpy 2.1.0 or higher, you can get the sense number and definition with tagger.senses("다리를 건넜다.").
Passing with_sense=True to tag(), tags(), taglist(), and tag_raw() also works.
It is a beta feature and requires a server of Bareun 3.1.0 or higher.
Q. Where is streaming correction used?
With Corrector.correct_error_stream() you can receive correction results in pieces in real time. It is a feature newly added in 2.0, useful for handling long sentences and building real-time feedback UIs.