feat: 增加AI配置文件与TTS自动朗读,修复二级页面返回按钮与音频播放
This commit is contained in:
@@ -10,11 +10,26 @@ import '../../widgets/app_widgets.dart';
|
||||
import '../../widgets/lexicon_lookup.dart';
|
||||
|
||||
class DialogueScenePage extends StatelessWidget {
|
||||
const DialogueScenePage({super.key, required this.onStart});
|
||||
const DialogueScenePage({
|
||||
super.key,
|
||||
required this.onStart,
|
||||
this.onBack,
|
||||
});
|
||||
final VoidCallback onStart;
|
||||
final VoidCallback? onBack;
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) => AppPage(
|
||||
appBar: onBack != null
|
||||
? AppBar(
|
||||
leading: IconButton(
|
||||
icon: const Icon(Icons.arrow_back),
|
||||
tooltip: "返回",
|
||||
onPressed: onBack,
|
||||
),
|
||||
title: const Text("AI 情境对话"),
|
||||
)
|
||||
: null,
|
||||
child: SpacedColumn(
|
||||
children: [
|
||||
const Eyebrow('按当前水平推荐'),
|
||||
@@ -157,10 +172,17 @@ class _DialoguePageState extends State<DialoguePage> {
|
||||
} else {
|
||||
turns.add(DialogueTurn(text: script.prompts.first, isLearner: false));
|
||||
}
|
||||
WidgetsBinding.instance.addPostFrameCallback((_) {
|
||||
if (mounted) {
|
||||
_playLatestAi(slow: false);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
@override
|
||||
void dispose() {
|
||||
VoiceService.instance.stopSpeaking();
|
||||
VoiceService.instance.stopListening();
|
||||
VoiceService.instance.stopRecordingPlayback();
|
||||
if (!widget.state.keepRecordings) {
|
||||
VoiceService.instance.deleteRecording(recordingPath);
|
||||
@@ -217,20 +239,21 @@ class _DialoguePageState extends State<DialoguePage> {
|
||||
.toList(),
|
||||
);
|
||||
if (!mounted) return;
|
||||
final replyText = aiResponse?.reply ??
|
||||
(nextStage < script.prompts.length
|
||||
? script.prompts[nextStage]
|
||||
: 'Wonderful — nice meeting you!');
|
||||
setState(() {
|
||||
turns.add(
|
||||
DialogueTurn(
|
||||
text:
|
||||
aiResponse?.reply ??
|
||||
(nextStage < script.prompts.length
|
||||
? script.prompts[nextStage]
|
||||
: 'Wonderful — nice meeting you!'),
|
||||
text: replyText,
|
||||
isLearner: false,
|
||||
),
|
||||
);
|
||||
waitingForReply = false;
|
||||
});
|
||||
_saveDraft();
|
||||
VoiceService.instance.speak(replyText);
|
||||
}
|
||||
|
||||
void _saveDraft() {
|
||||
@@ -417,6 +440,11 @@ class _DialoguePageState extends State<DialoguePage> {
|
||||
final finished = stage == script.prompts.length;
|
||||
return AppPage(
|
||||
appBar: AppBar(
|
||||
leading: IconButton(
|
||||
icon: const Icon(Icons.arrow_back),
|
||||
tooltip: "返回",
|
||||
onPressed: () => widget.onFinished(null),
|
||||
),
|
||||
title: Text(
|
||||
'${widget.isLessonDialogue ? '课程对话' : '初次见面'} · ${finished ? 4 : stage + 1} / 4',
|
||||
),
|
||||
@@ -446,7 +474,37 @@ class _DialoguePageState extends State<DialoguePage> {
|
||||
: AppColors.softGreen,
|
||||
borderRadius: BorderRadius.circular(15),
|
||||
),
|
||||
child: LexiconText(turn.text, state: widget.state),
|
||||
child: Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: [
|
||||
LexiconText(turn.text, state: widget.state),
|
||||
if (!turn.isLearner) ...[
|
||||
const SizedBox(height: 6),
|
||||
GestureDetector(
|
||||
onTap: () => VoiceService.instance.speak(turn.text),
|
||||
child: const Row(
|
||||
mainAxisSize: MainAxisSize.min,
|
||||
children: [
|
||||
Icon(
|
||||
Icons.volume_up_outlined,
|
||||
size: 16,
|
||||
color: AppColors.green,
|
||||
),
|
||||
SizedBox(width: 4),
|
||||
Text(
|
||||
"播放",
|
||||
style: TextStyle(
|
||||
fontSize: 12,
|
||||
color: AppColors.green,
|
||||
fontWeight: FontWeight.w500,
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
],
|
||||
],
|
||||
),
|
||||
),
|
||||
);
|
||||
},
|
||||
@@ -612,13 +670,24 @@ class DialogueSummaryPage extends StatelessWidget {
|
||||
required this.onHome,
|
||||
required this.onLesson,
|
||||
required this.onRetry,
|
||||
this.onBack,
|
||||
});
|
||||
final DialogueSummaryData summary;
|
||||
final VoidCallback onHome;
|
||||
final VoidCallback onLesson;
|
||||
final VoidCallback onRetry;
|
||||
final VoidCallback? onBack;
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) => AppPage(
|
||||
appBar: AppBar(
|
||||
leading: IconButton(
|
||||
icon: const Icon(Icons.arrow_back),
|
||||
tooltip: "返回",
|
||||
onPressed: onBack ?? onHome,
|
||||
),
|
||||
title: const Text("对话完成"),
|
||||
),
|
||||
child: SpacedColumn(
|
||||
children: [
|
||||
const Eyebrow('对话完成'),
|
||||
|
||||
Reference in New Issue
Block a user