从零开始:用TypeScript和Whisper构建企业应用应用

云信安装大师
90
AI 质量分
11 5 月, 2025
5 分钟阅读
0 阅读

从零开始:用TypeScript和Whisper构建企业级应用

引言

在现代企业应用开发中,TypeScript因其类型安全和强大的工具支持而广受欢迎。而Whisper(OpenAI的语音识别模型)则为应用添加了语音交互能力。本文将带你从零开始,使用TypeScript和Whisper API构建一个具备语音识别功能的企业级应用。

准备工作

在开始之前,请确保你的开发环境满足以下要求:

  • Node.js (建议16.x或更高版本)
  • npm或yarn
  • TypeScript (我们将安装)
  • OpenAI账号 (用于获取API密钥)

1. 初始化项目

首先,创建一个新目录并初始化Node.js项目:

代码片段
mkdir ts-whisper-app
cd ts-whisper-app
npm init -y

2. 安装TypeScript

安装TypeScript作为开发依赖:

代码片段
npm install typescript --save-dev
npx tsc --init

这会创建一个默认的tsconfig.json文件。我们稍后会修改它。

3. 安装必要依赖

安装我们将使用的主要依赖:

代码片段
npm install openai axios dotenv express @types/express @types/node cors

项目结构设置

创建以下目录结构:

代码片段
ts-whisper-app/
├── src/
│   ├── controllers/
│   ├── services/
│   ├── utils/
│   └── index.ts
├── .env
├── package.json
└── tsconfig.json

配置TypeScript

修改tsconfig.json

代码片段
{
  "compilerOptions": {
    "target": "ES2020",
    "module": "commonjs",
    "outDir": "./dist",
    "rootDir": "./src",
    "strict": true,
    "esModuleInterop": true,
    "skipLibCheck": true,
    "forceConsistentCasingInFileNames": true,
    "moduleResolution": "node"
  },
  "include": ["src/**/*"],
  "exclude": ["node_modules"]
}

构建后端服务

1. 创建Express服务器

src/index.ts中创建基础服务器:

代码片段
import express from 'express';
import cors from 'cors';
import dotenv from 'dotenv';

dotenv.config();

const app = express();
const port = process.env.PORT || 3000;

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

app.get('/', (req, res) => {
  res.send('TypeScript + Whisper API Server');
});

app.listen(port, () => {
  console.log(`Server running at http://localhost:${port}`);
});

2. Whisper服务封装

src/services/whisper.service.ts中创建Whisper服务:

代码片段
import { Configuration, OpenAIApi } from 'openai';
import fs from 'fs';
import path from 'path';

class WhisperService {
  private openai: OpenAIApi;

  constructor() {
    const configuration = new Configuration({
      apiKey: process.env.OPENAI_API_KEY,
    });
    this.openai = new OpenAIApi(configuration);
  }

  async transcribeAudio(filePath: string): Promise<string> {
    try {
      const fileStream = fs.createReadStream(filePath);
      const fileName = path.basename(filePath);

      const response = await this.openai.createTranscription(
        fileStream as any, // Whisper API expects a File-like object
        'whisper-1',
        undefined,
        'text'
      );

      return response.data;
    } catch (error) {
      console.error('Error in transcription:', error);
      throw error;
    }
  }
}

export default new WhisperService();

3. Whisper控制器

src/controllers/whisper.controller.ts中创建控制器:

代码片段
import { Request, Response } from 'express';
import whisperService from '../services/whisper.service';

class WhisperController {
  async transcribe(req: Request, res: Response) {
    try {
      if (!req.file) {
        return res.status(400).json({ error: 'No audio file provided' });
      }

      const transcription = await whisperService.transcribeAudio(req.file.path);

      // Clean up the uploaded file after processing
      // In production, consider using a proper file storage solution

      return res.json({ transcription });
    } catch (error) {
      console.error(error);
      return res.status(500).json({ error: 'Failed to transcribe audio' });
    }
  }
}

export default new WhisperController();

4. API路由设置

更新src/index.ts添加文件上传和API路由:

代码片段
import express from 'express';
import cors from 'cors';
import dotenv from 'dotenv';
import multer from 'multer';
import whisperController from './controllers/whisper.controller';

dotenv.config();

const app = express();
const port = process.env.PORT || 3000;

// Configure multer for file uploads
const upload = multer({ dest: 'uploads/' });

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

// API Routes
app.post('/api/transcribe', upload.single('audio'), whisperController.transcribe);

app.get('/', (req, res) => {
  res.send('TypeScript + Whisper API Server');
});

app.listen(port, () => {
  console.log(`Server running at http://localhost:${port}`);
});

.env配置

创建.env文件并添加你的OpenAI API密钥:

代码片段
OPENAI_API_KEY=your_openai_api_key_here
PORT=3000

重要:确保将.env添加到你的.gitignore文件中,不要将API密钥提交到版本控制。

TypeScript编译与运行

添加以下脚本到package.json

代码片段
"scripts": {
  "build": "tsc",
  "start": "node dist/index.js",
  "dev": "ts-node-dev src/index.ts"
}

现在你可以使用以下命令运行开发服务器:

代码片段
npm run dev

或者构建并运行生产版本:

代码片段
npm run build && npm start

API测试示例

你可以使用Postman或curl测试API端点。这里是一个curl示例:

代码片段
curl -X POST \
     -H "Content-Type: multipart/form-data" \
     -F "[email]" \
     http://localhost:3000/api/transcribe \
     -o response.txt \
     --silent && cat response.txt && rm response.txt

Web前端集成(可选)

如果你想创建一个完整的前后端应用,可以添加一个简单的前端页面来录音并发送到后端。

React组件示例(在单独的前端项目中):

