使用chatgpt实现微信聊天小程序的代码示例

作者:秃头披风侠. 时间:2022-04-26 17:18:24 

前言

前一段时间使用java来调用chatgpt的接口,然后写了一个简单小程序,java调用chatgpt接口,实现专属于自己的人工智能助手,事实上,这个程序毛病挺多的,最不能让人接受的一点就是返回速度非常缓慢(即使使用非常好的外网服务器)。

现在,我改进了一下程序,使用异步请求的方式,基本可以实现秒回复。并且还基于webSocket编写了一个微信小程序来进行交互,可以直接使用微信小程序来进行体验。

效果展示

部分截图如下

使用chatgpt实现微信聊天小程序的代码示例

使用chatgpt实现微信聊天小程序的代码示例

使用chatgpt实现微信聊天小程序的代码示例

使用chatgpt实现微信聊天小程序的代码示例

使用chatgpt实现微信聊天小程序的代码示例

原理说明

在 java调用chatgpt接口,实现专属于自己的人工智能助手 我说明了java调用chatgpt的基本原理,这里的代码就是对这个代码的改进,使用异步请求的方式来进行。

使用chatgpt实现微信聊天小程序的代码示例

注意看官方文档,我们在请求时可以提供一个参数stream,然后就可以实现按照流的形式进行返回,这种方式基本可以做到没有延迟就给出答案。

由于这次改进的思路主要就是将请求改为了异步,其他的基本一样,所以就不做解释,直接给出代码了,代码上面都有注释

/**
    * 这个方法用于测试的,可以在控制台打印输出结果
    *
    * @param chatGptRequestParameter 请求的参数
    * @param question                问题
    */
   public void printAnswer(ChatRequestParameter chatGptRequestParameter, String question) {
       asyncClient.start();
       // 创建一个post请求
       AsyncRequestBuilder asyncRequest = AsyncRequestBuilder.post(url);

// 设置请求参数
       chatGptRequestParameter.addMessages(new ChatMessage("user", question));

// 请求的参数转换为字符串
       String valueAsString = null;
       try {
           valueAsString = objectMapper.writeValueAsString(chatGptRequestParameter);
       } catch (JsonProcessingException e) {
           e.printStackTrace();
       }

// 设置编码和请求参数
       ContentType contentType = ContentType.create("text/plain", charset);
       asyncRequest.setEntity(valueAsString, contentType);
       asyncRequest.setCharset(charset);

// 设置请求头
       asyncRequest.setHeader(HttpHeaders.CONTENT_TYPE, "application/json");
       // 设置登录凭证
       asyncRequest.setHeader(HttpHeaders.AUTHORIZATION, "Bearer " + apiKey);

// 下面就是生产者消费者模型
       CountDownLatch latch = new CountDownLatch(1);
       // 用于记录返回的答案
       StringBuilder sb = new StringBuilder();
       // 消费者
       AbstractCharResponseConsumer<HttpResponse> consumer = new AbstractCharResponseConsumer<HttpResponse>() {
           HttpResponse response;

@Override
           protected void start(HttpResponse response, ContentType contentType) throws HttpException, IOException {
               setCharset(charset);
               this.response = response;
           }

@Override
           protected int capacityIncrement() {
               return Integer.MAX_VALUE;
           }

@Override
           protected void data(CharBuffer src, boolean endOfStream) throws IOException {
               // 收到一个请求就进行处理
               String ss = src.toString();
               // 通过data:进行分割,如果不进行此步,可能返回的答案会少一些内容
               for (String s : ss.split("data:")) {
                   // 去除掉data:
                   if (s.startsWith("data:")) {
                       s = s.substring(5);
                   }
                   // 返回的数据可能是(DONE)
                   if (s.length() > 8) {
                       // 转换为对象
                       ChatResponseParameter responseParameter = objectMapper.readValue(s, ChatResponseParameter.class);
                       // 处理结果
                       for (Choice choice : responseParameter.getChoices()) {
                           String content = choice.getDelta().getContent();
                           if (content != null && !"".equals(content)) {
                               // 保存结果
                               sb.append(content);
                               // 将结果使用webSocket传送过去
                               System.out.print(content);
                           }
                       }
                   }
               }
           }

@Override
           protected HttpResponse buildResult() throws IOException {
               return response;
           }

@Override
           public void releaseResources() {
           }
       };

// 执行请求
       asyncClient.execute(asyncRequest.build(), consumer, new FutureCallback<HttpResponse>() {

@Override
           public void completed(HttpResponse response) {
               latch.countDown();
               chatGptRequestParameter.addMessages(new ChatMessage("assistant", sb.toString()));
               System.out.println("回答结束!!!");
           }

@Override
           public void failed(Exception ex) {
               latch.countDown();
               System.out.println("failed");
               ex.printStackTrace();
           }

@Override
           public void cancelled() {
               latch.countDown();
               System.out.println("cancelled");
           }

});
       try {
           latch.await();
       } catch (InterruptedException e) {
           e.printStackTrace();
       }
   }

