Whisper、React 和 Node 构建语音转文本 Web 应用程序(二)

简介: Whisper、React 和 Node 构建语音转文本 Web 应用程序(二)

前端

样式将使用 Tailwind 完成,但我不会介绍如何设置 Tailwind。您可以在此处阅读有关如何设置和使用 Tailwind 的信息

创建 TimePicker 组件

由于我们的 API 接受startTime和endTime,所以让我们使用TimePicker来创建一个组件react-select。

使用react-select只是将其他功能添加到选择菜单中,例如搜索选项,但这对本文并不重要,可以跳过。


让我们分解一下TimePicker下面的 React 组件:

进口和组件申报。首先,我们导入必要的包并声明我们的TimePicker组件。该TimePicker组件接受 props idlabelvalueonChangemaxDuration

import React, { useState, useEffect, useCallback } from 'react';
import Select from 'react-select';
const TimePicker = ({ id, label, value, onChange, maxDuration }) => {

解析valueprop。该valueprop 预计是一个时间字符串(格式HH:MM:SS)。这里我们将时间分为小时、分钟和秒:

const [hours, minutes, seconds] = value.split(':').map((v) => parseInt(v, 10));

计算最大值maxDuration是根据音频持续时间可以选择的最大时间(以秒为单位)。它被转换为小时、分钟和秒:

const validMaxDuration = maxDuration === Infinity ? 0 : maxDuration
const maxHours = Math.floor(validMaxDuration / 3600);
const maxMinutes = Math.floor((validMaxDuration % 3600) / 60);
const maxSeconds = Math.floor(validMaxDuration % 60);

时间选项选择。我们为可能的小时、分钟和秒选项创建数组,并创建状态挂钩来管理分钟和秒选项:

const hoursOptions = Array.from({ length: Math.max(0, maxHours) + 1 }, (_, i) => i);
const minutesSecondsOptions = Array.from({ length: 60 }, (_, i) => i);
const [minuteOptions, setMinuteOptions] = useState(minutesSecondsOptions);
const [secondOptions, setSecondOptions] = useState(minutesSecondsOptions);

更新值函数onChange该函数通过调用作为 prop 传入的函数来更新当前值:

const updateValue = (newHours, newMinutes, newSeconds) => {
    onChange(`${String(newHours).padStart(2, '0')}:${String(newMinutes).padStart(2, '0')}:${String(newSeconds).padStart(2, '0')}`);
};

更新分秒选项功能。此功能根据所选的小时和分钟更新分钟和秒选项:

const updateMinuteAndSecondOptions = useCallback((newHours, newMinutes) => {
    const minutesSecondsOptions = Array.from({ length: 60 }, (_, i) => i);
        let newMinuteOptions = minutesSecondsOptions;
        let newSecondOptions = minutesSecondsOptions;
        if (newHours === maxHours) {
            newMinuteOptions = Array.from({ length: Math.max(0, maxMinutes) + 1 }, (_, i) => i);
            if (newMinutes === maxMinutes) {
                newSecondOptions = Array.from({ length: Math.max(0, maxSeconds) + 1 }, (_, i) => i);
            }
        }
        setMinuteOptions(newMinuteOptions);
        setSecondOptions(newSecondOptions);
}, [maxHours, maxMinutes, maxSeconds]);

效果挂钩。这会调用updateMinuteAndSecondOptions何时hoursminutes更改:

useEffect(() => {
    updateMinuteAndSecondOptions(hours, minutes);
}, [hours, minutes, updateMinuteAndSecondOptions]);

辅助功能。这两个辅助函数将时间整数转换为选择选项,反之亦然:

const toOption = (value) => ({
    value: value,
    label: String(value).padStart(2, '0'),
});
const fromOption = (option) => option.value;

渲染。该render函数显示时间选择器,它由库管理的三个下拉菜单(小时、分钟、秒)组成react-select。更改选择框中的值将调用updateValueupdateMinuteAndSecondOptions,这已在上面进行了解释。

您可以在GitHub上找到 TimePicker 组件的完整源代码。

主要成分

现在让我们通过替换 来构建主要的前端组件App.js

应用程序组件将实现具有以下功能的转录页面:

  • 定义时间格式转换的辅助函数。
  • 更新startTime并endTime基于TimePicker组件的选择。
  • 定义一个getAudioDuration函数来检索音频文件的持续时间并更新audioDuration状态。
  • 处理要转录的音频文件的文件上传。
  • 定义一个transcribeAudio函数,通过向我们的 API 发出 HTTP POST 请求来发送音频文件。
  • 渲染文件上传的 UI。
  • TimePicker用于选择startTime和 的渲染组件endTime。
  • 显示通知消息。
  • 显示转录的文本。

让我们将该组件分解为几个较小的部分:

导入和辅助函数。导入必要的模块并定义时间转换的辅助函数:

import React, { useState, useCallback } from 'react';
import { useDropzone } from 'react-dropzone'; // for file upload
import axios from 'axios'; // to make network request
import TimePicker from './TimePicker'; // our custom TimePicker
import { toast, ToastContainer } from 'react-toastify'; // for toast notification
// Helper functions (timeToSeconds, secondsToTime, timeToMinutesAndSeconds)

组件声明和状态挂钩。声明TranscriptionPage组件并初始化状态挂钩:

const TranscriptionPage = () => {
  const [uploading, setUploading] = useState(false);
  const [transcription, setTranscription] = useState('');
  const [audioFile, setAudioFile] = useState(null);
  const [startTime, setStartTime] = useState('00:00:00');
  const [endTime, setEndTime] = useState('00:10:00'); // 10 minutes default endtime
  const [audioDuration, setAudioDuration] = useState(null);
  // ...

事件处理程序。定义各种事件处理程序 - 用于处理开始时间更改、获取音频持续时间、处理文件删除和转录音频:

const handleStartTimeChange = (newStartTime) => {
  //...
};
const getAudioDuration = (file) => {
  //...
};
const onDrop = useCallback((acceptedFiles) => {
  //...
}, []);
const transcribeAudio = async () => { // we'll explain this in detail shortly
  //...
};

使用 Dropzone 挂钩。使用库useDropzone中的钩子react-dropzone来处理文件丢失:

const { getRootProps, getInputProps, isDragActive, isDragReject } = useDropzone({
  onDrop,
  accept: 'audio/*',
});

渲染。最后,渲染组件。这包括用于文件上传的拖放区、TimePicker用于设置开始和结束时间的组件、用于启动转录过程的按钮以及用于显示转录结果的显示。

transcribeAudio函数是一个异步函数,负责将音频文件发送到服务器进行转录。让我们来分解一下:

const transcribeAudio = async () => {
    setUploading(true);
    try {
      const formData = new FormData();
      audioFile && formData.append('file', audioFile);
      formData.append('startTime', timeToMinutesAndSeconds(startTime));
      formData.append('endTime', timeToMinutesAndSeconds(endTime));
      const response = await axios.post(`http://localhost:3001/api/transcribe`, formData, {
        headers: { 'Content-Type': 'multipart/form-data' },
      });
      setTranscription(response.data.transcription);
      toast.success('Transcription successful.')
    } catch (error) {
      toast.error('An error occurred during transcription.');
    } finally {
      setUploading(false);
    }
  };

下面是更详细的介绍:


  1. setUploading(true);。此行将uploading状态设置为true,我们用它来向用户指示转录过程已经开始。
  2. const formData = new FormData();。FormData是一个 Web API,用于将表单数据发送到服务器。它允许我们发送键值对,其中值可以是 Blob、文件或字符串。
  3. 如果 不为 null ( ),则audioFile会附加到对象。开始时间和结束时间也会附加到对象中,但首先会转换为格式。formData``audioFile && formData.append('file', audioFile);``formData``MM:SS
  4. 该axios.post方法用于将 发送formData到服务器端点 ( http://localhost:3001/api/transcribe)。更改http://localhost:3001为服务器地址。这是通过await关键字完成的,这意味着该函数将暂停并等待 Promise 被解析或被拒绝。
  5. 如果请求成功,响应对象将包含转录结果 ( response.data.transcription)。transcription然后使用该函数将其设置为状态setTranscription。然后会显示成功的 Toast 通知。
  6. 如果在此过程中发生错误,则会显示错误 Toast 通知。
  7. 在该finally块中,无论结果如何(成功或错误),uploading状态都会被设置回false以允许用户重试。

本质上,该transcribeAudio函数负责协调整个转录过程,包括处理表单数据、发出服务器请求和处理服务器响应。

您可以在GitHub上找到 App 组件的完整源代码。

结论

我们已经到了最后,现在有了一个完整的 Web 应用程序,可以利用 Whisper 的强大功能将语音转录为文本。

我们绝对可以添加更多功能,但我会让您自己构建其余的功能。希望我们已经为您提供了一个良好的开端。

这是完整的源代码:

相关文章
|
1月前
|
前端开发
深入解析React Hooks:构建高效且可维护的前端应用
本文将带你走进React Hooks的世界,探索这一革新特性如何改变我们构建React组件的方式。通过分析Hooks的核心概念、使用方法和最佳实践,文章旨在帮助你充分利用Hooks来提高开发效率,编写更简洁、更可维护的前端代码。我们将通过实际代码示例,深入了解useState、useEffect等常用Hooks的内部工作原理,并探讨如何自定义Hooks以复用逻辑。
|
1月前
|
存储 JavaScript 前端开发
掌握现代Web开发的基石:深入理解React与Redux
【10月更文挑战第14天】掌握现代Web开发的基石:深入理解React与Redux
32 0
|
18天前
|
JavaScript 中间件 关系型数据库
构建高效的后端服务:Node.js 与 Express 的实践指南
在后端开发领域,Node.js 与 Express 的组合因其轻量级和高效性而广受欢迎。本文将深入探讨如何利用这一组合构建高性能的后端服务。我们将从 Node.js 的事件驱动和非阻塞 I/O 模型出发,解释其如何优化网络请求处理。接着,通过 Express 框架的简洁 API,展示如何快速搭建 RESTful API。文章还将涉及中间件的使用,以及如何结合 MySQL 数据库进行数据操作。最后,我们将讨论性能优化技巧,包括异步编程模式和缓存策略,以确保服务的稳定性和扩展性。
|
7天前
|
前端开发 JavaScript 开发者
从零开始构建你的第一个React应用
从零开始构建你的第一个React应用
18 2
|
7天前
|
JSON JavaScript API
深入浅出Node.js:从零开始构建RESTful API
【10月更文挑战第39天】 在数字化时代的浪潮中,API(应用程序编程接口)已成为连接不同软件应用的桥梁。本文将带领读者从零基础出发,逐步深入Node.js的世界,最终实现一个功能完备的RESTful API。通过实践,我们将探索如何利用Node.js的异步特性和强大的生态系统来构建高效、可扩展的服务。准备好迎接代码和概念的碰撞,一起解锁后端开发的新篇章。
|
21天前
|
资源调度 前端开发 数据可视化
构建高效的数据可视化仪表板:D3.js与React的融合之道
【10月更文挑战第25天】在数据驱动的时代,将复杂的数据集转换为直观、互动式的可视化表示已成为一项至关重要的技能。本文深入探讨了如何结合D3.js的强大可视化功能和React框架的响应式特性来构建高效、动态的数据可视化仪表板。文章首先介绍了D3.js和React的基础知识,然后通过一个实际的项目案例,详细阐述了如何将两者结合使用,并提供了实用的代码示例。无论你是数据科学家、前端开发者还是可视化爱好者,这篇文章都将为你提供宝贵的洞见和实用技能。
44 5
|
24天前
|
JavaScript 前端开发 持续交付
构建现代Web应用:Vue.js与Node.js的完美结合
【10月更文挑战第22天】随着互联网技术的快速发展,Web应用已经成为了人们日常生活和工作的重要组成部分。前端技术和后端技术的不断创新,为Web应用的构建提供了更多可能。在本篇文章中,我们将探讨Vue.js和Node.js这两大热门技术如何完美结合,构建现代Web应用。
22 4
|
25天前
|
Web App开发 JavaScript 中间件
构建高效后端服务:Node.js与Express框架的完美结合
【10月更文挑战第21天】本文将引导你走进Node.js和Express框架的世界,探索它们如何共同打造一个高效、可扩展的后端服务。通过深入浅出的解释和实际代码示例,我们将一起理解这一组合的魅力所在,并学习如何利用它们来构建现代Web应用。
45 1
|
11天前
|
JavaScript 前端开发 NoSQL
深入浅出:使用Node.js构建RESTful API
【10月更文挑战第35天】在数字时代的浪潮中,后端技术如同海洋中稳固的灯塔,为前端应用提供数据和逻辑支撑。本文旨在通过浅显易懂的方式,带领读者了解如何利用Node.js这一强大的后端平台,搭建一个高效、可靠的RESTful API。我们将从基础概念入手,逐步深入到代码实践,最终实现一个简单的API示例。这不仅是对技术的探索,也是对知识传递方式的一次创新尝试。让我们一起启航,探索Node.js的奥秘,解锁后端开发的无限可能。
|
13天前
|
Web App开发 JavaScript 前端开发
构建高效后端服务:Node.js与Express框架的实践
【10月更文挑战第33天】在数字化时代的浪潮中,后端服务的效率和可靠性成为企业竞争的关键。本文将深入探讨如何利用Node.js和Express框架构建高效且易于维护的后端服务。通过实践案例和代码示例,我们将揭示这一组合如何简化开发流程、优化性能,并提升用户体验。无论你是初学者还是有经验的开发者,这篇文章都将为你提供宝贵的见解和实用技巧。