mirror of
https://github.com/danny-avila/LibreChat.git
synced 2026-02-12 20:44:24 +01:00
Merge branch 'dev' into feat/prompt-enhancement
This commit is contained in:
commit
e1af9d21f0
309 changed files with 12487 additions and 6311 deletions
|
|
@ -1,6 +1,6 @@
|
|||
{
|
||||
"name": "@librechat/frontend",
|
||||
"version": "v0.7.8",
|
||||
"version": "v0.7.9-rc1",
|
||||
"description": "",
|
||||
"type": "module",
|
||||
"scripts": {
|
||||
|
|
|
|||
37
client/src/Providers/ActivePanelContext.tsx
Normal file
37
client/src/Providers/ActivePanelContext.tsx
Normal file
|
|
@ -0,0 +1,37 @@
|
|||
import { createContext, useContext, useState, ReactNode } from 'react';
|
||||
|
||||
interface ActivePanelContextType {
|
||||
active: string | undefined;
|
||||
setActive: (id: string) => void;
|
||||
}
|
||||
|
||||
const ActivePanelContext = createContext<ActivePanelContextType | undefined>(undefined);
|
||||
|
||||
export function ActivePanelProvider({
|
||||
children,
|
||||
defaultActive,
|
||||
}: {
|
||||
children: ReactNode;
|
||||
defaultActive?: string;
|
||||
}) {
|
||||
const [active, _setActive] = useState<string | undefined>(defaultActive);
|
||||
|
||||
const setActive = (id: string) => {
|
||||
localStorage.setItem('side:active-panel', id);
|
||||
_setActive(id);
|
||||
};
|
||||
|
||||
return (
|
||||
<ActivePanelContext.Provider value={{ active, setActive }}>
|
||||
{children}
|
||||
</ActivePanelContext.Provider>
|
||||
);
|
||||
}
|
||||
|
||||
export function useActivePanel() {
|
||||
const context = useContext(ActivePanelContext);
|
||||
if (context === undefined) {
|
||||
throw new Error('useActivePanel must be used within an ActivePanelProvider');
|
||||
}
|
||||
return context;
|
||||
}
|
||||
|
|
@ -1,9 +1,9 @@
|
|||
import React, { createContext, useContext, useState } from 'react';
|
||||
import { Constants, EModelEndpoint } from 'librechat-data-provider';
|
||||
import type { TPlugin, AgentToolType, Action, MCP } from 'librechat-data-provider';
|
||||
import type { MCP, Action, TPlugin, AgentToolType } from 'librechat-data-provider';
|
||||
import type { AgentPanelContextType } from '~/common';
|
||||
import { useAvailableToolsQuery, useGetActionsQuery } from '~/data-provider';
|
||||
import { useLocalize } from '~/hooks';
|
||||
import { useLocalize, useGetAgentsConfig } from '~/hooks';
|
||||
import { Panel } from '~/common';
|
||||
|
||||
const AgentPanelContext = createContext<AgentPanelContextType | undefined>(undefined);
|
||||
|
|
@ -40,57 +40,60 @@ export function AgentPanelProvider({ children }: { children: React.ReactNode })
|
|||
agent_id: agent_id || '',
|
||||
})) || [];
|
||||
|
||||
const groupedTools =
|
||||
tools?.reduce(
|
||||
(acc, tool) => {
|
||||
if (tool.tool_id.includes(Constants.mcp_delimiter)) {
|
||||
const [_toolName, serverName] = tool.tool_id.split(Constants.mcp_delimiter);
|
||||
const groupKey = `${serverName.toLowerCase()}`;
|
||||
if (!acc[groupKey]) {
|
||||
acc[groupKey] = {
|
||||
tool_id: groupKey,
|
||||
metadata: {
|
||||
name: `${serverName}`,
|
||||
pluginKey: groupKey,
|
||||
description: `${localize('com_ui_tool_collection_prefix')} ${serverName}`,
|
||||
icon: tool.metadata.icon || '',
|
||||
} as TPlugin,
|
||||
agent_id: agent_id || '',
|
||||
tools: [],
|
||||
};
|
||||
}
|
||||
acc[groupKey].tools?.push({
|
||||
tool_id: tool.tool_id,
|
||||
metadata: tool.metadata,
|
||||
agent_id: agent_id || '',
|
||||
});
|
||||
} else {
|
||||
acc[tool.tool_id] = {
|
||||
tool_id: tool.tool_id,
|
||||
metadata: tool.metadata,
|
||||
const groupedTools = tools?.reduce(
|
||||
(acc, tool) => {
|
||||
if (tool.tool_id.includes(Constants.mcp_delimiter)) {
|
||||
const [_toolName, serverName] = tool.tool_id.split(Constants.mcp_delimiter);
|
||||
const groupKey = `${serverName.toLowerCase()}`;
|
||||
if (!acc[groupKey]) {
|
||||
acc[groupKey] = {
|
||||
tool_id: groupKey,
|
||||
metadata: {
|
||||
name: `${serverName}`,
|
||||
pluginKey: groupKey,
|
||||
description: `${localize('com_ui_tool_collection_prefix')} ${serverName}`,
|
||||
icon: tool.metadata.icon || '',
|
||||
} as TPlugin,
|
||||
agent_id: agent_id || '',
|
||||
tools: [],
|
||||
};
|
||||
}
|
||||
return acc;
|
||||
},
|
||||
{} as Record<string, AgentToolType & { tools?: AgentToolType[] }>,
|
||||
) || {};
|
||||
acc[groupKey].tools?.push({
|
||||
tool_id: tool.tool_id,
|
||||
metadata: tool.metadata,
|
||||
agent_id: agent_id || '',
|
||||
});
|
||||
} else {
|
||||
acc[tool.tool_id] = {
|
||||
tool_id: tool.tool_id,
|
||||
metadata: tool.metadata,
|
||||
agent_id: agent_id || '',
|
||||
};
|
||||
}
|
||||
return acc;
|
||||
},
|
||||
{} as Record<string, AgentToolType & { tools?: AgentToolType[] }>,
|
||||
);
|
||||
|
||||
const value = {
|
||||
action,
|
||||
setAction,
|
||||
const { agentsConfig, endpointsConfig } = useGetAgentsConfig();
|
||||
|
||||
const value: AgentPanelContextType = {
|
||||
mcp,
|
||||
setMcp,
|
||||
mcps,
|
||||
setMcps,
|
||||
activePanel,
|
||||
setActivePanel,
|
||||
setCurrentAgentId,
|
||||
agent_id,
|
||||
groupedTools,
|
||||
/** Query data for actions and tools */
|
||||
actions,
|
||||
tools,
|
||||
action,
|
||||
setMcp,
|
||||
actions,
|
||||
setMcps,
|
||||
agent_id,
|
||||
setAction,
|
||||
activePanel,
|
||||
groupedTools,
|
||||
agentsConfig,
|
||||
setActivePanel,
|
||||
endpointsConfig,
|
||||
setCurrentAgentId,
|
||||
};
|
||||
|
||||
return <AgentPanelContext.Provider value={value}>{children}</AgentPanelContext.Provider>;
|
||||
|
|
|
|||
188
client/src/Providers/BadgeRowContext.tsx
Normal file
188
client/src/Providers/BadgeRowContext.tsx
Normal file
|
|
@ -0,0 +1,188 @@
|
|||
import React, { createContext, useContext, useEffect, useRef } from 'react';
|
||||
import { useSetRecoilState } from 'recoil';
|
||||
import { Tools, Constants, LocalStorageKeys, AgentCapabilities } from 'librechat-data-provider';
|
||||
import type { TAgentsEndpoint } from 'librechat-data-provider';
|
||||
import {
|
||||
useSearchApiKeyForm,
|
||||
useGetAgentsConfig,
|
||||
useCodeApiKeyForm,
|
||||
useToolToggle,
|
||||
useMCPSelect,
|
||||
} from '~/hooks';
|
||||
import { useGetStartupConfig } from '~/data-provider';
|
||||
import { ephemeralAgentByConvoId } from '~/store';
|
||||
|
||||
interface BadgeRowContextType {
|
||||
conversationId?: string | null;
|
||||
agentsConfig?: TAgentsEndpoint | null;
|
||||
mcpSelect: ReturnType<typeof useMCPSelect>;
|
||||
webSearch: ReturnType<typeof useToolToggle>;
|
||||
artifacts: ReturnType<typeof useToolToggle>;
|
||||
fileSearch: ReturnType<typeof useToolToggle>;
|
||||
codeInterpreter: ReturnType<typeof useToolToggle>;
|
||||
codeApiKeyForm: ReturnType<typeof useCodeApiKeyForm>;
|
||||
searchApiKeyForm: ReturnType<typeof useSearchApiKeyForm>;
|
||||
startupConfig: ReturnType<typeof useGetStartupConfig>['data'];
|
||||
}
|
||||
|
||||
const BadgeRowContext = createContext<BadgeRowContextType | undefined>(undefined);
|
||||
|
||||
export function useBadgeRowContext() {
|
||||
const context = useContext(BadgeRowContext);
|
||||
if (context === undefined) {
|
||||
throw new Error('useBadgeRowContext must be used within a BadgeRowProvider');
|
||||
}
|
||||
return context;
|
||||
}
|
||||
|
||||
interface BadgeRowProviderProps {
|
||||
children: React.ReactNode;
|
||||
isSubmitting?: boolean;
|
||||
conversationId?: string | null;
|
||||
}
|
||||
|
||||
export default function BadgeRowProvider({
|
||||
children,
|
||||
isSubmitting,
|
||||
conversationId,
|
||||
}: BadgeRowProviderProps) {
|
||||
const hasInitializedRef = useRef(false);
|
||||
const lastKeyRef = useRef<string>('');
|
||||
const { agentsConfig } = useGetAgentsConfig();
|
||||
const key = conversationId ?? Constants.NEW_CONVO;
|
||||
const setEphemeralAgent = useSetRecoilState(ephemeralAgentByConvoId(key));
|
||||
|
||||
/** Initialize ephemeralAgent from localStorage on mount and when conversation changes */
|
||||
useEffect(() => {
|
||||
if (isSubmitting) {
|
||||
return;
|
||||
}
|
||||
// Check if this is a new conversation or the first load
|
||||
if (!hasInitializedRef.current || lastKeyRef.current !== key) {
|
||||
hasInitializedRef.current = true;
|
||||
lastKeyRef.current = key;
|
||||
|
||||
// Load all localStorage values
|
||||
const codeToggleKey = `${LocalStorageKeys.LAST_CODE_TOGGLE_}${key}`;
|
||||
const webSearchToggleKey = `${LocalStorageKeys.LAST_WEB_SEARCH_TOGGLE_}${key}`;
|
||||
const fileSearchToggleKey = `${LocalStorageKeys.LAST_FILE_SEARCH_TOGGLE_}${key}`;
|
||||
const artifactsToggleKey = `${LocalStorageKeys.LAST_ARTIFACTS_TOGGLE_}${key}`;
|
||||
|
||||
const codeToggleValue = localStorage.getItem(codeToggleKey);
|
||||
const webSearchToggleValue = localStorage.getItem(webSearchToggleKey);
|
||||
const fileSearchToggleValue = localStorage.getItem(fileSearchToggleKey);
|
||||
const artifactsToggleValue = localStorage.getItem(artifactsToggleKey);
|
||||
|
||||
const initialValues: Record<string, any> = {};
|
||||
|
||||
if (codeToggleValue !== null) {
|
||||
try {
|
||||
initialValues[Tools.execute_code] = JSON.parse(codeToggleValue);
|
||||
} catch (e) {
|
||||
console.error('Failed to parse code toggle value:', e);
|
||||
}
|
||||
}
|
||||
|
||||
if (webSearchToggleValue !== null) {
|
||||
try {
|
||||
initialValues[Tools.web_search] = JSON.parse(webSearchToggleValue);
|
||||
} catch (e) {
|
||||
console.error('Failed to parse web search toggle value:', e);
|
||||
}
|
||||
}
|
||||
|
||||
if (fileSearchToggleValue !== null) {
|
||||
try {
|
||||
initialValues[Tools.file_search] = JSON.parse(fileSearchToggleValue);
|
||||
} catch (e) {
|
||||
console.error('Failed to parse file search toggle value:', e);
|
||||
}
|
||||
}
|
||||
|
||||
if (artifactsToggleValue !== null) {
|
||||
try {
|
||||
initialValues[AgentCapabilities.artifacts] = JSON.parse(artifactsToggleValue);
|
||||
} catch (e) {
|
||||
console.error('Failed to parse artifacts toggle value:', e);
|
||||
}
|
||||
}
|
||||
|
||||
// Always set values for all tools (use defaults if not in localStorage)
|
||||
// If ephemeralAgent is null, create a new object with just our tool values
|
||||
setEphemeralAgent((prev) => ({
|
||||
...(prev || {}),
|
||||
[Tools.execute_code]: initialValues[Tools.execute_code] ?? false,
|
||||
[Tools.web_search]: initialValues[Tools.web_search] ?? false,
|
||||
[Tools.file_search]: initialValues[Tools.file_search] ?? false,
|
||||
[AgentCapabilities.artifacts]: initialValues[AgentCapabilities.artifacts] ?? false,
|
||||
}));
|
||||
}
|
||||
}, [key, isSubmitting, setEphemeralAgent]);
|
||||
|
||||
/** Startup config */
|
||||
const { data: startupConfig } = useGetStartupConfig();
|
||||
|
||||
/** MCPSelect hook */
|
||||
const mcpSelect = useMCPSelect({ conversationId });
|
||||
|
||||
/** CodeInterpreter hooks */
|
||||
const codeApiKeyForm = useCodeApiKeyForm({});
|
||||
const { setIsDialogOpen: setCodeDialogOpen } = codeApiKeyForm;
|
||||
|
||||
const codeInterpreter = useToolToggle({
|
||||
conversationId,
|
||||
setIsDialogOpen: setCodeDialogOpen,
|
||||
toolKey: Tools.execute_code,
|
||||
localStorageKey: LocalStorageKeys.LAST_CODE_TOGGLE_,
|
||||
authConfig: {
|
||||
toolId: Tools.execute_code,
|
||||
queryOptions: { retry: 1 },
|
||||
},
|
||||
});
|
||||
|
||||
/** WebSearch hooks */
|
||||
const searchApiKeyForm = useSearchApiKeyForm({});
|
||||
const { setIsDialogOpen: setWebSearchDialogOpen } = searchApiKeyForm;
|
||||
|
||||
const webSearch = useToolToggle({
|
||||
conversationId,
|
||||
toolKey: Tools.web_search,
|
||||
localStorageKey: LocalStorageKeys.LAST_WEB_SEARCH_TOGGLE_,
|
||||
setIsDialogOpen: setWebSearchDialogOpen,
|
||||
authConfig: {
|
||||
toolId: Tools.web_search,
|
||||
queryOptions: { retry: 1 },
|
||||
},
|
||||
});
|
||||
|
||||
/** FileSearch hook */
|
||||
const fileSearch = useToolToggle({
|
||||
conversationId,
|
||||
toolKey: Tools.file_search,
|
||||
localStorageKey: LocalStorageKeys.LAST_FILE_SEARCH_TOGGLE_,
|
||||
isAuthenticated: true,
|
||||
});
|
||||
|
||||
/** Artifacts hook - using a custom key since it's not a Tool but a capability */
|
||||
const artifacts = useToolToggle({
|
||||
conversationId,
|
||||
toolKey: AgentCapabilities.artifacts,
|
||||
localStorageKey: LocalStorageKeys.LAST_ARTIFACTS_TOGGLE_,
|
||||
isAuthenticated: true,
|
||||
});
|
||||
|
||||
const value: BadgeRowContextType = {
|
||||
mcpSelect,
|
||||
webSearch,
|
||||
artifacts,
|
||||
fileSearch,
|
||||
agentsConfig,
|
||||
startupConfig,
|
||||
conversationId,
|
||||
codeApiKeyForm,
|
||||
codeInterpreter,
|
||||
searchApiKeyForm,
|
||||
};
|
||||
|
||||
return <BadgeRowContext.Provider value={value}>{children}</BadgeRowContext.Provider>;
|
||||
}
|
||||
|
|
@ -1,6 +1,7 @@
|
|||
export { default as AssistantsProvider } from './AssistantsContext';
|
||||
export { default as AgentsProvider } from './AgentsContext';
|
||||
export { default as ToastProvider } from './ToastContext';
|
||||
export * from './ActivePanelContext';
|
||||
export * from './AgentPanelContext';
|
||||
export * from './ChatContext';
|
||||
export * from './ShareContext';
|
||||
|
|
@ -22,3 +23,5 @@ export * from './CodeBlockContext';
|
|||
export * from './ToolCallsMapContext';
|
||||
export * from './SetConvoContext';
|
||||
export * from './SearchContext';
|
||||
export * from './BadgeRowContext';
|
||||
export { default as BadgeRowProvider } from './BadgeRowContext';
|
||||
|
|
|
|||
|
|
@ -206,9 +206,7 @@ export type AgentPanelProps = {
|
|||
setActivePanel: React.Dispatch<React.SetStateAction<Panel>>;
|
||||
setMcp: React.Dispatch<React.SetStateAction<t.MCP | undefined>>;
|
||||
setAction: React.Dispatch<React.SetStateAction<t.Action | undefined>>;
|
||||
endpointsConfig?: t.TEndpointsConfig;
|
||||
setCurrentAgentId: React.Dispatch<React.SetStateAction<string | undefined>>;
|
||||
agentsConfig?: t.TAgentsEndpoint | null;
|
||||
};
|
||||
|
||||
export type AgentPanelContextType = {
|
||||
|
|
@ -219,12 +217,14 @@ export type AgentPanelContextType = {
|
|||
mcps?: t.MCP[];
|
||||
setMcp: React.Dispatch<React.SetStateAction<t.MCP | undefined>>;
|
||||
setMcps: React.Dispatch<React.SetStateAction<t.MCP[] | undefined>>;
|
||||
groupedTools: Record<string, t.AgentToolType & { tools?: t.AgentToolType[] }>;
|
||||
tools: t.AgentToolType[];
|
||||
activePanel?: string;
|
||||
setActivePanel: React.Dispatch<React.SetStateAction<Panel>>;
|
||||
setCurrentAgentId: React.Dispatch<React.SetStateAction<string | undefined>>;
|
||||
groupedTools?: Record<string, t.AgentToolType & { tools?: t.AgentToolType[] }>;
|
||||
agent_id?: string;
|
||||
agentsConfig?: t.TAgentsEndpoint | null;
|
||||
endpointsConfig?: t.TEndpointsConfig | null;
|
||||
};
|
||||
|
||||
export type AgentModelPanelProps = {
|
||||
|
|
@ -336,6 +336,11 @@ export type TAskProps = {
|
|||
export type TOptions = {
|
||||
editedMessageId?: string | null;
|
||||
editedText?: string | null;
|
||||
editedContent?: {
|
||||
index: number;
|
||||
text: string;
|
||||
type: 'text' | 'think';
|
||||
};
|
||||
isRegenerate?: boolean;
|
||||
isContinued?: boolean;
|
||||
isEdited?: boolean;
|
||||
|
|
|
|||
|
|
@ -68,6 +68,7 @@ export default function ExportAndShareMenu({
|
|||
return (
|
||||
<>
|
||||
<DropdownPopup
|
||||
portal={true}
|
||||
menuId={menuId}
|
||||
focusLoop={true}
|
||||
unmountOnHide={true}
|
||||
|
|
|
|||
152
client/src/components/Chat/Input/Artifacts.tsx
Normal file
152
client/src/components/Chat/Input/Artifacts.tsx
Normal file
|
|
@ -0,0 +1,152 @@
|
|||
import React, { memo, useState, useCallback, useMemo } from 'react';
|
||||
import * as Ariakit from '@ariakit/react';
|
||||
import { ArtifactModes } from 'librechat-data-provider';
|
||||
import { WandSparkles, ChevronDown } from 'lucide-react';
|
||||
import CheckboxButton from '~/components/ui/CheckboxButton';
|
||||
import { useBadgeRowContext } from '~/Providers';
|
||||
import { useLocalize } from '~/hooks';
|
||||
import { cn } from '~/utils';
|
||||
|
||||
interface ArtifactsToggleState {
|
||||
enabled: boolean;
|
||||
mode: string;
|
||||
}
|
||||
|
||||
function Artifacts() {
|
||||
const localize = useLocalize();
|
||||
const { artifacts } = useBadgeRowContext();
|
||||
const { toggleState, debouncedChange, isPinned } = artifacts;
|
||||
|
||||
const [isPopoverOpen, setIsPopoverOpen] = useState(false);
|
||||
|
||||
const currentState = useMemo<ArtifactsToggleState>(() => {
|
||||
if (typeof toggleState === 'string' && toggleState) {
|
||||
return { enabled: true, mode: toggleState };
|
||||
}
|
||||
return { enabled: false, mode: '' };
|
||||
}, [toggleState]);
|
||||
|
||||
const isEnabled = currentState.enabled;
|
||||
const isShadcnEnabled = currentState.mode === ArtifactModes.SHADCNUI;
|
||||
const isCustomEnabled = currentState.mode === ArtifactModes.CUSTOM;
|
||||
|
||||
const handleToggle = useCallback(() => {
|
||||
if (isEnabled) {
|
||||
debouncedChange({ value: '' });
|
||||
} else {
|
||||
debouncedChange({ value: ArtifactModes.DEFAULT });
|
||||
}
|
||||
}, [isEnabled, debouncedChange]);
|
||||
|
||||
const handleShadcnToggle = useCallback(() => {
|
||||
if (isShadcnEnabled) {
|
||||
debouncedChange({ value: ArtifactModes.DEFAULT });
|
||||
} else {
|
||||
debouncedChange({ value: ArtifactModes.SHADCNUI });
|
||||
}
|
||||
}, [isShadcnEnabled, debouncedChange]);
|
||||
|
||||
const handleCustomToggle = useCallback(() => {
|
||||
if (isCustomEnabled) {
|
||||
debouncedChange({ value: ArtifactModes.DEFAULT });
|
||||
} else {
|
||||
debouncedChange({ value: ArtifactModes.CUSTOM });
|
||||
}
|
||||
}, [isCustomEnabled, debouncedChange]);
|
||||
|
||||
if (!isEnabled && !isPinned) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return (
|
||||
<div className="flex">
|
||||
<CheckboxButton
|
||||
className={cn('max-w-fit', isEnabled && 'rounded-r-none border-r-0')}
|
||||
checked={isEnabled}
|
||||
setValue={handleToggle}
|
||||
label={localize('com_ui_artifacts')}
|
||||
isCheckedClassName="border-amber-600/40 bg-amber-500/10 hover:bg-amber-700/10"
|
||||
icon={<WandSparkles className="icon-md" />}
|
||||
/>
|
||||
|
||||
{isEnabled && (
|
||||
<Ariakit.MenuProvider open={isPopoverOpen} setOpen={setIsPopoverOpen}>
|
||||
<Ariakit.MenuButton
|
||||
className={cn(
|
||||
'w-7 rounded-l-none rounded-r-full border-b border-l-0 border-r border-t border-border-light md:w-6',
|
||||
'border-amber-600/40 bg-amber-500/10 hover:bg-amber-700/10',
|
||||
'transition-colors',
|
||||
)}
|
||||
onClick={(e) => e.stopPropagation()}
|
||||
>
|
||||
<ChevronDown className="ml-1 h-4 w-4 text-text-secondary md:ml-0" />
|
||||
</Ariakit.MenuButton>
|
||||
|
||||
<Ariakit.Menu
|
||||
gutter={8}
|
||||
className={cn(
|
||||
'animate-popover z-50 flex max-h-[300px]',
|
||||
'flex-col overflow-auto overscroll-contain rounded-xl',
|
||||
'bg-surface-secondary px-1.5 py-1 text-text-primary shadow-lg',
|
||||
'border border-border-light',
|
||||
'min-w-[250px] outline-none',
|
||||
)}
|
||||
portal
|
||||
>
|
||||
<div className="px-2 py-1.5">
|
||||
<div className="mb-2 text-xs font-medium text-text-secondary">
|
||||
{localize('com_ui_artifacts_options')}
|
||||
</div>
|
||||
|
||||
{/* Include shadcn/ui Option */}
|
||||
<Ariakit.MenuItem
|
||||
hideOnClick={false}
|
||||
onClick={(event) => {
|
||||
event.preventDefault();
|
||||
event.stopPropagation();
|
||||
handleShadcnToggle();
|
||||
}}
|
||||
disabled={isCustomEnabled}
|
||||
className={cn(
|
||||
'mb-1 flex items-center justify-between rounded-lg px-2 py-2',
|
||||
'cursor-pointer outline-none transition-colors',
|
||||
'hover:bg-black/[0.075] dark:hover:bg-white/10',
|
||||
'data-[active-item]:bg-black/[0.075] dark:data-[active-item]:bg-white/10',
|
||||
isCustomEnabled && 'cursor-not-allowed opacity-50',
|
||||
)}
|
||||
>
|
||||
<div className="flex items-center gap-2">
|
||||
<Ariakit.MenuItemCheck checked={isShadcnEnabled} />
|
||||
<span className="text-sm">{localize('com_ui_include_shadcnui' as any)}</span>
|
||||
</div>
|
||||
</Ariakit.MenuItem>
|
||||
|
||||
{/* Custom Prompt Mode Option */}
|
||||
<Ariakit.MenuItem
|
||||
hideOnClick={false}
|
||||
onClick={(event) => {
|
||||
event.preventDefault();
|
||||
event.stopPropagation();
|
||||
handleCustomToggle();
|
||||
}}
|
||||
className={cn(
|
||||
'flex items-center justify-between rounded-lg px-2 py-2',
|
||||
'cursor-pointer outline-none transition-colors',
|
||||
'hover:bg-black/[0.075] dark:hover:bg-white/10',
|
||||
'data-[active-item]:bg-black/[0.075] dark:data-[active-item]:bg-white/10',
|
||||
)}
|
||||
>
|
||||
<div className="flex items-center gap-2">
|
||||
<Ariakit.MenuItemCheck checked={isCustomEnabled} />
|
||||
<span className="text-sm">{localize('com_ui_custom_prompt_mode' as any)}</span>
|
||||
</div>
|
||||
</Ariakit.MenuItem>
|
||||
</div>
|
||||
</Ariakit.Menu>
|
||||
</Ariakit.MenuProvider>
|
||||
)}
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
export default memo(Artifacts);
|
||||
147
client/src/components/Chat/Input/ArtifactsSubMenu.tsx
Normal file
147
client/src/components/Chat/Input/ArtifactsSubMenu.tsx
Normal file
|
|
@ -0,0 +1,147 @@
|
|||
import React from 'react';
|
||||
import * as Ariakit from '@ariakit/react';
|
||||
import { ChevronRight, WandSparkles } from 'lucide-react';
|
||||
import { ArtifactModes } from 'librechat-data-provider';
|
||||
import { PinIcon } from '~/components/svg';
|
||||
import { useLocalize } from '~/hooks';
|
||||
import { cn } from '~/utils';
|
||||
|
||||
interface ArtifactsSubMenuProps {
|
||||
isArtifactsPinned: boolean;
|
||||
setIsArtifactsPinned: (value: boolean) => void;
|
||||
artifactsMode: string;
|
||||
handleArtifactsToggle: () => void;
|
||||
handleShadcnToggle: () => void;
|
||||
handleCustomToggle: () => void;
|
||||
}
|
||||
|
||||
const ArtifactsSubMenu = ({
|
||||
isArtifactsPinned,
|
||||
setIsArtifactsPinned,
|
||||
artifactsMode,
|
||||
handleArtifactsToggle,
|
||||
handleShadcnToggle,
|
||||
handleCustomToggle,
|
||||
...props
|
||||
}: ArtifactsSubMenuProps) => {
|
||||
const localize = useLocalize();
|
||||
|
||||
const menuStore = Ariakit.useMenuStore({
|
||||
focusLoop: true,
|
||||
showTimeout: 100,
|
||||
placement: 'right',
|
||||
});
|
||||
|
||||
const isEnabled = artifactsMode !== '' && artifactsMode !== undefined;
|
||||
const isShadcnEnabled = artifactsMode === ArtifactModes.SHADCNUI;
|
||||
const isCustomEnabled = artifactsMode === ArtifactModes.CUSTOM;
|
||||
|
||||
return (
|
||||
<Ariakit.MenuProvider store={menuStore}>
|
||||
<Ariakit.MenuItem
|
||||
{...props}
|
||||
hideOnClick={false}
|
||||
render={
|
||||
<Ariakit.MenuButton
|
||||
onClick={(e: React.MouseEvent<HTMLButtonElement>) => {
|
||||
e.stopPropagation();
|
||||
handleArtifactsToggle();
|
||||
}}
|
||||
onMouseEnter={() => {
|
||||
if (isEnabled) {
|
||||
menuStore.show();
|
||||
}
|
||||
}}
|
||||
className="flex w-full cursor-pointer items-center justify-between rounded-lg p-2 hover:bg-surface-hover"
|
||||
/>
|
||||
}
|
||||
>
|
||||
<div className="flex items-center gap-2">
|
||||
<WandSparkles className="icon-md" />
|
||||
<span>{localize('com_ui_artifacts')}</span>
|
||||
{isEnabled && <ChevronRight className="ml-auto h-3 w-3" />}
|
||||
</div>
|
||||
<button
|
||||
type="button"
|
||||
onClick={(e) => {
|
||||
e.stopPropagation();
|
||||
setIsArtifactsPinned(!isArtifactsPinned);
|
||||
}}
|
||||
className={cn(
|
||||
'rounded p-1 transition-all duration-200',
|
||||
'hover:bg-surface-tertiary hover:shadow-sm',
|
||||
!isArtifactsPinned && 'text-text-secondary hover:text-text-primary',
|
||||
)}
|
||||
aria-label={isArtifactsPinned ? 'Unpin' : 'Pin'}
|
||||
>
|
||||
<div className="h-4 w-4">
|
||||
<PinIcon unpin={isArtifactsPinned} />
|
||||
</div>
|
||||
</button>
|
||||
</Ariakit.MenuItem>
|
||||
|
||||
{isEnabled && (
|
||||
<Ariakit.Menu
|
||||
portal={true}
|
||||
unmountOnHide={true}
|
||||
className={cn(
|
||||
'animate-popover-left z-50 ml-3 flex min-w-[250px] flex-col rounded-xl',
|
||||
'border border-border-light bg-surface-secondary px-1.5 py-1 shadow-lg',
|
||||
)}
|
||||
>
|
||||
<div className="px-2 py-1.5">
|
||||
<div className="mb-2 text-xs font-medium text-text-secondary">
|
||||
{localize('com_ui_artifacts_options')}
|
||||
</div>
|
||||
|
||||
{/* Include shadcn/ui Option */}
|
||||
<Ariakit.MenuItem
|
||||
hideOnClick={false}
|
||||
onClick={(event) => {
|
||||
event.preventDefault();
|
||||
event.stopPropagation();
|
||||
handleShadcnToggle();
|
||||
}}
|
||||
disabled={isCustomEnabled}
|
||||
className={cn(
|
||||
'mb-1 flex items-center justify-between rounded-lg px-2 py-2',
|
||||
'cursor-pointer text-text-primary outline-none transition-colors',
|
||||
'hover:bg-black/[0.075] dark:hover:bg-white/10',
|
||||
'data-[active-item]:bg-black/[0.075] dark:data-[active-item]:bg-white/10',
|
||||
isCustomEnabled && 'cursor-not-allowed opacity-50',
|
||||
)}
|
||||
>
|
||||
<div className="flex items-center gap-2">
|
||||
<Ariakit.MenuItemCheck checked={isShadcnEnabled} />
|
||||
<span className="text-sm">{localize('com_ui_include_shadcnui' as any)}</span>
|
||||
</div>
|
||||
</Ariakit.MenuItem>
|
||||
|
||||
{/* Custom Prompt Mode Option */}
|
||||
<Ariakit.MenuItem
|
||||
hideOnClick={false}
|
||||
onClick={(event) => {
|
||||
event.preventDefault();
|
||||
event.stopPropagation();
|
||||
handleCustomToggle();
|
||||
}}
|
||||
className={cn(
|
||||
'flex items-center justify-between rounded-lg px-2 py-2',
|
||||
'cursor-pointer text-text-primary outline-none transition-colors',
|
||||
'hover:bg-black/[0.075] dark:hover:bg-white/10',
|
||||
'data-[active-item]:bg-black/[0.075] dark:data-[active-item]:bg-white/10',
|
||||
)}
|
||||
>
|
||||
<div className="flex items-center gap-2">
|
||||
<Ariakit.MenuItemCheck checked={isCustomEnabled} />
|
||||
<span className="text-sm">{localize('com_ui_custom_prompt_mode' as any)}</span>
|
||||
</div>
|
||||
</Ariakit.MenuItem>
|
||||
</div>
|
||||
</Ariakit.Menu>
|
||||
)}
|
||||
</Ariakit.MenuProvider>
|
||||
);
|
||||
};
|
||||
|
||||
export default React.memo(ArtifactsSubMenu);
|
||||
|
|
@ -1,19 +1,24 @@
|
|||
import React, {
|
||||
memo,
|
||||
useState,
|
||||
useRef,
|
||||
useEffect,
|
||||
useCallback,
|
||||
useMemo,
|
||||
useState,
|
||||
useEffect,
|
||||
forwardRef,
|
||||
useReducer,
|
||||
useCallback,
|
||||
} from 'react';
|
||||
import { useRecoilValue, useRecoilCallback } from 'recoil';
|
||||
import type { LucideIcon } from 'lucide-react';
|
||||
import CodeInterpreter from './CodeInterpreter';
|
||||
import { BadgeRowProvider } from '~/Providers';
|
||||
import ToolsDropdown from './ToolsDropdown';
|
||||
import type { BadgeItem } from '~/common';
|
||||
import { useChatBadges } from '~/hooks';
|
||||
import { Badge } from '~/components/ui';
|
||||
import ToolDialogs from './ToolDialogs';
|
||||
import FileSearch from './FileSearch';
|
||||
import Artifacts from './Artifacts';
|
||||
import MCPSelect from './MCPSelect';
|
||||
import WebSearch from './WebSearch';
|
||||
import store from '~/store';
|
||||
|
|
@ -23,6 +28,7 @@ interface BadgeRowProps {
|
|||
onChange: (badges: Pick<BadgeItem, 'id'>[]) => void;
|
||||
onToggle?: (badgeId: string, currentActive: boolean) => void;
|
||||
conversationId?: string | null;
|
||||
isSubmitting?: boolean;
|
||||
isInChat: boolean;
|
||||
}
|
||||
|
||||
|
|
@ -136,6 +142,7 @@ const dragReducer = (state: DragState, action: DragAction): DragState => {
|
|||
function BadgeRow({
|
||||
showEphemeralBadges,
|
||||
conversationId,
|
||||
isSubmitting,
|
||||
onChange,
|
||||
onToggle,
|
||||
isInChat,
|
||||
|
|
@ -313,78 +320,84 @@ function BadgeRow({
|
|||
}, [dragState.draggedBadge, handleMouseMove, handleMouseUp]);
|
||||
|
||||
return (
|
||||
<div ref={containerRef} className="relative flex flex-wrap items-center gap-2">
|
||||
{tempBadges.map((badge, index) => (
|
||||
<React.Fragment key={badge.id}>
|
||||
{dragState.draggedBadge && dragState.insertIndex === index && ghostBadge && (
|
||||
<div className="badge-icon h-full">
|
||||
<Badge
|
||||
id={ghostBadge.id}
|
||||
icon={ghostBadge.icon as LucideIcon}
|
||||
label={ghostBadge.label}
|
||||
isActive={dragState.draggedBadgeActive}
|
||||
isEditing={isEditing}
|
||||
isAvailable={ghostBadge.isAvailable}
|
||||
isInChat={isInChat}
|
||||
/>
|
||||
</div>
|
||||
)}
|
||||
<BadgeWrapper
|
||||
badge={badge}
|
||||
isEditing={isEditing}
|
||||
isInChat={isInChat}
|
||||
onToggle={handleBadgeToggle}
|
||||
onDelete={handleDelete}
|
||||
onMouseDown={handleMouseDown}
|
||||
badgeRefs={badgeRefs}
|
||||
/>
|
||||
</React.Fragment>
|
||||
))}
|
||||
{dragState.draggedBadge && dragState.insertIndex === tempBadges.length && ghostBadge && (
|
||||
<div className="badge-icon h-full">
|
||||
<Badge
|
||||
id={ghostBadge.id}
|
||||
icon={ghostBadge.icon as LucideIcon}
|
||||
label={ghostBadge.label}
|
||||
isActive={dragState.draggedBadgeActive}
|
||||
isEditing={isEditing}
|
||||
isAvailable={ghostBadge.isAvailable}
|
||||
isInChat={isInChat}
|
||||
/>
|
||||
</div>
|
||||
)}
|
||||
{showEphemeralBadges === true && (
|
||||
<>
|
||||
<WebSearch conversationId={conversationId} />
|
||||
<CodeInterpreter conversationId={conversationId} />
|
||||
<MCPSelect conversationId={conversationId} />
|
||||
</>
|
||||
)}
|
||||
{ghostBadge && (
|
||||
<div
|
||||
className="ghost-badge h-full"
|
||||
style={{
|
||||
position: 'absolute',
|
||||
top: 0,
|
||||
left: 0,
|
||||
transform: `translateX(${dragState.mouseX - dragState.offsetX - (containerRectRef.current?.left || 0)}px)`,
|
||||
zIndex: 10,
|
||||
pointerEvents: 'none',
|
||||
}}
|
||||
>
|
||||
<Badge
|
||||
id={ghostBadge.id}
|
||||
icon={ghostBadge.icon as LucideIcon}
|
||||
label={ghostBadge.label}
|
||||
isActive={dragState.draggedBadgeActive}
|
||||
isAvailable={ghostBadge.isAvailable}
|
||||
isInChat={isInChat}
|
||||
isEditing
|
||||
isDragging
|
||||
/>
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
<BadgeRowProvider conversationId={conversationId} isSubmitting={isSubmitting}>
|
||||
<div ref={containerRef} className="relative flex flex-wrap items-center gap-2">
|
||||
{showEphemeralBadges === true && <ToolsDropdown />}
|
||||
{tempBadges.map((badge, index) => (
|
||||
<React.Fragment key={badge.id}>
|
||||
{dragState.draggedBadge && dragState.insertIndex === index && ghostBadge && (
|
||||
<div className="badge-icon h-full">
|
||||
<Badge
|
||||
id={ghostBadge.id}
|
||||
icon={ghostBadge.icon as LucideIcon}
|
||||
label={ghostBadge.label}
|
||||
isActive={dragState.draggedBadgeActive}
|
||||
isEditing={isEditing}
|
||||
isAvailable={ghostBadge.isAvailable}
|
||||
isInChat={isInChat}
|
||||
/>
|
||||
</div>
|
||||
)}
|
||||
<BadgeWrapper
|
||||
badge={badge}
|
||||
isEditing={isEditing}
|
||||
isInChat={isInChat}
|
||||
onToggle={handleBadgeToggle}
|
||||
onDelete={handleDelete}
|
||||
onMouseDown={handleMouseDown}
|
||||
badgeRefs={badgeRefs}
|
||||
/>
|
||||
</React.Fragment>
|
||||
))}
|
||||
{dragState.draggedBadge && dragState.insertIndex === tempBadges.length && ghostBadge && (
|
||||
<div className="badge-icon h-full">
|
||||
<Badge
|
||||
id={ghostBadge.id}
|
||||
icon={ghostBadge.icon as LucideIcon}
|
||||
label={ghostBadge.label}
|
||||
isActive={dragState.draggedBadgeActive}
|
||||
isEditing={isEditing}
|
||||
isAvailable={ghostBadge.isAvailable}
|
||||
isInChat={isInChat}
|
||||
/>
|
||||
</div>
|
||||
)}
|
||||
{showEphemeralBadges === true && (
|
||||
<>
|
||||
<WebSearch />
|
||||
<CodeInterpreter />
|
||||
<FileSearch />
|
||||
<Artifacts />
|
||||
<MCPSelect />
|
||||
</>
|
||||
)}
|
||||
{ghostBadge && (
|
||||
<div
|
||||
className="ghost-badge h-full"
|
||||
style={{
|
||||
position: 'absolute',
|
||||
top: 0,
|
||||
left: 0,
|
||||
transform: `translateX(${dragState.mouseX - dragState.offsetX - (containerRectRef.current?.left || 0)}px)`,
|
||||
zIndex: 10,
|
||||
pointerEvents: 'none',
|
||||
}}
|
||||
>
|
||||
<Badge
|
||||
id={ghostBadge.id}
|
||||
icon={ghostBadge.icon as LucideIcon}
|
||||
label={ghostBadge.label}
|
||||
isActive={dragState.draggedBadgeActive}
|
||||
isAvailable={ghostBadge.isAvailable}
|
||||
isInChat={isInChat}
|
||||
isEditing
|
||||
isDragging
|
||||
/>
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
<ToolDialogs />
|
||||
</BadgeRowProvider>
|
||||
);
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -305,6 +305,7 @@ const ChatForm = memo(({ index = 0 }: { index?: number }) => {
|
|||
</div>
|
||||
<BadgeRow
|
||||
showEphemeralBadges={!isAgentsEndpoint(endpoint) && !isAssistantsEndpoint(endpoint)}
|
||||
isSubmitting={isSubmitting || isSubmittingAdded}
|
||||
conversationId={conversationId}
|
||||
onChange={setBadges}
|
||||
isInChat={
|
||||
|
|
|
|||
|
|
@ -1,122 +1,37 @@
|
|||
import debounce from 'lodash/debounce';
|
||||
import React, { memo, useMemo, useCallback, useRef } from 'react';
|
||||
import { useRecoilState } from 'recoil';
|
||||
import React, { memo } from 'react';
|
||||
import { TerminalSquareIcon } from 'lucide-react';
|
||||
import {
|
||||
Tools,
|
||||
AuthType,
|
||||
Constants,
|
||||
LocalStorageKeys,
|
||||
PermissionTypes,
|
||||
Permissions,
|
||||
} from 'librechat-data-provider';
|
||||
import ApiKeyDialog from '~/components/SidePanel/Agents/Code/ApiKeyDialog';
|
||||
import { useLocalize, useHasAccess, useCodeApiKeyForm } from '~/hooks';
|
||||
import { PermissionTypes, Permissions } from 'librechat-data-provider';
|
||||
import CheckboxButton from '~/components/ui/CheckboxButton';
|
||||
import useLocalStorage from '~/hooks/useLocalStorageAlt';
|
||||
import { useVerifyAgentToolAuth } from '~/data-provider';
|
||||
import { ephemeralAgentByConvoId } from '~/store';
|
||||
import { useLocalize, useHasAccess } from '~/hooks';
|
||||
import { useBadgeRowContext } from '~/Providers';
|
||||
|
||||
const storageCondition = (value: unknown, rawCurrentValue?: string | null) => {
|
||||
if (rawCurrentValue) {
|
||||
try {
|
||||
const currentValue = rawCurrentValue?.trim() ?? '';
|
||||
if (currentValue === 'true' && value === false) {
|
||||
return true;
|
||||
}
|
||||
} catch (e) {
|
||||
console.error(e);
|
||||
}
|
||||
}
|
||||
return value !== undefined && value !== null && value !== '' && value !== false;
|
||||
};
|
||||
|
||||
function CodeInterpreter({ conversationId }: { conversationId?: string | null }) {
|
||||
const triggerRef = useRef<HTMLInputElement>(null);
|
||||
function CodeInterpreter() {
|
||||
const localize = useLocalize();
|
||||
const key = conversationId ?? Constants.NEW_CONVO;
|
||||
const { codeInterpreter, codeApiKeyForm } = useBadgeRowContext();
|
||||
const { toggleState: runCode, debouncedChange, isPinned } = codeInterpreter;
|
||||
const { badgeTriggerRef } = codeApiKeyForm;
|
||||
|
||||
const canRunCode = useHasAccess({
|
||||
permissionType: PermissionTypes.RUN_CODE,
|
||||
permission: Permissions.USE,
|
||||
});
|
||||
const [ephemeralAgent, setEphemeralAgent] = useRecoilState(ephemeralAgentByConvoId(key));
|
||||
const isCodeToggleEnabled = useMemo(() => {
|
||||
return ephemeralAgent?.execute_code ?? false;
|
||||
}, [ephemeralAgent?.execute_code]);
|
||||
|
||||
const { data } = useVerifyAgentToolAuth(
|
||||
{ toolId: Tools.execute_code },
|
||||
{
|
||||
retry: 1,
|
||||
},
|
||||
);
|
||||
const authType = useMemo(() => data?.message ?? false, [data?.message]);
|
||||
const isAuthenticated = useMemo(() => data?.authenticated ?? false, [data?.authenticated]);
|
||||
const { methods, onSubmit, isDialogOpen, setIsDialogOpen, handleRevokeApiKey } =
|
||||
useCodeApiKeyForm({});
|
||||
|
||||
const setValue = useCallback(
|
||||
(isChecked: boolean) => {
|
||||
setEphemeralAgent((prev) => ({
|
||||
...prev,
|
||||
execute_code: isChecked,
|
||||
}));
|
||||
},
|
||||
[setEphemeralAgent],
|
||||
);
|
||||
|
||||
const [runCode, setRunCode] = useLocalStorage<boolean>(
|
||||
`${LocalStorageKeys.LAST_CODE_TOGGLE_}${key}`,
|
||||
isCodeToggleEnabled,
|
||||
setValue,
|
||||
storageCondition,
|
||||
);
|
||||
|
||||
const handleChange = useCallback(
|
||||
(e: React.ChangeEvent<HTMLInputElement>, isChecked: boolean) => {
|
||||
if (!isAuthenticated) {
|
||||
setIsDialogOpen(true);
|
||||
e.preventDefault();
|
||||
return;
|
||||
}
|
||||
setRunCode(isChecked);
|
||||
},
|
||||
[setRunCode, setIsDialogOpen, isAuthenticated],
|
||||
);
|
||||
|
||||
const debouncedChange = useMemo(
|
||||
() => debounce(handleChange, 50, { leading: true }),
|
||||
[handleChange],
|
||||
);
|
||||
|
||||
if (!canRunCode) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return (
|
||||
<>
|
||||
(runCode || isPinned) && (
|
||||
<CheckboxButton
|
||||
ref={triggerRef}
|
||||
ref={badgeTriggerRef}
|
||||
className="max-w-fit"
|
||||
defaultChecked={runCode}
|
||||
checked={runCode}
|
||||
setValue={debouncedChange}
|
||||
label={localize('com_assistants_code_interpreter')}
|
||||
isCheckedClassName="border-purple-600/40 bg-purple-500/10 hover:bg-purple-700/10"
|
||||
icon={<TerminalSquareIcon className="icon-md" />}
|
||||
/>
|
||||
<ApiKeyDialog
|
||||
onSubmit={onSubmit}
|
||||
isOpen={isDialogOpen}
|
||||
triggerRef={triggerRef}
|
||||
register={methods.register}
|
||||
onRevoke={handleRevokeApiKey}
|
||||
onOpenChange={setIsDialogOpen}
|
||||
handleSubmit={methods.handleSubmit}
|
||||
isToolAuthenticated={isAuthenticated}
|
||||
isUserProvided={authType === AuthType.USER_PROVIDED}
|
||||
/>
|
||||
</>
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
|
|
|
|||
28
client/src/components/Chat/Input/FileSearch.tsx
Normal file
28
client/src/components/Chat/Input/FileSearch.tsx
Normal file
|
|
@ -0,0 +1,28 @@
|
|||
import React, { memo } from 'react';
|
||||
import CheckboxButton from '~/components/ui/CheckboxButton';
|
||||
import { useBadgeRowContext } from '~/Providers';
|
||||
import { VectorIcon } from '~/components/svg';
|
||||
import { useLocalize } from '~/hooks';
|
||||
|
||||
function FileSearch() {
|
||||
const localize = useLocalize();
|
||||
const { fileSearch } = useBadgeRowContext();
|
||||
const { toggleState: fileSearchEnabled, debouncedChange, isPinned } = fileSearch;
|
||||
|
||||
return (
|
||||
<>
|
||||
{(fileSearchEnabled || isPinned) && (
|
||||
<CheckboxButton
|
||||
className="max-w-fit"
|
||||
checked={fileSearchEnabled}
|
||||
setValue={debouncedChange}
|
||||
label={localize('com_assistants_file_search')}
|
||||
isCheckedClassName="border-green-600/40 bg-green-500/10 hover:bg-green-700/10"
|
||||
icon={<VectorIcon className="icon-md" />}
|
||||
/>
|
||||
)}
|
||||
</>
|
||||
);
|
||||
}
|
||||
|
||||
export default memo(FileSearch);
|
||||
|
|
@ -1,50 +1,44 @@
|
|||
import { memo, useMemo } from 'react';
|
||||
import { useRecoilValue } from 'recoil';
|
||||
import {
|
||||
Constants,
|
||||
supportsFiles,
|
||||
mergeFileConfig,
|
||||
isAgentsEndpoint,
|
||||
isEphemeralAgent,
|
||||
EndpointFileConfig,
|
||||
isAssistantsEndpoint,
|
||||
fileConfig as defaultFileConfig,
|
||||
} from 'librechat-data-provider';
|
||||
import { useChatContext } from '~/Providers';
|
||||
import type { EndpointFileConfig } from 'librechat-data-provider';
|
||||
import { useGetFileConfig } from '~/data-provider';
|
||||
import { ephemeralAgentByConvoId } from '~/store';
|
||||
import AttachFileMenu from './AttachFileMenu';
|
||||
import { useChatContext } from '~/Providers';
|
||||
import AttachFile from './AttachFile';
|
||||
|
||||
function AttachFileChat({ disableInputs }: { disableInputs: boolean }) {
|
||||
const { conversation } = useChatContext();
|
||||
|
||||
const { endpoint: _endpoint, endpointType } = conversation ?? { endpoint: null };
|
||||
|
||||
const key = conversation?.conversationId ?? Constants.NEW_CONVO;
|
||||
const ephemeralAgent = useRecoilValue(ephemeralAgentByConvoId(key));
|
||||
const isAgents = useMemo(
|
||||
() => isAgentsEndpoint(_endpoint) || isEphemeralAgent(_endpoint, ephemeralAgent),
|
||||
[_endpoint, ephemeralAgent],
|
||||
);
|
||||
const conversationId = conversation?.conversationId ?? Constants.NEW_CONVO;
|
||||
const { endpoint, endpointType } = conversation ?? { endpoint: null };
|
||||
const isAgents = useMemo(() => isAgentsEndpoint(endpoint), [endpoint]);
|
||||
const isAssistants = useMemo(() => isAssistantsEndpoint(endpoint), [endpoint]);
|
||||
|
||||
const { data: fileConfig = defaultFileConfig } = useGetFileConfig({
|
||||
select: (data) => mergeFileConfig(data),
|
||||
});
|
||||
|
||||
const endpointFileConfig = fileConfig.endpoints[_endpoint ?? ''] as
|
||||
| EndpointFileConfig
|
||||
| undefined;
|
||||
|
||||
const endpointSupportsFiles: boolean = supportsFiles[endpointType ?? _endpoint ?? ''] ?? false;
|
||||
const endpointFileConfig = fileConfig.endpoints[endpoint ?? ''] as EndpointFileConfig | undefined;
|
||||
const endpointSupportsFiles: boolean = supportsFiles[endpointType ?? endpoint ?? ''] ?? false;
|
||||
const isUploadDisabled = (disableInputs || endpointFileConfig?.disabled) ?? false;
|
||||
|
||||
if (isAgents) {
|
||||
return <AttachFileMenu disabled={disableInputs} />;
|
||||
}
|
||||
if (endpointSupportsFiles && !isUploadDisabled) {
|
||||
if (isAssistants && endpointSupportsFiles && !isUploadDisabled) {
|
||||
return <AttachFile disabled={disableInputs} />;
|
||||
} else if (isAgents || (endpointSupportsFiles && !isUploadDisabled)) {
|
||||
return (
|
||||
<AttachFileMenu
|
||||
disabled={disableInputs}
|
||||
conversationId={conversationId}
|
||||
endpointFileConfig={endpointFileConfig}
|
||||
/>
|
||||
);
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -1,35 +1,38 @@
|
|||
import { useSetRecoilState } from 'recoil';
|
||||
import * as Ariakit from '@ariakit/react';
|
||||
import React, { useRef, useState, useMemo } from 'react';
|
||||
import { FileSearch, ImageUpIcon, TerminalSquareIcon, FileType2Icon } from 'lucide-react';
|
||||
import { EToolResources, EModelEndpoint, defaultAgentCapabilities } from 'librechat-data-provider';
|
||||
import type { EndpointFileConfig } from 'librechat-data-provider';
|
||||
import { useLocalize, useGetAgentsConfig, useFileHandling, useAgentCapabilities } from '~/hooks';
|
||||
import { FileUpload, TooltipAnchor, DropdownPopup, AttachmentIcon } from '~/components';
|
||||
import { useGetEndpointsQuery } from '~/data-provider';
|
||||
import { useLocalize, useFileHandling } from '~/hooks';
|
||||
import { ephemeralAgentByConvoId } from '~/store';
|
||||
import { cn } from '~/utils';
|
||||
|
||||
interface AttachFileProps {
|
||||
interface AttachFileMenuProps {
|
||||
conversationId: string;
|
||||
disabled?: boolean | null;
|
||||
endpointFileConfig?: EndpointFileConfig;
|
||||
}
|
||||
|
||||
const AttachFile = ({ disabled }: AttachFileProps) => {
|
||||
const AttachFileMenu = ({ disabled, conversationId, endpointFileConfig }: AttachFileMenuProps) => {
|
||||
const localize = useLocalize();
|
||||
const isUploadDisabled = disabled ?? false;
|
||||
const inputRef = useRef<HTMLInputElement>(null);
|
||||
const [isPopoverActive, setIsPopoverActive] = useState(false);
|
||||
const setEphemeralAgent = useSetRecoilState(ephemeralAgentByConvoId(conversationId));
|
||||
const [toolResource, setToolResource] = useState<EToolResources | undefined>();
|
||||
const { data: endpointsConfig } = useGetEndpointsQuery();
|
||||
const { handleFileChange } = useFileHandling({
|
||||
overrideEndpoint: EModelEndpoint.agents,
|
||||
overrideEndpointFileConfig: endpointFileConfig,
|
||||
});
|
||||
|
||||
const { agentsConfig } = useGetAgentsConfig();
|
||||
/** TODO: Ephemeral Agent Capabilities
|
||||
* Allow defining agent capabilities on a per-endpoint basis
|
||||
* Use definition for agents endpoint for ephemeral agents
|
||||
* */
|
||||
const capabilities = useMemo(
|
||||
() => endpointsConfig?.[EModelEndpoint.agents]?.capabilities ?? [],
|
||||
[endpointsConfig],
|
||||
);
|
||||
const capabilities = useAgentCapabilities(agentsConfig?.capabilities ?? defaultAgentCapabilities);
|
||||
|
||||
const handleUploadClick = (isImage?: boolean) => {
|
||||
if (!inputRef.current) {
|
||||
|
|
@ -53,7 +56,7 @@ const AttachFile = ({ disabled }: AttachFileProps) => {
|
|||
},
|
||||
];
|
||||
|
||||
if (capabilities.includes(EToolResources.ocr)) {
|
||||
if (capabilities.ocrEnabled) {
|
||||
items.push({
|
||||
label: localize('com_ui_upload_ocr_text'),
|
||||
onClick: () => {
|
||||
|
|
@ -64,22 +67,27 @@ const AttachFile = ({ disabled }: AttachFileProps) => {
|
|||
});
|
||||
}
|
||||
|
||||
if (capabilities.includes(EToolResources.file_search)) {
|
||||
if (capabilities.fileSearchEnabled) {
|
||||
items.push({
|
||||
label: localize('com_ui_upload_file_search'),
|
||||
onClick: () => {
|
||||
setToolResource(EToolResources.file_search);
|
||||
/** File search is not automatically enabled to simulate legacy behavior */
|
||||
handleUploadClick();
|
||||
},
|
||||
icon: <FileSearch className="icon-md" />,
|
||||
});
|
||||
}
|
||||
|
||||
if (capabilities.includes(EToolResources.execute_code)) {
|
||||
if (capabilities.codeEnabled) {
|
||||
items.push({
|
||||
label: localize('com_ui_upload_code_files'),
|
||||
onClick: () => {
|
||||
setToolResource(EToolResources.execute_code);
|
||||
setEphemeralAgent((prev) => ({
|
||||
...prev,
|
||||
[EToolResources.execute_code]: true,
|
||||
}));
|
||||
handleUploadClick();
|
||||
},
|
||||
icon: <TerminalSquareIcon className="icon-md" />,
|
||||
|
|
@ -87,7 +95,7 @@ const AttachFile = ({ disabled }: AttachFileProps) => {
|
|||
}
|
||||
|
||||
return items;
|
||||
}, [capabilities, localize, setToolResource]);
|
||||
}, [capabilities, localize, setToolResource, setEphemeralAgent]);
|
||||
|
||||
const menuTrigger = (
|
||||
<TooltipAnchor
|
||||
|
|
@ -132,4 +140,4 @@ const AttachFile = ({ disabled }: AttachFileProps) => {
|
|||
);
|
||||
};
|
||||
|
||||
export default React.memo(AttachFile);
|
||||
export default React.memo(AttachFileMenu);
|
||||
|
|
|
|||
|
|
@ -7,7 +7,7 @@ import useLocalize from '~/hooks/useLocalize';
|
|||
import { OGDialog } from '~/components/ui';
|
||||
|
||||
interface DragDropModalProps {
|
||||
onOptionSelect: (option: string | undefined) => void;
|
||||
onOptionSelect: (option: EToolResources | undefined) => void;
|
||||
files: File[];
|
||||
isVisible: boolean;
|
||||
setShowModal: (showModal: boolean) => void;
|
||||
|
|
|
|||
|
|
@ -1,74 +1,27 @@
|
|||
import React, { memo, useRef, useMemo, useEffect, useCallback, useState } from 'react';
|
||||
import { useRecoilState } from 'recoil';
|
||||
import { Settings2 } from 'lucide-react';
|
||||
import React, { memo, useCallback, useState } from 'react';
|
||||
import { SettingsIcon } from 'lucide-react';
|
||||
import { Constants } from 'librechat-data-provider';
|
||||
import { useUpdateUserPluginsMutation } from 'librechat-data-provider/react-query';
|
||||
import { Constants, EModelEndpoint, LocalStorageKeys } from 'librechat-data-provider';
|
||||
import type { TPlugin, TPluginAuthConfig, TUpdateUserPlugins } from 'librechat-data-provider';
|
||||
import type { TUpdateUserPlugins, TPlugin } from 'librechat-data-provider';
|
||||
import MCPConfigDialog, { type ConfigFieldDetail } from '~/components/ui/MCPConfigDialog';
|
||||
import { useAvailableToolsQuery } from '~/data-provider';
|
||||
import useLocalStorage from '~/hooks/useLocalStorageAlt';
|
||||
import { useToastContext, useBadgeRowContext } from '~/Providers';
|
||||
import MultiSelect from '~/components/ui/MultiSelect';
|
||||
import { ephemeralAgentByConvoId } from '~/store';
|
||||
import { useToastContext } from '~/Providers';
|
||||
import MCPIcon from '~/components/ui/MCPIcon';
|
||||
import { MCPIcon } from '~/components/svg';
|
||||
import { useLocalize } from '~/hooks';
|
||||
|
||||
interface McpServerInfo {
|
||||
name: string;
|
||||
pluginKey: string;
|
||||
authConfig?: TPluginAuthConfig[];
|
||||
authenticated?: boolean;
|
||||
}
|
||||
|
||||
// Helper function to extract mcp_serverName from a full pluginKey like action_mcp_serverName
|
||||
const getBaseMCPPluginKey = (fullPluginKey: string): string => {
|
||||
const parts = fullPluginKey.split(Constants.mcp_delimiter);
|
||||
return Constants.mcp_prefix + parts[parts.length - 1];
|
||||
};
|
||||
|
||||
const storageCondition = (value: unknown, rawCurrentValue?: string | null) => {
|
||||
if (rawCurrentValue) {
|
||||
try {
|
||||
const currentValue = rawCurrentValue?.trim() ?? '';
|
||||
if (currentValue.length > 2) {
|
||||
return true;
|
||||
}
|
||||
} catch (e) {
|
||||
console.error(e);
|
||||
}
|
||||
}
|
||||
return Array.isArray(value) && value.length > 0;
|
||||
};
|
||||
|
||||
function MCPSelect({ conversationId }: { conversationId?: string | null }) {
|
||||
function MCPSelect() {
|
||||
const localize = useLocalize();
|
||||
const { showToast } = useToastContext();
|
||||
const key = conversationId ?? Constants.NEW_CONVO;
|
||||
const hasSetFetched = useRef<string | null>(null);
|
||||
const [isConfigModalOpen, setIsConfigModalOpen] = useState(false);
|
||||
const [selectedToolForConfig, setSelectedToolForConfig] = useState<McpServerInfo | null>(null);
|
||||
const { mcpSelect, startupConfig } = useBadgeRowContext();
|
||||
const { mcpValues, setMCPValues, mcpServerNames, mcpToolDetails, isPinned } = mcpSelect;
|
||||
|
||||
const { data: mcpToolDetails, isFetched } = useAvailableToolsQuery(EModelEndpoint.agents, {
|
||||
select: (data: TPlugin[]) => {
|
||||
const mcpToolsMap = new Map<string, McpServerInfo>();
|
||||
data.forEach((tool) => {
|
||||
const isMCP = tool.pluginKey.includes(Constants.mcp_delimiter);
|
||||
if (isMCP && tool.chatMenu !== false) {
|
||||
const parts = tool.pluginKey.split(Constants.mcp_delimiter);
|
||||
const serverName = parts[parts.length - 1];
|
||||
if (!mcpToolsMap.has(serverName)) {
|
||||
mcpToolsMap.set(serverName, {
|
||||
name: serverName,
|
||||
pluginKey: tool.pluginKey,
|
||||
authConfig: tool.authConfig,
|
||||
authenticated: tool.authenticated,
|
||||
});
|
||||
}
|
||||
}
|
||||
});
|
||||
return Array.from(mcpToolsMap.values());
|
||||
},
|
||||
});
|
||||
const [isConfigModalOpen, setIsConfigModalOpen] = useState(false);
|
||||
const [selectedToolForConfig, setSelectedToolForConfig] = useState<TPlugin | null>(null);
|
||||
|
||||
const updateUserPluginsMutation = useUpdateUserPluginsMutation({
|
||||
onSuccess: () => {
|
||||
|
|
@ -84,48 +37,6 @@ function MCPSelect({ conversationId }: { conversationId?: string | null }) {
|
|||
},
|
||||
});
|
||||
|
||||
const [ephemeralAgent, setEphemeralAgent] = useRecoilState(ephemeralAgentByConvoId(key));
|
||||
const mcpState = useMemo(() => {
|
||||
return ephemeralAgent?.mcp ?? [];
|
||||
}, [ephemeralAgent?.mcp]);
|
||||
|
||||
const setSelectedValues = useCallback(
|
||||
(values: string[] | null | undefined) => {
|
||||
if (!values) {
|
||||
return;
|
||||
}
|
||||
if (!Array.isArray(values)) {
|
||||
return;
|
||||
}
|
||||
setEphemeralAgent((prev) => ({
|
||||
...prev,
|
||||
mcp: values,
|
||||
}));
|
||||
},
|
||||
[setEphemeralAgent],
|
||||
);
|
||||
const [mcpValues, setMCPValues] = useLocalStorage<string[]>(
|
||||
`${LocalStorageKeys.LAST_MCP_}${key}`,
|
||||
mcpState,
|
||||
setSelectedValues,
|
||||
storageCondition,
|
||||
);
|
||||
|
||||
useEffect(() => {
|
||||
if (hasSetFetched.current === key) {
|
||||
return;
|
||||
}
|
||||
if (!isFetched) {
|
||||
return;
|
||||
}
|
||||
hasSetFetched.current = key;
|
||||
if ((mcpToolDetails?.length ?? 0) > 0) {
|
||||
setMCPValues(mcpValues.filter((mcp) => mcpToolDetails?.some((tool) => tool.name === mcp)));
|
||||
return;
|
||||
}
|
||||
setMCPValues([]);
|
||||
}, [isFetched, setMCPValues, mcpToolDetails, key, mcpValues]);
|
||||
|
||||
const renderSelectedValues = useCallback(
|
||||
(values: string[], placeholder?: string) => {
|
||||
if (values.length === 0) {
|
||||
|
|
@ -139,10 +50,6 @@ function MCPSelect({ conversationId }: { conversationId?: string | null }) {
|
|||
[localize],
|
||||
);
|
||||
|
||||
const mcpServerNames = useMemo(() => {
|
||||
return (mcpToolDetails ?? []).map((tool) => tool.name);
|
||||
}, [mcpToolDetails]);
|
||||
|
||||
const handleConfigSave = useCallback(
|
||||
(targetName: string, authData: Record<string, string>) => {
|
||||
if (selectedToolForConfig && selectedToolForConfig.name === targetName) {
|
||||
|
|
@ -198,10 +105,10 @@ function MCPSelect({ conversationId }: { conversationId?: string | null }) {
|
|||
setSelectedToolForConfig(tool);
|
||||
setIsConfigModalOpen(true);
|
||||
}}
|
||||
className="ml-2 flex h-6 w-6 items-center justify-center rounded p-1 hover:bg-black/10 dark:hover:bg-white/10"
|
||||
className="ml-2 flex h-6 w-6 items-center justify-center rounded p-1 hover:bg-surface-secondary"
|
||||
aria-label={`Configure ${serverName}`}
|
||||
>
|
||||
<Settings2 className={`h-4 w-4 ${tool.authenticated ? 'text-green-500' : ''}`} />
|
||||
<SettingsIcon className={`h-4 w-4 ${tool.authenticated ? 'text-green-500' : ''}`} />
|
||||
</button>
|
||||
</div>
|
||||
);
|
||||
|
|
@ -212,10 +119,17 @@ function MCPSelect({ conversationId }: { conversationId?: string | null }) {
|
|||
[mcpToolDetails, setSelectedToolForConfig, setIsConfigModalOpen],
|
||||
);
|
||||
|
||||
// Don't render if no servers are selected and not pinned
|
||||
if ((!mcpValues || mcpValues.length === 0) && !isPinned) {
|
||||
return null;
|
||||
}
|
||||
|
||||
if (!mcpToolDetails || mcpToolDetails.length === 0) {
|
||||
return null;
|
||||
}
|
||||
|
||||
const placeholderText =
|
||||
startupConfig?.interface?.mcpServers?.placeholder || localize('com_ui_mcp_servers');
|
||||
return (
|
||||
<>
|
||||
<MultiSelect
|
||||
|
|
@ -225,7 +139,7 @@ function MCPSelect({ conversationId }: { conversationId?: string | null }) {
|
|||
defaultSelectedValues={mcpValues ?? []}
|
||||
renderSelectedValues={renderSelectedValues}
|
||||
renderItemContent={renderItemContent}
|
||||
placeholder={localize('com_ui_mcp_servers')}
|
||||
placeholder={placeholderText}
|
||||
popoverClassName="min-w-fit"
|
||||
className="badge-icon min-w-fit"
|
||||
selectIcon={<MCPIcon className="icon-md text-text-primary" />}
|
||||
|
|
|
|||
103
client/src/components/Chat/Input/MCPSubMenu.tsx
Normal file
103
client/src/components/Chat/Input/MCPSubMenu.tsx
Normal file
|
|
@ -0,0 +1,103 @@
|
|||
import React from 'react';
|
||||
import * as Ariakit from '@ariakit/react';
|
||||
import { ChevronRight } from 'lucide-react';
|
||||
import { PinIcon, MCPIcon } from '~/components/svg';
|
||||
import { useLocalize } from '~/hooks';
|
||||
import { cn } from '~/utils';
|
||||
|
||||
interface MCPSubMenuProps {
|
||||
isMCPPinned: boolean;
|
||||
setIsMCPPinned: (value: boolean) => void;
|
||||
mcpValues?: string[];
|
||||
mcpServerNames: string[];
|
||||
handleMCPToggle: (serverName: string) => void;
|
||||
placeholder?: string;
|
||||
}
|
||||
|
||||
const MCPSubMenu = ({
|
||||
mcpValues,
|
||||
isMCPPinned,
|
||||
mcpServerNames,
|
||||
setIsMCPPinned,
|
||||
handleMCPToggle,
|
||||
placeholder,
|
||||
...props
|
||||
}: MCPSubMenuProps) => {
|
||||
const localize = useLocalize();
|
||||
|
||||
const menuStore = Ariakit.useMenuStore({
|
||||
focusLoop: true,
|
||||
showTimeout: 100,
|
||||
placement: 'right',
|
||||
});
|
||||
|
||||
return (
|
||||
<Ariakit.MenuProvider store={menuStore}>
|
||||
<Ariakit.MenuItem
|
||||
{...props}
|
||||
render={
|
||||
<Ariakit.MenuButton
|
||||
onClick={(e: React.MouseEvent<HTMLButtonElement>) => {
|
||||
e.stopPropagation();
|
||||
menuStore.toggle();
|
||||
}}
|
||||
className="flex w-full cursor-pointer items-center justify-between rounded-lg p-2 hover:bg-surface-hover"
|
||||
/>
|
||||
}
|
||||
>
|
||||
<div className="flex items-center gap-2">
|
||||
<MCPIcon className="icon-md" />
|
||||
<span>{placeholder || localize('com_ui_mcp_servers')}</span>
|
||||
<ChevronRight className="ml-auto h-3 w-3" />
|
||||
</div>
|
||||
<button
|
||||
type="button"
|
||||
onClick={(e) => {
|
||||
e.stopPropagation();
|
||||
setIsMCPPinned(!isMCPPinned);
|
||||
}}
|
||||
className={cn(
|
||||
'rounded p-1 transition-all duration-200',
|
||||
'hover:bg-surface-tertiary hover:shadow-sm',
|
||||
!isMCPPinned && 'text-text-secondary hover:text-text-primary',
|
||||
)}
|
||||
aria-label={isMCPPinned ? 'Unpin' : 'Pin'}
|
||||
>
|
||||
<div className="h-4 w-4">
|
||||
<PinIcon unpin={isMCPPinned} />
|
||||
</div>
|
||||
</button>
|
||||
</Ariakit.MenuItem>
|
||||
<Ariakit.Menu
|
||||
portal={true}
|
||||
unmountOnHide={true}
|
||||
className={cn(
|
||||
'animate-popover-left z-50 ml-3 flex min-w-[200px] flex-col rounded-xl',
|
||||
'border border-border-light bg-surface-secondary p-1 shadow-lg',
|
||||
)}
|
||||
>
|
||||
{mcpServerNames.map((serverName) => (
|
||||
<Ariakit.MenuItem
|
||||
key={serverName}
|
||||
onClick={(event) => {
|
||||
event.preventDefault();
|
||||
handleMCPToggle(serverName);
|
||||
}}
|
||||
className={cn(
|
||||
'flex items-center gap-2 rounded-lg px-2 py-1.5 text-text-primary hover:cursor-pointer',
|
||||
'scroll-m-1 outline-none transition-colors',
|
||||
'hover:bg-black/[0.075] dark:hover:bg-white/10',
|
||||
'data-[active-item]:bg-black/[0.075] dark:data-[active-item]:bg-white/10',
|
||||
'w-full min-w-0 text-sm',
|
||||
)}
|
||||
>
|
||||
<Ariakit.MenuItemCheck checked={mcpValues?.includes(serverName) ?? false} />
|
||||
<span>{serverName}</span>
|
||||
</Ariakit.MenuItem>
|
||||
))}
|
||||
</Ariakit.Menu>
|
||||
</Ariakit.MenuProvider>
|
||||
);
|
||||
};
|
||||
|
||||
export default React.memo(MCPSubMenu);
|
||||
66
client/src/components/Chat/Input/ToolDialogs.tsx
Normal file
66
client/src/components/Chat/Input/ToolDialogs.tsx
Normal file
|
|
@ -0,0 +1,66 @@
|
|||
import React, { useMemo } from 'react';
|
||||
import { AuthType } from 'librechat-data-provider';
|
||||
import SearchApiKeyDialog from '~/components/SidePanel/Agents/Search/ApiKeyDialog';
|
||||
import CodeApiKeyDialog from '~/components/SidePanel/Agents/Code/ApiKeyDialog';
|
||||
import { useBadgeRowContext } from '~/Providers';
|
||||
|
||||
function ToolDialogs() {
|
||||
const { webSearch, codeInterpreter, searchApiKeyForm, codeApiKeyForm } = useBadgeRowContext();
|
||||
const { authData: webSearchAuthData } = webSearch;
|
||||
const { authData: codeAuthData } = codeInterpreter;
|
||||
|
||||
const {
|
||||
methods: searchMethods,
|
||||
onSubmit: searchOnSubmit,
|
||||
isDialogOpen: searchDialogOpen,
|
||||
setIsDialogOpen: setSearchDialogOpen,
|
||||
handleRevokeApiKey: searchHandleRevoke,
|
||||
badgeTriggerRef: searchBadgeTriggerRef,
|
||||
menuTriggerRef: searchMenuTriggerRef,
|
||||
} = searchApiKeyForm;
|
||||
|
||||
const {
|
||||
methods: codeMethods,
|
||||
onSubmit: codeOnSubmit,
|
||||
isDialogOpen: codeDialogOpen,
|
||||
setIsDialogOpen: setCodeDialogOpen,
|
||||
handleRevokeApiKey: codeHandleRevoke,
|
||||
badgeTriggerRef: codeBadgeTriggerRef,
|
||||
menuTriggerRef: codeMenuTriggerRef,
|
||||
} = codeApiKeyForm;
|
||||
|
||||
const searchAuthTypes = useMemo(
|
||||
() => webSearchAuthData?.authTypes ?? [],
|
||||
[webSearchAuthData?.authTypes],
|
||||
);
|
||||
const codeAuthType = useMemo(() => codeAuthData?.message ?? false, [codeAuthData?.message]);
|
||||
|
||||
return (
|
||||
<>
|
||||
<SearchApiKeyDialog
|
||||
onSubmit={searchOnSubmit}
|
||||
authTypes={searchAuthTypes}
|
||||
isOpen={searchDialogOpen}
|
||||
onRevoke={searchHandleRevoke}
|
||||
register={searchMethods.register}
|
||||
onOpenChange={setSearchDialogOpen}
|
||||
handleSubmit={searchMethods.handleSubmit}
|
||||
triggerRefs={[searchMenuTriggerRef, searchBadgeTriggerRef]}
|
||||
isToolAuthenticated={webSearchAuthData?.authenticated ?? false}
|
||||
/>
|
||||
<CodeApiKeyDialog
|
||||
onSubmit={codeOnSubmit}
|
||||
isOpen={codeDialogOpen}
|
||||
onRevoke={codeHandleRevoke}
|
||||
register={codeMethods.register}
|
||||
onOpenChange={setCodeDialogOpen}
|
||||
handleSubmit={codeMethods.handleSubmit}
|
||||
triggerRefs={[codeMenuTriggerRef, codeBadgeTriggerRef]}
|
||||
isUserProvided={codeAuthType === AuthType.USER_PROVIDED}
|
||||
isToolAuthenticated={codeAuthData?.authenticated ?? false}
|
||||
/>
|
||||
</>
|
||||
);
|
||||
}
|
||||
|
||||
export default ToolDialogs;
|
||||
354
client/src/components/Chat/Input/ToolsDropdown.tsx
Normal file
354
client/src/components/Chat/Input/ToolsDropdown.tsx
Normal file
|
|
@ -0,0 +1,354 @@
|
|||
import React, { useState, useMemo, useCallback } from 'react';
|
||||
import * as Ariakit from '@ariakit/react';
|
||||
import { Globe, Settings, Settings2, TerminalSquareIcon } from 'lucide-react';
|
||||
import type { MenuItemProps } from '~/common';
|
||||
import {
|
||||
AuthType,
|
||||
Permissions,
|
||||
ArtifactModes,
|
||||
PermissionTypes,
|
||||
defaultAgentCapabilities,
|
||||
} from 'librechat-data-provider';
|
||||
import { TooltipAnchor, DropdownPopup } from '~/components';
|
||||
import { useLocalize, useHasAccess, useAgentCapabilities } from '~/hooks';
|
||||
import ArtifactsSubMenu from '~/components/Chat/Input/ArtifactsSubMenu';
|
||||
import MCPSubMenu from '~/components/Chat/Input/MCPSubMenu';
|
||||
import { PinIcon, VectorIcon } from '~/components/svg';
|
||||
import { useBadgeRowContext } from '~/Providers';
|
||||
import { cn } from '~/utils';
|
||||
|
||||
interface ToolsDropdownProps {
|
||||
disabled?: boolean;
|
||||
}
|
||||
|
||||
const ToolsDropdown = ({ disabled }: ToolsDropdownProps) => {
|
||||
const localize = useLocalize();
|
||||
const isDisabled = disabled ?? false;
|
||||
const [isPopoverActive, setIsPopoverActive] = useState(false);
|
||||
const {
|
||||
webSearch,
|
||||
mcpSelect,
|
||||
artifacts,
|
||||
fileSearch,
|
||||
agentsConfig,
|
||||
startupConfig,
|
||||
codeApiKeyForm,
|
||||
codeInterpreter,
|
||||
searchApiKeyForm,
|
||||
} = useBadgeRowContext();
|
||||
const { codeEnabled, webSearchEnabled, artifactsEnabled, fileSearchEnabled } =
|
||||
useAgentCapabilities(agentsConfig?.capabilities ?? defaultAgentCapabilities);
|
||||
|
||||
const { setIsDialogOpen: setIsCodeDialogOpen, menuTriggerRef: codeMenuTriggerRef } =
|
||||
codeApiKeyForm;
|
||||
const { setIsDialogOpen: setIsSearchDialogOpen, menuTriggerRef: searchMenuTriggerRef } =
|
||||
searchApiKeyForm;
|
||||
const {
|
||||
isPinned: isSearchPinned,
|
||||
setIsPinned: setIsSearchPinned,
|
||||
authData: webSearchAuthData,
|
||||
} = webSearch;
|
||||
const {
|
||||
isPinned: isCodePinned,
|
||||
setIsPinned: setIsCodePinned,
|
||||
authData: codeAuthData,
|
||||
} = codeInterpreter;
|
||||
const { isPinned: isFileSearchPinned, setIsPinned: setIsFileSearchPinned } = fileSearch;
|
||||
const { isPinned: isArtifactsPinned, setIsPinned: setIsArtifactsPinned } = artifacts;
|
||||
const {
|
||||
mcpValues,
|
||||
mcpServerNames,
|
||||
isPinned: isMCPPinned,
|
||||
setIsPinned: setIsMCPPinned,
|
||||
} = mcpSelect;
|
||||
|
||||
const canUseWebSearch = useHasAccess({
|
||||
permissionType: PermissionTypes.WEB_SEARCH,
|
||||
permission: Permissions.USE,
|
||||
});
|
||||
|
||||
const canRunCode = useHasAccess({
|
||||
permissionType: PermissionTypes.RUN_CODE,
|
||||
permission: Permissions.USE,
|
||||
});
|
||||
|
||||
const showWebSearchSettings = useMemo(() => {
|
||||
const authTypes = webSearchAuthData?.authTypes ?? [];
|
||||
if (authTypes.length === 0) return true;
|
||||
return !authTypes.every(([, authType]) => authType === AuthType.SYSTEM_DEFINED);
|
||||
}, [webSearchAuthData?.authTypes]);
|
||||
|
||||
const showCodeSettings = useMemo(
|
||||
() => codeAuthData?.message !== AuthType.SYSTEM_DEFINED,
|
||||
[codeAuthData?.message],
|
||||
);
|
||||
|
||||
const handleWebSearchToggle = useCallback(() => {
|
||||
const newValue = !webSearch.toggleState;
|
||||
webSearch.debouncedChange({ value: newValue });
|
||||
}, [webSearch]);
|
||||
|
||||
const handleCodeInterpreterToggle = useCallback(() => {
|
||||
const newValue = !codeInterpreter.toggleState;
|
||||
codeInterpreter.debouncedChange({ value: newValue });
|
||||
}, [codeInterpreter]);
|
||||
|
||||
const handleFileSearchToggle = useCallback(() => {
|
||||
const newValue = !fileSearch.toggleState;
|
||||
fileSearch.debouncedChange({ value: newValue });
|
||||
}, [fileSearch]);
|
||||
|
||||
const handleArtifactsToggle = useCallback(() => {
|
||||
const currentState = artifacts.toggleState;
|
||||
if (!currentState || currentState === '') {
|
||||
artifacts.debouncedChange({ value: ArtifactModes.DEFAULT });
|
||||
} else {
|
||||
artifacts.debouncedChange({ value: '' });
|
||||
}
|
||||
}, [artifacts]);
|
||||
|
||||
const handleShadcnToggle = useCallback(() => {
|
||||
const currentState = artifacts.toggleState;
|
||||
if (currentState === ArtifactModes.SHADCNUI) {
|
||||
artifacts.debouncedChange({ value: ArtifactModes.DEFAULT });
|
||||
} else {
|
||||
artifacts.debouncedChange({ value: ArtifactModes.SHADCNUI });
|
||||
}
|
||||
}, [artifacts]);
|
||||
|
||||
const handleCustomToggle = useCallback(() => {
|
||||
const currentState = artifacts.toggleState;
|
||||
if (currentState === ArtifactModes.CUSTOM) {
|
||||
artifacts.debouncedChange({ value: ArtifactModes.DEFAULT });
|
||||
} else {
|
||||
artifacts.debouncedChange({ value: ArtifactModes.CUSTOM });
|
||||
}
|
||||
}, [artifacts]);
|
||||
|
||||
const handleMCPToggle = useCallback(
|
||||
(serverName: string) => {
|
||||
const currentValues = mcpSelect.mcpValues ?? [];
|
||||
const newValues = currentValues.includes(serverName)
|
||||
? currentValues.filter((v) => v !== serverName)
|
||||
: [...currentValues, serverName];
|
||||
mcpSelect.setMCPValues(newValues);
|
||||
},
|
||||
[mcpSelect],
|
||||
);
|
||||
|
||||
const mcpPlaceholder = startupConfig?.interface?.mcpServers?.placeholder;
|
||||
|
||||
const dropdownItems: MenuItemProps[] = [];
|
||||
|
||||
if (fileSearchEnabled) {
|
||||
dropdownItems.push({
|
||||
onClick: handleFileSearchToggle,
|
||||
hideOnClick: false,
|
||||
render: (props) => (
|
||||
<div {...props}>
|
||||
<div className="flex items-center gap-2">
|
||||
<VectorIcon className="icon-md" />
|
||||
<span>{localize('com_assistants_file_search')}</span>
|
||||
</div>
|
||||
<button
|
||||
type="button"
|
||||
onClick={(e) => {
|
||||
e.stopPropagation();
|
||||
setIsFileSearchPinned(!isFileSearchPinned);
|
||||
}}
|
||||
className={cn(
|
||||
'rounded p-1 transition-all duration-200',
|
||||
'hover:bg-surface-secondary hover:shadow-sm',
|
||||
!isFileSearchPinned && 'text-text-secondary hover:text-text-primary',
|
||||
)}
|
||||
aria-label={isFileSearchPinned ? 'Unpin' : 'Pin'}
|
||||
>
|
||||
<div className="h-4 w-4">
|
||||
<PinIcon unpin={isFileSearchPinned} />
|
||||
</div>
|
||||
</button>
|
||||
</div>
|
||||
),
|
||||
});
|
||||
}
|
||||
|
||||
if (canUseWebSearch && webSearchEnabled) {
|
||||
dropdownItems.push({
|
||||
onClick: handleWebSearchToggle,
|
||||
hideOnClick: false,
|
||||
render: (props) => (
|
||||
<div {...props}>
|
||||
<div className="flex items-center gap-2">
|
||||
<Globe className="icon-md" />
|
||||
<span>{localize('com_ui_web_search')}</span>
|
||||
</div>
|
||||
<div className="flex items-center gap-1">
|
||||
{showWebSearchSettings && (
|
||||
<button
|
||||
type="button"
|
||||
onClick={(e) => {
|
||||
e.stopPropagation();
|
||||
setIsSearchDialogOpen(true);
|
||||
}}
|
||||
className={cn(
|
||||
'rounded p-1 transition-all duration-200',
|
||||
'hover:bg-surface-secondary hover:shadow-sm',
|
||||
'text-text-secondary hover:text-text-primary',
|
||||
)}
|
||||
aria-label="Configure web search"
|
||||
ref={searchMenuTriggerRef}
|
||||
>
|
||||
<div className="h-4 w-4">
|
||||
<Settings className="h-4 w-4" />
|
||||
</div>
|
||||
</button>
|
||||
)}
|
||||
<button
|
||||
type="button"
|
||||
onClick={(e) => {
|
||||
e.stopPropagation();
|
||||
setIsSearchPinned(!isSearchPinned);
|
||||
}}
|
||||
className={cn(
|
||||
'rounded p-1 transition-all duration-200',
|
||||
'hover:bg-surface-secondary hover:shadow-sm',
|
||||
!isSearchPinned && 'text-text-secondary hover:text-text-primary',
|
||||
)}
|
||||
aria-label={isSearchPinned ? 'Unpin' : 'Pin'}
|
||||
>
|
||||
<div className="h-4 w-4">
|
||||
<PinIcon unpin={isSearchPinned} />
|
||||
</div>
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
),
|
||||
});
|
||||
}
|
||||
|
||||
if (canRunCode && codeEnabled) {
|
||||
dropdownItems.push({
|
||||
onClick: handleCodeInterpreterToggle,
|
||||
hideOnClick: false,
|
||||
render: (props) => (
|
||||
<div {...props}>
|
||||
<div className="flex items-center gap-2">
|
||||
<TerminalSquareIcon className="icon-md" />
|
||||
<span>{localize('com_assistants_code_interpreter')}</span>
|
||||
</div>
|
||||
<div className="flex items-center gap-1">
|
||||
{showCodeSettings && (
|
||||
<button
|
||||
type="button"
|
||||
onClick={(e) => {
|
||||
e.stopPropagation();
|
||||
setIsCodeDialogOpen(true);
|
||||
}}
|
||||
ref={codeMenuTriggerRef}
|
||||
className={cn(
|
||||
'rounded p-1 transition-all duration-200',
|
||||
'hover:bg-surface-secondary hover:shadow-sm',
|
||||
'text-text-secondary hover:text-text-primary',
|
||||
)}
|
||||
aria-label="Configure code interpreter"
|
||||
>
|
||||
<div className="h-4 w-4">
|
||||
<Settings className="h-4 w-4" />
|
||||
</div>
|
||||
</button>
|
||||
)}
|
||||
<button
|
||||
type="button"
|
||||
onClick={(e) => {
|
||||
e.stopPropagation();
|
||||
setIsCodePinned(!isCodePinned);
|
||||
}}
|
||||
className={cn(
|
||||
'rounded p-1 transition-all duration-200',
|
||||
'hover:bg-surface-secondary hover:shadow-sm',
|
||||
!isCodePinned && 'text-text-primary hover:text-text-primary',
|
||||
)}
|
||||
aria-label={isCodePinned ? 'Unpin' : 'Pin'}
|
||||
>
|
||||
<div className="h-4 w-4">
|
||||
<PinIcon unpin={isCodePinned} />
|
||||
</div>
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
),
|
||||
});
|
||||
}
|
||||
|
||||
if (artifactsEnabled) {
|
||||
dropdownItems.push({
|
||||
hideOnClick: false,
|
||||
render: (props) => (
|
||||
<ArtifactsSubMenu
|
||||
{...props}
|
||||
isArtifactsPinned={isArtifactsPinned}
|
||||
setIsArtifactsPinned={setIsArtifactsPinned}
|
||||
artifactsMode={artifacts.toggleState as string}
|
||||
handleArtifactsToggle={handleArtifactsToggle}
|
||||
handleShadcnToggle={handleShadcnToggle}
|
||||
handleCustomToggle={handleCustomToggle}
|
||||
/>
|
||||
),
|
||||
});
|
||||
}
|
||||
|
||||
if (mcpServerNames && mcpServerNames.length > 0) {
|
||||
dropdownItems.push({
|
||||
hideOnClick: false,
|
||||
render: (props) => (
|
||||
<MCPSubMenu
|
||||
{...props}
|
||||
mcpValues={mcpValues}
|
||||
isMCPPinned={isMCPPinned}
|
||||
placeholder={mcpPlaceholder}
|
||||
mcpServerNames={mcpServerNames}
|
||||
setIsMCPPinned={setIsMCPPinned}
|
||||
handleMCPToggle={handleMCPToggle}
|
||||
/>
|
||||
),
|
||||
});
|
||||
}
|
||||
|
||||
const menuTrigger = (
|
||||
<TooltipAnchor
|
||||
render={
|
||||
<Ariakit.MenuButton
|
||||
disabled={isDisabled}
|
||||
id="tools-dropdown-button"
|
||||
aria-label="Tools Options"
|
||||
className={cn(
|
||||
'flex size-9 items-center justify-center rounded-full p-1 transition-colors hover:bg-surface-hover focus:outline-none focus:ring-2 focus:ring-primary focus:ring-opacity-50',
|
||||
)}
|
||||
>
|
||||
<div className="flex w-full items-center justify-center gap-2">
|
||||
<Settings2 className="icon-md" />
|
||||
</div>
|
||||
</Ariakit.MenuButton>
|
||||
}
|
||||
id="tools-dropdown-button"
|
||||
description={localize('com_ui_tools')}
|
||||
disabled={isDisabled}
|
||||
/>
|
||||
);
|
||||
|
||||
return (
|
||||
<DropdownPopup
|
||||
itemClassName="flex w-full cursor-pointer items-center justify-between hover:bg-surface-hover gap-5"
|
||||
menuId="tools-dropdown-menu"
|
||||
isOpen={isPopoverActive}
|
||||
setIsOpen={setIsPopoverActive}
|
||||
modal={true}
|
||||
unmountOnHide={true}
|
||||
trigger={menuTrigger}
|
||||
items={dropdownItems}
|
||||
iconClassName="mr-0"
|
||||
/>
|
||||
);
|
||||
};
|
||||
|
||||
export default React.memo(ToolsDropdown);
|
||||
|
|
@ -1,122 +1,37 @@
|
|||
import React, { memo, useRef, useMemo, useCallback } from 'react';
|
||||
import React, { memo } from 'react';
|
||||
import { Globe } from 'lucide-react';
|
||||
import debounce from 'lodash/debounce';
|
||||
import { useRecoilState } from 'recoil';
|
||||
import {
|
||||
Tools,
|
||||
AuthType,
|
||||
Constants,
|
||||
Permissions,
|
||||
PermissionTypes,
|
||||
LocalStorageKeys,
|
||||
} from 'librechat-data-provider';
|
||||
import ApiKeyDialog from '~/components/SidePanel/Agents/Search/ApiKeyDialog';
|
||||
import { useLocalize, useHasAccess, useSearchApiKeyForm } from '~/hooks';
|
||||
import { Permissions, PermissionTypes } from 'librechat-data-provider';
|
||||
import CheckboxButton from '~/components/ui/CheckboxButton';
|
||||
import useLocalStorage from '~/hooks/useLocalStorageAlt';
|
||||
import { useVerifyAgentToolAuth } from '~/data-provider';
|
||||
import { ephemeralAgentByConvoId } from '~/store';
|
||||
import { useLocalize, useHasAccess } from '~/hooks';
|
||||
import { useBadgeRowContext } from '~/Providers';
|
||||
|
||||
const storageCondition = (value: unknown, rawCurrentValue?: string | null) => {
|
||||
if (rawCurrentValue) {
|
||||
try {
|
||||
const currentValue = rawCurrentValue?.trim() ?? '';
|
||||
if (currentValue === 'true' && value === false) {
|
||||
return true;
|
||||
}
|
||||
} catch (e) {
|
||||
console.error(e);
|
||||
}
|
||||
}
|
||||
return value !== undefined && value !== null && value !== '' && value !== false;
|
||||
};
|
||||
|
||||
function WebSearch({ conversationId }: { conversationId?: string | null }) {
|
||||
const triggerRef = useRef<HTMLInputElement>(null);
|
||||
function WebSearch() {
|
||||
const localize = useLocalize();
|
||||
const key = conversationId ?? Constants.NEW_CONVO;
|
||||
const { webSearch: webSearchData, searchApiKeyForm } = useBadgeRowContext();
|
||||
const { toggleState: webSearch, debouncedChange, isPinned, authData } = webSearchData;
|
||||
const { badgeTriggerRef } = searchApiKeyForm;
|
||||
|
||||
const canUseWebSearch = useHasAccess({
|
||||
permissionType: PermissionTypes.WEB_SEARCH,
|
||||
permission: Permissions.USE,
|
||||
});
|
||||
const [ephemeralAgent, setEphemeralAgent] = useRecoilState(ephemeralAgentByConvoId(key));
|
||||
const isWebSearchToggleEnabled = useMemo(() => {
|
||||
return ephemeralAgent?.web_search ?? false;
|
||||
}, [ephemeralAgent?.web_search]);
|
||||
|
||||
const { data } = useVerifyAgentToolAuth(
|
||||
{ toolId: Tools.web_search },
|
||||
{
|
||||
retry: 1,
|
||||
},
|
||||
);
|
||||
const authTypes = useMemo(() => data?.authTypes ?? [], [data?.authTypes]);
|
||||
const isAuthenticated = useMemo(() => data?.authenticated ?? false, [data?.authenticated]);
|
||||
const { methods, onSubmit, isDialogOpen, setIsDialogOpen, handleRevokeApiKey } =
|
||||
useSearchApiKeyForm({});
|
||||
|
||||
const setValue = useCallback(
|
||||
(isChecked: boolean) => {
|
||||
setEphemeralAgent((prev) => ({
|
||||
...prev,
|
||||
web_search: isChecked,
|
||||
}));
|
||||
},
|
||||
[setEphemeralAgent],
|
||||
);
|
||||
|
||||
const [webSearch, setWebSearch] = useLocalStorage<boolean>(
|
||||
`${LocalStorageKeys.LAST_WEB_SEARCH_TOGGLE_}${key}`,
|
||||
isWebSearchToggleEnabled,
|
||||
setValue,
|
||||
storageCondition,
|
||||
);
|
||||
|
||||
const handleChange = useCallback(
|
||||
(e: React.ChangeEvent<HTMLInputElement>, isChecked: boolean) => {
|
||||
if (!isAuthenticated) {
|
||||
setIsDialogOpen(true);
|
||||
e.preventDefault();
|
||||
return;
|
||||
}
|
||||
setWebSearch(isChecked);
|
||||
},
|
||||
[setWebSearch, setIsDialogOpen, isAuthenticated],
|
||||
);
|
||||
|
||||
const debouncedChange = useMemo(
|
||||
() => debounce(handleChange, 50, { leading: true }),
|
||||
[handleChange],
|
||||
);
|
||||
|
||||
if (!canUseWebSearch) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return (
|
||||
<>
|
||||
(isPinned || (webSearch && authData?.authenticated)) && (
|
||||
<CheckboxButton
|
||||
ref={triggerRef}
|
||||
ref={badgeTriggerRef}
|
||||
className="max-w-fit"
|
||||
defaultChecked={webSearch}
|
||||
checked={webSearch}
|
||||
setValue={debouncedChange}
|
||||
label={localize('com_ui_search')}
|
||||
isCheckedClassName="border-blue-600/40 bg-blue-500/10 hover:bg-blue-700/10"
|
||||
icon={<Globe className="icon-md" />}
|
||||
/>
|
||||
<ApiKeyDialog
|
||||
onSubmit={onSubmit}
|
||||
authTypes={authTypes}
|
||||
isOpen={isDialogOpen}
|
||||
triggerRef={triggerRef}
|
||||
register={methods.register}
|
||||
onRevoke={handleRevokeApiKey}
|
||||
onOpenChange={setIsDialogOpen}
|
||||
handleSubmit={methods.handleSubmit}
|
||||
isToolAuthenticated={isAuthenticated}
|
||||
/>
|
||||
</>
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -83,7 +83,7 @@ export function filterModels(
|
|||
let modelName = modelId;
|
||||
|
||||
if (isAgentsEndpoint(endpoint.value) && agentsMap && agentsMap[modelId]) {
|
||||
modelName = agentsMap[modelId].name || modelId;
|
||||
modelName = agentsMap[modelId]?.name || modelId;
|
||||
} else if (
|
||||
isAssistantsEndpoint(endpoint.value) &&
|
||||
assistantsMap &&
|
||||
|
|
|
|||
|
|
@ -81,14 +81,23 @@ const ContentParts = memo(
|
|||
return (
|
||||
<>
|
||||
{content.map((part, idx) => {
|
||||
if (part?.type !== ContentTypes.TEXT || typeof part.text !== 'string') {
|
||||
if (!part) {
|
||||
return null;
|
||||
}
|
||||
const isTextPart =
|
||||
part?.type === ContentTypes.TEXT ||
|
||||
typeof (part as unknown as Agents.MessageContentText)?.text !== 'string';
|
||||
const isThinkPart =
|
||||
part?.type === ContentTypes.THINK ||
|
||||
typeof (part as unknown as Agents.ReasoningDeltaUpdate)?.think !== 'string';
|
||||
if (!isTextPart && !isThinkPart) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return (
|
||||
<EditTextPart
|
||||
index={idx}
|
||||
text={part.text}
|
||||
part={part as Agents.MessageContentText | Agents.ReasoningDeltaUpdate}
|
||||
messageId={messageId}
|
||||
isSubmitting={isSubmitting}
|
||||
enterEdit={enterEdit}
|
||||
|
|
|
|||
|
|
@ -1,14 +1,33 @@
|
|||
import { useState, useEffect } from 'react';
|
||||
import { X, ArrowDownToLine, PanelLeftOpen, PanelLeftClose } from 'lucide-react';
|
||||
import { useState, useEffect, useCallback, useRef } from 'react';
|
||||
import { X, ArrowDownToLine, PanelLeftOpen, PanelLeftClose, RotateCcw } from 'lucide-react';
|
||||
import { Button, OGDialog, OGDialogContent, TooltipAnchor } from '~/components';
|
||||
import { useLocalize } from '~/hooks';
|
||||
|
||||
const getQualityStyles = (quality: string): string => {
|
||||
if (quality === 'high') {
|
||||
return 'bg-green-100 text-green-800';
|
||||
}
|
||||
if (quality === 'low') {
|
||||
return 'bg-orange-100 text-orange-800';
|
||||
}
|
||||
return 'bg-gray-100 text-gray-800';
|
||||
};
|
||||
|
||||
export default function DialogImage({ isOpen, onOpenChange, src = '', downloadImage, args }) {
|
||||
const localize = useLocalize();
|
||||
const [isPromptOpen, setIsPromptOpen] = useState(false);
|
||||
const [imageSize, setImageSize] = useState<string | null>(null);
|
||||
|
||||
const getImageSize = async (url: string) => {
|
||||
// Zoom and pan state
|
||||
const [zoom, setZoom] = useState(1);
|
||||
const [panX, setPanX] = useState(0);
|
||||
const [panY, setPanY] = useState(0);
|
||||
const [isDragging, setIsDragging] = useState(false);
|
||||
const [dragStart, setDragStart] = useState({ x: 0, y: 0 });
|
||||
|
||||
const containerRef = useRef<HTMLDivElement>(null);
|
||||
|
||||
const getImageSize = useCallback(async (url: string) => {
|
||||
try {
|
||||
const response = await fetch(url, { method: 'HEAD' });
|
||||
const contentLength = response.headers.get('Content-Length');
|
||||
|
|
@ -25,7 +44,7 @@ export default function DialogImage({ isOpen, onOpenChange, src = '', downloadIm
|
|||
console.error('Error getting image size:', error);
|
||||
return null;
|
||||
}
|
||||
};
|
||||
}, []);
|
||||
|
||||
const formatFileSize = (bytes: number): string => {
|
||||
if (bytes === 0) return '0 Bytes';
|
||||
|
|
@ -37,11 +56,129 @@ export default function DialogImage({ isOpen, onOpenChange, src = '', downloadIm
|
|||
return parseFloat((bytes / Math.pow(k, i)).toFixed(2)) + ' ' + sizes[i];
|
||||
};
|
||||
|
||||
const getImageMaxWidth = () => {
|
||||
// On mobile (when panel overlays), use full width minus padding
|
||||
// On desktop, account for the side panel width
|
||||
if (isPromptOpen) {
|
||||
return window.innerWidth >= 640 ? 'calc(100vw - 22rem)' : 'calc(100vw - 2rem)';
|
||||
}
|
||||
return 'calc(100vw - 2rem)';
|
||||
};
|
||||
|
||||
const resetZoom = useCallback(() => {
|
||||
setZoom(1);
|
||||
setPanX(0);
|
||||
setPanY(0);
|
||||
}, []);
|
||||
|
||||
const getCursor = () => {
|
||||
if (zoom <= 1) return 'default';
|
||||
return isDragging ? 'grabbing' : 'grab';
|
||||
};
|
||||
|
||||
const handleDoubleClick = useCallback(() => {
|
||||
if (zoom > 1) {
|
||||
resetZoom();
|
||||
} else {
|
||||
// Zoom in to 2x on double click when at normal zoom
|
||||
setZoom(2);
|
||||
}
|
||||
}, [zoom, resetZoom]);
|
||||
|
||||
const handleWheel = useCallback(
|
||||
(e: React.WheelEvent<HTMLDivElement>) => {
|
||||
e.preventDefault();
|
||||
if (!containerRef.current) return;
|
||||
|
||||
const rect = containerRef.current.getBoundingClientRect();
|
||||
const mouseX = e.clientX - rect.left;
|
||||
const mouseY = e.clientY - rect.top;
|
||||
|
||||
// Calculate zoom factor
|
||||
const zoomFactor = e.deltaY > 0 ? 0.9 : 1.1;
|
||||
const newZoom = Math.min(Math.max(zoom * zoomFactor, 1), 5);
|
||||
|
||||
if (newZoom === zoom) return;
|
||||
|
||||
// If zooming back to 1, reset pan to center the image
|
||||
if (newZoom === 1) {
|
||||
setZoom(1);
|
||||
setPanX(0);
|
||||
setPanY(0);
|
||||
return;
|
||||
}
|
||||
|
||||
// Calculate the zoom center relative to the current viewport
|
||||
const containerCenterX = rect.width / 2;
|
||||
const containerCenterY = rect.height / 2;
|
||||
|
||||
// Calculate new pan position to zoom towards mouse cursor
|
||||
const zoomRatio = newZoom / zoom;
|
||||
const deltaX = (mouseX - containerCenterX - panX) * (zoomRatio - 1);
|
||||
const deltaY = (mouseY - containerCenterY - panY) * (zoomRatio - 1);
|
||||
|
||||
setZoom(newZoom);
|
||||
setPanX(panX - deltaX);
|
||||
setPanY(panY - deltaY);
|
||||
},
|
||||
[zoom, panX, panY],
|
||||
);
|
||||
|
||||
const handleMouseDown = useCallback(
|
||||
(e: React.MouseEvent<HTMLDivElement>) => {
|
||||
e.preventDefault();
|
||||
if (zoom <= 1) return;
|
||||
setIsDragging(true);
|
||||
setDragStart({
|
||||
x: e.clientX - panX,
|
||||
y: e.clientY - panY,
|
||||
});
|
||||
},
|
||||
[zoom, panX, panY],
|
||||
);
|
||||
|
||||
const handleMouseMove = useCallback(
|
||||
(e: React.MouseEvent<HTMLDivElement>) => {
|
||||
if (!isDragging || zoom <= 1) return;
|
||||
const newPanX = e.clientX - dragStart.x;
|
||||
const newPanY = e.clientY - dragStart.y;
|
||||
setPanX(newPanX);
|
||||
setPanY(newPanY);
|
||||
},
|
||||
[isDragging, dragStart, zoom],
|
||||
);
|
||||
const handleMouseUp = useCallback(() => {
|
||||
setIsDragging(false);
|
||||
}, []);
|
||||
|
||||
useEffect(() => {
|
||||
const onKey = (e: KeyboardEvent) => e.key === 'Escape' && resetZoom();
|
||||
document.addEventListener('keydown', onKey);
|
||||
return () => document.removeEventListener('keydown', onKey);
|
||||
}, [resetZoom]);
|
||||
|
||||
useEffect(() => {
|
||||
if (isOpen && src) {
|
||||
getImageSize(src).then(setImageSize);
|
||||
resetZoom();
|
||||
}
|
||||
}, [isOpen, src]);
|
||||
}, [isOpen, src, getImageSize, resetZoom]);
|
||||
|
||||
// Ensure image is centered when zoom changes to 1
|
||||
useEffect(() => {
|
||||
if (zoom === 1) {
|
||||
setPanX(0);
|
||||
setPanY(0);
|
||||
}
|
||||
}, [zoom]);
|
||||
|
||||
// Reset pan when panel opens/closes to maintain centering
|
||||
useEffect(() => {
|
||||
if (zoom === 1) {
|
||||
setPanX(0);
|
||||
setPanY(0);
|
||||
}
|
||||
}, [isPromptOpen, zoom]);
|
||||
|
||||
return (
|
||||
<OGDialog open={isOpen} onOpenChange={onOpenChange}>
|
||||
|
|
@ -52,7 +189,7 @@ export default function DialogImage({ isOpen, onOpenChange, src = '', downloadIm
|
|||
overlayClassName="bg-surface-primary opacity-95 z-50"
|
||||
>
|
||||
<div
|
||||
className={`absolute left-0 top-0 z-10 flex items-center justify-between p-4 transition-all duration-500 ease-in-out ${isPromptOpen ? 'right-80' : 'right-0'}`}
|
||||
className={`ease-[cubic-bezier(0.175,0.885,0.32,1.275)] absolute left-0 top-0 z-10 flex items-center justify-between p-3 transition-all duration-500 sm:p-4 ${isPromptOpen ? 'right-0 sm:right-80' : 'right-0'}`}
|
||||
>
|
||||
<TooltipAnchor
|
||||
description={localize('com_ui_close')}
|
||||
|
|
@ -62,11 +199,21 @@ export default function DialogImage({ isOpen, onOpenChange, src = '', downloadIm
|
|||
variant="ghost"
|
||||
className="h-10 w-10 p-0 hover:bg-surface-hover"
|
||||
>
|
||||
<X className="size-6" />
|
||||
<X className="size-7 sm:size-6" />
|
||||
</Button>
|
||||
}
|
||||
/>
|
||||
<div className="flex items-center gap-2">
|
||||
<div className="flex items-center gap-1 sm:gap-2">
|
||||
{zoom > 1 && (
|
||||
<TooltipAnchor
|
||||
description={localize('com_ui_reset_zoom')}
|
||||
render={
|
||||
<Button onClick={resetZoom} variant="ghost" className="h-10 w-10 p-0">
|
||||
<RotateCcw className="size-6" />
|
||||
</Button>
|
||||
}
|
||||
/>
|
||||
)}
|
||||
<TooltipAnchor
|
||||
description={localize('com_ui_download')}
|
||||
render={
|
||||
|
|
@ -88,9 +235,9 @@ export default function DialogImage({ isOpen, onOpenChange, src = '', downloadIm
|
|||
className="h-10 w-10 p-0"
|
||||
>
|
||||
{isPromptOpen ? (
|
||||
<PanelLeftOpen className="size-6" />
|
||||
<PanelLeftOpen className="size-7 sm:size-6" />
|
||||
) : (
|
||||
<PanelLeftClose className="size-6" />
|
||||
<PanelLeftClose className="size-7 sm:size-6" />
|
||||
)}
|
||||
</Button>
|
||||
}
|
||||
|
|
@ -100,36 +247,81 @@ export default function DialogImage({ isOpen, onOpenChange, src = '', downloadIm
|
|||
|
||||
{/* Main content area with image */}
|
||||
<div
|
||||
className={`flex h-full transition-all duration-500 ease-in-out ${isPromptOpen ? 'mr-80' : 'mr-0'}`}
|
||||
className={`ease-[cubic-bezier(0.175,0.885,0.32,1.275)] flex h-full transition-all duration-500 ${isPromptOpen ? 'mr-0 sm:mr-80' : 'mr-0'}`}
|
||||
>
|
||||
<div className="flex flex-1 items-center justify-center px-4 pb-4 pt-20">
|
||||
<img
|
||||
src={src}
|
||||
alt="Image"
|
||||
className="max-h-full max-w-full object-contain"
|
||||
<div
|
||||
ref={containerRef}
|
||||
className="flex flex-1 items-center justify-center px-2 pb-4 pt-16 sm:px-4 sm:pt-20"
|
||||
onWheel={handleWheel}
|
||||
onMouseDown={handleMouseDown}
|
||||
onMouseMove={handleMouseMove}
|
||||
onMouseUp={handleMouseUp}
|
||||
onMouseLeave={handleMouseUp}
|
||||
onDoubleClick={handleDoubleClick}
|
||||
style={{
|
||||
cursor: getCursor(),
|
||||
overflow: zoom > 1 ? 'hidden' : 'visible',
|
||||
minHeight: 0, // Allow flexbox to shrink
|
||||
}}
|
||||
>
|
||||
<div
|
||||
className="flex items-center justify-center transition-transform duration-100 ease-out"
|
||||
style={{
|
||||
maxHeight: 'calc(100vh - 6rem)',
|
||||
maxWidth: '100%',
|
||||
transform: `translate(${panX}px, ${panY}px) scale(${zoom})`,
|
||||
transformOrigin: 'center center',
|
||||
width: '100%',
|
||||
height: '100%',
|
||||
display: 'flex',
|
||||
alignItems: 'center',
|
||||
justifyContent: 'center',
|
||||
}}
|
||||
/>
|
||||
>
|
||||
<img
|
||||
src={src}
|
||||
alt="Image"
|
||||
className="block object-contain"
|
||||
style={{
|
||||
maxHeight: 'calc(100vh - 8rem)',
|
||||
maxWidth: getImageMaxWidth(),
|
||||
width: 'auto',
|
||||
height: 'auto',
|
||||
}}
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{/* Side Panel */}
|
||||
<div
|
||||
className={`shadow-l-lg fixed right-0 top-0 z-20 h-full w-80 transform rounded-l-2xl border-l border-border-light bg-surface-primary transition-transform duration-500 ease-in-out ${
|
||||
className={`sm:shadow-l-lg ease-[cubic-bezier(0.175,0.885,0.32,1.275)] fixed right-0 top-0 z-20 h-full w-full transform border-l border-border-light bg-surface-primary shadow-2xl backdrop-blur-sm transition-transform duration-500 sm:w-80 sm:rounded-l-2xl ${
|
||||
isPromptOpen ? 'translate-x-0' : 'translate-x-full'
|
||||
}`}
|
||||
>
|
||||
<div className="h-full overflow-y-auto p-6">
|
||||
<div className="mb-4">
|
||||
{/* Mobile pull handle - removed for cleaner look */}
|
||||
|
||||
<div className="h-full overflow-y-auto p-4 sm:p-6">
|
||||
{/* Mobile close button */}
|
||||
<div className="mb-4 flex items-center justify-between sm:hidden">
|
||||
<h3 className="text-lg font-semibold text-text-primary">
|
||||
{localize('com_ui_image_details')}
|
||||
</h3>
|
||||
<Button
|
||||
onClick={() => setIsPromptOpen(false)}
|
||||
variant="ghost"
|
||||
className="h-12 w-12 p-0"
|
||||
>
|
||||
<X className="size-6" />
|
||||
</Button>
|
||||
</div>
|
||||
|
||||
<div className="mb-4 hidden sm:block">
|
||||
<h3 className="mb-2 text-lg font-semibold text-text-primary">
|
||||
{localize('com_ui_image_details')}
|
||||
</h3>
|
||||
<div className="mb-4 h-px bg-border-medium"></div>
|
||||
</div>
|
||||
|
||||
<div className="space-y-6">
|
||||
<div className="space-y-4 sm:space-y-6">
|
||||
{/* Prompt Section */}
|
||||
<div>
|
||||
<h4 className="mb-2 text-sm font-medium text-text-primary">
|
||||
|
|
@ -157,13 +349,7 @@ export default function DialogImage({ isOpen, onOpenChange, src = '', downloadIm
|
|||
<div className="flex items-center justify-between">
|
||||
<span className="text-sm text-text-primary">{localize('com_ui_quality')}:</span>
|
||||
<span
|
||||
className={`rounded px-2 py-1 text-xs font-medium capitalize ${
|
||||
args?.quality === 'high'
|
||||
? 'bg-green-100 text-green-800'
|
||||
: args?.quality === 'low'
|
||||
? 'bg-orange-100 text-orange-800'
|
||||
: 'bg-gray-100 text-gray-800'
|
||||
}`}
|
||||
className={`rounded px-2 py-1 text-xs font-medium capitalize ${getQualityStyles(args?.quality || '')}`}
|
||||
>
|
||||
{args?.quality || 'Standard'}
|
||||
</span>
|
||||
|
|
|
|||
|
|
@ -1,8 +1,9 @@
|
|||
import { useRef, useEffect, useCallback, useMemo } from 'react';
|
||||
import { useForm } from 'react-hook-form';
|
||||
import { ContentTypes } from 'librechat-data-provider';
|
||||
import { useRecoilState, useRecoilValue } from 'recoil';
|
||||
import { useRef, useEffect, useCallback, useMemo } from 'react';
|
||||
import { useUpdateMessageContentMutation } from 'librechat-data-provider/react-query';
|
||||
import type { Agents } from 'librechat-data-provider';
|
||||
import type { TEditProps } from '~/common';
|
||||
import Container from '~/components/Chat/Messages/Content/Container';
|
||||
import { useChatContext, useAddedChatContext } from '~/Providers';
|
||||
|
|
@ -12,18 +13,19 @@ import { useLocalize } from '~/hooks';
|
|||
import store from '~/store';
|
||||
|
||||
const EditTextPart = ({
|
||||
text,
|
||||
part,
|
||||
index,
|
||||
messageId,
|
||||
isSubmitting,
|
||||
enterEdit,
|
||||
}: Omit<TEditProps, 'message' | 'ask'> & {
|
||||
}: Omit<TEditProps, 'message' | 'ask' | 'text'> & {
|
||||
index: number;
|
||||
messageId: string;
|
||||
part: Agents.MessageContentText | Agents.ReasoningDeltaUpdate;
|
||||
}) => {
|
||||
const localize = useLocalize();
|
||||
const { addedIndex } = useAddedChatContext();
|
||||
const { getMessages, setMessages, conversation } = useChatContext();
|
||||
const { ask, getMessages, setMessages, conversation } = useChatContext();
|
||||
const [latestMultiMessage, setLatestMultiMessage] = useRecoilState(
|
||||
store.latestMessageFamily(addedIndex),
|
||||
);
|
||||
|
|
@ -34,15 +36,16 @@ const EditTextPart = ({
|
|||
[getMessages, messageId],
|
||||
);
|
||||
|
||||
const chatDirection = useRecoilValue(store.chatDirection);
|
||||
|
||||
const textAreaRef = useRef<HTMLTextAreaElement | null>(null);
|
||||
const updateMessageContentMutation = useUpdateMessageContentMutation(conversationId ?? '');
|
||||
|
||||
const chatDirection = useRecoilValue(store.chatDirection).toLowerCase();
|
||||
const isRTL = chatDirection === 'rtl';
|
||||
const isRTL = chatDirection?.toLowerCase() === 'rtl';
|
||||
|
||||
const { register, handleSubmit, setValue } = useForm({
|
||||
defaultValues: {
|
||||
text: text ?? '',
|
||||
text: (ContentTypes.THINK in part ? part.think : part.text) || '',
|
||||
},
|
||||
});
|
||||
|
||||
|
|
@ -55,15 +58,7 @@ const EditTextPart = ({
|
|||
}
|
||||
}, []);
|
||||
|
||||
/*
|
||||
const resubmitMessage = () => {
|
||||
showToast({
|
||||
status: 'warning',
|
||||
message: localize('com_warning_resubmit_unsupported'),
|
||||
});
|
||||
|
||||
// const resubmitMessage = (data: { text: string }) => {
|
||||
// Not supported by AWS Bedrock
|
||||
const resubmitMessage = (data: { text: string }) => {
|
||||
const messages = getMessages();
|
||||
const parentMessage = messages?.find((msg) => msg.messageId === message?.parentMessageId);
|
||||
|
||||
|
|
@ -73,17 +68,19 @@ const EditTextPart = ({
|
|||
ask(
|
||||
{ ...parentMessage },
|
||||
{
|
||||
editedText: data.text,
|
||||
editedContent: {
|
||||
index,
|
||||
text: data.text,
|
||||
type: part.type,
|
||||
},
|
||||
editedMessageId: messageId,
|
||||
isRegenerate: true,
|
||||
isEdited: true,
|
||||
},
|
||||
);
|
||||
|
||||
setSiblingIdx((siblingIdx ?? 0) - 1);
|
||||
enterEdit(true);
|
||||
};
|
||||
*/
|
||||
|
||||
const updateMessage = (data: { text: string }) => {
|
||||
const messages = getMessages();
|
||||
|
|
@ -167,13 +164,13 @@ const EditTextPart = ({
|
|||
/>
|
||||
</div>
|
||||
<div className="mt-2 flex w-full justify-center text-center">
|
||||
{/* <button
|
||||
<button
|
||||
className="btn btn-primary relative mr-2"
|
||||
disabled={isSubmitting}
|
||||
onClick={handleSubmit(resubmitMessage)}
|
||||
>
|
||||
{localize('com_ui_save_submit')}
|
||||
</button> */}
|
||||
</button>
|
||||
<button
|
||||
className="btn btn-secondary relative mr-2"
|
||||
disabled={isSubmitting}
|
||||
|
|
|
|||
|
|
@ -233,9 +233,17 @@ export default function Fork({
|
|||
status: 'info',
|
||||
});
|
||||
},
|
||||
onError: () => {
|
||||
onError: (error) => {
|
||||
/** Rate limit error (429 status code) */
|
||||
const isRateLimitError =
|
||||
(error as any)?.response?.status === 429 ||
|
||||
(error as any)?.status === 429 ||
|
||||
(error as any)?.statusCode === 429;
|
||||
|
||||
showToast({
|
||||
message: localize('com_ui_fork_error'),
|
||||
message: isRateLimitError
|
||||
? localize('com_ui_fork_error_rate_limit')
|
||||
: localize('com_ui_fork_error'),
|
||||
status: 'error',
|
||||
});
|
||||
},
|
||||
|
|
|
|||
|
|
@ -62,6 +62,7 @@ const errorMessages = {
|
|||
const { info } = json;
|
||||
return info;
|
||||
},
|
||||
[ErrorTypes.GOOGLE_TOOL_CONFLICT]: 'com_error_google_tool_conflict',
|
||||
[ViolationTypes.BAN]:
|
||||
'Your account has been temporarily banned due to violations of our service.',
|
||||
invalid_api_key:
|
||||
|
|
|
|||
|
|
@ -17,7 +17,6 @@ import {
|
|||
General,
|
||||
Chat,
|
||||
Speech,
|
||||
Beta,
|
||||
Commands,
|
||||
Data,
|
||||
Account,
|
||||
|
|
@ -233,9 +232,6 @@ export default function Settings({ open, onOpenChange }: TDialogProps) {
|
|||
<Tabs.Content value={SettingsTabValues.CHAT}>
|
||||
<Chat />
|
||||
</Tabs.Content>
|
||||
<Tabs.Content value={SettingsTabValues.BETA}>
|
||||
<Beta />
|
||||
</Tabs.Content>
|
||||
<Tabs.Content value={SettingsTabValues.COMMANDS}>
|
||||
<Commands />
|
||||
</Tabs.Content>
|
||||
|
|
|
|||
|
|
@ -1,18 +0,0 @@
|
|||
import { memo } from 'react';
|
||||
import CodeArtifacts from './CodeArtifacts';
|
||||
import ChatBadges from './ChatBadges';
|
||||
|
||||
function Beta() {
|
||||
return (
|
||||
<div className="flex flex-col gap-3 p-1 text-sm text-text-primary">
|
||||
<div className="pb-3">
|
||||
<CodeArtifacts />
|
||||
</div>
|
||||
{/* <div className="pb-3">
|
||||
<ChatBadges />
|
||||
</div> */}
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
export default memo(Beta);
|
||||
|
|
@ -1,22 +0,0 @@
|
|||
import { useSetRecoilState } from 'recoil';
|
||||
import { Button } from '~/components/ui';
|
||||
import { useLocalize } from '~/hooks';
|
||||
import store from '~/store';
|
||||
|
||||
export default function ChatBadges() {
|
||||
const setIsEditing = useSetRecoilState<boolean>(store.isEditingBadges);
|
||||
const localize = useLocalize();
|
||||
|
||||
const handleEditChatBadges = () => {
|
||||
setIsEditing(true);
|
||||
};
|
||||
|
||||
return (
|
||||
<div className="flex items-center justify-between">
|
||||
<div>{localize('com_nav_edit_chat_badges')}</div>
|
||||
<Button variant="outline" onClick={handleEditChatBadges}>
|
||||
{localize('com_ui_edit')}
|
||||
</Button>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
|
@ -1,95 +0,0 @@
|
|||
import { useRecoilState } from 'recoil';
|
||||
import HoverCardSettings from '~/components/Nav/SettingsTabs/HoverCardSettings';
|
||||
import { Switch } from '~/components/ui';
|
||||
import { useLocalize } from '~/hooks';
|
||||
import store from '~/store';
|
||||
|
||||
export default function CodeArtifacts() {
|
||||
const [codeArtifacts, setCodeArtifacts] = useRecoilState<boolean>(store.codeArtifacts);
|
||||
const [includeShadcnui, setIncludeShadcnui] = useRecoilState<boolean>(store.includeShadcnui);
|
||||
const [customPromptMode, setCustomPromptMode] = useRecoilState<boolean>(store.customPromptMode);
|
||||
const localize = useLocalize();
|
||||
|
||||
const handleCodeArtifactsChange = (value: boolean) => {
|
||||
setCodeArtifacts(value);
|
||||
if (!value) {
|
||||
setIncludeShadcnui(false);
|
||||
setCustomPromptMode(false);
|
||||
}
|
||||
};
|
||||
|
||||
const handleIncludeShadcnuiChange = (value: boolean) => {
|
||||
setIncludeShadcnui(value);
|
||||
};
|
||||
|
||||
const handleCustomPromptModeChange = (value: boolean) => {
|
||||
setCustomPromptMode(value);
|
||||
if (value) {
|
||||
setIncludeShadcnui(false);
|
||||
}
|
||||
};
|
||||
|
||||
return (
|
||||
<div className="space-y-4">
|
||||
<h3 className="text-lg font-medium">{localize('com_ui_artifacts')}</h3>
|
||||
<div className="space-y-2">
|
||||
<SwitchItem
|
||||
id="codeArtifacts"
|
||||
label={localize('com_ui_artifacts_toggle')}
|
||||
checked={codeArtifacts}
|
||||
onCheckedChange={handleCodeArtifactsChange}
|
||||
hoverCardText="com_nav_info_code_artifacts"
|
||||
/>
|
||||
<SwitchItem
|
||||
id="includeShadcnui"
|
||||
label={localize('com_ui_include_shadcnui')}
|
||||
checked={includeShadcnui}
|
||||
onCheckedChange={handleIncludeShadcnuiChange}
|
||||
hoverCardText="com_nav_info_include_shadcnui"
|
||||
disabled={!codeArtifacts || customPromptMode}
|
||||
/>
|
||||
<SwitchItem
|
||||
id="customPromptMode"
|
||||
label={localize('com_ui_custom_prompt_mode')}
|
||||
checked={customPromptMode}
|
||||
onCheckedChange={handleCustomPromptModeChange}
|
||||
hoverCardText="com_nav_info_custom_prompt_mode"
|
||||
disabled={!codeArtifacts}
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
function SwitchItem({
|
||||
id,
|
||||
label,
|
||||
checked,
|
||||
onCheckedChange,
|
||||
hoverCardText,
|
||||
disabled = false,
|
||||
}: {
|
||||
id: string;
|
||||
label: string;
|
||||
checked: boolean;
|
||||
onCheckedChange: (value: boolean) => void;
|
||||
hoverCardText: string;
|
||||
disabled?: boolean;
|
||||
}) {
|
||||
return (
|
||||
<div className="flex items-center justify-between">
|
||||
<div className="flex items-center space-x-2">
|
||||
<div className={disabled ? 'text-gray-400' : ''}>{label}</div>
|
||||
<HoverCardSettings side="bottom" text={hoverCardText} />
|
||||
</div>
|
||||
<Switch
|
||||
id={id}
|
||||
checked={checked}
|
||||
onCheckedChange={onCheckedChange}
|
||||
className="ml-4"
|
||||
data-testid={id}
|
||||
disabled={disabled}
|
||||
/>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
|
@ -86,6 +86,7 @@ export const LangSelector = ({
|
|||
{ value: 'fr-FR', label: localize('com_nav_lang_french') },
|
||||
{ value: 'he-HE', label: localize('com_nav_lang_hebrew') },
|
||||
{ value: 'hu-HU', label: localize('com_nav_lang_hungarian') },
|
||||
{ value: 'hy-AM', label: localize('com_nav_lang_armenian') },
|
||||
{ value: 'it-IT', label: localize('com_nav_lang_italian') },
|
||||
{ value: 'pl-PL', label: localize('com_nav_lang_polish') },
|
||||
{ value: 'pt-BR', label: localize('com_nav_lang_brazilian_portuguese') },
|
||||
|
|
@ -96,9 +97,11 @@ export const LangSelector = ({
|
|||
{ value: 'cs-CZ', label: localize('com_nav_lang_czech') },
|
||||
{ value: 'sv-SE', label: localize('com_nav_lang_swedish') },
|
||||
{ value: 'ko-KR', label: localize('com_nav_lang_korean') },
|
||||
{ value: 'lv-LV', label: localize('com_nav_lang_latvian') },
|
||||
{ value: 'vi-VN', label: localize('com_nav_lang_vietnamese') },
|
||||
{ value: 'th-TH', label: localize('com_nav_lang_thai') },
|
||||
{ value: 'tr-TR', label: localize('com_nav_lang_turkish') },
|
||||
{ value: 'ug', label: localize('com_nav_lang_uyghur') },
|
||||
{ value: 'nl-NL', label: localize('com_nav_lang_dutch') },
|
||||
{ value: 'id-ID', label: localize('com_nav_lang_indonesia') },
|
||||
{ value: 'fi-FI', label: localize('com_nav_lang_finnish') },
|
||||
|
|
|
|||
|
|
@ -1,7 +1,6 @@
|
|||
export { default as General } from './General/General';
|
||||
export { default as Chat } from './Chat/Chat';
|
||||
export { default as Data } from './Data/Data';
|
||||
export { default as Beta } from './Beta/Beta';
|
||||
export { default as Commands } from './Commands/Commands';
|
||||
export { RevokeKeysButton } from './Data/RevokeKeysButton';
|
||||
export { default as Account } from './Account/Account';
|
||||
|
|
|
|||
|
|
@ -2,20 +2,20 @@ import { useMemo } from 'react';
|
|||
import { ChevronLeft } from 'lucide-react';
|
||||
import { AgentCapabilities } from 'librechat-data-provider';
|
||||
import { useFormContext, Controller } from 'react-hook-form';
|
||||
import type { AgentForm, AgentPanelProps } from '~/common';
|
||||
import type { AgentForm } from '~/common';
|
||||
import { useAgentPanelContext } from '~/Providers';
|
||||
import MaxAgentSteps from './MaxAgentSteps';
|
||||
import AgentChain from './AgentChain';
|
||||
import { useLocalize } from '~/hooks';
|
||||
import AgentChain from './AgentChain';
|
||||
import { Panel } from '~/common';
|
||||
|
||||
export default function AdvancedPanel({
|
||||
agentsConfig,
|
||||
setActivePanel,
|
||||
}: Pick<AgentPanelProps, 'setActivePanel' | 'agentsConfig'>) {
|
||||
export default function AdvancedPanel() {
|
||||
const localize = useLocalize();
|
||||
const methods = useFormContext<AgentForm>();
|
||||
const { control, watch } = methods;
|
||||
const currentAgentId = watch('id');
|
||||
|
||||
const { agentsConfig, setActivePanel } = useAgentPanelContext();
|
||||
const chainEnabled = useMemo(
|
||||
() => agentsConfig?.capabilities.includes(AgentCapabilities.chain) ?? false,
|
||||
[agentsConfig],
|
||||
|
|
|
|||
|
|
@ -1,9 +1,10 @@
|
|||
import React, { useState, useMemo, useCallback } from 'react';
|
||||
import { EModelEndpoint } from 'librechat-data-provider';
|
||||
import { Controller, useWatch, useFormContext } from 'react-hook-form';
|
||||
import { EModelEndpoint, AgentCapabilities } from 'librechat-data-provider';
|
||||
import type { AgentForm, AgentPanelProps, IconComponentTypes } from '~/common';
|
||||
import { cn, defaultTextProps, removeFocusOutlines, getEndpointField, getIconKey } from '~/utils';
|
||||
import { useToastContext, useFileMapContext, useAgentPanelContext } from '~/Providers';
|
||||
import useAgentCapabilities from '~/hooks/Agents/useAgentCapabilities';
|
||||
import Action from '~/components/SidePanel/Builder/Action';
|
||||
import { ToolSelectDialog } from '~/components/Tools';
|
||||
import { icons } from '~/hooks/Endpoint/Icons';
|
||||
|
|
@ -26,17 +27,20 @@ const inputClass = cn(
|
|||
removeFocusOutlines,
|
||||
);
|
||||
|
||||
export default function AgentConfig({
|
||||
agentsConfig,
|
||||
createMutation,
|
||||
endpointsConfig,
|
||||
}: Pick<AgentPanelProps, 'agentsConfig' | 'createMutation' | 'endpointsConfig'>) {
|
||||
export default function AgentConfig({ createMutation }: Pick<AgentPanelProps, 'createMutation'>) {
|
||||
const localize = useLocalize();
|
||||
const fileMap = useFileMapContext();
|
||||
const { showToast } = useToastContext();
|
||||
const methods = useFormContext<AgentForm>();
|
||||
const [showToolDialog, setShowToolDialog] = useState(false);
|
||||
const { actions, setAction, groupedTools: allTools, setActivePanel } = useAgentPanelContext();
|
||||
const {
|
||||
actions,
|
||||
setAction,
|
||||
agentsConfig,
|
||||
setActivePanel,
|
||||
endpointsConfig,
|
||||
groupedTools: allTools,
|
||||
} = useAgentPanelContext();
|
||||
|
||||
const { control } = methods;
|
||||
const provider = useWatch({ control, name: 'provider' });
|
||||
|
|
@ -45,34 +49,15 @@ export default function AgentConfig({
|
|||
const tools = useWatch({ control, name: 'tools' });
|
||||
const agent_id = useWatch({ control, name: 'id' });
|
||||
|
||||
const toolsEnabled = useMemo(
|
||||
() => agentsConfig?.capabilities?.includes(AgentCapabilities.tools) ?? false,
|
||||
[agentsConfig],
|
||||
);
|
||||
const actionsEnabled = useMemo(
|
||||
() => agentsConfig?.capabilities?.includes(AgentCapabilities.actions) ?? false,
|
||||
[agentsConfig],
|
||||
);
|
||||
const artifactsEnabled = useMemo(
|
||||
() => agentsConfig?.capabilities?.includes(AgentCapabilities.artifacts) ?? false,
|
||||
[agentsConfig],
|
||||
);
|
||||
const ocrEnabled = useMemo(
|
||||
() => agentsConfig?.capabilities?.includes(AgentCapabilities.ocr) ?? false,
|
||||
[agentsConfig],
|
||||
);
|
||||
const fileSearchEnabled = useMemo(
|
||||
() => agentsConfig?.capabilities?.includes(AgentCapabilities.file_search) ?? false,
|
||||
[agentsConfig],
|
||||
);
|
||||
const webSearchEnabled = useMemo(
|
||||
() => agentsConfig?.capabilities?.includes(AgentCapabilities.web_search) ?? false,
|
||||
[agentsConfig],
|
||||
);
|
||||
const codeEnabled = useMemo(
|
||||
() => agentsConfig?.capabilities?.includes(AgentCapabilities.execute_code) ?? false,
|
||||
[agentsConfig],
|
||||
);
|
||||
const {
|
||||
ocrEnabled,
|
||||
codeEnabled,
|
||||
toolsEnabled,
|
||||
actionsEnabled,
|
||||
artifactsEnabled,
|
||||
webSearchEnabled,
|
||||
fileSearchEnabled,
|
||||
} = useAgentCapabilities(agentsConfig?.capabilities);
|
||||
|
||||
const context_files = useMemo(() => {
|
||||
if (typeof agent === 'string') {
|
||||
|
|
@ -168,7 +153,7 @@ export default function AgentConfig({
|
|||
const visibleToolIds = new Set(selectedToolIds);
|
||||
|
||||
// Check what group parent tools should be shown if any subtool is present
|
||||
Object.entries(allTools).forEach(([toolId, toolObj]) => {
|
||||
Object.entries(allTools ?? {}).forEach(([toolId, toolObj]) => {
|
||||
if (toolObj.tools?.length) {
|
||||
// if any subtool of this group is selected, ensure group parent tool rendered
|
||||
if (toolObj.tools.some((st) => selectedToolIds.includes(st.tool_id))) {
|
||||
|
|
@ -299,6 +284,7 @@ export default function AgentConfig({
|
|||
<div className="mb-1">
|
||||
{/* // Render all visible IDs (including groups with subtools selected) */}
|
||||
{[...visibleToolIds].map((toolId, i) => {
|
||||
if (!allTools) return null;
|
||||
const tool = allTools[toolId];
|
||||
if (!tool) return null;
|
||||
return (
|
||||
|
|
|
|||
|
|
@ -7,8 +7,6 @@ import {
|
|||
Constants,
|
||||
SystemRoles,
|
||||
EModelEndpoint,
|
||||
TAgentsEndpoint,
|
||||
TEndpointsConfig,
|
||||
isAssistantsEndpoint,
|
||||
} from 'librechat-data-provider';
|
||||
import type { AgentForm, StringOption } from '~/common';
|
||||
|
|
@ -30,19 +28,15 @@ import { Button } from '~/components';
|
|||
import ModelPanel from './ModelPanel';
|
||||
import { Panel } from '~/common';
|
||||
|
||||
export default function AgentPanel({
|
||||
agentsConfig,
|
||||
endpointsConfig,
|
||||
}: {
|
||||
agentsConfig: TAgentsEndpoint | null;
|
||||
endpointsConfig: TEndpointsConfig;
|
||||
}) {
|
||||
export default function AgentPanel() {
|
||||
const localize = useLocalize();
|
||||
const { user } = useAuthContext();
|
||||
const { showToast } = useToastContext();
|
||||
const {
|
||||
activePanel,
|
||||
agentsConfig,
|
||||
setActivePanel,
|
||||
endpointsConfig,
|
||||
setCurrentAgentId,
|
||||
agent_id: current_agent_id,
|
||||
} = useAgentPanelContext();
|
||||
|
|
@ -323,14 +317,10 @@ export default function AgentPanel({
|
|||
<ModelPanel models={models} providers={providers} setActivePanel={setActivePanel} />
|
||||
)}
|
||||
{canEditAgent && !agentQuery.isInitialLoading && activePanel === Panel.builder && (
|
||||
<AgentConfig
|
||||
createMutation={create}
|
||||
agentsConfig={agentsConfig}
|
||||
endpointsConfig={endpointsConfig}
|
||||
/>
|
||||
<AgentConfig createMutation={create} />
|
||||
)}
|
||||
{canEditAgent && !agentQuery.isInitialLoading && activePanel === Panel.advanced && (
|
||||
<AdvancedPanel setActivePanel={setActivePanel} agentsConfig={agentsConfig} />
|
||||
<AdvancedPanel />
|
||||
)}
|
||||
{canEditAgent && !agentQuery.isInitialLoading && (
|
||||
<AgentFooter
|
||||
|
|
|
|||
|
|
@ -1,8 +1,5 @@
|
|||
import { useEffect, useMemo } from 'react';
|
||||
import { EModelEndpoint, AgentCapabilities } from 'librechat-data-provider';
|
||||
import type { TConfig, TEndpointsConfig, TAgentsEndpoint } from 'librechat-data-provider';
|
||||
import { useEffect } from 'react';
|
||||
import { AgentPanelProvider, useAgentPanelContext } from '~/Providers/AgentPanelContext';
|
||||
import { useGetEndpointsQuery } from '~/data-provider';
|
||||
import VersionPanel from './Version/VersionPanel';
|
||||
import { useChatContext } from '~/Providers';
|
||||
import ActionsPanel from './ActionsPanel';
|
||||
|
|
@ -22,21 +19,6 @@ function AgentPanelSwitchWithContext() {
|
|||
const { conversation } = useChatContext();
|
||||
const { activePanel, setCurrentAgentId } = useAgentPanelContext();
|
||||
|
||||
// TODO: Implement MCP endpoint
|
||||
const { data: endpointsConfig = {} as TEndpointsConfig } = useGetEndpointsQuery();
|
||||
|
||||
const agentsConfig = useMemo<TAgentsEndpoint | null>(() => {
|
||||
const config = endpointsConfig?.[EModelEndpoint.agents] ?? null;
|
||||
if (!config) return null;
|
||||
|
||||
return {
|
||||
...(config as TConfig),
|
||||
capabilities: Array.isArray(config.capabilities)
|
||||
? config.capabilities.map((cap) => cap as unknown as AgentCapabilities)
|
||||
: ([] as AgentCapabilities[]),
|
||||
} as TAgentsEndpoint;
|
||||
}, [endpointsConfig]);
|
||||
|
||||
useEffect(() => {
|
||||
const agent_id = conversation?.agent_id ?? '';
|
||||
if (agent_id) {
|
||||
|
|
@ -57,5 +39,5 @@ function AgentPanelSwitchWithContext() {
|
|||
if (activePanel === Panel.mcp) {
|
||||
return <MCPPanel />;
|
||||
}
|
||||
return <AgentPanel agentsConfig={agentsConfig} endpointsConfig={endpointsConfig} />;
|
||||
return <AgentPanel />;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -19,7 +19,7 @@ export default function AgentTool({
|
|||
allTools,
|
||||
}: {
|
||||
tool: string;
|
||||
allTools: Record<string, AgentToolType & { tools?: AgentToolType[] }>;
|
||||
allTools?: Record<string, AgentToolType & { tools?: AgentToolType[] }>;
|
||||
agent_id?: string;
|
||||
}) {
|
||||
const [isHovering, setIsHovering] = useState(false);
|
||||
|
|
@ -30,8 +30,10 @@ export default function AgentTool({
|
|||
const { showToast } = useToastContext();
|
||||
const updateUserPlugins = useUpdateUserPluginsMutation();
|
||||
const { getValues, setValue } = useFormContext<AgentForm>();
|
||||
if (!allTools) {
|
||||
return null;
|
||||
}
|
||||
const currentTool = allTools[tool];
|
||||
|
||||
const getSelectedTools = () => {
|
||||
if (!currentTool?.tools) return [];
|
||||
const formTools = getValues('tools') || [];
|
||||
|
|
@ -224,7 +226,7 @@ export default function AgentTool({
|
|||
}}
|
||||
className={cn(
|
||||
'h-4 w-4 rounded border border-gray-300 transition-all duration-200 hover:border-gray-400 dark:border-gray-600 dark:hover:border-gray-500',
|
||||
isExpanded ? 'opacity-100' : 'opacity-0',
|
||||
isExpanded ? 'visible' : 'pointer-events-none invisible',
|
||||
)}
|
||||
onClick={(e) => e.stopPropagation()}
|
||||
onKeyDown={(e) => {
|
||||
|
|
|
|||
|
|
@ -60,7 +60,7 @@ export default function Artifacts() {
|
|||
/>
|
||||
<SwitchItem
|
||||
id="includeShadcnui"
|
||||
label={localize('com_ui_include_shadcnui_agent')}
|
||||
label={localize('com_ui_include_shadcnui')}
|
||||
checked={isShadcnEnabled}
|
||||
onCheckedChange={handleShadcnuiChange}
|
||||
hoverCardText={localize('com_nav_info_include_shadcnui')}
|
||||
|
|
|
|||
|
|
@ -15,6 +15,7 @@ export default function ApiKeyDialog({
|
|||
register,
|
||||
handleSubmit,
|
||||
triggerRef,
|
||||
triggerRefs,
|
||||
}: {
|
||||
isOpen: boolean;
|
||||
onOpenChange: (open: boolean) => void;
|
||||
|
|
@ -24,7 +25,8 @@ export default function ApiKeyDialog({
|
|||
isToolAuthenticated: boolean;
|
||||
register: UseFormRegister<ApiKeyFormData>;
|
||||
handleSubmit: UseFormHandleSubmit<ApiKeyFormData>;
|
||||
triggerRef?: RefObject<HTMLInputElement>;
|
||||
triggerRef?: RefObject<HTMLInputElement | HTMLButtonElement>;
|
||||
triggerRefs?: RefObject<HTMLInputElement | HTMLButtonElement>[];
|
||||
}) {
|
||||
const localize = useLocalize();
|
||||
const languageIcons = [
|
||||
|
|
@ -41,7 +43,12 @@ export default function ApiKeyDialog({
|
|||
];
|
||||
|
||||
return (
|
||||
<OGDialog open={isOpen} onOpenChange={onOpenChange} triggerRef={triggerRef}>
|
||||
<OGDialog
|
||||
open={isOpen}
|
||||
onOpenChange={onOpenChange}
|
||||
triggerRef={triggerRef}
|
||||
triggerRefs={triggerRefs}
|
||||
>
|
||||
<OGDialogTemplate
|
||||
className="w-11/12 sm:w-[450px]"
|
||||
title=""
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
import { useState, useEffect } from 'react';
|
||||
import { useFormContext, Controller } from 'react-hook-form';
|
||||
import { MCP } from 'librechat-data-provider/dist/types/types/assistants';
|
||||
import type { MCP } from 'librechat-data-provider';
|
||||
import MCPAuth from '~/components/SidePanel/Builder/MCPAuth';
|
||||
import MCPIcon from '~/components/SidePanel/Agents/MCPIcon';
|
||||
import { Label, Checkbox } from '~/components/ui';
|
||||
|
|
|
|||
|
|
@ -1,13 +1,16 @@
|
|||
import { useState } from 'react';
|
||||
import { ChevronDown } from 'lucide-react';
|
||||
import * as Menu from '@ariakit/react/menu';
|
||||
import { AuthType, SearchCategories, RerankerTypes } from 'librechat-data-provider';
|
||||
import type { UseFormRegister, UseFormHandleSubmit } from 'react-hook-form';
|
||||
import {
|
||||
AuthType,
|
||||
SearchCategories,
|
||||
RerankerTypes,
|
||||
SearchProviders,
|
||||
ScraperTypes,
|
||||
} from 'librechat-data-provider';
|
||||
import type { SearchApiKeyFormData } from '~/hooks/Plugins/useAuthSearchTool';
|
||||
import type { MenuItemProps } from '~/common';
|
||||
import { Input, Button, OGDialog, Label } from '~/components/ui';
|
||||
import type { UseFormRegister, UseFormHandleSubmit } from 'react-hook-form';
|
||||
import InputSection, { type DropdownOption } from './InputSection';
|
||||
import OGDialogTemplate from '~/components/ui/OGDialogTemplate';
|
||||
import DropdownPopup from '~/components/ui/DropdownPopup';
|
||||
import { Button, OGDialog } from '~/components/ui';
|
||||
import { useGetStartupConfig } from '~/data-provider';
|
||||
import { useLocalize } from '~/hooks';
|
||||
|
||||
|
|
@ -21,6 +24,7 @@ export default function ApiKeyDialog({
|
|||
register,
|
||||
handleSubmit,
|
||||
triggerRef,
|
||||
triggerRefs,
|
||||
}: {
|
||||
isOpen: boolean;
|
||||
onOpenChange: (open: boolean) => void;
|
||||
|
|
@ -30,311 +34,188 @@ export default function ApiKeyDialog({
|
|||
isToolAuthenticated: boolean;
|
||||
register: UseFormRegister<SearchApiKeyFormData>;
|
||||
handleSubmit: UseFormHandleSubmit<SearchApiKeyFormData>;
|
||||
triggerRef?: React.RefObject<HTMLInputElement>;
|
||||
triggerRef?: React.RefObject<HTMLInputElement | HTMLButtonElement>;
|
||||
triggerRefs?: React.RefObject<HTMLInputElement | HTMLButtonElement>[];
|
||||
}) {
|
||||
const localize = useLocalize();
|
||||
const { data: config } = useGetStartupConfig();
|
||||
const [selectedReranker, setSelectedReranker] = useState<
|
||||
RerankerTypes.JINA | RerankerTypes.COHERE
|
||||
>(
|
||||
config?.webSearch?.rerankerType === RerankerTypes.COHERE
|
||||
? RerankerTypes.COHERE
|
||||
: RerankerTypes.JINA,
|
||||
|
||||
const [selectedProvider, setSelectedProvider] = useState(
|
||||
config?.webSearch?.searchProvider || SearchProviders.SERPER,
|
||||
);
|
||||
const [selectedReranker, setSelectedReranker] = useState(
|
||||
config?.webSearch?.rerankerType || RerankerTypes.JINA,
|
||||
);
|
||||
const [selectedScraper, setSelectedScraper] = useState(ScraperTypes.FIRECRAWL);
|
||||
|
||||
const [providerDropdownOpen, setProviderDropdownOpen] = useState(false);
|
||||
const [scraperDropdownOpen, setScraperDropdownOpen] = useState(false);
|
||||
const [rerankerDropdownOpen, setRerankerDropdownOpen] = useState(false);
|
||||
|
||||
const providerItems: MenuItemProps[] = [
|
||||
const providerOptions: DropdownOption[] = [
|
||||
{
|
||||
key: SearchProviders.SERPER,
|
||||
label: localize('com_ui_web_search_provider_serper'),
|
||||
onClick: () => {},
|
||||
inputs: {
|
||||
serperApiKey: {
|
||||
placeholder: localize('com_ui_enter_api_key'),
|
||||
type: 'password' as const,
|
||||
link: {
|
||||
url: 'https://serper.dev/api-keys',
|
||||
text: localize('com_ui_web_search_provider_serper_key'),
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
key: SearchProviders.SEARXNG,
|
||||
label: localize('com_ui_web_search_provider_searxng'),
|
||||
inputs: {
|
||||
searxngInstanceUrl: {
|
||||
placeholder: localize('com_ui_web_search_searxng_instance_url'),
|
||||
type: 'text' as const,
|
||||
},
|
||||
searxngApiKey: {
|
||||
placeholder: localize('com_ui_web_search_searxng_api_key'),
|
||||
type: 'password' as const,
|
||||
},
|
||||
},
|
||||
},
|
||||
];
|
||||
|
||||
const scraperItems: MenuItemProps[] = [
|
||||
{
|
||||
label: localize('com_ui_web_search_scraper_firecrawl'),
|
||||
onClick: () => {},
|
||||
},
|
||||
];
|
||||
|
||||
const rerankerItems: MenuItemProps[] = [
|
||||
const rerankerOptions: DropdownOption[] = [
|
||||
{
|
||||
key: RerankerTypes.JINA,
|
||||
label: localize('com_ui_web_search_reranker_jina'),
|
||||
onClick: () => setSelectedReranker(RerankerTypes.JINA),
|
||||
inputs: {
|
||||
jinaApiKey: {
|
||||
placeholder: localize('com_ui_web_search_jina_key'),
|
||||
type: 'password' as const,
|
||||
link: {
|
||||
url: 'https://jina.ai/api-dashboard/',
|
||||
text: localize('com_ui_web_search_reranker_jina_key'),
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
key: RerankerTypes.COHERE,
|
||||
label: localize('com_ui_web_search_reranker_cohere'),
|
||||
onClick: () => setSelectedReranker(RerankerTypes.COHERE),
|
||||
inputs: {
|
||||
cohereApiKey: {
|
||||
placeholder: localize('com_ui_web_search_cohere_key'),
|
||||
type: 'password' as const,
|
||||
link: {
|
||||
url: 'https://dashboard.cohere.com/welcome/login',
|
||||
text: localize('com_ui_web_search_reranker_cohere_key'),
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
];
|
||||
|
||||
const showProviderDropdown = !config?.webSearch?.searchProvider;
|
||||
const showScraperDropdown = !config?.webSearch?.scraperType;
|
||||
const showRerankerDropdown = !config?.webSearch?.rerankerType;
|
||||
const scraperOptions: DropdownOption[] = [
|
||||
{
|
||||
key: ScraperTypes.FIRECRAWL,
|
||||
label: localize('com_ui_web_search_scraper_firecrawl'),
|
||||
inputs: {
|
||||
firecrawlApiUrl: {
|
||||
placeholder: localize('com_ui_web_search_firecrawl_url'),
|
||||
type: 'text' as const,
|
||||
},
|
||||
firecrawlApiKey: {
|
||||
placeholder: localize('com_ui_enter_api_key'),
|
||||
type: 'password' as const,
|
||||
link: {
|
||||
url: 'https://docs.firecrawl.dev/introduction#api-key',
|
||||
text: localize('com_ui_web_search_scraper_firecrawl_key'),
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
];
|
||||
|
||||
const [dropdownOpen, setDropdownOpen] = useState({
|
||||
provider: false,
|
||||
reranker: false,
|
||||
scraper: false,
|
||||
});
|
||||
|
||||
// Determine which categories are SYSTEM_DEFINED
|
||||
const providerAuthType = authTypes.find(([cat]) => cat === SearchCategories.PROVIDERS)?.[1];
|
||||
const scraperAuthType = authTypes.find(([cat]) => cat === SearchCategories.SCRAPERS)?.[1];
|
||||
const rerankerAuthType = authTypes.find(([cat]) => cat === SearchCategories.RERANKERS)?.[1];
|
||||
|
||||
function renderRerankerInput() {
|
||||
if (config?.webSearch?.rerankerType === RerankerTypes.JINA) {
|
||||
return (
|
||||
<>
|
||||
<Input
|
||||
type="password"
|
||||
placeholder={localize('com_ui_web_search_jina_key')}
|
||||
autoComplete="one-time-code"
|
||||
readOnly={true}
|
||||
onFocus={(e) => (e.target.readOnly = false)}
|
||||
{...register('jinaApiKey')}
|
||||
/>
|
||||
<div className="mt-1 text-xs text-text-secondary">
|
||||
<a
|
||||
href="https://jina.ai/api-dashboard/"
|
||||
target="_blank"
|
||||
rel="noopener noreferrer"
|
||||
className="text-blue-500 hover:text-blue-600 dark:text-blue-400 dark:hover:text-blue-300"
|
||||
>
|
||||
{localize('com_ui_web_search_reranker_jina_key')}
|
||||
</a>
|
||||
</div>
|
||||
</>
|
||||
);
|
||||
}
|
||||
if (config?.webSearch?.rerankerType === RerankerTypes.COHERE) {
|
||||
return (
|
||||
<>
|
||||
<Input
|
||||
type="password"
|
||||
placeholder={localize('com_ui_web_search_cohere_key')}
|
||||
autoComplete="one-time-code"
|
||||
readOnly={true}
|
||||
onFocus={(e) => (e.target.readOnly = false)}
|
||||
{...register('cohereApiKey')}
|
||||
/>
|
||||
<div className="mt-1 text-xs text-text-secondary">
|
||||
<a
|
||||
href="https://dashboard.cohere.com/welcome/login"
|
||||
target="_blank"
|
||||
rel="noopener noreferrer"
|
||||
className="text-blue-500 hover:text-blue-600 dark:text-blue-400 dark:hover:text-blue-300"
|
||||
>
|
||||
{localize('com_ui_web_search_reranker_cohere_key')}
|
||||
</a>
|
||||
</div>
|
||||
</>
|
||||
);
|
||||
}
|
||||
if (!config?.webSearch?.rerankerType && selectedReranker === RerankerTypes.JINA) {
|
||||
return (
|
||||
<>
|
||||
<Input
|
||||
type="password"
|
||||
placeholder={localize('com_ui_web_search_jina_key')}
|
||||
autoComplete="one-time-code"
|
||||
readOnly={true}
|
||||
onFocus={(e) => (e.target.readOnly = false)}
|
||||
{...register('jinaApiKey')}
|
||||
/>
|
||||
<div className="mt-1 text-xs text-text-secondary">
|
||||
<a
|
||||
href="https://jina.ai/api-dashboard/"
|
||||
target="_blank"
|
||||
rel="noopener noreferrer"
|
||||
className="text-blue-500 hover:text-blue-600 dark:text-blue-400 dark:hover:text-blue-300"
|
||||
>
|
||||
{localize('com_ui_web_search_reranker_jina_key')}
|
||||
</a>
|
||||
</div>
|
||||
</>
|
||||
);
|
||||
}
|
||||
if (!config?.webSearch?.rerankerType && selectedReranker === RerankerTypes.COHERE) {
|
||||
return (
|
||||
<>
|
||||
<Input
|
||||
type="password"
|
||||
placeholder={localize('com_ui_web_search_cohere_key')}
|
||||
autoComplete="one-time-code"
|
||||
readOnly={true}
|
||||
onFocus={(e) => (e.target.readOnly = false)}
|
||||
{...register('cohereApiKey')}
|
||||
/>
|
||||
<div className="mt-1 text-xs text-text-secondary">
|
||||
<a
|
||||
href="https://dashboard.cohere.com/welcome/login"
|
||||
target="_blank"
|
||||
rel="noopener noreferrer"
|
||||
className="text-blue-500 hover:text-blue-600 dark:text-blue-400 dark:hover:text-blue-300"
|
||||
>
|
||||
{localize('com_ui_web_search_reranker_cohere_key')}
|
||||
</a>
|
||||
</div>
|
||||
</>
|
||||
);
|
||||
}
|
||||
return null;
|
||||
}
|
||||
const handleProviderChange = (key: string) => {
|
||||
setSelectedProvider(key as SearchProviders);
|
||||
};
|
||||
|
||||
const handleRerankerChange = (key: string) => {
|
||||
setSelectedReranker(key as RerankerTypes);
|
||||
};
|
||||
|
||||
const handleScraperChange = (key: string) => {
|
||||
setSelectedScraper(key as ScraperTypes);
|
||||
};
|
||||
|
||||
return (
|
||||
<OGDialog open={isOpen} onOpenChange={onOpenChange} triggerRef={triggerRef}>
|
||||
<OGDialog
|
||||
open={isOpen}
|
||||
onOpenChange={onOpenChange}
|
||||
triggerRef={triggerRef}
|
||||
triggerRefs={triggerRefs}
|
||||
>
|
||||
<OGDialogTemplate
|
||||
className="w-11/12 sm:w-[500px]"
|
||||
title=""
|
||||
main={
|
||||
<>
|
||||
<div className="mb-4 text-center font-medium">{localize('com_ui_web_search')}</div>
|
||||
<div className="mb-4 text-center text-sm">
|
||||
{localize('com_ui_web_search_api_subtitle')}
|
||||
</div>
|
||||
<form onSubmit={handleSubmit(onSubmit)}>
|
||||
{/* Search Provider Section */}
|
||||
{/* Provider Section */}
|
||||
{providerAuthType !== AuthType.SYSTEM_DEFINED && (
|
||||
<div className="mb-6">
|
||||
<div className="mb-2 flex items-center justify-between">
|
||||
<Label className="text-md w-fit font-medium">
|
||||
{localize('com_ui_web_search_provider')}
|
||||
</Label>
|
||||
{showProviderDropdown ? (
|
||||
<DropdownPopup
|
||||
menuId="search-provider-dropdown"
|
||||
items={providerItems}
|
||||
isOpen={providerDropdownOpen}
|
||||
setIsOpen={setProviderDropdownOpen}
|
||||
trigger={
|
||||
<Menu.MenuButton
|
||||
onClick={() => setProviderDropdownOpen(!providerDropdownOpen)}
|
||||
className="flex items-center rounded-md border border-border-light px-3 py-1 text-sm text-text-secondary"
|
||||
>
|
||||
{localize('com_ui_web_search_provider_serper')}
|
||||
<ChevronDown className="ml-1 h-4 w-4" />
|
||||
</Menu.MenuButton>
|
||||
}
|
||||
/>
|
||||
) : (
|
||||
<div className="text-sm text-text-secondary">
|
||||
{localize('com_ui_web_search_provider_serper')}
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
<Input
|
||||
type="password"
|
||||
placeholder={`${localize('com_ui_enter_api_key')}`}
|
||||
autoComplete="one-time-code"
|
||||
readOnly={true}
|
||||
onFocus={(e) => (e.target.readOnly = false)}
|
||||
{...register('serperApiKey', { required: true })}
|
||||
/>
|
||||
<div className="mt-1 text-xs text-text-secondary">
|
||||
<a
|
||||
href="https://serper.dev/api-key"
|
||||
target="_blank"
|
||||
rel="noopener noreferrer"
|
||||
className="text-blue-500 hover:text-blue-600 dark:text-blue-400 dark:hover:text-blue-300"
|
||||
>
|
||||
{localize('com_ui_web_search_provider_serper_key')}
|
||||
</a>
|
||||
</div>
|
||||
</div>
|
||||
<InputSection
|
||||
title={localize('com_ui_web_search_provider')}
|
||||
selectedKey={selectedProvider}
|
||||
onSelectionChange={handleProviderChange}
|
||||
dropdownOptions={providerOptions}
|
||||
showDropdown={!config?.webSearch?.searchProvider}
|
||||
register={register}
|
||||
dropdownOpen={dropdownOpen.provider}
|
||||
setDropdownOpen={(open) =>
|
||||
setDropdownOpen((prev) => ({ ...prev, provider: open }))
|
||||
}
|
||||
dropdownKey="provider"
|
||||
/>
|
||||
)}
|
||||
|
||||
{/* Scraper Section */}
|
||||
{scraperAuthType !== AuthType.SYSTEM_DEFINED && (
|
||||
<div className="mb-6">
|
||||
<div className="mb-2 flex items-center justify-between">
|
||||
<Label className="text-md w-fit font-medium">
|
||||
{localize('com_ui_web_search_scraper')}
|
||||
</Label>
|
||||
{showScraperDropdown ? (
|
||||
<DropdownPopup
|
||||
menuId="scraper-dropdown"
|
||||
items={scraperItems}
|
||||
isOpen={scraperDropdownOpen}
|
||||
setIsOpen={setScraperDropdownOpen}
|
||||
trigger={
|
||||
<Menu.MenuButton
|
||||
onClick={() => setScraperDropdownOpen(!scraperDropdownOpen)}
|
||||
className="flex items-center rounded-md border border-border-light px-3 py-1 text-sm text-text-secondary"
|
||||
>
|
||||
{localize('com_ui_web_search_scraper_firecrawl')}
|
||||
<ChevronDown className="ml-1 h-4 w-4" />
|
||||
</Menu.MenuButton>
|
||||
}
|
||||
/>
|
||||
) : (
|
||||
<div className="text-sm text-text-secondary">
|
||||
{localize('com_ui_web_search_scraper_firecrawl')}
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
<Input
|
||||
type="password"
|
||||
placeholder={`${localize('com_ui_enter_api_key')}`}
|
||||
autoComplete="one-time-code"
|
||||
readOnly={true}
|
||||
onFocus={(e) => (e.target.readOnly = false)}
|
||||
className="mb-2"
|
||||
{...register('firecrawlApiKey')}
|
||||
/>
|
||||
<Input
|
||||
type="text"
|
||||
placeholder={localize('com_ui_web_search_firecrawl_url')}
|
||||
className="mb-1"
|
||||
{...register('firecrawlApiUrl')}
|
||||
/>
|
||||
<div className="mt-1 text-xs text-text-secondary">
|
||||
<a
|
||||
href="https://docs.firecrawl.dev/introduction#api-key"
|
||||
target="_blank"
|
||||
rel="noopener noreferrer"
|
||||
className="text-blue-500 hover:text-blue-600 dark:text-blue-400 dark:hover:text-blue-300"
|
||||
>
|
||||
{localize('com_ui_web_search_scraper_firecrawl_key')}
|
||||
</a>
|
||||
</div>
|
||||
</div>
|
||||
<InputSection
|
||||
title={localize('com_ui_web_search_scraper')}
|
||||
selectedKey={selectedScraper}
|
||||
onSelectionChange={handleScraperChange}
|
||||
dropdownOptions={scraperOptions}
|
||||
showDropdown={!config?.webSearch?.scraperType}
|
||||
register={register}
|
||||
dropdownOpen={dropdownOpen.scraper}
|
||||
setDropdownOpen={(open) =>
|
||||
setDropdownOpen((prev) => ({ ...prev, scraper: open }))
|
||||
}
|
||||
dropdownKey="scraper"
|
||||
/>
|
||||
)}
|
||||
|
||||
{/* Reranker Section */}
|
||||
{rerankerAuthType !== AuthType.SYSTEM_DEFINED && (
|
||||
<div className="mb-6">
|
||||
<div className="mb-2 flex items-center justify-between">
|
||||
<Label className="text-md w-fit font-medium">
|
||||
{localize('com_ui_web_search_reranker')}
|
||||
</Label>
|
||||
{showRerankerDropdown && (
|
||||
<DropdownPopup
|
||||
menuId="reranker-dropdown"
|
||||
isOpen={rerankerDropdownOpen}
|
||||
setIsOpen={setRerankerDropdownOpen}
|
||||
items={rerankerItems}
|
||||
trigger={
|
||||
<Menu.MenuButton
|
||||
onClick={() => setRerankerDropdownOpen(!rerankerDropdownOpen)}
|
||||
className="flex items-center rounded-md border border-border-light px-3 py-1 text-sm text-text-secondary"
|
||||
>
|
||||
{selectedReranker === RerankerTypes.JINA
|
||||
? localize('com_ui_web_search_reranker_jina')
|
||||
: localize('com_ui_web_search_reranker_cohere')}
|
||||
<ChevronDown className="ml-1 h-4 w-4" />
|
||||
</Menu.MenuButton>
|
||||
}
|
||||
/>
|
||||
)}
|
||||
{!showRerankerDropdown && (
|
||||
<div className="text-sm text-text-secondary">
|
||||
{config?.webSearch?.rerankerType === RerankerTypes.COHERE
|
||||
? localize('com_ui_web_search_reranker_cohere')
|
||||
: localize('com_ui_web_search_reranker_jina')}
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
{renderRerankerInput()}
|
||||
</div>
|
||||
<InputSection
|
||||
title={localize('com_ui_web_search_reranker')}
|
||||
selectedKey={selectedReranker}
|
||||
onSelectionChange={handleRerankerChange}
|
||||
dropdownOptions={rerankerOptions}
|
||||
showDropdown={!config?.webSearch?.rerankerType}
|
||||
register={register}
|
||||
dropdownOpen={dropdownOpen.reranker}
|
||||
setDropdownOpen={(open) =>
|
||||
setDropdownOpen((prev) => ({ ...prev, reranker: open }))
|
||||
}
|
||||
dropdownKey="reranker"
|
||||
/>
|
||||
)}
|
||||
</form>
|
||||
</>
|
||||
|
|
@ -346,10 +227,7 @@ export default function ApiKeyDialog({
|
|||
}}
|
||||
buttons={
|
||||
isToolAuthenticated && (
|
||||
<Button
|
||||
onClick={onRevoke}
|
||||
className="bg-destructive text-white transition-all duration-200 hover:bg-destructive/80"
|
||||
>
|
||||
<Button onClick={onRevoke} className="bg-red-500 text-white hover:bg-red-600">
|
||||
{localize('com_ui_revoke')}
|
||||
</Button>
|
||||
)
|
||||
|
|
|
|||
144
client/src/components/SidePanel/Agents/Search/InputSection.tsx
Normal file
144
client/src/components/SidePanel/Agents/Search/InputSection.tsx
Normal file
|
|
@ -0,0 +1,144 @@
|
|||
import { useState } from 'react';
|
||||
import { ChevronDown, Eye, EyeOff } from 'lucide-react';
|
||||
import * as Menu from '@ariakit/react/menu';
|
||||
import type { UseFormRegister } from 'react-hook-form';
|
||||
import type { SearchApiKeyFormData } from '~/hooks/Plugins/useAuthSearchTool';
|
||||
import type { MenuItemProps } from '~/common';
|
||||
import { Input, Label } from '~/components/ui';
|
||||
import DropdownPopup from '~/components/ui/DropdownPopup';
|
||||
import { useLocalize } from '~/hooks';
|
||||
|
||||
interface InputConfig {
|
||||
placeholder: string;
|
||||
type?: 'text' | 'password';
|
||||
link?: {
|
||||
url: string;
|
||||
text: string;
|
||||
};
|
||||
}
|
||||
|
||||
interface DropdownOption {
|
||||
key: string;
|
||||
label: string;
|
||||
inputs?: Record<string, InputConfig>;
|
||||
}
|
||||
|
||||
interface InputSectionProps {
|
||||
title: string;
|
||||
selectedKey: string;
|
||||
onSelectionChange: (key: string) => void;
|
||||
dropdownOptions: DropdownOption[];
|
||||
showDropdown: boolean;
|
||||
register: UseFormRegister<SearchApiKeyFormData>;
|
||||
dropdownOpen: boolean;
|
||||
setDropdownOpen: (open: boolean) => void;
|
||||
dropdownKey: string;
|
||||
}
|
||||
|
||||
export default function InputSection({
|
||||
title,
|
||||
selectedKey,
|
||||
onSelectionChange,
|
||||
dropdownOptions,
|
||||
showDropdown,
|
||||
register,
|
||||
dropdownOpen,
|
||||
setDropdownOpen,
|
||||
dropdownKey,
|
||||
}: InputSectionProps) {
|
||||
const localize = useLocalize();
|
||||
const [passwordVisibility, setPasswordVisibility] = useState<Record<string, boolean>>({});
|
||||
const selectedOption = dropdownOptions.find((opt) => opt.key === selectedKey);
|
||||
const dropdownItems: MenuItemProps[] = dropdownOptions.map((option) => ({
|
||||
label: option.label,
|
||||
onClick: () => onSelectionChange(option.key),
|
||||
}));
|
||||
|
||||
const togglePasswordVisibility = (fieldName: string) => {
|
||||
setPasswordVisibility((prev) => ({
|
||||
...prev,
|
||||
[fieldName]: !prev[fieldName],
|
||||
}));
|
||||
};
|
||||
|
||||
return (
|
||||
<div className="mb-6">
|
||||
<div className="mb-2 flex items-center justify-between">
|
||||
<Label className="text-md w-fit font-medium">{title}</Label>
|
||||
{showDropdown ? (
|
||||
<DropdownPopup
|
||||
menuId={`${dropdownKey}-dropdown`}
|
||||
items={dropdownItems}
|
||||
isOpen={dropdownOpen}
|
||||
setIsOpen={setDropdownOpen}
|
||||
trigger={
|
||||
<Menu.MenuButton
|
||||
onClick={() => setDropdownOpen(!dropdownOpen)}
|
||||
className="flex items-center rounded-md border border-border-light px-3 py-1 text-sm text-text-secondary"
|
||||
>
|
||||
{selectedOption?.label}
|
||||
<ChevronDown className="ml-1 h-4 w-4" />
|
||||
</Menu.MenuButton>
|
||||
}
|
||||
/>
|
||||
) : (
|
||||
<div className="text-sm text-text-secondary">{selectedOption?.label}</div>
|
||||
)}
|
||||
</div>
|
||||
{selectedOption?.inputs &&
|
||||
Object.entries(selectedOption.inputs).map(([name, config], index) => (
|
||||
<div key={name}>
|
||||
<div className="relative">
|
||||
<Input
|
||||
type={'text'} // so password autofill doesn't show
|
||||
placeholder={config.placeholder}
|
||||
autoComplete={config.type === 'password' ? 'one-time-code' : 'off'}
|
||||
readOnly={config.type === 'password'}
|
||||
onFocus={
|
||||
config.type === 'password' ? (e) => (e.target.readOnly = false) : undefined
|
||||
}
|
||||
className={`${index > 0 ? 'mb-2' : 'mb-2'} ${
|
||||
config.type === 'password' ? 'pr-10' : ''
|
||||
}`}
|
||||
{...register(name as keyof SearchApiKeyFormData)}
|
||||
/>
|
||||
{config.type === 'password' && (
|
||||
<button
|
||||
type="button"
|
||||
onClick={() => togglePasswordVisibility(name)}
|
||||
className="absolute right-3 top-1/2 -translate-y-1/2 text-text-secondary transition-colors hover:text-text-primary"
|
||||
aria-label={
|
||||
passwordVisibility[name]
|
||||
? localize('com_ui_hide_password')
|
||||
: localize('com_ui_show_password')
|
||||
}
|
||||
>
|
||||
<div className="relative h-4 w-4">
|
||||
{passwordVisibility[name] ? (
|
||||
<EyeOff className="absolute inset-0 h-4 w-4 duration-200 animate-in fade-in" />
|
||||
) : (
|
||||
<Eye className="absolute inset-0 h-4 w-4 duration-200 animate-in fade-in" />
|
||||
)}
|
||||
</div>
|
||||
</button>
|
||||
)}
|
||||
</div>
|
||||
{config.link && (
|
||||
<div className="mt-1 text-xs text-text-secondary">
|
||||
<a
|
||||
href={config.link.url}
|
||||
target="_blank"
|
||||
rel="noopener noreferrer"
|
||||
className="text-blue-500 hover:text-blue-600 dark:text-blue-400 dark:hover:text-blue-300"
|
||||
>
|
||||
{config.link.text}
|
||||
</a>
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
))}
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
export type { InputConfig, DropdownOption };
|
||||
|
|
@ -17,9 +17,9 @@ import {
|
|||
} from '~/data-provider';
|
||||
import { cn, cardStyle, defaultTextProps, removeFocusOutlines } from '~/utils';
|
||||
import AssistantConversationStarters from './AssistantConversationStarters';
|
||||
import AssistantToolsDialog from '~/components/Tools/AssistantToolsDialog';
|
||||
import { useAssistantsMapContext, useToastContext } from '~/Providers';
|
||||
import { useSelectAssistant, useLocalize } from '~/hooks';
|
||||
import { ToolSelectDialog } from '~/components/Tools';
|
||||
import AppendDateCheckbox from './AppendDateCheckbox';
|
||||
import CapabilitiesForm from './CapabilitiesForm';
|
||||
import { SelectDropDown } from '~/components/ui';
|
||||
|
|
@ -468,11 +468,10 @@ export default function AssistantPanel({
|
|||
</button>
|
||||
</div>
|
||||
</div>
|
||||
<ToolSelectDialog
|
||||
<AssistantToolsDialog
|
||||
endpoint={endpoint}
|
||||
isOpen={showToolDialog}
|
||||
setIsOpen={setShowToolDialog}
|
||||
toolsFormKey="functions"
|
||||
endpoint={endpoint}
|
||||
/>
|
||||
</form>
|
||||
</FormProvider>
|
||||
|
|
|
|||
|
|
@ -52,6 +52,10 @@ export default function MemoryCreateDialog({
|
|||
if (axiosError.response?.status === 409 || errorMessage.includes('already exists')) {
|
||||
errorMessage = localize('com_ui_memory_key_exists');
|
||||
}
|
||||
// Check for key validation error (lowercase and underscores only)
|
||||
else if (errorMessage.includes('lowercase letters and underscores')) {
|
||||
errorMessage = localize('com_ui_memory_key_validation');
|
||||
}
|
||||
}
|
||||
} else if (error.message) {
|
||||
errorMessage = error.message;
|
||||
|
|
|
|||
|
|
@ -44,9 +44,29 @@ export default function MemoryEditDialog({
|
|||
status: 'success',
|
||||
});
|
||||
},
|
||||
onError: () => {
|
||||
onError: (error: Error) => {
|
||||
let errorMessage = localize('com_ui_error');
|
||||
|
||||
if (error && typeof error === 'object' && 'response' in error) {
|
||||
const axiosError = error as any;
|
||||
if (axiosError.response?.data?.error) {
|
||||
errorMessage = axiosError.response.data.error;
|
||||
|
||||
// Check for duplicate key error
|
||||
if (axiosError.response?.status === 409 || errorMessage.includes('already exists')) {
|
||||
errorMessage = localize('com_ui_memory_key_exists');
|
||||
}
|
||||
// Check for key validation error (lowercase and underscores only)
|
||||
else if (errorMessage.includes('lowercase letters and underscores')) {
|
||||
errorMessage = localize('com_ui_memory_key_validation');
|
||||
}
|
||||
}
|
||||
} else if (error.message) {
|
||||
errorMessage = error.message;
|
||||
}
|
||||
|
||||
showToast({
|
||||
message: localize('com_ui_error'),
|
||||
message: errorMessage,
|
||||
status: 'error',
|
||||
});
|
||||
},
|
||||
|
|
|
|||
|
|
@ -1,21 +1,15 @@
|
|||
import { useState } from 'react';
|
||||
import * as AccordionPrimitive from '@radix-ui/react-accordion';
|
||||
import type { NavLink, NavProps } from '~/common';
|
||||
import { Accordion, AccordionItem, AccordionContent } from '~/components/ui/Accordion';
|
||||
import { TooltipAnchor, Button } from '~/components';
|
||||
import { AccordionContent, AccordionItem, TooltipAnchor, Accordion, Button } from '~/components/ui';
|
||||
import { ActivePanelProvider, useActivePanel } from '~/Providers';
|
||||
import { useLocalize } from '~/hooks';
|
||||
import { cn } from '~/utils';
|
||||
|
||||
export default function Nav({ links, isCollapsed, resize, defaultActive }: NavProps) {
|
||||
function NavContent({ links, isCollapsed, resize }: Omit<NavProps, 'defaultActive'>) {
|
||||
const localize = useLocalize();
|
||||
const [active, _setActive] = useState<string | undefined>(defaultActive);
|
||||
const { active, setActive } = useActivePanel();
|
||||
const getVariant = (link: NavLink) => (link.id === active ? 'default' : 'ghost');
|
||||
|
||||
const setActive = (id: string) => {
|
||||
localStorage.setItem('side:active-panel', id + '');
|
||||
_setActive(id);
|
||||
};
|
||||
|
||||
return (
|
||||
<div
|
||||
data-collapsed={isCollapsed}
|
||||
|
|
@ -105,3 +99,11 @@ export default function Nav({ links, isCollapsed, resize, defaultActive }: NavPr
|
|||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
export default function Nav({ links, isCollapsed, resize, defaultActive }: NavProps) {
|
||||
return (
|
||||
<ActivePanelProvider defaultActive={defaultActive}>
|
||||
<NavContent links={links} isCollapsed={isCollapsed} resize={resize} />
|
||||
</ActivePanelProvider>
|
||||
);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -46,6 +46,10 @@ function DynamicInput({
|
|||
setInputValue(e, !isNaN(Number(e.target.value)));
|
||||
};
|
||||
|
||||
const placeholderText = placeholderCode
|
||||
? localize(placeholder as TranslationKeys) || placeholder
|
||||
: placeholder;
|
||||
|
||||
return (
|
||||
<div
|
||||
className={`flex flex-col items-center justify-start gap-6 ${
|
||||
|
|
@ -76,11 +80,7 @@ function DynamicInput({
|
|||
disabled={readonly}
|
||||
value={inputValue ?? defaultValue ?? ''}
|
||||
onChange={handleInputChange}
|
||||
placeholder={
|
||||
placeholderCode
|
||||
? localize(placeholder as TranslationKeys) || placeholder
|
||||
: placeholder
|
||||
}
|
||||
placeholder={placeholderText}
|
||||
className={cn(
|
||||
'flex h-10 max-h-10 w-full resize-none border-none bg-surface-secondary px-3 py-2',
|
||||
)}
|
||||
|
|
|
|||
|
|
@ -18,6 +18,7 @@ function DynamicSlider({
|
|||
setOption,
|
||||
optionType,
|
||||
options,
|
||||
enumMappings,
|
||||
readonly = false,
|
||||
showDefault = false,
|
||||
includeInput = true,
|
||||
|
|
@ -60,24 +61,68 @@ function DynamicSlider({
|
|||
|
||||
const enumToNumeric = useMemo(() => {
|
||||
if (isEnum && options) {
|
||||
return options.reduce((acc, mapping, index) => {
|
||||
acc[mapping] = index;
|
||||
return acc;
|
||||
}, {} as Record<string, number>);
|
||||
return options.reduce(
|
||||
(acc, mapping, index) => {
|
||||
acc[mapping] = index;
|
||||
return acc;
|
||||
},
|
||||
{} as Record<string, number>,
|
||||
);
|
||||
}
|
||||
return {};
|
||||
}, [isEnum, options]);
|
||||
|
||||
const valueToEnumOption = useMemo(() => {
|
||||
if (isEnum && options) {
|
||||
return options.reduce((acc, option, index) => {
|
||||
acc[index] = option;
|
||||
return acc;
|
||||
}, {} as Record<number, string>);
|
||||
return options.reduce(
|
||||
(acc, option, index) => {
|
||||
acc[index] = option;
|
||||
return acc;
|
||||
},
|
||||
{} as Record<number, string>,
|
||||
);
|
||||
}
|
||||
return {};
|
||||
}, [isEnum, options]);
|
||||
|
||||
const getDisplayValue = useCallback(
|
||||
(value: string | number | undefined | null): string => {
|
||||
if (isEnum && enumMappings && value != null) {
|
||||
const stringValue = String(value);
|
||||
// Check if the value exists in enumMappings
|
||||
if (stringValue in enumMappings) {
|
||||
const mappedValue = String(enumMappings[stringValue]);
|
||||
// Check if the mapped value is a localization key
|
||||
if (mappedValue.startsWith('com_')) {
|
||||
return localize(mappedValue as TranslationKeys) ?? mappedValue;
|
||||
}
|
||||
return mappedValue;
|
||||
}
|
||||
}
|
||||
// Always return a string for Input component compatibility
|
||||
if (value != null) {
|
||||
return String(value);
|
||||
}
|
||||
return String(defaultValue ?? '');
|
||||
},
|
||||
[isEnum, enumMappings, defaultValue, localize],
|
||||
);
|
||||
|
||||
const getDefaultDisplayValue = useCallback((): string => {
|
||||
if (defaultValue != null && enumMappings) {
|
||||
const stringDefault = String(defaultValue);
|
||||
if (stringDefault in enumMappings) {
|
||||
const mappedValue = String(enumMappings[stringDefault]);
|
||||
// Check if the mapped value is a localization key
|
||||
if (mappedValue.startsWith('com_')) {
|
||||
return localize(mappedValue as TranslationKeys) ?? mappedValue;
|
||||
}
|
||||
return mappedValue;
|
||||
}
|
||||
}
|
||||
return String(defaultValue ?? '');
|
||||
}, [defaultValue, enumMappings, localize]);
|
||||
|
||||
const handleValueChange = useCallback(
|
||||
(value: number) => {
|
||||
if (isEnum) {
|
||||
|
|
@ -115,12 +160,12 @@ function DynamicSlider({
|
|||
<div className="flex w-full items-center justify-between">
|
||||
<Label
|
||||
htmlFor={`${settingKey}-dynamic-setting`}
|
||||
className="text-left text-sm font-medium"
|
||||
className="break-words text-left text-sm font-medium"
|
||||
>
|
||||
{labelCode ? localize(label as TranslationKeys) ?? label : label || settingKey}{' '}
|
||||
{labelCode ? (localize(label as TranslationKeys) ?? label) : label || settingKey}{' '}
|
||||
{showDefault && (
|
||||
<small className="opacity-40">
|
||||
({localize('com_endpoint_default')}: {defaultValue})
|
||||
({localize('com_endpoint_default')}: {getDefaultDisplayValue()})
|
||||
</small>
|
||||
)}
|
||||
</Label>
|
||||
|
|
@ -132,13 +177,13 @@ function DynamicSlider({
|
|||
onChange={(value) => setInputValue(Number(value))}
|
||||
max={range ? range.max : (options?.length ?? 0) - 1}
|
||||
min={range ? range.min : 0}
|
||||
step={range ? range.step ?? 1 : 1}
|
||||
step={range ? (range.step ?? 1) : 1}
|
||||
controls={false}
|
||||
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',
|
||||
'reset-rc-number-input reset-rc-number-input-text-right h-auto w-12 border-0 py-1 text-xs group-hover/temp:border-gray-200',
|
||||
),
|
||||
)}
|
||||
/>
|
||||
|
|
@ -146,13 +191,13 @@ function DynamicSlider({
|
|||
<Input
|
||||
id={`${settingKey}-dynamic-setting-input`}
|
||||
disabled={readonly}
|
||||
value={selectedValue ?? defaultValue}
|
||||
value={getDisplayValue(selectedValue)}
|
||||
onChange={() => ({})}
|
||||
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',
|
||||
'reset-rc-number-input h-auto w-14 border-0 py-1 pl-1 text-center text-xs group-hover/temp:border-gray-200',
|
||||
),
|
||||
)}
|
||||
/>
|
||||
|
|
@ -164,19 +209,23 @@ function DynamicSlider({
|
|||
value={[
|
||||
isEnum
|
||||
? enumToNumeric[(selectedValue as number) ?? '']
|
||||
: (inputValue as number) ?? (defaultValue as number),
|
||||
: ((inputValue as number) ?? (defaultValue as number)),
|
||||
]}
|
||||
onValueChange={(value) => handleValueChange(value[0])}
|
||||
onDoubleClick={() => setInputValue(defaultValue as string | number)}
|
||||
max={max}
|
||||
min={range ? range.min : 0}
|
||||
step={range ? range.step ?? 1 : 1}
|
||||
step={range ? (range.step ?? 1) : 1}
|
||||
className="flex h-4 w-full"
|
||||
/>
|
||||
</HoverCardTrigger>
|
||||
{description && (
|
||||
<OptionHover
|
||||
description={descriptionCode ? localize(description as TranslationKeys) ?? description : description}
|
||||
description={
|
||||
descriptionCode
|
||||
? (localize(description as TranslationKeys) ?? description)
|
||||
: description
|
||||
}
|
||||
side={ESide.Left}
|
||||
/>
|
||||
)}
|
||||
|
|
|
|||
|
|
@ -50,7 +50,7 @@ function DynamicSwitch({
|
|||
<div className="flex justify-between">
|
||||
<Label
|
||||
htmlFor={`${settingKey}-dynamic-switch`}
|
||||
className="text-left text-sm font-medium"
|
||||
className="break-words text-left text-sm font-medium"
|
||||
>
|
||||
{labelCode ? (localize(label as TranslationKeys) ?? label) : label || settingKey}{' '}
|
||||
{showDefault && (
|
||||
|
|
|
|||
|
|
@ -29,7 +29,7 @@ function OptionHover({
|
|||
<HoverCardPortal>
|
||||
<HoverCardContent side={side} className={`z-[999] w-80 ${className}`} sideOffset={sideOffset}>
|
||||
<div className="space-y-2">
|
||||
<p className="text-sm text-gray-600 dark:text-gray-300">{text}</p>
|
||||
<p className="whitespace-pre-wrap text-sm text-text-secondary">{text}</p>
|
||||
</div>
|
||||
</HoverCardContent>
|
||||
</HoverCardPortal>
|
||||
|
|
|
|||
254
client/src/components/Tools/AssistantToolsDialog.tsx
Normal file
254
client/src/components/Tools/AssistantToolsDialog.tsx
Normal file
|
|
@ -0,0 +1,254 @@
|
|||
import { useEffect } from 'react';
|
||||
import { Search, X } from 'lucide-react';
|
||||
import { Dialog, DialogPanel, DialogTitle, Description } from '@headlessui/react';
|
||||
import { useFormContext } from 'react-hook-form';
|
||||
import { isAgentsEndpoint } from 'librechat-data-provider';
|
||||
import { useUpdateUserPluginsMutation } from 'librechat-data-provider/react-query';
|
||||
import type {
|
||||
AssistantsEndpoint,
|
||||
EModelEndpoint,
|
||||
TPluginAction,
|
||||
TError,
|
||||
} from 'librechat-data-provider';
|
||||
import type { TPluginStoreDialogProps } from '~/common/types';
|
||||
import { PluginPagination, PluginAuthForm } from '~/components/Plugins/Store';
|
||||
import { useLocalize, usePluginDialogHelpers } from '~/hooks';
|
||||
import { useAvailableToolsQuery } from '~/data-provider';
|
||||
import ToolItem from './ToolItem';
|
||||
|
||||
function AssistantToolsDialog({
|
||||
isOpen,
|
||||
endpoint,
|
||||
setIsOpen,
|
||||
}: TPluginStoreDialogProps & {
|
||||
endpoint: AssistantsEndpoint | EModelEndpoint.agents;
|
||||
}) {
|
||||
const localize = useLocalize();
|
||||
const { getValues, setValue } = useFormContext();
|
||||
const { data: tools } = useAvailableToolsQuery(endpoint);
|
||||
const isAgentTools = isAgentsEndpoint(endpoint);
|
||||
|
||||
const {
|
||||
maxPage,
|
||||
setMaxPage,
|
||||
currentPage,
|
||||
setCurrentPage,
|
||||
itemsPerPage,
|
||||
searchChanged,
|
||||
setSearchChanged,
|
||||
searchValue,
|
||||
setSearchValue,
|
||||
gridRef,
|
||||
handleSearch,
|
||||
handleChangePage,
|
||||
error,
|
||||
setError,
|
||||
errorMessage,
|
||||
setErrorMessage,
|
||||
showPluginAuthForm,
|
||||
setShowPluginAuthForm,
|
||||
selectedPlugin,
|
||||
setSelectedPlugin,
|
||||
} = usePluginDialogHelpers();
|
||||
|
||||
const updateUserPlugins = useUpdateUserPluginsMutation();
|
||||
const handleInstallError = (error: TError) => {
|
||||
setError(true);
|
||||
const errorMessage = error.response?.data?.message ?? '';
|
||||
if (errorMessage) {
|
||||
setErrorMessage(errorMessage);
|
||||
}
|
||||
setTimeout(() => {
|
||||
setError(false);
|
||||
setErrorMessage('');
|
||||
}, 5000);
|
||||
};
|
||||
|
||||
const handleInstall = (pluginAction: TPluginAction) => {
|
||||
const addFunction = () => {
|
||||
const fns = getValues('functions').slice();
|
||||
fns.push(pluginAction.pluginKey);
|
||||
setValue('functions', fns);
|
||||
};
|
||||
|
||||
if (!pluginAction.auth) {
|
||||
return addFunction();
|
||||
}
|
||||
|
||||
updateUserPlugins.mutate(pluginAction, {
|
||||
onError: (error: unknown) => {
|
||||
handleInstallError(error as TError);
|
||||
},
|
||||
onSuccess: addFunction,
|
||||
});
|
||||
|
||||
setShowPluginAuthForm(false);
|
||||
};
|
||||
|
||||
const onRemoveTool = (tool: string) => {
|
||||
setShowPluginAuthForm(false);
|
||||
updateUserPlugins.mutate(
|
||||
{ pluginKey: tool, action: 'uninstall', auth: null, isEntityTool: true },
|
||||
{
|
||||
onError: (error: unknown) => {
|
||||
handleInstallError(error as TError);
|
||||
},
|
||||
onSuccess: () => {
|
||||
const fns = getValues('functions').filter((fn: string) => fn !== tool);
|
||||
setValue('functions', fns);
|
||||
},
|
||||
},
|
||||
);
|
||||
};
|
||||
|
||||
const onAddTool = (pluginKey: string) => {
|
||||
setShowPluginAuthForm(false);
|
||||
const getAvailablePluginFromKey = tools?.find((p) => p.pluginKey === pluginKey);
|
||||
setSelectedPlugin(getAvailablePluginFromKey);
|
||||
|
||||
const { authConfig, authenticated = false } = getAvailablePluginFromKey ?? {};
|
||||
|
||||
if (authConfig && authConfig.length > 0 && !authenticated) {
|
||||
setShowPluginAuthForm(true);
|
||||
} else {
|
||||
handleInstall({ pluginKey, action: 'install', auth: null });
|
||||
}
|
||||
};
|
||||
|
||||
const filteredTools = tools?.filter((tool) =>
|
||||
tool.name.toLowerCase().includes(searchValue.toLowerCase()),
|
||||
);
|
||||
|
||||
useEffect(() => {
|
||||
if (filteredTools) {
|
||||
setMaxPage(Math.ceil(filteredTools.length / itemsPerPage));
|
||||
if (searchChanged) {
|
||||
setCurrentPage(1);
|
||||
setSearchChanged(false);
|
||||
}
|
||||
}
|
||||
}, [
|
||||
tools,
|
||||
itemsPerPage,
|
||||
searchValue,
|
||||
filteredTools,
|
||||
searchChanged,
|
||||
setMaxPage,
|
||||
setCurrentPage,
|
||||
setSearchChanged,
|
||||
]);
|
||||
|
||||
return (
|
||||
<Dialog
|
||||
open={isOpen}
|
||||
onClose={() => {
|
||||
setIsOpen(false);
|
||||
setCurrentPage(1);
|
||||
setSearchValue('');
|
||||
}}
|
||||
className="relative z-[102]"
|
||||
>
|
||||
{/* The backdrop, rendered as a fixed sibling to the panel container */}
|
||||
<div className="fixed inset-0 bg-surface-primary opacity-60 transition-opacity dark:opacity-80" />
|
||||
{/* Full-screen container to center the panel */}
|
||||
<div className="fixed inset-0 flex items-center justify-center p-4">
|
||||
<DialogPanel
|
||||
className="relative w-full transform overflow-hidden overflow-y-auto rounded-lg bg-surface-secondary text-left shadow-xl transition-all max-sm:h-full sm:mx-7 sm:my-8 sm:max-w-2xl lg:max-w-5xl xl:max-w-7xl"
|
||||
style={{ minHeight: '610px' }}
|
||||
>
|
||||
<div className="flex items-center justify-between border-b-[1px] border-border-medium px-4 pb-4 pt-5 sm:p-6">
|
||||
<div className="flex items-center">
|
||||
<div className="text-center sm:text-left">
|
||||
<DialogTitle className="text-lg font-medium leading-6 text-text-primary">
|
||||
{isAgentTools
|
||||
? localize('com_nav_tool_dialog_agents')
|
||||
: localize('com_nav_tool_dialog')}
|
||||
</DialogTitle>
|
||||
<Description className="text-sm text-text-secondary">
|
||||
{localize('com_nav_tool_dialog_description')}
|
||||
</Description>
|
||||
</div>
|
||||
</div>
|
||||
<div>
|
||||
<div className="sm:mt-0">
|
||||
<button
|
||||
onClick={() => {
|
||||
setIsOpen(false);
|
||||
setCurrentPage(1);
|
||||
}}
|
||||
className="inline-block rounded-full text-text-secondary transition-colors hover:text-text-primary"
|
||||
aria-label="Close dialog"
|
||||
type="button"
|
||||
>
|
||||
<X aria-hidden="true" />
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
{error && (
|
||||
<div
|
||||
className="relative m-4 rounded border border-red-400 bg-red-100 px-4 py-3 text-red-700"
|
||||
role="alert"
|
||||
>
|
||||
{localize('com_nav_plugin_auth_error')} {errorMessage}
|
||||
</div>
|
||||
)}
|
||||
{showPluginAuthForm && (
|
||||
<div className="p-4 sm:p-6 sm:pt-4">
|
||||
<PluginAuthForm
|
||||
plugin={selectedPlugin}
|
||||
onSubmit={(installActionData: TPluginAction) => handleInstall(installActionData)}
|
||||
isEntityTool={true}
|
||||
/>
|
||||
</div>
|
||||
)}
|
||||
<div className="p-4 sm:p-6 sm:pt-4">
|
||||
<div className="mt-4 flex flex-col gap-4">
|
||||
<div className="flex items-center justify-center space-x-4">
|
||||
<Search className="h-6 w-6 text-text-tertiary" />
|
||||
<input
|
||||
type="text"
|
||||
value={searchValue}
|
||||
onChange={handleSearch}
|
||||
placeholder={localize('com_nav_tool_search')}
|
||||
className="w-64 rounded border border-border-medium bg-transparent px-2 py-1 text-text-primary focus:outline-none"
|
||||
/>
|
||||
</div>
|
||||
<div
|
||||
ref={gridRef}
|
||||
className="grid grid-cols-1 grid-rows-2 gap-3 sm:grid-cols-2 lg:grid-cols-3 xl:grid-cols-4"
|
||||
style={{ minHeight: '410px' }}
|
||||
>
|
||||
{filteredTools &&
|
||||
filteredTools
|
||||
.slice((currentPage - 1) * itemsPerPage, currentPage * itemsPerPage)
|
||||
.map((tool, index) => (
|
||||
<ToolItem
|
||||
key={index}
|
||||
tool={tool}
|
||||
isInstalled={getValues('functions').includes(tool.pluginKey)}
|
||||
onAddTool={() => onAddTool(tool.pluginKey)}
|
||||
onRemoveTool={() => onRemoveTool(tool.pluginKey)}
|
||||
/>
|
||||
))}
|
||||
</div>
|
||||
</div>
|
||||
<div className="mt-2 flex flex-col items-center gap-2 sm:flex-row sm:justify-between">
|
||||
{maxPage > 0 ? (
|
||||
<PluginPagination
|
||||
currentPage={currentPage}
|
||||
maxPage={maxPage}
|
||||
onChangePage={handleChangePage}
|
||||
/>
|
||||
) : (
|
||||
<div style={{ height: '21px' }}></div>
|
||||
)}
|
||||
</div>
|
||||
</div>
|
||||
</DialogPanel>
|
||||
</div>
|
||||
</Dialog>
|
||||
);
|
||||
}
|
||||
|
||||
export default AssistantToolsDialog;
|
||||
|
|
@ -1,9 +1,9 @@
|
|||
import { XCircle, PlusCircleIcon, Wrench } from 'lucide-react';
|
||||
import { AgentToolType } from 'librechat-data-provider';
|
||||
import type { TPlugin, AgentToolType } from 'librechat-data-provider';
|
||||
import { useLocalize } from '~/hooks';
|
||||
|
||||
type ToolItemProps = {
|
||||
tool: AgentToolType;
|
||||
tool: TPlugin | AgentToolType;
|
||||
onAddTool: () => void;
|
||||
onRemoveTool: () => void;
|
||||
isInstalled?: boolean;
|
||||
|
|
@ -19,9 +19,13 @@ function ToolItem({ tool, onAddTool, onRemoveTool, isInstalled = false }: ToolIt
|
|||
}
|
||||
};
|
||||
|
||||
const name = tool.metadata?.name || tool.tool_id;
|
||||
const description = tool.metadata?.description || '';
|
||||
const icon = tool.metadata?.icon;
|
||||
const name =
|
||||
(tool as AgentToolType).metadata?.name ||
|
||||
(tool as AgentToolType).tool_id ||
|
||||
(tool as TPlugin).name;
|
||||
const description =
|
||||
(tool as AgentToolType).metadata?.description || (tool as TPlugin).description || '';
|
||||
const icon = (tool as AgentToolType).metadata?.icon || (tool as TPlugin).icon;
|
||||
|
||||
return (
|
||||
<div className="flex flex-col gap-4 rounded border border-border-medium bg-transparent p-6">
|
||||
|
|
|
|||
|
|
@ -67,15 +67,14 @@ function ToolSelectDialog({
|
|||
}, 5000);
|
||||
};
|
||||
|
||||
const toolsFormKey = 'tools';
|
||||
const handleInstall = (pluginAction: TPluginAction) => {
|
||||
const addFunction = () => {
|
||||
const installedToolIds: string[] = getValues(toolsFormKey) || [];
|
||||
const installedToolIds: string[] = getValues('tools') || [];
|
||||
// Add the parent
|
||||
installedToolIds.push(pluginAction.pluginKey);
|
||||
|
||||
// If this tool is a group, add subtools too
|
||||
const groupObj = groupedTools[pluginAction.pluginKey];
|
||||
const groupObj = groupedTools?.[pluginAction.pluginKey];
|
||||
if (groupObj?.tools && groupObj.tools.length > 0) {
|
||||
for (const sub of groupObj.tools) {
|
||||
if (!installedToolIds.includes(sub.tool_id)) {
|
||||
|
|
@ -83,7 +82,7 @@ function ToolSelectDialog({
|
|||
}
|
||||
}
|
||||
}
|
||||
setValue(toolsFormKey, Array.from(new Set(installedToolIds))); // no duplicates just in case
|
||||
setValue('tools', Array.from(new Set(installedToolIds))); // no duplicates just in case
|
||||
};
|
||||
|
||||
if (!pluginAction.auth) {
|
||||
|
|
@ -101,7 +100,7 @@ function ToolSelectDialog({
|
|||
};
|
||||
|
||||
const onRemoveTool = (toolId: string) => {
|
||||
const groupObj = groupedTools[toolId];
|
||||
const groupObj = groupedTools?.[toolId];
|
||||
const toolIdsToRemove = [toolId];
|
||||
if (groupObj?.tools && groupObj.tools.length > 0) {
|
||||
toolIdsToRemove.push(...groupObj.tools.map((sub) => sub.tool_id));
|
||||
|
|
@ -113,8 +112,8 @@ function ToolSelectDialog({
|
|||
onError: (error: unknown) => handleInstallError(error as TError),
|
||||
onSuccess: () => {
|
||||
const remainingToolIds =
|
||||
getValues(toolsFormKey)?.filter((toolId) => !toolIdsToRemove.includes(toolId)) || [];
|
||||
setValue(toolsFormKey, remainingToolIds);
|
||||
getValues('tools')?.filter((toolId) => !toolIdsToRemove.includes(toolId)) || [];
|
||||
setValue('tools', remainingToolIds);
|
||||
},
|
||||
},
|
||||
);
|
||||
|
|
@ -268,7 +267,7 @@ function ToolSelectDialog({
|
|||
<ToolItem
|
||||
key={index}
|
||||
tool={tool}
|
||||
isInstalled={getValues(toolsFormKey)?.includes(tool.tool_id) || false}
|
||||
isInstalled={getValues('tools')?.includes(tool.tool_id) || false}
|
||||
onAddTool={() => onAddTool(tool.tool_id)}
|
||||
onRemoveTool={() => onRemoveTool(tool.tool_id)}
|
||||
/>
|
||||
|
|
|
|||
|
|
@ -1,15 +1,31 @@
|
|||
export default function MCPIcon() {
|
||||
export default function MCPIcon({ className }: { className?: string }) {
|
||||
return (
|
||||
<svg
|
||||
width="195"
|
||||
height="195"
|
||||
viewBox="0 2 195 195"
|
||||
fill="none"
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
width="24"
|
||||
height="24"
|
||||
fill="currentColor"
|
||||
viewBox="0 0 24 24"
|
||||
className="h-4 w-4"
|
||||
className={className}
|
||||
>
|
||||
<path d="M11.016 2.099a3.998 3.998 0 0 1 5.58.072l.073.074a3.991 3.991 0 0 1 1.058 3.318 3.994 3.994 0 0 1 3.32 1.06l.073.071.048.047.071.075a3.998 3.998 0 0 1 0 5.506l-.071.074-8.183 8.182-.034.042a.267.267 0 0 0 .034.335l1.68 1.68a.8.8 0 0 1-1.131 1.13l-1.68-1.679a1.866 1.866 0 0 1-.034-2.604l8.26-8.261a2.4 2.4 0 0 0-.044-3.349l-.047-.047-.044-.043a2.4 2.4 0 0 0-3.349.043l-6.832 6.832-.03.029a.8.8 0 0 1-1.1-1.16l6.876-6.875a2.4 2.4 0 0 0-.044-3.35l-.179-.161a2.399 2.399 0 0 0-3.169.119l-.045.043-9.047 9.047-.03.028a.8.8 0 0 1-1.1-1.16l9.046-9.046.074-.072Z" />
|
||||
<path d="M13.234 4.404a.8.8 0 0 1 1.1 1.16l-6.69 6.691a2.399 2.399 0 1 0 3.393 3.393l6.691-6.692a.8.8 0 0 1 1.131 1.131l-6.691 6.692a4 4 0 0 1-5.581.07l-.073-.07a3.998 3.998 0 0 1 0-5.655l6.69-6.691.03-.029Z" />
|
||||
<path
|
||||
d="M25 97.8528L92.8823 29.9706C102.255 20.598 117.451 20.598 126.823 29.9706V29.9706C136.196 39.3431 136.196 54.5391 126.823 63.9117L75.5581 115.177"
|
||||
stroke="currentColor"
|
||||
strokeWidth="12"
|
||||
strokeLinecap="round"
|
||||
/>
|
||||
<path
|
||||
d="M76.2653 114.47L126.823 63.9117C136.196 54.5391 151.392 54.5391 160.765 63.9117L161.118 64.2652C170.491 73.6378 170.491 88.8338 161.118 98.2063L99.7248 159.6C96.6006 162.724 96.6006 167.789 99.7248 170.913L112.331 183.52"
|
||||
stroke="currentColor"
|
||||
strokeWidth="12"
|
||||
strokeLinecap="round"
|
||||
/>
|
||||
<path
|
||||
d="M109.853 46.9411L59.6482 97.1457C50.2757 106.518 50.2757 121.714 59.6482 131.087V131.087C69.0208 140.459 84.2168 140.459 93.5894 131.087L143.794 80.8822"
|
||||
stroke="currentColor"
|
||||
strokeWidth="12"
|
||||
strokeLinecap="round"
|
||||
/>
|
||||
</svg>
|
||||
);
|
||||
}
|
||||
|
|
|
|||
15
client/src/components/svg/VectorIcon.tsx
Normal file
15
client/src/components/svg/VectorIcon.tsx
Normal file
|
|
@ -0,0 +1,15 @@
|
|||
export default function VectorIcon({ className }: { className?: string }) {
|
||||
return (
|
||||
<svg
|
||||
width="20"
|
||||
height="20"
|
||||
viewBox="0 0 20 20"
|
||||
fill="currentColor"
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
className={className}
|
||||
aria-label=""
|
||||
>
|
||||
<path d="M7.45996 14.375C7.45996 13.3616 6.63844 12.54 5.625 12.54C4.61156 12.54 3.79004 13.3616 3.79004 14.375C3.79004 15.3884 4.61156 16.21 5.625 16.21C6.63844 16.21 7.45996 15.3884 7.45996 14.375ZM16.21 14.375C16.21 13.3616 15.3884 12.54 14.375 12.54C13.3616 12.54 12.54 13.3616 12.54 14.375C12.54 15.3884 13.3616 16.21 14.375 16.21C15.3884 16.21 16.21 15.3884 16.21 14.375ZM7.45996 5.625C7.45996 4.61156 6.63844 3.79004 5.625 3.79004C4.61156 3.79004 3.79004 4.61156 3.79004 5.625C3.79004 6.63844 4.61156 7.45996 5.625 7.45996C6.63844 7.45996 7.45996 6.63844 7.45996 5.625ZM16.21 5.625C16.21 4.61156 15.3884 3.79004 14.375 3.79004C13.3616 3.79004 12.54 4.61156 12.54 5.625C12.54 6.63844 13.3616 7.45996 14.375 7.45996C15.3884 7.45996 16.21 6.63844 16.21 5.625ZM17.54 14.375C17.54 16.123 16.123 17.54 14.375 17.54C12.627 17.54 11.21 16.123 11.21 14.375C11.21 12.627 12.627 11.21 14.375 11.21C16.123 11.21 17.54 12.627 17.54 14.375ZM8.79004 5.625C8.79004 7.37298 7.37298 8.79004 5.625 8.79004C3.87702 8.79004 2.45996 7.37298 2.45996 5.625C2.45996 3.87702 3.87702 2.45996 5.625 2.45996C7.37298 2.45996 8.79004 3.87702 8.79004 5.625ZM17.54 5.625C17.54 7.37298 16.123 8.79004 14.375 8.79004C13.7416 8.79004 13.153 8.60173 12.6582 8.28125L8.28125 12.6582C8.60173 13.153 8.79004 13.7416 8.79004 14.375C8.79004 16.123 7.37298 17.54 5.625 17.54C3.87702 17.54 2.45996 16.123 2.45996 14.375C2.45996 12.627 3.87702 11.21 5.625 11.21C6.25794 11.21 6.84623 11.3977 7.34082 11.7178L11.7178 7.34082C11.3977 6.84623 11.21 6.25794 11.21 5.625C11.21 3.87702 12.627 2.45996 14.375 2.45996C16.123 2.45996 17.54 3.87702 17.54 5.625Z" />
|
||||
</svg>
|
||||
);
|
||||
}
|
||||
|
|
@ -63,3 +63,5 @@ export { default as ThumbDownIcon } from './ThumbDownIcon';
|
|||
export { default as StarIcon } from './StarIcon';
|
||||
export { default as XAIcon } from './XAIcon';
|
||||
export { default as PersonalizationIcon } from './PersonalizationIcon';
|
||||
export { default as MCPIcon } from './MCPIcon';
|
||||
export { default as VectorIcon } from './VectorIcon';
|
||||
|
|
|
|||
|
|
@ -9,11 +9,15 @@ const CheckboxButton = React.forwardRef<
|
|||
icon?: React.ReactNode;
|
||||
label: string;
|
||||
className?: string;
|
||||
checked?: boolean;
|
||||
defaultChecked?: boolean;
|
||||
isCheckedClassName?: string;
|
||||
setValue?: (e: React.ChangeEvent<HTMLInputElement>, isChecked: boolean) => void;
|
||||
setValue?: (values: {
|
||||
e?: React.ChangeEvent<HTMLInputElement>;
|
||||
value: boolean | string;
|
||||
}) => void;
|
||||
}
|
||||
>(({ icon, label, setValue, className, defaultChecked, isCheckedClassName }, ref) => {
|
||||
>(({ icon, label, setValue, className, checked, defaultChecked, isCheckedClassName }, ref) => {
|
||||
const checkbox = useCheckboxStore();
|
||||
const isChecked = useStoreState(checkbox, (state) => state?.value);
|
||||
const onChange = (e: React.ChangeEvent<HTMLInputElement>) => {
|
||||
|
|
@ -21,20 +25,28 @@ const CheckboxButton = React.forwardRef<
|
|||
if (typeof isChecked !== 'boolean') {
|
||||
return;
|
||||
}
|
||||
setValue?.(e, !isChecked);
|
||||
setValue?.({ e, value: !isChecked });
|
||||
};
|
||||
|
||||
// Sync with controlled checked prop
|
||||
useEffect(() => {
|
||||
if (defaultChecked) {
|
||||
if (checked !== undefined) {
|
||||
checkbox.setValue(checked);
|
||||
}
|
||||
}, [checked, checkbox]);
|
||||
|
||||
// Set initial value from defaultChecked
|
||||
useEffect(() => {
|
||||
if (defaultChecked !== undefined && checked === undefined) {
|
||||
checkbox.setValue(defaultChecked);
|
||||
}
|
||||
}, [defaultChecked, checkbox]);
|
||||
}, [defaultChecked, checked, checkbox]);
|
||||
|
||||
return (
|
||||
<Checkbox
|
||||
ref={ref}
|
||||
store={checkbox}
|
||||
onChange={onChange}
|
||||
defaultChecked={defaultChecked}
|
||||
className={cn(
|
||||
// Base styling from MultiSelect's selectClassName
|
||||
'group relative inline-flex items-center justify-center gap-1.5',
|
||||
|
|
|
|||
|
|
@ -1,31 +0,0 @@
|
|||
export default function MCPIcon({ className }: { className?: string }) {
|
||||
return (
|
||||
<svg
|
||||
width="195"
|
||||
height="195"
|
||||
viewBox="0 2 195 195"
|
||||
fill="none"
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
className={className}
|
||||
>
|
||||
<path
|
||||
d="M25 97.8528L92.8823 29.9706C102.255 20.598 117.451 20.598 126.823 29.9706V29.9706C136.196 39.3431 136.196 54.5391 126.823 63.9117L75.5581 115.177"
|
||||
stroke="currentColor"
|
||||
strokeWidth="12"
|
||||
strokeLinecap="round"
|
||||
/>
|
||||
<path
|
||||
d="M76.2653 114.47L126.823 63.9117C136.196 54.5391 151.392 54.5391 160.765 63.9117L161.118 64.2652C170.491 73.6378 170.491 88.8338 161.118 98.2063L99.7248 159.6C96.6006 162.724 96.6006 167.789 99.7248 170.913L112.331 183.52"
|
||||
stroke="currentColor"
|
||||
strokeWidth="12"
|
||||
strokeLinecap="round"
|
||||
/>
|
||||
<path
|
||||
d="M109.853 46.9411L59.6482 97.1457C50.2757 106.518 50.2757 121.714 59.6482 131.087V131.087C69.0208 140.459 84.2168 140.459 93.5894 131.087L143.794 80.8822"
|
||||
stroke="currentColor"
|
||||
strokeWidth="12"
|
||||
strokeLinecap="round"
|
||||
/>
|
||||
</svg>
|
||||
);
|
||||
}
|
||||
|
|
@ -5,16 +5,26 @@ import { cn } from '~/utils';
|
|||
|
||||
interface OGDialogProps extends DialogPrimitive.DialogProps {
|
||||
triggerRef?: React.RefObject<HTMLButtonElement | HTMLInputElement | null>;
|
||||
triggerRefs?: React.RefObject<HTMLButtonElement | HTMLInputElement | null>[];
|
||||
}
|
||||
|
||||
const Dialog = React.forwardRef<HTMLDivElement, OGDialogProps>(
|
||||
({ children, triggerRef, onOpenChange, ...props }, _ref) => {
|
||||
({ children, triggerRef, triggerRefs, onOpenChange, ...props }, _ref) => {
|
||||
const handleOpenChange = (open: boolean) => {
|
||||
if (!open && triggerRef?.current) {
|
||||
setTimeout(() => {
|
||||
triggerRef.current?.focus();
|
||||
}, 0);
|
||||
}
|
||||
if (triggerRefs?.length) {
|
||||
triggerRefs.forEach((ref) => {
|
||||
if (ref?.current) {
|
||||
setTimeout(() => {
|
||||
ref.current?.focus();
|
||||
}, 0);
|
||||
}
|
||||
});
|
||||
}
|
||||
onOpenChange?.(open);
|
||||
};
|
||||
|
||||
|
|
|
|||
|
|
@ -1,3 +1,4 @@
|
|||
export * from './Accordion';
|
||||
export * from './AnimatedTabs';
|
||||
export * from './AlertDialog';
|
||||
export * from './Breadcrumb';
|
||||
|
|
@ -28,7 +29,6 @@ export * from './Pagination';
|
|||
export * from './Progress';
|
||||
export * from './InputOTP';
|
||||
export { default as Badge } from './Badge';
|
||||
export { default as MCPIcon } from './MCPIcon';
|
||||
export { default as Combobox } from './Combobox';
|
||||
export { default as Dropdown } from './Dropdown';
|
||||
export { default as SplitText } from './SplitText';
|
||||
|
|
|
|||
|
|
@ -2,15 +2,16 @@ import {
|
|||
QueryKeys,
|
||||
dataService,
|
||||
EModelEndpoint,
|
||||
isAgentsEndpoint,
|
||||
defaultOrderQuery,
|
||||
defaultAssistantsVersion,
|
||||
} from 'librechat-data-provider';
|
||||
import { useQuery, useInfiniteQuery, useQueryClient } from '@tanstack/react-query';
|
||||
import type {
|
||||
InfiniteData,
|
||||
UseInfiniteQueryOptions,
|
||||
QueryObserverResult,
|
||||
UseQueryOptions,
|
||||
InfiniteData,
|
||||
} from '@tanstack/react-query';
|
||||
import type t from 'librechat-data-provider';
|
||||
import type {
|
||||
|
|
@ -203,7 +204,7 @@ export const useAvailableToolsQuery = <TData = t.TPlugin[]>(
|
|||
const keyExpiry = queryClient.getQueryData<TCheckUserKeyResponse>([QueryKeys.name, endpoint]);
|
||||
const userProvidesKey = !!endpointsConfig?.[endpoint]?.userProvide;
|
||||
const keyProvided = userProvidesKey ? !!keyExpiry?.expiresAt : true;
|
||||
const enabled = !!endpointsConfig?.[endpoint] && keyProvided;
|
||||
const enabled = isAgentsEndpoint(endpoint) ? true : !!endpointsConfig?.[endpoint] && keyProvided;
|
||||
const version: string | number | undefined =
|
||||
endpointsConfig?.[endpoint]?.version ?? defaultAssistantsVersion[endpoint];
|
||||
return useQuery<t.TPlugin[], unknown, TData>(
|
||||
|
|
|
|||
|
|
@ -1,2 +1,4 @@
|
|||
export { default as useAgentsMap } from './useAgentsMap';
|
||||
export { default as useSelectAgent } from './useSelectAgent';
|
||||
export { default as useAgentCapabilities } from './useAgentCapabilities';
|
||||
export { default as useGetAgentsConfig } from './useGetAgentsConfig';
|
||||
|
|
|
|||
61
client/src/hooks/Agents/useAgentCapabilities.ts
Normal file
61
client/src/hooks/Agents/useAgentCapabilities.ts
Normal file
|
|
@ -0,0 +1,61 @@
|
|||
import { useMemo } from 'react';
|
||||
import { AgentCapabilities } from 'librechat-data-provider';
|
||||
|
||||
interface AgentCapabilitiesResult {
|
||||
toolsEnabled: boolean;
|
||||
actionsEnabled: boolean;
|
||||
artifactsEnabled: boolean;
|
||||
ocrEnabled: boolean;
|
||||
fileSearchEnabled: boolean;
|
||||
webSearchEnabled: boolean;
|
||||
codeEnabled: boolean;
|
||||
}
|
||||
|
||||
export default function useAgentCapabilities(
|
||||
capabilities: AgentCapabilities[] | undefined,
|
||||
): AgentCapabilitiesResult {
|
||||
const toolsEnabled = useMemo(
|
||||
() => capabilities?.includes(AgentCapabilities.tools) ?? false,
|
||||
[capabilities],
|
||||
);
|
||||
|
||||
const actionsEnabled = useMemo(
|
||||
() => capabilities?.includes(AgentCapabilities.actions) ?? false,
|
||||
[capabilities],
|
||||
);
|
||||
|
||||
const artifactsEnabled = useMemo(
|
||||
() => capabilities?.includes(AgentCapabilities.artifacts) ?? false,
|
||||
[capabilities],
|
||||
);
|
||||
|
||||
const ocrEnabled = useMemo(
|
||||
() => capabilities?.includes(AgentCapabilities.ocr) ?? false,
|
||||
[capabilities],
|
||||
);
|
||||
|
||||
const fileSearchEnabled = useMemo(
|
||||
() => capabilities?.includes(AgentCapabilities.file_search) ?? false,
|
||||
[capabilities],
|
||||
);
|
||||
|
||||
const webSearchEnabled = useMemo(
|
||||
() => capabilities?.includes(AgentCapabilities.web_search) ?? false,
|
||||
[capabilities],
|
||||
);
|
||||
|
||||
const codeEnabled = useMemo(
|
||||
() => capabilities?.includes(AgentCapabilities.execute_code) ?? false,
|
||||
[capabilities],
|
||||
);
|
||||
|
||||
return {
|
||||
ocrEnabled,
|
||||
codeEnabled,
|
||||
toolsEnabled,
|
||||
actionsEnabled,
|
||||
artifactsEnabled,
|
||||
webSearchEnabled,
|
||||
fileSearchEnabled,
|
||||
};
|
||||
}
|
||||
35
client/src/hooks/Agents/useGetAgentsConfig.ts
Normal file
35
client/src/hooks/Agents/useGetAgentsConfig.ts
Normal file
|
|
@ -0,0 +1,35 @@
|
|||
import { useMemo } from 'react';
|
||||
import { EModelEndpoint, AgentCapabilities } from 'librechat-data-provider';
|
||||
import type { TAgentsEndpoint, TEndpointsConfig, TConfig } from 'librechat-data-provider';
|
||||
import { useGetEndpointsQuery } from '~/data-provider';
|
||||
|
||||
interface UseGetAgentsConfigOptions {
|
||||
endpointsConfig?: TEndpointsConfig;
|
||||
}
|
||||
|
||||
export default function useGetAgentsConfig(options?: UseGetAgentsConfigOptions): {
|
||||
agentsConfig?: TAgentsEndpoint | null;
|
||||
endpointsConfig?: TEndpointsConfig | null;
|
||||
} {
|
||||
const { endpointsConfig: providedConfig } = options || {};
|
||||
|
||||
const { data: queriedConfig } = useGetEndpointsQuery({
|
||||
enabled: !providedConfig,
|
||||
});
|
||||
|
||||
const endpointsConfig = providedConfig || queriedConfig;
|
||||
|
||||
const agentsConfig = useMemo<TAgentsEndpoint | null>(() => {
|
||||
const config = endpointsConfig?.[EModelEndpoint.agents] ?? null;
|
||||
if (!config) return null;
|
||||
|
||||
return {
|
||||
...(config as TConfig),
|
||||
capabilities: Array.isArray(config.capabilities)
|
||||
? config.capabilities.map((cap) => cap as unknown as AgentCapabilities)
|
||||
: ([] as AgentCapabilities[]),
|
||||
} as TAgentsEndpoint;
|
||||
}, [endpointsConfig]);
|
||||
|
||||
return { agentsConfig, endpointsConfig };
|
||||
}
|
||||
|
|
@ -6,6 +6,7 @@ import {
|
|||
QueryKeys,
|
||||
ContentTypes,
|
||||
EModelEndpoint,
|
||||
isAgentsEndpoint,
|
||||
parseCompactConvo,
|
||||
replaceSpecialVars,
|
||||
isAssistantsEndpoint,
|
||||
|
|
@ -24,7 +25,6 @@ import type { TAskFunction, ExtendedFile } from '~/common';
|
|||
import useSetFilesToDelete from '~/hooks/Files/useSetFilesToDelete';
|
||||
import useGetSender from '~/hooks/Conversations/useGetSender';
|
||||
import store, { useGetEphemeralAgent } from '~/store';
|
||||
import { getArtifactsMode } from '~/utils/artifacts';
|
||||
import { getEndpointField, logger } from '~/utils';
|
||||
import useUserKey from '~/hooks/Input/useUserKey';
|
||||
import { useNavigate } from 'react-router-dom';
|
||||
|
|
@ -36,15 +36,6 @@ const logChatRequest = (request: Record<string, unknown>) => {
|
|||
logger.log('=====================================');
|
||||
};
|
||||
|
||||
const usesContentStream = (endpoint: EModelEndpoint | undefined, endpointType?: string) => {
|
||||
if (endpointType === EModelEndpoint.custom) {
|
||||
return true;
|
||||
}
|
||||
if (endpoint === EModelEndpoint.openAI || endpoint === EModelEndpoint.azureOpenAI) {
|
||||
return true;
|
||||
}
|
||||
};
|
||||
|
||||
export default function useChatFunctions({
|
||||
index = 0,
|
||||
files,
|
||||
|
|
@ -76,9 +67,6 @@ export default function useChatFunctions({
|
|||
const setFilesToDelete = useSetFilesToDelete();
|
||||
const getEphemeralAgent = useGetEphemeralAgent();
|
||||
const isTemporary = useRecoilValue(store.isTemporary);
|
||||
const codeArtifacts = useRecoilValue(store.codeArtifacts);
|
||||
const includeShadcnui = useRecoilValue(store.includeShadcnui);
|
||||
const customPromptMode = useRecoilValue(store.customPromptMode);
|
||||
const { getExpiry } = useUserKey(immutableConversation?.endpoint ?? '');
|
||||
const setShowStopButton = useSetRecoilState(store.showStopButtonByIndex(index));
|
||||
const resetLatestMultiMessage = useResetRecoilState(store.latestMessageFamily(index + 1));
|
||||
|
|
@ -93,7 +81,7 @@ export default function useChatFunctions({
|
|||
messageId = null,
|
||||
},
|
||||
{
|
||||
editedText = null,
|
||||
editedContent = null,
|
||||
editedMessageId = null,
|
||||
isResubmission = false,
|
||||
isRegenerate = false,
|
||||
|
|
@ -195,10 +183,6 @@ export default function useChatFunctions({
|
|||
endpointType,
|
||||
overrideConvoId,
|
||||
overrideUserMessageId,
|
||||
artifacts:
|
||||
endpoint !== EModelEndpoint.agents
|
||||
? getArtifactsMode({ codeArtifacts, includeShadcnui, customPromptMode })
|
||||
: undefined,
|
||||
},
|
||||
convo,
|
||||
) as TEndpointOption;
|
||||
|
|
@ -245,14 +229,11 @@ export default function useChatFunctions({
|
|||
setFilesToDelete({});
|
||||
}
|
||||
|
||||
const generation = editedText ?? latestMessage?.text ?? '';
|
||||
const responseText = isEditOrContinue ? generation : '';
|
||||
|
||||
const responseMessageId =
|
||||
editedMessageId ?? (latestMessage?.messageId ? latestMessage?.messageId + '_' : null) ?? null;
|
||||
const initialResponse: TMessage = {
|
||||
sender: responseSender,
|
||||
text: responseText,
|
||||
text: '',
|
||||
endpoint: endpoint ?? '',
|
||||
parentMessageId: isRegenerate ? messageId : intermediateId,
|
||||
messageId: responseMessageId ?? `${isRegenerate ? messageId : intermediateId}_`,
|
||||
|
|
@ -272,34 +253,37 @@ export default function useChatFunctions({
|
|||
{
|
||||
type: ContentTypes.TEXT,
|
||||
[ContentTypes.TEXT]: {
|
||||
value: responseText,
|
||||
value: '',
|
||||
},
|
||||
},
|
||||
];
|
||||
} else if (endpoint === EModelEndpoint.agents) {
|
||||
initialResponse.model = conversation?.agent_id ?? '';
|
||||
} else if (endpoint != null) {
|
||||
initialResponse.model = isAgentsEndpoint(endpoint)
|
||||
? (conversation?.agent_id ?? '')
|
||||
: (conversation?.model ?? '');
|
||||
initialResponse.text = '';
|
||||
initialResponse.content = [
|
||||
{
|
||||
type: ContentTypes.TEXT,
|
||||
[ContentTypes.TEXT]: {
|
||||
value: responseText,
|
||||
|
||||
if (editedContent && latestMessage?.content) {
|
||||
initialResponse.content = cloneDeep(latestMessage.content);
|
||||
const { index, text, type } = editedContent;
|
||||
if (initialResponse.content && index >= 0 && index < initialResponse.content.length) {
|
||||
const contentPart = initialResponse.content[index];
|
||||
if (type === ContentTypes.THINK && contentPart.type === ContentTypes.THINK) {
|
||||
contentPart[ContentTypes.THINK] = text;
|
||||
} else if (type === ContentTypes.TEXT && contentPart.type === ContentTypes.TEXT) {
|
||||
contentPart[ContentTypes.TEXT] = text;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
initialResponse.content = [
|
||||
{
|
||||
type: ContentTypes.TEXT,
|
||||
[ContentTypes.TEXT]: {
|
||||
value: '',
|
||||
},
|
||||
},
|
||||
},
|
||||
];
|
||||
setShowStopButton(true);
|
||||
} else if (usesContentStream(endpoint, endpointType)) {
|
||||
initialResponse.text = '';
|
||||
initialResponse.content = [
|
||||
{
|
||||
type: ContentTypes.TEXT,
|
||||
[ContentTypes.TEXT]: {
|
||||
value: responseText,
|
||||
},
|
||||
},
|
||||
];
|
||||
setShowStopButton(true);
|
||||
} else {
|
||||
];
|
||||
}
|
||||
setShowStopButton(true);
|
||||
}
|
||||
|
||||
|
|
@ -316,7 +300,6 @@ export default function useChatFunctions({
|
|||
endpointOption,
|
||||
userMessage: {
|
||||
...currentMsg,
|
||||
generation,
|
||||
responseMessageId,
|
||||
overrideParentMessageId: isRegenerate ? messageId : null,
|
||||
},
|
||||
|
|
@ -328,6 +311,7 @@ export default function useChatFunctions({
|
|||
initialResponse,
|
||||
isTemporary,
|
||||
ephemeralAgent,
|
||||
editedContent,
|
||||
};
|
||||
|
||||
if (isRegenerate) {
|
||||
|
|
|
|||
|
|
@ -30,6 +30,14 @@ const useSetIndexOptions: TUseSetOptions = (preset = false) => {
|
|||
};
|
||||
}
|
||||
|
||||
// Auto-enable Responses API when web search is enabled
|
||||
if (param === 'web_search' && newValue === true) {
|
||||
const currentUseResponsesApi = conversation?.useResponsesApi ?? false;
|
||||
if (!currentUseResponsesApi) {
|
||||
update['useResponsesApi'] = true;
|
||||
}
|
||||
}
|
||||
|
||||
setConversation(
|
||||
(prevState) =>
|
||||
tConvoUpdateSchema.parse({
|
||||
|
|
|
|||
84
client/src/hooks/Files/useClientResize.ts
Normal file
84
client/src/hooks/Files/useClientResize.ts
Normal file
|
|
@ -0,0 +1,84 @@
|
|||
import { mergeFileConfig } from 'librechat-data-provider';
|
||||
import { useCallback } from 'react';
|
||||
import { useGetFileConfig } from '~/data-provider';
|
||||
import {
|
||||
resizeImage,
|
||||
shouldResizeImage,
|
||||
supportsClientResize,
|
||||
type ResizeOptions,
|
||||
type ResizeResult,
|
||||
} from '~/utils/imageResize';
|
||||
|
||||
/**
|
||||
* Hook for client-side image resizing functionality
|
||||
* Integrates with LibreChat's file configuration system
|
||||
*/
|
||||
export const useClientResize = () => {
|
||||
const { data: fileConfig = null } = useGetFileConfig({
|
||||
select: (data) => mergeFileConfig(data),
|
||||
});
|
||||
|
||||
// Safe access to clientImageResize config with fallbacks
|
||||
// eslint-disable-next-line react-hooks/exhaustive-deps
|
||||
const config = (fileConfig as any)?.clientImageResize ?? {
|
||||
enabled: false,
|
||||
maxWidth: 1900,
|
||||
maxHeight: 1900,
|
||||
quality: 0.92,
|
||||
};
|
||||
const isEnabled = config?.enabled ?? false;
|
||||
|
||||
/**
|
||||
* Resizes an image if client-side resizing is enabled and supported
|
||||
* @param file - The image file to resize
|
||||
* @param options - Optional resize options to override defaults
|
||||
* @returns Promise resolving to either the resized file result or original file
|
||||
*/
|
||||
const resizeImageIfNeeded = useCallback(
|
||||
async (
|
||||
file: File,
|
||||
options?: Partial<ResizeOptions>,
|
||||
): Promise<{ file: File; resized: boolean; result?: ResizeResult }> => {
|
||||
// Return original file if resizing is disabled
|
||||
if (!isEnabled) {
|
||||
return { file, resized: false };
|
||||
}
|
||||
|
||||
// Return original file if browser doesn't support resizing
|
||||
if (!supportsClientResize()) {
|
||||
console.warn('Client-side image resizing not supported in this browser');
|
||||
return { file, resized: false };
|
||||
}
|
||||
|
||||
// Return original file if it doesn't need resizing
|
||||
if (!shouldResizeImage(file)) {
|
||||
return { file, resized: false };
|
||||
}
|
||||
|
||||
try {
|
||||
const resizeOptions: Partial<ResizeOptions> = {
|
||||
maxWidth: config?.maxWidth,
|
||||
maxHeight: config?.maxHeight,
|
||||
quality: config?.quality,
|
||||
...options,
|
||||
};
|
||||
|
||||
const result = await resizeImage(file, resizeOptions);
|
||||
return { file: result.file, resized: true, result };
|
||||
} catch (error) {
|
||||
console.warn('Client-side image resizing failed:', error);
|
||||
return { file, resized: false };
|
||||
}
|
||||
},
|
||||
[isEnabled, config],
|
||||
);
|
||||
|
||||
return {
|
||||
isEnabled,
|
||||
isSupported: supportsClientResize(),
|
||||
config,
|
||||
resizeImageIfNeeded,
|
||||
};
|
||||
};
|
||||
|
||||
export default useClientResize;
|
||||
|
|
@ -1,43 +1,46 @@
|
|||
import { useState, useMemo } from 'react';
|
||||
import { useDrop } from 'react-dnd';
|
||||
import { useRecoilValue } from 'recoil';
|
||||
import { NativeTypes } from 'react-dnd-html5-backend';
|
||||
import { useQueryClient } from '@tanstack/react-query';
|
||||
import { useRecoilValue, useSetRecoilState } from 'recoil';
|
||||
import {
|
||||
Constants,
|
||||
QueryKeys,
|
||||
Constants,
|
||||
EModelEndpoint,
|
||||
isAgentsEndpoint,
|
||||
isEphemeralAgent,
|
||||
EToolResources,
|
||||
AgentCapabilities,
|
||||
isAssistantsEndpoint,
|
||||
} from 'librechat-data-provider';
|
||||
import type * as t from 'librechat-data-provider';
|
||||
import type { DropTargetMonitor } from 'react-dnd';
|
||||
import useFileHandling from './useFileHandling';
|
||||
import type * as t from 'librechat-data-provider';
|
||||
import store, { ephemeralAgentByConvoId } from '~/store';
|
||||
import useFileHandling from './useFileHandling';
|
||||
|
||||
export default function useDragHelpers() {
|
||||
const queryClient = useQueryClient();
|
||||
const [showModal, setShowModal] = useState(false);
|
||||
const [draggedFiles, setDraggedFiles] = useState<File[]>([]);
|
||||
const conversation = useRecoilValue(store.conversationByIndex(0)) || undefined;
|
||||
const key = useMemo(
|
||||
() => conversation?.conversationId ?? Constants.NEW_CONVO,
|
||||
[conversation?.conversationId],
|
||||
const setEphemeralAgent = useSetRecoilState(
|
||||
ephemeralAgentByConvoId(conversation?.conversationId ?? Constants.NEW_CONVO),
|
||||
);
|
||||
const ephemeralAgent = useRecoilValue(ephemeralAgentByConvoId(key));
|
||||
|
||||
const handleOptionSelect = (toolResource: string | undefined) => {
|
||||
const handleOptionSelect = (toolResource: EToolResources | undefined) => {
|
||||
/** File search is not automatically enabled to simulate legacy behavior */
|
||||
if (toolResource && toolResource !== EToolResources.file_search) {
|
||||
setEphemeralAgent((prev) => ({
|
||||
...prev,
|
||||
[toolResource]: true,
|
||||
}));
|
||||
}
|
||||
handleFiles(draggedFiles, toolResource);
|
||||
setShowModal(false);
|
||||
setDraggedFiles([]);
|
||||
};
|
||||
|
||||
const isAgents = useMemo(
|
||||
() =>
|
||||
isAgentsEndpoint(conversation?.endpoint) ||
|
||||
isEphemeralAgent(conversation?.endpoint, ephemeralAgent),
|
||||
[conversation?.endpoint, ephemeralAgent],
|
||||
() => !isAssistantsEndpoint(conversation?.endpoint),
|
||||
[conversation?.endpoint],
|
||||
);
|
||||
|
||||
const { handleFiles } = useFileHandling({
|
||||
|
|
|
|||
|
|
@ -1,31 +1,33 @@
|
|||
import { useQueryClient } from '@tanstack/react-query';
|
||||
import type { TEndpointsConfig, TError } from 'librechat-data-provider';
|
||||
import {
|
||||
defaultAssistantsVersion,
|
||||
fileConfig as defaultFileConfig,
|
||||
EModelEndpoint,
|
||||
isAgentsEndpoint,
|
||||
isAssistantsEndpoint,
|
||||
mergeFileConfig,
|
||||
QueryKeys,
|
||||
} from 'librechat-data-provider';
|
||||
import debounce from 'lodash/debounce';
|
||||
import React, { useCallback, useEffect, useMemo, useRef, useState } from 'react';
|
||||
import { v4 } from 'uuid';
|
||||
import { useQueryClient } from '@tanstack/react-query';
|
||||
import {
|
||||
QueryKeys,
|
||||
EModelEndpoint,
|
||||
mergeFileConfig,
|
||||
isAgentsEndpoint,
|
||||
isAssistantsEndpoint,
|
||||
defaultAssistantsVersion,
|
||||
fileConfig as defaultFileConfig,
|
||||
} from 'librechat-data-provider';
|
||||
import debounce from 'lodash/debounce';
|
||||
import type { EndpointFileConfig, TEndpointsConfig, TError } from 'librechat-data-provider';
|
||||
import type { ExtendedFile, FileSetter } from '~/common';
|
||||
import { useGetFileConfig, useUploadFileMutation } from '~/data-provider';
|
||||
import useLocalize, { TranslationKeys } from '~/hooks/useLocalize';
|
||||
import { useChatContext } from '~/Providers/ChatContext';
|
||||
import { useToastContext } from '~/Providers/ToastContext';
|
||||
import { logger, validateFiles } from '~/utils';
|
||||
import { processFileForUpload } from '~/utils/heicConverter';
|
||||
import { useDelayedUploadToast } from './useDelayedUploadToast';
|
||||
import { processFileForUpload } from '~/utils/heicConverter';
|
||||
import { useToastContext } from '~/Providers/ToastContext';
|
||||
import { useChatContext } from '~/Providers/ChatContext';
|
||||
import { logger, validateFiles } from '~/utils';
|
||||
import useClientResize from './useClientResize';
|
||||
import useUpdateFiles from './useUpdateFiles';
|
||||
|
||||
type UseFileHandling = {
|
||||
overrideEndpoint?: EModelEndpoint;
|
||||
fileSetter?: FileSetter;
|
||||
overrideEndpoint?: EModelEndpoint;
|
||||
fileFilter?: (file: File) => boolean;
|
||||
overrideEndpointFileConfig?: EndpointFileConfig;
|
||||
additionalMetadata?: Record<string, string | undefined>;
|
||||
};
|
||||
|
||||
|
|
@ -41,6 +43,7 @@ const useFileHandling = (params?: UseFileHandling) => {
|
|||
const { addFile, replaceFile, updateFileById, deleteFileById } = useUpdateFiles(
|
||||
params?.fileSetter ?? setFiles,
|
||||
);
|
||||
const { resizeImageIfNeeded } = useClientResize();
|
||||
|
||||
const agent_id = params?.additionalMetadata?.agent_id ?? '';
|
||||
const assistant_id = params?.additionalMetadata?.assistant_id ?? '';
|
||||
|
|
@ -148,6 +151,10 @@ const useFileHandling = (params?: UseFileHandling) => {
|
|||
|
||||
const formData = new FormData();
|
||||
formData.append('endpoint', endpoint);
|
||||
formData.append(
|
||||
'original_endpoint',
|
||||
conversation?.endpointType || conversation?.endpoint || '',
|
||||
);
|
||||
formData.append('file', extendedFile.file as File, encodeURIComponent(filename));
|
||||
formData.append('file_id', extendedFile.file_id);
|
||||
|
||||
|
|
@ -244,8 +251,9 @@ const useFileHandling = (params?: UseFileHandling) => {
|
|||
fileList,
|
||||
setError,
|
||||
endpointFileConfig:
|
||||
fileConfig?.endpoints[endpoint] ??
|
||||
fileConfig?.endpoints.default ??
|
||||
params?.overrideEndpointFileConfig ??
|
||||
fileConfig?.endpoints?.[endpoint] ??
|
||||
fileConfig?.endpoints?.default ??
|
||||
defaultFileConfig.endpoints[endpoint] ??
|
||||
defaultFileConfig.endpoints.default,
|
||||
});
|
||||
|
|
@ -298,7 +306,7 @@ const useFileHandling = (params?: UseFileHandling) => {
|
|||
}
|
||||
|
||||
// Process file for HEIC conversion if needed
|
||||
const processedFile = await processFileForUpload(
|
||||
const heicProcessedFile = await processFileForUpload(
|
||||
originalFile,
|
||||
0.9,
|
||||
(conversionProgress) => {
|
||||
|
|
@ -311,23 +319,50 @@ const useFileHandling = (params?: UseFileHandling) => {
|
|||
},
|
||||
);
|
||||
|
||||
// If file was converted, update with new file and preview
|
||||
if (processedFile !== originalFile) {
|
||||
let finalProcessedFile = heicProcessedFile;
|
||||
|
||||
// Apply client-side resizing if available and appropriate
|
||||
if (heicProcessedFile.type.startsWith('image/')) {
|
||||
try {
|
||||
const resizeResult = await resizeImageIfNeeded(heicProcessedFile);
|
||||
finalProcessedFile = resizeResult.file;
|
||||
|
||||
// Show toast notification if image was resized
|
||||
if (resizeResult.resized && resizeResult.result) {
|
||||
const { originalSize, newSize, compressionRatio } = resizeResult.result;
|
||||
const originalSizeMB = (originalSize / (1024 * 1024)).toFixed(1);
|
||||
const newSizeMB = (newSize / (1024 * 1024)).toFixed(1);
|
||||
const savedPercent = Math.round((1 - compressionRatio) * 100);
|
||||
|
||||
showToast({
|
||||
message: `Image resized: ${originalSizeMB}MB → ${newSizeMB}MB (${savedPercent}% smaller)`,
|
||||
status: 'success',
|
||||
duration: 3000,
|
||||
});
|
||||
}
|
||||
} catch (resizeError) {
|
||||
console.warn('Image resize failed, using original:', resizeError);
|
||||
// Continue with HEIC processed file if resizing fails
|
||||
}
|
||||
}
|
||||
|
||||
// If file was processed (HEIC converted or resized), update with new file and preview
|
||||
if (finalProcessedFile !== originalFile) {
|
||||
URL.revokeObjectURL(initialPreview); // Clean up original preview
|
||||
const newPreview = URL.createObjectURL(processedFile);
|
||||
const newPreview = URL.createObjectURL(finalProcessedFile);
|
||||
|
||||
const updatedExtendedFile: ExtendedFile = {
|
||||
...initialExtendedFile,
|
||||
file: processedFile,
|
||||
type: processedFile.type,
|
||||
file: finalProcessedFile,
|
||||
type: finalProcessedFile.type,
|
||||
preview: newPreview,
|
||||
progress: 0.5, // Conversion complete, ready for upload
|
||||
size: processedFile.size,
|
||||
progress: 0.5, // Processing complete, ready for upload
|
||||
size: finalProcessedFile.size,
|
||||
};
|
||||
|
||||
replaceFile(updatedExtendedFile);
|
||||
|
||||
const isImage = processedFile.type.split('/')[0] === 'image';
|
||||
const isImage = finalProcessedFile.type.split('/')[0] === 'image';
|
||||
if (isImage) {
|
||||
loadImage(updatedExtendedFile, newPreview);
|
||||
continue;
|
||||
|
|
@ -335,7 +370,7 @@ const useFileHandling = (params?: UseFileHandling) => {
|
|||
|
||||
await startUpload(updatedExtendedFile);
|
||||
} else {
|
||||
// File wasn't converted, proceed with original
|
||||
// File wasn't processed, proceed with original
|
||||
const isImage = originalFile.type.split('/')[0] === 'image';
|
||||
const tool_resource =
|
||||
initialExtendedFile.tool_resource ?? params?.additionalMetadata?.tool_resource;
|
||||
|
|
|
|||
|
|
@ -15,12 +15,11 @@ import BookmarkPanel from '~/components/SidePanel/Bookmarks/BookmarkPanel';
|
|||
import MemoryViewer from '~/components/SidePanel/Memories/MemoryViewer';
|
||||
import PanelSwitch from '~/components/SidePanel/Builder/PanelSwitch';
|
||||
import PromptsAccordion from '~/components/Prompts/PromptsAccordion';
|
||||
import { Blocks, MCPIcon, AttachmentIcon } from '~/components/svg';
|
||||
import Parameters from '~/components/SidePanel/Parameters/Panel';
|
||||
import FilesPanel from '~/components/SidePanel/Files/Panel';
|
||||
import MCPPanel from '~/components/SidePanel/MCP/MCPPanel';
|
||||
import { Blocks, AttachmentIcon } from '~/components/svg';
|
||||
import { useGetStartupConfig } from '~/data-provider';
|
||||
import MCPIcon from '~/components/ui/MCPIcon';
|
||||
import { useHasAccess } from '~/hooks';
|
||||
|
||||
export default function useSideNavLinks({
|
||||
|
|
@ -80,7 +79,7 @@ export default function useSideNavLinks({
|
|||
title: 'com_sidepanel_assistant_builder',
|
||||
label: '',
|
||||
icon: Blocks,
|
||||
id: 'assistants',
|
||||
id: EModelEndpoint.assistants,
|
||||
Component: PanelSwitch,
|
||||
});
|
||||
}
|
||||
|
|
@ -95,7 +94,7 @@ export default function useSideNavLinks({
|
|||
title: 'com_sidepanel_agent_builder',
|
||||
label: '',
|
||||
icon: Blocks,
|
||||
id: 'agents',
|
||||
id: EModelEndpoint.agents,
|
||||
Component: AgentPanelSwitch,
|
||||
});
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,3 +1,5 @@
|
|||
export * from './useMCPSelect';
|
||||
export * from './useToolToggle';
|
||||
export { default as useAuthCodeTool } from './useAuthCodeTool';
|
||||
export { default as usePluginInstall } from './usePluginInstall';
|
||||
export { default as useCodeApiKeyForm } from './useCodeApiKeyForm';
|
||||
|
|
|
|||
|
|
@ -4,7 +4,14 @@ import { AuthType, Tools, QueryKeys } from 'librechat-data-provider';
|
|||
import { useUpdateUserPluginsMutation } from 'librechat-data-provider/react-query';
|
||||
|
||||
export type SearchApiKeyFormData = {
|
||||
// Selected options
|
||||
selectedProvider: string;
|
||||
selectedReranker: string;
|
||||
selectedScraper: string;
|
||||
// API keys and URLs
|
||||
serperApiKey: string;
|
||||
searxngInstanceUrl: string;
|
||||
searxngApiKey: string;
|
||||
firecrawlApiKey: string;
|
||||
firecrawlApiUrl: string;
|
||||
jinaApiKey: string;
|
||||
|
|
@ -42,6 +49,8 @@ const useAuthSearchTool = (options?: { isEntityTool: boolean }) => {
|
|||
(data: SearchApiKeyFormData) => {
|
||||
const auth = Object.entries({
|
||||
serperApiKey: data.serperApiKey,
|
||||
searxngInstanceUrl: data.searxngInstanceUrl,
|
||||
searxngApiKey: data.searxngApiKey,
|
||||
firecrawlApiKey: data.firecrawlApiKey,
|
||||
firecrawlApiUrl: data.firecrawlApiUrl,
|
||||
jinaApiKey: data.jinaApiKey,
|
||||
|
|
|
|||
|
|
@ -1,5 +1,5 @@
|
|||
// client/src/hooks/Plugins/useCodeApiKeyForm.ts
|
||||
import { useState, useCallback } from 'react';
|
||||
import { useRef, useState, useCallback } from 'react';
|
||||
import { useForm } from 'react-hook-form';
|
||||
import type { ApiKeyFormData } from '~/common';
|
||||
import useAuthCodeTool from '~/hooks/Plugins/useAuthCodeTool';
|
||||
|
|
@ -12,6 +12,8 @@ export default function useCodeApiKeyForm({
|
|||
onRevoke?: () => void;
|
||||
}) {
|
||||
const methods = useForm<ApiKeyFormData>();
|
||||
const menuTriggerRef = useRef<HTMLButtonElement>(null);
|
||||
const badgeTriggerRef = useRef<HTMLInputElement>(null);
|
||||
const [isDialogOpen, setIsDialogOpen] = useState(false);
|
||||
const { installTool, removeTool } = useAuthCodeTool({ isEntityTool: true });
|
||||
const { reset } = methods;
|
||||
|
|
@ -39,5 +41,7 @@ export default function useCodeApiKeyForm({
|
|||
setIsDialogOpen,
|
||||
handleRevokeApiKey,
|
||||
onSubmit: onSubmitHandler,
|
||||
badgeTriggerRef,
|
||||
menuTriggerRef,
|
||||
};
|
||||
}
|
||||
|
|
|
|||
114
client/src/hooks/Plugins/useMCPSelect.ts
Normal file
114
client/src/hooks/Plugins/useMCPSelect.ts
Normal file
|
|
@ -0,0 +1,114 @@
|
|||
import { useRef, useEffect, useCallback, useMemo } from 'react';
|
||||
import { useRecoilState } from 'recoil';
|
||||
import { Constants, LocalStorageKeys, EModelEndpoint } from 'librechat-data-provider';
|
||||
import type { TPlugin } from 'librechat-data-provider';
|
||||
import { useAvailableToolsQuery } from '~/data-provider';
|
||||
import useLocalStorage from '~/hooks/useLocalStorageAlt';
|
||||
import { ephemeralAgentByConvoId } from '~/store';
|
||||
|
||||
const storageCondition = (value: unknown, rawCurrentValue?: string | null) => {
|
||||
if (rawCurrentValue) {
|
||||
try {
|
||||
const currentValue = rawCurrentValue?.trim() ?? '';
|
||||
if (currentValue.length > 2) {
|
||||
return true;
|
||||
}
|
||||
} catch (e) {
|
||||
console.error(e);
|
||||
}
|
||||
}
|
||||
return Array.isArray(value) && value.length > 0;
|
||||
};
|
||||
|
||||
interface UseMCPSelectOptions {
|
||||
conversationId?: string | null;
|
||||
}
|
||||
|
||||
export function useMCPSelect({ conversationId }: UseMCPSelectOptions) {
|
||||
const key = conversationId ?? Constants.NEW_CONVO;
|
||||
const hasSetFetched = useRef<string | null>(null);
|
||||
const [ephemeralAgent, setEphemeralAgent] = useRecoilState(ephemeralAgentByConvoId(key));
|
||||
const { data: mcpToolDetails, isFetched } = useAvailableToolsQuery(EModelEndpoint.agents, {
|
||||
select: (data: TPlugin[]) => {
|
||||
const mcpToolsMap = new Map<string, TPlugin>();
|
||||
data.forEach((tool) => {
|
||||
const isMCP = tool.pluginKey.includes(Constants.mcp_delimiter);
|
||||
if (isMCP && tool.chatMenu !== false) {
|
||||
const parts = tool.pluginKey.split(Constants.mcp_delimiter);
|
||||
const serverName = parts[parts.length - 1];
|
||||
if (!mcpToolsMap.has(serverName)) {
|
||||
mcpToolsMap.set(serverName, {
|
||||
name: serverName,
|
||||
pluginKey: tool.pluginKey,
|
||||
authConfig: tool.authConfig,
|
||||
authenticated: tool.authenticated,
|
||||
});
|
||||
}
|
||||
}
|
||||
});
|
||||
return Array.from(mcpToolsMap.values());
|
||||
},
|
||||
});
|
||||
|
||||
const mcpState = useMemo(() => {
|
||||
return ephemeralAgent?.mcp ?? [];
|
||||
}, [ephemeralAgent?.mcp]);
|
||||
|
||||
const setSelectedValues = useCallback(
|
||||
(values: string[] | null | undefined) => {
|
||||
if (!values) {
|
||||
return;
|
||||
}
|
||||
if (!Array.isArray(values)) {
|
||||
return;
|
||||
}
|
||||
setEphemeralAgent((prev) => ({
|
||||
...prev,
|
||||
mcp: values,
|
||||
}));
|
||||
},
|
||||
[setEphemeralAgent],
|
||||
);
|
||||
|
||||
const [mcpValues, setMCPValues] = useLocalStorage<string[]>(
|
||||
`${LocalStorageKeys.LAST_MCP_}${key}`,
|
||||
mcpState,
|
||||
setSelectedValues,
|
||||
storageCondition,
|
||||
);
|
||||
|
||||
const [isPinned, setIsPinned] = useLocalStorage<boolean>(
|
||||
`${LocalStorageKeys.PIN_MCP_}${key}`,
|
||||
true,
|
||||
);
|
||||
|
||||
useEffect(() => {
|
||||
if (hasSetFetched.current === key) {
|
||||
return;
|
||||
}
|
||||
if (!isFetched) {
|
||||
return;
|
||||
}
|
||||
hasSetFetched.current = key;
|
||||
if ((mcpToolDetails?.length ?? 0) > 0) {
|
||||
setMCPValues(mcpValues.filter((mcp) => mcpToolDetails?.some((tool) => tool.name === mcp)));
|
||||
return;
|
||||
}
|
||||
setMCPValues([]);
|
||||
}, [isFetched, setMCPValues, mcpToolDetails, key, mcpValues]);
|
||||
|
||||
const mcpServerNames = useMemo(() => {
|
||||
return (mcpToolDetails ?? []).map((tool) => tool.name);
|
||||
}, [mcpToolDetails]);
|
||||
|
||||
return {
|
||||
isPinned,
|
||||
mcpValues,
|
||||
setIsPinned,
|
||||
setMCPValues,
|
||||
mcpServerNames,
|
||||
ephemeralAgent,
|
||||
mcpToolDetails,
|
||||
setEphemeralAgent,
|
||||
};
|
||||
}
|
||||
|
|
@ -1,4 +1,4 @@
|
|||
import { useState, useCallback } from 'react';
|
||||
import { useRef, useState, useCallback } from 'react';
|
||||
import { useForm } from 'react-hook-form';
|
||||
import useAuthSearchTool from '~/hooks/Plugins/useAuthSearchTool';
|
||||
import type { SearchApiKeyFormData } from '~/hooks/Plugins/useAuthSearchTool';
|
||||
|
|
@ -11,18 +11,19 @@ export default function useSearchApiKeyForm({
|
|||
onRevoke?: () => void;
|
||||
}) {
|
||||
const methods = useForm<SearchApiKeyFormData>();
|
||||
const menuTriggerRef = useRef<HTMLButtonElement>(null);
|
||||
const badgeTriggerRef = useRef<HTMLInputElement>(null);
|
||||
const [isDialogOpen, setIsDialogOpen] = useState(false);
|
||||
const { installTool, removeTool } = useAuthSearchTool({ isEntityTool: true });
|
||||
const { reset } = methods;
|
||||
|
||||
const onSubmitHandler = useCallback(
|
||||
(data: SearchApiKeyFormData) => {
|
||||
reset();
|
||||
installTool(data);
|
||||
setIsDialogOpen(false);
|
||||
onSubmit?.();
|
||||
},
|
||||
[onSubmit, reset, installTool],
|
||||
[onSubmit, installTool],
|
||||
);
|
||||
|
||||
const handleRevokeApiKey = useCallback(() => {
|
||||
|
|
@ -38,5 +39,7 @@ export default function useSearchApiKeyForm({
|
|||
setIsDialogOpen,
|
||||
handleRevokeApiKey,
|
||||
onSubmit: onSubmitHandler,
|
||||
badgeTriggerRef,
|
||||
menuTriggerRef,
|
||||
};
|
||||
}
|
||||
|
|
|
|||
131
client/src/hooks/Plugins/useToolToggle.ts
Normal file
131
client/src/hooks/Plugins/useToolToggle.ts
Normal file
|
|
@ -0,0 +1,131 @@
|
|||
import { useCallback, useMemo, useEffect } from 'react';
|
||||
import debounce from 'lodash/debounce';
|
||||
import { useRecoilState } from 'recoil';
|
||||
import { Constants, LocalStorageKeys } from 'librechat-data-provider';
|
||||
import type { VerifyToolAuthResponse } from 'librechat-data-provider';
|
||||
import type { UseQueryOptions } from '@tanstack/react-query';
|
||||
import { useVerifyAgentToolAuth } from '~/data-provider';
|
||||
import useLocalStorage from '~/hooks/useLocalStorageAlt';
|
||||
import { ephemeralAgentByConvoId } from '~/store';
|
||||
|
||||
const storageCondition = (value: unknown, rawCurrentValue?: string | null) => {
|
||||
if (rawCurrentValue) {
|
||||
try {
|
||||
const currentValue = rawCurrentValue?.trim() ?? '';
|
||||
if (currentValue === 'true' && value === false) {
|
||||
return true;
|
||||
}
|
||||
} catch (e) {
|
||||
console.error(e);
|
||||
}
|
||||
}
|
||||
return value !== undefined && value !== null;
|
||||
};
|
||||
|
||||
type ToolValue = boolean | string;
|
||||
|
||||
interface UseToolToggleOptions {
|
||||
conversationId?: string | null;
|
||||
toolKey: string;
|
||||
localStorageKey: LocalStorageKeys;
|
||||
isAuthenticated?: boolean;
|
||||
setIsDialogOpen?: (open: boolean) => void;
|
||||
/** Options for auth verification */
|
||||
authConfig?: {
|
||||
toolId: string;
|
||||
queryOptions?: UseQueryOptions<VerifyToolAuthResponse>;
|
||||
};
|
||||
}
|
||||
|
||||
export function useToolToggle({
|
||||
conversationId,
|
||||
toolKey,
|
||||
localStorageKey,
|
||||
isAuthenticated: externalIsAuthenticated,
|
||||
setIsDialogOpen,
|
||||
authConfig,
|
||||
}: UseToolToggleOptions) {
|
||||
const key = conversationId ?? Constants.NEW_CONVO;
|
||||
const [ephemeralAgent, setEphemeralAgent] = useRecoilState(ephemeralAgentByConvoId(key));
|
||||
|
||||
const authQuery = useVerifyAgentToolAuth(
|
||||
{ toolId: authConfig?.toolId || '' },
|
||||
{
|
||||
enabled: !!authConfig?.toolId,
|
||||
...authConfig?.queryOptions,
|
||||
},
|
||||
);
|
||||
|
||||
const isAuthenticated = useMemo(
|
||||
() =>
|
||||
externalIsAuthenticated ?? (authConfig ? (authQuery?.data?.authenticated ?? false) : false),
|
||||
[externalIsAuthenticated, authConfig, authQuery.data?.authenticated],
|
||||
);
|
||||
|
||||
// Keep localStorage in sync
|
||||
const [, setLocalStorageValue] = useLocalStorage<ToolValue>(
|
||||
`${localStorageKey}${key}`,
|
||||
false,
|
||||
undefined,
|
||||
storageCondition,
|
||||
);
|
||||
|
||||
// The actual current value comes from ephemeralAgent
|
||||
const toolValue = useMemo(() => {
|
||||
return ephemeralAgent?.[toolKey] ?? false;
|
||||
}, [ephemeralAgent, toolKey]);
|
||||
|
||||
const isToolEnabled = useMemo(() => {
|
||||
// For backward compatibility, treat truthy string values as enabled
|
||||
if (typeof toolValue === 'string') {
|
||||
return toolValue.length > 0;
|
||||
}
|
||||
return toolValue === true;
|
||||
}, [toolValue]);
|
||||
|
||||
// Sync to localStorage when ephemeralAgent changes
|
||||
useEffect(() => {
|
||||
const value = ephemeralAgent?.[toolKey];
|
||||
if (value !== undefined) {
|
||||
setLocalStorageValue(value);
|
||||
}
|
||||
}, [ephemeralAgent, toolKey, setLocalStorageValue]);
|
||||
|
||||
const [isPinned, setIsPinned] = useLocalStorage<boolean>(`${localStorageKey}pinned`, false);
|
||||
|
||||
const handleChange = useCallback(
|
||||
({ e, value }: { e?: React.ChangeEvent<HTMLInputElement>; value: ToolValue }) => {
|
||||
if (isAuthenticated !== undefined && !isAuthenticated && setIsDialogOpen) {
|
||||
setIsDialogOpen(true);
|
||||
e?.preventDefault?.();
|
||||
return;
|
||||
}
|
||||
|
||||
// Update ephemeralAgent (localStorage will sync automatically via effect)
|
||||
setEphemeralAgent((prev) => ({
|
||||
...(prev || {}),
|
||||
[toolKey]: value,
|
||||
}));
|
||||
},
|
||||
[setIsDialogOpen, isAuthenticated, setEphemeralAgent, toolKey],
|
||||
);
|
||||
|
||||
const debouncedChange = useMemo(
|
||||
() => debounce(handleChange, 50, { leading: true }),
|
||||
[handleChange],
|
||||
);
|
||||
|
||||
return {
|
||||
toggleState: toolValue, // Return the actual value from ephemeralAgent
|
||||
handleChange,
|
||||
isToolEnabled,
|
||||
toolValue,
|
||||
setToggleState: (value: ToolValue) => handleChange({ value }), // Adapter for direct setting
|
||||
ephemeralAgent,
|
||||
debouncedChange,
|
||||
setEphemeralAgent,
|
||||
authData: authQuery?.data,
|
||||
isPinned,
|
||||
setIsPinned,
|
||||
};
|
||||
}
|
||||
|
|
@ -68,7 +68,7 @@ const createErrorMessage = ({
|
|||
errorMetadata?: Partial<TMessage>;
|
||||
submission: EventSubmission;
|
||||
error?: Error | unknown;
|
||||
}) => {
|
||||
}): TMessage => {
|
||||
const currentMessages = getMessages();
|
||||
const latestMessage = currentMessages?.[currentMessages.length - 1];
|
||||
let errorMessage: TMessage;
|
||||
|
|
@ -123,7 +123,7 @@ const createErrorMessage = ({
|
|||
error: true,
|
||||
};
|
||||
}
|
||||
return tMessageSchema.parse(errorMessage);
|
||||
return tMessageSchema.parse(errorMessage) as TMessage;
|
||||
};
|
||||
|
||||
export const getConvoTitle = ({
|
||||
|
|
@ -374,9 +374,6 @@ export default function useEventHandlers({
|
|||
});
|
||||
|
||||
let update = {} as TConversation;
|
||||
if (conversationId) {
|
||||
applyAgentTemplate(conversationId, submission.conversation.conversationId);
|
||||
}
|
||||
if (setConversation && !isAddedRequest) {
|
||||
setConversation((prevState) => {
|
||||
const parentId = isRegenerate ? userMessage.overrideParentMessageId : parentMessageId;
|
||||
|
|
@ -411,6 +408,14 @@ export default function useEventHandlers({
|
|||
});
|
||||
}
|
||||
|
||||
if (conversationId) {
|
||||
applyAgentTemplate(
|
||||
conversationId,
|
||||
submission.conversation.conversationId,
|
||||
submission.ephemeralAgent,
|
||||
);
|
||||
}
|
||||
|
||||
if (resetLatestMessage) {
|
||||
resetLatestMessage();
|
||||
}
|
||||
|
|
@ -513,6 +518,15 @@ export default function useEventHandlers({
|
|||
}
|
||||
return update;
|
||||
});
|
||||
|
||||
if (conversation.conversationId && submission.ephemeralAgent) {
|
||||
applyAgentTemplate(
|
||||
conversation.conversationId,
|
||||
submissionConvo.conversationId,
|
||||
submission.ephemeralAgent,
|
||||
);
|
||||
}
|
||||
|
||||
if (location.pathname === '/c/new') {
|
||||
navigate(`/c/${conversation.conversationId}`, { replace: true });
|
||||
}
|
||||
|
|
@ -521,18 +535,19 @@ export default function useEventHandlers({
|
|||
setIsSubmitting(false);
|
||||
},
|
||||
[
|
||||
setShowStopButton,
|
||||
setCompleted,
|
||||
getMessages,
|
||||
announcePolite,
|
||||
navigate,
|
||||
genTitle,
|
||||
setConversation,
|
||||
isAddedRequest,
|
||||
setIsSubmitting,
|
||||
getMessages,
|
||||
setMessages,
|
||||
queryClient,
|
||||
setCompleted,
|
||||
isAddedRequest,
|
||||
announcePolite,
|
||||
setConversation,
|
||||
setIsSubmitting,
|
||||
setShowStopButton,
|
||||
location.pathname,
|
||||
navigate,
|
||||
applyAgentTemplate,
|
||||
],
|
||||
);
|
||||
|
||||
|
|
@ -550,7 +565,7 @@ export default function useEventHandlers({
|
|||
queryClient.setQueryData<TMessage[]>([QueryKeys.messages, convoId], finalMessages);
|
||||
};
|
||||
|
||||
const parseErrorResponse = (data: TResData | Partial<TMessage>) => {
|
||||
const parseErrorResponse = (data: TResData | Partial<TMessage>): TMessage => {
|
||||
const metadata = data['responseMessage'] ?? data;
|
||||
const errorMessage: Partial<TMessage> = {
|
||||
...initialResponse,
|
||||
|
|
@ -563,7 +578,7 @@ export default function useEventHandlers({
|
|||
errorMessage.messageId = v4();
|
||||
}
|
||||
|
||||
return tMessageSchema.parse(errorMessage);
|
||||
return tMessageSchema.parse(errorMessage) as TMessage;
|
||||
};
|
||||
|
||||
if (!data) {
|
||||
|
|
@ -613,7 +628,7 @@ export default function useEventHandlers({
|
|||
...data,
|
||||
error: true,
|
||||
parentMessageId: userMessage.messageId,
|
||||
});
|
||||
}) as TMessage;
|
||||
|
||||
setErrorMessages(receivedConvoId, errorResponse);
|
||||
if (receivedConvoId && paramId === Constants.NEW_CONVO && newConversation) {
|
||||
|
|
|
|||
|
|
@ -7,10 +7,8 @@ import {
|
|||
Constants,
|
||||
/* @ts-ignore */
|
||||
createPayload,
|
||||
isAgentsEndpoint,
|
||||
LocalStorageKeys,
|
||||
removeNullishValues,
|
||||
isAssistantsEndpoint,
|
||||
} from 'librechat-data-provider';
|
||||
import type { TMessage, TPayload, TSubmission, EventSubmission } from 'librechat-data-provider';
|
||||
import type { EventHandlerParams } from './useEventHandlers';
|
||||
|
|
@ -100,9 +98,7 @@ export default function useSSE(
|
|||
|
||||
const payloadData = createPayload(submission);
|
||||
let { payload } = payloadData;
|
||||
if (isAssistantsEndpoint(payload.endpoint) || isAgentsEndpoint(payload.endpoint)) {
|
||||
payload = removeNullishValues(payload) as TPayload;
|
||||
}
|
||||
payload = removeNullishValues(payload) as TPayload;
|
||||
|
||||
let textIndex = null;
|
||||
|
||||
|
|
|
|||
|
|
@ -55,6 +55,26 @@ export default function useStepHandler({
|
|||
const messageMap = useRef(new Map<string, TMessage>());
|
||||
const stepMap = useRef(new Map<string, Agents.RunStep>());
|
||||
|
||||
const calculateContentIndex = (
|
||||
baseIndex: number,
|
||||
initialContent: TMessageContentParts[],
|
||||
incomingContentType: string,
|
||||
existingContent?: TMessageContentParts[],
|
||||
): number => {
|
||||
/** Only apply -1 adjustment for TEXT or THINK types when they match existing content */
|
||||
if (
|
||||
initialContent.length > 0 &&
|
||||
(incomingContentType === ContentTypes.TEXT || incomingContentType === ContentTypes.THINK)
|
||||
) {
|
||||
const targetIndex = baseIndex + initialContent.length - 1;
|
||||
const existingType = existingContent?.[targetIndex]?.type;
|
||||
if (existingType === incomingContentType) {
|
||||
return targetIndex;
|
||||
}
|
||||
}
|
||||
return baseIndex + initialContent.length;
|
||||
};
|
||||
|
||||
const updateContent = (
|
||||
message: TMessage,
|
||||
index: number,
|
||||
|
|
@ -170,6 +190,11 @@ export default function useStepHandler({
|
|||
lastAnnouncementTimeRef.current = currentTime;
|
||||
}
|
||||
|
||||
let initialContent: TMessageContentParts[] = [];
|
||||
if (submission?.editedContent != null) {
|
||||
initialContent = submission?.initialResponse?.content ?? initialContent;
|
||||
}
|
||||
|
||||
if (event === 'on_run_step') {
|
||||
const runStep = data as Agents.RunStep;
|
||||
const responseMessageId = runStep.runId ?? '';
|
||||
|
|
@ -189,7 +214,7 @@ export default function useStepHandler({
|
|||
parentMessageId: userMessage.messageId,
|
||||
conversationId: userMessage.conversationId,
|
||||
messageId: responseMessageId,
|
||||
content: [],
|
||||
content: initialContent,
|
||||
};
|
||||
|
||||
messageMap.current.set(responseMessageId, response);
|
||||
|
|
@ -214,7 +239,9 @@ export default function useStepHandler({
|
|||
},
|
||||
};
|
||||
|
||||
updatedResponse = updateContent(updatedResponse, runStep.index, contentPart);
|
||||
/** Tool calls don't need index adjustment */
|
||||
const currentIndex = runStep.index + initialContent.length;
|
||||
updatedResponse = updateContent(updatedResponse, currentIndex, contentPart);
|
||||
});
|
||||
|
||||
messageMap.current.set(responseMessageId, updatedResponse);
|
||||
|
|
@ -234,7 +261,9 @@ export default function useStepHandler({
|
|||
|
||||
const response = messageMap.current.get(responseMessageId);
|
||||
if (response) {
|
||||
const updatedResponse = updateContent(response, agent_update.index, data);
|
||||
// Agent updates don't need index adjustment
|
||||
const currentIndex = agent_update.index + initialContent.length;
|
||||
const updatedResponse = updateContent(response, currentIndex, data);
|
||||
messageMap.current.set(responseMessageId, updatedResponse);
|
||||
const currentMessages = getMessages() || [];
|
||||
setMessages([...currentMessages.slice(0, -1), updatedResponse]);
|
||||
|
|
@ -255,7 +284,13 @@ export default function useStepHandler({
|
|||
? messageDelta.delta.content[0]
|
||||
: messageDelta.delta.content;
|
||||
|
||||
const updatedResponse = updateContent(response, runStep.index, contentPart);
|
||||
const currentIndex = calculateContentIndex(
|
||||
runStep.index,
|
||||
initialContent,
|
||||
contentPart.type || '',
|
||||
response.content,
|
||||
);
|
||||
const updatedResponse = updateContent(response, currentIndex, contentPart);
|
||||
|
||||
messageMap.current.set(responseMessageId, updatedResponse);
|
||||
const currentMessages = getMessages() || [];
|
||||
|
|
@ -277,7 +312,13 @@ export default function useStepHandler({
|
|||
? reasoningDelta.delta.content[0]
|
||||
: reasoningDelta.delta.content;
|
||||
|
||||
const updatedResponse = updateContent(response, runStep.index, contentPart);
|
||||
const currentIndex = calculateContentIndex(
|
||||
runStep.index,
|
||||
initialContent,
|
||||
contentPart.type || '',
|
||||
response.content,
|
||||
);
|
||||
const updatedResponse = updateContent(response, currentIndex, contentPart);
|
||||
|
||||
messageMap.current.set(responseMessageId, updatedResponse);
|
||||
const currentMessages = getMessages() || [];
|
||||
|
|
@ -318,7 +359,9 @@ export default function useStepHandler({
|
|||
contentPart.tool_call.expires_at = runStepDelta.delta.expires_at;
|
||||
}
|
||||
|
||||
updatedResponse = updateContent(updatedResponse, runStep.index, contentPart);
|
||||
/** Tool calls don't need index adjustment */
|
||||
const currentIndex = runStep.index + initialContent.length;
|
||||
updatedResponse = updateContent(updatedResponse, currentIndex, contentPart);
|
||||
});
|
||||
|
||||
messageMap.current.set(responseMessageId, updatedResponse);
|
||||
|
|
@ -350,7 +393,9 @@ export default function useStepHandler({
|
|||
tool_call: result.tool_call,
|
||||
};
|
||||
|
||||
updatedResponse = updateContent(updatedResponse, runStep.index, contentPart, true);
|
||||
/** Tool calls don't need index adjustment */
|
||||
const currentIndex = runStep.index + initialContent.length;
|
||||
updatedResponse = updateContent(updatedResponse, currentIndex, contentPart, true);
|
||||
|
||||
messageMap.current.set(responseMessageId, updatedResponse);
|
||||
const updatedMessages = messages.map((msg) =>
|
||||
|
|
|
|||
|
|
@ -1,4 +1,6 @@
|
|||
{
|
||||
"chat_direction_left_to_right": "شيء ما يحتاج أن يوضع هنا. كان فارغاً",
|
||||
"chat_direction_right_to_left": "شيء ما يحتاج أن يوضع هنا. كان فارغاً",
|
||||
"com_a11y_ai_composing": "الذكاء الاصطناعي ما زال يكتب",
|
||||
"com_a11y_end": "انتهى الذكاء الاصطناعي من الرد",
|
||||
"com_a11y_start": "بدأ الذكاء الاصطناعي بالرد",
|
||||
|
|
@ -9,6 +11,9 @@
|
|||
"com_agents_create_error": "حدث خطأ أثناء إنشاء الوكيل الخاص بك",
|
||||
"com_agents_description_placeholder": "اختياري: اشرح عميلك هنا",
|
||||
"com_agents_enable_file_search": "تمكين البحث عن الملفات",
|
||||
"com_agents_file_context": "سياق الملف (قارئ الحروف البصري)",
|
||||
"com_agents_file_context_disabled": "يحب أولاً إنشاء الوكيل قبل رفع الملف لمحلل سياق الملف",
|
||||
"com_agents_file_context_info": "الملفات المرفوعة كـ \"سياق\" تتم معالجتها باستخدام قارئ الحروف البصري (OCR) لاستخراج النص، والذي يُضاف بعد ذلك إلى التعليمات الموجِهة للوكيل. مثالية للوثائق والصور التي تحتوي على نص أو ملفات PDF حيث تحتاج إلى المحتوى النصي الكامل للملف.",
|
||||
"com_agents_file_search_disabled": "يجب إنشاء الوكيل قبل تحميل الملفات للبحث في الملفات.",
|
||||
"com_agents_file_search_info": "عند التمكين، سيتم إعلام الوكيل بأسماء الملفات المدرجة أدناه بالضبط، مما يتيح له استرجاع السياق ذي الصلة من هذه الملفات.",
|
||||
"com_agents_instructions_placeholder": "التعليمات النظامية التي يستخدمها الوكيل",
|
||||
|
|
@ -567,6 +572,8 @@
|
|||
"com_ui_fork_success": "تم تفريع المحادثة بنجاح",
|
||||
"com_ui_fork_visible": "الرسائل المرئية فقط",
|
||||
"com_ui_go_to_conversation": "انتقل إلى المحادثة",
|
||||
"com_ui_good_afternoon": "طاب يومك",
|
||||
"com_ui_good_morning": "صباح الخير",
|
||||
"com_ui_happy_birthday": "إنه عيد ميلادي الأول!",
|
||||
"com_ui_host": "مُضيف",
|
||||
"com_ui_image_gen": "توليد الصور",
|
||||
|
|
@ -622,10 +629,17 @@
|
|||
"com_ui_prompts_allow_use": "السماح باستخدام الأوامر",
|
||||
"com_ui_provider": "مزود",
|
||||
"com_ui_read_aloud": "قراءة بصوت عالٍ",
|
||||
"com_ui_reference_saved_memories_description": "السماح للمساعد لاستخدام والرجوع لذكرياتك المخزنة عند الإجابة",
|
||||
"com_ui_regenerate": "إعادة توليد",
|
||||
"com_ui_regenerating": "جار إعادة التوليد...",
|
||||
"com_ui_region": "المنطقة",
|
||||
"com_ui_rename": "إعادة تسمية",
|
||||
"com_ui_rename_conversation": "إعادة تسمية المحادثة",
|
||||
"com_ui_rename_failed": "فشل في إعادة تسمية المحادثة",
|
||||
"com_ui_rename_prompt": "إعادة تسمية الأمر",
|
||||
"com_ui_requires_auth": "يتطلب مصادقة",
|
||||
"com_ui_reset_var": "إعادة تعيين {{0}}",
|
||||
"com_ui_reset_zoom": "إعادة تعيين التقريب",
|
||||
"com_ui_result": "النتيجة",
|
||||
"com_ui_revoke": "إلغاء",
|
||||
"com_ui_revoke_info": "إلغاء جميع بيانات الاعتماد المقدمة من المستخدم.",
|
||||
|
|
@ -634,13 +648,20 @@
|
|||
"com_ui_revoke_keys": "إلغاء المفاتيح",
|
||||
"com_ui_revoke_keys_confirm": "هل أنت متأكد من أنك تريد إلغاء جميع المفاتيح؟",
|
||||
"com_ui_role_select": "الدور",
|
||||
"com_ui_roleplay": "القيام بالدور",
|
||||
"com_ui_run_code": "تنفيذ الشفرة",
|
||||
"com_ui_run_code_error": "حدث خطأ أثناء تشغيل الكود",
|
||||
"com_ui_run_code_error": "حدث خطأ أثناء تشغيل الشفرة",
|
||||
"com_ui_save": "حفظ",
|
||||
"com_ui_save_submit": "حفظ وإرسال",
|
||||
"com_ui_saved": "تم الحفظ!",
|
||||
"com_ui_saving": "جار الحفظ...",
|
||||
"com_ui_schema": "المخطط",
|
||||
"com_ui_scope": "مجال",
|
||||
"com_ui_search": "بحث",
|
||||
"com_ui_seconds": "ثواني",
|
||||
"com_ui_secret_key": "مفتاح سري",
|
||||
"com_ui_select": "اختر",
|
||||
"com_ui_select_all": "تحديد الكل",
|
||||
"com_ui_select_file": "اختر ملفًا",
|
||||
"com_ui_select_model": "اختر نموذجًا",
|
||||
"com_ui_select_provider": "اختر مزودًا",
|
||||
|
|
@ -654,20 +675,34 @@
|
|||
"com_ui_share_create_message": "سيظل اسمك وأي رسائل تضيفها بعد المشاركة خاصة.",
|
||||
"com_ui_share_delete_error": "حدث خطأ أثناء حذف الرابط المشترك.",
|
||||
"com_ui_share_error": "حدث خطأ أثناء مشاركة رابط الدردشة",
|
||||
"com_ui_share_form_description": "شيء ما يحتاج أن يوضع هنا. كان فارغاً",
|
||||
"com_ui_share_link_to_chat": "شارك الرابط في الدردشة",
|
||||
"com_ui_share_to_all_users": "مشاركة مع جميع المستخدمين",
|
||||
"com_ui_share_update_message": "سيظل اسمك والتعليمات المخصصة وأي رسائل تضيفها بعد المشاركة خاصة.",
|
||||
"com_ui_share_var": "مشاركة {{0}}",
|
||||
"com_ui_shared_link_bulk_delete_success": "تم حذف الرابط المشترك بنجاح",
|
||||
"com_ui_shared_link_delete_success": "تم حذف الرابط المشترك بنجاح",
|
||||
"com_ui_shared_link_not_found": "الرابط المشترك غير موجود",
|
||||
"com_ui_shared_prompts": "المطالبات المشتركة",
|
||||
"com_ui_shop": "تسووق",
|
||||
"com_ui_show": "عرض",
|
||||
"com_ui_show_all": "عرض الكل",
|
||||
"com_ui_show_image_details": "إظهار تفاصيل الصورة",
|
||||
"com_ui_show_qr": "إظهار رمز الـ QR",
|
||||
"com_ui_sign_in_to_domain": "تسجيل الدخول الى {{0}}",
|
||||
"com_ui_simple": "بسيط",
|
||||
"com_ui_size": "الحجم",
|
||||
"com_ui_special_var_current_date": "التاريخ الآن",
|
||||
"com_ui_special_var_current_datetime": "التاريخ والوقت الآن",
|
||||
"com_ui_special_var_current_user": "المستخدم الحالي",
|
||||
"com_ui_special_variables": "المتغيرات الخاصة:",
|
||||
"com_ui_special_variables_more_info": "يمكنك اختيار متغيّر خاص من القائمة المنسدلة أدناه: {{current_date}}` (today's date and day of week), `{{current_datetime}}` (local date and time), `{{utc_iso_datetime}}` (UTC ISO datetime), و `{{current_user}}` (your account name).",
|
||||
"com_ui_speech_while_submitting": "لا يمكن إرسال الكلام أثناء إنشاء الرد",
|
||||
"com_ui_stop": "توقف",
|
||||
"com_ui_storage": "التخزين",
|
||||
"com_ui_submit": "إرسال",
|
||||
"com_ui_teach_or_explain": "علِّم",
|
||||
"com_ui_temporary": "دردشة مؤقتة",
|
||||
"com_ui_terms_and_conditions": "شروط الخدمة",
|
||||
"com_ui_terms_of_service": "شروط الخدمة",
|
||||
"com_ui_tools": "أدوات المساعدين",
|
||||
|
|
@ -695,6 +730,5 @@
|
|||
"com_ui_versions": "الإصدارات",
|
||||
"com_ui_yes": "نعم",
|
||||
"com_ui_zoom": "تكبير",
|
||||
"com_user_message": "أنت",
|
||||
"com_warning_resubmit_unsupported": "إعادة إرسال رسالة الذكاء الاصطناعي غير مدعومة لنقطة النهاية هذه"
|
||||
"com_user_message": "أنت"
|
||||
}
|
||||
|
|
@ -322,7 +322,6 @@
|
|||
"com_nav_delete_cache_storage": "Esborra la memòria cau de TTS",
|
||||
"com_nav_delete_data_info": "Totes les teves dades s'eliminaran.",
|
||||
"com_nav_delete_warning": "AVÍS: Això eliminarà permanentment el teu compte.",
|
||||
"com_nav_edit_chat_badges": "Edita les insígnies del xat",
|
||||
"com_nav_enable_cache_tts": "Habilita la memòria cau TTS",
|
||||
"com_nav_enable_cloud_browser_voice": "Utilitza veus al núvol",
|
||||
"com_nav_enabled": "Habilitat",
|
||||
|
|
@ -688,7 +687,6 @@
|
|||
"com_ui_import_conversation_info": "Importa converses des d'un fitxer JSON",
|
||||
"com_ui_import_conversation_success": "Converses importades amb èxit",
|
||||
"com_ui_include_shadcnui": "Inclou instruccions de components shadcn/ui",
|
||||
"com_ui_include_shadcnui_agent": "Inclou instruccions shadcn/ui",
|
||||
"com_ui_input": "Entrada",
|
||||
"com_ui_instructions": "Instruccions",
|
||||
"com_ui_late_night": "Bona matinada",
|
||||
|
|
@ -868,6 +866,5 @@
|
|||
"com_ui_x_selected": "{{0}} seleccionats",
|
||||
"com_ui_yes": "Sí",
|
||||
"com_ui_zoom": "Zoom",
|
||||
"com_user_message": "Tu",
|
||||
"com_warning_resubmit_unsupported": "Tornar a enviar el missatge de la IA no està suportat per aquest endpoint."
|
||||
"com_user_message": "Tu"
|
||||
}
|
||||
|
|
@ -720,6 +720,5 @@
|
|||
"com_ui_write": "Psát",
|
||||
"com_ui_yes": "Ano",
|
||||
"com_ui_zoom": "Přiblížit",
|
||||
"com_user_message": "Vy",
|
||||
"com_warning_resubmit_unsupported": "Opětovné odeslání AI zprávy není pro tento koncový bod podporováno."
|
||||
"com_user_message": "Vy"
|
||||
}
|
||||
|
|
@ -21,6 +21,7 @@
|
|||
"com_agents_name_placeholder": "Valgfrit: Navnet på agenten",
|
||||
"com_agents_no_access": "Du har ikke adgang til at redigere denne agent.",
|
||||
"com_agents_not_available": "Agent ikke tilgængelig",
|
||||
"com_agents_search_info": "Når det er aktiveret, kan din agent søge på nettet efter opdaterede oplysninger. Kræver en gyldig API-nøgle.",
|
||||
"com_agents_search_name": "Søg agenter efter navn",
|
||||
"com_agents_update_error": "Der opstod en fejl ved opdateringen af din agent.",
|
||||
"com_assistants_action_attempt": "Assistenten vil tale med {{0}}",
|
||||
|
|
@ -38,6 +39,7 @@
|
|||
"com_assistants_code_interpreter": "Kodefortolker",
|
||||
"com_assistants_code_interpreter_files": "Filerne nedenfor er kun til Kodefortolker:",
|
||||
"com_assistants_code_interpreter_info": "Kodefortolkeren gør det muligt for assistenten at skrive og køre kode. Dette værktøj kan behandle filer med forskellige data og formateringer og generere filer såsom grafer.",
|
||||
"com_assistants_completed_action": "Talte med {{0}}",
|
||||
"com_assistants_completed_function": "Kørte {{0}}",
|
||||
"com_assistants_conversation_starters": "Samtalestartere",
|
||||
"com_assistants_conversation_starters_placeholder": "Indtast en samtalestarter",
|
||||
|
|
@ -48,6 +50,7 @@
|
|||
"com_assistants_description_placeholder": "Valgfrit: Beskriv din assistent her",
|
||||
"com_assistants_domain_info": "Assistenten sendte disse oplysninger til {{0}}",
|
||||
"com_assistants_file_search": "Filsøgning",
|
||||
"com_assistants_file_search_info": "Filsøgning giver assistenten mulighed for at hente viden fra filer, som du eller dine brugere uploader. Når en fil er uploadet, beslutter assistenten automatisk, hvornår der skal hentes indhold baseret på brugeranmodninger. Vedhæftning af vektorlagre til filsøgning er endnu ikke understøttet. Du kan vedhæfte dem fra Provider Playground eller vedhæfte filer til beskeder til filsøgning på trådbasis.",
|
||||
"com_assistants_function_use": "Assistent brugt {{0}}",
|
||||
"com_assistants_image_vision": "Billedvision",
|
||||
"com_assistants_instructions_placeholder": "De systeminstruktioner, som assistenten bruger",
|
||||
|
|
@ -59,6 +62,7 @@
|
|||
"com_assistants_non_retrieval_model": "Filsøgning er ikke aktiveret på denne model. Vælg venligst en anden model.",
|
||||
"com_assistants_retrieval": "Hentning",
|
||||
"com_assistants_running_action": "Afvikler handling",
|
||||
"com_assistants_running_var": "Kører {{0}}",
|
||||
"com_assistants_search_name": "Søg assistenter efter navn",
|
||||
"com_assistants_update_actions_error": "Der opstod en fejl ved oprettelse eller opdatering af handlingen.",
|
||||
"com_assistants_update_actions_success": "Vellykket oprettet eller opdateret Handling",
|
||||
|
|
@ -120,6 +124,7 @@
|
|||
"com_auth_reset_password_if_email_exists": "Hvis der findes en konto med denne e-mail, er der sendt en e-mail med instruktioner til nulstilling af adgangskode. Sørg for at tjekke din spam-mappe.",
|
||||
"com_auth_reset_password_link_sent": "E-mail sendt",
|
||||
"com_auth_reset_password_success": "Nulstilling af adgangskode genemført",
|
||||
"com_auth_saml_login": "Fortsæt med SAML",
|
||||
"com_auth_sign_in": "Log ind",
|
||||
"com_auth_sign_up": "Tilmeld dig",
|
||||
"com_auth_submit_registration": "Send registrering",
|
||||
|
|
@ -131,6 +136,8 @@
|
|||
"com_auth_username_min_length": "Brugernavn skal være mindst 2 tegn",
|
||||
"com_auth_verify_your_identity": "Bekræft din identitet",
|
||||
"com_auth_welcome_back": "Velkommen tilbage",
|
||||
"com_citation_more_details": "Flere detaljer om {{label}}",
|
||||
"com_citation_source": "Kilde",
|
||||
"com_click_to_download": "(klik her for at downloade)",
|
||||
"com_download_expired": "(download udløbet)",
|
||||
"com_download_expires": "(klik her for at downloade - udløber {{0}})",
|
||||
|
|
@ -142,6 +149,10 @@
|
|||
"com_endpoint_anthropic_maxoutputtokens": "Maksimalt antal tokens, der kan genereres i svaret. Angiv en lavere værdi for kortere svar og en højere værdi for længere svar. Bemærk: Modeller kan stoppe, før de når dette maksimum.",
|
||||
"com_endpoint_anthropic_prompt_cache": "Prompt caching gør det muligt at genbruge store kontekster eller instruktioner på tværs af API-kald, hvilket reducerer omkostninger og ventetid.",
|
||||
"com_endpoint_anthropic_temp": "Spænder fra 0 til 1. Brug temp tættere på 0 til analytiske/ multiple choice-opgaver og tættere på 1 til kreative og generative opgaver. Vi anbefaler at ændre dette eller Top P, men ikke begge dele.",
|
||||
"com_endpoint_anthropic_thinking": "Aktiverer intern ræsonnering for understøttede Claude-modeller (3.7 Sonnet). Bemærk: kræver, at \"Thinking Budget\" er indstillet og lavere end \"Max Output Tokens\"",
|
||||
"com_endpoint_anthropic_thinking_budget": "Bestemmer det maksimale antal tokens, som Claude må bruge til sin interne ræsonnementsproces. Større budgetter kan forbedre kvaliteten af svarene ved at muliggøre en mere grundig analyse af komplekse problemer, selv om Claude måske ikke bruger hele det tildelte budget, især ved intervaller over 32K. Denne indstilling skal være lavere end \"Max Output Tokens\".",
|
||||
"com_endpoint_anthropic_topk": "Top-k ændrer, hvordan modellen udvælger symboler til output. En top-k på 1 betyder, at det valgte token er det mest sandsynlige blandt alle tokens i modellens ordforråd (også kaldet grådig afkodning), mens en top-k på 3 betyder, at det næste token vælges blandt de 3 mest sandsynlige tokens (ved hjælp af temperatur).",
|
||||
"com_endpoint_anthropic_topp": "Top-p ændrer, hvordan modellen udvælger tokens til output. Tokens vælges fra de mest K (se topK-parameter) sandsynlige til de mindst sandsynlige, indtil summen af deres sandsynligheder er lig med top-p-værdien.",
|
||||
"com_endpoint_assistant": "Assistent",
|
||||
"com_endpoint_assistant_model": "Assistentmodel",
|
||||
"com_endpoint_assistant_placeholder": "Vælg en assistent fra sidepanelet til højre",
|
||||
|
|
@ -154,6 +165,7 @@
|
|||
"com_endpoint_config_google_gemini_api": "(Gemini API)",
|
||||
"com_endpoint_config_google_service_key": "Google Service Konto -nøgle",
|
||||
"com_endpoint_config_key": "Angiv API-nøgle",
|
||||
"com_endpoint_config_key_encryption": "Din nøgle vil blive krypteret og slettet den",
|
||||
"com_endpoint_config_key_for": "Indstil API-nøgle til",
|
||||
"com_endpoint_config_key_google_need_to": "Du er nødt til at",
|
||||
"com_endpoint_config_key_google_service_account": "Opret en servicekonto",
|
||||
|
|
@ -186,6 +198,8 @@
|
|||
"com_endpoint_google_custom_name_placeholder": "Indstil et brugerdefineret navn til Google",
|
||||
"com_endpoint_google_maxoutputtokens": "Maksimalt antal tokens, der kan genereres i svaret. Angiv en lavere værdi for kortere svar og en højere værdi for længere svar. Bemærk: Modeller kan stoppe, før de når dette maksimum.",
|
||||
"com_endpoint_google_temp": "Højere værdier = mere tilfældige, mens lavere værdier = mere fokuserede og deterministiske. Vi anbefaler at ændre dette eller Top P, men ikke begge dele.",
|
||||
"com_endpoint_google_topk": "Top-k ændrer, hvordan modellen udvælger symboler til output. En top-k på 1 betyder, at det valgte token er det mest sandsynlige blandt alle tokens i modellens ordforråd (også kaldet grådig afkodning), mens en top-k på 3 betyder, at det næste token vælges blandt de 3 mest sandsynlige tokens (ved hjælp af temperatur).",
|
||||
"com_endpoint_google_topp": "Top-p ændrer, hvordan modellen udvælger tokens til output. Tokens vælges fra de mest K (se topK-parameter) sandsynlige til de mindst sandsynlige, indtil summen af deres sandsynligheder er lig med top-p-værdien.",
|
||||
"com_endpoint_instructions_assistants": "Overskriv instruktioner",
|
||||
"com_endpoint_instructions_assistants_placeholder": "Overstyrer instruktionerne fra assistenten. Det er nyttigt, hvis man vil ændre adfærden for hver enkelt kørsel.",
|
||||
"com_endpoint_max_output_tokens": "Maks. output-tokens",
|
||||
|
|
@ -196,6 +210,18 @@
|
|||
"com_endpoint_no_presets": "Ingen forudindstillinger endnu, brug indstillingsknappen til at oprette en",
|
||||
"com_endpoint_open_menu": "Åbn menu",
|
||||
"com_endpoint_openai_custom_name_placeholder": "Indstil et brugerdefineret navn til AI'en",
|
||||
"com_endpoint_openai_detail": "Opløsningen for Vision-anmodninger. \"Lav\" er billigere og hurtigere, \"Høj\" er mere detaljeret og dyrere, og \"Auto\" vælger automatisk mellem de to baseret på billedopløsningen.",
|
||||
"com_endpoint_openai_freq": "Tal mellem -2,0 og 2,0. Positive værdier straffer nye tokens baseret på deres eksisterende frekvens i teksten indtil videre, hvilket mindsker modellens sandsynlighed for at gentage den samme linje ordret.",
|
||||
"com_endpoint_openai_max": "Det maksimale antal tokens, der skal genereres. Den samlede længde af input-tokens og genererede tokens er begrænset af modellens kontekstlængde.",
|
||||
"com_endpoint_openai_max_tokens": "Valgfrit 'max_tokens'-felt, der repræsenterer det maksimale antal tokens, der kan genereres i chatudfyldningen. Den samlede længde af input-tokens og genererede tokens er begrænset af modellernes kontekstlængde. Du kan opleve fejl, hvis dette antal overskrider det maksimale antal kontekst-tokens.",
|
||||
"com_endpoint_openai_pres": "Tal mellem -2,0 og 2,0. Positive værdier straffer nye tokens baseret på, om de optræder i teksten indtil videre, hvilket øger modellens sandsynlighed for at tale om nye emner.",
|
||||
"com_endpoint_openai_prompt_prefix_placeholder": "Indstil brugerdefinerede instruktioner, der skal inkluderes i systembeskeden. Standard: ingen",
|
||||
"com_endpoint_openai_reasoning_effort": "Kun o1- og o3-modeller: Begrænser indsatsen for ræsonnement for ræsonnerende modeller. At reducere ræsonneringsindsatsen kan resultere i hurtigere svar og færre tokens brugt på ræsonnering i et svar.",
|
||||
"com_endpoint_openai_resend": "Send alle tidligere vedhæftede billeder igen. Bemærk: Dette kan øge tokenomkostningerne betydeligt, og du kan opleve fejl med mange vedhæftede billeder.",
|
||||
"com_endpoint_openai_resend_files": "Send alle tidligere vedhæftede filer igen. Bemærk: Dette vil øge tokenomkostningerne, og du kan opleve fejl med mange vedhæftede filer.",
|
||||
"com_endpoint_openai_stop": "Op til 4 sekvenser, hvor API'en stopper med at generere yderligere tokens.",
|
||||
"com_endpoint_openai_temp": "Højere værdier = mere tilfældige, mens lavere værdier = mere fokuserede og deterministiske. Vi anbefaler at ændre dette eller Top P, men ikke begge dele.",
|
||||
"com_endpoint_openai_topp": "Et alternativ til sampling med temperatur, kaldet nucleus sampling, hvor modellen tager højde for resultaterne af tokens med top_p sandsynlighedsmasse. Så 0,1 betyder, at kun de tokens, der har den største sandsynlighedsmasse på 10 %, tages i betragtning. Vi anbefaler at ændre dette eller temperaturen, men ikke begge dele.",
|
||||
"com_endpoint_output": "Produktion",
|
||||
"com_endpoint_plug_image_detail": "Billeddetaljer",
|
||||
"com_endpoint_plug_resend_files": "Send filer igen",
|
||||
|
|
@ -249,7 +275,10 @@
|
|||
"com_error_files_upload": "Der opstod en fejl under upload af filen.",
|
||||
"com_error_files_upload_canceled": "Anmodningen om filoverførsel blev annulleret. Bemærk: Filuploaden kan stadig være under behandling og skal slettes manuelt.",
|
||||
"com_error_files_validation": "Der opstod en fejl under validering af filen.",
|
||||
"com_error_input_length": "Antallet af tokener i den seneste meddelelse er for langt og overskrider tokengrænsen, eller dine tokengrænseparametre er forkert konfigureret, hvilket påvirker kontekstvinduet negativt. Mere information: {{0}}. Forkort venligst din besked, juster den maksimale kontekststørrelse fra samtaleparametrene, eller forgren samtalen for at fortsætte.",
|
||||
"com_error_invalid_agent_provider": "Den \"{{0}}\"-udbyder er ikke tilgængelig for brug med agenter. Gå til din agents indstillinger, og vælg en aktuelt tilgængelig udbyder.",
|
||||
"com_error_invalid_user_key": "Ugyldig nøgle angivet. Angiv venligst en gyldig nøgle, og prøv igen.",
|
||||
"com_error_moderation": "Det ser ud til, at det indsendte indhold er blevet markeret af vores moderationssystem for ikke at være i overensstemmelse med vores retningslinjer for fællesskabet. Vi kan ikke gå videre med dette specifikke emne. Hvis du har andre spørgsmål eller emner, du gerne vil udforske, kan du redigere din besked eller oprette en ny samtale.",
|
||||
"com_error_no_base_url": "Ingen base-URL fundet. Angiv venligst en og prøv igen.",
|
||||
"com_error_no_user_key": "Ingen nøgle fundet. Angiv venligst en nøgle, og prøv igen.",
|
||||
"com_files_filter": "Filtrer filer ...",
|
||||
|
|
@ -275,6 +304,27 @@
|
|||
"com_nav_auto_transcribe_audio": "Automatisk transskribering af lyd",
|
||||
"com_nav_automatic_playback": "Autoplay Seneste besked",
|
||||
"com_nav_balance": "Balance",
|
||||
"com_nav_balance_auto_refill_disabled": "Automatisk genopfyldning er deaktiveret.",
|
||||
"com_nav_balance_auto_refill_error": "Fejl ved indlæsning af indstillinger for automatisk genopfyldning.",
|
||||
"com_nav_balance_auto_refill_settings": "Indstillinger for automatisk genopfyldning",
|
||||
"com_nav_balance_day": "dag",
|
||||
"com_nav_balance_days": "dage",
|
||||
"com_nav_balance_every": "Hver",
|
||||
"com_nav_balance_hour": "time",
|
||||
"com_nav_balance_hours": "timer",
|
||||
"com_nav_balance_interval": "Interval:",
|
||||
"com_nav_balance_last_refill": "Sidste genopfyldning:",
|
||||
"com_nav_balance_minute": "minut",
|
||||
"com_nav_balance_minutes": "minutter",
|
||||
"com_nav_balance_month": "måned",
|
||||
"com_nav_balance_months": "måneder",
|
||||
"com_nav_balance_next_refill": "Næste genopfyldning:",
|
||||
"com_nav_balance_next_refill_info": "Den næste genopfyldning sker kun automatisk, når begge betingelser er opfyldt: Det angivne tidsinterval er gået siden sidste genopfyldning, og hvis du sender en besked, vil din saldo falde til under nul.",
|
||||
"com_nav_balance_refill_amount": "Genopfyldningsmængde:",
|
||||
"com_nav_balance_second": "anden",
|
||||
"com_nav_balance_seconds": "sekunder",
|
||||
"com_nav_balance_week": "uge",
|
||||
"com_nav_balance_weeks": "uger",
|
||||
"com_nav_browser": "Browser",
|
||||
"com_nav_center_chat_input": "Center Chat Input på velkomstskærmen",
|
||||
"com_nav_change_picture": "Skift billede",
|
||||
|
|
@ -298,7 +348,6 @@
|
|||
"com_nav_delete_cache_storage": "Slet TTS-cache-lagring",
|
||||
"com_nav_delete_data_info": "Alle dine data vil blive slettet.",
|
||||
"com_nav_delete_warning": "ADVARSEL: Dette vil slette din konto permanent.",
|
||||
"com_nav_edit_chat_badges": "Rediger chat-badges",
|
||||
"com_nav_enable_cache_tts": "Aktivér cache-TTS",
|
||||
"com_nav_enable_cloud_browser_voice": "Brug cloud-baserede stemmer",
|
||||
"com_nav_enabled": "Aktiveret",
|
||||
|
|
@ -325,18 +374,31 @@
|
|||
"com_nav_info_code_artifacts": "Aktiverer visning af eksperimentelle kodeartefakter ved siden af chatten",
|
||||
"com_nav_info_code_artifacts_agent": "Aktiverer brugen af kodeartefakter for denne agent. Som standard tilføjes yderligere instruktioner specifikke for brugen af artefakter, medmindre \"Brugerdefineret prompttilstand\" er aktiveret.",
|
||||
"com_nav_info_custom_prompt_mode": "Når den er aktiveret, vil standardsystemprompten for artefakter ikke blive inkluderet. Alle instruktioner til generering af artefakter skal angives manuelt i denne tilstand.",
|
||||
"com_nav_info_enter_to_send": "Når den er aktiveret, sender du din besked ved at trykke på `ENTER`. Når den er deaktiveret, vil et tryk på Enter tilføje en ny linje, og du skal trykke på `CTRL + ENTER` / `⌘ + ENTER` for at sende din besked.",
|
||||
"com_nav_info_fork_change_default": "`Kun synlige beskeder` inkluderer kun den direkte sti til den valgte besked. `Include related branches` tilføjer grene langs stien. `Include all to/from here` inkluderer alle forbundne beskeder og grene.",
|
||||
"com_nav_info_fork_split_target_setting": "Når den er aktiveret, vil forking begynde fra målbeskeden til den seneste besked i samtalen i henhold til den valgte adfærd.",
|
||||
"com_nav_info_include_shadcnui": "Når det er aktiveret, vil der blive inkluderet instruktioner til brug af shadcn/ui-komponenter. shadcn/ui er en samling af genanvendelige komponenter, der er bygget med Radix UI og Tailwind CSS. Bemærk: Det er lange instruktioner, og du bør kun aktivere dem, hvis det er vigtigt for dig at informere LLM om de korrekte importer og komponenter. For mere information om disse komponenter, besøg: https://ui.shadcn.com/",
|
||||
"com_nav_info_latex_parsing": "Når det er aktiveret, vil LaTeX-kode i meddelelser blive gengivet som matematiske ligninger. Hvis du deaktiverer dette, kan det forbedre ydeevnen, hvis du ikke har brug for LaTeX-rendering.",
|
||||
"com_nav_info_save_badges_state": "Når den er aktiveret, gemmes chatbadgenes tilstand. Det betyder, at hvis du opretter en ny chat, vil badges forblive i samme tilstand som i den forrige chat. Hvis du deaktiverer denne mulighed, vil badges blive nulstillet til deres standardtilstand, hver gang du opretter en ny chat.",
|
||||
"com_nav_info_save_draft": "Når det er aktiveret, gemmes den tekst og de vedhæftede filer, du indtaster i chatformularen, automatisk lokalt som kladder. Disse kladder vil være tilgængelige, selv om du genindlæser siden eller skifter til en anden samtale. Kladder gemmes lokalt på din enhed og slettes, når beskeden er sendt.",
|
||||
"com_nav_info_show_thinking": "Når den er aktiveret, vil chatten som standard vise de tænkende dropdowns åbne, så du kan se AI'ens ræsonnementer i realtid. Når den er deaktiveret, forbliver de tænkende dropdowns lukket som standard for at give en renere og mere strømlinet grænseflade.",
|
||||
"com_nav_info_user_name_display": "Når den er aktiveret, vises afsenderens brugernavn over hver besked, du sender. Når det er deaktiveret, vil du kun se \"Du\" over dine beskeder.",
|
||||
"com_nav_lang_arabic": "Arabisk",
|
||||
"com_nav_lang_auto": "Automatisk detektion",
|
||||
"com_nav_lang_brazilian_portuguese": "Portugisisk Brasiliansk",
|
||||
"com_nav_lang_catalan": "Catalansk",
|
||||
"com_nav_lang_chinese": "Kinesisk",
|
||||
"com_nav_lang_czech": "Tjekkisk",
|
||||
"com_nav_lang_danish": "Dansk",
|
||||
"com_nav_lang_dutch": "Hollandsk",
|
||||
"com_nav_lang_english": "Engelsk",
|
||||
"com_nav_lang_estonian": "Estisk",
|
||||
"com_nav_lang_finnish": "Finsk",
|
||||
"com_nav_lang_french": "Fransk ",
|
||||
"com_nav_lang_georgian": "Georgisk",
|
||||
"com_nav_lang_german": "Tysk",
|
||||
"com_nav_lang_hebrew": "Hebraisk",
|
||||
"com_nav_lang_hungarian": "Ungarsk",
|
||||
"com_nav_lang_indonesia": "Indonesien",
|
||||
"com_nav_lang_italian": "Italiensk",
|
||||
"com_nav_lang_japanese": "Japansk",
|
||||
|
|
@ -350,6 +412,7 @@
|
|||
"com_nav_lang_thai": "Thai",
|
||||
"com_nav_lang_traditional_chinese": "Kinesisk",
|
||||
"com_nav_lang_turkish": "Tyrkisk",
|
||||
"com_nav_lang_vietnamese": "Vietnamesisk",
|
||||
"com_nav_language": "Sprog",
|
||||
"com_nav_latex_parsing": "Parsing af LaTeX i beskeder (kan påvirke ydeevnen)",
|
||||
"com_nav_log_out": "Log ud",
|
||||
|
|
@ -374,6 +437,7 @@
|
|||
"com_nav_search_placeholder": "Søg efter beskeder",
|
||||
"com_nav_send_message": "Send besked",
|
||||
"com_nav_setting_account": "Konto",
|
||||
"com_nav_setting_balance": "Balance",
|
||||
"com_nav_setting_beta": "Beta-funktioner",
|
||||
"com_nav_setting_chat": "Chat",
|
||||
"com_nav_setting_data": "Datakontrol",
|
||||
|
|
@ -411,6 +475,12 @@
|
|||
"com_sidepanel_hide_panel": "Skjul panel",
|
||||
"com_sidepanel_manage_files": "Administrer filer",
|
||||
"com_sidepanel_parameters": "Parametre",
|
||||
"com_sources_image_alt": "Søgeresultatbillede",
|
||||
"com_sources_more_sources": "+{{count}} kilder",
|
||||
"com_sources_tab_all": "Alle",
|
||||
"com_sources_tab_images": "Billeder",
|
||||
"com_sources_tab_news": "Nyheder",
|
||||
"com_sources_title": "Kilder",
|
||||
"com_ui_2fa_account_security": "To-faktor-autentificering tilføjer et ekstra lag af sikkerhed til din konto",
|
||||
"com_ui_2fa_disable": "Deaktiver 2FA",
|
||||
"com_ui_2fa_disable_error": "Der opstod en fejl ved deaktivering af to-faktor-autentificering",
|
||||
|
|
@ -445,6 +515,20 @@
|
|||
"com_ui_agent_recursion_limit_info": "Begrænser, hvor mange trin agenten kan tage i en kørsel, før den giver et endeligt svar. Standard er 25 trin. Et trin er enten en AI API-anmodning eller en værktøjsbrugsrunde. For eksempel tager en grundlæggende værktøjsinteraktion 3 trin: indledende anmodning, værktøjsbrug og opfølgende anmodning.",
|
||||
"com_ui_agent_shared_to_all": "Der skal stå noget her. Det var tomt.",
|
||||
"com_ui_agent_var": "{{0}} agent",
|
||||
"com_ui_agent_version": "Version",
|
||||
"com_ui_agent_version_active": "Aktiv version",
|
||||
"com_ui_agent_version_duplicate": "Duplikatversion fundet. Dette vil skabe en version, der er identisk med Version {{versionIndex}}.",
|
||||
"com_ui_agent_version_empty": "Ingen tilgængelige versioner",
|
||||
"com_ui_agent_version_error": "Fejl ved hentning af versioner",
|
||||
"com_ui_agent_version_history": "Versionshistorik",
|
||||
"com_ui_agent_version_no_agent": "Ingen agent valgt. Vælg venligst en agent for at se versionshistorikken.",
|
||||
"com_ui_agent_version_no_date": "Dato ikke tilgængelig",
|
||||
"com_ui_agent_version_restore": "Gendan",
|
||||
"com_ui_agent_version_restore_confirm": "Er du sikker på, at du vil gendanne denne version?",
|
||||
"com_ui_agent_version_restore_error": "Kunne ikke gendanne version",
|
||||
"com_ui_agent_version_restore_success": "Version gendannet med succes",
|
||||
"com_ui_agent_version_title": "Version {{versionNumber}}",
|
||||
"com_ui_agent_version_unknown_date": "Ukendt dato",
|
||||
"com_ui_agents": "Agenter",
|
||||
"com_ui_agents_allow_create": "Tillad oprettelse af agenter",
|
||||
"com_ui_agents_allow_share_global": "Tillad deling af agenter til alle brugere",
|
||||
|
|
@ -528,6 +612,7 @@
|
|||
"com_ui_confirm_change": "Bekræft ændring",
|
||||
"com_ui_context": "Kontekst",
|
||||
"com_ui_continue": "Fortsæt",
|
||||
"com_ui_controls": "Kontrolelementer",
|
||||
"com_ui_convo_delete_error": "Kunne ikke slette samtalen",
|
||||
"com_ui_copied": "Kopieret!",
|
||||
"com_ui_copied_to_clipboard": "Kopieret til udklipsholder",
|
||||
|
|
@ -617,8 +702,23 @@
|
|||
"com_ui_fork_default": "Brug standard forgreningsmulighed",
|
||||
"com_ui_fork_error": "Der opstod en fejl under forgreningen af samtalen",
|
||||
"com_ui_fork_from_message": "Vælg en forgreningsmulighed",
|
||||
"com_ui_fork_info_1": "Brug denne indstilling til at forkaste meddelelser med den ønskede adfærd.",
|
||||
"com_ui_fork_info_2": "\"Forgrening\" betyder, at man opretter en ny samtale, der starter/slutter med specifikke beskeder i den aktuelle samtale og opretter en kopi i henhold til de valgte indstillinger.",
|
||||
"com_ui_fork_info_3": "\"Målbeskeden\" henviser enten til den besked, som denne popup blev åbnet fra, eller, hvis du markerer \"{{0}}\", den seneste besked i samtalen.",
|
||||
"com_ui_fork_info_branches": "Denne indstilling forgrener de synlige beskeder sammen med relaterede grene",
|
||||
"com_ui_fork_info_button_label": "Se oplysninger om forgrening af samtaler",
|
||||
"com_ui_fork_info_remember": "Marker dette for at huske de indstillinger, du vælger, til fremtidig brug, hvilket gør det hurtigere at forgrene samtaler som ønsket.",
|
||||
"com_ui_fork_info_start": "Hvis det er markeret, vil forgrening begynde fra denne besked til den seneste besked i samtalen i henhold til den adfærd, der er valgt ovenfor.",
|
||||
"com_ui_fork_info_target": "Denne indstilling forgrener alle beskeder, der fører op til målbeskeden, inklusive dens naboer",
|
||||
"com_ui_fork_info_visible": "Denne indstilling deler kun de synlige meddelelser; med andre ord den direkte vej til målmeddelelsen uden nogen forgrening.",
|
||||
"com_ui_fork_more_details_about": "Se yderligere oplysninger og detaljer om \"{{0}}\" forgreningsmulighed",
|
||||
"com_ui_fork_more_info_options": "Se detaljeret forklaring af alle forgreningslindstillinger og deres adfærd",
|
||||
"com_ui_fork_processing": "Forgrener samtale...",
|
||||
"com_ui_fork_remember": "Husk ",
|
||||
"com_ui_fork_remember_checked": "Dit valg vil blive husket efter brug. Du kan til enhver tid ændre det i indstillingerne.",
|
||||
"com_ui_fork_split_target": "Start forgrening her",
|
||||
"com_ui_fork_split_target_setting": "Start forgrening fra målbesked som standard",
|
||||
"com_ui_fork_success": "Samtalen er forgrenet",
|
||||
"com_ui_fork_visible": "Kun synlige beskeder",
|
||||
"com_ui_generate_backup": "Generer backup-koder",
|
||||
"com_ui_generate_qrcode": "Generer QR-kode",
|
||||
|
|
@ -643,7 +743,6 @@
|
|||
"com_ui_import_conversation_info": "Importer samtaler fra en JSON-fil",
|
||||
"com_ui_import_conversation_success": "Samtaler importeret med succes",
|
||||
"com_ui_include_shadcnui": "Inkluder instruktioner til shadcn/ui-komponenter",
|
||||
"com_ui_include_shadcnui_agent": "Inkluder instruktioner til shadcn/ui",
|
||||
"com_ui_input": "Input",
|
||||
"com_ui_instructions": "Instruktioner",
|
||||
"com_ui_late_night": "Glædelig sen aften",
|
||||
|
|
@ -818,11 +917,29 @@
|
|||
"com_ui_version_var": "Version {{0}}",
|
||||
"com_ui_versions": "Versioner",
|
||||
"com_ui_view_source": "Se kilde-chat",
|
||||
"com_ui_web_search": "Websøgning",
|
||||
"com_ui_web_search_cohere_key": "Indtast Cohere API-nøgle",
|
||||
"com_ui_web_search_firecrawl_url": "Firecrawl API URL (valgfri)",
|
||||
"com_ui_web_search_jina_key": "Indtast Jina API-nøgle",
|
||||
"com_ui_web_search_processing": "Behandler resultater",
|
||||
"com_ui_web_search_provider": "Søgeudbyder",
|
||||
"com_ui_web_search_provider_serper": "Serper API",
|
||||
"com_ui_web_search_provider_serper_key": "Få din Serper API-nøgle",
|
||||
"com_ui_web_search_reading": "Læser resultater",
|
||||
"com_ui_web_search_reranker": "Genanker",
|
||||
"com_ui_web_search_reranker_cohere": "Cohere",
|
||||
"com_ui_web_search_reranker_cohere_key": "Få din Cohere API-nøgle",
|
||||
"com_ui_web_search_reranker_jina": "Jina AI",
|
||||
"com_ui_web_search_reranker_jina_key": "Få din Jina API-nøgle",
|
||||
"com_ui_web_search_scraper": "Skraber",
|
||||
"com_ui_web_search_scraper_firecrawl": "Firecrawl API",
|
||||
"com_ui_web_search_scraper_firecrawl_key": "Få din Firecrawl API-nøgle",
|
||||
"com_ui_web_searching": "Søger på nettet",
|
||||
"com_ui_web_searching_again": "Søger på nettet igen",
|
||||
"com_ui_weekend_morning": "God weekend",
|
||||
"com_ui_write": "Skriver",
|
||||
"com_ui_x_selected": "{{0}} udvalgt",
|
||||
"com_ui_yes": "Ja",
|
||||
"com_ui_zoom": "Zoom",
|
||||
"com_user_message": "Du",
|
||||
"com_warning_resubmit_unsupported": "Genindsendelse af AI-beskeden understøttes ikke for dette slutpunkt."
|
||||
"com_user_message": "Du"
|
||||
}
|
||||
|
|
@ -17,16 +17,23 @@
|
|||
"com_agents_file_search_disabled": "Der Agent muss erstellt werden, bevor Dateien für die Dateisuche hochgeladen werden können.",
|
||||
"com_agents_file_search_info": "Wenn aktiviert, wird der Agent über die unten aufgelisteten exakten Dateinamen informiert und kann dadurch relevante Informationen aus diesen Dateien abrufen",
|
||||
"com_agents_instructions_placeholder": "Die Systemanweisungen, die der Agent verwendet",
|
||||
"com_agents_mcp_description_placeholder": "Erkläre in wenigen Worten, was es tut",
|
||||
"com_agents_mcp_icon_size": "Mindestgröße 128 x 128 px",
|
||||
"com_agents_mcp_info": "Füge deinem Agenten MCP-Server hinzu, damit er Aufgaben ausführen und mit externen Diensten interagieren kann",
|
||||
"com_agents_mcp_name_placeholder": "Eigenes Tool",
|
||||
"com_agents_mcp_trust_subtext": "Benutzerdefinierte Konnektoren werden nicht von LibreChat verifiziert.",
|
||||
"com_agents_mcps_disabled": "Du musst zuerst einen Agenten erstellen, bevor du MCPs hinzufügen kannst.",
|
||||
"com_agents_missing_provider_model": "Bitte wählen Sie einen Anbieter und ein Modell aus, bevor Sie einen Agenten erstellen.",
|
||||
"com_agents_name_placeholder": "Optional: Der Name des Agenten",
|
||||
"com_agents_no_access": "Du hast keine Berechtigung, diesen Agenten zu bearbeiten.",
|
||||
"com_agents_no_agent_id_error": "Keine Agenten-ID gefunden. Bitte stelle sicher, dass der Agent zuerst erstellt wurde.",
|
||||
"com_agents_not_available": "Agent nicht verfügbar",
|
||||
"com_agents_search_info": "Wenn diese Funktion aktiviert ist, kann der Agent im Internet nach aktuellen Informationen suchen. Erfordert einen gültigen API-Schlüssel.",
|
||||
"com_agents_search_name": "Agenten nach Namen suchen",
|
||||
"com_agents_update_error": "Beim Aktualisieren deines Agenten ist ein Fehler aufgetreten.",
|
||||
"com_assistants_action_attempt": "Assistent möchte kommunizieren mit {{0}}",
|
||||
"com_assistants_actions": "Aktionen",
|
||||
"com_assistants_actions_disabled": "Du müsst einen Assistenten erstellen, bevor du Aktionen hinzufügen kannst.",
|
||||
"com_assistants_actions_disabled": "Du musst einen Assistenten erstellen, bevor du Aktionen hinzufügen kannst.",
|
||||
"com_assistants_actions_info": "Lasse deinen Assistenten Informationen abrufen oder Aktionen über APIs ausführen",
|
||||
"com_assistants_add_actions": "Aktionen hinzufügen",
|
||||
"com_assistants_add_tools": "Werkzeuge hinzufügen",
|
||||
|
|
@ -124,6 +131,7 @@
|
|||
"com_auth_reset_password_if_email_exists": "Wenn ein Konto mit dieser E-Mail-Adresse existiert, wurde eine E-Mail mit Anweisungen zum Zurücksetzen des Passworts gesendet. Bitte überprüfe auch deinen Spam-Ordner.",
|
||||
"com_auth_reset_password_link_sent": "E-Mail gesendet",
|
||||
"com_auth_reset_password_success": "Passwort erfolgreich zurückgesetzt",
|
||||
"com_auth_saml_login": "Weiter mit SAML",
|
||||
"com_auth_sign_in": "Anmelden",
|
||||
"com_auth_sign_up": "Registrieren",
|
||||
"com_auth_submit_registration": "Registrierung absenden",
|
||||
|
|
@ -135,8 +143,8 @@
|
|||
"com_auth_username_min_length": "Benutzername muss mindestens 2 Zeichen lang sein",
|
||||
"com_auth_verify_your_identity": "Bestätige deine Identität",
|
||||
"com_auth_welcome_back": "Willkommen zurück",
|
||||
"com_citation_more_details": "Mehr Details über {{label}}",
|
||||
"com_citation_source": "Quelle",
|
||||
"com_citation_more_details": "Mehr Details über {{label}}\n",
|
||||
"com_citation_source": "Quelle\n",
|
||||
"com_click_to_download": "(hier klicken zum Herunterladen)",
|
||||
"com_download_expired": "Download abgelaufen",
|
||||
"com_download_expires": "(hier klicken zum Herunterladen - läuft ab am {{0}})",
|
||||
|
|
@ -197,8 +205,11 @@
|
|||
"com_endpoint_google_custom_name_placeholder": "Lege einen benutzerdefinierten Namen für Google fest",
|
||||
"com_endpoint_google_maxoutputtokens": "Maximale Anzahl von Token, die in der Antwort generiert werden können. Gib einen niedrigeren Wert für kürzere Antworten und einen höheren Wert für längere Antworten an. Hinweis: Modelle können möglicherweise vor Erreichen dieses Maximums stoppen.",
|
||||
"com_endpoint_google_temp": "Höhere Werte = zufälliger, während niedrigere Werte = fokussierter und deterministischer. Wir empfehlen, entweder dies oder Top P zu ändern, aber nicht beides.",
|
||||
"com_endpoint_google_thinking": "Aktiviert oder deaktiviert die Argumentation. Diese Einstellung wird nur von bestimmten Modellen (Serie 2.5) unterstützt. Bei älteren Modellen hat diese Einstellung möglicherweise keine Wirkung.",
|
||||
"com_endpoint_google_thinking_budget": "Gibt die Anzahl der Tokens an, die das Modell \"zum Nachdenken\" verwendet. Die tatsächliche Anzahl kann je nach Eingabeaufforderung diesen Wert über- oder unterschreiten.\n\nDiese Einstellung wird nur von bestimmten Modellen (2.5-Serie) unterstützt. Gemini 2.5 Pro unterstützt 128–32.768 Token. Gemini 2.5 Flash unterstützt 0–24.576 Token. Gemini 2.5 Flash Lite unterstützt 512–24.576 Token.\n\nLeer lassen oder auf „-1“ setzen, damit das Modell automatisch entscheidet, wann und wie viel nachgedacht werden soll. Standardmäßig denkt Gemini 2.5 Flash Lite nicht.",
|
||||
"com_endpoint_google_topk": "Top-k ändert, wie das Modell Token für die Antwort auswählt. Ein Top-k von 1 bedeutet, dass das ausgewählte Token das wahrscheinlichste unter allen Token im Vokabular des Modells ist (auch Greedy-Decoding genannt), während ein Top-k von 3 bedeutet, dass das nächste Token aus den 3 wahrscheinlichsten Token ausgewählt wird (unter Verwendung der Temperatur).",
|
||||
"com_endpoint_google_topp": "Top-p ändert, wie das Modell Token für die Antwort auswählt. Token werden von den wahrscheinlichsten K (siehe topK-Parameter) bis zu den am wenigsten wahrscheinlichen ausgewählt, bis die Summe ihrer Wahrscheinlichkeiten dem Top-p-Wert entspricht.",
|
||||
"com_endpoint_google_use_search_grounding": "Nutze den Abgleich mit der Google-Suche, um Antworten auf Basis von Echtzeit-Informationen aus dem Web zu fundieren. Dies ermöglicht den Modellen, auf aktuelle Informationen zuzugreifen und genauere, aktuellere Antworten zu geben.",
|
||||
"com_endpoint_instructions_assistants": "Anweisungen überschreiben",
|
||||
"com_endpoint_instructions_assistants_placeholder": "Überschreibt die Anweisungen des Assistenten. Dies ist nützlich, um das Verhalten auf Basis einzelner Ausführungen zu modifizieren.",
|
||||
"com_endpoint_max_output_tokens": "Max. Antwort-Token",
|
||||
|
|
@ -206,7 +217,7 @@
|
|||
"com_endpoint_message_new": "Nachricht an {{0}}",
|
||||
"com_endpoint_message_not_appendable": "Bearbeite deine Nachricht oder generiere neu.",
|
||||
"com_endpoint_my_preset": "Meine Voreinstellung",
|
||||
"com_endpoint_no_presets": "Noch keine Voreinstellungen, verwende die KI-Einstellungsschaltfläche, um eine zu erstellen",
|
||||
"com_endpoint_no_presets": "Noch keine Voreinstellungen, verwende die KI-Einstellungsschaltfläche, um eine Voreinstellung zu erstellen",
|
||||
"com_endpoint_open_menu": "Menü öffnen",
|
||||
"com_endpoint_openai_custom_name_placeholder": "Lege einen benutzerdefinierten Namen für die KI fest.",
|
||||
"com_endpoint_openai_detail": "Die Auflösung für Bilderkennungs-Anfragen. \"Niedrig\" ist günstiger und schneller, \"Hoch\" ist detaillierter und teurer, und \"Auto\" wählt automatisch zwischen den beiden basierend auf der Bildauflösung.",
|
||||
|
|
@ -215,12 +226,15 @@
|
|||
"com_endpoint_openai_max_tokens": "Optionales 'max_tokens'-Feld, das die maximale Anzahl von Token darstellt, die in der Chat-Vervollständigung generiert werden können. Die Gesamtlänge der Eingabe-Token und der generierten Token ist durch die Kontextlänge des Modells begrenzt. Du kannst Fehler erleben, wenn diese Zahl die maximalen Kontext-Token überschreitet.",
|
||||
"com_endpoint_openai_pres": "Zahl zwischen -2,0 und 2,0. Positive Werte bestrafen neue Token basierend darauf, ob sie im bisherigen Text vorkommen, wodurch die Wahrscheinlichkeit des Modells erhöht wird, über neue Themen zu sprechen.",
|
||||
"com_endpoint_openai_prompt_prefix_placeholder": "Lege benutzerdefinierte Anweisungen fest, die in die Systemnachricht an die KI aufgenommen werden sollen. Standard: keine",
|
||||
"com_endpoint_openai_reasoning_effort": "Nur für o1-Modelle: Begrenzt den Aufwand des Nachdenkens bei Schlussfolgerungsmodellen. Die Reduzierung des Nachdenkeaufwands kann zu schnelleren Antworten und weniger Token führen, die für das Überlegen vor einer Antwort verwendet werden.",
|
||||
"com_endpoint_openai_reasoning_effort": "Nur o1- und o3-Modelle: Beschränkt den Schlussfolgerungsaufwand für Schlussfolgerungsmodelle. Ein reduzierter Schlussfolgerungsaufwand kann zu schnelleren Antworten und weniger Tokens führen, die für die Schlussfolgerung in einer Antwort verwendet werden.",
|
||||
"com_endpoint_openai_reasoning_summary": "Nur für Responses-API: Eine Zusammenfassung des Denkprozesses des Modells. Dies kann nützlich sein, um den Denkprozess zu debuggen und zu verstehen. Wähle zwischen \"keine\", \"automatisch\", \"kurz\" oder \"detailliert\".",
|
||||
"com_endpoint_openai_resend": "Alle im Chat zuvor angehängten Bilder mit jeder neuen Nachricht erneut senden. Hinweis: Dies kann die Kosten der Anfrage aufgrund höherer Token-Anzahl erheblich erhöhen und du kannst bei vielen Bildanhängen Fehler erleben.",
|
||||
"com_endpoint_openai_resend_files": "Alle im Chat zuvor angehängten Dateien mit jeder neuen Nachricht erneut senden. Hinweis: Dies wird die Kosten der Anfrage aufgrund höherer Token-Anzahl erheblich erhöhen und du kannst bei vielen Anhängen Fehler erleben.",
|
||||
"com_endpoint_openai_stop": "Bis zu 4 Sequenzen, bei denen die API keine weiteren Token generiert.",
|
||||
"com_endpoint_openai_temp": "Entspricht der Kreativität der KI. Höhere Werte = zufälliger und kreativer, während niedrigere Werte = unkreativer und deterministischer. Wir empfehlen, entweder dies oder Top P zu ändern, aber nicht beides. Temperaturen über 1 sind nicht empfehlenswert.",
|
||||
"com_endpoint_openai_topp": "Eine Alternative zum Sampling mit Temperatur, genannt Nucleus-Sampling, bei dem das Modell die Ergebnisse der Token mit Top-p-Wahrscheinlichkeitsmasse berücksichtigt. So bedeutet 0,1, dass nur die Token betrachtet werden, die die Top 10% der Wahrscheinlichkeitsmasse ausmachen. Wir empfehlen, entweder dies oder die Temperatur zu ändern, aber nicht beides.",
|
||||
"com_endpoint_openai_use_responses_api": "Nutze die Responses-API anstelle von Chat Completions. Diese API enthält erweiterte Funktionen von OpenAI. Erforderlich für o1-pro, o3-pro und um Zusammenfassungen des Denkprozesses zu aktivieren.",
|
||||
"com_endpoint_openai_use_web_search": "Aktiviere die Websuche über die integrierten Suchfunktionen von OpenAI. Dies ermöglicht es dem Modell, das Web nach aktuellen Informationen zu durchsuchen und präzisere, aktuellere Antworten zu geben.",
|
||||
"com_endpoint_output": "Antwort",
|
||||
"com_endpoint_plug_image_detail": "Bild-Detail",
|
||||
"com_endpoint_plug_resend_files": "Anhänge erneut senden",
|
||||
|
|
@ -251,6 +265,7 @@
|
|||
"com_endpoint_prompt_prefix_assistants_placeholder": "Lege zusätzliche Anweisungen oder Kontext zusätzlich zu den Hauptanweisungen des Assistenten fest. Wird ignoriert, wenn leer.",
|
||||
"com_endpoint_prompt_prefix_placeholder": "Lege benutzerdefinierte Anweisungen oder Kontext fest. Wird ignoriert, wenn leer.",
|
||||
"com_endpoint_reasoning_effort": "Denkaufwand",
|
||||
"com_endpoint_reasoning_summary": "Zusammenfassung des Denkprozesses",
|
||||
"com_endpoint_save_as_preset": "Voreinstellung speichern",
|
||||
"com_endpoint_search": "Endpunkt nach Namen suchen",
|
||||
"com_endpoint_search_endpoint_models": "{{0}} KI-Modelle durchsuchen...",
|
||||
|
|
@ -266,6 +281,8 @@
|
|||
"com_endpoint_top_k": "Top K",
|
||||
"com_endpoint_top_p": "Top P",
|
||||
"com_endpoint_use_active_assistant": "Aktiven Assistenten verwenden",
|
||||
"com_endpoint_use_responses_api": "Responses-API nutzen",
|
||||
"com_endpoint_use_search_grounding": "Fundierung mit Google-Websuche",
|
||||
"com_error_expired_user_key": "Der angegebene API-Key für {{0}} ist am {{1}} abgelaufen. Bitte gebe einen neuen API-Key ein und versuche es erneut.",
|
||||
"com_error_files_dupe": "Doppelte Datei erkannt.",
|
||||
"com_error_files_empty": "Leere Dateien sind nicht zulässig",
|
||||
|
|
@ -274,7 +291,9 @@
|
|||
"com_error_files_upload": "Beim Hochladen der Datei ist ein Fehler aufgetreten",
|
||||
"com_error_files_upload_canceled": "Die Datei-Upload-Anfrage wurde abgebrochen. Hinweis: Der Upload-Vorgang könnte noch im Hintergrund laufen und die Datei muss möglicherweise manuell gelöscht werden.",
|
||||
"com_error_files_validation": "Bei der Validierung der Datei ist ein Fehler aufgetreten.",
|
||||
"com_error_input_length": "Die Token-Anzahl der letzten Nachricht ist zu hoch und überschreitet das Token-Limit ({{0}}). Bitte kürze deine Nachricht, passe die maximale Kontextgröße in den Gesprächsparametern an oder erstelle eine Abzweigung des Gesprächs, um fortzufahren.",
|
||||
"com_error_google_tool_conflict": "Die integrierten Google-Tools können nicht zusammen mit externen Tools verwendet werden. Bitte deaktiviere entweder die integrierten oder die externen Tools.",
|
||||
"com_error_heic_conversion": "Das HEIC-Bild konnte nicht in JPEG konvertiert werden. Bitte versuchen Sie, das Bild manuell zu konvertieren oder verwenden Sie ein anderes Format.",
|
||||
"com_error_input_length": "Die Anzahl der Tokens der letzten Nachricht ist zu lang und überschreitet das Token-Limit. Oder Ihre Token-Limit-Parameter sind falsch konfiguriert, was sich negativ auf das Kontextfenster auswirkt. Weitere Informationen: {{0}}. Bitte kürzen Sie Ihre Nachricht, passen Sie die maximale Kontextgröße in den Konversationsparametern an oder teilen Sie die Konversation auf, um fortzufahren.",
|
||||
"com_error_invalid_agent_provider": "Der Anbieter \"{{0}}\" steht für die Verwendung mit Agents nicht zur Verfügung. Bitte gehe zu den Einstellungen deines Agents und wähle einen aktuell verfügbaren Anbieter aus.",
|
||||
"com_error_invalid_user_key": "Ungültiger API-Key angegeben. Bitte gebe einen gültigen API-Key ein und versuche es erneut.",
|
||||
"com_error_moderation": "Es scheint, dass der eingereichte Inhalt von unserem Moderationssystem als nicht mit unseren Community-Richtlinien vereinbar gekennzeichnet wurde. Wir können mit diesem spezifischen Thema nicht fortfahren. Wenn Sie andere Fragen oder Themen haben, die Sie erkunden möchten, bearbeiten Sie bitte Ihre Nachricht oder erstellen Sie eine neue Konversation.",
|
||||
|
|
@ -285,6 +304,7 @@
|
|||
"com_files_number_selected": "{{0}} von {{1}} Datei(en) ausgewählt",
|
||||
"com_generated_files": "Generierte Dateien:",
|
||||
"com_hide_examples": "Beispiele ausblenden",
|
||||
"com_info_heic_converting": "HEIC-Bild wird in JPEG konventiert...",
|
||||
"com_nav_2fa": "Zwei-Faktor-Authentifizierung (2FA)",
|
||||
"com_nav_account_settings": "Kontoeinstellungen",
|
||||
"com_nav_always_make_prod": "Neue Versionen direkt produktiv nehmen",
|
||||
|
|
@ -302,6 +322,27 @@
|
|||
"com_nav_auto_transcribe_audio": "Audio automatisch transkribieren",
|
||||
"com_nav_automatic_playback": "Automatische Wiedergabe der neuesten Nachricht",
|
||||
"com_nav_balance": "Guthaben",
|
||||
"com_nav_balance_auto_refill_disabled": "Automatisches Auffüllen ist deaktiviert",
|
||||
"com_nav_balance_auto_refill_error": "Die Einstellungen ",
|
||||
"com_nav_balance_auto_refill_settings": "Einstellungen zum automatischen Auffüllen",
|
||||
"com_nav_balance_day": "Tag",
|
||||
"com_nav_balance_days": "Tage",
|
||||
"com_nav_balance_every": "Jeden",
|
||||
"com_nav_balance_hour": "Stunde",
|
||||
"com_nav_balance_hours": "Stunden",
|
||||
"com_nav_balance_interval": "Intervall",
|
||||
"com_nav_balance_last_refill": "Letztes Auffüllen:",
|
||||
"com_nav_balance_minute": "Minute",
|
||||
"com_nav_balance_minutes": "Minuten",
|
||||
"com_nav_balance_month": "Monat",
|
||||
"com_nav_balance_months": "Monate",
|
||||
"com_nav_balance_next_refill": "Nächstes Auffüllen:",
|
||||
"com_nav_balance_next_refill_info": "Die nächste Aufladung erfolgt nur dann automatisch, wenn beide Bedingungen erfüllt sind: Das angegebene Zeitintervall ist seit der letzten Aufladung verstrichen, und das Senden einer Aufforderung würde dazu führen, dass das Guthaben unter Null sinkt.",
|
||||
"com_nav_balance_refill_amount": "Nachfüllmenge:",
|
||||
"com_nav_balance_second": "Sekunde",
|
||||
"com_nav_balance_seconds": "Sekunden",
|
||||
"com_nav_balance_week": "Woche",
|
||||
"com_nav_balance_weeks": "Wochen",
|
||||
"com_nav_browser": "Browser",
|
||||
"com_nav_center_chat_input": "Chat-Eingabe im Willkommensbildschirm zentrieren",
|
||||
"com_nav_change_picture": "Bild ändern",
|
||||
|
|
@ -325,7 +366,6 @@
|
|||
"com_nav_delete_cache_storage": "TTS-Cache-Speicher löschen",
|
||||
"com_nav_delete_data_info": "Alle deine Daten werden gelöscht.",
|
||||
"com_nav_delete_warning": "WARNUNG: Dies wird dein Konto dauerhaft löschen.",
|
||||
"com_nav_edit_chat_badges": "Chat Badges editieren",
|
||||
"com_nav_enable_cache_tts": "TTS-Caching aktivieren",
|
||||
"com_nav_enable_cloud_browser_voice": "Cloud-basierte Stimmen verwenden",
|
||||
"com_nav_enabled": "Aktiviert",
|
||||
|
|
@ -349,6 +389,7 @@
|
|||
"com_nav_font_size_xs": "Sehr klein",
|
||||
"com_nav_help_faq": "Hilfe & FAQ",
|
||||
"com_nav_hide_panel": "Rechte Seitenleiste verstecken",
|
||||
"com_nav_info_balance": "Der Saldo zeigt an, wie viele Token-Credits Sie noch verwenden können. Token-Credits werden in Geldwert umgerechnet (z. B. 1000 Credits = 0,001 USD).",
|
||||
"com_nav_info_code_artifacts": "Aktiviert die Anzeige experimenteller Code-Artefakte neben dem Chat",
|
||||
"com_nav_info_code_artifacts_agent": "Aktiviert die Verwendung von Code-Artefakten für diesen Agenten. Standardmäßig werden zusätzliche, spezielle Anweisungen für die Nutzung von Artefakten hinzugefügt, es sei denn, der \"Benutzerdefinierte Prompt-Modus\" ist aktiviert.",
|
||||
"com_nav_info_custom_prompt_mode": "Wenn aktiviert, wird die Standard-Systemaufforderung für Artefakte nicht eingeschlossen. Alle Anweisungen zur Erzeugung von Artefakten müssen in diesem Modus manuell bereitgestellt werden.",
|
||||
|
|
@ -396,6 +437,8 @@
|
|||
"com_nav_log_out": "Abmelden",
|
||||
"com_nav_long_audio_warning": "Längere Texte benötigen mehr Zeit zur Verarbeitung.",
|
||||
"com_nav_maximize_chat_space": "Chat-Bereich maximieren",
|
||||
"com_nav_mcp_vars_update_error": "Fehler beim Aktualisieren der benutzerdefinierten MCP-Benutzervariablen: {{0}}",
|
||||
"com_nav_mcp_vars_updated": "Die MCP-Benutzervariablen wurden erfolgreich aktualisiert.",
|
||||
"com_nav_modular_chat": "Ermöglicht das Wechseln der Endpunkte mitten im Gespräch",
|
||||
"com_nav_my_files": "Meine Dateien",
|
||||
"com_nav_not_supported": "Nicht unterstützt",
|
||||
|
|
@ -415,10 +458,13 @@
|
|||
"com_nav_search_placeholder": "Nachrichten durchsuchen",
|
||||
"com_nav_send_message": "Nachricht senden",
|
||||
"com_nav_setting_account": "Konto",
|
||||
"com_nav_setting_balance": "Saldo",
|
||||
"com_nav_setting_beta": "Beta-Funktionen",
|
||||
"com_nav_setting_chat": "Chat",
|
||||
"com_nav_setting_data": "Datensteuerung",
|
||||
"com_nav_setting_general": "Allgemein",
|
||||
"com_nav_setting_mcp": "MCP Einstellungen",
|
||||
"com_nav_setting_personalization": "Personalisierung",
|
||||
"com_nav_setting_speech": "Sprache",
|
||||
"com_nav_settings": "Einstellungen",
|
||||
"com_nav_shared_links": "Geteilte Links",
|
||||
|
|
@ -445,19 +491,22 @@
|
|||
"com_show_agent_settings": "Agenteneinstellungen anzeigen",
|
||||
"com_show_completion_settings": "Vervollständigungseinstellungen anzeigen",
|
||||
"com_show_examples": "Beispiele anzeigen",
|
||||
"com_sidepanel_agent_builder": "Agenten Ersteller",
|
||||
"com_sidepanel_agent_builder": "Agenten erstellen",
|
||||
"com_sidepanel_assistant_builder": "Assistenten-Ersteller",
|
||||
"com_sidepanel_attach_files": "Dateien anhängen",
|
||||
"com_sidepanel_conversation_tags": "Lesezeichen",
|
||||
"com_sidepanel_hide_panel": "Seitenleiste ausblenden",
|
||||
"com_sidepanel_manage_files": "Dateien verwalten",
|
||||
"com_sidepanel_mcp_enter_value": "Gib den Wert für {{0}} ein",
|
||||
"com_sidepanel_mcp_no_servers_with_vars": "Keine MCP-Server mit konfigurierbaren Variablen.",
|
||||
"com_sidepanel_mcp_variables_for": "MCP Variablen für {{0}}",
|
||||
"com_sidepanel_parameters": "KI-Einstellungen",
|
||||
"com_sources_image_alt": "Suchergebnis Bild",
|
||||
"com_sources_more_sources": "+{{count}} Quellen",
|
||||
"com_sources_image_alt": "Suchergebnis Bild\n",
|
||||
"com_sources_more_sources": "+{{count}} Quellen\n",
|
||||
"com_sources_tab_all": "Alles",
|
||||
"com_sources_tab_images": "Bilder",
|
||||
"com_sources_tab_news": "Nachrichten",
|
||||
"com_sources_title": "Quellen",
|
||||
"com_sources_title": "Quellen\n",
|
||||
"com_ui_2fa_account_security": "Die Zwei-Faktor-Authentifizierung bietet Ihrem Konto eine zusätzliche Sicherheitsebene.",
|
||||
"com_ui_2fa_disable": "2FA deaktivieren",
|
||||
"com_ui_2fa_disable_error": "Beim Deaktivieren der Zwei-Faktor-Authentifizierung ist ein Fehler aufgetreten.",
|
||||
|
|
@ -471,9 +520,11 @@
|
|||
"com_ui_accept": "Ich akzeptiere",
|
||||
"com_ui_action_button": "Aktionstaste",
|
||||
"com_ui_add": "Hinzufügen",
|
||||
"com_ui_add_mcp": "MCP hinzufügen",
|
||||
"com_ui_add_mcp_server": "MCP Server hinzufügen",
|
||||
"com_ui_add_model_preset": "Ein KI-Modell oder eine Voreinstellung für eine zusätzliche Antwort hinzufügen",
|
||||
"com_ui_add_multi_conversation": "Mehrere Chats hinzufügen",
|
||||
"com_ui_adding_details": "Hinzufügen von Details",
|
||||
"com_ui_adding_details": "Hinzufügen von Details\n",
|
||||
"com_ui_admin": "Admin",
|
||||
"com_ui_admin_access_warning": "Das Deaktivieren des Admin-Zugriffs auf diese Funktion kann zu unerwarteten Problemen in der Benutzeroberfläche führen, die ein Neuladen erfordern. Nach dem Speichern kann dies nur über die Schnittstelleneinstellung in der librechat.yaml-Konfiguration rückgängig gemacht werden, was sich auf alle Rollen auswirkt.",
|
||||
"com_ui_admin_settings": "Admin-Einstellungen",
|
||||
|
|
@ -484,7 +535,7 @@
|
|||
"com_ui_agent_chain_info": "Ermöglicht das Erstellen von Agenten-Sequenzen. Jeder Agent kann auf die Ausgaben vorheriger Agenten in der Kette zugreifen. Basiert auf der \"Mixture-of-Agents\"-Architektur, bei der Agenten vorherige Ausgaben als zusätzliche Informationen verwenden.",
|
||||
"com_ui_agent_chain_max": "Du hast die maximale Anzahl von {{0}} Agenten erreicht.",
|
||||
"com_ui_agent_delete_error": "Beim Löschen des Assistenten ist ein Fehler aufgetreten",
|
||||
"com_ui_agent_deleted": "Assistent erfolgreich gelöscht",
|
||||
"com_ui_agent_deleted": "Agent erfolgreich gelöscht",
|
||||
"com_ui_agent_duplicate_error": "Beim Duplizieren des Assistenten ist ein Fehler aufgetreten",
|
||||
"com_ui_agent_duplicated": "Agent wurde erfolgreich dupliziert",
|
||||
"com_ui_agent_editing_allowed": "Andere Nutzende können diesen Agenten bereits bearbeiten",
|
||||
|
|
@ -493,18 +544,21 @@
|
|||
"com_ui_agent_shared_to_all": "Hier muss etwas eingegeben werden. War leer.",
|
||||
"com_ui_agent_var": "{{0}} Agent",
|
||||
"com_ui_agent_version": "Version",
|
||||
"com_ui_agent_version_active": "Aktive Version",
|
||||
"com_ui_agent_version_active": "Aktive Version\n",
|
||||
"com_ui_agent_version_duplicate": "Doppelte Version entdeckt. Dies würde eine Version erzeugen, die identisch mit der Version {{versionIndex}} ist.",
|
||||
"com_ui_agent_version_empty": "Keine Versionen verfügbar",
|
||||
"com_ui_agent_version_empty": "Keine Versionen verfügbar\n",
|
||||
"com_ui_agent_version_error": "Fehler beim Abrufen der Versionen",
|
||||
"com_ui_agent_version_history": "Versionsgeschichte",
|
||||
"com_ui_agent_version_history": "Versionsgeschichte\n",
|
||||
"com_ui_agent_version_no_agent": "Kein Agent ausgewählt. Bitte wähle einen Agenten aus, um den Versionsverlauf anzuzeigen.",
|
||||
"com_ui_agent_version_no_date": "Datum nicht verfügbar",
|
||||
"com_ui_agent_version_restore": "Wiederherstellen",
|
||||
"com_ui_agent_version_no_date": "Datum nicht verfügbar\n",
|
||||
"com_ui_agent_version_restore": "Wiederherstellen\n",
|
||||
"com_ui_agent_version_restore_confirm": "Bist du sicher, dass du diese Version wiederherstellen willst?",
|
||||
"com_ui_agent_version_unknown_date": "Unbekanntes Datum",
|
||||
"com_ui_agent_version_restore_error": "Die Version konnte nicht wiederhergestellt werden",
|
||||
"com_ui_agent_version_restore_success": "Die Version wurde erfolgreich hergestellt",
|
||||
"com_ui_agent_version_title": "Version {{versionNumber}}",
|
||||
"com_ui_agent_version_unknown_date": "Unbekanntes Datum\n",
|
||||
"com_ui_agents": "Agenten",
|
||||
"com_ui_agents_allow_create": "Erlaube Agents zu erstellen",
|
||||
"com_ui_agents_allow_create": "Erlaube Agenten zu erstellen",
|
||||
"com_ui_agents_allow_share_global": "Erlaube das Teilen von Agenten mit allen Nutzern",
|
||||
"com_ui_agents_allow_use": "Verwendung von Agenten erlauben",
|
||||
"com_ui_all": "alle",
|
||||
|
|
@ -536,8 +590,11 @@
|
|||
"com_ui_auth_url": "Autorisierungs-URL",
|
||||
"com_ui_authentication": "Authentifizierung",
|
||||
"com_ui_authentication_type": "Authentifizierungstyp",
|
||||
"com_ui_auto": "Auto",
|
||||
"com_ui_available_tools": "Verfügbare Tools",
|
||||
"com_ui_avatar": "Avatar",
|
||||
"com_ui_azure": "Azure",
|
||||
"com_ui_back": "Zurück",
|
||||
"com_ui_back_to_chat": "Zurück zum Chat",
|
||||
"com_ui_back_to_prompts": "Zurück zu den Prompts",
|
||||
"com_ui_backup_codes": "Backup-Codes",
|
||||
|
|
@ -567,7 +624,8 @@
|
|||
"com_ui_bulk_delete_error": "Geteilte Links konnten nicht gelöscht werden.",
|
||||
"com_ui_callback_url": "Callback-URL",
|
||||
"com_ui_cancel": "Abbrechen",
|
||||
"com_ui_category": "Kategorie",
|
||||
"com_ui_cancelled": "Abgebrochen",
|
||||
"com_ui_category": "Kategorie\n",
|
||||
"com_ui_chat": "Chat",
|
||||
"com_ui_chat_history": "Chatverlauf",
|
||||
"com_ui_clear": "Löschen",
|
||||
|
|
@ -576,11 +634,13 @@
|
|||
"com_ui_client_secret": "Client Secret",
|
||||
"com_ui_close": "Schließen",
|
||||
"com_ui_close_menu": "Menü schließen",
|
||||
"com_ui_close_window": "Fenster schliessen",
|
||||
"com_ui_code": "Code",
|
||||
"com_ui_collapse_chat": "Chat einklappen",
|
||||
"com_ui_command_placeholder": "Optional: Gib einen Promptbefehl ein oder den Namen.",
|
||||
"com_ui_command_usage_placeholder": "Wähle einen Prompt nach Befehl oder Name aus",
|
||||
"com_ui_complete_setup": "Einrichtung abschließen",
|
||||
"com_ui_configure_mcp_variables_for": "Konfiguriere Variablen für {{0}}",
|
||||
"com_ui_confirm_action": "Aktion bestätigen",
|
||||
"com_ui_confirm_admin_use_change": "Wenn du diese Einstellung änderst, wird der Zugriff für Administratoren, einschließlich dir selbst, gesperrt. Bist du sicher, dass du fortfahren möchtest?",
|
||||
"com_ui_confirm_change": "Änderung bestätigen",
|
||||
|
|
@ -595,8 +655,10 @@
|
|||
"com_ui_copy_to_clipboard": "In die Zwischenablage kopieren",
|
||||
"com_ui_create": "Erstellen",
|
||||
"com_ui_create_link": "Link erstellen",
|
||||
"com_ui_create_memory": "Gedächtnis erstellen",
|
||||
"com_ui_create_prompt": "Prompt erstellen",
|
||||
"com_ui_creating_image": "Bild wird erstellt. Kann einen Moment dauern",
|
||||
"com_ui_current": "Aktuell",
|
||||
"com_ui_currently_production": "Aktuell im Produktivbetrieb",
|
||||
"com_ui_custom": "Benutzerdefiniert",
|
||||
"com_ui_custom_header_name": "Benutzerdefinierter Headername",
|
||||
|
|
@ -629,13 +691,20 @@
|
|||
"com_ui_delete_confirm": "Dies wird löschen:",
|
||||
"com_ui_delete_confirm_prompt_version_var": "Dies wird die ausgewählte Version für \"{{0}}\" löschen. Wenn keine anderen Versionen existieren, wird der Prompt gelöscht.",
|
||||
"com_ui_delete_conversation": "Chat löschen?",
|
||||
"com_ui_delete_mcp": "MCP löschen",
|
||||
"com_ui_delete_mcp_confirm": "Bist du sicher, dass du diesen MCP-Server löschen möchtest?",
|
||||
"com_ui_delete_mcp_error": "Fehler beim Löschen des MCP-Servers",
|
||||
"com_ui_delete_mcp_success": "MCP-Server erfolgreich gelöscht",
|
||||
"com_ui_delete_memory": "Gedächtnis löschen",
|
||||
"com_ui_delete_prompt": "Prompt löschen?",
|
||||
"com_ui_delete_shared_link": "Geteilten Link löschen?",
|
||||
"com_ui_delete_tool": "Werkzeug löschen",
|
||||
"com_ui_delete_tool_confirm": "Bist du sicher, dass du dieses Werkzeug löschen möchtest?",
|
||||
"com_ui_deleted": "Gelöscht",
|
||||
"com_ui_descending": "Absteigend",
|
||||
"com_ui_description": "Beschreibung",
|
||||
"com_ui_description_placeholder": "Optional: Gib eine Beschreibung für den Prompt ein",
|
||||
"com_ui_deselect_all": "Alle abwählen",
|
||||
"com_ui_disabling": "Deaktiviere …",
|
||||
"com_ui_download": "Herunterladen",
|
||||
"com_ui_download_artifact": "Artefakt herunterladen",
|
||||
|
|
@ -650,24 +719,45 @@
|
|||
"com_ui_duplication_processing": "Konversation wird dupliziert...",
|
||||
"com_ui_duplication_success": "Unterhaltung erfolgreich dupliziert",
|
||||
"com_ui_edit": "Bearbeiten",
|
||||
"com_ui_edit_editing_image": "Bild bearbeiten",
|
||||
"com_ui_edit_editing_image": "Bild bearbeiten\n",
|
||||
"com_ui_edit_mcp_server": "MCP-Server bearbeiten",
|
||||
"com_ui_edit_memory": "Gedächtnis bearbeiten",
|
||||
"com_ui_empty_category": "-",
|
||||
"com_ui_endpoint": "Endpunkt",
|
||||
"com_ui_endpoint_menu": "LLM-Endpunkt-Menü",
|
||||
"com_ui_enter": "Eingabe",
|
||||
"com_ui_enter_api_key": "API-Schlüssel eingeben",
|
||||
"com_ui_enter_key": "Schlüssel eingeben",
|
||||
"com_ui_enter_openapi_schema": "Gib hier dein OpenAPI-Schema ein",
|
||||
"com_ui_enter_value": "Wert eingeben",
|
||||
"com_ui_error": "Fehler",
|
||||
"com_ui_error_connection": "Verbindungsfehler zum Server. Versuche, die Seite zu aktualisieren.",
|
||||
"com_ui_error_save_admin_settings": "Beim Speichern Ihrer Admin-Einstellungen ist ein Fehler aufgetreten.",
|
||||
"com_ui_error_updating_preferences": "Fehler beim Aktualisieren der Einstellungen",
|
||||
"com_ui_examples": "Beispiele",
|
||||
"com_ui_expand_chat": "Chat erweitern",
|
||||
"com_ui_export_convo_modal": "Konversation exportieren",
|
||||
"com_ui_feedback_more": "Mehr ...",
|
||||
"com_ui_feedback_more_information": "Zusätzliches Feedback",
|
||||
"com_ui_feedback_negative": "Muss verbessert werden",
|
||||
"com_ui_feedback_placeholder": "Geben Sie hier bitte weiteres Feedback an",
|
||||
"com_ui_feedback_positive": "Prima, sehr gut",
|
||||
"com_ui_feedback_tag_attention_to_detail": "Liebe zum Detail",
|
||||
"com_ui_feedback_tag_bad_style": "Clear and Well-Written",
|
||||
"com_ui_feedback_tag_clear_well_written": "Klar und gut geschrieben",
|
||||
"com_ui_feedback_tag_creative_solution": "Kreative Lösung",
|
||||
"com_ui_feedback_tag_inaccurate": "Ungenaue oder falsche Antwort",
|
||||
"com_ui_feedback_tag_missing_image": "Bild erwartet",
|
||||
"com_ui_feedback_tag_not_helpful": "Es fehlten nützliche Informationen",
|
||||
"com_ui_feedback_tag_not_matched": "Entspricht nicht der Anfrage",
|
||||
"com_ui_feedback_tag_other": "Anderer Fehler",
|
||||
"com_ui_feedback_tag_unjustified_refusal": "Mit anderer Begründung abgelehnt",
|
||||
"com_ui_field_required": "Dieses Feld ist erforderlich",
|
||||
"com_ui_files": "Dateien",
|
||||
"com_ui_file_size": "Dateigröße",
|
||||
"com_ui_files": "Dateien\n",
|
||||
"com_ui_filter_prompts": "Prompts filtern",
|
||||
"com_ui_filter_prompts_name": "Prompts nach Namen filtern",
|
||||
"com_ui_final_touch": "Letzter Schliff",
|
||||
"com_ui_final_touch": "Letzter Schliff\n",
|
||||
"com_ui_finance": "Finanzen",
|
||||
"com_ui_fork": "Abzweigen",
|
||||
"com_ui_fork_all_target": "Alle bis/von hier einbeziehen",
|
||||
|
|
@ -697,7 +787,8 @@
|
|||
"com_ui_generate_backup": "Backup-Codes generieren",
|
||||
"com_ui_generate_qrcode": "QR-Code generieren",
|
||||
"com_ui_generating": "Generiere …",
|
||||
"com_ui_getting_started": "Erste Schritte",
|
||||
"com_ui_generation_settings": "Einstellungen für die Generierung",
|
||||
"com_ui_getting_started": "Erste Schritte\n",
|
||||
"com_ui_global_group": "Leer – etwas fehlt noch",
|
||||
"com_ui_go_back": "Zurück",
|
||||
"com_ui_go_to_conversation": "Zur Konversation gehen",
|
||||
|
|
@ -705,11 +796,14 @@
|
|||
"com_ui_good_evening": "Guten Abend",
|
||||
"com_ui_good_morning": "Guten Morgen",
|
||||
"com_ui_happy_birthday": "Es ist mein 1. Geburtstag!",
|
||||
"com_ui_hide_image_details": "Details zum Bild ausblenden",
|
||||
"com_ui_hide_qr": "QR-Code ausblenden",
|
||||
"com_ui_host": "Host",
|
||||
"com_ui_icon": "Icon",
|
||||
"com_ui_idea": "Ideen",
|
||||
"com_ui_image_created": "Bild erstellt",
|
||||
"com_ui_image_edited": "Bild bearbeitet",
|
||||
"com_ui_image_created": "Bild erstellt\n",
|
||||
"com_ui_image_details": "Details zum Bild",
|
||||
"com_ui_image_edited": "Bild bearbeitet\n",
|
||||
"com_ui_image_gen": "Bildgenerierung",
|
||||
"com_ui_import": "Importieren",
|
||||
"com_ui_import_conversation_error": "Beim Importieren Ihrer Konversationen ist ein Fehler aufgetreten",
|
||||
|
|
@ -717,9 +811,9 @@
|
|||
"com_ui_import_conversation_info": "Konversationen aus einer JSON-Datei importieren",
|
||||
"com_ui_import_conversation_success": "Konversationen erfolgreich importiert",
|
||||
"com_ui_include_shadcnui": "Anweisungen für shadcn/ui-Komponenten einschließen",
|
||||
"com_ui_include_shadcnui_agent": "shadcn/ui-Anweisungen einfügen",
|
||||
"com_ui_input": "Eingabe",
|
||||
"com_ui_instructions": "Anweisungen",
|
||||
"com_ui_key": "Schlüssel",
|
||||
"com_ui_late_night": "Schöne späte Nacht",
|
||||
"com_ui_latest_footer": "Alle KIs für alle.",
|
||||
"com_ui_latest_production_version": "Neueste Produktiv-Version",
|
||||
|
|
@ -732,7 +826,25 @@
|
|||
"com_ui_logo": "{{0}} Logo",
|
||||
"com_ui_manage": "Verwalten",
|
||||
"com_ui_max_tags": "Die maximale Anzahl ist {{0}}, es werden die neuesten Werte verwendet.",
|
||||
"com_ui_mcp_dialog_desc": "Bitte geben Sie unten die erforderlichen Informationen ein.",
|
||||
"com_ui_mcp_enter_var": "Geben Sie einen Wert für {{0}} ein",
|
||||
"com_ui_mcp_server_not_found": "Server nicht gefunden",
|
||||
"com_ui_mcp_servers": "MCP Server",
|
||||
"com_ui_mcp_url": "MCP-Server-URL",
|
||||
"com_ui_memories": "Gedächtnisse",
|
||||
"com_ui_memories_allow_create": "Erinnerungen erstellen erlauben",
|
||||
"com_ui_memories_allow_opt_out": "Benutzern erlauben, die Erinnerungsnutzung zu deaktivieren",
|
||||
"com_ui_memories_allow_read": "Erinnerungen lesen erlauben",
|
||||
"com_ui_memories_allow_update": "Erinnerungen aktualisieren erlauben",
|
||||
"com_ui_memories_allow_use": "Erinnerungen nutzen erlauben",
|
||||
"com_ui_memories_filter": "Erinnerungen filtern...",
|
||||
"com_ui_memory": "Erinnerung",
|
||||
"com_ui_memory_created": "Erinnerung erfolgreich erstellt",
|
||||
"com_ui_memory_deleted": "Erinnerung gelöscht",
|
||||
"com_ui_memory_deleted_items": "Gelöschte Erinnerungen",
|
||||
"com_ui_memory_key_exists": "Eine Erinnerung mit diesem Schlüssel existiert bereits. Bitte verwende einen anderen Schlüssel.",
|
||||
"com_ui_memory_updated": "Erinnerung aktualisiert",
|
||||
"com_ui_memory_updated_items": "Aktualisierte Erinnerungen",
|
||||
"com_ui_mention": "Erwähne einen Endpunkt, Assistenten oder eine Voreinstellung, um schnell dorthin zu wechseln",
|
||||
"com_ui_min_tags": "Es können nicht mehr Werte entfernt werden, mindestens {{0}} sind erforderlich.",
|
||||
"com_ui_misc": "Verschiedenes",
|
||||
|
|
@ -751,17 +863,30 @@
|
|||
"com_ui_no_category": "Keine Kategorie",
|
||||
"com_ui_no_changes": "Keine Änderungen zum Aktualisieren",
|
||||
"com_ui_no_data": "Leer – etwas fehlt noch",
|
||||
"com_ui_no_personalization_available": "Derzeit sind keine Personalisierungsoptionen verfügbar.",
|
||||
"com_ui_no_read_access": "Du hast keine Berechtigung, Erinnerungen anzuzeigen.",
|
||||
"com_ui_no_terms_content": "Keine Inhalte der Allgemeinen Geschäftsbedingungen zum Anzeigen",
|
||||
"com_ui_no_valid_items": "Leer - Text fehlt noch",
|
||||
"com_ui_none": "Keine",
|
||||
"com_ui_not_used": "Nicht verwendet",
|
||||
"com_ui_nothing_found": "Nichts gefunden",
|
||||
"com_ui_oauth": "OAuth",
|
||||
"com_ui_oauth_connected_to": "Verbunden mit",
|
||||
"com_ui_oauth_error_callback_failed": "Authentifizierungs Callback fehlgeschlagen. Bitte versuchen Sie es erneut.",
|
||||
"com_ui_oauth_error_generic": "Authentifizierung fehlgeschlagen. Bitte versuchen Sie es erneut.",
|
||||
"com_ui_oauth_error_invalid_state": "Ungültiger Statusparameter. Bitte versuchen Sie es erneut.",
|
||||
"com_ui_oauth_error_missing_code": "Autorisierungscode fehlt. Bitte versuchen Sie es erneut.",
|
||||
"com_ui_oauth_error_missing_state": "Statusparameter fehlt. Bitte versuchen Sie es erneut.",
|
||||
"com_ui_oauth_error_title": "Authentifizierung fehlgeschlagen",
|
||||
"com_ui_oauth_success_description": "Ihre Authentifizierung war erfolgreich. Dieses Fenster schliesst sich in",
|
||||
"com_ui_oauth_success_title": "Authentifizierung erfolgreich",
|
||||
"com_ui_of": "von",
|
||||
"com_ui_off": "Aus",
|
||||
"com_ui_on": "An",
|
||||
"com_ui_openai": "OpenAI",
|
||||
"com_ui_optional": "(Optional)",
|
||||
"com_ui_page": "Seite",
|
||||
"com_ui_preferences_updated": "Einstellungen erfolgreich aktualisiert",
|
||||
"com_ui_prev": "Zurück",
|
||||
"com_ui_preview": "Vorschau",
|
||||
"com_ui_privacy_policy": "Datenschutzerklärung",
|
||||
|
|
@ -779,8 +904,11 @@
|
|||
"com_ui_prompts_allow_share_global": "Teilen von Prompts mit allen Benutzern erlauben",
|
||||
"com_ui_prompts_allow_use": "Verwendung von Prompts erlauben",
|
||||
"com_ui_provider": "Anbieter",
|
||||
"com_ui_quality": "Qualität",
|
||||
"com_ui_read_aloud": "Vorlesen",
|
||||
"com_ui_redirecting_to_provider": "Weiterleitung zu {{0}}, einen Moment bitte...",
|
||||
"com_ui_reference_saved_memories": "Gespeicherte Erinnerungen referenzieren",
|
||||
"com_ui_reference_saved_memories_description": "Erlaube dem Assistenten, deine gespeicherten Erinnerungen beim Antworten zu referenzieren und zu nutzen.",
|
||||
"com_ui_refresh_link": "Link aktualisieren",
|
||||
"com_ui_regenerate": "Neu generieren",
|
||||
"com_ui_regenerate_backup": "Backup-Codes neu generieren",
|
||||
|
|
@ -792,6 +920,7 @@
|
|||
"com_ui_rename_prompt": "Prompt umbenennen",
|
||||
"com_ui_requires_auth": "Authentifizierung erforderlich",
|
||||
"com_ui_reset_var": "{{0}} zurücksetzen",
|
||||
"com_ui_reset_zoom": "Zoom zurücksetzen",
|
||||
"com_ui_result": "Ergebnis",
|
||||
"com_ui_revoke": "Widerrufen",
|
||||
"com_ui_revoke_info": "Benutzer-API-Keys widerrufen",
|
||||
|
|
@ -807,11 +936,14 @@
|
|||
"com_ui_save_badge_changes": "Änderungen an Badges speichern?",
|
||||
"com_ui_save_submit": "Speichern & Absenden",
|
||||
"com_ui_saved": "Gespeichert!",
|
||||
"com_ui_saving": "Sicherung läuft...",
|
||||
"com_ui_schema": "Schema",
|
||||
"com_ui_scope": "Umfang",
|
||||
"com_ui_search": "Suche",
|
||||
"com_ui_seconds": "Sekunden",
|
||||
"com_ui_secret_key": "Geheimschlüssel",
|
||||
"com_ui_select": "Auswählen",
|
||||
"com_ui_select_all": "Alle auswählen",
|
||||
"com_ui_select_file": "Datei auswählen",
|
||||
"com_ui_select_model": "Ein KI-Modell auswählen",
|
||||
"com_ui_select_provider": "Wähle einen Anbieter",
|
||||
|
|
@ -837,6 +969,7 @@
|
|||
"com_ui_shop": "Einkaufen",
|
||||
"com_ui_show": "Anzeigen",
|
||||
"com_ui_show_all": "Alle anzeigen",
|
||||
"com_ui_show_image_details": "Details zum Bild anzeigen",
|
||||
"com_ui_show_qr": "QR-Code anzeigen",
|
||||
"com_ui_sign_in_to_domain": "Anmelden bei {{0}}",
|
||||
"com_ui_simple": "Einfach",
|
||||
|
|
@ -858,15 +991,23 @@
|
|||
"com_ui_terms_of_service": "Nutzungsbedingungen",
|
||||
"com_ui_thinking": "Nachdenken...",
|
||||
"com_ui_thoughts": "Gedanken",
|
||||
"com_ui_token": "Token",
|
||||
"com_ui_token_exchange_method": "Token-Austauschmethode",
|
||||
"com_ui_token_url": "Token-URL",
|
||||
"com_ui_tokens": "Tokens",
|
||||
"com_ui_tool_collection_prefix": "Eine Tools Sammlung von",
|
||||
"com_ui_tool_info": "Tool Information",
|
||||
"com_ui_tool_more_info": "Mehr Information über dieses Tool",
|
||||
"com_ui_tools": "Werkzeuge",
|
||||
"com_ui_travel": "Reisen",
|
||||
"com_ui_trust_app": "Ich vertraue dieser Anwendung",
|
||||
"com_ui_unarchive": "Aus Archiv holen",
|
||||
"com_ui_unarchive_error": "Konversation konnte nicht aus dem Archiv geholt werden",
|
||||
"com_ui_unknown": "Unbekannt",
|
||||
"com_ui_untitled": "Unbenannt",
|
||||
"com_ui_update": "Aktualisieren",
|
||||
"com_ui_update_mcp_error": "Beim Erstellen oder Aktualisieren des MCP ist ein Fehler aufgetreten.",
|
||||
"com_ui_update_mcp_success": "MCP erfolgreich erstellt oder aktualisiert",
|
||||
"com_ui_upload": "Hochladen",
|
||||
"com_ui_upload_code_files": "Hochladen für Code-Interpreter",
|
||||
"com_ui_upload_delay": "Das Hochladen von \"{{0}}\" dauert etwas länger. Bitte warte, während die Datei für den Abruf indexiert wird.",
|
||||
|
|
@ -881,34 +1022,37 @@
|
|||
"com_ui_upload_ocr_text": "Hochladen als Text",
|
||||
"com_ui_upload_success": "Datei erfolgreich hochgeladen",
|
||||
"com_ui_upload_type": "Upload-Typ auswählen",
|
||||
"com_ui_usage": "Nutzung",
|
||||
"com_ui_use_2fa_code": "Stattdessen 2FA-Code verwenden",
|
||||
"com_ui_use_backup_code": "Stattdessen Backup-Code verwenden",
|
||||
"com_ui_use_memory": "Erinnerung nutzen",
|
||||
"com_ui_use_micrphone": "Mikrofon verwenden",
|
||||
"com_ui_use_prompt": "Prompt verwenden",
|
||||
"com_ui_used": "Verwendet",
|
||||
"com_ui_value": "Wert",
|
||||
"com_ui_variables": "Variablen",
|
||||
"com_ui_variables_info": "Verwende doppelte geschweifte Klammern in Ihrem Text, um Variablen zu erstellen, z.B. {{Beispielvariable}}, die du später beim Verwenden des Prompts ausfüllen kannst.",
|
||||
"com_ui_verify": "Überprüfen",
|
||||
"com_ui_version_var": "Version {{0}}",
|
||||
"com_ui_versions": "Versionen",
|
||||
"com_ui_view_memory": "Erinnerung anzeigen",
|
||||
"com_ui_view_source": "Quell-Chat anzeigen",
|
||||
"com_ui_web_search": "Web-Suche",
|
||||
"com_ui_web_search_api_subtitle": "Suche im Internet nach aktuellen Informationen",
|
||||
"com_ui_web_search_cohere_key": "Cohere API-Schlüssel eingeben",
|
||||
"com_ui_web_search_firecrawl_url": "Firecrawl API URL (optional)",
|
||||
"com_ui_web_search": "Web-Suche\n",
|
||||
"com_ui_web_search_cohere_key": "Cohere API-Key eingeben",
|
||||
"com_ui_web_search_firecrawl_url": "Firecrawl API URL (optional)\n",
|
||||
"com_ui_web_search_jina_key": "Den Jina API Schlüssel eingeben",
|
||||
"com_ui_web_search_processing": "Ergebnisse verarbeiten",
|
||||
"com_ui_web_search_provider": "Anbieter der Suche",
|
||||
"com_ui_web_search_provider_serper": "Serper API",
|
||||
"com_ui_web_search_provider_serper": "Serper API\n",
|
||||
"com_ui_web_search_provider_serper_key": "Einen Serper API Schlüssel holen",
|
||||
"com_ui_web_search_reading": "Lesen der Suchergebnisse",
|
||||
"com_ui_web_search_reranker": "Reranker",
|
||||
"com_ui_web_search_reranker_cohere": "Cohere",
|
||||
"com_ui_web_search_reranker_cohere_key": "Einen Cohere API-Schlüssel holen",
|
||||
"com_ui_web_search_reranker_jina": "Jina AI",
|
||||
"com_ui_web_search_reranker_jina": "Jina AI\n",
|
||||
"com_ui_web_search_reranker_jina_key": "Einen Jina API Schlüssel holen",
|
||||
"com_ui_web_search_scraper": "Scraper",
|
||||
"com_ui_web_search_scraper_firecrawl": "Firecrawl API",
|
||||
"com_ui_web_search_scraper_firecrawl": "Firecrawl API\n",
|
||||
"com_ui_web_search_scraper_firecrawl_key": "Einen Firecrawl API Schlüssel holen",
|
||||
"com_ui_web_searching": "Internetsuche läuft",
|
||||
"com_ui_web_searching_again": "Sucht erneut im Internet",
|
||||
|
|
@ -917,6 +1061,5 @@
|
|||
"com_ui_x_selected": "{{0}} ausgewählt",
|
||||
"com_ui_yes": "Ja",
|
||||
"com_ui_zoom": "Zoom",
|
||||
"com_user_message": "Du",
|
||||
"com_warning_resubmit_unsupported": "Das erneute Senden der KI-Nachricht wird für diesen Endpunkt nicht unterstützt."
|
||||
"com_user_message": "Du"
|
||||
}
|
||||
|
|
@ -160,6 +160,7 @@
|
|||
"com_endpoint_anthropic_thinking_budget": "Determines the max number of tokens Claude is allowed use for its internal reasoning process. Larger budgets can improve response quality by enabling more thorough analysis for complex problems, although Claude may not use the entire budget allocated, especially at ranges above 32K. This setting must be lower than \"Max Output Tokens.\"",
|
||||
"com_endpoint_anthropic_topk": "Top-k changes how the model selects tokens for output. A top-k of 1 means the selected token is the most probable among all tokens in the model's vocabulary (also called greedy decoding), while a top-k of 3 means that the next token is selected from among the 3 most probable tokens (using temperature).",
|
||||
"com_endpoint_anthropic_topp": "Top-p changes how the model selects tokens for output. Tokens are selected from most K (see topK parameter) probable to least until the sum of their probabilities equals the top-p value.",
|
||||
"com_endpoint_anthropic_use_web_search": "Enable web search functionality using Anthropic's built-in search capabilities. This allows the model to search the web for up-to-date information and provide more accurate, current responses.",
|
||||
"com_endpoint_assistant": "Assistant",
|
||||
"com_endpoint_assistant_model": "Assistant Model",
|
||||
"com_endpoint_assistant_placeholder": "Please select an Assistant from the right-hand Side Panel",
|
||||
|
|
@ -205,8 +206,11 @@
|
|||
"com_endpoint_google_custom_name_placeholder": "Set a custom name for Google",
|
||||
"com_endpoint_google_maxoutputtokens": "Maximum number of tokens that can be generated in the response. Specify a lower value for shorter responses and a higher value for longer responses. Note: models may stop before reaching this maximum.",
|
||||
"com_endpoint_google_temp": "Higher values = more random, while lower values = more focused and deterministic. We recommend altering this or Top P but not both.",
|
||||
"com_endpoint_google_thinking": "Enables or disables reasoning. This setting is only supported by certain models (2.5 series). For older models, this setting may have no effect.",
|
||||
"com_endpoint_google_thinking_budget": "Guides the number of thinking tokens the model uses. The actual amount may exceed or fall below this value depending on the prompt.\n\nThis setting is only supported by certain models (2.5 series). Gemini 2.5 Pro supports 128-32,768 tokens. Gemini 2.5 Flash supports 0-24,576 tokens. Gemini 2.5 Flash Lite supports 512-24,576 tokens.\n\nLeave blank or set to \"-1\" to let the model automatically decide when and how much to think. By default, Gemini 2.5 Flash Lite does not think.",
|
||||
"com_endpoint_google_topk": "Top-k changes how the model selects tokens for output. A top-k of 1 means the selected token is the most probable among all tokens in the model's vocabulary (also called greedy decoding), while a top-k of 3 means that the next token is selected from among the 3 most probable tokens (using temperature).",
|
||||
"com_endpoint_google_topp": "Top-p changes how the model selects tokens for output. Tokens are selected from most K (see topK parameter) probable to least until the sum of their probabilities equals the top-p value.",
|
||||
"com_endpoint_google_use_search_grounding": "Use Google's search grounding feature to enhance responses with real-time web search results. This enables models to access current information and provide more accurate, up-to-date answers.",
|
||||
"com_endpoint_instructions_assistants": "Override Instructions",
|
||||
"com_endpoint_instructions_assistants_placeholder": "Overrides the instructions of the assistant. This is useful for modifying the behavior on a per-run basis.",
|
||||
"com_endpoint_max_output_tokens": "Max Output Tokens",
|
||||
|
|
@ -224,11 +228,14 @@
|
|||
"com_endpoint_openai_pres": "Number between -2.0 and 2.0. Positive values penalize new tokens based on whether they appear in the text so far, increasing the model's likelihood to talk about new topics.",
|
||||
"com_endpoint_openai_prompt_prefix_placeholder": "Set custom instructions to include in System Message. Default: none",
|
||||
"com_endpoint_openai_reasoning_effort": "o1 and o3 models only: constrains effort on reasoning for reasoning models. Reducing reasoning effort can result in faster responses and fewer tokens used on reasoning in a response.",
|
||||
"com_endpoint_openai_reasoning_summary": "Responses API only: A summary of the reasoning performed by the model. This can be useful for debugging and understanding the model's reasoning process. Set to none,auto, concise, or detailed.",
|
||||
"com_endpoint_openai_resend": "Resend all previously attached images. Note: this can significantly increase token cost and you may experience errors with many image attachments.",
|
||||
"com_endpoint_openai_resend_files": "Resend all previously attached files. Note: this will increase token cost and you may experience errors with many attachments.",
|
||||
"com_endpoint_openai_stop": "Up to 4 sequences where the API will stop generating further tokens.",
|
||||
"com_endpoint_openai_temp": "Higher values = more random, while lower values = more focused and deterministic. We recommend altering this or Top P but not both.",
|
||||
"com_endpoint_openai_topp": "An alternative to sampling with temperature, called nucleus sampling, where the model considers the results of the tokens with top_p probability mass. So 0.1 means only the tokens comprising the top 10% probability mass are considered. We recommend altering this or temperature but not both.",
|
||||
"com_endpoint_openai_use_responses_api": "Use the Responses API instead of Chat Completions, which includes extended features from OpenAI. Required for o1-pro, o3-pro, and to enable reasoning summaries.",
|
||||
"com_endpoint_openai_use_web_search": "Enable web search functionality using OpenAI's built-in search capabilities. This allows the model to search the web for up-to-date information and provide more accurate, current responses.",
|
||||
"com_endpoint_output": "Output",
|
||||
"com_endpoint_plug_image_detail": "Image Detail",
|
||||
"com_endpoint_plug_resend_files": "Resend Files",
|
||||
|
|
@ -259,6 +266,7 @@
|
|||
"com_endpoint_prompt_prefix_assistants_placeholder": "Set additional instructions or context on top of the Assistant's main instructions. Ignored if empty.",
|
||||
"com_endpoint_prompt_prefix_placeholder": "Set custom instructions or context. Ignored if empty.",
|
||||
"com_endpoint_reasoning_effort": "Reasoning Effort",
|
||||
"com_endpoint_reasoning_summary": "Reasoning Summary",
|
||||
"com_endpoint_save_as_preset": "Save As Preset",
|
||||
"com_endpoint_search": "Search endpoint by name",
|
||||
"com_endpoint_search_endpoint_models": "Search {{0}} models...",
|
||||
|
|
@ -274,6 +282,8 @@
|
|||
"com_endpoint_top_k": "Top K",
|
||||
"com_endpoint_top_p": "Top P",
|
||||
"com_endpoint_use_active_assistant": "Use Active Assistant",
|
||||
"com_endpoint_use_responses_api": "Use Responses API",
|
||||
"com_endpoint_use_search_grounding": "Grounding with Google Search",
|
||||
"com_error_expired_user_key": "Provided key for {{0}} expired at {{1}}. Please provide a new key and try again.",
|
||||
"com_error_files_dupe": "Duplicate file detected.",
|
||||
"com_error_files_empty": "Empty files are not allowed.",
|
||||
|
|
@ -282,6 +292,7 @@
|
|||
"com_error_files_upload": "An error occurred while uploading the file.",
|
||||
"com_error_files_upload_canceled": "The file upload request was canceled. Note: the file upload may still be processing and will need to be manually deleted.",
|
||||
"com_error_files_validation": "An error occurred while validating the file.",
|
||||
"com_error_google_tool_conflict": "Usage of built-in Google tools are not supported with external tools. Please disable either the built-in tools or the external tools.",
|
||||
"com_error_heic_conversion": "Failed to convert HEIC image to JPEG. Please try converting the image manually or use a different format.",
|
||||
"com_error_input_length": "The latest message token count is too long, exceeding the token limit, or your token limit parameters are misconfigured, adversely affecting the context window. More info: {{0}}. Please shorten your message, adjust the max context size from the conversation parameters, or fork the conversation to continue.",
|
||||
"com_error_invalid_agent_provider": "The \"{{0}}\" provider is not available for use with Agents. Please go to your agent's settings and select a currently available provider.",
|
||||
|
|
@ -357,7 +368,6 @@
|
|||
"com_nav_delete_cache_storage": "Delete TTS cache storage",
|
||||
"com_nav_delete_data_info": "All your data will be deleted.",
|
||||
"com_nav_delete_warning": "WARNING: This will permanently delete your account.",
|
||||
"com_nav_edit_chat_badges": "Edit Chat Badges",
|
||||
"com_nav_enable_cache_tts": "Enable cache TTS",
|
||||
"com_nav_enable_cloud_browser_voice": "Use cloud-based voices",
|
||||
"com_nav_enabled": "Enabled",
|
||||
|
|
@ -395,6 +405,7 @@
|
|||
"com_nav_info_show_thinking": "When enabled, the chat will display the thinking dropdowns open by default, allowing you to view the AI's reasoning in real-time. When disabled, the thinking dropdowns will remain closed by default for a cleaner and more streamlined interface",
|
||||
"com_nav_info_user_name_display": "When enabled, the username of the sender will be shown above each message you send. When disabled, you will only see \"You\" above your messages.",
|
||||
"com_nav_lang_arabic": "العربية",
|
||||
"com_nav_lang_armenian": "Հայերեն",
|
||||
"com_nav_lang_auto": "Auto detect",
|
||||
"com_nav_lang_brazilian_portuguese": "Português Brasileiro",
|
||||
"com_nav_lang_catalan": "Català",
|
||||
|
|
@ -414,6 +425,7 @@
|
|||
"com_nav_lang_italian": "Italiano",
|
||||
"com_nav_lang_japanese": "日本語",
|
||||
"com_nav_lang_korean": "한국어",
|
||||
"com_nav_lang_latvian": "Latviski",
|
||||
"com_nav_lang_persian": "فارسی",
|
||||
"com_nav_lang_polish": "Polski",
|
||||
"com_nav_lang_portuguese": "Português",
|
||||
|
|
@ -423,6 +435,7 @@
|
|||
"com_nav_lang_thai": "ไทย",
|
||||
"com_nav_lang_traditional_chinese": "繁體中文",
|
||||
"com_nav_lang_turkish": "Türkçe",
|
||||
"com_nav_lang_uyghur": "Uyƣur tili",
|
||||
"com_nav_lang_vietnamese": "Tiếng Việt",
|
||||
"com_nav_language": "Language",
|
||||
"com_nav_latex_parsing": "Parsing LaTeX in messages (may affect performance)",
|
||||
|
|
@ -563,6 +576,7 @@
|
|||
"com_ui_archive_error": "Failed to archive conversation",
|
||||
"com_ui_artifact_click": "Click to open",
|
||||
"com_ui_artifacts": "Artifacts",
|
||||
"com_ui_artifacts_options": "Artifacts Options",
|
||||
"com_ui_artifacts_toggle": "Toggle Artifacts UI",
|
||||
"com_ui_artifacts_toggle_agent": "Enable Artifacts",
|
||||
"com_ui_ascending": "Asc",
|
||||
|
|
@ -582,6 +596,7 @@
|
|||
"com_ui_auth_url": "Authorization URL",
|
||||
"com_ui_authentication": "Authentication",
|
||||
"com_ui_authentication_type": "Authentication Type",
|
||||
"com_ui_auto": "Auto",
|
||||
"com_ui_available_tools": "Available Tools",
|
||||
"com_ui_avatar": "Avatar",
|
||||
"com_ui_azure": "Azure",
|
||||
|
|
@ -631,6 +646,7 @@
|
|||
"com_ui_command_placeholder": "Optional: Enter a command for the prompt or name will be used",
|
||||
"com_ui_command_usage_placeholder": "Select a Prompt by command or name",
|
||||
"com_ui_complete_setup": "Complete Setup",
|
||||
"com_ui_concise": "Concise",
|
||||
"com_ui_configure_mcp_variables_for": "Configure Variables for {{0}}",
|
||||
"com_ui_confirm_action": "Confirm Action",
|
||||
"com_ui_confirm_admin_use_change": "Changing this setting will block access for admins, including yourself. Are you sure you want to proceed?",
|
||||
|
|
@ -696,6 +712,7 @@
|
|||
"com_ui_description": "Description",
|
||||
"com_ui_description_placeholder": "Optional: Enter a description to display for the prompt",
|
||||
"com_ui_deselect_all": "Deselect All",
|
||||
"com_ui_detailed": "Detailed",
|
||||
"com_ui_disabling": "Disabling...",
|
||||
"com_ui_download": "Download",
|
||||
"com_ui_download_artifact": "Download Artifact",
|
||||
|
|
@ -757,6 +774,7 @@
|
|||
"com_ui_fork_change_default": "Default fork option",
|
||||
"com_ui_fork_default": "Use default fork option",
|
||||
"com_ui_fork_error": "There was an error forking the conversation",
|
||||
"com_ui_fork_error_rate_limit": "Too many fork requests. Please try again later",
|
||||
"com_ui_fork_from_message": "Select a fork option",
|
||||
"com_ui_fork_info_1": "Use this setting to fork messages with the desired behavior.",
|
||||
"com_ui_fork_info_2": "\"Forking\" refers to creating a new conversation that start/end from specific messages in the current conversation, creating a copy according to the options selected.",
|
||||
|
|
@ -789,7 +807,9 @@
|
|||
"com_ui_good_morning": "Good morning",
|
||||
"com_ui_happy_birthday": "It's my 1st birthday!",
|
||||
"com_ui_hide_image_details": "Hide Image Details",
|
||||
"com_ui_hide_password": "Hide password",
|
||||
"com_ui_hide_qr": "Hide QR Code",
|
||||
"com_ui_high": "High",
|
||||
"com_ui_host": "Host",
|
||||
"com_ui_icon": "Icon",
|
||||
"com_ui_idea": "Ideas",
|
||||
|
|
@ -803,7 +823,6 @@
|
|||
"com_ui_import_conversation_info": "Import conversations from a JSON file",
|
||||
"com_ui_import_conversation_success": "Conversations imported successfully",
|
||||
"com_ui_include_shadcnui": "Include shadcn/ui components instructions",
|
||||
"com_ui_include_shadcnui_agent": "Include shadcn/ui instructions",
|
||||
"com_ui_input": "Input",
|
||||
"com_ui_instructions": "Instructions",
|
||||
"com_ui_key": "Key",
|
||||
|
|
@ -817,6 +836,7 @@
|
|||
"com_ui_loading": "Loading...",
|
||||
"com_ui_locked": "Locked",
|
||||
"com_ui_logo": "{{0}} Logo",
|
||||
"com_ui_low": "Low",
|
||||
"com_ui_manage": "Manage",
|
||||
"com_ui_max_tags": "Maximum number allowed is {{0}}, using latest values.",
|
||||
"com_ui_mcp_dialog_desc": "Please enter the necessary information below.",
|
||||
|
|
@ -824,6 +844,7 @@
|
|||
"com_ui_mcp_server_not_found": "Server not found.",
|
||||
"com_ui_mcp_servers": "MCP Servers",
|
||||
"com_ui_mcp_url": "MCP Server URL",
|
||||
"com_ui_medium": "Medium",
|
||||
"com_ui_memories": "Memories",
|
||||
"com_ui_memories_allow_create": "Allow creating Memories",
|
||||
"com_ui_memories_allow_opt_out": "Allow users to opt out of Memories",
|
||||
|
|
@ -836,6 +857,7 @@
|
|||
"com_ui_memory_deleted": "Memory deleted",
|
||||
"com_ui_memory_deleted_items": "Deleted Memories",
|
||||
"com_ui_memory_key_exists": "A memory with this key already exists. Please use a different key.",
|
||||
"com_ui_memory_key_validation": "Memory key must only contain lowercase letters and underscores.",
|
||||
"com_ui_memory_updated": "Updated saved memory",
|
||||
"com_ui_memory_updated_items": "Updated Memories",
|
||||
"com_ui_mention": "Mention an endpoint, assistant, or preset to quickly switch to it",
|
||||
|
|
@ -914,6 +936,7 @@
|
|||
"com_ui_rename_prompt": "Rename Prompt",
|
||||
"com_ui_requires_auth": "Requires Authentication",
|
||||
"com_ui_reset_var": "Reset {{0}}",
|
||||
"com_ui_reset_zoom": "Reset Zoom",
|
||||
"com_ui_result": "Result",
|
||||
"com_ui_revoke": "Revoke",
|
||||
"com_ui_revoke_info": "Revoke all user provided credentials",
|
||||
|
|
@ -963,6 +986,7 @@
|
|||
"com_ui_show": "Show",
|
||||
"com_ui_show_all": "Show All",
|
||||
"com_ui_show_image_details": "Show Image Details",
|
||||
"com_ui_show_password": "Show password",
|
||||
"com_ui_show_qr": "Show QR Code",
|
||||
"com_ui_sign_in_to_domain": "Sign-in to {{0}}",
|
||||
"com_ui_simple": "Simple",
|
||||
|
|
@ -1031,12 +1055,12 @@
|
|||
"com_ui_view_memory": "View Memory",
|
||||
"com_ui_view_source": "View source chat",
|
||||
"com_ui_web_search": "Web Search",
|
||||
"com_ui_web_search_api_subtitle": "Search the web for up-to-date information",
|
||||
"com_ui_web_search_cohere_key": "Enter Cohere API Key",
|
||||
"com_ui_web_search_firecrawl_url": "Firecrawl API URL (optional)",
|
||||
"com_ui_web_search_jina_key": "Enter Jina API Key",
|
||||
"com_ui_web_search_processing": "Processing results",
|
||||
"com_ui_web_search_provider": "Search Provider",
|
||||
"com_ui_web_search_provider_searxng": "SearXNG",
|
||||
"com_ui_web_search_provider_serper": "Serper API",
|
||||
"com_ui_web_search_provider_serper_key": "Get your Serper API key",
|
||||
"com_ui_web_search_reading": "Reading results",
|
||||
|
|
@ -1048,6 +1072,8 @@
|
|||
"com_ui_web_search_scraper": "Scraper",
|
||||
"com_ui_web_search_scraper_firecrawl": "Firecrawl API",
|
||||
"com_ui_web_search_scraper_firecrawl_key": "Get your Firecrawl API key",
|
||||
"com_ui_web_search_searxng_api_key": "Enter SearXNG API Key (optional)",
|
||||
"com_ui_web_search_searxng_instance_url": "SearXNG Instance URL",
|
||||
"com_ui_web_searching": "Searching the web",
|
||||
"com_ui_web_searching_again": "Searching the web again",
|
||||
"com_ui_weekend_morning": "Happy weekend",
|
||||
|
|
@ -1060,3 +1086,4 @@
|
|||
"com_ui_add_to_favorites": "Add to favorites",
|
||||
"com_ui_remove_from_favorites": "Remove from favorites"
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -310,7 +310,6 @@
|
|||
"com_nav_delete_cache_storage": "Eliminar almacenamiento caché de TTS",
|
||||
"com_nav_delete_data_info": "Se eliminarán todos sus datos",
|
||||
"com_nav_delete_warning": "ADVERTENCIA: Esta acción eliminará su cuenta de forma permanente.",
|
||||
"com_nav_edit_chat_badges": "Editar Insignias de Chat",
|
||||
"com_nav_enable_cache_tts": "Habilitar caché de texto a voz",
|
||||
"com_nav_enable_cloud_browser_voice": "Usar voces basadas en la nube",
|
||||
"com_nav_enabled": "Habilitado",
|
||||
|
|
@ -752,6 +751,5 @@
|
|||
"com_ui_x_selected": "{{0}} seleccionado",
|
||||
"com_ui_yes": "Sí",
|
||||
"com_ui_zoom": "Zoom",
|
||||
"com_user_message": "Usted",
|
||||
"com_warning_resubmit_unsupported": "No se admite el reenvío del mensaje de IA para este punto de conexión."
|
||||
"com_user_message": "Usted"
|
||||
}
|
||||
|
|
@ -21,6 +21,7 @@
|
|||
"com_agents_name_placeholder": "Valikuline: Agendi nimi",
|
||||
"com_agents_no_access": "Sul pole õigust seda agenti muuta.",
|
||||
"com_agents_not_available": "Agent pole saadaval",
|
||||
"com_agents_search_info": "Kui see on lubatud, saab sinu agent otsida veebist ajakohast teavet. Vajalik on kehtiv API võti.",
|
||||
"com_agents_search_name": "Otsi agente nime järgi",
|
||||
"com_agents_update_error": "Agendi uuendamisel tekkis viga.",
|
||||
"com_assistants_action_attempt": "Assistent soovib suhelda: {{0}}",
|
||||
|
|
@ -61,6 +62,7 @@
|
|||
"com_assistants_non_retrieval_model": "Selles mudelis pole failiotsing lubatud. Valige mõni muu mudel.",
|
||||
"com_assistants_retrieval": "Otsing",
|
||||
"com_assistants_running_action": "Käivitatakse tegevust",
|
||||
"com_assistants_running_var": "Töötab {{0}}",
|
||||
"com_assistants_search_name": "Otsi assistente nime järgi",
|
||||
"com_assistants_update_actions_error": "Tegevuse loomisel või uuendamisel tekkis viga.",
|
||||
"com_assistants_update_actions_success": "Tegevuse loomine või uuendamine õnnestus",
|
||||
|
|
@ -122,6 +124,7 @@
|
|||
"com_auth_reset_password_if_email_exists": "Kui selle e-postiga konto on olemas, on saadetud parooli lähtestamise juhistega e-kiri. Palun kontrolli oma rämpsposti kausta.",
|
||||
"com_auth_reset_password_link_sent": "E-kiri saadetud",
|
||||
"com_auth_reset_password_success": "Parooli lähtestamine õnnestus",
|
||||
"com_auth_saml_login": "Jätka SAML-iga",
|
||||
"com_auth_sign_in": "Logi sisse",
|
||||
"com_auth_sign_up": "Registreeru",
|
||||
"com_auth_submit_registration": "Saada registreerimine",
|
||||
|
|
@ -133,6 +136,8 @@
|
|||
"com_auth_username_min_length": "Kasutajanimi peab olema vähemalt 2 tähemärki",
|
||||
"com_auth_verify_your_identity": "Kontrolli",
|
||||
"com_auth_welcome_back": "Teretulemast tagasi",
|
||||
"com_citation_more_details": "Rohkem üksikasju {{label}} kohta",
|
||||
"com_citation_source": "Allikas",
|
||||
"com_click_to_download": "(vajuta siia, et alla laadida)",
|
||||
"com_download_expired": "(allalaadimine aegunud)",
|
||||
"com_download_expires": "(vajuta siia, et alla laadida - aegub {{0}})",
|
||||
|
|
@ -246,7 +251,7 @@
|
|||
"com_endpoint_prompt_prefix_assistants": "Täiendavad juhised",
|
||||
"com_endpoint_prompt_prefix_assistants_placeholder": "Määra täiendavad juhised või kontekst lisaks assistendi peamistele juhistele. Kui see on tühi, ignoreeritakse seda.",
|
||||
"com_endpoint_prompt_prefix_placeholder": "Määra kohandatud juhised või kontekst. Kui see on tühi, ignoreeritakse seda.",
|
||||
"com_endpoint_reasoning_effort": "Põhjendustegevus",
|
||||
"com_endpoint_reasoning_effort": "Arutluse tase",
|
||||
"com_endpoint_save_as_preset": "Salvesta eelseadistusena",
|
||||
"com_endpoint_search": "Otsi otspunkti nime järgi",
|
||||
"com_endpoint_search_endpoint_models": "Otsi {{0}} mudeleid...",
|
||||
|
|
@ -299,6 +304,27 @@
|
|||
"com_nav_auto_transcribe_audio": "Transkribeeri heli automaatselt",
|
||||
"com_nav_automatic_playback": "Esita viimane sõnum automaatselt",
|
||||
"com_nav_balance": "Saldo",
|
||||
"com_nav_balance_auto_refill_disabled": "Automaatne saldo täitmine on välja lülitatud.",
|
||||
"com_nav_balance_auto_refill_error": "Viga automaatse saldo täitmise seadete laadimisel.",
|
||||
"com_nav_balance_auto_refill_settings": "Automaatse saldo täitmise seaded",
|
||||
"com_nav_balance_day": "päev",
|
||||
"com_nav_balance_days": "päeva",
|
||||
"com_nav_balance_every": "Iga",
|
||||
"com_nav_balance_hour": "tund",
|
||||
"com_nav_balance_hours": "tundi",
|
||||
"com_nav_balance_interval": "Intervall:",
|
||||
"com_nav_balance_last_refill": "Viimane täiendus:",
|
||||
"com_nav_balance_minute": "minut",
|
||||
"com_nav_balance_minutes": "minutit",
|
||||
"com_nav_balance_month": "kuu",
|
||||
"com_nav_balance_months": "kuud",
|
||||
"com_nav_balance_next_refill": "Järgmine täiendus:",
|
||||
"com_nav_balance_next_refill_info": "Järgmine täiendamine toimub automaatselt ainult siis, kui mõlemad tingimused on täidetud: määratud ajavahemik on möödunud viimasest täiendamisest ja päringu saatmine põhjustaks sinu saldo langemise alla nulli.",
|
||||
"com_nav_balance_refill_amount": "Täitmise kogus:",
|
||||
"com_nav_balance_second": "sekund",
|
||||
"com_nav_balance_seconds": "sekundit",
|
||||
"com_nav_balance_week": "nädal",
|
||||
"com_nav_balance_weeks": "nädalat",
|
||||
"com_nav_browser": "Brauser",
|
||||
"com_nav_center_chat_input": "Kuva ",
|
||||
"com_nav_change_picture": "Muuda pilti",
|
||||
|
|
@ -322,7 +348,6 @@
|
|||
"com_nav_delete_cache_storage": "Kustuta TTS vahemälu",
|
||||
"com_nav_delete_data_info": "Kõik sinu andmed kustutatakse.",
|
||||
"com_nav_delete_warning": "HOIATUS: See kustutab sinu konto jäädavalt.",
|
||||
"com_nav_edit_chat_badges": "Muuda vestluse märgiseid",
|
||||
"com_nav_enable_cache_tts": "Luba TTS vahemälu",
|
||||
"com_nav_enable_cloud_browser_voice": "Kasuta pilvepõhiseid hääli",
|
||||
"com_nav_enabled": "Lubatud",
|
||||
|
|
@ -346,6 +371,7 @@
|
|||
"com_nav_font_size_xs": "Eriti väike",
|
||||
"com_nav_help_faq": "Abi ja KKK",
|
||||
"com_nav_hide_panel": "Peida kõige parempoolsem külgpaneel",
|
||||
"com_nav_info_balance": "Saldo näitab, kui palju märgikrediiti on sul kasutamiseks alles. Märgikrediidid tõlgitakse rahalisse väärtusesse (nt 1000 krediiti = 0,001 USD)",
|
||||
"com_nav_info_code_artifacts": "Võimaldab katsetuslike koodiartefaktide kuvamist vestluse kõrval",
|
||||
"com_nav_info_code_artifacts_agent": "Võimaldab selle agendi jaoks koodiartefaktide kasutamist. Vaikimisi lisatakse artefaktide kasutamisele spetsiifilised täiendavad juhised, välja arvatud juhul, kui on lubatud \"Kohandatud viibarežiim\".",
|
||||
"com_nav_info_custom_prompt_mode": "Kui see on lubatud, siis vaikimisi artefaktide süsteemiviipa ei lisata. Kõik artefakte genereerivad juhised tuleb selles režiimis käsitsi esitada.",
|
||||
|
|
@ -361,7 +387,10 @@
|
|||
"com_nav_lang_arabic": "العربية",
|
||||
"com_nav_lang_auto": "Tuvasta automaatselt",
|
||||
"com_nav_lang_brazilian_portuguese": "Português Brasileiro",
|
||||
"com_nav_lang_catalan": "Català",
|
||||
"com_nav_lang_chinese": "中文",
|
||||
"com_nav_lang_czech": "Čeština",
|
||||
"com_nav_lang_danish": "Taani",
|
||||
"com_nav_lang_dutch": "Nederlands",
|
||||
"com_nav_lang_english": "English",
|
||||
"com_nav_lang_estonian": "Eesti keel",
|
||||
|
|
@ -409,6 +438,7 @@
|
|||
"com_nav_search_placeholder": "Otsi sõnumeid",
|
||||
"com_nav_send_message": "Saada sõnum",
|
||||
"com_nav_setting_account": "Konto",
|
||||
"com_nav_setting_balance": "Saldo",
|
||||
"com_nav_setting_beta": "Beeta funktsioonid",
|
||||
"com_nav_setting_chat": "Vestlus",
|
||||
"com_nav_setting_data": "Andmekontroll",
|
||||
|
|
@ -446,6 +476,12 @@
|
|||
"com_sidepanel_hide_panel": "Peida paneel",
|
||||
"com_sidepanel_manage_files": "Halda faile",
|
||||
"com_sidepanel_parameters": "Parameetrid",
|
||||
"com_sources_image_alt": "Otsingutulemuse pilt",
|
||||
"com_sources_more_sources": "+{{count}} allikat",
|
||||
"com_sources_tab_all": "Kõik",
|
||||
"com_sources_tab_images": "Pildid",
|
||||
"com_sources_tab_news": "Uudised",
|
||||
"com_sources_title": "Allikad",
|
||||
"com_ui_2fa_account_security": "Kaheastmeline autentimine lisab teie kontole täiendava turvalisuse kihi",
|
||||
"com_ui_2fa_disable": "Lülita 2FA välja",
|
||||
"com_ui_2fa_disable_error": "Tekkis viga kaheastmelise autentimise väljalülitamisel",
|
||||
|
|
@ -457,9 +493,11 @@
|
|||
"com_ui_2fa_setup": "Seadista 2FA",
|
||||
"com_ui_2fa_verified": "Kaheastmeline autentimine õnnestus",
|
||||
"com_ui_accept": "Nõustun",
|
||||
"com_ui_action_button": "Tegevuse nupp",
|
||||
"com_ui_add": "Lisa",
|
||||
"com_ui_add_model_preset": "Lisa mudel või eelseadistus täiendava vastuse jaoks",
|
||||
"com_ui_add_multi_conversation": "Lisa mitmevestlus",
|
||||
"com_ui_adding_details": "Detailide lisamine",
|
||||
"com_ui_admin": "Administraator",
|
||||
"com_ui_admin_access_warning": "Administraatori juurdepääsu keelamine sellele funktsioonile võib põhjustada ootamatuid kasutajaliidese probleeme, mis nõuavad värskendamist. Kui see on salvestatud, on ainus viis taastada liideseseade kaudu librechat.yaml konfiguratsioonis, mis mõjutab kõiki rolle.",
|
||||
"com_ui_admin_settings": "Administraatori seaded",
|
||||
|
|
@ -478,6 +516,20 @@
|
|||
"com_ui_agent_recursion_limit_info": "Piirab, mitu sammu agent saab teha ühe käivituse jooksul enne lõpliku vastuse andmist. Vaikimisi lubatakse 25 sammu. Samm on kas AI API päring või tööriista kasutamise etapp. Näiteks, lihtne tööriista kasutamine võtab 3 sammu: esialgne päring, tööriista kasutamine ja järelpäring.",
|
||||
"com_ui_agent_shared_to_all": "Seda agenti on jagatud kõigi kasutajatega",
|
||||
"com_ui_agent_var": "{{0}} agent",
|
||||
"com_ui_agent_version": "Versioon",
|
||||
"com_ui_agent_version_active": "Aktiivne versioon",
|
||||
"com_ui_agent_version_duplicate": "Tuvastati duplikaatversioon. See looks versiooni, mis on identne versiooniga {{versionIndex}}.",
|
||||
"com_ui_agent_version_empty": "Versioone pole saadaval",
|
||||
"com_ui_agent_version_error": "Viga versioonide laadimisel",
|
||||
"com_ui_agent_version_history": "Versioonide ajalugu",
|
||||
"com_ui_agent_version_no_agent": "Agenti pole valitud. Palun vali agent, et näha versiooni ajalugu.",
|
||||
"com_ui_agent_version_no_date": "Kuupäev pole saadaval",
|
||||
"com_ui_agent_version_restore": "Taasta",
|
||||
"com_ui_agent_version_restore_confirm": "Oled sa kindel, et sa soovid selle versiooni taastada?",
|
||||
"com_ui_agent_version_restore_error": "Versiooni taastamine ebaõnnestus",
|
||||
"com_ui_agent_version_restore_success": "Versiooni taastamine õnnestus",
|
||||
"com_ui_agent_version_title": "Versioon {{versionNumber}}",
|
||||
"com_ui_agent_version_unknown_date": "Tundmatu kuupäev",
|
||||
"com_ui_agents": "Agendid",
|
||||
"com_ui_agents_allow_create": "Luba agentide loomine",
|
||||
"com_ui_agents_allow_share_global": "Luba agentide jagamine kõigile kasutajatele",
|
||||
|
|
@ -542,6 +594,7 @@
|
|||
"com_ui_bulk_delete_error": "Jagatud linkide kustutamine ebaõnnestus",
|
||||
"com_ui_callback_url": "Tagasikutsumise URL",
|
||||
"com_ui_cancel": "Tühista",
|
||||
"com_ui_cancelled": "Tühistatud",
|
||||
"com_ui_category": "Kategooria",
|
||||
"com_ui_chat": "Vestlus",
|
||||
"com_ui_chat_history": "Vestluse ajalugu",
|
||||
|
|
@ -571,6 +624,7 @@
|
|||
"com_ui_create": "Loo",
|
||||
"com_ui_create_link": "Loo link",
|
||||
"com_ui_create_prompt": "Loo sisend",
|
||||
"com_ui_creating_image": "Pildi loomine. Võib võtta hetke",
|
||||
"com_ui_currently_production": "Praegu tootmises",
|
||||
"com_ui_custom": "Kohandatud",
|
||||
"com_ui_custom_header_name": "Kohandatud päise nimi",
|
||||
|
|
@ -624,6 +678,7 @@
|
|||
"com_ui_duplication_processing": "Vestlust dubleeritakse...",
|
||||
"com_ui_duplication_success": "Vestluse dubleerimine õnnestus",
|
||||
"com_ui_edit": "Muuda",
|
||||
"com_ui_edit_editing_image": "Pildi muutmine",
|
||||
"com_ui_empty_category": "-",
|
||||
"com_ui_endpoint": "Otspunkt",
|
||||
"com_ui_endpoint_menu": "LLM otspunkti menüü",
|
||||
|
|
@ -636,9 +691,27 @@
|
|||
"com_ui_examples": "Näited",
|
||||
"com_ui_expand_chat": "Laiendage Vestlus",
|
||||
"com_ui_export_convo_modal": "Ekspordi vestluse modaal",
|
||||
"com_ui_feedback_more": "Rohkem...",
|
||||
"com_ui_feedback_more_information": "Anna täiendavat tagasisidet",
|
||||
"com_ui_feedback_negative": "Vajab täiustamist",
|
||||
"com_ui_feedback_placeholder": "Palun esitage siia täiendav tagasiside",
|
||||
"com_ui_feedback_positive": "Mulle meeldib see",
|
||||
"com_ui_feedback_tag_accurate_reliable": "Täpne ja usaldusväärne",
|
||||
"com_ui_feedback_tag_attention_to_detail": "Tähelepanu detailidele",
|
||||
"com_ui_feedback_tag_bad_style": "Kehv stiil või toon",
|
||||
"com_ui_feedback_tag_clear_well_written": "Selge ja hästi kirjutatud",
|
||||
"com_ui_feedback_tag_creative_solution": "Loominguline lahendus",
|
||||
"com_ui_feedback_tag_inaccurate": "Ebatäpne või vale vastus",
|
||||
"com_ui_feedback_tag_missing_image": "Oodati pilti",
|
||||
"com_ui_feedback_tag_not_helpful": "Puudus kasulik teave",
|
||||
"com_ui_feedback_tag_not_matched": "Ei vastanud minu päringule",
|
||||
"com_ui_feedback_tag_unjustified_refusal": "Keeldutud ilma põhjuseta",
|
||||
"com_ui_field_required": "See väli on kohustuslik",
|
||||
"com_ui_file_size": "Faili suurus",
|
||||
"com_ui_files": "Failid",
|
||||
"com_ui_filter_prompts": "Filtreeri sisendid",
|
||||
"com_ui_filter_prompts_name": "Filtreeri sisendeid nime järgi",
|
||||
"com_ui_final_touch": "Viimane puudutus",
|
||||
"com_ui_finance": "Raha",
|
||||
"com_ui_fork": "Hargne",
|
||||
"com_ui_fork_all_target": "Kaasa kõik siia/siit",
|
||||
|
|
@ -668,6 +741,7 @@
|
|||
"com_ui_generate_backup": "Loo varukoodid",
|
||||
"com_ui_generate_qrcode": "Loo QR-kood",
|
||||
"com_ui_generating": "Loomine...",
|
||||
"com_ui_getting_started": "Genereerimise seaded",
|
||||
"com_ui_global_group": "Ülene grupp",
|
||||
"com_ui_go_back": "Mine tagasi",
|
||||
"com_ui_go_to_conversation": "Mine vestlusesse",
|
||||
|
|
@ -675,9 +749,13 @@
|
|||
"com_ui_good_evening": "Tere õhtust",
|
||||
"com_ui_good_morning": "Tere hommikust",
|
||||
"com_ui_happy_birthday": "Mul on 1. sünnipäev!",
|
||||
"com_ui_hide_image_details": "Peida pildi detailid",
|
||||
"com_ui_hide_qr": "Peida QR-kood",
|
||||
"com_ui_host": "Host",
|
||||
"com_ui_idea": "Ideed",
|
||||
"com_ui_image_created": "Pilt loodud",
|
||||
"com_ui_image_details": "Pildi üksikasjad",
|
||||
"com_ui_image_edited": "Pilt muudetud",
|
||||
"com_ui_image_gen": "Pildi genereerimine",
|
||||
"com_ui_import": "Impordi",
|
||||
"com_ui_import_conversation_error": "Vestluste importimisel tekkis viga",
|
||||
|
|
@ -685,7 +763,6 @@
|
|||
"com_ui_import_conversation_info": "Impordi vestlused JSON-failist",
|
||||
"com_ui_import_conversation_success": "Vestluste importimine õnnestus",
|
||||
"com_ui_include_shadcnui": "Kaasa shadcn/ui komponentide juhised",
|
||||
"com_ui_include_shadcnui_agent": "Kaasa shadcn/ui juhised",
|
||||
"com_ui_input": "Sisend",
|
||||
"com_ui_instructions": "Juhised",
|
||||
"com_ui_late_night": "Head hilisõhtut",
|
||||
|
|
@ -747,6 +824,7 @@
|
|||
"com_ui_prompts_allow_share_global": "Luba sisendite jagamine kõigile kasutajatele",
|
||||
"com_ui_prompts_allow_use": "Luba sisendite kasutamine",
|
||||
"com_ui_provider": "Teenusepakkuja",
|
||||
"com_ui_quality": "Kvaliteet",
|
||||
"com_ui_read_aloud": "Loe valjusti",
|
||||
"com_ui_redirecting_to_provider": "Ümbersuunamine pakkujale {{0}}, palun oodake...",
|
||||
"com_ui_refresh_link": "Värskenda linki",
|
||||
|
|
@ -805,6 +883,7 @@
|
|||
"com_ui_shop": "Ostlemine",
|
||||
"com_ui_show": "Kuva",
|
||||
"com_ui_show_all": "Näita kõiki",
|
||||
"com_ui_show_image_details": "Näita pildi üksikasju",
|
||||
"com_ui_show_qr": "Näita QR-koodi",
|
||||
"com_ui_sign_in_to_domain": "Logi sisse {{0}}",
|
||||
"com_ui_simple": "Lihtne",
|
||||
|
|
@ -860,11 +939,29 @@
|
|||
"com_ui_version_var": "Versioon {{0}}",
|
||||
"com_ui_versions": "Versioonid",
|
||||
"com_ui_view_source": "Vaata algset vestlust",
|
||||
"com_ui_web_search": "Veebiotsing",
|
||||
"com_ui_web_search_cohere_key": "Sisesta Cohere API võti",
|
||||
"com_ui_web_search_firecrawl_url": "Firecrawl API URL (valikuline)",
|
||||
"com_ui_web_search_jina_key": "Sisesta Jina API võti",
|
||||
"com_ui_web_search_processing": "Tulemuste töötlemine",
|
||||
"com_ui_web_search_provider": "Otsingupakkuja",
|
||||
"com_ui_web_search_provider_serper": "Serper API",
|
||||
"com_ui_web_search_provider_serper_key": "Hangi oma Serperi API võti",
|
||||
"com_ui_web_search_reading": "Tulemuste lugemine",
|
||||
"com_ui_web_search_reranker": "Järjestaja",
|
||||
"com_ui_web_search_reranker_cohere": "Cohere",
|
||||
"com_ui_web_search_reranker_cohere_key": "Hangi oma Cohere API võti",
|
||||
"com_ui_web_search_reranker_jina": "Jina AI",
|
||||
"com_ui_web_search_reranker_jina_key": "Hangi oma Jina API võti",
|
||||
"com_ui_web_search_scraper": "Scraper",
|
||||
"com_ui_web_search_scraper_firecrawl": "Firecrawl API",
|
||||
"com_ui_web_search_scraper_firecrawl_key": "Hangi oma Firecrawli API võti",
|
||||
"com_ui_web_searching": "Veebist otsimine",
|
||||
"com_ui_web_searching_again": "Otsin uuesti veebist",
|
||||
"com_ui_weekend_morning": "Head nädalavahetust",
|
||||
"com_ui_write": "Kirjutamine",
|
||||
"com_ui_x_selected": "{{0}} valitud",
|
||||
"com_ui_yes": "Jah",
|
||||
"com_ui_zoom": "Suumi",
|
||||
"com_user_message": "Sina",
|
||||
"com_warning_resubmit_unsupported": "AI sõnumi uuesti esitamine pole selle otspunkti jaoks toetatud."
|
||||
"com_user_message": "Sina"
|
||||
}
|
||||
|
|
@ -322,7 +322,6 @@
|
|||
"com_nav_delete_cache_storage": "حافظه کش TTS را حذف کنید",
|
||||
"com_nav_delete_data_info": "تمام اطلاعات شما حذف خواهد شد.",
|
||||
"com_nav_delete_warning": "هشدار: با این کار حساب شما برای همیشه حذف می شود.",
|
||||
"com_nav_edit_chat_badges": "مدالهای چت را ویرایش کنید",
|
||||
"com_nav_enable_cache_tts": "کش TTS را فعال کنید",
|
||||
"com_nav_enable_cloud_browser_voice": "از صداهای مبتنی بر ابر استفاده کنید",
|
||||
"com_nav_enabled": "فعال شد",
|
||||
|
|
@ -679,7 +678,6 @@
|
|||
"com_ui_import_conversation_info": "مکالمات را از یک فایل JSON وارد کنید",
|
||||
"com_ui_import_conversation_success": "مکالمات با موفقیت وارد شد",
|
||||
"com_ui_include_shadcnui": "شامل دستورالعمل های اجزای shadcn/ui",
|
||||
"com_ui_include_shadcnui_agent": "دستورالعمل shadcn/ui را درج کنید",
|
||||
"com_ui_input": "ورودی",
|
||||
"com_ui_instructions": "دستورالعمل ها",
|
||||
"com_ui_late_night": "آخر شب مبارک",
|
||||
|
|
@ -847,6 +845,5 @@
|
|||
"com_ui_write": "نوشتن",
|
||||
"com_ui_yes": "بله",
|
||||
"com_ui_zoom": "بزرگنمایی ضربه بزنید؛",
|
||||
"com_user_message": "شما",
|
||||
"com_warning_resubmit_unsupported": "ارسال مجدد پیام هوش مصنوعی برای این نقطه پایانی پشتیبانی نمی شود."
|
||||
"com_user_message": "شما"
|
||||
}
|
||||
|
|
@ -1,4 +1,6 @@
|
|||
{
|
||||
"chat_direction_left_to_right": "Zone de saisie orientée de gauche à droite",
|
||||
"chat_direction_right_to_left": "Zone de saisie orientée de droite à gauche",
|
||||
"com_a11y_ai_composing": "L'IA est en train de composer",
|
||||
"com_a11y_end": "L'IA a terminé sa réponse",
|
||||
"com_a11y_start": "L'IA a commencé sa réponse",
|
||||
|
|
@ -15,21 +17,30 @@
|
|||
"com_agents_file_search_disabled": "L'agent doit être créé avant de pouvoir télécharger des fichiers pour la Recherche de Fichiers.",
|
||||
"com_agents_file_search_info": "Lorsque cette option est activée, l'agent sera informé des noms exacts des fichiers listés ci-dessous, lui permettant d'extraire le contexte pertinent de ces fichiers.",
|
||||
"com_agents_instructions_placeholder": "Les instructions système que l'agent utilise",
|
||||
"com_agents_mcp_description_placeholder": "Décrivez ce qu'il fait en quelques mots",
|
||||
"com_agents_mcp_icon_size": "Taille minimale de 128 x 128 pixels",
|
||||
"com_agents_mcp_info": "Ajoutez des serveurs MCP à vos agents pour lui permettre d'accomplir des tâches et d'interagir avec des services externes",
|
||||
"com_agents_mcp_name_placeholder": "Outil personnalisé",
|
||||
"com_agents_mcp_trust_subtext": "Connecteurs personnalisés non vérifiés par LibreChat",
|
||||
"com_agents_mcps_disabled": "Vous devez créer un agent avant d'ajouter des MCP.",
|
||||
"com_agents_missing_provider_model": "Veuillez sélectionner un fournisseur et un modèle avant de créer un agent.",
|
||||
"com_agents_name_placeholder": "Facultatif : Le nom de l'agent",
|
||||
"com_agents_no_access": "Vous n'avez pas l'autorisation de modifier cet agent.",
|
||||
"com_agents_no_agent_id_error": "Aucun identifiant (ID) d'agent trouvé. Assurez-vous que l'agent existe.",
|
||||
"com_agents_not_available": "Agent non disponible",
|
||||
"com_agents_search_info": "Lorsque cette option est activée, votre agent est autorisé à rechercher des informations récentes sur le web. Nécessite une clé API valide.",
|
||||
"com_agents_search_name": "Rechercher des agents par nom",
|
||||
"com_agents_update_error": "Une erreur s'est produite lors de la mise à jour de votre agent",
|
||||
"com_assistants_action_attempt": "L'assistant souhaite s'entretenir avec {{0}}",
|
||||
"com_assistants_action_attempt": "L'assistant souhaite échanger avec {{0}}",
|
||||
"com_assistants_actions": "Actions",
|
||||
"com_assistants_actions_disabled": "Vous devez créer un assistant avant d'ajouter des actions.",
|
||||
"com_assistants_actions_info": "Permettez à votre Assistant de récupérer des informations ou d'effectuer des actions via des API",
|
||||
"com_assistants_add_actions": "Ajouter des actions",
|
||||
"com_assistants_add_tools": "Ajouter des outils",
|
||||
"com_assistants_allow_sites_you_trust": "N'autorisez que les sites en lesquels vous avez confiance.",
|
||||
"com_assistants_allow_sites_you_trust": "Autoriser seulement les sites de confiance.",
|
||||
"com_assistants_append_date": "Ajouter la date et l'heure actuelles",
|
||||
"com_assistants_append_date_tooltip": "Lorsque activé, la date et l'heure actuelles du client seront ajoutées aux instructions du système de l'assistant.",
|
||||
"com_assistants_attempt_info": "Assistant souhaite envoyer les éléments suivants :",
|
||||
"com_assistants_available_actions": "Actions disponibles",
|
||||
"com_assistants_capabilities": "Capacités des assistants",
|
||||
"com_assistants_code_interpreter": "Interpréteur de code",
|
||||
|
|
@ -58,6 +69,7 @@
|
|||
"com_assistants_non_retrieval_model": "La recherche de fichiers n'est pas activée pour ce modèle. Veuillez sélectionner un autre modèle.",
|
||||
"com_assistants_retrieval": "Récupération",
|
||||
"com_assistants_running_action": "Action en cours",
|
||||
"com_assistants_running_var": "{{0}} en cours d'exécution",
|
||||
"com_assistants_search_name": "Rechercher des assistants par nom",
|
||||
"com_assistants_update_actions_error": "Une erreur s'est produite lors de la création ou de la mise à jour de l'action.",
|
||||
"com_assistants_update_actions_success": "Action créée ou mise à jour avec succès",
|
||||
|
|
@ -87,7 +99,7 @@
|
|||
"com_auth_email_verification_redirecting": "Redirection dans {{0}} secondes...",
|
||||
"com_auth_email_verification_resend_prompt": "Vous n'avez pas reçu de courriel ?",
|
||||
"com_auth_email_verification_success": "Courriel vérifié avec succès",
|
||||
"com_auth_email_verifying_ellipsis": "Vérification...",
|
||||
"com_auth_email_verifying_ellipsis": "Vérification en cours...",
|
||||
"com_auth_error_create": "Il y a eu une erreur lors de la tentative d'enregistrement de votre compte. Veuillez réessayer.",
|
||||
"com_auth_error_invalid_reset_token": "Ce jeton de réinitialisation de mot de passe n'est plus valide.",
|
||||
"com_auth_error_login": "Impossible de se connecter avec les informations fournies. Veuillez vérifier vos identifiants et réessayer.",
|
||||
|
|
@ -119,17 +131,20 @@
|
|||
"com_auth_reset_password_if_email_exists": "Si un compte avec ce courriel existe, un courriel avec des instructions de réinitialisation de mot de passe a été envoyé. Assurez-vous de vérifier votre dossier de courrier indésirable.",
|
||||
"com_auth_reset_password_link_sent": "Courriel envoyé",
|
||||
"com_auth_reset_password_success": "Réinitialisation du mot de passe réussie",
|
||||
"com_auth_saml_login": "Continuer avec SAML",
|
||||
"com_auth_sign_in": "Se connecter",
|
||||
"com_auth_sign_up": "S'inscrire",
|
||||
"com_auth_submit_registration": "Soumettre l'inscription",
|
||||
"com_auth_to_reset_your_password": "pour réinitialiser votre mot de passe.",
|
||||
"com_auth_to_try_again": "pour réessayer.",
|
||||
"com_auth_two_factor": "Consultez votre application préférée de mot de passe à usage unique pour obtenir un code.",
|
||||
"com_auth_two_factor": "Consultez votre application de mot de passe à usage unique pour obtenir un code.",
|
||||
"com_auth_username": "Nom d'utilisateur",
|
||||
"com_auth_username_max_length": "Le nom d'utilisateur doit être inférieur à 20 caractères",
|
||||
"com_auth_username_min_length": "Le nom d'utilisateur doit comporter au moins 3 caractères",
|
||||
"com_auth_verify_your_identity": "Vérifiez votre identité",
|
||||
"com_auth_welcome_back": "Content de te revoir",
|
||||
"com_citation_more_details": "Plus d'informations sur {{label}}",
|
||||
"com_citation_source": "Source",
|
||||
"com_click_to_download": "(cliquez ici pour télécharger)",
|
||||
"com_download_expired": "Téléchargement expiré",
|
||||
"com_download_expires": "(cliquez ici pour télécharger - expire le {{0}})",
|
||||
|
|
@ -179,6 +194,7 @@
|
|||
"com_endpoint_default_blank": "par défaut : vide",
|
||||
"com_endpoint_default_empty": "par défaut : vide",
|
||||
"com_endpoint_default_with_num": "par défaut : {{0}}",
|
||||
"com_endpoint_deprecated": "Obsolète",
|
||||
"com_endpoint_deprecated_info": "Ce point de terminaison est obsolète et pourrait être supprimé dans les versions futures, veuillez utiliser le point de terminaison de l'agent à la place.",
|
||||
"com_endpoint_deprecated_info_a11y": "Le point de terminaison du plugin est obsolète et pourrait être supprimé dans les versions futures, veuillez utiliser le point de terminaison de l'agent à la place.",
|
||||
"com_endpoint_examples": " Exemples",
|
||||
|
|
@ -189,8 +205,11 @@
|
|||
"com_endpoint_google_custom_name_placeholder": "Définir un nom personnalisé pour Google",
|
||||
"com_endpoint_google_maxoutputtokens": "Nombre maximum de jetons qui peuvent être générés dans la réponse. Spécifiez une valeur plus faible pour des réponses plus courtes et une valeur plus élevée pour des réponses plus longues.",
|
||||
"com_endpoint_google_temp": "Des valeurs plus élevées = plus aléatoires, tandis que des valeurs plus faibles = plus concentrées et déterministes. Nous vous recommandons de modifier ceci ou Top P mais pas les deux.",
|
||||
"com_endpoint_google_thinking": "Active / désactive le raisonnement. Ce réglage n'est pris en charge que par certains modèles (de la série des 2.5). Pour les modèles plus anciens, ce réglage peut n'avoir aucun effet ou l'empêcher de fonctionner.",
|
||||
"com_endpoint_google_thinking_budget": "Indique au modèle sur le nombre de jetons à utiliser pour la réflexion. Selon le message, le nombre de jetons effectivement consommés peut être supérieur ou inférieur à la valeur spécifiée.\n\nCe réglage n'est pris en charge que par certains modèles (de la série des 2.5). Gemini 2.5 Pro accepte une valeur comprise entre 128 et 32 768 jetons. Gemini 2.5 Flash accepte entre 0 et 24 576 jetons. Gemini 2.5 Flash Lite accepte entre 512 et 24 576 jetons.\n\nLaissez vide ou avec une valeur de \"-1\" pour laisser le model décider seul s'il doit réfléchir et à quel point il doit réfléchir. Par défaut, Gemini 2.5 Flash Lite ne réfléchit pas.",
|
||||
"com_endpoint_google_topk": "Top-k change la façon dont le modèle sélectionne les jetons pour la sortie. Un top-k de 1 signifie que le jeton sélectionné est le plus probable parmi tous les jetons du vocabulaire du modèle (également appelé décodage glouton), tandis qu'un top-k de 3 signifie que le jeton suivant est sélectionné parmi les 3 jetons les plus probables (en utilisant la température).",
|
||||
"com_endpoint_google_topp": "Top-p change la façon dont le modèle sélectionne les jetons pour la sortie. Les jetons sont sélectionnés du plus K (voir le paramètre topK) probable au moins jusqu'à ce que la somme de leurs probabilités égale la valeur top-p.",
|
||||
"com_endpoint_google_use_search_grounding": "Utilise la fonctionnalité d'ancrage aux recherches de google pour ajouter des résultats de recherches web en temps réels aux réponses. Cela permet aux modèles d'accéder aux informations récentes et de fournir une réponse plus précise et à jour.",
|
||||
"com_endpoint_instructions_assistants": "Instructions de remplacement",
|
||||
"com_endpoint_instructions_assistants_placeholder": "Remplace les instructions de l'assistant. Cela est utile pour modifier le comportement au cas par cas.",
|
||||
"com_endpoint_max_output_tokens": "Nombre maximum de jetons en sortie",
|
||||
|
|
@ -207,12 +226,14 @@
|
|||
"com_endpoint_openai_max_tokens": "Champ `max_tokens` optionnel, représentant le nombre maximum de jetons pouvant être générés dans la complétion de conversation. La longueur totale des jetons d'entrée et des jetons générés est limitée par la longueur du contexte du modèle. Vous pouvez rencontrer des erreurs si ce nombre dépasse le maximum de jetons de contexte.",
|
||||
"com_endpoint_openai_pres": "Nombre compris entre -2,0 et 2,0. Les valeurs positives pénalisent les nouveaux jetons en fonction du fait qu'ils apparaissent ou non dans le texte jusqu'à présent, augmentant ainsi la probabilité que le modèle parle de nouveaux sujets.",
|
||||
"com_endpoint_openai_prompt_prefix_placeholder": "Définir des instructions personnalisées à inclure dans le message système. Par défaut : aucun",
|
||||
"com_endpoint_openai_reasoning_effort": "Modèles o1 seulement : limite l'effort de raisonnement pour les modèles de raisonnement. La réduction de l'effort de raisonnement peut se traduire par des réponses plus rapides et moins de jetons utilisés pour le raisonnement dans une réponse",
|
||||
"com_endpoint_openai_reasoning_effort": "Uniquement pour les modèles o1 et o3 : limite l'effort de raisonnement pour les modèles de raisonnement. La réduction de l'effort de raisonnement peut se traduire par des réponses plus rapides et moins de jetons utilisés pour le raisonnement dans une réponse",
|
||||
"com_endpoint_openai_reasoning_summary": "API de Réponses uniquement : une synthèse du raisonnement est réalisé par le modèle. Cela peut être utile pour le débogage et pour comprendre les étapes de raisonnement du model. Les réglages possibles sont aucun, automatique, concis ou détaillé.",
|
||||
"com_endpoint_openai_resend": "Renvoyer toutes les images précédemment jointes. Remarque : cela peut augmenter considérablement le coût en jetons et vous pouvez rencontrer des erreurs avec de nombreuses images en pièces jointes.",
|
||||
"com_endpoint_openai_resend_files": "Renvoyer tous les fichiers précédemment joints. Remarque : cela augmentera le coût en jetons et vous pourriez rencontrer des erreurs avec de nombreuses pièces jointes.",
|
||||
"com_endpoint_openai_stop": "Jusqu'à 4 séquences où l'API cessera de générer d'autres jetons.",
|
||||
"com_endpoint_openai_temp": "Des valeurs plus élevées = plus aléatoires, tandis que des valeurs plus faibles = plus concentrées et déterministes. Nous vous recommandons de modifier ceci ou Top P mais pas les deux.",
|
||||
"com_endpoint_openai_topp": "Une alternative à l'échantillonnage avec température, appelée échantillonnage du noyau, où le modèle considère les résultats des jetons avec une masse de probabilité top_p. Ainsi, 0,1 signifie que seuls les jetons représentant les 10 % de masse de probabilité les plus élevés sont pris en compte. Nous vous recommandons de modifier ceci ou la température mais pas les deux.",
|
||||
"com_endpoint_openai_use_responses_api": "Utilise l'API de Réponses plutôt que la completion de messages, ce qui offre plus de fonctionnalités auprès d'OpenAI. Obligatoire pour o1-pro, o3-pro et pour activer la synthèse du raisonnement",
|
||||
"com_endpoint_output": "Sortie",
|
||||
"com_endpoint_plug_image_detail": "Détail de l'image",
|
||||
"com_endpoint_plug_resend_files": "Renvoyer les fichiers",
|
||||
|
|
@ -243,10 +264,11 @@
|
|||
"com_endpoint_prompt_prefix_assistants_placeholder": "Définir des instructions ou un contexte supplémentaire en plus des instructions principales de l'Assistant. Ignoré si vide.",
|
||||
"com_endpoint_prompt_prefix_placeholder": "Définir des instructions ou un contexte personnalisé. Ignoré si vide.",
|
||||
"com_endpoint_reasoning_effort": "Effort de raisonnement",
|
||||
"com_endpoint_reasoning_summary": "Synthèse du raisonnement",
|
||||
"com_endpoint_save_as_preset": "Enregistrer comme préréglage",
|
||||
"com_endpoint_search": "Rechercher un endpoint par nom",
|
||||
"com_endpoint_search_endpoint_models": "Recherche {{0}} modèles...",
|
||||
"com_endpoint_search_models": "Recherche de modèles...",
|
||||
"com_endpoint_search_endpoint_models": "Rechercher les modèles {{0}}...",
|
||||
"com_endpoint_search_models": "Rechercher les modèles...",
|
||||
"com_endpoint_search_var": "Recherche {{0}}...",
|
||||
"com_endpoint_set_custom_name": "Définir un nom personnalisé, au cas où vous trouveriez ce préréglage",
|
||||
"com_endpoint_skip_hover": "Activer le saut de l'étape de complétion, qui examine la réponse finale et les étapes générées",
|
||||
|
|
@ -258,6 +280,8 @@
|
|||
"com_endpoint_top_k": "Top K",
|
||||
"com_endpoint_top_p": "Top P",
|
||||
"com_endpoint_use_active_assistant": "Utiliser l'assistant actif",
|
||||
"com_endpoint_use_responses_api": "Utilise l'API de Réponses",
|
||||
"com_endpoint_use_search_grounding": "Ancrage avec les recherches Google",
|
||||
"com_error_expired_user_key": "La clé fournie pour {{0}} a expiré à {{1}}. Veuillez fournir une clé et réessayer.",
|
||||
"com_error_files_dupe": "Fichier en double détecté.",
|
||||
"com_error_files_empty": "Les fichiers vides ne sont pas autorisés",
|
||||
|
|
@ -266,6 +290,8 @@
|
|||
"com_error_files_upload": "Une erreur s'est produite lors du téléversement du fichier",
|
||||
"com_error_files_upload_canceled": "La demande de téléversement du fichier a été annulée. Remarque : le téléversement peut être toujours en cours de traitement et devra être supprimé manuellement.",
|
||||
"com_error_files_validation": "Une erreur s'est produite lors de la validation du fichier.",
|
||||
"com_error_google_tool_conflict": "L'utilisation combinée des outils intégrés de Google et d'outils externes n'est pas prise en charge. Veuillez désactiver soit les outils intégrés soit les outils externes.",
|
||||
"com_error_heic_conversion": "La conversion de l'image HEIC en JPEG a échoué. Essayez de convertir l'image manuellement ou utilisez un autre format.",
|
||||
"com_error_input_length": "Le nombre de jetons du dernier message est trop élevé et dépasse la limite autorisée ({{0}}). Veuillez raccourcir votre message, ajuster la taille maximale du contexte dans les paramètres de conversation, ou créer une nouvelle conversation pour continuer.",
|
||||
"com_error_invalid_agent_provider": "Le \"fournisseur {{0}} \" n'est pas disponible pour les agents. Veuillez vous rendre dans les paramètres de votre agent et sélectionner un fournisseur actuellement disponible.",
|
||||
"com_error_invalid_user_key": "Clé fournie non valide. Veuillez fournir une clé valide et réessayer.",
|
||||
|
|
@ -278,6 +304,7 @@
|
|||
"com_files_table": "quelquechose doit être renseigné ici. c'était vide",
|
||||
"com_generated_files": "Fichiers générés :",
|
||||
"com_hide_examples": "Masquer les exemples",
|
||||
"com_info_heic_converting": "Convertir les images HEIC en JPEG...",
|
||||
"com_nav_2fa": "Authentification à deux facteurs (2FA)",
|
||||
"com_nav_account_settings": "Paramètres du compte",
|
||||
"com_nav_always_make_prod": "Rendre toujours les nouvelles versions en production",
|
||||
|
|
@ -295,7 +322,29 @@
|
|||
"com_nav_auto_transcribe_audio": "Transcription audio automatique",
|
||||
"com_nav_automatic_playback": "Lecture automatique du dernier message (externe seulement)",
|
||||
"com_nav_balance": "Équilibre",
|
||||
"com_nav_balance_auto_refill_disabled": "Le rechargement automatique est désactivé.",
|
||||
"com_nav_balance_auto_refill_error": "Erreur lors du chargement des réglages de rechargement automatique.",
|
||||
"com_nav_balance_auto_refill_settings": "Réglages de rechargement automatique.",
|
||||
"com_nav_balance_day": "jour",
|
||||
"com_nav_balance_days": "jours",
|
||||
"com_nav_balance_every": "Chaque",
|
||||
"com_nav_balance_hour": "heure",
|
||||
"com_nav_balance_hours": "heures",
|
||||
"com_nav_balance_interval": "Délai :",
|
||||
"com_nav_balance_last_refill": "Dernier rechargement :",
|
||||
"com_nav_balance_minute": "minute",
|
||||
"com_nav_balance_minutes": "minutes",
|
||||
"com_nav_balance_month": "mois",
|
||||
"com_nav_balance_months": "mois",
|
||||
"com_nav_balance_next_refill": "Prochain rechargement :",
|
||||
"com_nav_balance_next_refill_info": "Le prochain rechargement s'effectura automatiquement lorsque les deux conditions seront remplies : le délai spécifié depuis le dernier rechargement est écoulé et l'envoi d'un message ferait tombé le solde en dessous de zéro.",
|
||||
"com_nav_balance_refill_amount": "Montant rechargé :",
|
||||
"com_nav_balance_second": "seconde",
|
||||
"com_nav_balance_seconds": "secondes",
|
||||
"com_nav_balance_week": "semaine",
|
||||
"com_nav_balance_weeks": "semaines",
|
||||
"com_nav_browser": "Navigateur",
|
||||
"com_nav_center_chat_input": "Centrer la zone de saisie avec l'écran d'accueil",
|
||||
"com_nav_change_picture": "Changer de photo",
|
||||
"com_nav_chat_commands": "Commandes de chat",
|
||||
"com_nav_chat_commands_info": "Ces commandes sont activées en tapant des caractères spécifiques au début de votre message. Chaque commande est déclenchée par son préfixe désigné. Vous pouvez les désactiver si vous utilisez fréquemment ces caractères pour commencer vos messages.",
|
||||
|
|
@ -317,7 +366,6 @@
|
|||
"com_nav_delete_cache_storage": "Supprimer le stockage du cache TTS",
|
||||
"com_nav_delete_data_info": "Toutes vos données seront supprimées.",
|
||||
"com_nav_delete_warning": "ATTENTION : Cela supprimera définitivement votre compte.",
|
||||
"com_nav_edit_chat_badges": "Modifier les badges de chat",
|
||||
"com_nav_enable_cache_tts": "Activer le cache TTS",
|
||||
"com_nav_enable_cloud_browser_voice": "Utiliser les voix cloud",
|
||||
"com_nav_enabled": "Activé",
|
||||
|
|
@ -341,6 +389,7 @@
|
|||
"com_nav_font_size_xs": "Très petit",
|
||||
"com_nav_help_faq": "Aide & FAQ",
|
||||
"com_nav_hide_panel": "Masquer le panneau latéral le plus à droite",
|
||||
"com_nav_info_balance": "Le solde affiche le nombre de crédits de jetons il vous reste à utiliser. Les crédits de jetons représentent une valeur monétaire (par exemple, 1 000 crédits = 0,001 $)",
|
||||
"com_nav_info_code_artifacts": "Active l'affichage des artéfacts de code expérimentaux à côté du chat",
|
||||
"com_nav_info_code_artifacts_agent": "Active l'utilisation d'artefacts de code pour cet agent. Par défaut, des instructions supplémentaires spécifiques à l'utilisation des artefacts sont ajoutées, à moins que le \"Mode d'invite personnalisé\" ne soit activé.",
|
||||
"com_nav_info_custom_prompt_mode": "Lorsqu'activé, le prompt système par défaut pour les artéfacts ne sera pas inclus. Toutes les instructions de génération d'artéfacts doivent être fournies manuellement dans ce mode.",
|
||||
|
|
@ -356,7 +405,10 @@
|
|||
"com_nav_lang_arabic": "العربية",
|
||||
"com_nav_lang_auto": "Détection automatique",
|
||||
"com_nav_lang_brazilian_portuguese": "Português Brasileiro",
|
||||
"com_nav_lang_catalan": "Catalan",
|
||||
"com_nav_lang_chinese": "中文",
|
||||
"com_nav_lang_czech": "Tchèque",
|
||||
"com_nav_lang_danish": "Danois",
|
||||
"com_nav_lang_dutch": "Nederlands",
|
||||
"com_nav_lang_english": "English",
|
||||
"com_nav_lang_estonian": "Eesti keel",
|
||||
|
|
@ -365,10 +417,12 @@
|
|||
"com_nav_lang_georgian": "ქართული",
|
||||
"com_nav_lang_german": "Deutsch",
|
||||
"com_nav_lang_hebrew": "עברית",
|
||||
"com_nav_lang_hungarian": "Hongrois",
|
||||
"com_nav_lang_indonesia": "Indonesia",
|
||||
"com_nav_lang_italian": "Italiano",
|
||||
"com_nav_lang_japanese": "日本語",
|
||||
"com_nav_lang_korean": "한국어",
|
||||
"com_nav_lang_persian": "Persan",
|
||||
"com_nav_lang_polish": "Polski",
|
||||
"com_nav_lang_portuguese": "Português",
|
||||
"com_nav_lang_russian": "Русский",
|
||||
|
|
@ -383,6 +437,8 @@
|
|||
"com_nav_log_out": "Se déconnecter",
|
||||
"com_nav_long_audio_warning": "Les textes plus longs prendront plus de temps à traiter.",
|
||||
"com_nav_maximize_chat_space": "Maximiser l'espace de discussion",
|
||||
"com_nav_mcp_vars_update_error": "Erreur lors de l'actualisation des variables de l'utilisateur MCP personnalisé : {{0}}",
|
||||
"com_nav_mcp_vars_updated": "Actualisation réussie des variables de l'utilisateur MCP personnalisé.",
|
||||
"com_nav_modular_chat": "Activer le changement de points de terminaison en cours de conversation",
|
||||
"com_nav_my_files": "Mes fichiers",
|
||||
"com_nav_not_supported": "Non pris en charge",
|
||||
|
|
@ -398,14 +454,17 @@
|
|||
"com_nav_profile_picture": "Photo de profil",
|
||||
"com_nav_save_badges_state": "Sauvegarder l'état des badges",
|
||||
"com_nav_save_drafts": "Enregistrer les brouillons localement",
|
||||
"com_nav_scroll_button": "Défilement jusqu'à la touche de fin",
|
||||
"com_nav_scroll_button": "Bouton de défilement jusqu'à la fin",
|
||||
"com_nav_search_placeholder": "Rechercher des messages",
|
||||
"com_nav_send_message": "Envoyer un message",
|
||||
"com_nav_setting_account": "Compte",
|
||||
"com_nav_setting_balance": "Solde",
|
||||
"com_nav_setting_beta": "Fonctionnalités bêta",
|
||||
"com_nav_setting_chat": "Chat",
|
||||
"com_nav_setting_data": "Contrôles des données",
|
||||
"com_nav_setting_general": "Général",
|
||||
"com_nav_setting_mcp": "Réglages MCP",
|
||||
"com_nav_setting_personalization": "Personnalisation",
|
||||
"com_nav_setting_speech": "Parole",
|
||||
"com_nav_settings": "Paramètres",
|
||||
"com_nav_shared_links": "Liens partagés",
|
||||
|
|
@ -438,26 +497,39 @@
|
|||
"com_sidepanel_conversation_tags": "Signets",
|
||||
"com_sidepanel_hide_panel": "Masquer le panneau",
|
||||
"com_sidepanel_manage_files": "Gérer les fichiers",
|
||||
"com_sidepanel_mcp_enter_value": "Saisissez la valeur de {{0}}",
|
||||
"com_sidepanel_mcp_no_servers_with_vars": "Aucun serveur MCP dont les variables sont configurables.",
|
||||
"com_sidepanel_mcp_variables_for": "Variables MCP de {{0}}",
|
||||
"com_sidepanel_parameters": "Paramètres",
|
||||
"com_sources_image_alt": "Image de résultat de recherche",
|
||||
"com_sources_more_sources": "+{{count}} sources",
|
||||
"com_sources_tab_all": "Tous",
|
||||
"com_sources_tab_images": "Images",
|
||||
"com_sources_tab_news": "Actualités",
|
||||
"com_sources_title": "Sources",
|
||||
"com_ui_2fa_account_security": "L'authentification à deux facteurs ajoute un niveau de sécurité supplémentaire à votre compte",
|
||||
"com_ui_2fa_disable": "Désactiver l'authentification à deux facteurs (2FA)",
|
||||
"com_ui_2fa_disable_error": "Une erreur s'est produite lors de la désactivation de l'authentification à deux facteurs.",
|
||||
"com_ui_2fa_disable_error": "Une erreur s'est produite lors de la désactivation de l'authentification à deux facteurs",
|
||||
"com_ui_2fa_disabled": "L'authentification à deux facteurs (2FA) a été désactivé",
|
||||
"com_ui_2fa_enable": "Activer l'authentification à deux facteurs (2FA)",
|
||||
"com_ui_2fa_enabled": "L'authentification à deux facteurs (2FA) a été activée",
|
||||
"com_ui_2fa_generate_error": "Une erreur s'est produite lors de la génération des paramètres d'authentification à deux facteurs.",
|
||||
"com_ui_2fa_generate_error": "Une erreur s'est produite lors de la génération des paramètres d'authentification à deux facteurs",
|
||||
"com_ui_2fa_invalid": "Code d'authentification à deux facteurs invalide",
|
||||
"com_ui_2fa_setup": "Configuration de l'authentification à deux facteurs (2FA)",
|
||||
"com_ui_2fa_verified": "Vérification réussie de l'authentification à deux facteurs",
|
||||
"com_ui_2fa_verified": "Vérification de l'authentification à deux facteurs réussie",
|
||||
"com_ui_accept": "J'accepte",
|
||||
"com_ui_action_button": "Bouton d'action",
|
||||
"com_ui_add": "Ajouter",
|
||||
"com_ui_add_mcp": "Ajouter MCP",
|
||||
"com_ui_add_mcp_server": "Ajouter un server MCP",
|
||||
"com_ui_add_model_preset": "Ajouter un modèle ou un préréglage pour une réponse supplémentaire",
|
||||
"com_ui_add_multi_conversation": "Ajouter plusieurs conversations",
|
||||
"com_ui_adding_details": "Ajouter des détails",
|
||||
"com_ui_admin": "Administrateur",
|
||||
"com_ui_admin_access_warning": "La désactivation de l'accès administrateur à cette fonctionnalité peut entraîner des problèmes d'interface imprévus nécessitant une actualisation. Une fois sauvegardé, le seul moyen de rétablir l'accès est via le paramètre d'interface dans la configuration librechat.yaml, ce qui affecte tous les rôles.",
|
||||
"com_ui_admin_settings": "Paramètres administratifs",
|
||||
"com_ui_advanced": "Avancé",
|
||||
"com_ui_advanced_settings": "Paramètres avancés",
|
||||
"com_ui_advanced_settings": "Réglages avancés",
|
||||
"com_ui_agent": "Agent",
|
||||
"com_ui_agent_chain": "Chaîne d'agents (mélange d'agents)",
|
||||
"com_ui_agent_chain_info": "Active la création des séquences d'agents. Chaque agent peut accéder aux résultats des agents précédents de la chaîne. Basé sur l'architecture \"mélange d'agents\" où les agents utilisent les résultats précédents comme information auxiliaire.",
|
||||
|
|
@ -468,18 +540,39 @@
|
|||
"com_ui_agent_duplicated": "Agent dupliqué avec succès",
|
||||
"com_ui_agent_editing_allowed": "D'autres utilisateurs peuvent déjà modifier cet agent",
|
||||
"com_ui_agent_recursion_limit": "Nombre maximal d'étapes de l'agent",
|
||||
"com_ui_agent_shared_to_all": "il faut faire quelque chose ici. c'était vide",
|
||||
"com_ui_agent_recursion_limit_info": "Limite le nombre d'étapes que l'agent peut exécuter avant de donner son résultat final. Par défaut, la limite est de 25 étapes. Une étape est soit une requête API soit une utilisation d'un outil. Par exemple, une utilisation simple d'un outil demande 3 étapes : requête initiale, utilisation de l'outil et envoi de la réponse.",
|
||||
"com_ui_agent_shared_to_all": "Partagé les agents à tous",
|
||||
"com_ui_agent_var": "agent {{0}}",
|
||||
"com_ui_agent_version": "Version",
|
||||
"com_ui_agent_version_active": "Version active",
|
||||
"com_ui_agent_version_duplicate": "Duplicata de version détecté. Cela créerait une version identique à la version {{versionIndex}}",
|
||||
"com_ui_agent_version_empty": "Aucune version disponible",
|
||||
"com_ui_agent_version_error": "Erreur lors de la collecte des versions",
|
||||
"com_ui_agent_version_history": "Historique des versions",
|
||||
"com_ui_agent_version_no_agent": "Aucun agent sélectionné. Veuillez sélectionner un agent pour voir l'historique des versions.",
|
||||
"com_ui_agent_version_no_date": "Aucune date disponible",
|
||||
"com_ui_agent_version_restore": "Restaurer",
|
||||
"com_ui_agent_version_restore_confirm": "Êtes-vous sûr de vouloir restaurer cette version ?",
|
||||
"com_ui_agent_version_restore_error": "Restauration de version échouée",
|
||||
"com_ui_agent_version_restore_success": "Restauration de version réussie",
|
||||
"com_ui_agent_version_title": "Version {{versionNumber}}",
|
||||
"com_ui_agent_version_unknown_date": "Date inconnue",
|
||||
"com_ui_agents": "Agents",
|
||||
"com_ui_agents_allow_create": "Autoriser la création d'Agents",
|
||||
"com_ui_agents_allow_share_global": "Autoriser le partage des Agents avec tous les utilisateurs",
|
||||
"com_ui_agents_allow_use": "Autoriser l'utilisation des Agents",
|
||||
"com_ui_all": "tout",
|
||||
"com_ui_all_proper": "Tout",
|
||||
"com_ui_analyzing": "Analyse en cours",
|
||||
"com_ui_analyzing_finished": "Analyse terminée",
|
||||
"com_ui_api_key": "Clé API",
|
||||
"com_ui_archive": "Archiver",
|
||||
"com_ui_archive_delete_error": "Suppression de la conversation archivée échouée",
|
||||
"com_ui_archive_error": "échec de l'archivage de la conversation",
|
||||
"com_ui_artifact_click": "Cliquer pour ouvrir",
|
||||
"com_ui_artifacts": "Artefacts",
|
||||
"com_ui_artifacts_toggle": "Afficher/Masquer l'interface des artefacts",
|
||||
"com_ui_artifacts_toggle_agent": "Activer Artifacts",
|
||||
"com_ui_ascending": "Croissant",
|
||||
"com_ui_assistant": "Assistant",
|
||||
"com_ui_assistant_delete_error": "Une erreur s'est produite lors de la suppression de l'assistant.",
|
||||
|
|
@ -490,12 +583,26 @@
|
|||
"com_ui_attach_error_openai": "Impossible de joindre les fichiers de l'Assistant à d'autres points d'accès",
|
||||
"com_ui_attach_error_size": "Limite de taille de fichier dépassée pour le point de terminaison :",
|
||||
"com_ui_attach_error_type": "Type de fichier non pris en charge pour ce point d'accès :",
|
||||
"com_ui_attach_remove": "Supprimer le fichier",
|
||||
"com_ui_attach_warn_endpoint": "Les fichiers non compatibles avec l'outil peuvent être ignorés",
|
||||
"com_ui_attachment": "Pièce jointe",
|
||||
"com_ui_auth_type": "Type d'auth",
|
||||
"com_ui_auth_url": "Adresse URL d'authentification",
|
||||
"com_ui_authentication": "Authentification",
|
||||
"com_ui_authentication_type": "Type d'authentification",
|
||||
"com_ui_auto": "Automatique",
|
||||
"com_ui_available_tools": "Outils disponibles",
|
||||
"com_ui_avatar": "Avatar",
|
||||
"com_ui_azure": "Azure",
|
||||
"com_ui_back": "Retour",
|
||||
"com_ui_back_to_chat": "Retour à la discussion",
|
||||
"com_ui_back_to_prompts": "Retour aux Prompts",
|
||||
"com_ui_backup_codes": "Codes de sauvegarde",
|
||||
"com_ui_backup_codes_regenerate_error": "Une erreur est survenue lors du renouvellement des codes de sauvegarde",
|
||||
"com_ui_backup_codes_regenerated": "Codes de sauvegarde renouvelé avec succès",
|
||||
"com_ui_basic": "Simple",
|
||||
"com_ui_basic_auth_header": "En-tête d'autorisation simple",
|
||||
"com_ui_bearer": "Porteur",
|
||||
"com_ui_bookmark_delete_confirm": "Êtes-vous sûr de vouloir supprimer ce signet?",
|
||||
"com_ui_bookmarks": "Signets",
|
||||
"com_ui_bookmarks_add": "Ajouter des signets",
|
||||
|
|
@ -515,23 +622,33 @@
|
|||
"com_ui_bookmarks_update_error": "Une erreur est survenue lors de la mise à jour du signet",
|
||||
"com_ui_bookmarks_update_success": "Signet mis à jour avec succès",
|
||||
"com_ui_bulk_delete_error": "Échec de la suppression des liens partagés",
|
||||
"com_ui_callback_url": "Adresse URL de callback",
|
||||
"com_ui_cancel": "Annuler",
|
||||
"com_ui_cancelled": "Annulé",
|
||||
"com_ui_category": "Catégorie",
|
||||
"com_ui_chat": "Discussion",
|
||||
"com_ui_chat_history": "Historique des discussions",
|
||||
"com_ui_clear": "Effacer",
|
||||
"com_ui_clear_all": "Tout effacer",
|
||||
"com_ui_client_id": "Identifiant (ID) du client",
|
||||
"com_ui_client_secret": "Secret du client",
|
||||
"com_ui_close": "Fermer",
|
||||
"com_ui_close_menu": "Fermer le menu",
|
||||
"com_ui_close_window": "Fermer la fenêtre",
|
||||
"com_ui_code": "Code",
|
||||
"com_ui_collapse_chat": "Réduire la discussion",
|
||||
"com_ui_command_placeholder": "Facultatif : Saisissez une commande pour l'invite ou le nom sera utilisé",
|
||||
"com_ui_command_usage_placeholder": "Sélectionnez un prompt par commande ou par nom",
|
||||
"com_ui_complete_setup": "Configuration complete",
|
||||
"com_ui_concise": "Concis",
|
||||
"com_ui_configure_mcp_variables_for": "Configurer les variables pour {{0}}",
|
||||
"com_ui_confirm_action": "Confirmer l'action",
|
||||
"com_ui_confirm_admin_use_change": "La modification de ce paramètre bloquera l'accès aux administrateurs, y compris vous-même. Êtes-vous sûr de vouloir continuer ?",
|
||||
"com_ui_confirm_change": "Confirmer le changement",
|
||||
"com_ui_confirm_change": "Confirmer la modification",
|
||||
"com_ui_context": "Contexte",
|
||||
"com_ui_continue": "Continuer",
|
||||
"com_ui_controls": "Contrôles",
|
||||
"com_ui_convo_delete_error": "Suppression de conversation échouée",
|
||||
"com_ui_copied": "Copié !",
|
||||
"com_ui_copied_to_clipboard": "Copié dans le presse-papier",
|
||||
"com_ui_copy_code": "Copier le code",
|
||||
|
|
@ -539,8 +656,13 @@
|
|||
"com_ui_copy_to_clipboard": "Copier dans le presse-papier",
|
||||
"com_ui_create": "Créer",
|
||||
"com_ui_create_link": "Créer un lien",
|
||||
"com_ui_create_memory": "Créer un Souvenir",
|
||||
"com_ui_create_prompt": "Créer un prompt",
|
||||
"com_ui_creating_image": "Création de l'image en cours. Cela peut prendre un moment",
|
||||
"com_ui_current": "Actuel",
|
||||
"com_ui_currently_production": "En cours de production",
|
||||
"com_ui_custom": "Personnalisé",
|
||||
"com_ui_custom_header_name": "Nom d'en-tête personnalisé",
|
||||
"com_ui_custom_prompt_mode": "Mode de prompt personnalisé",
|
||||
"com_ui_dashboard": "Tableau de bord",
|
||||
"com_ui_date": "Date",
|
||||
|
|
@ -561,6 +683,7 @@
|
|||
"com_ui_date_today": "Aujourd'hui",
|
||||
"com_ui_date_yesterday": "Hier",
|
||||
"com_ui_decline": "Je n'accepte pas",
|
||||
"com_ui_default_post_request": "Par défaut (requête POST)",
|
||||
"com_ui_delete": "Supprimer",
|
||||
"com_ui_delete_action": "Supprimer l'action",
|
||||
"com_ui_delete_action_confirm": "Êtes-vous sûr de vouloir supprimer cette action ?",
|
||||
|
|
@ -569,15 +692,28 @@
|
|||
"com_ui_delete_confirm": "Cela supprimera",
|
||||
"com_ui_delete_confirm_prompt_version_var": "Cela supprimera la version sélectionnée pour \"{{0}}.\" S'il n'existe aucune autre version, le prompt sera supprimé.",
|
||||
"com_ui_delete_conversation": "Supprimer la discussion?",
|
||||
"com_ui_delete_mcp": "Supprimer MCP",
|
||||
"com_ui_delete_mcp_confirm": "Êtes-vous sûr de vouloir supprimer ce serveur MCP ?",
|
||||
"com_ui_delete_mcp_error": "Suppression de serveur MCP échouée",
|
||||
"com_ui_delete_mcp_success": "Suppression de serveur MCP réussie",
|
||||
"com_ui_delete_memory": "Supprimer les Souvenirs",
|
||||
"com_ui_delete_prompt": "Supprimer le Prompt?",
|
||||
"com_ui_delete_shared_link": "Supprimer le lien partagé ?",
|
||||
"com_ui_delete_tool": "Supprimer l'outil",
|
||||
"com_ui_delete_tool_confirm": "Êtes-vous sûr de vouloir supprimer cet outil ?",
|
||||
"com_ui_deleted": "Supprimé",
|
||||
"com_ui_descending": "Décroissant",
|
||||
"com_ui_description": "Description",
|
||||
"com_ui_description_placeholder": "Optionnel : Entrez une description à afficher dans le prompt",
|
||||
"com_ui_deselect_all": "Tout désélectionner ",
|
||||
"com_ui_detailed": "Détaillée",
|
||||
"com_ui_disabling": "Désactivation en cours...",
|
||||
"com_ui_download": "Télécharger",
|
||||
"com_ui_download_artifact": "Télécharger Artifact",
|
||||
"com_ui_download_backup": "Télécharger les codes de sauvegarde",
|
||||
"com_ui_download_backup_tooltip": "Avant de continuer, téléchargez vos codes de sauvegarde. Vous en aurez besoin pour récupérer un accès si vous perdez votre appareil authenticator",
|
||||
"com_ui_download_error": "Erreur lors du téléchargement du fichier. Le fichier a peut-être été supprimé.",
|
||||
"com_ui_drag_drop": "Glisser et déposer",
|
||||
"com_ui_dropdown_variables": "Variables déroulantes :",
|
||||
"com_ui_dropdown_variables_info": "Créez des menus déroulants personnalisés pour vos prompts : `{{nom_variable:option1|option2|option3}}`",
|
||||
"com_ui_duplicate": "Dupliquer",
|
||||
|
|
@ -585,18 +721,49 @@
|
|||
"com_ui_duplication_processing": "Duplication de la conversation en cours...",
|
||||
"com_ui_duplication_success": "Conversation dupliquée avec succès",
|
||||
"com_ui_edit": "Modifier",
|
||||
"com_ui_edit_editing_image": "Edition de l'image",
|
||||
"com_ui_edit_mcp_server": "Editer le serveur MCP",
|
||||
"com_ui_edit_memory": "Editer les Souvenirs",
|
||||
"com_ui_empty_category": "-",
|
||||
"com_ui_endpoint": "Point de terminaison",
|
||||
"com_ui_endpoint_menu": "Menu des points de terminaison LLM",
|
||||
"com_ui_enter": "Entrer",
|
||||
"com_ui_enter_api_key": "Saisir la clé API",
|
||||
"com_ui_enter_key": "Entrez la clé",
|
||||
"com_ui_enter_openapi_schema": "Saisissez votre schéma OpenAPI ici",
|
||||
"com_ui_enter_value": "Entrez la valeur",
|
||||
"com_ui_error": "Erreur",
|
||||
"com_ui_error_connection": "Erreur de connexion au serveur, essayez de rafraîchir la page.",
|
||||
"com_ui_error_save_admin_settings": "Une erreur est survenue lors de la sauvegarde de vos paramètres administratifs.",
|
||||
"com_ui_error_updating_preferences": "Une erreur est survenue lors de l'édition des préférences",
|
||||
"com_ui_examples": "Exemples",
|
||||
"com_ui_expand_chat": "Etendre le message",
|
||||
"com_ui_export_convo_modal": "Exporter la conversation",
|
||||
"com_ui_feedback_more": "Plus...",
|
||||
"com_ui_feedback_more_information": "Envoyer des retours supplémentaires",
|
||||
"com_ui_feedback_negative": "Amélioration nécessaires",
|
||||
"com_ui_feedback_placeholder": "Veuillez indiquer vos retours supplémentaires ici",
|
||||
"com_ui_feedback_positive": "J'adore",
|
||||
"com_ui_feedback_tag_accurate_reliable": "Précis et fiable",
|
||||
"com_ui_feedback_tag_attention_to_detail": "Attention aux détails",
|
||||
"com_ui_feedback_tag_bad_style": "Style ou ton inadapté",
|
||||
"com_ui_feedback_tag_clear_well_written": "Clair et bien écrit",
|
||||
"com_ui_feedback_tag_creative_solution": "Solution créative",
|
||||
"com_ui_feedback_tag_inaccurate": "Réponse imprécise ou incorrecte",
|
||||
"com_ui_feedback_tag_many": "Nombreux",
|
||||
"com_ui_feedback_tag_missing_image": "Image manquante",
|
||||
"com_ui_feedback_tag_not_helpful": "Manquait d'informations utiles",
|
||||
"com_ui_feedback_tag_not_matched": "Ne répond pas à ma demande",
|
||||
"com_ui_feedback_tag_one": "Un seul",
|
||||
"com_ui_feedback_tag_other": "Autre",
|
||||
"com_ui_feedback_tag_unjustified_refusal": "A refusé sans raison",
|
||||
"com_ui_field_required": "Ce champ est obligatoire",
|
||||
"com_ui_file_size": "Taille du fichier",
|
||||
"com_ui_files": "Fichiers",
|
||||
"com_ui_filter_prompts": "Filtrer les messages",
|
||||
"com_ui_filter_prompts_name": "Filtrer les prompts par nom",
|
||||
"com_ui_final_touch": "Touche finale",
|
||||
"com_ui_finance": "Finance",
|
||||
"com_ui_fork": "Bifurquer",
|
||||
"com_ui_fork_all_target": "Inclure tout à partir d'ici",
|
||||
"com_ui_fork_branches": "Inclure les branches associées",
|
||||
|
|
@ -608,10 +775,13 @@
|
|||
"com_ui_fork_info_2": "\"Forker\" fait référence à la création d'une nouvelle conversation qui commence/se termine à partir de messages spécifiques dans la conversation actuelle, en créant une copie selon les options sélectionnées.",
|
||||
"com_ui_fork_info_3": "Le terme \"message cible\" fait référence soit au message à partir duquel cette fenêtre contextuelle a été ouverte, soit, si vous cochez \"{{0}}\", au dernier message de la conversation.",
|
||||
"com_ui_fork_info_branches": "Cette option divise les messages visibles, ainsi que les branches associées ; en d'autres termes, le chemin direct vers le message cible, y compris les branches le long du chemin.",
|
||||
"com_ui_fork_info_button_label": "Voir les informations sur les fourches de conversations",
|
||||
"com_ui_fork_info_remember": "Cochez cette case pour mémoriser les options que vous sélectionnez pour une utilisation future, ce qui vous permettra de bifurquer plus rapidement les conversations selon vos préférences.",
|
||||
"com_ui_fork_info_start": "Si cette option est cochée, le fork commencera à partir de ce message jusqu'au dernier message de la conversation, selon le comportement sélectionné ci-dessus.",
|
||||
"com_ui_fork_info_target": "Cette option divise tous les messages menant au message cible, y compris ses voisins ; en d'autres termes, toutes les branches de messages, qu'elles soient visibles ou non et quel que soit leur chemin, sont incluses.",
|
||||
"com_ui_fork_info_visible": "Cette option permet de diviser uniquement les messages visibles ; en d'autres termes, le chemin direct vers le message cible, sans aucune branche.",
|
||||
"com_ui_fork_more_details_about": "Voir plus d'informations sur l'option de fouche \"{{0}}",
|
||||
"com_ui_fork_more_info_options": "Voir des explications détaillées sur toutes les options de fourches et leurs effets",
|
||||
"com_ui_fork_processing": "Bifurquer la conversation...",
|
||||
"com_ui_fork_remember": "Se souvenir",
|
||||
"com_ui_fork_remember_checked": "Votre sélection sera mémorisée après utilisation. Vous pouvez la modifier à tout moment dans les paramètres.",
|
||||
|
|
@ -619,12 +789,29 @@
|
|||
"com_ui_fork_split_target_setting": "Démarrer la bifurcation à partir du message cible par défaut",
|
||||
"com_ui_fork_success": "Conversation bifurquée avec succès",
|
||||
"com_ui_fork_visible": "Messages visibles uniquement",
|
||||
"com_ui_go_back": "Retourner",
|
||||
"com_ui_generate_backup": "Générer des codes de sauvegarde",
|
||||
"com_ui_generate_qrcode": "Générer un QR Code",
|
||||
"com_ui_generating": "Génération en cours...",
|
||||
"com_ui_generation_settings": "Réglages de génération",
|
||||
"com_ui_getting_started": "Commencer",
|
||||
"com_ui_global_group": "Groupe global",
|
||||
"com_ui_go_back": "Revenir en arrière",
|
||||
"com_ui_go_to_conversation": "Aller à la conversation",
|
||||
"com_ui_good_afternoon": "Bon après-midi",
|
||||
"com_ui_good_evening": "Bonne soirée",
|
||||
"com_ui_good_morning": "Bonjour",
|
||||
"com_ui_happy_birthday": "C'est mon premier anniversaire !",
|
||||
"com_ui_hide_qr": "Cacher le code QR",
|
||||
"com_ui_hide_image_details": "Cacher les informations de l'images",
|
||||
"com_ui_hide_qr": "Cacher le QR code",
|
||||
"com_ui_high": "Elevé",
|
||||
"com_ui_host": "Hôte",
|
||||
"com_ui_icon": "Icône",
|
||||
"com_ui_idea": "Idées",
|
||||
"com_ui_image_created": "Image créée",
|
||||
"com_ui_image_details": "Informations de l'image",
|
||||
"com_ui_image_edited": "Image éditée",
|
||||
"com_ui_image_gen": "Génération d'image",
|
||||
"com_ui_import": "Importer",
|
||||
"com_ui_import_conversation_error": "Une erreur s'est produite lors de l'importation de vos conversations",
|
||||
"com_ui_import_conversation_file_type_error": "Type de fichier non pris en charge pour l'importation",
|
||||
"com_ui_import_conversation_info": "Importer des conversations à partir d'un fichier JSON",
|
||||
|
|
@ -632,35 +819,82 @@
|
|||
"com_ui_include_shadcnui": "Inclure les instructions des composants shadcn/ui",
|
||||
"com_ui_input": "Entrée",
|
||||
"com_ui_instructions": "Instructions",
|
||||
"com_ui_key": "Clé",
|
||||
"com_ui_late_night": "Bonne nocturne",
|
||||
"com_ui_latest_footer": "Chaque IA pour tout le monde.",
|
||||
"com_ui_latest_production_version": "Dernière version de production",
|
||||
"com_ui_latest_version": "Dernière version",
|
||||
"com_ui_librechat_code_api_key": "Obtenir votre clé API pour l'interpréteur de code LibreChat",
|
||||
"com_ui_librechat_code_api_subtitle": "Sécurisé. Multilingue. Fichiers d'entrée/sortie.",
|
||||
"com_ui_librechat_code_api_title": "Exécuter le code IA",
|
||||
"com_ui_loading": "Chargement en cours...",
|
||||
"com_ui_locked": "Verrouillé",
|
||||
"com_ui_logo": "Logo {{0}}",
|
||||
"com_ui_low": "Faible",
|
||||
"com_ui_manage": "Gérer",
|
||||
"com_ui_max_tags": "Le nombre maximum autorisé est {{0}}, en utilisant les dernières valeurs.",
|
||||
"com_ui_mcp_dialog_desc": "Veuillez saisir les informations importantes ci-dessous.",
|
||||
"com_ui_mcp_enter_var": "Saisissez la valeur de {{0}}",
|
||||
"com_ui_mcp_server_not_found": "Le serveur n'a pas été trouvé.",
|
||||
"com_ui_mcp_servers": "Serveurs MCP",
|
||||
"com_ui_mcp_url": "Adresse URL du serveur MCP",
|
||||
"com_ui_medium": "Modéré",
|
||||
"com_ui_memories": "Souvenirs",
|
||||
"com_ui_memories_allow_create": "Autoriser la création de Souvenirs",
|
||||
"com_ui_memories_allow_opt_out": "Autoriser les utilisateurs à désactiver les Souvenirs",
|
||||
"com_ui_memories_allow_read": "Autoriser la lecture des Souvenirs",
|
||||
"com_ui_memories_allow_update": "Autoriser la mise à jour des Souvenirs",
|
||||
"com_ui_memories_allow_use": "Autoriser l'utilisation des Souvenirs",
|
||||
"com_ui_memories_filter": "Filtrer les Souvenirs",
|
||||
"com_ui_memory": "Souvenir",
|
||||
"com_ui_memory_created": "Souvenir créé avec succès",
|
||||
"com_ui_memory_deleted": "Souvenir supprimé",
|
||||
"com_ui_memory_deleted_items": "Souvenirs supprimés",
|
||||
"com_ui_memory_key_exists": "Un Souvenir existe déjà avec cette clé. Veuillez utiliser une autre clé.",
|
||||
"com_ui_memory_updated": "Actualiser le Souvenir enregistré",
|
||||
"com_ui_memory_updated_items": "Souvenirs enregistrés",
|
||||
"com_ui_mention": "Mentionnez un point de terminaison, un assistant ou un préréglage pour basculer rapidement vers celui-ci",
|
||||
"com_ui_min_tags": "Impossible de supprimer plus de valeurs, un minimum de {{0}} est requis.",
|
||||
"com_ui_misc": "Divers",
|
||||
"com_ui_model": "Modèle",
|
||||
"com_ui_model_parameters": "Paramètres du modèle",
|
||||
"com_ui_more_info": "Plus d'informations",
|
||||
"com_ui_my_prompts": "Mes Prompts",
|
||||
"com_ui_name": "Nom",
|
||||
"com_ui_new": "Nouveau",
|
||||
"com_ui_new_chat": "Nouvelle conversation",
|
||||
"com_ui_new_conversation_title": "Nouveau titre de conversation",
|
||||
"com_ui_next": "Suivant",
|
||||
"com_ui_no": "Non",
|
||||
"com_ui_no_backup_codes": "Aucun code de sauvegarde disponible. Veuillez générer de nouveaux codes.",
|
||||
"com_ui_no_bookmarks": "Il semble que vous n'ayez pas encore de favoris. Cliquez sur une discussion pour en ajouter un",
|
||||
"com_ui_no_category": "Aucune catégorie",
|
||||
"com_ui_no_changes": "Aucune modification à mettre à jour",
|
||||
"com_ui_no_data": "Aucune donnée",
|
||||
"com_ui_no_personalization_available": "Aucune personnalisation disponible",
|
||||
"com_ui_no_read_access": "Vous n'avez pas l'authorisation de voir les Souvenirs.",
|
||||
"com_ui_no_terms_content": "Aucun contenu de conditions d'utilisation à afficher",
|
||||
"com_ui_no_valid_items": "Aucun élément valide",
|
||||
"com_ui_none": "Aucun",
|
||||
"com_ui_not_used": "Inutilisé",
|
||||
"com_ui_nothing_found": "Aucun résultat trouvé",
|
||||
"com_ui_oauth": "OAuth",
|
||||
"com_ui_oauth_connected_to": "Connecté à",
|
||||
"com_ui_oauth_error_callback_failed": "Le rappel d'authentification a échoué. Veuillez réessayer.",
|
||||
"com_ui_oauth_error_generic": "L'authentification a échoué. Veuillez réessayer.",
|
||||
"com_ui_oauth_error_invalid_state": "Paramètre d'état invalide. Veuillez réessayer.",
|
||||
"com_ui_oauth_error_missing_code": "Code d'authorisation manquant. Veuillez réessayer.",
|
||||
"com_ui_oauth_error_missing_state": "Paramètre d'état manquant. Veuillez réessayer.",
|
||||
"com_ui_oauth_error_title": "L'authentification a échoué.",
|
||||
"com_ui_oauth_success_description": "Vous vous êtes authentifié avec succès. La fenêtre va se fermer.",
|
||||
"com_ui_oauth_success_title": "Authentification réussie",
|
||||
"com_ui_of": "des",
|
||||
"com_ui_off": "Désactivé",
|
||||
"com_ui_on": "Activé",
|
||||
"com_ui_openai": "OpenAI",
|
||||
"com_ui_optional": "(optionnel)",
|
||||
"com_ui_page": "Page",
|
||||
"com_ui_preferences_updated": "Préférences enregistrées avec succès",
|
||||
"com_ui_prev": "Précédent",
|
||||
"com_ui_preview": "Aperçu",
|
||||
"com_ui_privacy_policy": "Politique de confidentialité",
|
||||
|
|
@ -678,11 +912,23 @@
|
|||
"com_ui_prompts_allow_share_global": "Autoriser le partage des Prompts à tous les utilisateurs",
|
||||
"com_ui_prompts_allow_use": "Autoriser l'utilisation de Prompts",
|
||||
"com_ui_provider": "Fournisseur",
|
||||
"com_ui_quality": "Qualité",
|
||||
"com_ui_read_aloud": "Lire à haute voix",
|
||||
"com_ui_redirecting_to_provider": "Redirection en cours vers {{0}}, veuillez patienter...",
|
||||
"com_ui_reference_saved_memories": "Indexer les Souvenirs enregistrés",
|
||||
"com_ui_reference_saved_memories_description": "Autoriser l'assistant à accéder aux index des Souvenirs enregistrés et à les utiliser pour répondre",
|
||||
"com_ui_refresh_link": "Rafraîchir le lien",
|
||||
"com_ui_regenerate": "Régénérer",
|
||||
"com_ui_regenerate_backup": "Régénérer les codes de sauvegarde",
|
||||
"com_ui_regenerating": "Régénération en cours...",
|
||||
"com_ui_region": "Région",
|
||||
"com_ui_rename": "Renommer",
|
||||
"com_ui_rename_conversation": "Renommer la conversation",
|
||||
"com_ui_rename_failed": "Le changement de nom de la conversation a échoué",
|
||||
"com_ui_rename_prompt": "Renommer le message",
|
||||
"com_ui_requires_auth": "Nécessite une authentification",
|
||||
"com_ui_reset_var": "Réinitialiser {{0}}",
|
||||
"com_ui_reset_zoom": "Réinitialiser le zoom",
|
||||
"com_ui_result": "Résultat",
|
||||
"com_ui_revoke": "Révoquer",
|
||||
"com_ui_revoke_info": "Révoquer toutes les informations d'identification fournies par l'utilisateur",
|
||||
|
|
@ -691,13 +937,21 @@
|
|||
"com_ui_revoke_keys": "Révoquer les clés",
|
||||
"com_ui_revoke_keys_confirm": "Êtes-vous sûr de vouloir révoquer toutes les clés ?",
|
||||
"com_ui_role_select": "Sélectionner un rôle",
|
||||
"com_ui_roleplay": "Jeu de rôle",
|
||||
"com_ui_run_code": "Exécuter le code",
|
||||
"com_ui_run_code_error": "Une erreur s'est produite lors de l'exécution du code",
|
||||
"com_ui_save": "Sauvegarder",
|
||||
"com_ui_save_badge_changes": "Sauvegarder les changements de badges ?",
|
||||
"com_ui_save_submit": "Enregistrer et Soumettre",
|
||||
"com_ui_saved": "Enregistré!",
|
||||
"com_ui_saving": "Sauvegarde en cours...",
|
||||
"com_ui_schema": "Schéma",
|
||||
"com_ui_scope": "Périmètre",
|
||||
"com_ui_search": "Rechercher",
|
||||
"com_ui_seconds": "secondes",
|
||||
"com_ui_secret_key": "Clé secrète",
|
||||
"com_ui_select": "Sélectionner",
|
||||
"com_ui_select_all": "Tout sélectionner",
|
||||
"com_ui_select_file": "Sélectionner un fichier",
|
||||
"com_ui_select_model": "Sélectionner un modèle",
|
||||
"com_ui_select_provider": "Sélectionner un fournisseur",
|
||||
|
|
@ -711,47 +965,109 @@
|
|||
"com_ui_share_create_message": "Votre nom et tout message que vous ajoutez après le partage restent privés.",
|
||||
"com_ui_share_delete_error": "Une erreur est survenue lors de la suppression du lien partagé.",
|
||||
"com_ui_share_error": "Une erreur est survenue lors du partage du lien de la discussion",
|
||||
"com_ui_share_form_description": "Partager la description du formulaire",
|
||||
"com_ui_share_link_to_chat": "Partager le lien de la discussion",
|
||||
"com_ui_share_to_all_users": "Partager à tous les utilisateurs",
|
||||
"com_ui_share_update_message": "Votre nom, les instructions personnalisées et tout message que vous ajoutez après le partage restent privés.",
|
||||
"com_ui_share_var": "Partager {{0}}",
|
||||
"com_ui_shared_link_bulk_delete_success": "Suppression réussie des liens partagés",
|
||||
"com_ui_shared_link_delete_success": "Suppression réussie du lien partagé",
|
||||
"com_ui_shared_link_not_found": "Lien partagé introuvable",
|
||||
"com_ui_shared_prompts": "Prompts partagés",
|
||||
"com_ui_shop": "Faire des achats",
|
||||
"com_ui_show": "Montrer",
|
||||
"com_ui_show_all": "Tout afficher",
|
||||
"com_ui_show_image_details": "Montrer les informations de l'image",
|
||||
"com_ui_show_qr": "Afficher le QR code",
|
||||
"com_ui_sign_in_to_domain": "S'identifier à {{0}}",
|
||||
"com_ui_simple": "Simple",
|
||||
"com_ui_size": "Taille",
|
||||
"com_ui_special_var_current_date": "Date actuelle",
|
||||
"com_ui_special_var_current_datetime": "Date et heure actuelle",
|
||||
"com_ui_special_var_current_user": "Utilisateur actuel",
|
||||
"com_ui_special_var_iso_datetime": "Date et heure ISO UTC",
|
||||
"com_ui_special_variables": "Variables spéciales : Utilisez {{current_date}} pour la date actuelle, et {{current_user}} pour le nom de votre compte donné.",
|
||||
"com_ui_special_variables_more_info": "Vous pouvez sélectionner des variables spéciales dans le menu déroulant : `{{current_date}}` (date et jour de la semaine d'aujourd'hui), `{{current_datetime}}` (date et heure locales actuelles), `{{utc_iso_datetime}}` (date et heure ISO UTC actuelle), et `{{current_user}}` (votre nom d'utilisateur).",
|
||||
"com_ui_speech_while_submitting": "Impossible de soumettre un message vocal pendant la génération d'une réponse",
|
||||
"com_ui_sr_actions_menu": "Ouvrir le menu des actions pour \"{{0}}\"",
|
||||
"com_ui_stop": "Arrêt ",
|
||||
"com_ui_storage": "Stockage",
|
||||
"com_ui_submit": "Soumettre",
|
||||
"com_ui_teach_or_explain": "Apprendre",
|
||||
"com_ui_temporary": "Message éphémère",
|
||||
"com_ui_terms_and_conditions": "Conditions d'utilisation",
|
||||
"com_ui_terms_of_service": "Conditions d'utilisation",
|
||||
"com_ui_thinking": "Réflexion en cours...",
|
||||
"com_ui_thoughts": "Pensées",
|
||||
"com_ui_token": "jeton",
|
||||
"com_ui_token_exchange_method": "Méthode d'échange de jetons",
|
||||
"com_ui_token_url": "Adresse URL du jeton",
|
||||
"com_ui_tokens": "jetons",
|
||||
"com_ui_tool_collection_prefix": "Une collection d'outils de",
|
||||
"com_ui_tool_info": "Informations sur l'outils",
|
||||
"com_ui_tool_more_info": "Plus d'informations sur cet outil",
|
||||
"com_ui_tools": "Outils",
|
||||
"com_ui_travel": "Voyage",
|
||||
"com_ui_trust_app": "J'ai confiance en cette application",
|
||||
"com_ui_unarchive": "Désarchiver",
|
||||
"com_ui_unarchive_error": "Échec du désarchivage de la conversation",
|
||||
"com_ui_unknown": "Inconnu",
|
||||
"com_ui_untitled": "Sans titre",
|
||||
"com_ui_update": "Mettre à jour",
|
||||
"com_ui_update_mcp_error": "Une erreur est survenue lors de la création ou l'actualisation du MCP.",
|
||||
"com_ui_update_mcp_success": "Création ou actualisation du MCP réussie",
|
||||
"com_ui_upload": "Téléverser",
|
||||
"com_ui_upload_code_files": "Téléverser pour l'Interpréteur de Code",
|
||||
"com_ui_upload_delay": "Le téléversement de \"{{0}}\" prend plus de temps que prévu. Veuillez patienter pendant que le fichier termine son indexation pour la récupération.",
|
||||
"com_ui_upload_error": "Une erreur s'est produite lors du téléversement de votre fichier",
|
||||
"com_ui_upload_file_context": "Téléverser le contexte du fichier",
|
||||
"com_ui_upload_file_search": "Téléverser pour la recherche de fichiers",
|
||||
"com_ui_upload_files": "Téléverser des fichiers",
|
||||
"com_ui_upload_image": "Téléverser une image",
|
||||
"com_ui_upload_image_input": "Téléverser une image",
|
||||
"com_ui_upload_invalid": "Fichier non valide pour le téléchargement. L'image ne doit pas dépasser la limite",
|
||||
"com_ui_upload_invalid_var": "Fichier non valide pour le téléchargement. L'image ne doit pas dépasser {{0}} Mo",
|
||||
"com_ui_upload_ocr_text": "Téléverser en tant que texte",
|
||||
"com_ui_upload_success": "Fichier téléversé avec succès",
|
||||
"com_ui_upload_type": "Sélectionner le type de téléversement",
|
||||
"com_ui_usage": "Utilisation",
|
||||
"com_ui_use_2fa_code": "Utiliser un code 2FA à la place",
|
||||
"com_ui_use_backup_code": "Utiliser un code de sauvegarde à la place",
|
||||
"com_ui_use_memory": "Utiliser le Souvenir",
|
||||
"com_ui_use_micrphone": "Utiliser le microphone",
|
||||
"com_ui_use_prompt": "Utiliser le prompt",
|
||||
"com_ui_used": "Déjà utilisé",
|
||||
"com_ui_value": "Valeur",
|
||||
"com_ui_variables": "Variables",
|
||||
"com_ui_variables_info": "Utilisez des doubles accolades dans votre texte pour créer des variables, par exemple {{exemple de variable}}, à remplir ultérieurement lors de l'utilisation du prompt.",
|
||||
"com_ui_verify": "Vérifier",
|
||||
"com_ui_version_var": "Version {{0}}",
|
||||
"com_ui_versions": "Versions",
|
||||
"com_ui_view_memory": "Voir le Souvenir",
|
||||
"com_ui_view_source": "Voir le message d'origine",
|
||||
"com_ui_web_search": "Recherche web",
|
||||
"com_ui_web_search_cohere_key": "Entrez la clé API de Cohere",
|
||||
"com_ui_web_search_firecrawl_url": "Adresse URL de Firecrawl (optionnel)",
|
||||
"com_ui_web_search_jina_key": "Entrez la clé API de Jina",
|
||||
"com_ui_web_search_processing": "Traitement des résultats",
|
||||
"com_ui_web_search_provider": "Fournisseur de recherches web",
|
||||
"com_ui_web_search_provider_serper": "API de Serper",
|
||||
"com_ui_web_search_provider_serper_key": "Obtenez votre clé API pour Serper",
|
||||
"com_ui_web_search_reading": "Lecture des résultats",
|
||||
"com_ui_web_search_reranker": "Classeur sémantique",
|
||||
"com_ui_web_search_reranker_cohere": "Cohere",
|
||||
"com_ui_web_search_reranker_cohere_key": "Obtenez votre clé API pour Cohere",
|
||||
"com_ui_web_search_reranker_jina": "Jina AI",
|
||||
"com_ui_web_search_reranker_jina_key": "Obtenez votre clé API pour Jina",
|
||||
"com_ui_web_search_scraper": "Extracteur (scraper)",
|
||||
"com_ui_web_search_scraper_firecrawl": "API de Firecrawl",
|
||||
"com_ui_web_search_scraper_firecrawl_key": "Obtenez votre clé API pour Firecrawl",
|
||||
"com_ui_web_searching": "Rechercher sur le web",
|
||||
"com_ui_web_searching_again": "Rechercher à nouveau sur le web",
|
||||
"com_ui_weekend_morning": "Joyeux week-end",
|
||||
"com_ui_write": "Ecriture",
|
||||
"com_ui_x_selected": "{{0}} sélectionné",
|
||||
"com_ui_yes": "Oui",
|
||||
"com_ui_zoom": "Zoom",
|
||||
"com_user_message": "Vous",
|
||||
"com_warning_resubmit_unsupported": "La resoumission du message IA n'est pas prise en charge pour ce point de terminaison."
|
||||
"com_user_message": "Vous"
|
||||
}
|
||||
|
|
@ -17,10 +17,18 @@
|
|||
"com_agents_file_search_disabled": "יש ליצור את הסוכן לפני העלאת קבצים לחיפוש",
|
||||
"com_agents_file_search_info": "כאשר הסוכן מופעל הוא יקבל מידע על שמות הקבצים המפורטים להלן, כדי שהוא יוכל לאחזר את הקשר רלוונטי.",
|
||||
"com_agents_instructions_placeholder": "הוראות המערכת שבהן ישתמש הסוכן",
|
||||
"com_agents_mcp_description_placeholder": "הסבר בכמה מילים מה זה אמור לעשות",
|
||||
"com_agents_mcp_icon_size": "הגודל המינמלי הוא 128 x 128 פיקסלים",
|
||||
"com_agents_mcp_info": "הוסף לסוכן שרתי MCP כדי לאפשר לו לבצע משימות ולקיים אינטראקציות עם שירותים חיצוניים",
|
||||
"com_agents_mcp_name_placeholder": "כלי מותאם אישית",
|
||||
"com_agents_mcp_trust_subtext": "המחברים המותאמים אישית אינם מאומתים על ידי LibreChat",
|
||||
"com_agents_mcps_disabled": "עליך ליצור סוכן לפני הוספת שרתי MCP",
|
||||
"com_agents_missing_provider_model": "אנא בחר את הספק ואת הדגם לפני יצירת הסוכן.",
|
||||
"com_agents_name_placeholder": "אופציונלי: שם הסוכן",
|
||||
"com_agents_no_access": "אין לך גישה לערוך את הסוכן הזה.",
|
||||
"com_agents_no_agent_id_error": "לא נמצא מזהה סוכן. אנא ודא שהסוכן נוצר תחילה",
|
||||
"com_agents_not_available": "הסוכן לא זמין",
|
||||
"com_agents_search_info": "כאשר אפשרות זו מופעלת, היא מאפשרת לסוכן שלך לחפש מידע עדכני באינטרנט. נדרש מפתח API תקף.",
|
||||
"com_agents_search_name": "חפש סוכן לפי שם",
|
||||
"com_agents_update_error": "אירעה שגיאה בעדכון הסוכן שלך.",
|
||||
"com_assistants_action_attempt": "הסוכן מעוניין לתקשר עם {{0}}",
|
||||
|
|
@ -61,6 +69,7 @@
|
|||
"com_assistants_non_retrieval_model": "חיפוש בקבצים אינו מופעל במודל הזה. אנא בחר מודל אחר",
|
||||
"com_assistants_retrieval": "אחזור",
|
||||
"com_assistants_running_action": "פעולות ריצה",
|
||||
"com_assistants_running_var": "{{0}} בריצה",
|
||||
"com_assistants_search_name": "חפש סייען לפי שם",
|
||||
"com_assistants_update_actions_error": "אירעה שגיאה ביצירה או העדכון של הפעולה.",
|
||||
"com_assistants_update_actions_success": "הפעולה נוצרה או עודכנה בהצלחה",
|
||||
|
|
@ -122,6 +131,7 @@
|
|||
"com_auth_reset_password_if_email_exists": "אם קיים חשבון עם דוא\"ל זה, נשלח דוא\"ל עם הוראות לאיפוס סיסמה. אנא הקפד לבדוק גם בתיקיית הספאם שלך.",
|
||||
"com_auth_reset_password_link_sent": "אימייל (דוא\"ל) נשלח",
|
||||
"com_auth_reset_password_success": "איפוס סיסמה הצליח",
|
||||
"com_auth_saml_login": "המשך עם SAML",
|
||||
"com_auth_sign_in": "כניסה",
|
||||
"com_auth_sign_up": "הירשם",
|
||||
"com_auth_submit_registration": "שלח רישום",
|
||||
|
|
@ -133,6 +143,8 @@
|
|||
"com_auth_username_min_length": "שם משתמש חייב להיות לפחות 2 תווים",
|
||||
"com_auth_verify_your_identity": "אמת את הזהות שלך",
|
||||
"com_auth_welcome_back": "ברוכים הבאים",
|
||||
"com_citation_more_details": "פרטים נוספים על {{label}}",
|
||||
"com_citation_source": "מקור",
|
||||
"com_click_to_download": "(לחץ כאן להורדה)",
|
||||
"com_download_expired": "(פג תוקף ההורדה)",
|
||||
"com_download_expires": "(לחץ כאן כדי להוריד - יפוג בעוד {{0}}) ",
|
||||
|
|
@ -193,8 +205,11 @@
|
|||
"com_endpoint_google_custom_name_placeholder": "הגדר שם מותאם אישית עבור Google",
|
||||
"com_endpoint_google_maxoutputtokens": " המספר המרבי של אסימונים שניתן להפיק בתגובה. ציין ערך נמוך יותר עבור תגובות קצרות יותר וערך גבוה יותר עבור תגובות ארוכות יותר.",
|
||||
"com_endpoint_google_temp": "ערכים גבוהים יותר = יותר אקראיים, בעוד שערכים נמוכים יותר = יותר ממוקד ודטרמיניסטי. אנו ממליצים לשנות את זה או את Top P אבל לא את שניהם.",
|
||||
"com_endpoint_google_thinking": "מאפשר או מבטל את החשיבה. הגדרה זו נתמכת רק על ידי דגמים מסוימים (סדרה 2.5). עבור דגמים ישנים יותר, ייתכן שלהגדרה זו לא תהיה השפעה.",
|
||||
"com_endpoint_google_thinking_budget": "מנחה את מספר טוקני החשיבה שהמודל משתמש בהם. הכמות בפועל עלולה לחרוג או להיות נמוכה מערך זה בהתאם לפרומפט.\n\nהגדרה זו נתמכת רק על ידי מודלים מסוימים (סדרת 2.5). Gemini 2.5 Pro תומך ב-128-32,768 טוקנים. Gemini 2.5 Flash תומך ב-0-24,576 טוקנים. Gemini 2.5 Flash Lite תומך ב-512-24,576 טוקנים.\n\nהשאירו ריק או הגדירו ל-\"-1\" כדי לאפשר למודל להחליט באופן אוטומטי מתי וכמה לחשוב. כברירת מחדל, Gemini 2.5 Flash Lite לא חושב.",
|
||||
"com_endpoint_google_topk": "Top-k משנה את האופן שבו המודל בוחר אסימונים לפלט. Top-k של 1 פירושו שהאסימון שנבחר הוא הסביר ביותר מבין כל האסימונים באוצר המילים של הדגם (נקרא גם פענוח חמדן), בעוד ש-top-k של 3 פירושו שהאסימון הבא נבחר מבין 3 הכי הרבה. אסימונים סבירים (באמצעות טמפרטורה).",
|
||||
"com_endpoint_google_topp": "Top-p משנה את האופן שבו המודל בוחר אסימונים לפלט. אסימונים נבחרים מרוב K (ראה פרמטר topK) ככל הנראה לפחות עד ה-sum של ההסתברויות שלהם שווה לערך ה-p העליון.",
|
||||
"com_endpoint_google_use_search_grounding": "השתמשו בחיפוש גוגל כדי לשפר את התגובות עם תוצאות חיפוש בזמן אמת. זה מאפשר למודלים לגשת למידע עדכני ולספק תשובות מדויקות ועדכניות יותר",
|
||||
"com_endpoint_instructions_assistants": "עקוף הוראות",
|
||||
"com_endpoint_instructions_assistants_placeholder": "עובר את הוראות הסייען. זה שימושי לשינוי ההתנהגות על בסיס ריצה.",
|
||||
"com_endpoint_max_output_tokens": "אסימוני פלט מרבי",
|
||||
|
|
@ -211,7 +226,8 @@
|
|||
"com_endpoint_openai_max_tokens": "שדה 'max_tokens' אופציונלי, הוא מייצג את המספר המרבי של טוקנים שניתן ליצור בהשלמת הצ'אט. האורך הכולל של טוקני קלט והטוקנים שנוצרו מוגבל על ידי אורך ההקשר של המודל. אתה עלול להיתקל בשגיאות אם המספר הזה חורג מטוקני ההקשר המקסימליים.",
|
||||
"com_endpoint_openai_pres": "מספר בין -2.0 ל-2.0. ערכים חיוביים מענישים אסימונים חדשים על סמך האם הם מופיעים בטקסט עד כה, ומגדילים את הסבירות של המודל לדבר על נושאים חדשים.",
|
||||
"com_endpoint_openai_prompt_prefix_placeholder": "הגדר הוראות מותאמות אישית לכלול בהודעת המערכת. ברירת מחדל: אין",
|
||||
"com_endpoint_openai_reasoning_effort": "במודלים o1 בלבד: מגביל את מאמץ ההנמקה במודלים של הגיון. הפחתת מאמץ החשיבה יכולה לגרום לתגובות מהירות יותר ולפחות טוקנים בשימוש בהנמקה בתגובה.",
|
||||
"com_endpoint_openai_reasoning_effort": "במודלים o1 ו-o3 בלבד: מגביל את מאמץ ההנמקה במודלים של הגיון. הפחתת מאמץ החשיבה יכולה לגרום לתגובות מהירות יותר ולפחות טוקנים בשימוש בהנמקה בתגובה.",
|
||||
"com_endpoint_openai_reasoning_summary": "Responses API בלבד: סיכום של החשיבה שבוצעה על ידי המודל. זה יכול להיות שימושי לאיתור שגיאות ולהבנת תהליך החשיבה של המודל. אפשרויות הגדרה: ללא, אוטומטי, תמציתי, מפורט.",
|
||||
"com_endpoint_openai_resend": "שלח שוב את כל התמונות שצורפו בעבר. הערה: זה יכול להגדיל משמעותית את עלות האסימונים ואתה עלול להיתקל בשגיאות עם קבצים מצורפים רבים של תמונות.",
|
||||
"com_endpoint_openai_resend_files": "שלח שוב את כל הקבצים שצורפו בעבר. הערה: זה יגדיל את עלות הטוקנים, ואתה עלול להיתקל בשגיאות עם קבצים מצורפים רבים.",
|
||||
"com_endpoint_openai_stop": "עד 4 רצפים שבהם ה-API יפסיק לייצר טוקנים נוספים.",
|
||||
|
|
@ -270,7 +286,8 @@
|
|||
"com_error_files_upload": "אירעה שגיאה בעת העלאת הקובץ",
|
||||
"com_error_files_upload_canceled": "בקשת העלאת הקובץ בוטלה. הערה: ייתכן שהעלאת הקובץ עדיין בעיבוד ותצטרך למחוק אותו בצורה ידנית.",
|
||||
"com_error_files_validation": "אירעה שגיאה במהלך אימות הקובץ.",
|
||||
"com_error_input_length": "מספר הטוקנים של ההודעות האחרונות גבוה מדי, והוא חורג ממגבלת האסימונים ({{0}} בהתאמה). אנא קצר את ההודעה שלך, שנה את גודל ההקשר המקסימלי בפרמטרי השיחה, או התחל שיחה חדשה.",
|
||||
"com_error_heic_conversion": "המרת התמונה בפורמט HEIC לפורמט JPEG נכשלה. אנא נסה להמיר את התמונה ידנית או להשתמש בפורמט אחר.",
|
||||
"com_error_input_length": "מספר הטוקנים של ההודעות האחרונות גבוה מדי, והוא חורג ממגבלת האסימונים ({{0}} בהתאמה. אנא קצר את ההודעה שלך, שנה את גודל ההקשר המקסימלי בפרמטרי השיחה, או התחל שיחה חדשה.",
|
||||
"com_error_invalid_agent_provider": "המודלים של \"{{0}}\" אינם זמינים לשימוש עם סוכנים. אנא עבור להגדרות הסוכן שלך ובחר ספק הזמין כרגע.",
|
||||
"com_error_invalid_user_key": "מפתח שסופק אינו חוקי. אנא ספק מפתח חוקי ונסה שוב.",
|
||||
"com_error_moderation": "נראה שהתוכן שנשלח סומן על ידי מערכת הניהול שלנו בגלל שהוא אינו תואם את הנחיות הקהילה שלנו. אנחנו לא יכולים להמשיך עם הנושא הספציפי הזה. אם יש לך שאלות או נושאים אחרים שתרצה לחקור, אנא ערוך את ההודעה שלך, או צור שיחה חדשה.",
|
||||
|
|
@ -282,29 +299,51 @@
|
|||
"com_files_table": "השדה חייב להכיל תוכן, הוא אינו יכול להישאר ריק",
|
||||
"com_generated_files": "קבצים שנוצרו:",
|
||||
"com_hide_examples": "הסתר דוגמאות",
|
||||
"com_info_heic_converting": "המרת התמונה מפורמט HEIC לפורמט JPEG...",
|
||||
"com_nav_2fa": "אימות דו-שלבי (2FA)",
|
||||
"com_nav_account_settings": "הגדרות חשבון",
|
||||
"com_nav_always_make_prod": "ייצר תמיד גרסאות חדשות",
|
||||
"com_nav_archive_created_at": "תאריך ייצור",
|
||||
"com_nav_archive_name": "שם",
|
||||
"com_nav_archived_chats": "שיחות מארכיון",
|
||||
"com_nav_archived_chats": "שיחות בארכיון",
|
||||
"com_nav_at_command": "@-פקודה",
|
||||
"com_nav_at_command_description": "הפקודה \"@\" משמשת כמנגנון הפעלה/החלפה של נקודות קצה, מודלים, הגדרות קבועות מראש וכו'.",
|
||||
"com_nav_audio_play_error": "שגיאה בהפעלת אודיו: {{0}}",
|
||||
"com_nav_audio_process_error": "שגיאה בעיבוד האודיו: {{0}}",
|
||||
"com_nav_auto_scroll": "Auto-s גלול אל הכי חדש בפתיחה",
|
||||
"com_nav_auto_scroll": "בפתיחת צ׳אט גלול אוטומטית להודעה האחרונה",
|
||||
"com_nav_auto_send_prompts": "שליחת הנחיות (פרומפטים) אוטומטית",
|
||||
"com_nav_auto_send_text": "טקסט לשליחה אוטומטית",
|
||||
"com_nav_auto_send_text_disabled": "הגדר -1 כדי להשבית",
|
||||
"com_nav_auto_transcribe_audio": "תמלול אוטומטי של אודיו",
|
||||
"com_nav_automatic_playback": "הפעלה אוטומטית של ההודעה האחרונה",
|
||||
"com_nav_balance": "לְאַזֵן",
|
||||
"com_nav_balance_auto_refill_disabled": "מילוי אוטומטי מושבת",
|
||||
"com_nav_balance_auto_refill_error": "שגיאה בטעינת הגדרות המילוי האוטומטי",
|
||||
"com_nav_balance_auto_refill_settings": "הגדרות מילוי אוטומטי",
|
||||
"com_nav_balance_day": "יום",
|
||||
"com_nav_balance_days": "ימי",
|
||||
"com_nav_balance_every": "כל",
|
||||
"com_nav_balance_hour": "שעה",
|
||||
"com_nav_balance_hours": "שעות",
|
||||
"com_nav_balance_interval": "מרווח זמן",
|
||||
"com_nav_balance_last_refill": "מילוי אחרון:",
|
||||
"com_nav_balance_minute": "דקה",
|
||||
"com_nav_balance_minutes": "דקות",
|
||||
"com_nav_balance_month": "חודש",
|
||||
"com_nav_balance_months": "חודשים",
|
||||
"com_nav_balance_next_refill": "המילוי הבא:",
|
||||
"com_nav_balance_next_refill_info": "המילוי הבא יתרחש אוטומטית רק כאשר שני התנאים הבאים יתקיימו: מרווח הזמן שנקבע חלף מאז המילוי האחרון, ושליחת בקשה תגרום ליתרה שלך לרדת מתחת לאפס.",
|
||||
"com_nav_balance_refill_amount": "סכום המילוי:",
|
||||
"com_nav_balance_second": "שניה",
|
||||
"com_nav_balance_seconds": "שניות",
|
||||
"com_nav_balance_week": "שבוע",
|
||||
"com_nav_balance_weeks": "שבועות",
|
||||
"com_nav_browser": "דפדפן",
|
||||
"com_nav_center_chat_input": "מרכז תיבת הצ'אט במסך הברוכים הבאים",
|
||||
"com_nav_center_chat_input": "מרכז תיבת הצ'אט במסך ברוכים הבאים",
|
||||
"com_nav_change_picture": "שנה תמונה",
|
||||
"com_nav_chat_commands": "פקודות צ'אט",
|
||||
"com_nav_chat_commands_info": "פקודות אלו מופעלות על ידי הקלדת תווים ספציפיים בתחילת ההודעה. כל פקודה מופעלת על ידי הקידומת המיועדת לה. אתה יכול להשבית אותם אם אתה משתמש בתווים אלה לעתים קרובות כדי להתחיל הודעות.",
|
||||
"com_nav_chat_direction": "כיוונון צ'אט",
|
||||
"com_nav_chat_direction": "כיוון הכתיבה",
|
||||
"com_nav_clear_all_chats": "נקה את כל השיחות",
|
||||
"com_nav_clear_cache_confirm_message": "האם אתה בטוח שברצונך לנקות את המטמון?",
|
||||
"com_nav_clear_conversation": "נקה שיחות",
|
||||
|
|
@ -322,7 +361,6 @@
|
|||
"com_nav_delete_cache_storage": "מחק אחסון מטמון TTS",
|
||||
"com_nav_delete_data_info": "כל הנתונים שלך יימחקו",
|
||||
"com_nav_delete_warning": "אזהרה: פעולה זו תמחק לצמיתות את חשבונך.",
|
||||
"com_nav_edit_chat_badges": "עריכת תוויות צ'אט",
|
||||
"com_nav_enable_cache_tts": "אפשר מטמון ב- TTS",
|
||||
"com_nav_enable_cloud_browser_voice": "השתמש בקולות מבוססי ענן",
|
||||
"com_nav_enabled": "מופעל",
|
||||
|
|
@ -345,7 +383,8 @@
|
|||
"com_nav_font_size_xl": "גדול מאוד",
|
||||
"com_nav_font_size_xs": "קט מאוד",
|
||||
"com_nav_help_faq": "עזרה ושאלות נפוצות",
|
||||
"com_nav_hide_panel": "הסתר לוח הצד הימני ביותר",
|
||||
"com_nav_hide_panel": "הסתר את לוח הצד הימני",
|
||||
"com_nav_info_balance": "היתרה מראה כמה קרדיטים של אסימונים (טוקנים) נותרו לך להשתמש. זיכויים של אסימונים מתורגמים לערך כספי (לדוגמה, 1000 זיכויים = $0.001 USD)",
|
||||
"com_nav_info_code_artifacts": "אפשר הצגה של רכיבי תצוגת קוד ניסיוניים לצד הצ'אט",
|
||||
"com_nav_info_code_artifacts_agent": "אפשר שימוש ברכיבי תצוגת קוד עבור סוכן זה כברירת מחדל, מתווספות הוראות נוספות ספציפיות לשימוש ברכיבי התצוגה אלא אם \"מצב הנחיה מותאם אישית\" מופעל.",
|
||||
"com_nav_info_custom_prompt_mode": "כאשר אפשרות זו מופעלת, הנחיית ברירת המחדל של מערכת רכיבי תצוגה לא תיכלל. כל ההוראות ליצירת רכיבי תצוגה יהיו חייבות להינתן באופן ידני במצב זה.",
|
||||
|
|
@ -390,6 +429,8 @@
|
|||
"com_nav_log_out": "צא",
|
||||
"com_nav_long_audio_warning": "העיבוד של טקסטים ארוכים ייקח יותר זמן.",
|
||||
"com_nav_maximize_chat_space": "הגדל את שטח הצ'אט",
|
||||
"com_nav_mcp_vars_update_error": "שגיאה בעדכון משתני משתמש מותאמים אישית של MCP: {{0}}",
|
||||
"com_nav_mcp_vars_updated": "משתני משתמש מותאמים אישית של MCP עודכנו בהצלחה.",
|
||||
"com_nav_modular_chat": "אפשר החלפת נקודות קצה באמצע שיחה",
|
||||
"com_nav_my_files": "הקבצים שלי",
|
||||
"com_nav_not_supported": "לא נתמך",
|
||||
|
|
@ -404,15 +445,18 @@
|
|||
"com_nav_plus_command_description": "הפעל או בטל את הפקודה '+' כדי להוסיף הגדרת תגובות מרובות",
|
||||
"com_nav_profile_picture": "תמונת פרופיל",
|
||||
"com_nav_save_badges_state": "שמור מצב תגים",
|
||||
"com_nav_save_drafts": "שמיר את האפצה באותו מחשב",
|
||||
"com_nav_save_drafts": "שמור טיוטות באופן מקומי",
|
||||
"com_nav_scroll_button": "לחצן לגלילה עד הסוף",
|
||||
"com_nav_search_placeholder": "חפש הודעות",
|
||||
"com_nav_send_message": "שלח הודעה",
|
||||
"com_nav_setting_account": "חשבון",
|
||||
"com_nav_setting_balance": "לאזן",
|
||||
"com_nav_setting_beta": "תכונות ביטא",
|
||||
"com_nav_setting_chat": "צ'אט",
|
||||
"com_nav_setting_data": "בקרות נתונים",
|
||||
"com_nav_setting_general": "כללי",
|
||||
"com_nav_setting_mcp": "הגדרות MCP",
|
||||
"com_nav_setting_personalization": "התאמה אישית",
|
||||
"com_nav_setting_speech": "דיבור",
|
||||
"com_nav_settings": "הגדרות",
|
||||
"com_nav_shared_links": "קישורים משותפים",
|
||||
|
|
@ -423,7 +467,7 @@
|
|||
"com_nav_speech_to_text": "דיבור לטקסט",
|
||||
"com_nav_stop_generating": "עצור את היצירה",
|
||||
"com_nav_text_to_speech": "טקסט לדיבור",
|
||||
"com_nav_theme": "נושא",
|
||||
"com_nav_theme": "ערכת נושא (בהיר/כהה)",
|
||||
"com_nav_theme_dark": "כהה",
|
||||
"com_nav_theme_light": "אור",
|
||||
"com_nav_theme_system": "מערכת",
|
||||
|
|
@ -433,7 +477,7 @@
|
|||
"com_nav_tool_remove": "הסר",
|
||||
"com_nav_tool_search": "כלי חיפוש",
|
||||
"com_nav_user": "משתמש",
|
||||
"com_nav_user_msg_markdown": "הצגת הודעות משתמש כ-Markdown",
|
||||
"com_nav_user_msg_markdown": "הצגת הודעות משתמש כמרקדאון (Markdown)",
|
||||
"com_nav_user_name_display": "הצג שם משתמש בהודעות",
|
||||
"com_nav_voice_select": "קול",
|
||||
"com_show_agent_settings": "הצג הגדרות סוכן",
|
||||
|
|
@ -445,7 +489,16 @@
|
|||
"com_sidepanel_conversation_tags": "סימניות",
|
||||
"com_sidepanel_hide_panel": "הסתר פאנל",
|
||||
"com_sidepanel_manage_files": "נהל קבצים",
|
||||
"com_sidepanel_mcp_enter_value": "הזן ערך עבור {{0}}",
|
||||
"com_sidepanel_mcp_no_servers_with_vars": "אין שרתי MCP עם משתנים הניתנים להגדרה.",
|
||||
"com_sidepanel_mcp_variables_for": "משתני MCP עבור {{0}}",
|
||||
"com_sidepanel_parameters": "פרמטרים",
|
||||
"com_sources_image_alt": "תמונת תוצאות החיפוש",
|
||||
"com_sources_more_sources": "+{{count}}} מקורות",
|
||||
"com_sources_tab_all": "הכל",
|
||||
"com_sources_tab_images": "תמונות",
|
||||
"com_sources_tab_news": "חדשות",
|
||||
"com_sources_title": "מקורות",
|
||||
"com_ui_2fa_account_security": "אימות דו-שלבי מוסיף שכבת אבטחה נוספת לחשבון שלך",
|
||||
"com_ui_2fa_disable": "השבת אימות דו-שלבי (2FA)",
|
||||
"com_ui_2fa_disable_error": "התרחשה שגיאה בעת ביטול האימות הדו-שלבי",
|
||||
|
|
@ -457,9 +510,13 @@
|
|||
"com_ui_2fa_setup": "הגדר אימות דו-שלבי (2FA)",
|
||||
"com_ui_2fa_verified": "האימות הדו-שלבי אומת בהצלחה",
|
||||
"com_ui_accept": "אני מקבל",
|
||||
"com_ui_action_button": "לחצן פעולה",
|
||||
"com_ui_add": "הוסף",
|
||||
"com_ui_add_mcp": "הוסף MCP",
|
||||
"com_ui_add_mcp_server": "הוסף שרת MCP",
|
||||
"com_ui_add_model_preset": "הוספת מודל או הגדרה קבועה לתגובה נוספת",
|
||||
"com_ui_add_multi_conversation": "הוספת תמיכה בשיחות מרובות",
|
||||
"com_ui_adding_details": "הוספת פרטים",
|
||||
"com_ui_admin": "אדמין",
|
||||
"com_ui_admin_access_warning": "השבתת גישת המנהל לתכונה זו עלולה לגרום לבעיות בלתי צפויות בממשק המשתמש שידרשו רענון. אם השינוי נשמר, הדרך היחידה להחזיר את ההגדרה היא דרך הגדרת הממשק בקובץ librechat.yaml, שמשפיעה על כל התפקידים.",
|
||||
"com_ui_admin_settings": "הגדרות אדמין",
|
||||
|
|
@ -478,6 +535,20 @@
|
|||
"com_ui_agent_recursion_limit_info": "מגביל את מספר השלבים שהסוכן יכול לבצע בריצה לפני מתן תגובה סופית. ברירת המחדל היא 25 שלבים. שלב הוא בקשת API של בינה מלאכותית או סבב שימוש בכלי. לדוגמה, אינטראקציה בסיסית עם כלי לוקחת 3 שלבים: בקשה ראשונית, שימוש בכלי, ובקשת המשך.",
|
||||
"com_ui_agent_shared_to_all": "השדה חייב להכיל תוכן, אי אפשר להשאיר אותו ריק",
|
||||
"com_ui_agent_var": "{{0}} סוכנים",
|
||||
"com_ui_agent_version": "גרסה",
|
||||
"com_ui_agent_version_active": "גרסת הפעלה",
|
||||
"com_ui_agent_version_duplicate": "זוהתה גרסה כפולה, פעולה זו תיצור גרסה זהה לגרסה {{versionIndex}}.",
|
||||
"com_ui_agent_version_empty": "אין גרסאות זמינות",
|
||||
"com_ui_agent_version_error": "שגיאה באחזור גרסאות",
|
||||
"com_ui_agent_version_history": "היסטוריית גרסאות",
|
||||
"com_ui_agent_version_no_agent": "לא נבחר סוכן. אנא בחר סוכן כדי להציג את היסטוריית הגרסאות.",
|
||||
"com_ui_agent_version_no_date": "תאריך לא זמין",
|
||||
"com_ui_agent_version_restore": "לשחזר",
|
||||
"com_ui_agent_version_restore_confirm": "האם אתה בטוח שברצונך לשחזר גרסה זו?",
|
||||
"com_ui_agent_version_restore_error": "שחזור הגרסה נכשל",
|
||||
"com_ui_agent_version_restore_success": "הגרסה שוחזרה בהצלחה",
|
||||
"com_ui_agent_version_title": "גרסה {{versionNumber}}",
|
||||
"com_ui_agent_version_unknown_date": "תאריך לא ידוע",
|
||||
"com_ui_agents": "סוכנים",
|
||||
"com_ui_agents_allow_create": "אפשר יצירת סוכנים",
|
||||
"com_ui_agents_allow_share_global": "אפשר שיתוף סוכנים לכל המשתמשים",
|
||||
|
|
@ -487,7 +558,7 @@
|
|||
"com_ui_analyzing": "ניתוח",
|
||||
"com_ui_analyzing_finished": "סיים ניתוח",
|
||||
"com_ui_api_key": "מפתח API",
|
||||
"com_ui_archive": "ארכיון",
|
||||
"com_ui_archive": "לארכיון",
|
||||
"com_ui_archive_delete_error": "מחיקת השיחה מהארכיון נכשלה",
|
||||
"com_ui_archive_error": "אירעה שגיאה באירכוב השיחה",
|
||||
"com_ui_artifact_click": "לחץ לפתיחה",
|
||||
|
|
@ -504,14 +575,17 @@
|
|||
"com_ui_attach_error_openai": "לא ניתן לצרף את קבצי הסייען לנקודות קצה אחרות",
|
||||
"com_ui_attach_error_size": "חרגת ממגבלת גודל הקובץ עבור נקודת הקצה:",
|
||||
"com_ui_attach_error_type": "סוג קובץ לא נתמך עבור נקודת קצה:",
|
||||
"com_ui_attach_remove": "הסר קובץ",
|
||||
"com_ui_attach_remove": "הסר את הקובץ",
|
||||
"com_ui_attach_warn_endpoint": "עשוי להתעלם מקבצים שאינם של הסייען שאין להם כלי תואם",
|
||||
"com_ui_attachment": "קובץ מצורף",
|
||||
"com_ui_auth_type": "סוג אישור",
|
||||
"com_ui_auth_url": "כתובת URL לאימות הרשאה",
|
||||
"com_ui_authentication": "אימות",
|
||||
"com_ui_authentication_type": "סוג אימות",
|
||||
"com_ui_auto": "אוטומטי",
|
||||
"com_ui_available_tools": "כלים זמינים",
|
||||
"com_ui_avatar": "אווטאר",
|
||||
"com_ui_back": "חזור",
|
||||
"com_ui_back_to_chat": "חזור לצ'אט",
|
||||
"com_ui_back_to_prompts": "חזור להנחיות (פרומפטים)",
|
||||
"com_ui_backup_codes": "קודי גיבוי",
|
||||
|
|
@ -541,6 +615,7 @@
|
|||
"com_ui_bulk_delete_error": "מחיקת קישורים משותפים נכשלה",
|
||||
"com_ui_callback_url": "כתובת URL להחזרת המידע",
|
||||
"com_ui_cancel": "בטל",
|
||||
"com_ui_cancelled": "בוטל",
|
||||
"com_ui_category": "קָטֵגוֹרִיָה",
|
||||
"com_ui_chat": "צ'אט",
|
||||
"com_ui_chat_history": "נקה היסטוריה",
|
||||
|
|
@ -550,11 +625,13 @@
|
|||
"com_ui_client_secret": "ב",
|
||||
"com_ui_close": "סגור",
|
||||
"com_ui_close_menu": "סגור תפריט",
|
||||
"com_ui_close_window": "סגור חלון",
|
||||
"com_ui_code": "קוד",
|
||||
"com_ui_collapse_chat": "כווץ צ'אט",
|
||||
"com_ui_command_placeholder": "אופציונלי: הזן פקודה להנחיה (פרומפט), או שיעשה שימוש בשם",
|
||||
"com_ui_command_usage_placeholder": "בחר הנחיה (פרומפט) לפי פקודה או שם",
|
||||
"com_ui_complete_setup": "ההגדרה הושלמה",
|
||||
"com_ui_configure_mcp_variables_for": "הגדרת משתנים עבור {{0}}",
|
||||
"com_ui_confirm_action": "אשר פעולה",
|
||||
"com_ui_confirm_admin_use_change": "שינוי הגדרה זו יחסום גישה למנהלים, כולל אותך. האם אתה בטוח שברצונך להמשיך?",
|
||||
"com_ui_confirm_change": "אשר את השינוי",
|
||||
|
|
@ -569,7 +646,10 @@
|
|||
"com_ui_copy_to_clipboard": "העתק ללוח",
|
||||
"com_ui_create": "צור",
|
||||
"com_ui_create_link": "צור קישור",
|
||||
"com_ui_create_memory": "צור זכרון",
|
||||
"com_ui_create_prompt": "צור הנחיה (פרומפט)",
|
||||
"com_ui_creating_image": "יוצר תמונה. ייתכן שייקח מספר רגעים.",
|
||||
"com_ui_current": "נוכחי",
|
||||
"com_ui_currently_production": "נוצר עכשיו",
|
||||
"com_ui_custom": "מותאם אישית",
|
||||
"com_ui_custom_header_name": "שם כותרת מותאם אישית",
|
||||
|
|
@ -602,13 +682,20 @@
|
|||
"com_ui_delete_confirm": "זה ימחק",
|
||||
"com_ui_delete_confirm_prompt_version_var": "פעולה זו תמחק את הגרסה שנבחרה עבור \"{{0}}\". אם לא קיימות גרסאות נוספות, ההנחיה תימחק.",
|
||||
"com_ui_delete_conversation": "למחוק את השיחה (צאט)?",
|
||||
"com_ui_delete_mcp": "מחק MCP",
|
||||
"com_ui_delete_mcp_confirm": "האם אתה בטוח שברצונך למחוק את שרת ה-MCP הזה?",
|
||||
"com_ui_delete_mcp_error": "מחיקת שרת MCP נכשלה",
|
||||
"com_ui_delete_mcp_success": "שרת ה-MCP נמחק בהצלחה",
|
||||
"com_ui_delete_memory": "מחק זיכרון",
|
||||
"com_ui_delete_prompt": "מחק הנחיה (פרומפט)",
|
||||
"com_ui_delete_shared_link": "מחק קישור שיתוף",
|
||||
"com_ui_delete_tool": "מחק כלי",
|
||||
"com_ui_delete_tool_confirm": "האת אתה בטוח שאתה רוצה למחוק את הכלי הזה?",
|
||||
"com_ui_deleted": "נמחק",
|
||||
"com_ui_descending": "תיאור",
|
||||
"com_ui_description": "תיאור",
|
||||
"com_ui_description_placeholder": "אופציונלי: הזן תיאור שיוצג עבור ההנחיה (פרומפט)",
|
||||
"com_ui_deselect_all": "בטל את הבחירה של הכל",
|
||||
"com_ui_disabling": "מבטל הפעלה...",
|
||||
"com_ui_download": "הורדות",
|
||||
"com_ui_download_artifact": "רכיב תצוגת הורדות",
|
||||
|
|
@ -623,21 +710,46 @@
|
|||
"com_ui_duplication_processing": "משכפל את השיחה...",
|
||||
"com_ui_duplication_success": "השיחה שוכפלה בהצלחה",
|
||||
"com_ui_edit": "ערוך",
|
||||
"com_ui_edit_editing_image": "עורך את התמונה",
|
||||
"com_ui_edit_mcp_server": "עריכת שרת MCP",
|
||||
"com_ui_edit_memory": "ערוך זכרון",
|
||||
"com_ui_empty_category": "-",
|
||||
"com_ui_endpoint": "נקודת קצה",
|
||||
"com_ui_endpoint_menu": "תפריט נקודת קצה LLM",
|
||||
"com_ui_enter": "Enter",
|
||||
"com_ui_enter_api_key": "הכנס מפתח API",
|
||||
"com_ui_enter_key": "מקש Enter",
|
||||
"com_ui_enter_openapi_schema": "הזן כאן את סכימת OpenAPI שלך",
|
||||
"com_ui_enter_value": "הזן ערך",
|
||||
"com_ui_error": "שגיאה",
|
||||
"com_ui_error_connection": "שגיאה בחיבור לשרת, נסה לרענן את הדף",
|
||||
"com_ui_error_save_admin_settings": "אירעה שגיאה בשמירת הגדרות הניהול שלך",
|
||||
"com_ui_error_updating_preferences": "אירעה שגיאה בעדכון העדפות",
|
||||
"com_ui_examples": "דוגמאות",
|
||||
"com_ui_expand_chat": "הרחב צ'אט",
|
||||
"com_ui_export_convo_modal": "חלון ייצוא שיחה",
|
||||
"com_ui_feedback_more": "יותר...",
|
||||
"com_ui_feedback_more_information": "ספק משוב נוסף",
|
||||
"com_ui_feedback_negative": "טעון שיפור",
|
||||
"com_ui_feedback_placeholder": "אנא ספק כאן כל משוב נוסף",
|
||||
"com_ui_feedback_positive": "אוהב את זה",
|
||||
"com_ui_feedback_tag_accurate_reliable": "מדויק ואמין",
|
||||
"com_ui_feedback_tag_attention_to_detail": "תשומת לב לפרטים",
|
||||
"com_ui_feedback_tag_bad_style": "סגנון גרוע",
|
||||
"com_ui_feedback_tag_clear_well_written": "כתוב ברור ומדויק",
|
||||
"com_ui_feedback_tag_creative_solution": "פתרון יצירתי",
|
||||
"com_ui_feedback_tag_inaccurate": "תשובה לא מדויקת או שגויה",
|
||||
"com_ui_feedback_tag_missing_image": "ציפיתי לתמונה",
|
||||
"com_ui_feedback_tag_not_helpful": "חסר מידע שימושי",
|
||||
"com_ui_feedback_tag_not_matched": "לא מתאים לבקשה שלי",
|
||||
"com_ui_feedback_tag_other": "בעיות אחרות",
|
||||
"com_ui_feedback_tag_unjustified_refusal": "סורב ללא סיבה",
|
||||
"com_ui_field_required": "שדה זה נדרש",
|
||||
"com_ui_file_size": "גודל הקובץ",
|
||||
"com_ui_files": "קבצים",
|
||||
"com_ui_filter_prompts": "סינון הנחיות (פרומפטים)",
|
||||
"com_ui_filter_prompts_name": "סינון הנחיות (פרומפטים) לפי שם",
|
||||
"com_ui_final_touch": "גימור סופי",
|
||||
"com_ui_finance": "פיננסי",
|
||||
"com_ui_fork": "הסתעפות",
|
||||
"com_ui_fork_all_target": "כלול את כל ההודעות שנשלחו/התקבלו מכאן.",
|
||||
|
|
@ -667,6 +779,8 @@
|
|||
"com_ui_generate_backup": "צור קודי גיבוי",
|
||||
"com_ui_generate_qrcode": "צור קוד QR",
|
||||
"com_ui_generating": "יוצר...",
|
||||
"com_ui_generation_settings": "הגדרות יצירה",
|
||||
"com_ui_getting_started": "תחילת העבודה",
|
||||
"com_ui_global_group": "שדה זה לא יכול להישאר ריק",
|
||||
"com_ui_go_back": "חזור",
|
||||
"com_ui_go_to_conversation": "חזור לצ'אט",
|
||||
|
|
@ -674,9 +788,14 @@
|
|||
"com_ui_good_evening": "ערב ",
|
||||
"com_ui_good_morning": "ערב טוב",
|
||||
"com_ui_happy_birthday": "זה יום ההולדת הראשון שלי!",
|
||||
"com_ui_hide_image_details": "הסתר פרטי תמונה",
|
||||
"com_ui_hide_qr": "הסתר קוד QR",
|
||||
"com_ui_host": "מארח",
|
||||
"com_ui_icon": "אייקון",
|
||||
"com_ui_idea": "רעיונות",
|
||||
"com_ui_image_created": "התמונה נוצרה",
|
||||
"com_ui_image_details": "פרטי התמונה",
|
||||
"com_ui_image_edited": "התמונה נערכה",
|
||||
"com_ui_image_gen": "מחולל תמונות",
|
||||
"com_ui_import": "ייבוא",
|
||||
"com_ui_import_conversation_error": "אירעה שגיאה בעת ייבוא השיחות שלך",
|
||||
|
|
@ -684,9 +803,9 @@
|
|||
"com_ui_import_conversation_info": "ייבא שיחות מקובץ JSON",
|
||||
"com_ui_import_conversation_success": "השיחות יובאו בהצלחה",
|
||||
"com_ui_include_shadcnui": "יש לכלול הוראות לשימוש ברכיבי ממשק המשתמש של shadcn/ui",
|
||||
"com_ui_include_shadcnui_agent": "יש לכלול הוראות שימוש ב-shadcn/ui",
|
||||
"com_ui_input": "קלט",
|
||||
"com_ui_instructions": "הוראות",
|
||||
"com_ui_key": "מפתח",
|
||||
"com_ui_late_night": "לילה טוב",
|
||||
"com_ui_latest_footer": "גישה לכל הבינות המלאכותיות (AI) לכולם",
|
||||
"com_ui_latest_production_version": "גרסת הפיתוח העדכנית ביותר",
|
||||
|
|
@ -699,7 +818,25 @@
|
|||
"com_ui_logo": "\"לוגו {{0}}\"",
|
||||
"com_ui_manage": "נהל",
|
||||
"com_ui_max_tags": "המספר המקסימלי המותר על פי הערכים העדכניים הוא {{0}}.",
|
||||
"com_ui_mcp_dialog_desc": "אנא הזן למטה את המידע הדרוש",
|
||||
"com_ui_mcp_enter_var": "הזן ערך עבור {{0}}",
|
||||
"com_ui_mcp_server_not_found": "נשרת לא נמצא",
|
||||
"com_ui_mcp_servers": "שרתי MCP",
|
||||
"com_ui_mcp_url": "קישור לשרת ה-MCP",
|
||||
"com_ui_memories": "זכרונות",
|
||||
"com_ui_memories_allow_create": "אפשר יצירת זיכרונות",
|
||||
"com_ui_memories_allow_opt_out": "אפשר למשתמשים לבטל את הזיכרונות",
|
||||
"com_ui_memories_allow_read": "אפשר קריאת זיכרונות",
|
||||
"com_ui_memories_allow_update": "אפשר עדכון זיכרונות",
|
||||
"com_ui_memories_allow_use": "אפשר שימוש בזיכרונות",
|
||||
"com_ui_memories_filter": "סינון זיכרונות...",
|
||||
"com_ui_memory": "זכרון",
|
||||
"com_ui_memory_created": "הזיכרון נוצר בהצלחה",
|
||||
"com_ui_memory_deleted": "הזיכרון נמחק",
|
||||
"com_ui_memory_deleted_items": "זכרונות שנמחקו",
|
||||
"com_ui_memory_key_exists": "זיכרון עם מפתח זה כבר קיים. אנא השתמש במפתח אחר.",
|
||||
"com_ui_memory_updated": "זיכרון שמור מעודכן",
|
||||
"com_ui_memory_updated_items": "זיכרונות מעודכנים",
|
||||
"com_ui_mention": "ציין נקודת קצה, סייען, או הנחייה (פרופמט) כדי לעבור אליה במהירות",
|
||||
"com_ui_min_tags": "לא ניתן למחוק ערכים נוספים, יש צורך במינימום {{0}} ערכים.",
|
||||
"com_ui_misc": "כללי",
|
||||
|
|
@ -718,16 +855,29 @@
|
|||
"com_ui_no_category": "אין קטגוריה",
|
||||
"com_ui_no_changes": "אין שינויים לעדכן",
|
||||
"com_ui_no_data": "השדה חייב להכיל תוכן, הוא לא יכול להישאר ריק",
|
||||
"com_ui_no_personalization_available": "אין אפשרויות התאמה אישית זמינות כרגע",
|
||||
"com_ui_no_read_access": "אין לך הרשאה לצפות בזיכרונות",
|
||||
"com_ui_no_terms_content": "אין תוכן תנאים והגבלות להצגה",
|
||||
"com_ui_no_valid_items": "השדה חייב להכיל תוכן, הוא לא יכול להישאר ריק",
|
||||
"com_ui_none": "אף אחד",
|
||||
"com_ui_not_used": "לא בשימוש",
|
||||
"com_ui_nothing_found": "לא נמצא",
|
||||
"com_ui_oauth": "פרוטוקול אימות פתוח (OAuth)",
|
||||
"com_ui_oauth_connected_to": "מחובר ל",
|
||||
"com_ui_oauth_error_callback_failed": "ניסיון האימות החוזר נכשל. אנא נסה שוב.",
|
||||
"com_ui_oauth_error_generic": "האימות נכשל. אנא נסה שוב.",
|
||||
"com_ui_oauth_error_invalid_state": "פרמטר המצב (state) אינו תקין. אנא נסו שוב",
|
||||
"com_ui_oauth_error_missing_code": "פרמטר המצב (state) חסר. אנא נסה שוב.",
|
||||
"com_ui_oauth_error_missing_state": "פרמטר המצב (state) חסר. אנא נסה שוב.",
|
||||
"com_ui_oauth_error_title": "האימות נכשל",
|
||||
"com_ui_oauth_success_description": "האימות בוצע בהצלחה. חלון זה ייסגר בעוד",
|
||||
"com_ui_oauth_success_title": "האימות בוצע בהצלחה",
|
||||
"com_ui_of": "של",
|
||||
"com_ui_off": "של",
|
||||
"com_ui_on": "פעיל",
|
||||
"com_ui_optional": "(אופציונלי)",
|
||||
"com_ui_page": "עמוד",
|
||||
"com_ui_preferences_updated": "ההעדפות עודכנו בהצלחה",
|
||||
"com_ui_prev": "הקודם",
|
||||
"com_ui_preview": "תצוגה מקדימה",
|
||||
"com_ui_privacy_policy": "מדיניות פרטיות",
|
||||
|
|
@ -745,8 +895,11 @@
|
|||
"com_ui_prompts_allow_share_global": "אפשר שיתוף הנחיות (פרומפטים) עם כל המשתמשים",
|
||||
"com_ui_prompts_allow_use": "אפשר שימוש בהנחיות (פרומפטים)",
|
||||
"com_ui_provider": "ספק",
|
||||
"com_ui_quality": "איכות",
|
||||
"com_ui_read_aloud": "הקראה",
|
||||
"com_ui_redirecting_to_provider": "מבצע הפניה ל-{{0}}, אנא המתן...",
|
||||
"com_ui_reference_saved_memories": "הפניה לזכרונות שמורים",
|
||||
"com_ui_reference_saved_memories_description": "אפשר לסוכן להתייחס ולהשתמש בזיכרונות השמורים שלך בעת התגובה",
|
||||
"com_ui_refresh_link": "רענון קישור",
|
||||
"com_ui_regenerate": "לחדש",
|
||||
"com_ui_regenerate_backup": "צור קודי גיבוי מחדש",
|
||||
|
|
@ -758,6 +911,7 @@
|
|||
"com_ui_rename_prompt": "שנה שם הנחיה (פרומפט)",
|
||||
"com_ui_requires_auth": "נדרש אימות",
|
||||
"com_ui_reset_var": "איפוס {{0}}",
|
||||
"com_ui_reset_zoom": "איפוס זום",
|
||||
"com_ui_result": "תוצאה",
|
||||
"com_ui_revoke": "בטל",
|
||||
"com_ui_revoke_info": "בטל את כל האישורים שסופקו על ידי המשתמש",
|
||||
|
|
@ -767,17 +921,20 @@
|
|||
"com_ui_revoke_keys_confirm": "האם אתה בטוח שברצונך לבטל את כל המפתחות?",
|
||||
"com_ui_role_select": "תפקיד",
|
||||
"com_ui_roleplay": "משחק תפקידים",
|
||||
"com_ui_run_code": "הרץ קו",
|
||||
"com_ui_run_code": "הרץ קוד",
|
||||
"com_ui_run_code_error": "אירעה שגיאה בהרצת הקוד",
|
||||
"com_ui_save": "שמור",
|
||||
"com_ui_save_badge_changes": "האם לשמור את השינויים בתגים?",
|
||||
"com_ui_save_submit": "שמור ושלח",
|
||||
"com_ui_saved": "שמור!",
|
||||
"com_ui_saving": "שומר...",
|
||||
"com_ui_schema": "סכמה",
|
||||
"com_ui_scope": "תחום",
|
||||
"com_ui_search": "חיפוש",
|
||||
"com_ui_seconds": "שניות",
|
||||
"com_ui_secret_key": "מפתח סודי",
|
||||
"com_ui_select": "בחר",
|
||||
"com_ui_select_all": "בחר הכל",
|
||||
"com_ui_select_file": "בחר קובץ",
|
||||
"com_ui_select_model": "בחר מודל",
|
||||
"com_ui_select_provider": "בחר ספק",
|
||||
|
|
@ -803,6 +960,7 @@
|
|||
"com_ui_shop": "קניות",
|
||||
"com_ui_show": "הצג",
|
||||
"com_ui_show_all": "הראה הכל",
|
||||
"com_ui_show_image_details": "הצג את פרטי התמונה",
|
||||
"com_ui_show_qr": "הראה קוד QR",
|
||||
"com_ui_sign_in_to_domain": "היכנס אל {{0}}",
|
||||
"com_ui_simple": "פשוט",
|
||||
|
|
@ -824,15 +982,23 @@
|
|||
"com_ui_terms_of_service": "תנאי השירות",
|
||||
"com_ui_thinking": "חושב...",
|
||||
"com_ui_thoughts": "מחשבות",
|
||||
"com_ui_token": "טוקן",
|
||||
"com_ui_token_exchange_method": "שיטת החלפת טוקנים",
|
||||
"com_ui_token_url": "קישור URL לטוקן",
|
||||
"com_ui_tokens": "טוקנים",
|
||||
"com_ui_tool_collection_prefix": "אוסף כלים מבית",
|
||||
"com_ui_tool_info": "מידע על הכלי",
|
||||
"com_ui_tool_more_info": "יותר מידע אודות הכלי הזה",
|
||||
"com_ui_tools": "כלים",
|
||||
"com_ui_travel": "מסע",
|
||||
"com_ui_unarchive": "לארכיון",
|
||||
"com_ui_unarchive_error": "אירעה שגיאה בארכיון השיחה",
|
||||
"com_ui_trust_app": "אני סומך על האפליקציה הזו",
|
||||
"com_ui_unarchive": "הוצא מהארכיון",
|
||||
"com_ui_unarchive_error": "הוצאת השיחה מהארכיון נכשלה",
|
||||
"com_ui_unknown": "לא ידוע",
|
||||
"com_ui_untitled": "ללא כותרת",
|
||||
"com_ui_untitled": "ללא כותר",
|
||||
"com_ui_update": "עדכון",
|
||||
"com_ui_update_mcp_error": "אירעה שגיאה ביצירה או עדכון של ה-MCP.",
|
||||
"com_ui_update_mcp_success": "ה-MCP נוצר או עודכן בהצלחה",
|
||||
"com_ui_upload": "העלה",
|
||||
"com_ui_upload_code_files": "העלאה עבור מפענח הקוד",
|
||||
"com_ui_upload_delay": "העלאת \"{{0}}\" לוקחת יותר זמן מהצפוי. אנא המתן בזמן שהקובץ מסיים את האינדוקס לאחזור.",
|
||||
|
|
@ -847,22 +1013,39 @@
|
|||
"com_ui_upload_ocr_text": "העלה קובץ כקובץ טקסט",
|
||||
"com_ui_upload_success": "הקובץ הועלה בהצלחה",
|
||||
"com_ui_upload_type": "בחר סוג העלאה",
|
||||
"com_ui_usage": "ניצול",
|
||||
"com_ui_use_2fa_code": "השתמש בקוד אימות דו-שלבי (2FA) במקום",
|
||||
"com_ui_use_backup_code": "השתמש בקוד גיבוי במקום",
|
||||
"com_ui_use_memory": "השתמש בזיכרון",
|
||||
"com_ui_use_micrphone": "שימוש במיקורפון",
|
||||
"com_ui_use_prompt": "השתמש בהנחיה (פרומפט)",
|
||||
"com_ui_used": "נוצל",
|
||||
"com_ui_value": "ערך",
|
||||
"com_ui_variables": "משתנים",
|
||||
"com_ui_variables_info": "השתמש בסוגריים מסולסלות כפולות בטקסט שלך ליצירת משתנים, לדוגמא `{{example variable}}`, כדי למלא אותם מאוחר יותר בשימוש בהנחיה.",
|
||||
"com_ui_verify": "אמת",
|
||||
"com_ui_version_var": "גרסה {{0}}",
|
||||
"com_ui_versions": "גרסה",
|
||||
"com_ui_view_memory": "הצג זיכרון",
|
||||
"com_ui_view_source": "הצג צ'אט מקורי",
|
||||
"com_ui_web_search": "חיפוש ברשת",
|
||||
"com_ui_web_search_cohere_key": "הכנס מפתח API של Cohere",
|
||||
"com_ui_web_search_firecrawl_url": "כתובת URL של ממשק ה-API של Firecrawl (אופציונלי)",
|
||||
"com_ui_web_search_jina_key": "הזן את מפתח ה-API של Jina",
|
||||
"com_ui_web_search_processing": "עיבוד התוצאות",
|
||||
"com_ui_web_search_provider": "ספק החיפוש",
|
||||
"com_ui_web_search_provider_serper": "ממשק ה-API של Serper",
|
||||
"com_ui_web_search_provider_serper_key": "קבל מפתח API של Serper ",
|
||||
"com_ui_web_search_reading": "קריאת התוצאות",
|
||||
"com_ui_web_search_reranker_cohere_key": "קבל מפתח API של Cohere",
|
||||
"com_ui_web_search_reranker_jina_key": "קבל מפתח API של Jina",
|
||||
"com_ui_web_search_scraper_firecrawl_key": "קבל מפתח API של Firecrawl",
|
||||
"com_ui_web_searching": "חיפוש ברשת",
|
||||
"com_ui_web_searching_again": "חיפוש נוסף ברשת",
|
||||
"com_ui_weekend_morning": "סוף שבוע נעים!",
|
||||
"com_ui_write": "כתיבה",
|
||||
"com_ui_x_selected": "{{0}} נבחר",
|
||||
"com_ui_yes": "כן",
|
||||
"com_ui_zoom": "זום",
|
||||
"com_user_message": "אתה",
|
||||
"com_warning_resubmit_unsupported": "שליחת הודעה מחדש אינה נתמכת עבור נקודת קצה זו."
|
||||
"com_user_message": "אתה"
|
||||
}
|
||||
|
|
@ -322,7 +322,6 @@
|
|||
"com_nav_delete_cache_storage": "TTS gyorsítótár tárolásának törlése",
|
||||
"com_nav_delete_data_info": "Minden adata törlésre kerül.",
|
||||
"com_nav_delete_warning": "FIGYELEM: Ez véglegesen törli fiókját.",
|
||||
"com_nav_edit_chat_badges": "Csevegőjelvények szerkesztése",
|
||||
"com_nav_enable_cache_tts": "TTS gyorsítótár engedélyezése",
|
||||
"com_nav_enable_cloud_browser_voice": "Felhőalapú hangok használata",
|
||||
"com_nav_enabled": "Engedélyezve",
|
||||
|
|
@ -679,7 +678,6 @@
|
|||
"com_ui_import_conversation_info": "Beszélgetések importálása JSON fájlból",
|
||||
"com_ui_import_conversation_success": "Beszélgetések sikeresen importálva",
|
||||
"com_ui_include_shadcnui": "shadcn/ui komponensek utasításainak belefoglalása",
|
||||
"com_ui_include_shadcnui_agent": "shadcn/ui utasítások belefoglalása",
|
||||
"com_ui_input": "Bevitel",
|
||||
"com_ui_instructions": "Utasítások",
|
||||
"com_ui_late_night": "Kellemes éjszakát",
|
||||
|
|
@ -847,6 +845,5 @@
|
|||
"com_ui_write": "Írás",
|
||||
"com_ui_yes": "Igen",
|
||||
"com_ui_zoom": "Zoom",
|
||||
"com_user_message": "Ön",
|
||||
"com_warning_resubmit_unsupported": "Az AI üzenet újraküldése nem támogatott ennél a végpontnál."
|
||||
"com_user_message": "Ön"
|
||||
}
|
||||
169
client/src/locales/hy/translation.json
Normal file
169
client/src/locales/hy/translation.json
Normal file
|
|
@ -0,0 +1,169 @@
|
|||
{
|
||||
"chat_direction_left_to_right": "այստեղ ինչ-որ բան պետք է ավելացնել։ դատարկ էր։",
|
||||
"chat_direction_right_to_left": "այստեղ ինչ-որ բան պետք է ավելացնել։ դատարկ էր։",
|
||||
"com_a11y_ai_composing": "AI-ն դեռ շարունակում է գրել։",
|
||||
"com_a11y_end": "AI-ն ավարտեց իր պատասխանը։",
|
||||
"com_a11y_start": "AI-ն սկսել է պատասխանը։",
|
||||
"com_agents_allow_editing": "Թույլ տալ այլ օգտատերերին խմբագրել ձեր գործակալին",
|
||||
"com_agents_by_librechat": "LibreChat-ի կողմից",
|
||||
"com_agents_code_interpreter": "Միացված լինելու դեպքում, թույլ է տալիս ձեր գործակալին օգտագործել LibreChat Code Interpreter API-ը՝ ստեղծված կոդը, այդ թվում՝ ֆայլերի մշակումը, անվտանգ կերպով գործարկելու համար: Պահանջվում է վավեր API բանալի:",
|
||||
"com_agents_code_interpreter_title": "Կոդի մեկնաբանիչ API",
|
||||
"com_agents_create_error": "Ձեր գործակալը ստեղծելիս սխալ է տեղի ունեցել։",
|
||||
"com_agents_description_placeholder": "Կամընտրական: Այստեղ նկարագրեք ձեր գործակալին",
|
||||
"com_agents_enable_file_search": "Միացնել ֆայլերի որոնումը",
|
||||
"com_agents_file_context": "Ֆայլի ճանաչում (OCR)",
|
||||
"com_agents_file_context_disabled": "Գործակալը պետք է ստեղծվի ֆայլերը վերբեռնելուց առաջ ֆայլերի ճանաչման համար:",
|
||||
"com_agents_mcp_icon_size": "Նվազագույն չափը՝ 128 x 128 px",
|
||||
"com_agents_mcp_name_placeholder": "Անհատական գործիք",
|
||||
"com_agents_name_placeholder": "Կամընտրական: Գործակալի անունը",
|
||||
"com_agents_no_access": "Դուք իրավունք չունեք խմբագրելու այս գործակալը։",
|
||||
"com_agents_not_available": "Գործակալը հասանելի չէ",
|
||||
"com_agents_search_name": "Որոնել գործակալներին ըստ անվան",
|
||||
"com_assistants_actions": "Գործողություններ",
|
||||
"com_assistants_add_actions": "Ավելացնել գործողություններ",
|
||||
"com_assistants_add_tools": "Ավելացնել գործիքներ",
|
||||
"com_assistants_allow_sites_you_trust": "Թույլ տալ միայն այն կայքերը, որոնց վստահում եք։",
|
||||
"com_assistants_append_date": "Ավելացնել ընթացիկ ամսաթիվը և ժամը",
|
||||
"com_assistants_available_actions": "Հասանելի գործողություններ",
|
||||
"com_assistants_capabilities": "Հնարավորություններ",
|
||||
"com_assistants_code_interpreter": "Կոդի մեկնաբանիչ",
|
||||
"com_assistants_conversation_starters": "Զրույցի մեկնարկներ",
|
||||
"com_assistants_conversation_starters_placeholder": "Մուտքագրեք զրույցի սկիզբը",
|
||||
"com_assistants_create_success": "Հաջողությամբ ստեղծվեց",
|
||||
"com_assistants_file_search": "Ֆայլերի որոնում",
|
||||
"com_assistants_image_vision": "Պատկերի տեսողություն",
|
||||
"com_assistants_knowledge": "Գիտելիքներ",
|
||||
"com_assistants_name_placeholder": "Կամընտրական: Օգնականի անունը",
|
||||
"com_assistants_retrieval": "Տվյալների ստացում",
|
||||
"com_assistants_running_action": "Գործողությունը կատարվում է",
|
||||
"com_assistants_search_name": "Որոնել օգնականներին ըստ անունի",
|
||||
"com_assistants_update_success": "Հաջողությամբ թարմացվեց",
|
||||
"com_auth_already_have_account": "Արդեն ունե՞ք ակաունթ։",
|
||||
"com_auth_apple_login": "Մուտք գործել Apple-ի միջոցով",
|
||||
"com_auth_back_to_login": "Վերադառնալ մուտքագրման էջ",
|
||||
"com_auth_click": "Սեղմեք",
|
||||
"com_auth_click_here": "Սեղմեք այստեղ",
|
||||
"com_auth_continue": "Շարունակել",
|
||||
"com_auth_create_account": "Ստեղծեք ձեր ակաունթը",
|
||||
"com_auth_email": "Էլ․ հասցե",
|
||||
"com_auth_email_address": "Էլ․ հասցե",
|
||||
"com_auth_email_required": "Էլ․ հասցեն պարտադիր է",
|
||||
"com_auth_email_resend_link": "Ուղարկել էլ․ հասցեն կրկին",
|
||||
"com_auth_email_verification_failed": "Էլ․ փոստի հաստատումը ձախողվեց",
|
||||
"com_auth_email_verification_success": "\"Էլ․ հասցեն հաջողությամբ հաստատվեց",
|
||||
"com_auth_email_verifying_ellipsis": "Ստուգվում է...",
|
||||
"com_auth_facebook_login": "Շարունակել Facebook-ի միջոցով",
|
||||
"com_auth_full_name": "Լրիվ անուն",
|
||||
"com_auth_github_login": "Շարունակել Github-ի միջոցով",
|
||||
"com_auth_google_login": "Շարունակել Google-ի միջոցով",
|
||||
"com_auth_here": "ԱՅՍՏԵՂ",
|
||||
"com_auth_login": "Մուտք",
|
||||
"com_auth_name_required": "Անունը պարտադիր է",
|
||||
"com_auth_no_account": "Դեռ օգտվող չե՞ք։",
|
||||
"com_auth_password": "Գաղտնաբառ",
|
||||
"com_auth_password_confirm": "Հաստատել գաղտնաբառը",
|
||||
"com_auth_password_forgot": "Մոռացե՞լ եք գաղտնաբառը",
|
||||
"com_auth_password_not_match": "Գաղտնաբառերը չեն համընկնում",
|
||||
"com_auth_password_required": "Գաղտնաբառը պարտադիր է",
|
||||
"com_auth_registration_success_insecure": "Գրանցումն ավարտվել է հաջողությամբ։",
|
||||
"com_auth_reset_password": "Վերականգնել գաղտնաբառը",
|
||||
"com_auth_reset_password_link_sent": "Էլ․ նամակը ուղարկվել է",
|
||||
"com_auth_reset_password_success": "Գաղտնաբառը հաջողությամբ վերականգնվեց",
|
||||
"com_auth_sign_in": "Մուտք գործել",
|
||||
"com_auth_sign_up": "Գրանցվել",
|
||||
"com_auth_to_reset_your_password": "գաղտնաբառը վերականգնելու համար։",
|
||||
"com_auth_to_try_again": "նորից փորձելու համար։",
|
||||
"com_auth_username": "Օգտանուն (կամընտրական)",
|
||||
"com_auth_welcome_back": "Բարի վերադարձ",
|
||||
"com_citation_more_details": "Լրացուցիչ մանրամասներ {{label}}-ի մասին",
|
||||
"com_citation_source": "Աղբյուր",
|
||||
"com_click_to_download": "(սեղմեք այստեղ ներբեռնելու համար)",
|
||||
"com_download_expired": "(ներբեռնելու ժամկետը սպառվել է)",
|
||||
"com_download_expires": "(սեղմեք այստեղ ներբեռնելու համար – կսպառվի {{0}} հետո)",
|
||||
"com_endpoint": "Endpoint",
|
||||
"com_endpoint_agent": "Գործակալ",
|
||||
"com_endpoint_agent_placeholder": "Խնդրում ենք ընտրել գործակալին",
|
||||
"com_endpoint_ai": "AI",
|
||||
"com_endpoint_assistant": "Օգնական",
|
||||
"com_endpoint_assistant_model": "Օգնականի մոդել",
|
||||
"com_endpoint_completion": "Լրացում",
|
||||
"com_endpoint_completion_model": "Լրացման մոդել (նախընտրելի է՝ GPT-4)",
|
||||
"com_endpoint_config_click_here": "Սեղմեք այստեղ",
|
||||
"com_endpoint_config_google_api_key": "Google API Key",
|
||||
"com_endpoint_config_google_cloud_platform": "(Google Cloud Platform-ից)",
|
||||
"com_endpoint_config_google_gemini_api": "(Gemini API)",
|
||||
"com_endpoint_config_google_service_key": "Google Service Account Key",
|
||||
"com_endpoint_config_key": "Մուտքագրեք API key-ը",
|
||||
"com_endpoint_config_key_encryption": "Ձեր բանալին կգաղտնագրվի և կհեռացվի",
|
||||
"com_endpoint_config_key_for": "Մուտքագրեք API key-ը՝",
|
||||
"com_endpoint_config_key_google_need_to": "Դուք պետք է",
|
||||
"com_endpoint_config_key_google_service_account": "Ստեղծել ծառայողական օգտահաշիվ",
|
||||
"com_endpoint_config_key_google_vertex_ai": "Միացնել Vertex AI-ը",
|
||||
"com_endpoint_config_key_name": "Key",
|
||||
"com_endpoint_config_key_never_expires": "Ձեր key-ը երբեք չի սպառվի",
|
||||
"com_endpoint_custom_name": "Անհատական անուն",
|
||||
"com_endpoint_deprecated": "Հնացած",
|
||||
"com_endpoint_examples": "Օրինակ",
|
||||
"com_endpoint_export": "Արտահանել",
|
||||
"com_endpoint_export_share": "Արտահանել/Կիսվել",
|
||||
"com_endpoint_message": "Հաղորդագրություն",
|
||||
"com_endpoint_message_new": "Հաղորդագրություն {{0}}",
|
||||
"com_endpoint_my_preset": "Իմ պրեսեթը",
|
||||
"com_endpoint_open_menu": "Բացել մենյուն",
|
||||
"com_endpoint_output": "Ելք",
|
||||
"com_endpoint_preset": "պրեսեթ",
|
||||
"com_endpoint_preset_default_item": "Սկզբնական",
|
||||
"com_endpoint_preset_default_none": "Սկզբնական նախադրված պրեսեթը ակտիվ չէ։",
|
||||
"com_endpoint_preset_import": "Պրեսեթը ներմուծվեց։",
|
||||
"com_endpoint_preset_name": "Պրեսեթի անուն",
|
||||
"com_endpoint_preset_selected": "Պրեսեթը ակտիվ է։",
|
||||
"com_endpoint_preset_selected_title": "Ակտիվ է։",
|
||||
"com_endpoint_preset_title": "Պրեսեթ",
|
||||
"com_endpoint_presets": "պրեսեթներ",
|
||||
"com_endpoint_save_as_preset": "Պահպանել որպես պրեսեթ",
|
||||
"com_endpoint_temperature": "Temperature",
|
||||
"com_error_files_dupe": "Հայտնաբերվել է կրկնվող ֆայլ։",
|
||||
"com_hide_examples": "Թաքցնել օրինակները",
|
||||
"com_nav_2fa": "Երկուփուլային նույնականացում (2FA)",
|
||||
"com_nav_account_settings": "Ակաունթի կարգավորումներ",
|
||||
"com_nav_archive_name": "Անուն",
|
||||
"com_nav_balance": "Հաշվեկշիռ",
|
||||
"com_nav_balance_every": "Ամեն",
|
||||
"com_nav_balance_refill_amount": "Լիցքավորման գումարը՝",
|
||||
"com_nav_browser": "Բրաուզեր",
|
||||
"com_nav_close_sidebar": "Փակել կողային վահանակը",
|
||||
"com_nav_commands": "Հրամաններ",
|
||||
"com_nav_delete_account": "Ջնջել ակաունթը",
|
||||
"com_nav_delete_account_confirm": "Ջնջե՞լ ակաունթը։ Հաստատո՞ւմ եք։",
|
||||
"com_nav_enabled": "Միացված է",
|
||||
"com_nav_export": "Արտահանել",
|
||||
"com_nav_font_size_base": "Միջին",
|
||||
"com_nav_font_size_lg": "Մեծ",
|
||||
"com_nav_font_size_sm": "Փոքր",
|
||||
"com_nav_font_size_xl": "Շատ մեծ",
|
||||
"com_nav_font_size_xs": "Շատ փոքր",
|
||||
"com_nav_lang_arabic": "العربية",
|
||||
"com_nav_lang_armenian": "Հայերեն",
|
||||
"com_nav_lang_catalan": "Català",
|
||||
"com_nav_lang_chinese": "中文",
|
||||
"com_nav_lang_czech": "Čeština",
|
||||
"com_nav_lang_danish": "Dansk",
|
||||
"com_nav_lang_english": "English",
|
||||
"com_nav_lang_french": "Français",
|
||||
"com_nav_lang_georgian": "ქართული",
|
||||
"com_nav_lang_hebrew": "עברית",
|
||||
"com_nav_lang_persian": "فارسی",
|
||||
"com_nav_lang_russian": "Русский",
|
||||
"com_nav_lang_spanish": "Español",
|
||||
"com_nav_lang_thai": "ไทย",
|
||||
"com_nav_lang_traditional_chinese": "繁體中文",
|
||||
"com_nav_lang_turkish": "Türkçe",
|
||||
"com_nav_lang_uyghur": "Uyƣur tili",
|
||||
"com_nav_lang_vietnamese": "Tiếng Việt",
|
||||
"com_nav_language": "Լեզու",
|
||||
"com_nav_log_out": "Ելք",
|
||||
"com_nav_setting_account": "Ակաունթ",
|
||||
"com_nav_setting_balance": "Հաշվեկշիռ",
|
||||
"com_nav_tool_remove": "Հեռացնել",
|
||||
"com_ui_2fa_enable": "Միացնել 2FA-ն"
|
||||
}
|
||||
|
|
@ -22,13 +22,16 @@ import translationJa from './ja/translation.json';
|
|||
import translationKa from './ka/translation.json';
|
||||
import translationSv from './sv/translation.json';
|
||||
import translationKo from './ko/translation.json';
|
||||
import translationLv from './lv/translation.json';
|
||||
import translationTh from './th/translation.json';
|
||||
import translationTr from './tr/translation.json';
|
||||
import translationUg from './ug/translation.json';
|
||||
import translationVi from './vi/translation.json';
|
||||
import translationNl from './nl/translation.json';
|
||||
import translationId from './id/translation.json';
|
||||
import translationHe from './he/translation.json';
|
||||
import translationHu from './hu/translation.json';
|
||||
import translationHy from './hy/translation.json';
|
||||
import translationFi from './fi/translation.json';
|
||||
import translationZh_Hans from './zh-Hans/translation.json';
|
||||
import translationZh_Hant from './zh-Hant/translation.json';
|
||||
|
|
@ -57,13 +60,16 @@ export const resources = {
|
|||
ka: { translation: translationKa },
|
||||
sv: { translation: translationSv },
|
||||
ko: { translation: translationKo },
|
||||
lv: { translation: translationLv },
|
||||
th: { translation: translationTh },
|
||||
tr: { translation: translationTr },
|
||||
ug: { translation: translationUg },
|
||||
vi: { translation: translationVi },
|
||||
nl: { translation: translationNl },
|
||||
id: { translation: translationId },
|
||||
he: { translation: translationHe },
|
||||
hu: { translation: translationHu },
|
||||
hy: { translation: translationHy },
|
||||
fi: { translation: translationFi },
|
||||
} as const;
|
||||
|
||||
|
|
|
|||
|
|
@ -314,7 +314,6 @@
|
|||
"com_nav_delete_cache_storage": "Elimina cache TTS",
|
||||
"com_nav_delete_data_info": "Tutti i tuoi dati verranno eliminati.",
|
||||
"com_nav_delete_warning": "ATTENZIONE: Questa azione eliminerà definitivamente il tuo account.",
|
||||
"com_nav_edit_chat_badges": "Modifica i badge della chat",
|
||||
"com_nav_enable_cache_tts": "Abilita cache TTS",
|
||||
"com_nav_enable_cloud_browser_voice": "Usa voci basate su cloud",
|
||||
"com_nav_enabled": "Abilitato",
|
||||
|
|
@ -664,7 +663,6 @@
|
|||
"com_ui_import_conversation_info": "Importa conversazioni da un file JSON",
|
||||
"com_ui_import_conversation_success": "Conversazioni importate con successo",
|
||||
"com_ui_include_shadcnui": "Includi istruzioni per i componenti shadcn/ui",
|
||||
"com_ui_include_shadcnui_agent": "Includere istruzioni shadcn/ui",
|
||||
"com_ui_input": "Input",
|
||||
"com_ui_instructions": "Istruzioni",
|
||||
"com_ui_late_night": "Buona tarda serata",
|
||||
|
|
@ -829,6 +827,5 @@
|
|||
"com_ui_write": "Scrittura",
|
||||
"com_ui_yes": "Sì",
|
||||
"com_ui_zoom": "Zoom",
|
||||
"com_user_message": "Mostra nome utente nei messaggi",
|
||||
"com_warning_resubmit_unsupported": "Il reinvio del messaggio AI non è supportato per questo endpoint."
|
||||
"com_user_message": "Mostra nome utente nei messaggi"
|
||||
}
|
||||
|
|
@ -21,6 +21,7 @@
|
|||
"com_agents_name_placeholder": "オプション: エージェントの名前",
|
||||
"com_agents_no_access": "このエージェントを編集する権限がありません。",
|
||||
"com_agents_not_available": "エージェントは利用できません",
|
||||
"com_agents_search_info": "有効にすると、エージェントが最新の情報を取得するためにWEB検索を行うようになります。有効なAPIキーが必要です。",
|
||||
"com_agents_search_name": "名前でエージェントを検索",
|
||||
"com_agents_update_error": "エージェントの更新中にエラーが発生しました。",
|
||||
"com_assistants_action_attempt": "アシスタントは{{0}}と話したいです",
|
||||
|
|
@ -322,7 +323,6 @@
|
|||
"com_nav_delete_cache_storage": "TTSキャッシュストレージを削除",
|
||||
"com_nav_delete_data_info": "すべてのデータが削除されます。",
|
||||
"com_nav_delete_warning": "警告: この操作により、アカウントが完全に削除されます。",
|
||||
"com_nav_edit_chat_badges": "チャットバッジの編集",
|
||||
"com_nav_enable_cache_tts": "キャッシュTTSを有効化",
|
||||
"com_nav_enable_cloud_browser_voice": "クラウドベースの音声を使用",
|
||||
"com_nav_enabled": "有効化",
|
||||
|
|
@ -688,7 +688,6 @@
|
|||
"com_ui_import_conversation_info": "JSONファイルから会話をインポートする",
|
||||
"com_ui_import_conversation_success": "会話のインポートに成功しました",
|
||||
"com_ui_include_shadcnui": "shadcn/uiコンポーネントの指示を含める",
|
||||
"com_ui_include_shadcnui_agent": "shadcn/uiの指示を含む",
|
||||
"com_ui_input": "入力",
|
||||
"com_ui_instructions": "指示文",
|
||||
"com_ui_late_night": "遅い夜を楽しんで",
|
||||
|
|
@ -868,6 +867,5 @@
|
|||
"com_ui_x_selected": "{{0}}が選択された",
|
||||
"com_ui_yes": "はい",
|
||||
"com_ui_zoom": "ズーム",
|
||||
"com_user_message": "あなた",
|
||||
"com_warning_resubmit_unsupported": "このエンドポイントではAIメッセージの再送信はサポートされていません"
|
||||
"com_user_message": "あなた"
|
||||
}
|
||||
|
|
@ -1,28 +1,69 @@
|
|||
{
|
||||
"com_nav_lang_arabic": "العربية",
|
||||
"chat_direction_left_to_right": "ველის შევსება სავალდებულოა",
|
||||
"chat_direction_right_to_left": "ველის შევსება სავალდებულოა",
|
||||
"com_a11y_ai_composing": "ხელოვნური ინტელექტი კვლავ წერის პროცესშია.",
|
||||
"com_a11y_end": "ხელოვნურმა ინტელექტმა დაასრულა თავისი პასუხი.",
|
||||
"com_a11y_start": "ხელოვნურმა ინტელექტმა დაიწყო პასუხის გაცემა.",
|
||||
"com_agents_allow_editing": "ნება მიეცით სხვა მომხმარებლებს დაარედაქტიროს თქვენი აგენტი",
|
||||
"com_agents_by_librechat": "LibreChat-ის მიერ",
|
||||
"com_agents_code_interpreter_title": "კოდის ინტერპრეტატორის API",
|
||||
"com_agents_create_error": "თქვენი აგენტის შექმნისასდაფიქსირდა შეცდომა",
|
||||
"com_agents_description_placeholder": "არასავალდებულო: აღწერეთ თქვენი აგენტი",
|
||||
"com_agents_enable_file_search": "ფაილების ძიების ჩართვა",
|
||||
"com_agents_file_context": "ფაილის კონტექსტი (OCR)",
|
||||
"com_agents_file_context_disabled": "ფაილის კონტექსტისთვის, ატვირთვამდე უნდა შეიქმნას აგენტი.",
|
||||
"com_agents_file_context_info": "„კონტექსტის“ სახით ატვირთული ფაილები დამუშავდება OCR-ის გამოყენებით ტექსტის ამოსაღებად, რომელიც შემდეგ დაემატება აგენტის ინსტრუქციებს. იდეალურია დოკუმენტებისთვის, ტექსტიანი სურათებისთვის ან PDF ფაილებისთვის, სადაც გჭირდებათ ფაილის შინაარსი.",
|
||||
"com_agents_instructions_placeholder": "სისტემის ინსტრუქციები, რომლებსაც გამოიყენებს აგენტი",
|
||||
"com_agents_mcp_description_placeholder": "რამდენიმე სიტყვით ახსენით დავალება",
|
||||
"com_agents_mcp_icon_size": "მინიმალური ზომა 128 x 128 პიქსელი",
|
||||
"com_agents_mcp_name_placeholder": "მორგებული ინსტრუმენტი",
|
||||
"com_agents_mcp_trust_subtext": "მორგებული კონექტორები არ არის დამოწმებული LibreChat-ის მიერ",
|
||||
"com_agents_mcps_disabled": "MCP-ების დამატებამდე საჭიროა შეიქმნას აგენტი.",
|
||||
"com_agents_missing_provider_model": "გთხოვთ, აგენტის შექმნამდე აირჩიოთ პროვაიდერი და მოდელი.",
|
||||
"com_agents_name_placeholder": "არასავალდებულო: აგენტის სახელი",
|
||||
"com_agents_no_access": "თქვენ არ გაქვთ შესაბამისი წვდომა აგენტის რედაქტირებისთვის",
|
||||
"com_agents_no_agent_id_error": "აგენტის ID ვერ მოიძებნა. გთხოვთ, დარწმუნდეთ, რომ აგენტი შექმნილია.",
|
||||
"com_agents_not_available": "აგენტი მიუწვდომელია",
|
||||
"com_agents_search_name": "აგენტების ძებნა სახელით",
|
||||
"com_agents_update_error": "თქვენი აგენტის განახლებისას დაფიქსირდა შეცდომა",
|
||||
"com_assistants_action_attempt": "ასისტენტს სურს გაესაუბროს {{0}}",
|
||||
"com_assistants_actions": "მოქმედებები",
|
||||
"com_assistants_actions_disabled": "მოქმედებების დამატებამდე საჭიროა ასისტენტის შექმნა.",
|
||||
"com_assistants_actions_info": "მიეცით თქვენს ასისტენტს საშუალება, მოიძიოს ინფორმაცია ან შეასრულოს ქმედებები API-ების მეშვეობით",
|
||||
"com_assistants_add_actions": "მოქმედებების დამატება",
|
||||
"com_assistants_add_tools": "ინსტრუმენტების დამატება",
|
||||
"com_assistants_allow_sites_you_trust": "მიუთითეთ მხოლოდ სანდო ვებ-რესურსები",
|
||||
"com_assistants_append_date": "მიმდინარე თარიღისა და დროის დამატება",
|
||||
"com_assistants_attempt_info": "ასისტენტს სურს შემდეგი ინფორმაციის გაგზავნა:",
|
||||
"com_assistants_available_actions": "ხელმისაწვდომი მოქმედებები",
|
||||
"com_assistants_capabilities": "შესაძლებლობები",
|
||||
"com_assistants_code_interpreter": "კოდის ინტერპრეტატორი",
|
||||
"com_assistants_conversation_starters": "საუბრის დასაწყისი",
|
||||
"com_assistants_create_success": "შეიქმნა წარმატებით",
|
||||
"com_nav_lang_arabic": "არაბული",
|
||||
"com_nav_lang_auto": "ავტომატური ამოცნობა",
|
||||
"com_nav_lang_brazilian_portuguese": "Português Brasileiro",
|
||||
"com_nav_lang_chinese": "中文",
|
||||
"com_nav_lang_dutch": "Nederlands",
|
||||
"com_nav_lang_english": "English",
|
||||
"com_nav_lang_estonian": "Eesti keel",
|
||||
"com_nav_lang_finnish": "Suomi",
|
||||
"com_nav_lang_french": "Français",
|
||||
"com_nav_lang_brazilian_portuguese": "პორტუგალიური",
|
||||
"com_nav_lang_chinese": "ჩინური",
|
||||
"com_nav_lang_dutch": "ნიდერლანდური",
|
||||
"com_nav_lang_english": "ინგლსური",
|
||||
"com_nav_lang_estonian": "ესტონური",
|
||||
"com_nav_lang_finnish": "ფინური",
|
||||
"com_nav_lang_french": "ფრანგული",
|
||||
"com_nav_lang_georgian": "ქართული",
|
||||
"com_nav_lang_german": "Deutsch",
|
||||
"com_nav_lang_hebrew": "עברית",
|
||||
"com_nav_lang_indonesia": "Indonesia",
|
||||
"com_nav_lang_italian": "Italiano",
|
||||
"com_nav_lang_japanese": "日本語",
|
||||
"com_nav_lang_korean": "한국어",
|
||||
"com_nav_lang_polish": "Polski",
|
||||
"com_nav_lang_portuguese": "Português",
|
||||
"com_nav_lang_russian": "Русский",
|
||||
"com_nav_lang_spanish": "Español",
|
||||
"com_nav_lang_swedish": "Svenska",
|
||||
"com_nav_lang_thai": "ไทย",
|
||||
"com_nav_lang_traditional_chinese": "繁體中文",
|
||||
"com_nav_lang_turkish": "Türkçe",
|
||||
"com_nav_lang_vietnamese": "Tiếng Việt",
|
||||
"com_nav_lang_german": "გერმანული",
|
||||
"com_nav_lang_hebrew": "ებრაული",
|
||||
"com_nav_lang_indonesia": "ინდონეზიური",
|
||||
"com_nav_lang_italian": "იტალიური",
|
||||
"com_nav_lang_japanese": "იაპონური",
|
||||
"com_nav_lang_korean": "კორეული",
|
||||
"com_nav_lang_polish": "პოლონური",
|
||||
"com_nav_lang_portuguese": "პორტუგალიური",
|
||||
"com_nav_lang_russian": "რუსული",
|
||||
"com_nav_lang_spanish": "ესპანური",
|
||||
"com_nav_lang_swedish": "შვედური",
|
||||
"com_nav_lang_thai": "ტაი",
|
||||
"com_nav_lang_traditional_chinese": "ჩინური ტრადიციული",
|
||||
"com_nav_lang_turkish": "თურქული",
|
||||
"com_nav_lang_vietnamese": "ვიეტნამური",
|
||||
"com_nav_language": "ენა"
|
||||
}
|
||||
|
|
@ -17,6 +17,10 @@
|
|||
"com_agents_file_search_disabled": "파일 검색을 위해 파일을 업로드하기 전에 에이전트를 먼저 생성해야 합니다",
|
||||
"com_agents_file_search_info": "활성화하면 에이전트가 아래 나열된 파일명들을 정확히 인식하여 해당 파일들에서 관련 내용을 검색할 수 있습니다.",
|
||||
"com_agents_instructions_placeholder": "에이전트가 사용하는 시스템 지침",
|
||||
"com_agents_mcp_description_placeholder": "역할을 간단히 소개해주세요",
|
||||
"com_agents_mcp_icon_size": "최소 크기 128 x 128 픽셀",
|
||||
"com_agents_mcp_info": "에이전트가 작업을 수행하고 외부 서비스와 연동할 수 있도록 MCP 서버를 추가하세요",
|
||||
"com_agents_mcp_name_placeholder": "커스텀 툴",
|
||||
"com_agents_missing_provider_model": "에이전트를 생성하기 전에 제공업체와 모델을 선택해 주세요",
|
||||
"com_agents_name_placeholder": "선택 사항: 에이전트의 이름",
|
||||
"com_agents_no_access": "이 에이전트를 수정할 권한이 없습니다",
|
||||
|
|
@ -326,7 +330,6 @@
|
|||
"com_nav_delete_cache_storage": "TTS 캐시 저장소 삭제",
|
||||
"com_nav_delete_data_info": "모든 데이터가 삭제됩니다.",
|
||||
"com_nav_delete_warning": "경고: 이 작업은 계정을 영구적으로 삭제합니다.",
|
||||
"com_nav_edit_chat_badges": "채팅 배지 편집",
|
||||
"com_nav_enable_cache_tts": "TTS 캐시 사용",
|
||||
"com_nav_enable_cloud_browser_voice": "클라우드 기반 음성 사용",
|
||||
"com_nav_enabled": "활성화됨",
|
||||
|
|
@ -350,6 +353,7 @@
|
|||
"com_nav_font_size_xs": "아주 작게",
|
||||
"com_nav_help_faq": "도움말 및 FAQ",
|
||||
"com_nav_hide_panel": "오른쪽 사이드 패널 숨기기",
|
||||
"com_nav_info_balance": "잔액은 사용 가능한 토큰 크레딧의 수를 나타냅니다. 토큰 크레딧은 금전적 가치로 환산되며 (예: 1000 크레딧 = 0.001달러)입니다.",
|
||||
"com_nav_info_code_artifacts": "채팅 옆에 실험적 코드 결과물 표시 활성화",
|
||||
"com_nav_info_code_artifacts_agent": "이 에이전트에 대해 코드 아티팩트 사용을 가능하게 합니다. 기본적으로 아티팩트 사용과 관련된 추가 지침이 포함되며, \"커스텀 프롬프트 모드\"가 활성화되지 않은 경우에만 적용됩니다.",
|
||||
"com_nav_info_custom_prompt_mode": "활성화하면 기본 아티팩트 시스템 프롬프트가 포함되지 않습니다. 이 모드에서는 아티팩트 생성을 위한 모든 지시사항을 수동으로 입력해야 합니다.",
|
||||
|
|
@ -416,6 +420,7 @@
|
|||
"com_nav_search_placeholder": "메시지 검색",
|
||||
"com_nav_send_message": "메시지 보내기",
|
||||
"com_nav_setting_account": "계정",
|
||||
"com_nav_setting_balance": "잔액",
|
||||
"com_nav_setting_beta": "베타 기능",
|
||||
"com_nav_setting_chat": "채팅",
|
||||
"com_nav_setting_data": "데이터 제어",
|
||||
|
|
@ -472,6 +477,8 @@
|
|||
"com_ui_accept": "동의합니다",
|
||||
"com_ui_action_button": "액션 버튼",
|
||||
"com_ui_add": "추가",
|
||||
"com_ui_add_mcp": "MCP 추가",
|
||||
"com_ui_add_mcp_server": "MCP 서버 추가",
|
||||
"com_ui_add_model_preset": "추가 응답을 위한 모델 또는 프리셋 추가",
|
||||
"com_ui_add_multi_conversation": "다중 응답 대화 추가",
|
||||
"com_ui_adding_details": "세부 정보 추가 중",
|
||||
|
|
@ -540,6 +547,7 @@
|
|||
"com_ui_auth_url": "인증 URL",
|
||||
"com_ui_authentication": "인증",
|
||||
"com_ui_authentication_type": "인증 방식",
|
||||
"com_ui_available_tools": "사용 가능 툴",
|
||||
"com_ui_avatar": "프로필 사진",
|
||||
"com_ui_azure": "Azure",
|
||||
"com_ui_back_to_chat": "채팅으로 돌아가기",
|
||||
|
|
@ -571,6 +579,7 @@
|
|||
"com_ui_bulk_delete_error": "공유 링크 삭제 실패",
|
||||
"com_ui_callback_url": "콜백 URL",
|
||||
"com_ui_cancel": "취소",
|
||||
"com_ui_cancelled": "취소됨",
|
||||
"com_ui_category": "카테고리",
|
||||
"com_ui_chat": "채팅",
|
||||
"com_ui_chat_history": "대화 기록",
|
||||
|
|
@ -599,6 +608,7 @@
|
|||
"com_ui_copy_to_clipboard": "클립보드에 복사",
|
||||
"com_ui_create": "만들기",
|
||||
"com_ui_create_link": "링크 만들기",
|
||||
"com_ui_create_memory": "메모리 생성",
|
||||
"com_ui_create_prompt": "프롬프트 만들기",
|
||||
"com_ui_creating_image": "이미지 생성 중입니다. 잠시 기다려 주세요.",
|
||||
"com_ui_currently_production": "현재 프로덕션 중",
|
||||
|
|
@ -633,13 +643,20 @@
|
|||
"com_ui_delete_confirm": "이 채팅이 삭제됩니다",
|
||||
"com_ui_delete_confirm_prompt_version_var": "선택한 \"{{0}}\"의 버전이 삭제됩니다. 다른 버전이 없다면 프롬프트도 함께 삭제됩니다.",
|
||||
"com_ui_delete_conversation": "채팅을 삭제하시겠습니까?",
|
||||
"com_ui_delete_mcp": "MCP 삭제",
|
||||
"com_ui_delete_mcp_confirm": "MCP 서버를 삭제하시겠습니까?",
|
||||
"com_ui_delete_mcp_error": "MCP 서버 삭제 실패",
|
||||
"com_ui_delete_mcp_success": "MCP 서버 삭제 완료",
|
||||
"com_ui_delete_memory": "메모리 삭제",
|
||||
"com_ui_delete_prompt": "프롬프트를 삭제하시겠습니까?",
|
||||
"com_ui_delete_shared_link": "공유 링크를 삭제하시겠습니까?",
|
||||
"com_ui_delete_tool": "도구 삭제",
|
||||
"com_ui_delete_tool_confirm": "이 도구를 삭제하시겠습니까?",
|
||||
"com_ui_deleted": "삭제 완료",
|
||||
"com_ui_descending": "내림차순",
|
||||
"com_ui_description": "설명",
|
||||
"com_ui_description_placeholder": "선택 사항: 프롬프트에 표시할 설명을 입력하세요",
|
||||
"com_ui_deselect_all": "모두 선택 해제",
|
||||
"com_ui_disabling": "비활성화 중...",
|
||||
"com_ui_download": "다운로드",
|
||||
"com_ui_download_artifact": "아티팩트 다운로드",
|
||||
|
|
@ -655,19 +672,40 @@
|
|||
"com_ui_duplication_success": "대화가 성공적으로 복제되었습니다",
|
||||
"com_ui_edit": "편집",
|
||||
"com_ui_edit_editing_image": "이미지 편집 중",
|
||||
"com_ui_edit_mcp_server": "MCP 서버 편집",
|
||||
"com_ui_edit_memory": "메모리 편집",
|
||||
"com_ui_empty_category": "-",
|
||||
"com_ui_endpoint": "엔드포인트",
|
||||
"com_ui_endpoint_menu": "LLM 엔드포인트 메뉴",
|
||||
"com_ui_enter": "Enter",
|
||||
"com_ui_enter_api_key": "API 키 입력",
|
||||
"com_ui_enter_key": "키 입력",
|
||||
"com_ui_enter_openapi_schema": "OpenAPI 스키마를 입력하세요",
|
||||
"com_ui_enter_value": "값 입력",
|
||||
"com_ui_error": "오류",
|
||||
"com_ui_error_connection": "서버 연결 오류가 발생했습니다. 페이지를 새로고침해 주세요.",
|
||||
"com_ui_error_save_admin_settings": "관리자 설정을 저장하는 중 오류가 발생했습니다.",
|
||||
"com_ui_error_updating_preferences": "설정 업데이트 오류",
|
||||
"com_ui_examples": "예시",
|
||||
"com_ui_expand_chat": "채팅 확장",
|
||||
"com_ui_export_convo_modal": "대화 내보내기",
|
||||
"com_ui_feedback_more": "더보기...",
|
||||
"com_ui_feedback_more_information": "추가 피드백 제공",
|
||||
"com_ui_feedback_negative": "개선 필요",
|
||||
"com_ui_feedback_placeholder": "여기에 추가 피드백을 제공해주세요",
|
||||
"com_ui_feedback_positive": "좋아요",
|
||||
"com_ui_feedback_tag_accurate_reliable": "정확하고 신뢰할 수 있음",
|
||||
"com_ui_feedback_tag_attention_to_detail": "디테일 함",
|
||||
"com_ui_feedback_tag_bad_style": "표현이나 말투가 어색함",
|
||||
"com_ui_feedback_tag_clear_well_written": "글이 분명하고 매끄럽게 작성됨",
|
||||
"com_ui_feedback_tag_inaccurate": "정확하지 않거나 잘못된 응답",
|
||||
"com_ui_feedback_tag_missing_image": "이미지가 포함될 줄 알았음",
|
||||
"com_ui_feedback_tag_not_helpful": "유용한 정보가 부족함",
|
||||
"com_ui_feedback_tag_not_matched": "요청과 다름",
|
||||
"com_ui_feedback_tag_other": "다른 문제점",
|
||||
"com_ui_feedback_tag_unjustified_refusal": "정확한 이유 없이 거절됨",
|
||||
"com_ui_field_required": "이 필드는 필수입니다",
|
||||
"com_ui_file_size": "파일 크기",
|
||||
"com_ui_files": "파일",
|
||||
"com_ui_filter_prompts": "프롬프트 필터링",
|
||||
"com_ui_filter_prompts_name": "이름으로 프롬프트 필터링",
|
||||
|
|
@ -701,6 +739,7 @@
|
|||
"com_ui_generate_backup": "백업 코드 생성",
|
||||
"com_ui_generate_qrcode": "QR 코드 생성",
|
||||
"com_ui_generating": "생성 중...",
|
||||
"com_ui_generation_settings": "출력 설정",
|
||||
"com_ui_getting_started": "시작하기",
|
||||
"com_ui_global_group": "내용이 비어 있었습니다.",
|
||||
"com_ui_go_back": "뒤로가기",
|
||||
|
|
@ -709,10 +748,13 @@
|
|||
"com_ui_good_evening": "좋은 저녁입니다",
|
||||
"com_ui_good_morning": "좋은 아침입니다",
|
||||
"com_ui_happy_birthday": "내 첫 생일이야!",
|
||||
"com_ui_hide_image_details": "이미지 세부정보 숨기기",
|
||||
"com_ui_hide_qr": "QR 코드 숨기기",
|
||||
"com_ui_host": "호스트",
|
||||
"com_ui_icon": "아이콘",
|
||||
"com_ui_idea": "아이디어",
|
||||
"com_ui_image_created": "이미지 생성됨",
|
||||
"com_ui_image_details": "이미지 세부정보",
|
||||
"com_ui_image_edited": "이미지 편집됨",
|
||||
"com_ui_image_gen": "이미지 생성",
|
||||
"com_ui_import": "가져오기",
|
||||
|
|
@ -721,9 +763,9 @@
|
|||
"com_ui_import_conversation_info": "JSON 파일에서 대화 가져오기",
|
||||
"com_ui_import_conversation_success": "대화가 성공적으로 가져와졌습니다",
|
||||
"com_ui_include_shadcnui": "shadcn/ui 컴포넌트 설치 안내",
|
||||
"com_ui_include_shadcnui_agent": "shadcn/ui 지침 포함",
|
||||
"com_ui_input": "입력",
|
||||
"com_ui_instructions": "설명",
|
||||
"com_ui_key": "키",
|
||||
"com_ui_late_night": "늦은 밤에도 행복하세요",
|
||||
"com_ui_latest_footer": "모두를 위한 AI, 한곳에서",
|
||||
"com_ui_latest_production_version": "최신 프로덕션 버전",
|
||||
|
|
@ -737,6 +779,21 @@
|
|||
"com_ui_manage": "관리",
|
||||
"com_ui_max_tags": "최대 {{0}}개까지만 허용됩니다. 최신 값을 사용 중입니다.",
|
||||
"com_ui_mcp_servers": "MCP 서버",
|
||||
"com_ui_mcp_url": "MCP 서버 URL",
|
||||
"com_ui_memories": "메모리",
|
||||
"com_ui_memories_allow_create": "메모리 생성 허용",
|
||||
"com_ui_memories_allow_opt_out": "사용자가 메모리 기능을 비활성화할 수 있도록 허용",
|
||||
"com_ui_memories_allow_read": "메모리 읽기 허용",
|
||||
"com_ui_memories_allow_update": "메모리 업데이트 허용",
|
||||
"com_ui_memories_allow_use": "메모리 사용 허용",
|
||||
"com_ui_memories_filter": "메모리 필터링...",
|
||||
"com_ui_memory": "메모리",
|
||||
"com_ui_memory_created": "메모리 생성 완료",
|
||||
"com_ui_memory_deleted": "메모리 삭제 완료",
|
||||
"com_ui_memory_deleted_items": "삭제된 메모리",
|
||||
"com_ui_memory_key_exists": "이 키를 가진 메모리가 이미 존재합니다. 다른 키를 사용해주세요.",
|
||||
"com_ui_memory_updated": "저장된 메모리 업데이트 완료",
|
||||
"com_ui_memory_updated_items": "저장된 메모리",
|
||||
"com_ui_mention": "엔드포인트, 어시스턴트 또는 프리셋을 언급하여 빠르게 전환하세요",
|
||||
"com_ui_min_tags": "최소 {{0}}개는 필수로 입력해야 합니다. 더 이상 값을 제거할 수 없습니다.",
|
||||
"com_ui_misc": "기타",
|
||||
|
|
@ -755,6 +812,8 @@
|
|||
"com_ui_no_category": "카테고리 없음",
|
||||
"com_ui_no_changes": "업데이트할 변경 사항이 없습니다",
|
||||
"com_ui_no_data": "내용이 비어 있었습니다.",
|
||||
"com_ui_no_personalization_available": "현재 개인화 설정을 사용할 수 없습니다",
|
||||
"com_ui_no_read_access": "메모리를 확인할 수 있는 권한이 없습니다",
|
||||
"com_ui_no_terms_content": "이용 약관 내용이 없습니다",
|
||||
"com_ui_no_valid_items": "내용이 비어 있었습니다.",
|
||||
"com_ui_none": "없음",
|
||||
|
|
@ -765,7 +824,9 @@
|
|||
"com_ui_off": "꺼짐",
|
||||
"com_ui_on": "켜기",
|
||||
"com_ui_openai": "OpenAI",
|
||||
"com_ui_optional": "(선택사항)",
|
||||
"com_ui_page": "페이지",
|
||||
"com_ui_preferences_updated": "설정 업데이트 완료",
|
||||
"com_ui_prev": "이전",
|
||||
"com_ui_preview": "미리보기",
|
||||
"com_ui_privacy_policy": "개인정보 보호정책",
|
||||
|
|
@ -785,6 +846,8 @@
|
|||
"com_ui_provider": "제공자",
|
||||
"com_ui_read_aloud": "소리내어 읽기",
|
||||
"com_ui_redirecting_to_provider": "{{0}}로 이동하는 중입니다. 잠시 기다리세요...",
|
||||
"com_ui_reference_saved_memories": "저장된 메모리 참고",
|
||||
"com_ui_reference_saved_memories_description": "어시스턴트가 답변할 때 저장된 메모리를 참고하고 사용할 수 있도록 허용합니다",
|
||||
"com_ui_refresh_link": "링크 새로고침",
|
||||
"com_ui_regenerate": "재생성",
|
||||
"com_ui_regenerate_backup": "백업 코드 재생성",
|
||||
|
|
@ -816,6 +879,7 @@
|
|||
"com_ui_search": "검색",
|
||||
"com_ui_secret_key": "비밀 키",
|
||||
"com_ui_select": "선택",
|
||||
"com_ui_select_all": "모두 선택",
|
||||
"com_ui_select_file": "파일 선택",
|
||||
"com_ui_select_model": "모델 선택",
|
||||
"com_ui_select_provider": "제공자 선택",
|
||||
|
|
@ -841,6 +905,7 @@
|
|||
"com_ui_shop": "쇼핑",
|
||||
"com_ui_show": "보기",
|
||||
"com_ui_show_all": "전체 보기",
|
||||
"com_ui_show_image_details": "이미지 세부사항 보기",
|
||||
"com_ui_show_qr": "QR 코드 보기",
|
||||
"com_ui_sign_in_to_domain": "{{0}}에 로그인",
|
||||
"com_ui_simple": "간단",
|
||||
|
|
@ -862,15 +927,20 @@
|
|||
"com_ui_terms_of_service": "이용 약관",
|
||||
"com_ui_thinking": "생각중...",
|
||||
"com_ui_thoughts": "생각",
|
||||
"com_ui_token": "토큰",
|
||||
"com_ui_token_exchange_method": "토큰 교환 방식",
|
||||
"com_ui_token_url": "토큰 URL",
|
||||
"com_ui_tokens": "토큰",
|
||||
"com_ui_tools": "도구",
|
||||
"com_ui_travel": "여행",
|
||||
"com_ui_trust_app": "신뢰할 수 있는 어플리케이션",
|
||||
"com_ui_unarchive": "아카이브 해제",
|
||||
"com_ui_unarchive_error": "대화 아카이브 해제 실패",
|
||||
"com_ui_unknown": "알 수 없음",
|
||||
"com_ui_untitled": "제목 없음",
|
||||
"com_ui_update": "업데이트",
|
||||
"com_ui_update_mcp_error": " MCP 생성 혹은 업데이트 중 오류가 발생했습니다.",
|
||||
"com_ui_update_mcp_success": "MCP 생성 혹은 업데이트 완료",
|
||||
"com_ui_upload": "업로드",
|
||||
"com_ui_upload_code_files": "코드 인터프리터용 파일 업로드",
|
||||
"com_ui_upload_delay": "\"{{0}}\" 파일 업로드에 예상보다 시간이 더 걸리고 있습니다. 파일 인덱싱이 완료될 때까지 기다려 주세요.",
|
||||
|
|
@ -885,19 +955,22 @@
|
|||
"com_ui_upload_ocr_text": "텍스트로 업로드",
|
||||
"com_ui_upload_success": "파일 업로드 성공",
|
||||
"com_ui_upload_type": "업로드 유형 선택",
|
||||
"com_ui_usage": "사용량",
|
||||
"com_ui_use_2fa_code": "2FA 코드 사용",
|
||||
"com_ui_use_backup_code": "백업 코드 사용",
|
||||
"com_ui_use_memory": "메모리 사용",
|
||||
"com_ui_use_micrphone": "마이크 사용",
|
||||
"com_ui_use_prompt": "프롬프트 사용",
|
||||
"com_ui_used": "사용됨",
|
||||
"com_ui_value": "값",
|
||||
"com_ui_variables": "변수",
|
||||
"com_ui_variables_info": "텍스트에 이중 중괄호를 사용하여 변수를 만들 수 있습니다. 예를 들어 `{{예시 변수}}`와 같이 작성하면 나중에 프롬프트를 사용할 때 해당 부분을 채울 수 있습니다.",
|
||||
"com_ui_verify": "확인",
|
||||
"com_ui_version_var": "버전 {{0}}",
|
||||
"com_ui_versions": "버전",
|
||||
"com_ui_view_memory": "메모리 보기",
|
||||
"com_ui_view_source": "원본 채팅 보기",
|
||||
"com_ui_web_search": "웹 검색",
|
||||
"com_ui_web_search_api_subtitle": "최신 정보를 검색하기 위해 웹 검색",
|
||||
"com_ui_web_search_cohere_key": "Cohere API 키 입력",
|
||||
"com_ui_web_search_firecrawl_url": "Firecrawl API URL (선택 사항)",
|
||||
"com_ui_web_search_jina_key": "Jina API 키 입력",
|
||||
|
|
@ -921,6 +994,5 @@
|
|||
"com_ui_x_selected": "{{0}}개 선택됨",
|
||||
"com_ui_yes": "네",
|
||||
"com_ui_zoom": "확대/축소",
|
||||
"com_user_message": "당신",
|
||||
"com_warning_resubmit_unsupported": "이 엔드포인트에서는 AI 메시지 재전송이 지원되지 않습니다"
|
||||
"com_user_message": "당신"
|
||||
}
|
||||
1076
client/src/locales/lv/translation.json
Normal file
1076
client/src/locales/lv/translation.json
Normal file
File diff suppressed because it is too large
Load diff
|
|
@ -21,16 +21,21 @@
|
|||
"com_agents_name_placeholder": "De naam van de agent",
|
||||
"com_agents_no_access": "Je hebt geen toegang om deze agent te bewerken.",
|
||||
"com_agents_not_available": "Agent niet beschikbaar",
|
||||
"com_agents_search_info": "Wanneer ingeschakeld, stelt het je agent in staat om het web te doorzoeken naar actuele informatie. Vereist een geldige API-sleutel.",
|
||||
"com_agents_search_name": "Agents zoeken op naam",
|
||||
"com_agents_update_error": "Er is een fout opgetreden bij het updaten van je agent.",
|
||||
"com_assistants_action_attempt": "Assistent wil praten met {{0}}",
|
||||
"com_assistants_actions": "Actions",
|
||||
"com_assistants_actions_disabled": "Maak een assistent aan voordat je actions toevoegt.",
|
||||
"com_assistants_actions_info": "Laat je Assistent informatie ophalen of acties uitvoeren via API’s",
|
||||
"com_assistants_add_actions": "Actie Toevoegen",
|
||||
"com_assistants_add_tools": "Tool Toevoegen",
|
||||
"com_assistants_allow_sites_you_trust": "Sta alleen sites to die je vertrouwt",
|
||||
"com_assistants_append_date": "Voeg huidige datum & tijd toe",
|
||||
"com_assistants_append_date_tooltip": "Wanneer ingeschakeld, worden de huidige datum en tijd van de client toegevoegd aan de systeeminstructies van de assistent.",
|
||||
"com_assistants_attempt_info": "Assistent wil het volgende sturen:",
|
||||
"com_assistants_available_actions": "Beschikbare Acties",
|
||||
"com_assistants_capabilities": "Mogelijkheden",
|
||||
"com_assistants_code_interpreter": "Code Interpreter",
|
||||
"com_assistants_code_interpreter_files": "Bestanden hieronder zijn alleen voor Code Interpreter",
|
||||
"com_assistants_code_interpreter_info": "Code Interpreter stelt de assistent in staat om code te schrijven en uit te voeren. Deze tool kan bestanden met uiteenlopende data en opmaak verwerken en bestanden genereren, zoals grafieken.",
|
||||
|
|
@ -39,7 +44,9 @@
|
|||
"com_assistants_conversation_starters": "Gesprekstarters",
|
||||
"com_assistants_conversation_starters_placeholder": "Voeg een gesprekstarters toe",
|
||||
"com_assistants_create_error": "Er was een error bij het maken van je assistant",
|
||||
"com_assistants_create_success": "Succesvol gecreëerd",
|
||||
"com_assistants_delete_actions_error": "Er was een error bij het verwijderen van de actie",
|
||||
"com_assistants_delete_actions_success": "Succesvol een actie verwijderd van Assistent",
|
||||
"com_assistants_description_placeholder": "Optioneel: Beschrijf jouw Assistant hier",
|
||||
"com_assistants_domain_info": "Assistant heeft deze informatie verstuurd naar {{0}}",
|
||||
"com_assistants_file_search": "Zoeken naar bestanden",
|
||||
|
|
@ -55,6 +62,7 @@
|
|||
"com_assistants_non_retrieval_model": "Bestandszoekfunctie is niet ingeschakeld op dit model. Selecteer een ander model.",
|
||||
"com_assistants_retrieval": "Ophalen",
|
||||
"com_assistants_running_action": "Lopende actie",
|
||||
"com_assistants_running_var": "{{0}} uitvoeren",
|
||||
"com_assistants_search_name": "Zoek assistenten op naam",
|
||||
"com_assistants_update_actions_error": "Er is een fout opgetreden bij het maken of bijwerken van de actie.",
|
||||
"com_assistants_update_actions_success": "Actie succesvol aangemaakt of bijgewerkt",
|
||||
|
|
@ -79,12 +87,19 @@
|
|||
"com_auth_email_resent_success": "Verificatie-e-mail succesvol opnieuw verzonden",
|
||||
"com_auth_email_verification_failed": "E-mailverificatie mislukt",
|
||||
"com_auth_email_verification_failed_token_missing": "Verificatie mislukt, token ontbreekt",
|
||||
"com_auth_email_verification_in_progress": "Email verifieren, een moment geduld a.u.b.",
|
||||
"com_auth_email_verification_invalid": "Ongeldige e-mailverificatie",
|
||||
"com_auth_email_verification_redirecting": "Doorsturen in {{0}} seconden...",
|
||||
"com_auth_email_verification_resend_prompt": "E-mail niet ontvangen?",
|
||||
"com_auth_email_verification_success": "E-mail succesvol geverifieerd",
|
||||
"com_auth_email_verifying_ellipsis": "Bezig met verifiëren...",
|
||||
"com_auth_error_create": "Er is een fout opgetreden bij het registreren van uw account. Probeer het opnieuw.",
|
||||
"com_auth_error_invalid_reset_token": "Dit wachtwoord resettoken is niet langer geldig.",
|
||||
"com_auth_error_login": "Kan niet inloggen met de verstrekte informatie. Controleer uw referenties en probeer het opnieuw.",
|
||||
"com_auth_error_login_ban": "Uw account is tijdelijk verbannen vanwege schendingen van onze service.",
|
||||
"com_auth_error_login_rl": "Te veel inlogpogingen in een korte tijd. Probeer het later nog eens.",
|
||||
"com_auth_error_login_server": "Er was een interne serverfout. Wacht een paar momenten en probeer het opnieuw.",
|
||||
"com_auth_error_login_unverified": "Je account is nog niet geverifieerd. Controleer je e-mail voor een verificatielink.",
|
||||
"com_auth_facebook_login": "Inloggen met Facebook",
|
||||
"com_auth_full_name": "Volledige naam",
|
||||
"com_auth_github_login": "Inloggen met Github",
|
||||
|
|
@ -103,9 +118,13 @@
|
|||
"com_auth_password_min_length": "Wachtwoord moet minstens 8 tekens bevatten",
|
||||
"com_auth_password_not_match": "Wachtwoorden komen niet overeen",
|
||||
"com_auth_password_required": "Wachtwoord is verplicht",
|
||||
"com_auth_registration_success_generic": "Controleer je e-mail om je e-mailadres te verifiëren.",
|
||||
"com_auth_registration_success_insecure": "Registratie succesvol.",
|
||||
"com_auth_reset_password": "Stel uw wachtwoord opnieuw in",
|
||||
"com_auth_reset_password_if_email_exists": "Als er een account bestaat met dat e-mailadres, is er een e-mail met instructies voor het opnieuw instellen van je wachtwoord verzonden. Vergeet niet je spamfolder te controleren.",
|
||||
"com_auth_reset_password_link_sent": "E-mail verzonden",
|
||||
"com_auth_reset_password_success": "Wachtwoord opnieuw ingesteld",
|
||||
"com_auth_saml_login": "Ga door met SAML",
|
||||
"com_auth_sign_in": "Inloggen",
|
||||
"com_auth_sign_up": "Aanmelden",
|
||||
"com_auth_submit_registration": "Registratie indienen",
|
||||
|
|
@ -114,16 +133,34 @@
|
|||
"com_auth_username": "Gebruikersnaam (optioneel)",
|
||||
"com_auth_username_max_length": "Gebruikersnaam mag niet langer zijn dan 20 tekens",
|
||||
"com_auth_username_min_length": "Gebruikersnaam moet minstens 2 tekens bevatten",
|
||||
"com_auth_verify_your_identity": "Verifieer je identiteit",
|
||||
"com_auth_welcome_back": "Welkom terug",
|
||||
"com_citation_more_details": "Meer details van {{label}}",
|
||||
"com_citation_source": "Bron",
|
||||
"com_click_to_download": "(klik hier om te downloaden)",
|
||||
"com_download_expired": "(download verlopen)",
|
||||
"com_download_expires": "(klik hier om te downloaden - verloopt op {{0}})",
|
||||
"com_endpoint": "Eindpunt",
|
||||
"com_endpoint_agent": "Agent",
|
||||
"com_endpoint_agent_model": "Agentmodel (Aanbevolen: GPT-3,5)",
|
||||
"com_endpoint_agent_placeholder": "Selecteer een Agent",
|
||||
"com_endpoint_ai": "AI",
|
||||
"com_endpoint_anthropic_maxoutputtokens": "Maximum aantal tokens dat kan worden gegenereerd in de reactie. Geef een lagere waarde op voor kortere reacties en een hogere waarde voor langere reacties.",
|
||||
"com_endpoint_anthropic_prompt_cache": "Promptcaching maakt het mogelijk om een grote context of instructies opnieuw te gebruiken bij API-aanroepen, wat kosten en vertraging vermindert.",
|
||||
"com_endpoint_anthropic_temp": "Varieert van 0 tot 1. Gebruik een lagere temp voor analytische / meerkeuze taken en een hogere temp voor creatieve en generatieve taken. We raden aan dit of Top P te wijzigen, maar niet beide.",
|
||||
"com_endpoint_anthropic_thinking": "Schakelt interne redenering in voor ondersteunde Claude-modellen (3.7 Sonnet). Let op: vereist dat het \"Thinking Budget\" is ingesteld en lager is dan \"Max Output Tokens\".",
|
||||
"com_endpoint_anthropic_thinking_budget": "Bepaalt het maximale aantal tokens dat Claude mag gebruiken voor zijn interne redeneerproces. Grotere budgetten kunnen de kwaliteit van de antwoorden verbeteren door grondigere analyses mogelijk te maken voor complexe problemen, hoewel Claude mogelijk niet het volledige toegewezen budget gebruikt, vooral bij bereiken boven de 32K. Deze instelling moet lager zijn dan \"Max Output Tokens\".",
|
||||
"com_endpoint_anthropic_topk": "Top-k verandert hoe het model tokens selecteert voor uitvoer. Een top-k van 1 betekent dat het geselecteerde token het meest waarschijnlijk is van alle tokens in de vocabulaire van het model (ook wel 'greedy decoding' genoemd), terwijl een top-k van 3 betekent dat het volgende token wordt geselecteerd uit de 3 meest waarschijnlijke tokens (met behulp van temperatuur).",
|
||||
"com_endpoint_anthropic_topp": "Top-p verandert hoe het model tokens selecteert voor uitvoer. Tokens worden geselecteerd van meest K (zie topK-parameter) waarschijnlijk tot minst waarschijnlijk totdat de som van hun kansen gelijk is aan de top-p-waarde.",
|
||||
"com_endpoint_assistant": "Assistent",
|
||||
"com_endpoint_assistant_model": "Assistent Model",
|
||||
"com_endpoint_completion": "Voltooiing",
|
||||
"com_endpoint_completion_model": "Voltooiingsmodel (Aanbevolen: GPT-4)",
|
||||
"com_endpoint_config_click_here": "Klik Hier",
|
||||
"com_endpoint_config_google_api_key": "Google API Key",
|
||||
"com_endpoint_config_google_cloud_platform": "(van Google Cloud Platform)",
|
||||
"com_endpoint_config_google_gemini_api": "(Gemini API)",
|
||||
"com_endpoint_config_google_service_key": "Google Service Account Key",
|
||||
"com_endpoint_config_key": "API-sleutel instellen",
|
||||
"com_endpoint_config_key_encryption": "Uw sleutel wordt versleuteld en verwijderd op",
|
||||
"com_endpoint_config_key_for": "API-sleutel instellen voor",
|
||||
|
|
@ -136,8 +173,12 @@
|
|||
"com_endpoint_config_key_import_json_key_invalid": "Ongeldige Serviceaccount-JSON-sleutel, heb je het juiste bestand geïmporteerd?",
|
||||
"com_endpoint_config_key_import_json_key_success": "Serviceaccount-JSON-sleutel succesvol geïmporteerd",
|
||||
"com_endpoint_config_key_name": "Sleutel",
|
||||
"com_endpoint_config_key_never_expires": "Je sleutel zal nooit verlopen.",
|
||||
"com_endpoint_config_placeholder": "Stel je sleutel in via de header om te kunnen chatten.",
|
||||
"com_endpoint_config_value": "Voer waarde in voor",
|
||||
"com_endpoint_context": "Context",
|
||||
"com_endpoint_context_info": "Het maximale aantal tokens dat kan worden gebruikt voor context. Gebruik dit om te bepalen hoeveel tokens per verzoek worden verzonden. Als dit niet wordt opgegeven, worden de standaardwaarden van het systeem gebruikt op basis van de bekende contextgrootte van modellen. Het instellen van hogere waarden kan leiden tot fouten en/of hogere kosten per token.",
|
||||
"com_endpoint_context_tokens": "Maximale Context Tokens",
|
||||
"com_endpoint_custom_name": "Aangepaste naam",
|
||||
"com_endpoint_default": "standaard",
|
||||
"com_endpoint_default_blank": "standaard: leeg",
|
||||
|
|
@ -145,6 +186,7 @@
|
|||
"com_endpoint_default_with_num": "standaard: {{0}}",
|
||||
"com_endpoint_examples": " Voorinstellingen",
|
||||
"com_endpoint_export": "Exporteren",
|
||||
"com_endpoint_export_share": "Exporteer/Deel",
|
||||
"com_endpoint_frequency_penalty": "Frequentiestraf",
|
||||
"com_endpoint_func_hover": "Schakel het gebruik van plug-ins als OpenAI-functies in",
|
||||
"com_endpoint_google_custom_name_placeholder": "Stel een aangepaste naam in voor Google",
|
||||
|
|
@ -153,6 +195,7 @@
|
|||
"com_endpoint_google_topk": "Top-k verandert hoe het model tokens selecteert voor uitvoer. Een top-k van 1 betekent dat het geselecteerde token het meest waarschijnlijk is van alle tokens in de vocabulaire van het model (ook wel 'greedy decoding' genoemd), terwijl een top-k van 3 betekent dat het volgende token wordt geselecteerd uit de 3 meest waarschijnlijke tokens (met behulp van temperatuur).",
|
||||
"com_endpoint_google_topp": "Top-p verandert hoe het model tokens selecteert voor uitvoer. Tokens worden geselecteerd van meest K (zie topK-parameter) waarschijnlijk tot minst waarschijnlijk totdat de som van hun kansen gelijk is aan de top-p-waarde.",
|
||||
"com_endpoint_max_output_tokens": "Max. uitvoertokens",
|
||||
"com_endpoint_message": "Bericht",
|
||||
"com_endpoint_my_preset": "Mijn voorinstelling",
|
||||
"com_endpoint_no_presets": "Nog geen voorinstellingen, gebruik de instellingenknop om er een te maken",
|
||||
"com_endpoint_open_menu": "Open menu",
|
||||
|
|
|
|||
Some files were not shown because too many files have changed in this diff Show more
Loading…
Add table
Add a link
Reference in a new issue