AI:完善AI功能,封装阿里通义千问
hwmom-htk
xs 4 months ago
parent 1d77494d9d
commit 26a4ed046c

@ -11,8 +11,17 @@ import com.google.gson.GsonBuilder;
import com.google.gson.JsonArray; import com.google.gson.JsonArray;
import com.google.gson.JsonElement; import com.google.gson.JsonElement;
import com.google.gson.JsonObject; import com.google.gson.JsonObject;
import org.dromara.ai.domain.AiAsrRecord;
import org.dromara.ai.mapper.AiAsrRecordMapper;
import org.dromara.common.constant.HwMomAiConstants;
import org.dromara.common.core.utils.StringUtils;
import org.dromara.common.encrypt.utils.EncryptUtils;
import org.dromara.common.satoken.utils.LoginHelper;
import org.dromara.system.api.RemoteConfigService;
import org.slf4j.Logger; import org.slf4j.Logger;
import org.slf4j.LoggerFactory; import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service; import org.springframework.stereotype.Service;
import java.io.BufferedReader; import java.io.BufferedReader;
@ -20,6 +29,7 @@ import java.io.InputStreamReader;
import java.net.HttpURLConnection; import java.net.HttpURLConnection;
import java.net.URL; import java.net.URL;
import java.util.Arrays; import java.util.Arrays;
import java.util.Date;
import java.util.List; import java.util.List;
/** /**
@ -30,16 +40,23 @@ public class AliAsrServiceImpl implements AliAsrService {
private static final Logger logger = LoggerFactory.getLogger(AliAsrServiceImpl.class); private static final Logger logger = LoggerFactory.getLogger(AliAsrServiceImpl.class);
@Autowired
private AiAsrRecordMapper aiAsrRecordMapper;
// 从配置文件读取API Key // 从配置文件读取API Key
// @Value("${aliyun.asr.api-key}") @Value("${asr.aliyun.api-key}")
private String apiKey = "sk-ce77518fcbc54b2bbee2a7c793be6492"; private String apiKey;
// 临时文件存储路径 // 临时文件存储路径
// @Value("${file.upload.temp-dir}") // @Value("${file.upload.temp-dir}")
// private String tempDir; // private String tempDir;
// 模型名称 // 模型名称
private static final String MODEL_NAME = "sensevoice-v1"; // 从配置文件读取API Key
@Value("${asr.aliyun.model-name}")
private String modelName;
// private static final String MODEL_NAME = "sensevoice-v1";
// 语言提示 // 语言提示
private static final String[] LANGUAGE_HINTS = {"zh"}; private static final String[] LANGUAGE_HINTS = {"zh"};
@ -73,9 +90,13 @@ public class AliAsrServiceImpl implements AliAsrService {
public String recognizeSpeechByUrl(String audioUrl) { public String recognizeSpeechByUrl(String audioUrl) {
try { try {
// 构建识别参数 // 构建识别参数
if(StringUtils.isEmpty(apiKey) || StringUtils.isEmpty(modelName)){
throw new RuntimeException("请配置apiKey和modelName");
}
TranscriptionParam param = TranscriptionParam.builder() TranscriptionParam param = TranscriptionParam.builder()
.apiKey(apiKey) .apiKey(EncryptUtils.decryptByBase64(apiKey))
.model(MODEL_NAME) .model(modelName)
.fileUrls(Arrays.asList(audioUrl)) .fileUrls(Arrays.asList(audioUrl))
.parameter("language_hints", LANGUAGE_HINTS) .parameter("language_hints", LANGUAGE_HINTS)
.build(); .build();
@ -88,6 +109,15 @@ public class AliAsrServiceImpl implements AliAsrService {
logger.info("语音识别任务提交成功TaskId: {}", taskId); logger.info("语音识别任务提交成功TaskId: {}", taskId);
// 循环获取任务执行结果,直到任务结束 // 循环获取任务执行结果,直到任务结束
//保存语音识别记录
AiAsrRecord aiAsrRecord = new AiAsrRecord();
aiAsrRecord.setModelName(modelName);
aiAsrRecord.setAsrFileUrl(audioUrl);
aiAsrRecord.setTenantId(LoginHelper.getTenantId());
aiAsrRecord.setCreateBy(LoginHelper.getUserId());
aiAsrRecord.setCreateDept(LoginHelper.getDeptId());
aiAsrRecord.setCreateTime(new Date());
while (true) { while (true) {
result = transcription.fetch(TranscriptionQueryParam.FromTranscriptionParam(param, taskId)); result = transcription.fetch(TranscriptionQueryParam.FromTranscriptionParam(param, taskId));
@ -95,6 +125,10 @@ public class AliAsrServiceImpl implements AliAsrService {
logger.info("语音识别任务完成TaskId: {}", taskId); logger.info("语音识别任务完成TaskId: {}", taskId);
break; break;
} else if (result.getTaskStatus() == TaskStatus.FAILED) { } else if (result.getTaskStatus() == TaskStatus.FAILED) {
aiAsrRecord.setAsrFailedReason(result.getResults().toString());
aiAsrRecord.setTaskId(taskId);
aiAsrRecord.setAsrResult(HwMomAiConstants.AI_ASR_RESULT_FAILED);
aiAsrRecordMapper.insert(aiAsrRecord);
logger.error("语音识别任务失败TaskId: {}, 错误信息: {}", taskId, result.getResults().toString()); logger.error("语音识别任务失败TaskId: {}, 错误信息: {}", taskId, result.getResults().toString());
throw new RuntimeException("语音识别任务失败: " + result.getResults().toString()); throw new RuntimeException("语音识别任务失败: " + result.getResults().toString());
} }
@ -104,7 +138,13 @@ public class AliAsrServiceImpl implements AliAsrService {
} }
// 解析识别结果 // 解析识别结果
return parseRecognitionResult(result); String recognitionResult = parseRecognitionResult(result);
aiAsrRecord.setAsrContent(recognitionResult);
aiAsrRecord.setAsrResult(HwMomAiConstants.AI_ASR_RESULT_SUCCESS);
aiAsrRecordMapper.insert(aiAsrRecord);
return recognitionResult;
} catch (Exception e) { } catch (Exception e) {
logger.error("语音识别过程发生错误", e); logger.error("语音识别过程发生错误", e);

@ -0,0 +1,117 @@
package org.dromara.ai.controller;
import java.util.List;
import lombok.RequiredArgsConstructor;
import jakarta.servlet.http.HttpServletResponse;
import jakarta.validation.constraints.*;
import cn.dev33.satoken.annotation.SaCheckPermission;
import org.springframework.web.bind.annotation.*;
import org.springframework.validation.annotation.Validated;
import org.dromara.common.idempotent.annotation.RepeatSubmit;
import org.dromara.common.log.annotation.Log;
import org.dromara.common.web.core.BaseController;
import org.dromara.common.mybatis.core.page.PageQuery;
import org.dromara.common.core.domain.R;
import org.dromara.common.core.validate.AddGroup;
import org.dromara.common.core.validate.EditGroup;
import org.dromara.common.log.enums.BusinessType;
import org.dromara.common.excel.utils.ExcelUtil;
import org.dromara.ai.domain.vo.AiAsrRecordVo;
import org.dromara.ai.domain.bo.AiAsrRecordBo;
import org.dromara.ai.service.IAiAsrRecordService;
import org.dromara.common.mybatis.core.page.TableDataInfo;
/**
* AI
* 访:/ai/asrRecord
*
* @author xins
* @date 2025-10-13
*/
@Validated
@RequiredArgsConstructor
@RestController
@RequestMapping("/asrRecord")
public class AiAsrRecordController extends BaseController {
private final IAiAsrRecordService aiAsrRecordService;
/**
* AI
*/
@SaCheckPermission("ai:asrRecord:list")
@GetMapping("/list")
public TableDataInfo<AiAsrRecordVo> list(AiAsrRecordBo bo, PageQuery pageQuery) {
return aiAsrRecordService.queryPageList(bo, pageQuery);
}
/**
* AI
*/
@SaCheckPermission("ai:asrRecord:export")
@Log(title = "AI语音识别记录", businessType = BusinessType.EXPORT)
@PostMapping("/export")
public void export(AiAsrRecordBo bo, HttpServletResponse response) {
List<AiAsrRecordVo> list = aiAsrRecordService.queryList(bo);
ExcelUtil.exportExcel(list, "AI语音识别记录", AiAsrRecordVo.class, response);
}
/**
* AI
*
* @param asrRecordId
*/
@SaCheckPermission("ai:asrRecord:query")
@GetMapping("/{asrRecordId}")
public R<AiAsrRecordVo> getInfo(@NotNull(message = "主键不能为空")
@PathVariable Long asrRecordId) {
return R.ok(aiAsrRecordService.queryById(asrRecordId));
}
/**
* AI
*/
@SaCheckPermission("ai:asrRecord:add")
@Log(title = "AI语音识别记录", businessType = BusinessType.INSERT)
@RepeatSubmit()
@PostMapping()
public R<Void> add(@Validated(AddGroup.class) @RequestBody AiAsrRecordBo bo) {
return toAjax(aiAsrRecordService.insertByBo(bo));
}
/**
* AI
*/
@SaCheckPermission("ai:asrRecord:edit")
@Log(title = "AI语音识别记录", businessType = BusinessType.UPDATE)
@RepeatSubmit()
@PutMapping()
public R<Void> edit(@Validated(EditGroup.class) @RequestBody AiAsrRecordBo bo) {
return toAjax(aiAsrRecordService.updateByBo(bo));
}
/**
* AI
*
* @param asrRecordIds
*/
@SaCheckPermission("ai:asrRecord:remove")
@Log(title = "AI语音识别记录", businessType = BusinessType.DELETE)
@DeleteMapping("/{asrRecordIds}")
public R<Void> remove(@NotEmpty(message = "主键不能为空")
@PathVariable Long[] asrRecordIds) {
return toAjax(aiAsrRecordService.deleteWithValidByIds(List.of(asrRecordIds), true));
}
/**
* AI
*/
@GetMapping("/getAiAsrRecordList")
public R<List<AiAsrRecordVo>> getAiAsrRecordList(AiAsrRecordBo bo) {
List<AiAsrRecordVo> list = aiAsrRecordService.queryList(bo);
return R.ok(list);
}
}

