整合很简单,不过需要几个小条件
1.必须要有openai官方的key
2.国内需要有代理服务器或者国外的服务器把项目部署出去也没问题
我没有使用spring的springAI,听说很方便,日后有机会去体验体验,我今天用了两种方式整合了gpt
1.Chatgpt-Java : 📖 项目简介 | Chatgpt-Java (unfbx.com)
这个巨巨巨方便,整合gpt,可以跟着官网的快速入门走,一下就解决了
先导入maven依赖
<dependency>
<groupId>com.unfbx</groupId>
<artifactId>chatgpt-java</artifactId>
<version>1.1.5</version>
</dependency>
然后我直接写接口
@RestController
@RequestMapping("/ai")
@Api(tags = "ai")
public class AiController {
@ApiOperation("ai对话")
@PostMapping("/test")
public ResultResponse test(String msg){
OpenAiClient openAiClient = OpenAiClient.builder()
.apiKey(Arrays.asList("xxxxxxxxxxxxxxxxxxxxxxxxxxxxx"))
.build();
Message message = Message.builder().role(Message.Role.USER).content(msg).build();
ChatCompletion chatCompletion = ChatCompletion.builder().messages(Arrays.asList(message)).build();
ChatCompletionResponse chatCompletionResponse = openAiClient.chatCompletion(chatCompletion);
// chatCompletionResponse.getChoices().forEach(e -> {
// System.out.println(e.getMessage());
// });
return ResultResponse.success(chatCompletionResponse.getChoices());
}
}
xxxxxxxxxxxxxxx自己替换成自己的key哈。
结束,到这里就可以直接使用gpt了,自己去postman测试一下就行。
2.直接给官网api发请求
首先3个dto类
@Data
@NoArgsConstructor
@AllArgsConstructor
public class ChatBotRequest {
private String model;
private List<Message> messages;
private int n;
private double temperature;
private int max_tokens;
}
------------------------------------------
@Data
@AllArgsConstructor
@NoArgsConstructor
public class ChatBotResponse {
private List<Choice> choices;
@Data
@AllArgsConstructor
@NoArgsConstructor
public static class Choice {
private int index;
private Message message;
}
}
------------------------------------------
@Data
@NoArgsConstructor
@AllArgsConstructor
public class Message {
private String role;
private String content;
}
其次配置一下config
@Configuration
public class OpenAIChatGtpConfig {
private final String openaiApiKey = "xxxxxxxxxxxxxxxxxxxxxxx";
@Bean
public RestTemplate restTemplate() {
RestTemplate restTemplate = new RestTemplate();
restTemplate.getInterceptors().add((request, body, execution) -> {
request.getHeaders().add("Authorization", "Bearer " + openaiApiKey);
return execution.execute(request, body);
});
return restTemplate;
}
}
最后依然是直接写接口
@Api(tags = "chat")
@RestController
@RequestMapping("/chats")
public class ChatBotController {
@Autowired
private RestTemplate restTemplate;
@ApiOperation("chat")
@PostMapping("/chat")
public ChatBotResponse chat(@RequestParam("prompt") String prompt) {
ChatBotRequest request = new ChatBotRequest("gpt-3.5-turbo",
Arrays.asList(new Message("user", prompt)),
1,
0,
100);
ChatBotResponse chatBotResponse = restTemplate.postForObject("https://api.openai.com/v1/chat/completions", request, ChatBotResponse.class);
return chatBotResponse;
}
}
至此第二种整合方式也结束了,其实就这种阻塞式整合真的很简单,不过体验感其实比不上流式整合,回头什么时候去试试流式整合。
Cannot resolve method 'of' in 'List' 或 找不到符号of
顺带今天碰见了一点小报错,才知道Arrays.asList其实等同于List.of。不过List.of是jdk9里面新出的,jdk8没有,因此只能用自己的老东西Arrays.asList。( 参考的是【BUG】Cannot resolve method 'of' in 'List' 或 找不到符号of(非jdk8版本问题)_cannot resolve method 'of' in 'list-CSDN博客)
两种整合方式都可以顺利连通,不过此时我发现gpt竟然无法联系上下文。去网上找了很久发现原来暂时没有可以直接自己联系上下文的大模型,因此得自己来做操作。感到疑惑可以看一下这个博客:手把手教会你如何通过ChatGPT API实现上下文对话 - 个人文章 - SegmentFault 思否
原理很简单,每次把之前得mes全部拼接起来,直接开始实现吧:
maven依赖:
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-redis</artifactId>
</dependency>
@RestController
@RequestMapping("/ai")
@Api(tags = "ai")
public class AiController {
public static final String token = "sk-proj-xElzheeQc3nqZrWm3J6lT3BlbkFJRCQpGjcqfdkj5jsdC1KM";
private static final String CHAT_HISTORY_KEY = "chat_history";
@Autowired
private RedisTemplate<String, String> redisTemplate;
@Autowired
private AiService aiService;
@ApiOperation("ai对话")
@PostMapping("/tall")
public ResultResponse tall(@RequestParam("msg") String msg,@RequestParam("userId") String userId) {
String keyword = CHAT_HISTORY_KEY + "_tall" + userId;
ListOperations<String, String> listOps = redisTemplate.opsForList();
Message userMessage = Message.builder().role(Message.Role.USER).content(msg).build();
List<String> history = listOps.range(keyword , 0, -1);
List<Message> messages = new ArrayList<>();
for (String historicalMessage : history) {
messages.add(Message.builder().role(Message.Role.USER).content(historicalMessage).build());
}
messages.add(userMessage);
OpenAiClient openAiClient = OpenAiClient.builder()
.apiKey(Arrays.asList(token))
.build();
ChatCompletion chatCompletion = ChatCompletion
.builder()
.messages(messages)
.model("gpt-3.5-turbo")
.build();
ChatCompletionResponse chatCompletionResponse = openAiClient.chatCompletion(chatCompletion);
String gptResponse = chatCompletionResponse.getChoices().get(0).getMessage().getContent();
if(redisTemplate.opsForList().size(keyword ) >= 6){
listOps.leftPop(keyword );
}
listOps.rightPush(keyword, "user:"+msg); //指定role角色更有利于ai理解上下文信息
listOps.rightPush(keyword, "assistant:"+gptResponse);
return ResultResponse.success(gptResponse);
}
}
很简单,就用了redis得list结构当作一个消息队列用,记录最近得6条上下文,每次拼接过去就好。
防止缓存一直占空间,可以自己弄个定时器每天或者每个月清理一次消息队列。
先再自己得application上面加个开关注解:
@EnableScheduling
@SpringBootApplication()
public class ExamsystemApplication extends SpringBootServletInitializer
然后直接写定时器:
@Component
public class TimerTask {
@Autowired
private RedisTemplate<String, String> redisTemplate;
@Scheduled(cron = "0 0 0 1 * ?") // 每个月1号的凌晨执行
public void TaskMethod() {
try {
Set<String> keys = redisTemplate.keys("chat_history*");
redisTemplate.delete(keys);
} catch (Exception e) {
System.err.println("Failed to reset frequency: " + e.getMessage());
}
}
}
到现在ai也拥有上下文了,爽歪歪。