Dock ChatGPT to develop dialogue robot applet

foreword

ChatGPT has become very popular, and companies have begun to recruit ChatGPT engineers. It may be a necessary skill for programmers to connect to ChatGPT interfaces for enterprise-level development. This article is mainly based on the ChatGPT development interface for docking, using the WeChat applet to make a chat robot of your own, through this case you can expand infinitely

overall design

The overall design is relatively simple. We use the WeChat applet as the client interface for users, and the applet and the background use WebSocket for communication.
insert image description here
The final effect is as follows
insert image description here

ChatGPT interface docking

Note that there must be a ladder to access, the interface reference document: https://platform.openai.com/docs/api-reference/chat, find Chat in the Api Reference interface document, which contains the request description of the Chat dialogue interface

insert image description here
According to the documentation, we need to build a request address: https://api.openai.com:443/v1/chat/completions, post request submission, the parameters are:

{
    
    
    "model":"gpt-3.5-turbo",
    "messages":[
        {
    
    
            "role":"user",
            "content":"SpringBoot是什么"
        }
    ]
}

This is not enough, if direct access will report an error: apikey does not exist, we also need to create an APIKEY, address: https://platform.openai.com/account/api-keys

insert image description here

Then I use Postmain to do a simple test here. The request header plus APIKEY
insert image description here
to construct the request parameters in the Body is as follows.
insert image description here
According to the results, you can see that the returned format is

{
    
    
    "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
        }
    ]
}

Write background

In the background, we use SpringBoot for rapid development, mainly to integrate websocket to send and receive messages. The pom that needs to be imported is as follows

<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>

The second step is to define RestTemplate in the startup class to facilitate subsequent requests to ChatGPT

@SpringBootApplication
public class ChatGptApp {
    
    
    public static void main(String[] args) {
    
    
        SpringApplication.run(ChatGptApp.class);
    }


    @Bean
    public RestTemplate restTemplate(){
    
    
        
        return new RestTemplate();
    }

}

The third step is to configure websocket as follows

@Configuration
public class WebSocketConfig {
    
    

    @Bean
    public ServerEndpointExporter serverEndpointExporter() {
    
    
        return new ServerEndpointExporter();
    }
}

Step 4: Write the request entity class and encapsulate it according to the request parameters required by 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;
}

The following is the configuration and property objects in the parameter configuration 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;
}


Step 5: Write the request sending logic. The bottom layer uses RestTmpalte to send. Here you need two parameters APIKEY and URL address. I configured it in yaml and used the object to bind


@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";
}

The sixth step is to write the websocket server. The main need is to call ChatHttpSender to send the request after receiving the message, and then write the result back to the client. Here I use the RedsTemplate to call the ChatGpt interface, because it is synchronous, there will be a waiting situation

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);
        }
    }

}

Cloud on the server side

ChatGPT needs a ladder to access, so it is impossible to test locally. It is recommended to directly buy a foreign server for deployment. To buy a cloud server, you can read this article " Buy a Cloud Server ", and remember to buy a foreign server. Then package the project into a jar package, enter the root directory of the project and execute: mvn install, and find the project in the target directory, such as: springboot-chatgpt-1.0-SNAPSHOT.jar. Then upload it to the cloud server and execute Java -jar

insert image description here
This is done on the server side.

applet

For WeChat Mini Programs, you can download the client tools according to the WeChat Mini Program official website tutorial, and then import the existing front-end code for testing. The front end is mainly to layout and write the websocket client, here is a screenshot of the core code

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(" ", "&nbsp;");
        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
        })
      })
    })
  },

I have uploaded all the codes to Gitee, if you are interested, you can refer to them. Address: https://gitee.com/baidu11.com/chatgpt

Guess you like

Origin blog.csdn.net/u014494148/article/details/130440817