fix: 优化语音识别功能,增加转写中状态和错误处理

This commit is contained in:
qzl
2026-03-10 17:43:28 +08:00
parent f30bfc2006
commit 2ec0965322
2 changed files with 153 additions and 24 deletions
@@ -29,6 +29,8 @@ const _inputRadius = 24.0;
const _scrollDurationMs = 300;
const _rippleDurationMs = 1200;
const _recordingDotSize = 10.0;
const _transcribingSpinnerSize = 18.0;
const _transcribingStrokeWidth = 2.0;
/// 颜色常量
const _chatBgColor = Color(0xFFF8FAFC);
@@ -446,6 +448,8 @@ class _HomeScreenState extends State<HomeScreen>
Expanded(
child: _isRecording
? _buildListeningIndicator()
: _isTranscribing
? _buildTranscribingIndicator()
: TextField(
controller: _messageController,
minLines: 1,
@@ -474,15 +478,24 @@ class _HomeScreenState extends State<HomeScreen>
: _hasMessage
? () => _sendMessage(context)
: _startRecording,
child: Icon(
_isRecording || _hasMessage
? LucideIcons.send
: LucideIcons.mic,
size: _iconSize,
color: _isRecording || _hasMessage
? AppColors.blue600
: AppColors.slate500,
),
child: _isTranscribing
? const SizedBox(
width: _transcribingSpinnerSize,
height: _transcribingSpinnerSize,
child: CircularProgressIndicator(
strokeWidth: _transcribingStrokeWidth,
color: AppColors.blue600,
),
)
: Icon(
_isRecording || _hasMessage
? LucideIcons.send
: LucideIcons.mic,
size: _iconSize,
color: _isRecording || _hasMessage
? AppColors.blue600
: AppColors.slate500,
),
),
],
),
@@ -496,6 +509,7 @@ class _HomeScreenState extends State<HomeScreen>
Future<void> _sendMessage(BuildContext context) async {
final content = _messageController.text.trim();
if (content.isEmpty) return;
FocusScope.of(context).unfocus();
_messageController.clear();
context.read<ChatBloc>().sendMessage(content);
@@ -548,6 +562,27 @@ class _HomeScreenState extends State<HomeScreen>
);
}
Widget _buildTranscribingIndicator() {
return TweenAnimationBuilder<double>(
tween: Tween<double>(begin: 0.0, end: 1.0),
duration: const Duration(milliseconds: 180),
builder: (context, value, child) {
return Opacity(opacity: value, child: child);
},
child: const SizedBox(
key: ValueKey('transcribing_indicator'),
height: _inputMinHeight,
child: Align(
alignment: Alignment.centerLeft,
child: Text(
'语音识别中...',
style: TextStyle(fontSize: 14, color: AppColors.slate500),
),
),
),
);
}
Widget _buildWaveDot({required double scale}) {
return Transform.scale(
scale: scale,
@@ -599,13 +634,18 @@ class _HomeScreenState extends State<HomeScreen>
if (!mounted) {
return;
}
final normalizedTranscript = transcript.trim();
if (normalizedTranscript.isEmpty) {
Toast.show(context, '未识别到有效语音,请靠近麦克风并连续说话后重试', type: ToastType.error);
return;
}
_messageController.text = transcript;
_messageController.selection = TextSelection.fromPosition(
TextPosition(offset: transcript.length),
);
if (autoSendAfterTranscribe && transcript.trim().isNotEmpty) {
if (autoSendAfterTranscribe) {
_messageController.clear();
await _autoSendTranscript(transcript.trim());
await _autoSendTranscript(normalizedTranscript);
}
} catch (error) {
if (!mounted) {
@@ -613,11 +653,15 @@ class _HomeScreenState extends State<HomeScreen>
}
Toast.show(context, _readableError(error), type: ToastType.error);
} finally {
if (audioPath != null) {
final file = File(audioPath);
if (await file.exists()) {
await file.delete();
try {
if (audioPath != null) {
final file = File(audioPath);
if (await file.exists()) {
await file.delete();
}
}
} catch (_) {
// Ignore temp file cleanup errors to avoid blocking UI state recovery.
}
if (mounted) {
setState(() {