Commit 82c57840 by 彭顺

feat: 4月11日需求修改

parent 68f10d90
File added
package cn.iocoder.yudao.module.ai.controller.admin.agent;
import cn.iocoder.yudao.framework.common.pojo.CommonResult;
import cn.iocoder.yudao.framework.common.util.object.BeanUtils;
import cn.iocoder.yudao.module.ai.controller.admin.agent.vo.AgentCreateReqVO;
import cn.iocoder.yudao.module.ai.controller.admin.agent.vo.AgentMsgReqVO;
import cn.iocoder.yudao.module.ai.controller.admin.agent.vo.AgentUsedRespVO;
import cn.iocoder.yudao.module.ai.controller.admin.agent.vo.OrderInfoVO;
import cn.iocoder.yudao.module.ai.controller.admin.chat.vo.message.AiChatMessageRespVO;
import cn.iocoder.yudao.module.ai.controller.admin.agent.vo.*;
import cn.iocoder.yudao.module.ai.dal.dataobject.chat.AiChatConversationDO;
import cn.iocoder.yudao.module.ai.dal.dataobject.model.AiApiKeyDO;
import cn.iocoder.yudao.module.ai.dal.dataobject.model.AiChatModelDO;
......@@ -17,12 +12,16 @@ import cn.iocoder.yudao.module.ai.service.chat.AiChatMessageService;
import cn.iocoder.yudao.module.ai.service.model.AiApiKeyService;
import cn.iocoder.yudao.module.ai.service.model.AiChatModelService;
import cn.iocoder.yudao.module.ai.service.model.AiChatRoleService;
import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.ObjectMapper;
import io.swagger.v3.oas.annotations.Operation;
import io.swagger.v3.oas.annotations.Parameter;
import io.swagger.v3.oas.annotations.tags.Tag;
import jakarta.annotation.Resource;
import jakarta.annotation.security.PermitAll;
import jakarta.validation.Valid;
import org.json.JSONArray;
import org.json.JSONObject;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.*;
import org.springframework.validation.annotation.Validated;
......@@ -89,7 +88,7 @@ public class AgentChatController {
AgentUsedRespVO agentUsedRespVO = new AgentUsedRespVO();
agentUsedRespVO.setId(aiChatConversationDO.getId());
agentUsedRespVO.setRoleId(aiChatConversationDO.getRoleId());
agentUsedRespVO.setTitle(aiChatConversationDO.getTitle());
agentUsedRespVO.setCreateTime(aiChatConversationDO.getCreateTime());
AiChatRoleDO aiChatRoleDO = chatRoleService.getChatRole(aiChatConversationDO.getRoleId());
......@@ -106,13 +105,13 @@ public class AgentChatController {
return success(result);
}
@PostMapping("/get-messages")
@Operation(summary = "获得智能体对话消息")
public ResponseEntity<?> getAgentMessages(@RequestBody @Valid AgentMsgReqVO reqVO) {
@GetMapping("/get-extra-variables")
@Operation(summary = "获得智能体额外选项")
@Parameter(name = "roleId", required = true, description = "智能体ID", example = "1024")
public ResponseEntity<?> getAgentExtraVariables(@RequestParam("roleId") Long roleId) {
AiChatRoleDO aiRole = chatRoleService.getChatRole(reqVO.getRoleId());
AiChatConversationDO conversation = chatConversationService.getChatConversation(reqVO.getConversationId());
AiChatModelDO model = chatModelService.getChatModel(conversation.getModelId());
AiChatRoleDO aiRole = chatRoleService.getChatRole(roleId);
AiChatModelDO model = chatModelService.getChatModel(aiRole.getModelId());
AiApiKeyDO apiKeyDO = apiKeyService.getApiKey(model.getKeyId());
// 目标服务的URL
......@@ -120,9 +119,7 @@ public class AgentChatController {
// 构建请求参数
String appId = aiRole.getAppId();
String chatId = String.valueOf(reqVO.getConversationId());
// String appId = "66f225d52b2887652b418f82";
// String chatId = "1781604279872581766";
String chatId = "any_id_can_works";
boolean loadCustomFeedbacks = true;
// 构建URL与请求参数
......@@ -139,20 +136,36 @@ public class AgentChatController {
// 发送请求并接收响应
ResponseEntity<String> response = restTemplate.exchange(requestUrl, HttpMethod.GET, entity, String.class);
// 返回响应
return response;
JSONObject initJson = new JSONObject(response.getBody());
JSONObject initData = initJson.getJSONObject("data");
JSONArray variablesConfig = initData.getJSONObject("app")
.getJSONObject("chatConfig")
.optJSONArray("variables");
JSONObject data = new JSONObject();
data.put("status", 200);
data.put("data", variablesConfig);
data.put("msg", "");
// 4. 返回合并后的响应
return ResponseEntity.ok(data.toString());
}
@Operation(summary = "删除指定对话的上下文")
@DeleteMapping("/delete-context")
@Parameter(name = "conversationId", required = true, description = "对话编号", example = "1024")
public ResponseEntity<?> deleteChatMessageByConversationId(@RequestParam("conversationId") Long conversationId) {
@PostMapping("/get-messages")
@Operation(summary = "获得智能体对话消息")
public ResponseEntity<?> getAgentMessagesv2(@RequestBody @Valid AgentMsgReqVO reqVO) {
if(chatMessageService.checkMsgExist(reqVO.getConversationId())){
// 直接构建 JSON 字符串
String jsonResponse = "{ \"code\": 200, \"data\": {}, \"msg\": \"\" }";
AiChatConversationDO conversation = chatConversationService.getChatConversation(conversationId);
if(conversation.getRoleId() == null){
throw exception(CHAT_AGENT_NOT_EXISTS);
// 创建 ResponseEntity
ResponseEntity<String> response = ResponseEntity.ok(jsonResponse);
return response;
}
AiChatRoleDO aiRole = chatRoleService.getChatRole(conversation.getRoleId());
AiChatRoleDO aiRole = chatRoleService.getChatRole(reqVO.getRoleId());
AiChatConversationDO conversation = chatConversationService.getChatConversation(reqVO.getConversationId());
AiChatModelDO model = chatModelService.getChatModel(conversation.getModelId());
AiApiKeyDO apiKeyDO = apiKeyService.getApiKey(model.getKeyId());
......@@ -161,10 +174,20 @@ public class AgentChatController {
// 构建请求参数
String appId = aiRole.getAppId();
String chatId = String.valueOf(conversationId);
String chatId = String.valueOf(reqVO.getConversationId());
boolean loadCustomFeedbacks = true;
// 构建请求体
Map<String, Object> requestBody = new HashMap<>();
requestBody.put("offset", reqVO.getOffset());
requestBody.put("pageSize", reqVO.getPageSize());
requestBody.put("chatId", chatId);
requestBody.put("appId", appId);
requestBody.put("loadCustomFeedbacks", loadCustomFeedbacks);
requestBody.put("type", "normal");
// 构建URL与请求参数
String requestUrl = baseUrl + "/core/chat/delHistory?appId=" + appId + "&chatId=" + chatId;
String requestUrl = baseUrl + "/core/chat/getPaginationRecords";
// 设置请求头
HttpHeaders headers = new HttpHeaders();
......@@ -172,15 +195,97 @@ public class AgentChatController {
headers.set("Authorization", "Bearer " + apiKeyDO.getApiKey());
// 构建请求实体
HttpEntity<String> entity = new HttpEntity<>(headers);
HttpEntity<Map<String, Object>> entity = new HttpEntity<>(requestBody, headers);
// 发送请求并接收响应
ResponseEntity<String> response = restTemplate.exchange(requestUrl, HttpMethod.DELETE, entity, String.class);
ResponseEntity<String> response = restTemplate.exchange(requestUrl, HttpMethod.POST, entity, String.class);
chatMessageService.deleteChatMessageByConversationId(conversationId, getLoginUserId());
// 返回响应
return response;
}
// @PostMapping("/get-messages")
// @Operation(summary = "获得智能体对话消息")
// public ResponseEntity<?> getAgentMessagesv2(@RequestBody @Valid AgentMsgReqVO reqVO) {
// if(chatMessageService.checkMsgExist(reqVO.getConversationId())) {
// // 直接构建 JSON 字符串
// String jsonResponse = "{ \"code\": 200, \"data\": {}, \"msg\": \"\" }";
// // 创建 ResponseEntity
// return ResponseEntity.ok(jsonResponse);
// }
//
// AiChatRoleDO aiRole = chatRoleService.getChatRole(reqVO.getRoleId());
// AiChatConversationDO conversation = chatConversationService.getChatConversation(reqVO.getConversationId());
// AiChatModelDO model = chatModelService.getChatModel(conversation.getModelId());
// AiApiKeyDO apiKeyDO = apiKeyService.getApiKey(model.getKeyId());
//
// // 目标服务的URL
// String baseUrl = apiKeyDO.getUrl();
//
// // 构建请求参数
// String appId = aiRole.getAppId();
// String chatId = String.valueOf(reqVO.getConversationId());
// boolean loadCustomFeedbacks = true;
//
// // 1. 首先获取init数据
// String initUrl = baseUrl + "/core/chat/init?appId=" + appId + "&chatId=" + chatId + "&loadCustomFeedbacks=" + loadCustomFeedbacks;
// HttpHeaders headers = new HttpHeaders();
// headers.setContentType(MediaType.APPLICATION_JSON);
// headers.set("Authorization", "Bearer " + apiKeyDO.getApiKey());
// HttpEntity<String> initEntity = new HttpEntity<>(headers);
// ResponseEntity<String> initResponse = restTemplate.exchange(initUrl, HttpMethod.GET, initEntity, String.class);
//
// // 解析init响应获取variables和app.chatConfig.variables
// JSONObject initJson = new JSONObject(initResponse.getBody());
// JSONObject initData = initJson.getJSONObject("data");
//// JSONObject variables = initData.optJSONObject("variables");
// JSONArray variablesConfig = initData.getJSONObject("app")
// .getJSONObject("chatConfig")
// .optJSONArray("variables");
//
// // 2. 获取分页记录
// Map<String, Object> requestBody = new HashMap<>();
// requestBody.put("offset", reqVO.getOffset());
// requestBody.put("pageSize", reqVO.getPageSize());
// requestBody.put("chatId", chatId);
// requestBody.put("appId", appId);
// requestBody.put("loadCustomFeedbacks", loadCustomFeedbacks);
// requestBody.put("type", "normal");
//
// String recordsUrl = baseUrl + "/core/chat/getPaginationRecords";
// HttpEntity<Map<String, Object>> recordsEntity = new HttpEntity<>(requestBody, headers);
// ResponseEntity<String> recordsResponse = restTemplate.exchange(recordsUrl, HttpMethod.POST, recordsEntity, String.class);
//
// // 3. 合并数据到分页记录响应中
// JSONObject recordsJson = new JSONObject(recordsResponse.getBody());
// JSONObject data = recordsJson.optJSONObject("data");
// if (data == null) {
// data = new JSONObject();
// recordsJson.put("data", data);
// }
//
// // 合并variables和variablesConfig
//// if (variables != null) {
//// data.put("variables", variables);
//// }
// if (variablesConfig != null) {
// data.put("variables", variablesConfig);
// }
//
// // 4. 返回合并后的响应
// return ResponseEntity.ok(recordsJson.toString());
// }
@Operation(summary = "删除指定对话的上下文")
@DeleteMapping("/delete-context")
@Parameter(name = "conversationId", required = true, description = "对话编号", example = "1024")
public CommonResult<Boolean> deleteChatMessageByConversationId(@RequestParam("conversationId") Long conversationId) {
chatMessageService.deleteChatMessageByConversationId(conversationId, getLoginUserId());
return success(true);
}
@PostMapping("/get-order-info")
@Operation(summary = "获取jp通知单所需信息")
@Parameter(name = "vbeln", required = true, description = "SAP销售订单编号", example = "2024102922")
......@@ -204,4 +309,63 @@ public class AgentChatController {
return success(orderInfoService.getOrderInfoRequest(url, payload));
}
@PostMapping("/feedback")
@Operation(summary = "更新反馈信息")
public ResponseEntity<?> updateUserFeedback(@RequestBody @Valid AgentFeedBackReqVO reqVO) {
AiChatRoleDO aiRole = chatRoleService.getChatRole(reqVO.getRoleId());
AiChatConversationDO conversation = chatConversationService.getChatConversation(reqVO.getConversationId());
AiChatModelDO model = chatModelService.getChatModel(conversation.getModelId());
AiApiKeyDO apiKeyDO = apiKeyService.getApiKey(model.getKeyId());
// 目标服务的URL
String baseUrl = apiKeyDO.getUrl();
// 构建请求参数
String appId = aiRole.getAppId();
String chatId = String.valueOf(reqVO.getConversationId());
String chatItemId = reqVO.getMessageId();
String userBadFeedback = reqVO.getUserBadFeedback();
String userGoodFeedback = reqVO.getUserGoodFeedback();
// 构建请求体
Map<String, Object> requestBody = new HashMap<>();
requestBody.put("appId", appId);
requestBody.put("chatId", chatId);
requestBody.put("chatItemId", chatItemId);
// 判断 userBadFeedback 和 userGoodFeedback 哪个不为 null
if (userBadFeedback != null) {
requestBody.put("userBadFeedback", userBadFeedback);
} else if (userGoodFeedback != null) {
requestBody.put("userGoodFeedback", userGoodFeedback);
}
// 将请求体转换为JSON字符串
ObjectMapper objectMapper = new ObjectMapper();
String requestBodyJson;
try {
requestBodyJson = objectMapper.writeValueAsString(requestBody);
} catch (JsonProcessingException e) {
throw new RuntimeException("Failed to convert request body to JSON", e);
}
// 构建URL与请求参数
String requestUrl = baseUrl + "/core/chat/feedback/updateUserFeedback";
// 设置请求头
HttpHeaders headers = new HttpHeaders();
headers.setContentType(MediaType.APPLICATION_JSON);
headers.set("Authorization", "Bearer " + apiKeyDO.getApiKey());
// 构建请求实体
HttpEntity<String> entity = new HttpEntity<>(requestBodyJson, headers);
// 发送请求并接收响应
ResponseEntity<String> response = restTemplate.exchange(requestUrl, HttpMethod.POST, entity, String.class);
// 返回响应
return response;
}
}
......@@ -10,4 +10,7 @@ public class AgentCreateReqVO {
@Schema(description = "智能体编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "10")
private Long roleId;
@Schema(description = "第一条消息作为标题", requiredMode = Schema.RequiredMode.REQUIRED, example = "你好")
private String firstMsg;
}
package cn.iocoder.yudao.module.ai.controller.admin.agent.vo;
import io.swagger.v3.oas.annotations.media.Schema;
import lombok.Data;
@Schema(description = "管理后台 - Agent FeedBack Request VO")
@Data
public class AgentFeedBackReqVO {
@Schema(description = "智能体编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "32")
private Long roleId;
@Schema(description = "对话编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "1024")
private Long conversationId;
@Schema(description = "消息编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "1024")
private String messageId;
@Schema(description = "好反馈", example = "yes")
private String userGoodFeedback;
@Schema(description = "坏反馈", example = "回复效果差")
private String userBadFeedback;
}
......@@ -11,4 +11,10 @@ public class AgentMsgReqVO {
@Schema(description = "对话编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "1024")
private Long conversationId;
@Schema(description = "分页偏移", requiredMode = Schema.RequiredMode.REQUIRED, example = "0")
private Long offset;
@Schema(description = "分页大小", requiredMode = Schema.RequiredMode.REQUIRED, example = "10")
private Long pageSize;
}
......@@ -20,6 +20,9 @@ public class AgentUsedRespVO {
@Trans(type = TransType.SIMPLE, target = AiChatRoleDO.class, fields = {"name", "avatar"}, refs = {"roleName", "roleAvatar"})
private Long roleId;
@Schema(description = "对话标题", example = "你好")
private String title;
@Schema(description = "创建时间", requiredMode = Schema.RequiredMode.REQUIRED)
private LocalDateTime createTime;
......@@ -28,7 +31,7 @@ public class AgentUsedRespVO {
@Schema(description = "智能体头像", example = "https://www.iocoder.cn/1.png")
private String roleAvatar;
@Schema(description = "智能体名字", example = "小黄")
@Schema(description = "智能体名字", example = "政府PPT编制")
private String roleName;
}
......@@ -8,10 +8,7 @@ import cn.iocoder.yudao.framework.common.pojo.CommonResult;
import cn.iocoder.yudao.framework.common.pojo.PageResult;
import cn.iocoder.yudao.framework.common.util.collection.MapUtils;
import cn.iocoder.yudao.framework.common.util.object.BeanUtils;
import cn.iocoder.yudao.module.ai.controller.admin.chat.vo.message.AiChatMessagePageReqVO;
import cn.iocoder.yudao.module.ai.controller.admin.chat.vo.message.AiChatMessageRespVO;
import cn.iocoder.yudao.module.ai.controller.admin.chat.vo.message.AiChatMessageSendReqVO;
import cn.iocoder.yudao.module.ai.controller.admin.chat.vo.message.AiChatMessageSendRespVO;
import cn.iocoder.yudao.module.ai.controller.admin.chat.vo.message.*;
import cn.iocoder.yudao.module.ai.dal.dataobject.chat.AiChatConversationDO;
import cn.iocoder.yudao.module.ai.dal.dataobject.chat.AiChatMessageDO;
import cn.iocoder.yudao.module.ai.dal.dataobject.model.AiChatRoleDO;
......@@ -41,6 +38,8 @@ import java.net.MalformedURLException;
import java.util.Collections;
import java.util.List;
import java.util.Map;
import java.util.UUID;
import java.util.concurrent.ThreadLocalRandom;
import static cn.iocoder.yudao.framework.common.pojo.CommonResult.success;
import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.convertSet;
......@@ -83,13 +82,23 @@ public class AiChatMessageController {
public Flux<CommonResult<AiChatMessageSendRespVO>> sendChatMessageStream(@Valid @RequestBody AiChatMessageSendReqVO sendReqVO) throws MalformedURLException {
// 禁用ruoyi的上下文能力
sendReqVO.setUseContext(false);
String originalUrl = sendReqVO.getFileUrl();
if(originalUrl != null && originalUrl.contains("218.77.58.8")){
// 替换IP地址
String replacedUrl = originalUrl.replace("218.77.58.8", "192.168.252.71");
sendReqVO.setFileUrl(replacedUrl);
List<String> originalUrls = sendReqVO.getFileUrl();
if (originalUrls != null) {
for (int i = 0; i < originalUrls.size(); i++) {
String originalUrl = originalUrls.get(i);
if (originalUrl != null && originalUrl.contains("218.77.58.8")) {
// 替换IP地址
String replacedUrl = originalUrl.replace("218.77.58.8", "192.168.252.71");
originalUrls.set(i, replacedUrl); // 更新列表中的URL
}
}
sendReqVO.setFileUrl(originalUrls); // 将更新后的列表重新设置到sendReqVO中
}
return chatMessageService.sendChatMessageStream(sendReqVO, getLoginUserId());
// 如果 responseChatId 为 null,则随机初始化一个 id
if (sendReqVO.getResponseChatItemId() == null) {
sendReqVO.setResponseChatItemId(generateBase62UniqueId(20));
}
return chatMessageService.sendChatMessageStream(sendReqVO, getLoginUserId(), originalUrls);
}
@Operation(summary = "获得指定对话的消息列表")
......@@ -147,4 +156,37 @@ public class AiChatMessageController {
return success(true);
}
@Operation(summary = "反馈", description = "反馈回复是否有用")
@PostMapping("/feedback")
@PreAuthorize("@ss.hasPermission('ai:chat-message:update')")
public CommonResult<Boolean> feedback(@Valid @RequestBody AiChatMessageFeedBackReqVO sendReqVO) {
chatMessageService.updateFeedback(sendReqVO);
return success(true);
}
private String generateBase62UniqueId(int length) {
// Base62 字符集(0-9, A-Z, a-z)
final String BASE62 = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz";
StringBuilder sb = new StringBuilder(length);
// 使用 UUID 作为随机源
UUID uuid = UUID.randomUUID();
long mostSignificantBits = uuid.getMostSignificantBits();
long leastSignificantBits = uuid.getLeastSignificantBits();
// 将 UUID 的 128 位数据转换为 Base62
for (int i = 0; i < length; i++) {
// 取随机位并映射到 Base62 字符集
long randomValue = ThreadLocalRandom.current().nextLong(62);
if (i < 11) {
randomValue = (mostSignificantBits >>> (i * 5)) & 0x3F; // 取 6 位
} else {
randomValue = (leastSignificantBits >>> ((i - 11) * 5)) & 0x3F; // 取 6 位
}
sb.append(BASE62.charAt((int) (randomValue % 62)));
}
return sb.toString();
}
}
package cn.iocoder.yudao.module.ai.controller.admin.chat.vo.message;
import cn.iocoder.yudao.framework.ai.core.model.fastgpt.FastGPTOptions;
import io.swagger.v3.oas.annotations.media.Schema;
import jakarta.validation.constraints.NotNull;
import lombok.Data;
import java.util.List;
@Schema(description = "管理后台 - AI 聊天消息反馈")
@Data
public class AiChatMessageFeedBackReqVO {
@Schema(description = "消息编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "1024")
@NotNull(message = "消息编号不能为空")
private Long id;
@Schema(description = "反馈内容", example = "回答不准确")
// @NotEmpty(message = "聊天内容不能为空")
private String fdContent;
@Schema(description = "是否有用", example = "true")
private Boolean useful;
}
......@@ -4,6 +4,7 @@ import io.swagger.v3.oas.annotations.media.Schema;
import lombok.Data;
import java.time.LocalDateTime;
import java.util.List;
@Schema(description = "管理后台 - AI 聊天消息 Response VO")
@Data
......@@ -47,4 +48,13 @@ public class AiChatMessageRespVO {
@Schema(description = "角色名字", example = "小黄")
private String roleName;
@Schema(description = "对话文件列表")
private List<String> fileUrls;
@Schema(description = "是否有用")
private Boolean useful;
@Schema(description = "反馈内容")
private String fdContent;
}
......@@ -8,6 +8,8 @@ import jakarta.validation.constraints.Size;
import lombok.Data;
import lombok.experimental.Accessors;
import java.util.List;
@Schema(description = "管理后台 - AI 聊天消息发送 Request VO")
@Data
public class AiChatMessageSendReqVO {
......@@ -23,10 +25,15 @@ public class AiChatMessageSendReqVO {
@Schema(description = "是否携带上下文", example = "true")
private Boolean useContext;
// @Schema(description = "文件路径")
// private String fileUrl;
@Schema(description = "文件路径")
private String fileUrl;
private List<String> fileUrl;
@Schema(description = "变量")
private FastGPTOptions.Variables variables;
@Schema(description = "回复信息预设ID")
private String responseChatItemId;
}
......@@ -31,6 +31,9 @@ public class AiChatMessageSendRespVO {
@Schema(description = "创建时间", requiredMode = Schema.RequiredMode.REQUIRED)
private LocalDateTime createTime;
@Schema(description = "消息编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "1024")
private String chatItemId;
}
}
package cn.iocoder.yudao.module.ai.dal.dataobject.chat;
import com.baomidou.mybatisplus.annotation.TableField;
import com.baomidou.mybatisplus.annotation.TableId;
import com.baomidou.mybatisplus.extension.handlers.JacksonTypeHandler;
import org.springframework.ai.chat.messages.MessageType;
import cn.iocoder.yudao.framework.mybatis.core.dataobject.BaseDO;
import cn.iocoder.yudao.module.ai.dal.dataobject.model.AiChatModelDO;
......@@ -9,13 +11,15 @@ import com.baomidou.mybatisplus.annotation.KeySequence;
import com.baomidou.mybatisplus.annotation.TableName;
import lombok.*;
import java.util.List;
/**
* AI Chat 消息 DO
*
* @since 2024/4/14 17:35
* @since 2024/4/14 17:35
*/
@TableName("ai_chat_message")
@TableName(value = "ai_chat_message", autoResultMap = true)
@KeySequence("ai_chat_conversation_seq") // 用于 Oracle、PostgreSQL、Kingbase、DB2、H2 数据库的主键自增。如果是 MySQL 等数据库,可不写。
@Data
@EqualsAndHashCode(callSuper = true)
......@@ -87,4 +91,20 @@ public class AiChatMessageDO extends BaseDO {
*/
private Boolean useContext;
/**
* 文件链接
*/
@TableField(typeHandler = JacksonTypeHandler.class)
private List<String> fileUrls;
/**
* 是否有用
*/
private Boolean useful;
/**
* 反馈内容
*/
private String fdContent;
}
......@@ -6,12 +6,13 @@ import cn.iocoder.yudao.framework.common.pojo.PageResult;
import cn.iocoder.yudao.framework.common.util.collection.CollectionUtils;
import cn.iocoder.yudao.framework.mybatis.core.mapper.BaseMapperX;
import cn.iocoder.yudao.framework.mybatis.core.query.LambdaQueryWrapperX;
import cn.iocoder.yudao.module.ai.controller.admin.chat.vo.conversation.AiChatConversationPageReqVO;
import cn.iocoder.yudao.module.ai.controller.admin.chat.vo.message.AiChatMessagePageReqVO;
import cn.iocoder.yudao.module.ai.dal.dataobject.chat.AiChatConversationDO;
import cn.iocoder.yudao.module.ai.dal.dataobject.chat.AiChatMessageDO;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import org.apache.ibatis.annotations.Mapper;
import org.apache.ibatis.annotations.Param;
import org.apache.ibatis.annotations.Select;
import java.util.Collection;
import java.util.Collections;
......@@ -47,14 +48,31 @@ public interface AiChatMessageMapper extends BaseMapperX<AiChatMessageDO> {
record -> MapUtil.getInt(record, "count" ));
}
default PageResult<AiChatMessageDO> selectPage(AiChatMessagePageReqVO pageReqVO) {
return selectPage(pageReqVO, new LambdaQueryWrapperX<AiChatMessageDO>()
.eqIfPresent(AiChatMessageDO::getConversationId, pageReqVO.getConversationId())
.eqIfPresent(AiChatMessageDO::getUserId, pageReqVO.getUserId())
.likeIfPresent(AiChatMessageDO::getContent, pageReqVO.getContent())
.betweenIfPresent(AiChatMessageDO::getCreateTime, pageReqVO.getCreateTime())
.orderByDesc(AiChatMessageDO::getId));
}
// default PageResult<AiChatMessageDO> selectPage(AiChatMessagePageReqVO pageReqVO) {
// return selectPage(pageReqVO, new LambdaQueryWrapperX<AiChatMessageDO>()
// .eqIfPresent(AiChatMessageDO::getConversationId, pageReqVO.getConversationId())
// .eqIfPresent(AiChatMessageDO::getUserId, pageReqVO.getUserId())
// .likeIfPresent(AiChatMessageDO::getContent, pageReqVO.getContent())
// .betweenIfPresent(AiChatMessageDO::getCreateTime, pageReqVO.getCreateTime())
// .orderByDesc(AiChatMessageDO::getId));
// }
/**
* 分页查询,忽略逻辑删除的过滤条件
*/
@Select({
"<script>",
"SELECT * FROM ai_chat_message",
"<where>",
" <if test='req.conversationId != null'> AND conversation_id = #{req.conversationId} </if>",
" <if test='req.userId != null'> AND user_id = #{req.userId} </if>",
" <if test='req.content != null'> AND content LIKE CONCAT('%', #{req.content}, '%') </if>",
" <if test='req.createTime != null'> AND create_time BETWEEN #{req.createTime[0]} AND #{req.createTime[1]} </if>",
"</where>",
"ORDER BY id DESC",
"</script>"
})
IPage<AiChatMessageDO> selectPage(@Param("page") IPage<AiChatMessageDO> page, @Param("req") AiChatMessagePageReqVO pageReqVO);
default Long selectCounts(Long conId){
return selectCount(new LambdaQueryWrapperX<AiChatMessageDO>()
......
......@@ -169,17 +169,17 @@ public class AiChatConversationServiceImpl implements AiChatConversationService
Assert.notNull(model, "智能体未配置推理模型");
validateChatModel(model);
AiChatConversationDO conversationExist= chatConversationMapper.selectByRoleAndUserId(createReqVO.getRoleId(), userId);
if(conversationExist != null){
return conversationExist.getId();
}
// AiChatConversationDO conversationExist= chatConversationMapper.selectByRoleAndUserId(createReqVO.getRoleId(), userId);
// if(conversationExist != null){
// return conversationExist.getId();
// }
// 2. 创建 AiChatConversationDO 聊天对话
AiChatConversationDO conversation = new AiChatConversationDO().setUserId(userId).setPinned(false)
.setModelId(model.getId()).setModel(model.getModel())
.setTemperature(model.getTemperature()).setMaxTokens(model.getMaxTokens()).setMaxContexts(model.getMaxContexts());
if (role != null) {
conversation.setTitle(role.getName()).setRoleId(role.getId()).setSystemMessage(role.getSystemMessage());
conversation.setTitle(createReqVO.getFirstMsg()).setRoleId(role.getId()).setSystemMessage(role.getSystemMessage());
} else {
conversation.setTitle(AiChatConversationDO.TITLE_DEFAULT);
}
......
......@@ -2,6 +2,7 @@ package cn.iocoder.yudao.module.ai.service.chat;
import cn.iocoder.yudao.framework.common.pojo.CommonResult;
import cn.iocoder.yudao.framework.common.pojo.PageResult;
import cn.iocoder.yudao.module.ai.controller.admin.chat.vo.message.AiChatMessageFeedBackReqVO;
import cn.iocoder.yudao.module.ai.controller.admin.chat.vo.message.AiChatMessagePageReqVO;
import cn.iocoder.yudao.module.ai.controller.admin.chat.vo.message.AiChatMessageSendReqVO;
import cn.iocoder.yudao.module.ai.controller.admin.chat.vo.message.AiChatMessageSendRespVO;
......@@ -36,7 +37,7 @@ public interface AiChatMessageService {
* @param userId 用户编号
* @return 发送结果
*/
Flux<CommonResult<AiChatMessageSendRespVO>> sendChatMessageStream(AiChatMessageSendReqVO sendReqVO, Long userId) throws MalformedURLException;
Flux<CommonResult<AiChatMessageSendRespVO>> sendChatMessageStream(AiChatMessageSendReqVO sendReqVO, Long userId, List<String> originalUrls) throws MalformedURLException;
/**
* 获得指定对话的消息列表
......@@ -62,6 +63,8 @@ public interface AiChatMessageService {
*/
void deleteChatMessageByConversationId(Long conversationId, Long userId);
boolean checkMsgExist(Long conversationId);
/**
* 【管理员】删除消息
*
......@@ -85,4 +88,5 @@ public interface AiChatMessageService {
*/
PageResult<AiChatMessageDO> getChatMessagePage(AiChatMessagePageReqVO pageReqVO);
void updateFeedback(AiChatMessageFeedBackReqVO sendReqVO);
}
......@@ -9,8 +9,8 @@ import cn.iocoder.yudao.framework.common.pojo.CommonResult;
import cn.iocoder.yudao.framework.common.pojo.PageResult;
import cn.iocoder.yudao.framework.common.util.object.BeanUtils;
import cn.iocoder.yudao.framework.tenant.core.util.TenantUtils;
import cn.iocoder.yudao.module.ai.controller.admin.chat.vo.conversation.AiChatConversationRespVO;
import cn.iocoder.yudao.module.ai.controller.admin.chat.vo.conversation.AiChatConversationUpdateMyReqVO;
import cn.iocoder.yudao.module.ai.controller.admin.chat.vo.message.AiChatMessageFeedBackReqVO;
import cn.iocoder.yudao.module.ai.controller.admin.chat.vo.message.AiChatMessagePageReqVO;
import cn.iocoder.yudao.module.ai.controller.admin.chat.vo.message.AiChatMessageSendReqVO;
import cn.iocoder.yudao.module.ai.controller.admin.chat.vo.message.AiChatMessageSendRespVO;
......@@ -21,6 +21,8 @@ import cn.iocoder.yudao.module.ai.dal.mysql.chat.AiChatMessageMapper;
import cn.iocoder.yudao.module.ai.enums.ErrorCodeConstants;
import cn.iocoder.yudao.module.ai.service.model.AiApiKeyService;
import cn.iocoder.yudao.module.ai.service.model.AiChatModelService;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import jakarta.annotation.Resource;
import lombok.extern.slf4j.Slf4j;
import org.springframework.ai.chat.messages.*;
......@@ -29,8 +31,6 @@ import org.springframework.ai.chat.model.ChatResponse;
import org.springframework.ai.chat.model.StreamingChatModel;
import org.springframework.ai.chat.prompt.ChatOptions;
import org.springframework.ai.chat.prompt.Prompt;
import org.springframework.core.io.ClassPathResource;
import org.springframework.core.io.FileUrlResource;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.MimeTypeUtils;
......@@ -81,11 +81,11 @@ public class AiChatMessageServiceImpl implements AiChatMessageService {
// 2. 插入 user 发送消息
AiChatMessageDO userMessage = createChatMessage(conversation.getId(), null, model,
userId, conversation.getRoleId(), MessageType.USER, sendReqVO.getContent(), sendReqVO.getUseContext());
userId, conversation.getRoleId(), MessageType.USER, sendReqVO.getContent(), sendReqVO.getUseContext(), sendReqVO.getFileUrl());
// 3.1 插入 assistant 接收消息
AiChatMessageDO assistantMessage = createChatMessage(conversation.getId(), userMessage.getId(), model,
userId, conversation.getRoleId(), MessageType.ASSISTANT, "", sendReqVO.getUseContext());
userId, conversation.getRoleId(), MessageType.ASSISTANT, "", sendReqVO.getUseContext(), sendReqVO.getFileUrl());
// 3.2 创建 chat 需要的 Prompt
Prompt prompt = buildPrompt(conversation, historyMessages, model, sendReqVO);
......@@ -99,7 +99,7 @@ public class AiChatMessageServiceImpl implements AiChatMessageService {
}
@Override
public Flux<CommonResult<AiChatMessageSendRespVO>> sendChatMessageStream(AiChatMessageSendReqVO sendReqVO, Long userId) throws MalformedURLException {
public Flux<CommonResult<AiChatMessageSendRespVO>> sendChatMessageStream(AiChatMessageSendReqVO sendReqVO, Long userId, List<String> originalUrls) throws MalformedURLException {
// 1.1 校验对话存在
AiChatConversationDO conversation = chatConversationService.validateChatConversationExists(sendReqVO.getConversationId());
if (ObjUtil.notEqual(conversation.getUserId(), userId)) {
......@@ -112,13 +112,14 @@ public class AiChatMessageServiceImpl implements AiChatMessageService {
// 2. 插入 user 发送消息
Long count = chatMessageMapper.selectCounts(conversation.getId());
if(count == 0 && Objects.equals(conversation.getTitle(), AiChatConversationDO.TITLE_DEFAULT)){
if(count == 0){
// if(count == 0 && Objects.equals(conversation.getTitle(), AiChatConversationDO.TITLE_DEFAULT)){
AiChatConversationUpdateMyReqVO updateMyReq = BeanUtils.toBean(conversation, AiChatConversationUpdateMyReqVO.class);
updateMyReq.setTitle(sendReqVO.getContent());
chatConversationService.updateChatConversationMy(updateMyReq, userId);
}
AiChatMessageDO userMessage = createChatMessage(conversation.getId(), null, model,
userId, conversation.getRoleId(), MessageType.USER, sendReqVO.getContent(), sendReqVO.getUseContext());
userId, conversation.getRoleId(), MessageType.USER, sendReqVO.getContent(), sendReqVO.getUseContext(), originalUrls);
// 3.1 插入 assistant 接收消息
// AiChatMessageDO assistantMessage = createChatMessage(conversation.getId(), userMessage.getId(), model,
......@@ -141,7 +142,7 @@ public class AiChatMessageServiceImpl implements AiChatMessageService {
contentBuffer.append(newContent);
// 响应结果
return success(new AiChatMessageSendRespVO().setSend(BeanUtils.toBean(userMessage, AiChatMessageSendRespVO.Message.class))
.setReceive(BeanUtils.toBean(assistantMessage, AiChatMessageSendRespVO.Message.class).setContent(newContent)));
.setReceive(BeanUtils.toBean(assistantMessage, AiChatMessageSendRespVO.Message.class).setContent(newContent).setChatItemId(sendReqVO.getResponseChatItemId())));
}).doOnComplete(() -> {
// 忽略租户,因为 Flux 异步无法透传租户
// TenantUtils.executeIgnore(() -> chatMessageMapper.updateById(new AiChatMessageDO().setId(assistantMessage.getId()).setContent(contentBuffer.toString())));
......@@ -174,8 +175,18 @@ public class AiChatMessageServiceImpl implements AiChatMessageService {
contextMessages.forEach(message -> chatMessages.add(AiUtils.buildMessage(message.getType(), message.getContent())));
// 1.3 user message 新发送消息
UserMessage send_message;
if(sendReqVO.getFileUrl() != null && !Objects.equals(sendReqVO.getFileUrl(), "")){
send_message = new UserMessage(sendReqVO.getContent(), new Media(MimeTypeUtils.TEXT_PLAIN, new URL(sendReqVO.getFileUrl())));
if(sendReqVO.getFileUrl() != null && !sendReqVO.getFileUrl().isEmpty()){
List<Media> mediaList = new ArrayList<>();
for (String fileUrl : sendReqVO.getFileUrl()) {
try {
mediaList.add(new Media(MimeTypeUtils.TEXT_PLAIN, new URL(fileUrl)));
} catch (MalformedURLException e) {
// 处理URL异常
e.printStackTrace();
}
}
send_message = new UserMessage(sendReqVO.getContent(), mediaList);
} else {
send_message = new UserMessage(sendReqVO.getContent());
}
......@@ -185,7 +196,7 @@ public class AiChatMessageServiceImpl implements AiChatMessageService {
// 2. 构建 ChatOptions 对象
AiPlatformEnum platform = AiPlatformEnum.validatePlatform(model.getPlatform());
ChatOptions chatOptions = AiUtils.buildChatOptions(platform, model.getModel(),
conversation.getTemperature(), conversation.getMaxTokens(), String.valueOf(conversation.getId()), sendReqVO.getVariables());
conversation.getTemperature(), conversation.getMaxTokens(), String.valueOf(conversation.getId()), sendReqVO.getVariables(), sendReqVO.getResponseChatItemId());
return new Prompt(chatMessages, chatOptions);
}
......@@ -230,10 +241,10 @@ public class AiChatMessageServiceImpl implements AiChatMessageService {
private AiChatMessageDO createChatMessage(Long conversationId, Long replyId,
AiChatModelDO model, Long userId, Long roleId,
MessageType messageType, String content, Boolean useContext) {
MessageType messageType, String content, Boolean useContext, List<String> fileUrls) {
AiChatMessageDO message = new AiChatMessageDO().setConversationId(conversationId).setReplyId(replyId)
.setModel(model.getModel()).setModelId(model.getId()).setUserId(userId).setRoleId(roleId)
.setType(messageType.getValue()).setContent(content).setUseContext(useContext);
.setType(messageType.getValue()).setContent(content).setUseContext(useContext).setFileUrls(fileUrls);
message.setCreateTime(LocalDateTime.now());
chatMessageMapper.insert(message);
return message;
......@@ -267,6 +278,13 @@ public class AiChatMessageServiceImpl implements AiChatMessageService {
}
@Override
public boolean checkMsgExist(Long conversationId) {
// 1. 校验消息存在
List<AiChatMessageDO> messages = chatMessageMapper.selectListByConversationId(conversationId);
return CollUtil.isEmpty(messages);
}
@Override
public void deleteChatMessageByAdmin(Long id) {
// 1. 校验消息存在
AiChatMessageDO message = chatMessageMapper.selectById(id);
......@@ -284,7 +302,26 @@ public class AiChatMessageServiceImpl implements AiChatMessageService {
@Override
public PageResult<AiChatMessageDO> getChatMessagePage(AiChatMessagePageReqVO pageReqVO) {
return chatMessageMapper.selectPage(pageReqVO);
// return chatMessageMapper.selectPage(pageReqVO);
// 创建分页对象
IPage<AiChatMessageDO> page = new Page<>(pageReqVO.getPageNo(), pageReqVO.getPageSize());
// 调用 Mapper 方法
IPage<AiChatMessageDO> resultPage = chatMessageMapper.selectPage(page, pageReqVO);
// 转换为 PageResult
return new PageResult<>(resultPage.getRecords(), resultPage.getTotal());
}
@Override
public void updateFeedback(AiChatMessageFeedBackReqVO sendReqVO) {
// 1. 校验消息存在
AiChatMessageDO message = chatMessageMapper.selectById(sendReqVO.getId());
if (message == null) {
throw exception(CHAT_MESSAGE_NOT_EXIST);
}
// 2. 执行更新
message.setUseful(sendReqVO.getUseful());
message.setFdContent(sendReqVO.getFdContent());
chatMessageMapper.updateById(message);
}
}
......@@ -108,7 +108,7 @@ public class AiMindMapServiceImpl implements AiMindMapService {
List<Message> chatMessages = buildMessages(generateReqVO, systemMessage);
// 2. 构建 options 对象
AiPlatformEnum platform = AiPlatformEnum.validatePlatform(model.getPlatform());
ChatOptions options = AiUtils.buildChatOptions(platform, model.getModel(), model.getTemperature(), model.getMaxTokens(), "", null);
ChatOptions options = AiUtils.buildChatOptions(platform, model.getModel(), model.getTemperature(), model.getMaxTokens(), "", null, "");
return new Prompt(chatMessages, options);
}
......
......@@ -126,7 +126,7 @@ public class AiWriteServiceImpl implements AiWriteService {
List<Message> chatMessages = buildMessages(generateReqVO, systemMessage);
// 2. 构建 options 对象
AiPlatformEnum platform = AiPlatformEnum.validatePlatform(model.getPlatform());
ChatOptions options = AiUtils.buildChatOptions(platform, model.getModel(), model.getTemperature(), model.getMaxTokens(), "", null);
ChatOptions options = AiUtils.buildChatOptions(platform, model.getModel(), model.getTemperature(), model.getMaxTokens(), "", null, "");
return new Prompt(chatMessages, options);
}
......
......@@ -113,28 +113,28 @@ public class FastGPTApi {
}
@JsonInclude(Include.NON_NULL)
public static record ChatCompletionRequest(List<ChatCompletionMessage> messages, String model, String chatId, FastGPTOptions.Variables variables, Float frequencyPenalty, Map<String, Integer> logitBias, Boolean logprobs, Integer topLogprobs, Integer maxTokens, Integer n, Float presencePenalty, ResponseFormat responseFormat, Integer seed, List<String> stop, Boolean stream, Float temperature, Float topP, List<FunctionTool> tools, Object toolChoice, String user) {
public static record ChatCompletionRequest(List<ChatCompletionMessage> messages, String model, String chatId, FastGPTOptions.Variables variables, String responseChatItemId, Float frequencyPenalty, Map<String, Integer> logitBias, Boolean logprobs, Integer topLogprobs, Integer maxTokens, Integer n, Float presencePenalty, ResponseFormat responseFormat, Integer seed, List<String> stop, Boolean stream, Float temperature, Float topP, List<FunctionTool> tools, Object toolChoice, String user) {
public ChatCompletionRequest(List<ChatCompletionMessage> messages, String model, Float temperature) {
this(messages, model, (String)null, (FastGPTOptions.Variables)null, (Float)null, (Map)null, (Boolean)null, (Integer)null, (Integer)null, (Integer)null, (Float)null, (ResponseFormat)null, (Integer)null, (List)null, false, temperature, (Float)null, (List)null, (Object)null, (String)null);
this(messages, model, (String)null, (FastGPTOptions.Variables)null, (String)null, (Float)null, (Map)null, (Boolean)null, (Integer)null, (Integer)null, (Integer)null, (Float)null, (ResponseFormat)null, (Integer)null, (List)null, false, temperature, (Float)null, (List)null, (Object)null, (String)null);
}
public ChatCompletionRequest(List<ChatCompletionMessage> messages, String model, Float temperature, boolean stream) {
this(messages, model, (String)null, (FastGPTOptions.Variables)null, (Float)null, (Map)null, (Boolean)null, (Integer)null, (Integer)null, (Integer)null, (Float)null, (ResponseFormat)null, (Integer)null, (List)null, stream, temperature, (Float)null, (List)null, (Object)null, (String)null);
this(messages, model, (String)null, (FastGPTOptions.Variables)null, (String)null, (Float)null, (Map)null, (Boolean)null, (Integer)null, (Integer)null, (Integer)null, (Float)null, (ResponseFormat)null, (Integer)null, (List)null, stream, temperature, (Float)null, (List)null, (Object)null, (String)null);
}
public ChatCompletionRequest(List<ChatCompletionMessage> messages, String model, List<FunctionTool> tools, Object toolChoice) {
this(messages, model, (String)null, (FastGPTOptions.Variables)null, (Float)null, (Map)null, (Boolean)null, (Integer)null, (Integer)null, (Integer)null, (Float)null, (ResponseFormat)null, (Integer)null, (List)null, false, 0.8F, (Float)null, tools, toolChoice, (String)null);
this(messages, model, (String)null, (FastGPTOptions.Variables)null, (String)null, (Float)null, (Map)null, (Boolean)null, (Integer)null, (Integer)null, (Integer)null, (Float)null, (ResponseFormat)null, (Integer)null, (List)null, false, 0.8F, (Float)null, tools, toolChoice, (String)null);
}
public ChatCompletionRequest(List<ChatCompletionMessage> messages, Boolean stream) {
this(messages, (String)null, (String)null, (FastGPTOptions.Variables)null, (Float)null, (Map)null, (Boolean)null, (Integer)null, (Integer)null, (Integer)null, (Float)null, (ResponseFormat)null, (Integer)null, (List)null, stream, (Float)null, (Float)null, (List)null, (Object)null, (String)null);
this(messages, (String)null, (String)null, (FastGPTOptions.Variables)null, (String)null, (Float)null, (Map)null, (Boolean)null, (Integer)null, (Integer)null, (Integer)null, (Float)null, (ResponseFormat)null, (Integer)null, (List)null, stream, (Float)null, (Float)null, (List)null, (Object)null, (String)null);
}
public ChatCompletionRequest(List<ChatCompletionMessage> messages, String model, String chatId, FastGPTOptions.Variables variables, Boolean stream) {
this(messages, model, chatId, variables, (Float)null, (Map)null, (Boolean)null, (Integer)null, (Integer)null, (Integer)null, (Float)null, (ResponseFormat)null, (Integer)null, (List)null, stream, (Float)null, (Float)null, (List)null, (Object)null, (String)null);
public ChatCompletionRequest(List<ChatCompletionMessage> messages, String model, String chatId, FastGPTOptions.Variables variables, String responseChatItemId, Boolean stream) {
this(messages, model, chatId, variables, responseChatItemId, (Float)null, (Map)null, (Boolean)null, (Integer)null, (Integer)null, (Integer)null, (Float)null, (ResponseFormat)null, (Integer)null, (List)null, stream, (Float)null, (Float)null, (List)null, (Object)null, (String)null);
}
public ChatCompletionRequest(@JsonProperty("messages") List<ChatCompletionMessage> messages, @JsonProperty("model") String model, @JsonProperty("chatId") String chatId, @JsonProperty("variables") FastGPTOptions.Variables variables, @JsonProperty("frequency_penalty") Float frequencyPenalty, @JsonProperty("logit_bias") Map<String, Integer> logitBias, @JsonProperty("logprobs") Boolean logprobs, @JsonProperty("top_logprobs") Integer topLogprobs, @JsonProperty("max_tokens") Integer maxTokens, @JsonProperty("n") Integer n, @JsonProperty("presence_penalty") Float presencePenalty, @JsonProperty("response_format") ResponseFormat responseFormat, @JsonProperty("seed") Integer seed, @JsonProperty("stop") List<String> stop, @JsonProperty("stream") Boolean stream, @JsonProperty("temperature") Float temperature, @JsonProperty("top_p") Float topP, @JsonProperty("tools") List<FunctionTool> tools, @JsonProperty("tool_choice") Object toolChoice, @JsonProperty("user") String user) {
public ChatCompletionRequest(@JsonProperty("messages") List<ChatCompletionMessage> messages, @JsonProperty("model") String model, @JsonProperty("chatId") String chatId, @JsonProperty("variables") FastGPTOptions.Variables variables, @JsonProperty("responseChatItemId") String responseChatItemId, @JsonProperty("frequency_penalty") Float frequencyPenalty, @JsonProperty("logit_bias") Map<String, Integer> logitBias, @JsonProperty("logprobs") Boolean logprobs, @JsonProperty("top_logprobs") Integer topLogprobs, @JsonProperty("max_tokens") Integer maxTokens, @JsonProperty("n") Integer n, @JsonProperty("presence_penalty") Float presencePenalty, @JsonProperty("response_format") ResponseFormat responseFormat, @JsonProperty("seed") Integer seed, @JsonProperty("stop") List<String> stop, @JsonProperty("stream") Boolean stream, @JsonProperty("temperature") Float temperature, @JsonProperty("top_p") Float topP, @JsonProperty("tools") List<FunctionTool> tools, @JsonProperty("tool_choice") Object toolChoice, @JsonProperty("user") String user) {
this.messages = messages;
this.model = model;
this.chatId = chatId;
......@@ -155,6 +155,7 @@ public class FastGPTApi {
this.tools = tools;
this.toolChoice = toolChoice;
this.user = user;
this.responseChatItemId = responseChatItemId;
}
@JsonProperty("messages")
......@@ -177,6 +178,11 @@ public class FastGPTApi {
return this.variables;
}
@JsonProperty("responseChatItemId")
public String responseChatItemId() {
return this.responseChatItemId;
}
@JsonProperty("frequency_penalty")
public Float frequencyPenalty() {
return this.frequencyPenalty;
......
......@@ -164,7 +164,7 @@ public class FastGPTChatModel extends AbstractFunctionCallSupport<FastGPTApi.Cha
Set<String> promptEnabledFunctions = this.handleFunctionCallbackConfigurations(updatedRuntimeOptions, true);
functionsForThisRequest.addAll(promptEnabledFunctions);
// request = (FastGPTApi.ChatCompletionRequest)ModelOptionsUtils.merge(updatedRuntimeOptions, request, FastGPTApi.ChatCompletionRequest.class);
request = new FastGPTApi.ChatCompletionRequest(chatCompletionMessages, updatedRuntimeOptions.getModel(), updatedRuntimeOptions.getChatId(), updatedRuntimeOptions.getVariables(), stream);
request = new FastGPTApi.ChatCompletionRequest(chatCompletionMessages, updatedRuntimeOptions.getModel(), updatedRuntimeOptions.getChatId(), updatedRuntimeOptions.getVariables(), updatedRuntimeOptions.getResponseChatItemId(), stream);
}
// if (this.defaultOptions != null) {
......
......@@ -65,6 +65,9 @@ public class FastGPTOptions implements FunctionCallingOptions, ChatOptions {
@JsonIgnore
private Set<String> functions = new HashSet();
@JsonProperty("responseChatItemId")
private String responseChatItemId;
@JsonInclude(Include.NON_NULL)
public static record Variables(String scenarios) {
public Variables(@JsonProperty("scenarios") String scenarios) {
......@@ -108,6 +111,14 @@ public class FastGPTOptions implements FunctionCallingOptions, ChatOptions {
this.chatId = chatId;
}
public String getResponseChatItemId() {
return this.responseChatItemId;
}
public void setResponseChatItemId(String responseChatItemId) {
this.responseChatItemId = responseChatItemId;
}
public Float getFrequencyPenalty() {
return this.frequencyPenalty;
}
......@@ -249,6 +260,7 @@ public class FastGPTOptions implements FunctionCallingOptions, ChatOptions {
int result = 1;
result = 31 * result + (this.model == null ? 0 : this.model.hashCode());
result = 31 * result + (this.chatId == null ? 0 : this.chatId.hashCode());
result = 31 * result + (this.responseChatItemId == null ? 0 : this.responseChatItemId.hashCode());
result = 31 * result + (this.frequencyPenalty == null ? 0 : this.frequencyPenalty.hashCode());
result = 31 * result + (this.logitBias == null ? 0 : this.logitBias.hashCode());
result = 31 * result + (this.logprobs == null ? 0 : this.logprobs.hashCode());
......@@ -290,6 +302,13 @@ public class FastGPTOptions implements FunctionCallingOptions, ChatOptions {
} else if (!this.chatId.equals(other.chatId)) {
return false;
}
if (this.responseChatItemId == null) {
if (other.responseChatItemId != null) {
return false;
}
} else if (!this.responseChatItemId.equals(other.responseChatItemId)) {
return false;
}
if (this.frequencyPenalty == null) {
if (other.frequencyPenalty != null) {
......@@ -555,5 +574,10 @@ public class FastGPTOptions implements FunctionCallingOptions, ChatOptions {
public FastGPTOptions build() {
return this.options;
}
public Builder withChatItemId(String responseChatItemId) {
this.options.responseChatItemId = responseChatItemId;
return this;
}
}
}
......@@ -21,7 +21,7 @@ import org.springframework.ai.zhipuai.ZhiPuAiChatOptions;
*/
public class AiUtils {
public static ChatOptions buildChatOptions(AiPlatformEnum platform, String model, Double temperature, Integer maxTokens, String chatId, FastGPTOptions.Variables variables) {
public static ChatOptions buildChatOptions(AiPlatformEnum platform, String model, Double temperature, Integer maxTokens, String chatId, FastGPTOptions.Variables variables, String chatItemId) {
Float temperatureF = temperature != null ? temperature.floatValue() : null;
//noinspection EnhancedSwitchMigration
switch (platform) {
......@@ -43,7 +43,7 @@ public class AiUtils {
case OLLAMA:
return OllamaOptions.create().withModel(model).withTemperature(temperatureF).withNumPredict(maxTokens);
case FAST_GPT:
return FastGPTOptions.builder().withModel(model).withTemperature(temperatureF).withMaxTokens(maxTokens).withChatId(chatId).withVariables(variables).build();
return FastGPTOptions.builder().withModel(model).withTemperature(temperatureF).withMaxTokens(maxTokens).withChatId(chatId).withVariables(variables).withChatItemId(chatItemId).build();
default:
throw new IllegalArgumentException(StrUtil.format("未知平台({})", platform));
}
......
......@@ -75,6 +75,7 @@ mybatis-plus:
# id-type: ASSIGN_ID # 分配 ID,默认使用雪花算法。注意,Oracle、PostgreSQL、Kingbase、DB2、H2 数据库时,需要去除实体类上的 @KeySequence 注解
logic-delete-value: 1 # 逻辑已删除值(默认为 1)
logic-not-delete-value: 0 # 逻辑未删除值(默认为 0)
logic-delete-field: deleted # 逻辑删除字段名
banner: false # 关闭控制台的 Banner 打印
type-aliases-package: ${yudao.info.base-package}.module.*.dal.dataobject
encryptor:
......
......@@ -17,6 +17,8 @@ export interface ChatMessageVO {
createTime: Date // 创建时间
roleAvatar: string // 角色头像
userAvatar: string // 创建时间
useful: boolean // 是否有用
fdContent: boolean // 反馈内容
}
// AI chat 聊天
......
......@@ -10,6 +10,8 @@ declare module 'vue' {
AddNode: typeof import('./../components/SimpleProcessDesigner/src/addNode.vue')['default']
AppLinkInput: typeof import('./../components/AppLinkInput/index.vue')['default']
AppLinkSelectDialog: typeof import('./../components/AppLinkInput/AppLinkSelectDialog.vue')['default']
'AutoComponents.d': typeof import('./auto-components.d.ts')['default']
'AutoImports.d': typeof import('./auto-imports.d.ts')['default']
Backtop: typeof import('./../components/Backtop/src/Backtop.vue')['default']
CardTitle: typeof import('./../components/Card/src/CardTitle.vue')['default']
ColorInput: typeof import('./../components/ColorInput/index.vue')['default']
......
......@@ -83,6 +83,12 @@
<dict-tag :type="DICT_TYPE.INFRA_BOOLEAN_STRING" :value="scope.row.useContext" />
</template>
</el-table-column>
<el-table-column label="是否有用" align="center" prop="useful" width="100">
<template #default="scope">
<dict-tag :type="DICT_TYPE.INFRA_BOOLEAN_STRING" :value="scope.row.useful" />
</template>
</el-table-column>
<el-table-column label="反馈内容" align="center" prop="fdContent" width="300" />
<el-table-column label="操作" align="center" fixed="right">
<template #default="scope">
<el-button
......
......@@ -13,14 +13,14 @@
:on-exceed="handleExceed"
:on-success="submitFormSuccess"
:http-request="httpRequest"
accept=".jpg, .png, .gif"
accept=""
drag
>
<i class="el-icon-upload"></i>
<div class="el-upload__text"> 将文件拖到此处,或 <em>点击上传</em></div>
<template #tip>
<div class="el-upload__tip" style="color: red">
提示:仅允许导入 jpg、png、gif 格式文件
提示:文件大小低于64M
</div>
</template>
</el-upload>
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or sign in to comment