eubinecto / politely

A hybrid politeness styler for the Korean Language / 하이브리드 존댓말 변환기
https://politely.streamlitapp.com
49 stars 0 forks source link

write test cases as detailed in here #51

Closed eubinecto closed 2 years ago

eubinecto commented 2 years ago

1 -> 2, 3 2 -> 3 으로 가는 것은 허용하지만, 3 -> 1, 2는 허용하지 않는 편이 개발이 더 편할 것 같다.

왜? 예를 들면 이런 예시를 일일히 수작업으로 고쳐야 한다:

main_test.py::TestStyler::test_irregular_conjugation_bieup_harmonious_with_syllables 2022-05-04 15:00:28.485 INFO    root: khaiii opened with rsc_dir: "/Users/eubinecto/Projects/Big/politely/venv/lib/python3.8/site-packages/khaiii/share/khaiii", opt_str: ""
FAILED [100%]l_last = ['ㄱ', 'ㅗ', 'ㅂ']
r_first = ['ㅇ', 'ㅏ', ' ']
ㅂ 불규칙: 고와요
l_last = ['ㄱ', 'ㅗ', 'ㅂ']
r_first = ['ㅇ', 'ㅏ', ' ']
ㅂ 불규칙: 고와
l_last = ['ㄱ', 'ㅗ', 'ㅂ']
r_first = ['ㅇ', 'ㅓ', ' ']
ㅂ 불규칙: 고워

main_test.py:195 (TestStyler.test_irregular_conjugation_bieup_harmonious_with_syllables)
'모래가 참 고워.' != '모래가 참 고와.'

Expected :'모래가 참 고와.'
Actual   :'모래가 참 고워.'
<Click to see difference>

self = <main_test.TestStyler testMethod=test_irregular_conjugation_bieup_harmonious_with_syllables>

    def test_irregular_conjugation_bieup_harmonious_with_syllables(self):
        """
        모음조화가 이루어진 ㅂ 불규칙
        """
        sent = "모래가 참 고와."
        self.assertEqual("모래가 참 고와.", self.styler(sent, self.ban[0], self.ban[1]))  # noqa
        self.assertEqual("모래가 참 고와요.", self.styler(sent, self.jon[0], self.jon[1]))
        self.assertEqual("모래가 참 곱습니다.", self.styler(sent, self.formal[0], self.formal[1]))
        sent = "모래가 참 고와요."
        self.assertEqual("모래가 참 고와.", self.styler(sent, self.ban[0], self.ban[1]))  # noqa
        self.assertEqual("모래가 참 고와요.", self.styler(sent, self.jon[0], self.jon[1]))
        self.assertEqual("모래가 참 곱습니다.", self.styler(sent, self.formal[0], self.formal[1]))
        sent = "모래가 참 곱습니다."
>       self.assertEqual("모래가 참 고와.", self.styler(sent, self.ban[0], self.ban[1]))  # noqa

위가 무엇을 보여주는 것인가? 다음은 가능하다:

고와 -> 고와요 
고와 -> 곱습니다
고와요 -> 고와
고와요 -> 곱습니다

하지만 곱습니다 -> 고와는 불가능하다:

곱습니다  -> 고워

왜? 습니다의 경우 1, 2의 경우가 전부 또는 어요로 통일되기 때문이다. 원래의 어미가 무엇이었는지... 알길이 없다. 이건 어요도 마찬가지이지만, 위에서 볼 수 있듯 어요의 초성은 와 마찬가지로 모음이라, 1일 때의 어간활용을 어지간해서는 그대로 따라간다. 하지만 습니다의 초성은 자음이다. 그래서 위처럼 어간의 활용이 1, 2인 경우와 다를 수 밖에 없다.

어차피 반말부터 공부하는 외국인들은 숫자가 커지는 경우를 더 필요로 할것이기 때문에, politeness를 줄이는 알고리즘은 data augmentation의 용도가 아닌이상.. 굳이 필요없다.

그래서 우리는... 더이상 3 -> 1, 2는 지원하지 않겠다...! 그래야 개발에 속도가 붙을 것 같다.

eubinecto commented 2 years ago

문제점

