TASK:LLM;

This commit is contained in:
shahaibo
2025-05-18 12:46:12 +08:00
parent bf92edb267
commit 59ffa38ff7
23 changed files with 600 additions and 8 deletions

View File

@@ -0,0 +1,40 @@
package com.ai.da.service;
import com.ai.da.common.response.PageBaseResponse;
import com.ai.da.mapper.primary.entity.Account;
import com.ai.da.mapper.primary.entity.AccountExtend;
import com.ai.da.mapper.primary.entity.ChatMessage;
import com.ai.da.mapper.primary.entity.TrialOrder;
import com.ai.da.model.dto.*;
import com.ai.da.model.vo.AccountLoginVO;
import com.ai.da.model.vo.AccountPreLoginVO;
import com.ai.da.model.vo.BindEmailVO;
import com.ai.da.model.vo.PersonalHomepageVO;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.service.IService;
import org.springframework.web.multipart.MultipartFile;
import org.springframework.web.servlet.mvc.method.annotation.SseEmitter;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpSession;
import java.util.List;
import java.util.Map;
import java.util.Set;
/**
* 服务类
*
* @author easy-generator
* @since 2022-08-11
*/
public interface LLMService {
SseEmitter stream(String prompt, Long projectId, String fileUrl, String token);
Long chatCreateProject(String prompt);
List<String> uploadFile(MultipartFile file);
List<ChatMessage> getChatHistory(Long projectId);
}

View File

@@ -1,8 +1,9 @@
package com.ai.da.service;
import com.ai.da.model.dto.ProgressDTO;
import com.ai.da.model.vo.AuthPrincipalVo;
public interface ProductImageService {
void asyncInitialize(Long brandId);
void asyncInitialize(Long brandId, AuthPrincipalVo userHolder);
// double getInitializeProgress(Long brandId);
}

View File

@@ -62,4 +62,6 @@ public interface SysFileService extends IService<SysFile> {
List<SysFile> getByIds(List<Long> ids);
SysFile getOneBySex(Long styleId, String sex, String ageGroup);
SysFile getOneBySex(String styleName, String sex, String ageGroup);
}

View File

@@ -622,6 +622,10 @@ public class CollectionElementServiceImpl extends ServiceImpl<CollectionElementM
}else {
elementVO.setDesignNum(8);
}
if (null != designDTO.getBrandId()) {
elementVO.setBrandId(designDTO.getBrandId());
elementVO.setBrandScale(designDTO.getBrandScale());
}
return elementVO;
}

View File