大家代码可以直接不看,反正最终的效果就是可以实现问了问题就返回结果。运行效果如下

使用chatgpt实现微信聊天小程序的代码示例

使用chatgpt实现微信聊天小程序的代码示例

可以发现,输出就类似于官方的那种效果,一个字一个字的输出

服务器端代码说明

我使用java搭建了一个简单的服务器端程序,提供最基础的用户登录校验功能,以及提供了WebSocket通信。

用户校验的代码

package com.ttpfx.controller;

import com.ttpfx.entity.User;
import com.ttpfx.service.UserService;
import com.ttpfx.utils.R;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

import javax.annotation.Resource;
import java.util.Objects;
import java.util.concurrent.ConcurrentHashMap;

/**
* @author ttpfx
* @date 2023/3/29
*/
@RestController
@RequestMapping("/user")
public class UserController {

@Resource
   private UserService userService;

public static ConcurrentHashMap<String, User> loginUser = new ConcurrentHashMap<>();

public static ConcurrentHashMap<String, Long> loginUserKey = new ConcurrentHashMap<>();
   @RequestMapping("/login")
   public R login(String username, String password) {
       if (username == null) return R.fail("必须填写用户名");

User user = userService.queryByName(username);
       if (user == null) return R.fail("用户名不存在");
       String targetPassword = user.getPassword();
       if (targetPassword == null) return R.fail("用户密码异常");
       if (!targetPassword.equals(password)) return R.fail("密码错误");

loginUser.put(username, user);
       loginUserKey.put(username, System.currentTimeMillis());
       return R.ok(String.valueOf(loginUserKey.get(username)));
   }

@RequestMapping("/logout")
   public R logout(String username) {
       loginUser.remove(username);
       loginUserKey.remove(username);
       return R.ok();
   }

@RequestMapping("/checkUserKey")
   public R checkUserKey(String username, Long key){
       if (username==null || key == null)return R.fail("用户校验异常");
       if (!Objects.equals(loginUserKey.get(username), key)){
           return R.fail("用户在其他地方登录!!!");
       }
       return R.ok();
   }

@RequestMapping("/loginUser")
   public R loginUser(){
       return R.ok("success",loginUser.keySet());
   }
}

基于webSocket通信的代码

package com.ttpfx.server;

import com.fasterxml.jackson.databind.ObjectMapper;
import com.ttpfx.entity.UserLog;
import com.ttpfx.model.ChatModel;
import com.ttpfx.service.UserLogService;
import com.ttpfx.service.UserService;
import com.ttpfx.vo.chat.ChatRequestParameter;
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.time.LocalDateTime;
import java.util.concurrent.ConcurrentHashMap;

