提交 6f0554ab authored 作者: songchuancai's avatar songchuancai

调整语速

上级 ed9e49bf
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'package:flutter_tts/flutter_tts.dart';
import 'package:flutter_tts/flutter_tts.dart'; import '../models/chat_message.dart';
import 'package:flutter_markdown/flutter_markdown.dart';
import '../models/chat_message.dart'; import '../pallete.dart';
class ChatBubble extends StatefulWidget {
final ChatMessage message;
import 'package:flutter_markdown/flutter_markdown.dart';
final bool isTyping;
const ChatBubble({
import '../pallete.dart'; Key? key,
required this.message,
this.isTyping = false,
}) : super(key: key);
class ChatBubble extends StatefulWidget {
@override
final ChatMessage message; State<ChatBubble> createState() => _ChatBubbleState();
}
final bool isTyping;
class _ChatBubbleState extends State<ChatBubble> {
final FlutterTts flutterTts = FlutterTts();
const ChatBubble({ bool isPlaying = false;
Key? key, @override
void initState() {
required this.message, super.initState();
this.isTyping = false, flutterTts.setLanguage("zh-CN");
}) : super(key: key); // 设置语速
flutterTts.setSpeechRate(2.5);
@override // 设置音调
State<ChatBubble> createState() => _ChatBubbleState(); flutterTts.setPitch(1.0);
} flutterTts.setCompletionHandler(() {
if (mounted) {
setState(() {
isPlaying = false;
class _ChatBubbleState extends State<ChatBubble> { });
}
final FlutterTts flutterTts = FlutterTts(); });
flutterTts.setCancelHandler(() {
if (mounted) {
bool isPlaying = false; setState(() {
isPlaying = false;
});
}
@override });
void initState() { flutterTts.setErrorHandler((error) {
if (mounted) {
super.initState(); setState(() {
isPlaying = false;
});
}
flutterTts.setLanguage("zh-CN"); });
}
Future<void> _handlePlayStop() async {
// 设置语速 if (isPlaying) {
// 如果正在播放,则停止
await flutterTts.stop();
flutterTts.setSpeechRate(2.5);
if (mounted) {
setState(() {
isPlaying = false;
// 设置音调 });
}
} else {
// 如果未播放,则开始播放
flutterTts.setPitch(0.8);
if (mounted) {
setState(() {
isPlaying = true;
flutterTts.setCompletionHandler(() { });
}
if (mounted) {
try {
setState(() { await flutterTts.speak(widget.message.text);
} catch (e) {
isPlaying = false; print('TTS Error: $e');
}); if (mounted) {
setState(() {
} isPlaying = false;
});
}); }
}
}
}
flutterTts.setCancelHandler(() {
@override
if (mounted) { Widget build(BuildContext context) {
return Align(
setState(() { alignment: widget.message.isUserMessage
? Alignment.centerRight
isPlaying = false; : Alignment.centerLeft,
child: Container(
}); margin: const EdgeInsets.symmetric(vertical: 4),
padding: const EdgeInsets.all(12),
} constraints: BoxConstraints(
maxWidth: MediaQuery.of(context).size.width * 0.7,
}); ),
decoration: BoxDecoration(
color: widget.message.isUserMessage
? Pallete.firstSuggestionBoxColor
flutterTts.setErrorHandler((error) { : Pallete.assistantCircleColor,
borderRadius: BorderRadius.circular(15).copyWith(
if (mounted) { bottomRight: widget.message.isUserMessage ? Radius.zero : null,
bottomLeft: !widget.message.isUserMessage ? Radius.zero : null,
setState(() { ),
),
isPlaying = false; child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
}); children: [
widget.message.isUserMessage
} ? Text(
widget.message.text,
}); style: const TextStyle(
color: Colors.white,
} fontSize: 16,
),
)
: MarkdownBody(
Future<void> _handlePlayStop() async { data: widget.message.text,
selectable: true,
if (isPlaying) { styleSheet: MarkdownStyleSheet(
p: const TextStyle(
// 如果正在播放,则停止 color: Colors.black,
fontSize: 16,
),
code: const TextStyle(
await flutterTts.stop(); color: Colors.white,
fontFamily: 'monospace',
fontSize: 14,
height: 1.5,
if (mounted) { backgroundColor: Colors.transparent,
),
setState(() { codeblockPadding: const EdgeInsets.all(16),
codeblockDecoration: BoxDecoration(
isPlaying = false; color: const Color(0xFF1E1E1E),
borderRadius: BorderRadius.circular(8),
}); ),
blockquote: const TextStyle(
} color: Colors.black87,
fontSize: 16,
} else { height: 1.5,
),
// 如果未播放,则开始播放 blockquoteDecoration: BoxDecoration(
border: Border(
left: BorderSide(
color: Colors.grey[300]!,
if (mounted) { width: 4,
),
setState(() { ),
),
isPlaying = true; listBullet: const TextStyle(color: Colors.black87),
),
}); ),
if (!widget.message.isUserMessage && !widget.isTyping) ...[
} const SizedBox(height: 8),
Row(
mainAxisSize: MainAxisSize.min,
children: [
try { IconButton(
icon: Icon(
await flutterTts.speak(widget.message.text); isPlaying ? Icons.stop_circle : Icons.play_circle,
color: Colors.black87,
} catch (e) { size: 20,
),
print('TTS Error: $e'); constraints: const BoxConstraints(
minWidth: 32,
minHeight: 32,
),
if (mounted) { padding: EdgeInsets.zero,
onPressed: _handlePlayStop,
setState(() { ),
if (isPlaying)
isPlaying = false; Text(
'正在播放...',
}); style: TextStyle(
color: Colors.black87,
} fontSize: 12,
),
} ),
],
} ),
],
} ],
),
),
);
@override }
Widget build(BuildContext context) { @override
void dispose() {
return Align( flutterTts.stop();
alignment: widget.message.isUserMessage super.dispose();
}
? Alignment.centerRight }
: Alignment.centerLeft,
child: Container(
margin: const EdgeInsets.symmetric(vertical: 4),
padding: const EdgeInsets.all(12),
constraints: BoxConstraints(
maxWidth: MediaQuery.of(context).size.width * 0.7,
),
decoration: BoxDecoration(
color: widget.message.isUserMessage
? Pallete.firstSuggestionBoxColor
: Pallete.assistantCircleColor,
borderRadius: BorderRadius.circular(15).copyWith(
bottomRight: widget.message.isUserMessage ? Radius.zero : null,
bottomLeft: !widget.message.isUserMessage ? Radius.zero : null,
),
),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
widget.message.isUserMessage
? Text(
widget.message.text,
style: const TextStyle(
color: Colors.white,
fontSize: 16,
),
)
: MarkdownBody(
data: widget.message.text,
selectable: true,
styleSheet: MarkdownStyleSheet(
p: const TextStyle(
color: Colors.black,
fontSize: 16,
),
code: const TextStyle(
color: Colors.white,
fontFamily: 'monospace',
fontSize: 14,
height: 1.5,
backgroundColor: Colors.transparent,
),
codeblockPadding: const EdgeInsets.all(16),
codeblockDecoration: BoxDecoration(
color: const Color(0xFF1E1E1E),
borderRadius: BorderRadius.circular(8),
),
blockquote: const TextStyle(
color: Colors.black87,
fontSize: 16,
height: 1.5,
),
blockquoteDecoration: BoxDecoration(
border: Border(
left: BorderSide(
color: Colors.grey[300]!,
width: 4,
),
),
),
listBullet: const TextStyle(color: Colors.black87),
),
),
if (!widget.message.isUserMessage && !widget.isTyping) ...[
const SizedBox(height: 8),
Row(
mainAxisSize: MainAxisSize.min,
children: [
IconButton(
icon: Icon(
isPlaying ? Icons.stop_circle : Icons.play_circle,
color: Colors.black87,
size: 20,
),
constraints: const BoxConstraints(
minWidth: 32,
minHeight: 32,
),
padding: EdgeInsets.zero,
onPressed: _handlePlayStop,
),
if (isPlaying)
Text(
'正在播放...',
style: TextStyle(
color: Colors.black87,
fontSize: 12,
),
),
],
),
],
],
),
),
);
}
@override
void dispose() {
flutterTts.stop();
super.dispose();
}
}
\ No newline at end of file
Markdown 格式
0%
您添加了 0 到此讨论。请谨慎行事。
请先完成此评论的编辑!
注册 或者 后发表评论