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

这篇具有很好参考价值的文章主要介绍了Whisper、React 和 Node 构建语音转文本 Web 应用程序。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。

在本文中,我们将使用 OpenAI 的 Whisper 以及 React、Node.js 和 FFmpeg 构建一个语音转文本应用程序。该应用程序将获取用户输入,使用 OpenAI 的 Whisper API 将其合成为语音,并输出结果文本。Whisper 提供了我用过的最准确的语音到文本转录,即使对于非英语母语人士也是如此。

介绍

OpenAI解释说,Whisper 是一种自动语音识别 (ASR) 系统,经过 680,000 小时从网络收集的多语言和多任务监督数据的训练。

文本比音频更容易搜索和存储。然而,将音频转录为文本可能非常费力。像 Whisper 这样的 ASR 可以检测语音,并非常快速地将音频转录为文本,非常准确,这使其成为一种特别有用的工具。

先决条件

本文面向熟悉 JavaScript 并且对 React 和 Express 有基本了解的开发人员。

如果您想一起构建,则需要 API 密钥。您可以通过在 OpenAI 平台上注册帐户来获取。获得 API 密钥后,请确保其安全并且不要公开共享。

技术堆栈

我们将使用 Create React App (CRA) 构建此应用程序的前端。我们在前端要做的就是上传文件、选择时间边界、发出网络请求和管理一些状态。为了简单起见,我选择了 CRA。随意使用您喜欢的任何前端库,甚至是普通的旧 JS。代码应该大部分是可转移的。

对于后端,我们将使用 Node.js 和 Express,这样我们就可以坚持使用此应用程序的完整 JS 堆栈。您可以使用 Fastify 或任何其他替代方案来代替 Express,并且您仍然应该能够遵循。

注意:为了使本文重点关注主题,将链接到长代码块,以便我们可以专注于手头的实际任务。

设置项目

我们首先创建一个新文件夹,其中包含用于组织目的的项目的前端和后端。请随意选择您喜欢的任何其他结构:

mkdir speech-to-text-app
cd speech-to-text-app

接下来,我们使用以下命令初始化一个新的 React 应用程序create-react-app

npx create-react-app frontend

导航到新frontend文件夹并安装以使用以下代码axios发出网络请求和文件上传:react-dropzone

cd frontend
npm install axios react-dropzone react-select react-toastify

现在,让我们切换回主文件夹并创建backend文件夹:

cd ..
mkdir backend
cd backend

接下来,我们在backend目录中初始化一个新的 Node 应用程序,同时安装所需的库:

npm init -y
npm install express dotenv cors multer form-data axios fluent-ffmpeg ffmetadata ffmpeg-static
npm install --save-dev nodemon

在上面的代码中,我们安装了以下库:

  • dotenv:有必要让我们的 OpenAI API 密钥远离源代码。
  • cors:启用跨域请求。
  • multer:用于上传音频文件的中间件。它将一个.fileor.files对象添加到请求对象,然后我们将在路由处理程序中访问该对象。
  • form-data:以编程方式创建带有文件上传和字段的表单并将其提交到服务器。
  • axios:向 Whisper 端点发出网络请求。

另外,由于我们将使用 FFmpeg 进行音频修剪,因此我们有这些库:

  • fluent-ffmpeg:这提供了一个流畅的 API 来与 FFmpeg 工具配合使用,我们将使用它来进行音频修剪。
  • ffmetadata:这用于读取和写入媒体文件中的元数据。我们需要它来检索音频持续时间。
  • ffmpeg-static:这为不同平台提供静态 FFmpeg 二进制文件,并简化了 FFmpeg 的部署。

Node.js 应用程序的入口文件是index.js. 在文件夹内创建文件backend并在代码编辑器中打开它。让我们连接一个基本的 Express 服务器:

const express = require('express');
const cors = require('cors');
const app = express();

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

app.get('/', (req, res) => {
  res.send('Welcome to the Speech-to-Text API!');
});

const PORT = process.env.PORT || 3001;
app.listen(PORT, () => {
  console.log(`Server is running on port ${PORT}`);
});

