当前位置: 首页 > news >正文

用Rust实现免费调用ChatGPT的命令行工具 (一)

代码已经开源:🚀 fgpt 欢迎大家star⭐和fork 👏

ChatGPT现在免费提供了GPT3.5的Web访问,不需要注册就可以直接使用,但是,它的使用方式是通过Web页面,不够方便。

更多技术分享关注 入职啦(https://ruzhila.cn/?from=csdn)

Shell-GPT 是一个流行的OpenAI 命令行工具,可以调用ChatGPT的API,但是它需要注册并获取API密钥,并且需要Python环境,对于一些不熟悉Python的用户来说,可能不太方便。

无依赖命令行使用GPT还是非常方便的,因此我决定用Rust实现一个类似的工具💡,不需要注册就可以直接使用,支持CLIOpenAI API代理的两种模式, 实际的运行效果:

在这里插入图片描述

📖 文章系列分为三部分发布,记录完整的过程:

  • 基于ChatGPT的Web API实现基本的调用,内置支持代理(这个很重要)
  • 完善命令行的功能: 支持代码、文件输入、交互式输入等
  • 实现OpenAI API代理,兼容OpenAI的OpenAPI接口, 等同于免费使用GPT3.5的API

ChatGPT的Web API工作流程

通过分析ChatGPT的Web API,我们可以发现它的工作流程如下:

  • 调用backend-anon/sentinel/chat-requirements接口,获取一个token
  • 调用backend-anon/conversation接口,基于SSE获取聊天的结果

所以要做的事情,就是根据这个流程,用Rust实现完整的流程,已达到调用ChatGPT的目的。

我设计了一个简单的使用方式:

fgpt "输出一段python代码,实现字符串反转"

fgpt这个命令行工具,会调用ChatGPT的Web API,返回一段Python代码,并且根据SSE实现打字机的效果和交互式的输入。

需要用到哪些Rust的库(第一个版本)

第一个版本目标是完成基本的调用,所以只需要能使用命令行参数、发送HTTP请求、序列化和反序列化、日志输出、生成uuid、正则表达式匹配、实现Stream的功能等。

第一个版本大概需要用到以下几个库:

  • clap 用于解析命令行参数
  • reqwest 用于发送HTTP请求
  • tokio 用于异步编程
  • serde 用于序列化和反序列化
  • logenv_logger 用于日志输出
  • uuid用来生成uuidregex 用于正则表达式匹配
  • featuresBytes 用于实现Stream的功能

程序结构分析

fgpt的代码结构如下:

mpi@mpis-Mac-mini fgpt % ls src 
cli.rs          main.rs         proxy.rs        fgpt.rs

主要的代码实现在src/fgpt.rs中,src中包含了cli.rsproxy.rs两个模块,分别实现了CLIOpenAI API代理的功能。

fgpt.rs 的实现

命令行API代理只是呈现的方式不同,但是实现的逻辑是一样的,背后调用的都是fgpt.rs的逻辑。

所以我基于Stream的特性,设计了一个能够支持CLIAPI代理的通用的Stream,可以充分利用好``Stream`的特性:

pub(crate) struct CompletionStream {response_stream: Pin<Box<dyn Stream<Item = Result<Bytes, reqwest::Error>> + Send>>,
}impl Stream for CompletionStream {type Item = reqwest::Result<String>;fn poll_next(mut self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Option<Self::Item>> {match self.response_stream.as_mut().poll_next(cx) {Poll::Ready(Some(Ok(data))) => {....},}}}
}/// 调用实现这样的效果,这样就可以支持CLI和API代理
let stream = CompletionStream::new(reqwest::Client::new(), url, token);
while let Some(result) = stream.next().await {println!("{}", result.unwrap());
}

解析Web API的返回结果

ChatGPT的返回结果是一个SSE的流,从测试的情况来看,返回有3种情况:

  • data: {"message": .... } 表示返回的是聊天的结果
  • data: 2024-03-12 12:12:14.12 表示这个是一个心跳包
  • data: [DONE] 表示当前的聊天结束

根据这个特点,实现了一个Enum用来表示这三种情况:

enum ChatGPTResponse {Data(CompletionResponse),Done,Heartbeat,Text(String),
}

为了考虑后续的兼容性,当出现消息不能被CompletionResponse解析当时候,还能够返回原始的消息,多兼容了一个Text当类型:

CompletionResponse是根据ChatGPT返回的消息解析出来的结构体,不展开讨论

impl From<&BytesMut> for CompletionEvent {fn from(line: &BytesMut) -> CompletionEvent {...serde_json::from_str(line_str).map(CompletionEvent::Data).unwrap_or(CompletionEvent::Text(line_str.to_string()))}}
}

如何实现打字机的效果

根据OpenAI的OpenAPI文档,我们可以知道,ChatGPT的返回结果是一个Delta的结果,也就是说,每次返回的结果都是上一次的增量。

但是Web API并没有这个Delta的字段,每次返回都是完整的结果,所以我们需要自己实现这个效果。 这个实现也是比较简单,就是保留上一次的结果,然后和当前的结果进行比较,然后输出差异部分, 实际上用的是strip_prefix这个函数:

let mut textbuf = String::new();while let Some(message) = stream.next().await {match message {Ok(crate::fgpt::CompletionEvent::Data(message)) => {let text = message.message.content.parts.join("\n");let delta_chars = text.strip_prefix(textbuf.as_str()).unwrap_or(text.as_str());textbuf = text.clone();print!("{}", delta_chars);let _ = std::io::stdout().flush();}}....}

为了实现打字机的效果,print!(..)之后,需要flush一下,这样才能实现效果,否则会等到换行的时候才输出,不符合我们的预期。

总结

这个工具是昨天开始构思,下午吃完饭的时候开始写,晚上就写完第一个可以运行的版本,总共写了410行的Rust代码,明天会继续完善功能,实现更多的功能,比如支持文件输入、代码输入、交互式输入等。

可以加群学习
在这里插入图片描述

相关文章:

用Rust实现免费调用ChatGPT的命令行工具 (一)

代码已经开源&#xff1a;&#x1f680; fgpt 欢迎大家star⭐和fork &#x1f44f; ChatGPT现在免费提供了GPT3.5的Web访问&#xff0c;不需要注册就可以直接使用&#xff0c;但是&#xff0c;它的使用方式是通过Web页面&#xff0c;不够方便。 更多技术分享关注 入职啦&…...

mysql 查询实战1-题目

学习了mysql 查询实战-变量方式-解答-CSDN博客&#xff0c;接着练习sql&#xff0c;从实战中多练习。 1&#xff0c;题目&#xff1a; 1&#xff0c;查询部门工资最高的员工 1&#xff0c;建表&#xff1a; DROP TABLE IF EXISTS department; create table department(dept_i…...

Word学习笔记之奇偶页的页眉与页码设置

1. 常用格式 在毕业论文中&#xff0c;往往有一下要求&#xff1a; 奇数页右下角显示、偶数页左下角显示奇数页眉为每章标题、偶数页眉为论文标题 2. 问题解决 2.1 前期准备 首先&#xff0c;不论时要求 1、还是要求 2&#xff0c;这里我们都要做一下设置&#xff1a; 鼠…...

数据赋能(58)——要求:数据赋能实施部门能力

“要求&#xff1a;数据赋能实施部门能力”是作为标准的参考内容编写的。 在实施数据赋能中&#xff0c;数据赋能实施部门的能力体现在多个方面&#xff0c;关键能力如下图所示。 在实施数据赋能的过程中&#xff0c;数据赋能实施部门应具备的关键能力如下。 理性思维与逻辑分…...

Unity URP PBR_Cook-Torrance模型

Cook-Torrance模型是一个微表面光照模型&#xff0c;认为物体的表面可以看作是由许多个理想的镜面反射体微小平面组成的。 单点反射镜面反射漫反射占比*漫反射 漫反射 基础色/Π 镜面反射DFG/4(NV)(NL) D代表微平面分布函数&#xff0c;描述的是法线与半角向量normalize(L…...

Unity之XR Interaction Toolkit如何在VR中实现渐变黑屏效果

前言 做VR的时候,有时会有跳转场景,切换位置,切换环境,切换进度等等需求,此时相机的画面如果不切换个黑屏,总会感觉很突兀。刚好Unity的XR Interaction Toolkit插件在2.5.x版本,出了一个TunnelingVignette的效果,我们今天就来分析一下他是如何使用的,然后我们自己再来…...

html+vue编写分页功能

效果&#xff1a; html关键代码&#xff1a; <div class"ui-jqgrid-resize-mark" id"rs_mlist_table_C87E35BE"> </div><div class"list_component_pager ui-jqgrid-pager undefined" dir"ltr"><div id"pg…...

计算机网络 实验指导 实验17

实验17 配置无线网络实验 1.实验拓扑图 Table PC0 和 Table PC1 最开始可能还会连Access Point0&#xff0c;无影响后面会改 名称接口IP地址网关地址Router0fa0/0210.10.10.1fa0/1220.10.10.2Tablet PC0210.10.10.11Tablet PC1210.10.10.12Wireless互联网220.10.10.2LAN192.16…...

在 Vue中,v-for 指令的使用

在 Vue中&#xff0c;v-for 指令用于渲染一个列表&#xff0c;基于源数据多次渲染元素或模板块。它对于展示数组或对象中的数据特别有用。 数组渲染 假设你有一个数组&#xff0c;并且你想为每个数组元素渲染一个 <li> 标签&#xff1a; <template> <ul>…...

达梦数据库执行sql报错:数据溢出

数据库执行sql报错数据溢出 单独查询对应的数字进行计算是不是超过了某个字段类型的上限或下限 如果已经超过了&#xff0c;进行对字段进行cast类型转换处理&#xff0c;转换为dec num都可以尝试 这里就是从 max(T.BLOCK_ID as dec*8192t.bytes)/1024/1024 max_MB,换成了这个…...

从「宏大叙事」到「生活叙事」,小红书品牌种草的的“正确姿势”

不同于抖音和微博&#xff0c;在小红书上&#xff0c;品牌营销的基调应该是怎样的&#xff1f;品牌怎样与小红书用户对话&#xff1f;什么样的内容&#xff0c;才能走进小红书用户的心中&#xff1f;本期&#xff0c;小编将带大家洞察品牌在小红书营销的“正确姿势”。从「小美…...

Python Selenium 的基本使用方法

文章目录 1. 概述2. 安装Chrome及ChromeDriver2.1 安装Chrome2.2 安装ChromeDriver 3. 安装Selenium4. 常见用法4.1 启动4.2 查找元素4.3 等待页面加载元素 1. 概述 Selenium 是一个用于自动化 web 浏览器的工具&#xff0c;它提供了一套用于测试 web 应用程序的工具和库。Sel…...

上位机图像处理和嵌入式模块部署(树莓派4b固件功能设计)

【 声明&#xff1a;版权所有&#xff0c;欢迎转载&#xff0c;请勿用于商业用途。 联系信箱&#xff1a;feixiaoxing 163.com】 前面我们说过&#xff0c;上位机的功能都是基于插件进行开发的。但是上位机的成本比较贵&#xff0c;一般的企业不一定愿意接接受。这个时候另外一…...

新手入门人工智能:从零开始学习AI的正确途径

你是否对人工智能&#xff08;AI&#xff09;充满了好奇心和探索欲&#xff1f;你是否想了解如何从零开始学习AI&#xff0c;成为一名人工智能领域的专家&#xff1f;那么&#xff0c;这篇文章就是为你准备的&#xff01;我们将带你了解人工智能的基本概念&#xff0c;学习如何…...

ubuntu git相关操作

1 安装git sudo apt install git git --version git version 2.25.1 2 解决git超时 2.1 扩大post的buffer git config --global http.postBuffer 524288000 git config --global http.postBuffer 157286400 2.2 换回HTTP1上传。上传之后再切换回HTTP2 …...

IDEA工具|添加 GitLab 账户之两三事

&#x1f4eb; 作者简介&#xff1a;「六月暴雪飞梨花」&#xff0c;专注于研究Java&#xff0c;就职于科技型公司后端工程师 &#x1f3c6; 近期荣誉&#xff1a;华为云云享专家、阿里云专家博主、腾讯云优秀创作者、ACDU成员 &#x1f525; 三连支持&#xff1a;欢迎 ❤️关注…...

蓝桥杯:棋盘(Java)

目录 问题描述输入格式输出格式代码实现 问题描述 小蓝拥有n n大小的棋盘&#xff0c;一开始棋盘上全都是白子。小蓝进行了m.次操作&#xff0c;每次操作会将棋盘上某个范围内的所有棋子的颜色取反&#xff08;也就是白色棋子变为黑色&#xff0c;黑色棋子变为白色)。请输出所…...

跨界融合:ERP与TMS的区分、相通之处、融合方式,全告诉你。

Hi&#xff0c;如今系统的边界越来越模糊&#xff0c;A系统和B系统会有一些功能的交叉&#xff0c;贝格前端工场今天开始介绍第二篇ERP和TMS的融合。 一、什么是ERP和TMS ERP是企业资源规划&#xff08;Enterprise Resource Planning&#xff09;的缩写&#xff0c;是一种集成…...

SAP Smartform转存PDF方法汇总

用户会有保存SF至本地PDF文件的需求,下面详细说明一下Smartform转成PDF的四种方法,其中,方法二和三相比于其他方法更便捷实用,如果还有其他方法,欢迎留言补充。 一、代码开发 1)先调用smartform函数获取OTF格式数据 2)后调用函数CONVERT_OTF转换成PDF格式数据 3)再…...

Linux【实战篇】—— NFS服务搭建与配置

目录 一、介绍 1.1什么是NFS&#xff1f; 1.2客户端与服务端之间的NFS如何进行数据传输&#xff1f; 1.3RPC和NFS的启动顺序 1.4NFS服务 系统守护进程 二、安装NFS服务端 2.1安装NFS服务 2.2 创建共享目录 2.3创建共享目录首页文件 2.4关闭防火墙 2.5启动NFS服务 2.…...

【论文笔记】若干矿井粉尘检测算法概述

总的来说&#xff0c;传统机器学习、传统机器学习与深度学习的结合、LSTM等算法所需要的数据集来源于矿井传感器测量的粉尘浓度&#xff0c;通过建立回归模型来预测未来矿井的粉尘浓度。传统机器学习算法性能易受数据中极端值的影响。YOLO等计算机视觉算法所需要的数据集来源于…...

ElasticSearch搜索引擎之倒排索引及其底层算法

文章目录 一、搜索引擎1、什么是搜索引擎?2、搜索引擎的分类3、常用的搜索引擎4、搜索引擎的特点二、倒排索引1、简介2、为什么倒排索引不用B+树1.创建时间长,文件大。2.其次,树深,IO次数可怕。3.索引可能会失效。4.精准度差。三. 倒排索引四、算法1、Term Index的算法2、 …...

MySQL中【正则表达式】用法

MySQL 中正则表达式通过 REGEXP 或 RLIKE 操作符实现&#xff08;两者等价&#xff09;&#xff0c;用于在 WHERE 子句中进行复杂的字符串模式匹配。以下是核心用法和示例&#xff1a; 一、基础语法 SELECT column_name FROM table_name WHERE column_name REGEXP pattern; …...

UR 协作机器人「三剑客」:精密轻量担当(UR7e)、全能协作主力(UR12e)、重型任务专家(UR15)

UR协作机器人正以其卓越性能在现代制造业自动化中扮演重要角色。UR7e、UR12e和UR15通过创新技术和精准设计满足了不同行业的多样化需求。其中&#xff0c;UR15以其速度、精度及人工智能准备能力成为自动化领域的重要突破。UR7e和UR12e则在负载规格和市场定位上不断优化&#xf…...

在WSL2的Ubuntu镜像中安装Docker

Docker官网链接: https://docs.docker.com/engine/install/ubuntu/ 1、运行以下命令卸载所有冲突的软件包&#xff1a; for pkg in docker.io docker-doc docker-compose docker-compose-v2 podman-docker containerd runc; do sudo apt-get remove $pkg; done2、设置Docker…...

智能分布式爬虫的数据处理流水线优化:基于深度强化学习的数据质量控制

在数字化浪潮席卷全球的今天&#xff0c;数据已成为企业和研究机构的核心资产。智能分布式爬虫作为高效的数据采集工具&#xff0c;在大规模数据获取中发挥着关键作用。然而&#xff0c;传统的数据处理流水线在面对复杂多变的网络环境和海量异构数据时&#xff0c;常出现数据质…...

服务器--宝塔命令

一、宝塔面板安装命令 ⚠️ 必须使用 root 用户 或 sudo 权限执行&#xff01; sudo su - 1. CentOS 系统&#xff1a; yum install -y wget && wget -O install.sh http://download.bt.cn/install/install_6.0.sh && sh install.sh2. Ubuntu / Debian 系统…...

【C++进阶篇】智能指针

C内存管理终极指南&#xff1a;智能指针从入门到源码剖析 一. 智能指针1.1 auto_ptr1.2 unique_ptr1.3 shared_ptr1.4 make_shared 二. 原理三. shared_ptr循环引用问题三. 线程安全问题四. 内存泄漏4.1 什么是内存泄漏4.2 危害4.3 避免内存泄漏 五. 最后 一. 智能指针 智能指…...

【Linux手册】探秘系统世界:从用户交互到硬件底层的全链路工作之旅

目录 前言 操作系统与驱动程序 是什么&#xff0c;为什么 怎么做 system call 用户操作接口 总结 前言 日常生活中&#xff0c;我们在使用电子设备时&#xff0c;我们所输入执行的每一条指令最终大多都会作用到硬件上&#xff0c;比如下载一款软件最终会下载到硬盘上&am…...

Python 高效图像帧提取与视频编码:实战指南

Python 高效图像帧提取与视频编码:实战指南 在音视频处理领域,图像帧提取与视频编码是基础但极具挑战性的任务。Python 结合强大的第三方库(如 OpenCV、FFmpeg、PyAV),可以高效处理视频流,实现快速帧提取、压缩编码等关键功能。本文将深入介绍如何优化这些流程,提高处理…...