※ 졸업작품 아이디어는 공개되지 않습니다(+아이디어 관련 기능 공개 x).

기능, 구현 코드만 공개됩니다. 또한 팀 프로젝트였기 때문에 제가 직접 개발했던 부분만 공개합니다.

 

 

이번에는 Django와 MariaDB를 연결해 데이터를 주고 받고 웹 화면에 출력하는 기능까지 구현해보겠습니다.

 

 

MariaDB를 설치하는 방법은 구글에 많이 나와있으니 따로 설명하지 않겠습니다.

 

 

먼저, DB 테이블을 만들어야 하는데, 아래 형식처럼 만들어주시면 됩니다. MySQL 코드 역시 구글에 많으므로 생략합니다.

 

 

 

그럼 이제 image 속성에 들어있는 경로대로 이미지를 넣어줘야합니다.

 

 

제 앱 이름이 imtest입니다. 즉, 앱 이름 폴더 안에 위의 사진처럼 폴더와 사진을 넣어주시면 됩니다.

 

 

또한 Django와 MariaDB를 연결하기 위해서 config/settings.py에 아래 코드를 작성합니다.

 

DATABASES = {
    'default': {
        'ENGINE': 'django.db.backends.mysql',
        'NAME' : 'DB명',
        'USER' : 'root',
        'PASSWORD' : 'mkmk', #MariaDB 로그인 시 비밀번호
        'HOST' : '', #디폴트는 로컬호스트
        'PORT' : '3307', #기본은 3306인데 저는 다른 DBMS가 3306을 쓰고 있어서 3307로 했습니다.
    }
}

 

 

그 다음은 Django에서 DB 접근을 위해 앱 폴더에 있는 models.py에 DB 구조를 알려줘야 합니다.

 

 

파이참 터미널에서

python manage.py inspectdb

 

라고 쳐주게 되면 DjangoDB를 탐지하여 코드가 주르륵 나오게 됩니다.

 

 

예를 들어 test라는 테이블 명으로 만들었다면 class Test(models.Model): 로 시작하는 코드가 터미널에 출력됩니다. 

 

 

이 코드를 그대로 복사해 model.py에 붙여넣으면 끝입니다.

 

저는 title과 image를 character속성으로 지정했기 때문에 CharField라고 출력되는 것을 확인할 수 있습니다.

 

id 속성은 테이블 생성 시 MariaDB에서 자동으로 붙이도록 설정했기 때문에 Django에서는 따로 출력되지 않았습니다.

 

 

 

models.py에 새로운 코드가 입력되었으니 Django에게 알려야합니다. (갱신과 같은 의미)

 

터미널에 아래 코드를 순서대로 입력하면 됩니다.

 

python manage.py makemigrations # DB 갱신
python manage.py migrate # DB 갱신

 

 

이제 views.py도 약간 수정을 해야 합니다. 그냥 전체 코드를 통으로 올리겠습니다.

from django.shortcuts import render
from .googlespeech import Gspeech
from .realtimeapicall import RGspeech
import time
from django.http import HttpResponse
from django.views.decorators.csrf import csrf_exempt
from django.template import loader
# Create your views here.
from .models import WordCard #추가

def home(request): #접속 시 첫 화면
    return render(request, 'button.html')


@csrf_exempt
def apic(request): #api 호출 함수
    gsp = RGspeech()
    while True:
            # 음성 인식 될때까지 대기 한다.
        stt = gsp.getText()
        if stt is None:
            break
        print(stt)
        pretitle.append(stt)
        time.sleep(0.01)
        data = models.py의 class명(테이블명).objects.get(title = stt) # 조건에 맞는 1개의 행만 가져옴
        src = data.image
        break

    #stt값으로 ajax(디비조회) -> 값 가져와서 -> 뿌려주기

    return HttpResponse(src)

 

Django에서는 objects를 이용하면 DB 값을 쉽게 가져올 수 있습니다.

 

마지막 부분 코드를 보면 가져온 이미지 경로를 src에 넣고 src를 반환하고 있습니다. 기억해두세요.

 

 

 

마지막으로 button.html만 살짝 고치면 끝입니다.

<!DOCTYPE html>


<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>hello world!</title>
    <script src="https://ajax.googleapis.com/ajax/libs/jquery/1.8.3/jquery.min.js"></script>

