【微信小程序变通实现DeepSeek支持语音】

发布于:2025-03-20 ⋅ 阅读:(20) ⋅ 点赞:(0)

微信小程序实现录音转文字,并调用后端服务(Node.js)进行语音识别和,然后调用DeepSeek 处理的完整实现。

整体架构

  1. 前端(微信小程序):
    • 实现录音功能。
    • 将录音文件上传到后端。
    • 接收后端返回的语音识别结果,并显示在可编辑的文本框中。
    • 调用 DeepSeek 处理文本。
  2. 后端(Node.js):
    • 接收小程序上传的录音文件。
    • 调用腾讯云语音识别(ASR)服务,将语音转换为文字。
    • 返回识别结果给小程序。
    • 提供 DeepSeek 处理接口。

步骤 1:后端开发(Node.js)

1. 项目结构

复制

backend/
├── server.js            # 主入口文件
├── config.js            # 配置文件
├── asrService.js        # 腾讯云语音识别服务
├── deepseekService.js   # DeepSeek 处理服务
└── package.json         # 依赖文件
2. 安装依赖

bash

复制

npm install express multer tencentcloud-sdk-nodejs axios
3. 配置文件 (config.js)

javascript

复制

module.exports = {
  tencentCloud: {
    secretId: 'your-tencent-secret-id', // 腾讯云 SecretId
    secretKey: 'your-tencent-secret-key', // 腾讯云 SecretKey
    region: 'ap-guangzhou' // 腾讯云区域
  },
  deepseek: {
    apiKey: 'your-deepseek-api-key', // DeepSeek API 密钥
    apiUrl: 'https://api.deepseek.com/v1/chat/completions' // DeepSeek API 地址
  }
};
4. 腾讯云语音识别服务 (asrService.js)

javascript

复制

const tencentcloud = require('tencentcloud-sdk-nodejs');
const AsrClient = tencentcloud.asr.v20190614.Client;
const { tencentCloud } = require('./config');

const client = new AsrClient({
  credential: {
    secretId: tencentCloud.secretId,
    secretKey: tencentCloud.secretKey,
  },
  region: tencentCloud.region,
  profile: {
    httpProfile: {
      endpoint: 'asr.tencentcloudapi.com',
    },
  },
});

/**
 * 调用腾讯云语音识别
 * @param {string} audioBase64 - 音频文件的 base64 数据
 * @returns {Promise<string>} - 识别结果
 */
async function recognizeAudio(audioBase64) {
  const params = {
    EngineModelType: '16k_zh', // 16k 中文普通话
    VoiceFormat: 'wav',        // 音频格式
    Data: audioBase64          // 音频数据
  };

  const response = await client.SentenceRecognition(params);
  return response.Result;
}

module.exports = { recognizeAudio };
5. DeepSeek 处理服务 (deepseekService.js)

javascript

复制

const axios = require('axios');
const { deepseek } = require('./config');

/**
 * 调用 DeepSeek 处理文本
 * @param {string} text - 需要处理的文本
 * @returns {Promise<string>} - 处理结果
 */
async function processText(text) {
  const response = await axios.post(
    deepseek.apiUrl,
    {
      model: 'deepseek-chat',
      messages: [
        { role: 'system', content: '你是一个文本处理助手。' },
        { role: 'user', content: text }
      ]
    },
    {
      headers: {
        'Content-Type': 'application/json',
        'Authorization': `Bearer ${deepseek.apiKey}`
      }
    }
  );

  return response.data.choices[0].message.content;
}

module.exports = { processText };
6. 主入口文件 (server.js)

javascript

复制

const express = require('express');
const multer = require('multer');
const { recognizeAudio } = require('./asrService');
const { processText } = require('./deepseekService');
const path = require('path');

const app = express();
const upload = multer({ dest: 'uploads/' }); // 临时存储上传文件

// 语音识别接口
app.post('/api/recognize', upload.single('audio'), async (req, res) => {
  try {
    const filePath = req.file.path;
    const fileData = require('fs').readFileSync(filePath, { encoding: 'base64' });
    const result = await recognizeAudio(fileData);
    res.json({ success: true, data: result });
  } catch (error) {
    res.status(500).json({ success: false, message: error.message });
  }
});

// DeepSeek 处理接口
app.post('/api/process', express.json(), async (req, res) => {
  try {
    const { text } = req.body;
    const result = await processText(text);
    res.json({ success: true, data: result });
  } catch (error) {
    res.status(500).json({ success: false, message: error.message });
  }
});

// 启动服务器
const PORT = 3000;
app.listen(PORT, () => {
  console.log(`Server is running on http://localhost:${PORT}`);
});

步骤 2:前端开发(微信小程序)

1. 项目结构

复制

miniprogram/
├── pages/
│   ├── index/
│   │   ├── index.js       # 页面逻辑
│   │   ├── index.wxml     # 页面结构
│   │   └── index.wxss     # 页面样式
├── app.js                 # 小程序逻辑
├── app.json               # 小程序配置
└── app.wxss               # 全局样式
2. 页面逻辑 (index.js)

javascript

复制

const app = getApp();

