后台管理功能开发,AI配置管理
This commit is contained in:
@@ -0,0 +1,290 @@
|
||||
package com.emotion.controller;
|
||||
|
||||
import com.emotion.common.PageResult;
|
||||
import com.emotion.common.Result;
|
||||
import com.emotion.dto.request.aiconfig.*;
|
||||
import com.emotion.dto.response.aiconfig.AiConfigResponse;
|
||||
import com.emotion.service.AiConfigService;
|
||||
import io.swagger.v3.oas.annotations.Operation;
|
||||
import io.swagger.v3.oas.annotations.tags.Tag;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.validation.annotation.Validated;
|
||||
import org.springframework.web.bind.annotation.*;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* AI配置控制器
|
||||
*
|
||||
* @author system
|
||||
* @date 2025-10-30
|
||||
*/
|
||||
@RestController
|
||||
@RequestMapping("/aiConfig")
|
||||
@Tag(name = "AI配置管理", description = "AI配置的增删改查功能")
|
||||
public class AiConfigController {
|
||||
|
||||
@Autowired
|
||||
private AiConfigService aiConfigService;
|
||||
|
||||
/**
|
||||
* 分页查询AI配置
|
||||
*/
|
||||
@Operation(summary = "分页查询AI配置", description = "分页查询AI配置列表")
|
||||
@GetMapping("/page")
|
||||
public Result<PageResult<AiConfigResponse>> getPage(@Validated AiConfigPageRequest request) {
|
||||
PageResult<AiConfigResponse> pageResult = aiConfigService.getPageWithResponse(request);
|
||||
return Result.success(pageResult);
|
||||
}
|
||||
|
||||
/**
|
||||
* 根据ID获取AI配置
|
||||
*/
|
||||
@Operation(summary = "根据ID获取AI配置", description = "根据ID获取AI配置详情")
|
||||
@GetMapping("/detail")
|
||||
public Result<AiConfigResponse> getById(@RequestParam String id) {
|
||||
AiConfigResponse response = aiConfigService.getAiConfigResponseById(id);
|
||||
if (response == null) {
|
||||
return Result.notFound("AI配置不存在");
|
||||
}
|
||||
return Result.success(response);
|
||||
}
|
||||
|
||||
/**
|
||||
* 创建AI配置
|
||||
*/
|
||||
@Operation(summary = "创建AI配置", description = "创建新的AI配置")
|
||||
@PostMapping("/create")
|
||||
public Result<AiConfigResponse> create(@RequestBody @Validated AiConfigCreateRequest request) {
|
||||
AiConfigResponse response = aiConfigService.createAiConfigWithResponse(request);
|
||||
if (response == null) {
|
||||
return Result.error("创建失败");
|
||||
}
|
||||
return Result.success("创建成功", response);
|
||||
}
|
||||
|
||||
/**
|
||||
* 更新AI配置
|
||||
*/
|
||||
@Operation(summary = "更新AI配置", description = "更新指定AI配置")
|
||||
@PutMapping("/update")
|
||||
public Result<AiConfigResponse> update(@RequestBody @Validated AiConfigUpdateRequest request) {
|
||||
AiConfigResponse response = aiConfigService.updateAiConfigWithResponse(request);
|
||||
if (response == null) {
|
||||
return Result.error("更新失败");
|
||||
}
|
||||
return Result.success("更新成功", response);
|
||||
}
|
||||
|
||||
/**
|
||||
* 删除AI配置
|
||||
*/
|
||||
@Operation(summary = "删除AI配置", description = "删除指定AI配置")
|
||||
@DeleteMapping("/delete")
|
||||
public Result<Void> delete(@RequestParam String id) {
|
||||
boolean deleted = aiConfigService.removeById(id);
|
||||
if (!deleted) {
|
||||
return Result.error("删除失败");
|
||||
}
|
||||
return Result.success();
|
||||
}
|
||||
|
||||
/**
|
||||
* 根据配置类型查询AI配置
|
||||
*/
|
||||
@Operation(summary = "根据配置类型查询AI配置", description = "根据配置类型查询AI配置列表")
|
||||
@GetMapping("/byConfigType")
|
||||
public Result<List<AiConfigResponse>> getByConfigType(@RequestParam String configType) {
|
||||
List<AiConfigResponse> responses = aiConfigService.getByConfigTypeWithResponse(configType);
|
||||
return Result.success(responses);
|
||||
}
|
||||
|
||||
/**
|
||||
* 根据服务提供商查询AI配置
|
||||
*/
|
||||
@Operation(summary = "根据服务提供商查询AI配置", description = "根据服务提供商查询AI配置列表")
|
||||
@GetMapping("/byProvider")
|
||||
public Result<List<AiConfigResponse>> getByProvider(@RequestParam String provider) {
|
||||
List<AiConfigResponse> responses = aiConfigService.getByProviderWithResponse(provider);
|
||||
return Result.success(responses);
|
||||
}
|
||||
|
||||
/**
|
||||
* 根据使用场景查询AI配置
|
||||
*/
|
||||
@Operation(summary = "根据使用场景查询AI配置", description = "根据使用场景查询AI配置列表")
|
||||
@GetMapping("/byUsageScenario")
|
||||
public Result<List<AiConfigResponse>> getByUsageScenario(@RequestParam String usageScenario) {
|
||||
List<AiConfigResponse> responses = aiConfigService.getByUsageScenarioWithResponse(usageScenario);
|
||||
return Result.success(responses);
|
||||
}
|
||||
|
||||
/**
|
||||
* 根据环境查询AI配置
|
||||
*/
|
||||
@Operation(summary = "根据环境查询AI配置", description = "根据环境查询AI配置列表")
|
||||
@GetMapping("/byEnvironment")
|
||||
public Result<List<AiConfigResponse>> getByEnvironment(@RequestParam String environment) {
|
||||
List<AiConfigResponse> responses = aiConfigService.getByEnvironmentWithResponse(environment);
|
||||
return Result.success(responses);
|
||||
}
|
||||
|
||||
/**
|
||||
* 查询已启用的AI配置
|
||||
*/
|
||||
@Operation(summary = "查询已启用的AI配置", description = "查询已启用的AI配置列表")
|
||||
@GetMapping("/enabled")
|
||||
public Result<List<AiConfigResponse>> getEnabledConfigs() {
|
||||
List<AiConfigResponse> responses = aiConfigService.getEnabledConfigsWithResponse();
|
||||
return Result.success(responses);
|
||||
}
|
||||
|
||||
/**
|
||||
* 查询已禁用的AI配置
|
||||
*/
|
||||
@Operation(summary = "查询已禁用的AI配置", description = "查询已禁用的AI配置列表")
|
||||
@GetMapping("/disabled")
|
||||
public Result<List<AiConfigResponse>> getDisabledConfigs() {
|
||||
List<AiConfigResponse> responses = aiConfigService.getDisabledConfigsWithResponse();
|
||||
return Result.success(responses);
|
||||
}
|
||||
|
||||
/**
|
||||
* 查询默认配置
|
||||
*/
|
||||
@Operation(summary = "查询默认配置", description = "查询默认配置列表")
|
||||
@GetMapping("/default")
|
||||
public Result<List<AiConfigResponse>> getDefaultConfigs() {
|
||||
List<AiConfigResponse> responses = aiConfigService.getDefaultConfigsWithResponse();
|
||||
return Result.success(responses);
|
||||
}
|
||||
|
||||
/**
|
||||
* 根据配置键值查询AI配置
|
||||
*/
|
||||
@Operation(summary = "根据配置键值查询AI配置", description = "根据配置键值查询AI配置")
|
||||
@GetMapping("/byConfigKey")
|
||||
public Result<AiConfigResponse> getByConfigKey(@RequestParam String configKey) {
|
||||
AiConfigResponse response = aiConfigService.getByConfigKeyWithResponse(configKey);
|
||||
if (response == null) {
|
||||
return Result.notFound("AI配置不存在");
|
||||
}
|
||||
return Result.success(response);
|
||||
}
|
||||
|
||||
/**
|
||||
* 启用AI配置
|
||||
*/
|
||||
@Operation(summary = "启用AI配置", description = "启用指定AI配置")
|
||||
@PutMapping("/enable")
|
||||
public Result<Void> enableConfig(@RequestParam String id) {
|
||||
boolean enabled = aiConfigService.enableConfig(id);
|
||||
if (!enabled) {
|
||||
return Result.error("启用失败");
|
||||
}
|
||||
return Result.success();
|
||||
}
|
||||
|
||||
/**
|
||||
* 禁用AI配置
|
||||
*/
|
||||
@Operation(summary = "禁用AI配置", description = "禁用指定AI配置")
|
||||
@PutMapping("/disable")
|
||||
public Result<Void> disableConfig(@RequestParam String id) {
|
||||
boolean disabled = aiConfigService.disableConfig(id);
|
||||
if (!disabled) {
|
||||
return Result.error("禁用失败");
|
||||
}
|
||||
return Result.success();
|
||||
}
|
||||
|
||||
/**
|
||||
* 设置为默认配置
|
||||
*/
|
||||
@Operation(summary = "设置为默认配置", description = "设置指定AI配置为默认配置")
|
||||
@PutMapping("/setDefault")
|
||||
public Result<Void> setAsDefault(@RequestParam String id) {
|
||||
boolean set = aiConfigService.setAsDefault(id);
|
||||
if (!set) {
|
||||
return Result.error("设置默认配置失败");
|
||||
}
|
||||
return Result.success();
|
||||
}
|
||||
|
||||
/**
|
||||
* 取消默认配置
|
||||
*/
|
||||
@Operation(summary = "取消默认配置", description = "取消指定AI配置的默认设置")
|
||||
@PutMapping("/unsetDefault")
|
||||
public Result<Void> unsetDefault(@RequestParam String id) {
|
||||
boolean unset = aiConfigService.unsetDefault(id);
|
||||
if (!unset) {
|
||||
return Result.error("取消默认配置失败");
|
||||
}
|
||||
return Result.success();
|
||||
}
|
||||
|
||||
/**
|
||||
* 根据使用场景和环境查询最优配置
|
||||
*/
|
||||
@Operation(summary = "查询最优配置", description = "根据使用场景和环境查询最优配置")
|
||||
@GetMapping("/bestConfig")
|
||||
public Result<AiConfigResponse> getBestConfig(@RequestParam String usageScenario,
|
||||
@RequestParam String environment) {
|
||||
AiConfigResponse response = aiConfigService.getBestConfigWithResponse(usageScenario, environment);
|
||||
if (response == null) {
|
||||
return Result.notFound("未找到匹配的AI配置");
|
||||
}
|
||||
return Result.success(response);
|
||||
}
|
||||
|
||||
/**
|
||||
* 统计已启用配置数量
|
||||
*/
|
||||
@Operation(summary = "统计已启用配置数量", description = "统计已启用配置数量")
|
||||
@GetMapping("/countEnabled")
|
||||
public Result<Long> countEnabledConfigs() {
|
||||
Long count = aiConfigService.countEnabledConfigs();
|
||||
return Result.success(count);
|
||||
}
|
||||
|
||||
/**
|
||||
* 统计已禁用配置数量
|
||||
*/
|
||||
@Operation(summary = "统计已禁用配置数量", description = "统计已禁用配置数量")
|
||||
@GetMapping("/countDisabled")
|
||||
public Result<Long> countDisabledConfigs() {
|
||||
Long count = aiConfigService.countDisabledConfigs();
|
||||
return Result.success(count);
|
||||
}
|
||||
|
||||
/**
|
||||
* 统计默认配置数量
|
||||
*/
|
||||
@Operation(summary = "统计默认配置数量", description = "统计默认配置数量")
|
||||
@GetMapping("/countDefault")
|
||||
public Result<Long> countDefaultConfigs() {
|
||||
Long count = aiConfigService.countDefaultConfigs();
|
||||
return Result.success(count);
|
||||
}
|
||||
|
||||
/**
|
||||
* 根据配置类型统计数量
|
||||
*/
|
||||
@Operation(summary = "根据配置类型统计数量", description = "根据配置类型统计数量")
|
||||
@GetMapping("/countByConfigType")
|
||||
public Result<Long> countByConfigType(@RequestParam String configType) {
|
||||
Long count = aiConfigService.countByConfigType(configType);
|
||||
return Result.success(count);
|
||||
}
|
||||
|
||||
/**
|
||||
* 根据服务提供商统计数量
|
||||
*/
|
||||
@Operation(summary = "根据服务提供商统计数量", description = "根据服务提供商统计数量")
|
||||
@GetMapping("/countByProvider")
|
||||
public Result<Long> countByProvider(@RequestParam String provider) {
|
||||
Long count = aiConfigService.countByProvider(provider);
|
||||
return Result.success(count);
|
||||
}
|
||||
}
|
||||
+214
@@ -0,0 +1,214 @@
|
||||
package com.emotion.dto.request.aiconfig;
|
||||
|
||||
import lombok.Data;
|
||||
|
||||
import javax.validation.constraints.NotBlank;
|
||||
import javax.validation.constraints.NotNull;
|
||||
import java.math.BigDecimal;
|
||||
|
||||
/**
|
||||
* 创建AI配置请求
|
||||
*
|
||||
* @author system
|
||||
* @date 2025-10-30
|
||||
*/
|
||||
@Data
|
||||
public class AiConfigCreateRequest {
|
||||
|
||||
/**
|
||||
* 配置名称
|
||||
*/
|
||||
@NotBlank(message = "配置名称不能为空")
|
||||
private String configName;
|
||||
|
||||
/**
|
||||
* 配置键值 (唯一标识)
|
||||
*/
|
||||
@NotBlank(message = "配置键值不能为空")
|
||||
private String configKey;
|
||||
|
||||
/**
|
||||
* 配置类型: coze-扣子, openai-OpenAI, claude-Claude, gemini-Gemini等
|
||||
*/
|
||||
@NotBlank(message = "配置类型不能为空")
|
||||
private String configType;
|
||||
|
||||
/**
|
||||
* 服务提供商: coze, openai, anthropic, google等
|
||||
*/
|
||||
@NotBlank(message = "服务提供商不能为空")
|
||||
private String provider;
|
||||
|
||||
/**
|
||||
* API基础URL
|
||||
*/
|
||||
@NotBlank(message = "API基础URL不能为空")
|
||||
private String apiBaseUrl;
|
||||
|
||||
/**
|
||||
* API访问令牌 (加密存储)
|
||||
*/
|
||||
@NotBlank(message = "API访问令牌不能为空")
|
||||
private String apiToken;
|
||||
|
||||
/**
|
||||
* API版本
|
||||
*/
|
||||
private String apiVersion;
|
||||
|
||||
/**
|
||||
* 模型名称
|
||||
*/
|
||||
private String modelName;
|
||||
|
||||
/**
|
||||
* Bot ID (Coze专用)
|
||||
*/
|
||||
private String botId;
|
||||
|
||||
/**
|
||||
* Workflow ID (Coze专用)
|
||||
*/
|
||||
private String workflowId;
|
||||
|
||||
/**
|
||||
* 超时时间(毫秒)
|
||||
*/
|
||||
private Integer timeoutMs;
|
||||
|
||||
/**
|
||||
* 重试次数
|
||||
*/
|
||||
private Integer retryCount;
|
||||
|
||||
/**
|
||||
* 重试延迟(毫秒)
|
||||
*/
|
||||
private Integer retryDelayMs;
|
||||
|
||||
/**
|
||||
* 最大Token数
|
||||
*/
|
||||
private Integer maxTokens;
|
||||
|
||||
/**
|
||||
* 温度参数 (0.0-2.0)
|
||||
*/
|
||||
private BigDecimal temperature;
|
||||
|
||||
/**
|
||||
* Top-p参数 (0.0-1.0)
|
||||
*/
|
||||
private BigDecimal topP;
|
||||
|
||||
/**
|
||||
* 是否支持流式输出: 0-不支持, 1-支持
|
||||
*/
|
||||
private Integer supportStream;
|
||||
|
||||
/**
|
||||
* 是否支持函数调用: 0-不支持, 1-支持
|
||||
*/
|
||||
private Integer supportFunctionCall;
|
||||
|
||||
/**
|
||||
* 是否支持视觉理解: 0-不支持, 1-支持
|
||||
*/
|
||||
private Integer supportVision;
|
||||
|
||||
/**
|
||||
* 是否支持文件上传: 0-不支持, 1-支持
|
||||
*/
|
||||
private Integer supportFileUpload;
|
||||
|
||||
/**
|
||||
* 使用场景: chat-聊天, summary-总结, emotion_analysis-情绪分析, content_generation-内容生成等
|
||||
*/
|
||||
@NotBlank(message = "使用场景不能为空")
|
||||
private String usageScenario;
|
||||
|
||||
/**
|
||||
* 优先级 (数值越大优先级越高)
|
||||
*/
|
||||
private Integer priority;
|
||||
|
||||
/**
|
||||
* 输入Token价格(每1K)
|
||||
*/
|
||||
private BigDecimal inputPricePer1k;
|
||||
|
||||
/**
|
||||
* 输出Token价格(每1K)
|
||||
*/
|
||||
private BigDecimal outputPricePer1k;
|
||||
|
||||
/**
|
||||
* 货币单位
|
||||
*/
|
||||
private String currency;
|
||||
|
||||
/**
|
||||
* 每分钟请求限制
|
||||
*/
|
||||
private Integer rateLimitPerMinute;
|
||||
|
||||
/**
|
||||
* 每小时请求限制
|
||||
*/
|
||||
private Integer rateLimitPerHour;
|
||||
|
||||
/**
|
||||
* 每日请求限制
|
||||
*/
|
||||
private Integer rateLimitPerDay;
|
||||
|
||||
/**
|
||||
* 是否启用: 0-禁用, 1-启用
|
||||
*/
|
||||
private Integer isEnabled;
|
||||
|
||||
/**
|
||||
* 是否为默认配置: 0-否, 1-是
|
||||
*/
|
||||
private Integer isDefault;
|
||||
|
||||
/**
|
||||
* 环境: development-开发, testing-测试, production-生产
|
||||
*/
|
||||
private String environment;
|
||||
|
||||
/**
|
||||
* 自定义请求头
|
||||
*/
|
||||
private String customHeaders;
|
||||
|
||||
/**
|
||||
* 自定义参数
|
||||
*/
|
||||
private String customParams;
|
||||
|
||||
/**
|
||||
* Webhook回调地址
|
||||
*/
|
||||
private String webhookUrl;
|
||||
|
||||
/**
|
||||
* 健康检查URL
|
||||
*/
|
||||
private String healthCheckUrl;
|
||||
|
||||
/**
|
||||
* 健康检查间隔(分钟)
|
||||
*/
|
||||
private Integer healthCheckIntervalMinutes;
|
||||
|
||||
/**
|
||||
* 配置描述
|
||||
*/
|
||||
private String description;
|
||||
|
||||
/**
|
||||
* 使用说明
|
||||
*/
|
||||
private String usageNotes;
|
||||
}
|
||||
+26
@@ -0,0 +1,26 @@
|
||||
package com.emotion.dto.request.aiconfig;
|
||||
|
||||
import lombok.Data;
|
||||
|
||||
import javax.validation.constraints.NotBlank;
|
||||
|
||||
/**
|
||||
* AI配置默认设置请求
|
||||
*
|
||||
* @author system
|
||||
* @date 2025-10-30
|
||||
*/
|
||||
@Data
|
||||
public class AiConfigDefaultRequest {
|
||||
|
||||
/**
|
||||
* 配置ID
|
||||
*/
|
||||
@NotBlank(message = "配置ID不能为空")
|
||||
private String id;
|
||||
|
||||
/**
|
||||
* 是否为默认配置: 0-否, 1-是
|
||||
*/
|
||||
private Integer isDefault;
|
||||
}
|
||||
+26
@@ -0,0 +1,26 @@
|
||||
package com.emotion.dto.request.aiconfig;
|
||||
|
||||
import lombok.Data;
|
||||
|
||||
import javax.validation.constraints.NotBlank;
|
||||
|
||||
/**
|
||||
* AI配置启用/禁用请求
|
||||
*
|
||||
* @author system
|
||||
* @date 2025-10-30
|
||||
*/
|
||||
@Data
|
||||
public class AiConfigEnableRequest {
|
||||
|
||||
/**
|
||||
* 配置ID
|
||||
*/
|
||||
@NotBlank(message = "配置ID不能为空")
|
||||
private String id;
|
||||
|
||||
/**
|
||||
* 是否启用: 0-禁用, 1-启用
|
||||
*/
|
||||
private Integer isEnabled;
|
||||
}
|
||||
+51
@@ -0,0 +1,51 @@
|
||||
package com.emotion.dto.request.aiconfig;
|
||||
|
||||
import com.emotion.dto.request.PageRequest;
|
||||
import lombok.Data;
|
||||
import lombok.EqualsAndHashCode;
|
||||
|
||||
/**
|
||||
* AI配置分页查询请求
|
||||
*
|
||||
* @author system
|
||||
* @date 2025-10-30
|
||||
*/
|
||||
@Data
|
||||
@EqualsAndHashCode(callSuper = true)
|
||||
public class AiConfigPageRequest extends PageRequest {
|
||||
|
||||
/**
|
||||
* 关键词搜索(配置名称、配置键值、描述)
|
||||
*/
|
||||
private String keyword;
|
||||
|
||||
/**
|
||||
* 配置类型
|
||||
*/
|
||||
private String configType;
|
||||
|
||||
/**
|
||||
* 服务提供商
|
||||
*/
|
||||
private String provider;
|
||||
|
||||
/**
|
||||
* 使用场景
|
||||
*/
|
||||
private String usageScenario;
|
||||
|
||||
/**
|
||||
* 是否启用: 0-禁用, 1-启用
|
||||
*/
|
||||
private Integer isEnabled;
|
||||
|
||||
/**
|
||||
* 是否为默认配置: 0-否, 1-是
|
||||
*/
|
||||
private Integer isDefault;
|
||||
|
||||
/**
|
||||
* 环境: development-开发, testing-测试, production-生产
|
||||
*/
|
||||
private String environment;
|
||||
}
|
||||
+212
@@ -0,0 +1,212 @@
|
||||
package com.emotion.dto.request.aiconfig;
|
||||
|
||||
import lombok.Data;
|
||||
|
||||
import javax.validation.constraints.NotBlank;
|
||||
import java.math.BigDecimal;
|
||||
|
||||
/**
|
||||
* 更新AI配置请求
|
||||
*
|
||||
* @author system
|
||||
* @date 2025-10-30
|
||||
*/
|
||||
@Data
|
||||
public class AiConfigUpdateRequest {
|
||||
|
||||
/**
|
||||
* 配置ID
|
||||
*/
|
||||
@NotBlank(message = "配置ID不能为空")
|
||||
private String id;
|
||||
|
||||
/**
|
||||
* 配置名称
|
||||
*/
|
||||
private String configName;
|
||||
|
||||
/**
|
||||
* 配置键值 (唯一标识)
|
||||
*/
|
||||
private String configKey;
|
||||
|
||||
/**
|
||||
* 配置类型: coze-扣子, openai-OpenAI, claude-Claude, gemini-Gemini等
|
||||
*/
|
||||
private String configType;
|
||||
|
||||
/**
|
||||
* 服务提供商: coze, openai, anthropic, google等
|
||||
*/
|
||||
private String provider;
|
||||
|
||||
/**
|
||||
* API基础URL
|
||||
*/
|
||||
private String apiBaseUrl;
|
||||
|
||||
/**
|
||||
* API访问令牌 (加密存储)
|
||||
*/
|
||||
private String apiToken;
|
||||
|
||||
/**
|
||||
* API版本
|
||||
*/
|
||||
private String apiVersion;
|
||||
|
||||
/**
|
||||
* 模型名称
|
||||
*/
|
||||
private String modelName;
|
||||
|
||||
/**
|
||||
* Bot ID (Coze专用)
|
||||
*/
|
||||
private String botId;
|
||||
|
||||
/**
|
||||
* Workflow ID (Coze专用)
|
||||
*/
|
||||
private String workflowId;
|
||||
|
||||
/**
|
||||
* 超时时间(毫秒)
|
||||
*/
|
||||
private Integer timeoutMs;
|
||||
|
||||
/**
|
||||
* 重试次数
|
||||
*/
|
||||
private Integer retryCount;
|
||||
|
||||
/**
|
||||
* 重试延迟(毫秒)
|
||||
*/
|
||||
private Integer retryDelayMs;
|
||||
|
||||
/**
|
||||
* 最大Token数
|
||||
*/
|
||||
private Integer maxTokens;
|
||||
|
||||
/**
|
||||
* 温度参数 (0.0-2.0)
|
||||
*/
|
||||
private BigDecimal temperature;
|
||||
|
||||
/**
|
||||
* Top-p参数 (0.0-1.0)
|
||||
*/
|
||||
private BigDecimal topP;
|
||||
|
||||
/**
|
||||
* 是否支持流式输出: 0-不支持, 1-支持
|
||||
*/
|
||||
private Integer supportStream;
|
||||
|
||||
/**
|
||||
* 是否支持函数调用: 0-不支持, 1-支持
|
||||
*/
|
||||
private Integer supportFunctionCall;
|
||||
|
||||
/**
|
||||
* 是否支持视觉理解: 0-不支持, 1-支持
|
||||
*/
|
||||
private Integer supportVision;
|
||||
|
||||
/**
|
||||
* 是否支持文件上传: 0-不支持, 1-支持
|
||||
*/
|
||||
private Integer supportFileUpload;
|
||||
|
||||
/**
|
||||
* 使用场景: chat-聊天, summary-总结, emotion_analysis-情绪分析, content_generation-内容生成等
|
||||
*/
|
||||
private String usageScenario;
|
||||
|
||||
/**
|
||||
* 优先级 (数值越大优先级越高)
|
||||
*/
|
||||
private Integer priority;
|
||||
|
||||
/**
|
||||
* 输入Token价格(每1K)
|
||||
*/
|
||||
private BigDecimal inputPricePer1k;
|
||||
|
||||
/**
|
||||
* 输出Token价格(每1K)
|
||||
*/
|
||||
private BigDecimal outputPricePer1k;
|
||||
|
||||
/**
|
||||
* 货币单位
|
||||
*/
|
||||
private String currency;
|
||||
|
||||
/**
|
||||
* 每分钟请求限制
|
||||
*/
|
||||
private Integer rateLimitPerMinute;
|
||||
|
||||
/**
|
||||
* 每小时请求限制
|
||||
*/
|
||||
private Integer rateLimitPerHour;
|
||||
|
||||
/**
|
||||
* 每日请求限制
|
||||
*/
|
||||
private Integer rateLimitPerDay;
|
||||
|
||||
/**
|
||||
* 是否启用: 0-禁用, 1-启用
|
||||
*/
|
||||
private Integer isEnabled;
|
||||
|
||||
/**
|
||||
* 是否为默认配置: 0-否, 1-是
|
||||
*/
|
||||
private Integer isDefault;
|
||||
|
||||
/**
|
||||
* 环境: development-开发, testing-测试, production-生产
|
||||
*/
|
||||
private String environment;
|
||||
|
||||
/**
|
||||
* 自定义请求头
|
||||
*/
|
||||
private String customHeaders;
|
||||
|
||||
/**
|
||||
* 自定义参数
|
||||
*/
|
||||
private String customParams;
|
||||
|
||||
/**
|
||||
* Webhook回调地址
|
||||
*/
|
||||
private String webhookUrl;
|
||||
|
||||
/**
|
||||
* 健康检查URL
|
||||
*/
|
||||
private String healthCheckUrl;
|
||||
|
||||
/**
|
||||
* 健康检查间隔(分钟)
|
||||
*/
|
||||
private Integer healthCheckIntervalMinutes;
|
||||
|
||||
/**
|
||||
* 配置描述
|
||||
*/
|
||||
private String description;
|
||||
|
||||
/**
|
||||
* 使用说明
|
||||
*/
|
||||
private String usageNotes;
|
||||
}
|
||||
@@ -0,0 +1,206 @@
|
||||
package com.emotion.dto.response.aiconfig;
|
||||
|
||||
import com.emotion.dto.response.BaseResponse;
|
||||
import lombok.Data;
|
||||
import lombok.EqualsAndHashCode;
|
||||
|
||||
/**
|
||||
* AI配置响应类
|
||||
*
|
||||
* @author system
|
||||
* @date 2025-10-30
|
||||
*/
|
||||
@Data
|
||||
@EqualsAndHashCode(callSuper = true)
|
||||
public class AiConfigResponse extends BaseResponse {
|
||||
|
||||
/**
|
||||
* 配置名称
|
||||
*/
|
||||
private String configName;
|
||||
|
||||
/**
|
||||
* 配置键值 (唯一标识)
|
||||
*/
|
||||
private String configKey;
|
||||
|
||||
/**
|
||||
* 配置类型: coze-扣子, openai-OpenAI, claude-Claude, gemini-Gemini等
|
||||
*/
|
||||
private String configType;
|
||||
|
||||
/**
|
||||
* 服务提供商: coze, openai, anthropic, google等
|
||||
*/
|
||||
private String provider;
|
||||
|
||||
/**
|
||||
* API基础URL
|
||||
*/
|
||||
private String apiBaseUrl;
|
||||
|
||||
/**
|
||||
* API访问令牌 (脱敏显示)
|
||||
*/
|
||||
private String apiToken;
|
||||
|
||||
/**
|
||||
* API版本
|
||||
*/
|
||||
private String apiVersion;
|
||||
|
||||
/**
|
||||
* 模型名称
|
||||
*/
|
||||
private String modelName;
|
||||
|
||||
/**
|
||||
* Bot ID (Coze专用)
|
||||
*/
|
||||
private String botId;
|
||||
|
||||
/**
|
||||
* Workflow ID (Coze专用)
|
||||
*/
|
||||
private String workflowId;
|
||||
|
||||
/**
|
||||
* 超时时间(毫秒)
|
||||
*/
|
||||
private Integer timeoutMs;
|
||||
|
||||
/**
|
||||
* 重试次数
|
||||
*/
|
||||
private Integer retryCount;
|
||||
|
||||
/**
|
||||
* 重试延迟(毫秒)
|
||||
*/
|
||||
private Integer retryDelayMs;
|
||||
|
||||
/**
|
||||
* 最大Token数
|
||||
*/
|
||||
private Integer maxTokens;
|
||||
|
||||
/**
|
||||
* 温度参数 (0.0-2.0)
|
||||
*/
|
||||
private Double temperature;
|
||||
|
||||
/**
|
||||
* Top-p参数 (0.0-1.0)
|
||||
*/
|
||||
private Double topP;
|
||||
|
||||
/**
|
||||
* 是否支持流式输出: 0-不支持, 1-支持
|
||||
*/
|
||||
private Integer supportStream;
|
||||
|
||||
/**
|
||||
* 是否支持函数调用: 0-不支持, 1-支持
|
||||
*/
|
||||
private Integer supportFunctionCall;
|
||||
|
||||
/**
|
||||
* 是否支持视觉理解: 0-不支持, 1-支持
|
||||
*/
|
||||
private Integer supportVision;
|
||||
|
||||
/**
|
||||
* 是否支持文件上传: 0-不支持, 1-支持
|
||||
*/
|
||||
private Integer supportFileUpload;
|
||||
|
||||
/**
|
||||
* 使用场景: chat-聊天, summary-总结, emotion_analysis-情绪分析, content_generation-内容生成等
|
||||
*/
|
||||
private String usageScenario;
|
||||
|
||||
/**
|
||||
* 优先级 (数值越大优先级越高)
|
||||
*/
|
||||
private Integer priority;
|
||||
|
||||
/**
|
||||
* 输入Token价格(每1K)
|
||||
*/
|
||||
private Double inputPricePer1k;
|
||||
|
||||
/**
|
||||
* 输出Token价格(每1K)
|
||||
*/
|
||||
private Double outputPricePer1k;
|
||||
|
||||
/**
|
||||
* 货币单位
|
||||
*/
|
||||
private String currency;
|
||||
|
||||
/**
|
||||
* 每分钟请求限制
|
||||
*/
|
||||
private Integer rateLimitPerMinute;
|
||||
|
||||
/**
|
||||
* 每小时请求限制
|
||||
*/
|
||||
private Integer rateLimitPerHour;
|
||||
|
||||
/**
|
||||
* 每日请求限制
|
||||
*/
|
||||
private Integer rateLimitPerDay;
|
||||
|
||||
/**
|
||||
* 是否启用: 0-禁用, 1-启用
|
||||
*/
|
||||
private Integer isEnabled;
|
||||
|
||||
/**
|
||||
* 是否为默认配置: 0-否, 1-是
|
||||
*/
|
||||
private Integer isDefault;
|
||||
|
||||
/**
|
||||
* 环境: development-开发, testing-测试, production-生产
|
||||
*/
|
||||
private String environment;
|
||||
|
||||
/**
|
||||
* 自定义请求头
|
||||
*/
|
||||
private String customHeaders;
|
||||
|
||||
/**
|
||||
* 自定义参数
|
||||
*/
|
||||
private String customParams;
|
||||
|
||||
/**
|
||||
* Webhook回调地址
|
||||
*/
|
||||
private String webhookUrl;
|
||||
|
||||
/**
|
||||
* 健康检查URL
|
||||
*/
|
||||
private String healthCheckUrl;
|
||||
|
||||
/**
|
||||
* 健康检查间隔(分钟)
|
||||
*/
|
||||
private Integer healthCheckIntervalMinutes;
|
||||
|
||||
/**
|
||||
* 配置描述
|
||||
*/
|
||||
private String description;
|
||||
|
||||
/**
|
||||
* 使用说明
|
||||
*/
|
||||
private String usageNotes;
|
||||
}
|
||||
@@ -0,0 +1,254 @@
|
||||
package com.emotion.entity;
|
||||
|
||||
import com.baomidou.mybatisplus.annotation.*;
|
||||
import com.emotion.common.BaseEntity;
|
||||
import lombok.experimental.SuperBuilder;
|
||||
import lombok.NoArgsConstructor;
|
||||
import lombok.AllArgsConstructor;
|
||||
import lombok.Data;
|
||||
import lombok.EqualsAndHashCode;
|
||||
|
||||
import java.math.BigDecimal;
|
||||
|
||||
/**
|
||||
* AI配置实体类
|
||||
*
|
||||
* @author system
|
||||
* @date 2025-10-30
|
||||
*/
|
||||
@Data
|
||||
@EqualsAndHashCode(callSuper = true)
|
||||
@SuperBuilder
|
||||
@NoArgsConstructor
|
||||
@AllArgsConstructor
|
||||
@TableName("t_ai_config")
|
||||
public class AiConfig extends BaseEntity {
|
||||
|
||||
/**
|
||||
* 配置名称
|
||||
*/
|
||||
@TableField("config_name")
|
||||
private String configName;
|
||||
|
||||
/**
|
||||
* 配置键值 (唯一标识)
|
||||
*/
|
||||
@TableField("config_key")
|
||||
private String configKey;
|
||||
|
||||
/**
|
||||
* 配置类型: coze-扣子, openai-OpenAI, claude-Claude, gemini-Gemini等
|
||||
*/
|
||||
@TableField("config_type")
|
||||
private String configType;
|
||||
|
||||
/**
|
||||
* 服务提供商: coze, openai, anthropic, google等
|
||||
*/
|
||||
@TableField("provider")
|
||||
private String provider;
|
||||
|
||||
/**
|
||||
* API基础URL
|
||||
*/
|
||||
@TableField("api_base_url")
|
||||
private String apiBaseUrl;
|
||||
|
||||
/**
|
||||
* API访问令牌 (加密存储)
|
||||
*/
|
||||
@TableField("api_token")
|
||||
private String apiToken;
|
||||
|
||||
/**
|
||||
* API版本
|
||||
*/
|
||||
@TableField("api_version")
|
||||
private String apiVersion;
|
||||
|
||||
/**
|
||||
* 模型名称
|
||||
*/
|
||||
@TableField("model_name")
|
||||
private String modelName;
|
||||
|
||||
/**
|
||||
* Bot ID (Coze专用)
|
||||
*/
|
||||
@TableField("bot_id")
|
||||
private String botId;
|
||||
|
||||
/**
|
||||
* Workflow ID (Coze专用)
|
||||
*/
|
||||
@TableField("workflow_id")
|
||||
private String workflowId;
|
||||
|
||||
/**
|
||||
* 超时时间(毫秒)
|
||||
*/
|
||||
@TableField("timeout_ms")
|
||||
private Integer timeoutMs;
|
||||
|
||||
/**
|
||||
* 重试次数
|
||||
*/
|
||||
@TableField("retry_count")
|
||||
private Integer retryCount;
|
||||
|
||||
/**
|
||||
* 重试延迟(毫秒)
|
||||
*/
|
||||
@TableField("retry_delay_ms")
|
||||
private Integer retryDelayMs;
|
||||
|
||||
/**
|
||||
* 最大Token数
|
||||
*/
|
||||
@TableField("max_tokens")
|
||||
private Integer maxTokens;
|
||||
|
||||
/**
|
||||
* 温度参数 (0.0-2.0)
|
||||
*/
|
||||
@TableField("temperature")
|
||||
private BigDecimal temperature;
|
||||
|
||||
/**
|
||||
* Top-p参数 (0.0-1.0)
|
||||
*/
|
||||
@TableField("top_p")
|
||||
private BigDecimal topP;
|
||||
|
||||
/**
|
||||
* 是否支持流式输出: 0-不支持, 1-支持
|
||||
*/
|
||||
@TableField("support_stream")
|
||||
private Integer supportStream;
|
||||
|
||||
/**
|
||||
* 是否支持函数调用: 0-不支持, 1-支持
|
||||
*/
|
||||
@TableField("support_function_call")
|
||||
private Integer supportFunctionCall;
|
||||
|
||||
/**
|
||||
* 是否支持视觉理解: 0-不支持, 1-支持
|
||||
*/
|
||||
@TableField("support_vision")
|
||||
private Integer supportVision;
|
||||
|
||||
/**
|
||||
* 是否支持文件上传: 0-不支持, 1-支持
|
||||
*/
|
||||
@TableField("support_file_upload")
|
||||
private Integer supportFileUpload;
|
||||
|
||||
/**
|
||||
* 使用场景: chat-聊天, summary-总结, emotion_analysis-情绪分析, content_generation-内容生成等
|
||||
*/
|
||||
@TableField("usage_scenario")
|
||||
private String usageScenario;
|
||||
|
||||
/**
|
||||
* 优先级 (数值越大优先级越高)
|
||||
*/
|
||||
@TableField("priority")
|
||||
private Integer priority;
|
||||
|
||||
/**
|
||||
* 输入Token价格(每1K)
|
||||
*/
|
||||
@TableField("input_price_per_1k")
|
||||
private BigDecimal inputPricePer1k;
|
||||
|
||||
/**
|
||||
* 输出Token价格(每1K)
|
||||
*/
|
||||
@TableField("output_price_per_1k")
|
||||
private BigDecimal outputPricePer1k;
|
||||
|
||||
/**
|
||||
* 货币单位
|
||||
*/
|
||||
@TableField("currency")
|
||||
private String currency;
|
||||
|
||||
/**
|
||||
* 每分钟请求限制
|
||||
*/
|
||||
@TableField("rate_limit_per_minute")
|
||||
private Integer rateLimitPerMinute;
|
||||
|
||||
/**
|
||||
* 每小时请求限制
|
||||
*/
|
||||
@TableField("rate_limit_per_hour")
|
||||
private Integer rateLimitPerHour;
|
||||
|
||||
/**
|
||||
* 每日请求限制
|
||||
*/
|
||||
@TableField("rate_limit_per_day")
|
||||
private Integer rateLimitPerDay;
|
||||
|
||||
/**
|
||||
* 是否启用: 0-禁用, 1-启用
|
||||
*/
|
||||
@TableField("is_enabled")
|
||||
private Integer isEnabled;
|
||||
|
||||
/**
|
||||
* 是否为默认配置: 0-否, 1-是
|
||||
*/
|
||||
@TableField("is_default")
|
||||
private Integer isDefault;
|
||||
|
||||
/**
|
||||
* 环境: development-开发, testing-测试, production-生产
|
||||
*/
|
||||
@TableField("environment")
|
||||
private String environment;
|
||||
|
||||
/**
|
||||
* 自定义请求头
|
||||
*/
|
||||
@TableField("custom_headers")
|
||||
private String customHeaders;
|
||||
|
||||
/**
|
||||
* 自定义参数
|
||||
*/
|
||||
@TableField("custom_params")
|
||||
private String customParams;
|
||||
|
||||
/**
|
||||
* Webhook回调地址
|
||||
*/
|
||||
@TableField("webhook_url")
|
||||
private String webhookUrl;
|
||||
|
||||
/**
|
||||
* 健康检查URL
|
||||
*/
|
||||
@TableField("health_check_url")
|
||||
private String healthCheckUrl;
|
||||
|
||||
/**
|
||||
* 健康检查间隔(分钟)
|
||||
*/
|
||||
@TableField("health_check_interval_minutes")
|
||||
private Integer healthCheckIntervalMinutes;
|
||||
|
||||
/**
|
||||
* 配置描述
|
||||
*/
|
||||
@TableField("description")
|
||||
private String description;
|
||||
|
||||
/**
|
||||
* 使用说明
|
||||
*/
|
||||
@TableField("usage_notes")
|
||||
private String usageNotes;
|
||||
}
|
||||
@@ -0,0 +1,15 @@
|
||||
package com.emotion.mapper;
|
||||
|
||||
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
|
||||
import com.emotion.entity.AiConfig;
|
||||
import org.apache.ibatis.annotations.Mapper;
|
||||
|
||||
/**
|
||||
* AI配置Mapper接口
|
||||
*
|
||||
* @author system
|
||||
* @date 2025-10-30
|
||||
*/
|
||||
@Mapper
|
||||
public interface AiConfigMapper extends BaseMapper<AiConfig> {
|
||||
}
|
||||
@@ -0,0 +1,179 @@
|
||||
package com.emotion.service;
|
||||
|
||||
import com.baomidou.mybatisplus.core.metadata.IPage;
|
||||
import com.baomidou.mybatisplus.extension.service.IService;
|
||||
import com.emotion.common.PageResult;
|
||||
import com.emotion.dto.request.aiconfig.*;
|
||||
import com.emotion.dto.response.aiconfig.AiConfigResponse;
|
||||
import com.emotion.entity.AiConfig;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* AI配置服务接口
|
||||
*
|
||||
* @author system
|
||||
* @date 2025-10-30
|
||||
*/
|
||||
public interface AiConfigService extends IService<AiConfig> {
|
||||
|
||||
/**
|
||||
* 分页查询AI配置
|
||||
*/
|
||||
IPage<AiConfig> getPage(AiConfigPageRequest request);
|
||||
|
||||
/**
|
||||
* 分页查询AI配置并返回响应对象
|
||||
*/
|
||||
PageResult<AiConfigResponse> getPageWithResponse(AiConfigPageRequest request);
|
||||
|
||||
/**
|
||||
* 根据ID获取AI配置响应对象
|
||||
*/
|
||||
AiConfigResponse getAiConfigResponseById(String id);
|
||||
|
||||
/**
|
||||
* 创建AI配置并返回响应对象
|
||||
*/
|
||||
AiConfigResponse createAiConfigWithResponse(AiConfigCreateRequest request);
|
||||
|
||||
/**
|
||||
* 更新AI配置并返回响应对象
|
||||
*/
|
||||
AiConfigResponse updateAiConfigWithResponse(AiConfigUpdateRequest request);
|
||||
|
||||
/**
|
||||
* 根据配置类型查询AI配置
|
||||
*/
|
||||
List<AiConfig> getByConfigType(String configType);
|
||||
|
||||
/**
|
||||
* 根据配置类型查询AI配置并返回响应对象
|
||||
*/
|
||||
List<AiConfigResponse> getByConfigTypeWithResponse(String configType);
|
||||
|
||||
/**
|
||||
* 根据服务提供商查询AI配置
|
||||
*/
|
||||
List<AiConfig> getByProvider(String provider);
|
||||
|
||||
/**
|
||||
* 根据服务提供商查询AI配置并返回响应对象
|
||||
*/
|
||||
List<AiConfigResponse> getByProviderWithResponse(String provider);
|
||||
|
||||
/**
|
||||
* 根据使用场景查询AI配置
|
||||
*/
|
||||
List<AiConfig> getByUsageScenario(String usageScenario);
|
||||
|
||||
/**
|
||||
* 根据使用场景查询AI配置并返回响应对象
|
||||
*/
|
||||
List<AiConfigResponse> getByUsageScenarioWithResponse(String usageScenario);
|
||||
|
||||
/**
|
||||
* 根据环境查询AI配置
|
||||
*/
|
||||
List<AiConfig> getByEnvironment(String environment);
|
||||
|
||||
/**
|
||||
* 根据环境查询AI配置并返回响应对象
|
||||
*/
|
||||
List<AiConfigResponse> getByEnvironmentWithResponse(String environment);
|
||||
|
||||
/**
|
||||
* 查询已启用的AI配置
|
||||
*/
|
||||
List<AiConfig> getEnabledConfigs();
|
||||
|
||||
/**
|
||||
* 查询已启用的AI配置并返回响应对象
|
||||
*/
|
||||
List<AiConfigResponse> getEnabledConfigsWithResponse();
|
||||
|
||||
/**
|
||||
* 查询已禁用的AI配置
|
||||
*/
|
||||
List<AiConfig> getDisabledConfigs();
|
||||
|
||||
/**
|
||||
* 查询已禁用的AI配置并返回响应对象
|
||||
*/
|
||||
List<AiConfigResponse> getDisabledConfigsWithResponse();
|
||||
|
||||
/**
|
||||
* 查询默认配置
|
||||
*/
|
||||
List<AiConfig> getDefaultConfigs();
|
||||
|
||||
/**
|
||||
* 查询默认配置并返回响应对象
|
||||
*/
|
||||
List<AiConfigResponse> getDefaultConfigsWithResponse();
|
||||
|
||||
/**
|
||||
* 根据配置键值查询AI配置
|
||||
*/
|
||||
AiConfig getByConfigKey(String configKey);
|
||||
|
||||
/**
|
||||
* 根据配置键值查询AI配置并返回响应对象
|
||||
*/
|
||||
AiConfigResponse getByConfigKeyWithResponse(String configKey);
|
||||
|
||||
/**
|
||||
* 启用AI配置
|
||||
*/
|
||||
boolean enableConfig(String id);
|
||||
|
||||
/**
|
||||
* 禁用AI配置
|
||||
*/
|
||||
boolean disableConfig(String id);
|
||||
|
||||
/**
|
||||
* 设置为默认配置
|
||||
*/
|
||||
boolean setAsDefault(String id);
|
||||
|
||||
/**
|
||||
* 取消默认配置
|
||||
*/
|
||||
boolean unsetDefault(String id);
|
||||
|
||||
/**
|
||||
* 根据使用场景和环境查询最优配置
|
||||
*/
|
||||
AiConfig getBestConfig(String usageScenario, String environment);
|
||||
|
||||
/**
|
||||
* 根据使用场景和环境查询最优配置并返回响应对象
|
||||
*/
|
||||
AiConfigResponse getBestConfigWithResponse(String usageScenario, String environment);
|
||||
|
||||
/**
|
||||
* 统计已启用配置数量
|
||||
*/
|
||||
Long countEnabledConfigs();
|
||||
|
||||
/**
|
||||
* 统计已禁用配置数量
|
||||
*/
|
||||
Long countDisabledConfigs();
|
||||
|
||||
/**
|
||||
* 统计默认配置数量
|
||||
*/
|
||||
Long countDefaultConfigs();
|
||||
|
||||
/**
|
||||
* 根据配置类型统计数量
|
||||
*/
|
||||
Long countByConfigType(String configType);
|
||||
|
||||
/**
|
||||
* 根据服务提供商统计数量
|
||||
*/
|
||||
Long countByProvider(String provider);
|
||||
}
|
||||
@@ -0,0 +1,411 @@
|
||||
package com.emotion.service.impl;
|
||||
|
||||
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
|
||||
import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
|
||||
import com.baomidou.mybatisplus.core.metadata.IPage;
|
||||
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
|
||||
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
|
||||
import com.emotion.common.PageResult;
|
||||
import com.emotion.dto.request.aiconfig.AiConfigCreateRequest;
|
||||
import com.emotion.dto.request.aiconfig.AiConfigPageRequest;
|
||||
import com.emotion.dto.request.aiconfig.AiConfigUpdateRequest;
|
||||
import com.emotion.dto.response.aiconfig.AiConfigResponse;
|
||||
import com.emotion.entity.AiConfig;
|
||||
import com.emotion.mapper.AiConfigMapper;
|
||||
import com.emotion.service.AiConfigService;
|
||||
import com.emotion.util.SnowflakeIdGenerator;
|
||||
import org.springframework.beans.BeanUtils;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.stereotype.Service;
|
||||
import org.springframework.util.StringUtils;
|
||||
|
||||
import java.time.format.DateTimeFormatter;
|
||||
import java.util.List;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
/**
|
||||
* AI配置服务实现类
|
||||
*
|
||||
* @author system
|
||||
* @date 2025-10-30
|
||||
*/
|
||||
@Service
|
||||
public class AiConfigServiceImpl extends ServiceImpl<AiConfigMapper, AiConfig> implements AiConfigService {
|
||||
|
||||
@Autowired
|
||||
private SnowflakeIdGenerator snowflakeIdGenerator;
|
||||
|
||||
private static final DateTimeFormatter DATE_TIME_FORMATTER = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss");
|
||||
|
||||
@Override
|
||||
public IPage<AiConfig> getPage(AiConfigPageRequest request) {
|
||||
Page<AiConfig> page = new Page<>(request.getCurrent(), request.getSize());
|
||||
LambdaQueryWrapper<AiConfig> wrapper = new LambdaQueryWrapper<>();
|
||||
|
||||
// 关键词搜索
|
||||
if (StringUtils.hasText(request.getKeyword())) {
|
||||
wrapper.and(w -> w.like(AiConfig::getConfigName, request.getKeyword())
|
||||
.or().like(AiConfig::getConfigKey, request.getKeyword())
|
||||
.or().like(AiConfig::getDescription, request.getKeyword()));
|
||||
}
|
||||
|
||||
// 配置类型过滤
|
||||
if (StringUtils.hasText(request.getConfigType())) {
|
||||
wrapper.eq(AiConfig::getConfigType, request.getConfigType());
|
||||
}
|
||||
|
||||
// 服务提供商过滤
|
||||
if (StringUtils.hasText(request.getProvider())) {
|
||||
wrapper.eq(AiConfig::getProvider, request.getProvider());
|
||||
}
|
||||
|
||||
// 使用场景过滤
|
||||
if (StringUtils.hasText(request.getUsageScenario())) {
|
||||
wrapper.eq(AiConfig::getUsageScenario, request.getUsageScenario());
|
||||
}
|
||||
|
||||
// 是否启用过滤
|
||||
if (request.getIsEnabled() != null) {
|
||||
wrapper.eq(AiConfig::getIsEnabled, request.getIsEnabled());
|
||||
}
|
||||
|
||||
// 是否为默认配置过滤
|
||||
if (request.getIsDefault() != null) {
|
||||
wrapper.eq(AiConfig::getIsDefault, request.getIsDefault());
|
||||
}
|
||||
|
||||
// 环境过滤
|
||||
if (StringUtils.hasText(request.getEnvironment())) {
|
||||
wrapper.eq(AiConfig::getEnvironment, request.getEnvironment());
|
||||
}
|
||||
|
||||
// 排序
|
||||
if (StringUtils.hasText(request.getOrderBy())) {
|
||||
if ("asc".equalsIgnoreCase(request.getOrderDirection())) {
|
||||
wrapper.orderByAsc(getLambdaByField(request.getOrderBy()));
|
||||
} else {
|
||||
wrapper.orderByDesc(getLambdaByField(request.getOrderBy()));
|
||||
}
|
||||
} else {
|
||||
wrapper.orderByDesc(AiConfig::getCreateTime);
|
||||
}
|
||||
|
||||
return this.page(page, wrapper);
|
||||
}
|
||||
|
||||
@Override
|
||||
public PageResult<AiConfigResponse> getPageWithResponse(AiConfigPageRequest request) {
|
||||
IPage<AiConfig> page = getPage(request);
|
||||
List<AiConfigResponse> responses = page.getRecords().stream()
|
||||
.map(this::convertToResponse)
|
||||
.collect(Collectors.toList());
|
||||
|
||||
PageResult<AiConfigResponse> result = new PageResult<>();
|
||||
result.setCurrent(page.getCurrent());
|
||||
result.setSize(page.getSize());
|
||||
result.setTotal(page.getTotal());
|
||||
result.setPages(page.getPages());
|
||||
result.setRecords(responses);
|
||||
return result;
|
||||
}
|
||||
|
||||
@Override
|
||||
public AiConfigResponse getAiConfigResponseById(String id) {
|
||||
AiConfig aiConfig = this.getById(id);
|
||||
return aiConfig != null ? convertToResponse(aiConfig) : null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public AiConfigResponse createAiConfigWithResponse(AiConfigCreateRequest request) {
|
||||
AiConfig aiConfig = new AiConfig();
|
||||
BeanUtils.copyProperties(request, aiConfig);
|
||||
aiConfig.setId(String.valueOf(snowflakeIdGenerator.nextId()));
|
||||
|
||||
boolean saved = this.save(aiConfig);
|
||||
return saved ? convertToResponse(aiConfig) : null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public AiConfigResponse updateAiConfigWithResponse(AiConfigUpdateRequest request) {
|
||||
AiConfig aiConfig = this.getById(request.getId());
|
||||
if (aiConfig == null) {
|
||||
return null;
|
||||
}
|
||||
|
||||
BeanUtils.copyProperties(request, aiConfig);
|
||||
boolean updated = this.updateById(aiConfig);
|
||||
return updated ? convertToResponse(aiConfig) : null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<AiConfig> getByConfigType(String configType) {
|
||||
LambdaQueryWrapper<AiConfig> wrapper = new LambdaQueryWrapper<>();
|
||||
wrapper.eq(AiConfig::getConfigType, configType);
|
||||
wrapper.orderByDesc(AiConfig::getPriority);
|
||||
return this.list(wrapper);
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<AiConfigResponse> getByConfigTypeWithResponse(String configType) {
|
||||
return getByConfigType(configType).stream()
|
||||
.map(this::convertToResponse)
|
||||
.collect(Collectors.toList());
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<AiConfig> getByProvider(String provider) {
|
||||
LambdaQueryWrapper<AiConfig> wrapper = new LambdaQueryWrapper<>();
|
||||
wrapper.eq(AiConfig::getProvider, provider);
|
||||
wrapper.orderByDesc(AiConfig::getPriority);
|
||||
return this.list(wrapper);
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<AiConfigResponse> getByProviderWithResponse(String provider) {
|
||||
return getByProvider(provider).stream()
|
||||
.map(this::convertToResponse)
|
||||
.collect(Collectors.toList());
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<AiConfig> getByUsageScenario(String usageScenario) {
|
||||
LambdaQueryWrapper<AiConfig> wrapper = new LambdaQueryWrapper<>();
|
||||
wrapper.eq(AiConfig::getUsageScenario, usageScenario);
|
||||
wrapper.eq(AiConfig::getIsEnabled, 1);
|
||||
wrapper.orderByDesc(AiConfig::getPriority);
|
||||
return this.list(wrapper);
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<AiConfigResponse> getByUsageScenarioWithResponse(String usageScenario) {
|
||||
return getByUsageScenario(usageScenario).stream()
|
||||
.map(this::convertToResponse)
|
||||
.collect(Collectors.toList());
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<AiConfig> getByEnvironment(String environment) {
|
||||
LambdaQueryWrapper<AiConfig> wrapper = new LambdaQueryWrapper<>();
|
||||
wrapper.eq(AiConfig::getEnvironment, environment);
|
||||
wrapper.orderByDesc(AiConfig::getPriority);
|
||||
return this.list(wrapper);
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<AiConfigResponse> getByEnvironmentWithResponse(String environment) {
|
||||
return getByEnvironment(environment).stream()
|
||||
.map(this::convertToResponse)
|
||||
.collect(Collectors.toList());
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<AiConfig> getEnabledConfigs() {
|
||||
LambdaQueryWrapper<AiConfig> wrapper = new LambdaQueryWrapper<>();
|
||||
wrapper.eq(AiConfig::getIsEnabled, 1);
|
||||
wrapper.orderByDesc(AiConfig::getPriority);
|
||||
return this.list(wrapper);
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<AiConfigResponse> getEnabledConfigsWithResponse() {
|
||||
return getEnabledConfigs().stream()
|
||||
.map(this::convertToResponse)
|
||||
.collect(Collectors.toList());
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<AiConfig> getDisabledConfigs() {
|
||||
LambdaQueryWrapper<AiConfig> wrapper = new LambdaQueryWrapper<>();
|
||||
wrapper.eq(AiConfig::getIsEnabled, 0);
|
||||
wrapper.orderByDesc(AiConfig::getCreateTime);
|
||||
return this.list(wrapper);
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<AiConfigResponse> getDisabledConfigsWithResponse() {
|
||||
return getDisabledConfigs().stream()
|
||||
.map(this::convertToResponse)
|
||||
.collect(Collectors.toList());
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<AiConfig> getDefaultConfigs() {
|
||||
LambdaQueryWrapper<AiConfig> wrapper = new LambdaQueryWrapper<>();
|
||||
wrapper.eq(AiConfig::getIsDefault, 1);
|
||||
wrapper.orderByDesc(AiConfig::getPriority);
|
||||
return this.list(wrapper);
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<AiConfigResponse> getDefaultConfigsWithResponse() {
|
||||
return getDefaultConfigs().stream()
|
||||
.map(this::convertToResponse)
|
||||
.collect(Collectors.toList());
|
||||
}
|
||||
|
||||
@Override
|
||||
public AiConfig getByConfigKey(String configKey) {
|
||||
LambdaQueryWrapper<AiConfig> wrapper = new LambdaQueryWrapper<>();
|
||||
wrapper.eq(AiConfig::getConfigKey, configKey);
|
||||
return this.getOne(wrapper);
|
||||
}
|
||||
|
||||
@Override
|
||||
public AiConfigResponse getByConfigKeyWithResponse(String configKey) {
|
||||
AiConfig aiConfig = getByConfigKey(configKey);
|
||||
return aiConfig != null ? convertToResponse(aiConfig) : null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean enableConfig(String id) {
|
||||
LambdaUpdateWrapper<AiConfig> wrapper = new LambdaUpdateWrapper<>();
|
||||
wrapper.eq(AiConfig::getId, id);
|
||||
wrapper.set(AiConfig::getIsEnabled, 1);
|
||||
return this.update(wrapper);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean disableConfig(String id) {
|
||||
LambdaUpdateWrapper<AiConfig> wrapper = new LambdaUpdateWrapper<>();
|
||||
wrapper.eq(AiConfig::getId, id);
|
||||
wrapper.set(AiConfig::getIsEnabled, 0);
|
||||
return this.update(wrapper);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean setAsDefault(String id) {
|
||||
LambdaUpdateWrapper<AiConfig> wrapper = new LambdaUpdateWrapper<>();
|
||||
wrapper.eq(AiConfig::getId, id);
|
||||
wrapper.set(AiConfig::getIsDefault, 1);
|
||||
return this.update(wrapper);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean unsetDefault(String id) {
|
||||
LambdaUpdateWrapper<AiConfig> wrapper = new LambdaUpdateWrapper<>();
|
||||
wrapper.eq(AiConfig::getId, id);
|
||||
wrapper.set(AiConfig::getIsDefault, 0);
|
||||
return this.update(wrapper);
|
||||
}
|
||||
|
||||
@Override
|
||||
public AiConfig getBestConfig(String usageScenario, String environment) {
|
||||
LambdaQueryWrapper<AiConfig> wrapper = new LambdaQueryWrapper<>();
|
||||
wrapper.eq(AiConfig::getUsageScenario, usageScenario);
|
||||
wrapper.eq(AiConfig::getEnvironment, environment);
|
||||
wrapper.eq(AiConfig::getIsEnabled, 1);
|
||||
wrapper.orderByDesc(AiConfig::getIsDefault);
|
||||
wrapper.orderByDesc(AiConfig::getPriority);
|
||||
wrapper.last("LIMIT 1");
|
||||
return this.getOne(wrapper);
|
||||
}
|
||||
|
||||
@Override
|
||||
public AiConfigResponse getBestConfigWithResponse(String usageScenario, String environment) {
|
||||
AiConfig aiConfig = getBestConfig(usageScenario, environment);
|
||||
return aiConfig != null ? convertToResponse(aiConfig) : null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Long countEnabledConfigs() {
|
||||
LambdaQueryWrapper<AiConfig> wrapper = new LambdaQueryWrapper<>();
|
||||
wrapper.eq(AiConfig::getIsEnabled, 1);
|
||||
return this.count(wrapper);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Long countDisabledConfigs() {
|
||||
LambdaQueryWrapper<AiConfig> wrapper = new LambdaQueryWrapper<>();
|
||||
wrapper.eq(AiConfig::getIsEnabled, 0);
|
||||
return this.count(wrapper);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Long countDefaultConfigs() {
|
||||
LambdaQueryWrapper<AiConfig> wrapper = new LambdaQueryWrapper<>();
|
||||
wrapper.eq(AiConfig::getIsDefault, 1);
|
||||
return this.count(wrapper);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Long countByConfigType(String configType) {
|
||||
LambdaQueryWrapper<AiConfig> wrapper = new LambdaQueryWrapper<>();
|
||||
wrapper.eq(AiConfig::getConfigType, configType);
|
||||
return this.count(wrapper);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Long countByProvider(String provider) {
|
||||
LambdaQueryWrapper<AiConfig> wrapper = new LambdaQueryWrapper<>();
|
||||
wrapper.eq(AiConfig::getProvider, provider);
|
||||
return this.count(wrapper);
|
||||
}
|
||||
|
||||
/**
|
||||
* 将实体转换为响应对象
|
||||
*/
|
||||
private AiConfigResponse convertToResponse(AiConfig aiConfig) {
|
||||
AiConfigResponse response = new AiConfigResponse();
|
||||
BeanUtils.copyProperties(aiConfig, response);
|
||||
|
||||
// 格式化时间
|
||||
if (aiConfig.getCreateTime() != null) {
|
||||
response.setCreateTime(aiConfig.getCreateTime().format(DATE_TIME_FORMATTER));
|
||||
}
|
||||
if (aiConfig.getUpdateTime() != null) {
|
||||
response.setUpdateTime(aiConfig.getUpdateTime().format(DATE_TIME_FORMATTER));
|
||||
}
|
||||
|
||||
// 脱敏处理API Token
|
||||
if (StringUtils.hasText(aiConfig.getApiToken())) {
|
||||
String token = aiConfig.getApiToken();
|
||||
if (token.length() > 8) {
|
||||
response.setApiToken(token.substring(0, 4) + "****" + token.substring(token.length() - 4));
|
||||
} else {
|
||||
response.setApiToken("****");
|
||||
}
|
||||
}
|
||||
|
||||
// 转换BigDecimal为Double
|
||||
if (aiConfig.getTemperature() != null) {
|
||||
response.setTemperature(aiConfig.getTemperature().doubleValue());
|
||||
}
|
||||
if (aiConfig.getTopP() != null) {
|
||||
response.setTopP(aiConfig.getTopP().doubleValue());
|
||||
}
|
||||
if (aiConfig.getInputPricePer1k() != null) {
|
||||
response.setInputPricePer1k(aiConfig.getInputPricePer1k().doubleValue());
|
||||
}
|
||||
if (aiConfig.getOutputPricePer1k() != null) {
|
||||
response.setOutputPricePer1k(aiConfig.getOutputPricePer1k().doubleValue());
|
||||
}
|
||||
|
||||
return response;
|
||||
}
|
||||
|
||||
/**
|
||||
* 根据字段名获取对应的Lambda表达式
|
||||
*/
|
||||
private com.baomidou.mybatisplus.core.toolkit.support.SFunction<AiConfig, ?> getLambdaByField(String field) {
|
||||
switch (field) {
|
||||
case "configName":
|
||||
return AiConfig::getConfigName;
|
||||
case "configKey":
|
||||
return AiConfig::getConfigKey;
|
||||
case "configType":
|
||||
return AiConfig::getConfigType;
|
||||
case "provider":
|
||||
return AiConfig::getProvider;
|
||||
case "usageScenario":
|
||||
return AiConfig::getUsageScenario;
|
||||
case "priority":
|
||||
return AiConfig::getPriority;
|
||||
case "createTime":
|
||||
return AiConfig::getCreateTime;
|
||||
case "updateTime":
|
||||
return AiConfig::getUpdateTime;
|
||||
default:
|
||||
return AiConfig::getCreateTime;
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user