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

微信小程序实现录音转文字,并调用后端服务(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. 录音权限:
    • 确保小程序已获取录音权限。
相关推荐
不如摸鱼去13 小时前
Wot UI 2.1.0 发布:ConfigProvider 全局配置能力升级
ui·小程序·uni-app
这是个栗子15 小时前
微信小程序开发(九)- uni-app微信小程序商城
微信小程序·小程序·uni-app·vue·vuex
TuCoder17 小时前
景区导览小程序功能选型指南:刚需配置、增值功能与技术避坑要点
小程序
小羊Yveesss19 小时前
2026年知识付费小程序多少钱一个?
小程序
一只皮卡皮卡丘20 小时前
微信小程序tab页苹果显示安卓不显示的问题
微信小程序·小程序
六月的可乐20 小时前
【干货】小程序虚拟瀑布流探索小结
前端·react.js·小程序
前端 贾公子2 天前
小程序蓝牙打印探索与实践(上)
小程序
拙慕JULY2 天前
小程序返回 base64 文件报错
开发语言·javascript·小程序
dh131222505252 天前
按月季度销售业绩核算小程序
小程序·销售小程序·绩效小程序·业绩统计小程序·业绩核算小程序
拙慕JULY2 天前
微信小程序自定义标题背景色
微信小程序·小程序