初始代码
This commit is contained in:
25
yunzhupaas-boot-common/yunzhupaas-common-ai/pom.xml
Normal file
25
yunzhupaas-boot-common/yunzhupaas-common-ai/pom.xml
Normal file
@@ -0,0 +1,25 @@
|
||||
<?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>
|
||||
<parent>
|
||||
<groupId>com.yunzhupaas</groupId>
|
||||
<artifactId>yunzhupaas-boot-common</artifactId>
|
||||
<version>5.2.0-RELEASE</version>
|
||||
</parent>
|
||||
|
||||
<artifactId>yunzhupaas-common-ai</artifactId>
|
||||
|
||||
<dependencies>
|
||||
<dependency>
|
||||
<groupId>com.yunzhupaas</groupId>
|
||||
<artifactId>yunzhupaas-common-core</artifactId>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>com.unfbx</groupId>
|
||||
<artifactId>chatgpt-java</artifactId>
|
||||
</dependency>
|
||||
</dependencies>
|
||||
|
||||
</project>
|
||||
@@ -0,0 +1,203 @@
|
||||
package com.yunzhupaas.config;
|
||||
|
||||
import com.unfbx.chatgpt.OpenAiClient;
|
||||
import com.unfbx.chatgpt.function.KeyRandomStrategy;
|
||||
import com.unfbx.chatgpt.function.KeyStrategyFunction;
|
||||
import com.unfbx.chatgpt.interceptor.DefaultOpenAiAuthInterceptor;
|
||||
import com.unfbx.chatgpt.interceptor.OpenAiAuthInterceptor;
|
||||
import com.yunzhupaas.constants.AiConstants;
|
||||
import com.yunzhupaas.service.OpenAiService;
|
||||
import com.yunzhupaas.service.impl.DefaultOpenAiServiceImpl;
|
||||
import com.yunzhupaas.service.impl.DisabledOpenAiServiceImpl;
|
||||
import com.yunzhupaas.util.StringUtil;
|
||||
import okhttp3.Authenticator;
|
||||
import okhttp3.OkHttpClient;
|
||||
import org.springframework.beans.factory.annotation.Qualifier;
|
||||
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
|
||||
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
|
||||
import org.springframework.boot.context.properties.ConfigurationProperties;
|
||||
import org.springframework.context.annotation.Bean;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
|
||||
import java.net.InetSocketAddress;
|
||||
import java.net.PasswordAuthentication;
|
||||
import java.net.Proxy;
|
||||
import java.util.List;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
|
||||
/**
|
||||
* AI客户端 自动配置
|
||||
*
|
||||
* @author 云筑产品开发平台组
|
||||
* @copyright 深圳市乐程软件有限公司
|
||||
* @date 2024/10/9 14:03
|
||||
*/
|
||||
@Configuration(proxyBeanMethods = false)
|
||||
public class AiAutoConfiguration {
|
||||
|
||||
@Bean
|
||||
@ConditionalOnMissingBean
|
||||
@ConditionalOnProperty(prefix = AiConstants.CONFIGURATION_PREFIX, name = "enabled", havingValue = "false", matchIfMissing = true)
|
||||
public OpenAiService getDisabledOpenAiService() {
|
||||
return new DisabledOpenAiServiceImpl();
|
||||
}
|
||||
|
||||
@Configuration(proxyBeanMethods = false)
|
||||
@ConditionalOnProperty(prefix = AiConstants.CONFIGURATION_PREFIX, name = "enabled", havingValue = "true")
|
||||
public static class AiEnabledConfiguration {
|
||||
|
||||
@Bean
|
||||
@ConfigurationProperties(prefix = AiConstants.CONFIGURATION_PREFIX)
|
||||
public AiProperties getAiProperties() {
|
||||
return new AiProperties();
|
||||
}
|
||||
|
||||
@Bean
|
||||
public OpenAiService getDefaultOpenAiService(OpenAiClient openAiClient, AiProperties aiProperties) {
|
||||
return new DefaultOpenAiServiceImpl(openAiClient, aiProperties);
|
||||
}
|
||||
|
||||
@Bean
|
||||
@ConditionalOnMissingBean
|
||||
public OpenAiClient getOpenAiClient(
|
||||
@Qualifier(AiConstants.DEFAULT_HTTP_CLIENT_BEAN_NAME) OkHttpClient okHttpClient,
|
||||
KeyStrategyFunction<List<String>, String> keyStrategyFunction, OpenAiAuthInterceptor authInterceptor,
|
||||
AiProperties aiProperties) {
|
||||
String apiHost = aiProperties.getApiHost();
|
||||
// 需要以 / 结尾
|
||||
if (!apiHost.isEmpty() && !apiHost.endsWith("/")) {
|
||||
apiHost += "/";
|
||||
}
|
||||
// 构造openAiClient
|
||||
return OpenAiClient.builder()
|
||||
.apiHost(apiHost)
|
||||
.apiKey(aiProperties.getApiKey())
|
||||
.keyStrategy(keyStrategyFunction)
|
||||
.authInterceptor(authInterceptor)
|
||||
.okHttpClient(okHttpClient)
|
||||
.build();
|
||||
}
|
||||
|
||||
/*
|
||||
* @Bean
|
||||
*
|
||||
* @ConditionalOnMissingBean
|
||||
* public OpenAiStreamClient
|
||||
* getOpenAiStreamClient(@Qualifier(AiConstants.DEFAULT_HTTP_CLIENT_BEAN_NAME)
|
||||
* OkHttpClient okHttpClient
|
||||
* , KeyStrategyFunction<List<String>, String> keyStrategyFunction,
|
||||
* OpenAiAuthInterceptor authInterceptor, AiProperties aiProperties) {
|
||||
* String apiHost = aiProperties.getApiHost();
|
||||
* // 需要以 / 结尾
|
||||
* if(!apiHost.isEmpty() && !apiHost.endsWith("/")){
|
||||
* apiHost +="/";
|
||||
* }
|
||||
* // 构造openAiClient
|
||||
* return OpenAiStreamClient.builder()
|
||||
* .apiHost(apiHost)
|
||||
* .apiKey(aiProperties.getApiKey())
|
||||
* .keyStrategy(keyStrategyFunction)
|
||||
* .authInterceptor(authInterceptor)
|
||||
* .okHttpClient(okHttpClient)
|
||||
* .build();
|
||||
* }
|
||||
*/
|
||||
|
||||
/**
|
||||
* 多 Key 选择策略
|
||||
*/
|
||||
@Bean
|
||||
@ConditionalOnMissingBean
|
||||
public KeyStrategyFunction<List<String>, String> getDefaultOpenAiKeyStrategyFunction() {
|
||||
return new KeyRandomStrategy();
|
||||
}
|
||||
|
||||
/**
|
||||
* 认证拦截器
|
||||
*
|
||||
* @see com.unfbx.chatgpt.interceptor.DynamicKeyOpenAiAuthInterceptor 动态移除无效Key
|
||||
*/
|
||||
@Bean
|
||||
@ConditionalOnMissingBean
|
||||
public OpenAiAuthInterceptor getDefaultOpenAiAuthInterceptor() {
|
||||
return new DefaultOpenAiAuthInterceptor();
|
||||
}
|
||||
|
||||
/**
|
||||
* 默认okhttpclient
|
||||
*/
|
||||
@Bean(name = AiConstants.DEFAULT_HTTP_CLIENT_BEAN_NAME)
|
||||
@ConditionalOnMissingBean(name = AiConstants.DEFAULT_HTTP_CLIENT_BEAN_NAME)
|
||||
public OkHttpClient getDefaultOpenAiOkHttpClient(AiProperties aiProperties) {
|
||||
OkHttpClient.Builder builder = new OkHttpClient.Builder();
|
||||
|
||||
if (aiProperties.getProxy() != null
|
||||
&& StringUtil.isNotEmpty(aiProperties.getProxy().getHost())
|
||||
&& aiProperties.getProxy().getPort() != null) {
|
||||
// 设置代理
|
||||
builder.proxy(new Proxy(aiProperties.getProxy().getType(),
|
||||
new InetSocketAddress(aiProperties.getProxy().getHost(), aiProperties.getProxy().getPort())));
|
||||
// 设置代理认证
|
||||
if (StringUtil.isNotEmpty(aiProperties.getProxy().getUsername())
|
||||
&& StringUtil.isNotEmpty(aiProperties.getProxy().getPassword())) {
|
||||
builder.proxyAuthenticator(Authenticator.JAVA_NET_AUTHENTICATOR);
|
||||
java.net.Authenticator.setDefault(new java.net.Authenticator() {
|
||||
@Override
|
||||
protected PasswordAuthentication getPasswordAuthentication() {
|
||||
// 返回代理的用户名和密码
|
||||
return new PasswordAuthentication(aiProperties.getProxy().getUsername(),
|
||||
aiProperties.getProxy().getPassword().toCharArray());
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
/*
|
||||
* try {
|
||||
* // 创建一个信任所有证书的 TrustManager
|
||||
* final TrustManager[] trustAllCerts = new TrustManager[]{
|
||||
* new X509TrustManager() {
|
||||
*
|
||||
* @Override
|
||||
* public void checkClientTrusted(X509Certificate[] chain, String authType)
|
||||
* throws CertificateException {
|
||||
* }
|
||||
*
|
||||
* @Override
|
||||
* public void checkServerTrusted(X509Certificate[] chain, String authType)
|
||||
* throws CertificateException {
|
||||
* }
|
||||
*
|
||||
* @Override
|
||||
* public X509Certificate[] getAcceptedIssuers() {
|
||||
* return new X509Certificate[]{};
|
||||
* }
|
||||
* }
|
||||
* };
|
||||
*
|
||||
* // 安装所有信任管理器
|
||||
* final SSLContext sslContext = SSLContext.getInstance("SSL");
|
||||
* sslContext.init(null, trustAllCerts, new java.security.SecureRandom());
|
||||
*
|
||||
* // 创建 OkHttpClient 并配置 SSL socket factory 和 hostname verifier
|
||||
* final SSLSocketFactory sslSocketFactory = sslContext.getSocketFactory();
|
||||
*
|
||||
* // 信任所有证书
|
||||
* builder.sslSocketFactory(sslSocketFactory, (X509TrustManager)
|
||||
* trustAllCerts[0]);
|
||||
* builder.hostnameVerifier((hostname, session) -> true);
|
||||
* } catch (Exception e) {
|
||||
* throw new RuntimeException(e);
|
||||
* }
|
||||
*/
|
||||
|
||||
return builder
|
||||
.callTimeout(aiProperties.getTimeout(), TimeUnit.SECONDS)
|
||||
.connectTimeout(aiProperties.getTimeout(), TimeUnit.SECONDS)
|
||||
.writeTimeout(aiProperties.getTimeout(), TimeUnit.SECONDS)
|
||||
.readTimeout(aiProperties.getTimeout(), TimeUnit.SECONDS)
|
||||
.build();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,134 @@
|
||||
package com.yunzhupaas.config;
|
||||
|
||||
import com.yunzhupaas.constants.AiConstants;
|
||||
import lombok.Data;
|
||||
|
||||
import java.time.Duration;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* AI 配置
|
||||
*
|
||||
* @author 云筑产品开发平台组
|
||||
* @copyright 深圳市乐程软件有限公司
|
||||
* @date 2024/10/9 14:03
|
||||
*/
|
||||
@Data
|
||||
public class AiProperties {
|
||||
|
||||
/**
|
||||
* 是否启用
|
||||
*/
|
||||
private boolean enabled;
|
||||
|
||||
/**
|
||||
* openai服务器
|
||||
*/
|
||||
private String apiHost = AiConstants.OPENAI_HOST;
|
||||
|
||||
/**
|
||||
* openai key
|
||||
*/
|
||||
private List<String> apiKey;
|
||||
|
||||
/**
|
||||
* 超时时间
|
||||
*/
|
||||
private Long timeout = 30L;
|
||||
|
||||
/**
|
||||
* 每个用户限制时间内的请求次数
|
||||
*/
|
||||
private Integer userLimitCount = 1;
|
||||
|
||||
/**
|
||||
* 每个用户限制时间频率
|
||||
*/
|
||||
private Duration userLimitTime = Duration.ofSeconds(3);
|
||||
|
||||
/**
|
||||
* 全部请求限制时间内的请求次数
|
||||
*/
|
||||
private Integer totalLimitCount = 500;
|
||||
|
||||
/**
|
||||
* 全部请求限制时间频率
|
||||
*/
|
||||
private Duration totalLimitTime = Duration.ofMinutes(1L);
|
||||
|
||||
/**
|
||||
* 代理配置
|
||||
*/
|
||||
private Proxy proxy = new Proxy();
|
||||
|
||||
/**
|
||||
* 对话配置
|
||||
*/
|
||||
private ChatOption chat = new ChatOption();
|
||||
|
||||
|
||||
|
||||
|
||||
@Data
|
||||
public class ChatOption{
|
||||
|
||||
/**
|
||||
* @see AiConstants.Model
|
||||
*/
|
||||
private String mode = AiConstants.Model.QWEN_25_3;
|
||||
|
||||
/**
|
||||
* 设置seed参数会使文本生成过程更具有确定性,通常用于使模型每次运行的结果一致。
|
||||
* 在每次模型调用时传入相同的seed值(由您指定),并保持其他参数不变,模型将很可能返回相同的结果。
|
||||
*/
|
||||
private Integer seed = 1234;
|
||||
|
||||
/**
|
||||
* 允许模型生成的最大Token数。
|
||||
*/
|
||||
private Integer maxTokens = 1500;
|
||||
|
||||
/**
|
||||
* 核采样的概率阈值,用于控制模型生成文本的多样性。
|
||||
* top_p越高,生成的文本更多样。反之,生成的文本更确定。
|
||||
* 由于temperature与top_p均可以控制生成文本的多样性,因此建议您只设置其中一个值。
|
||||
*/
|
||||
private Double topP = 0.8;
|
||||
|
||||
/**
|
||||
* 采样温度,用于控制模型生成文本的多样性。
|
||||
* temperature越高,生成的文本更多样,反之,生成的文本更确定。
|
||||
* 由于temperature与top_p均可以控制生成文本的多样性,因此建议您只设置其中一个值。
|
||||
*/
|
||||
private Double temperature = 0.85;
|
||||
|
||||
private boolean enableSearch = true;
|
||||
|
||||
}
|
||||
|
||||
|
||||
@Data
|
||||
public class Proxy{
|
||||
/**
|
||||
* HTTP, SOCKS
|
||||
*/
|
||||
private java.net.Proxy.Type type = java.net.Proxy.Type.HTTP;
|
||||
/**
|
||||
* 代理域名
|
||||
*/
|
||||
private String host;
|
||||
/**
|
||||
* 代理端口
|
||||
*/
|
||||
private Integer port;
|
||||
/**
|
||||
* 代理用户名
|
||||
*/
|
||||
private String username;
|
||||
/**
|
||||
* 代理密码
|
||||
*/
|
||||
private String password;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,58 @@
|
||||
package com.yunzhupaas.constants;
|
||||
|
||||
/**
|
||||
* AI 常量
|
||||
*
|
||||
* @author 云筑产品开发平台组
|
||||
* @copyright 深圳市乐程软件有限公司
|
||||
* @date 2024/10/9 14:05
|
||||
*/
|
||||
public class AiConstants {
|
||||
|
||||
public static final String OPENAI_HOST = "https://dashscope.aliyuncs.com/compatible-mode/";
|
||||
|
||||
public static final String CONFIGURATION_PREFIX = "spring.cloud.ai.openai";
|
||||
|
||||
public static final String DEFAULT_HTTP_CLIENT_BEAN_NAME = "defaultOpenAiHttpClient";
|
||||
|
||||
public static final String GEN_MODEL_COMPNENT = "- input - textarea - inputNumber - switch - radio - checkbox - select - datePicker - timePicker - uploadFile - uploadImg - colorPicker - rate - slider - editor - depSelect - posSelect - userSelect - roleSelect - areaSelect - signature - sign - location";
|
||||
|
||||
public static final String GEN_MODEL_QUETION = "根据当前业务需求,设计相应的表单结构。请仅返回JSON数据,不包含其他任何形式的内容。预期结果是一个JSON数组,因涉及不同表单需求,故可能包含多个表单对象。请确保命名规避数据库与编程保留字。\n"
|
||||
+
|
||||
"所需表单应充分利用以下组件列表进行设计: " + GEN_MODEL_COMPNENT + "。\n" +
|
||||
"参考给定的JSON格式,属性包含:中文名(tableTitle)、英文名(tableName)、字段列表(fields);字段列表是一个json数组,包含字段英文名(fieldName)、字段中文名(fieldTitle)等;"
|
||||
+
|
||||
"创建表单结构,示例如下: [ { \"tableTitle\": \"商城订单\", \"tableName\": \"online_order_form\", \"fields\": [ {\"fieldTitle\": \"订单编号\", \"fieldName\": \"order_id\", \"fieldDbType\": \"varchar\", \"fieldComponent\": \"input\"}, {\"fieldTitle\": \"订单状态\", \"fieldName\": \"order_status\", \"fieldDbType\": \"int\", \"fieldComponent\": \"radio\", \"fieldOptions\":[{\"id\":\"1\", \"fullName\":\"未付款\"},{\"id\":\"2\", \"fullName\":\"已付款\"}]}] }, { \"tableTitle\": \"订单商品明细\", \"tableName\": \"order_item_details\", \"fields\": [ {\"fieldTitle\": \"订单ID(外键)\", \"fieldName\": \"order_id_fk\", \"fieldDbType\": \"varchar\", \"fieldComponent\": \"input\"}, {\"fieldTitle\": \"商品名称\", \"fieldName\": \"product_name\", \"fieldDbType\": \"varchar\", \"fieldComponent\": \"input\"}, {\"fieldTitle\": \"商品数量\", \"fieldName\": \"quantity\", \"fieldDbType\": \"int\", \"fieldComponent\": \"inputNumber\"}] } ]\n"
|
||||
+
|
||||
"请依据实际业务逻辑,合理选择组件与字段类型,确保设计的表单既能满足数据收集需求,又便于用户操作。";
|
||||
|
||||
public static final String CHAT_PRE_QUETION = "深圳市乐程软件有限公司下的低代码产品YUNZHUPAAS介绍";
|
||||
|
||||
/**
|
||||
* 模型名称
|
||||
*
|
||||
* @see com.unfbx.chatgpt.entity.chat.ChatCompletion.Model
|
||||
* <a href=
|
||||
* "https://help.aliyun.com/zh/model-studio/getting-started/models">阿里官方稳定模型列表</a>
|
||||
*/
|
||||
public static class Model {
|
||||
|
||||
/**
|
||||
* 通义千问系列效果最好的模型,适合复杂、多步骤的任务。
|
||||
*/
|
||||
public static final String QWEN_MAX = "qwen-max";
|
||||
/**
|
||||
* 通义千问系列速度最快、成本很低的模型,适合简单任务。
|
||||
*/
|
||||
public static final String QWEN_TURBO = "qwen-turbo";
|
||||
/**
|
||||
* 通义千问开源版, 可部署参数最高的版本, 云版本收费
|
||||
*/
|
||||
public static final String QWEN_25_72 = "qwen2.5-72b-instruct";
|
||||
/**
|
||||
* 通义千问开源版, 官方提供接口免费版本, 云版本限时免费
|
||||
*/
|
||||
public static final String QWEN_25_3 = "qwen2.5-3b-instruct";
|
||||
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,42 @@
|
||||
package com.yunzhupaas.service;
|
||||
|
||||
import com.unfbx.chatgpt.entity.chat.Message;
|
||||
import com.yunzhupaas.model.ai.AiFormModel;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
|
||||
/**
|
||||
* AI服务工具
|
||||
* @author 云筑产品开发平台组
|
||||
* @copyright 深圳市乐程软件有限公司
|
||||
* @date 2024/10/9 14:38
|
||||
*/
|
||||
public interface OpenAiService {
|
||||
|
||||
/**
|
||||
* 简单对话
|
||||
* @param prompt
|
||||
*/
|
||||
String completion(String prompt);
|
||||
|
||||
/**
|
||||
* 连续对话
|
||||
* @param messages 历史对话内容
|
||||
*/
|
||||
String completion(Message... messages);
|
||||
|
||||
/**
|
||||
* 生成表单
|
||||
* @param businessName 业务名称
|
||||
* @return
|
||||
*/
|
||||
String generatorModelStr(String businessName);
|
||||
|
||||
/**
|
||||
* 生成表单
|
||||
* @param prompt
|
||||
* @return
|
||||
*/
|
||||
List<AiFormModel> generatorModelVO(String prompt);
|
||||
}
|
||||
@@ -0,0 +1,101 @@
|
||||
package com.yunzhupaas.service.impl;
|
||||
|
||||
import com.alibaba.fastjson.JSON;
|
||||
import com.alibaba.fastjson.TypeReference;
|
||||
import com.unfbx.chatgpt.OpenAiClient;
|
||||
import com.unfbx.chatgpt.entity.chat.ChatCompletion;
|
||||
import com.unfbx.chatgpt.entity.chat.ChatCompletionResponse;
|
||||
import com.unfbx.chatgpt.entity.chat.Message;
|
||||
import com.yunzhupaas.config.AiProperties;
|
||||
import com.yunzhupaas.constant.MsgCode;
|
||||
import com.yunzhupaas.constants.AiConstants;
|
||||
import com.yunzhupaas.exception.DataException;
|
||||
import com.yunzhupaas.model.ai.AiFormModel;
|
||||
import com.yunzhupaas.service.OpenAiService;
|
||||
import com.yunzhupaas.util.StringUtil;
|
||||
import lombok.AllArgsConstructor;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
|
||||
import java.util.Arrays;
|
||||
import java.util.List;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
/**
|
||||
* OpenAi 实现类
|
||||
*
|
||||
* @author 云筑产品开发平台组
|
||||
* @copyright 深圳市乐程软件有限公司
|
||||
* @date 2024/10/9 14:39
|
||||
*/
|
||||
@Slf4j
|
||||
@AllArgsConstructor
|
||||
public class DefaultOpenAiServiceImpl implements OpenAiService {
|
||||
|
||||
private OpenAiClient openAiClient;
|
||||
private AiProperties aiProperties;
|
||||
|
||||
@Override
|
||||
public String completion(String prompt) {
|
||||
Message sendMessage = Message.builder().role(Message.Role.USER).content(prompt).build();
|
||||
ChatCompletion chatCompletion;
|
||||
if (StringUtil.isNotEmpty(prompt) && prompt.toLowerCase().contains("com.yunzhupaas")) {
|
||||
Message sysMessage = Message.builder().role(Message.Role.SYSTEM).content(AiConstants.CHAT_PRE_QUETION).build();
|
||||
chatCompletion = getDefaultChatComletion(sysMessage, sendMessage);
|
||||
} else {
|
||||
chatCompletion = getDefaultChatComletion(sendMessage);
|
||||
}
|
||||
ChatCompletionResponse chatCompletionResponse = openAiClient.chatCompletion(chatCompletion);
|
||||
return chatCompletionResponse.getChoices().stream().map(chatChoice -> chatChoice.getMessage().getContent()).collect(Collectors.joining());
|
||||
}
|
||||
|
||||
@Override
|
||||
public String generatorModelStr(String businessName) {
|
||||
Message sysMessage = Message.builder().role(Message.Role.SYSTEM).content(AiConstants.GEN_MODEL_QUETION).build();
|
||||
String userTemplate = "当前业务需求是:";
|
||||
Message sendMessage = Message.builder().role(Message.Role.USER).content(userTemplate + businessName).build();
|
||||
|
||||
ChatCompletion chatCompletion = getDefaultChatComletion(sysMessage, sendMessage);
|
||||
ChatCompletionResponse chatCompletionResponse = openAiClient.chatCompletion(chatCompletion);
|
||||
return chatCompletionResponse.getChoices().stream().map(chatChoice -> chatChoice.getMessage().getContent()).collect(Collectors.joining());
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<AiFormModel> generatorModelVO(String prompt) {
|
||||
String result = "";
|
||||
List<AiFormModel> aiFormModels;
|
||||
try {
|
||||
result = generatorModelStr(prompt);
|
||||
int startIndex = result.indexOf("[");
|
||||
int endIndex = result.lastIndexOf("]");
|
||||
if (startIndex != -1 && endIndex != -1 && startIndex < endIndex) {
|
||||
result = result.substring(startIndex, endIndex + 1).trim();
|
||||
}
|
||||
aiFormModels = JSON.parseObject(result, new TypeReference<List<AiFormModel>>() {
|
||||
});
|
||||
} catch (Exception e) {
|
||||
log.error("AI表单生成转换失败: {}, {}", result, e.getMessage());
|
||||
throw new DataException(MsgCode.SYS181.get());
|
||||
}
|
||||
return aiFormModels;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String completion(Message... messages) {
|
||||
ChatCompletion chatCompletion = getDefaultChatComletion(messages);
|
||||
ChatCompletionResponse chatCompletionResponse = openAiClient.chatCompletion(chatCompletion);
|
||||
return chatCompletionResponse.getChoices().stream().map(chatChoice -> chatChoice.getMessage().getContent()).collect(Collectors.joining());
|
||||
}
|
||||
|
||||
private ChatCompletion getDefaultChatComletion(Message... messages) {
|
||||
AiProperties.ChatOption chatOption = aiProperties.getChat();
|
||||
return ChatCompletion.builder()
|
||||
.model(chatOption.getMode())
|
||||
.temperature(chatOption.getTemperature())
|
||||
.topP(chatOption.getTopP())
|
||||
.seed(chatOption.getSeed())
|
||||
.maxTokens(chatOption.getMaxTokens())
|
||||
.messages(Arrays.asList(messages)).build();
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
@@ -0,0 +1,41 @@
|
||||
package com.yunzhupaas.service.impl;
|
||||
|
||||
import com.unfbx.chatgpt.entity.chat.Message;
|
||||
import com.yunzhupaas.constant.MsgCode;
|
||||
import com.yunzhupaas.exception.DataException;
|
||||
import com.yunzhupaas.model.ai.AiFormModel;
|
||||
import com.yunzhupaas.service.OpenAiService;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* 未启用是空实现
|
||||
* @author 云筑产品开发平台组
|
||||
* @copyright 深圳市乐程软件有限公司
|
||||
* @date 2024/10/15 17:00
|
||||
*/
|
||||
public class DisabledOpenAiServiceImpl implements OpenAiService {
|
||||
@Override
|
||||
public String completion(String prompt) {
|
||||
return throwError();
|
||||
}
|
||||
|
||||
@Override
|
||||
public String completion(Message... messages) {
|
||||
return throwError();
|
||||
}
|
||||
|
||||
@Override
|
||||
public String generatorModelStr(String businessName) {
|
||||
return throwError();
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<AiFormModel> generatorModelVO(String prompt) {
|
||||
return throwError();
|
||||
}
|
||||
|
||||
public <T> T throwError(){
|
||||
throw new DataException(MsgCode.SYS180.get());
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,51 @@
|
||||
package com.yunzhupaas.util;
|
||||
|
||||
import cn.hutool.cache.CacheUtil;
|
||||
import cn.hutool.cache.impl.TimedCache;
|
||||
import com.yunzhupaas.config.AiProperties;
|
||||
|
||||
import java.util.concurrent.atomic.AtomicInteger;
|
||||
|
||||
|
||||
/**
|
||||
* AI接口限流
|
||||
*
|
||||
* @author 云筑产品开发平台组
|
||||
* @copyright 深圳市乐程软件有限公司
|
||||
* @date 2025/3/7 10:00
|
||||
*/
|
||||
public class AiLimitUtil {
|
||||
|
||||
private static AiProperties aiProperties;
|
||||
|
||||
private static TimedCache<String, AtomicInteger> limit = null;
|
||||
|
||||
private static final String TOTAL_KEY = "ai_limit_total";
|
||||
|
||||
public AiLimitUtil(AiProperties aiProperties) {
|
||||
AiLimitUtil.aiProperties = aiProperties;
|
||||
if (limit == null) {
|
||||
limit = CacheUtil.newTimedCache(aiProperties.getUserLimitTime().toMillis());
|
||||
// 一分钟清理一次无用数据
|
||||
limit.schedulePrune(1000L * 60);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 是否可以请求
|
||||
* @param userId
|
||||
* @return
|
||||
*/
|
||||
public static boolean tryAcquire(String userId) {
|
||||
if (StringUtil.isNotEmpty(userId)) {
|
||||
// 按用户限制
|
||||
AtomicInteger userCount = limit.get(userId, false, AtomicInteger::new);
|
||||
if (userCount.incrementAndGet() > aiProperties.getUserLimitCount()) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
// 所有请求限制
|
||||
AtomicInteger totalCount = limit.get(TOTAL_KEY, false, aiProperties.getTotalLimitTime().toMillis(), AtomicInteger::new);
|
||||
return totalCount.incrementAndGet() <= aiProperties.getTotalLimitCount();
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user