<script type="text/javascript">
    var csrftoken = jQuery("[name=csrfmiddlewaretoken]").val();
function csrfSafeMethod(method) {
    // these HTTP methods do not require CSRF protection
    return (/^(GET|HEAD|OPTIONS|TRACE)$/.test(method));
}
$.ajaxSetup({
    beforeSend: function (xhr, settings) {
        if (!csrfSafeMethod(settings.type) && !this.crossDomain) {
            xhr.setRequestHeader("X-CSRFToken", csrftoken);
        }
    }
});


function apic(){
    $.ajax({
    url : "{% url 'apic' %}",
    type : "post",
    }).done(function (data) {
       stt.src = data;
    });

}

</script>


</head>

<body>
<a href="/apic" class="button">api 호출 시작 </a>
<br>

<a href="javascript:void(0);" onclick="apic();">페이지 이동 없이 api 호출</a>
<br>

<img id = "stt" src=''>
<br>


</body>
</html>

 

img 태그를 보시면 views.py에서 받은 src를 전달받습니다. src는 이미지 경로 값이고, img태그는 경로값으로 image를 찾아 출력시키는 태그입니다. 

 

 

그럼 이제 "페이지 이동 없이 api 호출"을 클릭한 후 발음이 제대로 인식되었다면 DB에 지정해둔 사과 이미지가 웹 화면에 뜨게 됩니다!

 

 

+ Google Speech API에서 약간의 문제점

테스트를 하던 중 한국어에 100% 특화된 API가 아니다보니 잘못 인식되는 경우가 가끔 있습니다. API나 사람의 발음, 인식이 힘든 받침 단어 등의 문제라서 저희 입장에서 고칠 수 있는 문제 같지는 않지만 완벽하지는 않다는 것을 말씀드립니다.

 

 

 

 

이것으로 기본적인 기능에 관한 포스팅은 끝입니다. 

 

다음 포스팅에서는 기본적인 기능을 응용한 부가적 기능에 대한 내용을 포스팅할 예정입니다.

 

 

'졸업작품(4학년)' 카테고리의 다른 글

Django-Google Speech API 연결  (0) 2021.01.11
졸업작품 소개  (0) 2021.01.11

 

 

※ 졸업작품 아이디어는 공개되지 않습니다(+아이디어 관련 기능 공개 x). 기능, 구현 코드만 공개됩니다.

또한 팀 프로젝트였기 때문에 제가 직접 개발했던 부분만 공개합니다.

 

웹 환경에서 음성 인식을 이용해 DB에 있는 이미지를 불러오는 것이 주요 기능입니다.

 

구조

이번에는 1번 과정을 끝낼 겁니다.

 

[ Google Speech API 환경 설정]

 

먼저 환경 세팅부터 해야하는 데, 복잡하다면 복잡해 보이는 데 막상 하면 그렇게 어렵지는 않습니다.

 

1. 구글 클라우드 플랫폼에 로그인 합니다. (구글 아이디가 있다면 가입할 필요 없습니다.)

 

2. 그 다음 아래 포스팅을 보고 3.파이썬 예제 테스트해보기에서 11번까지 따라하시면 됩니다. 클라우드 플랫폼이 지속적으로 업데이트되는 바람에 현재 화면과 조금 다르지만 전체적으로는 동일하기 때문에 보고 하셔도 무방합니다. 제가 참고했던 포스팅 링크입니다. https://webnautes.tistory.com/1247

 

음성인식, Google Cloud Speech-to-Text API 사용해보기

Google Cloud Speech-to-Text API 서비스 계정 키를 발급받아서 샘플 코드를 실행하는 방법을 설명합니다. 결제 신용카드를 등록해야 할 수 있습니다. 2018. 9. 21 최초작성 2020. 11. 3 최종작성 1. Cloud Speech..

webnautes.tistory.com

 

(아래는 혹시 따라하다가 오류가 났거나 권장하는 내용을 추가한 것입니다) 

* 현재는 프로젝트를 디폴트로 만들어주는 거 같은데 새로 만드는 것이 좋음.

** 다 하고 난 후에 구글 클라우드 플랫폼 대시보드 화면에서 화면 상단에 팝업처럼 계정 뭐 해야된다고 뜰 때는 클릭해서 꼭 더 설정해줘야함! (정확히 무슨 내용이었는 지는 기억이 안나지만 300달러 사용을 누려보세요? 이런 내용이었던 것 같음)