Page({
  data: {
    isRecording: false,      // 是否正在录音
    recordTime: 0,           // 录音时长
    resultText: '',          // 识别结果
    editedText: '',          // 编辑后的文本
    isLoading: false         // 加载状态
  },

  // 开始录音
  startRecord() {
    this.setData({ isRecording: true, recordTime: 0 });

    this.recorderManager = wx.getRecorderManager();
    this.recorderManager.start({
      format: 'wav',         // 录音格式
      sampleRate: 16000,     // 采样率
      numberOfChannels: 1,   // 声道数
      encodeBitRate: 48000   // 编码码率
    });

    this.timer = setInterval(() => {
      this.setData({ recordTime: this.data.recordTime + 1 });
    }, 1000);

    this.recorderManager.onStop((res) => {
      clearInterval(this.timer);
      this.setData({ isRecording: false });
      this.uploadAudio(res.tempFilePath); // 上传录音文件
    });
  },

  // 停止录音
  stopRecord() {
    if (this.recorderManager) {
      this.recorderManager.stop();
    }
  },

  // 上传录音文件
  uploadAudio(filePath) {
    this.setData({ isLoading: true });

    wx.uploadFile({
      url: 'http://localhost:3000/api/recognize', // 后端语音识别接口
      filePath: filePath,
      name: 'audio',
      success: (res) => {
        const result = JSON.parse(res.data);
        if (result.success) {
          this.setData({ resultText: result.data, editedText: result.data });
        } else {
          wx.showToast({ title: '识别失败', icon: 'none' });
        }
      },
      fail: (err) => {
        wx.showToast({ title: '上传失败', icon: 'none' });
      },
      complete: () => {
        this.setData({ isLoading: false });
      }
    });
  },

  // 编辑文本
  handleEditText(e) {
    this.setData({ editedText: e.detail.value });
  },

  // 调用 DeepSeek 处理文本
  processText() {
    const { editedText } = this.data;
    if (!editedText) {
      wx.showToast({ title: '请输入文本', icon: 'none' });
      return;
    }

    this.setData({ isLoading: true });

    wx.request({
      url: 'http://localhost:3000/api/process', // 后端 DeepSeek 处理接口
      method: 'POST',
      data: { text: editedText },
      success: (res) => {
        if (res.data.success) {
          this.setData({ resultText: res.data.data });
        } else {
          wx.showToast({ title: '处理失败', icon: 'none' });
        }
      },
      fail: (err) => {
        wx.showToast({ title: '网络错误', icon: 'none' });
      },
      complete: () => {
        this.setData({ isLoading: false });
      }
    });
  }
});
3. 页面结构 (index.wxml)

xml

复制

<view class="container">
  <!-- 录音按钮 -->
  <view class="record-button">
    <button
      bindtap="{{isRecording ? 'stopRecord' : 'startRecord'}}"
      class="{{isRecording ? 'stop-button' : 'start-button'}}"
    >
      {{isRecording ? '停止录音' : '开始录音'}}
    </button>
    <text class="record-time" wx:if="{{isRecording}}">{{recordTime}}s</text>
  </view>

  <!-- 识别结果 -->
  <view class="result-box">
    <text class="result-title">识别结果:</text>
    <textarea
      value="{{editedText}}"
      bindinput="handleEditText"
      placeholder="识别结果将显示在这里"
      class="result-text"
    ></textarea>
  </view>

  <!-- 处理按钮 -->
  <button bindtap="processText" class="process-button">调用 DeepSeek 处理</button>

  <!-- 处理结果 -->
  <view class="result-box">
    <text class="result-title">处理结果:</text>
    <textarea
      value="{{resultText}}"
      placeholder="处理结果将显示在这里"
      disabled
      class="result-text"
    ></textarea>
  </view>

  <!-- 加载状态 -->
  <view class="loading" wx:if="{{isLoading}}">
    <text>处理中...</text>
  </view>
</view>

运行 HTML

4. 页面样式 (index.wxss)

css

复制

.container {
  padding: 20px;
  display: flex;
  flex-direction: column;
  align-items: center;
}

.record-button {
  display: flex;
  flex-direction: column;
  align-items: center;
  margin-bottom: 20px;
}

.start-button {
  background-color: #07c160;
  color: white;
}

.stop-button {
  background-color: #f5222d;
  color: white;
}

.record-time {
  margin-top: 10px;
  font-size: 14px;
  color: #666;
}

.result-box {
  width: 100%;
  margin-top: 20px;
}

.result-title {
  font-size: 16px;
  font-weight: bold;
  margin-bottom: 10px;
}

.result-text {
  width: 100%;
  height: 100px;
  border: 1px solid #ccc;
  border-radius: 5px;
  padding: 10px;
  font-size: 14px;
}

.process-button {
  margin-top: 20px;
  background-color: #1890ff;
  color: white;
}

.loading {
  margin-top: 20px;
  font-size: 14px;
  color: #666;
}
5. 小程序配置 (app.json)

json

复制

{
  "pages": [
    "pages/index/index"
  ],
  "window": {
    "navigationBarTitleText": "录音转文字",
    "navigationBarBackgroundColor": "#07c160",
    "navigationBarTextStyle": "white"
  }
}

步骤 3:测试

  1. 启动后端服务:

    bash

    复制

    node server.js
    
  2. 在微信开发者工具中运行小程序。

  3. 测试录音、语音识别、文本编辑和 DeepSeek 处理功能。


注意事项

  1. 后端部署:
    • 将后端服务部署到云服务器(如腾讯云、阿里云),并配置 HTTPS。
  2. API 密钥安全:
    • 不要将 API 密钥暴露在前端代码中。
  3. 录音权限:
    • 确保小程序已获取录音权限。