初始化

This commit is contained in:
2026-02-22 18:56:10 +08:00
commit 26677972a6
3112 changed files with 255972 additions and 0 deletions

View File

@@ -0,0 +1,38 @@
package tech.easyflow.ai.config;
import org.springframework.boot.context.event.ApplicationReadyEvent;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.event.EventListener;
import tech.easyflow.ai.mapper.*;
import tech.easyflow.common.util.SpringContextUtil;
import tech.easyflow.common.dict.DictManager;
import tech.easyflow.common.dict.loader.DbDataLoader;
import javax.annotation.Resource;
@Configuration
public class AiDictAutoConfig {
@Resource
private WorkflowMapper workflowMapper;
@Resource
private WorkflowCategoryMapper workflowCategoryMapper;
@Resource
private BotCategoryMapper botCategoryMapper;
@Resource
private ResourceCategoryMapper resourceCategoryMapper;
@Resource
private DocumentCollectionCategoryMapper documentCollectionCategoryMapper;
@EventListener(ApplicationReadyEvent.class)
public void onApplicationStartup() {
DictManager dictManager = SpringContextUtil.getBean(DictManager.class);
dictManager.putLoader(new DbDataLoader<>("aiWorkFlow", workflowMapper, "id", "title", null, null, false));
dictManager.putLoader(new DbDataLoader<>("aiWorkFlowCategory", workflowCategoryMapper, "id", "category_name", null, null, false));
dictManager.putLoader(new DbDataLoader<>("aiBotCategory", botCategoryMapper, "id", "category_name", null, null, false));
dictManager.putLoader(new DbDataLoader<>("aiResourceCategory", resourceCategoryMapper, "id", "category_name", null, null, false));
dictManager.putLoader(new DbDataLoader<>("aiDocumentCollectionCategory", documentCollectionCategoryMapper, "id", "category_name", null, null, false));
}
}

View File

@@ -0,0 +1,35 @@
package tech.easyflow.ai.config;
import com.easyagents.engine.es.ESConfig;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Component;
@Component
public class AiEsConfig extends ESConfig {
@Value("${rag.searcher.elastic.host}")
@Override
public void setHost(String host) {
super.setHost(host);
}
@Value("${rag.searcher.elastic.userName}")
@Override
public void setUserName(String userName) {
super.setUserName(userName);
}
@Value("${rag.searcher.elastic.password}")
@Override
public void setPassword(String password) {
super.setPassword(password);
}
@Value("${rag.searcher.elastic.indexName}")
@Override
public void setIndexName(String indexName) {
super.setIndexName(indexName);
}
}

View File

@@ -0,0 +1,17 @@
package tech.easyflow.ai.config;
import com.easyagents.search.engine.lucene.LuceneConfig;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Component;
@Component
public class AiLuceneConfig extends LuceneConfig {
@Value("${rag.searcher.lucene.indexDirPath}")
@Override
public void setIndexDirPath(String indexDirPath) {
super.setIndexDirPath(indexDirPath);
}
}

View File

@@ -0,0 +1,13 @@
package tech.easyflow.ai.config;
import org.mybatis.spring.annotation.MapperScan;
import org.springframework.boot.autoconfigure.AutoConfiguration;
@MapperScan("tech.easyflow.ai.mapper")
@AutoConfiguration
public class AiModuleConfig {
public AiModuleConfig() {
System.out.println("启用模块 >>>>>>>>>> module-ai");
}
}

View File

@@ -0,0 +1,19 @@
package tech.easyflow.ai.config;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.context.annotation.Configuration;
@Configuration
@ConfigurationProperties(prefix = "node.bochaai")
public class BochaaiProps {
private String apiKey;
public String getApiKey() {
return apiKey;
}
public void setApiKey(String apiKey) {
this.apiKey = apiKey;
}
}

View File