@ -0,0 +1,107 @@
package org.dromara.ai.domain;
import com.fasterxml.jackson.annotation.JsonIgnore;
import com.fasterxml.jackson.annotation.JsonInclude;
import org.dromara.common.tenant.core.TenantEntity;
import com.baomidou.mybatisplus.annotation.*;
import lombok.Data;
import lombok.EqualsAndHashCode;
import java.io.Serial;
import java.io.Serializable;
import java.util.Date;
import java.util.HashMap;
import java.util.Map;
/**
* AI ai_asr_record
*
* @author xins
* @date 2025-10-13
*/
@Data
@TableName("ai_asr_record")
public class AiAsrRecord implements Serializable {
@Serial
private static final long serialVersionUID = 1L;
/**
* ID
*/
@TableId(value = "asr_record_id", type = IdType.AUTO)
private Long asrRecordId;
/**
* AIIDai_platform
*/
private Long platformId;
/**
*
*/
private String modelName;
/**
*
*/
private String asrFileUrl;
/**
* ID
*/
private String taskId;
/**
*
*/
private String asrContent;
/**
* (10)
*/
private String asrResult;
/**
*
*/
private String asrFailedReason;
/**
*
*/
private String tenantId;
/**
*
*/
@JsonIgnore
@TableField(exist = false)
private String searchValue;
/**
*
*/
@TableField(fill = FieldFill.INSERT)
private Long createDept;
/**
*
*/
@TableField(fill = FieldFill.INSERT)
private Long createBy;
/**
*
*/
@TableField(fill = FieldFill.INSERT)
private Date createTime;
/**
*
*/
@JsonInclude(JsonInclude.Include.NON_EMPTY)
@TableField(exist = false)
private Map<String, Object> params = new HashMap<>();
}

@ -0,0 +1,68 @@
package org.dromara.ai.domain.bo;
import com.alibaba.excel.annotation.ExcelProperty;
import org.dromara.ai.domain.AiAsrRecord;
import org.dromara.common.mybatis.core.domain.BaseEntity;
import org.dromara.common.core.validate.AddGroup;
import org.dromara.common.core.validate.EditGroup;
import io.github.linpeilie.annotations.AutoMapper;
import lombok.Data;
import lombok.EqualsAndHashCode;
import jakarta.validation.constraints.*;
/**
* AI ai_asr_record
*
* @author xins
* @date 2025-10-13
*/
@Data
@EqualsAndHashCode(callSuper = true)
@AutoMapper(target = AiAsrRecord.class, reverseConvertGenerate = false)
public class AiAsrRecordBo extends BaseEntity {
/**
* ID
*/
private Long asrRecordId;
/**
* AIIDai_platform
*/
private Long platformId;
/**
*
*/
@ExcelProperty(value = "模型名称")
@NotBlank(message = "模型名称不能为空", groups = { AddGroup.class, EditGroup.class })
private String modelName;
/**
*
*/
private String asrFileUrl;
/**
* ID
*/
private String taskId;
/**
*
*/
private String asrContent;
/**
* (10)
*/
@NotBlank(message = "识别结果(1成功0失败)不能为空", groups = { AddGroup.class, EditGroup.class })
private String asrResult;
/**
*
*/
private String asrFailedReason;
}

