dashan
2 years ago
commit
48ab525e9d
13 changed files with 522 additions and 0 deletions
@ -0,0 +1,31 @@ |
|||||||
|
# Compiled class file |
||||||
|
*.class |
||||||
|
|
||||||
|
# Log file |
||||||
|
*.log |
||||||
|
|
||||||
|
# BlueJ files |
||||||
|
*.ctxt |
||||||
|
|
||||||
|
# Mobile Tools for Java (J2ME) |
||||||
|
.mtj.tmp/ |
||||||
|
|
||||||
|
# Package Files # |
||||||
|
*.jar |
||||||
|
*.war |
||||||
|
*.nar |
||||||
|
*.ear |
||||||
|
*.zip |
||||||
|
*.tar.gz |
||||||
|
*.rar |
||||||
|
|
||||||
|
# virtual machine crash logs, see http://www.java.com/en/download/help/error_hotspot.xml |
||||||
|
hs_err_pid* |
||||||
|
|
||||||
|
/*.iml |
||||||
|
|
||||||
|
/*/*.iml |
||||||
|
/.idea/ |
||||||
|
|
||||||
|
/docs/ppt/~*.pptx |
||||||
|
/docs/config/docker.config |
@ -0,0 +1,78 @@ |
|||||||
|
<?xml version="1.0" encoding="UTF-8"?> |
||||||
|
<project xmlns="http://maven.apache.org/POM/4.0.0" |
||||||
|
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" |
||||||
|
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"> |
||||||
|
<modelVersion>4.0.0</modelVersion> |
||||||
|
|
||||||
|
<groupId>cn.dashan</groupId> |
||||||
|
<artifactId>chatbot-api</artifactId> |
||||||
|
<version>1.0-SNAPSHOT</version> |
||||||
|
|
||||||
|
<properties> |
||||||
|
<maven.compiler.source>8</maven.compiler.source> |
||||||
|
<maven.compiler.target>8</maven.compiler.target> |
||||||
|
</properties> |
||||||
|
|
||||||
|
<parent> |
||||||
|
<groupId>org.springframework.boot</groupId> |
||||||
|
<artifactId>spring-boot-starter-parent</artifactId> |
||||||
|
<version>2.3.5.RELEASE</version> |
||||||
|
<relativePath/> <!-- lookup parent from repository --> |
||||||
|
</parent> |
||||||
|
<dependencies> |
||||||
|
<dependency> |
||||||
|
<groupId>org.springframework.boot</groupId> |
||||||
|
<artifactId>spring-boot-starter-web</artifactId> |
||||||
|
</dependency> |
||||||
|
<dependency> |
||||||
|
<groupId>org.springframework.boot</groupId> |
||||||
|
<artifactId>spring-boot-starter-test</artifactId> |
||||||
|
<scope>test</scope> |
||||||
|
</dependency> |
||||||
|
<dependency> |
||||||
|
<groupId>com.alibaba</groupId> |
||||||
|
<artifactId>fastjson</artifactId> |
||||||
|
<version>1.2.58</version> |
||||||
|
</dependency> |
||||||
|
</dependencies> |
||||||
|
|
||||||
|
<build> |
||||||
|
<finalName>chatbot-api</finalName> |
||||||
|
<resources> |
||||||
|
<resource> |
||||||
|
<directory>src/main/resources</directory> |
||||||
|
<filtering>true</filtering> |
||||||
|
<includes> |
||||||
|
<include>**/**</include> |
||||||
|
</includes> |
||||||
|
</resource> |
||||||
|
</resources> |
||||||
|
<testResources> |
||||||
|
<testResource> |
||||||
|
<directory>src/test/resources</directory> |
||||||
|
<filtering>true</filtering> |
||||||
|
<includes> |
||||||
|
<include>**/**</include> |
||||||
|
</includes> |
||||||
|
</testResource> |
||||||
|
</testResources> |
||||||
|
<plugins> |
||||||
|
<plugin> |
||||||
|
<groupId>org.apache.maven.plugins</groupId> |
||||||
|
<artifactId>maven-surefire-plugin</artifactId> |
||||||
|
<version>2.12.4</version> |
||||||
|
<configuration> |
||||||
|
<skipTests>true</skipTests> |
||||||
|
</configuration> |
||||||
|
</plugin> |
||||||
|
<plugin> |
||||||
|
<groupId>org.apache.maven.plugins</groupId> |
||||||
|
<artifactId>maven-compiler-plugin</artifactId> |
||||||
|
<configuration> |
||||||
|
<source>8</source> |
||||||
|
<target>8</target> |
||||||
|
</configuration> |
||||||
|
</plugin> |
||||||
|
</plugins> |
||||||
|
</build> |
||||||
|
</project> |
@ -0,0 +1,23 @@ |
|||||||
|
package cn.dashan.chatbot; |
||||||
|
|
||||||
|
import org.springframework.boot.SpringApplication; |
||||||
|
import org.springframework.boot.autoconfigure.SpringBootApplication; |
||||||
|
import org.springframework.context.annotation.Bean; |
||||||
|
import org.springframework.web.client.RestTemplate; |
||||||
|
|
||||||
|
/** |
||||||
|
* @author ds |
||||||
|
* @since 2023/2/11 |
||||||
|
*/ |
||||||
|
@SpringBootApplication |
||||||
|
public class ChatBotApplication { |
||||||
|
|
||||||
|
public static void main(String[] args) { |
||||||
|
SpringApplication.run(ChatBotApplication.class,args); |
||||||
|
} |
||||||
|
|
||||||
|
@Bean |
||||||
|
public RestTemplate restTemplate(){ |
||||||
|
return new RestTemplate(); |
||||||
|
} |
||||||
|
} |
@ -0,0 +1,40 @@ |
|||||||
|
package cn.dashan.chatbot.api; |
||||||
|
|
||||||
|
import cn.dashan.chatbot.common.RestResponse; |
||||||
|
import cn.dashan.chatbot.model.enums.OpenAIModel; |
||||||
|
import cn.dashan.chatbot.service.IOpenAI; |
||||||
|
import org.slf4j.Logger; |
||||||
|
import org.slf4j.LoggerFactory; |
||||||
|
import org.springframework.web.bind.annotation.GetMapping; |
||||||
|
import org.springframework.web.bind.annotation.RequestParam; |
||||||
|
import org.springframework.web.bind.annotation.RestController; |
||||||
|
|
||||||
|
/** |
||||||
|
* @author ds |
||||||
|
* @since 2023/2/11 |
||||||
|
*/ |
||||||
|
@RestController |
||||||
|
public class ChatBotApi { |
||||||
|
|
||||||
|
Logger logger = LoggerFactory.getLogger(ChatBotApi.class); |
||||||
|
|
||||||
|
private final IOpenAI openAI; |
||||||
|
|
||||||
|
public ChatBotApi(IOpenAI openAI) { |
||||||
|
this.openAI = openAI; |
||||||
|
} |
||||||
|
|
||||||
|
@GetMapping("/bot") |
||||||
|
public RestResponse<String> bot( |
||||||
|
@RequestParam("question") String question, |
||||||
|
@RequestParam("model") OpenAIModel model |
||||||
|
){ |
||||||
|
logger.info("执行bot接口,客户端传参-model:{},question:{}",model,question); |
||||||
|
try { |
||||||
|
return new RestResponse.Builder<String>(RestResponse.MSG.SUCCESS).setDate(openAI.doChatGPT(question,model)).builder(); |
||||||
|
}catch (RuntimeException e){ |
||||||
|
logger.error("ChatGPT执行异常:",e); |
||||||
|
return new RestResponse.Builder<String>(RestResponse.MSG.FAILURE).setMsg(e.getMessage()).builder(); |
||||||
|
} |
||||||
|
} |
||||||
|
} |
@ -0,0 +1,84 @@ |
|||||||
|
package cn.dashan.chatbot.common; |
||||||
|
|
||||||
|
import java.io.Serializable; |
||||||
|
|
||||||
|
/** |
||||||
|
* @author ds |
||||||
|
* @since 2023/2/11 |
||||||
|
*/ |
||||||
|
public class RestResponse<T> implements Serializable { |
||||||
|
|
||||||
|
private final int code; |
||||||
|
private final String msg; |
||||||
|
private final T data; |
||||||
|
|
||||||
|
|
||||||
|
public enum MSG{ |
||||||
|
SUCCESS(1,"SUCCESS"), |
||||||
|
FAILURE(0,"FAILURE"); |
||||||
|
|
||||||
|
private final int code; |
||||||
|
private final String msg; |
||||||
|
|
||||||
|
MSG(int code, String msg) { |
||||||
|
this.code = code; |
||||||
|
this.msg = msg; |
||||||
|
} |
||||||
|
|
||||||
|
public int getCode() { |
||||||
|
return this.code; |
||||||
|
} |
||||||
|
|
||||||
|
public String getMsg() { |
||||||
|
return this.msg; |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
public static class Builder<T>{ |
||||||
|
private final int code; |
||||||
|
private String msg; |
||||||
|
private T data; |
||||||
|
|
||||||
|
public Builder(int code){ |
||||||
|
this.code=code; |
||||||
|
} |
||||||
|
|
||||||
|
public Builder(MSG msg){ |
||||||
|
this.msg=msg.msg; |
||||||
|
this.code= msg.code; |
||||||
|
} |
||||||
|
|
||||||
|
public Builder<T> setMsg(String msg){ |
||||||
|
this.msg=msg; |
||||||
|
return this; |
||||||
|
} |
||||||
|
|
||||||
|
public Builder<T> setDate(T data){ |
||||||
|
this.data=data; |
||||||
|
return this; |
||||||
|
} |
||||||
|
|
||||||
|
public RestResponse<T> builder(){ |
||||||
|
return new RestResponse<>(this); |
||||||
|
} |
||||||
|
|
||||||
|
} |
||||||
|
|
||||||
|
private RestResponse(Builder<T> builder){ |
||||||
|
this.code=builder.code; |
||||||
|
this.msg=builder.msg; |
||||||
|
this.data=builder.data; |
||||||
|
} |
||||||
|
|
||||||
|
public int getCode() { |
||||||
|
return code; |
||||||
|
} |
||||||
|
|
||||||
|
public String getMsg() { |
||||||
|
return msg; |
||||||
|
} |
||||||
|
|
||||||
|
public T getData() { |
||||||
|
return data; |
||||||
|
} |
||||||
|
} |
@ -0,0 +1,36 @@ |
|||||||
|
package cn.dashan.chatbot.model.enums; |
||||||
|
|
||||||
|
/** |
||||||
|
* @author ds |
||||||
|
* @since 2023/2/11 |
||||||
|
*/ |
||||||
|
public enum OpenAIModel { |
||||||
|
TEXT_DEVINCI_003(1,"text-davinci-003",4000), |
||||||
|
TEXT_CURIE_001(2,"text-curie-001",2000), |
||||||
|
TEXT_BABBAGE_001(3,"text-babbage-001",2000), |
||||||
|
TEXT_ADA_001(4,"text-ada-001",2000) |
||||||
|
; |
||||||
|
|
||||||
|
|
||||||
|
private final int modelId; |
||||||
|
private final String model; |
||||||
|
private final int maxTokens; |
||||||
|
|
||||||
|
OpenAIModel(int modelId, String model, int maxTokens) { |
||||||
|
this.modelId = modelId; |
||||||
|
this.model = model; |
||||||
|
this.maxTokens = maxTokens; |
||||||
|
} |
||||||
|
|
||||||
|
public int getMaxTokens() { |
||||||
|
return maxTokens; |
||||||
|
} |
||||||
|
|
||||||
|
public int getModelId() { |
||||||
|
return modelId; |
||||||
|
} |
||||||
|
|
||||||
|
public String getModel() { |
||||||
|
return model; |
||||||
|
} |
||||||
|
} |
@ -0,0 +1,59 @@ |
|||||||
|
package cn.dashan.chatbot.model.vo; |
||||||
|
|
||||||
|
import java.util.List; |
||||||
|
|
||||||
|
/** |
||||||
|
* @author ds |
||||||
|
* @since 2023/2/12 |
||||||
|
*/ |
||||||
|
public class AIAnswer { |
||||||
|
private String id; |
||||||
|
|
||||||
|
private String object; |
||||||
|
|
||||||
|
private int created; |
||||||
|
|
||||||
|
private String model; |
||||||
|
|
||||||
|
private List<Choices> choices; |
||||||
|
|
||||||
|
public String getId() { |
||||||
|
return id; |
||||||
|
} |
||||||
|
|
||||||
|
public void setId(String id) { |
||||||
|
this.id = id; |
||||||
|
} |
||||||
|
|
||||||
|
public String getObject() { |
||||||
|
return object; |
||||||
|
} |
||||||
|
|
||||||
|
public void setObject(String object) { |
||||||
|
this.object = object; |
||||||
|
} |
||||||
|
|
||||||
|
public int getCreated() { |
||||||
|
return created; |
||||||
|
} |
||||||
|
|
||||||
|
public void setCreated(int created) { |
||||||
|
this.created = created; |
||||||
|
} |
||||||
|
|
||||||
|
public String getModel() { |
||||||
|
return model; |
||||||
|
} |
||||||
|
|
||||||
|
public void setModel(String model) { |
||||||
|
this.model = model; |
||||||
|
} |
||||||
|
|
||||||
|
public List<Choices> getChoices() { |
||||||
|
return choices; |
||||||
|
} |
||||||
|
|
||||||
|
public void setChoices(List<Choices> choices) { |
||||||
|
this.choices = choices; |
||||||
|
} |
||||||
|
} |
@ -0,0 +1,47 @@ |
|||||||
|
package cn.dashan.chatbot.model.vo; |
||||||
|
|
||||||
|
/** |
||||||
|
* @author ds |
||||||
|
* @since 2023/2/12 |
||||||
|
*/ |
||||||
|
public class Choices { |
||||||
|
private String text; |
||||||
|
|
||||||
|
private int index; |
||||||
|
|
||||||
|
private String logprobs; |
||||||
|
|
||||||
|
private String finish_reason; |
||||||
|
|
||||||
|
public String getText() { |
||||||
|
return text; |
||||||
|
} |
||||||
|
|
||||||
|
public void setText(String text) { |
||||||
|
this.text = text; |
||||||
|
} |
||||||
|
|
||||||
|
public int getIndex() { |
||||||
|
return index; |
||||||
|
} |
||||||
|
|
||||||
|
public void setIndex(int index) { |
||||||
|
this.index = index; |
||||||
|
} |
||||||
|
|
||||||
|
public String getLogprobs() { |
||||||
|
return logprobs; |
||||||
|
} |
||||||
|
|
||||||
|
public void setLogprobs(String logprobs) { |
||||||
|
this.logprobs = logprobs; |
||||||
|
} |
||||||
|
|
||||||
|
public String getFinish_reason() { |
||||||
|
return finish_reason; |
||||||
|
} |
||||||
|
|
||||||
|
public void setFinish_reason(String finish_reason) { |
||||||
|
this.finish_reason = finish_reason; |
||||||
|
} |
||||||
|
} |
@ -0,0 +1,19 @@ |
|||||||
|
package cn.dashan.chatbot.service; |
||||||
|
|
||||||
|
import cn.dashan.chatbot.model.enums.OpenAIModel; |
||||||
|
|
||||||
|
/** |
||||||
|
* @author ds |
||||||
|
* @since 2023/2/11 |
||||||
|
*/ |
||||||
|
public interface IOpenAI { |
||||||
|
|
||||||
|
/** |
||||||
|
* 向chatGPT发送请求 |
||||||
|
* @param question 问题 |
||||||
|
* @param model 型号 |
||||||
|
* @return 回答 |
||||||
|
* @throws RuntimeException 请求chatGPT异常或解析响应结果异常 |
||||||
|
*/ |
||||||
|
String doChatGPT(String question, OpenAIModel model) throws RuntimeException; |
||||||
|
} |
@ -0,0 +1,91 @@ |
|||||||
|
package cn.dashan.chatbot.service.impl; |
||||||
|
|
||||||
|
import cn.dashan.chatbot.model.enums.OpenAIModel; |
||||||
|
import cn.dashan.chatbot.model.vo.AIAnswer; |
||||||
|
import cn.dashan.chatbot.model.vo.Choices; |
||||||
|
import cn.dashan.chatbot.service.IOpenAI; |
||||||
|
import com.alibaba.fastjson.JSON; |
||||||
|
import com.alibaba.fastjson.JSONObject; |
||||||
|
import org.slf4j.Logger; |
||||||
|
import org.slf4j.LoggerFactory; |
||||||
|
import org.springframework.beans.factory.annotation.Value; |
||||||
|
import org.springframework.http.HttpEntity; |
||||||
|
import org.springframework.http.HttpHeaders; |
||||||
|
import org.springframework.http.HttpStatus; |
||||||
|
import org.springframework.http.ResponseEntity; |
||||||
|
import org.springframework.stereotype.Service; |
||||||
|
import org.springframework.web.client.RestTemplate; |
||||||
|
|
||||||
|
import java.util.HashMap; |
||||||
|
import java.util.Map; |
||||||
|
|
||||||
|
/** |
||||||
|
* @author ds |
||||||
|
* @since 2023/2/11 |
||||||
|
*/ |
||||||
|
@Service |
||||||
|
public class OpenAI implements IOpenAI { |
||||||
|
Logger logger = LoggerFactory.getLogger(OpenAI.class); |
||||||
|
|
||||||
|
@Value("${chatbot-api.bot.openAiKey}") |
||||||
|
private String openAiKey; |
||||||
|
|
||||||
|
private final RestTemplate restTemplate; |
||||||
|
public OpenAI(RestTemplate restTemplate) { |
||||||
|
this.restTemplate = restTemplate; |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* 使用RestTemplate 实现chatGPT发送请求 |
||||||
|
* @param question 问题 |
||||||
|
* @param model 型号 |
||||||
|
* @return 回答 |
||||||
|
* @throws RuntimeException 请求chatGPT异常或解析响应结果异常 |
||||||
|
*/ |
||||||
|
@Override |
||||||
|
public String doChatGPT(String question, OpenAIModel model) throws RuntimeException { |
||||||
|
logger.info("机器人{},接收消息:{}",model,question); |
||||||
|
//构建请求头
|
||||||
|
HttpHeaders headers = new HttpHeaders(); |
||||||
|
headers.set("Authorization","Bearer "+openAiKey); |
||||||
|
headers.set("Content-Type", "application/json"); |
||||||
|
|
||||||
|
//请求参数
|
||||||
|
Map<String,Object> params = new HashMap<>(); |
||||||
|
params.put("model",model.getModel()); |
||||||
|
params.put("prompt",question); |
||||||
|
params.put("temperature",0); |
||||||
|
params.put("max_tokens",model.getMaxTokens()); |
||||||
|
|
||||||
|
//构建请求体
|
||||||
|
HttpEntity<String> request = new HttpEntity<>(JSON.toJSONString(params),headers); |
||||||
|
|
||||||
|
//执行请求
|
||||||
|
ResponseEntity<String> responseEntity = restTemplate.postForEntity("https://api.openai.com/v1/completions", request, String.class); |
||||||
|
|
||||||
|
//判断执行是否成功
|
||||||
|
if (!HttpStatus.OK.equals(responseEntity.getStatusCode())){ |
||||||
|
logger.error("OpenAI 服务端接口请求异常:{}-{}",responseEntity.getStatusCode().value(),responseEntity.getStatusCode().getReasonPhrase()); |
||||||
|
throw new RuntimeException("ChatGPT 任务执行异常"); |
||||||
|
} |
||||||
|
|
||||||
|
|
||||||
|
//解析请求
|
||||||
|
StringBuilder stringBuilder = new StringBuilder(); |
||||||
|
try { |
||||||
|
AIAnswer answer = JSON.parseObject(responseEntity.getBody(),AIAnswer.class); |
||||||
|
assert answer != null; |
||||||
|
for (Choices choice : answer.getChoices()) { |
||||||
|
stringBuilder.append(choice.getText()); |
||||||
|
} |
||||||
|
}catch (RuntimeException e){ |
||||||
|
logger.error("answer 解析失败",e); |
||||||
|
throw new RuntimeException("answer 解析失败"); |
||||||
|
} |
||||||
|
|
||||||
|
String answerTest = stringBuilder.toString().replaceFirst("\\n", "").replaceFirst("\\n", ""); |
||||||
|
|
||||||
|
logger.info("机器人{},回答问题:{}",model,answerTest); |
||||||
|
return answerTest; |
||||||
|
} |
||||||
|
} |
@ -0,0 +1,6 @@ |
|||||||
|
server: |
||||||
|
port: 8092 |
||||||
|
# 分组任务配置 |
||||||
|
chatbot-api: |
||||||
|
bot: |
||||||
|
openAiKey: ###设置openai上申请的api key |
Loading…
Reference in new issue