feat: 集成 KieAI 服务,移除 models-integration 子项目

- 添加 Gemini 2.5 Flash 对话接口(流式+非流式)
- 添加 NanoBanana 图像生成/编辑接口
- 添加 Sora2 视频生成接口(文生视频、图生视频、去水印)
- 移除 models-integration 子项目(功能已迁移至主后端)
- 新增测试文档和 Playwright E2E 配置
- 更新前端页面和 API 接口
- 更新后端配置和日志处理
This commit is contained in:
2026-03-03 15:33:50 +08:00
parent 1ddb051977
commit 4be53dcd1b
586 changed files with 21142 additions and 25130 deletions

File diff suppressed because one or more lines are too long

View File

@@ -1,4 +0,0 @@
{ "app": "Cjava22", "timestamp":"2026-02-03 11:52:04.963", "level": "DEBUG", "thread": "SpringContextShutdownHook",
"class": "o.s.b.w.s.c.AnnotationConfigServletWebServerApplicationContext",
"message": "Closing org.springframework.boot.web.servlet.context.AnnotationConfigServletWebServerApplicationContext@53aac487, started on Sun Feb 01 23:11:14 CST 2026" }

View File

@@ -1,153 +0,0 @@
{
"app": "Cjava22",
"timestamp":"2026-02-01 23:11:40.942",
"level": "ERROR",
"thread": "http-nio-20822-exec-1",
"class": "c.z.s.exception.GlobalExceptionHandler",
"message": "捕获到异常:" }
org.springframework.web.util.NestedServletException: Handler dispatch failed; nested exception is java.lang.NoSuchMethodError: io.jsonwebtoken.JwtBuilder.signWith(Ljava/security/Key;Lio/jsonwebtoken/SignatureAlgorithm;)Lio/jsonwebtoken/JwtBuilder;
at org.springframework.web.servlet.DispatcherServlet.doDispatch(DispatcherServlet.java:1055)
at org.springframework.web.servlet.DispatcherServlet.doService(DispatcherServlet.java:943)
at org.springframework.web.servlet.FrameworkServlet.processRequest(FrameworkServlet.java:1006)
at org.springframework.web.servlet.FrameworkServlet.doPost(FrameworkServlet.java:909)
at javax.servlet.http.HttpServlet.service(HttpServlet.java:665)
at org.springframework.web.servlet.FrameworkServlet.service(FrameworkServlet.java:883)
at javax.servlet.http.HttpServlet.service(HttpServlet.java:750)
at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:231)
at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:166)
at org.apache.tomcat.websocket.server.WsFilter.doFilter(WsFilter.java:53)
at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:193)
at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:166)
at org.springframework.web.filter.CorsFilter.doFilterInternal(CorsFilter.java:92)
at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:119)
at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:193)
at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:166)
at com.zbkj.front.filter.ResponseFilter.doFilter(ResponseFilter.java:32)
at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:193)
at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:166)
at com.alibaba.druid.support.http.WebStatFilter.doFilter(WebStatFilter.java:124)
at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:193)
at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:166)
at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:320)
at org.springframework.security.web.access.intercept.FilterSecurityInterceptor.invoke(FilterSecurityInterceptor.java:126)
at org.springframework.security.web.access.intercept.FilterSecurityInterceptor.doFilter(FilterSecurityInterceptor.java:90)
at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:334)
at org.springframework.security.web.access.ExceptionTranslationFilter.doFilter(ExceptionTranslationFilter.java:118)
at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:334)
at org.springframework.security.web.session.SessionManagementFilter.doFilter(SessionManagementFilter.java:137)
at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:334)
at org.springframework.security.web.authentication.AnonymousAuthenticationFilter.doFilter(AnonymousAuthenticationFilter.java:111)
at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:334)
at org.springframework.security.web.servletapi.SecurityContextHolderAwareRequestFilter.doFilter(SecurityContextHolderAwareRequestFilter.java:158)
at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:334)
at org.springframework.security.web.savedrequest.RequestCacheAwareFilter.doFilter(RequestCacheAwareFilter.java:63)
at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:334)
at org.springframework.security.web.authentication.logout.LogoutFilter.doFilter(LogoutFilter.java:116)
at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:334)
at org.springframework.security.web.header.HeaderWriterFilter.doHeadersAfter(HeaderWriterFilter.java:92)
at org.springframework.security.web.header.HeaderWriterFilter.doFilterInternal(HeaderWriterFilter.java:77)
at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:119)
at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:334)
at org.springframework.security.web.context.SecurityContextPersistenceFilter.doFilter(SecurityContextPersistenceFilter.java:105)
at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:334)
at org.springframework.security.web.context.request.async.WebAsyncManagerIntegrationFilter.doFilterInternal(WebAsyncManagerIntegrationFilter.java:56)
at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:119)
at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:334)
at org.springframework.security.web.FilterChainProxy.doFilterInternal(FilterChainProxy.java:215)
at org.springframework.security.web.FilterChainProxy.doFilter(FilterChainProxy.java:178)
at org.springframework.web.filter.DelegatingFilterProxy.invokeDelegate(DelegatingFilterProxy.java:358)
at org.springframework.web.filter.DelegatingFilterProxy.doFilter(DelegatingFilterProxy.java:271)
at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:193)
at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:166)
at org.springframework.web.filter.RequestContextFilter.doFilterInternal(RequestContextFilter.java:100)
at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:119)
at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:193)
at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:166)
at org.springframework.web.filter.FormContentFilter.doFilterInternal(FormContentFilter.java:93)
at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:119)
at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:193)
at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:166)
at org.springframework.boot.actuate.metrics.web.servlet.WebMvcMetricsFilter.doFilterInternal(WebMvcMetricsFilter.java:109)
at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:119)
at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:193)
at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:166)
at org.springframework.web.filter.CharacterEncodingFilter.doFilterInternal(CharacterEncodingFilter.java:201)
at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:119)
at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:193)
at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:166)
at org.apache.catalina.core.StandardWrapperValve.invoke(StandardWrapperValve.java:202)
at org.apache.catalina.core.StandardContextValve.invoke(StandardContextValve.java:96)
at org.apache.catalina.authenticator.AuthenticatorBase.invoke(AuthenticatorBase.java:541)
at org.apache.catalina.core.StandardHostValve.invoke(StandardHostValve.java:139)
at org.apache.catalina.valves.ErrorReportValve.invoke(ErrorReportValve.java:92)
at org.apache.catalina.core.StandardEngineValve.invoke(StandardEngineValve.java:74)
at org.apache.catalina.connector.CoyoteAdapter.service(CoyoteAdapter.java:343)
at org.apache.coyote.http11.Http11Processor.service(Http11Processor.java:373)
at org.apache.coyote.AbstractProcessorLight.process(AbstractProcessorLight.java:65)
at org.apache.coyote.AbstractProtocol$ConnectionHandler.process(AbstractProtocol.java:868)
at org.apache.tomcat.util.net.NioEndpoint$SocketProcessor.doRun(NioEndpoint.java:1594)
at org.apache.tomcat.util.net.SocketProcessorBase.run(SocketProcessorBase.java:49)
at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1149)
at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:624)
at org.apache.tomcat.util.threads.TaskThread$WrappingRunnable.run(TaskThread.java:61)
at java.lang.Thread.run(Thread.java:750)
Caused by: java.lang.NoSuchMethodError: io.jsonwebtoken.JwtBuilder.signWith(Ljava/security/Key;Lio/jsonwebtoken/SignatureAlgorithm;)Lio/jsonwebtoken/JwtBuilder;
at com.coze.openapi.service.auth.JWTOAuthClient.generateJWT(JWTOAuthClient.java:104)
at com.coze.openapi.service.auth.JWTOAuthClient.doGetAccessToken(JWTOAuthClient.java:83)
at com.coze.openapi.service.auth.JWTOAuthClient.getAccessToken(JWTOAuthClient.java:48)
at com.zbkj.service.service.impl.tool.ToolCozeServiceImpl.getClient(ToolCozeServiceImpl.java:69)
at com.zbkj.service.service.impl.tool.ToolCozeServiceImpl.workflow(ToolCozeServiceImpl.java:175)
at com.zbkj.front.controller.CozeController.runWorkflow(CozeController.java:72)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
at java.lang.reflect.Method.invoke(Method.java:498)
at org.springframework.web.method.support.InvocableHandlerMethod.doInvoke(InvocableHandlerMethod.java:190)
at org.springframework.web.method.support.InvocableHandlerMethod.invokeForRequest(InvocableHandlerMethod.java:138)
at org.springframework.web.servlet.mvc.method.annotation.ServletInvocableHandlerMethod.invokeAndHandle(ServletInvocableHandlerMethod.java:105)
at org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter.invokeHandlerMethod(RequestMappingHandlerAdapter.java:879)
at org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter.handleInternal(RequestMappingHandlerAdapter.java:793)
at org.springframework.web.servlet.mvc.method.AbstractHandlerMethodAdapter.handle(AbstractHandlerMethodAdapter.java:87)
at org.springframework.web.servlet.DispatcherServlet.doDispatch(DispatcherServlet.java:1040)
... 84 common frames omitted
{
"app": "Cjava22",
"timestamp":"2026-02-01 23:11:47.304",
"level": "ERROR",
"thread": "Druid-ConnectionPool-Create-2045500291",
"class": "com.alibaba.druid.pool.DruidDataSource",
"message": "create connection holder error" }
com.mysql.cj.jdbc.exceptions.CommunicationsException: Communications link failure
The last packet successfully received from the server was 1,602 milliseconds ago. The last packet sent successfully to the server was 1,969 milliseconds ago.
at com.mysql.cj.jdbc.exceptions.SQLError.createCommunicationsException(SQLError.java:175)
at com.mysql.cj.jdbc.exceptions.SQLExceptionsMapping.translateException(SQLExceptionsMapping.java:64)
at com.mysql.cj.jdbc.ConnectionImpl.isReadOnly(ConnectionImpl.java:1374)
at com.mysql.cj.jdbc.ConnectionImpl.isReadOnly(ConnectionImpl.java:1359)
at com.alibaba.druid.pool.DruidConnectionHolder.<init>(DruidConnectionHolder.java:137)
at com.alibaba.druid.pool.DruidConnectionHolder.<init>(DruidConnectionHolder.java:77)
at com.alibaba.druid.pool.DruidDataSource.put(DruidDataSource.java:2412)
at com.alibaba.druid.pool.DruidDataSource$CreateConnectionThread.run(DruidDataSource.java:2757)
Caused by: com.mysql.cj.exceptions.CJCommunicationsException: Communications link failure
The last packet successfully received from the server was 1,602 milliseconds ago. The last packet sent successfully to the server was 1,969 milliseconds ago.
at sun.reflect.NativeConstructorAccessorImpl.newInstance0(Native Method)
at sun.reflect.NativeConstructorAccessorImpl.newInstance(NativeConstructorAccessorImpl.java:62)
at sun.reflect.DelegatingConstructorAccessorImpl.newInstance(DelegatingConstructorAccessorImpl.java:45)
at java.lang.reflect.Constructor.newInstance(Constructor.java:423)
at com.mysql.cj.exceptions.ExceptionFactory.createException(ExceptionFactory.java:62)
at com.mysql.cj.exceptions.ExceptionFactory.createException(ExceptionFactory.java:105)
at com.mysql.cj.exceptions.ExceptionFactory.createException(ExceptionFactory.java:150)
at com.mysql.cj.exceptions.ExceptionFactory.createCommunicationsException(ExceptionFactory.java:166)
at com.mysql.cj.protocol.a.NativeProtocol.clearInputStream(NativeProtocol.java:870)
at com.mysql.cj.protocol.a.NativeProtocol.sendCommand(NativeProtocol.java:682)
at com.mysql.cj.protocol.a.NativeProtocol.sendCommand(NativeProtocol.java:156)
at com.mysql.cj.NativeSession.queryServerVariable(NativeSession.java:589)
at com.mysql.cj.jdbc.ConnectionImpl.isReadOnly(ConnectionImpl.java:1366)
... 5 common frames omitted
Caused by: java.io.IOException: Socket is closed.
at com.mysql.cj.protocol.AbstractSocketConnection.getMysqlInput(AbstractSocketConnection.java:73)
at com.mysql.cj.protocol.a.NativeProtocol.clearInputStream(NativeProtocol.java:866)
... 9 common frames omitted

