Flutter GetX 实现 ChatGPT 简单聊天界面

Flutter 是一款跨平台的移动应用开发框架,而 GetX 是 Flutter 中一种简单易用的状态管理和路由管理工具。本篇我们将使用 Flutter 和 GetX 实现一个简单的聊天界面,以与 ChatGPT 进行交互。

我们需要在 Flutter 项目中引入 GetX 库。在pubspec.yaml文件中添加以下依赖:

dependencies:
  flutter:
    sdk: flutter
  get: 

main函数中添加以下代码:

void main() {
  //在main函数第一行添加这句话
  WidgetsFlutterBinding.ensureInitialized();
  runApp(GetMaterialApp(
    home: ChatPage(),
  ));
}

确保Flutter Widgets已经初始化,并且启动应用程序的ChatPage页面。

接下来,我们需要创建一个ApiProvider类,用于与 OpenAI API 进行交互。这个类继承自GetConnectGetConnect是一个轻量级的 HTTP 客户端,它能够简化与 API 的通信过程。以下是ApiProvider类的代码:

class ApiProvider extends GetConnect {

  /// 这里填写自己OpenAI API Key
  final String apiKey = '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';
  final String baseUrl = 'https://api.openai.com';
  final Duration timeout = Duration(seconds: 30);

  Map<String, String> _headers() {
    return {
      'Content-Type': 'application/json',
      'Authorization': 'Bearer $apiKey',
    };
  }

  ApiProvider() {
    httpClient.baseUrl = baseUrl;
    httpClient.timeout = timeout;
    httpClient.addAuthenticator((request)  {
      request.headers.addAll(_headers());
      return request;
    });
  }

  Future<Response> completions(String body) {
    return post('/v1/chat/completions', body);
  }
}

在这个类中,我们设置了 API 的基础 URL 和超时时间,并实现了 HTTP 请求的授权和身份验证。我们还实现了completions方法,用于向 OpenAI API 发送请求并获取聊天机器人的回复。注意这里需要设置自己账号的API KEY, 地址: https://platform.openai.com/account/api-keys

接下来,我们需要创建一个ChatLogic类,用于处理聊天机器人的逻辑。以下是ChatLogic类的代码:

class ChatLogic extends GetxController {
  final ChatState state = ChatState();
  final ApiProvider provider = ApiProvider();

  Future<void> sendMessage(String content) async {
    state.requestStatus(content);
    update();
    final response = await provider.completions(json.encode({
      "model": "gpt-3.5-turbo",
      "messages": [{"role": "user", "content": "$content"}]
    }));
    try {
      if(response.statusCode == 200) {
        final data = response.body;
        final text = data['choices'][0]['message']['content'];
        state.responseStatus(text);
      } else {
        state.responseStatus(response.statusText ?? '请求错误,请稍后重试');
      }
    } catch(error) {
      state.responseStatus(error.toString());
    }
    update();
  }
}

在这个类中,我们创建了一个sendMessage方法,该方法接收用户的消息并发送给 OpenAI API,然后等待 API 返回响应。在收到响应后,我们将从 API 返回的 JSON 数据中提取出回复消息的内容,并将其更新到ChatState状态类的messages列表中,然后在 UI 中显示。

接下来,我们需要创建一个ChatState类来管理我们的应用程序状态。以下是ChatState类的代码:

class ChatState {

  String message = '';
  String sender = 'user';
  bool isRequesting = false;
  List<Map<String, dynamic>> messages = [];

  void requestStatus(String content) {
    messages.add({'text': content, 'sender': 'user'});
    sender = 'bot';
    messages.add({'text': '正在回复中...', 'sender': sender});
    isRequesting = true;
    message = '';
  }

  void responseStatus(String content) {
    messages.removeLast(); // Remove "正在回复中..." 状态
    messages.add({'text': content, 'sender': sender});
    sender = 'user';
    isRequesting = false;
  }
}

