NextJS 및 ExpressJS PlatoBlockchain 데이터 인텔리전스를 사용하여 음성을 PDF로 변환. 수직 검색. 일체 포함.

NextJS 및 ExpressJS를 사용하여 음성을 PDF로 변환

음성 인터페이스가 점점 더 중요해짐에 따라 음성 상호 작용으로 할 수 있는 몇 가지를 탐구할 가치가 있습니다. 예를 들어, 우리가 무언가를 말하고 그것을 전사하고 다운로드 가능한 PDF로 펌핑할 수 있다면 어떨까요?

글쎄, 스포일러 경고 : 우리는 절대적으로 그렇게! 이를 실현하기 위해 함께 엮을 수 있는 라이브러리와 프레임워크가 있으며 이것이 이 기사에서 함께 할 것입니다.

이것들은 우리가 사용하는 도구입니다

먼저 Next.js와 Express.js의 두 가지 주요 플레이어입니다.

다음 .js 정적 사이트 구축을 위한 주요 기능을 포함하여 React의 추가 기능에 대한 설명입니다. 동적 라우팅, 이미지 최적화, 기본 제공 도메인 및 하위 도메인 라우팅, 빠른 새로 고침, 파일 시스템 라우팅 및 API 경로와 같은 즉시 제공되는 기능으로 인해 많은 개발자가 선택합니다. 많은, 많은 다른 것들.

우리의 경우에는 Next.js가 필요합니다. API 경로 우리의 클라이언트 서버에. 우리는 텍스트 파일을 받아 PDF로 변환하고 파일 시스템에 쓴 다음 클라이언트에 응답을 보내는 경로를 원합니다.

익스프레스.js 라우팅, HTTP 도우미 및 템플릿을 사용하는 작은 Node.js 앱을 얻을 수 있습니다. 이것은 우리가 사물 간에 데이터를 전달하고 구문 분석할 때 필요한 API용 서버입니다.

사용할 다른 종속성이 있습니다.

  1. 반응 음성 인식: 음성을 텍스트로 변환하여 React 구성 요소에서 사용할 수 있도록 하는 라이브러리입니다.
  2. 재생기 런타임: 문제 해결을 위한 라이브러리 "regeneratorRuntime react-speech-recognition을 사용할 때 Next.js에 표시되는 오류가 정의되지 않았습니다.
  3. html-pdf-노드: HTML 페이지 또는 공개 URL을 PDF로 변환하기 위한 라이브러리
  4. 액시 오스: 브라우저와 Node.js 모두에서 HTTP 요청을 만들기 위한 라이브러리
  5. : 교차 출처 자원 공유가 가능한 라이브러리

설정

가장 먼저 할 일은 두 개의 프로젝트 폴더를 만드는 것입니다. 하나는 클라이언트용이고 다른 하나는 서버용입니다. 원하는 대로 이름을 지정합니다. 내 이름을 짓고 있어 audio-to-pdf-clientaudio-to-pdf-server각각.

클라이언트 측에서 Next.js를 시작하는 가장 빠른 방법은 다음으로 부트스트랩하는 것입니다. 다음 앱 만들기. 따라서 터미널을 열고 클라이언트 프로젝트 폴더에서 다음 명령을 실행합니다.

npx create-next-app client

이제 Express 서버가 필요합니다. 우리는 그것을 얻을 수 있습니다 cd-ing 서버 프로젝트 폴더로 이동하고 실행 npm init 명령. NS package.json 파일이 완료되면 서버 프로젝트 폴더에 생성됩니다.

우리는 여전히 Express를 실제로 설치해야 합니다. npm install express. 이제 우리는 새로운 index.js 서버 프로젝트 폴더에 파일을 만들고 이 코드를 거기에 놓습니다.

const express = require("express")
const app = express()

app.listen(4000, () => console.log("Server is running on port 4000"))

서버를 실행할 준비가 되셨습니까?

node index.js

앞으로 진행하려면 몇 개의 폴더와 다른 파일이 더 필요합니다.

  • 만들기 components 클라이언트 프로젝트 폴더의 폴더.
  • 만들기 SpeechToText.jsx 에 파일을 components 하위 폴더.

