feat: user stt language
This commit is contained in:
@@ -64,9 +64,12 @@ export const updateAudioConfig = async (token: string, payload: OpenAIConfigForm
|
||||
return res;
|
||||
};
|
||||
|
||||
export const transcribeAudio = async (token: string, file: File) => {
|
||||
export const transcribeAudio = async (token: string, file: File, language?: string) => {
|
||||
const data = new FormData();
|
||||
data.append('file', file);
|
||||
if (language) {
|
||||
data.append('language', language);
|
||||
}
|
||||
|
||||
let error = null;
|
||||
const res = await fetch(`${AUDIO_API_BASE_URL}/transcriptions`, {
|
||||
|
||||
@@ -1,8 +1,12 @@
|
||||
import { WEBUI_API_BASE_URL } from '$lib/constants';
|
||||
|
||||
export const uploadFile = async (token: string, file: File) => {
|
||||
export const uploadFile = async (token: string, file: File, metadata?: object | null) => {
|
||||
const data = new FormData();
|
||||
data.append('file', file);
|
||||
if (metadata) {
|
||||
data.append('metadata', JSON.stringify(metadata));
|
||||
}
|
||||
|
||||
let error = null;
|
||||
|
||||
const res = await fetch(`${WEBUI_API_BASE_URL}/files/`, {
|
||||
|
||||
@@ -17,7 +17,6 @@
|
||||
import { WEBUI_API_BASE_URL } from '$lib/constants';
|
||||
import FileItem from '../common/FileItem.svelte';
|
||||
import Image from '../common/Image.svelte';
|
||||
import { transcribeAudio } from '$lib/apis/audio';
|
||||
import FilesOverlay from '../chat/MessageInput/FilesOverlay.svelte';
|
||||
|
||||
export let placeholder = $i18n.t('Send a Message');
|
||||
@@ -160,7 +159,19 @@
|
||||
|
||||
try {
|
||||
// During the file upload, file content is automatically extracted.
|
||||
const uploadedFile = await uploadFile(localStorage.token, file);
|
||||
|
||||
// If the file is an audio file, provide the language for STT.
|
||||
let metadata = null;
|
||||
if (
|
||||
(file.type.startsWith('audio/') || file.type.startsWith('video/')) &&
|
||||
$settings?.audio?.stt?.language
|
||||
) {
|
||||
metadata = {
|
||||
language: $settings?.audio?.stt?.language
|
||||
};
|
||||
}
|
||||
|
||||
const uploadedFile = await uploadFile(localStorage.token, file, metadata);
|
||||
|
||||
if (uploadedFile) {
|
||||
console.info('File upload completed:', {
|
||||
|
||||
@@ -591,9 +591,20 @@
|
||||
throw new Error('Created file is empty');
|
||||
}
|
||||
|
||||
// If the file is an audio file, provide the language for STT.
|
||||
let metadata = null;
|
||||
if (
|
||||
(file.type.startsWith('audio/') || file.type.startsWith('video/')) &&
|
||||
$settings?.audio?.stt?.language
|
||||
) {
|
||||
metadata = {
|
||||
language: $settings?.audio?.stt?.language
|
||||
};
|
||||
}
|
||||
|
||||
// Upload file to server
|
||||
console.log('Uploading file to server...');
|
||||
const uploadedFile = await uploadFile(localStorage.token, file);
|
||||
const uploadedFile = await uploadFile(localStorage.token, file, metadata);
|
||||
|
||||
if (!uploadedFile) {
|
||||
throw new Error('Server returned null response for file upload');
|
||||
|
||||
@@ -27,7 +27,6 @@
|
||||
createMessagesList,
|
||||
extractCurlyBraceWords
|
||||
} from '$lib/utils';
|
||||
import { transcribeAudio } from '$lib/apis/audio';
|
||||
import { uploadFile } from '$lib/apis/files';
|
||||
import { generateAutoCompletion } from '$lib/apis';
|
||||
import { deleteFileById } from '$lib/apis/files';
|
||||
@@ -249,8 +248,19 @@
|
||||
files = [...files, fileItem];
|
||||
|
||||
try {
|
||||
// If the file is an audio file, provide the language for STT.
|
||||
let metadata = null;
|
||||
if (
|
||||
(file.type.startsWith('audio/') || file.type.startsWith('video/')) &&
|
||||
$settings?.audio?.stt?.language
|
||||
) {
|
||||
metadata = {
|
||||
language: $settings?.audio?.stt?.language
|
||||
};
|
||||
}
|
||||
|
||||
// During the file upload, file content is automatically extracted.
|
||||
const uploadedFile = await uploadFile(localStorage.token, file);
|
||||
const uploadedFile = await uploadFile(localStorage.token, file, metadata);
|
||||
|
||||
if (uploadedFile) {
|
||||
console.log('File upload completed:', {
|
||||
|
||||
@@ -153,7 +153,11 @@
|
||||
await tick();
|
||||
const file = blobToFile(audioBlob, 'recording.wav');
|
||||
|
||||
const res = await transcribeAudio(localStorage.token, file).catch((error) => {
|
||||
const res = await transcribeAudio(
|
||||
localStorage.token,
|
||||
file,
|
||||
$settings?.audio?.stt?.language
|
||||
).catch((error) => {
|
||||
toast.error(`${error}`);
|
||||
return null;
|
||||
});
|
||||
|
||||
@@ -150,7 +150,11 @@
|
||||
return;
|
||||
}
|
||||
|
||||
const res = await transcribeAudio(localStorage.token, file).catch((error) => {
|
||||
const res = await transcribeAudio(
|
||||
localStorage.token,
|
||||
file,
|
||||
$settings?.audio?.stt?.language
|
||||
).catch((error) => {
|
||||
toast.error(`${error}`);
|
||||
return null;
|
||||
});
|
||||
|
||||
@@ -9,6 +9,7 @@
|
||||
import Switch from '$lib/components/common/Switch.svelte';
|
||||
import { round } from '@huggingface/transformers';
|
||||
import Spinner from '$lib/components/common/Spinner.svelte';
|
||||
import Tooltip from '$lib/components/common/Tooltip.svelte';
|
||||
const dispatch = createEventDispatcher();
|
||||
|
||||
const i18n = getContext('i18n');
|
||||
@@ -22,6 +23,7 @@
|
||||
let nonLocalVoices = false;
|
||||
|
||||
let STTEngine = '';
|
||||
let STTLanguage = '';
|
||||
|
||||
let TTSEngine = '';
|
||||
let TTSEngineConfig = {};
|
||||
@@ -89,6 +91,7 @@
|
||||
responseAutoPlayback = $settings.responseAutoPlayback ?? false;
|
||||
|
||||
STTEngine = $settings?.audio?.stt?.engine ?? '';
|
||||
STTLanguage = $settings?.audio?.stt?.language ?? '';
|
||||
|
||||
TTSEngine = $settings?.audio?.tts?.engine ?? '';
|
||||
TTSEngineConfig = $settings?.audio?.tts?.engineConfig ?? {};
|
||||
@@ -156,7 +159,8 @@
|
||||
saveSettings({
|
||||
audio: {
|
||||
stt: {
|
||||
engine: STTEngine !== '' ? STTEngine : undefined
|
||||
engine: STTEngine !== '' ? STTEngine : undefined,
|
||||
language: STTLanguage !== '' ? STTLanguage : undefined
|
||||
},
|
||||
tts: {
|
||||
engine: TTSEngine !== '' ? TTSEngine : undefined,
|
||||
@@ -189,6 +193,26 @@
|
||||
</select>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class=" py-0.5 flex w-full justify-between">
|
||||
<div class=" self-center text-xs font-medium">{$i18n.t('Language')}</div>
|
||||
|
||||
<div class="flex items-center relative text-xs px-3">
|
||||
<Tooltip
|
||||
content={$i18n.t(
|
||||
'The language of the input audio. Supplying the input language in ISO-639-1 (e.g. en) format will improve accuracy and latency. Leave blank to automatically detect the language.'
|
||||
)}
|
||||
placement="top"
|
||||
>
|
||||
<input
|
||||
type="text"
|
||||
bind:value={STTLanguage}
|
||||
placeholder={$i18n.t('e.g. en')}
|
||||
class=" text-sm text-right bg-transparent dark:text-gray-300 outline-hidden"
|
||||
/>
|
||||
</Tooltip>
|
||||
</div>
|
||||
</div>
|
||||
{/if}
|
||||
|
||||
<div class=" py-0.5 flex w-full justify-between">
|
||||
@@ -269,7 +293,7 @@
|
||||
<div class=" py-0.5 flex w-full justify-between">
|
||||
<div class=" self-center text-xs font-medium">{$i18n.t('Speech Playback Speed')}</div>
|
||||
|
||||
<div class="flex items-center relative text-xs">
|
||||
<div class="flex items-center relative text-xs px-3">
|
||||
<input
|
||||
type="number"
|
||||
min="0"
|
||||
|
||||
@@ -1,73 +0,0 @@
|
||||
<script lang="ts">
|
||||
import { DropdownMenu } from 'bits-ui';
|
||||
import { getContext } from 'svelte';
|
||||
|
||||
import { showSettings } from '$lib/stores';
|
||||
import { flyAndScale } from '$lib/utils/transitions';
|
||||
|
||||
import Dropdown from '$lib/components/common/Dropdown.svelte';
|
||||
import QuestionMarkCircle from '$lib/components/icons/QuestionMarkCircle.svelte';
|
||||
import Keyboard from '$lib/components/icons/Keyboard.svelte';
|
||||
import Map from '$lib/components/icons/Map.svelte';
|
||||
|
||||
const i18n = getContext('i18n');
|
||||
|
||||
export let showDocsHandler: Function;
|
||||
export let showShortcutsHandler: Function;
|
||||
|
||||
export let onClose: Function = () => {};
|
||||
</script>
|
||||
|
||||
<Dropdown
|
||||
on:change={(e) => {
|
||||
if (e.detail === false) {
|
||||
onClose();
|
||||
}
|
||||
}}
|
||||
>
|
||||
<slot />
|
||||
|
||||
<div slot="content">
|
||||
<DropdownMenu.Content
|
||||
class="w-full max-w-[200px] rounded-xl px-1 py-1.5 border border-gray-300/30 dark:border-gray-700/50 z-50 bg-white dark:bg-gray-850 dark:text-white shadow-lg"
|
||||
sideOffset={4}
|
||||
side="top"
|
||||
align="end"
|
||||
transition={flyAndScale}
|
||||
>
|
||||
<DropdownMenu.Item
|
||||
class="flex gap-2 items-center px-3 py-2 text-sm cursor-pointer hover:bg-gray-50 dark:hover:bg-gray-800 rounded-md"
|
||||
id="chat-share-button"
|
||||
on:click={() => {
|
||||
window.open('https://docs.openwebui.com', '_blank');
|
||||
}}
|
||||
>
|
||||
<QuestionMarkCircle className="size-5" />
|
||||
<div class="flex items-center">{$i18n.t('Documentation')}</div>
|
||||
</DropdownMenu.Item>
|
||||
|
||||
<!-- Releases -->
|
||||
<DropdownMenu.Item
|
||||
class="flex gap-2 items-center px-3 py-2 text-sm cursor-pointer hover:bg-gray-50 dark:hover:bg-gray-800 rounded-md"
|
||||
id="menu-item-releases"
|
||||
on:click={() => {
|
||||
window.open('https://github.com/open-webui/open-webui/releases', '_blank');
|
||||
}}
|
||||
>
|
||||
<Map className="size-5" />
|
||||
<div class="flex items-center">{$i18n.t('Releases')}</div>
|
||||
</DropdownMenu.Item>
|
||||
|
||||
<DropdownMenu.Item
|
||||
class="flex gap-2 items-center px-3 py-2 text-sm cursor-pointer hover:bg-gray-50 dark:hover:bg-gray-800 rounded-md"
|
||||
id="chat-share-button"
|
||||
on:click={() => {
|
||||
showShortcutsHandler();
|
||||
}}
|
||||
>
|
||||
<Keyboard className="size-5" />
|
||||
<div class="flex items-center">{$i18n.t('Keyboard shortcuts')}</div>
|
||||
</DropdownMenu.Item>
|
||||
</DropdownMenu.Content>
|
||||
</div>
|
||||
</Dropdown>
|
||||
@@ -276,8 +276,19 @@
|
||||
files = [...files, fileItem];
|
||||
|
||||
try {
|
||||
// If the file is an audio file, provide the language for STT.
|
||||
let metadata = null;
|
||||
if (
|
||||
(file.type.startsWith('audio/') || file.type.startsWith('video/')) &&
|
||||
$settings?.audio?.stt?.language
|
||||
) {
|
||||
metadata = {
|
||||
language: $settings?.audio?.stt?.language
|
||||
};
|
||||
}
|
||||
|
||||
// During the file upload, file content is automatically extracted.
|
||||
const uploadedFile = await uploadFile(localStorage.token, file);
|
||||
const uploadedFile = await uploadFile(localStorage.token, file, metadata);
|
||||
|
||||
if (uploadedFile) {
|
||||
console.log('File upload completed:', {
|
||||
|
||||
@@ -26,10 +26,7 @@
|
||||
updateFileFromKnowledgeById,
|
||||
updateKnowledgeById
|
||||
} from '$lib/apis/knowledge';
|
||||
|
||||
import { transcribeAudio } from '$lib/apis/audio';
|
||||
import { blobToFile } from '$lib/utils';
|
||||
import { processFile } from '$lib/apis/retrieval';
|
||||
|
||||
import Spinner from '$lib/components/common/Spinner.svelte';
|
||||
import Files from './KnowledgeBase/Files.svelte';
|
||||
@@ -158,7 +155,18 @@
|
||||
knowledge.files = [...(knowledge.files ?? []), fileItem];
|
||||
|
||||
try {
|
||||
const uploadedFile = await uploadFile(localStorage.token, file).catch((e) => {
|
||||
// If the file is an audio file, provide the language for STT.
|
||||
let metadata = null;
|
||||
if (
|
||||
(file.type.startsWith('audio/') || file.type.startsWith('video/')) &&
|
||||
$settings?.audio?.stt?.language
|
||||
) {
|
||||
metadata = {
|
||||
language: $settings?.audio?.stt?.language
|
||||
};
|
||||
}
|
||||
|
||||
const uploadedFile = await uploadFile(localStorage.token, file, metadata).catch((e) => {
|
||||
toast.error(`${e}`);
|
||||
return null;
|
||||
});
|
||||
|
||||
Reference in New Issue
Block a user