import 'package:flutter/material.dart'; import 'package:flutter_markdown/flutter_markdown.dart'; import 'package:flutter_screenutil/flutter_screenutil.dart'; import 'package:get/get.dart'; import '../controllers/meeting_details_controller.dart'; class AIBottomSheet extends StatefulWidget { const AIBottomSheet({super.key}); @override State createState() => _AIBottomSheetState(); } class _AIBottomSheetState extends State { final _controller = Get.find(); final TextEditingController _texController = TextEditingController(); List _dataList = []; final List _cruxList = [ '添加代办事项', '提取结论', '生成关键指标', ]; bool _isLoading = false; @override void dispose() { _texController.dispose(); super.dispose(); } @override Widget build(BuildContext context) { return Container( padding: EdgeInsets.symmetric(horizontal: 12.w), constraints: BoxConstraints( maxHeight: 1.sh - 50.h - MediaQuery.of(context).viewInsets.bottom, ), child: Column( children: [ Container( padding: EdgeInsets.symmetric(vertical: 10.w), child: Row( mainAxisAlignment: MainAxisAlignment.spaceBetween, children: [ 26.horizontalSpace, Text( 'Ask AI', style: TextStyle( fontSize: 16.sp, color: Colors.black87, fontWeight: FontWeight.bold, ), ), GestureDetector( onTap: () => Get.back(), child: Container( width: 26.w, height: 26.w, decoration: BoxDecoration( color: Colors.grey[100], borderRadius: BorderRadius.circular(26.r), ), child: Icon( Icons.close, size: 18.w, color: Colors.grey[400], ), ), ), ], ), ), Expanded( child: _dataList.isNotEmpty ? Align( alignment: Alignment.topCenter, child: ListView.builder( itemCount: _dataList.length, shrinkWrap: true, reverse: true, itemBuilder: (BuildContext context, int index) { Map data = _dataList[index]; return _item(data, index == 0); }, ), ) : _empty(), ), _inputBox(), ], ), ); } Widget _item(Map data, bool isBorder) { return Container( padding: EdgeInsets.symmetric(vertical: 20.w), decoration: BoxDecoration( border: isBorder ? null : Border( bottom: BorderSide( width: 1, color: Colors.grey[400]!, ), ), ), child: Column( children: [ Align( alignment: Alignment.centerRight, child: Container( padding: EdgeInsets.all(10.w), decoration: BoxDecoration( color: Colors.grey[200], borderRadius: BorderRadius.circular(12.r), ), child: Text( data['user'], style: TextStyle( fontSize: 14.sp, ), ), ), ), if (data['assistant'].isNotEmpty) Container( padding: EdgeInsets.symmetric(vertical: 20.w), alignment: Alignment.centerLeft, child: MarkdownBody( data: data['assistant'], ), ), ], ), ); } Widget _empty() { return Padding( padding: EdgeInsets.symmetric(vertical: 10.w), child: Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ Text( '今天我能帮您做点什么呢?', style: TextStyle( fontSize: 18.sp, fontWeight: FontWeight.bold, ), ), Padding( padding: EdgeInsets.only(top: 10.w, bottom: 30.w), child: Row( children: [ Icon( Icons.audio_file_outlined, size: 14.w, color: Colors.grey[500], ), 2.horizontalSpace, Text( _controller.meetingData.value.title, style: TextStyle( color: Colors.grey[500], fontSize: 12.sp, ), ), ], ), ), ...List.generate( _cruxList.length, (int index) => GestureDetector( onTap: () { _sendMessage(_cruxList[index]); }, child: Container( width: double.infinity, padding: EdgeInsets.symmetric(horizontal: 15.w, vertical: 8.w), margin: EdgeInsets.symmetric(vertical: 5.w), decoration: BoxDecoration( color: Colors.grey[100], borderRadius: BorderRadius.circular(20.r), border: Border.all( color: Colors.grey[300]!, ), ), child: Text( _cruxList[index], style: TextStyle(fontSize: 12.sp), ), ), ), ), ], ), ); } Widget _inputBox() { return Container( height: 42.w, padding: EdgeInsets.symmetric(horizontal: 10.w), margin: EdgeInsets.only(bottom: 10.w), decoration: BoxDecoration( borderRadius: BorderRadius.circular(42.r), gradient: LinearGradient( begin: Alignment.centerLeft, end: Alignment.centerRight, colors: [ const Color(0xFFab47bc).withOpacity(0.1), // 薰衣草紫 const Color(0xFFec407a).withOpacity(0.2), // 品红 ], ), ), child: Row( children: [ 5.horizontalSpace, Expanded( child: TextField( controller: _texController, style: TextStyle( fontSize: 16.sp, color: Colors.black87, letterSpacing: 0, height: 1.4, ), decoration: InputDecoration( hintText: '问 AI ...', hintStyle: TextStyle( fontSize: 16.sp, color: Colors.grey[400], letterSpacing: 0, height: 1.4, ), isDense: true, fillColor: Colors.transparent, border: InputBorder.none, contentPadding: EdgeInsets.zero, ), onSubmitted: _sendMessage, ), ), 10.horizontalSpace, GestureDetector( onTap: () { _sendMessage(_texController.text); }, child: Container( width: 26.w, height: 26.w, decoration: BoxDecoration( color: Colors.grey, borderRadius: BorderRadius.circular(26.r), ), child: Icon( Icons.arrow_upward, size: 18.w, color: Colors.white, ), ), ), ], ), ); } void _sendMessage(String value) { if (_isLoading || value.isEmpty) return; setState(() { _isLoading = true; }); _dataList.insert(0, { 'user': value, 'assistant': ''' # 角色 你是一名卓越的会议记录专家,拥有超强的信息归纳与细分能力。不仅能高效处理各类通用场景会议,精准提炼会议核心内容,为后续思维导图生成奠定坚实基础,还能将整理好的会议记录巧妙转化为清晰直观的思维导图。 ## 技能 ### 技能 1: 通用会议内容深度细分 1. 深入全面剖析给定的通用场景会议内容,精准区分不同主题板块,如会议目标、讨论事项、决策结果、行动安排、问题与挑战等。 2. 对每个主题板块进行细致分解,形成具体要点与细节。若涉及人员,人员名称保留[],清晰明确其角色与贡献;涉及流程,梳理出关键步骤与节点。 3. 以层次分明、逻辑紧密的方式整理细分内容,使其契合思维导图的结构特点。 ===回复示例=== - **会议目标**: - 目标 1:[详细且全面阐述目标 1] - 目标 2:[如有多个目标,依次详细罗列] - **讨论事项**: - 事项 1: - 观点 1:[详细说明提出观点 1 的人员及具体内容] - 观点 2:[详细阐述不同观点及相关人员] - 事项 2:[按此格式详细罗列其他讨论事项] - **决策结果**: - 决策 1:[具体且完整表述决策内容] - 决策 2:[详细列出其他决策] - **行动安排**: - 任务 1: - 负责人:[具体姓名] - 时间节点:[精确到具体时间] - 任务内容:[详细描述任务具体内容] - 任务 2:[依此格式详细罗列其他任务] - **问题与挑战**: - 问题 1:[具体清晰描述问题] - 挑战 1:[详细说明面临的挑战及相关说明] ===示例结束=== ''', }); _texController.clear(); setState(() { _isLoading = false; }); } }