From 55060b6c7124b3e593a022c29967edd92dd478ef Mon Sep 17 00:00:00 2001 From: dahua <970263611@qq.com> Date: Sat, 9 Aug 2025 14:38:33 +0800 Subject: [PATCH 1/3] =?UTF-8?q?=E4=BC=98=E5=8C=96pg=E6=95=B0=E6=8D=AE?= =?UTF-8?q?=E5=BA=93=E4=B8=8D=E5=85=BC=E5=AE=B9=E9=97=AE=E9=A2=98=EF=BC=8C?= =?UTF-8?q?=E4=B9=9F=E4=B8=BA=E6=9B=B4=E5=A4=9A=E6=95=B0=E6=8D=AE=E5=BA=93?= =?UTF-8?q?=E5=85=BC=E5=AE=B9=E5=81=9A=E9=93=BA=E5=9E=AB?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../dialect/DynamicColumnIntegrator.java | 57 +++++++++++++++++++ .../model/entity/DynamicModelEntity.java | 6 +- .../model/service/ModelServiceImpl.java | 51 ++++++++++------- .../ai/example/manus/llm/LlmService.java | 3 - .../entity/PlanExecutionRecordEntity.java | 2 +- .../org.hibernate.integrator.spi.Integrator | 1 + 6 files changed, 93 insertions(+), 27 deletions(-) create mode 100644 spring-ai-alibaba-jmanus/src/main/java/com/alibaba/cloud/ai/example/manus/dynamic/dialect/DynamicColumnIntegrator.java create mode 100644 spring-ai-alibaba-jmanus/src/main/resources/META-INF/services/org.hibernate.integrator.spi.Integrator diff --git a/spring-ai-alibaba-jmanus/src/main/java/com/alibaba/cloud/ai/example/manus/dynamic/dialect/DynamicColumnIntegrator.java b/spring-ai-alibaba-jmanus/src/main/java/com/alibaba/cloud/ai/example/manus/dynamic/dialect/DynamicColumnIntegrator.java new file mode 100644 index 0000000000..580c55b819 --- /dev/null +++ b/spring-ai-alibaba-jmanus/src/main/java/com/alibaba/cloud/ai/example/manus/dynamic/dialect/DynamicColumnIntegrator.java @@ -0,0 +1,57 @@ +package com.alibaba.cloud.ai.example.manus.dynamic.dialect; + +import com.alibaba.cloud.ai.example.manus.recorder.entity.PlanExecutionRecordEntity; +import org.checkerframework.checker.initialization.qual.Initialized; +import org.checkerframework.checker.nullness.qual.NonNull; +import org.checkerframework.checker.nullness.qual.UnknownKeyFor; +import org.hibernate.boot.Metadata; +import org.hibernate.dialect.Dialect; +import org.hibernate.dialect.H2Dialect; +import org.hibernate.dialect.MySQLDialect; +import org.hibernate.dialect.PostgreSQLDialect; +import org.hibernate.engine.jdbc.spi.JdbcServices; +import org.hibernate.engine.spi.SessionFactoryImplementor; +import org.hibernate.integrator.spi.Integrator; +import org.hibernate.mapping.PersistentClass; +import org.hibernate.mapping.Property; +import org.hibernate.service.spi.SessionFactoryServiceRegistry; +import org.springframework.stereotype.Component; + +/** + * auth: dahua time: 20250809 + */ +@Component +public class DynamicColumnIntegrator implements Integrator { + + @Override + public void integrate(Metadata metadata, SessionFactoryImplementor sessionFactory, + SessionFactoryServiceRegistry serviceRegistry) { + JdbcServices jdbcServices = serviceRegistry.getService(JdbcServices.class); + Dialect dialect = jdbcServices.getDialect(); + PersistentClass persistentClass = metadata.getEntityBinding(PlanExecutionRecordEntity.class.getName()); + if (persistentClass == null) { + return; + } + Property contentProperty = persistentClass.getProperty("planExecutionRecord"); + if (contentProperty == null) { + return; + } + contentProperty.getColumns().forEach(column -> { + if (dialect instanceof PostgreSQLDialect) { // pg + column.setSqlType("TEXT"); + } + else if (dialect instanceof MySQLDialect) { // mysql + column.setSqlType("LONGTEXT"); + } + else if (dialect instanceof H2Dialect) { // h2 + column.setSqlType("LONGTEXT"); + } + }); + } + + @Override + public void disintegrate(@UnknownKeyFor @NonNull @Initialized SessionFactoryImplementor sessionFactory, + @UnknownKeyFor @NonNull @Initialized SessionFactoryServiceRegistry serviceRegistry) { + } + +} diff --git a/spring-ai-alibaba-jmanus/src/main/java/com/alibaba/cloud/ai/example/manus/dynamic/model/entity/DynamicModelEntity.java b/spring-ai-alibaba-jmanus/src/main/java/com/alibaba/cloud/ai/example/manus/dynamic/model/entity/DynamicModelEntity.java index 616120209c..7916f31487 100644 --- a/spring-ai-alibaba-jmanus/src/main/java/com/alibaba/cloud/ai/example/manus/dynamic/model/entity/DynamicModelEntity.java +++ b/spring-ai-alibaba-jmanus/src/main/java/com/alibaba/cloud/ai/example/manus/dynamic/model/entity/DynamicModelEntity.java @@ -50,13 +50,13 @@ public class DynamicModelEntity { @Column(nullable = false, columnDefinition = "boolean default false") private boolean isDefault; - @Column(nullable = true, columnDefinition = "DOUBLE DEFAULT 0.7") + @Column private Double temperature; - @Column(nullable = true, columnDefinition = "DOUBLE DEFAULT NULL") + @Column private Double topP; - @Column(nullable = true) + @Column private String completionsPath; public DynamicModelEntity() { diff --git a/spring-ai-alibaba-jmanus/src/main/java/com/alibaba/cloud/ai/example/manus/dynamic/model/service/ModelServiceImpl.java b/spring-ai-alibaba-jmanus/src/main/java/com/alibaba/cloud/ai/example/manus/dynamic/model/service/ModelServiceImpl.java index 0ac65b6f66..5185aea287 100644 --- a/spring-ai-alibaba-jmanus/src/main/java/com/alibaba/cloud/ai/example/manus/dynamic/model/service/ModelServiceImpl.java +++ b/spring-ai-alibaba-jmanus/src/main/java/com/alibaba/cloud/ai/example/manus/dynamic/model/service/ModelServiceImpl.java @@ -15,25 +15,7 @@ */ package com.alibaba.cloud.ai.example.manus.dynamic.model.service; -import java.net.MalformedURLException; -import java.net.URL; -import java.util.ArrayList; -import java.util.List; -import java.util.Map; -import java.util.Optional; -import java.util.stream.Collectors; - -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; -import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.http.HttpEntity; -import org.springframework.http.HttpHeaders; -import org.springframework.http.HttpMethod; -import org.springframework.http.ResponseEntity; -import org.springframework.stereotype.Service; -import org.springframework.transaction.annotation.Transactional; -import org.springframework.web.client.RestTemplate; - +import cn.hutool.core.util.StrUtil; import com.alibaba.cloud.ai.example.manus.dynamic.agent.entity.DynamicAgentEntity; import com.alibaba.cloud.ai.example.manus.dynamic.agent.repository.DynamicAgentRepository; import com.alibaba.cloud.ai.example.manus.dynamic.model.entity.DynamicModelEntity; @@ -46,8 +28,25 @@ import com.alibaba.cloud.ai.example.manus.dynamic.model.repository.DynamicModelRepository; import com.alibaba.cloud.ai.example.manus.event.JmanusEventPublisher; import com.alibaba.cloud.ai.example.manus.event.ModelChangeEvent; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.http.HttpEntity; +import org.springframework.http.HttpHeaders; +import org.springframework.http.HttpMethod; +import org.springframework.http.ResponseEntity; +import org.springframework.stereotype.Service; +import org.springframework.transaction.annotation.Transactional; +import org.springframework.util.StringUtils; +import org.springframework.web.client.RestTemplate; -import cn.hutool.core.util.StrUtil; +import java.net.MalformedURLException; +import java.net.URL; +import java.util.ArrayList; +import java.util.List; +import java.util.Map; +import java.util.Optional; +import java.util.stream.Collectors; @Service public class ModelServiceImpl implements ModelService { @@ -82,6 +81,8 @@ public ModelConfig getModelById(String id) { @Override public ModelConfig createModel(ModelConfig config) { try { + // Set default values + setDefaultConfig(config); // Check if an Model with the same name already exists DynamicModelEntity existingModel = repository.findByModelName(config.getModelName()); if (existingModel != null) { @@ -119,6 +120,7 @@ public ModelConfig createModel(ModelConfig config) { @Override public ModelConfig updateModel(ModelConfig config) { + setDefaultConfig(config); DynamicModelEntity entity = repository.findById(config.getId()) .orElseThrow(() -> new IllegalArgumentException("Model not found: " + config.getId())); @@ -348,6 +350,15 @@ private void updateEntityFromConfig(DynamicModelEntity entity, ModelConfig confi entity.setCompletionsPath(config.getCompletionsPath()); } + private void setDefaultConfig(ModelConfig modelConfig) { + if (modelConfig.getTemperature() == null) { + modelConfig.setTemperature(0.7); + } + if (!StringUtils.hasText(modelConfig.getCompletionsPath())) { + modelConfig.setCompletionsPath("/v1/chat/completions"); + } + } + @Override @Transactional public void setDefaultModel(Long modelId) { diff --git a/spring-ai-alibaba-jmanus/src/main/java/com/alibaba/cloud/ai/example/manus/llm/LlmService.java b/spring-ai-alibaba-jmanus/src/main/java/com/alibaba/cloud/ai/example/manus/llm/LlmService.java index 9a101d2f22..d66bd8d98b 100644 --- a/spring-ai-alibaba-jmanus/src/main/java/com/alibaba/cloud/ai/example/manus/llm/LlmService.java +++ b/spring-ai-alibaba-jmanus/src/main/java/com/alibaba/cloud/ai/example/manus/llm/LlmService.java @@ -423,9 +423,6 @@ private OpenAiApi openAiApi(RestClient.Builder restClientBuilder, WebClient.Buil .filter((request, next) -> next.exchange(request).timeout(Duration.ofMinutes(10))); String completionsPath = dynamicModelEntity.getCompletionsPath(); - if (!StringUtils.hasText(completionsPath)) { - completionsPath = "/v1/chat/completions"; - } return new OpenAiApi(dynamicModelEntity.getBaseUrl(), new SimpleApiKey(dynamicModelEntity.getApiKey()), multiValueMap, completionsPath, "/v1/embeddings", restClientBuilder, enhancedWebClientBuilder, diff --git a/spring-ai-alibaba-jmanus/src/main/java/com/alibaba/cloud/ai/example/manus/recorder/entity/PlanExecutionRecordEntity.java b/spring-ai-alibaba-jmanus/src/main/java/com/alibaba/cloud/ai/example/manus/recorder/entity/PlanExecutionRecordEntity.java index 50d7110326..a9a7b955a9 100644 --- a/spring-ai-alibaba-jmanus/src/main/java/com/alibaba/cloud/ai/example/manus/recorder/entity/PlanExecutionRecordEntity.java +++ b/spring-ai-alibaba-jmanus/src/main/java/com/alibaba/cloud/ai/example/manus/recorder/entity/PlanExecutionRecordEntity.java @@ -42,7 +42,7 @@ public class PlanExecutionRecordEntity { private Date gmtModified; @Convert(converter = StringAttributeConverter.class) - @Column(columnDefinition = "longtext") + @Column private PlanExecutionRecord planExecutionRecord; public Long getId() { diff --git a/spring-ai-alibaba-jmanus/src/main/resources/META-INF/services/org.hibernate.integrator.spi.Integrator b/spring-ai-alibaba-jmanus/src/main/resources/META-INF/services/org.hibernate.integrator.spi.Integrator new file mode 100644 index 0000000000..f2a709cd10 --- /dev/null +++ b/spring-ai-alibaba-jmanus/src/main/resources/META-INF/services/org.hibernate.integrator.spi.Integrator @@ -0,0 +1 @@ +com.alibaba.cloud.ai.example.manus.dynamic.dialect.DynamicColumnIntegrator From 527fe45d04fc71ce94a50ed25a92e3b3a985049a Mon Sep 17 00:00:00 2001 From: dahua <970263611@qq.com> Date: Sat, 9 Aug 2025 14:46:25 +0800 Subject: [PATCH 2/3] =?UTF-8?q?=E5=8E=BB=E9=99=A4=E6=97=A0=E6=95=88?= =?UTF-8?q?=E5=BC=95=E7=94=A8?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../java/com/alibaba/cloud/ai/example/manus/llm/LlmService.java | 1 - 1 file changed, 1 deletion(-) diff --git a/spring-ai-alibaba-jmanus/src/main/java/com/alibaba/cloud/ai/example/manus/llm/LlmService.java b/spring-ai-alibaba-jmanus/src/main/java/com/alibaba/cloud/ai/example/manus/llm/LlmService.java index d66bd8d98b..06a0e1ccfe 100644 --- a/spring-ai-alibaba-jmanus/src/main/java/com/alibaba/cloud/ai/example/manus/llm/LlmService.java +++ b/spring-ai-alibaba-jmanus/src/main/java/com/alibaba/cloud/ai/example/manus/llm/LlmService.java @@ -42,7 +42,6 @@ import org.springframework.stereotype.Service; import org.springframework.util.LinkedMultiValueMap; import org.springframework.util.MultiValueMap; -import org.springframework.util.StringUtils; import org.springframework.web.client.RestClient; import org.springframework.web.reactive.function.client.WebClient; import reactor.core.publisher.Flux; From 543f0520268e902157033d0ca1a5074cb83aa049 Mon Sep 17 00:00:00 2001 From: dahua <970263611@qq.com> Date: Sat, 9 Aug 2025 14:48:56 +0800 Subject: [PATCH 3/3] =?UTF-8?q?=E6=B7=BB=E5=8A=A0=E5=8D=8F=E8=AE=AE?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../dynamic/dialect/DynamicColumnIntegrator.java | 15 +++++++++++++++ 1 file changed, 15 insertions(+) diff --git a/spring-ai-alibaba-jmanus/src/main/java/com/alibaba/cloud/ai/example/manus/dynamic/dialect/DynamicColumnIntegrator.java b/spring-ai-alibaba-jmanus/src/main/java/com/alibaba/cloud/ai/example/manus/dynamic/dialect/DynamicColumnIntegrator.java index 580c55b819..4804604196 100644 --- a/spring-ai-alibaba-jmanus/src/main/java/com/alibaba/cloud/ai/example/manus/dynamic/dialect/DynamicColumnIntegrator.java +++ b/spring-ai-alibaba-jmanus/src/main/java/com/alibaba/cloud/ai/example/manus/dynamic/dialect/DynamicColumnIntegrator.java @@ -1,3 +1,18 @@ +/* + * Copyright 2025 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * https://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ package com.alibaba.cloud.ai.example.manus.dynamic.dialect; import com.alibaba.cloud.ai.example.manus.recorder.entity.PlanExecutionRecordEntity;