🔄 feat: chat direction (LTR-RTL) (#3260)

* feat: chat direction

* fix: FileRow

* feat: smooth trigger transition
This commit is contained in:
Marco Beretta 2024-07-17 16:08:13 +02:00 committed by GitHub
parent d5782ac66c
commit 237a0de8b6
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
31 changed files with 145 additions and 111 deletions

View file

@ -4,16 +4,19 @@ import { ListeningIcon, Spinner } from '~/components/svg';
import { useLocalize, useSpeechToText } from '~/hooks';
import { useChatFormContext } from '~/Providers';
import { globalAudioId } from '~/common';
import { cn } from '~/utils';
export default function AudioRecorder({
textAreaRef,
methods,
ask,
isRTL,
disabled,
}: {
textAreaRef: React.RefObject<HTMLTextAreaElement>;
methods: ReturnType<typeof useChatFormContext>;
ask: (data: { text: string }) => void;
isRTL: boolean;
disabled: boolean;
}) {
const localize = useLocalize();
@ -77,7 +80,12 @@ export default function AudioRecorder({
<button
onClick={isListening ? handleStopRecording : handleStartRecording}
disabled={disabled}
className="absolute bottom-1.5 right-12 flex h-[30px] w-[30px] items-center justify-center rounded-lg p-0.5 transition-colors hover:bg-gray-200 dark:hover:bg-gray-700 md:bottom-3 md:right-12"
className={cn(
'absolute flex h-[30px] w-[30px] items-center justify-center rounded-lg p-0.5 transition-colors hover:bg-gray-200 dark:hover:bg-gray-700',
isRTL
? 'bottom-1.5 left-4 md:bottom-3 md:left-12'
: 'bottom-1.5 right-12 md:bottom-3 md:right-12',
)}
type="button"
>
{renderIcon()}

View file

@ -48,6 +48,9 @@ const ChatForm = ({ index = 0 }) => {
store.showMentionPopoverFamily(index),
);
const chatDirection = useRecoilValue(store.chatDirection).toLowerCase();
const isRTL = chatDirection === 'rtl';
const { requiresKey } = useRequiresKey();
const handleKeyUp = useHandleKeyUp({
index,
@ -149,6 +152,7 @@ const ChatForm = ({ index = 0 }) => {
files={files}
setFiles={setFiles}
setFilesLoading={setFilesLoading}
isRTL={isRTL}
Wrapper={({ children }) => (
<div className="mx-2 mt-2 flex flex-wrap gap-2 px-2.5 md:pl-0 md:pr-4">
{children}
@ -179,7 +183,7 @@ const ChatForm = ({ index = 0 }) => {
? ' pl-10 md:pl-[55px]'
: 'pl-3 md:pl-4',
'm-0 w-full resize-none border-0 bg-transparent py-[10px] placeholder-black/50 focus:ring-0 focus-visible:ring-0 dark:bg-transparent dark:placeholder-white/50 md:py-3.5 ',
SpeechToText ? 'pr-20 md:pr-[85px]' : 'pr-10 md:pr-12',
SpeechToText && !isRTL ? 'pr-20 md:pr-[85px]' : 'pr-10 md:pr-12',
'max-h-[65vh] md:max-h-[75vh]',
removeFocusRings,
)}
@ -188,15 +192,21 @@ const ChatForm = ({ index = 0 }) => {
<AttachFile
endpoint={_endpoint ?? ''}
endpointType={endpointType}
isRTL={isRTL}
disabled={disableInputs}
/>
{(isSubmitting || isSubmittingAdded) && (showStopButton || showStopAdded) ? (
<StopButton stop={handleStopGenerating} setShowStopButton={setShowStopButton} />
<StopButton
stop={handleStopGenerating}
setShowStopButton={setShowStopButton}
isRTL={isRTL}
/>
) : (
endpoint && (
<SendButton
ref={submitButtonRef}
control={methods.control}
isRTL={isRTL}
disabled={!!(filesLoading || isSubmitting || disableInputs)}
/>
)
@ -206,6 +216,7 @@ const ChatForm = ({ index = 0 }) => {
disabled={!!disableInputs}
textAreaRef={textAreaRef}
ask={submitMessage}
isRTL={isRTL}
methods={methods}
/>
)}

View file

@ -9,14 +9,17 @@ import { useGetFileConfig } from '~/data-provider';
import { AttachmentIcon } from '~/components/svg';
import { FileUpload } from '~/components/ui';
import { useFileHandling } from '~/hooks';
import { cn } from '~/utils';
const AttachFile = ({
endpoint,
endpointType,
isRTL,
disabled = false,
}: {
endpoint: EModelEndpoint | '';
endpointType?: EModelEndpoint;
isRTL: boolean;
disabled?: boolean | null;
}) => {
const { handleFileChange } = useFileHandling();
@ -30,7 +33,14 @@ const AttachFile = ({
}
return (
<div className="absolute bottom-2 left-2 md:bottom-3 md:left-4">
<div
className={cn(
'absolute',
isRTL
? 'bottom-2 right-14 md:bottom-3.5 md:right-3'
: 'bottom-2 left-2 md:bottom-3.5 md:left-4',
)}
>
<FileUpload handleFileChange={handleFileChange} className="flex">
<button
disabled={!!disabled}

View file

@ -13,6 +13,7 @@ export default function FileRow({
assistant_id,
tool_resource,
fileFilter,
isRTL,
Wrapper,
}: {
files: Map<string, ExtendedFile>;
@ -21,6 +22,7 @@ export default function FileRow({
fileFilter?: (file: ExtendedFile) => boolean;
assistant_id?: string;
tool_resource?: EToolResources;
isRTL?: boolean;
Wrapper?: React.FC<{ children: React.ReactNode }>;
}) {
const files = Array.from(_files.values()).filter((file) =>
@ -64,8 +66,11 @@ export default function FileRow({
}
const renderFiles = () => {
// Inline style for RTL
const rowStyle = isRTL ? { display: 'flex', flexDirection: 'row-reverse' } : {};
return (
<>
<div style={rowStyle as React.CSSProperties}>
{files
.reduce(
(acc, current) => {
@ -90,10 +95,9 @@ export default function FileRow({
/>
);
}
return <FileContainer key={index} file={file} onDelete={handleDelete} />;
})}
</>
</div>
);
};

View file

@ -9,42 +9,48 @@ import { cn } from '~/utils';
type SendButtonProps = {
disabled: boolean;
control: Control<{ text: string }>;
isRTL: boolean;
};
const SubmitButton = React.memo(
forwardRef((props: { disabled: boolean }, ref: React.ForwardedRef<HTMLButtonElement>) => {
const localize = useLocalize();
return (
<TooltipProvider delayDuration={250}>
<Tooltip>
<TooltipTrigger asChild>
<button
ref={ref}
disabled={props.disabled}
className={cn(
'absolute bottom-1.5 right-2 rounded-lg border border-black p-0.5 text-white transition-colors enabled:bg-black disabled:bg-black disabled:text-gray-400 disabled:opacity-10 dark:border-white dark:bg-white dark:disabled:bg-white md:bottom-3 md:right-3',
)}
data-testid="send-button"
type="submit"
>
<span className="" data-state="closed">
<SendIcon size={24} />
</span>
</button>
</TooltipTrigger>
<TooltipContent side="top" sideOffset={10}>
{localize('com_nav_send_message')}
</TooltipContent>
</Tooltip>
</TooltipProvider>
);
}),
forwardRef(
(props: { disabled: boolean; isRTL: boolean }, ref: React.ForwardedRef<HTMLButtonElement>) => {
const localize = useLocalize();
return (
<TooltipProvider delayDuration={250}>
<Tooltip>
<TooltipTrigger asChild>
<button
ref={ref}
disabled={props.disabled}
className={cn(
'absolute rounded-lg border border-black p-0.5 text-white transition-colors enabled:bg-black disabled:bg-black disabled:text-gray-400 disabled:opacity-10 dark:border-white dark:bg-white dark:disabled:bg-white',
props.isRTL
? 'bottom-1.5 left-2 md:bottom-3 md:left-3'
: 'bottom-1.5 right-2 md:bottom-3 md:right-3',
)}
data-testid="send-button"
type="submit"
>
<span className="" data-state="closed">
<SendIcon size={24} />
</span>
</button>
</TooltipTrigger>
<TooltipContent side="top" sideOffset={10}>
{localize('com_nav_send_message')}
</TooltipContent>
</Tooltip>
</TooltipProvider>
);
},
),
);
const SendButton = React.memo(
forwardRef((props: SendButtonProps, ref: React.ForwardedRef<HTMLButtonElement>) => {
const data = useWatch({ control: props.control });
return <SubmitButton ref={ref} disabled={props.disabled || !data?.text} />;
return <SubmitButton ref={ref} disabled={props.disabled || !data?.text} isRTL={props.isRTL} />;
}),
);

View file

@ -1,6 +1,13 @@
export default function StopButton({ stop, setShowStopButton }) {
import { cn } from '~/utils';
export default function StopButton({ stop, setShowStopButton, isRTL }) {
return (
<div className="absolute bottom-3 right-2 md:bottom-4 md:right-4">
<div
className={cn(
'absolute',
isRTL ? 'bottom-3 left-2 md:bottom-4 md:left-4' : 'bottom-3 right-2 md:bottom-4 md:right-4',
)}
>
<button
type="button"
className="border-gizmo-gray-900 rounded-full border-2 p-1 dark:border-gray-200"

View file

@ -11,7 +11,7 @@ import {
TransitionChild,
} from '@headlessui/react';
import { GearIcon, DataIcon, SpeechIcon, UserIcon, ExperimentIcon } from '~/components/svg';
import { General, Messages, Speech, Beta, Data, Account } from './SettingsTabs';
import { General, Chat, Speech, Beta, Data, Account } from './SettingsTabs';
import { useMediaQuery, useLocalize } from '~/hooks';
import { cn } from '~/utils';
@ -100,7 +100,7 @@ export default function Settings({ open, onOpenChange }: TDialogProps) {
>
<Tabs.Trigger
className={cn(
'group m-1 flex items-center justify-start gap-2 rounded-md px-2 py-1.5 text-sm text-black radix-state-active:bg-white radix-state-active:text-black dark:text-white dark:radix-state-active:bg-gray-600',
'group m-1 flex items-center justify-start gap-2 rounded-md px-2 py-1.5 text-sm text-black transition-all duration-200 ease-in-out radix-state-active:bg-white radix-state-active:text-black dark:text-white dark:radix-state-active:bg-gray-600',
isSmallScreen
? 'flex-1 items-center justify-center text-nowrap text-sm dark:text-gray-500 dark:radix-state-active:text-white'
: 'bg-white radix-state-active:bg-gray-200',
@ -114,21 +114,21 @@ export default function Settings({ open, onOpenChange }: TDialogProps) {
</Tabs.Trigger>
<Tabs.Trigger
className={cn(
'group m-1 flex items-center justify-start gap-2 rounded-md px-2 py-1.5 text-sm text-black radix-state-active:bg-white radix-state-active:text-black dark:text-white dark:radix-state-active:bg-gray-600',
'group m-1 flex items-center justify-start gap-2 rounded-md px-2 py-1.5 text-sm text-black transition-all duration-200 ease-in-out radix-state-active:bg-white radix-state-active:text-black dark:text-white dark:radix-state-active:bg-gray-600',
isSmallScreen
? 'flex-1 items-center justify-center text-nowrap text-sm dark:text-gray-500 dark:radix-state-active:text-white'
: 'bg-white radix-state-active:bg-gray-200',
isSmallScreen ? '' : 'dark:bg-gray-700',
)}
value={SettingsTabValues.MESSAGES}
value={SettingsTabValues.CHAT}
style={{ userSelect: 'none' }}
>
<MessageSquare className="icon-sm" />
{localize('com_endpoint_messages')}
{localize('com_nav_setting_chat')}
</Tabs.Trigger>
<Tabs.Trigger
className={cn(
'group m-1 flex items-center justify-start gap-2 rounded-md px-2 py-1.5 text-sm text-black radix-state-active:bg-white radix-state-active:text-black dark:text-white dark:radix-state-active:bg-gray-600',
'group m-1 flex items-center justify-start gap-2 rounded-md px-2 py-1.5 text-sm text-black transition-all duration-200 ease-in-out radix-state-active:bg-white radix-state-active:text-black dark:text-white dark:radix-state-active:bg-gray-600',
isSmallScreen
? 'flex-1 items-center justify-center text-nowrap text-sm dark:text-gray-500 dark:radix-state-active:text-white'
: 'bg-white radix-state-active:bg-gray-200',
@ -142,7 +142,7 @@ export default function Settings({ open, onOpenChange }: TDialogProps) {
</Tabs.Trigger>
<Tabs.Trigger
className={cn(
'group m-1 flex items-center justify-start gap-2 rounded-md px-2 py-1.5 text-sm text-black radix-state-active:bg-white radix-state-active:text-black dark:text-white dark:radix-state-active:bg-gray-600',
'group m-1 flex items-center justify-start gap-2 rounded-md px-2 py-1.5 text-sm text-black transition-all duration-200 ease-in-out radix-state-active:bg-white radix-state-active:text-black dark:text-white dark:radix-state-active:bg-gray-600',
isSmallScreen
? 'flex-1 items-center justify-center text-nowrap text-sm dark:text-gray-500 dark:radix-state-active:text-white'
: 'bg-white radix-state-active:bg-gray-200',
@ -156,7 +156,7 @@ export default function Settings({ open, onOpenChange }: TDialogProps) {
</Tabs.Trigger>
<Tabs.Trigger
className={cn(
'group m-1 flex items-center justify-start gap-2 rounded-md px-2 py-1.5 text-sm text-black radix-state-active:bg-white radix-state-active:text-black dark:text-white dark:radix-state-active:bg-gray-600',
'group m-1 flex items-center justify-start gap-2 rounded-md px-2 py-1.5 text-sm text-black transition-all duration-200 ease-in-out radix-state-active:bg-white radix-state-active:text-black dark:text-white dark:radix-state-active:bg-gray-600',
isSmallScreen
? 'flex-1 items-center justify-center text-nowrap text-sm dark:text-gray-500 dark:radix-state-active:text-white'
: 'bg-white radix-state-active:bg-gray-200',
@ -170,7 +170,7 @@ export default function Settings({ open, onOpenChange }: TDialogProps) {
</Tabs.Trigger>
<Tabs.Trigger
className={cn(
'group m-1 flex items-center justify-start gap-2 rounded-md px-2 py-1.5 text-sm text-black radix-state-active:bg-white radix-state-active:text-black dark:text-white dark:radix-state-active:bg-gray-600',
'group m-1 flex items-center justify-start gap-2 rounded-md px-2 py-1.5 text-sm text-black transition-all duration-200 ease-in-out radix-state-active:bg-white radix-state-active:text-black dark:text-white dark:radix-state-active:bg-gray-600',
isSmallScreen
? 'flex-1 items-center justify-center text-nowrap text-sm dark:text-gray-500 dark:radix-state-active:text-white'
: 'bg-white radix-state-active:bg-gray-200',
@ -185,7 +185,7 @@ export default function Settings({ open, onOpenChange }: TDialogProps) {
</Tabs.List>
<div className="max-h-[373px] overflow-auto sm:w-full sm:max-w-none md:pr-0.5 md:pt-0.5">
<General />
<Messages />
<Chat />
<Beta />
<Speech />
<Data />

View file

@ -4,15 +4,19 @@ import { SettingsTabValues } from 'librechat-data-provider';
import SendMessageKeyEnter from './EnterToSend';
import ShowCodeSwitch from './ShowCodeSwitch';
import { ForkSettings } from './ForkSettings';
import ChatDirection from './ChatDirection';
import SaveDraft from './SaveDraft';
function Messages() {
function Chat() {
return (
<Tabs.Content value={SettingsTabValues.MESSAGES} role="tabpanel" className="md: w-full">
<Tabs.Content value={SettingsTabValues.CHAT} role="tabpanel" className="md: w-full">
<div className="flex flex-col gap-3 text-sm text-black dark:text-gray-50">
<div className="border-b pb-3 last-of-type:border-b-0 dark:border-gray-600">
<SendMessageKeyEnter />
</div>
<div className="border-b pb-3 last-of-type:border-b-0 dark:border-gray-600">
<ChatDirection />
</div>
<div className="border-b pb-3 last-of-type:border-b-0 dark:border-gray-600">
<ShowCodeSwitch />
</div>
@ -25,4 +29,4 @@ function Messages() {
);
}
export default memo(Messages);
export default memo(Chat);

View file

@ -0,0 +1,31 @@
import React from 'react';
import { useRecoilState } from 'recoil';
import { useLocalize } from '~/hooks';
import store from '~/store';
const ChatDirection = () => {
const [direction, setDirection] = useRecoilState(store.chatDirection);
const localize = useLocalize();
const toggleChatDirection = () => {
setDirection((prev) => (prev === 'LTR' ? 'RTL' : 'LTR'));
};
return (
<div className="flex items-center justify-between">
<div className="flex items-center space-x-2">
<span>{localize('com_nav_chat_direction')}</span>
</div>
<label
onClick={toggleChatDirection}
data-testid="chatDirection"
className="btn btn-neutral relative"
style={{ userSelect: 'none' }}
>
{direction.toLowerCase()}
</label>
</div>
);
};
export default ChatDirection;

View file

@ -1,5 +1,5 @@
export { default as General } from './General/General';
export { default as Messages } from './Messages/Messages';
export { default as Chat } from './Chat/Chat';
export { ClearChatsButton } from './General/General';
export { default as Data } from './Data/Data';
export { default as Beta } from './Beta/Beta';

View file

@ -1,10 +1,14 @@
import { useRecoilValue } from 'recoil';
import { forwardRef, useLayoutEffect, useState } from 'react';
import ReactTextareaAutosize from 'react-textarea-autosize';
import type { TextareaAutosizeProps } from 'react-textarea-autosize';
import store from '~/store';
export const TextareaAutosize = forwardRef<HTMLTextAreaElement, TextareaAutosizeProps>(
(props, ref) => {
const [, setIsRerendered] = useState(false);
const chatDirection = useRecoilValue(store.chatDirection).toLowerCase();
useLayoutEffect(() => setIsRerendered(true), []);
return <ReactTextareaAutosize dir="auto" {...props} ref={ref} />;
return <ReactTextareaAutosize dir={chatDirection} {...props} ref={ref} />;
},
);

View file

@ -112,7 +112,7 @@ export default function useTextarea({
? getAssistantName({ name: assistantName, localize })
: getSender(conversation as TEndpointOption);
return `${localize('com_endpoint_message')} ${sender ? sender : 'ChatGPT'}`;
return `${localize('com_endpoint_message')} ${sender ? sender : 'AI'}`;
};
const placeholder = getPlaceholderText();

View file

@ -469,7 +469,6 @@ export default {
com_ui_max_tags: 'الحد الأقصى المسموح به هو {0}، باستخدام أحدث القيم.',
com_auth_back_to_login: 'العودة إلى تسجيل الدخول',
com_endpoint_message: 'رسالة',
com_endpoint_messages: 'رسائل',
com_endpoint_message_not_appendable: 'عدّل رسالتك أو أعد إنشاءها.',
com_endpoint_context_tokens: 'الحد الأقصى لرموز السياق',
com_endpoint_context_info:
@ -2294,10 +2293,6 @@ export const comparisons = {
english: 'Message',
translated: 'رسالة',
},
com_endpoint_messages: {
english: 'Messages',
translated: 'رسائل',
},
com_endpoint_message_not_appendable: {
english: 'Edit your message or Regenerate.',
translated: 'عدّل رسالتك أو أعد إنشاءها.',

View file

@ -565,7 +565,6 @@ export default {
com_ui_min_tags:
'Es können keine weiteren Werte entfernt werden, mindestens {0} sind erforderlich.',
com_ui_max_tags: 'Die maximal erlaubte Anzahl ist {0}, die neuesten Werte werden verwendet.',
com_endpoint_messages: 'Nachrichten',
com_endpoint_context_tokens: 'Max. Kontexttoken',
com_endpoint_context_info:
'Die maximale Anzahl an Token, die für den Kontext verwendet werden kann. Verwenden Sie dies, um zu steuern, wie viele Token pro Anfrage gesendet werden. Wenn nicht angegeben, werden systemseitige Standardwerte basierend auf der bekannten Kontextgröße der Modelle verwendet. Höhere Werte können zu Fehlern und/oder höheren Tokenkosten führen.',
@ -2603,10 +2602,6 @@ export const comparisons = {
english: 'Maximum number allowed is {0}, using latest values.',
translated: 'Die maximal erlaubte Anzahl ist {0}, die neuesten Werte werden verwendet.',
},
com_endpoint_messages: {
english: 'Messages',
translated: 'Nachrichten',
},
com_endpoint_context_tokens: {
english: 'Max Context Tokens',
translated: 'Max. Kontexttoken',

View file

@ -371,7 +371,6 @@ export default {
'WARNING: Misuse of this feature can get you BANNED from using Bing! Click on \'System Message\' for full instructions and the default message if omitted, which is the \'Sydney\' preset that is considered safe.',
com_endpoint_system_message: 'System Message',
com_endpoint_message: 'Message',
com_endpoint_messages: 'Messages',
com_endpoint_message_not_appendable: 'Edit your message or Regenerate.',
com_endpoint_default_blank: 'default: blank',
com_endpoint_default_false: 'default: false',
@ -597,6 +596,7 @@ export default {
com_nav_enter_to_send: 'Press Enter to send messages',
com_nav_user_name_display: 'Display username in messages',
com_nav_save_drafts: 'Save drafts locally',
com_nav_chat_direction: 'Chat direction',
com_nav_show_code: 'Always show code when using code interpreter',
com_nav_auto_send_prompts: 'Auto-send Prompts',
com_nav_always_make_prod: 'Always make new versions production',
@ -660,6 +660,7 @@ export default {
com_nav_info_delete_cache_storage:
'This action will delete all cached TTS (Text-to-Speech) audio files stored on your device. Cached audio files are used to speed up playback of previously generated TTS audio, but they can consume storage space on your device.',
com_nav_setting_general: 'General',
com_nav_setting_chat: 'Chat',
com_nav_setting_beta: 'Beta features',
com_nav_setting_data: 'Data controls',
com_nav_setting_account: 'Account',

View file

@ -539,7 +539,6 @@ export default {
com_ui_import_conversation_file_type_error:
'com_ui_import_conversation_file_type_error: Tipo de archivo no compatible para importar',
com_ui_min_tags: 'No se pueden eliminar más valores, se requiere un mínimo de {0}.',
com_endpoint_messages: 'Mensajes',
com_endpoint_context_tokens: 'Máximo de tokens de contexto',
com_endpoint_stop_placeholder: 'Separe los valores presionando `Intro`',
com_error_no_base_url:
@ -2513,10 +2512,6 @@ export const comparisons = {
english: 'Cannot remove more values, a minimum of {0} are required.',
translated: 'No se pueden eliminar más valores, se requiere un mínimo de {0}.',
},
com_endpoint_messages: {
english: 'Messages',
translated: 'Mensajes',
},
com_endpoint_context_tokens: {
english: 'Max Context Tokens',
translated: 'Máximo de tokens de contexto',

View file

@ -571,7 +571,6 @@ export default {
com_ui_min_tags: 'Impossible de supprimer plus de valeurs, un minimum de {0} est requis.',
com_ui_max_tags: 'Le nombre maximum autorisé est {0}, en utilisant les dernières valeurs.',
com_auth_back_to_login: 'Retour à la connexion',
com_endpoint_messages: 'Messages',
com_endpoint_context_tokens: 'Jetons de contexte maximum',
com_endpoint_context_info:
'Le nombre maximum de jetons qui peuvent être utilisés pour le contexte. Utilisez ceci pour contrôler le nombre de jetons envoyés par requête. Si non spécifié, les valeurs par défaut du système seront utilisées en fonction de la taille de contexte connue des modèles. Définir des valeurs plus élevées peut entraîner des erreurs et/ou un coût en jetons plus élevé.',
@ -2733,10 +2732,6 @@ export const comparisons = {
english: 'Back to Login',
translated: 'Retour à la connexion',
},
com_endpoint_messages: {
english: 'Messages',
translated: 'Messages',
},
com_endpoint_context_tokens: {
english: 'Max Context Tokens',
translated: 'Jetons de contexte maximum',

View file

@ -293,7 +293,6 @@ export default {
'ATTENZIONE: L\'uso improprio di questa funzione può farti BANNARE dall\'utilizzo di Bing! Clicca su "Messaggio di sistema" per le istruzioni complete e il messaggio predefinito se omesso, che è il preset "Sydney" considerato sicuro.',
com_endpoint_system_message: 'Messaggio di sistema',
com_endpoint_message: 'Messaggio',
com_endpoint_messages: 'Messaggi',
com_endpoint_message_not_appendable: 'Modifica il tuo messaggio o Rigenera.',
com_endpoint_default_blank: 'predefinito: vuoto',
com_endpoint_default_false: 'predefinito: falso',
@ -1649,10 +1648,6 @@ export const comparisons = {
english: 'Message',
translated: 'Messaggio',
},
com_endpoint_messages: {
english: 'Messages',
translated: 'Messaggi',
},
com_endpoint_message_not_appendable: {
english: 'Edit your message or Regenerate.',
translated: 'Modifica il tuo messaggio o Rigenera.',

View file

@ -544,7 +544,6 @@ export default {
com_ui_mention:
'エンドポイント、アシスタント、またはプリセットを素早く切り替えるには、それらを言及してください。',
com_ui_import_conversation_file_type_error: 'サポートされていないインポート形式です',
com_endpoint_messages: 'メッセージ',
com_endpoint_context_tokens: 'コンテキストトークン数の最大値',
com_endpoint_context_info:
'コンテキストに使用できるトークンの最大数です。リクエストごとに送信されるトークン数を制御するために使用します。指定しない場合は、既知のモデルのコンテキストサイズに基づいてシステムのデフォルト値が使用されます。高い値を設定すると、エラーが発生したり、トークンコストが高くなる可能性があります。',
@ -2568,10 +2567,6 @@ export const comparisons = {
english: 'Unsupported import type',
translated: 'サポートされていないインポート形式です',
},
com_endpoint_messages: {
english: 'Messages',
translated: 'メッセージ',
},
com_endpoint_context_tokens: {
english: 'Max Context Tokens',
translated: 'コンテキストトークン数の最大値',

View file

@ -455,7 +455,6 @@ export default {
com_auth_error_login_server: '내부 서버 오류가 발생했습니다. 잠시 기다렸다가 다시 시도해 주세요.',
com_auth_back_to_login: '로그인 화면으로 돌아가기',
com_endpoint_message: '메시지',
com_endpoint_messages: '메시지',
com_endpoint_message_not_appendable: '메시지를 수정하거나 다시 생성하세요.',
com_endpoint_context_tokens: '최대 컨텍스트 토큰 수',
com_endpoint_context_info:
@ -2257,10 +2256,6 @@ export const comparisons = {
english: 'Message',
translated: '메시지',
},
com_endpoint_messages: {
english: 'Messages',
translated: '메시지',
},
com_endpoint_message_not_appendable: {
english: 'Edit your message or Regenerate.',
translated: '메시지를 수정하거나 다시 생성하세요.',

View file

@ -518,7 +518,6 @@ export default {
com_ui_terms_of_service: 'Условия использования',
com_ui_min_tags: 'Нельзя удалить больше значений, требуется минимум {0}.',
com_ui_max_tags: 'Максимально допустимое количество - {0}, используются последние значения.',
com_endpoint_messages: 'Сообщения',
com_endpoint_context_tokens: 'Максимальное количество контекстных токенов',
com_endpoint_context_info:
'Максимальное количество токенов, которое может быть использовано для контекста. Используется для контроля количества токенов, отправляемых за один запрос. Если не указано, будут использованы системные значения по умолчанию, основанные на известном размере контекста моделей. Установка более высоких значений может привести к ошибкам и/или более высокой стоимости токенов.',
@ -2466,10 +2465,6 @@ export const comparisons = {
english: 'Maximum number allowed is {0}, using latest values.',
translated: 'Максимально допустимое количество - {0}, используются последние значения.',
},
com_endpoint_messages: {
english: 'Messages',
translated: 'Сообщения',
},
com_endpoint_context_tokens: {
english: 'Max Context Tokens',
translated: 'Максимальное количество контекстных токенов',

View file

@ -507,7 +507,6 @@ export default {
com_ui_import_conversation_file_type_error: '不支持的导入类型',
com_ui_min_tags: '无法再移除更多值,至少需要保留{0}个。',
com_ui_max_tags: '最多允许{0}个,使用最新值。',
com_endpoint_messages: '消息',
com_endpoint_context_tokens: '最大上下文词元数',
com_endpoint_context_info:
'可用于上下文的最大词元数。用于控制每个请求发送的词元数量。如果未指定,将根据已知模型的上下文大小使用系统默认值。设置较高的值可能会导致错误和/或更高的词元成本。',
@ -2501,10 +2500,6 @@ export const comparisons = {
english: 'Maximum number allowed is {0}, using latest values.',
translated: '最多允许{0}个,使用最新值。',
},
com_endpoint_messages: {
english: 'Messages',
translated: '消息',
},
com_endpoint_context_tokens: {
english: 'Max Context Tokens',
translated: '最大上下文词元数',

View file

@ -446,7 +446,6 @@ export default {
com_ui_max_tags: '允許的最大數量為 {0},已使用最新值。',
com_auth_back_to_login: '返回登入',
com_endpoint_message: '訊息',
com_endpoint_messages: '訊息',
com_endpoint_message_not_appendable: '無法附加訊息或重新生成。',
com_endpoint_context_tokens: '最大前後文 token 數',
com_endpoint_context_info:
@ -2264,10 +2263,6 @@ export const comparisons = {
english: 'Message',
translated: '訊息',
},
com_endpoint_messages: {
english: 'Messages',
translated: '訊息',
},
com_endpoint_message_not_appendable: {
english: 'Edit your message or Regenerate.',
translated: '無法附加訊息或重新生成。',

View file

@ -951,10 +951,6 @@ Write a prompt that is mindful of the nuances in the language with respect to it
- **english**: Message
- **translated**: Messaggio
- **com_endpoint_messages**:
- **english**: Messages
- **translated**: Messaggi
- **com_endpoint_message_not_appendable**:
- **english**: Edit your message or Regenerate.
- **translated**: Modifica il tuo messaggio o Rigenera.

View file

@ -25,6 +25,7 @@ const localStorageAtoms = {
// Messages settings
enterToSend: atomWithLocalStorage('enterToSend', true),
chatDirection: atomWithLocalStorage('chatDirection', 'LTR'),
showCode: atomWithLocalStorage('showCode', false),
saveDrafts: atomWithLocalStorage('saveDrafts', false),
forkSetting: atomWithLocalStorage('forkSetting', ''),

View file

@ -1058,6 +1058,7 @@ button {
border-color:transparent;
border-radius:.5rem;
border-width:1px;
cursor: pointer;
display:inline-flex;
font-size:.875rem;
font-weight:500;
@ -2182,4 +2183,4 @@ ol ol):not(:where([class~=not-prose] *)) {
.move-up {
animation: moveUp 4s ease-in-out infinite;
}
}

View file

@ -842,9 +842,9 @@ export enum SettingsTabValues {
*/
GENERAL = 'general',
/**
* Tab for Messages Settings
* Tab for Chat Settings
*/
MESSAGES = 'messages',
CHAT = 'chat',
/**
* Tab for Speech Settings
*/