前言
ChatGPT已经非常火爆了,企业开始招聘ChatGPT工程师,可能对接ChatGPT接口进行企业级开发是程序员必备的技能了。本篇文章主要是基于ChatGPT开发接口进行对接,使用微信小程序制作一款自己的聊天机器人,通过这一案例你可以展开无限的扩展
整体设计
整体设计比较简单,我们使用微信小程序作为客户端界面提供用户使用,小程序和后台使用WebSocket进行通信。
最终效果如下
ChatGPT接口对接
注意要有梯子才可以访问,接口参考文档:https://platform.openai.com/docs/api-reference/chat ,在Api Reference 接口文档中找到Chat ,里面有Chat对话接口的请求说明
根据文档说明,我们需要构建一个请求地址为:https://api.openai.com:443/v1/chat/completions ,post请求提交,参数为:
{
"model":"gpt-3.5-turbo",
"messages":[
{
"role":"user",
"content":"SpringBoot是什么"
}
]
}
这样还不够,如果直接访问会报错:apikey不存在,我们还需要创建一个APIKEY,地址:https://platform.openai.com/account/api-keys
然后我这里使用Postmain做一个简单测试,请求头加上APIKEY
在Body中构建请求参数效果如下
根据结果可以看到返回的格式为
{
"id": "chatcmpl-7A6KvI2ybOjR2xHvejz3ysoDFmA54",
"object": "chat.completion",
"created": 1682641993,
"model": "gpt-3.5-turbo-0301",
"usage": {
"prompt_tokens": 14,
"completion_tokens": 147,
"total_tokens": 161
},
"choices": [
{
"message": {
"role": "assistant",
"content": "Spring Boot 是 Spring 框架的一部分,是一个快速开发框架,可以从头开始构建独立的 Spring 应用程序。它通过自动配置功能和嵌入式 Web 服务器可以快速地开发出一个基于 Spring 框架的 Web 应用程序。Spring Boot 构建于 Spring 框架之上,使得开发者可以更方便地集成 Spring 框架的各种组件和其他第三方库,同时避免了繁琐的 XML 配置。"
},
"finish_reason": "stop",
"index": 0
}
]
}
编写后台
后台我们使用SpringBoot快速开发,主要是整合websocket收发消息,需要导入的pom如下
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-websocket</artifactId>
</dependency>
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>fastjson</artifactId>
<version>1.2.78</version>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
</plugin>
</plugins>
</build>
第二步,启动类中定义RestTemplate,方便后续向ChatGPT发请求
@SpringBootApplication
public class ChatGptApp {
public static void main(String[] args) {
SpringApplication.run(ChatGptApp.class);
}
@Bean
public RestTemplate restTemplate(){
return new RestTemplate();
}
}
第三步,配置websocket,如下
@Configuration
public class WebSocketConfig {
@Bean
public ServerEndpointExporter serverEndpointExporter() {
return new ServerEndpointExporter();
}
}
第四步:编写请求实体类,根据ChatGPT要求的请求参数来封装
@Data
public class ChatMessageParam {
//model 代表了使用chatgpt的哪个模型
private String model = "gpt-3.5-turbo";
//请求消息,要去以数组格式
private List<ChatMessage> messages = new ArrayList<>();
//往message中添加message
public void addMessages(ChatMessage message) {
this.messages.add(message);
}
public ChatMessageParam(){}
public ChatMessageParam(ChatMessage message){
this.messages.add(message);
}
}
@Data
@NoArgsConstructor
@AllArgsConstructor
public class ChatMessage {
private String role;
private String content;
}
下面是参数配置application.yaml中的配置和属性对象
server:
port: 80
chatgpt:
apikey: 你的apikey
apiurl: "https://api.openai.com:443/v1/chat/completions"
//参数对象
@Component
@ConfigurationProperties(prefix = "chatgpt")
@Data
public class ChatGptProperties {
private String apikey;
private String apiurl;
}
第五步:编写请求发送逻辑,底层使用的是RestTmpalte来发送.这里需要两个参数 APIKEY和URL地址,我在yaml中进行了配置,并使用对象进行绑定
@Component
@Slf4j
public class ChatHttpSender {
//HTTP客户端
@Autowired
private RestTemplate restTemplate;
//ChtGPT配置
@Autowired
private ChatGptProperties chatProperties;
public String post(String message){
//封装参数对象
ChatMessageParam param = new ChatMessageParam(new ChatMessage(ChatGptConstants.ROLE,message));
//添加请求头
HttpHeaders httpHeaders = new HttpHeaders();
//设置apikey
httpHeaders.add(AUTHORIZATION,String.format(PRE_BEARER,chatProperties.getApikey()));
httpHeaders.add("text/plain", StandardCharsets.UTF_8.toString());
httpHeaders.add("Content-Type", "application/json");
//构建Post请求
HttpEntity entity = new HttpEntity(param,httpHeaders);
log.info("发送请求 {}",entity);
//向ChatGPT发送请求
String json = restTemplate.postForObject(chatProperties.getApiurl(), entity, String.class);
//解析结果,拿到message
JSONArray choices = JSON.parseObject(json).getJSONArray("choices");
JSONObject jsonObject = choices.getJSONObject(0);
String content = jsonObject.getJSONObject("message").getString("content");
log.info("拿到结果 {}",content);
return content;
}
}
//常量类
public class ChatGptConstants {
public static final String MODEL = "gpt-3.5-turbo";
public static final String ROLE = "user";
public static final String AUTHORIZATION = "Authorization";
public static final String PRE_BEARER = "Bearer %s";
}
第六步,编写websocket服务端,主需要是收到消息后调用ChatHttpSender发送请求,然后把结果写回给客户端。这里我使用的是RedsTemplate调用ChatGpt接口,因为是同步,会出现等待的情况
package org.example.socket;
import lombok.extern.slf4j.Slf4j;
import org.example.http.ChatHttpSender;
import org.springframework.stereotype.Component;
import javax.annotation.Resource;
import javax.websocket.*;
import javax.websocket.server.PathParam;
import javax.websocket.server.ServerEndpoint;
import java.io.IOException;
import java.util.concurrent.ConcurrentHashMap;
@Component
//服务器端点
@ServerEndpoint("/chatWebSocket/{uid}")
@Slf4j
public class ChatSocketServer {
//定义了一个请求发送器
private static ChatHttpSender httpSender;
//用map把websocket客户端存储七年,客户端集合,key是uid
private static ConcurrentHashMap<String, ChatSocketServer> socketClients = new ConcurrentHashMap<>();
//会话对象,通过他来向客户端发请求
private Session session;
//接收uid,代表客户端用户
private String uid = "";
//注入sender
@Resource
public void setHttpSender(ChatHttpSender httpSender){
this.httpSender = httpSender;
}
/**
* 建立连接
* @param session 会话
* @param uid 连接用户名称
*/
@OnOpen
public void onOpen(Session session, @PathParam("uid") String uid) {
this.session = session;
this.uid = uid;
socketClients.put(uid, this);
log.info("客户端{} , 建立连接",uid);
}
@OnClose
public void onClose() {
socketClients.remove(uid);
log.info("客户端{} , 关闭连接",uid);
}
@OnMessage
public void onMessage(String message, Session session) {
log.info("收到消息,UID:{} 内容: {} ",uid,message);
try {
//httpSender向chatGPT发起请求,拿到结果
String result = httpSender.post(message);
//给客户端返回结果
sendMessage(result);
}catch (Exception e){
e.printStackTrace();
sendMessage("服务器故障");
}
}
@OnError
public void onError(Session session, Throwable error) {
error.printStackTrace();
log.error("发生错误,{} ",uid,error.getMessage());
}
public void sendMessage(String message) {
log.error("发送消息,UID:{} ,内容:{} ",uid,message);
try {
this.session.getBasicRemote().sendText(message);
} catch (IOException e) {
throw new RuntimeException(e);
}
}
}
服务端上云
ChatGPT需要梯子才能访问,所以在本地是测不通的,建议直接买一台国外的服务器进行部署。购买云服务器可以看这篇文章《购买一台云服务器》,记得买国外的服务器。然后把项目打成jar包,进入项目根目录执行:mvn install ,在target目录找到项目比如:springboot-chatgpt-1.0-SNAPSHOT.jar 。然后上传到云服务器上,执行Java -jar 即可
到此服务器端搞定。
小程序端
微信小程序大家可以根据微信小程序官网教程去下载客户端工具,然后导入已有前端代码来测试。前端主要是布局和写websocket客户端,这里截一下核心代码
onShow: function () {
//链接服务器端
wx.connectSocket({
url: 'ws://170.106.152.44/chatWebSocket/uid' + Math.round(Math.random()*10)
})
wx.onSocketOpen((res) => {
socketOpen = true
wx.showToast({
icon: 'none',
title: '会话建立成功',
duration: 500
})
socketMsgQueue = []
//处理返回的消息
wx.onSocketMessage((result) => {
result.data = result.data.replace(" ", " ");
curAnsCount++;
if (curAnsCount % lineCount == 0) {
wx.createSelectorQuery().select('#chatPage').boundingClientRect(function (rect) {
// 使页面滚动到底部
wx.pageScrollTo({
scrollTop: rect.bottom
})
}).exec()
}
msgList[msgList.length - 1].content = result.data
this.setData({
msgList
})
})
})
},
所有代码我已经上传的Gitee,有兴趣可以去参考一下。地址:https://gitee.com/baidu11.com/chatgpt