mirror of
https://github.com/open-webui/open-webui
synced 2025-05-15 11:06:15 +00:00
feat: emoji call
This commit is contained in:
parent
53858c9b0e
commit
2e4f060ebb
@ -242,7 +242,15 @@ export const generateEmoji = async (
|
|||||||
throw error;
|
throw error;
|
||||||
}
|
}
|
||||||
|
|
||||||
return res?.choices[0]?.message?.content.replace(/["']/g, '') ?? null;
|
const response = res?.choices[0]?.message?.content.replace(/["']/g, '') ?? null;
|
||||||
|
|
||||||
|
if (response) {
|
||||||
|
if (/\p{Extended_Pictographic}/u.test(response)) {
|
||||||
|
return response.match(/\p{Extended_Pictographic}/gu)[0];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return null;
|
||||||
};
|
};
|
||||||
|
|
||||||
export const generateSearchQuery = async (
|
export const generateSearchQuery = async (
|
||||||
|
@ -338,7 +338,7 @@
|
|||||||
|
|
||||||
speechSynthesis.speak(currentUtterance);
|
speechSynthesis.speak(currentUtterance);
|
||||||
currentUtterance.onend = async (e) => {
|
currentUtterance.onend = async (e) => {
|
||||||
await new Promise((r) => setTimeout(r, 100));
|
await new Promise((r) => setTimeout(r, 200));
|
||||||
resolve(e);
|
resolve(e);
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
@ -402,9 +402,20 @@
|
|||||||
|
|
||||||
// Audio cache map where key is the content and value is the Audio object.
|
// Audio cache map where key is the content and value is the Audio object.
|
||||||
const audioCache = new Map();
|
const audioCache = new Map();
|
||||||
|
const emojiCache = new Map();
|
||||||
|
|
||||||
const fetchAudio = async (content) => {
|
const fetchAudio = async (content) => {
|
||||||
if (!audioCache.has(content)) {
|
if (!audioCache.has(content)) {
|
||||||
try {
|
try {
|
||||||
|
// Set the emoji for the content if needed
|
||||||
|
if ($settings?.showEmojiInCall ?? false) {
|
||||||
|
const emoji = await generateEmoji(localStorage.token, modelId, content, chatId);
|
||||||
|
if (emoji) {
|
||||||
|
emojiCache.set(content, emoji);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if ($config.audio.tts.engine !== '') {
|
||||||
const res = await synthesizeOpenAISpeech(
|
const res = await synthesizeOpenAISpeech(
|
||||||
localStorage.token,
|
localStorage.token,
|
||||||
$settings?.audio?.tts?.voice ?? $config?.audio?.tts?.voice,
|
$settings?.audio?.tts?.voice ?? $config?.audio?.tts?.voice,
|
||||||
@ -419,10 +430,14 @@
|
|||||||
const blobUrl = URL.createObjectURL(blob);
|
const blobUrl = URL.createObjectURL(blob);
|
||||||
audioCache.set(content, new Audio(blobUrl));
|
audioCache.set(content, new Audio(blobUrl));
|
||||||
}
|
}
|
||||||
|
} else {
|
||||||
|
audioCache.set(content, true);
|
||||||
|
}
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
console.error('Error synthesizing speech:', error);
|
console.error('Error synthesizing speech:', error);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return audioCache.get(content);
|
return audioCache.get(content);
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -436,6 +451,15 @@
|
|||||||
|
|
||||||
if (audioCache.has(content)) {
|
if (audioCache.has(content)) {
|
||||||
// If content is available in the cache, play it
|
// If content is available in the cache, play it
|
||||||
|
|
||||||
|
// Set the emoji for the content if available
|
||||||
|
if (($settings?.showEmojiInCall ?? false) && emojiCache.has(content)) {
|
||||||
|
emoji = emojiCache.get(content);
|
||||||
|
} else {
|
||||||
|
emoji = null;
|
||||||
|
}
|
||||||
|
|
||||||
|
if ($config.audio.tts.engine !== '') {
|
||||||
try {
|
try {
|
||||||
console.log(
|
console.log(
|
||||||
'%c%s',
|
'%c%s',
|
||||||
@ -450,6 +474,9 @@
|
|||||||
} catch (error) {
|
} catch (error) {
|
||||||
console.error('Error playing audio:', error);
|
console.error('Error playing audio:', error);
|
||||||
}
|
}
|
||||||
|
} else {
|
||||||
|
await speakSpeechSynthesisHandler(content);
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
// If not available in the cache, push it back to the queue and delay
|
// If not available in the cache, push it back to the queue and delay
|
||||||
messages[id].unshift(content); // Re-queue the content at the start
|
messages[id].unshift(content); // Re-queue the content at the start
|
||||||
@ -475,8 +502,6 @@
|
|||||||
|
|
||||||
chatStreaming = true;
|
chatStreaming = true;
|
||||||
|
|
||||||
if ($config.audio.tts.engine !== '') {
|
|
||||||
// set currentMessageId to id
|
|
||||||
if (currentMessageId !== id) {
|
if (currentMessageId !== id) {
|
||||||
console.log(`Received chat start event for message ID ${id}`);
|
console.log(`Received chat start event for message ID ${id}`);
|
||||||
|
|
||||||
@ -489,7 +514,6 @@
|
|||||||
// Start monitoring and playing audio for the message ID
|
// Start monitoring and playing audio for the message ID
|
||||||
monitorAndPlayAudio(id, audioAbortController.signal);
|
monitorAndPlayAudio(id, audioAbortController.signal);
|
||||||
}
|
}
|
||||||
}
|
|
||||||
};
|
};
|
||||||
|
|
||||||
const chatEventHandler = async (e) => {
|
const chatEventHandler = async (e) => {
|
||||||
@ -499,7 +523,6 @@
|
|||||||
// "content" here is a sentence from the assistant,
|
// "content" here is a sentence from the assistant,
|
||||||
// there will be many sentences for the same "id"
|
// there will be many sentences for the same "id"
|
||||||
|
|
||||||
if ($config.audio.tts.engine !== '') {
|
|
||||||
if (currentMessageId === id) {
|
if (currentMessageId === id) {
|
||||||
console.log(`Received chat event for message ID ${id}: ${content}`);
|
console.log(`Received chat event for message ID ${id}: ${content}`);
|
||||||
|
|
||||||
@ -517,7 +540,6 @@
|
|||||||
console.error('Failed to fetch or play audio:', error);
|
console.error('Failed to fetch or play audio:', error);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
};
|
};
|
||||||
|
|
||||||
const chatFinishHandler = async (e) => {
|
const chatFinishHandler = async (e) => {
|
||||||
@ -525,12 +547,7 @@
|
|||||||
// "content" here is the entire message from the assistant
|
// "content" here is the entire message from the assistant
|
||||||
|
|
||||||
chatStreaming = false;
|
chatStreaming = false;
|
||||||
|
|
||||||
if ($config.audio.tts.engine !== '') {
|
|
||||||
finishedMessages[id] = true;
|
finishedMessages[id] = true;
|
||||||
} else {
|
|
||||||
speakSpeechSynthesisHandler(content);
|
|
||||||
}
|
|
||||||
};
|
};
|
||||||
|
|
||||||
eventTarget.addEventListener('chat:start', chatStartHandler);
|
eventTarget.addEventListener('chat:start', chatStartHandler);
|
||||||
@ -561,7 +578,20 @@
|
|||||||
<div class="max-w-lg w-full h-screen max-h-[100dvh] flex flex-col justify-between p-3 md:p-6">
|
<div class="max-w-lg w-full h-screen max-h-[100dvh] flex flex-col justify-between p-3 md:p-6">
|
||||||
{#if camera}
|
{#if camera}
|
||||||
<div class="flex justify-center items-center w-full h-20 min-h-20">
|
<div class="flex justify-center items-center w-full h-20 min-h-20">
|
||||||
{#if loading}
|
{#if emoji}
|
||||||
|
<div
|
||||||
|
class=" transition-all rounded-full"
|
||||||
|
style="font-size:{rmsLevel * 100 > 4
|
||||||
|
? '4.5'
|
||||||
|
: rmsLevel * 100 > 2
|
||||||
|
? '4.25'
|
||||||
|
: rmsLevel * 100 > 1
|
||||||
|
? '3.75'
|
||||||
|
: '3.5'}rem;width: 100%; text-align:center;"
|
||||||
|
>
|
||||||
|
{emoji}
|
||||||
|
</div>
|
||||||
|
{:else if loading}
|
||||||
<svg
|
<svg
|
||||||
class="size-12 text-gray-900 dark:text-gray-400"
|
class="size-12 text-gray-900 dark:text-gray-400"
|
||||||
viewBox="0 0 24 24"
|
viewBox="0 0 24 24"
|
||||||
@ -598,19 +628,6 @@
|
|||||||
r="3"
|
r="3"
|
||||||
/><circle class="spinner_qM83 spinner_ZTLf" cx="20" cy="12" r="3" /></svg
|
/><circle class="spinner_qM83 spinner_ZTLf" cx="20" cy="12" r="3" /></svg
|
||||||
>
|
>
|
||||||
{:else if emoji}
|
|
||||||
<div
|
|
||||||
class=" transition-all rounded-full"
|
|
||||||
style="font-size:{rmsLevel * 100 > 4
|
|
||||||
? '4.5'
|
|
||||||
: rmsLevel * 100 > 2
|
|
||||||
? '4.25'
|
|
||||||
: rmsLevel * 100 > 1
|
|
||||||
? '3.75'
|
|
||||||
: '3.5'}rem;width: 100%; text-align:center;"
|
|
||||||
>
|
|
||||||
{emoji}
|
|
||||||
</div>
|
|
||||||
{:else}
|
{:else}
|
||||||
<div
|
<div
|
||||||
class=" {rmsLevel * 100 > 4
|
class=" {rmsLevel * 100 > 4
|
||||||
@ -628,7 +645,20 @@
|
|||||||
|
|
||||||
<div class="flex justify-center items-center flex-1 h-full w-full max-h-full">
|
<div class="flex justify-center items-center flex-1 h-full w-full max-h-full">
|
||||||
{#if !camera}
|
{#if !camera}
|
||||||
{#if loading}
|
{#if emoji}
|
||||||
|
<div
|
||||||
|
class=" transition-all rounded-full"
|
||||||
|
style="font-size:{rmsLevel * 100 > 4
|
||||||
|
? '13'
|
||||||
|
: rmsLevel * 100 > 2
|
||||||
|
? '12'
|
||||||
|
: rmsLevel * 100 > 1
|
||||||
|
? '11.5'
|
||||||
|
: '11'}rem;width:100%;text-align:center;"
|
||||||
|
>
|
||||||
|
{emoji}
|
||||||
|
</div>
|
||||||
|
{:else if loading}
|
||||||
<svg
|
<svg
|
||||||
class="size-44 text-gray-900 dark:text-gray-400"
|
class="size-44 text-gray-900 dark:text-gray-400"
|
||||||
viewBox="0 0 24 24"
|
viewBox="0 0 24 24"
|
||||||
@ -665,19 +695,6 @@
|
|||||||
r="3"
|
r="3"
|
||||||
/><circle class="spinner_qM83 spinner_ZTLf" cx="20" cy="12" r="3" /></svg
|
/><circle class="spinner_qM83 spinner_ZTLf" cx="20" cy="12" r="3" /></svg
|
||||||
>
|
>
|
||||||
{:else if emoji}
|
|
||||||
<div
|
|
||||||
class=" transition-all rounded-full"
|
|
||||||
style="font-size:{rmsLevel * 100 > 4
|
|
||||||
? '13'
|
|
||||||
: rmsLevel * 100 > 2
|
|
||||||
? '12'
|
|
||||||
: rmsLevel * 100 > 1
|
|
||||||
? '11.5'
|
|
||||||
: '11'}rem;width:100%;text-align:center;"
|
|
||||||
>
|
|
||||||
{emoji}
|
|
||||||
</div>
|
|
||||||
{:else}
|
{:else}
|
||||||
<div
|
<div
|
||||||
class=" {rmsLevel * 100 > 4
|
class=" {rmsLevel * 100 > 4
|
||||||
|
Loading…
Reference in New Issue
Block a user