更新package.json文件夹backend以包含启动和开发脚本:

"scripts": {
  "start": "node index.js",
  "dev": "nodemon index.js",
}

上面的代码只是注册了一个简单的GET路由。当我们运行npm run dev并前往localhost:3001或无论我们的端口是什么时,我们应该看到欢迎文本。

整合耳语

现在是时候添加秘制酱汁了!在本节中,我们将:

  • POST接受路由上的文件上传
  • 将文件转换为可读流
  • 非常重要的是,将文件发送到 Whisper 进行转录
  • 以 JSON 形式发送回响应

现在让我们.env在文件夹的根目录创建一个文件backend来存储我们的 API 密钥,并记住将其添加到gitignore

OPENAI_API_KEY=YOUR_API_KEY_HERE

首先,让我们导入一些更新文件上传、网络请求和流媒体所需的库:

const  multer  =  require('multer')
const  FormData  =  require('form-data');
const { Readable } =  require('stream');
const  axios  =  require('axios');

const  upload  =  multer();

接下来,我们将创建一个简单的实用程序函数,将文件缓冲区转换为可读流,并将其发送到 Whisper:

const  bufferToStream  = (buffer) => {
  return  Readable.from(buffer);
}

我们将创建一个新路由 ,/api/transcribe并使用 axios 向 OpenAI 发出请求。

首先,axios在文件顶部导入app.jsconst axios = require('axios');.

然后,创建新路线,如下所示:

app.post('/api/transcribe', upload.single('file'), async (req, res) => {
  try {
    const  audioFile  = req.file;
    if (!audioFile) {
      return res.status(400).json({ error: 'No audio file provided' });
    }
    const  formData  =  new  FormData();
    const  audioStream  =  bufferToStream(audioFile.buffer);
    formData.append('file', audioStream, { filename: 'audio.mp3', contentType: audioFile.mimetype });
    formData.append('model', 'whisper-1');
    formData.append('response_format', 'json');
    const  config  = {
      headers: {
        "Content-Type": `multipart/form-data; boundary=${formData._boundary}`,
        "Authorization": `Bearer ${process.env.OPENAI_API_KEY}`,
      },
    };
    // Call the OpenAI Whisper API to transcribe the audio
    const  response  =  await axios.post('https://api.openai.com/v1/audio/transcriptions', formData, config);
    const  transcription  = response.data.text;
    res.json({ transcription });
  } catch (error) {
    res.status(500).json({ error: 'Error transcribing audio' });
  }
});

在上面的代码中,我们使用实用程序函数bufferToStream将音频文件缓冲区转换为可读流,然后通过网络请求将其发送到 Whisper 和await响应,然后将响应作为响应发回JSON

您可以查看文档以了解有关 Whisper 请求和响应的更多信息。

安装 FFmpeg

我们将在下面添加附加功能,以允许用户转录部分音频。为此,我们的 API 端点将接受startTimeendTime,之后我们将使用 修剪音频ffmpeg

安装适用于 Windows 的 FFmpeg

要安装 Windows 版 FFmpeg,请按照以下简单步骤操作:

  1. 在这里访问 FFmpeg 官方网站的下载页面。
  2. Windows 图标下有几个链接。选择 gyan.dev 提供的“Windows Builds”链接。
  3. 下载与我们的系统(32 或 64 位)相对应的版本。确保下载“静态”版本以获取包含的所有库。
  4. 解压缩下载的 ZIP 文件。我们可以将提取的文件夹放置在我们喜欢的任何位置。
  5. 要从命令行使用 FFmpeg 而无需导航到其文件夹,请将 FFmpegbin文件夹添加到系统 PATH。

为 macOS 安装 FFmpeg

如果我们在 macOS 上,我们可以使用 Homebrew 安装 FFmpeg:

brew install ffmpeg

为 Linux 安装 FFmpeg

如果我们在 Linux 上,我们可以使用aptdnf或来安装 FFmpeg pacman,具体取决于我们的 Linux 发行版。这是安装命令apt

sudo apt update
sudo apt install ffmpeg

