使用Flutter构建ChatGPT客户端:快速入门指南

3ecf7efb356160c1718b7cf23333d75e.jpeg

开篇

在本篇博客文章中,我们将通过OpenAI的API构建一个简单的对话界面,与ChatGPT进行聊天。

近来OpenAI和ChatGPT的热度很高,尤其是最近发布的GPT-4。这类工具的大量使用案例已经涌现出来,但目前人们最常用ChatGPT的方式是通过chat.openai.com进行聊天。我一直在使用ChatGPT来激发灵感、编写一些Flutter代码片段,甚至是撰写这篇博客文章的大纲!当然,它建议的大纲非常乐观,因此我不得不略过一些部分,但它仍然提供了足够的指引,让我能够立即开始。

然而,OpenAI的官方聊天界面体验并不好。它非常有限,聊天历史记录经常无法正常工作。已经有人使用Web技术构建了更好的UI和用户体验的ChatGPT客户端应用程序,例如TypingMind。

作为Flutter开发者,我不禁想到Flutter非常适合作为ChatGPT客户端应用程序的选择!Flutter具有跨平台能力和丰富的UI组件,是这样一个项目的完美选择。我们可以编写一次代码,然后将应用程序发布在Web、iOS、Android以及桌面平台上:Windows、macOS和Linux。

ChatGPT API

要使用OpenAI的任何API,您需要注册并获取API密钥。请注意,API使用可能会产生费用,您需要提供付款详细信息。我们将使用的gpt-3.5-turbo模型相对便宜,除非您经常使用它,否则不应花费太多钱。

具体来说,我们将使用Chat API(聊天完成),该API支持两个OpenAI的模型:gpt-3.5-turbo和gpt-4。我们可以在此处找到Chat API的完整参考,其中涉及在
https://api.openai.com/v1/chat/completions 上执行POST请求。

此时,我们可以使用http库向Chat API发送必需的数据并解析响应。但是,由于Dart和Flutter社区的贡献,已经在pub.dev上提供了一个可用的包:dart_openai。它将为我们进行API请求并返回解析后的响应,因此我们只需获取响应文本并在应用程序中显示即可。

以下是一个接受用户消息并返回ChatGPT响应的方法:

Future<String> completeChat(String message) async {final chatCompletion = await OpenAI.instance.chat.create(model: 'gpt-3.5-turbo',messages: [OpenAIChatCompletionChoiceMessageModel(content: message,role: 'user',),],);return chatCompletion.choices.first.message.content;
}

由于这将是一次对话,因此我们需要在请求中传递以前的消息,以便ChatGPT具有到目前为止整个对话的上下文,而不仅仅是用户的最后一条消息。

class ChatMessage {ChatMessage(this.content, this.isUserMessage);final String content;final bool isUserMessage;
}Future<String> completeChat(List<ChatMessage> messages) async {final chatCompletion = await OpenAI.instance.chat.create(model: 'gpt-3.5-turbo',messages: [...previousMessages.map((e) => OpenAIChatCompletionChoiceMessageModel(role: e.isUserMessage ? 'user' : 'assistant',content: e.content,),),],);return chatCompletion.choices.first.message.content;
}

上面的方法接受用户的最后一条消息以及对话中的所有先前消息。请注意,在API请求中,ChatGPT的响应标有助手的角色。

现在,我们把最终版本的completeChat方法放到一个ChatApi类中,以便稍后使用。

// models/chat_message.dart
class ChatMessage {ChatMessage(this.content, this.isUserMessage);final String content;final bool isUserMessage;
}
// api/chat_api.dart
import 'package:chatgpt_client/models/chat_message.dart';
import 'package:chatgpt_client/secrets.dart';
import 'package:dart_openai/openai.dart';class ChatApi {
static const _model = 'gpt-3.5-turbo'; // 设置模型为"gpt-3.5-turbo"ChatApi() { // 构造函数,设置OpenAI的apiKey和organization
OpenAI.apiKey = openAiApiKey;
OpenAI.organization = openAiOrg;
}Future<String> completeChat(List<ChatMessage> messages) async {
// 定义方法completeChat,接收ChatMessage列表类型参数messages,并返回Future<String>类型
final chatCompletion = await OpenAI.instance.chat.create( // 调用OpenAI的chat.create方法,获取ChatCompletionModel对象
model: _model, // 传递模型参数
messages: messages // 传递对话历史消息参数,并将ChatMessage列表转换为OpenAIChatCompletionChoiceMessageModel列表
.map((e) => OpenAIChatCompletionChoiceMessageModel(
role: e.isUserMessage ? 'user' : 'assistant', // 指定消息发送者角色
content: e.content, // 传递消息文本内容
))
.toList(),
);
return chatCompletion.choices.first.message.content; // 返回ChatCompletionModel对象中的消息内容
}
}

