AI-一分钟生成一个文本转语音的小工具(react版)
AI生成一个文本转语音的小工具
·
1、提示词
(1)轻量、适合很老的Macbook Pro;(2)有中文支持,且生成语音高质量;(3)免费、开源;(4)方便编程小白使用;(5)不使用内置的UI样式,单独创建并使用scss文件来引入需要使用的样式文件;
2、生成预览效果
创建了一个基于Web Speech API的文本转语音工具,具有语音选择、语速调节、音调调节等功能,界面简洁直观,完全免费且支持中文。
3、生成文件
依赖安装:lucide-react@latest
1、index.jsx
import { useState, useEffect } from "react";
import { Play, Pause, Square } from "lucide-react";
import "../styles/index.scss";
const Index = () => {
const [text, setText] = useState("");
const [voices, setVoices] = useState([]);
const [selectedVoice, setSelectedVoice] = useState("");
const [rate, setRate] = useState(1.0);
const [pitch, setPitch] = useState(1.0);
const [isPlaying, setIsPlaying] = useState(false);
useEffect(() => {
const loadVoices = () => {
const availableVoices = window.speechSynthesis.getVoices();
setVoices(availableVoices);
const chineseVoice = availableVoices.find(voice => voice.lang.includes('zh'));
setSelectedVoice(chineseVoice?.name || availableVoices[0]?.name);
};
loadVoices();
window.speechSynthesis.onvoiceschanged = loadVoices;
return () => {
window.speechSynthesis.cancel();
};
}, []);
const speak = () => {
if (!text) return;
window.speechSynthesis.cancel();
const utterance = new SpeechSynthesisUtterance(text);
utterance.voice = voices.find(voice => voice.name === selectedVoice);
utterance.rate = rate;
utterance.pitch = pitch;
utterance.onstart = () => setIsPlaying(true);
utterance.onend = () => setIsPlaying(false);
utterance.onerror = () => setIsPlaying(false);
window.speechSynthesis.speak(utterance);
};
const pause = () => {
window.speechSynthesis.pause();
setIsPlaying(false);
};
const resume = () => {
window.speechSynthesis.resume();
setIsPlaying(true);
};
const stop = () => {
window.speechSynthesis.cancel();
setIsPlaying(false);
};
return (
<div className="text-to-speech">
<div className="text-to-speech__container">
<h1 className="text-to-speech__title">文本转语音工具</h1>
<div>
<textarea
className="text-to-speech__textarea"
placeholder="请输入要转换的文本..."
value={text}
onChange={(e) => setText(e.target.value)}
/>
<div className="text-to-speech__controls">
<div className="text-to-speech__control-group">
<label className="text-to-speech__label">选择声音:</label>
<select
className="text-to-speech__select"
value={selectedVoice}
onChange={(e) => setSelectedVoice(e.target.value)}
>
{voices.map((voice) => (
<option key={voice.name} value={voice.name}>
{`${voice.name} (${voice.lang})`}
</option>
))}
</select>
</div>
<div className="text-to-speech__control-group">
<label className="text-to-speech__label">
语速 ({rate.toFixed(1)}):
</label>
<input
type="range"
className="text-to-speech__slider"
min="0.5"
max="2"
step="0.1"
value={rate}
onChange={(e) => setRate(parseFloat(e.target.value))}
/>
</div>
<div className="text-to-speech__control-group">
<label className="text-to-speech__label">
音调 ({pitch.toFixed(1)}):
</label>
<input
type="range"
className="text-to-speech__slider"
min="0.5"
max="2"
step="0.1"
value={pitch}
onChange={(e) => setPitch(parseFloat(e.target.value))}
/>
</div>
</div>
<div className="text-to-speech__buttons">
{!isPlaying ? (
<button
onClick={speak}
className="text-to-speech__button text-to-speech__button--play"
>
<Play className="w-5 h-5 mr-2" />
播放
</button>
) : (
<button
onClick={pause}
className="text-to-speech__button text-to-speech__button--pause"
>
<Pause className="w-5 h-5 mr-2" />
暂停
</button>
)}
<button
onClick={stop}
className="text-to-speech__button text-to-speech__button--stop"
>
<Square className="w-5 h-5 mr-2" />
停止
</button>
</div>
</div>
<div className="text-to-speech__tips">
<p>提示:此工具使用浏览器内置的 Web Speech API,完全免费且无需安装。</p>
<p>支持中文和多种语言,可调节语速和音调。</p>
</div>
</div>
</div>
);
};
export default Index;
2、index.scss
// 变量定义
$primary-color: #3b82f6;
$secondary-color: #f3f4f6;
$text-color: #1f2937;
$border-color: #e5e7eb;
// 混合器
@mixin flex-center {
display: flex;
justify-content: center;
align-items: center;
}
@mixin button-base {
padding: 0.5rem 1.5rem;
border-radius: 0.375rem;
font-weight: 500;
cursor: pointer;
transition: all 0.2s;
@include flex-center;
}
// 全局样式
.text-to-speech {
min-height: 100vh;
padding: 2rem;
background: linear-gradient(180deg, #f9fafb 0%, #f3f4f6 100%);
&__container {
max-width: 42rem;
margin: 0 auto;
background: white;
border-radius: 0.5rem;
box-shadow: 0 4px 6px -1px rgba(0, 0, 0, 0.1);
padding: 2rem;
}
&__title {
font-size: 1.875rem;
font-weight: 700;
text-align: center;
color: $text-color;
margin-bottom: 2rem;
}
&__textarea {
width: 100%;
min-height: 200px;
padding: 1rem;
border: 2px solid $border-color;
border-radius: 0.375rem;
font-size: 1.125rem;
resize: vertical;
&:focus {
border-color: $primary-color;
outline: none;
}
}
&__controls {
display: grid;
grid-template-columns: 1fr;
gap: 1.5rem;
margin-top: 1.5rem;
@media (min-width: 768px) {
grid-template-columns: repeat(2, 1fr);
}
}
&__control-group {
display: flex;
flex-direction: column;
gap: 0.75rem;
}
&__label {
font-size: 0.875rem;
font-weight: 500;
color: $text-color;
}
&__select {
width: 100%;
padding: 0.5rem;
border: 1px solid $border-color;
border-radius: 0.375rem;
background-color: white;
}
&__slider {
width: 100%;
height: 4px;
background: $border-color;
border-radius: 2px;
appearance: none;
&::-webkit-slider-thumb {
appearance: none;
width: 16px;
height: 16px;
background: $primary-color;
border-radius: 50%;
cursor: pointer;
}
}
&__buttons {
@include flex-center;
gap: 1rem;
margin-top: 2rem;
}
&__button {
@include button-base;
&--play {
background-color: $primary-color;
color: white;
&:hover {
background-color: darken($primary-color, 10%);
}
}
&--pause {
background-color: #ca8a04;
color: white;
&:hover {
background-color: darken(#ca8a04, 10%);
}
}
&--stop {
border: 2px solid $border-color;
color: $text-color;
&:hover {
background-color: $secondary-color;
}
}
}
&__tips {
text-align: center;
color: #6b7280;
font-size: 0.875rem;
margin-top: 2rem;
p {
margin: 0.5rem 0;
}
}
}
3、全局文件 index.css
@import './styles/index.scss';
* {
margin: 0;
padding: 0;
box-sizing: border-box;
}
body {
font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, 'Helvetica Neue', Arial, sans-serif;
-webkit-font-smoothing: antialiased;
-moz-osx-font-smoothing: grayscale;
}
更多推荐
所有评论(0)