在这个类中,存储了聊天应用程序的状态信息,包括消息、发送者、请求状态和历史消息列表。requestStatus()方法用于更新状态以反映正在发送消息的状态,responseStatus()方法用于更新状态以反映接收到的消息。

最后,我们定义了ChatPage类,它继承自StatelessWidget,它将用于展示聊天对话框。以下是ChatPage类的代码:

class ChatPage extends StatelessWidget {
  ChatPage({Key? key}) : super(key: key);

  final logic = Get.put(ChatLogic());
  final state = Get.find<ChatLogic>().state;

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        centerTitle: true,
        title: Text('你问我答'),
      ),
      body: GetBuilder<ChatLogic>(
        builder: (context) => Column(
          children: [
            Expanded(
              child: ListView.builder(
                itemCount: state.messages.length,
                itemBuilder: (BuildContext context, int index) {
                  Map m = state.messages[index];
                  return Padding(
                    padding: const EdgeInsets.all(8.0),
                    child: Row(
                      mainAxisAlignment: m['sender'] == 'user'
                          ? MainAxisAlignment.end
                          : MainAxisAlignment.start,
                      children: [
                        Flexible(
                          child: Container(
                            padding: const EdgeInsets.all(8.0),
                            decoration: BoxDecoration(
                              borderRadius: BorderRadius.circular(8.0),
                              color: m['sender'] == 'user'
                                  ? Colors.green[100]
                                  : Colors.white,
                            ),
                            child: Text(m['text']),
                          ),
                        )
                      ],
                    ),
                  );
                },
              ),
            ),
            Container(
              decoration: BoxDecoration(
                color: Colors.white,
                borderRadius: BorderRadius.only(
                  topLeft: Radius.circular(12.0),
                  topRight: Radius.circular(12.0),
                ),
              ),
              child: Row(
                children: [
                  Expanded(
                    child: Padding(
                      padding: const EdgeInsets.all(8.0),
                      child: TextField(
                          decoration: InputDecoration(
                            hintText: '请输入消息',
                            border: InputBorder.none,
                          ),
                          controller:
                              TextEditingController(text: state.message),
                          onChanged: (value) {
                            state.message = value;
                          }),
                    ),
                  ),
                  IconButton(
                    icon: Icon(Icons.send),
                    onPressed: state.isRequesting
                        ? null
                        : () {
                            logic.sendMessage(state.message);
                          },
                  ),
                ],
              ),
            ),
          ],
        ),
      ),
    );
  }
}

该类包含一个ChatLogic实例和一个ChatState实例。在build()方法中,我们使用GetBuilder包装整个聊天界面。这个界面包括一个消息列表和一个输入框,用户可以在其中输入消息并发送给聊天机器人。ListView.builder用于显示历史消息,TextFieldIconButton用于接收用户输入并发送消息。在发送消息之前,会检查当前状态是否为请求状态,以避免重复发送请求。

到这里一个简单的聊天功能就完成了,运行下看看效果吧:

在这里插入图片描述

综上所述,本篇介绍了一个使用 Flutter 和 OpenAI API 实现的基于 GPT-3 的聊天机器人。通过实现ApiProvider、ChatLogicChatState类,我们能够将 OpenAI API 的功能集成到 Flutter 应用程序中,并实现一个基本的聊天界面。感兴趣的小伙们可以自己试试哈,Demo地址:https://github.com/smallmarker/OpenAIChat

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

学大数据算跟风吗?

随着互联网、物联网和人工智能等技术的不断发展&#xff0c;大数据技术逐渐进入人们的视野&#xff0c;成为一个备受关注的热点话题。那么&#xff0c;大数据专业好学吗&#xff1f;前景如何&#xff1f;下面我们来一起探讨一下。 一、大数据专业的学习难度 大数据技术是一种综…

八大排序算法之归并排序(递归实现+非递归实现)

