brunch

You can make anything
by writing

C.S.Lewis

by 향이 Sep 19. 2017

구글 음성인식으로 녹취를 풀어보자 #2

음성인식, 좀 더 똑똑하게 만드는 방법은 없을까?

안녕하세요~ 오늘도 누런돼지 기자입니다.

지난 번에 구글 음성인식을 간단하게 맛본 뒤 계속해서 뒷맛이 개운치 않았습니다.

정녕 네놈은 쓸데가 없는 것이냐...

좀 더 똑똑한 결과물을 내놓을 수는 없는 것이냐...


그러다 음성인식 설명서를 탐독하던 중 재미있는 옵션 하나를 발견했습니다.

바로 'speech_context'라는 것인데요.

설명에는 음성인식에 '힌트'를 주는 것이라고 써 있습니다.

(ㅎㅎ 당연히 영어로 된 걸 구글 번역기를 돌렸지요)

파이썬 음성인식 활용법 설명에도 다음과 같이 사용법이 나와 있습니다.

Using speech context hints to get better results. This can be used to improve the accuracy for specific words and phrases. This can also be used to add new words to the vocabulary of the recognizer (음성 컨텍스트 힌트를 사용하여 더 나은 결과를 얻으십시오. 특정 단어 및 구문의 정확도를 높이기 위해 사용할 수 있습니다. 이것은 또한 인식기의 어휘에 새로운 단어를 추가하는 데 사용될 수 있습니다.)


오 정말???


이걸 어떻게 사용하는지 궁금했습니다.

한 번 해 봤습니다.

사용례를 보니 아주 간단합니다. 

config 변수 내부에 speech_context 라는 속성을 하나 더 추가하면 됩니다.

영어니까 hi, good afternoon 같은 걸 추가해뒀군요.


config=speech.types.RecognitionConfig(
    encoding='LINEAR16',
    language_code='en-US',
    sample_rate_hertz=44100,
    speech_contexts=[speech.types.SpeechContext(
        phrases=['hi', 'good afternoon']
        )]
)


그렇다면 지난 번 음성인식에서 쓴 강신준 교수님의 자본론 강의를 더 잘 인식하려면 어떤 텍스트가 필요할까요? 우선 떠올릴 수 있는 건 기사입니다. 


강연을 바탕으로 한 기사를 긁어서 쭉 넣어보려고 합니다.

그러면 더 인식률이 높아지지 않을까요? ㅋㅋㅋ


우선 알아두어야 할 것은, 추가할 수 있는 구문의 한계가 있다는 겁니다.

구문 하나당 100자를 넘을 수 없고, 총 문자수는 10000자를 넘길 수 없습니다.

요청 당 구문은 500이라고 돼 있는데, 왜 그런지 1개 이상은 안 들어가더군요;;; (제가 잘못 넣어서인가)


먼저 제가 생각한 방법은 이 기사에서 주요 단어를 추출해서 넣어보는 것입니다.

아무래도 자주 노출되는 단어이다 보니, 많이 쓰이고 또 이런 단어들이 많다고 구글 AI에 미리 알려주면 좋지 않을까 하는 막연한(?) 생각에서였습니다.


단어 추출도 파이썬으로 처리합니다. 아래 블로그의 도움을 많이 받았습니다.


가운데 text라는 변수에 기사를 모두 긁어 넣었습니다. 따옴표만 제거하고요.

따옴표 제거 루틴까지 만들려다가.... 귀찮아서 atom 에디터의 ctrl+D(같은 문자 선택) 기능을 사용해 그냥 수작업으로 제거했습니다... (그게 더 빨라요 ㅠ)


from konlpy.tag import Twitter
from collections import Counter

def get_tags(text, ntags=50):
    spliter = Twitter()
    nouns = spliter.nouns(text)
    count = Counter(nouns)
    return_list = []
    for n, c in count.most_common(ntags):
        temp = {'tag': n, 'count': c}
        return_list.append(temp)
    return return_list

text = "매주 토요일 경향신문에 오늘, 자본을 읽다를 연재하고 있는 강신준 동아대 교수가 지난 10일 독자들과 만났다. 강의 30분 전부터 경향신문사 대회의실에 모여든 청중들은 강 교수와 시작 전 가벼운 질의응답을 주고받으며 열기를 고조시켰다. 앳된 대학생에서 백발의 노인까지 70여명이 금세 강연장을 가득 채웠다. 강연을 듣기 위해 대전·대구 등 지방에서 찾아온 열성 독자들도 있었다..... (하략)"

