package com.guwan.backend.controller; import cn.hutool.json.JSONObject; import com.guwan.backend.annotation.OperationLog; import com.guwan.backend.client.SimpleTTSClient; import com.guwan.backend.client.VoiceServiceClient; import com.guwan.backend.common.Result; import com.guwan.backend.mongodb.*; import com.guwan.backend.pojo.entity.BookContent; import com.guwan.backend.util.MinioUtil; import dev.langchain4j.community.model.dashscope.QwenChatModel; import dev.langchain4j.community.model.dashscope.QwenStreamingChatModel; import dev.langchain4j.model.chat.response.ChatResponse; import dev.langchain4j.model.chat.response.StreamingChatResponseHandler; import io.minio.MinioClient; import lombok.RequiredArgsConstructor; import lombok.extern.slf4j.Slf4j; import okhttp3.OkHttpClient; import okhttp3.Request; import okhttp3.Response; import org.apache.poi.xslf.usermodel.XMLSlideShow; import org.apache.poi.xslf.usermodel.XSLFSlide; import org.apache.tika.metadata.Metadata; import org.apache.tika.parser.AutoDetectParser; import org.apache.tika.parser.ParseContext; import org.apache.tika.parser.Parser; import org.apache.tika.sax.BodyContentHandler; import org.springframework.web.bind.annotation.*; import org.springframework.web.multipart.MultipartFile; import reactor.core.publisher.Flux; import javax.imageio.ImageIO; import java.awt.*; import java.awt.geom.Rectangle2D; import java.awt.image.BufferedImage; import java.io.File; import java.io.FileInputStream; import java.io.IOException; import java.io.InputStream; import java.net.URL; import java.time.Instant; import java.time.LocalDate; import java.time.ZoneId; import java.util.ArrayList; import java.util.Date; import java.util.List; import java.util.UUID; import java.util.regex.Matcher; import java.util.regex.Pattern; @Slf4j @RestController @RequestMapping("/api/common") @RequiredArgsConstructor public class CommonController { private final MinioUtil minioUtil; private final VoiceServiceClient voiceServiceClient; private final SimpleTTSClient simpleTTSClient; private final MinioClient minioClient; //private final BookContentService bookContentService; private final MongodbUserService mongodbUserService; private final EveryReadDetailOfMongodbService everyReadDetailOfMongodbService; private final QwenChatModel qwenChatModel; private final QwenStreamingChatModel qwenStreamingChatModel; private final TestDateRepository testDateRepository; private final TestDateDao testDateDao; @PostMapping("/uploadFile") public Result uploadFile(String bucketName, MultipartFile file){ return Result.success(minioUtil.getUrl(minioUtil.getFileUrl (bucketName, minioUtil.uploadFile(bucketName, file)))); } // @PostMapping("/addBookComment") // public Result addBookComment(String url) { // log.debug(url); // // "http://localhost:9000/txt/8357cf6b-9637-4354-9ee6-2717141f665a.txt"; // OkHttpClient client = new OkHttpClient(); // // // 创建一个请求对象 // Request request = new Request.Builder() // .url(url) // .build(); // // // 发起同步请求 // try { // String content = getTextUsingOkHttp(client, request); // ArrayList bookContents = processContent(content); // bookContentService.saveBatch(bookContents); // // } catch (IOException e) { // e.printStackTrace(); // } // // return Result.success("ok"); // } // 通过 OkHttpClient 发起同步请求获取文件内容 public static String getTextUsingOkHttp(OkHttpClient client, Request request) throws IOException { try (Response response = client.newCall(request).execute()) { if (response.isSuccessful()) { return response.body().string(); // 返回文件内容 } else { throw new IOException("Unexpected code " + response); } } } // 处理文件内容,提取卷和节 public static ArrayList processContent(String content) { // 正则表达式,提取卷和节 String volumePattern = "第([一二三四五六七八九十]+)卷"; // 提取卷 String sectionPattern = "第([一二三四五六七八九十零百]+)节:(.*)"; // 提取节及其节名 // 提取卷 Pattern volumeRegex = Pattern.compile(volumePattern); Matcher volumeMatcher = volumeRegex.matcher(content); // 提取节 Pattern sectionRegex = Pattern.compile(sectionPattern); Matcher sectionMatcher = sectionRegex.matcher(content); // 列表来存储所有卷和节的内容 List volumes = new ArrayList<>(); // 存储所有卷的标题 List sections = new ArrayList<>(); // 存储所有节的标题 List sectionContents = new ArrayList<>(); // 存储每节的正文内容 // 收集卷的信息 while (volumeMatcher.find()) { String volume = "第" + volumeMatcher.group(1) + "卷"; volumes.add(volume); } // 收集节的信息 while (sectionMatcher.find()) { String sectionTitle = "第" + sectionMatcher.group(1) + "节:" + sectionMatcher.group(2).trim(); // 这里去掉节名前后空格 sections.add(sectionTitle); // 获取节的正文内容 int start = sectionMatcher.end(); // 获取节标题之后的位置 int end = content.length(); // 默认到文件末尾 // 查找下一个节的位置(即本节内容的结束位置) Matcher nextSectionMatcher = sectionRegex.matcher(content); if (nextSectionMatcher.find(start)) { end = nextSectionMatcher.start(); } // 获取当前节的正文内容 String sectionContent = content.substring(start, end).trim(); sectionContents.add(sectionContent); } // 标记是否是第一次匹配到“第一节” boolean isFirstSection = true; ArrayList bookContents = new ArrayList<>(); int sectionId = 1; // 输出卷和节信息 for (int i = 0; i < volumes.size(); i++) { // 输出卷的标题 // 输出该卷的每一节标题和正文内容 for (int j = 0; j < sections.size(); j++) { // System.out.print(volumes.get(i)); String section = sections.get(j); String sectionContent = sectionContents.get(j); // 输出节标题 // System.out.println(" " + section); // 输出节的正文内容 // System.out.println(" 正文: " + sectionContent); // 如果是“第一节”,并且不是第一次出现,递增卷的索引 if (section.contains("第一节") && !isFirstSection) { i++; // 不是第一次才递增 } // 第一次匹配到“第一节”后,标记为false isFirstSection = false; BookContent bookContent = new BookContent(); bookContent.setBookName("大爱仙尊"); bookContent.setVolume(volumes.get(i)); bookContent.setSection(section); bookContent.setSectionContent(sectionContent); bookContent.setSectionId(sectionId++); System.out.println("bookContent = " + bookContent); bookContents.add(bookContent); } } return bookContents; } // @GetMapping("/getBookComment") // public Result getBookComment(Long id) { // BookContent bookContent = bookContentService.getById(id); // return Result.success(bookContent.getSectionContent()); // } // @GetMapping("/getBookContent") // public Result getBookContent(String bookName, Long id) { // BookContent bookContent = bookContentService.getBookContent(bookName, id); // return Result.success(bookContent.getSectionContent()); // } // @GetMapping("/getBookCommentByPath") // public ResponseEntity> getBookCommentByPath(@RequestParam("id") Long id) { // // 从数据库中获取评论内容 // //String comments = bookContentService.getById(id).getSectionContent(); // // BookContent byId = bookContentService.lambdaQuery() // .eq(BookContent::getBookName, "大爱仙尊") // .eq(BookContent::getSectionId, id).one(); // // // 构造返回数据 // Map response = new HashMap<>(); // response.put("data", byId); // // return ResponseEntity.ok(response); // // } @GetMapping("/testMongodb") public Result testMongodb(){ User user = new User(); user.setId("1"); user.setName("1"); user.setAge(1L); user.setEmail("1"); mongodbUserService.save(user); return Result.success(); } @PostMapping("/everyRead") public Result everyRead(@RequestBody EveryReadDetailOfMongodb everyReadDetailOfMongodb){ everyReadDetailOfMongodbService.save(everyReadDetailOfMongodb); return Result.success(); } @GetMapping("/getUserOneTotalTime") @OperationLog(description = "统计用户某本书的读书时间") public Result getUserOneTotalTime(@RequestParam Long userId){ //return Result.success(); // everyReadDetailOfMongodbService.getUserOneTotalTime(userId); return Result.success(everyReadDetailOfMongodbService.getUserOneTotalTime(userId)); } /** * model 默认值 /model/faster-whisper-small/ */ @PostMapping("/convertVoiceToText") public Result convertVoiceToText(MultipartFile file, String model) { if (model == null){ model = "/model/faster-whisper-small/"; } return Result.success(voiceServiceClient.voiceToText(file, model)); } @PostMapping("/simpleTTS") public Result simpleTTS(String input, String voiceModel) { if (voiceModel == null) { voiceModel = "zh-CN-XiaoxiaoNeural"; } // 使用 JSONObject 构造JSON JSONObject jsonObject = new JSONObject(); jsonObject.putOpt("input", input); jsonObject.putOpt("voice", voiceModel); String jsonInputString = jsonObject.toString(); System.out.println(jsonInputString); // jsonInputString = "{\"input\": \"想听个啥123\", \"voice\": \"zh-CN-XiaoxiaoNeural\", \"style\": \"\", \"rate\": 0, \"pitch\": 0}"; String url = minioUtil.getUrl(minioUtil.getFileUrl("temp", minioUtil.uploadByteArray( simpleTTSClient.saveAudio(jsonInputString), "mp3"))); return Result.success(url); } @PostMapping("/testPart") public void testPart(@RequestPart(value = "file", required = false) MultipartFile file, @RequestPart(value = "str1", required = false) String str1, @RequestPart(value = "f1", required = false) String f1) { String s = null; if (file != null) { s = minioUtil.uploadFile("temp", file); } System.out.println("s = " + s); System.out.println("str1 = " + str1); System.out.println("f1 = " + f1); } @PostMapping("/testPartOfFloat") public void testPartOfFloat(@RequestPart(value = "file", required = false) MultipartFile file, @RequestPart(value = "str1", required = false) String str1, @RequestPart(value = "f1", required = false) Float f1) { String s = null; if (file != null) { s = minioUtil.uploadFile("temp", file); } System.out.println("s = " + s); System.out.println("str1 = " + str1); System.out.println("f1 = " + f1); } @PostMapping("/testParam") public void testParm(@RequestPart(value = "file", required = false) MultipartFile file, @RequestParam(value = "str1", required = true) String str1, @RequestParam(value = "f1", required = false) Float f1) { String s = null; if (file != null) { s = minioUtil.uploadFile("temp", file); } System.out.println("s = " + s); System.out.println("str1 = " + str1); System.out.println("f1 = " + f1); } @GetMapping("/testQwen") public Result testQwen(@RequestParam(value = "str1", required = false) String message) { var response = qwenChatModel.chat(message); System.out.println("response = " + response); return Result.success(response); } @GetMapping(value = "/testQwenStreaming", produces = "text/steam;charset=UTF-8") public Flux testQwenStreaming( @RequestParam(value = "message", required = false) String message) { Flux flux = Flux.create(fluxSink -> { qwenStreamingChatModel.chat(message, new StreamingChatResponseHandler() { //每一次流式响应的文本 @Override public void onPartialResponse(String partialResponse) { fluxSink.next(partialResponse); } //响应结束的文本 @Override public void onCompleteResponse(ChatResponse chatResponse) { fluxSink.complete(); } @Override public void onError(Throwable throwable) { fluxSink.error(throwable); } }); }); return flux; } @GetMapping("/PPTToImageConverter") public void PPTToImageConverter() throws IOException { String pptFile = "D:\\00_桌面\\公司简介.pptx"; // PPT 文件路径 String outputDir = "output_images"; // 输出目录 FileInputStream inputStream = new FileInputStream(pptFile); XMLSlideShow ppt = new XMLSlideShow(inputStream); inputStream.close(); // 创建输出目录 File dir = new File(outputDir); if (!dir.exists()) { dir.mkdirs(); } // 获取幻灯片 int slideNumber = 1; for (XSLFSlide slide : ppt.getSlides()) { Dimension pgsize = ppt.getPageSize(); BufferedImage img = new BufferedImage(pgsize.width, pgsize.height, BufferedImage.TYPE_INT_ARGB); Graphics2D graphics = img.createGraphics(); // 设置背景为白色 graphics.setPaint(Color.WHITE); graphics.fill(new Rectangle2D.Float(0, 0, pgsize.width, pgsize.height)); // 渲染幻灯片 slide.draw(graphics); // 输出为图片 File outputFile = new File(outputDir + "/slide_" + slideNumber + ".png"); ImageIO.write(img, "png", outputFile); System.out.println("Saved slide: " + outputFile.getAbsolutePath()); slideNumber++; } ppt.close(); } @GetMapping("/videoDuration") public void VideoDuration() throws IOException { String preSignedUrl = "http://localhost:9000/videos/ffffad37-9804-4765-ae18-3f8dcda9bea8.mp4"; // Minio 预签名 URL // minioClient.getObject() InputStream stream = minioUtil.getFileInputStream("videos", "ffffad37-9804-4765-ae18-3f8dcda9bea8.mp4"); System.out.println("stream = " + stream); try { Metadata metadata = new Metadata(); Parser parser = new AutoDetectParser(); parser.parse(stream, new BodyContentHandler(), metadata, new ParseContext()); String duration = metadata.get("duration"); System.out.println("视频时长(毫秒): " + duration); } catch (Exception e) { e.printStackTrace(); } } @PostMapping("/testPostUseParam") //测试公司写法 public void testPostUseParam(@RequestParam("ids") List ids, @RequestParam("str") String str){ System.out.println("ids = " + ids); System.out.println("str = " + str); } @GetMapping("/testGetParam") public void testGetParam(@RequestParam("ids") List ids, @RequestParam("str") String str){ System.out.println("ids = " + ids); System.out.println("str = " + str); } @GetMapping("/testDate") public void testDate(){ TestDate testDate = new TestDate(); testDate.setId(UUID.randomUUID().toString()); Instant now = Instant.now(); //Instant now = Instant.now(); // 获取当前系统默认时区 ZoneId zoneId = ZoneId.systemDefault(); // 获取今天的 00:00:00 Instant todayStart = LocalDate.now(zoneId) .atStartOfDay(zoneId) .toInstant(); // 假设 testDate 有一个 setDate(Instant instant) 方法 testDate.setDate(Date.from(todayStart)); // testDate.setDate(new Date()); testDateRepository.insert(testDate); } @GetMapping("/testDateFind") public void testDateFind(){ TestDate testDate = new TestDate(); testDate.setId(UUID.randomUUID().toString()); Instant now = Instant.now(); //Instant now = Instant.now(); // 获取当前系统默认时区 ZoneId zoneId = ZoneId.systemDefault(); // 获取今天的 00:00:00 Instant todayStart = LocalDate.now(zoneId) .atStartOfDay(zoneId) .toInstant(); Date from = Date.from(todayStart); List byDate = testDateDao.findByDate(from); System.out.println("byDate = " + byDate); } @PostMapping("/sendCode") public void sendCode(@RequestParam String code){ System.out.println("code = " + code); } }