main_test.py:238: AssertionError
-------------------------------------------------------------------------- Captured stdout call --------------------------------------------------------------------------
l_last = ['ㅈ', 'ㅜ', 'ㅂ']
r_first = ['ㅇ', 'ㅓ', ' ']
ㅂ 불규칙: 주워요
======================================================================== short test summary info =========================================================================
FAILED main_test.py::TestStyler::test_irregular_jup - AssertionError: '저 쓰레기를 주웁시다.' != '저 쓰레기를 줍웁시다.'
    def test_irregular_jup(self):
        sent = "저 쓰레기를 줍자."
        self.assertEqual("저 쓰레기를 줍자.", self.styler(sent, self.ban[0], self.ban[1]))  # noqa
        self.assertEqual("저 쓰레기를 주워요.", self.styler(sent, self.jon[0], self.jon[1]))
        self.assertEqual("저 쓰레기를 주웁시다.", self.styler(sent, self.formal[0], self.formal[1]))

줍 + 어요 -> 주워요는 오케이. 하지만 줍 + ㅂ시다 -> 주웁시다는 not okay.

왜?

아.. if-else문의 반복이기에, 두개 이상의 케이스에 해당돼도 한 케이스만 적용하고 끝나버리기 때문인 것으로 보인다.

그렇다면 어떻게 해결할까?

if-else의 연속을 여러개의 if문의 나열로 바꿔야한다. 음.. 그게 말이 쉽지..ㅠㅠ

일단 방법을 한번 생각해보자. soynlp에서는 어떻게 하고 있지? 어떻게 여러개의 규칙을 적용하고 있을까? 분명 순서가 중요해질텐데...

    # ㄷ 불규칙 활용: 깨달 + 아 -> 깨달아
    if l_last[2] == 'ㄷ' and r_first[0] == 'ㅇ':
        l = stem[:-1] + compose(l_last[0], l_last[1], 'ㄹ')
        surface = l + ending
        candidates.add(surface)
        candidates.add(stem + ending) # 받 + 았다 -> 받았다
        if debug:
            print('ㄷ 불규칙: {}'.format(surface))

    # 르 불규칙 활용: 구르 + 어 -> 굴러
    if ( (l_last_ == '르' and stem[-2:] != '푸르') and
         (r_first_ == '아' or r_first_ == '어') and l_len >= 2 ):
        c0, c1, c2 = decompose(stem[-2])
        l = stem[:-2] + compose(c0, c1, 'ㄹ')
        r = compose('ㄹ', r_first[1], r_first[2]) + ending[1:]
        surface = l + r
        candidates.add(surface)
        if debug:
            print('르 불규칙: {}'.format(surface))

soynlp는 여러개가 순차적으로 적용되는 건 고려하지 않는다. 즉... 줍 + ㅂ시다 -> 줍웁시다 -> 주웁시다 이렇게 변화하는 과정은 고려하지 않고. 줍 + ㅂ시다 -> 줍웁시다 (1) 줍 + ㅂ시다 -> 주ㅂ시다 (2)

이렇게 두가지가 존재한다고 보는듯. 음... 나는 순서까지 고려를 해야할 것 같다. 이것에 대한 고민은 내일 이어서하기

오늘 뭐했음? - 정리

뭘했는지 쉽게 설명

어간의 활용 알고리즘을 수정하고 있다. "줍 + ㅂ시다 -> 주웁시다"가 가능토록 하는게 목표인데. 현재 내 코드는 "줍 + ㅂ시다 -> 줍웁시다" 라고 출력한다. 즉 ㅂ탈락이 일어나야하는데 내 코드 상에서는 일어나지 않는다. 이 원인이 무엇인지 파악을 해야하는데, 시간상 일단 문제인식에 의의를 두고 내일로 넘기겠다!

eubinecto commented 2 years ago

음... 일단 알고리즘 구현은 나중으로 미뤄보고.

지금은 애초에 계획했던 테스트만 쓰고 끝내자. TDD라고 생각하면 된다. 일단 failing test를 만들고, 나중에 하나씩 pass하도록 바꾸면 된다.

eubinecto commented 2 years ago

오늘 뭐했지? 쉽게 설명

다음과 같이, soynlp에서 소개한 용언의 활용 케이스를 그대로 테스트에 옮겼다:

https://github.com/eubinecto/politely/blob/6165ef1c708e3ef2a70cf4174a7a46e156e12fe4/main_test.py#L247-L336

하나만 예를 들며 설명해보자면 이런걸 테스트하고 있다:

입력 = "하늘이 파랗다." 인 경우.

저 테스트를 돌려보면 아직 완벽하지 않기 때문에 20개 중 8개는 패스하지 못한다. 하지만 개발을 시작하기전, 분명한 목표를 설정해둔다는 것에 오늘의 활동에 의의를 둔다.

... 그런데 이렇게 복잡한 한국어를 난 도대체 어떻게 하고 있는거지? 체득된 문법이란 참 신기한 것 같다.