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

  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 keyopenai.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;@Overridepublic 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;@Overridepublic 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;@Overridepublic void setEnvironment(Environment environment) {this.environment = environment;}@Overridepublic void setApplicationContext(ApplicationContext applicationContext) throws BeansException {// chatgpt、gpt4RestTemplate 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);// 设置keyrestTemplate.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;@Overridepublic 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 {@Resourceprivate ChatGptModelService chatGptModelService;@Overridepublic String getAnswer(String prompt, HttpServletRequest request) {return chatGptModelService.answer(prompt, request);}
}

6.Controller控制器类

@Controller
public class AiController {@Resourceprivate AiService aiService;@PostMapping("/tools/ai/submitQuestion")@ResponseBodypublic Result submitQuestion(String prompt, HttpServletRequest request) {return Result.success(aiService.getAnswer(prompt, request));}@PostMapping("/tools/ai/historyDialogus")@ResponseBodypublic 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.hqwc.cn/news/478647.html

如若内容造成侵权/违法违规/事实不符,请联系编程知识网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

hot100 -- 滑动窗口

目录 &#x1f33c;无重复字符 -- 最长子串 AC 滑动窗口&#xff08;桶&#xff09; &#x1f33c;所有字母异位词 AC 滑动窗口 桶 AC 滑动窗口&#xff08;优化&#xff09; &#x1f33c;无重复字符 -- 最长子串 一开始考虑用 BF暴力 或者 KMP 的&#xff0c;后来想…

彻底解决pycharm中的Python解释器重复-无法重命名和删除不干净的问题

Python解释器重复-无法重命名和删除 问题及原因&#xff1a;PyCharm在删除解释器配置时&#xff0c;并没有完全清除所有相关的配置信息&#xff0c;特别是关于解释器命名的部分。这可能导致即使删除了旧的解释器配置&#xff0c;PyCharm仍然“记住”了之前的命名序号&#xff…

log4j2的使用

基础用法 1. pom文件导入依赖 junit用来做测试 <dependency><groupId>org.apache.logging.log4j</groupId><artifactId>log4j-core</artifactId><version>2.5</version></dependency><dependency><groupId>org.…

《Arthas》--问题定位神器--常用指令一图全知

阿丹&#xff1a; 因为一个图太大&#xff0c;直接放出来影响观看&#xff0c;我给他们分开来。 图中关键标识&#xff1a; 基础命令&#xff1a; class相关 jvm相关 字节码增强 ArtHas 基础命令 help 查看命令帮助信息 cls 清空当前屏幕区域 session 查看当前会话的信息 …

vulhub中Apache Log4j Server 反序列化命令执行漏洞复现(CVE-2017-5645)

Apache Log4j是一个用于Java的日志记录库&#xff0c;其支持启动远程日志服务器。Apache Log4j 2.8.2之前的2.x版本中存在安全漏洞。攻击者可利用该漏洞执行任意代码。 1.我们使用ysoserial生成payload&#xff0c;然后直接发送给your-ip:4712端口即可。 java -jar ysoserial-…

【FastAPI】P3 请求与响应

目录 请求路径参数查询参数 响应JSON 响应文本响应返回 Pydantic 模型 在网络通讯中&#xff0c;请求&#xff08;Request&#xff09; 与 响应&#xff08;Response&#xff09; 扮演着至关重要的角色&#xff0c;它们构成了客户端与服务器间互动的根本理念。 请求&#xff0…

数据结构day1

定义一个学生结构体&#xff0c;包含结构体成员&#xff1a;身高&#xff0c;姓名&#xff0c;成绩&#xff1b;定义一个结构体数组有7个成员&#xff0c;要求终端输入结构体成员的值&#xff0c;根据学生成绩&#xff0c;进行冒泡排序。 #include <stdio.h> #include &l…

Bert基础(一)--transformer概览

1、简介 当下最先进的深度学习架构之一&#xff0c;Transformer被广泛应用于自然语言处理领域。它不单替代了以前流行的循环神经网络(recurrent neural network, RNN)和长短期记忆(long short-term memory, LSTM)网络&#xff0c;并且以它为基础衍生出了诸如BERT、GPT-3、T5等…

请求数据是写在组件的methods中还是在vuex的action中?

作为一名Web前端开发者&#xff0c;我们经常面临一个重要决策&#xff1a;将请求数据写在组件的methods中还是在Vuex的action中。这个问题涉及到了组件的数据流管理和代码结构的设计&#xff0c;不同的方案对于项目的可维护性和扩展性都有着不同的影响。 首先&#xff0c;让我…

普通人如何开启真正的赚钱之路

您好&#xff0c;我是码农飞哥&#xff08;wei158556&#xff09;&#xff0c;感谢您阅读本文&#xff0c;欢迎一键三连哦。&#x1f4aa;&#x1f3fb; 1. Python基础专栏&#xff0c;基础知识一网打尽&#xff0c;9.9元买不了吃亏&#xff0c;买不了上当。 Python从入门到精通…

【PHP】web服务器支持PHP_环境配置

一、PHP运行目前为止主要有4方式 &#xff08;1&#xff09;以模块加载的方式运行&#xff0c;初学者可能不容易理解&#xff0c;其实就是将PHP集成到Apache服务器&#xff0c; 以同一个进程运行。 &#xff08;2&#xff09;以CGI的方式运行&#xff0c;CGI英文叫…

Maven(基础)、MyBatis

简介 Apache Maven是一个项目管理和构建工具&#xff0c;它基于项目对象模型 (POM)的概念&#xff0c;通过一小段描述信息来管理项目的构建、报告和文档 官网: http://maven.apache.org/ Maven作用 Maven是专门用于管理和构建Java项目的工具&#xff0c;它的主要功能有&#x…