fix: 修复一事一流程元数据添加失败,添加语音转文字接口
This commit is contained in:
parent
85393210fa
commit
919ab51570
|
|
@ -1,6 +1,7 @@
|
|||
import request from '@/utils/request'
|
||||
import requestStream from '@/utils/requestStream'
|
||||
|
||||
import { fileUploadRequest } from '@/utils/request'
|
||||
|
||||
|
||||
// 聊天消息相关接口定义
|
||||
|
|
@ -85,3 +86,11 @@ export const stopMessagesStream = (chatType: Number,taskId: string, userId: stri
|
|||
}
|
||||
})
|
||||
}
|
||||
|
||||
export const voiceToText = (data: FormData) => {
|
||||
return fileUploadRequest({
|
||||
url: '/brichat-service/chat/voiceToText',
|
||||
method: 'post',
|
||||
data
|
||||
})
|
||||
}
|
||||
|
|
|
|||
|
|
@ -24,6 +24,32 @@
|
|||
:autosize="{ minRows: 1, maxRows: 4 }"
|
||||
>
|
||||
</el-input>
|
||||
<!-- 语音录音按钮 -->
|
||||
<button
|
||||
class="voice-button"
|
||||
@mousedown="startRecording"
|
||||
@mouseup="stopRecording"
|
||||
@mouseleave="stopRecording"
|
||||
@touchstart="startRecording"
|
||||
@touchend="stopRecording"
|
||||
:disabled="isLoading"
|
||||
:class="{ 'recording': isRecording }"
|
||||
>
|
||||
<template v-if="isRecording">
|
||||
<div class="recording-animation">
|
||||
<svg viewBox="0 0 24 24" class="voice-icon recording">
|
||||
<path fill="currentColor" d="M12 14c1.66 0 2.99-1.34 2.99-3L15 5c0-1.66-1.34-3-3-3S9 3.34 9 5v6c0 1.66 1.34 3 3 3zm5.3-3c0 3-2.54 5.1-5.3 5.1S6.7 14 6.7 11H5c0 3.41 2.72 6.23 6 6.72V21h2v-3.28c3.28-.48 6-3.3 6-6.72h-1.7z"/>
|
||||
</svg>
|
||||
</div>
|
||||
</template>
|
||||
<template v-else-if="isProcessingVoice">
|
||||
<span class="loading-icon voice-loading"></span>
|
||||
</template>
|
||||
<svg v-else viewBox="0 0 24 24" class="voice-icon">
|
||||
<path fill="currentColor" d="M12 14c1.66 0 2.99-1.34 2.99-3L15 5c0-1.66-1.34-3-3-3S9 3.34 9 5v6c0 1.66 1.34 3 3 3zm5.3-3c0 3-2.54 5.1-5.3 5.1S6.7 14 6.7 11H5c0 3.41 2.72 6.23 6 6.72V21h2v-3.28c3.28-.48 6-3.3 6-6.72h-1.7z"/>
|
||||
</svg>
|
||||
</button>
|
||||
|
||||
<el-button
|
||||
type="primary"
|
||||
class="send-button"
|
||||
|
|
@ -45,8 +71,10 @@
|
|||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
import { ref, watch } from 'vue'
|
||||
import { ref, watch, onUnmounted } from 'vue'
|
||||
import { useI18n } from 'vue-i18n'
|
||||
import { voiceToText } from '@/api/chat'
|
||||
import { ElMessage } from 'element-plus'
|
||||
|
||||
const { t } = useI18n()
|
||||
|
||||
|
|
@ -69,6 +97,12 @@ const emit = defineEmits<Emits>()
|
|||
|
||||
const inputText = ref(props.modelValue)
|
||||
|
||||
// 语音录制相关状态
|
||||
const isRecording = ref(false)
|
||||
const isProcessingVoice = ref(false)
|
||||
let mediaRecorder: MediaRecorder | null = null
|
||||
let audioChunks: Blob[] = []
|
||||
|
||||
// 监听输入值变化
|
||||
watch(inputText, (newValue) => {
|
||||
emit('update:modelValue', newValue)
|
||||
|
|
@ -78,6 +112,119 @@ watch(inputText, (newValue) => {
|
|||
watch(() => props.modelValue, (newValue) => {
|
||||
inputText.value = newValue
|
||||
})
|
||||
|
||||
// 开始录音
|
||||
const startRecording = async () => {
|
||||
if (isRecording.value || isProcessingVoice.value) return
|
||||
|
||||
try {
|
||||
const stream = await navigator.mediaDevices.getUserMedia({
|
||||
audio: {
|
||||
echoCancellation: true,
|
||||
noiseSuppression: true,
|
||||
autoGainControl: true
|
||||
}
|
||||
})
|
||||
|
||||
// 检查浏览器支持的音频格式
|
||||
const mimeTypes = [
|
||||
'audio/webm;codecs=opus',
|
||||
'audio/webm',
|
||||
'audio/mp4',
|
||||
'audio/wav'
|
||||
]
|
||||
|
||||
let selectedMimeType = 'audio/webm'
|
||||
for (const mimeType of mimeTypes) {
|
||||
if (MediaRecorder.isTypeSupported(mimeType)) {
|
||||
selectedMimeType = mimeType
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
mediaRecorder = new MediaRecorder(stream, { mimeType: selectedMimeType })
|
||||
audioChunks = []
|
||||
|
||||
mediaRecorder.ondataavailable = (event) => {
|
||||
if (event.data.size > 0) {
|
||||
audioChunks.push(event.data)
|
||||
}
|
||||
}
|
||||
|
||||
mediaRecorder.onstop = async () => {
|
||||
const audioBlob = new Blob(audioChunks, { type: selectedMimeType })
|
||||
await processVoiceToText(audioBlob)
|
||||
|
||||
// 停止所有音频轨道
|
||||
stream.getTracks().forEach(track => track.stop())
|
||||
}
|
||||
|
||||
mediaRecorder.start()
|
||||
isRecording.value = true
|
||||
|
||||
} catch (error) {
|
||||
console.error('获取麦克风权限失败:', error)
|
||||
ElMessage.error('无法访问麦克风,请检查权限设置')
|
||||
}
|
||||
}
|
||||
|
||||
// 停止录音
|
||||
const stopRecording = () => {
|
||||
if (!isRecording.value || !mediaRecorder) return
|
||||
|
||||
isRecording.value = false
|
||||
mediaRecorder.stop()
|
||||
}
|
||||
|
||||
// 处理语音转文字
|
||||
const processVoiceToText = async (audioBlob: Blob) => {
|
||||
if (audioBlob.size === 0) {
|
||||
ElMessage.warning('录音时间过短,请重新录制')
|
||||
return
|
||||
}
|
||||
|
||||
isProcessingVoice.value = true
|
||||
|
||||
try {
|
||||
const formData = new FormData()
|
||||
|
||||
// 根据录音格式设置文件扩展名
|
||||
const fileExtension = audioBlob.type.includes('wav') ? 'wav' :
|
||||
audioBlob.type.includes('mp4') ? 'mp3' : 'webm'
|
||||
|
||||
formData.append('file', audioBlob, `recording.${fileExtension}`)
|
||||
|
||||
const response = await voiceToText(formData)
|
||||
|
||||
if (response && response.data) {
|
||||
const transcribedText = response.data
|
||||
if (transcribedText.trim()) {
|
||||
// 将转换的文字添加到输入框中
|
||||
const currentText = inputText.value
|
||||
const newText = currentText ? `${currentText} ${transcribedText}` : transcribedText
|
||||
inputText.value = newText
|
||||
emit('update:modelValue', newText)
|
||||
ElMessage.success('语音转换成功')
|
||||
} else {
|
||||
ElMessage.warning('未识别到有效语音内容')
|
||||
}
|
||||
} else {
|
||||
ElMessage.error('语音转换失败')
|
||||
}
|
||||
} catch (error) {
|
||||
console.error('语音转文字失败:', error)
|
||||
ElMessage.error('语音转换失败,请重试')
|
||||
} finally {
|
||||
isProcessingVoice.value = false
|
||||
}
|
||||
}
|
||||
|
||||
// 组件卸载时清理资源
|
||||
onUnmounted(() => {
|
||||
if (mediaRecorder && mediaRecorder.state !== 'inactive') {
|
||||
mediaRecorder.stop()
|
||||
}
|
||||
})
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
|
|
@ -188,7 +335,7 @@ watch(() => props.modelValue, (newValue) => {
|
|||
}
|
||||
|
||||
:deep(.el-textarea__inner) {
|
||||
padding: 1rem 4rem 1rem 1.5rem;
|
||||
padding: 1rem 6rem 1rem 1.5rem;
|
||||
border-radius: 16px;
|
||||
border: 1px solid #e5e7eb;
|
||||
background: transparent;
|
||||
|
|
@ -274,6 +421,127 @@ watch(() => props.modelValue, (newValue) => {
|
|||
display: none;
|
||||
}
|
||||
|
||||
/* 语音按钮样式 */
|
||||
.voice-button {
|
||||
position: absolute;
|
||||
right: 4rem;
|
||||
top: 50%;
|
||||
transform: translateY(-50%);
|
||||
height: 2.5rem;
|
||||
width: 2.5rem;
|
||||
min-height: 2.5rem;
|
||||
padding: 0;
|
||||
border-radius: 50%;
|
||||
background: #6b7280;
|
||||
transition: all 0.3s cubic-bezier(0.4, 0, 0.2, 1);
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
border: none;
|
||||
cursor: pointer;
|
||||
box-shadow: 0 2px 8px rgba(107, 114, 128, 0.25);
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
.voice-button:not(:disabled) {
|
||||
background: linear-gradient(135deg, #6b7280 0%, #4b5563 100%);
|
||||
}
|
||||
|
||||
.voice-button:disabled {
|
||||
opacity: 0.7;
|
||||
cursor: not-allowed;
|
||||
}
|
||||
|
||||
.voice-button:hover:not(:disabled) {
|
||||
transform: translateY(-50%) scale(1.05);
|
||||
box-shadow: 0 4px 12px rgba(107, 114, 128, 0.3);
|
||||
background: linear-gradient(135deg, #9ca3af 0%, #6b7280 100%);
|
||||
}
|
||||
|
||||
/* 录音状态样式 */
|
||||
.voice-button.recording {
|
||||
background: linear-gradient(135deg, #ef4444 0%, #dc2626 100%);
|
||||
box-shadow: 0 4px 12px rgba(239, 68, 68, 0.4);
|
||||
animation: recordingPulse 1.5s ease-in-out infinite;
|
||||
}
|
||||
|
||||
.voice-button.recording:hover {
|
||||
background: linear-gradient(135deg, #f87171 0%, #ef4444 100%);
|
||||
}
|
||||
|
||||
/* 录音脉冲动画 */
|
||||
@keyframes recordingPulse {
|
||||
0%, 100% {
|
||||
transform: translateY(-50%) scale(1);
|
||||
box-shadow: 0 4px 12px rgba(239, 68, 68, 0.4);
|
||||
}
|
||||
50% {
|
||||
transform: translateY(-50%) scale(1.1);
|
||||
box-shadow: 0 6px 20px rgba(239, 68, 68, 0.6);
|
||||
}
|
||||
}
|
||||
|
||||
.voice-icon {
|
||||
width: 1.25rem;
|
||||
height: 1.25rem;
|
||||
transition: all 0.3s ease;
|
||||
color: #ffffff;
|
||||
}
|
||||
|
||||
.voice-icon.recording {
|
||||
animation: microphoneWave 0.8s ease-in-out infinite alternate;
|
||||
}
|
||||
|
||||
/* 麦克风波动动画 */
|
||||
@keyframes microphoneWave {
|
||||
from {
|
||||
transform: scale(1);
|
||||
}
|
||||
to {
|
||||
transform: scale(1.1);
|
||||
}
|
||||
}
|
||||
|
||||
/* 录音动画容器 */
|
||||
.recording-animation {
|
||||
position: relative;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
}
|
||||
|
||||
.recording-animation::before {
|
||||
content: '';
|
||||
position: absolute;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
border-radius: 50%;
|
||||
background: rgba(255, 255, 255, 0.2);
|
||||
animation: ripple 1.5s ease-out infinite;
|
||||
}
|
||||
|
||||
/* 波纹动画 */
|
||||
@keyframes ripple {
|
||||
0% {
|
||||
transform: scale(0.8);
|
||||
opacity: 1;
|
||||
}
|
||||
100% {
|
||||
transform: scale(2);
|
||||
opacity: 0;
|
||||
}
|
||||
}
|
||||
|
||||
/* 语音处理加载图标 */
|
||||
.voice-loading {
|
||||
width: 1.25rem;
|
||||
height: 1.25rem;
|
||||
border: 2px solid rgba(255, 255, 255, 0.3);
|
||||
border-radius: 50%;
|
||||
border-top-color: #ffffff;
|
||||
animation: spin 0.8s linear infinite;
|
||||
}
|
||||
|
||||
.input-footer {
|
||||
display: none;
|
||||
}
|
||||
|
|
@ -301,6 +569,24 @@ watch(() => props.modelValue, (newValue) => {
|
|||
border-width: 1.5px;
|
||||
}
|
||||
|
||||
/* 移动端语音按钮适配 */
|
||||
.voice-button {
|
||||
right: 3rem;
|
||||
height: 2.25rem;
|
||||
width: 2.25rem;
|
||||
min-height: 2.25rem;
|
||||
}
|
||||
|
||||
.voice-icon,
|
||||
.voice-loading {
|
||||
width: 1rem;
|
||||
height: 1rem;
|
||||
}
|
||||
|
||||
.voice-loading {
|
||||
border-width: 1.5px;
|
||||
}
|
||||
|
||||
/* 移动端中止按钮适配 */
|
||||
.stop-button-container {
|
||||
top: -2rem;
|
||||
|
|
|
|||
|
|
@ -7,10 +7,17 @@ import io.github.guoshiqiufeng.dify.chat.dto.request.ChatMessageSendRequest;
|
|||
import io.github.guoshiqiufeng.dify.chat.dto.response.ChatMessageSendCompletionResponse;
|
||||
import io.swagger.annotations.Api;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.springframework.http.MediaType;
|
||||
import org.springframework.beans.factory.annotation.Value;
|
||||
import org.springframework.core.io.ByteArrayResource;
|
||||
import org.springframework.http.*;
|
||||
import org.springframework.util.LinkedMultiValueMap;
|
||||
import org.springframework.util.MultiValueMap;
|
||||
import org.springframework.web.bind.annotation.*;
|
||||
import org.springframework.web.client.RestTemplate;
|
||||
import org.springframework.web.multipart.MultipartFile;
|
||||
import reactor.core.publisher.Flux;
|
||||
import javax.annotation.Resource;
|
||||
import java.util.Map;
|
||||
|
||||
|
||||
@Api(tags = "对话聊天接口")
|
||||
|
|
@ -22,6 +29,17 @@ public class ChatController {
|
|||
|
||||
@Resource
|
||||
private ChatService chatService;
|
||||
|
||||
|
||||
|
||||
@Resource
|
||||
private RestTemplate restTemplate;
|
||||
|
||||
@Value("${voice2text.url}")
|
||||
private String voice2textUrl;
|
||||
|
||||
@Value("${voice2text.model}")
|
||||
private String voice2textModel;
|
||||
/***
|
||||
* 故障诊断对话接口
|
||||
* @param
|
||||
|
|
@ -50,6 +68,65 @@ public class ChatController {
|
|||
|
||||
|
||||
|
||||
/***
|
||||
* 语音转文字
|
||||
* @param file 音频文件
|
||||
* @return 转换后的文字
|
||||
*/
|
||||
@PostMapping("/voiceToText")
|
||||
public String voiceToText(@RequestParam("file") MultipartFile file){
|
||||
try {
|
||||
log.info("开始语音转文字,文件名: {}, 文件大小: {} bytes",
|
||||
file.getOriginalFilename(), file.getSize());
|
||||
|
||||
// 1. 参数验证
|
||||
if (file == null || file.isEmpty()) {
|
||||
log.error("语音文件为空");
|
||||
throw new IllegalArgumentException("语音文件不能为空");
|
||||
}
|
||||
|
||||
// 2. 构建请求头
|
||||
HttpHeaders headers = new HttpHeaders();
|
||||
headers.setContentType(MediaType.MULTIPART_FORM_DATA);
|
||||
|
||||
// 3. 构建请求体
|
||||
MultiValueMap<String, Object> body = new LinkedMultiValueMap<>();
|
||||
body.add("model", voice2textModel);
|
||||
|
||||
// 添加文件数据
|
||||
ByteArrayResource fileResource = new ByteArrayResource(file.getBytes()) {
|
||||
@Override
|
||||
public String getFilename() {
|
||||
return file.getOriginalFilename();
|
||||
}
|
||||
};
|
||||
body.add("file", fileResource);
|
||||
|
||||
// 4. 发送请求
|
||||
HttpEntity<MultiValueMap<String, Object>> requestEntity = new HttpEntity<>(body, headers);
|
||||
ResponseEntity<Map> response = restTemplate.postForEntity(voice2textUrl, requestEntity, Map.class);
|
||||
|
||||
// 5. 处理响应
|
||||
if (response.getStatusCode() == HttpStatus.OK && response.getBody() != null) {
|
||||
Map<String, Object> responseBody = response.getBody();
|
||||
String text = (String) responseBody.get("text");
|
||||
log.info("语音转文字成功,结果: {}", text);
|
||||
return text;
|
||||
} else {
|
||||
log.error("语音转文字失败,响应状态: {}, 响应体: {}",
|
||||
response.getStatusCode(), response.getBody());
|
||||
throw new RuntimeException("语音转文字服务调用失败");
|
||||
}
|
||||
|
||||
} catch (Exception e) {
|
||||
log.error("语音转文字异常: {}", e.getMessage(), e);
|
||||
throw new RuntimeException("语音转文字失败: " + e.getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
|
|
|||
|
|
@ -94,17 +94,17 @@ public class KnowledgeBaseController {
|
|||
return ResultUtils.error("索引删除失败: " + e.getMessage());
|
||||
}
|
||||
}
|
||||
@ApiOperation("创建单个文件的索引")
|
||||
@PostMapping("/createIndex")
|
||||
public ResultUtils createIndex(@RequestParam("documentId") String documentId) throws Exception {
|
||||
|
||||
try{
|
||||
esTDatasetFilesImporter.importDocumentId(documentId);
|
||||
return ResultUtils.success("索引创建成功");
|
||||
} catch (IOException e) {
|
||||
return ResultUtils.error("索引创建失败: " + e.getMessage());
|
||||
}
|
||||
}
|
||||
// @ApiOperation("创建单个文件的索引")
|
||||
// @PostMapping("/createIndex")
|
||||
// public ResultUtils createIndex(@RequestParam("documentId") String documentId) throws Exception {
|
||||
//
|
||||
// try{
|
||||
// esTDatasetFilesImporter.importDocumentId(documentId);
|
||||
// return ResultUtils.success("索引创建成功");
|
||||
// } catch (IOException e) {
|
||||
// return ResultUtils.error("索引创建失败: " + e.getMessage());
|
||||
// }
|
||||
// }
|
||||
// @ApiOperation("创建所有文件的索引")
|
||||
// @PostMapping("/createAllIndex")
|
||||
// public ResultUtils createAllIndex() throws Exception {
|
||||
|
|
|
|||
|
|
@ -59,5 +59,5 @@ public interface MetadataService {
|
|||
* @param file 文件
|
||||
* @return 处理后的元数据列表
|
||||
*/
|
||||
List<DifyMetadata> handleYsylcMetadata(String datasetId, String documentId, MultipartFile file);
|
||||
List<DifyMetadata> handleYsylcMetadata(String datasetId, String documentId, MultipartFile file,String metadataId);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -229,15 +229,12 @@ public class DifyDatasetApiServiceImpl implements DifyDatasetApiService {
|
|||
stepStartTime = System.currentTimeMillis();
|
||||
Map<String, String> document = (Map<String, String>) res.getBody().get("document");
|
||||
|
||||
long wordCount = Long.parseLong(document.get("word_count"));
|
||||
//long wordCount = Long.parseLong(document.get("word_count"));
|
||||
//批次号
|
||||
String batch= (String) res.getBody().get("batch");
|
||||
String documentId = document.get("id");
|
||||
logger.info("获取文档ID完成: {}, 耗时: {} ms", documentId, System.currentTimeMillis() - stepStartTime);
|
||||
|
||||
|
||||
|
||||
|
||||
// 8. 记录文件信息到助手服务数据库
|
||||
stepStartTime = System.currentTimeMillis();
|
||||
TDatasetFiles datasetFiles = new TDatasetFiles();
|
||||
|
|
@ -432,7 +429,7 @@ public class DifyDatasetApiServiceImpl implements DifyDatasetApiService {
|
|||
List<DifyMetadata> docMetadatas = res.getBody().getDocMetadatas();
|
||||
for (DifyMetadata metadata : docMetadatas) {
|
||||
if (DifyConstants.METADATA_YSYLC_JSON_URL.equals(metadata.getName())) {
|
||||
currentMetadatas = metadataService.handleYsylcMetadata(datasetId, documentId, file);
|
||||
currentMetadatas = metadataService.handleYsylcMetadata(datasetId, documentId, file,metadata.getId());
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -152,7 +152,7 @@ public class MetadataServiceImpl implements MetadataService {
|
|||
}
|
||||
|
||||
@Override
|
||||
public List<DifyMetadata> handleYsylcMetadata(String datasetId, String documentId, MultipartFile file) {
|
||||
public List<DifyMetadata> handleYsylcMetadata(String datasetId, String documentId, MultipartFile file,String metadataId) {
|
||||
// 异步执行
|
||||
CompletableFuture.runAsync(() -> {
|
||||
String apiKey = tApiKeyService.getApiKeyFromCache(DifyConstants.API_KEY_YSYLC_DATA_PROC);
|
||||
|
|
@ -160,6 +160,7 @@ public class MetadataServiceImpl implements MetadataService {
|
|||
});
|
||||
|
||||
DifyMetadata newMetadata = new DifyMetadata();
|
||||
newMetadata.setId(metadataId);
|
||||
newMetadata.setType(DifyConstants.METADATA_TYPE_STRING);
|
||||
newMetadata.setName(DifyConstants.METADATA_YSYLC_JSON_URL);
|
||||
newMetadata.setValue(ysylcJsonPath + file.getOriginalFilename() + ".json");
|
||||
|
|
|
|||
|
|
@ -3,6 +3,7 @@ package com.bjtds.brichat.util;
|
|||
import com.bjtds.brichat.entity.dataset.TDatasetFiles;
|
||||
import com.bjtds.brichat.service.DatasetFilesService;
|
||||
import com.bjtds.brichat.service.EsTDatasetFilesService;
|
||||
import io.swagger.models.auth.In;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
|
|
@ -28,9 +29,9 @@ public class EsTDatasetFilesImporter {
|
|||
@Autowired
|
||||
private StringRedisTemplate redisTemplate;
|
||||
|
||||
public void importDocumentId(String documentId) throws IOException {
|
||||
public void importDocumentId(Integer fileId) throws IOException {
|
||||
// 一次性获取完整的文档信息
|
||||
TDatasetFiles datasetFiles = datasetFilesService.getFileById(Integer.valueOf(documentId));
|
||||
TDatasetFiles datasetFiles = datasetFilesService.getFileById(fileId);
|
||||
if (datasetFiles == null) {
|
||||
throw new IllegalArgumentException("datasetFiles 不存在");
|
||||
}
|
||||
|
|
|
|||
|
|
@ -85,3 +85,8 @@ elasticsearch:
|
|||
#是否删除索引,重新构建索引
|
||||
deleteIndex: ${es-deleteIndex:false}
|
||||
|
||||
voice2text:
|
||||
url: ${voice2text-url:http://192.168.1.211:11023/v1/audio/transcriptions}
|
||||
model: ${voice2text-model:whisper-1}
|
||||
|
||||
|
||||
|
|
|
|||
|
|
@ -81,3 +81,6 @@ elasticsearch:
|
|||
#是否删除索引,重新构建索引
|
||||
deleteIndex: ${es-deleteIndex:false}
|
||||
|
||||
voice2text:
|
||||
url: ${voice2text-url:http://192.168.8.253:11023/v1/audio/transcriptions}
|
||||
model: ${voice2text-model:whisper-1}
|
||||
Loading…
Reference in New Issue