“`typescript jsx
// AudioRecorder.tsx
import React, { useState } from ‘react’;
import axios from ‘axios’;

const AudioRecorder = () => {
const [recording, setRecording] = useState(false);
const [mediaRecorder, setMediaRecorder] = useState(null);
const [transcription, setTranscription] = useState(”);

const startRecording = async () => {
try {
const stream = await navigator.mediaDevices.getUserMedia({ audio: true });
const recorder = new MediaRecorder(stream);
let chunks: BlobPart[] = [];

代码片段
       recorder.ondataavailable = (e) => chunks.push(e.data); 
       recorder.onstop = async () => { 
           const blob = new Blob(chunks, { type: 'audio/wav' }); 
           chunks = []; 

           // Send to backend for transcription 
           const formData = new FormData(); 
           formData.append('audio', blob, 'recording.wav'); 

           try { 
               const response = await axios.post( 
                   'http://localhost:3000/api/transcribe',  
                   formData,  
                   { headers: { 'Content-Type': 'multipart/form-data' } } 
               ); 

               setTranscription(response.data.transcription); 
           } catch (error) { 
               console.error('Error sending audio:', error); 
           } 
       }; 

       recorder.start(); 
       setMediaRecorder(recorder); 
       setRecording(true); 

   } catch (error) { 
       console.error('Error accessing microphone:', error); 
   }

};

const stopRecording = () => {
if (mediaRecorder) {
mediaRecorder.stop();
setRecording(false);

代码片段
       // Stop all tracks in the stream to release the microphone  
       mediaRecorder.stream.getTracks().forEach(track => track.stop());  
   }

};

return (

Voice Transcription

代码片段
       <button onClick={recording ? stopRecording : startRecording}>  
           {recording ? 'Stop Recording' : 'Start Recording'}  
       </button>  

       <div style={{ marginTop: '20px' }}>  
           <h3>Transcription:</h3>  
           <p>{transcription || '(No transcription yet)'}</p>  
       </div>  
   </div>

);
};

export default AudioRecorder;

// App.tsx – Main component

function App() {

return (

);

}

export default App;

代码片段

## **实践经验与注意事项**

1. **文件处理**:
   - `multer`中间件会将上传的文件保存到本地磁盘。在生产环境中,你应该考虑:
     - **文件大小限制**:设置合理的限制以防止大文件上传导致的问题。
     ```typescript   
     const upload = multer({   
         dest: '/tmp/uploads/',   
         limits: {   
             fileSize: MAX_FILE_SIZE_BYTES // e.g.,10MB   
         },   
         fileFilter(req,file,cb){   
             if(!file.mimetype.match(/audio\/(wav|mp3|mpeg)/)){   
                 return cb(new Error("Only audio files are allowed"));   
             }   
             cb(null,true);   
         }   
     })   
    
  1. 错误处理

    • WhisperService.transcribeAudio()方法中的错误处理是基本的。在生产环境中,你可能需要:
      • 重试机制:对于网络错误或API限制错误。
      • 更详细的日志记录:记录请求ID、时间戳等信息以便调试。
  2. 安全性考虑

    • CORS配置:在生产环境中,应该严格限制允许的来源。
      代码片段
      app.use(cors({    
          origin:[    
              process.env.FRONTEND_URL!,    
              process.env.LOCALHOST_URL!    
          ],    
          methods:"GET,POST",    
          credentials:true    
      }))    <br>
      
  3. 性能优化

    • 音频预处理:对于长时间录音,考虑分割音频后再发送给Whisper。
    • 缓存结果:如果应用场景允许,缓存常见短语的转录结果以减少API调用。
  4. 成本控制

    • OpenAI API按使用量计费。对于企业应用:

      • 监控用量:实现简单的用量监控系统。
        “`typescript
        class UsageTracker{
        private static instance : UsageTracker;
        private monthlyUsage : number=0;

        private constructor(){}

        public static getInstance():UsageTracker{
        if(!UsageTracker.instance){
        UsageTracker.instance=new UsageTracker();
        }
        return UsageTracker.instance;
        }

        public recordUsage(costInCents : number){
        this.monthlyUsage+=costInCents;
        if(this.monthlyUsage > MONTHLY_BUDGET){
        // Alert admin or disable service temporarily
        }
        }

        public getMonthlyUsage(){
        return this.monthlyUsage;
        }
        }

  5. 部署考虑

当准备部署时:

  • 环境变量管理:使用专门的秘密管理服务如AWS Secrets Manager或Azure Key Vault。

  • 容器化:考虑将应用打包为Docker容器:

代码片段
FROM node:slim        
WORKDIR /usr/src/app        
COPY package*.json ./        
RUN npm install        
COPY . .        
RUN npm run build        
EXPOSE ${PORT}        
CMD ["node","dist/index.js"]        

然后构建并运行:

代码片段
docker build -t ts-whisper-app .        
docker run -p ${PORT}:${PORT} --env-file .env ts-whisper-app        

7.扩展可能性

这个基础架构可以扩展为:

-会议记录系统(结合多个讲话者识别)

-实时字幕服务(结合WebSocket)

-语音命令控制面板

总结

在本教程中我们完成了:

1.TypeScript+Express后端服务的搭建

2.OpenAI Whisper API的集成

3.音频文件上传和处理流程

4.(可选)前端录音组件示例

关键点回顾:

-TypeScript的类型系统帮助我们在开发阶段捕获潜在错误

-multer中间件简化了文件上传处理

-Whisper API提供了高质量的语音转文本功能

下一步可以考虑:

1.用户认证:添加JWT认证以保护API端点

2.数据库集成:存储转录历史记录

3.队列系统:对于大量请求实现异步处理

原创 高质量