mirror of
https://github.com/danny-avila/LibreChat.git
synced 2025-12-17 08:50:15 +01:00
✨ feat: auto send text slider (#3312)
* feat: convert main component to float * feat: convert the remaining components * feat: use `recoilState` instead of `recoilValue` * feat: replaced `AutoSendTextSwitch` to `AutoSendTextSelector` * feat: use `autoSendText` in the `useSpeechToTextExternal` hook * fix: `autoSendText` timeout
This commit is contained in:
parent
d5d188eebf
commit
d5782ac66c
14 changed files with 737 additions and 749 deletions
|
|
@ -38,8 +38,8 @@ const ChatForm = ({ index = 0 }) => {
|
||||||
const submitButtonRef = useRef<HTMLButtonElement>(null);
|
const submitButtonRef = useRef<HTMLButtonElement>(null);
|
||||||
const textAreaRef = useRef<HTMLTextAreaElement | null>(null);
|
const textAreaRef = useRef<HTMLTextAreaElement | null>(null);
|
||||||
|
|
||||||
const SpeechToText = useRecoilValue(store.speechToText);
|
const SpeechToText = useRecoilState<boolean>(store.speechToText);
|
||||||
const TextToSpeech = useRecoilValue(store.textToSpeech);
|
const TextToSpeech = useRecoilState<boolean>(store.textToSpeech);
|
||||||
const automaticPlayback = useRecoilValue(store.automaticPlayback);
|
const automaticPlayback = useRecoilValue(store.automaticPlayback);
|
||||||
|
|
||||||
const [showStopButton, setShowStopButton] = useRecoilState(store.showStopButtonByIndex(index));
|
const [showStopButton, setShowStopButton] = useRecoilState(store.showStopButtonByIndex(index));
|
||||||
|
|
|
||||||
|
|
@ -10,15 +10,15 @@ export default function ConversationModeSwitch({
|
||||||
}) {
|
}) {
|
||||||
const localize = useLocalize();
|
const localize = useLocalize();
|
||||||
const [conversationMode, setConversationMode] = useRecoilState<boolean>(store.conversationMode);
|
const [conversationMode, setConversationMode] = useRecoilState<boolean>(store.conversationMode);
|
||||||
const [speechToText] = useRecoilState<boolean>(store.speechToText);
|
const speechToText = useRecoilState<boolean>(store.speechToText);
|
||||||
const [textToSpeech] = useRecoilState<boolean>(store.textToSpeech);
|
const textToSpeech = useRecoilState<boolean>(store.textToSpeech);
|
||||||
const [, setAutoSendText] = useRecoilState<boolean>(store.autoSendText);
|
const [, setAutoSendText] = useRecoilState(store.autoSendText);
|
||||||
const [, setDecibelValue] = useRecoilState(store.decibelValue);
|
const [, setDecibelValue] = useRecoilState(store.decibelValue);
|
||||||
const [, setAutoTranscribeAudio] = useRecoilState<boolean>(store.autoTranscribeAudio);
|
const [, setAutoTranscribeAudio] = useRecoilState<boolean>(store.autoTranscribeAudio);
|
||||||
|
|
||||||
const handleCheckedChange = (value: boolean) => {
|
const handleCheckedChange = (value: boolean) => {
|
||||||
setAutoTranscribeAudio(value);
|
setAutoTranscribeAudio(value);
|
||||||
setAutoSendText(value);
|
setAutoSendText(3);
|
||||||
setDecibelValue(-45);
|
setDecibelValue(-45);
|
||||||
setConversationMode(value);
|
setConversationMode(value);
|
||||||
if (onCheckedChange) {
|
if (onCheckedChange) {
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,50 @@
|
||||||
|
import React from 'react';
|
||||||
|
import { useRecoilState } from 'recoil';
|
||||||
|
import { cn, defaultTextProps, optionText } from '~/utils/';
|
||||||
|
import { Slider, InputNumber } from '~/components/ui';
|
||||||
|
import { useLocalize } from '~/hooks';
|
||||||
|
import store from '~/store';
|
||||||
|
|
||||||
|
export default function AutoSendTextSelector() {
|
||||||
|
const localize = useLocalize();
|
||||||
|
|
||||||
|
const speechToText = useRecoilState<boolean>(store.speechToText);
|
||||||
|
const [autoSendText, setAutoSendText] = useRecoilState(store.autoSendText);
|
||||||
|
|
||||||
|
return (
|
||||||
|
<div className="flex items-center justify-between">
|
||||||
|
<div className="flex items-center justify-between">
|
||||||
|
<div>{localize('com_nav_auto_send_text')}</div>
|
||||||
|
<div className="w-2" />
|
||||||
|
<small className="opacity-40">({localize('com_nav_auto_send_text_disabled')})</small>
|
||||||
|
</div>
|
||||||
|
<div className="flex items-center justify-between">
|
||||||
|
<Slider
|
||||||
|
value={[autoSendText ?? -1]}
|
||||||
|
onValueChange={(value) => setAutoSendText(value[0])}
|
||||||
|
doubleClickHandler={() => setAutoSendText(-1)}
|
||||||
|
min={-1}
|
||||||
|
max={60}
|
||||||
|
step={1}
|
||||||
|
className="ml-4 flex h-4 w-24"
|
||||||
|
disabled={!speechToText}
|
||||||
|
/>
|
||||||
|
<div className="w-2" />
|
||||||
|
<InputNumber
|
||||||
|
value={`${autoSendText} s`}
|
||||||
|
disabled={!speechToText}
|
||||||
|
onChange={(value) => setAutoSendText(value ? value[0] : 0)}
|
||||||
|
min={-1}
|
||||||
|
max={60}
|
||||||
|
className={cn(
|
||||||
|
defaultTextProps,
|
||||||
|
cn(
|
||||||
|
optionText,
|
||||||
|
'reset-rc-number-input reset-rc-number-input-text-right h-auto w-12 border-0 group-hover/temp:border-gray-200',
|
||||||
|
),
|
||||||
|
)}
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
@ -1,35 +0,0 @@
|
||||||
import { useRecoilState } from 'recoil';
|
|
||||||
import { Switch } from '~/components/ui';
|
|
||||||
import { useLocalize } from '~/hooks';
|
|
||||||
import store from '~/store';
|
|
||||||
|
|
||||||
export default function AutoSendTextSwitch({
|
|
||||||
onCheckedChange,
|
|
||||||
}: {
|
|
||||||
onCheckedChange?: (value: boolean) => void;
|
|
||||||
}) {
|
|
||||||
const localize = useLocalize();
|
|
||||||
const [autoSendText, setAutoSendText] = useRecoilState<boolean>(store.autoSendText);
|
|
||||||
const [SpeechToText] = useRecoilState<boolean>(store.speechToText);
|
|
||||||
|
|
||||||
const handleCheckedChange = (value: boolean) => {
|
|
||||||
setAutoSendText(value);
|
|
||||||
if (onCheckedChange) {
|
|
||||||
onCheckedChange(value);
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
return (
|
|
||||||
<div className="flex items-center justify-between">
|
|
||||||
<div>{localize('com_nav_auto_send_text')}</div>
|
|
||||||
<Switch
|
|
||||||
id="AutoSendText"
|
|
||||||
checked={autoSendText}
|
|
||||||
onCheckedChange={handleCheckedChange}
|
|
||||||
className="ml-4"
|
|
||||||
data-testid="AutoSendText"
|
|
||||||
disabled={!SpeechToText}
|
|
||||||
/>
|
|
||||||
</div>
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
@ -12,7 +12,7 @@ export default function AutoTranscribeAudioSwitch({
|
||||||
const [autoTranscribeAudio, setAutoTranscribeAudio] = useRecoilState<boolean>(
|
const [autoTranscribeAudio, setAutoTranscribeAudio] = useRecoilState<boolean>(
|
||||||
store.autoTranscribeAudio,
|
store.autoTranscribeAudio,
|
||||||
);
|
);
|
||||||
const [speechToText] = useRecoilState<boolean>(store.speechToText);
|
const speechToText = useRecoilState<boolean>(store.speechToText);
|
||||||
|
|
||||||
const handleCheckedChange = (value: boolean) => {
|
const handleCheckedChange = (value: boolean) => {
|
||||||
setAutoTranscribeAudio(value);
|
setAutoTranscribeAudio(value);
|
||||||
|
|
|
||||||
|
|
@ -1,5 +1,5 @@
|
||||||
import React from 'react';
|
import React from 'react';
|
||||||
import { useRecoilState, useRecoilValue } from 'recoil';
|
import { useRecoilState } from 'recoil';
|
||||||
import { Slider, InputNumber } from '~/components/ui';
|
import { Slider, InputNumber } from '~/components/ui';
|
||||||
import { useLocalize } from '~/hooks';
|
import { useLocalize } from '~/hooks';
|
||||||
import store from '~/store';
|
import store from '~/store';
|
||||||
|
|
@ -7,7 +7,7 @@ import { cn, defaultTextProps, optionText } from '~/utils/';
|
||||||
|
|
||||||
export default function DecibelSelector() {
|
export default function DecibelSelector() {
|
||||||
const localize = useLocalize();
|
const localize = useLocalize();
|
||||||
const speechToText = useRecoilValue(store.speechToText);
|
const speechToText = useRecoilState<boolean>(store.speechToText);
|
||||||
const [decibelValue, setDecibelValue] = useRecoilState(store.decibelValue);
|
const [decibelValue, setDecibelValue] = useRecoilState(store.decibelValue);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
|
|
|
||||||
|
|
@ -1,38 +0,0 @@
|
||||||
import React from 'react';
|
|
||||||
import '@testing-library/jest-dom/extend-expect';
|
|
||||||
import { render, fireEvent } from 'test/layout-test-utils';
|
|
||||||
import AutoSendTextSwitch from '../AutoSendTextSwitch';
|
|
||||||
import { RecoilRoot } from 'recoil';
|
|
||||||
|
|
||||||
describe('AutoSendTextSwitch', () => {
|
|
||||||
/**
|
|
||||||
* Mock function to set the auto-send-text state.
|
|
||||||
*/
|
|
||||||
let mockSetAutoSendText: jest.Mock<void, [boolean]> | ((value: boolean) => void) | undefined;
|
|
||||||
|
|
||||||
beforeEach(() => {
|
|
||||||
mockSetAutoSendText = jest.fn();
|
|
||||||
});
|
|
||||||
|
|
||||||
it('renders correctly', () => {
|
|
||||||
const { getByTestId } = render(
|
|
||||||
<RecoilRoot>
|
|
||||||
<AutoSendTextSwitch />
|
|
||||||
</RecoilRoot>,
|
|
||||||
);
|
|
||||||
|
|
||||||
expect(getByTestId('AutoSendText')).toBeInTheDocument();
|
|
||||||
});
|
|
||||||
|
|
||||||
it('calls onCheckedChange when the switch is toggled', () => {
|
|
||||||
const { getByTestId } = render(
|
|
||||||
<RecoilRoot>
|
|
||||||
<AutoSendTextSwitch onCheckedChange={mockSetAutoSendText} />
|
|
||||||
</RecoilRoot>,
|
|
||||||
);
|
|
||||||
const switchElement = getByTestId('AutoSendText');
|
|
||||||
fireEvent.click(switchElement);
|
|
||||||
|
|
||||||
expect(mockSetAutoSendText).toHaveBeenCalledWith(true);
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
@ -1,4 +1,4 @@
|
||||||
export { default as AutoSendTextSwitch } from './AutoSendTextSwitch';
|
export { default as AutoSendTextSelector } from './AutoSendTextSelector';
|
||||||
export { default as SpeechToTextSwitch } from './SpeechToTextSwitch';
|
export { default as SpeechToTextSwitch } from './SpeechToTextSwitch';
|
||||||
export { default as EngineSTTDropdown } from './EngineSTTDropdown';
|
export { default as EngineSTTDropdown } from './EngineSTTDropdown';
|
||||||
export { default as DecibelSelector } from './DecibelSelector';
|
export { default as DecibelSelector } from './DecibelSelector';
|
||||||
|
|
|
||||||
|
|
@ -20,7 +20,7 @@ import {
|
||||||
AutoTranscribeAudioSwitch,
|
AutoTranscribeAudioSwitch,
|
||||||
LanguageSTTDropdown,
|
LanguageSTTDropdown,
|
||||||
SpeechToTextSwitch,
|
SpeechToTextSwitch,
|
||||||
AutoSendTextSwitch,
|
AutoSendTextSelector,
|
||||||
EngineSTTDropdown,
|
EngineSTTDropdown,
|
||||||
DecibelSelector,
|
DecibelSelector,
|
||||||
} from './STT';
|
} from './STT';
|
||||||
|
|
@ -220,8 +220,8 @@ function Speech() {
|
||||||
<DecibelSelector />
|
<DecibelSelector />
|
||||||
</div>
|
</div>
|
||||||
)}
|
)}
|
||||||
<div className="border-b last-of-type:border-b-0 dark:border-gray-700">
|
<div className="border-b pb-3 last-of-type:border-b-0 dark:border-gray-700">
|
||||||
<AutoSendTextSwitch />
|
<AutoSendTextSelector />
|
||||||
</div>
|
</div>
|
||||||
<div className="h-px bg-black/20 bg-white/20" role="none" />
|
<div className="h-px bg-black/20 bg-white/20" role="none" />
|
||||||
<div className="border-b pb-3 last-of-type:border-b-0 dark:border-gray-700">
|
<div className="border-b pb-3 last-of-type:border-b-0 dark:border-gray-700">
|
||||||
|
|
|
||||||
|
|
@ -10,7 +10,7 @@ const useSpeechToTextExternal = (onTranscriptionComplete: (text: string) => void
|
||||||
const { externalSpeechToText } = useGetAudioSettings();
|
const { externalSpeechToText } = useGetAudioSettings();
|
||||||
const [speechToText] = useRecoilState<boolean>(store.speechToText);
|
const [speechToText] = useRecoilState<boolean>(store.speechToText);
|
||||||
const [autoTranscribeAudio] = useRecoilState<boolean>(store.autoTranscribeAudio);
|
const [autoTranscribeAudio] = useRecoilState<boolean>(store.autoTranscribeAudio);
|
||||||
const [autoSendText] = useRecoilState<boolean>(store.autoSendText);
|
const [autoSendText] = useRecoilState(store.autoSendText);
|
||||||
const [text, setText] = useState<string>('');
|
const [text, setText] = useState<string>('');
|
||||||
const [isListening, setIsListening] = useState(false);
|
const [isListening, setIsListening] = useState(false);
|
||||||
const [permission, setPermission] = useState(false);
|
const [permission, setPermission] = useState(false);
|
||||||
|
|
@ -27,10 +27,11 @@ const useSpeechToTextExternal = (onTranscriptionComplete: (text: string) => void
|
||||||
const extractedText = data.text;
|
const extractedText = data.text;
|
||||||
setText(extractedText);
|
setText(extractedText);
|
||||||
setIsRequestBeingMade(false);
|
setIsRequestBeingMade(false);
|
||||||
if (autoSendText && speechToText && extractedText.length > 0) {
|
|
||||||
|
if (autoSendText > -1 && speechToText && extractedText.length > 0) {
|
||||||
setTimeout(() => {
|
setTimeout(() => {
|
||||||
onTranscriptionComplete(extractedText);
|
onTranscriptionComplete(extractedText);
|
||||||
}, 3000);
|
}, autoSendText * 1000);
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
onError: () => {
|
onError: () => {
|
||||||
|
|
|
||||||
|
|
@ -628,7 +628,8 @@ export default {
|
||||||
com_nav_delete_warning: 'WARNING: This will permanently delete your account.',
|
com_nav_delete_warning: 'WARNING: This will permanently delete your account.',
|
||||||
com_nav_delete_data_info: 'All your data will be deleted.',
|
com_nav_delete_data_info: 'All your data will be deleted.',
|
||||||
com_nav_conversation_mode: 'Conversation Mode',
|
com_nav_conversation_mode: 'Conversation Mode',
|
||||||
com_nav_auto_send_text: 'Auto send text (after 3 sec)',
|
com_nav_auto_send_text: 'Auto send text',
|
||||||
|
com_nav_auto_send_text_disabled: 'set -1 to disable',
|
||||||
com_nav_auto_transcribe_audio: 'Auto transcribe audio',
|
com_nav_auto_transcribe_audio: 'Auto transcribe audio',
|
||||||
com_nav_db_sensitivity: 'Decibel sensitivity',
|
com_nav_db_sensitivity: 'Decibel sensitivity',
|
||||||
com_nav_playback_rate: 'Audio Playback Rate',
|
com_nav_playback_rate: 'Audio Playback Rate',
|
||||||
|
|
|
||||||
|
|
@ -30,8 +30,7 @@ export default {
|
||||||
'Avustaja täytyy ensin luoda, ja Kooditulkki tai Tiedonhaku täytyy olla päällä ja asetukset tallennettuna, ennen kuin tiedostoja voidaan ladata Tietoihin.',
|
'Avustaja täytyy ensin luoda, ja Kooditulkki tai Tiedonhaku täytyy olla päällä ja asetukset tallennettuna, ennen kuin tiedostoja voidaan ladata Tietoihin.',
|
||||||
com_assistants_image_vision: 'Kuvanäkö',
|
com_assistants_image_vision: 'Kuvanäkö',
|
||||||
com_assistants_code_interpreter: 'Kooditulkki',
|
com_assistants_code_interpreter: 'Kooditulkki',
|
||||||
com_assistants_code_interpreter_files:
|
com_assistants_code_interpreter_files: 'Seuraavat tiedostot ovat vain Kooditulkin käytettävissä:',
|
||||||
'Seuraavat tiedostot ovat vain Kooditulkin käytettävissä:',
|
|
||||||
com_assistants_retrieval: 'Tiedonhaku',
|
com_assistants_retrieval: 'Tiedonhaku',
|
||||||
com_assistants_search_name: 'Hae Avustajia nimen perusteella',
|
com_assistants_search_name: 'Hae Avustajia nimen perusteella',
|
||||||
com_assistants_tools: 'Työkalut',
|
com_assistants_tools: 'Työkalut',
|
||||||
|
|
@ -50,7 +49,8 @@ export default {
|
||||||
com_assistants_update_actions_success: 'Toiminto luotiiin tai päivitettiin onnistuneesti',
|
com_assistants_update_actions_success: 'Toiminto luotiiin tai päivitettiin onnistuneesti',
|
||||||
com_assistants_update_actions_error: 'Toiminnon luomisessa tai päivittämisessä tapahtui virhe.',
|
com_assistants_update_actions_error: 'Toiminnon luomisessa tai päivittämisessä tapahtui virhe.',
|
||||||
com_assistants_delete_actions_error: 'Toiminnon poistamisessa tapahtui virhe.',
|
com_assistants_delete_actions_error: 'Toiminnon poistamisessa tapahtui virhe.',
|
||||||
com_assistants_actions_info: 'Salli Avustajalle Tiedonhaku tai Toimintojen suorittaminen API-kutsujen kautta',
|
com_assistants_actions_info:
|
||||||
|
'Salli Avustajalle Tiedonhaku tai Toimintojen suorittaminen API-kutsujen kautta',
|
||||||
com_assistants_name_placeholder: 'Valinnainen: Avustajan nimi',
|
com_assistants_name_placeholder: 'Valinnainen: Avustajan nimi',
|
||||||
com_assistants_instructions_placeholder: 'Avustajan käyttämät järjestelmäohjeet',
|
com_assistants_instructions_placeholder: 'Avustajan käyttämät järjestelmäohjeet',
|
||||||
com_assistants_description_placeholder: 'Valinnainen: Kuvaus Avustajasta',
|
com_assistants_description_placeholder: 'Valinnainen: Kuvaus Avustajasta',
|
||||||
|
|
@ -79,7 +79,8 @@ export default {
|
||||||
com_ui_download_error: 'Virhe tiedoston lataamisesta. Tiedosto on saatettu poistaa.',
|
com_ui_download_error: 'Virhe tiedoston lataamisesta. Tiedosto on saatettu poistaa.',
|
||||||
com_ui_attach_error_type: 'Päätepiste ei tue tiedostotyyppiä::',
|
com_ui_attach_error_type: 'Päätepiste ei tue tiedostotyyppiä::',
|
||||||
com_ui_attach_error_openai: 'Avustajan tiedostoja ei voi liittää muihin päätepisteisiin',
|
com_ui_attach_error_openai: 'Avustajan tiedostoja ei voi liittää muihin päätepisteisiin',
|
||||||
com_ui_attach_warn_endpoint: 'Ilman yhteensopivaa työkalua muut kuin Avustajan tiedostot voidaan jättää huomiotta.',
|
com_ui_attach_warn_endpoint:
|
||||||
|
'Ilman yhteensopivaa työkalua muut kuin Avustajan tiedostot voidaan jättää huomiotta.',
|
||||||
com_ui_attach_error_size: 'Tiedoston koko ylittää päätepisteen rajan:',
|
com_ui_attach_error_size: 'Tiedoston koko ylittää päätepisteen rajan:',
|
||||||
com_ui_attach_error:
|
com_ui_attach_error:
|
||||||
'Tiedosto ei voi liittää. Luo tai valitse keskustelu, tai kokeile ladata sivu uudestaan.',
|
'Tiedosto ei voi liittää. Luo tai valitse keskustelu, tai kokeile ladata sivu uudestaan.',
|
||||||
|
|
@ -147,7 +148,8 @@ export default {
|
||||||
com_ui_showing: 'Näytetään',
|
com_ui_showing: 'Näytetään',
|
||||||
com_ui_of: '/',
|
com_ui_of: '/',
|
||||||
com_ui_entries: 'Merkinnät',
|
com_ui_entries: 'Merkinnät',
|
||||||
com_ui_pay_per_call: 'Kaikki tekoälykeskustelut yhdessä paikassa. Maksa kerrasta, älä kuukaudesta.',
|
com_ui_pay_per_call:
|
||||||
|
'Kaikki tekoälykeskustelut yhdessä paikassa. Maksa kerrasta, älä kuukaudesta.',
|
||||||
com_ui_new_footer: 'Kaikki tekoälykeskustelut yhdessä paikassa.',
|
com_ui_new_footer: 'Kaikki tekoälykeskustelut yhdessä paikassa.',
|
||||||
com_ui_latest_footer: 'Kaikki tekoälyt kaikille.',
|
com_ui_latest_footer: 'Kaikki tekoälyt kaikille.',
|
||||||
com_ui_enter: 'Syötä',
|
com_ui_enter: 'Syötä',
|
||||||
|
|
@ -155,8 +157,10 @@ export default {
|
||||||
com_ui_none_selected: 'Ei valintaa',
|
com_ui_none_selected: 'Ei valintaa',
|
||||||
com_ui_upload_success: 'Tiedoston lataus onnistui',
|
com_ui_upload_success: 'Tiedoston lataus onnistui',
|
||||||
com_ui_upload_error: 'Tiedoston lataamisessa tapahtui virhe',
|
com_ui_upload_error: 'Tiedoston lataamisessa tapahtui virhe',
|
||||||
com_ui_upload_invalid: 'Virheellinen ladattava tiedosto. Tiedoston täytyy olla kokorajaan mahtuva kuvatiedosto',
|
com_ui_upload_invalid:
|
||||||
com_ui_upload_invalid_var: 'Virheellinen ladattava tiedosto. Tiedoston täytyy olla enintään {0} MB kokoinen kuvatiedosto',
|
'Virheellinen ladattava tiedosto. Tiedoston täytyy olla kokorajaan mahtuva kuvatiedosto',
|
||||||
|
com_ui_upload_invalid_var:
|
||||||
|
'Virheellinen ladattava tiedosto. Tiedoston täytyy olla enintään {0} MB kokoinen kuvatiedosto',
|
||||||
com_ui_cancel: 'Peruuta',
|
com_ui_cancel: 'Peruuta',
|
||||||
com_ui_save: 'Tallenna',
|
com_ui_save: 'Tallenna',
|
||||||
com_ui_renaming_var: 'Uudelleennimetään "{0}"',
|
com_ui_renaming_var: 'Uudelleennimetään "{0}"',
|
||||||
|
|
@ -256,7 +260,8 @@ export default {
|
||||||
com_ui_share_error: 'Keskustelulinkin jakamisessa tapahtui virhe',
|
com_ui_share_error: 'Keskustelulinkin jakamisessa tapahtui virhe',
|
||||||
com_ui_share_retrieve_error: 'Jaettujen linkkien jakamisessa tapahtui virhe',
|
com_ui_share_retrieve_error: 'Jaettujen linkkien jakamisessa tapahtui virhe',
|
||||||
com_ui_share_delete_error: 'Jaetun linkin poistossa tapahtui virhe',
|
com_ui_share_delete_error: 'Jaetun linkin poistossa tapahtui virhe',
|
||||||
com_ui_share_create_message: 'Nimesi ja jakamisen jälkeen lisätäämäsi viestit pysyvät yksityisinä.',
|
com_ui_share_create_message:
|
||||||
|
'Nimesi ja jakamisen jälkeen lisätäämäsi viestit pysyvät yksityisinä.',
|
||||||
com_ui_share_created_message:
|
com_ui_share_created_message:
|
||||||
'Jakolinkki keskusteluun on luotu. Hallinnoi aiemmin jaettuja keskusteluja milloin vain Asetusten kautta.',
|
'Jakolinkki keskusteluun on luotu. Hallinnoi aiemmin jaettuja keskusteluja milloin vain Asetusten kautta.',
|
||||||
com_ui_share_update_message:
|
com_ui_share_update_message:
|
||||||
|
|
@ -291,10 +296,8 @@ export default {
|
||||||
'Kirjautuminen annetuilla tiedoilla ei onnistunut. Tarkista kirjautumistiedot, ja yritä uudestaan.',
|
'Kirjautuminen annetuilla tiedoilla ei onnistunut. Tarkista kirjautumistiedot, ja yritä uudestaan.',
|
||||||
com_auth_error_login_rl:
|
com_auth_error_login_rl:
|
||||||
'Liian monta kirjautumisyritystä lyhyen ajan sisällä. Yritä myöhemmin uudestaan.',
|
'Liian monta kirjautumisyritystä lyhyen ajan sisällä. Yritä myöhemmin uudestaan.',
|
||||||
com_auth_error_login_ban:
|
com_auth_error_login_ban: 'Tilisi on väliaikaisesti suljettu palvelun sääntöjen rikkomisesta.',
|
||||||
'Tilisi on väliaikaisesti suljettu palvelun sääntöjen rikkomisesta.',
|
com_auth_error_login_server: 'Tapahtui sisäinen palvelinvirhe. Odota hetki, ja yritä uudestaan.',
|
||||||
com_auth_error_login_server:
|
|
||||||
'Tapahtui sisäinen palvelinvirhe. Odota hetki, ja yritä uudestaan.',
|
|
||||||
com_auth_error_login_unverified:
|
com_auth_error_login_unverified:
|
||||||
'Tiliäsi ei ole vahvistettu. Vahvistuslinkin pitäisi löytyä sähköposteistasi.',
|
'Tiliäsi ei ole vahvistettu. Vahvistuslinkin pitäisi löytyä sähköposteistasi.',
|
||||||
com_auth_no_account: 'Ei tunnusta?',
|
com_auth_no_account: 'Ei tunnusta?',
|
||||||
|
|
@ -319,8 +322,7 @@ export default {
|
||||||
com_auth_password_not_match: 'Salasanat eivät täsmää',
|
com_auth_password_not_match: 'Salasanat eivät täsmää',
|
||||||
com_auth_continue: 'Jatka',
|
com_auth_continue: 'Jatka',
|
||||||
com_auth_create_account: 'Luo tili',
|
com_auth_create_account: 'Luo tili',
|
||||||
com_auth_error_create:
|
com_auth_error_create: 'Tilin rekisteröinnissä tapahtui virhe. Yritä uudestaan.',
|
||||||
'Tilin rekisteröinnissä tapahtui virhe. Yritä uudestaan.',
|
|
||||||
com_auth_full_name: 'Koko nimi',
|
com_auth_full_name: 'Koko nimi',
|
||||||
com_auth_name_required: 'Nimi on pakollinen',
|
com_auth_name_required: 'Nimi on pakollinen',
|
||||||
com_auth_name_min_length: 'Nimessä on oltava vähintään 3 merkkiä',
|
com_auth_name_min_length: 'Nimessä on oltava vähintään 3 merkkiä',
|
||||||
|
|
@ -332,7 +334,8 @@ export default {
|
||||||
com_auth_already_have_account: 'Käyttäjätilisi on jo luotu?',
|
com_auth_already_have_account: 'Käyttäjätilisi on jo luotu?',
|
||||||
com_auth_login: 'Kirjaudu',
|
com_auth_login: 'Kirjaudu',
|
||||||
com_auth_registration_success_insecure: 'Rekisteröityminen onnistui.',
|
com_auth_registration_success_insecure: 'Rekisteröityminen onnistui.',
|
||||||
com_auth_registration_success_generic: 'Tarkista sähköpostisi sähköpostiosoitteen vahvistamiseksi.',
|
com_auth_registration_success_generic:
|
||||||
|
'Tarkista sähköpostisi sähköpostiosoitteen vahvistamiseksi.',
|
||||||
com_auth_reset_password: 'Aseta uusi salasana',
|
com_auth_reset_password: 'Aseta uusi salasana',
|
||||||
com_auth_click: 'Napauta',
|
com_auth_click: 'Napauta',
|
||||||
com_auth_here: 'TÄTÄ',
|
com_auth_here: 'TÄTÄ',
|
||||||
|
|
@ -355,7 +358,8 @@ export default {
|
||||||
com_auth_email_verification_success: 'Sähköposti varmennettu',
|
com_auth_email_verification_success: 'Sähköposti varmennettu',
|
||||||
com_auth_email_resent_success: 'Varmennussähköpostin uudelleenlähetys onnistui',
|
com_auth_email_resent_success: 'Varmennussähköpostin uudelleenlähetys onnistui',
|
||||||
com_auth_email_resent_failed: 'Varmennussähköpostin uudelleenlähetys epäonnistui',
|
com_auth_email_resent_failed: 'Varmennussähköpostin uudelleenlähetys epäonnistui',
|
||||||
com_auth_email_verification_failed_token_missing: 'Varmennus epäonnistui tunnisteen puuttumisen vuoksi',
|
com_auth_email_verification_failed_token_missing:
|
||||||
|
'Varmennus epäonnistui tunnisteen puuttumisen vuoksi',
|
||||||
com_auth_email_verification_invalid: 'Sähköpostin varmentaminen ei voimassa',
|
com_auth_email_verification_invalid: 'Sähköpostin varmentaminen ei voimassa',
|
||||||
com_auth_email_verification_in_progress: 'Varmennetaan sähköpostia. Ole hyvä ja odota.',
|
com_auth_email_verification_in_progress: 'Varmennetaan sähköpostia. Ole hyvä ja odota.',
|
||||||
com_auth_email_verification_resend_prompt: 'Sähköposti ei saapunut perille?',
|
com_auth_email_verification_resend_prompt: 'Sähköposti ei saapunut perille?',
|
||||||
|
|
@ -383,7 +387,7 @@ export default {
|
||||||
com_endpoint_token_count: 'Token-määrä',
|
com_endpoint_token_count: 'Token-määrä',
|
||||||
com_endpoint_output: 'Tulos',
|
com_endpoint_output: 'Tulos',
|
||||||
com_endpoint_context_tokens: 'Konteksti-tokenien maksimimäärä',
|
com_endpoint_context_tokens: 'Konteksti-tokenien maksimimäärä',
|
||||||
com_endpoint_context_info: `Kontekstia varten käytettävien tokeneiden maksimimäärä. Käytä tätä pyyntökohtaisten token-määrien hallinnointiin. Jos tätä ei määritetä, käytössä ovat järjestelmän oletusarvot perustuen tiedossa olevien mallien konteksti-ikkunoiden kokoon. Korkeamman arvon asettaminen voi aiheuttaa virheitä tai korkeamman token-hinnan.`,
|
com_endpoint_context_info: 'Kontekstia varten käytettävien tokeneiden maksimimäärä. Käytä tätä pyyntökohtaisten token-määrien hallinnointiin. Jos tätä ei määritetä, käytössä ovat järjestelmän oletusarvot perustuen tiedossa olevien mallien konteksti-ikkunoiden kokoon. Korkeamman arvon asettaminen voi aiheuttaa virheitä tai korkeamman token-hinnan.',
|
||||||
com_endpoint_google_temp:
|
com_endpoint_google_temp:
|
||||||
'Korkeampi arvo = satunnaisempi; matalampi arvo = keskittyneempi ja deterministisempi. Suosittelemme, että muokkaat tätä tai Top P:tä, mutta ei molempia.',
|
'Korkeampi arvo = satunnaisempi; matalampi arvo = keskittyneempi ja deterministisempi. Suosittelemme, että muokkaat tätä tai Top P:tä, mutta ei molempia.',
|
||||||
com_endpoint_google_topp:
|
com_endpoint_google_topp:
|
||||||
|
|
@ -393,7 +397,8 @@ export default {
|
||||||
com_endpoint_google_maxoutputtokens:
|
com_endpoint_google_maxoutputtokens:
|
||||||
'Maksimimäärä tokeneillre, joita generoidaan tulokseen. Valitse pienempi arvo saadaksesi lyhyempiä vastauksia, ja suurempi arvo pitkiä vastauksia varten.',
|
'Maksimimäärä tokeneillre, joita generoidaan tulokseen. Valitse pienempi arvo saadaksesi lyhyempiä vastauksia, ja suurempi arvo pitkiä vastauksia varten.',
|
||||||
com_endpoint_google_custom_name_placeholder: 'Aseta Googlelle mukautettu nimi',
|
com_endpoint_google_custom_name_placeholder: 'Aseta Googlelle mukautettu nimi',
|
||||||
com_endpoint_prompt_prefix_placeholder: 'Aseta mukautetut ohjeet tai konteksti. Jätetään huomiotta, jos tyhjä.',
|
com_endpoint_prompt_prefix_placeholder:
|
||||||
|
'Aseta mukautetut ohjeet tai konteksti. Jätetään huomiotta, jos tyhjä.',
|
||||||
com_endpoint_instructions_assistants_placeholder:
|
com_endpoint_instructions_assistants_placeholder:
|
||||||
'Yliajaa Avustajan ohjeet. Tätä voi hyödyntää käytöksen muuttamiseen keskustelukohtaisesti.',
|
'Yliajaa Avustajan ohjeet. Tätä voi hyödyntää käytöksen muuttamiseen keskustelukohtaisesti.',
|
||||||
com_endpoint_prompt_prefix_assistants_placeholder:
|
com_endpoint_prompt_prefix_assistants_placeholder:
|
||||||
|
|
@ -428,7 +433,8 @@ export default {
|
||||||
'Lähetä uudestaan kaikki aiemmin liitetyt tiedostot. Huom: tämä lisää token-kustannuksia, ja useiden tiedostojen käsittelystä kerralla voi seurata virheitä.',
|
'Lähetä uudestaan kaikki aiemmin liitetyt tiedostot. Huom: tämä lisää token-kustannuksia, ja useiden tiedostojen käsittelystä kerralla voi seurata virheitä.',
|
||||||
com_endpoint_openai_detail:
|
com_endpoint_openai_detail:
|
||||||
'Kuvatarkkuus Vision-pyynnöille. "Matala" on halvempi ja nopeampi, "Korkea" on yksityiskohtaisempi ja kalliimpi, ja "Auto" valitsee näiden välillä automaattisesti kuvan koon perusteella.',
|
'Kuvatarkkuus Vision-pyynnöille. "Matala" on halvempi ja nopeampi, "Korkea" on yksityiskohtaisempi ja kalliimpi, ja "Auto" valitsee näiden välillä automaattisesti kuvan koon perusteella.',
|
||||||
com_endpoint_openai_stop: 'Enintään 4 sekvenssiä, joiden kohdalla API lopettaa tokenien luomisen.',
|
com_endpoint_openai_stop:
|
||||||
|
'Enintään 4 sekvenssiä, joiden kohdalla API lopettaa tokenien luomisen.',
|
||||||
com_endpoint_openai_custom_name_placeholder: 'Anna tekoälylle mukautettu nimi',
|
com_endpoint_openai_custom_name_placeholder: 'Anna tekoälylle mukautettu nimi',
|
||||||
com_endpoint_openai_prompt_prefix_placeholder:
|
com_endpoint_openai_prompt_prefix_placeholder:
|
||||||
'Aseta mukautetut ohjeet Järjestelmäohjeisiin sisällytettäväksi. Oletus: tyhjä',
|
'Aseta mukautetut ohjeet Järjestelmäohjeisiin sisällytettäväksi. Oletus: tyhjä',
|
||||||
|
|
@ -488,7 +494,8 @@ export default {
|
||||||
com_endpoint_presets_clear_warning:
|
com_endpoint_presets_clear_warning:
|
||||||
'Haluatko varmasti tyhjentää kaikki esiasetukset? Tätä toimintoa ei voi perua.',
|
'Haluatko varmasti tyhjentää kaikki esiasetukset? Tätä toimintoa ei voi perua.',
|
||||||
com_endpoint_not_implemented: 'Ei toteutettu',
|
com_endpoint_not_implemented: 'Ei toteutettu',
|
||||||
com_endpoint_no_presets: 'Ei vielä esiasetuksia. Käytä Asetukset-painiketta luodaksesi esiasetuksen.',
|
com_endpoint_no_presets:
|
||||||
|
'Ei vielä esiasetuksia. Käytä Asetukset-painiketta luodaksesi esiasetuksen.',
|
||||||
com_endpoint_not_available: 'Päätepistettä ei ole tarjolla',
|
com_endpoint_not_available: 'Päätepistettä ei ole tarjolla',
|
||||||
com_endpoint_view_options: 'Katseluvaihtoehdot',
|
com_endpoint_view_options: 'Katseluvaihtoehdot',
|
||||||
com_endpoint_save_convo_as_preset: 'Tallenna keskustelu esiasetukseksi',
|
com_endpoint_save_convo_as_preset: 'Tallenna keskustelu esiasetukseksi',
|
||||||
|
|
@ -513,9 +520,11 @@ export default {
|
||||||
com_endpoint_config_google_cloud_platform: '(Google Cloud Platform:ista)',
|
com_endpoint_config_google_cloud_platform: '(Google Cloud Platform:ista)',
|
||||||
com_endpoint_config_google_api_key: 'Google API Key',
|
com_endpoint_config_google_api_key: 'Google API Key',
|
||||||
com_endpoint_config_google_gemini_api: '(Gemini API)',
|
com_endpoint_config_google_gemini_api: '(Gemini API)',
|
||||||
com_endpoint_config_google_api_info: 'Saadaksesi Generative Language API -avaimesi (Gemini:a varten),',
|
com_endpoint_config_google_api_info:
|
||||||
|
'Saadaksesi Generative Language API -avaimesi (Gemini:a varten),',
|
||||||
com_endpoint_config_key_import_json_key: 'Tuo palveluosoitteen JSON-avain.',
|
com_endpoint_config_key_import_json_key: 'Tuo palveluosoitteen JSON-avain.',
|
||||||
com_endpoint_config_key_import_json_key_success: 'Palveluosoitteetn JSON-avain tuotu onnistuneesti',
|
com_endpoint_config_key_import_json_key_success:
|
||||||
|
'Palveluosoitteetn JSON-avain tuotu onnistuneesti',
|
||||||
com_endpoint_config_key_import_json_key_invalid:
|
com_endpoint_config_key_import_json_key_invalid:
|
||||||
'Virheellinen palveluosoitteen JSON-avain. Toitko oikean tiedoston?',
|
'Virheellinen palveluosoitteen JSON-avain. Toitko oikean tiedoston?',
|
||||||
com_endpoint_config_key_get_edge_key: 'Saadaksisi pääsytunnuksesi Bingiä varten, kirjaudu',
|
com_endpoint_config_key_get_edge_key: 'Saadaksisi pääsytunnuksesi Bingiä varten, kirjaudu',
|
||||||
|
|
@ -523,7 +532,8 @@ export default {
|
||||||
'Käytä kehitystyökaluja ja lisäosaa sivustolle kirjautuneena _U -evästeen kopioimiseen. Jos tämä ei toimi, seuraa näitä',
|
'Käytä kehitystyökaluja ja lisäosaa sivustolle kirjautuneena _U -evästeen kopioimiseen. Jos tämä ei toimi, seuraa näitä',
|
||||||
com_endpoint_config_key_edge_instructions: 'ohjeita',
|
com_endpoint_config_key_edge_instructions: 'ohjeita',
|
||||||
com_endpoint_config_key_edge_full_key_string: 'saadaksesi täydet evästemerkkijonot.',
|
com_endpoint_config_key_edge_full_key_string: 'saadaksesi täydet evästemerkkijonot.',
|
||||||
com_endpoint_config_key_chatgpt: 'Saadaksesi pääsytunnuksesi ChatGPT:n \'ilmaisversiota\' varten, kirjaudu',
|
com_endpoint_config_key_chatgpt:
|
||||||
|
'Saadaksesi pääsytunnuksesi ChatGPT:n \'ilmaisversiota\' varten, kirjaudu',
|
||||||
com_endpoint_config_key_chatgpt_then_visit: 'sitten vieraile',
|
com_endpoint_config_key_chatgpt_then_visit: 'sitten vieraile',
|
||||||
com_endpoint_config_key_chatgpt_copy_token: 'Kopioi pääsytunnus.',
|
com_endpoint_config_key_chatgpt_copy_token: 'Kopioi pääsytunnus.',
|
||||||
com_endpoint_config_key_google_need_to: 'Sinun täytyy',
|
com_endpoint_config_key_google_need_to: 'Sinun täytyy',
|
||||||
|
|
@ -566,8 +576,7 @@ export default {
|
||||||
com_show_examples: 'Näytä esimerkit',
|
com_show_examples: 'Näytä esimerkit',
|
||||||
com_nav_plugin_search: 'Hae lisäosaa',
|
com_nav_plugin_search: 'Hae lisäosaa',
|
||||||
com_nav_tool_search: 'Hakutyökalut',
|
com_nav_tool_search: 'Hakutyökalut',
|
||||||
com_nav_plugin_auth_error:
|
com_nav_plugin_auth_error: 'Tämän lisäosan varmentamisessa tapahtui virhe. Yritä uudestaan.',
|
||||||
'Tämän lisäosan varmentamisessa tapahtui virhe. Yritä uudestaan.',
|
|
||||||
com_nav_export_filename: 'Tiedoston nimi',
|
com_nav_export_filename: 'Tiedoston nimi',
|
||||||
com_nav_export_filename_placeholder: 'Aseta tiedoston nimi',
|
com_nav_export_filename_placeholder: 'Aseta tiedoston nimi',
|
||||||
com_nav_export_type: 'Tyyppi',
|
com_nav_export_type: 'Tyyppi',
|
||||||
|
|
@ -620,7 +629,8 @@ export default {
|
||||||
com_nav_delete_account_confirm: 'Poista käyttäjätili - oletko varma?',
|
com_nav_delete_account_confirm: 'Poista käyttäjätili - oletko varma?',
|
||||||
com_nav_delete_account_button: 'Poista käyttäjätilini pysyvästi',
|
com_nav_delete_account_button: 'Poista käyttäjätilini pysyvästi',
|
||||||
com_nav_delete_account_email_placeholder: 'Syötä käyttäjätilisi sähköpostiosoite',
|
com_nav_delete_account_email_placeholder: 'Syötä käyttäjätilisi sähköpostiosoite',
|
||||||
com_nav_delete_account_confirm_placeholder: 'Jatkaaksesi syötä "DELETE" alla olevaan syötekenttään',
|
com_nav_delete_account_confirm_placeholder:
|
||||||
|
'Jatkaaksesi syötä "DELETE" alla olevaan syötekenttään',
|
||||||
com_nav_delete_warning: 'VAROITUS: Tämä poistaa käyttäjätilisi pysyvästi.',
|
com_nav_delete_warning: 'VAROITUS: Tämä poistaa käyttäjätilisi pysyvästi.',
|
||||||
com_nav_delete_data_info: 'Kaikki tietosi poistetaan.',
|
com_nav_delete_data_info: 'Kaikki tietosi poistetaan.',
|
||||||
com_nav_conversation_mode: 'Keskustelumoodi',
|
com_nav_conversation_mode: 'Keskustelumoodi',
|
||||||
|
|
@ -660,5 +670,4 @@ export default {
|
||||||
com_nav_setting_speech: 'Puhe',
|
com_nav_setting_speech: 'Puhe',
|
||||||
com_nav_language: 'Kieli',
|
com_nav_language: 'Kieli',
|
||||||
com_nav_lang_auto: 'Tunnista automaattisesti',
|
com_nav_lang_auto: 'Tunnista automaattisesti',
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -45,7 +45,7 @@ const localStorageAtoms = {
|
||||||
languageSTT: atomWithLocalStorage('languageSTT', ''),
|
languageSTT: atomWithLocalStorage('languageSTT', ''),
|
||||||
autoTranscribeAudio: atomWithLocalStorage('autoTranscribeAudio', false),
|
autoTranscribeAudio: atomWithLocalStorage('autoTranscribeAudio', false),
|
||||||
decibelValue: atomWithLocalStorage('decibelValue', -45),
|
decibelValue: atomWithLocalStorage('decibelValue', -45),
|
||||||
autoSendText: atomWithLocalStorage('autoSendText', false),
|
autoSendText: atomWithLocalStorage('autoSendText', -1),
|
||||||
|
|
||||||
textToSpeech: atomWithLocalStorage('textToSpeech', true),
|
textToSpeech: atomWithLocalStorage('textToSpeech', true),
|
||||||
engineTTS: atomWithLocalStorage('engineTTS', 'browser'),
|
engineTTS: atomWithLocalStorage('engineTTS', 'browser'),
|
||||||
|
|
|
||||||
|
|
@ -304,7 +304,7 @@ const speechTab = z
|
||||||
languageSTT: z.string().optional(),
|
languageSTT: z.string().optional(),
|
||||||
autoTranscribeAudio: z.boolean().optional(),
|
autoTranscribeAudio: z.boolean().optional(),
|
||||||
decibelValue: z.number().optional(),
|
decibelValue: z.number().optional(),
|
||||||
autoSendText: z.boolean().optional(),
|
autoSendText: z.number().optional(),
|
||||||
}),
|
}),
|
||||||
)
|
)
|
||||||
.optional(),
|
.optional(),
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue