ABOUT ME

-

Today
-
Yesterday
-
Total
-
  • Google Cloud Speech API (STT library)와 Unicode 인코딩 문제를 해결한 후기
    I'm a Developer 2017. 5. 26. 03:29

    대학원에서 프로젝트 수행하면서 몇일을 골머리썩었네요.



    현재 프로젝트에서는 라즈베리파이3를 활용하여, 음성인식을 통해 지하철 목적지를 말하는 기능이 필요했습니다.

    그래서 Google Cloud Speech API로 음성인식을 통해 목적지를 Text로 바꿔주는 기능을 구현해야했는데 한 가지 문제가 발생했습니다.

    (물론 이전에 Mic streaming으로 구현하는 것도 문제가 있었는데, github에 issue사항 뒤지다가 안된다는 소스를 줏어서 돌렸는데 잘되었습니다.)


    이 부분이 문제의 화면입니다.

    마이크 입력으로 응답을 받아온 부분입니다.

    영어(en-US)로 할 땐, 깔끔하게 잘 받아왔는데, 한글로하니까(ko-KR)... 한글 인코딩을 못 읽더군요.... (망할 Google Cloud Speech API에서 아직 지원을 안하는 건지? 아니면 제 환경이 이상한건지 모르겠지만, 제 최선의 방법으로 몇일을 고민해봤습니다.)

    우선 데이터를 분해했습니다.

    그래서 transcript 안에 있는 유니코드를 인코딩하기 위한 작업을 시작했습니다.


    삽질 과정은 넘나 길기 때문에 해결과정을 말씀드릴게요.

    넘어온 각 숫자(1바이트에 해당하는)들은 모두 8진수 숫자입니다. 

    이를 파악한 것은 한글 유니코드 표를 보고 알았죠.

    한글 유니코드표 (UTF-8) 한글코드 범위(AC00~D7AF)



    위의 링크를 참고해보니,

    좌측에 보이시는 것처럼 (234, 175, 128) 숫자가 좀 작아보였습니다. 그래서 얼추 진법이 다를 거라고 추측했습니다. 바로 10진수로 제가 받은 값들을 바꿔보니, 얼추 비슷한 숫자들이 나오기 시작했습니다.


    자 그리고 또 한 가지 특징은 숫자모음 3개가 모여서, 한개의 character를 만드는 것을 볼 수 있습니다.

    문자열 인코딩의 모든 것

    위의 링크에 들어가보시면 

    "컴퓨터를 다루면서 자주 보았을 UTF-8은 유니코드 인코딩 중에 하나로, 문자열을 8-bit 기반으로 저장한다. ANSI 문자(영어 포함)는 그대로(1 바이트로) 아시아 문자는 3 바이트로 가변 표기하는 인코딩 방식이다. "

    라고 고수님께서 포스팅 해놓으신 것을 참고하였습니다.

    즉 3자리 숫자 하나가 한 바이트이고,  그 숫자 3개가 모여야 비로소 하나의 완성형 한글이 된다는 것입니다.

    이에 따라 저는 3개씩 나누어 합쳤습니다.

    그리고 위 블로그에서 설명처럼 3바이트의 각각의 숫자를 2진수로 변환하여, 알고리즘을 짰습니다.

    다음은 예 입니다.

    1110xxxx 10xxxxxx 10xxxxxx

    '가'가 매핑된 U+AC00은

    0xAC00 = 44,032 = 10101100 00000000 이고

    이제 x 표시한 부분에 순서대로 넣어주면 된다고 하는군요.

    11101010    10110000      10000000

    234             176                128

    EA                B0                  80

    제가 가지고 있는 데이터는  가장 밑에 234 176 128 이기 때문에 저는 역순으로 알고리즘을 대충... 만들었습니다.

    다음과 같습니다. 여기서 r은 352, 260, 225와 같은 8진수 숫자값들입니다.

    별거 없습니다. 위에서 xxxx들에 매핑되도록 자르고 붙이고 한거죠

    for r in result_list:

                    if r == '':

                        continue


                    if i == 0:

                        first_code = bin(int(r, 8))

                        first_code = first_code[-4:]

                    elif i == 1:

                        second_code = bin(int(r, 8))

                        third_code = second_code[-2:]

                        second_code = second_code[-6:-2]

                    elif i == 2:

                        fourth_code = bin(int(r, 8))

                        fourth_code = fourth_code[-6:]

                    i = i+1


                    if i == 3:

                        i=0

                        word_list.append(parsing_korean(first_code, second_code, third_code, fourth_code))


    def parsing_korean(c1, c2, c3, c4):
        word = '0b'+c1+c2+c3+c4
        return chr(int(word,2))

    ** 참고로 chr은 유니코드를 문자로 바꿔주는 메소드입니다. (python 2.x버전에서는 unichr() 입니다.) 문자열 관련 메소드들은 다음 링크를 참고하시면 좋을 듯 합니다.


    Python 문자열 관련 함수

    http://egloos.zum.com/itbaby/v/4243381




    네.. 결국



    사당역이라는 글자를 출력하고 말았습니다. 역시 구글이군요 .. (급태세전환) 인식률도 아주 좋아요.
    새벽 2시가 되어서야 비로소... (하지만 이 감격을 블로그에 옮기느라 3시 30분이 되었군요)

    네 여기까지 제가 감동 받은 스토리 좀 썼습니다.

    근데 분명 이렇게 험하게 할만한 작업이 아닐텐데 .. 여전히 모르겠네요 인코딩을 이렇게까지 직접 해줘야하는 건지ㅠㅠ

    혹시 이 글을 보시는 선생님들께서 좋은 방법이 있다면 알려주셨으면 좋겠습니다. ㅎㅎ


    'I'm a Developer' 카테고리의 다른 글

    블로그 이전  (0) 2020.09.29
    VIM 꾸미기  (0) 2017.08.17
    지하철 공공데이터 사용하기  (3) 2017.04.26

    댓글

Designed by Tistory.