修剪代码中的音频

为什么我们需要修剪音频?假设用户有一个长达一小时的音频文件,并且只想从 15 分钟标记转录到 45 分钟标记。使用 FFmpeg,我们可以修剪到精确的startTimeendTime,然后将修剪后的流发送到 Whisper 进行转录。

首先,我们将导入以下库:

const ffmpeg = require('fluent-ffmpeg');
const ffmpegPath = require('ffmpeg-static');
const ffmetadata = require('ffmetadata');
const fs  =  require('fs');

ffmpeg.setFfmpegPath(ffmpegPath);
  • fluent-ffmpeg是一个 Node.js 模块,提供与 FFmpeg 交互的流畅 API。
  • ffmetadata将用于读取音频文件的元数据 - 具体来说,duration.
  • ffmpeg.setFfmpegPath(ffmpegPath)用于显式设置 FFmpeg 二进制文件的路径。

接下来,让我们创建一个实用函数,将传递的时间转换为mm:ss秒。这可以在我们的app.post路线之外,就像bufferToStream函数一样:

/**
 * Convert time string of the format 'mm:ss' into seconds.
 * @param {string} timeString - Time string in the format 'mm:ss'.
 * @return {number} - The time in seconds.
 */
const parseTimeStringToSeconds = timeString => {
    const [minutes, seconds] = timeString.split(':').map(tm => parseInt(tm));
    return minutes * 60 + seconds;
}

接下来,我们应该更新我们的app.post路线以执行以下操作:

  • 接受startTimeendTime
  • 计算持续时间
  • 处理基本的错误处理
  • 将音频缓冲区转换为流
  • 使用 FFmpeg 修剪音频
  • 将修剪后的音频发送至 OpenAI 进行转录

trimAudio函数在指定的开始时间和结束时间之间修剪音频流,并返回一个使用修剪后的音频数据进行解析的承诺。如果在此过程中的任何一点发生错误,则 Promise 将因该错误而被拒绝。

