Web Speech API:浏览器端实现的:文字转语音,语音转文字

Web Speech API
在这里插入图片描述

Web Speech API简单介绍

两个重要功能
1、语音合成(文字转语音,输入一段文本,输出语音)
2、语音识别(语音转文字,通过麦克风朗读一段文本,输处文字)

这里只测试了 谷歌,火狐,IE  3个浏览器,用的都是最新版本,
手机用的安卓,苹果,自带的浏览器测试。

简单进行了测试后结果:
1、语音合成:
3端通用,PC,安卓H5(获取不到朗读人声选项),苹果H5,
2、语音识别,只有苹果H5端可以使用
兼容性没有深入研究,只是确保PC上能进行语音合成。

使用vue3进行测试

<template>
  <div id="app">
    <h1>Web Speech API 演示</h1>
    <div class="speech-control">
      <div class="recognition-section">
        <h3>语音识别</h3>
        <button @click="startRecognition" :disabled="isRecognizing">
          {{ isRecognizing ? '正在识别...' : '开始识别' }}
        </button>
        <div v-if="recognizedText" class="result">
          识别结果: {{ recognizedText }}
        </div>
      </div>

      <div class="synthesis-section">
        <h3>语音合成</h3>
        <div class="voice-selection">
          <h4>选择语音</h4>
          <div class="voice-list">
            <div v-for="voice in voices" :key="voice.name" class="voice-item">
              <input
                type="radio"
                :id="voice.name"
                :value="voice"
                v-model="selectedVoice"
                :name="'voice'"
              />
              <label :for="voice.name">
                {{ voice.name }} ({{ voice.lang }})
                <span v-if="voice.default" class="default-badge">默认</span>
              </label>
            </div>
          </div>
        </div>
        <div class="input-group">
          <input v-model="textToSpeak" placeholder="输入要朗读的文本" />
          <button @click="speak" :disabled="!textToSpeak">朗读</button>
        </div>
        <div class="controls">
          <button @click="pause">暂停</button>
          <button @click="resume">继续</button>
          <button @click="stop">停止</button>
        </div>
      </div>
    </div>
  </div>
</template>

<script setup>
import { ref, onMounted } from 'vue';
import { speechRecognition, speechSynthesis } from '@/utils/speechService';

const isRecognizing = ref(false);
const recognizedText = ref('');
const textToSpeak = ref('');
const voices = ref([]);
const selectedVoice = ref(null);

// 加载语音列表
const loadVoices = () => {
  // 获取可用的语音列表
  voices.value = speechSynthesis.getVoices();
  
  // 如果语音列表为空,等待voiceschanged事件
  if (voices.value.length === 0) {
    window.speechSynthesis.onvoiceschanged = () => {
      voices.value = speechSynthesis.getVoices();
      // 默认选择第一个中文语音
      const chineseVoice = voices.value.find(voice => voice.lang.includes('zh'));
      if (chineseVoice) {
        selectedVoice.value = chineseVoice;
      }
    };
  } else {
    // 默认选择第一个中文语音
    const chineseVoice = voices.value.find(voice => voice.lang.includes('zh'));
    if (chineseVoice) {
      selectedVoice.value = chineseVoice;
    }
  }
};

// 在组件挂载后加载语音列表
onMounted(() => {
  // 添加一个小延迟,确保浏览器完全准备好
  setTimeout(() => {
    loadVoices();
  }, 100);
});

const startRecognition = () => {
  isRecognizing.value = true;
  speechRecognition.start((result) => {
    recognizedText.value = result;
    isRecognizing.value = false;
  });
};

const speak = () => {
  speechSynthesis.speak(textToSpeak.value, {
    lang: 'zh-CN',
    pitch: 1,
    rate: 1,
    voice: selectedVoice.value
  });
};

const pause = () => {
  speechSynthesis.pause();
};

const resume = () => {
  speechSynthesis.resume();
};

const stop = () => {
  speechSynthesis.stop();
};
</script>

<style>
#app {
  font-family: Arial, sans-serif;
  -webkit-font-smoothing: antialiased;
  -moz-osx-font-smoothing: grayscale;
  text-align: center;
  color: #2c3e50;
  margin-top: 60px;
}

