在springboot项目中调用openai API及我遇到的问题

news2024/12/23 23:07:32
  1. 这两天我在自己的网站中集成了openai API,引入chatgpt对话机器人,中途遇到了很多坑,记录一下。
  2. 文章中会涉及一些付费工具,如果你有类似功能的工具,完全可以使用自己的。(主要是我想澄清一下,我不是广告)。
  3. 如果当前什么都没有的小伙伴,在我的这篇教程里可能需要支出最少两三百块,我得提前说好,避免某些不愿意在这些事情上花钱的小伙伴浪费时间。
  4. 有问题可以私信我,看到的话,能帮忙我会尽量帮忙的。

目录

一、关于如何访问到Openai的接口(已经有api key的小伙伴可以跳过这一章)

二、在linux上部署Clash(不部署在Linux服务器上的小伙伴可以跳过这一章)

三、工程代码

1.配置文件增添配置项

2.根据openai文档中提到的参数,创建发送请求和接收回复需要的四个类(其中有一个是内部类,哈哈哈)

1)消息类

2)请求类

3)回应类(其中有内部类Choice)

3.RestTemplat设置代理以及添加api key

4.chatgpt对话工具类

5.service服务类

接口

实现类

6.Controller控制器类

7.页面

四、运行代码可能出现的一些问题

1.出现SSL问题,远程终端停止握手

2.启用了代理,也有ssl证书了,发送请求总是回复429 too many requests

关于充值的问题

五、看效果


一、关于如何访问到Openai的接口(已经有api key的小伙伴可以跳过这一章)

能看到这篇文章的各位,应该都是有自己的科学工具的,没有的话可以用我现在正在使用的科学工具。

注册一个openai账号,我是去年注册的账号,当时海外手机号是用的sms-activate,不知道现在行不行了。

然后跟着下面的步骤走

二、在linux上部署Clash(不部署在Linux服务器上的小伙伴可以跳过这一章)

如果觉得我写的太乱了不好看,可以看这篇文章

  1. 访问Clash资源站,在内核板块找一个合适的。
  2. 下载Country.mmdb文件,连接中下载过来的把名字前缀去掉就行了。
  3. configure.yaml文件,可以在1中提到的Clash资源站中下载windows版本的,根据科学工具网站中的教程导入到windows版中,再拷贝出来(主要是我没有找到直接导出的方式)。
  4. 仪表盘在github中下载。
  5. 把上面下载的五个文件传入到/root/.config/clash文件夹下。
  6. 解压clash压缩包文件并改名为clash(不改也可以,就是后面打这么多字比较麻烦),解压仪表盘并改名为dashboard。
  7. 修改configure.ymal文件。加入
    external-controller: '0.0.0.0:9090'
    external-ui: /root/.config/clash/dashboard

    放在顶格整齐的位置就行,我放在dns的上面了

  8. 使用命令启动clash
    /root/.config/clash/clash -d /root/.config/clash/ &

    能够访问ip:9090/ui就是成功了。

  9. 最后我发现如果单纯使用命令来启动clash,如果我退出shell终端clash就会关闭,如果你也有这样的问题,可以把clash配置为系统服务。创建文件/etc/systemd/system/clash.service,写入
    [Unit]
    Description=Clash daemon, A rule-based proxy in Go.
    [Service]
    Type=simple
    User=root
    ExecStart=/root/.config/clash/clash -d /root/.config/clash/
    Restart=on-failure
    [Install]
    WantedBy=multi-user.target
  10. 执行命令
    systemctl daemon-reload
    后就可以使用systemctl start clash.service命令来启动clash,使用systemctl status clash查看clash状态。

三、工程代码

配置完服务器环境就是编码部分了。

1.配置文件增添配置项

在application.properties中添加

openai.key=你的api key

openai.chatgtp.model=gpt-3.5-turbo
openai.chatgtp.api.url=https://api.openai.com/v1/chat/completions

2.根据openai文档中提到的参数,创建发送请求和接收回复需要的四个类(其中有一个是内部类,哈哈哈)

