mirror of
https://gitcode.com/ageerle/ruoyi-ai.git
synced 2026-03-13 20:53:42 +08:00
Merge branch 'main' of https://github.com/MuSan-Li/ruoyi-ai into feature_20250811_fix_code_generator
This commit is contained in:
@@ -8,6 +8,7 @@ import lombok.EqualsAndHashCode;
|
||||
import org.ruoyi.core.domain.BaseEntity;
|
||||
|
||||
import java.io.Serial;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* 聊天模型对象 chat_model
|
||||
@@ -80,5 +81,10 @@ public class ChatModel extends BaseEntity {
|
||||
*/
|
||||
private String remark;
|
||||
|
||||
/**
|
||||
* 模型能力
|
||||
*/
|
||||
private String modelCapability;
|
||||
|
||||
|
||||
}
|
||||
|
||||
@@ -5,14 +5,14 @@ import com.alibaba.excel.annotation.ExcelIgnoreUnannotated;
|
||||
import com.alibaba.excel.annotation.ExcelProperty;
|
||||
import io.github.linpeilie.annotations.AutoMapper;
|
||||
import lombok.Data;
|
||||
import lombok.Getter;
|
||||
import org.ruoyi.common.sensitive.annotation.Sensitive;
|
||||
import org.ruoyi.common.sensitive.core.SensitiveStrategy;
|
||||
import org.ruoyi.domain.ChatModel;
|
||||
|
||||
import java.io.Serial;
|
||||
import java.io.Serializable;
|
||||
|
||||
|
||||
import java.util.List;
|
||||
|
||||
|
||||
/**
|
||||
@@ -96,4 +96,138 @@ public class ChatModelVo implements Serializable {
|
||||
@ExcelProperty(value = "备注")
|
||||
private String remark;
|
||||
|
||||
/**
|
||||
* 模型能力
|
||||
*/
|
||||
@ExcelProperty(value = "模型能力")
|
||||
private String modelCapability;
|
||||
|
||||
/**
|
||||
* 模型能力列表
|
||||
*/
|
||||
private List<Ability> modelAbilities = getModelAbilities();
|
||||
|
||||
/**
|
||||
* 模型能力类,类似枚举的静态内部类
|
||||
*/
|
||||
@Getter
|
||||
public static final class Ability {
|
||||
// 获取能力名称
|
||||
private final String name;
|
||||
private final String description;
|
||||
|
||||
// 静态字段存储默认能力(类似枚举常量)
|
||||
public static final Ability IMAGE = new Ability("IMAGE", "图片理解");
|
||||
public static final Ability VIDEO = new Ability("VIDEO", "视频理解");
|
||||
public static final Ability SPEECH = new Ability("SPEECH", "语音理解");
|
||||
|
||||
// 动态扩展能力存储
|
||||
private static final java.util.Map<String, Ability> EXTENDED_ABILITIES = new java.util.HashMap<>();
|
||||
|
||||
// 私有构造确保受限
|
||||
private Ability(String name, String description) {
|
||||
this.name = name;
|
||||
this.description = description;
|
||||
}
|
||||
|
||||
// 静态工厂方法(类似枚举valueOf)
|
||||
public static Ability valueOf(String name) {
|
||||
// 先检查默认能力
|
||||
switch (name) {
|
||||
case "IMAGE": return IMAGE;
|
||||
case "VIDEO": return VIDEO;
|
||||
case "SPEECH": return SPEECH;
|
||||
default:
|
||||
// 检查扩展能力
|
||||
Ability ability = EXTENDED_ABILITIES.get(name);
|
||||
if (ability != null) return ability;
|
||||
throw new IllegalArgumentException("Unknown ability: " + name);
|
||||
}
|
||||
}
|
||||
|
||||
// 动态注册新能力(后期从数据库调用)
|
||||
public static synchronized Ability registerAbility(String name, String description) {
|
||||
if (name == null || name.trim().isEmpty()) {
|
||||
throw new IllegalArgumentException("Ability name cannot be empty");
|
||||
}
|
||||
|
||||
// 避免重复注册
|
||||
if (EXTENDED_ABILITIES.containsKey(name)) {
|
||||
return EXTENDED_ABILITIES.get(name);
|
||||
}
|
||||
|
||||
// 检查是否与默认能力冲突
|
||||
try {
|
||||
valueOf(name);
|
||||
throw new IllegalArgumentException("Ability already exists as default: " + name);
|
||||
} catch (IllegalArgumentException e) {
|
||||
// 正常情况,继续注册
|
||||
}
|
||||
|
||||
Ability newAbility = new Ability(name, description);
|
||||
EXTENDED_ABILITIES.put(name, newAbility);
|
||||
return newAbility;
|
||||
}
|
||||
|
||||
// 获取所有能力(默认+扩展)
|
||||
public static java.util.Set<Ability> getAllAbilities() {
|
||||
java.util.Map<String, Ability> all = new java.util.HashMap<>();
|
||||
all.put(IMAGE.name, IMAGE);
|
||||
all.put(VIDEO.name, VIDEO);
|
||||
all.put(SPEECH.name, SPEECH);
|
||||
all.putAll(EXTENDED_ABILITIES);
|
||||
return java.util.Collections.unmodifiableSet((java.util.Set<? extends Ability>) all.values());
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return name;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(Object o) {
|
||||
if (this == o) return true;
|
||||
if (o == null || getClass() != o.getClass()) return false;
|
||||
Ability ability = (Ability) o;
|
||||
return name.equals(ability.name);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
return name.hashCode();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 将 modelCapability 字符串转换为 Ability 列表
|
||||
* @return Ability 列表
|
||||
*/
|
||||
public java.util.List<Ability> getModelAbilities() {
|
||||
if (modelCapability == null || modelCapability.trim().isEmpty()) {
|
||||
return java.util.Collections.emptyList();
|
||||
}
|
||||
|
||||
// 解析 JSON 格式的字符串数组
|
||||
String trimmed = modelCapability.trim();
|
||||
if (!trimmed.startsWith("[") || !trimmed.endsWith("]")) {
|
||||
throw new IllegalArgumentException("Invalid modelCapability format: " + modelCapability);
|
||||
}
|
||||
|
||||
String content = trimmed.substring(1, trimmed.length() - 1).trim();
|
||||
if (content.isEmpty()) {
|
||||
return java.util.Collections.emptyList();
|
||||
}
|
||||
|
||||
java.util.List<Ability> abilities = new java.util.ArrayList<>();
|
||||
String[] items = content.split(",");
|
||||
for (String item : items) {
|
||||
String cleanedItem = item.trim();
|
||||
if (cleanedItem.startsWith("\"") && cleanedItem.endsWith("\"") && cleanedItem.length() >= 2) {
|
||||
String abilityName = cleanedItem.substring(1, cleanedItem.length() - 1);
|
||||
abilities.add(Ability.valueOf(abilityName));
|
||||
}
|
||||
}
|
||||
|
||||
return abilities;
|
||||
}
|
||||
}
|
||||
@@ -1,5 +1,6 @@
|
||||
package org.ruoyi.generator.controller;
|
||||
|
||||
import cn.hutool.core.net.URLDecoder;
|
||||
import jakarta.validation.constraints.NotNull;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import org.ruoyi.common.core.domain.R;
|
||||
@@ -8,10 +9,11 @@ import org.ruoyi.generator.service.IGenTableService;
|
||||
import org.ruoyi.generator.service.SchemaFieldService;
|
||||
import org.springframework.context.annotation.Profile;
|
||||
import org.springframework.web.bind.annotation.GetMapping;
|
||||
import org.springframework.web.bind.annotation.PathVariable;
|
||||
import org.springframework.web.bind.annotation.RequestMapping;
|
||||
import org.springframework.web.bind.annotation.RestController;
|
||||
|
||||
import java.nio.charset.StandardCharsets;
|
||||
|
||||
/**
|
||||
* 代码生成 操作处理
|
||||
*
|
||||
@@ -46,4 +48,18 @@ public class GenController extends BaseController {
|
||||
genTableService.generateCodeToClasspathByTableNames(tableNameStr);
|
||||
return R.ok("代码生成成功");
|
||||
}
|
||||
|
||||
/**
|
||||
* 生成前端代码
|
||||
*
|
||||
* @param workPath 执行命令路径
|
||||
* @param previewCode 执行生成前端文件命令
|
||||
*/
|
||||
@GetMapping("/batchGenFrontendCode")
|
||||
public R<String> batchGenFrontendCode(@NotNull(message = "路径不能为空") String workPath, @NotNull(message = "指令不能为空") String previewCode) {
|
||||
String decodedWorkPath = URLDecoder.decode(workPath, StandardCharsets.UTF_8);
|
||||
String decodedPreviewCode = URLDecoder.decode(previewCode, StandardCharsets.UTF_8);
|
||||
genTableService.generateFrontendTemplateFiles(decodedWorkPath, decodedPreviewCode);
|
||||
return R.ok("代码生成成功");
|
||||
}
|
||||
}
|
||||
|
||||
@@ -21,18 +21,9 @@ import org.ruoyi.generator.util.VelocityInitializer;
|
||||
import org.ruoyi.generator.util.VelocityUtils;
|
||||
import org.springframework.stereotype.Service;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.FileWriter;
|
||||
import java.io.StringWriter;
|
||||
import java.io.*;
|
||||
import java.nio.charset.StandardCharsets;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Date;
|
||||
import java.util.HashMap;
|
||||
import java.util.HashSet;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Objects;
|
||||
import java.util.Set;
|
||||
import java.util.*;
|
||||
|
||||
/**
|
||||
* 业务 服务层实现
|
||||
@@ -62,6 +53,41 @@ public class GenTableServiceImpl implements IGenTableService {
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void generateFrontendTemplateFiles(String workPath, String previewCode) {
|
||||
String os = System.getProperty("os.name").toLowerCase();
|
||||
|
||||
ProcessBuilder builder;
|
||||
if (os.contains("win")) {
|
||||
// Windows下用 cmd /c 执行 previewCode
|
||||
builder = new ProcessBuilder("cmd.exe", "/c", previewCode);
|
||||
} else {
|
||||
// macOS/Linux 用 bash -c 执行 previewCode
|
||||
builder = new ProcessBuilder("bash", "-c", previewCode);
|
||||
}
|
||||
|
||||
// 设置工作目录
|
||||
builder.directory(new File(workPath));
|
||||
builder.redirectErrorStream(true);
|
||||
|
||||
try (BufferedReader reader = new BufferedReader(
|
||||
new InputStreamReader(
|
||||
builder.start().getInputStream(),
|
||||
StandardCharsets.UTF_8
|
||||
)
|
||||
)) {
|
||||
String line;
|
||||
log.info("执行结果:");
|
||||
while ((line = reader.readLine()) != null) {
|
||||
log.info(line);
|
||||
}
|
||||
|
||||
} catch (Exception e) {
|
||||
log.error("生成前端代码出错", e);
|
||||
throw new RuntimeException("生成前端代码失败", e);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 根据表名称生成代码到classpath
|
||||
*/
|
||||
|
||||
@@ -13,4 +13,12 @@ public interface IGenTableService {
|
||||
* @param tableName 表名称数组
|
||||
*/
|
||||
void generateCodeToClasspathByTableNames(String tableName);
|
||||
|
||||
/**
|
||||
* 生成前端文件
|
||||
*
|
||||
* @param workPath 执行命令路径
|
||||
* @param previewCode 执行生成前端文件命令
|
||||
*/
|
||||
void generateFrontendTemplateFiles(String workPath, String previewCode);
|
||||
}
|
||||
|
||||
3
script/sql/update/20250808.sql
Normal file
3
script/sql/update/20250808.sql
Normal file
@@ -0,0 +1,3 @@
|
||||
-- 聊天模型表添加模型能力字段
|
||||
alter table chat_model
|
||||
add model_capability varchar(255) default '[]' not null comment '模型能力';
|
||||
@@ -74,7 +74,7 @@ SET FOREIGN_KEY_CHECKS = 1;
|
||||
|
||||
|
||||
-- 菜单
|
||||
INSERT INTO `sys_menu` (`menu_id`, `menu_name`, `parent_id`, `order_num`, `path`, `component`, `query_param`, `is_frame`, `is_cache`, `menu_type`, `visible`, `status`, `perms`, `icon`, `create_dept`, `create_by`, `create_time`, `update_by`, `update_time`, `remark`) VALUES (1946483381643743233, '知识库角色管理', 1775500307898949634, '12', 'knowledgeRole', 'system/knowledgeRole/index', NULL, 1, 0, 'C', '0', '0', NULL, 'ri:user-3-fill', 103, 1, '2025-07-19 16:41:17', NULL, NULL, '知识库角色管理');
|
||||
INSERT INTO `sys_menu` (`menu_id`, `menu_name`, `parent_id`, `order_num`, `path`, `component`, `query_param`, `is_frame`, `is_cache`, `menu_type`, `visible`, `status`, `perms`, `icon`, `create_dept`, `create_by`, `create_time`, `update_by`, `update_time`, `remark`) VALUES (1946483381643743233, '知识库角色管理', 1775500307898949634, '12', 'knowledgeRole', 'operator/knowledgeRole/index', NULL, 1, 0, 'C', '0', '0', NULL, 'ri:user-3-fill', 103, 1, '2025-07-19 16:41:17', NULL, NULL, '知识库角色管理');
|
||||
|
||||
-- 用户表添加字段
|
||||
ALTER TABLE sys_user
|
||||
|
||||
Reference in New Issue
Block a user