|
|
|
@ -22,7 +22,7 @@ class _AIBottomSheetState extends State<AIBottomSheet> { |
|
|
|
final _deapsoundAI = DeapsoundAIService(); |
|
|
|
StreamSubscription? _aiResponseSubscription; |
|
|
|
|
|
|
|
final TextEditingController _texController = TextEditingController(); |
|
|
|
final TextEditingController _textController = TextEditingController(); |
|
|
|
|
|
|
|
String _allText = ''; |
|
|
|
|
|
|
|
@ -33,6 +33,8 @@ class _AIBottomSheetState extends State<AIBottomSheet> { |
|
|
|
'提取结论', |
|
|
|
'生成关键指标', |
|
|
|
]; |
|
|
|
final StringBuffer _buffer = StringBuffer(); |
|
|
|
bool _isAdd = true; |
|
|
|
|
|
|
|
bool _isLoading = false; |
|
|
|
|
|
|
|
@ -53,7 +55,7 @@ class _AIBottomSheetState extends State<AIBottomSheet> { |
|
|
|
|
|
|
|
@override |
|
|
|
void dispose() { |
|
|
|
_texController.dispose(); |
|
|
|
_textController.dispose(); |
|
|
|
_scrollController.dispose(); |
|
|
|
_aiResponseSubscription?.cancel(); |
|
|
|
super.dispose(); |
|
|
|
@ -112,7 +114,7 @@ class _AIBottomSheetState extends State<AIBottomSheet> { |
|
|
|
reverse: true, |
|
|
|
itemBuilder: (BuildContext context, int index) { |
|
|
|
Map data = _dataList[index]; |
|
|
|
return _item(data); |
|
|
|
return _item(index, data); |
|
|
|
}, |
|
|
|
), |
|
|
|
) |
|
|
|
@ -124,7 +126,12 @@ class _AIBottomSheetState extends State<AIBottomSheet> { |
|
|
|
); |
|
|
|
} |
|
|
|
|
|
|
|
Widget _item(Map data) { |
|
|
|
Widget _item(int index, Map data) { |
|
|
|
List list = []; |
|
|
|
if (index == 0 && data['cruxtext'].isNotEmpty) { |
|
|
|
list = data['cruxtext'].split(RegExp(r'[??]')); |
|
|
|
list = list.where((element) => element.isNotEmpty).toList(); |
|
|
|
} |
|
|
|
return Column( |
|
|
|
children: [ |
|
|
|
Container( |
|
|
|
@ -152,6 +159,51 @@ class _AIBottomSheetState extends State<AIBottomSheet> { |
|
|
|
data: data['assistant'], |
|
|
|
), |
|
|
|
), |
|
|
|
if (list.isNotEmpty) |
|
|
|
Padding( |
|
|
|
padding: EdgeInsets.symmetric(vertical: 10.w), |
|
|
|
child: Column( |
|
|
|
crossAxisAlignment: CrossAxisAlignment.start, |
|
|
|
children: [ |
|
|
|
Padding( |
|
|
|
padding: EdgeInsets.only(bottom: 5.w), |
|
|
|
child: Text( |
|
|
|
'继续提问', |
|
|
|
style: TextStyle( |
|
|
|
color: Colors.grey, |
|
|
|
fontSize: 13.sp, |
|
|
|
fontWeight: FontWeight.bold, |
|
|
|
), |
|
|
|
), |
|
|
|
), |
|
|
|
...List.generate( |
|
|
|
list.length, |
|
|
|
(int idx) => GestureDetector( |
|
|
|
onTap: () { |
|
|
|
_sendMessage('${list[idx]}?'); |
|
|
|
}, |
|
|
|
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(12.r), |
|
|
|
border: Border.all( |
|
|
|
color: Colors.grey[300]!, |
|
|
|
), |
|
|
|
), |
|
|
|
child: Text( |
|
|
|
'${list[idx]}?', |
|
|
|
style: TextStyle(fontSize: 14.sp), |
|
|
|
), |
|
|
|
), |
|
|
|
), |
|
|
|
), |
|
|
|
], |
|
|
|
), |
|
|
|
), |
|
|
|
], |
|
|
|
); |
|
|
|
} |
|
|
|
@ -239,7 +291,7 @@ class _AIBottomSheetState extends State<AIBottomSheet> { |
|
|
|
5.horizontalSpace, |
|
|
|
Expanded( |
|
|
|
child: TextField( |
|
|
|
controller: _texController, |
|
|
|
controller: _textController, |
|
|
|
style: TextStyle( |
|
|
|
fontSize: 16.sp, |
|
|
|
color: Colors.black87, |
|
|
|
@ -265,7 +317,7 @@ class _AIBottomSheetState extends State<AIBottomSheet> { |
|
|
|
10.horizontalSpace, |
|
|
|
GestureDetector( |
|
|
|
onTap: () { |
|
|
|
_sendMessage(_texController.text); |
|
|
|
_sendMessage(_textController.text); |
|
|
|
}, |
|
|
|
child: Container( |
|
|
|
width: 26.w, |
|
|
|
@ -288,12 +340,15 @@ class _AIBottomSheetState extends State<AIBottomSheet> { |
|
|
|
|
|
|
|
void _sendMessage(String value) { |
|
|
|
if (_isLoading || value.isEmpty) return; |
|
|
|
_texController.clear(); |
|
|
|
_buffer.clear(); |
|
|
|
_isAdd = true; |
|
|
|
_textController.clear(); |
|
|
|
setState(() { |
|
|
|
_isLoading = true; |
|
|
|
_dataList.insert(0, { |
|
|
|
'user': value, |
|
|
|
'assistant': '', |
|
|
|
'cruxtext': '', |
|
|
|
}); |
|
|
|
}); |
|
|
|
if (_dataList.length > 1) { |
|
|
|
@ -307,11 +362,27 @@ class _AIBottomSheetState extends State<AIBottomSheet> { |
|
|
|
); |
|
|
|
_aiResponseSubscription = responseStream.listen( |
|
|
|
(chunk) { |
|
|
|
setState(() { |
|
|
|
_dataList.first['assistant'] += chunk; |
|
|
|
}); |
|
|
|
_buffer.write(chunk); |
|
|
|
final text = _buffer.toString(); |
|
|
|
Map item = _dataList.first; |
|
|
|
if (_isAdd) { |
|
|
|
final index = text.indexOf('@continue_asking@'); |
|
|
|
if (index != -1) { |
|
|
|
item['assistant'] = text.substring(0, index); |
|
|
|
_isAdd = false; |
|
|
|
} else { |
|
|
|
item['assistant'] = text; |
|
|
|
} |
|
|
|
setState(() {}); |
|
|
|
} |
|
|
|
}, |
|
|
|
onDone: () { |
|
|
|
final text = _buffer.toString(); |
|
|
|
final index = text.indexOf('@continue_asking@'); |
|
|
|
if (index != -1) { |
|
|
|
_dataList.first['cruxtext'] = |
|
|
|
text.substring(index + '@continue_asking@'.length).trim(); |
|
|
|
} |
|
|
|
setState(() { |
|
|
|
_isLoading = false; |
|
|
|
}); |
|
|
|
@ -325,6 +396,11 @@ class _AIBottomSheetState extends State<AIBottomSheet> { |
|
|
|
'role': 'system', |
|
|
|
'content': '你只能根据这段对话记录回答问题,禁止引入外部知识。对话内容:$_allText', |
|
|
|
}, |
|
|
|
{ |
|
|
|
'role': 'system', |
|
|
|
'content': |
|
|
|
'请基于对话上下文生成内容。在回复末尾,添加2-4个简短的、旨在继续对话的问题,并放入@continue_asking@后面。', |
|
|
|
}, |
|
|
|
]; |
|
|
|
for (int i = _dataList.length - 1; i >= 0; i--) { |
|
|
|
messages.add({'role': 'user', 'content': _dataList[i]['user']}); |
|
|
|
|