|
|
@ -72,102 +72,7 @@ public class ImContentServiceImpl extends ServiceImpl<ImContentMapper, ImContent |
|
|
|
|
|
|
|
|
|
|
|
@Override |
|
|
|
@Override |
|
|
|
@Transactional(rollbackFor = Exception.class) |
|
|
|
@Transactional(rollbackFor = Exception.class) |
|
|
|
@SneakyThrows |
|
|
|
public ImContent chatCompletions(ImContent imContent) { |
|
|
|
public Map<String, Object> completions(ImContent imContent, MultipartFile file) { |
|
|
|
|
|
|
|
SecurityUtils.openInterfaceTemporaryLoginSession(imContent.getSendUserId()); |
|
|
|
|
|
|
|
if (imContent.getContentType().equals(ImMessageTypeEnum.AUDIO.getValue())) { |
|
|
|
|
|
|
|
Optional.ofNullable(file).orElseThrow(() -> new CheckedException("当前语音文件为空,请检查后重试!")); |
|
|
|
|
|
|
|
OpenAiService openAiService = AiUtil.getOpenAiService(); |
|
|
|
|
|
|
|
String speechName = "speech.mp3"; |
|
|
|
|
|
|
|
String sendFileName = IdUtil.simpleUUID() + StrUtil.DOT + FileUtil.extName(file.getOriginalFilename()); |
|
|
|
|
|
|
|
String receiveFileName = IdUtil.simpleUUID() + StrUtil.DOT + FileUtil.extName(speechName); |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// 构建发送文件信息进行OSS存储
|
|
|
|
|
|
|
|
OssFile sendOssOssFile = new OssFile() |
|
|
|
|
|
|
|
.setFileName(sendFileName) |
|
|
|
|
|
|
|
.setBucketName(ossProperties.getBucketName()) |
|
|
|
|
|
|
|
.setOriginal(file.getOriginalFilename()) |
|
|
|
|
|
|
|
.setType(FileUtil.extName(file.getOriginalFilename())) |
|
|
|
|
|
|
|
.setFileSize(file.getSize()) |
|
|
|
|
|
|
|
.setMimeType(file.getContentType()); |
|
|
|
|
|
|
|
ossTemplate.putObject(ossProperties.getBucketName(), sendFileName, file.getContentType(), file.getInputStream()); |
|
|
|
|
|
|
|
String sendVoiceUrl = ossTemplate.getObjectURL(ossProperties.getBucketName(), sendFileName); |
|
|
|
|
|
|
|
sendOssOssFile.setAvailablePath(sendVoiceUrl); |
|
|
|
|
|
|
|
fileService.save(sendOssOssFile); |
|
|
|
|
|
|
|
imContent.setFiles(sendOssOssFile.getId()); |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
File inputVoiceFile = File.createTempFile(FileUtil.getPrefix(file.getOriginalFilename()), StrUtil.DOT + FileUtil.extName(file.getOriginalFilename())); |
|
|
|
|
|
|
|
File outputVoiceFile = File.createTempFile(FileUtil.getPrefix(speechName), StrUtil.DOT + FileUtil.extName(speechName)); |
|
|
|
|
|
|
|
ImContent receiveContent; |
|
|
|
|
|
|
|
OssFile receiveOssOssFile; |
|
|
|
|
|
|
|
try { |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// 语音转文字
|
|
|
|
|
|
|
|
CreateTranscriptionRequest request = CreateTranscriptionRequest.builder() |
|
|
|
|
|
|
|
.model("whisper-1") |
|
|
|
|
|
|
|
.language("zh") |
|
|
|
|
|
|
|
.build(); |
|
|
|
|
|
|
|
FileUtil.writeBytes(file.getBytes(), inputVoiceFile); |
|
|
|
|
|
|
|
TranscriptionResult transcriptionResult = openAiService.createTranscription(request, inputVoiceFile); |
|
|
|
|
|
|
|
imContent.setContent(transcriptionResult.getText()); |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// ai涡轮增压
|
|
|
|
|
|
|
|
receiveContent = askChatCompletion(imContent); |
|
|
|
|
|
|
|
receiveContent.setContentType(ImMessageTypeEnum.AUDIO.getValue()); |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// 文字转语音
|
|
|
|
|
|
|
|
CreateSpeechRequest createSpeechRequest = CreateSpeechRequest.builder() |
|
|
|
|
|
|
|
.model("tts-1") |
|
|
|
|
|
|
|
.input(receiveContent.getContent()) |
|
|
|
|
|
|
|
.voice(openAiConfigProperties.getVoice()) |
|
|
|
|
|
|
|
.responseFormat(FileUtil.extName(speechName)) |
|
|
|
|
|
|
|
.speed(openAiConfigProperties.getSpeed()) |
|
|
|
|
|
|
|
.build(); |
|
|
|
|
|
|
|
ResponseBody responseBody = openAiService.createSpeech(createSpeechRequest); |
|
|
|
|
|
|
|
FileUtil.writeBytes(responseBody.bytes(), outputVoiceFile); |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// 获取输出音频时长
|
|
|
|
|
|
|
|
AudioFile outputAudioFile = AudioFileIO.read(outputVoiceFile); |
|
|
|
|
|
|
|
long outputVoiceDuration = outputAudioFile.getAudioHeader().getTrackLength(); |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// 构建发送文件信息进行OSS存储
|
|
|
|
|
|
|
|
receiveOssOssFile = new OssFile() |
|
|
|
|
|
|
|
.setFileName(receiveFileName) |
|
|
|
|
|
|
|
.setBucketName(ossProperties.getBucketName()) |
|
|
|
|
|
|
|
.setOriginal(speechName) |
|
|
|
|
|
|
|
.setType(FileUtil.extName(speechName)) |
|
|
|
|
|
|
|
.setFileSize(responseBody.contentLength()) |
|
|
|
|
|
|
|
.setDuration(outputVoiceDuration) |
|
|
|
|
|
|
|
.setMimeType(Objects.requireNonNull(responseBody.contentType()).toString()); |
|
|
|
|
|
|
|
ossTemplate.putObject(ossProperties.getBucketName(), receiveFileName, Objects.requireNonNull(responseBody.contentType()).toString(), FileUtil.getInputStream(outputVoiceFile)); |
|
|
|
|
|
|
|
String receiveVoiceUrl = ossTemplate.getObjectURL(ossProperties.getBucketName(), receiveFileName); |
|
|
|
|
|
|
|
receiveOssOssFile.setAvailablePath(receiveVoiceUrl); |
|
|
|
|
|
|
|
fileService.save(receiveOssOssFile); |
|
|
|
|
|
|
|
} catch (Exception e) { |
|
|
|
|
|
|
|
throw new CheckedException(e.getLocalizedMessage()); |
|
|
|
|
|
|
|
} finally { |
|
|
|
|
|
|
|
if (inputVoiceFile.delete()) |
|
|
|
|
|
|
|
System.out.println("已成功删除临时输入语音文件!"); |
|
|
|
|
|
|
|
if (outputVoiceFile.delete()) |
|
|
|
|
|
|
|
System.out.println("已成功删除临时输输出语音文件!"); |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// ai chat message build
|
|
|
|
|
|
|
|
receiveContent.setFiles(receiveOssOssFile.getId()); |
|
|
|
|
|
|
|
super.save(receiveContent); |
|
|
|
|
|
|
|
Map<String, Object> result = Convert.toMap(String.class, Object.class, receiveContent); |
|
|
|
|
|
|
|
result.putAll(Convert.toMap(String.class, Object.class, receiveOssOssFile)); |
|
|
|
|
|
|
|
return result; |
|
|
|
|
|
|
|
} else { |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// ai chat message build
|
|
|
|
|
|
|
|
ImContent receiveContent = askChatCompletion(imContent); |
|
|
|
|
|
|
|
super.save(receiveContent); |
|
|
|
|
|
|
|
return Convert.toMap(String.class, Object.class, receiveContent); |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
private ImContent askChatCompletion(ImContent imContent) { |
|
|
|
|
|
|
|
if (StrUtil.isBlank(imContent.getContent())) { |
|
|
|
if (StrUtil.isBlank(imContent.getContent())) { |
|
|
|
throw new CheckedException("提问内容不能为空请检查!"); |
|
|
|
throw new CheckedException("提问内容不能为空请检查!"); |
|
|
|
} |
|
|
|
} |
|
|
@ -195,25 +100,124 @@ public class ImContentServiceImpl extends ServiceImpl<ImContentMapper, ImContent |
|
|
|
return chatMessage; |
|
|
|
return chatMessage; |
|
|
|
}).collect(Collectors.toList()); |
|
|
|
}).collect(Collectors.toList()); |
|
|
|
|
|
|
|
|
|
|
|
// 提问消息
|
|
|
|
// Completion消息
|
|
|
|
ChatMessage askMessage = new ChatMessage(ChatMessageRole.USER.value(), imContent.getContent()); |
|
|
|
ChatMessage completionMessage = new ChatMessage(ChatMessageRole.USER.value(), imContent.getContent()); |
|
|
|
historyMessages.add(askMessage); |
|
|
|
historyMessages.add(completionMessage); |
|
|
|
|
|
|
|
|
|
|
|
ChatCompletionResult chatCompletionResult = AiUtil.getChatCompletion(historyMessages); |
|
|
|
ChatCompletionResult chatCompletionResult = AiUtil.getChatCompletion(historyMessages); |
|
|
|
List<ChatCompletionChoice> choiceList = chatCompletionResult.getChoices(); |
|
|
|
List<ChatCompletionChoice> choiceList = chatCompletionResult.getChoices(); |
|
|
|
|
|
|
|
|
|
|
|
if (choiceList.isEmpty()) { |
|
|
|
if (choiceList.isEmpty()) { |
|
|
|
throw new CheckedException("Ai生成解析失败!"); |
|
|
|
throw new CheckedException("Ai生成内容解析失败!"); |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
// 构建AI生成消息
|
|
|
|
// ai chat message build
|
|
|
|
return new ImContent() |
|
|
|
ImContent receiveContent = new ImContent() |
|
|
|
.setSendUserId(imContent.getReceiveUserId()) |
|
|
|
.setSendUserId(imContent.getReceiveUserId()) |
|
|
|
.setSendTime(LocalDateTime.now()) |
|
|
|
.setSendTime(LocalDateTime.now()) |
|
|
|
.setReceiveUserId(SecurityUtils.getCasUser().getId()) |
|
|
|
.setReceiveUserId(SecurityUtils.getCasUser().getId()) |
|
|
|
.setReceiveTime(LocalDateTime.now()) |
|
|
|
.setReceiveTime(LocalDateTime.now()) |
|
|
|
.setContent(choiceList.get(0).getMessage().getContent()) |
|
|
|
.setContent(choiceList.get(0).getMessage().getContent()) |
|
|
|
.setContentType(ImMessageTypeEnum.TEXT.getValue()); |
|
|
|
.setContentType(imContent.getContentType()); |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
super.save(receiveContent); |
|
|
|
|
|
|
|
return receiveContent; |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
@Override |
|
|
|
|
|
|
|
@SneakyThrows |
|
|
|
|
|
|
|
@Transactional(rollbackFor = Exception.class) |
|
|
|
|
|
|
|
public ImContent audioTranscriptions(ImContent imContent, MultipartFile file) { |
|
|
|
|
|
|
|
Optional.ofNullable(file).orElseThrow(() -> new CheckedException("当前语音文件为空,请检查后重试!")); |
|
|
|
|
|
|
|
OpenAiService openAiService = AiUtil.getOpenAiService(); |
|
|
|
|
|
|
|
String sendFileName = IdUtil.simpleUUID() + StrUtil.DOT + FileUtil.extName(file.getOriginalFilename()); |
|
|
|
|
|
|
|
File inputVoiceFile = File.createTempFile(FileUtil.getPrefix(file.getOriginalFilename()), StrUtil.DOT + FileUtil.extName(file.getOriginalFilename())); |
|
|
|
|
|
|
|
try { |
|
|
|
|
|
|
|
// 获取输入音频时长
|
|
|
|
|
|
|
|
FileUtil.writeBytes(file.getBytes(), inputVoiceFile); |
|
|
|
|
|
|
|
AudioFile inputAudioFile = AudioFileIO.read(inputVoiceFile); |
|
|
|
|
|
|
|
long inputVoiceDuration = inputAudioFile.getAudioHeader().getTrackLength(); |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// 构建发送文件信息进行OSS存储
|
|
|
|
|
|
|
|
OssFile sendOssOssFile = new OssFile() |
|
|
|
|
|
|
|
.setFileName(sendFileName) |
|
|
|
|
|
|
|
.setBucketName(ossProperties.getBucketName()) |
|
|
|
|
|
|
|
.setOriginal(file.getOriginalFilename()) |
|
|
|
|
|
|
|
.setType(FileUtil.extName(file.getOriginalFilename())) |
|
|
|
|
|
|
|
.setDuration(inputVoiceDuration) |
|
|
|
|
|
|
|
.setFileSize(file.getSize()) |
|
|
|
|
|
|
|
.setMimeType(file.getContentType()); |
|
|
|
|
|
|
|
ossTemplate.putObject(ossProperties.getBucketName(), sendFileName, file.getContentType(), file.getInputStream()); |
|
|
|
|
|
|
|
String sendVoiceUrl = ossTemplate.getObjectURL(ossProperties.getBucketName(), sendFileName); |
|
|
|
|
|
|
|
sendOssOssFile.setAvailablePath(sendVoiceUrl); |
|
|
|
|
|
|
|
fileService.save(sendOssOssFile); |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// 语音转文字
|
|
|
|
|
|
|
|
CreateTranscriptionRequest request = CreateTranscriptionRequest.builder() |
|
|
|
|
|
|
|
.model("whisper-1") |
|
|
|
|
|
|
|
.language("zh") |
|
|
|
|
|
|
|
.build(); |
|
|
|
|
|
|
|
TranscriptionResult transcriptionResult = openAiService.createTranscription(request, inputVoiceFile); |
|
|
|
|
|
|
|
imContent.setContent(transcriptionResult.getText()); |
|
|
|
|
|
|
|
imContent.setFiles(sendOssOssFile.getId()); |
|
|
|
|
|
|
|
} catch (Exception e) { |
|
|
|
|
|
|
|
throw new CheckedException(e.getLocalizedMessage()); |
|
|
|
|
|
|
|
} finally { |
|
|
|
|
|
|
|
if (inputVoiceFile.delete()) |
|
|
|
|
|
|
|
System.out.println("已成功删除临时输入语音文件!"); |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
return imContent; |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
@Override |
|
|
|
|
|
|
|
@SneakyThrows |
|
|
|
|
|
|
|
@Transactional(rollbackFor = Exception.class) |
|
|
|
|
|
|
|
public OssFile audioSpeech(ImContent imContent) { |
|
|
|
|
|
|
|
Optional.ofNullable(imContent.getId()).orElseThrow(() -> new CheckedException("当前聊天内容ID必传,需要进行文件绑定请检查后重试!")); |
|
|
|
|
|
|
|
OpenAiService openAiService = AiUtil.getOpenAiService(); |
|
|
|
|
|
|
|
String speechName = "speech.mp3"; |
|
|
|
|
|
|
|
String receiveFileName = IdUtil.simpleUUID() + StrUtil.DOT + FileUtil.extName(speechName); |
|
|
|
|
|
|
|
File outputVoiceFile = File.createTempFile(FileUtil.getPrefix(speechName), StrUtil.DOT + FileUtil.extName(speechName)); |
|
|
|
|
|
|
|
OssFile receiveOssOssFile; |
|
|
|
|
|
|
|
try { |
|
|
|
|
|
|
|
// 文字转语音
|
|
|
|
|
|
|
|
CreateSpeechRequest createSpeechRequest = CreateSpeechRequest.builder() |
|
|
|
|
|
|
|
.model("tts-1") |
|
|
|
|
|
|
|
.input(imContent.getContent()) |
|
|
|
|
|
|
|
.voice(openAiConfigProperties.getVoice()) |
|
|
|
|
|
|
|
.responseFormat(FileUtil.extName(speechName)) |
|
|
|
|
|
|
|
.speed(openAiConfigProperties.getSpeed()) |
|
|
|
|
|
|
|
.build(); |
|
|
|
|
|
|
|
ResponseBody responseBody = openAiService.createSpeech(createSpeechRequest); |
|
|
|
|
|
|
|
FileUtil.writeBytes(responseBody.bytes(), outputVoiceFile); |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// 获取输出音频时长
|
|
|
|
|
|
|
|
AudioFile outputAudioFile = AudioFileIO.read(outputVoiceFile); |
|
|
|
|
|
|
|
long outputVoiceDuration = outputAudioFile.getAudioHeader().getTrackLength(); |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// 构建发送文件信息进行OSS存储
|
|
|
|
|
|
|
|
receiveOssOssFile = new OssFile() |
|
|
|
|
|
|
|
.setFileName(receiveFileName) |
|
|
|
|
|
|
|
.setBucketName(ossProperties.getBucketName()) |
|
|
|
|
|
|
|
.setOriginal(speechName) |
|
|
|
|
|
|
|
.setType(FileUtil.extName(speechName)) |
|
|
|
|
|
|
|
.setFileSize(responseBody.contentLength()) |
|
|
|
|
|
|
|
.setDuration(outputVoiceDuration) |
|
|
|
|
|
|
|
.setMimeType(Objects.requireNonNull(responseBody.contentType()).toString()); |
|
|
|
|
|
|
|
ossTemplate.putObject(ossProperties.getBucketName(), receiveFileName, Objects.requireNonNull(responseBody.contentType()).toString(), FileUtil.getInputStream(outputVoiceFile)); |
|
|
|
|
|
|
|
String receiveVoiceUrl = ossTemplate.getObjectURL(ossProperties.getBucketName(), receiveFileName); |
|
|
|
|
|
|
|
receiveOssOssFile.setAvailablePath(receiveVoiceUrl); |
|
|
|
|
|
|
|
fileService.save(receiveOssOssFile); |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// 给当前音频聊天内容绑定音频文件
|
|
|
|
|
|
|
|
super.update(Wrappers.<ImContent>lambdaUpdate().eq(ImContent::getId, imContent.getId()).set(ImContent::getFiles, receiveOssOssFile.getId())); |
|
|
|
|
|
|
|
} catch (Exception e) { |
|
|
|
|
|
|
|
throw new CheckedException(e.getLocalizedMessage()); |
|
|
|
|
|
|
|
} finally { |
|
|
|
|
|
|
|
if (outputVoiceFile.delete()) |
|
|
|
|
|
|
|
System.out.println("已成功删除临时输出语音文件!"); |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
return receiveOssOssFile; |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
} |
|
|
|
} |
|
|
|