【代码新增】AI:开启 AI 租户的能力
This commit is contained in:
parent
c98495dfcb
commit
2e73959a2c
|
@ -32,6 +32,11 @@
|
|||
<version>${revision}</version>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>cn.iocoder.boot</groupId>
|
||||
<artifactId>yudao-spring-boot-starter-biz-tenant</artifactId>
|
||||
</dependency>
|
||||
|
||||
<!-- Web 相关 -->
|
||||
<dependency>
|
||||
<groupId>cn.iocoder.boot</groupId>
|
||||
|
|
|
@ -2,6 +2,7 @@
|
|||
POST {{baseUrl}}/ai/chat/message/send
|
||||
Content-Type: application/json
|
||||
Authorization: {{token}}
|
||||
tenant-id: {{adminTenentId}}
|
||||
|
||||
{
|
||||
"conversationId": "1781604279872581724",
|
||||
|
@ -12,9 +13,10 @@ Authorization: {{token}}
|
|||
POST {{baseUrl}}/ai/chat/message/send-stream
|
||||
Content-Type: application/json
|
||||
Authorization: {{token}}
|
||||
tenant-id: {{adminTenentId}}
|
||||
|
||||
{
|
||||
"conversationId": "1781604279872581690",
|
||||
"conversationId": "1781604279872581724",
|
||||
"content": "1+1=?"
|
||||
}
|
||||
|
||||
|
|
|
@ -57,6 +57,4 @@ public class AiImageRespVO {
|
|||
@Schema(description = "创建时间", requiredMode = Schema.RequiredMode.REQUIRED)
|
||||
private LocalDateTime createTime;
|
||||
|
||||
|
||||
|
||||
}
|
||||
|
|
|
@ -76,6 +76,11 @@ public class AiImageDO extends BaseDO {
|
|||
*/
|
||||
private Integer status;
|
||||
|
||||
/**
|
||||
* 完成时间
|
||||
*/
|
||||
private LocalDateTime finishTime;
|
||||
|
||||
/**
|
||||
* 绘画错误信息
|
||||
*/
|
||||
|
@ -112,11 +117,6 @@ public class AiImageDO extends BaseDO {
|
|||
*/
|
||||
private String taskId;
|
||||
|
||||
/**
|
||||
* 完成时间
|
||||
*/
|
||||
private LocalDateTime finishTime;
|
||||
|
||||
public static class ButtonTypeHandler extends AbstractJsonTypeHandler<Object> {
|
||||
|
||||
@Override
|
||||
|
|
|
@ -8,6 +8,7 @@ import cn.iocoder.yudao.framework.ai.core.util.AiUtils;
|
|||
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.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;
|
||||
|
@ -125,11 +126,14 @@ public class AiChatMessageServiceImpl implements AiChatMessageService {
|
|||
return success(new AiChatMessageSendRespVO().setSend(BeanUtils.toBean(userMessage, AiChatMessageSendRespVO.Message.class))
|
||||
.setReceive(BeanUtils.toBean(assistantMessage, AiChatMessageSendRespVO.Message.class).setContent(newContent)));
|
||||
}).doOnComplete(() -> {
|
||||
chatMessageMapper.updateById(new AiChatMessageDO().setId(assistantMessage.getId()).setContent(contentBuffer.toString()));
|
||||
// 忽略租户,因为 Flux 异步无法透传租户
|
||||
TenantUtils.executeIgnore(() ->
|
||||
chatMessageMapper.updateById(new AiChatMessageDO().setId(assistantMessage.getId()).setContent(contentBuffer.toString())));
|
||||
}).doOnError(throwable -> {
|
||||
// TODO @芋艿:失败的情况下,要不要删除消息
|
||||
log.error("[sendChatMessageStream][userId({}) sendReqVO({}) 发生异常]", userId, sendReqVO, throwable);
|
||||
chatMessageMapper.updateById(new AiChatMessageDO().setId(assistantMessage.getId()).setContent(throwable.getMessage()));
|
||||
// 忽略租户,因为 Flux 异步无法透传租户
|
||||
TenantUtils.executeIgnore(() ->
|
||||
chatMessageMapper.updateById(new AiChatMessageDO().setId(assistantMessage.getId()).setContent(throwable.getMessage())));
|
||||
}).onErrorResume(error -> Flux.just(error(ErrorCodeConstants.CHAT_STREAM_ERROR)));
|
||||
}
|
||||
|
||||
|
|
|
@ -5,6 +5,7 @@ import cn.iocoder.yudao.framework.ai.core.enums.AiPlatformEnum;
|
|||
import cn.iocoder.yudao.framework.ai.core.util.AiUtils;
|
||||
import cn.iocoder.yudao.framework.common.pojo.CommonResult;
|
||||
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.write.vo.AiWriteGenerateReqVO;
|
||||
import cn.iocoder.yudao.module.ai.dal.dataobject.model.AiChatModelDO;
|
||||
import cn.iocoder.yudao.module.ai.dal.dataobject.write.AiWriteDO;
|
||||
|
@ -75,10 +76,14 @@ public class AiWriteServiceImpl implements AiWriteService {
|
|||
// 响应结果
|
||||
return success(newContent);
|
||||
}).doOnComplete(() -> {
|
||||
writeMapper.updateById(new AiWriteDO().setId(writeDO.getId()).setGeneratedContent(contentBuffer.toString()));
|
||||
// 忽略租户,因为 Flux 异步无法透传租户
|
||||
TenantUtils.executeIgnore(() ->
|
||||
writeMapper.updateById(new AiWriteDO().setId(writeDO.getId()).setGeneratedContent(contentBuffer.toString())));
|
||||
}).doOnError(throwable -> {
|
||||
log.error("[AI Write][generateReqVO({}) 发生异常]", generateReqVO, throwable);
|
||||
writeMapper.updateById(new AiWriteDO().setId(writeDO.getId()).setErrorMessage(throwable.getMessage()));
|
||||
log.error("[generateWriteContent][generateReqVO({}) 发生异常]", generateReqVO, throwable);
|
||||
// 忽略租户,因为 Flux 异步无法透传租户
|
||||
TenantUtils.executeIgnore(() ->
|
||||
writeMapper.updateById(new AiWriteDO().setId(writeDO.getId()).setErrorMessage(throwable.getMessage())));
|
||||
}).onErrorResume(error -> Flux.just(error(ErrorCodeConstants.WRITE_STREAM_ERROR)));
|
||||
}
|
||||
|
||||
|
|
|
@ -163,7 +163,7 @@ public class AiClientFactoryImpl implements AiClientFactory {
|
|||
* 可参考 {@link QianFanAutoConfiguration#qianFanChatModel(QianFanConnectionProperties, QianFanChatProperties, RestClient.Builder, RetryTemplate, ResponseErrorHandler)}
|
||||
*/
|
||||
private static QianFanChatModel buildYiYanChatClient(String key) {
|
||||
// TODO 芋艿:貌似目前设置,request 势必会报错
|
||||
// TODO @xin:貌似目前设置,request 势必会报错;看看能不能有办法,参考 buildQianWenChatClient,调用 QianFanAutoConfiguration#qianFanChatModel初始化,当然 key 要用自己的哈
|
||||
List<String> keys = StrUtil.split(key, '|');
|
||||
Assert.equals(keys.size(), 2, "YiYanChatClient 的密钥需要 (appKey|secretKey) 格式");
|
||||
String appKey = keys.get(0);
|
||||
|
@ -191,8 +191,8 @@ public class AiClientFactoryImpl implements AiClientFactory {
|
|||
private static TongYiChatModel buildQianWenChatClient(String key) {
|
||||
com.alibaba.dashscope.aigc.generation.Generation generation = SpringUtil.getBean(Generation.class);
|
||||
TongYiChatProperties chatOptions = SpringUtil.getBean(TongYiChatProperties.class);
|
||||
// TODO @芋艿:貌似 apiKey 是全局唯一的???得测试下
|
||||
// TODO @芋艿:貌似阿里云不是增量返回的
|
||||
// TODO @xin:貌似 apiKey 是全局唯一的???得测试下
|
||||
// TODO @xin:貌似阿里云不是增量返回的
|
||||
TongYiConnectionProperties connectionProperties = new TongYiConnectionProperties();
|
||||
connectionProperties.setApiKey(key);
|
||||
return new TongYiAutoConfiguration().tongYiChatClient(generation, chatOptions, connectionProperties);
|
||||
|
|
|
@ -70,12 +70,6 @@ spring:
|
|||
port: 6379 # 端口
|
||||
database: 0 # 数据库索引
|
||||
# password: dev # 密码,建议生产环境开启
|
||||
server:
|
||||
servlet:
|
||||
encoding:
|
||||
enabled: true
|
||||
charset: UTF-8
|
||||
force: true
|
||||
|
||||
--- #################### 定时任务相关配置 ####################
|
||||
|
||||
|
@ -226,8 +220,6 @@ yudao:
|
|||
enable: false
|
||||
demo: false # 关闭演示模式
|
||||
tencent-lbs-key: TVDBZ-TDILD-4ON4B-PFDZA-RNLKH-VVF6E # QQ 地图的密钥 https://lbs.qq.com/service/staticV2/staticGuide/staticDoc
|
||||
tenant:
|
||||
enable: false
|
||||
|
||||
justauth:
|
||||
enabled: true
|
||||
|
|
|
@ -34,6 +34,13 @@ spring:
|
|||
redis:
|
||||
time-to-live: 1h # 设置过期时间为 1 小时
|
||||
|
||||
server:
|
||||
servlet:
|
||||
encoding:
|
||||
enabled: true
|
||||
charset: UTF-8 # 必须设置 UTF-8,避免 WebFlux 流式返回(AI 场景)会乱码问题
|
||||
force: true
|
||||
|
||||
--- #################### 接口文档配置 ####################
|
||||
|
||||
springdoc:
|
||||
|
|
Loading…
Reference in New Issue