【微信小程序(云开发模式)变通实现DeepSeek支持语音】

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

整体架构

  1. 前端(微信小程序):
    • 使用微信小程序云开发能力,实现录音功能。
    • 将录音文件上传到云存储。
    • 调用云函数进行语音识别和 DeepSeek 处理。
    • 界面模仿 DeepSeek,支持文本编辑。
  2. 后端(云函数 + Node.js):
    • 使用云函数调用腾讯云语音识别(ASR)服务。
    • 调用 DeepSeek API 处理文本。

步骤 1:初始化云开发环境

  1. 在微信开发者工具中创建小程序项目,并开通云开发。

  2. project.config.json 中配置云函数目录:

    json

    复制

    {
      "cloudfunctionRoot": "cloud/functions/"
    }
    
  3. 初始化云开发环境:

    javascript

    复制

    wx.cloud.init({
      env: 'your-env-id', // 替换为你的云环境 ID
      traceUser: true
    });
    

步骤 2:编写云函数

1. 云函数结构

复制

cloud/
├── functions/
│   ├── asr/              # 语音识别云函数
│   │   ├── index.js
│   │   ├── config.json
│   │   └── package.json
│   ├── deepseek/         # DeepSeek 处理云函数
│   │   ├── index.js
│   │   ├── config.json
│   │   └── package.json
2. 语音识别云函数 (asr/index.js)

javascript

复制

const tencentcloud = require('tencentcloud-sdk-nodejs');
const AsrClient = tencentcloud.asr.v20190614.Client;
const fs = require('fs');
const path = require('path');

exports.main = async (event, context) => {
  const { fileID } = event;

  // 下载录音文件
  const fileContent = await wx.cloud.downloadFile({
    fileID: fileID
  });
  const audioPath = fileContent.tempFilePath;
  const audioData = fs.readFileSync(audioPath, { encoding: 'base64' });

  // 调用腾讯云语音识别
  const client = new AsrClient({
    credential: {
      secretId: process.env.TENCENT_SECRET_ID, // 从环境变量获取
      secretKey: process.env.TENCENT_SECRET_KEY
    },
    region: 'ap-guangzhou',
    profile: {
      httpProfile: {
        endpoint: 'asr.tencentcloudapi.com'
      }
    }
  });

  const params = {
    EngineModelType: '16k_zh',
    VoiceFormat: 'wav',
    Data: audioData
  };

  try {
    const response = await client.SentenceRecognition(params);
    return {
      success: true,
      data: response.Result
    };
  } catch (error) {
    return {
      success: false,
      message: error.message
    };
  }
};
3. DeepSeek 处理云函数 (deepseek/index.js)

javascript

复制

const axios = require('axios');

exports.main = async (event, context) => {
  const { text } = event;

  try {
    const response = await axios.post(
      'https://api.deepseek.com/v1/chat/completions',
      {
        model: 'deepseek-chat',
        messages: [
          { role: 'system', content: '你是一个文本处理助手。' },
          { role: 'user', content: text }
        ]
      },
      {
        headers: {
          'Content-Type': 'application/json',
          'Authorization': `Bearer ${process.env.DEEPSEEK_API_KEY}` // 从环境变量获取
        }
      }
    );

    return {
      success: true,
      data: response.data.choices[0].message.content
    };
  } catch (error) {
    return {
      success: false,
      message: error.message
    };
  }
};
4. 安装依赖

在云函数目录下运行:

bash

复制

npm install tencentcloud-sdk-nodejs axios
5. 配置环境变量

在云开发控制台中,为云函数配置环境变量:

  • TENCENT_SECRET_ID: 腾讯云 SecretId
  • TENCENT_SECRET_KEY: 腾讯云 SecretKey
  • DEEPSEEK_API_KEY: DeepSeek API 密钥

步骤 3:编写小程序前端

1. 页面结构

复制

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

javascript

复制

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(async (res) => {
      clearInterval(this.timer);
      this.setData({ isRecording: false });
      await this.uploadAudio(res.tempFilePath); // 上传录音文件
    });
  },

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

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

    try {
      // 上传到云存储
      const uploadRes = await wx.cloud.uploadFile({
        cloudPath: `audios/${Date.now()}.wav`,
        filePath: filePath
      });

      // 调用语音识别云函数
      const asrRes = await wx.cloud.callFunction({
        name: 'asr',
        data: { fileID: uploadRes.fileID }
      });

      if (asrRes.result.success) {
        this.setData({ resultText: asrRes.result.data, editedText: asrRes.result.data });
      } else {
        wx.showToast({ title: '识别失败', icon: 'none' });
      }
    } catch (error) {
      wx.showToast({ title: '上传失败', icon: 'none' });
    } finally {
      this.setData({ isLoading: false });
    }
  },

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

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

    this.setData({ isLoading: true });

    try {
      const deepseekRes = await wx.cloud.callFunction({
        name: 'deepseek',
        data: { text: editedText }
      });

      if (deepseekRes.result.success) {
        this.setData({ resultText: deepseekRes.result.data });
      } else {
        wx.showToast({ title: '处理失败', icon: 'none' });
      }
    } catch (error) {
      wx.showToast({ title: '网络错误', icon: 'none' });
    } finally {
      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;
  background-color: #F5F5F5;
  min-height: 100vh;
}

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

.start-button {
  background-color: #07C160;
  color: white;
  width: 80%;
}

.stop-button {
  background-color: #F5222D;
  color: white;
  width: 80%;
}

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

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

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

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

.process-button {
  margin-top: 20px;
  background-color: #1890FF;
  color: white;
  width: 80%;
}

.loading {
  margin-top: 20px;
  font-size: 14px;
  color: #666666;
  text-align: center;
}

步骤 4:测试

  1. 在微信开发者工具中运行小程序。
  2. 测试录音、语音识别、文本编辑和 DeepSeek 处理功能。

注意事项

  1. 云函数部署:
    • 确保云函数已上传并部署。
  2. 环境变量:
    • 在云开发控制台中正确配置环境变量。
  3. 录音权限:
    • 确保小程序已获取录音权限。