Flutter AI 访问多个AI 模型
在上一篇中我们构建了一个可以访问多模型聊天应用,现在设置菜单可以选择不同的大模型
因为代码较多,没有将所有代码贴出(也没有上传GitHub)如果有需要在在评论区留言,我会更新文章或者上传代码
模型选择
我创建了一个名为 _showPopupMenu 的函数,在用户点击 IconButton 时调用该函数,然后使用 showMenu 函数显示一个类似于 PopupMenuButton 的菜单。用户选择了某个 AI 类型后会更新标题和相应的 AI 服务实例。
我增加一个 _showAISelectionMenu 方法
写法 1
void _showAISelectionMenu(BuildContext context) {
showModalBottomSheet(
context: context,
builder: (BuildContext context) {
return Container(
child: Wrap(
children: <Widget>[
ListTile(
leading: Icon(Icons.chat),
title: Text('ChatGPT'),
onTap: () {
setState(() {
_appBarTitle = 'ChatGPT'; // 更新标题
_aiProvider = AIProvider(type: 'ChatGPT'); // 更新 AIProvider
});
Navigator.pop(context);
},
),
ListTile(
leading: Icon(Icons.android),
title: Text('文心一言'),
onTap: () {
setState(() {
_appBarTitle = '文心一言'; // 更新标题
_aiProvider = AIProvider(type: 'ErnieBot'); // 更新 AIProvider
});
Navigator.pop(context);
},
),
ListTile(
leading: Icon(Icons.question_answer),
title: Text('通义千问'),
onTap: () {
setState(() {
_appBarTitle = '通义千问'; // 更新标题
_aiProvider = AIProvider(type: 'QwenBot'); // 更新 AIProvider
});
Navigator.pop(context);
},
),
// 添加更多的 AI 类型
],
),
);
},
);
}
//...
}
这样写方法中重复代码太多了,我将 AI 类型和对应的标题定义为两个列表 aiTypes 和 aiTitles。然后在 _showAISelectionMenu 方法中使用 ListView.builder 来遍历这两个列表,生成对应的 ListTile 列表。同时,我添加了一个辅助方法 _buildIcon 来根据 AI 类型生成对应的图标。这样可以减少重复的代码,并使代码更加清晰易读。
写法 2
void _showAISelectionMenu(BuildContext context) {
showModalBottomSheet(
context: context,
builder: (BuildContext context) {
return Container(
child: ListView.builder(
itemCount: aiTypes.length,
itemBuilder: (BuildContext context, int index) {
String aiType = aiTypes[index];
String aiTitle = aiTitles[index];
return ListTile(
leading: _buildIcon(aiType),
title: Text(aiTitle),
onTap: () {
setState(() {
_appBarTitle = aiTitle; // 更新标题
_aiProvider = AIProvider(type: aiType); // 更新 AIProvider
});
Navigator.pop(context);
},
);
},
),
);
},
);
}
Widget _buildIcon(String aiType) {
switch (aiType) {
case 'ChatGPT':
return Icon(Icons.chat);
case 'ErnieBot':
return Icon(Icons.android);
case 'QwenBot':
return Icon(Icons.question_answer);
default:
return Icon(Icons.help);
}
}
final List<String> aiTypes = ['ChatGPT', 'ErnieBot', 'QwenBot'];
final List<String> aiTitles = ['ChatGPT', '文心一言', '通义千问'];
具体模型选择
写法 1
class _ChatScreenState extends State<ChatScreen> {
final TextEditingController _textController = TextEditingController();
final List<Message> _messages = [];
AIProvider _aiProvider = AIProvider();
String _appBarTitle = 'ChatGPT'; // 初始标题
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text(_appBarTitle),
actions: [
IconButton(
icon: Icon(Icons.settings),
onPressed: () {
_showPopupMenu(context);
},
),
],
),
body: Container(
//...
),
);
}
void _showPopupMenu(BuildContext context) async {
final selectedValue = await showMenu<String>(
context: context,
position: RelativeRect.fromLTRB(100, 100, 0, 100), // 根据需要调整位置
items: [
PopupMenuItem<String>(
value: 'ChatGPT',
child: Text('ChatGPT'),
),
PopupMenuItem<String>(
value: 'ErnieBot',
child: Text('文心一言'),
),
PopupMenuItem<String>(
value: 'QwenBot',
child: Text('通义千问'),
),
// 添加更多的 AI 类型
],
);
if (selectedValue != null) {
setState(() {
_appBarTitle = selectedValue == 'QwenBot' ? '通义千问' : selectedValue; // 更新标题
_aiProvider = AIProvider(type: selectedValue); // 更新 AIProvider
});
}
}
//...
}
这样写方法中重复代码太多了,我们可以使用 List.generate 来生成 PopupMenuButton 的子菜单项,通过循环遍历 aiTypes 列表,并使用每个元素创建一个 PopupMenuItem。这样就可以实现通过循环构造 PopupMenuButton 的子菜单项。
写法 2
void _showPopupMenu(BuildContext context) {
showMenu(
context: context,
position: RelativeRect.fromLTRB(0, AppBar().preferredSize.height, 0, 0),
items: List.generate(aiTypes.length, (index) {
return PopupMenuItem<String>(
value: aiTypes[index],
child: Text(aiTitles[index]),
);
}),
elevation: 8.0,
).then((value) {
if (value != null) {
setState(() {
_appBarTitle = value == 'QwenBot' ? '通义千问' : value; // 更新标题
_aiProvider = AIProvider(type: value); // 更新 AIProvider
});
}
});
}