本文正在参加「金石计划」
介绍
最近ChatGPT风靡全球,网络上对 OpenAI 和 ChatGPT 进行了大量宣传,尤其是最近发布的 GPT-4。此类工具的大量用例不断涌现,人们使用它完成写论文、画美女、生成代码等等操作,但到目前为止,人们使用 ChatGPT 最广泛的方式是通过chat.openai.com。我也在上面使用 ChatGPT 干活,编写一些代码片段、优化代码、添加注释等,作为疲于应对日报的开发,现在已经利用ChatGPT解脱了。
以前的日报:
再看看现的日报多么内卷:
工作内容:
再也不用担心日报被领导批评了。
然而,OpenAI 官方聊天界面的体验并不好。它非常有限,而且聊天记录经常不能正常工作。作为开发人员,也想开发下自己的应用,方便自己使用,而在选择语言的时候考虑过 Compose 和 Flutter,作为 Flutter 长期使用人员,我觉得 Flutter 非常适合 ChatGPT 客户端应用程序!凭借其跨平台能力和丰富的 UI 组件,Flutter 是此类项目的完美选择,我们只需编写一次代码,就可以在网络、iOS、Android 以及桌面平台:Windows、macOS 和 Linux 上发布我们的应用程序。在这个文章里,我将构建一个简单的应用,包含通过 API 与 OpenAI 的 ChatGPT 聊天、并实现翻译、生成图片的功能,还带有日夜主题。
这篇文章其实也是利用ChatGPT写的。
入门
在我们开发应用之前,让我们对 ChatGPT API 的基础知识理有一个基本的了解。
OpenAI 有许多具有不同功能的 AI模型。但是我们今天要使用的模型**gpt-3.5-turbo**
是已知最有能力的模型,具有更高的准确性、更快的响应时间和改进的自然语言理解能力。
我们将使用以下 API:
Create chat completion
POST https://api.openai.com/v1/chat/completions
//Creates a completion for the chat message
Create imageBeta
POST https://api.openai.com/v1/images/generations
//Creates an image given a prompt.
要使用此 API,我们需要生成一个 API 密钥。可以在此处生成 API 密钥(需要在 OpenAI 上创建一个帐户)。
body
它采用以下格式的JSON :
{
"model": "gpt-3.5-turbo",
"messages": [{"role": "user", "content": "Hello!"}]
}
并且,返回response
这样的:
{
"id": "chatcmpl-123",
"object": "chat.completion",
"created": 1677652288,
"choices": [{
"index": 0,
"message": {
"role": "assistant",
"content": "Hello there, how may I assist you today?",
},
"finish_reason": "stop"
}],
"usage": {
"prompt_tokens": 9,
"completion_tokens": 12,
"total_tokens": 21
}
}
我们可以使用flutter_nb_net库发送携带带所需数据的请求,并解析响应。pub.dev 上也有一个可用的包:dart_openai,它可以直接发出 API 请求并返回解析后的响应,想走捷径的可以使用这个包。
应用程序
我们将只创建一个简单的应用程序,它能够接受用户输入,使用 API 获取响应,然后将它们显示在聊天气泡中。
最终界面将如下所示:
聊天机器人
UI的搭建分为三部分:
- 标题栏:具有几个导航按钮。
- 聊天列表:有用户气泡和 AI 气泡。
- 输入框:接收用户输入并发送到 ChatGPT API。
状态管理依然使用getx
,使用插件一键生成代码结构。
建立聊天气泡
聊天列表的item
是一个自定义控件ChatWidget
,参数index
区别用户和 AI。
用户气泡:
class UserChatView extends StatelessWidget {
const UserChatView({Key? key, required this.msg}) : super(key: key);
final String msg;
@override
Widget build(BuildContext context) {
return Row(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
const SizedBox(width: 40.0),
Expanded(
child: Align(
alignment: Alignment.centerRight,
child: Container(
padding: const EdgeInsets.all(8.0),
decoration: BoxDecoration(
color: Get.theme.colorScheme.secondaryContainer,
borderRadius: BorderRadius.circular(16.0),
),
child: Text(
msg,
style: TextStyle(
color: Get.theme.colorScheme.onSecondaryContainer,
),
),
),
),
),
const SizedBox(width: 8.0),
const CircleAvatar(
backgroundImage: AssetImage(Assets.imagesPerson),
radius: 16.0,
)
],
);
}
}
AI 气泡需要有打字机的效果,文字一个一个显示,好像机器人在一个一个输入一样:
class AiChatView extends StatelessWidget {
const AiChatView({super.key, required this.msg, required this.shouldAnimate});
final String msg;
final bool shouldAnimate;
@override
Widget build(BuildContext context) {
return Row(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
const CircleAvatar(
backgroundImage: AssetImage(Assets.imagesOpenaiLogo),
radius: 16.0,
),
const SizedBox(width: 8.0),
Expanded(
child: Container(
padding: const EdgeInsets.all(8.0),
decoration: BoxDecoration(
color: Get.theme.colorScheme.tertiaryContainer,
borderRadius: BorderRadius.circular(16.0),
boxShadow: [
BoxShadow(
color: Colors.black.withOpacity(0.05),
blurRadius: 5,
offset: const Offset(0, 2),
),
],
),
child: shouldAnimate
? DefaultTextStyle(
style: TextStyle(
color: Get.theme.colorScheme.onTertiaryContainer,
fontWeight: FontWeight.w700,
fontSize: 16),
child: AnimatedTextKit(
isRepeatingAnimation: false,
repeatForever: false,
displayFullTextOnTap: true,
totalRepeatCount: 1,
animatedTexts: [
TyperAnimatedText(
msg.trim(),
),
]),
)
: Text(
msg.trim(),
style: TextStyle(
color: Get.theme.colorScheme.onTertiaryContainer,
fontWeight: FontWeight.w700,
fontSize: 16),
),
),
),
const SizedBox(width: 40.0),
],
);
}
}
逻辑层
本来有选择模型的逻辑,后来去掉了,只有一个发消息和接受接收消息的逻辑:
Future<void> sendMessageAndGetAnswers({required String msg}) async {
if (currentModel.toLowerCase().startsWith("gpt")) {
chatList.addAll(await repository.sendMessageGPT(
message: msg,
modelId: currentModel,
));
} else {
chatList.addAll(await repository.sendMessage(
message: msg,
modelId: currentModel,
));
}
_isTyping = false;
update();
}
下面是效果:
翻译
翻译的 UI 分为四部分:
- 标题栏。
- 翻译语言。
- 输入框:接收用户输入并发送到 ChatGPT API。
- 显示框:接收ChatGPT API 返回的翻译。
这里有一些待完成的功能:
-
复制
-
删除
-
切换语言
-
多语言选择
生成图片
点击首页标题栏的第二个 Action ,会跳转到生成图片页面,默认有一个图片展示。
UI 部分:
-
标题栏。
-
输入框。
-
画廊:展示 ChatGPT API 返回的图片。
配置的接口数据是每次返回4张图片,尺寸是256×256:
var result = await post<ImageModel, ImageModel>('/images/generations',
data: jsonEncode({
"prompt": message,
"n": 4,
"size": "256x256",
}),
decodeType: ImageModel());
prompt
:要生成图片的文字描述。n
:返回的张数。size
:图片尺寸。
画廊是一个自定义控件。
浅色模式
除了上面的功能,这个 app 按照 Material 3 设计,包含浅色模式和深色模式:
原文链接:https://juejin.cn/post/7220793382021070903 作者:北海道浪子