下文中的类都没有写构造器和set、get方法,为了缩减篇幅。在toString()方法中调用jackson是为了在RestTemplate中直接发送。

1)消息类

用于保存消息和发出消息的角色

public class ChatMessage {
    // 角色
    private String role;
    // 消息内容
    private String content;

    @Override
    public String toString() {
        try {
            return new ObjectMapper().writeValueAsString(this);
        } catch (JsonProcessingException e) {
            throw new RuntimeException(e);
        }
    }
}

2)请求类

用于指定模型以及发送历史对话记录

public class ChatRequest {
    // 使用的模型
    private String model;
    // 历史对话记录
    private List<ChatMessage> messages;

    @Override
    public String toString() {
        try {
            return new ObjectMapper().writeValueAsString(this);
        } catch (JsonProcessingException e) {
            throw new RuntimeException(e);
        }
    }
}

3)回应类(其中有内部类Choice)

public class ChatResponse {
    // GPT返回的对话列表
    private List<Choice> choices;

    public static class Choice {
        private int index;
        private ChatMessage message;
    }

}

3.RestTemplat设置代理以及添加api key

这里使用了springboot提供的钩子

@Component
public class ApiCodeLoadAware implements EnvironmentAware, ApplicationContextAware {

    Environment environment;

    @Override
    public void setEnvironment(Environment environment) {
        this.environment = environment;

    }

    @Override
    public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {

        // chatgpt、gpt4
        RestTemplate restTemplate = new RestTemplate();
        // 设置代理
        SimpleClientHttpRequestFactory simpleClientHttpRequestFactory = new SimpleClientHttpRequestFactory();
        Proxy proxy = new Proxy(Proxy.Type.HTTP, new InetSocketAddress("127.0.0.1", 7890));
        simpleClientHttpRequestFactory.setProxy(proxy);
        restTemplate.setRequestFactory(simpleClientHttpRequestFactory);
        // 设置key
        restTemplate.getInterceptors().add(((request, body, execution) -> {
            request.getHeaders().add("Authorization", "Bearer " +  environment.getProperty("openai.key"));
            return execution.execute(request, body);
        }));

        ChatGptModelService chatGptModelService = applicationContext.getBean(ChatGptModelService.class);
        chatGptModelService.setRestTemplate(restTemplate);
    }
}

4.chatgpt对话工具类

实际对接了多个模型,所以使用工具类实现模型的对话功能,再由service调用各个工具类。

这里直接返回的context是markdown格式的,有需要的小伙伴可以自行查找markdown转html的工具,java和js都有大佬写好的现成的。

@Component
public class ChatGptModelService implements AiModelService{

    private static final Logger logger = LoggerFactory.getLogger(ChatGptModelService.class);

    @Value("${openai.chatgtp.api.url}")
    private String endpoint;

    @Value(("${openai.chatgtp.model}"))
    private String model;

    @Override
    public String answer(String prompt, HttpServletRequest request) {
        // 使用session保存历史对话记录
        HttpSession session = request.getSession();

        // 获取历史对话列表,chatMessages实现连续对话、chatDialogues便于页面显示
        List<ChatMessage> chatMessages = (List<ChatMessage>) session.getAttribute(ConstValuePool.CHAT_MESSAGE_DIALOGUES);
        List<String> chatDialogues = (List<String>) session.getAttribute(ConstValuePool.CHAT_DIALOGUES);
        if (chatMessages == null) {
            chatMessages = new ArrayList<>();
            chatDialogues = new ArrayList<>();
            session.setAttribute(ConstValuePool.CHAT_DIALOGUES, chatDialogues);
            session.setAttribute(ConstValuePool.CHAT_MESSAGE_DIALOGUES, chatMessages);
        }
        chatMessages.add(new ChatMessage("user", prompt));
        chatDialogues.add(prompt);

        ChatRequest chatRequest = new ChatRequest(this.model, chatMessages);

        ChatResponse response = ConstValuePool.PROXY_OPENAI_REST_TEMPLATE
                .postForObject(
                        this.endpoint,
                        chatRequest,
                        ChatResponse.class
                );
        logger.debug(response.toString());
        List<ChatResponse.Choice> choices = response.getChoices();
        ChatMessage message = null;
        if (CollectionUtil.isEmpty(choices)) {
            message = new ChatMessage(null, "error:发生了错误");
        }else {
            message = choices.get(choices.size() - 1).getMessage();
            chatMessages.add(message);
        }

        chatDialogues.add(message.getContent());

        return message.getContent();
    }
}

