|
|
|
|
@ -1,13 +1,18 @@
|
|
|
|
|
package org.dromara.ai.service.impl;
|
|
|
|
|
|
|
|
|
|
import com.alibaba.excel.util.StringUtils;
|
|
|
|
|
import com.alibaba.fastjson.JSON;
|
|
|
|
|
import com.alibaba.fastjson.JSONArray;
|
|
|
|
|
import com.alibaba.fastjson.JSONObject;
|
|
|
|
|
import com.fasterxml.jackson.core.JsonProcessingException;
|
|
|
|
|
import org.dromara.ai.domain.AiFormSettingDetail;
|
|
|
|
|
import org.dromara.ai.domain.AiModel;
|
|
|
|
|
import org.dromara.ai.domain.vo.AiModelVo;
|
|
|
|
|
import org.dromara.ai.domain.dto.AiTableConditionWrapper;
|
|
|
|
|
import org.dromara.ai.domain.dto.AiTableData;
|
|
|
|
|
import org.dromara.ai.domain.dto.AiTableQueryCondition;
|
|
|
|
|
import org.dromara.ai.mapper.AiModelMapper;
|
|
|
|
|
import org.dromara.ai.process.dto.AIFillFormRequest;
|
|
|
|
|
import org.dromara.ai.process.dto.AIResponse;
|
|
|
|
|
import org.dromara.ai.test.ChatRequest;
|
|
|
|
|
import org.dromara.ai.mapper.SQLServerDatabaseMetaMapper;
|
|
|
|
|
import org.dromara.ai.process.dto.AIMessage;
|
|
|
|
|
import org.dromara.ai.process.dto.AIRequest;
|
|
|
|
|
@ -43,9 +48,6 @@ public class AIAssistantServiceImpl implements IAIAssistantService {
|
|
|
|
|
@Autowired
|
|
|
|
|
private AiModelMapper aiModelMapper;
|
|
|
|
|
|
|
|
|
|
@Autowired
|
|
|
|
|
private Map<String, IUnifiedAIProviderProcessor> aiProviderProcessorMap;
|
|
|
|
|
|
|
|
|
|
@Autowired
|
|
|
|
|
private AIProviderProcessorFactory aiProviderProcessorFactory;
|
|
|
|
|
|
|
|
|
|
@ -58,6 +60,9 @@ public class AIAssistantServiceImpl implements IAIAssistantService {
|
|
|
|
|
@Autowired
|
|
|
|
|
private StringRedisTemplate redisTemplate;
|
|
|
|
|
|
|
|
|
|
@Autowired
|
|
|
|
|
private SQLServerDatabaseMetaMapper sQLServerDatabaseMetaMapper;
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* 流式聊天接口
|
|
|
|
|
*
|
|
|
|
|
@ -365,7 +370,191 @@ public class AIAssistantServiceImpl implements IAIAssistantService {
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// /**
|
|
|
|
|
/**
|
|
|
|
|
* ai智能表单填报
|
|
|
|
|
*
|
|
|
|
|
* @param aiFillFormRequest
|
|
|
|
|
* @return String
|
|
|
|
|
*/
|
|
|
|
|
@Override
|
|
|
|
|
public JSONObject aiFillForm(AIFillFormRequest aiFillFormRequest) {
|
|
|
|
|
|
|
|
|
|
// List<String> fields = Arrays.asList("dept_id as deptId", "dept_name as deptName");
|
|
|
|
|
// Map<String, Object> condition = new HashMap<>();
|
|
|
|
|
// condition.put("dept_name", "测试");
|
|
|
|
|
// List<Map<String, Object>> tableData = sQLServerDatabaseMetaMapper.dynamicSelect("sys_dept", fields, condition, "", "");
|
|
|
|
|
//
|
|
|
|
|
// if (tableData != null) {
|
|
|
|
|
// return "";
|
|
|
|
|
// }
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
String naturalLanguageQuery = aiFillFormRequest.getNaturalLanguageQuery();
|
|
|
|
|
List<AiFormSettingDetail> aiFormSettingDetailList = aiFillFormRequest.getFormSettingDetailList();
|
|
|
|
|
StringBuilder sb = new StringBuilder("你是一个智能表单填充助手。请根据我的要求、提供的数据库表字段信息,生成一份用于直接填充Vue3前端表单的JSON数据。\n\n");
|
|
|
|
|
|
|
|
|
|
sb.append("【要求】\n");
|
|
|
|
|
sb.append(naturalLanguageQuery).append(",\n\n");
|
|
|
|
|
|
|
|
|
|
sb.append("【数据库表信息】\n");
|
|
|
|
|
sb.append(getFormattedFormSettingDetails(aiFormSettingDetailList));
|
|
|
|
|
|
|
|
|
|
sb.append("\n【输出要求】\n");
|
|
|
|
|
sb.append("1. 请根据我的核心要求,智能推断并填充所有相关字段的值\n");
|
|
|
|
|
sb.append("2. 生成一个纯净的JSON对象,不要任何额外的解释、文本或markdown代码块标记,键是字段名,值是根据我的要求推断出来的值\n");
|
|
|
|
|
// sb.append("3. 请返回**纯净的JSON格式**数据,不要任何额外的解释、文本或markdown代码块标记\n");
|
|
|
|
|
sb.append("3. 仅返回一个JSON对象,不要返回JSON数组,不要返回任何测试数据和推测的数据\n");
|
|
|
|
|
sb.append("4. 其他没有要求返回的数据返回空字符串\n");
|
|
|
|
|
|
|
|
|
|
IUnifiedAIProviderProcessor processor = aiProviderProcessorFactory.getProcessorByPlatformId(1L);
|
|
|
|
|
AIMessage aiMessage = new AIMessage();
|
|
|
|
|
aiMessage.setRole("user");
|
|
|
|
|
aiMessage.setContent(sb.toString());
|
|
|
|
|
|
|
|
|
|
AIRequest aiRequest = new AIRequest();
|
|
|
|
|
aiRequest.setMessages(Collections.singletonList(aiMessage));
|
|
|
|
|
aiRequest.setModelId(1L);
|
|
|
|
|
|
|
|
|
|
Mono<AIResponse> response = processor.chat(aiRequest);
|
|
|
|
|
if (Objects.requireNonNull(response.block()).isSuccess()) {
|
|
|
|
|
String content = response.block().getContent().toString();
|
|
|
|
|
JSONObject contentJson = JSONObject.parseObject(content);
|
|
|
|
|
parseRelateTable(aiFormSettingDetailList, contentJson);
|
|
|
|
|
System.out.println(contentJson.toJSONString());
|
|
|
|
|
return contentJson;
|
|
|
|
|
|
|
|
|
|
} else {
|
|
|
|
|
throw new RuntimeException("生成sql语句失败" + response.block().getErrorMessage());
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
private void parseRelateTable(List<AiFormSettingDetail> aiFormSettingDetailList, JSONObject contentJson) {
|
|
|
|
|
for (AiFormSettingDetail aiFormSettingDetail : aiFormSettingDetailList) {
|
|
|
|
|
if (aiFormSettingDetail.getSettingFlag().equals("1")) {
|
|
|
|
|
String fieldType = StringUtils.isBlank(aiFormSettingDetail.getFieldType()) ? HwMomAiConstants.AI_FORM_SETTING_FIELD_TYPE_NORMAL : aiFormSettingDetail.getFieldType();
|
|
|
|
|
String relateTableName = aiFormSettingDetail.getRelateTableName();
|
|
|
|
|
String relateTableFields = aiFormSettingDetail.getRelateTableFields();
|
|
|
|
|
if (fieldType.equals(HwMomAiConstants.AI_FORM_SETTING_FIELD_TYPE_RELATE) &&
|
|
|
|
|
StringUtils.isNotBlank(relateTableName) && StringUtils.isNotBlank(relateTableFields)) {
|
|
|
|
|
Object value = contentJson.get(aiFormSettingDetail.getFormProp());
|
|
|
|
|
if (value != null && value instanceof JSONArray) {
|
|
|
|
|
JSONArray valueArr = (JSONArray) value;
|
|
|
|
|
if (valueArr.size() > 0) {
|
|
|
|
|
JSONObject conditionJson = valueArr.getJSONObject(0);
|
|
|
|
|
Set<String> conditionKeys = conditionJson.keySet();
|
|
|
|
|
Map<String, Object> conditionMap = new HashMap<>();
|
|
|
|
|
for (String conditionKey : conditionKeys) {
|
|
|
|
|
conditionMap.put(camelToSnakeEnhanced(conditionKey), conditionJson.get(conditionKey));
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
JSONArray relateTableFieldArr = JSONArray.parseArray(relateTableFields);
|
|
|
|
|
|
|
|
|
|
// List<String> relateTableFieldList = Arrays.asList(relateTableFields.split(","));
|
|
|
|
|
List<String> relateTableFieldList = relateTableFieldArr.stream()
|
|
|
|
|
.map(obj -> {
|
|
|
|
|
JSONObject jsonObj = (JSONObject) obj;
|
|
|
|
|
return jsonObj.getString("fieldName") + " as " + jsonObj.getString("formProp");
|
|
|
|
|
})
|
|
|
|
|
.collect(Collectors.toList());
|
|
|
|
|
|
|
|
|
|
String relateFilterCondition = aiFormSettingDetail.getRelateFilterCondition();
|
|
|
|
|
//[{fieldKey:'del_flag',fieldValue:'0',conditionSymbol:'='}]
|
|
|
|
|
// 创建条件包装类
|
|
|
|
|
AiTableConditionWrapper wrapper = new AiTableConditionWrapper();
|
|
|
|
|
if(StringUtils.isNotBlank(relateFilterCondition)){
|
|
|
|
|
// 解析JSON字符串为条件列表
|
|
|
|
|
List<AiTableQueryCondition> conditions = JSON.parseArray(relateFilterCondition, AiTableQueryCondition.class);
|
|
|
|
|
wrapper.setAiTableQueryConditions(conditions);
|
|
|
|
|
// JSONArray relateFilterConditionArr = JSONArray.parseArray(relateFilterCondition);
|
|
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
List<Map<String, Object>> tableData = sQLServerDatabaseMetaMapper.dynamicSelect(relateTableName, relateTableFieldList, conditionMap, wrapper,"", "");
|
|
|
|
|
JSONArray relateTableDataArr = new JSONArray();
|
|
|
|
|
for (Map<String, Object> tableD : tableData) {
|
|
|
|
|
// JSONObject tableDataJson = new JSONObject();
|
|
|
|
|
JSONArray tableFiledDataArr = new JSONArray();
|
|
|
|
|
|
|
|
|
|
// tableDataJson.put("relateTableDesc",aiFormSettingDetail.getRelateTableDesc());
|
|
|
|
|
AiTableData aiTableData = new AiTableData();
|
|
|
|
|
aiTableData.setFieldKey("relateTableDesc");
|
|
|
|
|
aiTableData.setFieldValue(aiFormSettingDetail.getRelateTableDesc());
|
|
|
|
|
aiTableData.setFieldType("3");//在选择时显示的title
|
|
|
|
|
tableFiledDataArr.add(aiTableData);
|
|
|
|
|
Set<String> tableDataKeys = tableD.keySet();
|
|
|
|
|
for (String tableDataKey : tableDataKeys) {
|
|
|
|
|
// tableDataJson.put(tableDataKey,tableD.get(tableDataKey));
|
|
|
|
|
|
|
|
|
|
aiTableData = new AiTableData();
|
|
|
|
|
if (tableDataKey.contains("Id")) {
|
|
|
|
|
aiTableData.setFieldType("1");//主键,赋值使用
|
|
|
|
|
} else {
|
|
|
|
|
aiTableData.setFieldType("2");//显示使用
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
aiTableData.setFieldKey(tableDataKey);
|
|
|
|
|
aiTableData.setFieldValue(tableD.get(tableDataKey));
|
|
|
|
|
|
|
|
|
|
tableFiledDataArr.add(aiTableData);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
relateTableDataArr.add(tableFiledDataArr);
|
|
|
|
|
}
|
|
|
|
|
contentJson.put(aiFormSettingDetail.getFormProp(), relateTableDataArr);
|
|
|
|
|
System.out.println(tableData);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
private String getFormattedFormSettingDetails(List<AiFormSettingDetail> aiFormSettingDetailList) {
|
|
|
|
|
StringBuilder sb = new StringBuilder("字段列表:\n");
|
|
|
|
|
for (AiFormSettingDetail aiFormSettingDetail : aiFormSettingDetailList) {
|
|
|
|
|
if (aiFormSettingDetail.getSettingFlag().equals("1")) {
|
|
|
|
|
sb.append("- 字段名:").append(aiFormSettingDetail.getFieldName())
|
|
|
|
|
.append(",返回的JSON数据Key值:").append(aiFormSettingDetail.getFormProp())
|
|
|
|
|
.append(",字段描述:").append(aiFormSettingDetail.getFieldDesc());
|
|
|
|
|
String fieldType = StringUtils.isBlank(aiFormSettingDetail.getFieldType()) ? HwMomAiConstants.AI_FORM_SETTING_FIELD_TYPE_NORMAL : aiFormSettingDetail.getFieldType();
|
|
|
|
|
if (fieldType.equals(HwMomAiConstants.AI_FORM_SETTING_FIELD_TYPE_RELATE)) {
|
|
|
|
|
sb.append(" 备注:如果需要从关联表获取数据,则返回此关联表的查询条件即可,返回示例如下:[{'fieldName':'fieldValue'}],fieldName从字段名获取,如果不需要从关联表获取数据则返回空");
|
|
|
|
|
} else if (fieldType.equals(HwMomAiConstants.AI_FORM_SETTING_FIELD_TYPE_DICT)) {
|
|
|
|
|
sb.append(" 备注:如果有符合条件的数据,则根据要求返回字典的数值");
|
|
|
|
|
}
|
|
|
|
|
sb.append("\n");
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
}
|
|
|
|
|
return sb.toString();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* 增强版的驼峰转下划线,处理各种边界情况
|
|
|
|
|
*/
|
|
|
|
|
public String camelToSnakeEnhanced(String camelCase) {
|
|
|
|
|
if (camelCase == null || camelCase.isEmpty()) {
|
|
|
|
|
return camelCase;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// 处理全大写的情况(如"URL" -> "url")
|
|
|
|
|
if (camelCase.equals(camelCase.toUpperCase())) {
|
|
|
|
|
return camelCase.toLowerCase();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
String result = camelCase.replaceAll("([a-z])([A-Z])", "$1_$2")
|
|
|
|
|
.replaceAll("([A-Z])([A-Z][a-z])", "$1_$2")
|
|
|
|
|
.toLowerCase();
|
|
|
|
|
|
|
|
|
|
return result;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// /**
|
|
|
|
|
// * 在新建AI模型或修改AI模型时,测试AI模型是否可用,验证apikey和apisecret等信息
|
|
|
|
|
// * @param provider
|
|
|
|
|
// * @param aiRequest
|
|
|
|
|
@ -394,17 +583,4 @@ public class AIAssistantServiceImpl implements IAIAssistantService {
|
|
|
|
|
//
|
|
|
|
|
// return true;
|
|
|
|
|
// }
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
public String aiFillForm() {
|
|
|
|
|
String aiClient = "deepSeek";
|
|
|
|
|
IUnifiedAIProviderProcessor service = aiProviderProcessorMap.get(aiClient);
|
|
|
|
|
if (service == null) {
|
|
|
|
|
throw new IllegalArgumentException("Unsupported payment type");
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return "";
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|