더 진행하기 전에 약간의 정리가 필요합니다. 특히, 기본 코드를 교체해야 합니다. pages/index.js 파일:

import Head from "next/head";
import SpeechToText from "../components/SpeechToText";

export default function Home() {
  return (
    <div className="home">
      <Head>
        <title>Audio To PDF</title>
        <meta
          name="description"
          content="An app that converts audio to pdf in the browser"
        />
        <link rel="icon" href="/ko/favicon.ico" />
      </Head>

      <h1>Convert your speech to pdf</h1>

      <main>
        <SpeechToText />
      </main>
    </div>
  );
}

수입 SpeechToText 구성 요소는 결국 다음에서 내보내집니다. components/SpeechToText.jsx.

다른 의존성을 설치하자

좋습니다. 앱에 대한 초기 설정이 필요하지 않습니다. 이제 전달되는 데이터를 처리하는 라이브러리를 설치할 수 있습니다.

다음을 사용하여 클라이언트 종속성을 설치할 수 있습니다.

npm install react-speech-recognition regenerator-runtime axios

다음은 Express 서버 종속 항목입니다. cd 서버 프로젝트 폴더에 다음을 설치합니다.

npm install html-pdf-node cors

일시 중지하고 프로젝트 폴더의 파일이 제대로 유지되는지 확인하는 것이 좋습니다. 이 시점에서 클라이언트 프로젝트 폴더에 있어야 하는 내용은 다음과 같습니다.

/audio-to-pdf-web-client
├─ /components
|  └── SpeechToText.jsx
├─ /pages
|  ├─ _app.js
|  └── index.js
└── /styles
    ├─globals.css
    └── Home.module.css

다음은 서버 프로젝트 폴더에 있어야 하는 내용입니다.

/audio-to-pdf-server
└── index.js

UI 빌드

글쎄, 우리의 Speech-to-PDF는 상호작용할 방법이 없다면 그다지 좋지 않을 것입니다. <SpeechToText>.

자신의 마크업을 완전히 사용할 수 있습니다. 다음은 우리가 함께 만들고 있는 조각에 대한 아이디어를 제공하기 위한 것입니다.

import React from "react";

const SpeechToText = () => {
  return (
    <>
      <section>
        <div className="button-container">
          <button type="button" style={{ "--bgColor": "blue" }}>
            Start
          </button>
          <button type="button" style={{ "--bgColor": "orange" }}>
            Stop
          </button>
        </div>
        <div
          className="words"
          contentEditable
          suppressContentEditableWarning={true}
        ></div>
        <div className="button-container">
          <button type="button" style={{ "--bgColor": "red" }}>
            Reset
          </button>
          <button type="button" style={{ "--bgColor": "green" }}>
            Convert to pdf
          </button>
        </div>
      </section>
    </>
  );
};

export default SpeechToText;

이 구성 요소는 반응 조각 HTML을 포함하는 <``section``> 세 개의 div를 포함하는 요소:

  • .button-container 음성 인식을 시작하고 중지하는 데 사용되는 두 개의 버튼이 있습니다.
  • .wordscontentEditablesuppressContentEditableWarning 속성을 사용하여 이 요소를 편집 가능하게 만들고 React의 경고를 표시하지 않습니다.
  • 다른 .button-container 음성을 PDF로 재설정하고 변환하는 데 사용할 두 개의 버튼이 더 있습니다.

스타일링은 완전히 다른 것입니다. 여기에서는 다루지 않겠지만 내가 작성한 몇 가지 스타일을 시작점으로 사용할 수 있습니다. styles/global.css 파일.

전체 CSS 보기
html,
body {
  padding: 0;
  margin: 0;
  font-family: -apple-system, BlinkMacSystemFont, Segoe UI, Roboto, Oxygen,
    Ubuntu, Cantarell, Fira Sans, Droid Sans, Helvetica Neue, sans-serif;
}

a {
  color: inherit;
  text-decoration: none;
}

* {
  box-sizing: border-box;
}

.home {
  background-color: #333;
  min-height: 100%;
  padding: 0 1rem;
  padding-bottom: 3rem;
}