View File

@@ -2,6 +2,7 @@ package com.zbkj.front.controller;
import com.zbkj.common.config.KieAIConfig;
import com.zbkj.common.request.kieai.CreateProTextToVideoRequest;
import com.zbkj.common.request.kieai.KieAIGeminiChatRequest;
import com.zbkj.common.request.kieai.KieAINanoBananaRequest;
import com.zbkj.common.request.kieai.Sora2Request;
import com.zbkj.common.response.kieai.KieAICreateTaskResponse;
@@ -19,6 +20,7 @@ import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.*;
import org.springframework.web.servlet.mvc.method.annotation.SseEmitter;
import javax.validation.constraints.Min;
import javax.validation.constraints.NotBlank;
@@ -49,6 +51,36 @@ public class KieAIController {
@Autowired
private KieAIConfig kieAIConfig;
// ==================== Gemini 2.5 Flash Chat ====================
/**
* Gemini 2.5 Flash 对话(根据 stream 参数返回流式或非流式)
*/
@PostMapping("/gemini/chat")
@ApiOperation(value = "Gemini 2.5 Flash 对话", notes = "根据 stream 参数返回流式(SSE)或非流式(JSON)")
public Object geminiChat(@RequestBody @Validated KieAIGeminiChatRequest request) {
try {
if (Boolean.TRUE.equals(request.getStream())) {
return toolKieAIService.geminiChatStream(request);
}
Map<String, Object> result = toolKieAIService.geminiChat(request);
return CommonResult.success(result);
} catch (Exception e) {
logger.error("Gemini chat 失败", e);
return CommonResult.failed("Gemini 对话失败: " + e.getMessage());
}
}
/**
* Gemini 2.5 Flash 流式对话
*/
@PostMapping(value = "/gemini/chat/stream", produces = "text/event-stream")
@ApiOperation(value = "Gemini 2.5 Flash 流式对话", notes = "使用 SSE 实时推送响应")
public SseEmitter geminiChatStream(@RequestBody @Validated KieAIGeminiChatRequest request) {
request.setStream(true);
return toolKieAIService.geminiChatStream(request);
}
/**
* 创建文本生成图像任务
*/

View File

@@ -312,6 +312,16 @@ public class ToolController {
return CommonResult.success(toolKnowledgeService.getNutrientDetail(name));
}
/**
* 为 cover_image 为空的饮食指南/科普文章生成封面图KieAI 1:1100KB 内,上传 OSS 并更新 v2_knowledge
*/
@ApiOperation(value = "补全知识封面图")
@PostMapping("/knowledge/fill-cover-images")
public CommonResult<Integer> fillKnowledgeCoverImages(@RequestParam(defaultValue = "10") int limit) {
int updated = toolKnowledgeService.fillMissingCoverImages(limit);
return CommonResult.success(updated);
}
// ==================== 打卡社区相关 ====================
/**
@@ -486,6 +496,15 @@ public class ToolController {
return CommonResult.success(toolHomeService.getHealthStatus());
}
/**
* 获取首页展示配置(如四大功能入口是否显示,由 eb_system_config 中 field01 控制1=显示)
*/
@ApiOperation(value = "获取首页展示配置")
@GetMapping("/home/display-config")
public CommonResult<Map<String, Object>> getHomeDisplayConfig() {
return CommonResult.success(toolHomeService.getDisplayConfig());
}
// ==================== 食谱相关 ====================
/**

View File

@@ -1,6 +1,6 @@
# CRMEB 相关配置
crmeb:
imagePath: /usr/local/crmeb/crmebimage/ # 服务器图片路径配置 斜杠结尾
imagePath: /www/wwwroot/crmebimage/ # 服务器图片路径配置 斜杠结尾
asyncConfig: true #是否同步config表数据到redis
server:

View File

@@ -104,7 +104,9 @@ mybatis-plus:
logic-not-delete-value: 0 # 逻辑未删除值(默认为 0)
# 行为验证码
# 行为验证码captcha.enabled: false 可关闭验证,便于测试)
captcha:
enabled: false
aj:
captcha:
type: default # 验证码类型