tags = get_tags(text)
tagsSum = ""
for tag in tags:
    noun = tag['tag']
    count = tag['count']
    tagsSum += ("'" + noun + "', ")
print(tagsSum)


결과는 이렇습니다.


코드를 약간 변형시켜 가장 빈출 단어부터 차례로 나오게 하되, 우리가 긁어붙이기 쉽도록 ' ' 안에 넣어서 콤마로 구분해 출력했습니다.


이제 이걸 갖다 붙이기만 하면 됩니다.


speech_context 속성이 추가된 것(붉은 부분) 외에 코드는 지난 번과 변화가 없습니다.

아, 다만 맨 윗줄에 utf-8 선언이 들어갔는데, 가끔 파이썬에서 한글을 인식하지 못하는 경우가 있더라고요. 찾아보니 인코딩 방식을 미리 선언해야 한다고 해서 넣었습니다.


# -*- coding: utf-8 -*-

import io
import os

from google.cloud import speech
from google.cloud.speech import enums
from google.cloud.speech import types

GOOGLE_APPLICATION_CREDENTIALS = "speech-f2bbad4ce134.json"

client = speech.SpeechClient()

with io.open("kangsj1m.flac", 'rb') as audio_file:
    content = audio_file.read()

audio = types.RecognitionAudio(content=content)
config = types.RecognitionConfig(
    encoding='FLAC',
    sample_rate_hertz=16000,
    language_code='ko-KR',
    speech_contexts=[speech.types.SpeechContext(
        phrases = ['자본주의', '것', '사회', '시간', '생산', '교수', '더', '소비', '사람', '강', '마르크스', '수', '노동', '때문', '이', ' 노동시간', '노동자', '생산력', '우리', '여가', '그', '공황', '투입', '때', '자본', '나라', '은행', '강연', '등', '청중', '독자', '해방', '독일', '바로', '이전', '반면', '조직', '이상', '준', '베짱이', '대가', '정도', '의사결정', '계속', '시작', '체제', '이유', '은', '방법', '이후']
    )]
)

response = client.recognize(config, audio)
print('Waiting for operation to complete...')

for k in response.results:
    alternatives = k.alternatives
    for alternative in alternatives:
        print('Transcript: {}'.format(alternative.transcript))
        print('Confidence: {}'.format(alternative.confidence))


두근두근... 과연 결과는?

똑같습니다 ㅠㅠㅠㅠㅠㅠ

아무 변화도 없습니다 ㅠㅠㅠㅠㅠ


(원래 인식 결과)

그러니 자본주의는 필연적으로 항상 생산이 저 보다 많습니다 그럴까요 자본주의에서 만들어지는 모든 물건을 궁극적으로 누군가가 일을 해야 되는데 여러분 스코피라고 하는 것은 누가  소비하는 유저 소비하는 누구냐 인간이에요 자동차 기름 혹시 자기들이 원료를 사는 것을 법이라고 할지 모르지만 그거는 아직  최종소비에 도달 하지 않은 중간소변 오거든요 모든 사람이 아니다 사람이 그런데 사람이 볼까요 이렇게 하는 거거든요 요산 수치 개선을 위한 너도 공유가치라고 하는 것을 피하기 위해서 하는 거지 아니거든요 왜냐면 이거는 이 사람한테 돈을 벌어 준비해서 돈으로 하는 겁니다 자본가는


(맥락 적용 뒤 인식 결과)

그러니 자본주의는 필연적으로 항상 생산이 저 보다 많습니다 그럴까요 자본주의에서 만들어지는 모든 물건을 궁극적으로 누군가가 일을 해야 되는데 여러분 스코피라고 하는 것은 누가  소비하는 유저 소비하는 누구냐 인간이에요 자동차 기능 혹시 자기들이 원료를 사는 것을 법이라고 할지 모르지만 그거는 아직  최종소비에 도달 하지 않은 중간소변 오거든요 숙제를 모든 사람이 아니다 사람이 그런데 사람 볼까요 이렇게 하는 거거든요 요산 수치 개선을 위한 너도 공유가치라고 하는 것을 피하기 위해서 하는 거지 아니거든요 왜냐면 이거는 이 사람한테 돈을 벌어 준비해서 돈으로 하는 겁니다 자본가는 

자세히 살펴보니 '기름 => 기능' 정도의 변화가 있지만(붉은 부분) 별로 생산적인 변화도 아니네요.