5.service服务类

接口

public interface AiService {

    String getAnswer(String prompt, HttpServletRequest request);
}

实现类

@Service
public class AiServiceImpl implements AiService {

    @Resource
    private ChatGptModelService chatGptModelService;

    @Override
    public String getAnswer(String prompt, HttpServletRequest request) {
        return chatGptModelService.answer(prompt, request);
    }
}

6.Controller控制器类

@Controller
public class AiController {

    @Resource
    private AiService aiService;


    @PostMapping("/tools/ai/submitQuestion")
    @ResponseBody
    public Result submitQuestion(String prompt, HttpServletRequest request) {
        return Result.success(aiService.getAnswer(prompt, request));
    }

    @PostMapping("/tools/ai/historyDialogus")
    @ResponseBody
    public Result historyDialogus(HttpSession session) {
        List<String> res = (List<String>)session.getAttribute(ConstValuePool.CHAT_DIALOGUES);
        if (res == null) {
            res = ConstValuePool.EMPTY_STRING_LIST;
        }
        return Result.success(res);
    }
}

7.页面

我的前端能力很差,就不发我的前端页面了,相信大家来看这篇文章,或多或少都有自己编码和上网查询资料的能力了。

四、运行代码可能出现的一些问题

写这篇文章就是为了总结这些问题,我搞了三天都在搞这些问题。

1.出现SSL问题,远程终端停止握手

启动clash调用代码以后可能会出现报错ssl peer shut down incorrectly,这是由于openai的api处于安全性考虑要求调用接口的网站也必须使用https协议。

但是他们好像只有是https协议就行,我用的不安全的证书在本地做测试也能成功调用。

我自己使用的服务器是阿里云的,我本来想在阿里云申请一个ssl证书。但是阿里云的免费证书有效期只有三个月,而且我在昨天晚上六点发起的申请,到现在还没见到证书的影子。

真的不是黑阿里,这次效率确实不高,我还特地回去查了一下记录

腾讯云的免费证书有效期有一年,而且处理速度蛮快,昨天五分钟就给我搞好了,可以试试看腾讯云。

2.启用了代理,也有ssl证书了,发送请求总是回复429 too many requests

这个点太离谱了,我看文档里免费用户对gpt-3.5-turbo模型有3RPM(3个请求每分钟),4000TPM(4000个tokens每分钟,没记错的话应该是4000)的配额,而且也有五刀的免费额度的。

我一开始以为是使用代理的原因会发送不止三个请求导致的,所以我打算氪点金,成为一阶用户。于是我就找了一个虚拟卡运营商,充了10刀

充完了发现五刀的免费额度没了,只有10刀,这里我测试用了一点所以只有9.94刀了。

关于充值的问题

网上有些不建议用虚拟卡的教程,但是得用到苹果机,555,我是低人一等的卑微安卓机用户。

一开始我是看到了WildCard的,结果到现在(2024/02/19 22:46)为止,它还是无法注册。

后来看到depay以及被禁用了。。。

还有OneKey不让中国地区做身份验证。。。

后来我在犄角旮旯里找到了一个还能用的FOMEPay,开卡我花了246.81,真的很心痛。

但是氪完以后,429的问题就没有了。

五、看效果

欸~嘶~为什么第一次回复是英文的

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1460678.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

LPDDR6与LPDDR5 ZQ Calibration技术探讨

LPDDR6相比LPDDR5在ZQ校准这一块删除了command-based相关的描述&#xff0c;删除了ZQ校准模式切换的描述&#xff0c;仅支持background-based的校准。 回顾一下LPDDR5 基于background-based的校准&#xff1a; background ZQC是通过MR28 OP[5]来选择的&#xff0c;当选择为0&a…

