Skip to content

Commit

Permalink
refactor: 支持使用浏览器语音播放
Browse files Browse the repository at this point in the history
  • Loading branch information
liuruibin committed Sep 12, 2024
1 parent 2429149 commit d551462
Show file tree
Hide file tree
Showing 13 changed files with 45 additions and 110 deletions.
18 changes: 18 additions & 0 deletions apps/application/migrations/0013_application_tts_type.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
# Generated by Django 4.2.15 on 2024-09-12 11:01

from django.db import migrations, models


class Migration(migrations.Migration):

dependencies = [
('application', '0012_application_stt_model_application_stt_model_enable_and_more'),
]

operations = [
migrations.AddField(
model_name='application',
name='tts_type',
field=models.CharField(default='BROWSER', max_length=20, verbose_name='语音播放类型'),
),
]
1 change: 1 addition & 0 deletions apps/application/models/application.py
Original file line number Diff line number Diff line change
Expand Up @@ -58,6 +58,7 @@ class Application(AppModelMixin):
stt_model = models.ForeignKey(Model, related_name='stt_model_id', on_delete=models.SET_NULL, db_constraint=False, blank=True, null=True)
tts_model_enable = models.BooleanField(verbose_name="语音合成模型是否启用", default=False)
stt_model_enable = models.BooleanField(verbose_name="语音识别模型是否启用", default=False)
tts_type = models.CharField(verbose_name="语音播放类型", max_length=20, default="BROWSER")

@staticmethod
def get_default_model_prompt():
Expand Down
5 changes: 4 additions & 1 deletion apps/application/serializers/application_serializers.py
Original file line number Diff line number Diff line change
Expand Up @@ -694,6 +694,7 @@ def profile(self, with_valid=True):
'tts_model_id': application.tts_model_id,
'stt_model_enable': application.stt_model_enable,
'tts_model_enable': application.tts_model_enable,
'tts_type': application.tts_type,
'work_flow': application.work_flow,
'show_source': application_access_token.show_source})

Expand Down Expand Up @@ -745,7 +746,7 @@ def edit(self, instance: Dict, with_valid=True):

update_keys = ['name', 'desc', 'model_id', 'multiple_rounds_dialogue', 'prologue', 'status',
'dataset_setting', 'model_setting', 'problem_optimization', 'dialogue_number',
'stt_model_id', 'tts_model_id', 'tts_model_enable', 'stt_model_enable',
'stt_model_id', 'tts_model_id', 'tts_model_enable', 'stt_model_enable', 'tts_type',
'api_key_is_active', 'icon', 'work_flow', 'model_params_setting']
for update_key in update_keys:
if update_key in instance and instance.get(update_key) is not None:
Expand Down Expand Up @@ -865,6 +866,8 @@ def get_work_flow_model(instance):
instance['stt_model_enable'] = node_data['stt_model_enable']
if 'tts_model_enable' in node_data:
instance['tts_model_enable'] = node_data['tts_model_enable']
if 'tts_type' in node_data:
instance['tts_type'] = node_data['tts_type']
break

def speech_to_text(self, file, with_valid=True):
Expand Down
2 changes: 1 addition & 1 deletion apps/application/views/application_views.py
Original file line number Diff line number Diff line change
Expand Up @@ -178,7 +178,7 @@ class Model(APIView):
tags=["应用"],
manual_parameters=ApplicationApi.Model.get_request_params_api())
@has_permissions(ViewPermission(
[RoleConstants.ADMIN, RoleConstants.USER, RoleConstants.APPLICATION_ACCESS_TOKEN],
[RoleConstants.ADMIN, RoleConstants.USER],
[lambda r, keywords: Permission(group=Group.APPLICATION, operate=Operate.USE,
dynamic_tag=keywords.get('application_id'))],
compare=CompareConstants.AND))
Expand Down

This file was deleted.

Original file line number Diff line number Diff line change
Expand Up @@ -17,25 +17,19 @@
ModelInfoManage
from setting.models_provider.impl.local_model_provider.credential.embedding import LocalEmbeddingCredential
from setting.models_provider.impl.local_model_provider.credential.reranker import LocalRerankerCredential
from setting.models_provider.impl.local_model_provider.credential.tts import BrowserTextToSpeechCredential
from setting.models_provider.impl.local_model_provider.model.embedding import LocalEmbedding
from setting.models_provider.impl.local_model_provider.model.reranker import LocalReranker
from setting.models_provider.impl.local_model_provider.model.tts import BrowserTextToSpeech
from smartdoc.conf import PROJECT_DIR

