|
|
@ -1,4 +1,5 @@ |
|
|
import 'package:flutter/material.dart'; |
|
|
import 'package:flutter/material.dart'; |
|
|
|
|
|
import 'package:flutter_markdown/flutter_markdown.dart'; |
|
|
import 'package:flutter_screenutil/flutter_screenutil.dart'; |
|
|
import 'package:flutter_screenutil/flutter_screenutil.dart'; |
|
|
import 'package:get/get.dart'; |
|
|
import 'package:get/get.dart'; |
|
|
|
|
|
|
|
|
@ -14,6 +15,8 @@ class AIBottomSheet extends StatefulWidget { |
|
|
class _AIBottomSheetState extends State<AIBottomSheet> { |
|
|
class _AIBottomSheetState extends State<AIBottomSheet> { |
|
|
final _controller = Get.find<MeetingDetailsController>(); |
|
|
final _controller = Get.find<MeetingDetailsController>(); |
|
|
|
|
|
|
|
|
|
|
|
final TextEditingController _texController = TextEditingController(); |
|
|
|
|
|
|
|
|
List _dataList = []; |
|
|
List _dataList = []; |
|
|
|
|
|
|
|
|
final List _cruxList = [ |
|
|
final List _cruxList = [ |
|
|
@ -22,11 +25,21 @@ class _AIBottomSheetState extends State<AIBottomSheet> { |
|
|
'生成关键指标', |
|
|
'生成关键指标', |
|
|
]; |
|
|
]; |
|
|
|
|
|
|
|
|
|
|
|
bool _isLoading = false; |
|
|
|
|
|
|
|
|
|
|
|
@override |
|
|
|
|
|
void dispose() { |
|
|
|
|
|
_texController.dispose(); |
|
|
|
|
|
super.dispose(); |
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
@override |
|
|
@override |
|
|
Widget build(BuildContext context) { |
|
|
Widget build(BuildContext context) { |
|
|
return Container( |
|
|
return Container( |
|
|
height: 1.sh - 50.h, |
|
|
|
|
|
padding: EdgeInsets.symmetric(horizontal: 12.w), |
|
|
padding: EdgeInsets.symmetric(horizontal: 12.w), |
|
|
|
|
|
constraints: BoxConstraints( |
|
|
|
|
|
maxHeight: 1.sh - 50.h - MediaQuery.of(context).viewInsets.bottom, |
|
|
|
|
|
), |
|
|
child: Column( |
|
|
child: Column( |
|
|
children: [ |
|
|
children: [ |
|
|
Container( |
|
|
Container( |
|
|
@ -49,7 +62,7 @@ class _AIBottomSheetState extends State<AIBottomSheet> { |
|
|
width: 26.w, |
|
|
width: 26.w, |
|
|
height: 26.w, |
|
|
height: 26.w, |
|
|
decoration: BoxDecoration( |
|
|
decoration: BoxDecoration( |
|
|
color: Colors.white, |
|
|
color: Colors.grey[100], |
|
|
borderRadius: BorderRadius.circular(26.r), |
|
|
borderRadius: BorderRadius.circular(26.r), |
|
|
), |
|
|
), |
|
|
child: Icon( |
|
|
child: Icon( |
|
|
@ -58,12 +71,25 @@ class _AIBottomSheetState extends State<AIBottomSheet> { |
|
|
color: Colors.grey[400], |
|
|
color: Colors.grey[400], |
|
|
), |
|
|
), |
|
|
), |
|
|
), |
|
|
) |
|
|
), |
|
|
], |
|
|
], |
|
|
), |
|
|
), |
|
|
), |
|
|
), |
|
|
Expanded( |
|
|
Expanded( |
|
|
child: _dataList.isNotEmpty ? SizedBox() : _empty(), |
|
|
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(), |
|
|
_inputBox(), |
|
|
], |
|
|
], |
|
|
@ -71,6 +97,50 @@ class _AIBottomSheetState extends State<AIBottomSheet> { |
|
|
); |
|
|
); |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
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() { |
|
|
Widget _empty() { |
|
|
return Padding( |
|
|
return Padding( |
|
|
padding: EdgeInsets.symmetric(vertical: 10.w), |
|
|
padding: EdgeInsets.symmetric(vertical: 10.w), |
|
|
@ -106,20 +176,25 @@ class _AIBottomSheetState extends State<AIBottomSheet> { |
|
|
), |
|
|
), |
|
|
...List.generate( |
|
|
...List.generate( |
|
|
_cruxList.length, |
|
|
_cruxList.length, |
|
|
(int index) => Container( |
|
|
(int index) => GestureDetector( |
|
|
width: double.infinity, |
|
|
onTap: () { |
|
|
padding: EdgeInsets.symmetric(horizontal: 15.w, vertical: 8.w), |
|
|
_sendMessage(_cruxList[index]); |
|
|
margin: EdgeInsets.symmetric(vertical: 5.w), |
|
|
}, |
|
|
decoration: BoxDecoration( |
|
|
child: Container( |
|
|
color: Colors.grey[100], |
|
|
width: double.infinity, |
|
|
borderRadius: BorderRadius.circular(20.r), |
|
|
padding: EdgeInsets.symmetric(horizontal: 15.w, vertical: 8.w), |
|
|
border: Border.all( |
|
|
margin: EdgeInsets.symmetric(vertical: 5.w), |
|
|
color: Colors.grey[300]!, |
|
|
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), |
|
|
), |
|
|
), |
|
|
), |
|
|
|
|
|
child: Text( |
|
|
|
|
|
_cruxList[index], |
|
|
|
|
|
style: TextStyle(fontSize: 12.sp), |
|
|
|
|
|
), |
|
|
), |
|
|
), |
|
|
), |
|
|
), |
|
|
), |
|
|
@ -130,12 +205,115 @@ class _AIBottomSheetState extends State<AIBottomSheet> { |
|
|
|
|
|
|
|
|
Widget _inputBox() { |
|
|
Widget _inputBox() { |
|
|
return Container( |
|
|
return Container( |
|
|
height: 40.w, |
|
|
height: 42.w, |
|
|
padding: EdgeInsets.symmetric(horizontal: 10.w), |
|
|
padding: EdgeInsets.symmetric(horizontal: 10.w), |
|
|
decoration: BoxDecoration(), |
|
|
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( |
|
|
child: Row( |
|
|
children: [], |
|
|
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; |
|
|
|
|
|
}); |
|
|
|
|
|
} |
|
|
} |
|
|
} |
|
|
|