一个基于C#开发的、开源的特殊字符输入法

emoji表情在社交网络非常流行&#xff0c;我们在手机也非常方便输入&#xff0c;但是在PC电脑我们一般需要到归集好的网页拷贝&#xff0c;所以今天推荐一个Windows小工具&#xff0c;让你方便输入特殊字符和emoji表情。 01 项目简介 这是一个基于C#开发的开源项目&#xff0…

解锁动态体验:探秘文件二维码生成的多重魅力

文件生成二维码&#xff0c;作为一种动态二维码&#xff0c;不仅能够存储丰富的信息&#xff0c;更通过其独特的特点为用户带来了全新的使用体验。让我们一起深入探讨这一引人注目的技术。 1. 数据追踪&#xff1a;揭示用户互动的面纱 在二维彩虹的文件二维码中&#xff0c;数…

使用 Next.js 连接 mysql 数据库

前言 本文主要为大家介绍&#xff0c;如何使用 Next 框架实现一个简单的后端接口&#xff0c;并且从数据库中请求数据返回给前端。 实现 创建api/getData文件夹 项目创建完成后在 app 文件下新建api文件夹&#xff0c;在 api 文件夹下新建 getData 文件夹&#xff0c;在 ge…

聊一聊bpmn-js中的Viewer和Modeler

通过之前对于bpmn-js的学习,可以完成一个基础的Bpmn编辑器(或者叫建模器)的显示和简单绘制,若需要做更多工作还需加强对其的内部实现的了解。通过使用我们可以知道bpmn-js中有两个比较重要的操作对象:bpmnViewer和bpmnModeler。 Viewer:一般习惯性对齐命名对象称之为bpmnVi…

golang入门介绍-1

今天开始发布关于go语言入门到实战内容&#xff0c;各位小伙伴准备好。 go介绍 Go语言&#xff08;或 Golang&#xff09;起源于 2007 年&#xff0c;并在 2009 年正式对外发布。是由 Google 公司开发的一种静态强类型、编译型、并发型、并具有垃圾回收功能的编程语言。 Go 是…

在哪些领域中最需要使用 OCR 识别技术?真实场景介绍

根据我们的项目经验总结来说&#xff0c;OCR&#xff08;光学字符识别&#xff09;技术在多个领域中扮演着至关重要的角色&#xff0c;它能够将图像中的文本内容转换为机器可读的格式&#xff0c;极大地提高了数据处理的效率和准确性。以下是一些主要领域及其对应的应用场景和用…

phar反序列化原理及利用

phar是什么&#xff1f; phar 是 PHP 的一种归档文件格式&#xff0c;类似于 ZIP 或 TAR 文件&#xff0c;它可以包含多个文件和目录&#xff0c;并且可以像访问普通文件系统一样在 PHP 中进行访问。在php 5.3 或更高版本中默认开启 在php.ini中配置如下时&#xff0c;才能生成…

LabVIEW压电驱动迟滞补偿控制

LabVIEW压电驱动迟滞补偿控制 随着精密控制技术的迅速发展&#xff0c;压电陶瓷驱动器因其高精度和快速响应特性&#xff0c;在微纳精密定位系统中得到了广泛应用。然而&#xff0c;压电材料固有的迟滞非线性特性严重影响了其定位精度和重复性。开发了一种基于LabVIEWFPGA的压…

【初始RabbitMQ】死信队列的实现

死信的概念 死信&#xff0c;顾名思义就是无法被消费的消息&#xff0c;字面意思可以这样理解&#xff0c;一般来说&#xff0c;producer 将消息投递到 broker 或者直接到 queue 里了&#xff0c;consumer 从 queue 取出消息 进行消费&#xff0c;但某些时候由于特定的原因导致…

Java 那些诗一般的 数据类型 (1)

