更新记录

1.0.1(2024-12-27) 下载此版本

优化使用方法

1.0.0(2024-12-27) 下载此版本

init

1.0.2(2024-12-27) 下载此版本

init

查看更多

平台兼容性

Vue2 Vue3
App 快应用 微信小程序 支付宝小程序 百度小程序 字节小程序 QQ小程序
HBuilderX 3.1.0 app-vue
钉钉小程序 快手小程序 飞书小程序 京东小程序 鸿蒙元服务
×
H5-Safari Android Browser 微信浏览器(Android) QQ浏览器(Android) Chrome IE Edge Firefox PC-Safari

uniapp 文本转语音

  • 基于 Minimax API 的 UniApp 文本转语音工具,支持文本分段、队列播放、暂停恢复等功能。
  • 目前只内置了 Minimax文本转语音
  • Minimax 的语音生成技术以其自然、情感丰富和实时性强而著称

API_KEY、GroupId 获取方法

https://platform.minimaxi.com/user-center/basic-information/interface-key

NPM 地址

特性

  • 🎯 自动文本分段处理
  • 🔄 队列播放管理
  • ⏯️ 支持暂停/恢复
  • 📦 轻量级封装
  • 🎨 完整的事件系统
  • 💫 支持长文本处理

安装 (推荐 npm 安装,而不是导入)

npm install uniapp-text-to-speech

基础使用

import SpeechSynthesisUtil from 'uniapp-text-to-speech';
// 初始化
const tts = new SpeechSynthesisUtil({
    API_KEY: 'your_minimax_api_key', // Minimax API密钥
    GroupId: 'your_group_id', // Minimax 组ID
    MAX_QUEUE_LENGTH: 3, // 可选:音频队列最大长度
    modelConfig: { // 可选:音频生成配置
        model: 'speech-01-240228',
        voice_setting: {
            "voice_id": "female-tianmei",
            "speed": 1,
            "vol": 1,
            }
        },
        // 其他配置...
    }
});

// 基础播放
try {
    await tts.textToSpeech('你好,世界!');
} catch (error) {
    console.error('语音合成失败:', error);
}

分段使用

  • 模拟 AI 大模型流式返回数据,自动会处理合成分段:["你好","我是一个ai机器人","我的名字叫做阿强"]
import SpeechSynthesisUtil from "uniapp-text-to-speech";
// 初始化
const tts = new SpeechSynthesisUtil({
  API_KEY: "your_minimax_api_key", // Minimax API密钥
  GroupId: "your_group_id", // Minimax 组ID
});

const mockTexts = ['你好,', '我是', '人工智能助手,', '很高兴认识你!'];

try {
    for (const text of mockTexts) {
        await tts.processText(text);
    }
    await tts.flushRemainingText();
} catch (error) {
    addLog(`分段播放失败: ${error.message}`);
}

高级功能

1. 事件监听

import { EventType } from "uniapp-text-to-speech";
// 监听合成开始
tts.on(EventType.SYNTHESIS_START, ({ text }) => {
  console.log(`开始合成文本: ${text}`);
});

// 监听播放开始
tts.on(EventType.AUDIO_PLAY, ({ currentText }) => {
  console.log(`正在播放: ${currentText}`);
  status.value = "播放中";
});

// 监听播放结束
tts.on(EventType.AUDIO_END, ({ finishedText }) => {
  console.log(`播放完成: ${finishedText}`);
  status.value = "就绪";
  progress.value = 100;
});

// 监听错误
tts.on(EventType.ERROR, ({ error }) => {
  console.log(`错误: ${error.message}`);
  status.value = "错误";
});

// 监听暂停
tts.on(EventType.PAUSE, () => {
  console.log("播放已暂停");
  status.value = "已暂停";
  isPaused.value = true;
});

// 监听恢复
tts.on(EventType.RESUME, () => {
  console.log("播放已恢复");
  status.value = "播放中";
  isPaused.value = false;
});

2. 暂停和恢复

// 暂停播放
tts.pause();
// 恢复播放
tts.resume();
// 切换播放/暂停状态
tts.togglePlay();

3. 长文本分段处理

// 自动按标点符号分段处理长文本
await tts.processText("这是第一句话。这是第二句话!这是第三句话?");
// 强制处理剩余未播放的文本
await tts.flushRemainingText();
// 重置文本处理器
tts.resetTextProcessor();

4. 状态管理

// 获取当前状态
const state = tts.getState();
console.log("是否正在播放:", state.isPlaying);
console.log("是否已暂停:", state.isPaused);
// 重置所有状态
tts.reset();

