赞
踩
chatGPT是一款高效强大的语言模型,能够给我们的生活带来极大的改变。无论是学习知识还是工作效率,chatGPT都能为我们提供有力的帮助。它可以帮助我们快速获取所需的知识,同时可以帮助我们提高工作效率,包括写文章、文案、推荐策略、生成代码、写周报,流程图等等。此外,它还可以成为您智能的助手,帮您打理日常事务,如一键预约、贴心提醒等。对于小朋友们来说,他还可以为他们写作文。总之,chatGPT是一个多功能的智能管家,不管您的需求是什么,它都能为您提供强大的支持。欢迎有需要的朋友戳链接体验:Talk-Bot,不喜勿喷,广交益友
废话不多说,直接上代码
这种方式比较常用,我们这里引入github上PlexPt大神封装好的类直接引用即可,地址为:chatgpt-java,也可以自己封装哈
<dependency>
<groupId>com.github.plexpt</groupId>
<artifactId>chatgpt</artifactId>
<version>4.0.7</version>
</dependency>
private static final String OPENAI_API_HOST = "https://api.openai.com/"; @PostMapping(value = "/v1/stream") public SseEmitter streamEvents(@RequestBody ChatRequest chatRequest) { SseEmitter sseEmitter = new SseEmitter(-1L); // 不需要代理的话,注销此行 Proxy proxy = Proxys.http("192.168.1.98", 7890); ChatGPTStream chatGPTStream = ChatGPTStream.builder() .timeout(600) .apiKey("你的openApiKey") .proxy(proxy) .apiHost(OPENAI_API_HOST) .build() .init(); SseStreamListener listener = new SseStreamListener(sseEmitter); Message message = Message.of(chatRequest.getInput()); ChatCompletion chatCompletion = ChatCompletion.builder() .model(ChatCompletion.Model.GPT_3_5_TURBO.getName()) .messages(Arrays.asList(message)) .build(); chatGPTStream.streamChatCompletion(chatCompletion, listener); listener.setOnComplate(msg -> { //回答完成,可以做一些事情 sseEmitter.complete(); }); return sseEmitter; }
前端调用,这里使用fetchEventSource,普通的eventSource不能发送post参数
import { fetchEventSource } from '@microsoft/fetch-event-source'; const reqData = { id: '111', input: 'java编码实现快速排序算法', chatlog: [], }; const headers = { 'Content-Type': 'application/json', }; const eventSource = new fetchEventSource('/api/v1/stream', { method: 'POST', headers: headers, // 设置下,不然请求会一直重发 openWhenHidden: true, body: JSON.stringify(reqData), onopen(response) { console.info('eventSource open: ', response); }, onmessage(event) { console.log('eventSource msg: ', event.data); }, onerror(err) { console.log('eventSource error: ' + err); }, onclose() { console.log('eventSource close'); } });
Message、ChatCompletion、ChatCompletionResponse 类都是根据官方需要的参数封装的实体,这里暂不能提供了,主要看思路吧
<dependency>
<groupId>cn.hutool</groupId>
<artifactId>hutool-all</artifactId>
<version>5.8.22</version>
</dependency>
private static final String OPENAI_API_HOST = "https://api.openai.com/"; private static final Map<String, Integer> API_KEY_MAP = new LinkedHashMap<String, Integer>() { { put("你的openApiKey", 5); put("你的openApiKey", 5); } }; @PostMapping("/v1/stream") public void streamHandler(@RequestBody ChatRequest chatRequest, HttpServletResponse response) throws Exception { String input = chatRequest.getInput(); //按权重分配key List<String> weightList = new ArrayList<>(API_KEY_MAP.entrySet().size()); for (Map.Entry<String, Integer> entry : API_KEY_MAP.entrySet()) { String element = entry.getKey(); Integer weight = entry.getValue(); for (int i = 0; i < weight; i++) { weightList.add(element); } } // 不需要代理的话,注销此行 proxy = new Proxy(Proxy.Type.HTTP, new InetSocketAddress("192.168.1.98", 7890)); Message message = Message.builder().role(Message.Role.USER).content(input).build(); ChatCompletion chatCompletion = ChatCompletion.builder().messages(Arrays.asList(message)).stream(true).build(); String requestBody = JSONUtil.toJsonStr(chatCompletion); HttpRequest client = HttpRequest.post(OPENAI_API_HOST + "v1/chat/completions") .contentType(ContentType.JSON.getValue()) .bearerAuth(RandomUtil.randomEle(weightList)) .keepAlive(true) .setProxy(proxy) .timeout(300000) .body(requestBody); BufferedReader reader = new BufferedReader(new InputStreamReader(client.executeAsync().bodyStream())); String line; try { while ((line = reader.readLine()) != null) { line = StrUtil.replace(line, "data: ", ""); if (StrUtil.isEmpty(line)) { continue; } if (!StrUtil.equals("[DONE]", line)) { ChatCompletionResponse chatCompletionResponse; try { // 官方错误返回不是一个json格式的,这里兼容下 chatCompletionResponse = JSONUtil.toBean(line, ChatCompletionResponse.class); } catch (Exception e) { // 自己打印日志 continue; } if (Objects.isNull(chatCompletionResponse) || Objects.isNull(chatCompletionResponse.getChoices()) || chatCompletionResponse.getChoices().isEmpty()) { continue; } if (!StrUtil.equals("stop", chatCompletionResponse.getChoices().get(0).getFinishReason())) { String content = chatCompletionResponse.getChoices().get(0).getDelta().getContent(); if (StrUtil.isEmpty(content)) { continue; } response.getWriter().write(content); response.getWriter().flush(); } } } } catch (Exception e) { // 自己打印日志,line = reader.readLine()这行代码读取会出现超时的情况,所以加了个try catch } reader.close(); response.getWriter().close(); }
nginx配置,这个必须加上
proxy_http_version 1.1;
前端调用,这里使用原生xhr方式,比较简单
const reqData = { id: '111', input: 'java编码实现快速排序算法', chatlog: [], }; const xhr = new XMLHttpRequest(); xhr.open('POST', '/api/v1/stream'); xhr.setRequestHeader('Content-Type', 'application/json'); xhr.send(JSON.stringify(reqData)); xhr.onreadystatechange = function () { if (xhr.status === 200) { if (xhr.readyState === xhr.LOADING) { console.log("data:", xhr.responseText); } if (xhr.readyState === xhr.DONE) { console.log("data:", xhr.responseText); } } }; xhr.onerror = function (error) { console.error('error:', error); };
这种方式实现起来稍微复杂些,跟SseEmitter实现方式差别不大,感兴趣的可以用chatGPT生成一下,哈哈哈,链接戳:Talk-Bot(请各位大佬手下留情啊!!!!)
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。