本篇会加入个人的所谓‘鱼式疯言’ ❤️❤️❤️鱼式疯言:❤️❤️❤️此疯言非彼疯言 而是理解过并总结出来通俗易懂的大白话, 小编会尽可能的在每个概念后插入鱼式疯言,帮助大家理解的. &#x1f92d;&#x1f92d;&#x1f92d;可能说的不是那么严谨.但小编初心是能让更多人…

私房菜|私房菜定制上门服务系统|基于springboot+vue私房菜定制上门服务系统设计与实现(源码+数据库+文档)

私房菜定制上门服务系统目录 目录 基于springbootvue私房菜定制上门服务系统设计与实现 一、前言 二、系统功能设计 三、系统实现 1、管理员功能实现 &#xff08;1&#xff09;菜品管理 &#xff08;2&#xff09;公告管理 &#xff08;3&#xff09; 厨师管理 2、用…

四非保研之旅

大家好&#xff0c;我是工藤学编程&#xff0c;虽有万分感概&#xff0c;但是话不多说&#xff0c;先直接进入正题&#xff0c;抒情环节最后再说&#xff0c;哈哈哈 写在开头 我的分享是来给大家涨信心的&#xff0c;网上的大佬们都太强了&#xff0c;大家拿我涨涨信心&#…

Linux 上安装及卸载JDK(包含yum方式)

一、 删除JDK 1、先输入java -version查看是否安装了JDK [rootiZbp117bkiezirqkean6g3Z java-11-openjdk-11.0.21.0.9-2.0.3.al8.x86_64]# java -version openjdk version "11.0.21" 2023-10-17 LTS OpenJDK Runtime Environment (Red_Hat-11.0.21.0.9-1) (build 1…

新版AI系统ChatGPT源码支持GPT-4/支持AI绘画去授权

源码获取方式 搜一搜&#xff1a;万能工具箱合集 点击资源库直接进去获取源码即可 如果没看到就是待更新&#xff0c;会陆续更新上 新版AI系统ChatGPT网站源码支持GPT-4/支持AI绘画/Prompt应用/MJ绘画源码/PCH5端/免授权&#xff0c;支持关联上下文&#xff0c;意间绘画模型…

面向对象详解,面向对象的三大特征:封装、继承、多态

文章目录 一、面向对象与面向过程1、什么是面向过程&#xff1f;2、什么是面向对象&#xff1f; 二、类与对象1. 初识对象2. 类的成员方法2.1 类的定义和使用2.2 成员方法 3. 类和对象4. 魔法方法1. _ _ inint _ _ 构造方法2. _ _ str _ _ 字符串方法3. _ _ lt _ _ 小于符号比较…

基于python社交网络大数据分析系统的设计与实现

项目&#xff1a;基于python社交网络大数据分析系统的设计与实现 摘 要 社交网络大数据分析系统是一种能自动从网络上收集信息的工具&#xff0c;可根据用户的需求定向采集特定数据信息的工具&#xff0c;本项目通过研究爬取微博网来实现社交网络大数据分析系统功能。对于采集…

十二、通过色彩空间转换进行更换图片背景

项目功能实现&#xff1a;对一张白色背景的图片进行更换成蓝色背景&#xff0c;类似抠图更换背景操作 按照之前的博文结构来&#xff0c;这里就不在赘述了 一、头文件 inrange.h #pragma once#include<opencv2/opencv.hpp>using namespace cv;class INRANGE{ public:v…

leetcode hot100组合综合四

本题中&#xff0c;是要求nums中求的总和为target的排列数&#xff0c;因为题中说了&#xff0c;元素顺序不同&#xff0c;则可以视为不同的结果之一。 所以&#xff0c;根据对背包问题的总结&#xff0c;本题中元素可以重复使用&#xff0c;是完全背包并且需要求排列数&#…

我是怎么用静态IP代理为Google账号保驾护航的

我为何要使用到静态IP代理服务 我是一名IT从业者&#xff0c;在很多年前就加入了一家跨国软件公司&#xff0c;日常需要在全世界各地跟甲方沟通&#xff0c;负责的工作中重要的一块就是Google广告&#xff0c;为此公司还特意给配置了一台笔记本电脑。 目录 我为何要使用到静态…