@ -0,0 +1,80 @@
package org.dromara.ai.domain.vo;
import org.dromara.ai.domain.AiAsrRecord;
import com.alibaba.excel.annotation.ExcelIgnoreUnannotated;
import com.alibaba.excel.annotation.ExcelProperty;
import org.dromara.common.excel.annotation.ExcelDictFormat;
import org.dromara.common.excel.convert.ExcelDictConvert;
import io.github.linpeilie.annotations.AutoMapper;
import lombok.Data;
import java.io.Serial;
import java.io.Serializable;
import java.util.Date;
/**
* AI ai_asr_record
*
* @author xins
* @date 2025-10-13
*/
@Data
@ExcelIgnoreUnannotated
@AutoMapper(target = AiAsrRecord.class)
public class AiAsrRecordVo implements Serializable {
@Serial
private static final long serialVersionUID = 1L;
/**
* ID
*/
@ExcelProperty(value = "记录ID主键")
private Long asrRecordId;
/**
* AIIDai_platform
*/
@ExcelProperty(value = "AI平台ID")
private Long platformId;
/**
*
*/
@ExcelProperty(value = "模型名称")
private String modelName;
/**
*
*/
@ExcelProperty(value = "语音识别文件地址")
private String asrFileUrl;
/**
* ID
*/
@ExcelProperty(value = "任务ID")
private String taskId;
/**
*
*/
@ExcelProperty(value = "语音识别内容")
private String asrContent;
/**
* (10)
*/
@ExcelProperty(value = "识别结果(1成功0失败)")
private String asrResult;
/**
*
*/
@ExcelProperty(value = "识别失败原因")
private String asrFailedReason;
}

@ -0,0 +1,15 @@
package org.dromara.ai.mapper;
import org.dromara.ai.domain.AiAsrRecord;
import org.dromara.ai.domain.vo.AiAsrRecordVo;
import org.dromara.common.mybatis.core.mapper.BaseMapperPlus;
/**
* AIMapper
*
* @author xins
* @date 2025-10-13
*/
public interface AiAsrRecordMapper extends BaseMapperPlus<AiAsrRecord, AiAsrRecordVo> {
}

@ -25,5 +25,10 @@ public class AIMessage {
* *
*/ */
private Long timestamp; private Long timestamp;
/**
* AIID
*/
private Long modelId;
} }

@ -96,8 +96,11 @@ public interface IUnifiedAIProviderProcessor {
* @param takeFlag * @param takeFlag
* @param completeFlag * @param completeFlag
* @param userId * @param userId
* @param tenantId
* @param deptId
*/ */
public void saveTokenUsage(String messageDetailType, String questionContent, String answerContent, TokenUsage tokenUsage, public void saveTokenUsage(String messageDetailType, String questionContent, String answerContent, TokenUsage tokenUsage,
Long modelId, Long knowledgeBaseId, Long knowledgeContentId, Long modelId, Long knowledgeBaseId, Long knowledgeContentId,
Long chatMessageId,String sessionId,String takeFlag,String completeFlag,Long userId); Long chatMessageId,String sessionId,String takeFlag,String completeFlag,
Long userId,String tenantId,Long deptId);
} }