/**
* @author ttpfx
* @date 2023/3/28
*/
@Component
@ServerEndpoint("/chatWebSocket/{username}")
public class ChatWebSocketServer {

/**
    * 静态变量,用来记录当前在线连接数。应该把它设计成线程安全的。
    */
   private static int onlineCount = 0;
   /**
    * concurrent包的线程安全Map,用来存放每个客户端对应的MyWebSocket对象。
    */
   private static ConcurrentHashMap<String, ChatWebSocketServer> chatWebSocketMap = new ConcurrentHashMap<>();

/**
    * 与某个客户端的连接会话,需要通过它来给客户端发送数据
    */
   private Session session;
   /**
    * 接收的username
    */
   private String username = "";

private UserLog userLog;

private static UserService userService;
   private static UserLogService userLogService;

@Resource
   public void setUserService(UserService userService) {
       ChatWebSocketServer.userService = userService;
   }

@Resource
   public void setUserLogService(UserLogService userLogService) {
       ChatWebSocketServer.userLogService = userLogService;
   }

private ObjectMapper objectMapper = new ObjectMapper();
   private static ChatModel chatModel;

@Resource
   public void setChatModel(ChatModel chatModel) {
       ChatWebSocketServer.chatModel = chatModel;
   }

ChatRequestParameter chatRequestParameter = new ChatRequestParameter();

/**
    * 建立连接
    * @param session 会话
    * @param username 连接用户名称
    */
   @OnOpen
   public void onOpen(Session session, @PathParam("username") String username) {
       this.session = session;
       this.username = username;
       this.userLog = new UserLog();
       // 这里的用户id不可能为null,出现null,那么就是非法请求
       try {
           this.userLog.setUserId(userService.queryByName(username).getId());
       } catch (Exception e) {
           e.printStackTrace();
           try {
               session.close();
           } catch (IOException ex) {
               ex.printStackTrace();
           }
       }
       this.userLog.setUsername(username);
       chatWebSocketMap.put(username, this);
       onlineCount++;
       System.out.println(username + "--open");
   }

@OnClose
   public void onClose() {
       chatWebSocketMap.remove(username);
       System.out.println(username + "--close");
   }

@OnMessage
   public void onMessage(String message, Session session) {
       System.out.println(username + "--" + message);
       // 记录日志
       this.userLog.setDateTime(LocalDateTime.now());
       this.userLog.setPreLogId(this.userLog.getLogId() == null ? -1 : this.userLog.getLogId());
       this.userLog.setLogId(null);
       this.userLog.setQuestion(message);
       long start = System.currentTimeMillis();
       // 这里就会返回结果
       String answer = chatModel.getAnswer(session, chatRequestParameter, message);
       long end = System.currentTimeMillis();
       this.userLog.setConsumeTime(end - start);
       this.userLog.setAnswer(answer);
       userLogService.save(userLog);
   }

@OnError
   public void onError(Session session, Throwable error) {
       error.printStackTrace();
   }

public void sendMessage(String message) throws IOException {
       this.session.getBasicRemote().sendText(message);
   }

public static void sendInfo(String message, String toUserId) throws IOException {
       chatWebSocketMap.get(toUserId).sendMessage(message);
   }
}

我们只需要编写简单的前端代码,就可以实现和后端的socket通信。对于后端,我们只需要改一下apiKey和数据库配置就可以直接运行了。

微信小程序代码说明

我写了一个简单微信小程序来和后端进行通信,界面如下

使用chatgpt实现微信聊天小程序的代码示例

使用chatgpt实现微信聊天小程序的代码示例

使用chatgpt实现微信聊天小程序的代码示例

使用chatgpt实现微信聊天小程序的代码示例

大家只需要下载源代码,然将程序中的ip改为自己服务器的ip即可

代码链接

github的地址为 https://github.com/c-ttpfx/chatgpt-java-wx
可以直接使用 git clone https://github.com/c-ttpfx/chatgpt-java-wx.git 下载代码到本地

我在github里面说明了安装使用的基本步骤,大家按照步骤使用即可

gpt:
 proxy:
   host: 127.0.0.1
   port: 7890

来源:https://blog.csdn.net/m0_51545690/article/details/129886385

标签:chatgpt,微信,聊天,小程序
0
投稿

猜你喜欢

  • Android实现可拖动层叠卡片布局

    2023-03-25 03:28:06
  • idea mybatis配置log4j打印sql语句的示例

    2023-11-25 10:32:39
  • Java深入了解数据结构之栈与队列的详解

    2022-03-24 08:12:27
  • 下载软件后使用c#获取文件的md5码示例

    2022-02-08 21:39:58
  • Java Runtime的使用详解

    2021-10-23 06:46:39
  • Java数据结构之线索化二叉树的实现

    2022-03-16 15:25:34
  • Spring Boot如何通过自定义注解实现日志打印详解

    2022-07-04 14:10:18
  • 详解微信小程序 同步异步解决办法

    2022-08-14 00:08:58
  • C#中的问号(?号)用法小结

    2023-12-26 08:03:25
  • Android中FontMetrics的几个属性全面讲解

    2023-11-14 14:57:20
  • Java源码解析之object类

    2023-11-05 00:46:28
  • android打开本地图像的方法

    2022-10-26 08:01:42
  • spring cloud升级到spring boot 2.x/Finchley.RELEASE遇到的坑

    2022-01-04 20:40:56
  • Java JDK与cglib动态代理有什么区别

    2023-07-23 08:10:15
  • Java使用CountDownLatch实现网络同步请求的示例代码

    2022-04-23 18:40:52
  • C# winform点击生成二维码实例代码

    2023-12-10 08:17:20
  • Java两个乒乓球队比赛名单问题(判断素数)

    2022-11-15 08:39:20
  • java日期工具类实例分享

    2023-05-17 17:50:40
  • Android实现多级树形菜单并支持多选功能

    2023-08-29 20:01:04
  • C#中获取二维数组的行数和列数以及多维数组各个维度的长度

    2022-08-06 12:08:55
  • asp之家 软件编程 m.aspxhome.com