embedding_text2vec_base_chinese = ModelInfo('shibing624/text2vec-base-chinese', '', ModelTypeConst.EMBEDDING,
LocalEmbeddingCredential(), LocalEmbedding)
bge_reranker_v2_m3 = ModelInfo('BAAI/bge-reranker-v2-m3', '', ModelTypeConst.RERANKER,
LocalRerankerCredential(), LocalReranker)

browser_tts = ModelInfo('browser_tts', '', ModelTypeConst.TTS, BrowserTextToSpeechCredential(), BrowserTextToSpeech)


model_info_manage = (ModelInfoManage.builder().append_model_info(embedding_text2vec_base_chinese)
.append_default_model_info(embedding_text2vec_base_chinese)
.append_model_info(bge_reranker_v2_m3)
.append_default_model_info(bge_reranker_v2_m3)
.append_model_info(browser_tts)
.build())


Expand Down

This file was deleted.

1 change: 1 addition & 0 deletions ui/src/api/type/application.ts
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@ interface ApplicationFormType {
tts_model_id?: string
stt_model_enable?: boolean
tts_model_enable?: boolean
tts_type?: string
}
interface chatType {
id: string
Expand Down
21 changes: 5 additions & 16 deletions ui/src/components/ai-chat/index.vue
Original file line number Diff line number Diff line change
Expand Up @@ -239,13 +239,7 @@ const props = defineProps({
chatId: {
type: String,
default: ''
}, // 历史记录Id
ttsModelOptions: {
type: Object,
default: () => {
return {}
}
}
} // 历史记录Id
})
const emit = defineEmits(['refresh', 'scroll'])
Expand Down Expand Up @@ -771,20 +765,14 @@ const uploadRecording = async (audioBlob: Blob) => {
}
const playAnswerText = (text: string) => {
if (
props.ttsModelOptions?.model_local_provider?.filter(
(v: any) => v.id === props.data.tts_model_id
).length > 0
) {
if (props.data.tts_type === 'BROWSER') {
// 创建一个新的 SpeechSynthesisUtterance 实例
const utterance = new SpeechSynthesisUtterance(text)
// 调用浏览器的朗读功能
window.speechSynthesis.speak(utterance)
return
}
applicationApi
.postTextToSpeech(props.data.id as string, { text: text }, loading)
if (props.data.tts_type === 'TTS') {
applicationApi.postTextToSpeech(props.data.id as string, { 'text': text }, loading)
.then((res: any) => {
// 假设我们有一个 MP3 文件的字节数组
// 创建 Blob 对象
Expand All @@ -810,6 +798,7 @@ const playAnswerText = (text: string) => {
.catch((err) => {
console.log('err: ', err)
})
}
}
onMounted(() => {
Expand Down
20 changes: 2 additions & 18 deletions ui/src/views/application-workflow/index.vue
Original file line number Diff line number Diff line change
Expand Up @@ -138,7 +138,7 @@
</div>
</div>
<div class="scrollbar-height">
<AiChat :data="detail" :tts-model-options="ttsModelOptions"></AiChat>
<AiChat :data="detail"></AiChat>
</div>
</div>
</el-collapse-transition>
Expand All @@ -157,7 +157,6 @@ import { datetimeFormat } from '@/utils/time'
import useStore from '@/stores'
import { WorkFlowInstance } from '@/workflow/common/validate'
import { hasPermission } from '@/utils/permission'
import { groupBy } from 'lodash'

const { user, application } = useStore()
const router = useRouter()
Expand All @@ -182,7 +181,6 @@ const enlarge = ref(false)
const saveTime = ref<any>('')
const activeName = ref('base')
const functionLibList = ref<any[]>([])
const ttsModelOptions = ref<any>(null)

function publicHandle() {
workflowRef.value
Expand Down Expand Up @@ -290,6 +288,7 @@ function getDetail() {
detail.value = res.data
detail.value.stt_model_id = res.data.stt_model
detail.value.tts_model_id = res.data.tts_model
detail.value.tts_type = res.data.tts_type
saveTime.value = res.data?.update_time
})
}
Expand All @@ -312,20 +311,6 @@ function getList() {
})
}

function getTTSModel() {
loading.value = true
applicationApi
.getApplicationTTSModel(id)
.then((res: any) => {
ttsModelOptions.value = groupBy(res?.data, 'provider')
loading.value = false
})
.catch(() => {
loading.value = false
})
}


/**
* 定时保存
*/
Expand All @@ -345,7 +330,6 @@ const closeInterval = () => {
}

onMounted(() => {
getTTSModel()
getDetail()
getList()
// 初始化定时任务
Expand Down
9 changes: 8 additions & 1 deletion ui/src/views/application/ApplicationSetting.vue
Original file line number Diff line number Diff line change
Expand Up @@ -369,7 +369,12 @@
<el-switch v-model="applicationForm.tts_model_enable"/>
</div>
</template>
<el-radio-group v-model="applicationForm.tts_type">
<el-radio label="浏览器播放(免费)" value="BROWSER"/>
<el-radio label="TTS模型" value="TTS"/>
</el-radio-group>
<el-select
v-if="applicationForm.tts_type === 'TTS'"
v-model="applicationForm.tts_model_id"
class="w-full"
popper-class="select-model"
Expand Down Expand Up @@ -464,7 +469,7 @@
</h4>
</div>
<div class="scrollbar-height">
<AiChat :data="applicationForm" :tts-model-options="ttsModelOptions"></AiChat>
<AiChat :data="applicationForm"></AiChat>
</div>
</div>
</el-col>
Expand Down Expand Up @@ -556,6 +561,7 @@ const applicationForm = ref<ApplicationFormType>({
tts_model_id: '',
stt_model_enable: false,
tts_model_enable: false,
tts_type: 'BROWSER',
type: 'SIMPLE'
})
Expand Down Expand Up @@ -657,6 +663,7 @@ function getDetail() {
applicationForm.value.model_id = res.data.model
applicationForm.value.stt_model_id = res.data.stt_model
applicationForm.value.tts_model_id = res.data.tts_model
applicationForm.value.tts_type = res.data.tts_type
})
}
Expand Down
20 changes: 0 additions & 20 deletions ui/src/views/chat/pc/index.vue
Original file line number Diff line number Diff line change
Expand Up @@ -108,7 +108,6 @@
:appId="applicationDetail?.id"
:record="currentRecordList"
:chatId="currentChatId"
:tts-model-options="ttsModelOptions"
@refresh="refresh"
@scroll="handleScroll"
>
Expand All @@ -131,8 +130,6 @@ import { marked } from 'marked'
import { saveAs } from 'file-saver'
import { isAppIcon } from '@/utils/application'
import useStore from '@/stores'
import applicationApi from '@/api/application'
import { groupBy } from 'lodash'
import useResize from '@/layout/hooks/useResize'
useResize()
Expand Down Expand Up @@ -170,8 +167,6 @@ const left_loading = ref(false)
const applicationDetail = ref<any>({})
const applicationAvailable = ref<boolean>(true)
const chatLogeData = ref<any[]>([])
const ttsModelOptions = ref<any>(null)
const paginationConfig = ref({
current_page: 1,
Expand Down Expand Up @@ -233,7 +228,6 @@ function getAppProfile() {
if (res.data?.show_history || !user.isEnterprise()) {
getChatLog(applicationDetail.value.id)
}
getTTSModel()
})
.catch(() => {
applicationAvailable.value = false
Expand Down Expand Up @@ -342,20 +336,6 @@ async function exportHTML(): Promise<void> {
saveAs(blob, suggestedName)
}
function getTTSModel() {
loading.value = true
applicationApi
.getApplicationTTSModel(applicationDetail.value.id)
.then((res: any) => {
ttsModelOptions.value = groupBy(res?.data, 'provider')
loading.value = false
})
.catch(() => {
loading.value = false
})
}
onMounted(() => {
user.changeUserType(2)
getAccessToken(accessToken)
Expand Down
5 changes: 5 additions & 0 deletions ui/src/workflow/nodes/base-node/index.vue
Original file line number Diff line number Diff line change
Expand Up @@ -135,7 +135,12 @@
<el-switch v-model="form_data.tts_model_enable" />
</div>
</template>
<el-radio-group v-model="form_data.tts_type">
<el-radio label="浏览器播放(免费)" value="BROWSER"/>
<el-radio label="TTS模型" value="TTS"/>
</el-radio-group>
<el-select
v-if="form_data.tts_type === 'TTS'"
v-model="form_data.tts_model_id"
class="w-full"
popper-class="select-model"
Expand Down

0 comments on commit d551462

Please sign in to comment.