本文正在参与「金石方案」

介绍

最近ChatGPT流行全球,网络上对 OpenAI 和 ChatGPT 进行了很多宣扬,尤其是最近发布的 GPT-4。此类东西的很多用例不断涌现,人们运用它完成写论文、画美女、生成代码等等操作,但到目前为止,人们运用 ChatGPT 最广泛的方法仍是是通过chat.openai.com。我也一直在官网上运用 ChatGPT 干活,编写一些代码片段、优化代码、添加注释等,作为疲于应对日报的开发,现在现已运用ChatGPT解脱了。

曾经的日报:

运用 Flutter 构建 ChatGPT 客户端应用程序

再看看现的日报多么内卷,再也不用担心日报被领导批评了。

作业内容:

运用 Flutter 构建 ChatGPT 客户端应用程序

然而,OpenAI 官方谈天界面的体会并不友好。它功用非常有限,并且经常性的谈天记录不能正常作业。作为开发人员,也想开发下一个 AI 运用,便当自己运用,一开始在选择言语的时分一起考虑过 Compose 和 Flutter,作为这两个结构的长期运用人员,我觉得 Flutter 非常适宜 ChatGPT 客户端运用程序,仰仗其跨途径才干和丰厚的 UI 组件,Flutter 是此类项目的完美选择,只需编写一次代码,就可以在网络、iOSAndroid 以及桌面途径: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,生成图像的巨细。有必要是256x256512x5121024x1024之一。
  • response_format:默认为url,生成的图像回来的格式。有必要是 或urlb64_json之一。
  • user:用户的唯一标识符。

我们可以运用flutter_nb_net库发送带着参数的央求,并解析呼应。pub.dev 上也有一个集成 API 的包:dart_openai,想走捷径的可以运用这个包。

运用程序

先创立一个简略的运用程序,主页是一个常规的谈天页面,可以承受用户输入,运用 API 获取呼应,然后将它们显现在谈天气泡中。

毕竟界面将如下所示:

运用 Flutter 构建 ChatGPT 客户端应用程序

谈天页面

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发送央求,得到回来的消息。

下面是效果:

运用 Flutter 构建 ChatGPT 客户端应用程序

谈天功用现已实现,可以高兴的和 Chatgpt 尬聊了,日报再也难不倒我了。

后面还有一篇,介绍翻译和生成图片。