h1 {
  width: 100%;
  max-width: 400px;
  margin: auto;
  padding: 2rem 0;
  text-align: center;
  text-transform: capitalize;
  color: white;
  font-size: 1rem;
}

.button-container {
  text-align: center;
  display: flex;
  justify-content: center;
  gap: 3rem;
}

button {
  color: white;
  background-color: var(--bgColor);
  font-size: 1.2rem;
  padding: 0.5rem 1.5rem;
  border: none;
  border-radius: 20px;
  cursor: pointer;
}

button:hover {
  opacity: 0.9;
}

button:active {
  transform: scale(0.99);
}

.words {
  max-width: 700px;
  margin: 50px auto;
  height: 50vh;
  border-radius: 5px;
  padding: 1rem 2rem 1rem 5rem;
  background-image: -webkit-gradient(
    linear,
    0 0,
    0 100%,
    from(#d9eaf3),
    color-stop(4%, #fff)
  ) 0 4px;
  background-size: 100% 3rem;
  background-attachment: scroll;
  position: relative;
  line-height: 3rem;
  overflow-y: auto;
}

.success,
.error {
  background-color: #fff;
  margin: 1rem auto;
  padding: 0.5rem 1rem;
  border-radius: 5px;
  width: max-content;
  text-align: center;
  display: block;
}

.success {
  color: green;
}

.error {
  color: red;
}

거기에 있는 CSS 변수는 버튼의 배경색을 제어하는 ​​데 사용됩니다.

최신 변경 사항을 살펴보겠습니다! 운영 npm run dev 터미널에서 확인하십시오.

방문할 때 브라우저에서 이 항목을 확인해야 합니다. http://localhost:3000:

NextJS 및 ExpressJS를 사용하여 음성을 PDF로 변환

우리의 첫 번째 연설을 텍스트로 변환합니다!

취해야 할 첫 번째 조치는 필요한 종속성을 <SpeechToText> 구성 요소:

import React, { useRef, useState } from "react";
import SpeechRecognition, {
  useSpeechRecognition,
} from "react-speech-recognition";
import axios from "axios";

그런 다음 브라우저에서 음성 인식을 지원하는지 확인하고 지원되지 않는 경우 알림을 표시합니다.

const speechRecognitionSupported =
  SpeechRecognition.browserSupportsSpeechRecognition();

if (!speechRecognitionSupported) {
  return <div>Your browser does not support speech recognition.</div>;
}

다음으로 추출해 보겠습니다. transcriptresetTranscript 인사말 useSpeechRecognition() 훅:

const { transcript, resetTranscript } = useSpeechRecognition();

이것이 우리가 처리하는 상태에 필요한 것입니다. listening:

const [listening, setListening] = useState(false);

우리도 필요합니다 ref 위한 div 와 더불어 contentEditable 속성을 추가한 다음 ref 그것에 속성을 부여하고 통과 transcript as children:

const textBodyRef = useRef(null);

…그리고:

<div
  className="words"
  contentEditable
  ref={textBodyRef}
  suppressContentEditableWarning={true}
  >
  {transcript}
</div>

여기서 마지막으로 필요한 것은 음성 인식을 트리거하고 해당 기능을 onClick 버튼의 이벤트 리스너. 버튼은 듣기를 설정합니다. true 그리고 지속적으로 실행되도록 합니다. 추가 이벤트가 발생하지 않도록 해당 상태에 있는 버튼을 비활성화합니다.

const startListening = () => {
  setListening(true);
  SpeechRecognition.startListening({
    continuous: true,
  });
};

…그리고:

<button
  type="button"
  onClick={startListening}
  style={{ "--bgColor": "blue" }}
  disabled={listening}
>
  Start
</button>

버튼을 클릭하면 이제 전사가 시작됩니다.

더 많은 기능

알겠습니다. 스타트 청취. 하지만 이제 다음과 같은 몇 가지 다른 작업도 수행해야 합니다. stopListening, resetTexthandleConversion. 그 기능들을 만들어 봅시다.

const stopListening = () => {
  setListening(false);
  SpeechRecognition.stopListening();
};

const resetText = () => {
  stopListening();
  resetTranscript();
  textBodyRef.current.innerText = "";
};

const handleConversion = async () => {}

각각의 기능이 추가됩니다. onClick 해당 버튼의 이벤트 리스너:

<button
  type="button"
  onClick={stopListening}
  style={{ "--bgColor": "orange" }}
  disabled={listening === false}
>
  Stop
</button>

<div className="button-container">
  <button
    type="button"
    onClick={resetText}
    style={{ "--bgColor": "red" }}
  >
    Reset
  </button>
  <button
    type="button"
    style={{ "--bgColor": "green" }}
    onClick={handleConversion}
  >
    Convert to pdf
  </button>
</div>

XNUMXD덴탈의 handleConversion 함수는 결국 API 요청을 만들 것이기 ​​때문에 비동기식입니다. "중지" 버튼에는 수신이 false일 때 트리거되는 비활성화된 속성이 있습니다.

서버를 다시 시작하고 브라우저를 새로 고치면 이제 브라우저에서 음성 기록을 시작, 중지 및 재설정할 수 있습니다.

이제 우리에게 필요한 것은 앱이 베끼다 음성을 PDF 파일로 변환하여 인식합니다. 이를 위해서는 Express.js의 서버 측 경로가 필요합니다.

API 경로 설정

이 경로의 목적은 텍스트 파일을 가져 와서 PDF로 변환하고 해당 PDF를 파일 시스템에 작성한 다음 클라이언트에 응답을 보내는 것입니다.

설정하려면 server/index.js 파일 및 가져오기 html-pdf-nodefs 파일 시스템을 작성하고 여는 데 사용할 종속성.

const HTMLToPDF = require("html-pdf-node");
const fs = require("fs");
const cors = require("cors)

다음으로 경로를 설정합니다.

app.use(cors())
app.use(express.json())

app.post("/", (req, res) => {
  // etc.
})

그런 다음 사용에 필요한 옵션을 정의합니다. html-pdf-node 경로 내부:

let options = { format: "A4" };
let file = {
  content: `<html><body><pre style='font-size: 1.2rem'>${req.body.text}</pre></body></html>`,
};

XNUMXD덴탈의 options 개체는 용지 크기와 스타일을 설정하는 값을 허용합니다. 용지 크기는 일반적으로 웹에서 사용하는 크기 단위와 매우 다른 시스템을 따릅니다. 예를 들어, A4는 일반적인 글자 크기입니다..

XNUMXD덴탈의 file 객체는 공개 웹사이트의 URL 또는 HTML 마크업을 허용합니다. HTML 페이지를 생성하기 위해 다음을 사용합니다. html, body, pre HTML 태그 및 텍스트 req.body.

원하는 스타일을 적용할 수 있습니다.

다음으로 추가하겠습니다. trycatch 도중에 나타날 수 있는 오류를 처리하려면:

try {

} catch(error){
  console.log(error);
  res.status(500).send(error);
}

다음으로 우리는 generatePdf 인사말 html-pdf-node 생성하는 라이브러리 pdfBuffer (원시 PDF 파일) 파일에서 고유한 pdfName:

HTMLToPDF.generatePdf(file, options).then((pdfBuffer) => {
  // console.log("PDF Buffer:-", pdfBuffer);
  const pdfName = "./data/speech" + Date.now() + ".pdf";

  // Next code here
}

거기에서 파일 시스템 모듈을 사용하여 작성하고 읽고 (예, 마침내!) 클라이언트 앱에 응답을 보냅니다.

fs.writeFile(pdfName, pdfBuffer, function (writeError) {
  if (writeError) {
    return res
      .status(500)
      .json({ message: "Unable to write file. Try again." });
  }

  fs.readFile(pdfName, function (readError, readData) {
    if (!readError && readData) {
      // console.log({ readData });
      res.setHeader("Content-Type", "application/pdf");
      res.setHeader("Content-Disposition", "attachment");
      res.send(readData);
      return;
    }

    return res
      .status(500)
      .json({ message: "Unable to write file. Try again." });
  });
});

조금 분해해 보겠습니다.

  • XNUMXD덴탈의 writeFile filesystem 모듈은 파일 이름, 데이터 및 파일에 쓰는 데 문제가 있는 경우 오류 메시지를 반환할 수 있는 콜백 함수를 허용합니다. 오류 엔드포인트를 제공하는 CDN으로 작업하는 경우 해당 엔드포인트를 대신 사용할 수 있습니다.
  • XNUMXD덴탈의 readFile filesystem 모듈은 파일 이름과 읽기 오류 및 읽기 데이터를 반환할 수 있는 콜백 함수를 허용합니다. 읽기 오류가 없고 읽기 데이터가 있으면 클라이언트에 응답을 구성하고 보냅니다. 다시 말하지만, CDN의 엔드포인트가 있는 경우 이를 대체할 수 있습니다.
  • XNUMXD덴탈의 res.setHeader("Content-Type", "application/pdf"); PDF 파일을 보내고 있음을 브라우저에 알립니다.
  • XNUMXD덴탈의 res.setHeader("Content-Disposition", "attachment"); 수신된 데이터를 다운로드할 수 있도록 브라우저에 지시합니다.

API 경로가 준비되었으므로 앱에서 사용할 수 있습니다. http://localhost:4000. 애플리케이션의 클라이언트 부분으로 진행하여 완료할 수 있습니다. handleConversion 기능.

변환 처리

작업을 시작하기 전에 handleConversion 함수를 사용하려면 로드, 오류, 성공 및 기타 메시지에 대한 API 요청을 처리하는 상태를 만들어야 합니다. 우리는 React를 사용할 것입니다. useState 후크 설정:

const [response, setResponse] = useState({
  loading: false,
  message: "",
  error: false,
  success: false,
});

. handleConversion 함수를 사용하면 코드를 실행하기 전에 웹 페이지가 로드되었는지 확인하고 div 와 더불어 editable 속성이 비어 있지 않습니다.

if (typeof window !== "undefined") {
const userText = textBodyRef.current.innerText;
  // console.log(textBodyRef.current.innerText);

  if (!userText) {
    alert("Please speak or write some text.");
    return;
  }
}

최종 API 요청을 래핑하여 진행합니다. trycatch, 발생할 수 있는 오류 처리 및 응답 상태 업데이트:

try {

} catch(error){
  setResponse({
    ...response,
    loading: false,
    error: true,
    message:
      "An unexpected error occurred. Text not converted. Please try again",
    success: false,
  });
}

다음으로 응답 상태에 대한 몇 가지 값을 설정하고 다음을 위한 구성도 설정합니다. axios 서버에 게시 요청을 합니다.

setResponse({
  ...response,
  loading: true,
  message: "",
  error: false,
  success: false,
});
const config = {
  headers: {
    "Content-Type": "application/json",
  },
  responseType: "blob",
};

const res = await axios.post(
  "http://localhost:4000",
  {
    text: textBodyRef.current.innerText,
  },
  config
);

성공적인 응답을 받으면 적절한 값으로 응답 상태를 설정하고 브라우저에 수신된 PDF를 다운로드하도록 지시합니다.

setResponse({
  ...response,
  loading: false,
  error: false,
  message:
    "Conversion was successful. Your download will start soon...",
  success: true,
});

// convert the received data to a file
const url = window.URL.createObjectURL(new Blob([res.data]));
// create an anchor element
const link = document.createElement("a");
// set the href of the created anchor element
link.href = url;
// add the download attribute, give the downloaded file a name
link.setAttribute("download", "yourfile.pdf");
// add the created anchor tag to the DOM
document.body.appendChild(link);
// force a click on the link to start a simulated download
link.click();

그리고 contentEditable 아래에서 다음을 사용할 수 있습니다. div 메시지 표시:

<div>
  {response.success && <i className="success">{response.message}</i>}
  {response.error && <i className="error">{response.message}</i>}
</div>

최종 코드

서버와 클라이언트 모두에 대한 전체 소스 코드를 확인할 수 있도록 GitHub에 모든 것을 패키징했습니다.

타임 스탬프 :

더보기 CSS 트릭