后台管理功能开发,AI配置管理

This commit is contained in:
2025-10-30 14:50:44 +08:00
parent dc0413d084
commit 8b6e3d0815
23 changed files with 4463 additions and 4 deletions
@@ -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);
}
}
@@ -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;
}
@@ -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;
}
@@ -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;
}
@@ -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;
}
@@ -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;
}
}
}