🎨 悠米(chatgpt) 服务功能优化
🎨 悠米(chatgpt) 服务功能优化
This commit is contained in:
commit
7aca99c8d4
6
pom.xml
6
pom.xml
@ -152,7 +152,7 @@
|
|||||||
<dependency>
|
<dependency>
|
||||||
<groupId>com.alibaba</groupId>
|
<groupId>com.alibaba</groupId>
|
||||||
<artifactId>fastjson</artifactId>
|
<artifactId>fastjson</artifactId>
|
||||||
<version>2.0.20</version>
|
<version>2.0.25</version>
|
||||||
</dependency>
|
</dependency>
|
||||||
<!-- shiro权限控制框架 -->
|
<!-- shiro权限控制框架 -->
|
||||||
<dependency>
|
<dependency>
|
||||||
@ -305,12 +305,12 @@
|
|||||||
<dependency>
|
<dependency>
|
||||||
<groupId>cn.hutool</groupId>
|
<groupId>cn.hutool</groupId>
|
||||||
<artifactId>hutool-core</artifactId>
|
<artifactId>hutool-core</artifactId>
|
||||||
<version>5.8.11</version>
|
<version>5.8.19</version>
|
||||||
</dependency>
|
</dependency>
|
||||||
<dependency>
|
<dependency>
|
||||||
<groupId>cn.hutool</groupId>
|
<groupId>cn.hutool</groupId>
|
||||||
<artifactId>hutool-http</artifactId>
|
<artifactId>hutool-http</artifactId>
|
||||||
<version>5.8.11</version>
|
<version>5.8.19</version>
|
||||||
</dependency>
|
</dependency>
|
||||||
|
|
||||||
<dependency>
|
<dependency>
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
package com.rymcu.forest.config;
|
package com.rymcu.forest.config;
|
||||||
|
|
||||||
import com.alibaba.fastjson.support.spring.FastJsonJsonView;
|
import com.alibaba.fastjson.support.spring.annotation.FastJsonView;
|
||||||
import com.rymcu.forest.core.exception.BusinessException;
|
import com.rymcu.forest.core.exception.BusinessException;
|
||||||
import com.rymcu.forest.core.exception.ServiceException;
|
import com.rymcu.forest.core.exception.ServiceException;
|
||||||
import com.rymcu.forest.core.exception.TransactionException;
|
import com.rymcu.forest.core.exception.TransactionException;
|
||||||
@ -47,7 +47,7 @@ public class BaseExceptionHandler {
|
|||||||
result = new GlobalResult<>(ResultCode.UNAUTHORIZED);
|
result = new GlobalResult<>(ResultCode.UNAUTHORIZED);
|
||||||
logger.info("用户无权限");
|
logger.info("用户无权限");
|
||||||
} else if (ex instanceof UnknownAccountException) {
|
} else if (ex instanceof UnknownAccountException) {
|
||||||
// 账号或密码错误
|
// 未知账号
|
||||||
result = new GlobalResult<>(ResultCode.UNKNOWN_ACCOUNT);
|
result = new GlobalResult<>(ResultCode.UNKNOWN_ACCOUNT);
|
||||||
logger.info(ex.getMessage());
|
logger.info(ex.getMessage());
|
||||||
} else if (ex instanceof AccountException) {
|
} else if (ex instanceof AccountException) {
|
||||||
@ -91,7 +91,7 @@ public class BaseExceptionHandler {
|
|||||||
return result;
|
return result;
|
||||||
} else {
|
} else {
|
||||||
ModelAndView mv = new ModelAndView();
|
ModelAndView mv = new ModelAndView();
|
||||||
FastJsonJsonView view = new FastJsonJsonView();
|
FastJsonView view = new FastJsonView();
|
||||||
Map<String, Object> attributes = new HashMap(2);
|
Map<String, Object> attributes = new HashMap(2);
|
||||||
if (ex instanceof UnauthenticatedException) {
|
if (ex instanceof UnauthenticatedException) {
|
||||||
attributes.put("code", ResultCode.UNAUTHENTICATED.getCode());
|
attributes.put("code", ResultCode.UNAUTHENTICATED.getCode());
|
||||||
@ -99,6 +99,16 @@ public class BaseExceptionHandler {
|
|||||||
} else if (ex instanceof UnauthorizedException) {
|
} else if (ex instanceof UnauthorizedException) {
|
||||||
attributes.put("code", ResultCode.UNAUTHORIZED.getCode());
|
attributes.put("code", ResultCode.UNAUTHORIZED.getCode());
|
||||||
attributes.put("message", ResultCode.UNAUTHORIZED.getMessage());
|
attributes.put("message", ResultCode.UNAUTHORIZED.getMessage());
|
||||||
|
} else if (ex instanceof UnknownAccountException) {
|
||||||
|
// 未知账号
|
||||||
|
attributes.put("code", ResultCode.UNKNOWN_ACCOUNT.getCode());
|
||||||
|
attributes.put("message", ex.getMessage());
|
||||||
|
logger.info(ex.getMessage());
|
||||||
|
} else if (ex instanceof AccountException) {
|
||||||
|
// 账号或密码错误
|
||||||
|
attributes.put("code", ResultCode.INCORRECT_ACCOUNT_OR_PASSWORD.getCode());
|
||||||
|
attributes.put("message", ex.getMessage());
|
||||||
|
logger.info(ex.getMessage());
|
||||||
} else if (ex instanceof ServiceException) {
|
} else if (ex instanceof ServiceException) {
|
||||||
//业务失败的异常,如“账号或密码错误”
|
//业务失败的异常,如“账号或密码错误”
|
||||||
attributes.put("code", ((ServiceException) ex).getCode());
|
attributes.put("code", ((ServiceException) ex).getCode());
|
||||||
|
@ -4,8 +4,10 @@ import com.alibaba.fastjson.JSONObject;
|
|||||||
import com.rymcu.forest.core.result.GlobalResult;
|
import com.rymcu.forest.core.result.GlobalResult;
|
||||||
import com.rymcu.forest.core.result.GlobalResultGenerator;
|
import com.rymcu.forest.core.result.GlobalResultGenerator;
|
||||||
import com.rymcu.forest.entity.User;
|
import com.rymcu.forest.entity.User;
|
||||||
|
import com.rymcu.forest.openai.entity.ChatMessageModel;
|
||||||
import com.rymcu.forest.openai.service.OpenAiService;
|
import com.rymcu.forest.openai.service.OpenAiService;
|
||||||
import com.rymcu.forest.openai.service.SseService;
|
import com.rymcu.forest.openai.service.SseService;
|
||||||
|
import com.rymcu.forest.util.Html2TextUtil;
|
||||||
import com.rymcu.forest.util.UserUtils;
|
import com.rymcu.forest.util.UserUtils;
|
||||||
import com.theokanning.openai.completion.chat.ChatCompletionChoice;
|
import com.theokanning.openai.completion.chat.ChatCompletionChoice;
|
||||||
import com.theokanning.openai.completion.chat.ChatCompletionChunk;
|
import com.theokanning.openai.completion.chat.ChatCompletionChunk;
|
||||||
@ -13,6 +15,7 @@ import com.theokanning.openai.completion.chat.ChatCompletionRequest;
|
|||||||
import com.theokanning.openai.completion.chat.ChatMessage;
|
import com.theokanning.openai.completion.chat.ChatMessage;
|
||||||
import io.reactivex.Flowable;
|
import io.reactivex.Flowable;
|
||||||
import org.apache.commons.lang.StringUtils;
|
import org.apache.commons.lang.StringUtils;
|
||||||
|
import org.jetbrains.annotations.NotNull;
|
||||||
import org.springframework.beans.factory.annotation.Value;
|
import org.springframework.beans.factory.annotation.Value;
|
||||||
import org.springframework.web.bind.annotation.PostMapping;
|
import org.springframework.web.bind.annotation.PostMapping;
|
||||||
import org.springframework.web.bind.annotation.RequestBody;
|
import org.springframework.web.bind.annotation.RequestBody;
|
||||||
@ -22,6 +25,7 @@ import org.springframework.web.bind.annotation.RestController;
|
|||||||
import javax.annotation.Resource;
|
import javax.annotation.Resource;
|
||||||
import java.time.Duration;
|
import java.time.Duration;
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
|
import java.util.Collections;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -50,9 +54,36 @@ public class OpenAiController {
|
|||||||
ChatMessage chatMessage = new ChatMessage("user", message);
|
ChatMessage chatMessage = new ChatMessage("user", message);
|
||||||
List<ChatMessage> list = new ArrayList<>(4);
|
List<ChatMessage> list = new ArrayList<>(4);
|
||||||
list.add(chatMessage);
|
list.add(chatMessage);
|
||||||
|
return sendMessage(user, list);
|
||||||
|
}
|
||||||
|
|
||||||
|
@PostMapping("/new-chat")
|
||||||
|
public GlobalResult newChat(@RequestBody List<ChatMessageModel> messages) {
|
||||||
|
if (messages.isEmpty()) {
|
||||||
|
throw new IllegalArgumentException("参数异常!");
|
||||||
|
}
|
||||||
|
User user = UserUtils.getCurrentUserByToken();
|
||||||
|
Collections.reverse(messages);
|
||||||
|
List<ChatMessage> list = new ArrayList<>(messages.size());
|
||||||
|
if (messages.size() > 4) {
|
||||||
|
messages = messages.subList(messages.size() - 4, messages.size());
|
||||||
|
}
|
||||||
|
if (messages.size() >= 4 && messages.size() % 4 == 0) {
|
||||||
|
ChatMessage message = new ChatMessage("system", "简单总结一下你和用户的对话, 用作后续的上下文提示 prompt, 控制在 200 字内");
|
||||||
|
list.add(message);
|
||||||
|
}
|
||||||
|
messages.forEach(chatMessageModel -> {
|
||||||
|
ChatMessage message = new ChatMessage(chatMessageModel.getRole(), Html2TextUtil.getContent(chatMessageModel.getContent()));
|
||||||
|
list.add(message);
|
||||||
|
});
|
||||||
|
return sendMessage(user, list);
|
||||||
|
}
|
||||||
|
|
||||||
|
@NotNull
|
||||||
|
private GlobalResult sendMessage(User user, List<ChatMessage> list) {
|
||||||
OpenAiService service = new OpenAiService(token, Duration.ofSeconds(180));
|
OpenAiService service = new OpenAiService(token, Duration.ofSeconds(180));
|
||||||
ChatCompletionRequest completionRequest = ChatCompletionRequest.builder()
|
ChatCompletionRequest completionRequest = ChatCompletionRequest.builder()
|
||||||
.model("gpt-3.5-turbo")
|
.model("gpt-3.5-turbo-16k-0613")
|
||||||
.stream(true)
|
.stream(true)
|
||||||
.messages(list)
|
.messages(list)
|
||||||
.build();
|
.build();
|
||||||
|
@ -0,0 +1,26 @@
|
|||||||
|
package com.rymcu.forest.openai.entity;
|
||||||
|
|
||||||
|
import lombok.Data;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Created on 2023/7/16 14:52.
|
||||||
|
*
|
||||||
|
* @author ronger
|
||||||
|
* @email ronger-x@outlook.com
|
||||||
|
* @desc : com.rymcu.forest.openai.entity
|
||||||
|
*/
|
||||||
|
@Data
|
||||||
|
public class ChatMessageModel {
|
||||||
|
|
||||||
|
Long dataId;
|
||||||
|
|
||||||
|
String to;
|
||||||
|
|
||||||
|
String from;
|
||||||
|
|
||||||
|
Integer dataType;
|
||||||
|
|
||||||
|
String content;
|
||||||
|
|
||||||
|
String role;
|
||||||
|
}
|
@ -0,0 +1,29 @@
|
|||||||
|
package com.rymcu.forest.openai.service;
|
||||||
|
|
||||||
|
import okhttp3.Interceptor;
|
||||||
|
import okhttp3.Request;
|
||||||
|
import okhttp3.Response;
|
||||||
|
|
||||||
|
import java.io.IOException;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* OkHttp Interceptor that adds an ip address header
|
||||||
|
* @author ronger
|
||||||
|
*/
|
||||||
|
public class IpAddressInterceptor implements Interceptor {
|
||||||
|
|
||||||
|
private final String ip;
|
||||||
|
|
||||||
|
IpAddressInterceptor(String ip) {
|
||||||
|
this.ip = ip;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Response intercept(Chain chain) throws IOException {
|
||||||
|
Request request = chain.request()
|
||||||
|
.newBuilder()
|
||||||
|
.header("x-forwarded-for", ip)
|
||||||
|
.build();
|
||||||
|
return chain.proceed(request);
|
||||||
|
}
|
||||||
|
}
|
@ -5,6 +5,7 @@ import com.fasterxml.jackson.databind.DeserializationFeature;
|
|||||||
import com.fasterxml.jackson.databind.ObjectMapper;
|
import com.fasterxml.jackson.databind.ObjectMapper;
|
||||||
import com.fasterxml.jackson.databind.PropertyNamingStrategy;
|
import com.fasterxml.jackson.databind.PropertyNamingStrategy;
|
||||||
import com.rymcu.forest.util.SpringContextHolder;
|
import com.rymcu.forest.util.SpringContextHolder;
|
||||||
|
import com.rymcu.forest.util.Utils;
|
||||||
import com.theokanning.openai.DeleteResult;
|
import com.theokanning.openai.DeleteResult;
|
||||||
import com.theokanning.openai.OpenAiApi;
|
import com.theokanning.openai.OpenAiApi;
|
||||||
import com.theokanning.openai.OpenAiError;
|
import com.theokanning.openai.OpenAiError;
|
||||||
@ -30,18 +31,20 @@ import com.theokanning.openai.image.ImageResult;
|
|||||||
import com.theokanning.openai.model.Model;
|
import com.theokanning.openai.model.Model;
|
||||||
import com.theokanning.openai.moderation.ModerationRequest;
|
import com.theokanning.openai.moderation.ModerationRequest;
|
||||||
import com.theokanning.openai.moderation.ModerationResult;
|
import com.theokanning.openai.moderation.ModerationResult;
|
||||||
|
|
||||||
import io.reactivex.BackpressureStrategy;
|
import io.reactivex.BackpressureStrategy;
|
||||||
import io.reactivex.Flowable;
|
import io.reactivex.Flowable;
|
||||||
import io.reactivex.Single;
|
import io.reactivex.Single;
|
||||||
import okhttp3.*;
|
import okhttp3.*;
|
||||||
import org.springframework.core.env.Environment;
|
import org.springframework.core.env.Environment;
|
||||||
|
import org.springframework.web.context.request.RequestContextHolder;
|
||||||
|
import org.springframework.web.context.request.ServletRequestAttributes;
|
||||||
|
import retrofit2.Call;
|
||||||
import retrofit2.HttpException;
|
import retrofit2.HttpException;
|
||||||
import retrofit2.Retrofit;
|
import retrofit2.Retrofit;
|
||||||
import retrofit2.Call;
|
|
||||||
import retrofit2.adapter.rxjava2.RxJava2CallAdapterFactory;
|
import retrofit2.adapter.rxjava2.RxJava2CallAdapterFactory;
|
||||||
import retrofit2.converter.jackson.JacksonConverterFactory;
|
import retrofit2.converter.jackson.JacksonConverterFactory;
|
||||||
|
|
||||||
|
import javax.servlet.http.HttpServletRequest;
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.time.Duration;
|
import java.time.Duration;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
@ -336,8 +339,11 @@ public class OpenAiService {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public static OkHttpClient defaultClient(String token, Duration timeout) {
|
public static OkHttpClient defaultClient(String token, Duration timeout) {
|
||||||
|
HttpServletRequest request = ((ServletRequestAttributes) RequestContextHolder.getRequestAttributes()).getRequest();
|
||||||
|
String ip = Utils.getIpAddress(request);
|
||||||
return new OkHttpClient.Builder()
|
return new OkHttpClient.Builder()
|
||||||
.addInterceptor(new AuthenticationInterceptor(token))
|
.addInterceptor(new AuthenticationInterceptor(token))
|
||||||
|
.addInterceptor(new IpAddressInterceptor(ip))
|
||||||
.connectionPool(new ConnectionPool(5, 1, TimeUnit.SECONDS))
|
.connectionPool(new ConnectionPool(5, 1, TimeUnit.SECONDS))
|
||||||
.readTimeout(timeout.toMillis(), TimeUnit.MILLISECONDS)
|
.readTimeout(timeout.toMillis(), TimeUnit.MILLISECONDS)
|
||||||
.build();
|
.build();
|
||||||
|
Loading…
Reference in New Issue
Block a user