아, 그런데 phrases 가 단어가 아니라 '구'라는 뜻 아니겠습니까?

생각해 보니, word가 아니라 phrases니까 좀 긴 문장을 넣어도 될 것 같습니다.

그래서 이번에는 기사를 100글자 단위로 쪼개서 넣었습니다.


# -*- coding: utf-8 -*-

import io
import os

from google.cloud import speech
from google.cloud.speech import enums
from google.cloud.speech import types

GOOGLE_APPLICATION_CREDENTIALS = "speech-f2bbad4ce134.json"

text = "매주 토요일 경향신문에 오늘, 자본을 읽다를 연재하고 있는 강신준 동아대 교수가 지난 10일 독자들과 만났다. 강의 30분 전부터 경향신문사 대회의실에 모여든 청중들은 강 교수와 시작 전 가벼운 질의응답을 주고받으며 열기를 고조시켰다. 앳된 대학생에서 백발의 노인까지 70여명이 금세 강연장을 가득 채웠다. 강연을 듣기 위해 대전·대구 등 지방에서 찾아온 열성 독자들도 있었다. 강 교수가 카를 마르크스의 <자본>의 핵심 사상을 1시간 정도 강의한 뒤 독자들의 질의를 받는 방식으로 진행된 이번 만남은 예정 시간을 훌쩍 넘겨 2시간30분가량 진행됐다.(하략...)"

speechCon = []
for sp in range(1, 101):
    if sp*100 > len(text):
        speechCon.append(text[(sp-1)*100:len(text)-1])
        break
    speechCon.append(text[(sp-1)*100:sp*100])

client = speech.SpeechClient()

with io.open("kangsj1m.flac", 'rb') as audio_file:
    content = audio_file.read()

audio = types.RecognitionAudio(content=content)

config = types.RecognitionConfig(
    encoding='FLAC',
    sample_rate_hertz=16000,
    language_code='ko-KR',
    speech_contexts=[speech.types.SpeechContext(
        phrases = speechCon
    )]
)

response = client.recognize(config, audio)
print('Waiting for operation to complete...')

for k in response.results:
    alternatives = k.alternatives
    for alternative in alternatives:
        print('Transcript: {}'.format(alternative.transcript))
        print('Confidence: {}'.format(alternative.confidence))


(원래 인식 결과)

그러니 자본주의는 필연적으로 항상 생산이 보다 많습니다 그럴까요 자본주의에서 만들어지는 모든 물건을 궁극적으로 누군가가 일을 해야 되는데 여러분 스코피라고 하는 것은 누가  소비하는 유저 소비하는 누구냐 인간이에요 자동차 기름 혹시 자기들이 원료를 사는 것을 법이라고 할지 모르지만 그거는 아직  최종소비에 도달 하지 않은 중간소변 오거든요 모든 사람이 아니다 사람이 그런데 사람이 볼까요 이렇게 하는 거거든요 요산 수치 개선을 위한 너도 공유가치라고 하는 것을 피하기 위해서 하는 거지 아니거든요 왜냐면 이거는 이 사람한테 돈을 벌어 준비해서 돈으로 하는 겁니다 자본가는


(맥락 적용 뒤 인식 결과)

그런이 자본주의는 필연적으로 항상 생산이 소비보다 많습니다 그럴까요 자본주의에서 만들어지는 모든 물건을 궁극적으로 누군가가 일을 해야 되는데 여러분 스코피라고 하는 것은 누가  소비하는 유저 소비하는 누구냐 인간입니다 자동차 기름 혹시 자기들이 원료를 사는 것을 법이라고 할지 모르지만 그거는 아직  최종소비에 도달 하지 않은 중간소변 오거든요 모든 사람이 아니다 사람이 그런데 사람이 볼까요 이렇게 하는 거거든요 요산 수치 개선을 위한 노동 잉여가치란 하는 것을 피하기 위해서 운동하는 것이 아니거든요 왜냐면 이거는이 사람에게 돈을 벌어 주면 오늘 하는 겁니다 자본가는


역시 큰 변화는 없습니다. 잉여가치, 소비 같은 단어들을 인식하기 시작했지만 인식률이 극적으로 좋아지지는 않았습니다. ㅠㅠㅠㅠ


마지막으로, 제가 강의를 취재하면서 대충 받아쳤던 내용을 한 번 추가해 봤습니다.

물론 속기록을 추가하는 건 의미가 없습니다 ㅠ