请注意,在构造函数中,我们设置了API密钥和组织ID。如果没有API密钥,任何请求都将失败。组织ID是可选的,如果您在OpenAI平台上设置了多个组织,可以提供组织ID。

// secrets.dart
const openAiApiKey = 'YOUR_API_KEY';
const openAiOrg = 'YOUR_ORGANIZATION_ID';

为了避免将敏感信息提交到版本控制中,我们通常会将其存储在 secrets 文件中并在 .gitignore 中添加 secrets 文件,以便在提交时忽略这些文件。在 GitHub 上的项目存储库中,通常会提供一个名为 secrets_example.dart 的文件,其中包含占位符值,供开发人员参考并创建自己的 secrets 文件。

API密钥的注意事项

在本文中,我们正在构建一个客户端应用程序。像这样硬编码API密钥的应用程序不应该发布。由于API使用可能会产生费用,您不希望暴露自己的API密钥。

如果您想发布这样的应用程序,您有两个选择:

1.允许用户提供自己的API密钥开始聊天。用户可以通过应用程序提供他们的密钥,您可以将其安全地存储在本地存储中,以在每个API请求中使用。

2.而不是直接调用聊天API,可以调用一个服务器或边缘函数,然后使用自己的令牌调用聊天API。这样,您就不会暴露自己的API密钥,可以控制流量,并具有其他授权和速率限制要求。如果您选择这种方法,您可能需要考虑赚钱,因为经常使用应用程序的用户将花费您的钱!

构建前端界面

现在 Chat API 已准备好使用,是时候开始构建 UI 了。如果你从零开始,可以使用 "flutter create" 命令初始化一个 Flutter 项目:

flutter create my_chatgpt_client

UI将是相当标准的,包含两个主要的组件:消息编辑器和消息气泡。主屏幕将是聊天中所有消息的列表(作为消息气泡),消息编辑器在底部,我们可以在其中输入消息。

让我们从消息编辑器小部件开始:

// widgets/message_composer.dartimport 'package:flutter/material.dart';class MessageComposer extends StatelessWidget {MessageComposer({required this.onSubmitted, // 回调函数,当用户输入文本提交时调用required this.awaitingResponse, // 是否正在等待 Chat API 的响应super.key,});final TextEditingController _messageController = TextEditingController(); // 用于文本输入的控制器final void Function(String) onSubmitted; // 回调函数,当用户输入文本提交时调用final bool awaitingResponse; // 是否正在等待 Chat API 的响应@overrideWidget build(BuildContext context) {return Container(padding: const EdgeInsets.all(12), // 内边距color: Theme.of(context).colorScheme.secondaryContainer.withOpacity(0.05), // 颜色child: SafeArea(child: Row(children: [Expanded(child: !awaitingResponse // 如果没有正在等待 Chat API 的响应? TextField(controller: _messageController, // 将文本控制器传递给 TextField 组件onSubmitted: onSubmitted, // 当用户提交文本时调用 onSubmitted 回调函数decoration: const InputDecoration(hintText: 'Write your message here...', // 提示文本border: InputBorder.none, // 边框),): Row(mainAxisAlignment: MainAxisAlignment.center, // 将子组件水平居中children: const [SizedBox(height: 24,width: 24,child: CircularProgressIndicator(), // 等待指示器),Padding(padding: EdgeInsets.all(16),child: Text('Fetching response...'), // 正在获取响应),],),),IconButton(onPressed: !awaitingResponse // 如果没有正在等待 Chat API 的响应? () => onSubmitted(_messageController.text) // 当用户点击发送按钮时调用 onSubmitted 回调函数: null, // 禁用按钮icon: const Icon(Icons.send), // 发送图标),],),),);}
}