API 文档

构造函数选项

参数 类型 必填 说明
API_KEY string Minimax API 密钥
GroupId string Minimax 组 ID
MAX_QUEUE_LENGTH number 音频队列最大长度,默认为 3
modelConfig object 合成语音配置,参考minimaxi

事件类型

事件名 说明 回调参数
SYNTHESIS_START 开始合成 { text: string }
SYNTHESIS_END 合成结束 { text: string }
AUDIO_PLAY 开始播放单个音频片段 { text: string }
AUDIO_END 所有音频播放完成 { text: string }
PAUSE 暂停播放 -
RESUME 恢复播放 -
ERROR 发生错误 { error: Error }

事件说明

  • AUDIO_PLAY: 每个音频片段开始播放时触发
  • AUDIO_END: 仅在所有音频片段都播放完成后触发一次

使用示例

import SpeechSynthesisUtil, { EventType } from "uniapp-text-to-speech";

const tts = new SpeechSynthesisUtil({
  API_KEY: "your_minimax_api_key",
  GroupId: "your_group_id",
  modelConfig: {
    model: "speech-01-240228",
    voice_setting: {
      voice_id: "female-yujie", // 默认使用悦姐声音
      speed: 1.2,
      vol: 1,
    },
  },
});

// 监听播放完成事件
tts.on(EventType.AUDIO_END, ({ text }) => {
  console.log("所有音频播放完成,最后播放的文本:", text);
});

// 分段播放示例
async function playMultipleTexts() {
  await tts.processText("第一段文本");
  await tts.processText("第二段文本");
  await tts.flushRemainingText(); // 确保所有文本都被处理
}

// 重置播放状态
tts.reset();

注意事项

  1. 需要先在 Minimax 申请 API_KEY 和 GroupId
  2. 文本会自动按标点符号分段处理,支持的标点符号优先级:
    • 高优先级:。!?
    • 中优先级:;:
    • 低优先级:,、
  3. 音频队列最大长度默认为 3,可以通过构造函数参数修改
  4. AUDIO_END 事件只会在所有音频片段播放完成后触发一次
  5. 使用 reset() 方法可以重置所有播放状态和计数器

主要的方

方法名 说明 参数 返回值
textToSpeech 文本转语音 text: string Promise
processText 处理长文本 text: string Promise
pause 暂停播放 - void
resume 恢复播放 - void
togglePlay 切换播放状态 - void
reset 重置所有状态 - void
on 添加事件监听 event: EventType, callback: Function void
off 移除事件监听 event: EventType, callback: Function void

完整的示例代码

<template>
    <div class="speech-demo">
        <!-- 基础演示区域 -->
        <section class="demo-section">
            <h3>基础演示</h3>
            <textarea v-model="basicText" placeholder="请输入要转换的文本"></textarea>
            <button @click="handleBasicSpeech">开始播放</button>
        </section>

        <!-- 分段演示区域 -->
        <section class="demo-section">
            <h3>分段播放演示</h3>
            <div class="segment-container">
                <div v-for="(text, index) in mockTexts" :key="index" class="segment">
                    <span>{{ text }}</span>
                </div>
            </div>
            <button @click="handleSegmentSpeech">分段播放</button>
        </section>

        <!-- 高级功能演示区域 -->
        <section class="demo-section">
            <h3>高级功能演示</h3>
            <div class="controls">
                <button @click="handleTogglePlay">{{ isPaused ? '继续' : '暂停' }}</button>
                <button @click="handleReset">重置</button>
            </div>
            <div class="status">
                <p>当前状态: {{ status }}</p>
                <p>播放进度: {{ progress }}%</p>
            </div>
        </section>

        <!-- 事件日志区域 -->
        <section class="demo-section">
            <h3>事件日志</h3>
            <div class="log-container">
                <div v-for="(log, index) in eventLogs" :key="index" class="log-item">
                    {{ log }}
                </div>
            </div>
        </section>
    </div>
</template>