目录 一.归并排序的基本思想 归并排序算法思想(排升序为例) 二.两个有序子序列(同一个数组中)的归并(排升序) 两个有序序列归并操作代码: 三.归并排序的递归实现 递归归并排序的实现:(后序遍历递归) 递归函数抽象分析: 四.非递归归并排序的实现 1.非递归归并排序算法…

全景丨0基础学习VR全景制作,后期篇第九章:控制点和遮罩工具

本节教程&#xff0c;我们介绍拼接软件PTGui Pro 矫正拉直全景图水平的方法。矫正拉直全景图可以通过后期软件PTGui做到&#xff0c;但我更想跟大家强调的是前期拍摄时&#xff0c;查看水平仪&#xff0c;调平三脚架尤为重要。后期软件强行矫正&#xff0c;不可避免的会因为追求…

蓝桥杯Web前端练习题-----水果拼盘

一、水果拼盘 介绍 目前 CSS3 中新增的 Flex 弹性布局已经成为前端页面布局的首选方案&#xff0c;本题可以使用 Flex 属性快速完成布局。 准备 开始答题前&#xff0c;需要先打开本题的项目代码文件夹&#xff0c;目录结构如下&#xff1a; ├── css │ └── style.…

acm省赛:高桥和低桥(三种做法:区间计数、树状数组、线段树)

题目描述 有个脑筋急转弯是这样的&#xff1a;有距离很近的一高一低两座桥&#xff0c;两次洪水之后高桥被淹了两次&#xff0c;低桥却只被淹了一次&#xff0c;为什么&#xff1f;答案是&#xff1a;因为低桥太低了&#xff0c;第一次洪水退去之后水位依然在低桥之上&#xff…

chatGPT爆火,什么时候中国能有自己的“ChatGPT“

目录 引言 一、ChatGPT爆火 二、中国何时能有自己的"ChatGPT" 三、为什么openai可以做出chatGPT? 四、结论 引言 随着人工智能技术的不断发展&#xff0c;自然语言处理技术也逐渐成为了研究的热点之一。其中&#xff0c;ChatGPT作为一项领先的自然语言处理技术…

PID控制算法详解

1. 前言 PID 即 Proportional&#xff08;比例&#xff09;&#xff0c;Integral&#xff08;积分&#xff09;&#xff0c;Differential&#xff08;微分&#xff09;的英文缩写。顾名思义&#xff0c;PID 控制算法是结合比例&#xff0c;积分和微分三种环节于一体的自动控制…

刷题之最长公共/上升子序列问题

目录 一、最长公共子序列问题&#xff08;LCS&#xff09; 1、题目 2、题目解读 ​编辑 3、代码 四、多写一题 五、应用 二、最长上升子序列问题&#xff08;LIS&#xff09; 1、题目 2、题目解读 3、代码 四、多写一道 Ⅰ、题目解读 Ⅱ、代码 一、最长公共子序列问题&…

Android实时显示时间日期(极简)

Android实时显示时间日期示例图示例图解析TextClock时间控件常用的xml属性及常用方法示例源代码.xml文件.java示例图 示例图解析 格式说明yyyy/MM/dd年月日HH:mm:ss时分秒EEEE星期几EE周几 TextClock时间控件 常用的xml属性及常用方法 属性对应的方法说明android:timeZonese…

7个最好的PDF编辑器,帮你像编辑Word一样编辑PDF

PDF 是具有数字思维的组织的重要交流工具。提供高效的工作流程和更好的安全性&#xff0c;可以创建重要文档并与客户、同事和员工共享。文档的布局已锁定&#xff0c;因此无论在什么设备上查看&#xff0c;格式都保持不变。这是让每个人保持一致的好方法——尤其是那些使用Micr…

JVM垃圾回收机制

