From aa6cc25ab41f3f01c9de8fdf346bb4248fb9a32e Mon Sep 17 00:00:00 2001 From: ziin Date: Thu, 2 Apr 2026 09:53:48 +0800 Subject: [PATCH] =?UTF-8?q?=E6=9B=B4=E6=96=B0AI=E9=99=AA=E8=81=8A=E8=A7=92?= =?UTF-8?q?=E8=89=B2=E6=9F=A5=E8=AF=A2=E4=BB=A5=E6=94=AF=E6=8C=81=E5=9B=BD?= =?UTF-8?q?=E9=99=85=E5=8C=96=E4=BF=A1=E6=81=AF?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../controller/AiCompanionController.java | 31 ++++++-- .../mapper/KeyboardAiCompanionI18nMapper.java | 12 +++ .../model/entity/KeyboardAiCompanion.java | 20 ----- .../model/entity/KeyboardAiCompanionI18n.java | 78 +++++++++++++++++++ .../KeyboardAiCompanionI18nService.java | 13 ++++ .../service/KeyboardAiCompanionService.java | 30 +++++-- .../KeyboardAiCompanionI18nServiceImpl.java | 18 +++++ .../impl/KeyboardAiCompanionServiceImpl.java | 65 +++++++++++++--- .../mapper/KeyboardAiCompanionI18nMapper.xml | 20 +++++ .../mapper/KeyboardAiCompanionMapper.xml | 5 +- 10 files changed, 245 insertions(+), 47 deletions(-) create mode 100644 src/main/java/com/yolo/keyborad/mapper/KeyboardAiCompanionI18nMapper.java create mode 100644 src/main/java/com/yolo/keyborad/model/entity/KeyboardAiCompanionI18n.java create mode 100644 src/main/java/com/yolo/keyborad/service/KeyboardAiCompanionI18nService.java create mode 100644 src/main/java/com/yolo/keyborad/service/impl/KeyboardAiCompanionI18nServiceImpl.java create mode 100644 src/main/resources/mapper/KeyboardAiCompanionI18nMapper.xml diff --git a/src/main/java/com/yolo/keyborad/controller/AiCompanionController.java b/src/main/java/com/yolo/keyborad/controller/AiCompanionController.java index cfc2554..99fff9d 100644 --- a/src/main/java/com/yolo/keyborad/controller/AiCompanionController.java +++ b/src/main/java/com/yolo/keyborad/controller/AiCompanionController.java @@ -42,9 +42,17 @@ public class AiCompanionController { @PostMapping("/page") @Operation(summary = "分页查询AI陪聊角色", description = "分页查询已上线的AI陪聊角色列表,包含点赞数、评论数和当前用户点赞状态") - public BaseResponse> pageList(@RequestBody PageDTO pageDTO) { + public BaseResponse> pageList( + @RequestBody PageDTO pageDTO, + @RequestHeader(value = "Accept-Language", required = false) String acceptLanguage + ) { Long userId = StpUtil.getLoginIdAsLong(); - IPage result = aiCompanionService.pageListWithLikeStatus(userId, pageDTO.getPageNum(), pageDTO.getPageSize()); + IPage result = aiCompanionService.pageListWithLikeStatus( + userId, + pageDTO.getPageNum(), + pageDTO.getPageSize(), + acceptLanguage + ); return ResultUtils.success(result); } @@ -62,28 +70,35 @@ public class AiCompanionController { @GetMapping("/liked") @Operation(summary = "获取当前用户点赞过的AI角色列表", description = "查询当前用户点赞过的所有AI角色,返回角色详细信息") - public BaseResponse> getLikedCompanions() { + public BaseResponse> getLikedCompanions( + @RequestHeader(value = "Accept-Language", required = false) String acceptLanguage + ) { Long userId = StpUtil.getLoginIdAsLong(); - List result = aiCompanionService.getLikedCompanions(userId); + List result = aiCompanionService.getLikedCompanions(userId, acceptLanguage); return ResultUtils.success(result); } @GetMapping("/chatted") @Operation(summary = "获取当前用户聊过天的AI角色列表", description = "查询当前用户聊过天的所有AI角色,返回角色详细信息") - public BaseResponse> getChattedCompanions() { + public BaseResponse> getChattedCompanions( + @RequestHeader(value = "Accept-Language", required = false) String acceptLanguage + ) { Long userId = StpUtil.getLoginIdAsLong(); - List result = aiCompanionService.getChattedCompanions(userId); + List result = aiCompanionService.getChattedCompanions(userId, acceptLanguage); return ResultUtils.success(result); } @GetMapping("/{companionId}") @Operation(summary = "根据ID获取AI角色详情", description = "根据AI角色ID查询角色详细信息,包含点赞数、评论数和当前用户点赞状态") - public BaseResponse getCompanionById(@PathVariable Long companionId) { + public BaseResponse getCompanionById( + @PathVariable Long companionId, + @RequestHeader(value = "Accept-Language", required = false) String acceptLanguage + ) { if (companionId == null) { throw new BusinessException(ErrorCode.COMPANION_ID_EMPTY); } Long userId = StpUtil.getLoginIdAsLong(); - AiCompanionVO result = aiCompanionService.getCompanionById(userId, companionId); + AiCompanionVO result = aiCompanionService.getCompanionById(userId, companionId, acceptLanguage); return ResultUtils.success(result); } diff --git a/src/main/java/com/yolo/keyborad/mapper/KeyboardAiCompanionI18nMapper.java b/src/main/java/com/yolo/keyborad/mapper/KeyboardAiCompanionI18nMapper.java new file mode 100644 index 0000000..01895ca --- /dev/null +++ b/src/main/java/com/yolo/keyborad/mapper/KeyboardAiCompanionI18nMapper.java @@ -0,0 +1,12 @@ +package com.yolo.keyborad.mapper; + +import com.baomidou.mybatisplus.core.mapper.BaseMapper; +import com.yolo.keyborad.model.entity.KeyboardAiCompanionI18n; + +/* +* @author: ziin +* @date: 2026/4/2 09:35 +*/ + +public interface KeyboardAiCompanionI18nMapper extends BaseMapper { +} \ No newline at end of file diff --git a/src/main/java/com/yolo/keyborad/model/entity/KeyboardAiCompanion.java b/src/main/java/com/yolo/keyborad/model/entity/KeyboardAiCompanion.java index c11187c..508f10d 100644 --- a/src/main/java/com/yolo/keyborad/model/entity/KeyboardAiCompanion.java +++ b/src/main/java/com/yolo/keyborad/model/entity/KeyboardAiCompanion.java @@ -27,12 +27,6 @@ public class KeyboardAiCompanion { @Schema(description="陪聊角色唯一ID") private Long id; - /** - * 角色名称(展示用,如:Katie Leona) - */ - @TableField(value = "\"name\"") - @Schema(description="角色名称(展示用,如:Katie Leona)") - private String name; /** * 角色头像URL,用于列表页和聊天页 @@ -62,20 +56,6 @@ public class KeyboardAiCompanion { @Schema(description="角色年龄段描述(如:20s、25-30)") private String ageRange; - /** - * 一句话人设描述,用于卡片或列表展示 - */ - @TableField(value = "short_desc") - @Schema(description="一句话人设描述,用于卡片或列表展示") - private String shortDesc; - - /** - * 角色详细介绍文案,用于角色详情页 - */ - @TableField(value = "intro_text") - @Schema(description="角色详细介绍文案,用于角色详情页") - private String introText; - /** * 角色性格标签数组(如:温柔、黏人、治愈) */ diff --git a/src/main/java/com/yolo/keyborad/model/entity/KeyboardAiCompanionI18n.java b/src/main/java/com/yolo/keyborad/model/entity/KeyboardAiCompanionI18n.java new file mode 100644 index 0000000..6773e71 --- /dev/null +++ b/src/main/java/com/yolo/keyborad/model/entity/KeyboardAiCompanionI18n.java @@ -0,0 +1,78 @@ +package com.yolo.keyborad.model.entity; + +import com.baomidou.mybatisplus.annotation.IdType; +import com.baomidou.mybatisplus.annotation.TableField; +import com.baomidou.mybatisplus.annotation.TableId; +import com.baomidou.mybatisplus.annotation.TableName; +import io.swagger.v3.oas.annotations.media.Schema; +import java.util.Date; +import lombok.Data; + +/* +* @author: ziin +* @date: 2026/4/2 09:35 +*/ + +/** + * AI陪聊角色国际化表,用于存储不同语言下的角色名称、一句话描述和详细介绍 + */ +@Schema(description="AI陪聊角色国际化表,用于存储不同语言下的角色名称、一句话描述和详细介绍") +@Data +@TableName(value = "keyboard_ai_companion_i18n") +public class KeyboardAiCompanionI18n { + /** + * 主键ID + */ + @TableId(value = "id", type = IdType.AUTO) + @Schema(description="主键ID") + private Long id; + + /** + * 陪聊角色主表ID,对应 keyboard_ai_companion.id + */ + @TableField(value = "companion_id") + @Schema(description="陪聊角色主表ID,对应 keyboard_ai_companion.id") + private Long companionId; + + /** + * 语言标识,如 zh-CN、en-US、ja-JP + */ + @TableField(value = "\"locale\"") + @Schema(description="语言标识,如 zh-CN、en-US、ja-JP") + private String locale; + + /** + * 角色名称(多语言) + */ + @TableField(value = "\"name\"") + @Schema(description="角色名称(多语言)") + private String name; + + /** + * 一句话人设描述(多语言) + */ + @TableField(value = "short_desc") + @Schema(description="一句话人设描述(多语言)") + private String shortDesc; + + /** + * 角色详细介绍文案(多语言) + */ + @TableField(value = "intro_text") + @Schema(description="角色详细介绍文案(多语言)") + private String introText; + + /** + * 创建时间 + */ + @TableField(value = "created_at") + @Schema(description="创建时间") + private Date createdAt; + + /** + * 更新时间 + */ + @TableField(value = "updated_at") + @Schema(description="更新时间") + private Date updatedAt; +} \ No newline at end of file diff --git a/src/main/java/com/yolo/keyborad/service/KeyboardAiCompanionI18nService.java b/src/main/java/com/yolo/keyborad/service/KeyboardAiCompanionI18nService.java new file mode 100644 index 0000000..2ff4160 --- /dev/null +++ b/src/main/java/com/yolo/keyborad/service/KeyboardAiCompanionI18nService.java @@ -0,0 +1,13 @@ +package com.yolo.keyborad.service; + +import com.yolo.keyborad.model.entity.KeyboardAiCompanionI18n; +import com.baomidou.mybatisplus.extension.service.IService; + /* +* @author: ziin +* @date: 2026/4/2 09:35 +*/ + +public interface KeyboardAiCompanionI18nService extends IService{ + + +} diff --git a/src/main/java/com/yolo/keyborad/service/KeyboardAiCompanionService.java b/src/main/java/com/yolo/keyborad/service/KeyboardAiCompanionService.java index 8ebad84..f4ea011 100644 --- a/src/main/java/com/yolo/keyborad/service/KeyboardAiCompanionService.java +++ b/src/main/java/com/yolo/keyborad/service/KeyboardAiCompanionService.java @@ -20,7 +20,11 @@ public interface KeyboardAiCompanionService extends IService pageList(Integer pageNum, Integer pageSize); + IPage pageList(Integer pageNum, Integer pageSize, String acceptLanguage); + + default IPage pageList(Integer pageNum, Integer pageSize) { + return pageList(pageNum, pageSize, null); + } /** * 分页查询已上线的AI陪聊角色(带当前用户点赞状态) @@ -30,7 +34,11 @@ public interface KeyboardAiCompanionService extends IService pageListWithLikeStatus(Long userId, Integer pageNum, Integer pageSize); + IPage pageListWithLikeStatus(Long userId, Integer pageNum, Integer pageSize, String acceptLanguage); + + default IPage pageListWithLikeStatus(Long userId, Integer pageNum, Integer pageSize) { + return pageListWithLikeStatus(userId, pageNum, pageSize, null); + } /** * 根据AI人设ID获取系统提示词 @@ -46,7 +54,11 @@ public interface KeyboardAiCompanionService extends IService getLikedCompanions(Long userId); + List getLikedCompanions(Long userId, String acceptLanguage); + + default List getLikedCompanions(Long userId) { + return getLikedCompanions(userId, null); + } /** * 获取用户聊过天的AI角色列表 @@ -54,7 +66,11 @@ public interface KeyboardAiCompanionService extends IService getChattedCompanions(Long userId); + List getChattedCompanions(Long userId, String acceptLanguage); + + default List getChattedCompanions(Long userId) { + return getChattedCompanions(userId, null); + } /** * 根据ID获取AI角色详情(带点赞数、评论数和当前用户点赞状态) @@ -63,5 +79,9 @@ public interface KeyboardAiCompanionService extends IService implements KeyboardAiCompanionI18nService{ + +} diff --git a/src/main/java/com/yolo/keyborad/service/impl/KeyboardAiCompanionServiceImpl.java b/src/main/java/com/yolo/keyborad/service/impl/KeyboardAiCompanionServiceImpl.java index 82ae773..8f3df20 100644 --- a/src/main/java/com/yolo/keyborad/service/impl/KeyboardAiCompanionServiceImpl.java +++ b/src/main/java/com/yolo/keyborad/service/impl/KeyboardAiCompanionServiceImpl.java @@ -4,21 +4,26 @@ import cn.hutool.core.bean.BeanUtil; import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper; import com.baomidou.mybatisplus.core.metadata.IPage; import com.baomidou.mybatisplus.extension.plugins.pagination.Page; +import com.yolo.keyborad.mapper.KeyboardAiCompanionI18nMapper; import com.yolo.keyborad.common.ErrorCode; import com.yolo.keyborad.exception.BusinessException; import com.yolo.keyborad.model.entity.KeyboardAiCompanionComment; +import com.yolo.keyborad.model.entity.KeyboardAiCompanionI18n; import com.yolo.keyborad.model.entity.KeyboardAiCompanionLike; import com.yolo.keyborad.model.vo.AiCompanionVO; import com.yolo.keyborad.service.KeyboardAiCompanionCommentService; import com.yolo.keyborad.service.KeyboardAiCompanionLikeService; import com.yolo.keyborad.service.KeyboardAiChatMessageService; +import com.yolo.keyborad.utils.RequestLocaleUtils; import jakarta.annotation.Resource; import org.springframework.stereotype.Service; import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl; import com.yolo.keyborad.model.entity.KeyboardAiCompanion; import com.yolo.keyborad.mapper.KeyboardAiCompanionMapper; import com.yolo.keyborad.service.KeyboardAiCompanionService; +import org.springframework.util.StringUtils; +import java.util.Collections; import java.util.List; import java.util.Map; import java.util.Set; @@ -40,8 +45,11 @@ public class KeyboardAiCompanionServiceImpl extends ServiceImpl pageList(Integer pageNum, Integer pageSize) { + public IPage pageList(Integer pageNum, Integer pageSize, String acceptLanguage) { Page page = new Page<>(pageNum, pageSize); LambdaQueryWrapper queryWrapper = new LambdaQueryWrapper<>(); queryWrapper.eq(KeyboardAiCompanion::getStatus, 1) @@ -54,6 +62,7 @@ public class KeyboardAiCompanionServiceImpl extends ServiceImpl companionIds = entityPage.getRecords().stream() .map(KeyboardAiCompanion::getId) .collect(Collectors.toList()); + Map i18nMap = getCompanionI18nMap(companionIds, acceptLanguage); // 批量统计点赞数 Map likeCountMap = Map.of(); @@ -81,7 +90,7 @@ public class KeyboardAiCompanionServiceImpl extends ServiceImpl finalLikeCountMap = likeCountMap; Map finalCommentCountMap = commentCountMap; return entityPage.convert(entity -> { - AiCompanionVO vo = BeanUtil.copyProperties(entity, AiCompanionVO.class); + AiCompanionVO vo = toAiCompanionVO(entity, i18nMap); vo.setLikeCount(finalLikeCountMap.getOrDefault(entity.getId(), 0L).intValue()); vo.setCommentCount(finalCommentCountMap.getOrDefault(entity.getId(), 0L).intValue()); return vo; @@ -89,7 +98,7 @@ public class KeyboardAiCompanionServiceImpl extends ServiceImpl pageListWithLikeStatus(Long userId, Integer pageNum, Integer pageSize) { + public IPage pageListWithLikeStatus(Long userId, Integer pageNum, Integer pageSize, String acceptLanguage) { Page page = new Page<>(pageNum, pageSize); LambdaQueryWrapper queryWrapper = new LambdaQueryWrapper<>(); queryWrapper.eq(KeyboardAiCompanion::getStatus, 1) @@ -103,6 +112,7 @@ public class KeyboardAiCompanionServiceImpl extends ServiceImpl companionIds = entityPage.getRecords().stream() .map(KeyboardAiCompanion::getId) .collect(Collectors.toList()); + Map i18nMap = getCompanionI18nMap(companionIds, acceptLanguage); // 批量统计点赞数 Map likeCountMap = Map.of(); @@ -133,7 +143,7 @@ public class KeyboardAiCompanionServiceImpl extends ServiceImpl finalLikeCountMap = likeCountMap; Map finalCommentCountMap = commentCountMap; return entityPage.convert(entity -> { - AiCompanionVO vo = BeanUtil.copyProperties(entity, AiCompanionVO.class); + AiCompanionVO vo = toAiCompanionVO(entity, i18nMap); vo.setLikeCount(finalLikeCountMap.getOrDefault(entity.getId(), 0L).intValue()); vo.setCommentCount(finalCommentCountMap.getOrDefault(entity.getId(), 0L).intValue()); vo.setLiked(likedCompanionIds.contains(entity.getId())); @@ -154,7 +164,7 @@ public class KeyboardAiCompanionServiceImpl extends ServiceImpl getLikedCompanions(Long userId) { + public List getLikedCompanions(Long userId, String acceptLanguage) { // 获取用户点赞过的所有AI角色ID List likedCompanionIds = companionLikeService.getAllLikedCompanionIds(userId); if (likedCompanionIds.isEmpty()) { @@ -178,6 +188,7 @@ public class KeyboardAiCompanionServiceImpl extends ServiceImpl companionIds = companions.stream() .map(KeyboardAiCompanion::getId) .collect(Collectors.toList()); + Map i18nMap = getCompanionI18nMap(companionIds, acceptLanguage); // 批量统计点赞数 LambdaQueryWrapper likeWrapper = new LambdaQueryWrapper<>(); @@ -197,7 +208,7 @@ public class KeyboardAiCompanionServiceImpl extends ServiceImpl { - AiCompanionVO vo = BeanUtil.copyProperties(entity, AiCompanionVO.class); + AiCompanionVO vo = toAiCompanionVO(entity, i18nMap); vo.setLikeCount(likeCountMap.getOrDefault(entity.getId(), 0L).intValue()); vo.setCommentCount(commentCountMap.getOrDefault(entity.getId(), 0L).intValue()); vo.setLiked(true); // 用户已点赞 @@ -206,7 +217,7 @@ public class KeyboardAiCompanionServiceImpl extends ServiceImpl getChattedCompanions(Long userId) { + public List getChattedCompanions(Long userId, String acceptLanguage) { // 获取用户聊过天的所有AI角色ID List chattedCompanionIds = chatMessageService.getChattedCompanionIds(userId); if (chattedCompanionIds.isEmpty()) { @@ -228,6 +239,7 @@ public class KeyboardAiCompanionServiceImpl extends ServiceImpl companionIds = companions.stream() .map(KeyboardAiCompanion::getId) .collect(Collectors.toList()); + Map i18nMap = getCompanionI18nMap(companionIds, acceptLanguage); // 批量统计点赞数 LambdaQueryWrapper likeWrapper = new LambdaQueryWrapper<>(); @@ -256,7 +268,7 @@ public class KeyboardAiCompanionServiceImpl extends ServiceImpl { KeyboardAiCompanion entity = companionMap.get(id); - AiCompanionVO vo = BeanUtil.copyProperties(entity, AiCompanionVO.class); + AiCompanionVO vo = toAiCompanionVO(entity, i18nMap); vo.setLikeCount(likeCountMap.getOrDefault(entity.getId(), 0L).intValue()); vo.setCommentCount(commentCountMap.getOrDefault(entity.getId(), 0L).intValue()); vo.setLiked(likedCompanionIds.contains(entity.getId())); @@ -265,7 +277,7 @@ public class KeyboardAiCompanionServiceImpl extends ServiceImpl i18nMap = getCompanionI18nMap(List.of(companionId), acceptLanguage); + AiCompanionVO vo = toAiCompanionVO(companion, i18nMap); vo.setLikeCount((int) likeCount); vo.setCommentCount((int) commentCount); vo.setLiked(liked); return vo; } + + private AiCompanionVO toAiCompanionVO(KeyboardAiCompanion entity, Map i18nMap) { + AiCompanionVO vo = BeanUtil.copyProperties(entity, AiCompanionVO.class); + KeyboardAiCompanionI18n i18n = i18nMap.get(entity.getId()); + if (i18n == null) { + return vo; + } + vo.setName(i18n.getName()); + vo.setShortDesc(i18n.getShortDesc()); + vo.setIntroText(i18n.getIntroText()); + return vo; + } + + private Map getCompanionI18nMap(List companionIds, String acceptLanguage) { + String locale = RequestLocaleUtils.resolveLanguage(acceptLanguage); + if (companionIds == null || companionIds.isEmpty() || !StringUtils.hasText(locale)) { + return Collections.emptyMap(); + } + List i18nList = keyboardAiCompanionI18nMapper.selectList( + new LambdaQueryWrapper() + .in(KeyboardAiCompanionI18n::getCompanionId, companionIds) + .eq(KeyboardAiCompanionI18n::getLocale, locale) + ); + if (i18nList == null || i18nList.isEmpty()) { + return Collections.emptyMap(); + } + return i18nList.stream().collect(Collectors.toMap( + KeyboardAiCompanionI18n::getCompanionId, + item -> item, + (left, right) -> left + )); + } } diff --git a/src/main/resources/mapper/KeyboardAiCompanionI18nMapper.xml b/src/main/resources/mapper/KeyboardAiCompanionI18nMapper.xml new file mode 100644 index 0000000..ec82c47 --- /dev/null +++ b/src/main/resources/mapper/KeyboardAiCompanionI18nMapper.xml @@ -0,0 +1,20 @@ + + + + + + + + + + + + + + + + + + id, companion_id, "locale", "name", short_desc, intro_text, created_at, updated_at + + \ No newline at end of file diff --git a/src/main/resources/mapper/KeyboardAiCompanionMapper.xml b/src/main/resources/mapper/KeyboardAiCompanionMapper.xml index 6b1bf1e..5de85b8 100644 --- a/src/main/resources/mapper/KeyboardAiCompanionMapper.xml +++ b/src/main/resources/mapper/KeyboardAiCompanionMapper.xml @@ -5,13 +5,10 @@ - - - @@ -24,7 +21,7 @@ - id, "name", avatar_url, cover_image_url, gender, age_range, short_desc, intro_text, + id, avatar_url, cover_image_url, gender, age_range, personality_tags, speaking_style, system_prompt, "status", visibility, sort_order, popularity_score, created_at, updated_at