@@ -15,33 +15,46 @@ const currentAvatarIndex = ref(Math.random() * avatarList.value.length | 0)
15
15
const store = useConversationStore ()
16
16
const { ssmlToSpeak, isSynthesizing, isPlaying } = useSpeechService ({ isFetchAllVoice: false })
17
17
const allLanguages = computed (() => [... new Set (allVoices .map (v => v .locale ))].filter (l => Object .keys (supportLanguageMap ).includes (l )))
18
- const selectLanguage = ref (' ' )
19
- const filterVoices = ref <VoiceInfo []>([])
20
- const selectVoiceName = ref (' ' )
21
18
const desc = ref (' ' )
22
19
const name = ref (' ' )
23
20
const rate = ref (' 1.0' )
24
21
const previewText = ref (' polyglot is awesome!' )
25
- const filterStyles = ref <string []>([])
26
- const selectStyle = ref (' Neural' )
22
+ const presets = ref (' Act as if you are meeting someone for the first time. How would you introduce yourself and start a conversation?' )
27
23
28
- const canAdd = computed (() => !! (selectLanguage .value && selectVoiceName .value && desc .value && name .value ))
29
-
30
- onBeforeMount (() => {
31
- selectLanguage .value = allLanguages .value [0 ]
32
- changeSelectLanguage (selectLanguage .value )
33
- })
24
+ const voiceValue = ref <string []>([' en-US' , ' en-US-JennyNeural' , ' chat' ])
34
25
35
- watch (selectLanguage , changeSelectLanguage )
26
+ const selectLanguage = computed (() => voiceValue .value [0 ])
27
+ const selectVoiceName = computed (() => voiceValue .value [1 ])
28
+ const selectStyle = computed (() => voiceValue .value [2 ])
29
+ const canAdd = computed (() => !! (selectLanguage .value && selectVoiceName .value && desc .value && name .value ))
36
30
37
- function changeSelectLanguage(newSelectLanguage : string ) {
38
- filterVoices .value = allVoices .filter (v => v .locale === newSelectLanguage )
39
- selectVoiceName .value = filterVoices .value [0 ]?.shortName
31
+ interface Option {
32
+ label: string
33
+ value: string
34
+ children? : Option []
40
35
}
41
36
42
- watch (selectVoiceName , (n ) => {
43
- filterStyles .value = filterVoices .value .filter (v => v .shortName === n )[0 ]?.styleList || []
44
- selectStyle .value = filterStyles .value [0 ] || ' Neural'
37
+ const options = ref <Option [] >([])
38
+
39
+ onMounted (() => {
40
+ allLanguages .value .forEach ((item ) => {
41
+ const children: Option [] = []
42
+ allVoices .forEach ((v ) => {
43
+ if (v .locale === item ) {
44
+ children .push ({
45
+ value: v .shortName ,
46
+ label: ` ${v .gender === 1 ? ' 🧒🏻' : ' 👦🏻' } ${v .localName } ` ,
47
+ children: v .styleList ?.map (x => ({ label: voiceStyleMap [x ], value: x })) || [],
48
+ })
49
+ }
50
+ })
51
+
52
+ options .value .push ({
53
+ value: item ,
54
+ label: supportLanguageMap [item ],
55
+ children ,
56
+ })
57
+ })
45
58
})
46
59
47
60
const randomAvatar = getAvatarUrl (avatarList .value [Math .random () * avatarList .value .length | 0 ]) // 随机默认选择一个头像
@@ -60,7 +73,7 @@ const addChat = (event: any) => {
60
73
rate: + rate .value ,
61
74
isDefault: false ,
62
75
voiceStyle: selectStyle .value ,
63
- })
76
+ }, presets . value )
64
77
store .changeCurrentKey (uid )
65
78
emits (' close' )
66
79
}
@@ -74,16 +87,8 @@ const previewSpeech = () => {
74
87
}
75
88
</script >
76
89
77
- <script >
78
-
79
- </script >
80
-
81
90
<template >
82
- <div flex =" ~ col gap-3" items-center >
83
- <!-- <div text-lg font-bold>
84
- 自定义对话
85
- </div> -->
86
-
91
+ <div class =" wrapper" flex =" ~ col gap-3" items-center >
87
92
<div flex >
88
93
<Avatar v-model:image-url =" imageUrl" />
89
94
</div >
@@ -96,32 +101,17 @@ const previewSpeech = () => {
96
101
<input v-model =" desc" type =" text" >
97
102
</div >
98
103
<div flex >
99
- <label for =" " >语言</label >
100
- <select v-model =" selectLanguage" >
101
- <option v-for =" item in allLanguages" :key =" item" :value =" item" >
102
- {{ supportLanguageMap[item] }}
103
- </option >
104
- </select >
105
- </div >
106
- <div flex >
107
- <label for =" " >音色</label >
108
- <select v-model =" selectVoiceName" >
109
- <option v-for =" item in filterVoices" :key =" item.shortName" :value =" item.shortName" >
110
- {{ `${item.locale} / ${item.gender === 1 ? 'Female' : 'Male'} / ${item.localName}` }}
111
- </option >
112
- </select >
104
+ <label for =" " >语音</label >
105
+ <div w-55 flex >
106
+ <ElCascader v-model =" voiceValue" style =" width : 220px ;" :options =" options" />
107
+ </div >
113
108
</div >
114
109
<div flex >
115
- <label for =" " >风格</label >
116
- <select v-model =" selectStyle" >
117
- <option value =" Neural" >
118
- 正常
119
- </option >
120
-
121
- <option v-for =" item in filterStyles" :key =" item" :value =" item" >
122
- {{ voiceStyleMap[item] }}
123
- </option >
124
- </select >
110
+ <label for =" " >语速</label >
111
+ <div w-55 flex >
112
+ <input v-model =" rate" flex-1 type =" range" step =" 0.1" min =" 0.1" max =" 2.0" >
113
+ <span w-4 ml-1 >{{ Number(rate).toFixed(1) }}</span >
114
+ </div >
125
115
</div >
126
116
<div relative center-y >
127
117
<div flex >
@@ -137,18 +127,12 @@ const previewSpeech = () => {
137
127
</button >
138
128
</div >
139
129
</div >
130
+
131
+ <!-- todo -->
140
132
<div flex >
141
- <label for =" " >语速</label >
142
- <div w-55 flex >
143
- <input v-model =" rate" flex-1 type =" range" step =" 0.1" min =" 0.1" max =" 2.0" >
144
- <span w-4 ml-1 >{{ Number(rate).toFixed(1) }}</span >
145
- </div >
133
+ <label for =" " >场景预设</label >
134
+ <textarea v-model =" presets" :rows =" 3" placeholder =" system prompt" />
146
135
</div >
147
- <!-- todo -->
148
- <!-- <div flex>
149
- <label center-y justify-end mr-2 for="">预设</label>
150
- <textarea id="message" resize-none w-50 block p-2 text-sm placeholder="Write your thoughts here..." />
151
- </div> -->
152
136
<div center-y text-sm text-gray-500 >
153
137
<i inline-block w-4 h-4 m-1 cursor-auto i-ic:baseline-lightbulb />
154
138
点击头像可更换头像
@@ -162,12 +146,30 @@ const previewSpeech = () => {
162
146
163
147
<style scoped>
164
148
label {
165
- @apply center-y justify-end mr- 2 w- 20
149
+ @apply center-y justify-center w- 20
166
150
}
167
151
input {
168
- @apply w- 50 p- 2
152
+ @apply w- 50 p- 2 text- [#222]
169
153
}
170
154
select {
171
- @apply w- 55 select-settings
155
+ @apply w- 55 select-settings text- [#222]
156
+ }
157
+ textarea {
158
+ @apply resize-none w- 50 font-sans block p- 2 text- [#222]
159
+ }
160
+ textArea ::-webkit-scrollbar {
161
+ width : 0 ;
162
+ height : 0 ;
163
+ }
164
+ .wrapper :deep(.el-input__wrapper ){
165
+ box-shadow : 0 0 0 1px #777 inset ;
166
+ padding-top : 3px ;
167
+ padding-bottom : 3px ;
168
+ }
169
+ .wrapper :deep(.el-input__inner ){
170
+ color : #222 ;
171
+ }
172
+ .wrapper :deep(.el-input__wrapper ):hover {
173
+ box-shadow : 0 0 0 1px #777 inset ;
172
174
}
173
175
</style >
0 commit comments