Spell Checking API
The spell checking API inspects Korean sentences for spelling, word spacing, standard-language rules, loanword orthography, and sentence-level errors, and corrects them automatically. The result contains not only the corrected sentence but also detailed information about each corrected word and phrase.
- It analyzes the input text, finds the parts that need correction, and returns the corrected result.
- Correction categories are based on the Korean language norms of the National Institute of Korean Language (orthography, word spacing, standard language, and so on).
- Each position in the original text is mapped precisely to its corrected position, which helps with understanding the context.
- If a user decides a correction is inappropriate, the API helps them register the word in a custom dictionary. Entries can be added under several parts of speech: noun, proper noun, compound noun, verb, adjective, adverb, determiner, and interjection.
Try It Out
Click Authorize to register your API key, then use Try it out.
Spell Check Request
Request Message Definition
// Spell check request message
message CorrectErrorRequest {
// Input document
Document document = 1;
// Encoding type used to compute offsets
EncodingType encoding_type = 2;
// Custom dictionary domain. Only one can be specified.
// Will be removed in v4.0. Use the new custom_dict_names instead.
// If custom_dict_names is set, this value is ignored.
string custom_domain = 4 [deprecated = true];
// Custom dictionary names.
// Specify one or more dictionaries created with CustomDictionaryService.
// If more than one is given, the one listed first takes precedence.
repeated string custom_dict_names = 5;
// Options applied when running the spell checker.
RevisionConfig config = 11;
}
// Spell checker configuration.
// The defaults apply when no option is set.
// (Note) More options may be added over time.
message RevisionConfig {
// If true, sentence splitting is disabled.
bool disable_split_sentence = 1;
// Disable the compound-noun splitting dictionary
bool disable_caret_spacing = 2;
// Disable auxiliary-verb spacing
bool disable_vx_spacing = 3;
// Treat the given text as a title such as an article headline. Default false
bool treat_as_title = 4;
// Enable restricted punctuation usage
bool enable_limited_punctuation = 5;
// Enable removal of unnecessary whitespace
bool enable_cleanup_whitespace = 11;
// Enable sentence-level checks
bool enable_sentence_check = 21;
// Enable public-term refinement suggestions (confirmation blocks only; the text is not changed)
bool enable_public_term_refine = 22;
// Enable contested fixes (expressions the guidelines recommend against but that are common)
bool enable_contested_fix = 23;
// Disable the confirmation blocks for hateful or discriminatory expressions
bool disable_bias_check = 24;
}
Request Message Description
| Variable | Sub-variable | Description |
|---|---|---|
document | content | Put text consisting of multiple sentences here. Sentences are split by default. |
| language | Set this to ko_KR. This format generally combines a language with the country where it is used. If Bareun later supports the Korean used in North Korea, ko_KP could be used. | |
| encoding_type | EncodingType determines how the position of each word is computed during analysis. Suppose "안녕하세요" is split into "안녕", "하", "시", "어요". If the start position of "하" is 6, the encoding is UTF-8. If it is 2, the encoding is UTF-16 or UTF-32. Languages such as Python use UTF32 by default. In practice it is determined by the client's programming language. In C++, use UTF32 with std::wstring and UTF8 with plain std::string. Go and C++ typically use UTF-8. Java uses UTF-16. | |
| custom_domain | The name of a registered custom dictionary. | |
| custom_dict_names | Specify one or more dictionaries created with CustomDictionaryService. If more than one is given, the one listed first takes precedence. | |
| config | disable_split_sentence | Disables sentence splitting. Splitting is the default, so it is best not to use this option. |
| disable_caret_spacing | Do not apply the compound-noun splitting dictionary. It is applied by default. For example, when the attached word "인공지능" is found, its original dictionary form is "인공^지능", so it is split into "인공 지능". | |
| disable_vx_spacing | Minimize spacing of auxiliary verbs. By default, auxiliary verbs are spaced as much as possible, which is the standard spelling rule. | |
| treat_as_title | Treat the text as a title. Punctuation and some other handling differ for sentences used as titles. | |
| enable_limited_punctuation | Enable restricted punctuation usage. Only permitted symbols are allowed for periods, question marks, dashes, and similar marks. | |
| enable_cleanup_whitespace | Remove unnecessary whitespace in the text, in particular whitespace at the beginning or end of a sentence. | |
| enable_sentence_check | Enables sentence-level checks. Corrects an object marker that does not fit the predicate into a subject marker, and suggests, as a confirmation block, an active-voice rewrite of translationese passives (~에 의해 ~되다). The default is false. | |
| enable_public_term_refine | Enables public-term refinement suggestions. Suggests easier words, as confirmation blocks, for administrative terms refined by the National Institute of Korean Language and for Japanese-style terms, without changing the text. The default is false. | |
| enable_contested_fix | Enables contested fixes. Suggests, as confirmation blocks, expressions that the guidelines recommend against but that are common (좋은 하루 되세요, 회의에 있어서, and so on), and removes the plural -들 after a quantity expression from the text. The default is false. | |
| disable_bias_check | Turns off the confirmation blocks that suggest neutral wording for belittling or discriminatory expressions. The default is false (on). |
Correction Sessions (3.4.0)
Use this when you correct one long text, such as a whole book, in several requests. Open a session and keep sending requests with the same session_id.
Words that are not in the dictionary but appear two or more times in the document (names, business names, and so on) are then treated as known words instead of being corrected as typos.
The same spelling that differs only in spacing (서울경제 진흥원, 서울경제진흥원) counts as one word.
| RPC | What it does |
|---|---|
OpenSession | Opens a session. The custom dictionaries (custom_dict_names) and corrector settings (config) are fixed at this point and do not change until the session closes. The response returns session_id, session_revision, idle_timeout_seconds, and max_lifetime_seconds. |
CorrectError, StreamCorrectError | Put that value in the request's session_id. When a session is given, the request's config and custom_dict_names are ignored and the values chosen when the session was opened are used. session_revision in the response counts how many times the session has changed. |
GetSessionEvents | Returns the session events newer than since_revision. Use it to find out whether the session confirmed a new word after you received an earlier answer. Streaming correction receives the same information as a correction event. |
CloseSession | Closes the session and gives its slot back immediately. |
- A session can be used only with the API key that opened it, and it is not stored permanently on the server.
- The server closes a session by itself 10 minutes after the last call, or 1 hour after it was opened.
- There is a limit on concurrent sessions per key and per server. Above it, requests are rejected with
RESOURCE_EXHAUSTED. - A session ID the server does not know, or one that has expired, gets
NOT_FOUND(withSESSION_NOT_FOUNDorSESSION_EXPIREDin thebareun.ai/sessionerror detail). CallOpenSessionagain and resend the earlier part you need. - On a self-hosted server, sessions are kept in server memory by default. To share sessions across several instances, choose an external Redis with the
revisionSession.storesetting (Configuration).
Spell Check Response
Response Message Definition
// Spell check response
message CorrectErrorResponse {
// The original request document
string origin = 1;
// The corrected document
string revised = 2;
// One or more corrected results
repeated RevisedBlock revised_blocks = 3;
// List of whitespace ranges to remove from the input
repeated CleanUpRange whitespace_cleanup_ranges = 9;
// Corrected sentences
repeated RevisedSentence revised_sentences = 11;
// Information about correction help entries
map<string, ReviseHelp> helps = 12;
// Language of the text. If no language was specified, it is detected
// automatically and returned.
// If a language was specified, the same language is returned.
// The language is expressed like ko_KR.
string language = 99;
// Number of eojeol (word units)
int32 tokens_count = 100;
}
message RevisedSentence {
string origin = 1;
string revised = 2;
}
// RevisedBlock holds the original text to correct, the corrected result,
// the reason, and custom dictionary suggestions.
//
// - origin: The original text of the correction, with its position and range.
// - revised: The correction result. If there are several candidates, this holds
// the most representative one.
// - revisions: One or more correction candidates. Each result includes a score,
// a category, and help information.
// - nested: When several blocks are merged into one, the original blocks are
// included in the nested blocks.
// - lemma: A target may be left uncorrected. If it has to be added to a custom
// dictionary, the base form is given so that it can be added.
// - pos: When adding to the dictionary, holds the morphological information of the word.
//
// [Merging several blocks]
// When spacing and attaching corrections occur in several consecutive blocks,
// their boundaries can keep merging. For example, take
// "`하지만아무도도와드리지않았다.`". The blocks "하지만 아무도", "아무도 도와",
// "도와드리지", and "드리지 않았다." touch each other at their boundaries. In this
// case "`하지만아무도도와드리지않았다.`" is handled as a single block. Computing
// this in the UI takes a lot of effort, so the four cases above are described
// inside the `nested` blocks.
//
// [Suggesting custom dictionary candidates]
// When it is not appropriate to suggest a correction for a block in the original
// text, the user can register the word in a new dictionary. For this purpose the
// source form for registration is provided. For example, if the eojeol "신박했다"
// was corrected, "신박하" can be given as the lemma and "adjective" as the part
// of speech. This can also include compound nouns with spaced blocks. In that
// case, as in "제품^품질관리^체계", most UI units do not need to represent them in
// detail, but this is accounted for when you want to show the included blocks
// separately.
message RevisedBlock {
// Position and text of the original being corrected.
// Mostly an eojeol, but with nested it may include several blocks.
// If one eojeol has several corrections, they may be grouped.
TextSpan origin = 1;
// The corrected result, the most representative of several candidates
string revised = 2;
// Examples of various corrected sentences
repeated Revision revisions = 3;
// If one eojeol receives several edits, or edits in different eojeol touch
// at their boundaries and overlap, the original correction blocks are
// included in nested.
repeated RevisedBlock nested = 10;
// Base unit for adding to a custom dictionary. Not usable when nested exists.
string lemma = 4;
// Part of speech to add to the custom dictionary
CustomDictPos pos = 5;
}
// Information about a single correction
message Revision {
// The token proposed as the fix
string revised = 1;
// Score for the fix. A higher score means a stronger candidate.
double score = 2;
// RevisionCategory information
RevisionCategory category = 3;
// Help for the fix, as an index
string help_id = 4;
}
// Help object for a correction
message ReviseHelp {
// Help ID. Some help entries are fixed and some are generated dynamically.
string id = 1;
// Category of the sentence correction
RevisionCategory category = 2;
// Explanation of why it should change
string comment = 3;
// Sentences that could result from the change
repeated string examples = 4;
// Related rule
string rule_article = 5;
}
// Morpheme type for the custom dictionary
enum CustomDictPos {
// Not applicable
POS_UNK = 0;
// Compound noun dictionary
POS_NNG = 1;
// Proper noun dictionary
POS_NNP = 2;
// Compound noun splitting dictionary
POS_NNG_CARET = 3;
// Verb dictionary
POS_VV = 4;
// Adjective dictionary
POS_VA = 5;
// Determiner dictionary
POS_MM = 6;
// Interjection dictionary
POS_IC = 7;
}
// Categories of Korean sentence correction
enum RevisionCategory {
// No correction category
UNKNOWN = 0;
// Correction type: grammar and orthography
// Conjugation, particle attachment, punctuation, etc.
GRAMMER = 1;
// Correction type: word-level orthography rules
// Sai-siot, initial sound rule, Sino-Korean combinations (율/률), etc.
WORD = 2;
// Correction type: word spacing
SPACING = 3;
// Correction type: standard language in general
STANDARD = 8;
// Correction type: typo
TYPO = 9;
// Correction type: loanword orthography
FOREIGN_WORD = 10;
// Correction type: confusable words
CONFUSABLE_WORDS = 11;
// Correction type: sentence-level error
SENTENCE = 12;
// Correction type: needs confirmation
CONFIRM = 13;
// Thinking: waiting for streaming post-processing
THINKING = 14;
}
// CleanUpRange: range of unnecessary whitespace to remove from the input
message CleanUpRange {
// Position
int32 offset = 1;
// Length
int32 length = 2;
// Additional information about where to remove
enum CleanUpPosition {
// Start
START = 0;
// End
END = 1;
// Middle
MIDDLE = 2;
}
CleanUpPosition position = 3;
}
Response Message Description
| Variable | Sub-variable | Description |
|---|---|---|
| origin | The full original request text | |
| revised | The full corrected text | |
| revised_blocks[] | Correction blocks that allow various correction operations. | |
| origin | The original text, including the position of the target | |
| revised | The corrected result, the most representative of several candidates | |
| revisions | Various correction examples, including the category and help ID | |
| nested | When several blocks are merged into one, the original blocks were not necessarily wrong, so they are kept inside. Each nested block contains only its own individual edit, so it cannot hold every block faithfully. It exists for advanced use, so that only the relevant edits can be applied. | |
| lemma | Base unit for adding to a custom dictionary. Not usable when nested exists. | |
| whitespace_cleanup_ranges[] | List of whitespace ranges to remove from the input | |
| offset | Position | |
| length | Length | |
| position | One of three values: START, END, MIDDLE. | |
| revised_sentences[] | Sentence-level corrections of the whole text. Sentences are split automatically. | |
| origin | The sentence to correct | |
| revised | The corrected sentence | |
| helps{} | ||
| id | Help ID. Some help entries are fixed and some are generated dynamically. | |
| category | Correction category | |
| comment | Explanation of why it should change | |
| examples[] | Sentences that could result from the change | |
| rule_article | Related rule | |
| language | Language of the text. If no language was specified, it is detected automatically and returned. If a language was specified, the same language is returned. The language is expressed like ko_KR. | |
| tokens_count | Number of eojeol. |
Correction Categories
Corrections are classified into the following main categories:
| Category | Description |
|---|---|
| GRAMMER | Grammar and orthography: conjugation, particle attachment, punctuation, etc. |
| WORD | Word-level orthography rules: sai-siot, initial sound rule, etc. |
| SPACING | Word spacing |
| STANDARD | Standard language in general |
| TYPO | Typos |
| FOREIGN_WORD | Loanword orthography |
| CONFUSABLE_WORDS | Confusable words |
| SENTENCE | Sentence-level errors |
| CONFIRM | Needs confirmation |
| THINKING | Thinking (waiting for streaming post-processing) |
Streaming Spell Check (StreamCorrectError)
StreamCorrectError delivers correction results step by step through server streaming.
You first receive the initial correction (First), then receive post-processing results as progress, post, and cancelled events.
Stream Request Message Definition
message StreamCorrectErrorRequest {
// Same input as CorrectErrorRequest
Document document = 1;
EncodingType encoding_type = 2;
string custom_domain = 4 [deprecated = true];
repeated string custom_dict_names = 5;
RevisionConfig config = 11;
// Request ID (generated by the server if left empty)
int64 req_id = 101;
}
Stream Response Message Definition
message StreamCorrectErrorResponse {
oneof res {
StreamFirstCorrectError first = 1;
CancelledRevision cancelled = 2;
PostRevision post = 3;
ProgressRevision progress = 4;
}
}
Stream Response Types
| Type | Description |
|---|---|
| first | The first correction result. A body similar to CorrectErrorResponse, plus req_id and thinking_ids. |
| progress | Progress of the asynchronous correction. Progress messages are delivered per thinking_id. |
| post | The final, confirmed correction for a given thinking_id. |
| cancelled | Means the correction for a given thinking_id is finally not applied. |
Stream Processing Order
- When
firstarrives, show the first-pass correction on screen. - Track pending items by
thinking_ids. - Use
progressmessages that arrive later for status display (for example, "reviewing"). - Each
thinking_idends with eitherpostorcancelled.
Note: For server authorization and billing, StreamCorrectError is handled in the same function group as CorrectError. When the length in eojeol is calculated, only the first that was sent initially is billed. For example, if a space was inserted and then canceled, the eojeol is still counted as spaced in the first result.
Usage Restriction
StreamCorrectError cannot be used with a Free license. Only paid users can use this feature.
Correction Example
Input
어제도 너무더워서잠이오지를않았다.그런데, 오늘은 더심하네요.
(Roughly: "It was too hot yesterday too, so I couldn't sleep. But today is even worse." The input is deliberately written without proper word spacing.)
Response
{
"origin": "어제도 너무더워서잠이오지를않았다.그런데, 오늘은 더심하네요.",
"revised": "어제도 너무 더워서 잠이 오지를 않았다. 그런데, 오늘은 더 심하네요.",
"revised_blocks": [
{
"revisions": [
{
"revised": "너무 너무 더워서 잠이 오지를 않았다. 그런데,",
"score": 0.99,
"category": "CONFIRM",
"help_id": "Merged"
}
],
"nested": [
{
"revisions": [
{
"revised": "너무 더워서잠이오지를않았다.그런데,",
"score": 0,
"category": "SPACING",
"help_id": "띄어쓰기_공통"
}
],
"nested": [],
"origin": {
"content": "너무더워서잠이오지를않았다.그런데,",
"begin_offset": 6,
"length": 0
},
"revised": "너무 더워서잠이오지를않았다.그런데,",
"lemma": "",
"pos": "POS_UNK"
},
{
"revisions": [
{
"revised": "더워서 잠이오지를않았다.그런데,",
"score": 0,
"category": "SPACING",
"help_id": "띄어쓰기_공통"
}
],
"nested": [],
"origin": {
"content": "더워서잠이오지를않았다.그런데,",
"begin_offset": 9,
"length": 0
},
"revised": "더워서 잠이오지를않았다.그런데,",
"lemma": "",
"pos": "POS_UNK"
},
{
"revisions": [
{
"revised": "잠이 오지를않았다.그런데,",
"score": 0,
"category": "SPACING",
"help_id": "띄어쓰기_공통"
}
],
"nested": [],
"origin": {
"content": "잠이오지를않았다.그런데,",
"begin_offset": 11,
"length": 0
},
"revised": "잠이 오지를않았다.그런데,",
"lemma": "",
"pos": "POS_UNK"
},
{
"revisions": [
{
"revised": "지를 않았다.그런데,",
"score": 0,
"category": "SPACING",
"help_id": "띄어쓰기_공통"
}
],
"nested": [],
"origin": {
"content": "지를않았다.그런데,",
"begin_offset": 14,
"length": 0
},
"revised": "지를 않았다.그런데,",
"lemma": "",
"pos": "POS_UNK"
},
{
"revisions": [
{
"revised": "다. 그런데,",
"score": 0,
"category": "SPACING",
"help_id": "띄어쓰기_공통"
}
],
"nested": [],
"origin": {
"content": "다.그런데,",
"begin_offset": 18,
"length": 0
},
"revised": "다. 그런데,",
"lemma": "",
"pos": "POS_UNK"
}
],
"origin": {
"content": "너무더워서잠이오지를않았다.그런데,",
"begin_offset": 4,
"length": 18
},
"revised": "너무 너무 더워서 잠이 오지를 않았다. 그런데,",
"lemma": "",
"pos": "POS_UNK"
},
{
"revisions": [
{
"revised": "더 심하네요.",
"score": 0,
"category": "SPACING",
"help_id": "띄어쓰기_공통"
}
],
"nested": [],
"origin": {
"content": "더심하네요.",
"begin_offset": 28,
"length": 0
},
"revised": "더 심하네요.",
"lemma": "",
"pos": "POS_UNK"
}
],
"revised_sentences": [
{
"origin": "어제도 너무더워서잠이오지를않았다.",
"revised": "어제도 너무 더워서 잠이 오지를 않았다."
},
{
"origin": "그런데, 오늘은 더심하네요.",
"revised": "그런데, 오늘은 더 심하네요."
}
],
"helps": {
"Merged": {
"examples": [],
"id": "Merged",
"category": "CONFIRM",
"comment": "여러 개의 수정이 하나로 합쳐져서 표현됩니다. 개별 수정은 확인이 필요합니다.",
"rule_article": ""
},
"띄어쓰기_공통": {
"examples": [
"오늘 날씨 좋다."
],
"id": "띄어쓰기_공통",
"category": "SPACING",
"comment": "문장의 각 단어는 띄어 씀을 원칙으로 한다.",
"rule_article": "한글맞춤법, 제1장 총칙, 제2항"
}
},
"language": "ko_KR"
}
The comment values in helps are Korean explanations returned by the API. "여러 개의 수정이 하나로 합쳐져서 표현됩니다. 개별 수정은 확인이 필요합니다." means "Several edits are merged into one. The individual edits need confirmation." "문장의 각 단어는 띄어 씀을 원칙으로 한다." means "As a rule, each word in a sentence is written separately." (Hangul Orthography, Chapter 1, Article 2).
Python Client Example
from bareunpy import Corrector
# Initialize the Corrector
API_KEY = "YOUR-API-KEY" # Enter your own API key
HOST = "localhost" # When using a local server
PORT = 5656 # Port number
corrector = Corrector(apikey=API_KEY, host=HOST, port=PORT)
# Test correcting a single sentence
print("=== Single sentence ===")
single_sentence = "줄기가 얇아서 시들을 것 같은 꽃에물을 주었더니 고은 꽃이 피었다."
response = corrector.correct_error(content=single_sentence, auto_split=True)
print("Original:", response.origin)
print("Corrected:", response.revised)
# Test correcting multiple sentences
print("\n=== Multiple sentences ===")
multiple_sentences = [
"줄기가 얇아서 시들을 것 같은 꽃에물을 주었더니 고은 꽃이 피었다.",
"오늘은 철이네서 알타리무 다듬던데."
]
responses = corrector.correct_error_list(contents=multiple_sentences, auto_split=True)
for i, res in enumerate(responses):
print(f"\nSentence {i + 1}:")
print("Original:", res.origin)
print("Corrected:", res.revised)
Output
=== Single sentence ===
Original: 줄기가 얇아서 시들을 것 같은 꽃에물을 주었더니 고은 꽃이 피었다.
Corrected: 줄기가 얇아서 시들 것 같은 꽃에 물을 주었더니 고운 꽃이 피었다.
=== Multiple sentences ===
Sentence 1:
Original: 줄기가 얇아서 시들을 것 같은 꽃에물을 주었더니 고은 꽃이 피었다.
Corrected: 줄기가 얇아서 시들 것 같은 꽃에 물을 주었더니 고운 꽃이 피었다.
Sentence 2:
Original: 오늘은 철이네서 알타리무 다듬던데.
Corrected: 오늘은 철이네서 총각무 다듬던데.