Browse Source

feat(message_bubble): 使用Markdown渲染AI消息

为AI消息添加Markdown渲染支持,提升消息内容的可读性和格式化效果。用户消息仍保持普通文本显示。
weicu
lxm 1 year ago
parent
commit
cad2bc4f05
  1. 189
      lib/modules/agent/views/message_bubble.dart

189
lib/modules/agent/views/message_bubble.dart

@ -1,10 +1,12 @@
import 'package:common_utils/common_utils.dart'; import 'package:common_utils/common_utils.dart';
import 'package:deep_voice/modules/agent/views/message_bubble_navigation.dart'; import 'package:deep_voice/modules/agent/views/message_bubble_navigation.dart';
import 'weather_card.dart';
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'package:get/get.dart'; import 'package:get/get.dart';
import 'package:intl/intl.dart'; import 'package:intl/intl.dart';
import 'package:get_storage/get_storage.dart'; import 'package:get_storage/get_storage.dart';
import 'dart:io'; import 'dart:io';
import 'package:flutter_markdown/flutter_markdown.dart';
import '../controllers/agent_controller.dart'; import '../controllers/agent_controller.dart';
@ -120,63 +122,63 @@ class MessageBubble extends GetView<AgentController> {
} }
/// 构建头像 /// 构建头像
Widget _buildAvatar(bool isUser, BuildContext context) { // Widget _buildAvatar(bool isUser, BuildContext context) {
if (isUser) { // if (isUser) {
final storage = GetStorage(); // final storage = GetStorage();
final localAvatarPath = storage.read<String>('local_avatar') ?? ''; // final localAvatarPath = storage.read<String>('local_avatar') ?? '';
return Container( // return Container(
width: 36, // width: 36,
height: 36, // height: 36,
decoration: BoxDecoration( // decoration: BoxDecoration(
color: localAvatarPath.isEmpty ? Colors.grey[300] : null, // color: localAvatarPath.isEmpty ? Colors.grey[300] : null,
borderRadius: BorderRadius.circular(18), // borderRadius: BorderRadius.circular(18),
boxShadow: [ // boxShadow: [
BoxShadow( // BoxShadow(
color: Colors.black.withOpacity(0.05), // color: Colors.black.withOpacity(0.05),
blurRadius: 2, // blurRadius: 2,
offset: const Offset(0, 1), // offset: const Offset(0, 1),
), // ),
], // ],
), // ),
child: localAvatarPath.isNotEmpty // child: localAvatarPath.isNotEmpty
? ClipRRect( // ? ClipRRect(
borderRadius: BorderRadius.circular(18), // borderRadius: BorderRadius.circular(18),
child: Image.file( // child: Image.file(
File(localAvatarPath), // File(localAvatarPath),
fit: BoxFit.cover, // fit: BoxFit.cover,
), // ),
) // )
: Icon( // : Icon(
Icons.person, // Icons.person,
color: Colors.grey[700], // color: Colors.grey[700],
size: 20, // size: 20,
), // ),
); // );
} else { // } else {
// AI头像保持不变 // // AI头像保持不变
return Container( // return Container(
width: 36, // width: 36,
height: 36, // height: 36,
decoration: BoxDecoration( // decoration: BoxDecoration(
color: Theme.of(context).primaryColor, // color: Theme.of(context).primaryColor,
borderRadius: BorderRadius.circular(18), // borderRadius: BorderRadius.circular(18),
boxShadow: [ // boxShadow: [
BoxShadow( // BoxShadow(
color: Colors.black.withOpacity(0.05), // color: Colors.black.withOpacity(0.05),
blurRadius: 2, // blurRadius: 2,
offset: const Offset(0, 1), // offset: const Offset(0, 1),
), // ),
], // ],
), // ),
child: Icon( // child: Icon(
Icons.smart_toy_outlined, // Icons.smart_toy_outlined,
color: Colors.white, // color: Colors.white,
size: 20, // size: 20,
), // ),
); // );
} // }
} // }
/// 构建消息内容 /// 构建消息内容
Widget _buildMessageContent(BuildContext context) { Widget _buildMessageContent(BuildContext context) {
@ -300,6 +302,81 @@ class MessageBubble extends GetView<AgentController> {
// } // }
} }
// 使用Markdown渲染AI消息,用户消息仍然使用普通文本
if (!isUser) {
return MarkdownBody(
data: message,
styleSheet: MarkdownStyleSheet(
p: TextStyle(
color: Theme.of(context).brightness == Brightness.dark
? Colors.white.withOpacity(0.9)
: Colors.black87,
fontSize: 14,
height: 1.4,
fontWeight: FontWeight.w400,
),
h1: TextStyle(
color: Theme.of(context).brightness == Brightness.dark
? Colors.white
: Colors.black,
fontSize: 18,
fontWeight: FontWeight.bold,
),
h2: TextStyle(
color: Theme.of(context).brightness == Brightness.dark
? Colors.white
: Colors.black,
fontSize: 16,
fontWeight: FontWeight.bold,
),
h3: TextStyle(
color: Theme.of(context).brightness == Brightness.dark
? Colors.white
: Colors.black,
fontSize: 15,
fontWeight: FontWeight.bold,
),
code: TextStyle(
backgroundColor: Theme.of(context).brightness == Brightness.dark
? Colors.grey[800]
: Colors.grey[200],
fontFamily: 'monospace',
fontSize: 13,
),
codeblockDecoration: BoxDecoration(
color: Theme.of(context).brightness == Brightness.dark
? Colors.grey[800]
: Colors.grey[200],
borderRadius: BorderRadius.circular(4),
),
blockquote: TextStyle(
color: Theme.of(context).brightness == Brightness.dark
? Colors.grey[400]
: Colors.grey[700],
fontSize: 14,
fontStyle: FontStyle.italic,
),
blockquoteDecoration: BoxDecoration(
border: Border(
left: BorderSide(
color: Theme.of(context).brightness == Brightness.dark
? Colors.grey[600]!
: Colors.grey[400]!,
width: 4,
),
),
),
listBullet: TextStyle(
color: Theme.of(context).brightness == Brightness.dark
? Colors.white.withOpacity(0.9)
: Colors.black87,
fontSize: 14,
),
),
selectable: true,
);
}
// 用户消息仍然使用普通文本
return Text( return Text(
message, message,
style: TextStyle( style: TextStyle(

Loading…
Cancel
Save