*** 구글 sdk 깔고 프로젝트 번호 입력할 때(Cloud SDK 설치 - 6번 사진) 꼭 프로젝트 명을 확인 하고 선택할 것

**** Cloud SDK 설치 - 7번 사진에서 빨간 박스 글 위쪽 부분에 에러가 안 났는지 확인할 것 에러 났으면 프로젝트 다시 만들고 sdk 재설치하면 됨

*****파이썬 예제 테스트 해보기에서 10번 사진에 'gcloud'() 내부 또는 외부 명령, 실행할 수 있는 프로그램, 또는 배치 파일이 아닙니다. 에러가 뜨면 환경변수를 추가해야 함

시스템 환경변수의 path에 추가

C:\Program Files\Google\Cloud SDK\google-cloud-sdk\bin

C:\Program Files\Google\Cloud SDK\google-cloud-sdk.staging\bin

환경 변수 추가 후 파이참/비주얼스튜디오 종료 후 다시 켜야함

****** 파이썬 예제 테스트 해보기에서 11번 사진 패키지 설치 못한다고 에러 날 때

https://www.lfd.uci.edu/~gohlke/pythonlibs/#pyaudio 여기서 자신의 파이썬 버전 및 운영체제 비트에 맞는 whl 다운한 후 파이참/비주얼스튜디오 경로에 파일 넣어주고 터미널에

 

Python Extension Packages for Windows - Christoph Gohlke

by Christoph Gohlke, Laboratory for Fluorescence Dynamics, University of California, Irvine. Updated on 9 January 2021 at 17:25 UTC. This page provides 32- and 64-bit Windows binaries of many scientific open-source extension packages for the official CPyth

www.lfd.uci.edu

ex) pip install PyAudio0.2.11cp37cp37mwin_amd64.whl 실행하면 설치 완료!

 

 

[Django 코드 작성]

 

저는 파이참을 사용했고 파이참에서 Django 설치와 프로젝트 생성, 앱 생성까지는 되어있다는 가정하에 이어서 설명합니다.

 

생성하게되면 아래처럼 프로젝트 밑에 config 폴더, 앱이름폴더(자신이 지은 이름) 등등이 생깁니다. 

 

저는 앱 이름을 imtest로 했습니다.

그 다음엔 빨간 박스에 보이는 것처럼 앱 이름 폴더 밑에 별도로 폴더를 생성해주셔야 합니다.

이름은 templates로 정했는데 어떻게 짓든 상관은 없지만 암묵적으로 대부분 저렇게 짓는다고 해서 저렇게 지었습니다.

이 폴더에는 html 파일이 들어갑니다. 웹화면 html파일 작성 시 이 파일 내에서 합니다.

 

 

이제 본격적으로 환경 세팅을 위한 코드를 작성합니다.

 

앱을 만들었기 때문에 config/settings.py에 경로 추가

INSTALLED_APPS 마지막부분에 '앱이름', 삽입

 

config/urls.pyurlpatterns

path('', 앱이름.views.home, name='home'), 추가 (메인화면 경로 지정)

이 때 import 앱이름.views 해줘야 함

 

앱이름/views.py에 코드 작성

from django.shortcuts import render
from .googlespeech import Gspeech
import time
from django.http import HttpResponse
from django.views.decorators.csrf import csrf_exempt
from django.template import loader
# Create your views here.

def home(request): #접속 시 첫 화면
    return render(request, 'button.html')

@csrf_exempt
def apic(request): #api 호출 함수
    gsp = Gspeech()
    while True:
            # 음성 인식 될때까지 대기 한다.
        stt = gsp.getText()
        if stt is None:
            break
        print(stt)
        time.sleep(0.01)
        break

    return HttpResponse(str(stt))

 

 

 

앱폴더에 realtimeapicall.py 생성 후 그 파일에 코드 작성

# -*- coding: utf-8 -*-
#!/usr/bin/env python

# Copyright 2017 Google Inc. All Rights Reserved.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
#      http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.

from __future__ import division

import re
import sys

from google.cloud import speech
from google.cloud.speech import enums
from google.cloud.speech import types
import pyaudio
from six.moves import queue
from threading import Thread
import time