h1 {
  margin-bottom: 40px;
}

.speech-control {
  padding: 20px;
  max-width: 600px;
  margin: 0 auto;
}

.recognition-section,
.synthesis-section {
  margin-bottom: 30px;
  padding: 20px;
  border: 1px solid #ddd;
  border-radius: 8px;
}

.voice-selection {
  margin-bottom: 20px;
}

.voice-list {
  max-height: 200px;
  overflow-y: auto;
  border: 1px solid #eee;
  border-radius: 4px;
  padding: 10px;
}

.voice-item {
  margin-bottom: 8px;
  padding: 8px;
  border-radius: 4px;
  transition: background-color 0.2s;
}

.voice-item:hover {
  background-color: #f5f5f5;
}

.voice-item label {
  margin-left: 8px;
  cursor: pointer;
}

.default-badge {
  background-color: #4CAF50;
  color: white;
  padding: 2px 6px;
  border-radius: 4px;
  font-size: 12px;
  margin-left: 8px;
}

.input-group {
  display: flex;
  gap: 10px;
  margin-bottom: 15px;
}

input[type="text"] {
  flex: 1;
  padding: 8px;
  border: 1px solid #ddd;
  border-radius: 4px;
}

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

button:disabled {
  background-color: #cccccc;
  cursor: not-allowed;
}

.controls {
  display: flex;
  gap: 10px;
}

.result {
  margin-top: 15px;
  padding: 10px;
  background-color: #f5f5f5;
  border-radius: 4px;
}
</style>

speechService.js

// 语音识别服务
class SpeechRecognitionService {
    constructor() {
        this.recognition = null;
        this.isSupported = 'webkitSpeechRecognition' in window || 'SpeechRecognition' in window;

        if (this.isSupported) {
            const SpeechRecognition = window.SpeechRecognition || window.webkitSpeechRecognition;
            this.recognition = new SpeechRecognition();
            this.recognition.continuous = false;
            this.recognition.interimResults = false;
            this.recognition.lang = 'zh-CN';
        }
    }

    start(callback) {
        if (!this.isSupported) {
            console.error('您的浏览器不支持语音识别');
            return;
        }

        this.recognition.onresult = (event) => {
            const result = event.results[0][0].transcript;
            callback(result);
        };

        this.recognition.onerror = (event) => {
            console.error('语音识别错误:', event.error);
        };

        this.recognition.start();
    }

    stop() {
        if (this.recognition) {
            this.recognition.stop();
        }
    }
}

// 语音合成服务
class SpeechSynthesisService {
    constructor() {
        this.synthesis = window.speechSynthesis;
        this.isSupported = 'speechSynthesis' in window;
        this.voices = [];
        this.loadVoices();
    }

    loadVoices() {
        if (!this.isSupported) return;

        // 获取所有可用的语音
        this.voices = this.synthesis.getVoices();

        // 如果语音列表为空,等待voiceschanged事件
        if (this.voices.length === 0) {
            this.synthesis.onvoiceschanged = () => {
                this.voices = this.synthesis.getVoices();
            };
        }
    }

    getVoices() {
        return this.voices;
    }

    speak(text, options = {}) {
        if (!this.isSupported) {
            console.error('您的浏览器不支持语音合成');
            return;
        }

        const utterance = new SpeechSynthesisUtterance(text);

        // 设置语音参数
        utterance.lang = options.lang || 'zh-CN';
        utterance.pitch = options.pitch || 1;
        utterance.rate = options.rate || 1;
        utterance.volume = options.volume || 1;

        // 设置选择的语音
        if (options.voice) {
            utterance.voice = options.voice;
        }

        this.synthesis.speak(utterance);
    }

    stop() {
        if (this.synthesis) {
            this.synthesis.cancel();
        }
    }

    pause() {
        if (this.synthesis) {
            this.synthesis.pause();
        }
    }

    resume() {
        if (this.synthesis) {
            this.synthesis.resume();
        }
    }
}

export const speechRecognition = new SpeechRecognitionService();
export const speechSynthesis = new SpeechSynthesisService();

vue

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值