@@ -0,0 +1,288 @@
package com.ai.da.service.impl;
import com.ai.da.common.constant.CommonConstant;
import com.ai.da.common.context.UserContext;
import com.ai.da.common.security.jwt.JWTTokenHelper;
import com.ai.da.common.utils.MinioUtil;
import com.ai.da.mapper.primary.*;
import com.ai.da.mapper.primary.entity.*;
import com.ai.da.model.dto.ReceiveDesignParam;
import com.ai.da.model.enums.*;
import com.ai.da.model.vo.AuthPrincipalVo;
import com.ai.da.python.PythonService;
import com.ai.da.service.DesignService;
import com.ai.da.service.LLMService;
import com.ai.da.service.SysFileService;
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import org.springframework.stereotype.Service;
import org.springframework.util.StringUtils;
import org.springframework.web.multipart.MultipartFile;
import org.springframework.web.servlet.mvc.method.annotation.SseEmitter;
import javax.annotation.Resource;
import java.io.BufferedReader;
import java.io.InputStreamReader;
import java.io.OutputStream;
import java.net.HttpURLConnection;
import java.net.URL;
import java.nio.charset.StandardCharsets;
import java.time.LocalDateTime;
import java.util.ArrayList;
import java.util.List;
import java.util.Objects;
import java.util.UUID;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
@Service
public class LLMServiceImpl implements LLMService {
@Resource
private ChatMessageMapper chatMessageMapper;
@Resource
private ProjectMapper projectMapper;
@Resource
private PythonService pythonService;
@Resource
private WorkspaceMapper workspaceMapper;
@Resource
private SysFileService sysFileService;
@Resource
private MinioUtil minioUtil;
@Resource
private StyleMapper styleMapper;
@Resource
private WorkspaceRelStyleMapper workspaceRelStyleMapper;
@Resource
private JWTTokenHelper jwtTokenHelper;
@Resource
private DesignService designService;
private final ExecutorService executor = Executors.newCachedThreadPool();
@Override
public SseEmitter stream(String prompt, Long projectId, String fileUrl, String token) {
SseEmitter emitter = new SseEmitter(0L); // 永不超时
executor.submit(() -> {
try {
boolean validate = jwtTokenHelper.validateToken(token);
if (validate) {
AuthPrincipalVo principal = jwtTokenHelper.parserToUser(token);
Long accountId = principal.getId();
int userSeq = getNextSeq(projectId); // 获取当前session下一条消息序号
String url = "http://18.167.251.121:10002/chat-stream";
HttpURLConnection conn = (HttpURLConnection) new URL(url).openConnection();
conn.setRequestMethod("POST");
conn.setDoOutput(true);
conn.setRequestProperty("Content-Type", "application/json");
JSONObject jsonBodyObject = new JSONObject();
jsonBodyObject.put("session_id", projectId.toString());
jsonBodyObject.put("role", "user");
jsonBodyObject.put("image", ""); // 可扩展
jsonBodyObject.put("file", fileUrl != null ? fileUrl : "");
jsonBodyObject.put("message", prompt);
jsonBodyObject.put("enable_thinking", false);
// 1. 存储用户输入
ChatMessage userMessage = new ChatMessage();
userMessage.setRole("user");
userMessage.setProjectId(projectId);
userMessage.setSeq(userSeq);
userMessage.setCreateTime(LocalDateTime.now());
userMessage.setContent(jsonBodyObject.toJSONString());
userMessage.setAccountId(accountId);
chatMessageMapper.insert(userMessage);
try (OutputStream os = conn.getOutputStream()) {
byte[] input = jsonBodyObject.toJSONString().getBytes(StandardCharsets.UTF_8);
os.write(input, 0, input.length);
}
// 2. 流式接收并累积内容
StringBuilder responseBuilder = new StringBuilder();
try (BufferedReader reader = new BufferedReader(new InputStreamReader(conn.getInputStream(), StandardCharsets.UTF_8))) {
String line;
while ((line = reader.readLine()) != null) {
line = line.trim();
if (!line.isEmpty() && line.startsWith("data: ")) {
String jsonStr = line.substring(6);
System.out.println(jsonStr);
JSONObject json = JSON.parseObject(jsonStr);
String status = json.getString("status");
if ("[DONE]".equals(status)) {
break;
}
if (!StringUtils.isEmpty(status)) {
String content = json.getString("content");
if (!status.equals("[RUNNING]") && !status.equals("[DESIGN_SIGNAL]")) {
JSONObject toolsData = json.getJSONObject("tools_data");
ReceiveDesignParam receiveDesignParam = JSONObject.parseObject(JSONObject.toJSONString(toolsData), ReceiveDesignParam.class);
receiveDesignParam.setProjectId(projectId);
designService.receiveDesignParams(receiveDesignParam);
}
if (content != null) {
responseBuilder.append(content);
emitter.send(json.toJSONString());
}
}
}
}
}
// 3. 存储系统回复
int systemSeq = getNextSeq(projectId);
ChatMessage systemMessage = new ChatMessage();
systemMessage.setRole("user");
systemMessage.setProjectId(projectId);
systemMessage.setSeq(systemSeq);
systemMessage.setCreateTime(LocalDateTime.now());
systemMessage.setContent(responseBuilder.toString());
systemMessage.setAccountId(accountId);
chatMessageMapper.insert(systemMessage);
}
emitter.complete();
} catch (Exception e) {
emitter.completeWithError(e);
}
});
return emitter;
}
@Override
public Long chatCreateProject(String prompt) {
AuthPrincipalVo userHolder = UserContext.getUserHolder();
JSONObject jsonObject = pythonService.getProjectParam(prompt);
JSONObject data = jsonObject.getJSONObject("data");
Project project = new Project();
LocalDateTime now = LocalDateTime.now();
project.setUpdateTime(now);
project.setCreateTime(now);
project.setAccountId(userHolder.getId());
project.setName(data.getString("project_name"));
project.setOriginal(1);
String process = data.getString("process");
if (StringUtils.isEmpty(process)) {
project.setProcess(DesignProcess.SERIES_DESIGN.name());
}else {
if (DesignProcess.isValidName(process)) {
project.setProcess(process);
}else {
project.setProcess(DesignProcess.SERIES_DESIGN.name());
}
}
projectMapper.insert(project);
Workspace workspace = new Workspace();
workspace.setAccountId(userHolder.getId());
workspace.setCreateTime(now);
String ageGroup = data.getString("ageGroup");
if (StringUtils.isEmpty(ageGroup)) {
workspace.setAgeGroup("Adult");
}else {
if (AgeGroup.isValidName(process)) {
workspace.setAgeGroup(ageGroup);
}else {
workspace.setAgeGroup("Adult");
}
}
String gender = data.getString("gender");
if (StringUtils.isEmpty(gender)) {
workspace.setSex("Female");
}else {
if (Sex.isValidName(gender)) {
workspace.setSex(gender);
}else {
workspace.setSex("Female");
}
}
String position = data.getString("position");
if (StringUtils.isEmpty(position)) {
workspace.setPosition("Overall");
}else {
if (Position.isValidName(position)) {
workspace.setPosition(position);
}else {
workspace.setPosition("Overall");
}
}
workspace.setSystemDesignerPercentage(30);
workspace.setProjectId(project.getId());
String style = data.getString("style");
String styleName = null;
if (StringUtils.isEmpty(style)) {
styleName = StyleEnum.NEW_CHINESE.name();
}else {
if (StyleEnum.isValidName(style)) {
styleName = style;
}else {
styleName = StyleEnum.NEW_CHINESE.name();
}
}
SysFile sysFile = sysFileService.getOneBySex(styleName, workspace.getSex(), workspace.getAgeGroup());
if (workspace.getSex().equals(Sex.FEMALE.getValue())) {
workspace.setMannequinFemaleId(sysFile.getId());
workspace.setMannequinFemaleType("System");
}else {
workspace.setMannequinMaleId(sysFile.getId());
workspace.setMannequinMaleType("System");
}
workspaceMapper.insert(workspace);
if (!StringUtils.isEmpty(styleName)) {
QueryWrapper<Style> qw = new QueryWrapper<>();
qw.lambda().eq(Style::getName, styleName);
Style style1 = styleMapper.selectOne(qw);
if (Objects.nonNull(style1)) {
WorkspaceRelStyle rel = new WorkspaceRelStyle();
rel.setWorkspaceId(workspace.getId());
rel.setStyleId(style1.getId());
workspaceRelStyleMapper.insert(rel);
}
}
return project.getId();
}
@Override
public List<String> uploadFile(MultipartFile file) {
AuthPrincipalVo userHolder = UserContext.getUserHolder();
String minioUrl = minioUtil.upload("chat-message", userHolder.getId() + "", file);
String preSignedUrl = minioUtil.getPreSignedUrl(minioUrl, CommonConstant.MINIO_IMAGE_EXPIRE_TIME);
List<String> result = new ArrayList<>();
result.add(minioUrl);
result.add(preSignedUrl);
return result;
}
@Override
public List<ChatMessage> getChatHistory(Long projectId) {
QueryWrapper<ChatMessage> qw = new QueryWrapper<>();
qw.lambda().eq(ChatMessage::getProjectId, projectId);
qw.lambda().orderByAsc(ChatMessage::getSeq);
List<ChatMessage> chatMessages = chatMessageMapper.selectList(qw);
return chatMessages;
}
private int getNextSeq(Long projectId) {
QueryWrapper<ChatMessage> qw = new QueryWrapper<>();
qw.lambda().eq(ChatMessage::getProjectId, projectId);
qw.lambda().orderByDesc(ChatMessage::getSeq);
qw.last("limit 1");
ChatMessage chatMessage = chatMessageMapper.selectOne(qw);
if (Objects.nonNull(chatMessage)) {
return chatMessage.getSeq() + 1;
}
return 1;
}
}