文章目录JVM垃圾回收机制如何确定该对象是垃圾引用计数可达性分析如何释放对象常用策略JVM垃圾回收机制 以对象为单位来进行回收 如何确定该对象是垃圾 Java 中使用 可达性分析方法 Python 中时使用 引用计数方法 引用计数 使用额外的计数器&#xff0c;来记录某个对象有多少个…

文件上传的多种利用方式

文件上传的多种利用方式 文件上传漏洞除了可以通过绕过检测进行webshell的上传之外&#xff0c;还有多种其它的漏洞可以进行测试。 XSS漏洞 文件名造成的XSS 当上传任何文件时&#xff0c;文件名肯定是会反显示在网页上&#xff0c;可以使用 XSS Payload做文件名尝试将其上传到…

JeecgBoot 3.5.0 版本发布,开源的企业级低代码平台

项目介绍 JeecgBoot是一款企业级的低代码平台&#xff01;前后端分离架构 SpringBoot2.x&#xff0c;SpringCloud&#xff0c;Ant Design&Vue3&#xff0c;Mybatis-plus&#xff0c;Shiro&#xff0c;JWT 支持微服务。强大的代码生成器让前后端代码一键生成! JeecgBoot引领…

Winform/Csharp中使用StackExchange.Redis连接Redis存取数据并序列化对象/反序列化(支持redis key 模糊搜索)

场景 在winform程序中&#xff0c;需要连接Redis并根据Key进行模糊搜索&#xff0c;对value值进行反序列化为 对象之后进行数据处理和显示。 ServiceStack.redis 这里不使用servicestack.redis&#xff0c;因为这个已经商业化了&#xff0c;会出现每小时6000条数据的限制。…

如何将字符串反转?

参考答案 使用 StringBuilder 或 StringBuffer 的 reverse 方法&#xff0c;本质都调用了它们的父类 AbstractStringBuilder 的 reverse 方法实现。&#xff08;JDK1.8&#xff09;不考虑字符串中的字符是否是 Unicode 编码&#xff0c;自己实现。递归1. public AbstractStrin…

6.网络爬虫——BeautifulSoup详讲与实战

网络爬虫——BeautifulSoup详讲与实战BeautifulSoup简介&#xff1a;BS4下载安装BS4解析对象Tag节点遍历节点find_all()与find()find_all()find()豆瓣电影实战前言&#xff1a; &#x1f4dd;​&#x1f4dd;​此专栏文章是专门针对网络爬虫基础&#xff0c;欢迎免费订阅&#…

数据结构中的堆

一、树的重要知识点 节点的度&#xff1a;一个节点含有的子树的个数称为该节点的度&#xff08;有几个孩子&#xff09;叶节点或终端节点:度为0的节点称为叶节点&#xff1b;如上图&#xff1a;B、C、H、I...等节点为叶节点&#xff08;0个孩子&#xff09;非终端节点或分支节点…

java与Spring的循环依赖

java与Spring的循环依赖一、循环依赖是什么有什么危害二、循环依赖在Spring中的体现和类型三、Spirng如何解决循环依赖四、总结一、循环依赖是什么有什么危害 什么是循环依赖 java中循环依赖用一张图来说就是下图&#xff1a;在对象的创建过程中多个对象形成了依赖闭环&#xf…

指针进阶(中)

提示&#xff1a; 上集内容小复习&#x1f970;&#x1f970; int my_strlen(const char* str) {return 1; } int main() {//指针数组char* arr[10];//数组指针int arr2[5] { 0 };int(*p)[5] &arr2; //p是一个指向数组的指针变量//函数指针int (*pf)(const char*)&m…

对于并发的学习-AQS

AbstractQueueSynchronized AQS 是一个用来构建锁和同步器的框架&#xff0c;使用 AQS 能简单且高效地构造出应用广泛的大量的同步器&#xff0c;比如 ReentrantLock&#xff0c;Semaphore等。 AQS的原理 核心思想&#xff1a; 如果被请求的共享资源空闲&#xff0c;则将当前…
最新文章