@@ -0,0 +1,54 @@
package tech.easyflow.ai.config;
import com.easyagents.mcp.client.McpClientManager;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.DependsOn;
import tech.easyflow.ai.entity.Mcp;
import tech.easyflow.ai.service.impl.McpServiceImpl;
import tech.easyflow.common.util.StringUtil;
import javax.annotation.PostConstruct;
import javax.annotation.Resource;
import java.util.List;
import java.util.Optional;
import static tech.easyflow.ai.service.impl.McpServiceImpl.getFirstMcpServerName;
@Configuration
@DependsOn("mcpServiceImpl") // 确保 mcpService 先初始化
public class McpClientAutoConfig {
private final McpClientManager mcpClientManager = McpClientManager.getInstance();
private static final Logger log = LoggerFactory.getLogger(McpClientAutoConfig.class);
@Resource
private McpServiceImpl mcpService;
@PostConstruct
public void initMcpClient() {
log.info("开始初始化 MCP 客户端...");
List<Mcp> mcpList = mcpService.list();
log.info("获取到 MCP 配置列表,数量:{}", mcpList.size());
mcpList.forEach(mcp -> {
if (!mcp.getStatus()) {
return;
}
String configJson = mcp.getConfigJson();
String serverName = getFirstMcpServerName(configJson);
if (StringUtil.hasText(serverName)) {
try {
mcpClientManager.registerFromJson(configJson);
} catch (Exception e) {
log.error("MCP服务名称{} 注册失败", serverName, e);
}
log.info("MCP服务名称{} 注册成功", serverName);
} else {
log.error("MCP服务名称为{} 启动失败,配置 JSON 中未找到服务名称", mcp.getTitle());
}
});
}
}

View File

@@ -0,0 +1,40 @@
package tech.easyflow.ai.config;
import com.easyagents.engine.es.ElasticSearcher;
import com.easyagents.search.engine.lucene.LuceneSearcher;
import com.easyagents.search.engine.service.DocumentSearcher;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
@Configuration
public class SearcherFactory {
@Autowired
private AiLuceneConfig luceneConfig;
@Autowired
private AiEsConfig aiEsConfig;
@Bean
public LuceneSearcher luceneSearcher() {
return new LuceneSearcher(luceneConfig);
}
@Bean
public ElasticSearcher elasticSearcher() {
return new ElasticSearcher(aiEsConfig);
}
public DocumentSearcher getSearcher(String defaultSearcherType) {
switch (defaultSearcherType) {
case "elasticSearch":
return new ElasticSearcher(aiEsConfig);
case "lucene":
default:
return new LuceneSearcher(luceneConfig);
}
}
}

View File

@@ -0,0 +1,40 @@
package tech.easyflow.ai.config;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor;
import tech.easyflow.common.web.exceptions.BusinessException;
@Configuration
public class ThreadPoolConfig {
private static final Logger log = LoggerFactory.getLogger(ThreadPoolConfig.class);
/**
* SSE消息发送专用线程池
* 核心原则IO密集型任务网络推送线程数 = CPU核心数 * 2 + 1
*/
@Bean(name = "sseThreadPool")
public ThreadPoolTaskExecutor sseThreadPool() {
ThreadPoolTaskExecutor executor = new ThreadPoolTaskExecutor();
int cpuCoreNum = Runtime.getRuntime().availableProcessors(); // 获取CPU核心数4核返回4
executor.setCorePoolSize(cpuCoreNum * 2); // 核心线程数
executor.setMaxPoolSize(cpuCoreNum * 10); // 最大线程数(峰值时扩容,避免线程过多导致上下文切换)
executor.setQueueCapacity(8000); // 任务队列容量
executor.setKeepAliveSeconds(30); // 空闲线程存活时间30秒非核心线程空闲后销毁节省资源
executor.setThreadNamePrefix("sse-sender-");
// 拒绝策略
executor.setRejectedExecutionHandler((runnable, executorService) -> {
log.error("SSE线程池过载核心线程数{},最大线程数:{},队列任务数:{}",
executorService.getCorePoolSize(),
executorService.getMaximumPoolSize(),
executorService.getQueue().size());
// 抛出自定义异常,全局捕获后返回“服务繁忙”
throw new BusinessException("服务器忙,请稍后重试");
});
executor.initialize();
return executor;
}
}