<script setup lang="ts">
    import { ref, onMounted, onBeforeUnmount } from 'vue';
    import SpeechSynthesisUtil, { EventType } from 'uniapp-text-to-speech';

    // 响应式状态
    const basicText = ref('你好,这是一个基础示例。');
    const mockTexts = ref(['你好,', '我是', '人工智能助手,', '很高兴认识你!']);
    const status = ref('就绪');
    const progress = ref(0);
    const isPaused = ref(false);
    const eventLogs = ref<string[]>([]);

    // 初始化语音工具
    const tts = new SpeechSynthesisUtil({
        API_KEY: 'your_minimax_api_key', // Minimax API密钥
        GroupId: 'your_group_id', // Minimax 组ID
        modelConfig: {
            model: 'speech-01-240228',
            voice_setting: {
                voice_id: "female-yujie",
                speed: 1,
                vol: 1
            }
        }
    });

    // 添加日志
    const addLog = (message : string) => {
        eventLogs.value.unshift(`${new Date().toLocaleTimeString()}: ${message}`);
        if (eventLogs.value.length > 10) {
            eventLogs.value.pop();
        }
    };

    // 设置事件监听
    const setupEventListeners = () => {
        // 监听合成开始
        tts.on(EventType.SYNTHESIS_START, ({ text }) => {
            addLog(`开始合成文本: ${text}`);
        });

        // 监听播放开始
        tts.on(EventType.AUDIO_PLAY, ({ currentText }) => {
            addLog(`正在播放: ${currentText}`);
            status.value = '播放中';
        });

        // 监听播放结束
        tts.on(EventType.AUDIO_END, ({ finishedText }) => {
            addLog(`播放完成: ${finishedText}`);
            status.value = '就绪';
            progress.value = 100;
        });

        // 监听错误
        tts.on(EventType.ERROR, ({ error }) => {
            addLog(`错误: ${error.message}`);
            status.value = '错误';
        });

        // 监听暂停
        tts.on(EventType.PAUSE, () => {
            addLog('播放已暂停');
            status.value = '已暂停';
            isPaused.value = true;
        });

        // 监听恢复
        tts.on(EventType.RESUME, () => {
            addLog('播放已恢复');
            status.value = '播放中';
            isPaused.value = false;
        });
    };

    // 基础播放示例
    const handleBasicSpeech = async () => {
        try {
            await tts.textToSpeech(basicText.value);
        } catch (error) {
            addLog(`播放失败: ${error.message}`);
        }
    };

    // 分段播放示例
    const handleSegmentSpeech = async () => {
        try {
            for (const text of mockTexts.value) {
                await tts.processText(text);
            }
            await tts.flushRemainingText();
        } catch (error) {
            addLog(`分段播放失败: ${error.message}`);
        }
    };

    // 切换播放/暂停
    const handleTogglePlay = () => {
        tts.togglePlay();
    };

    // 重置播放
    const handleReset = () => {
        tts.reset();
        status.value = '就绪';
        progress.value = 0;
        isPaused.value = false;
        addLog('已重置所有状态');
    };

    // 生命周期钩子
    onMounted(() => {
        setupEventListeners();
    });

    onBeforeUnmount(() => {
        tts.reset();
    });
</script>

<style scoped>
    .speech-demo {
        padding: 20px;
        max-width: 800px;
        margin: 0 auto;
    }

    .demo-section {
        margin-bottom: 30px;
        padding: 20px;
        border: 1px solid #eee;
        border-radius: 8px;
    }

    h3 {
        margin-top: 0;
        margin-bottom: 15px;
        color: #333;
    }

    textarea {
        width: 100%;
        height: 100px;
        padding: 10px;
        margin-bottom: 10px;
        border: 1px solid #ddd;
        border-radius: 4px;
        resize: vertical;
    }

    button {
        padding: 8px 16px;
        margin-right: 10px;
        border: none;
        border-radius: 4px;
        background-color: #4CAF50;
        color: white;
        cursor: pointer;
    }

    button:disabled {
        background-color: #cccccc;
    }

    .segment-container {
        margin-bottom: 15px;
    }

    .segment {
        display: inline-block;
        padding: 5px 10px;
        margin: 5px;
        background-color: #f5f5f5;
        border-radius: 4px;
    }

    .controls {
        margin-bottom: 15px;
    }

    .status {
        padding: 10px;
        background-color: #f9f9f9;
        border-radius: 4px;
    }

    .log-container {
        height: 200px;
        overflow-y: auto;
        padding: 10px;
        background-color: #f5f5f5;
        border-radius: 4px;
    }

    .log-item {
        padding: 5px;
        border-bottom: 1px solid #eee;
        font-family: monospace;
    }
</style>

许可证

MIT

作者

乔振 qiaozhenleve@gmail.com

隐私、权限声明

1. 本插件需要申请的系统权限列表:

2. 本插件采集的数据、发送的服务器地址、以及数据用途说明:

3. 本插件是否包含广告,如包含需详细说明广告表达方式、展示频率:

许可协议

MIT协议

暂无用户评论。

使用中有什么不明白的地方,就向插件作者提问吧~ 我要提问