어렵게 받아치지 않아도 '짠'하고 만들어지는 녹취록를 만드는 게 목표인데, 속기로 받아친 걸 넣어주면 무슨 소용이겠습니까?

그래도 얼마나 잘 될까 하는 실험 정신으로 한 번 해 봤습니다.


제가 대충 받아친 건 다음과 같습니다. 이걸 아까 기사문 대신 넣고 돌려봅니다~


(녹취록)

자본주의는 필연적으로 항상 생산이 소비보다 많다. 왜 그런가. 자본주의에서 만들어지는 물건은 궁극적으로 소비가 돼야 하는데 소비는 누가 하나. 인간이다. 자본가들이 재료를 사는 것도 소비라고 할 수 있지만 중간소비다. 자본주의의 모든 소비는 사람이 하는 거다. 그런데, 사람이 하는 건 뭔가. 요것이다. 바로 이부분(필요노동시간)만 소비하는 거다. 여가시간을 소비를 위한 것이 아니라 이것은 자본가를 돈 벌어주기 위한 노동이다. 자본가는 노동자로부터 얻은 잉여가치로 소비하지 않는다. 돈을 벌려고 하는 거다. 그러니 예를 들어 1년에 1조라는 이익을 어떤 자본가가 벌었다고 치자. 이 사람이 1조를 벌어서 쓰겠는가. 개인적으로 쓸 수 없다. 그 사람은 세 끼 이상 밥을 먹을 수 없다. 차도 1대 이상 못 탄다. 이 부분만큼이 자본주의에서는 항상 과잉생산 되는 거다. 이 과잉생산이 내부회전을 통해 부분적으로 해소되겠지만 결국은 소비가 안 돼 해소가 되지 않는다. 결국 채이고 채여서 도저히 돌아갈 수 없는 상황, 그게 바로 경기변동이다. 그것이 최고도로 찼을 때 그것이 1815년부터 자본주의에 10년부터 꼬박꼬박 있었다. 1947, 1929년, 2007년 공황 등 70~80년 주기로 크게 터진다. 자본주의는 끊임없이 일상적으로 보는 것이 세일이다. 끊임없는 세일이 생산과 소비의 불균형을 맞추는 거다.


(원래 인식 결과)

그러니 자본주의는 필연적으로 항상 생산이 저 보다 많습니다 그럴까요 자본주의에서 만들어지는 모든 물건 궁극적으로 누군가가 일을 해야 되는데 여러분 스코피라고 하는 것은 누가  소비하는 유저 소비하는 누구냐 인간이에요 자동차 기름 혹시 자기들이 원료를 사는 것을 법이라고 할지 모르지만 그거는 아직  최종소비에 도달 하지 않은 중간소변 오거든요 모든 사람이 아니다 사람이 그런데 사람이 볼까요 이렇게 하는 거거든요 요산 수치 개선을 위한 너도 공유가치라고 하는 것을 피하기 위해서 하는 거지 아니거든요 왜냐면 이거는 이 사람한테 돈을 벌어 준비해서 돈으로 하는 겁니다 자본가는


(맥락 적용 뒤 인식 결과)

그러니 자본주의는 필연적으로 항상 생산이 소비보다 많습니다 그럴까요 자본주의에서 만들어지는 모든 물건 궁극적으로 누군가가 일을 해야 되는데 여러분 스코피라고 하는 것은 누가  소비하는 유저 소비하는 누구냐 인간이다 자본가들이 혹시 자기들이 원료를 사는 것을 법이라고 할지 모르지만 그거는 아직 최종소비에 도달 하지 않은 중간소비다 모든 요소를 모든 소비는 사람이 하는 건데 사람이 볼까요 이렇게 하는 거거든요 요산 수치 개선을 위한 너도 잉여가치로 하는 것을 피하기 위해서 운동하는 것이 아니거든요 왜냐면 이거는이 사람이 돈을 벌어주기 해서 돈을 하는 겁니다 자본가는


흠...

여전히 만족스럽지는 않습니다. '자본가' '중간소비' 같은 단어를 처음으로 인식했다는 데서 만족해야 할 것 같습니다.


혹시 좀 더 잘 되는 방법이 있으면 알려주세요 ㅠ

구글 음성인식, 꼭 쓰고 싶습니다! 네?


ps. 이전 작업이 궁금하시다면 아래 글을 참조하세요.



브런치는 최신 브라우저에 최적화 되어있습니다. IE chrome safari