View File

@@ -1,6 +1,7 @@
package com.ai.da.service.impl;
import cn.hutool.core.collection.CollectionUtil;
import com.ai.da.common.context.UserContext;
import com.ai.da.common.utils.RedisUtil;
import com.ai.da.mapper.primary.BrandRelLibraryMapper;
import com.ai.da.mapper.primary.LibraryMapper;
@@ -10,12 +11,14 @@ import com.ai.da.mapper.primary.entity.Library;
import com.ai.da.mapper.primary.entity.ProductImageAttribute;
import com.ai.da.mapper.secondary.entity.AttributeRecognitionJSON;
import com.ai.da.model.dto.ProgressDTO;
import com.ai.da.model.vo.AuthPrincipalVo;
import com.ai.da.python.PythonService;
import com.ai.da.service.ProductImageService;
import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.scheduling.annotation.Async;
import org.springframework.stereotype.Component;
import org.springframework.stereotype.Service;
@@ -23,6 +26,7 @@ import org.springframework.stereotype.Service;
import javax.annotation.Resource;
import java.util.List;
import java.util.Set;
import java.util.UUID;
import java.util.stream.Collectors;
@Service
@@ -42,10 +46,11 @@ public class ProductImageServiceImpl implements ProductImageService {
@Resource
private RedisUtil redisUtil;
@Value("${minio.bucketName.users}")
private String userBucket;
@Async
@Override
public void asyncInitialize(Long brandId) {
public void asyncInitialize(Long brandId, AuthPrincipalVo userHolder) {
System.out.println(">>> [asyncInitialize] 当前线程:" + Thread.currentThread().getName());
String progressKey = String.valueOf(brandId);
@@ -73,7 +78,7 @@ public class ProductImageServiceImpl implements ProductImageService {
JSONArray data = result.getJSONArray("data");
for (int i = 0; i < data.size(); i++) {
JSONObject obj = data.getJSONObject(i);
String gender = library.getLevel2Type();
String gender = library.getLevel3Type();
String category = null;
if (gender.equals("Female")) {
category = obj.getString("category_female");
@@ -89,6 +94,10 @@ public class ProductImageServiceImpl implements ProductImageService {
attr.setCategory(category);
attr.setImgUrl(imgUrl);
attr.setLibraryId(libraryId);
String imageName = UUID.randomUUID().toString();
String objectName = userHolder.getId() + "/imageToSketch/" + imageName;
String sketchPath = pythonService.imageToSketch(imgUrl, userBucket, objectName, "2", "");
attr.setImgUrl(sketchPath);
productImageAttributeMapper.insert(attr);
}
}

View File

@@ -303,6 +303,29 @@ public class SysFileServiceImpl extends ServiceImpl<SysFileMapper, SysFile> impl
return null;
}
@Override
public SysFile getOneBySex(String styleName, String sex, String ageGroup) {
QueryWrapper<SysFile> qw = new QueryWrapper<>();
qw.lambda().eq(SysFile::getLevel1Type, "Models");
qw.lambda().eq(SysFile::getLevel2Type, sex);
QueryWrapper<SysFileExtra> sysFileExtraQW = new QueryWrapper<>();
sysFileExtraQW.lambda().eq(SysFileExtra::getAgeGroup, ageGroup);
Set<Long> collect = sysFileExtraMapper.selectList(sysFileExtraQW).stream().map(SysFileExtra::getSysId).collect(Collectors.toSet());
if (!CollectionUtils.isEmpty(collect)) {
qw.lambda().in(SysFile::getId, collect);
}
if (!StringUtils.isEmpty(styleName)) {
qw.lambda().eq(SysFile::getLevel3Type, styleName);
}
List<SysFile> sysFileList = sysFileMapper.selectList(qw);
if (!CollectionUtils.isEmpty(sysFileList)) {
return sysFileList.get(0);
}
return null;
}
public static void main(String[] args) {
Style style = new Style();
if (Objects.nonNull(style)) {

View File

@@ -1170,8 +1170,8 @@ public class UserLikeGroupServiceImpl extends ServiceImpl<UserLikeGroupMapper, U
}
@Override
public Boolean productImageInitialize(ProductImageInitializeDTO productImageInitializeDTO) {
productImageService.asyncInitialize(productImageInitializeDTO.getBrandId());
AuthPrincipalVo userHolder = UserContext.getUserHolder();
productImageService.asyncInitialize(productImageInitializeDTO.getBrandId(), userHolder);
return true;
}