消息编辑器将在文本字段被提交(例如,按下Enter键)或者我们点击右侧的发送按钮时,调用我们传递给它的onSubmitted方法。我们可以使用awaitingResponse标志隐藏文本字段并禁用发送按钮。当我们等待API的响应时,我们将将此标志设置为true以表示消息正在提交中。

消息气泡小部件是一个简单的容器,根据消息是用户消息还是AI生成的消息,具有不同的背景颜色和发送者名称:

// widgets/message_bubble.dart
import 'package:flutter/material.dart';class MessageBubble extends StatelessWidget {const MessageBubble({required this.content,required this.isUserMessage,super.key,});final String content; // 消息内容final bool isUserMessage; // 是否为用户消息@overrideWidget build(BuildContext context) {final themeData = Theme.of(context);return Container(margin: const EdgeInsets.all(8), // 设置组件的边距decoration: BoxDecoration(color: isUserMessage // 根据消息类型设置不同的背景颜色? themeData.colorScheme.primary.withOpacity(0.4): themeData.colorScheme.secondary.withOpacity(0.4),borderRadius: const BorderRadius.all(Radius.circular(12)), // 设置圆角边框),child: Padding(padding: const EdgeInsets.all(12), // 设置内边距child: Column(crossAxisAlignment: CrossAxisAlignment.start,children: [Row(children: [Text(isUserMessage ? 'You' : 'AI', // 根据消息类型显示发送者style: const TextStyle(fontWeight: FontWeight.bold),),],),const SizedBox(height: 8),Text(content), // 显示消息内容],),),);}
}

现在我们已经准备好了所有必要的小部件,现在让我们将它们全部组合在主页上。下面是主聊天页面的代码:

// chat_page.dart
import 'package:chatgpt_client/api/chat_api.dart';
import 'package:chatgpt_client/models/chat_message.dart';
import 'package:chatgpt_client/widgets/message_bubble.dart';
import 'package:chatgpt_client/widgets/message_composer.dart';
import 'package:flutter/material.dart';class ChatPage extends StatefulWidget {const ChatPage({required this.chatApi,Key? key,}) : super(key: key);final ChatApi chatApi;@overrideState<ChatPage> createState() => _ChatPageState();
}class _ChatPageState extends State<ChatPage> {final _messages = <ChatMessage>[ChatMessage('Hello, how can I help?', false),];var _awaitingResponse = false;@overrideWidget build(BuildContext context) {return Scaffold(appBar: AppBar(title: const Text('Chat')),body: Column(children: [Expanded(child: ListView(children: [// 使用_spread_操作符将每个聊天消息转换为MessageBubble widget..._messages.map((msg) => MessageBubble(content: msg.content,isUserMessage: msg.isUserMessage,),),],),),// 使用MessageComposer widget显示用户输入MessageComposer(onSubmitted: _onSubmitted,awaitingResponse: _awaitingResponse,),],),);}

这是一个有状态的widget,它开始时显示消息"How can I help?",这样我们就不会从空白聊天开始了。

最后一部分是_onSubmitted方法,当用户提交一条消息时,它会通过消息编辑器被调用。

// _onSubmitted方法将会在用户输入一条新的聊天消息后被调用
Future<void> _onSubmitted(String message) async {setState(() {// 在UI中显示用户刚刚输入的消息_messages.add(ChatMessage(message, true));// 等待服务器的回复_awaitingResponse = true;});// 发送用户的消息到API,等待API返回回复final response = await widget.chatApi.completeChat(_messages);setState(() {// 在UI中显示API的回复_messages.add(ChatMessage(response, false));// 回复已经接收完成,不再等待_awaitingResponse = false;});
}

当用户提交一条新的消息时,我们会在 setState 中将该消息添加到聊天消息中,并将 _awaitingResponse 设置为 true。这将在对话中显示用户的消息,并禁用消息编辑器。

接下来,我们将所有消息传递给聊天 API,并等待响应。一旦我们得到了响应,我们会在 _messages 中添加它作为聊天消息,并在第二个 setState 调用中将 _awaitingResponse 设置回 false。

至此,对话流程就完成了!现在让我们看看它的实际效果:

c52e233d8007e4218e903abe16187273.png

这是应用程序的代码和主要方法:

import 'package:chatgpt_client/api/chat_api.dart';
import 'package:chatgpt_client/chat_page.dart';
import 'package:flutter/material.dart';void main() {// 运行ChatApprunApp(ChatApp(chatApi: ChatApi()));
}class ChatApp extends StatelessWidget {// 带有chatApi参数的构造函数const ChatApp({required this.chatApi, Key? key}) : super(key: key);final ChatApi chatApi; // chatApi属性@overrideWidget build(BuildContext context) {return MaterialApp(// MaterialApp,包含了应用的所有基本元素title: 'ChatGPT Client', // 应用的标题theme: ThemeData(// 设置应用的主题色colorScheme: ColorScheme.fromSeed(seedColor: Colors.teal, // 主色调secondary: Colors.lime, // 次要色调),),home: ChatPage(chatApi: chatApi), // ChatPage是这个应用的首页);}
}

解析markdown

在我们之前与ChatGPT的对话中,我们问了一个跟进问题“给我展示代码”。

a153cdfa175124f33f965fd5c439f78a.png

我们在回复中得到了相当数量的Flutter代码,但它们都是以markdown格式呈现的!我们将使用markdown_widget包来解决这个问题。

flutter pub add markdown_widget

在MessageBubble组件中,用MarkdownWidget替换包含消息内容的Text组件:

MarkdownWidget(data: content,shrinkWrap: true,
)

经过一次热重载,我们可以看到代码现在已经被正确解析了。这很容易!

f5bd74cd1bc2615f233f6a90af261fd3.png

错误处理

如果我们从OpenAI得到了错误响应怎么办?在测试中,我遇到了一些429(Too Many Requests)异常。如果你调用API太频繁,也可能出现这种错误,但也可能是因为OpenAI API总共接收到了太多的请求。

我们至少要处理这个错误并显示一个有用的消息。下面是修改后的_onSubmitted方法:

Future<void> _onSubmitted(String message) async {setState(() {_messages.add(ChatMessage(message, true)); // 将输入的消息添加到对话列表_awaitingResponse = true; // 设置正在等待响应标志});try {final response = await widget.chatApi.completeChat(_messages); // 调用 ChatApi 的 completeChat 方法来获取 OpenAI 的响应setState(() {_messages.add(ChatMessage(response, false)); // 将响应添加到对话列表_awaitingResponse = false; // 取消等待响应标志});} catch (err) {ScaffoldMessenger.of(context).showSnackBar(const SnackBar(content: Text('An error occurred. Please try again.')), // 显示错误信息提示条);setState(() {_awaitingResponse = false; // 取消等待响应标志});}
}

当然,这还可以进一步改进。我们可以提供一个选项,在不需要发送新消息的情况下重试响应,但也可以在 ChatApi 中自动重试请求而不显示错误。

结束

总结一下,现在我们已经有一个完全可用的聊天应用程序,可以随时在任何平台上与ChatGPT聊天了!

在这篇文章中,我们展示了如何构建一个基本的聊天应用程序,通过OpenAI的聊天API与ChatGPT进行对话。我们还添加了一些附加功能,如markdown解析和错误处理。

这些功能相当基础,但是我们可以通过这样的应用程序实现更多有用的功能,比如能够复制和/或共享响应。此外,我们可以使用本地或云数据库来存储对话,以便随时访问它们。

您可以在这里找到源代码。

https://github.com/dartling/chatgpt_client

今天的分享就到这里,感谢你的阅读,希望能够帮助到你,文章创作不易,如果你喜欢我的分享,别忘了点赞转发,让更多有需要的人看到,最后别忘记关注「前端达人」,你的支持将是我分享最大的动力,后续我会持续输出更多内容,敬请期待。

原文:
https://dartling.dev/building-a-chatgpt-client-app-with-flutter

作者:Christos

直接翻译,有自行改编和添加部分,翻译水平有限,难免有疏漏,欢迎指正

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.rhkb.cn/news/516.html

如若内容造成侵权/违法违规/事实不符,请联系长河编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

chatgpt使用初体验_incomplete

2023.03.19 &#xff0c;发现已经有大佬翻译了文档&#xff0c;下面内容不再进行原文翻译&#xff0c;只进行使用体验说明。 2023.03.22 i cant speak that (aHR0cHM6Ly9jaGF0Z3B0LmxlaXpoZW55dWtlamkuY29t) 还有一个就是我发现我之前都是在playgroud里面用的&#xff0c;实际是…

在国内使用 FOFA 查找免费无需注册无需验证的 ChatGPT Web 站点

文章目录 操作步骤注意事项关于 FOFA 的介绍 基于人工智能技术的 ChatGPT 通过自然语言处理技术进行智能对话&#xff0c;根据用户的需求和偏好进行个性化服务&#xff0c;在商业应用、教育领域、个性化服务等方面具有广泛的应用前景。 由于国内访问 ChatGPT 受到技术、政策、…

GPT-4和ChatGPT效果对比,差别太大了

文&#xff5c;Serendipity知乎 前言 GPT4上午朋友圈已经刷屏啦&#xff0c;不过我还在忙&#xff0c;刚刚才登上 GPT-4 &#xff0c;现在来体验一下~ 附 GPT-4 能力测试站&#xff08;直接注册即可&#xff0c;无需魔法&#xff09;&#xff1a; https://gpt4test.com 附 Chat…

ChatGPT介绍以及一些使用案例

❤️觉得内容不错的话&#xff0c;欢迎点赞收藏加关注&#x1f60a;&#x1f60a;&#x1f60a;&#xff0c;后续会继续输入更多优质内容❤️ &#x1f449;有问题欢迎大家加关注私戳或者评论&#xff08;包括但不限于NLP算法相关&#xff0c;linux学习相关&#xff0c;读研读博…

如何使用 ChatGPT 制作出色的简历?

您是否厌倦了制作完美的简历&#xff0c;却得不到潜在雇主的回应&#xff1f; 现在是时候转向人工智能和OpenAI开发的工具ChatGPT的力量了。 在本文中&#xff0c;我们将向您展示 ChatGPT 如何彻底改变您的求职并将您的简历提升到一个新的水平。 什么是ChatGPT&#xff1f; …

使用ChatGPT工具阅读文献的实战教程

大家好,我是herosunly。985院校硕士毕业,现担任算法研究员一职,热衷于机器学习算法研究与应用。曾获得阿里云天池比赛第一名,CCF比赛第二名,科大讯飞比赛第三名。拥有多项发明专利。对机器学习和深度学习拥有自己独到的见解。曾经辅导过若干个非计算机专业的学生进入到算法…

使用ChatGPT写论文

本教程介绍chargpt使用教程 :不需要翻墙,不需要注册,也不需要缴纳费用 通过本教程您将会使用chargpt写代码 写论文 。

ChatGPT如何4步制作ppt

1、在提问框写下&#xff08;一定要有冒号&#xff0c;换行复制你的内容&#xff09; 请根据以下文字&#xff0c;生成一个两级大内容纲&#xff1a; 这是你的内容 2、 请将以上文字生成Markdown语言格式&#xff0c;并放在代码块里&#xff0c;以方便我拷贝&#xff08;注意&a…

ChatGPT4Midjourney绘图

此款源码后台授权部署了一套后端&#xff0c;前端不限制数量&#xff0c;不限制域名。 该款源码现下已支持GPT3.5&#xff0c;GPT4&#xff0c;DALLE&#xff0c;Midj绘图&#xff0c;轻应用模块&#xff0c;邀请裂变 支付已对接叶已经对接了&#xff1a;支付宝当面付&#x…

免费使用chatgpt一分钟教你

免费使用chatgpt只需要一个插件 效果图如下 在新标签页直接可以使用chatgpt. 使用教程如下&#xff1a; 先进入插件官网&#xff1a;https://www.wetab.link/zh/ 选择浏览器 电脑下载最新的edg浏览器 打开浏览器设置&#xff0c;开启浏览器拓展 用edg浏览器打开官网选择edg …

ChatGPT45个插件列表

ChatGPT插件现已对所有人开放。 插件介绍&#xff1a; Slack: 查询Slack信息Zapier: 与5000应用&#xff0c;如Google Sheets和Docs进行交互。Expedia: 在一个地方激活你的旅行计划Klarna购物: 在成千上万的在线商店中搜索并比较价格。Vogue时尚杂志: 搜索时尚杂志的文章TO-D…

中文ChatGPT平替——ChatGLM:全新对话模型内测,手把手调教开源单卡版本

❤️觉得内容不错的话&#xff0c;欢迎点赞收藏加关注&#x1f60a;&#x1f60a;&#x1f60a;&#xff0c;后续会继续输入更多优质内容❤️ &#x1f449;有问题欢迎大家加关注私戳或者评论&#xff08;包括但不限于NLP算法相关&#xff0c;linux学习相关&#xff0c;读研读博…

为什么爆火的是 ChatGPT ?OpenAI 做对了什么?

击上方关注 “终端研发部” 设为“星标”&#xff0c;和你一起掌握更多数据库知识 声明&#xff1a;本文首发于我的知乎&#xff1a;httpss://www.zhihu.com/question/585105560/answer/2918122037 最近最火的莫过于ChatGPT了&#xff0c;漂亮国很多高校学生都会用来做作业写论…

ChatGPT和New Bing的区别不同是什么?

我获得了 New Bing 的体验资格之后&#xff0c;迫不及待的进行了第一次使用 New Bing 的尝试。 你是谁 我是必应&#xff0c;一个可以帮你搜索信息和聊天的网站。&#x1f60a; 你是chatgpt吗 不&#xff0c;我不是chatgpt。我是必应&#xff0c;一个可以帮你搜索信息和聊天…

爆火的ChatGPT是什么?一文带你了解

前言 本文将带大家了解ChatGPT是什么 最近你是不是被它刷屏了&#xff1f; ChatGPT是什么&#xff1f;很多人第一眼看到这个英文名字可能就失去了大半的兴趣&#xff0c;但是&#xff0c;相信我&#xff0c;你只需要花费一点点时间去了解它&#xff0c;你一定会充满兴趣&#…

如何正确使用chatgpt,让chatgpt回答优质内容?

我们以chatgpt写一篇文章为例。大家都知道&#xff0c;如果直接让chatgpt写某篇文章&#xff0c;他的回答总是简洁明了的&#xff0c;因为它定位就是聊天&#xff0c;而不是会像“舔狗”一样写一篇小作文。 并且他的回答&#xff0c;总是固定格式的&#xff0c;只要稍微了解ch…

ChatGPT的基本使用方法和具体使用案例(持续更新中。。。)

普通人使用ChatGPT重在磨练基本功&#xff0c;我下面提供的这套基本功如果你能融会贯通&#xff0c;对内容生产者们有着魔法级别的帮助&#xff0c;至少提升10倍的生产效率。 所谓ChatGPT的基本功核心是学会设置 Prompt &#xff0c; Prompt 你可以理解成「提示语」&#xff0…

【ChatGPT使用笔记】 ChatGPT回答不完整,如何获取后续的内容

____tz_zs 对于 ChatGPT 回答不完整的情况&#xff08;篇幅限制&#xff0c;没有说完&#xff09;&#xff0c;可以输入“继续”指令&#xff0c;让其继续回答下去&#xff0c;获得完整内容。 如下图&#xff0c;发问 “使用web3js 调用 eth链智能合约” 直到这里才是获得了刚…

你的 ChatGPT 使用姿势是错的!告诉你 4 个使用 ChatGPT 的小技巧

大部分人使用 ChatGPT 的方式都是错的&#xff0c;比如&#xff1a; 没有在提问时提供案例。忽略了可以通过设置 ChatGPT 的角色来控制它的行为。没有提供过多有效信息&#xff0c;而是让 ChatGPT 猜猜猜。 之所以会犯这些错误&#xff0c;是因为我们使用 ChatGPT 时还停留在…

干货 | ChatGPT使用指南,让你轻松上车AI世界!

Hello&#xff0c;大家好&#xff01; 这里是壹脑云科研圈&#xff0c;我是喵君姐姐~ 聊天机器人&#xff08;Chatbot&#xff09;是一种人工智能应用&#xff0c;可以模拟人类对话行为&#xff0c;以自然语言进行交互。 在过去的几年里&#xff0c;随着自然语言处理技术和深…