# Audio recording parameters
RATE = 16000
CHUNK = int(RATE / 10)  # 100ms

class MicrophoneStream(object):
    """Opens a recording stream as a generator yielding the audio chunks."""
    def __init__(self, rate, chunk):
        self._rate = rate
        self._chunk = chunk

        # Create a thread-safe buffer of audio data
        self._buff = queue.Queue()
        self.closed = True
        self.isPause = False

    def __enter__(self):
        self._audio_interface = pyaudio.PyAudio()
        self._audio_stream = self._audio_interface.open(
            format=pyaudio.paInt16,
            channels=1, rate=self._rate,
            input=True, frames_per_buffer=self._chunk,
            stream_callback=self._fill_buffer,
        )

        self.closed = False

        return self

    def __exit__(self, type, value, traceback):
        self._audio_stream.stop_stream()
        self._audio_stream.close()


        self.closed = True
        self._buff.put(None)
        self._audio_interface.terminate()

    def pause(self):
        if self.isPause == False:
            self.isPause = True


    def resume(self):
        if self.isPause == True:
            self.isPause = False


    def status(self):
        return self.isPause

    def _fill_buffer(self, in_data, frame_count, time_info, status_flags):
        """Continuously collect data from the audio stream, into the buffer."""
        if self.isPause == False:
            self._buff.put(in_data)
        #else
        return None, pyaudio.paContinue

    def generator(self):
        while not self.closed:
            chunk = self._buff.get()
            if chunk is None:
                return

            data = [chunk]

            while True:
                try:
                    chunk = self._buff.get(block=False)
                    if chunk is None:
                        return
                    data.append(chunk)
                except queue.Empty:
                    break

            yield b''.join(data)


# [END audio_stream]



class RGspeech(Thread):
    def __init__(self):
        Thread.__init__(self)

        self.language_code = 'ko-KR'  # a BCP-47 language tag

        self._buff = queue.Queue()

        self.client = speech.SpeechClient()
        self.config = types.RecognitionConfig(
            encoding=enums.RecognitionConfig.AudioEncoding.LINEAR16,
            sample_rate_hertz=RATE,
            language_code=self.language_code)
        self.streaming_config = types.StreamingRecognitionConfig(
            config=self.config,
            single_utterance=True, # 한 단어 인식 후 종료되도록 추가한 옵션
            interim_results=True)

        self.mic = None
        self.status = True

        self.daemon = True
        self.start()

    def __eixt__(self):
        self._buff.put(None)

    def run(self):
        with MicrophoneStream(RATE, CHUNK) as stream:
            self.mic = stream
            audio_generator = stream.generator()
            requests = (types.StreamingRecognizeRequest(audio_content=content)
                        for content in audio_generator)

            responses = self.client.streaming_recognize(self.streaming_config, requests)

            # Now, put the transcription responses to use.
            self.listen_print_loop(responses, stream)
        self._buff.put(None)
        self.status = False

    def pauseMic(self):
        if self.mic is not None:
            self.mic.pause()

    def resumeMic(self):
        if self.mic is not None:
            self.mic.resume()

    # 인식된 Text 가져가기
    def getText(self, block = True):
        return self._buff.get(block=block)

    # 음성인식 처리 루틴
    def listen_print_loop(self, responses, mic):
        num_chars_printed = 0
        try:
            for response in responses:
                if not response.results:
                    continue

                result = response.results[0]
                if not result.alternatives:
                    continue

                transcript = result.alternatives[0].transcript
                overwrite_chars = ' ' * (num_chars_printed - len(transcript))
                if not result.is_final:
                    sys.stdout.write(transcript + overwrite_chars + '\r')
                    sys.stdout.flush()
                    #### 추가 ### 화면에 인식 되는 동안 표시되는 부분.
                    num_chars_printed = len(transcript)
                else:
                    # 큐에 넣는다.
                    self._buff.put(transcript+overwrite_chars)
                    num_chars_printed = 0
        except:
            return

원본 코드는 원래 Git에 있는데 지금은 없어져서 출처는 남길 수가 없습니다.

또한 한 단어씩만 인식되는 코드는 아래 포스팅을 보고 따로 추가한 내용입니다.

poppy-leni.tistory.com/entry/Google-Cloud-STT-%EC%8A%A4%ED%8A%B8%EB%A6%AC%EB%B0%8D-%EB%81%9D%EB%82%98%EB%8A%94-%EC%A7%80%EC%A0%90-%EC%B2%B4%ED%81%AC

 

[ Google Cloud:STT ] 스트리밍 끝나는 지점 체크

Google Cloud Where is ended a point at Streaming STT #Python3.6.5 #command #사용자변수 Streaming service를 이용할 때 streaming되고 있는 data가 잡음인지 실제 사람의 음성(필요한 data)인지 구분하기 위..

poppy-leni.tistory.com

 

여기서 반드시 이 코드가 실행되는 지 확인해 보셔야 합니다. (실행 후 바로 말해보면 됨)

에러뜨면 아마 계정 활성화가 안되었다는 에러일텐데 그러면 sdk 재설치부터 하는 게 원인찾는 것보다 빠를거에요

 

이어서 config/urls.pyurlpatterns

path('apic/', 앱이름.views.apic, name='apic'), 추가 (viewsapic 함수가 동작하도록 경로 설정. ‘’는 제일 첫화면, ‘apic/’은 로컬 마지막 경로에 /apic 써주면 접근 가능함)

 

마지막으로 html 화면 작성

앱폴더에 templates폴더에 button.html 이라는 파일 생성 (html 파일명은 아무거나 상관없음)

그 후 코드 작성

<!DOCTYPE html>
<!--{% load imtest_tags %}-->
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>hello world!</title>
    <script src="https://ajax.googleapis.com/ajax/libs/jquery/1.8.3/jquery.min.js"></script>
<script type="text/javascript">
    var csrftoken = jQuery("[name=csrfmiddlewaretoken]").val();
function csrfSafeMethod(method) {
    // these HTTP methods do not require CSRF protection
    return (/^(GET|HEAD|OPTIONS|TRACE)$/.test(method));
}
$.ajaxSetup({
    beforeSend: function (xhr, settings) {
        if (!csrfSafeMethod(settings.type) && !this.crossDomain) {
            xhr.setRequestHeader("X-CSRFToken", csrftoken);
        }
    }
});

function apic(){
    $.ajax({
    url : "{% url 'apic' %}",
    type : "post",
    }).done(function (data) {
        document.getElementById('stt').innerHTML = data;
    });

}

</script>


</head>

<body>
<a href="/apic" class="button">api 호출 시작 </a>
<br>

<a href="javascript:void(0);" onclick="apic();">페이지 이동 없이 api 호출</a>

</body>
</html>

저는 ajax를 사용해서 새로고침 되지 않으면서 api를 호출하도록 구현했지만 굳이 비동기 필요하지 않으신 분들은 사용하지 않으셔도 됩니다. ajax코드도 마찬가지로 참고한 블로그가 있었는데 지금은 글이 없어져서 출처는 남길 수 없었습니다.

 

마지막으로 이제 터미널에서 python manage.py runserver 후 로컬에 접속해 화면에 링크텍스트가 뜨는 지 확인,

링크 누르기 전에는 api 동작 안하는 지 확인(말 해보면 됨), 누르고 나서 터미널에 음성이 텍스트로 변환되는 거 출력되는 지 확인하고 출력 된다면 웹 서버와 api 연동은 성공입니다.

 

다음 포스팅에는 DB와 연동해서 웹 화면에 DB에 저장된 이미지 출력시키는 기능을 구현합니다.

'졸업작품(4학년)' 카테고리의 다른 글

Django-MariaDB 연결  (0) 2021.01.21
졸업작품 소개  (0) 2021.01.11

 

졸업작품 아이디어는 공개되지 않습니다. 기능, 구현 코드만 공개됩니다.

 

개발 기간 : 2달

 

구현 : Django, Google Speech API, JavaScript, Python, MariaDB, Bootstrap, HTML, CSS

 

내용 : 웹&웹서버&DB에서 음성인식 기능 이용해 웹에서 DB 데이터 불러오기

 

팀 프로젝트였으므로 제가 개발한 부분만 공개할 예정입니다.

'졸업작품(4학년)' 카테고리의 다른 글

Django-MariaDB 연결  (0) 2021.01.21
Django-Google Speech API 연결  (0) 2021.01.11