572 lines
18 KiB
Java
572 lines
18 KiB
Java
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<String> uploadFile(String bucketName, MultipartFile file){
|
||
return Result.success(minioUtil.getUrl(minioUtil.getFileUrl
|
||
(bucketName, minioUtil.uploadFile(bucketName, file))));
|
||
}
|
||
|
||
// @PostMapping("/addBookComment")
|
||
// public Result<String> 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<BookContent> 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<BookContent> 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<String> volumes = new ArrayList<>(); // 存储所有卷的标题
|
||
List<String> sections = new ArrayList<>(); // 存储所有节的标题
|
||
List<String> 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<BookContent> 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<String> getBookComment(Long id) {
|
||
// BookContent bookContent = bookContentService.getById(id);
|
||
// return Result.success(bookContent.getSectionContent());
|
||
// }
|
||
|
||
|
||
// @GetMapping("/getBookContent")
|
||
// public Result<String> getBookContent(String bookName, Long id) {
|
||
// BookContent bookContent = bookContentService.getBookContent(bookName, id);
|
||
// return Result.success(bookContent.getSectionContent());
|
||
// }
|
||
|
||
|
||
|
||
|
||
// @GetMapping("/getBookCommentByPath")
|
||
// public ResponseEntity<Map<String, Object>> getBookCommentByPath(@RequestParam("id") Long id) {
|
||
// // 从数据库中获取评论内容
|
||
// //String comments = bookContentService.getById(id).getSectionContent();
|
||
//
|
||
// BookContent byId = bookContentService.lambdaQuery()
|
||
// .eq(BookContent::getBookName, "大爱仙尊")
|
||
// .eq(BookContent::getSectionId, id).one();
|
||
//
|
||
// // 构造返回数据
|
||
// Map<String, Object> 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<String> testQwenStreaming(
|
||
@RequestParam(value = "message", required = false) String message) {
|
||
|
||
Flux<String> 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<String> ids,
|
||
@RequestParam("str") String str){
|
||
System.out.println("ids = " + ids);
|
||
System.out.println("str = " + str);
|
||
}
|
||
|
||
|
||
|
||
@GetMapping("/testGetParam")
|
||
public void testGetParam(@RequestParam("ids") List<String> 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<TestDate> byDate = testDateDao.findByDate(from);
|
||
System.out.println("byDate = " + byDate);
|
||
|
||
|
||
}
|
||
|
||
|
||
@PostMapping("/sendCode")
|
||
public void sendCode(@RequestParam String code){
|
||
|
||
System.out.println("code = " + code);
|
||
|
||
}
|
||
|
||
|
||
|
||
}
|
||
|
||
|