오늘은 어제에 이어 기능들에 대해 조금더 찾아보고 Nest.JS 강의를 들으며 공부를 했습니다
발표 음성 텍스트화 STT(Speech To Text)
STT는 "음성 인식" 또는 "음성을 텍스트로 변환"하는 기술입니다. STT는 사용자가 말하는 음성을 컴퓨터가 이해할 수 있는 텍스트로 자동 변환해주는 기술로, 음성 데이터를 컴퓨터가 처리하고 텍스트로 변환하는 과정을 거칩니다.
유료
무료
<!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> 음성인식 시작 </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>
중지하기 </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 말이 등 주로 남아프리카 북동 지역에서 밀리 피해가 집중적으로 발생했습니다
비교해 보았을 때, 아래 문장이 위 문장을 기준으로 틀린 부분이나 빠진 부분을 포함하고 있습니다:
전 세계 틀고 뿔소에 약 80%가 서식하는 크루거국립공원에 670 몇 마리의 큰 코뿔소가 죽어 가장 큰 타격을 받았습니다 다음으로는 림포포에서 110만 콰줄루나탈 84 말이 음푸말랑가 70마리 노스웨스트 58 말이 등 주로 남아프리카 북동 지역에서 밀리 피해가 집중적으로 발생했습니다
위 문장을 기준으로 하면, 아래 부분이 틀렸거나 빠진 부분입니다:
위 부분을 수정하면 첫 번째 문장과 일치하게 됩니다.
NestJS는 효율적이고 확장 가능한 NodeJS Server-Side 어플리케이션을 만들기 위한 프레임워크입니다. 내부적으로 ExpressJS를 사용하며, 초기 설정을 통해서 Fastify를 사용할 수 도 있습니다.
NodeJS(및 server side JavaScript)를 위한 수많은 우수한 library, helper 및 도구들이 존재하지만, 아키텍처 문제를 효과적으로 해결한 라이브러리는 없습니다. 이를 위해서 NestJS는 개발자와 팀이, 테스트 가능하고 확장 가능하며 느슨하게 결합되어 유지 관리가 용이한 애플리케이션을 만들 수 있는 아키텍처를 제공합니다. 아키텍처는 Angular로부터 많은 영감을 받았습니다.
CLI를 이용해서 설치한다.
$ npm i -g @nestjs/cli
$ nest new nest_practice
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 어플리케이션의 엔트리 파일
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 요청 메소드 데코레이터가 있다.
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 {}