本文正在参与「金石方案」
介绍
最近ChatGPT流行全球,网络上对 OpenAI 和 ChatGPT 进行了很多宣扬,尤其是最近发布的 GPT-4。此类东西的很多用例不断涌现,人们运用它完成写论文、画美女、生成代码等等操作,但到目前为止,人们运用 ChatGPT 最广泛的方法仍是是通过chat.openai.com。我也一直在官网上运用 ChatGPT 干活,编写一些代码片段、优化代码、添加注释等,作为疲于应对日报的开发,现在现已运用ChatGPT解脱了。
曾经的日报:
再看看现的日报多么内卷,再也不用担心日报被领导批评了。
作业内容:
然而,OpenAI 官方谈天界面的体会并不友好。它功用非常有限,并且经常性的谈天记录不能正常作业。作为开发人员,也想开发下一个 AI 运用,便当自己运用,一开始在选择言语的时分一起考虑过 Compose 和 Flutter,作为这两个结构的长期运用人员,我觉得 Flutter 非常适宜 ChatGPT 客户端运用程序,仰仗其跨途径才干和丰厚的 UI 组件,Flutter 是此类项目的完美选择,只需编写一次代码,就可以在网络、iOS、Android 以及桌面途径:Windows、macOS 和 Linux 上发布我们的运用程序。毕竟,我选择了运用 Flutter 构建一个简略的 AI 运用,功用包含通过 API 与 OpenAI 的 ChatGPT 谈天、翻译、生成图片等,并且还带有深色、淡色主题适配。
这篇文章其实也是运用ChatGPT写的。
入门
在我们开发运用之前,让我们对 ChatGPT API 的基础知识理有一个底子的了解。
OpenAI 有许多具有不同功用的 AI 模型。可是我们今日要运用的模型**gpt-3.5-turbo
**是已知最有才干的模型,具有更高的准确性、更快的呼应时刻和改进的天然言语理解才干。
在运用 API 之前,我们需求生成一个 API 密钥用来鉴权。可以在此处生成 API 密钥(需求在 OpenAI 上创立一个帐户)。
我们将运用以下 API:
Create chat completion
POST https://api.openai.com/v1/chat/completions
//Creates a completion for the chat message
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
}
}
Create imageBeta
POST https://api.openai.com/v1/images/generations
//Creates an image given a prompt.
body
选用以下格式的JSON :
{
"prompt": "A cute baby sea otter",
"n": 2,
"size": "1024x1024"
}
- prompt:必填,所需图像的文本描绘。最大长度为 1000 个字符。
- n:默认为1,要生成的图像数。有必要介于 1 和 10 之间。
- size:默认为1024×1024,生成图像的巨细。有必要是
256x256
、512x512
、1024x1024
之一。 - response_format:默认为url,生成的图像回来的格式。有必要是 或
url
、b64_json
之一。 - user:用户的唯一标识符。
我们可以运用flutter_nb_net库发送带着参数的央求,并解析呼应。pub.dev 上也有一个集成 API 的包:dart_openai,想走捷径的可以运用这个包。
运用程序
先创立一个简略的运用程序,主页是一个常规的谈天页面,可以承受用户输入,运用 API 获取呼应,然后将它们显现在谈天气泡中。
毕竟界面将如下所示:
谈天页面
UI 的建立分为三部分:
-
标题栏:具有几个导航按钮。
-
谈天列表:有用户气泡和 AI 气泡。
-
输入框:接收用户输入并发送到 ChatGPT API。
标题栏的两个导航action
,点击跳转翻译和生成图片页面:
actions: <Widget>[
IconButton(
onPressed: () async {
Get.toNamed(Routes.TRANSLATE);
},
icon: const Icon(Icons.translate),
),
IconButton(
onPressed: () async {
Get.toNamed(Routes.IMAGE);
},
icon: const Icon(Icons.image),
),
],
还有一个侧边栏菜单,可以设置 API key:
drawer: const DrawerWidget(),
谈天列表:
ListView.builder(
controller: _listScrollController,
itemCount: controller.getChatList.length, //chatList.length,
itemBuilder: (context, index) {
return ChatWidget(
msg: controller
.getChatList[index].msg, // chatList[index].msg,
chatIndex: controller.getChatList[index]
.chatIndex, //chatList[index].chatIndex,
shouldAnimate:
controller.getChatList.length - 1 == index,
);
}),
谈天列表的item
是一个自定义控件ChatWidget
,参数index
区别用户和 AI。,用户的index
是0。
建立谈天气泡
用户气泡:
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 气泡需求有打字机的效果,仿生机器人在一个一个输入,这个效果运用了animated_text_kit实现的:
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
? InkWell(
onLongPress: () {
Clipboard.setData(ClipboardData(text: msg.trim()));
showToast("现已复制到剪切板");
},
child: 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(),
),
]),
),
)
: SelectableText(
msg.trim(),
style: TextStyle(
color: Get.theme.colorScheme.onTertiaryContainer,
fontWeight: FontWeight.w700,
fontSize: 16),
),
),
),
const SizedBox(width: 40.0),
],
);
}
}
外网的拜访有点慢,所以在等候的时分,显现一个加载状况:
if (controller.isTyping)
SpinKitThreeBounce(
color: Get.theme.colorScheme.secondary,
size: 18,
),
逻辑层
状况管理仍然运用getx
,运用GetX Template Generator插件一键生成代码结构。
本来有选择模型的逻辑,后来去掉了,只需一个发消息和承受接收消息的逻辑:
/// Method to send user message to GPT model and get answers
Future<void> sendMessageAndGetAnswers({required String msg}) async {
chatList.addAll(await repository.sendMessageGPT(
message: msg,
));
_isTyping = false;
update();
}
数据层:
class ChatRepository {
Future<List<ChatBean>> sendMessageGPT({required String message}) async {
var result = await post('/chat/completions',
data: jsonEncode({
"model": aiModel,
"messages": [
{
"role": "user",
"content": message,
}
]
}),
decodeType: ChatModel());
List<ChatBean> chatList = [];
result.when(success: (model) {
model.choices?.forEach((element) {
var content = element.message?.content;
if (content?.isNotEmpty ?? false) {
chatList.add(ChatBean(msg: content!, chatIndex: 1));
}
});
}, failure: (msg, __) {
showToast(msg);
});
return chatList;
}
}
网络央求运用非常棒的网络库flutter_nb_net发送央求,得到回来的消息。
下面是效果:
谈天功用现已实现,可以高兴的和 Chatgpt 尬聊了,日报再也难不倒我了。
后面还有一篇,介绍翻译和生成图片。