让我们逐步分解该功能。

  1. 定义修剪音频功能。该trimAudio函数是异步的,接受audioStreamendTime作为参数。我们定义用于处理音频的临时文件名:

    const trimAudio = async (audioStream, endTime) => {
        const tempFileName = `temp-${Date.now()}.mp3`;
        const outputFileName = `output-${Date.now()}.mp3`;
    
  2. 将流写入临时文件。我们使用 将传入的音频流写入临时文件fs.createWriteStream()。如果出现错误,则会Promise被拒绝:

    return new Promise((resolve, reject) => {
        audioStream.pipe(fs.createWriteStream(tempFileName))
    
  3. 读取元数据并设置 endTime。音频流完成写入临时文件后,我们使用 读取文件的元数据ffmetadata.read()。如果提供的时间endTime长于音频持续时间,我们将调整endTime为音频的持续时间:

    .on('finish', () => {
        ffmetadata.read(tempFileName, (err, metadata) => {
            if (err) reject(err);
            const duration = parseFloat(metadata.duration);
            if (endTime > duration) endTime = duration;
    
  4. 使用 FFmpeg 修剪音频。我们利用 FFmpeg 根据startSeconds接收到的开始时间 () 和timeDuration之前计算的持续时间 () 来修剪音频。修剪后的音频将写入输出文件:

    ffmpeg(tempFileName)
        .setStartTime(startSeconds)
        .setDuration(timeDuration)
        .output(outputFileName)
    
  5. 删除临时文件并解决承诺。修剪音频后,我们删除临时文件并将修剪后的音频读入缓冲区。将输出文件读取到缓冲区后,我们还使用 Node.js 文件系统将其删除。如果一切顺利,问题Promise就会得到解决trimmedAudioBuffer。如果出现错误,则会Promise被拒绝:

    .on('end', () => {
        fs.unlink(tempFileName, (err) => {
            if (err) console.error('Error deleting temp file:', err);
        });const trimmedAudioBuffer = fs.readFileSync(outputFileName);
    fs.unlink(outputFileName, (err) => {
        if (err) console.error('Error deleting output file:', err);
    });
    
    resolve(trimmedAudioBuffer);
    
    })
    .on('error', reject)
    .run();
    

端点的完整代码可在此GitHub 存储库中找到。

前端

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

创建 TimePicker 组件

由于我们的 API 接受startTimeendTime,所以让我们使用TimePicker来创建一个组件react-select
使用react-select只是将其他功能添加到选择菜单中,例如搜索选项,但这对本文并不重要,可以跳过。

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

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

    import React, { useState, useEffect, useCallback } from 'react';
    import Select from 'react-select';
    
    const TimePicker = ({ id, label, value, onChange, maxDuration }) => {
    
  2. 解析valueprop。该valueprop 预计是一个时间字符串(格式HH:MM:SS)。这里我们将时间分为小时、分钟和秒:

    const [hours, minutes, seconds] = value.split(':').map((v) => parseInt(v, 10));
    
  3. 计算最大值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);
    
  4. 时间选项选择。我们为可能的小时、分钟和秒选项创建数组,并创建状态挂钩来管理分钟和秒选项:

    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);
    
  5. 更新值函数onChange该函数通过调用作为 prop 传入的函数来更新当前值:

    const updateValue = (newHours, newMinutes, newSeconds) => {
        onChange(`${String(newHours).padStart(2, '0')}:${String(newMinutes).padStart(2, '0')}:${String(newSeconds).padStart(2, '0')}`);
    };
    
  6. 更新分秒选项功能。此功能根据所选的小时和分钟更新分钟和秒选项:

    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]);
    
  7. 效果挂钩。这会调用updateMinuteAndSecondOptions何时hoursminutes更改:

    useEffect(() => {
        updateMinuteAndSecondOptions(hours, minutes);
    }, [hours, minutes, updateMinuteAndSecondOptions]);
    
  8. 辅助功能。这两个辅助函数将时间整数转换为选择选项,反之亦然:

    const toOption = (value) => ({
        value: value,
        label: String(value).padStart(2, '0'),
    });
    const fromOption = (option) => option.value;
    
  9. 渲染。该render函数显示时间选择器,它由库管理的三个下拉菜单(小时、分钟、秒)组成react-select。更改选择框中的值将调用updateValueupdateMinuteAndSecondOptions,这已在上面进行了解释。

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

主要成分

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

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

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

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

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

    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)
    
  2. 组件声明和状态挂钩。声明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);
      // ...
    
  3. 事件处理程序。定义各种事件处理程序 - 用于处理开始时间更改、获取音频持续时间、处理文件删除和转录音频:

    const handleStartTimeChange = (newStartTime) => {
      //...
    };
    
    const getAudioDuration = (file) => {
      //...
    };
    
    const onDrop = useCallback((acceptedFiles) => {
      //...
    }, []);
    
    const transcribeAudio = async () => { // we'll explain this in detail shortly
      //...
    };
    
  4. 使用 Dropzone 挂钩。使用库useDropzone中的钩子react-dropzone来处理文件丢失:

    const { getRootProps, getInputProps, isDragActive, isDragReject } = useDropzone({
      onDrop,
      accept: 'audio/*',
    });
    
  5. 渲染。最后,渲染组件。这包括用于文件上传的拖放区、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 的强大功能将语音转录为文本。

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

这是完整的源代码:文章来源地址https://www.toymoban.com/news/detail-545366.html

  • GitHub 上的后端存储库
  • GitHub 上的前端存储库

到了这里,关于Whisper、React 和 Node 构建语音转文本 Web 应用程序的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包 赞助服务器费用

相关文章

  • Node.js 中的事件驱动编程:构建强大应用程序的利器

    引言: 在当今高度并发的网络环境下,构建高效、响应迅速的应用程序是开发人员的一项重要任务。Node.js,作为一种基于事件驱动编程模型的 JavaScript 运行环境,为开发人员提供了一个强大的工具。本文将介绍 Node.js 中的事件模型以及如何使用事件驱动编程模式构建强大的

    2024年02月10日
    浏览(47)
  • 创建web应用程序,React和Vue怎么选?

    React和Vue都是创建web应用程序的绝佳选择。React得到了科技巨头和庞大的开源社区的支持,代码库可以很大程度地扩展,允许你创建企业级web应用程序。React拥有大量合格甚至优秀的开发人员粉丝,可以解决你在开发阶段可能遇到的任何问题。 毫无疑问,React是创建跨平台解决

    2024年02月11日
    浏览(53)
  • 【Serverless Web 应用程序】构建流程

    【1】选择构建 Serverless Web 应用程序,程序架构如下所示: 【2】开发流程 【2.1】静态 Web 托管与持续部署: 所有的静态网页内容(HTML、CSS、JavaScript、图 像)和其他文件将由 AWS Amplify 控制台管理。用户将使用 AWS Amplify 控制 台公开的公共网站 URL 访问 Web。不需要额外运行

    2024年02月03日
    浏览(56)
  • 基于aws构建一个web应用程序

    经验帖以及个人总结。 一. 在创建EC2主机前,可先行创建密匙以及安全组。 关于安全组: 1. 入站规则(别人访问你做的一些限制) :开放ssh 端口。是为了可以进行linux相关的连接。                                                                      开放http端口。

    2024年02月08日
    浏览(44)
  • Whisper实现语音识别转文本

    #教程 主要参考开源免费离线语音识别神器whisper如何安装, OpenAI开源模型Whisper——音频转文字 Whisper是一个开源的 自动语音识别 系统,它在网络上收集了680,000小时的多语种和多任务监督数据进行训练,使得它可以将多种语言的音频转文字。 Whisper的好处是 开源免费、支持多

    2024年03月19日
    浏览(46)
  • 快速入门:使用 Spring Boot 构建 Web 应用程序

    本文将讨论以下主题: 安装 Java JDK、Gradle 或 Maven 和 Eclipse 或 IntelliJ IDEA 创建一个新的 Spring Boot 项目 运行 Spring Boot 应用程序 编写一个简单的 Web 应用程序 打包应用程序以用于生产环境 通过这些主题,您将能够开始使用 Spring Boot 并创建自己的 Web 应用程序。 Spring Boot是一个

    2024年02月07日
    浏览(76)
  • 解释 RESTful API,以及如何使用它构建 web 应用程序。

    RESTful API是一种利用HTTP协议进行通信的Web API设计风格,它采用了一组统一且可缓存的操作,包括GET、POST、PUT、DELETE等,通过URL来定位资源,以及使用JSON、XML等格式来传输数据,以实现系统之间的数据交互和资源共享。 使用RESTful API构建Web应用程序,首先需要设计API的URL、

    2024年02月11日
    浏览(66)
  • 使用PostgreSQL构建强大的Web应用程序:最佳实践和建议

    PostgreSQL是一个功能强大的开源关系型数据库,它拥有广泛的用户群和活跃的开发社区。越来越多的Web应用选择PostgreSQL作为数据库 backend。如何充分利用PostgreSQL的特性来构建健壮、高性能的Web应用?本文将给出一些最佳实践和建议。 一、选择合适的PostgreSQL数据类型 PostgreSQL提供

    2024年02月12日
    浏览(74)
  • 解释 RESTful API,以及如何使用它构建 web 应用程序

             RESTful API stands for Representational State Transfer Application Programming Interface. It is a set of principles and guidelines for building web services that provide data in a standard format, typically JSON or XML. RESTful API emphasizes on uniformity, scalability, reliability, performance, and flexibility. It operates on HTTP and follo

    2024年02月14日
    浏览(66)
  • C#使用whisper.net实现语音识别(语音转文本)

    目录 介绍 效果 输出信息  项目 代码 下载  github地址:https://github.com/sandrohanea/whisper.net Whisper.net. Speech to text made simple using Whisper Models 模型下载地址:https://huggingface.co/sandrohanea/whisper.net/tree/main/classic whisper_init_from_file_no_state: loading model from \\\'ggml-small.bin\\\' whisper_model_load: loading

    2024年02月05日
    浏览(37)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包