mirror of
https://github.com/danny-avila/LibreChat.git
synced 2025-12-16 16:30:15 +01:00
🔄 feat: chat direction (LTR-RTL) (#3260)
* feat: chat direction * fix: FileRow * feat: smooth trigger transition
This commit is contained in:
parent
d5782ac66c
commit
237a0de8b6
31 changed files with 145 additions and 111 deletions
|
|
@ -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()}
|
||||
|
|
|
|||
|
|
@ -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}
|
||||
/>
|
||||
)}
|
||||
|
|
|
|||
|
|
@ -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}
|
||||
|
|
|
|||
|
|
@ -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>
|
||||
);
|
||||
};
|
||||
|
||||
|
|
|
|||
|
|
@ -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} />;
|
||||
}),
|
||||
);
|
||||
|
||||
|
|
|
|||
|
|
@ -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"
|
||||
|
|
|
|||
|
|
@ -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 />
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
|
|
@ -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;
|
||||
|
|
@ -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';
|
||||
|
|
|
|||
|
|
@ -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} />;
|
||||
},
|
||||
);
|
||||
|
|
|
|||
|
|
@ -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();
|
||||
|
|
|
|||
|
|
@ -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: 'عدّل رسالتك أو أعد إنشاءها.',
|
||||
|
|
|
|||
|
|
@ -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',
|
||||
|
|
|
|||
|
|
@ -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',
|
||||
|
|
|
|||
|
|
@ -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',
|
||||
|
|
|
|||
|
|
@ -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',
|
||||
|
|
|
|||
|
|
@ -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.',
|
||||
|
|
|
|||
|
|
@ -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: 'コンテキストトークン数の最大値',
|
||||
|
|
|
|||
|
|
@ -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: '메시지를 수정하거나 다시 생성하세요.',
|
||||
|
|
|
|||
|
|
@ -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: 'Максимальное количество контекстных токенов',
|
||||
|
|
|
|||
|
|
@ -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: '最大上下文词元数',
|
||||
|
|
|
|||
|
|
@ -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: '無法附加訊息或重新生成。',
|
||||
|
|
|
|||
|
|
@ -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.
|
||||
|
|
|
|||
|
|
@ -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', ''),
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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
|
||||
*/
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue