7/12 Nest.JS

JK·2023년 7월 13일
0

오늘은 어제에 이어 기능들에 대해 조금더 찾아보고 Nest.JS 강의를 들으며 공부를 했습니다

STT

발표 음성 텍스트화 STT(Speech To Text)

STT란??

STT는 "음성 인식" 또는 "음성을 텍스트로 변환"하는 기술입니다. STT는 사용자가 말하는 음성을 컴퓨터가 이해할 수 있는 텍스트로 자동 변환해주는 기술로, 음성 데이터를 컴퓨터가 처리하고 텍스트로 변환하는 과정을 거칩니다.

STT 수행 과정

  1. 오디오 입력:
    STT 시스템은 오디오 입력을 받습니다. 이 입력은 사용자의 음성을 담고 있는 오디오 데이터입니다. 오디오 입력은 마이크, 녹음 파일 또는 실시간 음성 스트림 등 다양한 형태로 제공될 수 있습니다.
  2. 전처리:
    STT 시스템은 전처리 단계에서 오디오 입력을 분석하고 필요한 신호 처리 기술을 적용합니다. 이 단계에서는 잡음 제거, 음성 신호의 정규화, 특징 추출 등의 과정이 진행됩니다. 이를 통해 입력 데이터를 STT 모델이 이해할 수 있는 형태로 변환합니다.
  3. 음성 특징 추출:
    STT 시스템은 전처리된 오디오 데이터에서 음성의 특징을 추출합니다. 일반적으로 푸리에 변환(Fourier Transform)을 사용하여 시간-주파수 영역으로 변환하여 음성의 주요 특징을 포착합니다. 이러한 특징은 음소(phoneme)라고도 불리는 음성의 기본 단위를 나타내는 데 사용됩니다.
  4. 음성 모델 적용:
    추출된 음성 특징은 음성 모델에 입력으로 제공됩니다. 음성 모델은 훈련된 알고리즘 및 기계 학습 기술을 사용하여 음성 입력을 텍스트로 변환합니다. 음성 모델은 음성의 발음, 언어, 문맥 등을 이해하고 이를 텍스트로 매핑하는 역할을 수행합니다.
  5. 텍스트 출력:
    음성 모델은 입력된 음성에 대한 텍스트 출력을 생성합니다. 이 텍스트 출력은 STT 시스템의 최종 결과물로서, 사용자의 음성을 텍스트로 변환한 것입니다.
  6. 추가 처리 및 응용:
    STT 시스템은 텍스트 출력을 기반으로 추가적인 처리나 응용을 수행할 수 있습니다. 예를 들어, 텍스트의 정확도를 개선하기 위해 후처리 단계에서 오류 수정이나 문법 교정이 이루어질 수 있습니다.

사용할 수 있는 라이브러리

유료

  1. IBM Watson Speech to Text:
    IBM의 Watson 플랫폼에서 제공하는 STT 서비스입니다. 높은 인식 정확성과 다양한 언어 및 기능을 제공하며, REST API를 통해 쉽게 접근하고 사용할 수 있습니다.
  2. Microsoft Azure Speech to Text: Microsoft Azure 플랫폼의 STT 서비스로, 다양한 언어와 음성 형식을 지원합니다. 실시간 인식, 이벤트 기반 응답 등 다양한 기능을 제공하며, REST API를 통해 사용할 수 있습니다.
  3. Google Cloud Speech-to-Text: Google Cloud의 유료 버전인 Google Cloud Speech-to-Text는 높은 인식 정확성과 신뢰성을 제공합니다. 다양한 기능과 API 옵션을 지원하여 음성 인식을 다양한 응용 프로그램에 통합할 수 있습니다.

무료

  1. Mozilla DeepSpeech: Mozilla에서 개발한 오픈소스 음성 인식 엔진입니다. TensorFlow 기반으로 구현되었으며, 정확성과 성능이 뛰어나다고 알려져 있습니다. 다양한 프로그래밍 언어에서 사용할 수 있으며, Python API를 제공합니다.
  2. CMU Sphinx: Carnegie Mellon University에서 개발한 오픈소스 음성 인식 시스템입니다. 유연하고 확장 가능한 구조를 가지고 있으며, 다양한 언어와 플랫폼에서 사용할 수 있습니다.
  3. Kaldi: 오픈소스 음성 인식 툴킷으로, 연구 목적이나 응용 프로그램 개발에 사용됩니다. C++로 구현되었으며, 다양한 음성 인식 모델과 알고리즘을 제공합니다.

참고 사이트

HTML 코드로 체험

<!DOCTYPE html>

<html lang="ko">

<head>
    <link href="https://cdn.jsdelivr.net/npm/bootstrap@5.0.2/dist/css/bootstrap.min.css" rel="stylesheet" integrity="sha384-EVSTQN3/azprG1Anm3QDgpJLIm9Nao0Yz1ztcQTwFspd3yD65VohhpuuCOmLASjC" crossorigin="anonymous" />
</head>

<body>
    
<div class="container">

<div class="my-3">
    <button id="stt-start-button" class="btn btn-secondary" type="button"><svg xmlns="http://www.w3.org/2000/svg" class="icon icon-tabler icon-tabler-microphone" width="24" height="24" viewBox="0 0 24 24" stroke-width="2" stroke="currentColor" fill="none" stroke-linecap="round" stroke-linejoin="round">
        <path stroke="none" d="M0 0h24v24H0z" fill="none"></path>
        <rect x="9" y="2" width="6" height="11" rx="3"></rect>
        <path d="M5 10a7 7 0 0 0 14 0"></path>
        <line x1="8" y1="21" x2="16" y2="21"></line>
        <line x1="12" y1="17" x2="12" y2="21"></line>
     </svg>&nbsp;&nbsp;음성인식 시작 </button>

    <button id="stt-stop-button" class="btn btn-secondary d-none" type="button">
        <svg xmlns="http://www.w3.org/2000/svg" class="icon icon-tabler icon-tabler-microphone" width="24" height="24" viewBox="0 0 24 24" stroke-width="2" stroke="currentColor" fill="none" stroke-linecap="round" stroke-linejoin="round">
            <path stroke="none" d="M0 0h24v24H0z" fill="none"></path>
            <rect x="9" y="2" width="6" height="11" rx="3"></rect>
            <path d="M5 10a7 7 0 0 0 14 0"></path>
            <line x1="8" y1="21" x2="16" y2="21"></line>
            <line x1="12" y1="17" x2="12" y2="21"></line>
         </svg>
        
        
        <svg xmlns="http://www.w3.org/2000/svg" class="icon icon-tabler icon-tabler-antenna-bars-3" width="24" height="24" viewBox="0 0 24 24" stroke-width="2" stroke="currentColor" fill="none" stroke-linecap="round" stroke-linejoin="round">
        <path stroke="none" d="M0 0h24v24H0z" fill="none"></path>
        <line x1="6" y1="18" x2="6" y2="15"></line>
        <line x1="10" y1="18" x2="10" y2="12"></line>
        <line x1="14" y1="18" x2="14" y2="18.01"></line>
        <line x1="18" y1="18" x2="18" y2="18.01"></line>
     </svg>
        
        &nbsp;&nbsp; 중지하기 </button>
    <p id="message">버튼을 누르고 말씀하세요.</p> 
</div>

<form action="" method="post" id="stt-form">
    {% csrf_token %}
    <div class="my-3">
        <textarea name="content" class="form-control"></textarea>
    </div>
    <input type="submit" class="btn btn-primary" />
</form>

<script>
    const stt_start_button = document.querySelector("#stt-start-button");
    const stt_stop_button = document.querySelector("#stt-stop-button");

    var message = document.querySelector("#message");
    const stt_form = document.querySelector("#stt-form");
    const content_field = document.querySelector('#stt-form [name=content]');
    let content_field_value = "";  // STT 재시작시마다 results 값이 초기화됩니다.

    const SpeechRecognition = window.SpeechRecognition || window.webkitSpeechRecognition;
    const speech_recognition = new SpeechRecognition();
    speech_recognition.lang = "ko-kr";
    speech_recognition.continuous = true;

    function enable_stt() {
        content_field_value = content_field.value;

        speech_recognition.start();
        message.innerHTML = "음성인식 중...";
        stt_start_button.classList.toggle("d-none");
        stt_stop_button.classList.toggle("d-none");
    }

    function disable_stt() {
        speech_recognition.stop();
        message.innerHTML = "버튼을 누르고 말씀하세요.";
        stt_start_button.classList.toggle("d-none");
        stt_stop_button.classList.toggle("d-none");
    }
    
    // stt_start_button이 <form> 안에 있다면 submit 동작을 가지게 됩니다.
    // 그런데 다른 STT동작을 해야지, form submit을 해서는 안 되는 것이잖아요.
    // 아래 click handler에서 e.preventDefault(); 를 호출하여 원래 동작(form submit)을 안하게 하든지.
    // stt_start_button은 <form> 외부로 빼시는 것이 낫습니다.
    stt_start_button.addEventListener("click", () => { enable_stt(); });
    stt_stop_button.addEventListener("click", () => { disable_stt(); });

    speech_recognition.onresult = function (e) {
        console.log(e.results);
        // disable_stt();

        // 매 result 반환 시마다 e.results의 개수가 늘어납니다.
        const transcript = Array.from(e.results)
            .map(result => result[0])
            .map(speech => speech.transcript)
            .join(' ');

        console.log("transcript :", transcript);
        content_field.value = content_field_value + " " + transcript;
    };

    speech_recognition.onerror = function (e) {
        console.error(e);
        disable_stt();
    };

// script 안에 </html>이 있었습니다.

</script>

</div>

</body>

</html>

읽은 글

전 세계 큰코뿔소의 약 80%가 서식하는 크루거 국립공원에서 670여마리의 큰 코뿔소가 죽어 가장 큰 타격을 받았습니다.
다음으로는 림포포에서 110마리, 콰줄루나탈 84마리, 음푸말랑가 70마리, 노스웨스트 58마리 등 주로
남아프리카 북동부지역에서 밀렵피해가 집중적으로 발생했습니다.

결과

전 세계 틀고 뿔소에 약 80%가 서식하는 크루거국립공원에 670 몇 마리의 큰 코뿔소가 죽어 가장 큰 타격을 받았습니다 다음으로는 림포포에서 110만 콰줄루나탈 84 말이 음푸말랑가 70마리 노스웨스트 58 말이 등 주로 남아프리카 북동 지역에서 밀리 피해가 집중적으로 발생했습니다

Chat GPT로 비교 결과

비교해 보았을 때, 아래 문장이 위 문장을 기준으로 틀린 부분이나 빠진 부분을 포함하고 있습니다:

전 세계 틀고 뿔소에 약 80%가 서식하는 크루거국립공원에 670 몇 마리의 큰 코뿔소가 죽어 가장 큰 타격을 받았습니다 다음으로는 림포포에서 110만 콰줄루나탈 84 말이 음푸말랑가 70마리 노스웨스트 58 말이 등 주로 남아프리카 북동 지역에서 밀리 피해가 집중적으로 발생했습니다

위 문장을 기준으로 하면, 아래 부분이 틀렸거나 빠진 부분입니다:

  • "전 세계 큰코뿔소의"가 "전 세계 틀고 뿔소에"로 변경되었습니다.
  • "670여마리의 큰 코뿔소가"가 "670 몇 마리의 큰 코뿔소가"로 변경되었습니다.
  • "림포포에서 110마리"가 "림포포에서 110만"으로 변경되었습니다.
  • "음푸말랑가 70마리"가 "음푸말랑가 70 마리"로 변경되었습니다.
  • "노스웨스트 58마리"가 "노스웨스트 58 말이"로 변경되었습니다.
  • "주로 남아프리카 북동부지역에서"가 "주로 남아프리카 북동 지역에서"로 변경되었습니다.

위 부분을 수정하면 첫 번째 문장과 일치하게 됩니다.


Nest.JS

NestJS는 효율적이고 확장 가능한 NodeJS Server-Side 어플리케이션을 만들기 위한 프레임워크입니다. 내부적으로 ExpressJS를 사용하며, 초기 설정을 통해서 Fastify를 사용할 수 도 있습니다.

NodeJS(및 server side JavaScript)를 위한 수많은 우수한 library, helper 및 도구들이 존재하지만, 아키텍처 문제를 효과적으로 해결한 라이브러리는 없습니다. 이를 위해서 NestJS는 개발자와 팀이, 테스트 가능하고 확장 가능하며 느슨하게 결합되어 유지 관리가 용이한 애플리케이션을 만들 수 있는 아키텍처를 제공합니다. 아키텍처는 Angular로부터 많은 영감을 받았습니다.

설치

CLI를 이용해서 설치한다.

$ npm i -g @nestjs/cli
$ nest new nest_practice

src 내부 파일

nest new nest_practice 명령어를 통해서 새로운 Nest 어플리케이션을 만들면 node_modules, src 등과 eslint, tsconfig, prettier 등 설정과 관련된 파일들이 생성된다. 먼저 src 내부에는 어떤 파일들이 있는지 확인해보자.

src
├ app.controller.ts
├ app.controller.spec.ts
├ app.module.ts
├ app.service.ts
⎣ main.ts

app.controller.ts: 하나의 경로(여기서는 "/")를 가진 기본 컨트롤러
app.controller.spec.ts: 컨트롤러에 대한 유닛 테스트
app.module.ts: Nest 어플리케이션의 루트 모듈. 모든 Nest 모듈은 이 모듈에 연결되어야한다.
app.service.ts: 하나의 메소드를 가진 기본 서비스
main.ts: . Nest application instance를 생성하는 함수NestFactory를 사용하는, Nest 어플리케이션의 엔트리 파일

Express

Nest를 빠르고 쉽게 이해하기 위해서는 Express 코드와의 비교가 필요하다.

아래 코드는 express에서 controller와 router를 분리해서 사용하는 예시다.

// controller.js
export function sayHello (req, res) {
  res.send('Hello Express');
}

// router.js
const router = express.Router();
router.get('/', sayHello);

export default router;

// app.js

app.use('/', router);

// http://localhost:3000/

Hello Express

Controller

Nest에서 Controller는 express에서의 router라고 생각하면 된다. (Service는 바로 다음에 다룬다.)

// src/app.controller.ts
import { Controller, Get } from '@nestjs/common';
import { AppService } from './app.service';

@Controller()
export class AppController {
  constructor(private readonly appService: AppService) {}

  @Get()
  sayHello(): string {
    return this.appService.sayHello();
  }
}

// http://localhost:3000/

Hello Nest

@Controller()는 express의 app.use('/', router) 에서 '/'와 같은 역할을 한다. @Controller('say') 이렇게 인자로 string을 넘겨주면 express에서 app.use('/say', router)처럼 코드를 작성한 것과 같다.

@Get()은 express의 router.get('/', sayHello)에서 '/'와 같은 역할을 한다. @Get('hello') 이렇게 인자로 string을 넘겨주면 express에서 router.get('/hello', sayHello)처럼 코드를 작성한 것과 같다.

AppController 코드를 해석해보면 루트경로로 GET 요청이 들어오면 appService 안의 sayHello 함수를 실행하고 결과를 리턴해라이다. 추가적으로 Get말고도 Post, Delete 등 다른 HTTP 요청 메소드 데코레이터가 있다.

Service

Nest에서 Service는 express에서의 controller라고 생각하면 된다. Nest의 Controller와 비지니스 로직을 분리하기 위해 Service가 존재한다.

import { Injectable } from '@nestjs/common';

@Injectable()
export class AppService {
  sayHello(): string {
    return 'Hello Nest!';
  }
}

위와 같이 메소드를 정의하고 AppModule에서 provider로 등록을 하면 Controller에서 사용할 수 있다.

import { Module } from '@nestjs/common';
import { AppController } from './app.controller';
import { AppService } from './app.service';

@Module({
  imports: [],
  controllers: [AppController],
  providers: [AppService],
})
export class AppModule {}
profile
^^

0개의 댓글

관련 채용 정보