@ -9,8 +9,10 @@ import com.github.yulichang.wrapper.MPJLambdaWrapper;
import org.dromara.ai.domain.AiChatMessage; import org.dromara.ai.domain.AiChatMessage;
import org.dromara.ai.domain.AiChatMessageDetail; import org.dromara.ai.domain.AiChatMessageDetail;
import org.dromara.ai.domain.AiTokenUsage; import org.dromara.ai.domain.AiTokenUsage;
import org.dromara.ai.domain.vo.AiModelVo;
import org.dromara.ai.mapper.AiChatMessageDetailMapper; import org.dromara.ai.mapper.AiChatMessageDetailMapper;
import org.dromara.ai.mapper.AiChatMessageMapper; import org.dromara.ai.mapper.AiChatMessageMapper;
import org.dromara.ai.mapper.AiModelMapper;
import org.dromara.ai.mapper.AiTokenUsageMapper; import org.dromara.ai.mapper.AiTokenUsageMapper;
import org.dromara.ai.process.dto.AIMessage; import org.dromara.ai.process.dto.AIMessage;
import org.dromara.ai.process.dto.AIRequest; import org.dromara.ai.process.dto.AIRequest;
@ -20,6 +22,7 @@ import org.dromara.ai.process.enums.AIChatMessageTypeEnum;
import org.dromara.ai.process.provider.processor.IUnifiedAIProviderProcessor; import org.dromara.ai.process.provider.processor.IUnifiedAIProviderProcessor;
import org.dromara.ai.test.ChatRequest; import org.dromara.ai.test.ChatRequest;
import org.dromara.common.constant.HwMomAiConstants; import org.dromara.common.constant.HwMomAiConstants;
import org.dromara.common.encrypt.utils.EncryptUtils;
import org.dromara.common.satoken.utils.LoginHelper; import org.dromara.common.satoken.utils.LoginHelper;
import org.dromara.system.api.model.LoginUser; import org.dromara.system.api.model.LoginUser;
import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Autowired;
@ -50,6 +53,8 @@ public abstract class BaseAIProviderProcessor implements IUnifiedAIProviderProce
private AiChatMessageDetailMapper aiChatMessageDetailMapper; private AiChatMessageDetailMapper aiChatMessageDetailMapper;
@Autowired @Autowired
private AiTokenUsageMapper aiTokenUsageMapper; private AiTokenUsageMapper aiTokenUsageMapper;
@Autowired
private AiModelMapper aiModelMapper;
// 用于解析流式JSON块的模式 // 用于解析流式JSON块的模式
private static final Pattern JSON_PATTERN = Pattern.compile("\\{(?:[^{}]|\\{(?:[^{}]|\\{[^{}]*\\})*\\})*\\}"); private static final Pattern JSON_PATTERN = Pattern.compile("\\{(?:[^{}]|\\{(?:[^{}]|\\{[^{}]*\\})*\\})*\\}");
@ -82,34 +87,18 @@ public abstract class BaseAIProviderProcessor implements IUnifiedAIProviderProce
} }
} }
/** protected void configureApiKey(AIRequest request) {
* JSON if(request.getModelId()!=null){
*/ AiModelVo aiModelVo = aiModelMapper.selectVoById(request.getModelId());
protected abstract String extractContentFromStreamJson(String jsonChunk) throws Exception; if (aiModelVo != null) {
if (aiModelVo.getApiKey() == null) {
/** throw new RuntimeException("请设置AI模型的API Key");
* JSON }
*/ request.setApiKey(EncryptUtils.decryptByBase64(aiModelVo.getApiKey()));
protected abstract AIResponse extractAIResponse(String json) throws Exception; }
/**
* SSEJSON
*/
protected Flux<String> extractJsonChunks(String rawChunk) {
// 简单实现假设每个事件都是完整的JSON
// return Flux.just(data);
System.out.println("RawChunk: " + rawChunk);
// 从原始块中提取完整的JSON对象
Matcher matcher = JSON_PATTERN.matcher(rawChunk);
Flux<String> chunks = Flux.empty();
while (matcher.find()) {
chunks = chunks.concatWithValues(matcher.group());
} }
return chunks;
} }
/** /**
* http() * http()
* @param url * @param url
@ -117,24 +106,7 @@ public abstract class BaseAIProviderProcessor implements IUnifiedAIProviderProce
* @param apiKey * @param apiKey
* @return AIResponse * @return AIResponse
*/ */
public Mono<AIResponse> standardRequest(String url,String requestBody, String apiKey) { public abstract Mono<AIResponse> standardRequest(String url,String requestBody, String apiKey);
return webClient.post()
.uri(url)
.header(HttpHeaders.AUTHORIZATION, "Bearer " + apiKey)
.header(HttpHeaders.CONTENT_TYPE, MediaType.APPLICATION_JSON_VALUE)
.bodyValue(requestBody)
.retrieve()
.bodyToMono(String.class)
.flatMap(response -> {
try {
return Mono.just(extractAIResponse(response));
} catch (Exception e) {
return buildErrorResponse("解析响应失败: " + e.getMessage());
}
})
.onErrorResume(e -> buildErrorResponse("API调用失败: " + e.getMessage()));
// .timeout(Duration.ofSeconds(30));
}
/** /**
@ -166,6 +138,37 @@ public abstract class BaseAIProviderProcessor implements IUnifiedAIProviderProce
} }
/**
* JSON
*/
protected abstract String extractContentFromStreamJson(String jsonChunk) throws Exception;
/**
* JSON
*/
protected abstract AIResponse extractAIResponse(String json) throws Exception;
/**
* SSEJSON
*/
protected Flux<String> extractJsonChunks(String rawChunk) {
// 简单实现假设每个事件都是完整的JSON
// return Flux.just(data);
System.out.println("RawChunk: " + rawChunk);
// 从原始块中提取完整的JSON对象
Matcher matcher = JSON_PATTERN.matcher(rawChunk);
Flux<String> chunks = Flux.empty();
while (matcher.find()) {
chunks = chunks.concatWithValues(matcher.group());
}
return chunks;
}
@ -238,7 +241,8 @@ public abstract class BaseAIProviderProcessor implements IUnifiedAIProviderProce
saveTokenUsage(HwMomAiConstants.AI_CHAT_MESSAGE_DETAIL_TYPE_QUESTION, objectMapper.writeValueAsString(request.getQuestionContent()), saveTokenUsage(HwMomAiConstants.AI_CHAT_MESSAGE_DETAIL_TYPE_QUESTION, objectMapper.writeValueAsString(request.getQuestionContent()),
objectMapper.writeValueAsString(fullResponse), tokenUsage, request.getModelId(), request.getKnowledgeBaseId(), null, objectMapper.writeValueAsString(fullResponse), tokenUsage, request.getModelId(), request.getKnowledgeBaseId(), null,
aiChatMessage.getChatMessageId(),request.getSessionId(),request.getCarryHistoryFlag(),"1", loginUser.getUserId()); aiChatMessage.getChatMessageId(),request.getSessionId(),request.getCarryHistoryFlag(),"1",
loginUser.getUserId(),loginUser.getTenantId(), loginUser.getDeptId());
// AiChatMessageDetail aiChatMessageDetail = new AiChatMessageDetail(); // AiChatMessageDetail aiChatMessageDetail = new AiChatMessageDetail();
@ -283,11 +287,14 @@ public abstract class BaseAIProviderProcessor implements IUnifiedAIProviderProce
* @param takeFlag * @param takeFlag
* @param completeFlag * @param completeFlag
* @param userId * @param userId
* @param tenantId
* @param deptId
*/ */
@Override @Override
public void saveTokenUsage(String messageDetailType, String questionContent, String answerContent, TokenUsage tokenUsage, public void saveTokenUsage(String messageDetailType, String questionContent, String answerContent, TokenUsage tokenUsage,
Long modelId, Long knowledgeBaseId, Long knowledgeContentId, Long modelId, Long knowledgeBaseId, Long knowledgeContentId,
Long chatMessageId,String sessionId,String takeFlag,String completeFlag,Long userId) { Long chatMessageId,String sessionId,String takeFlag,String completeFlag,
Long userId,String tenantId,Long deptId) {
Long promptToken = tokenUsage!=null ? tokenUsage.getPromptToken():null; Long promptToken = tokenUsage!=null ? tokenUsage.getPromptToken():null;
Long completionToken = tokenUsage!=null ? tokenUsage.getCompletionToken():null; Long completionToken = tokenUsage!=null ? tokenUsage.getCompletionToken():null;
Long totalToken = tokenUsage!=null ? tokenUsage.getTotalToken():null; Long totalToken = tokenUsage!=null ? tokenUsage.getTotalToken():null;
@ -306,6 +313,9 @@ public abstract class BaseAIProviderProcessor implements IUnifiedAIProviderProce
aiChatMessageDetail.setCompleteFlag(completeFlag); aiChatMessageDetail.setCompleteFlag(completeFlag);
aiChatMessageDetail.setChatMessageId(chatMessageId); aiChatMessageDetail.setChatMessageId(chatMessageId);
aiChatMessageDetail.setSessionId(sessionId); aiChatMessageDetail.setSessionId(sessionId);
aiChatMessageDetail.setCreateBy(userId);
aiChatMessageDetail.setTenantId(tenantId);
aiChatMessageDetail.setCreateDept(deptId);
aiChatMessageDetailMapper.insert(aiChatMessageDetail); aiChatMessageDetailMapper.insert(aiChatMessageDetail);
MPJLambdaWrapper<AiTokenUsage> lqw = JoinWrappers.lambda(AiTokenUsage.class) MPJLambdaWrapper<AiTokenUsage> lqw = JoinWrappers.lambda(AiTokenUsage.class)

@ -25,6 +25,8 @@ import org.dromara.ai.service.IAiChatMessageService;
import org.dromara.common.encrypt.utils.EncryptUtils; import org.dromara.common.encrypt.utils.EncryptUtils;
import org.dromara.system.api.model.LoginUser; import org.dromara.system.api.model.LoginUser;
import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.HttpHeaders;
import org.springframework.http.MediaType;
import org.springframework.stereotype.Component; import org.springframework.stereotype.Component;
import reactor.core.publisher.Flux; import reactor.core.publisher.Flux;
import reactor.core.publisher.Mono; import reactor.core.publisher.Mono;
@ -47,16 +49,38 @@ public class DeepSeekProcessor extends BaseAIProviderProcessor {
// 用于解析流式JSON块的模式 // 用于解析流式JSON块的模式
private static final Pattern JSON_PATTERN = Pattern.compile("\\{(?:[^{}]|\\{(?:[^{}]|\\{[^{}]*\\})*\\})*\\}"); private static final Pattern JSON_PATTERN = Pattern.compile("\\{(?:[^{}]|\\{(?:[^{}]|\\{[^{}]*\\})*\\})*\\}");
// private final String apiKey = "sk-e1df7a607644479e8ebad3be233ddafa";
private final String apiUrl = "https://api.deepseek.com/v1/";
private static final String API_URL = "https://api.deepseek.com/v1/chat/completions"; private static final String API_URL = "https://api.deepseek.com/v1/chat/completions";
private final String deepSeekChatModel = "deepseek-chat"; private final String deepSeekChatModel = "deepseek-chat";
@Autowired
private AiModelMapper aiModelMapper;
/**
* http()
* @param url
* @param requestBody
* @param apiKey
* @return AIResponse
*/
@Override
public Mono<AIResponse> standardRequest(String url,String requestBody, String apiKey) {
return webClient.post()
.uri(url)
.header(HttpHeaders.AUTHORIZATION, "Bearer " + apiKey)
.header(HttpHeaders.CONTENT_TYPE, MediaType.APPLICATION_JSON_VALUE)
.bodyValue(requestBody)
.retrieve()
.bodyToMono(String.class)
.flatMap(response -> {
try {
return Mono.just(extractAIResponse(response));
} catch (Exception e) {
return buildErrorResponse("解析响应失败: " + e.getMessage());
}
})
.onErrorResume(e -> buildErrorResponse("API调用失败: " + e.getMessage()));
// .timeout(Duration.ofSeconds(30));
}
public Mono<AIResponse> chatTest(AIRequest request) { public Mono<AIResponse> chatTest(AIRequest request) {
AIMessage aiMessage = new AIMessage(); AIMessage aiMessage = new AIMessage();
aiMessage.setRole("user"); aiMessage.setRole("user");
@ -334,16 +358,7 @@ public class DeepSeekProcessor extends BaseAIProviderProcessor {
return ""; return "";
} }
private void configureApiKey(AIRequest request) {
AiModelVo aiModelVo = aiModelMapper.selectVoById(request.getModelId());
if (aiModelVo != null) {
if (aiModelVo.getApiKey() == null) {
throw new RuntimeException("请设置AI模型的API Key");
}
request.setApiKey(EncryptUtils.decryptByBase64(aiModelVo.getApiKey()));
}
}

@ -60,6 +60,17 @@ public class TencentLkeProcessor extends BaseAIProviderProcessor {
properties.getTencentLke().getModel()); properties.getTencentLke().getModel());
} }
/**
* http()
* @param url
* @param requestBody
* @param apiKey
* @return AIResponse
*/
@Override
public Mono<AIResponse> standardRequest(String url,String requestBody, String apiKey){
return null;
}
@Override @Override
public List<Double> getEmbeddingTest(AIRequest aiRequest) { public List<Double> getEmbeddingTest(AIRequest aiRequest) {

@ -2,12 +2,14 @@ package org.dromara.ai.process.provider.processor.impl;
//import com.example.deepseek.dto.EmbeddingResponse; //import com.example.deepseek.dto.EmbeddingResponse;
import com.alibaba.dashscope.aigc.generation.*;
import com.fasterxml.jackson.core.JsonParser; import com.fasterxml.jackson.core.JsonParser;
import com.fasterxml.jackson.core.JsonProcessingException; import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.JsonNode; import com.fasterxml.jackson.databind.JsonNode;
import com.fasterxml.jackson.databind.ObjectMapper; import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.node.ObjectNode; import com.fasterxml.jackson.databind.node.ObjectNode;
import com.tencentcloudapi.lkeap.v20240522.models.GetEmbeddingResponse; import com.tencentcloudapi.lkeap.v20240522.models.GetEmbeddingResponse;
import org.checkerframework.checker.units.qual.A;
import org.dromara.ai.domain.AiChatMessage; import org.dromara.ai.domain.AiChatMessage;
import org.dromara.ai.domain.AiChatMessageDetail; import org.dromara.ai.domain.AiChatMessageDetail;
import org.dromara.ai.mapper.AiChatMessageDetailMapper; import org.dromara.ai.mapper.AiChatMessageDetailMapper;
@ -22,14 +24,28 @@ import org.dromara.system.api.model.LoginUser;
import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component; import org.springframework.stereotype.Component;
import reactor.core.publisher.Flux; import reactor.core.publisher.Flux;
import reactor.core.publisher.FluxSink;
import reactor.core.publisher.Mono; import reactor.core.publisher.Mono;
import java.io.IOException; import java.io.IOException;
import java.util.ArrayList;
import java.util.Collections; import java.util.Collections;
import java.util.List; import java.util.List;
import java.util.concurrent.atomic.AtomicBoolean;
import java.util.regex.Matcher; import java.util.regex.Matcher;
import java.util.regex.Pattern; import java.util.regex.Pattern;
import java.util.Arrays;
import java.lang.System;
import com.alibaba.dashscope.common.Message;
import com.alibaba.dashscope.common.Role;
import com.alibaba.dashscope.exception.ApiException;
import com.alibaba.dashscope.exception.InputRequiredException;
import com.alibaba.dashscope.exception.NoApiKeyException;
import io.reactivex.Flowable;
import io.reactivex.schedulers.Schedulers;
/** /**
* @Author xins * @Author xins
* @Date 2025/8/15 11:00 * @Date 2025/8/15 11:00
@ -42,11 +58,7 @@ public class TongYiQianWenProcessor extends BaseAIProviderProcessor {
// 用于解析流式JSON块的模式 // 用于解析流式JSON块的模式
private static final Pattern JSON_PATTERN = Pattern.compile("\\{(?:[^{}]|\\{(?:[^{}]|\\{[^{}]*\\})*\\})*\\}"); private static final Pattern JSON_PATTERN = Pattern.compile("\\{(?:[^{}]|\\{(?:[^{}]|\\{[^{}]*\\})*\\})*\\}");
private final String apiKey = "sk-e1df7a607644479e8ebad3be233ddafa"; private static final String ALIYUN_MODEL_NAME = "qwen-plus";
private final String apiUrl = "https://api.t.com/v1/";
private static final String API_URL = "https://api.deepseek.com/v1/chat/completions";
private final String deepSeekChatModel = "deepseek-chat";
@Autowired @Autowired
@ -54,14 +66,57 @@ public class TongYiQianWenProcessor extends BaseAIProviderProcessor {
@Autowired @Autowired
private AiChatMessageDetailMapper aiChatMessageDetailMapper; private AiChatMessageDetailMapper aiChatMessageDetailMapper;
/**
* http()
* @param url
* @param requestBody
* @param apiKey
* @return AIResponse
*/
@Override
public Mono<AIResponse> standardRequest(String url,String requestBody, String apiKey){
return null;
}
/**
* http()
* @param aiRequest
* @return AIResponse
*/
private Mono<AIResponse> aliStandardRequest(AIRequest aiRequest){
Generation gen = new Generation();
Message systemMsg = Message.builder()
.role(Role.SYSTEM.getValue())
.content("You are a helpful assistant.")
.build();
Message userMsg = Message.builder()
.role(Role.USER.getValue())
.content(aiRequest.getText())
.build();
GenerationParam param = GenerationParam.builder()
// 若没有配置环境变量请用阿里云百炼API Key将下行替换为.apiKey("sk-xxx")
.apiKey(aiRequest.getApiKey())
// 模型列表https://help.aliyun.com/zh/model-studio/getting-started/models
.model(ALIYUN_MODEL_NAME)
.messages(Arrays.asList(systemMsg, userMsg))
.resultFormat(GenerationParam.ResultFormat.MESSAGE)
.build();
try {
GenerationResult generationResult = gen.call(param);
return Mono.just(extractAliAIResponse(generationResult));
} catch (NoApiKeyException e) {
throw new RuntimeException(e);
} catch (InputRequiredException e) {
throw new RuntimeException(e);
} catch (Exception e) {
throw new RuntimeException(e);
}
}
public Mono<AIResponse> chatTest(AIRequest request) { public Mono<AIResponse> chatTest(AIRequest request) {
AIMessage aiMessage = new AIMessage(); request.setText("这是一个测试请求,请回复'测试成功'");
aiMessage.setRole("user");
aiMessage.setContent("这是一个测试请求,请回复'测试成功'");
request.setMessages(Collections.singletonList(
aiMessage
));
String apiEncryptFlag = request.getApiKeyEncryptFlag(); String apiEncryptFlag = request.getApiKeyEncryptFlag();
if(apiEncryptFlag.equals("1")){ if(apiEncryptFlag.equals("1")){
request.setApiKey(EncryptUtils.decryptByBase64(request.getApiKey())); request.setApiKey(EncryptUtils.decryptByBase64(request.getApiKey()));
@ -74,56 +129,89 @@ public class TongYiQianWenProcessor extends BaseAIProviderProcessor {
@Override @Override
public Mono<AIResponse> chat(AIRequest request) { public Mono<AIResponse> chat(AIRequest request) {
try { try {
ObjectNode rootNode = objectMapper.createObjectNode(); configureApiKey(request);
rootNode.put("model", deepSeekChatModel); return aliStandardRequest(request);
rootNode.set("messages", objectMapper.valueToTree(request.getMessages())); } catch (Exception e) {
if (request.getTemperature() != null) {
rootNode.put("temperature", request.getTemperature());
}
if (request.getMaxTokens() != null) {
rootNode.put("max_tokens", request.getMaxTokens());
}
String requestBody = objectMapper.writeValueAsString(rootNode);
return standardRequest(API_URL, requestBody, request.getApiKey());
} catch (IOException e) {
return buildErrorResponse("构建请求失败: " + e.getMessage()); return buildErrorResponse("构建请求失败: " + e.getMessage());
} }
} }
/**
*
*/
private Flowable<GenerationResult> createStreamFlowable(AIRequest aiRequest)
throws ApiException, NoApiKeyException, InputRequiredException {
Generation gen = new Generation();
List<AIMessage> aiMessages = aiRequest.getMessages();
List<Message> messages = new ArrayList<>();
Message systemMsg = Message.builder()
.role(Role.SYSTEM.getValue())
.content("You are a helpful assistant.")
.build();
messages.add(systemMsg);
for(AIMessage aiMessage:aiMessages){
Message inputMessage = Message.builder()
.role(aiMessage.getRole())
.content(aiMessage.getContent())
.build();
messages.add(inputMessage);
}
GenerationParam param = GenerationParam.builder()
.apiKey(aiRequest.getApiKey())
.model(ALIYUN_MODEL_NAME)
.messages(messages)
.resultFormat(GenerationParam.ResultFormat.MESSAGE)
.build();
return gen.streamCall(param);
}
@Override @Override
public Flux<String> chatStreamContent(AIRequest request, LoginUser loginUser) { public Flux<String> chatStreamContent(AIRequest request, LoginUser loginUser) {
try { return null;
ObjectNode rootNode = objectMapper.createObjectNode(); }
rootNode.put("model", deepSeekChatModel);
rootNode.set("messages", objectMapper.valueToTree(request.getMessages()));
rootNode.put("stream", true);
if (request.getTemperature() != null) { /**
rootNode.put("temperature", request.getTemperature()); * GenerationResult
} */
private static String extractContent(GenerationResult result) {
// request.setApiKey(); if (result == null || result.getOutput() == null) {
// 执行流式请求并收集完整响应
StringBuilder fullResponseBuilder = new StringBuilder();
String requestBody = objectMapper.writeValueAsString(rootNode);
return null; return null;
// return executeStreamRequest(API_URL, requestBody, apiKey).doOnNext(chunk -> { }
// // 收集每个chunk
// fullResponseBuilder.append(chunk); try {
// }) return result.getOutput()
// .doOnComplete(() -> { .getChoices()
// // 流完成后保存到数据库 .get(0)
// saveChatMessage(request, fullResponseBuilder.toString()); .getMessage()
// }) .getContent();
// .doOnError(error -> { } catch (Exception e) {
// // 错误处理 return null;
//// log.error("流式请求出错", error); }
// }); }
} catch (IOException e) {
return Flux.error(new RuntimeException("构建请求失败: " + e.getMessage())); /**
*
*/
private static boolean isFinished(GenerationResult result) {
if (result == null || result.getOutput() == null) {
return false;
}
try {
String finishReason = result.getOutput()
.getChoices()
.get(0)
.getFinishReason();
return "stop".equals(finishReason);
} catch (Exception e) {
return false;
} }
} }
@ -162,6 +250,18 @@ public class TongYiQianWenProcessor extends BaseAIProviderProcessor {
} }
} }
protected AIResponse extractAliAIResponse(GenerationResult generationResult) throws Exception {
List<GenerationOutput.Choice> choices = generationResult.getOutput().getChoices();
String content = choices.get(0).getMessage().getContent();
GenerationUsage generationUsage = generationResult.getUsage();
TokenUsage tokenUsage = new TokenUsage(
generationUsage.getInputTokens().longValue(),generationUsage.getOutputTokens().longValue(),
generationUsage.getTotalTokens().longValue()
);
return new AIResponse(content, tokenUsage);
}
@Override @Override
protected AIResponse extractAIResponse(String json) throws Exception { protected AIResponse extractAIResponse(String json) throws Exception {
JsonNode node = objectMapper.readTree(json); JsonNode node = objectMapper.readTree(json);
@ -264,7 +364,67 @@ public class TongYiQianWenProcessor extends BaseAIProviderProcessor {
@Override @Override
public Flux<String> chatStream(AIRequest request, LoginUser loginUser) { public Flux<String> chatStream(AIRequest request, LoginUser loginUser) {
return null; configureApiKey(request);
return Flux.create(sink -> {
try {
Flowable<GenerationResult> flowable = createStreamFlowable(request);
AtomicBoolean isCompleted = new AtomicBoolean(false);
// 用于收集完整响应和token信息
TokenUsage finalTokenUsage = new TokenUsage(0L, 0L, 0L);
flowable.subscribe(
// onNext
generationResult -> {
if (sink.isCancelled()) {
return;
}
try {
String content = extractContent(generationResult);
if (content != null && !content.isEmpty()) {
sink.next(content);
}
// 检查是否结束
if (isFinished(generationResult)) {
if (!isCompleted.getAndSet(true)) {
sink.complete();
}
GenerationUsage usage = generationResult.getUsage();
finalTokenUsage.setPromptToken(usage.getInputTokens().longValue());
finalTokenUsage.setCompletionToken(usage.getOutputTokens().longValue());
finalTokenUsage.setTotalToken(usage.getTotalTokens().longValue());
saveChatMessage(request, content, finalTokenUsage, loginUser);
}
} catch (Exception e) {
sink.error(e);
}
},
// onError
error -> {
if (!isCompleted.getAndSet(true)) {
sink.error(error);
}
},
// onComplete
() -> {
if (!isCompleted.getAndSet(true)) {
sink.complete();
}
}
);
// 设置取消回调
sink.onCancel(() -> {
isCompleted.set(true);
// 可以在这里添加资源清理逻辑
});
} catch (Exception e) {
sink.error(e);
}
}, FluxSink.OverflowStrategy.BUFFER);
} }
@Override @Override

@ -0,0 +1,69 @@
package org.dromara.ai.service;
import org.dromara.ai.domain.AiAsrRecord;
import org.dromara.ai.domain.vo.AiAsrRecordVo;
import org.dromara.ai.domain.bo.AiAsrRecordBo;
import org.dromara.common.mybatis.core.page.TableDataInfo;
import org.dromara.common.mybatis.core.page.PageQuery;
import java.util.Collection;
import java.util.List;
/**
* AIService
*
* @author xins
* @date 2025-10-13
*/
public interface IAiAsrRecordService {
/**
* AI
*
* @param asrRecordId
* @return AI
*/
AiAsrRecordVo queryById(Long asrRecordId);
/**
* AI
*
* @param bo
* @param pageQuery
* @return AI
*/
TableDataInfo<AiAsrRecordVo> queryPageList(AiAsrRecordBo bo, PageQuery pageQuery);
/**
* AI
*
* @param bo
* @return AI
*/
List<AiAsrRecordVo> queryList(AiAsrRecordBo bo);
/**
* AI
*
* @param bo AI
* @return
*/
Boolean insertByBo(AiAsrRecordBo bo);
/**
* AI
*
* @param bo AI
* @return
*/
Boolean updateByBo(AiAsrRecordBo bo);
/**
* AI
*
* @param ids
* @param isValid
* @return
*/
Boolean deleteWithValidByIds(Collection<Long> ids, Boolean isValid);
}

@ -150,7 +150,7 @@ public class AIAssistantServiceImpl implements IAIAssistantService {
tencentLkeProcessor.saveTokenUsage(HwMomAiConstants.AI_CHAT_MESSAGE_DETAIL_TYPE_QUESTION_VECTOR,"AI问答获取向量", null, tokenUsage, tencentLkeProcessor.saveTokenUsage(HwMomAiConstants.AI_CHAT_MESSAGE_DETAIL_TYPE_QUESTION_VECTOR,"AI问答获取向量", null, tokenUsage,
embeddingModelId, aiRequest.getKnowledgeBaseId(), null, embeddingModelId, aiRequest.getKnowledgeBaseId(), null,
null, null, "0", "1",LoginHelper.getUserId()); null, null, "0", "1",LoginHelper.getUserId(),LoginHelper.getTenantId(),LoginHelper.getDeptId());
List<Double> queryEmbedding = tencentLkeProcessor.getEmbedding(embeddingResponses); List<Double> queryEmbedding = tencentLkeProcessor.getEmbedding(embeddingResponses);
@ -284,7 +284,7 @@ public class AIAssistantServiceImpl implements IAIAssistantService {
//``` //```
processor.saveTokenUsage(HwMomAiConstants.AI_CHAT_MESSAGE_DETAIL_TYPE_SQL,prompt, content,response.block().getTokenUsage(), processor.saveTokenUsage(HwMomAiConstants.AI_CHAT_MESSAGE_DETAIL_TYPE_SQL,prompt, content,response.block().getTokenUsage(),
aiRequest.getModelId(), null,null, aiRequest.getModelId(), null,null,
null,null,"0","1",LoginHelper.getUserId()); null,null,"0","1",LoginHelper.getUserId(),LoginHelper.getTenantId(),LoginHelper.getDeptId());
return extractSqlFromContent(content); return extractSqlFromContent(content);
} else { } else {
@ -434,6 +434,7 @@ public class AIAssistantServiceImpl implements IAIAssistantService {
Long modelId = aiFillFormRequest.getModelId(); Long modelId = aiFillFormRequest.getModelId();
AIRequest aiRequest = new AIRequest(); AIRequest aiRequest = new AIRequest();
aiRequest.setMessages(Collections.singletonList(aiMessage)); aiRequest.setMessages(Collections.singletonList(aiMessage));
aiRequest.setText(sb.toString());
aiRequest.setModelId(modelId); aiRequest.setModelId(modelId);
Mono<AIResponse> response = processor.chat(aiRequest); Mono<AIResponse> response = processor.chat(aiRequest);
@ -443,7 +444,7 @@ public class AIAssistantServiceImpl implements IAIAssistantService {
parseRelateTable(aiFormSettingDetailList, contentJson); parseRelateTable(aiFormSettingDetailList, contentJson);
processor.saveTokenUsage(HwMomAiConstants.AI_CHAT_MESSAGE_DETAIL_TYPE_FORM,sb.toString(), content, response.block().getTokenUsage(), processor.saveTokenUsage(HwMomAiConstants.AI_CHAT_MESSAGE_DETAIL_TYPE_FORM,sb.toString(), content, response.block().getTokenUsage(),
modelId, null, null, modelId, null, null,
null, null, "0", "1",LoginHelper.getUserId()); null, null, "0", "1",LoginHelper.getUserId(),LoginHelper.getTenantId(),LoginHelper.getDeptId());
System.out.println(contentJson.toJSONString()); System.out.println(contentJson.toJSONString());
return contentJson; return contentJson;

@ -0,0 +1,136 @@
package org.dromara.ai.service.impl;
import org.dromara.common.core.utils.MapstructUtils;
import org.dromara.common.core.utils.StringUtils;
import org.dromara.common.mybatis.core.page.TableDataInfo;
import org.dromara.common.mybatis.core.page.PageQuery;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.github.yulichang.toolkit.JoinWrappers;
import com.github.yulichang.wrapper.MPJLambdaWrapper;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import lombok.RequiredArgsConstructor;
import org.springframework.stereotype.Service;
import org.dromara.ai.domain.bo.AiAsrRecordBo;
import org.dromara.ai.domain.vo.AiAsrRecordVo;
import org.dromara.ai.domain.AiAsrRecord;
import org.dromara.ai.mapper.AiAsrRecordMapper;
import org.dromara.ai.service.IAiAsrRecordService;
import java.util.List;
import java.util.Map;
import java.util.Collection;
/**
* AIService
*
* @author xins
* @date 2025-10-13
*/
@RequiredArgsConstructor
@Service
public class AiAsrRecordServiceImpl implements IAiAsrRecordService {
private final AiAsrRecordMapper baseMapper;
/**
* AI
*
* @param asrRecordId
* @return AI
*/
@Override
public AiAsrRecordVo queryById(Long asrRecordId){
return baseMapper.selectVoById(asrRecordId);
}
/**
* AI
*
* @param bo
* @param pageQuery
* @return AI
*/
@Override
public TableDataInfo<AiAsrRecordVo> queryPageList(AiAsrRecordBo bo, PageQuery pageQuery) {
MPJLambdaWrapper<AiAsrRecord> lqw = buildQueryWrapper(bo);
Page<AiAsrRecordVo> result = baseMapper.selectVoPage(pageQuery.build(), lqw);
return TableDataInfo.build(result);
}
/**
* AI
*
* @param bo
* @return AI
*/
@Override
public List<AiAsrRecordVo> queryList(AiAsrRecordBo bo) {
MPJLambdaWrapper<AiAsrRecord> lqw = buildQueryWrapper(bo);
return baseMapper.selectVoList(lqw);
}
private MPJLambdaWrapper<AiAsrRecord> buildQueryWrapper(AiAsrRecordBo bo) {
Map<String, Object> params = bo.getParams();
MPJLambdaWrapper<AiAsrRecord> lqw = JoinWrappers.lambda(AiAsrRecord.class)
.selectAll(AiAsrRecord.class)
.eq(bo.getAsrRecordId() != null, AiAsrRecord::getAsrRecordId, bo.getAsrRecordId())
.eq(StringUtils.isNotBlank(bo.getAsrFileUrl()), AiAsrRecord::getAsrFileUrl, bo.getAsrFileUrl())
.eq(StringUtils.isNotBlank(bo.getAsrContent()), AiAsrRecord::getAsrContent, bo.getAsrContent())
.eq(StringUtils.isNotBlank(bo.getAsrResult()), AiAsrRecord::getAsrResult, bo.getAsrResult())
.eq(StringUtils.isNotBlank(bo.getAsrFailedReason()), AiAsrRecord::getAsrFailedReason, bo.getAsrFailedReason())
.orderByDesc(AiAsrRecord::getCreateTime);
return lqw;
}
/**
* AI
*
* @param bo AI
* @return
*/
@Override
public Boolean insertByBo(AiAsrRecordBo bo) {
AiAsrRecord add = MapstructUtils.convert(bo, AiAsrRecord.class);
validEntityBeforeSave(add);
boolean flag = baseMapper.insert(add) > 0;
if (flag) {
bo.setAsrRecordId(add.getAsrRecordId());
}
return flag;
}
/**
* AI
*
* @param bo AI
* @return
*/
@Override
public Boolean updateByBo(AiAsrRecordBo bo) {
AiAsrRecord update = MapstructUtils.convert(bo, AiAsrRecord.class);
validEntityBeforeSave(update);
return baseMapper.updateById(update) > 0;
}
/**
*
*/
private void validEntityBeforeSave(AiAsrRecord entity){
//TODO 做一些数据校验,如唯一约束
}
/**
* AI
*
* @param ids
* @param isValid
* @return
*/
@Override
public Boolean deleteWithValidByIds(Collection<Long> ids, Boolean isValid) {
if(isValid){
//TODO 做一些业务上的校验,判断是否需要校验
}
return baseMapper.deleteByIds(ids) > 0;
}
}

@ -172,6 +172,7 @@ public class AiChatMessageDetailServiceImpl implements IAiChatMessageDetailServi
aiAssistantMessage.setRole("assistant"); aiAssistantMessage.setRole("assistant");
aiAssistantMessage.setContent(aiChatMessageDetail.getAnswerContent()); aiAssistantMessage.setContent(aiChatMessageDetail.getAnswerContent());
aiAssistantMessage.setTimestamp(aiChatMessageDetail.getCreateTime().getTime()); aiAssistantMessage.setTimestamp(aiChatMessageDetail.getCreateTime().getTime());
aiAssistantMessage.setModelId(aiChatMessageDetail.getModelId());
aiMessages.add(aiAssistantMessage); aiMessages.add(aiAssistantMessage);
} }

@ -357,7 +357,7 @@ public class AiKnowledgeBaseServiceImpl implements IAiKnowledgeBaseService {
TokenUsage tokenUsage = new TokenUsage(null,null,usage.getTotalTokens()); TokenUsage tokenUsage = new TokenUsage(null,null,usage.getTotalTokens());
tencentLkeProcessor.saveTokenUsage(HwMomAiConstants.AI_CHAT_MESSAGE_DETAIL_TYPE_CONTENT_VECTOR,"AI上传知识库内容获取向量", null, tokenUsage, tencentLkeProcessor.saveTokenUsage(HwMomAiConstants.AI_CHAT_MESSAGE_DETAIL_TYPE_CONTENT_VECTOR,"AI上传知识库内容获取向量", null, tokenUsage,
modelId, aiRequest.getKnowledgeBaseId(), aiKnowledgeEmbedding.getKnowledgeContentId(), modelId, aiRequest.getKnowledgeBaseId(), aiKnowledgeEmbedding.getKnowledgeContentId(),
null, null, "0", "1", LoginHelper.getUserId()); null, null, "0", "1", LoginHelper.getUserId(),LoginHelper.getTenantId(),LoginHelper.getDeptId());
// 转换结果格式 // 转换结果格式

@ -0,0 +1,7 @@
<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE mapper
PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
"http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="org.dromara.ai.mapper.AiAsrRecordMapper">
</mapper>
Loading…
Cancel
Save