mirror of
https://github.com/langgenius/dify.git
synced 2026-04-25 21:26:15 +08:00
feat(model-selector): add status badges and empty states for model trigger
- Add credits exhausted and API key unavailable split layout using useCredentialPanelState - Replace deprecated AlertTriangle icon with Incompatible badge and tooltip - Add empty state with brain icon placeholder and configure model text - Move STATUS_I18N_KEY to declarations.ts as shared constant - Redesign HasNotSetAPI as inline card layout, remove WarningMask overlay - Move no-API-key warning inline in debug panel, add no-model-selected state - Add i18n keys for en-US, ja-JP, zh-Hans
This commit is contained in:
@ -2,25 +2,19 @@ import { fireEvent, render, screen } from '@testing-library/react'
|
||||
import * as React from 'react'
|
||||
import HasNotSetAPI from './has-not-set-api'
|
||||
|
||||
describe('HasNotSetAPI WarningMask', () => {
|
||||
it('should show default title when trial not finished', () => {
|
||||
render(<HasNotSetAPI isTrailFinished={false} onSetting={vi.fn()} />)
|
||||
describe('HasNotSetAPI', () => {
|
||||
it('should render the empty state copy', () => {
|
||||
render(<HasNotSetAPI onSetting={vi.fn()} />)
|
||||
|
||||
expect(screen.getByText('appDebug.notSetAPIKey.title')).toBeInTheDocument()
|
||||
expect(screen.getByText('appDebug.notSetAPIKey.description')).toBeInTheDocument()
|
||||
expect(screen.getByText('appDebug.noModelProviderConfigured')).toBeInTheDocument()
|
||||
expect(screen.getByText('appDebug.noModelProviderConfiguredTip')).toBeInTheDocument()
|
||||
})
|
||||
|
||||
it('should show trail finished title when flag is true', () => {
|
||||
render(<HasNotSetAPI isTrailFinished onSetting={vi.fn()} />)
|
||||
|
||||
expect(screen.getByText('appDebug.notSetAPIKey.trailFinished')).toBeInTheDocument()
|
||||
})
|
||||
|
||||
it('should call onSetting when primary button clicked', () => {
|
||||
it('should call onSetting when manage models button is clicked', () => {
|
||||
const onSetting = vi.fn()
|
||||
render(<HasNotSetAPI isTrailFinished={false} onSetting={onSetting} />)
|
||||
render(<HasNotSetAPI onSetting={onSetting} />)
|
||||
|
||||
fireEvent.click(screen.getByRole('button', { name: 'appDebug.notSetAPIKey.settingBtn' }))
|
||||
fireEvent.click(screen.getByRole('button', { name: 'appDebug.manageModels' }))
|
||||
expect(onSetting).toHaveBeenCalledTimes(1)
|
||||
})
|
||||
})
|
||||
|
||||
@ -2,38 +2,38 @@
|
||||
import type { FC } from 'react'
|
||||
import * as React from 'react'
|
||||
import { useTranslation } from 'react-i18next'
|
||||
import Button from '@/app/components/base/button'
|
||||
import WarningMask from '.'
|
||||
|
||||
export type IHasNotSetAPIProps = {
|
||||
isTrailFinished: boolean
|
||||
onSetting: () => void
|
||||
}
|
||||
|
||||
const icon = (
|
||||
<svg width="16" height="16" viewBox="0 0 16 16" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||
<path d="M14 6.00001L14 2.00001M14 2.00001H9.99999M14 2.00001L8 8M6.66667 2H5.2C4.0799 2 3.51984 2 3.09202 2.21799C2.71569 2.40973 2.40973 2.71569 2.21799 3.09202C2 3.51984 2 4.07989 2 5.2V10.8C2 11.9201 2 12.4802 2.21799 12.908C2.40973 13.2843 2.71569 13.5903 3.09202 13.782C3.51984 14 4.07989 14 5.2 14H10.8C11.9201 14 12.4802 14 12.908 13.782C13.2843 13.5903 13.5903 13.2843 13.782 12.908C14 12.4802 14 11.9201 14 10.8V9.33333" stroke="white" strokeWidth="1.5" strokeLinecap="round" strokeLinejoin="round" />
|
||||
</svg>
|
||||
|
||||
)
|
||||
|
||||
const HasNotSetAPI: FC<IHasNotSetAPIProps> = ({
|
||||
isTrailFinished,
|
||||
onSetting,
|
||||
}) => {
|
||||
const { t } = useTranslation()
|
||||
|
||||
return (
|
||||
<WarningMask
|
||||
title={isTrailFinished ? t('notSetAPIKey.trailFinished', { ns: 'appDebug' }) : t('notSetAPIKey.title', { ns: 'appDebug' })}
|
||||
description={t('notSetAPIKey.description', { ns: 'appDebug' })}
|
||||
footer={(
|
||||
<Button variant="primary" className="flex space-x-2" onClick={onSetting}>
|
||||
<span>{t('notSetAPIKey.settingBtn', { ns: 'appDebug' })}</span>
|
||||
{icon}
|
||||
</Button>
|
||||
)}
|
||||
/>
|
||||
<div className="flex grow flex-col items-center justify-center pb-[120px]">
|
||||
<div className="flex w-full max-w-[400px] flex-col gap-2 px-4 py-4">
|
||||
<div className="flex h-10 w-10 items-center justify-center rounded-[10px]">
|
||||
<div className="flex h-full w-full items-center justify-center overflow-hidden rounded-[10px] border-[0.5px] border-components-card-border bg-components-card-bg p-1 shadow-lg backdrop-blur-[5px]">
|
||||
<span className="i-ri-brain-2-line h-5 w-5 text-text-tertiary" />
|
||||
</div>
|
||||
</div>
|
||||
<div className="flex flex-col gap-1">
|
||||
<div className="text-text-secondary system-md-semibold">{t('noModelProviderConfigured', { ns: 'appDebug' })}</div>
|
||||
<div className="text-text-tertiary system-xs-regular">{t('noModelProviderConfiguredTip', { ns: 'appDebug' })}</div>
|
||||
</div>
|
||||
<button
|
||||
type="button"
|
||||
className="flex w-fit items-center gap-1 rounded-lg border-[0.5px] border-components-button-secondary-border bg-components-button-secondary-bg px-3 py-2 shadow-xs backdrop-blur-[5px]"
|
||||
onClick={onSetting}
|
||||
>
|
||||
<span className="text-components-button-secondary-accent-text system-sm-medium">{t('manageModels', { ns: 'appDebug' })}</span>
|
||||
<span className="i-ri-arrow-right-line h-4 w-4 text-components-button-secondary-accent-text" />
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
)
|
||||
}
|
||||
export default React.memo(HasNotSetAPI)
|
||||
|
||||
@ -33,7 +33,7 @@ import { ToastContext } from '@/app/components/base/toast/context'
|
||||
import TooltipPlus from '@/app/components/base/tooltip'
|
||||
import { ModelFeatureEnum, ModelTypeEnum } from '@/app/components/header/account-setting/model-provider-page/declarations'
|
||||
import { useDefaultModel } from '@/app/components/header/account-setting/model-provider-page/hooks'
|
||||
import { DEFAULT_CHAT_PROMPT_CONFIG, DEFAULT_COMPLETION_PROMPT_CONFIG, IS_CE_EDITION } from '@/config'
|
||||
import { DEFAULT_CHAT_PROMPT_CONFIG, DEFAULT_COMPLETION_PROMPT_CONFIG } from '@/config'
|
||||
import ConfigContext from '@/context/debug-configuration'
|
||||
import { useEventEmitterContextContext } from '@/context/event-emitter'
|
||||
import { useProviderContext } from '@/context/provider-context'
|
||||
@ -505,6 +505,26 @@ const Debug: FC<IDebug> = ({
|
||||
{
|
||||
!debugWithMultipleModel && (
|
||||
<div className="flex grow flex-col" ref={ref}>
|
||||
{/* No model provider configured */}
|
||||
{(!modelConfig.provider || !isAPIKeySet) && (
|
||||
<HasNotSetAPIKEY onSetting={onSetting} />
|
||||
)}
|
||||
{/* No model selected */}
|
||||
{modelConfig.provider && isAPIKeySet && !modelConfig.model_id && (
|
||||
<div className="flex grow flex-col items-center justify-center pb-[120px]">
|
||||
<div className="flex w-full max-w-[400px] flex-col gap-2 px-4 py-4">
|
||||
<div className="flex h-10 w-10 items-center justify-center rounded-[10px]">
|
||||
<div className="flex h-full w-full items-center justify-center overflow-hidden rounded-[10px] border-[0.5px] border-components-card-border bg-components-card-bg p-1 shadow-lg backdrop-blur-[5px]">
|
||||
<span className="i-ri-brain-2-line h-5 w-5 text-text-tertiary" />
|
||||
</div>
|
||||
</div>
|
||||
<div className="flex flex-col gap-1">
|
||||
<div className="text-text-secondary system-md-semibold">{t('noModelSelected', { ns: 'appDebug' })}</div>
|
||||
<div className="text-text-tertiary system-xs-regular">{t('noModelSelectedTip', { ns: 'appDebug' })}</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
)}
|
||||
{/* Chat */}
|
||||
{mode !== AppModeEnum.COMPLETION && (
|
||||
<div className="h-0 grow overflow-hidden">
|
||||
@ -570,7 +590,6 @@ const Debug: FC<IDebug> = ({
|
||||
/>
|
||||
)
|
||||
}
|
||||
{!isAPIKeySet && !readonly && (<HasNotSetAPIKEY isTrailFinished={!IS_CE_EDITION} onSetting={onSetting} />)}
|
||||
</>
|
||||
)
|
||||
}
|
||||
|
||||
@ -68,7 +68,7 @@ const ModelParameterModal: FC<ModelParameterModalProps> = ({
|
||||
const { t } = useTranslation()
|
||||
const { isAPIKeySet } = useProviderContext()
|
||||
const [open, setOpen] = useState(false)
|
||||
const { data: parameterRulesData, isPending: isLoading } = useModelParameterRules(provider, modelId)
|
||||
const { data: parameterRulesData, isLoading } = useModelParameterRules(provider, modelId)
|
||||
const {
|
||||
currentProvider,
|
||||
currentModel,
|
||||
|
||||
@ -15,6 +15,7 @@ import { MODEL_STATUS_TEXT } from '../declarations'
|
||||
import { useLanguage } from '../hooks'
|
||||
import ModelIcon from '../model-icon'
|
||||
import ModelName from '../model-name'
|
||||
import { useCredentialPanelState } from '../provider-added-card/use-credential-panel-state'
|
||||
|
||||
export type TriggerProps = {
|
||||
open?: boolean
|
||||
@ -40,18 +41,65 @@ const Trigger: FC<TriggerProps> = ({
|
||||
const { t } = useTranslation()
|
||||
const language = useLanguage()
|
||||
const { modelProviders } = useProviderContext()
|
||||
const isEmpty = !modelId || !providerName
|
||||
const currentModelProvider = modelProviders.find(p => p.provider === providerName)
|
||||
const state = useCredentialPanelState(currentModelProvider)
|
||||
const hasCredits = !state.isCreditsExhausted
|
||||
const showCreditsExhausted = !isEmpty && !hasCredits && state.supportsCredits
|
||||
const showApiKeyUnavailable = !isEmpty && state.variant === 'api-unavailable'
|
||||
|
||||
// Non-workflow status error: split layout with badge + settings button
|
||||
if ((showCreditsExhausted || showApiKeyUnavailable) && !isInWorkflow) {
|
||||
return (
|
||||
<div className="flex h-8 min-w-[296px] cursor-pointer items-center gap-px overflow-hidden rounded-lg">
|
||||
<div className="flex flex-1 items-center gap-0.5 rounded-l-lg bg-components-input-bg-normal p-1">
|
||||
<ModelIcon
|
||||
className="p-0.5"
|
||||
provider={currentProvider || modelProviders.find(item => item.provider === providerName)}
|
||||
modelName={currentModel?.model}
|
||||
/>
|
||||
<div className="flex flex-1 items-center truncate px-1 py-[3px]">
|
||||
{currentModel
|
||||
? <ModelName className="grow" modelItem={currentModel} showMode showFeatures />
|
||||
: <div className="truncate text-[13px] font-normal text-components-input-text-filled">{modelId}</div>}
|
||||
</div>
|
||||
<div className="flex shrink-0 items-center pr-0.5">
|
||||
<div className="flex min-w-[20px] shrink-0 items-center justify-center gap-[3px] rounded-md border border-text-warning bg-components-badge-bg-dimm px-[5px] py-0.5">
|
||||
<span className="i-ri-alert-fill h-3 w-3 text-text-warning" />
|
||||
<span className="whitespace-nowrap text-text-warning system-xs-medium">
|
||||
{t(showCreditsExhausted ? 'modelProvider.selector.creditsExhausted' : 'modelProvider.selector.apiKeyUnavailable', { ns: 'common' })}
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div className="flex shrink-0 items-center justify-center rounded-r-lg bg-components-button-tertiary-bg p-2">
|
||||
<SlidersH className="h-4 w-4 text-text-tertiary" />
|
||||
</div>
|
||||
</div>
|
||||
)
|
||||
}
|
||||
|
||||
return (
|
||||
<div
|
||||
className={cn(
|
||||
'relative flex h-8 cursor-pointer items-center rounded-lg px-2',
|
||||
'relative flex h-8 min-w-[296px] cursor-pointer items-center rounded-lg px-2',
|
||||
!isInWorkflow && 'border ring-inset hover:ring-[0.5px]',
|
||||
!isInWorkflow && (disabled ? 'border-text-warning bg-state-warning-hover ring-text-warning' : 'border-util-colors-indigo-indigo-600 bg-state-accent-hover ring-util-colors-indigo-indigo-600'),
|
||||
isInWorkflow && 'border border-workflow-block-parma-bg bg-workflow-block-parma-bg pr-[30px] hover:border-components-input-border-active',
|
||||
isInWorkflow && !isEmpty && 'border border-workflow-block-parma-bg bg-workflow-block-parma-bg pr-[30px] hover:border-components-input-border-active',
|
||||
isInWorkflow && isEmpty && 'border border-text-warning bg-state-warning-hover pr-[30px]',
|
||||
)}
|
||||
>
|
||||
{
|
||||
currentProvider && (
|
||||
isEmpty && (
|
||||
<div className="mr-2 flex h-6 w-6 shrink-0 items-center justify-center">
|
||||
<div className="flex h-5 w-5 items-center justify-center rounded-md border-[0.5px] border-components-panel-border-subtle bg-background-default-subtle">
|
||||
<span className="i-ri-brain-2-line h-3.5 w-3.5 text-text-quaternary" />
|
||||
</div>
|
||||
</div>
|
||||
)
|
||||
}
|
||||
{
|
||||
!isEmpty && currentProvider && (
|
||||
<ModelIcon
|
||||
className="mr-1.5 !h-5 !w-5"
|
||||
provider={currentProvider}
|
||||
@ -60,7 +108,7 @@ const Trigger: FC<TriggerProps> = ({
|
||||
)
|
||||
}
|
||||
{
|
||||
!currentProvider && (
|
||||
!isEmpty && !currentProvider && (
|
||||
<ModelIcon
|
||||
className="mr-1.5 !h-5 !w-5"
|
||||
provider={modelProviders.find(item => item.provider === providerName)}
|
||||
@ -69,7 +117,7 @@ const Trigger: FC<TriggerProps> = ({
|
||||
)
|
||||
}
|
||||
{
|
||||
currentModel && (
|
||||
!isEmpty && currentModel && (
|
||||
<ModelName
|
||||
className="mr-1.5 text-text-primary"
|
||||
modelItem={currentModel}
|
||||
@ -79,32 +127,57 @@ const Trigger: FC<TriggerProps> = ({
|
||||
)
|
||||
}
|
||||
{
|
||||
!currentModel && (
|
||||
!isEmpty && !currentModel && (
|
||||
<div className="mr-1 truncate text-[13px] font-medium text-text-primary">
|
||||
{modelId}
|
||||
</div>
|
||||
)
|
||||
}
|
||||
{
|
||||
disabled
|
||||
? (
|
||||
<Tooltip
|
||||
popupContent={
|
||||
hasDeprecated
|
||||
? t('modelProvider.deprecated', { ns: 'common' })
|
||||
: (modelDisabled && currentModel)
|
||||
? MODEL_STATUS_TEXT[currentModel.status as string][language]
|
||||
: ''
|
||||
}
|
||||
>
|
||||
<AlertTriangle className="h-4 w-4 text-[#F79009]" />
|
||||
</Tooltip>
|
||||
)
|
||||
: (
|
||||
<SlidersH className={cn(!isInWorkflow ? 'text-indigo-600' : 'text-text-tertiary', 'h-4 w-4 shrink-0')} />
|
||||
)
|
||||
isEmpty && (
|
||||
<div className="mr-1 flex-1 truncate text-[13px] font-normal text-text-secondary">
|
||||
{t('workflow:errorMsg.configureModel')}
|
||||
</div>
|
||||
)
|
||||
}
|
||||
{isInWorkflow && (<RiArrowDownSLine className="absolute right-2 top-[9px] h-3.5 w-3.5 text-text-tertiary" />)}
|
||||
{
|
||||
!isEmpty && (
|
||||
disabled
|
||||
? (
|
||||
hasDeprecated
|
||||
? (
|
||||
<Tooltip popupContent={t('modelProvider.selector.incompatibleTip', { ns: 'common' })}>
|
||||
<div className="ml-auto flex min-w-[20px] shrink-0 items-center justify-center gap-[3px] rounded-md border border-text-warning bg-components-badge-bg-dimm px-[5px] py-0.5">
|
||||
<span className="i-ri-alert-fill h-3 w-3 text-text-warning" />
|
||||
<span className="whitespace-nowrap text-text-warning system-xs-medium">
|
||||
{t('modelProvider.selector.incompatible', { ns: 'common' })}
|
||||
</span>
|
||||
</div>
|
||||
</Tooltip>
|
||||
)
|
||||
: (
|
||||
<Tooltip
|
||||
popupContent={
|
||||
(modelDisabled && currentModel)
|
||||
? MODEL_STATUS_TEXT[currentModel.status as string][language]
|
||||
: ''
|
||||
}
|
||||
>
|
||||
<AlertTriangle className="h-4 w-4 text-[#F79009]" />
|
||||
</Tooltip>
|
||||
)
|
||||
)
|
||||
: (
|
||||
<SlidersH className={cn(!isInWorkflow ? 'text-indigo-600' : 'text-text-tertiary', 'h-4 w-4 shrink-0')} />
|
||||
)
|
||||
)
|
||||
}
|
||||
{
|
||||
isEmpty && (
|
||||
<RiArrowDownSLine className={cn('h-4 w-4 shrink-0 text-text-tertiary', isInWorkflow && 'absolute right-2 top-[9px] h-3.5 w-3.5')} />
|
||||
)
|
||||
}
|
||||
{!isEmpty && isInWorkflow && (<RiArrowDownSLine className="absolute right-2 top-[9px] h-3.5 w-3.5 text-text-tertiary" />)}
|
||||
</div>
|
||||
)
|
||||
}
|
||||
|
||||
@ -1,6 +1,11 @@
|
||||
import type { TypeWithI18N } from '../header/account-setting/model-provider-page/declarations'
|
||||
import type { VarType } from '../workflow/types'
|
||||
|
||||
type LocalizedText<T = string> = {
|
||||
en_US: T
|
||||
zh_Hans: T
|
||||
[key: string]: T
|
||||
}
|
||||
|
||||
export enum LOC {
|
||||
tools = 'tools',
|
||||
app = 'app',
|
||||
@ -47,10 +52,10 @@ export type Collection = {
|
||||
id: string
|
||||
name: string
|
||||
author: string
|
||||
description: TypeWithI18N
|
||||
description: LocalizedText
|
||||
icon: string | Emoji
|
||||
icon_dark?: string | Emoji
|
||||
label: TypeWithI18N
|
||||
label: LocalizedText
|
||||
type: CollectionType | string
|
||||
team_credentials: Record<string, any>
|
||||
is_team_authorization: boolean
|
||||
@ -84,8 +89,8 @@ export type Collection = {
|
||||
|
||||
export type ToolParameter = {
|
||||
name: string
|
||||
label: TypeWithI18N
|
||||
human_description: TypeWithI18N
|
||||
label: LocalizedText
|
||||
human_description: LocalizedText
|
||||
type: string
|
||||
form: string
|
||||
llm_description: string
|
||||
@ -93,7 +98,7 @@ export type ToolParameter = {
|
||||
multiple: boolean
|
||||
default: string
|
||||
options?: {
|
||||
label: TypeWithI18N
|
||||
label: LocalizedText
|
||||
value: string
|
||||
}[]
|
||||
min?: number
|
||||
@ -102,8 +107,8 @@ export type ToolParameter = {
|
||||
|
||||
export type TriggerParameter = {
|
||||
name: string
|
||||
label: TypeWithI18N
|
||||
human_description: TypeWithI18N
|
||||
label: LocalizedText
|
||||
human_description: LocalizedText
|
||||
type: string
|
||||
form: string
|
||||
llm_description: string
|
||||
@ -111,7 +116,7 @@ export type TriggerParameter = {
|
||||
multiple: boolean
|
||||
default: string
|
||||
options?: {
|
||||
label: TypeWithI18N
|
||||
label: LocalizedText
|
||||
value: string
|
||||
}[]
|
||||
}
|
||||
@ -120,8 +125,8 @@ export type TriggerParameter = {
|
||||
export type Event = {
|
||||
name: string
|
||||
author: string
|
||||
label: TypeWithI18N
|
||||
description: TypeWithI18N
|
||||
label: LocalizedText
|
||||
description: LocalizedText
|
||||
parameters: TriggerParameter[]
|
||||
labels: string[]
|
||||
output_schema: Record<string, any>
|
||||
@ -130,7 +135,7 @@ export type Event = {
|
||||
export type Tool = {
|
||||
name: string
|
||||
author: string
|
||||
label: TypeWithI18N
|
||||
label: LocalizedText
|
||||
description: any
|
||||
parameters: ToolParameter[]
|
||||
labels: string[]
|
||||
@ -139,14 +144,14 @@ export type Tool = {
|
||||
|
||||
export type ToolCredential = {
|
||||
name: string
|
||||
label: TypeWithI18N
|
||||
help: TypeWithI18N | null
|
||||
placeholder: TypeWithI18N
|
||||
label: LocalizedText
|
||||
help: LocalizedText | null
|
||||
placeholder: LocalizedText
|
||||
type: string
|
||||
required: boolean
|
||||
default: string
|
||||
options?: {
|
||||
label: TypeWithI18N
|
||||
label: LocalizedText
|
||||
value: string
|
||||
}[]
|
||||
}
|
||||
@ -167,8 +172,8 @@ export type CustomCollectionBackend = {
|
||||
|
||||
export type ParamItem = {
|
||||
name: string
|
||||
label: TypeWithI18N
|
||||
human_description: TypeWithI18N
|
||||
label: LocalizedText
|
||||
human_description: LocalizedText
|
||||
llm_description: string
|
||||
type: string
|
||||
form: string
|
||||
@ -177,7 +182,7 @@ export type ParamItem = {
|
||||
min?: number
|
||||
max?: number
|
||||
options?: {
|
||||
label: TypeWithI18N
|
||||
label: LocalizedText
|
||||
value: string
|
||||
}[]
|
||||
}
|
||||
@ -233,8 +238,8 @@ export type WorkflowToolProviderResponse = {
|
||||
tool: {
|
||||
author: string
|
||||
name: string
|
||||
label: TypeWithI18N
|
||||
description: TypeWithI18N
|
||||
label: LocalizedText
|
||||
description: LocalizedText
|
||||
labels: string[]
|
||||
parameters: ParamItem[]
|
||||
output_schema: WorkflowToolProviderOutputSchema
|
||||
|
||||
@ -7016,9 +7016,6 @@
|
||||
"app/components/header/account-setting/model-provider-page/model-parameter-modal/trigger.tsx": {
|
||||
"no-restricted-imports": {
|
||||
"count": 1
|
||||
},
|
||||
"tailwindcss/no-unnecessary-whitespace": {
|
||||
"count": 2
|
||||
}
|
||||
},
|
||||
"app/components/header/account-setting/model-provider-page/model-selector/feature-icon.tsx": {
|
||||
|
||||
@ -235,11 +235,16 @@
|
||||
"inputs.run": "RUN",
|
||||
"inputs.title": "Debug & Preview",
|
||||
"inputs.userInputField": "User Input Field",
|
||||
"manageModels": "Manage models",
|
||||
"modelConfig.modeType.chat": "Chat",
|
||||
"modelConfig.modeType.completion": "Complete",
|
||||
"modelConfig.model": "Model",
|
||||
"modelConfig.setTone": "Set tone of responses",
|
||||
"modelConfig.title": "Model and Parameters",
|
||||
"noModelProviderConfigured": "No model provider configured",
|
||||
"noModelProviderConfiguredTip": "Install or configure a model provider to get started.",
|
||||
"noModelSelected": "No model selected",
|
||||
"noModelSelectedTip": "configure a model above to continue.",
|
||||
"noResult": "Output will be displayed here.",
|
||||
"notSetAPIKey.description": "The LLM provider key has not been set, and it needs to be set before debugging.",
|
||||
"notSetAPIKey.settingBtn": "Go to settings",
|
||||
|
||||
@ -235,11 +235,16 @@
|
||||
"inputs.run": "実行",
|
||||
"inputs.title": "デバッグとプレビュー",
|
||||
"inputs.userInputField": "ユーザー入力フィールド",
|
||||
"manageModels": "モデルを管理",
|
||||
"modelConfig.modeType.chat": "チャット",
|
||||
"modelConfig.modeType.completion": "完成",
|
||||
"modelConfig.model": "モデル",
|
||||
"modelConfig.setTone": "応答のトーンを設定する",
|
||||
"modelConfig.title": "モデルとパラメータ",
|
||||
"noModelProviderConfigured": "モデルプロバイダーが設定されていません",
|
||||
"noModelProviderConfiguredTip": "モデルプロバイダーをインストールまたは設定して開始してください。",
|
||||
"noModelSelected": "モデルが選択されていません",
|
||||
"noModelSelectedTip": "続行するには、上でモデルを設定してください。",
|
||||
"noResult": "出力はここに表示されます。",
|
||||
"notSetAPIKey.description": "LLM プロバイダーキーが設定されていません。デバッグする前に設定する必要があります。",
|
||||
"notSetAPIKey.settingBtn": "設定に移動",
|
||||
|
||||
@ -235,11 +235,16 @@
|
||||
"inputs.run": "运行",
|
||||
"inputs.title": "调试与预览",
|
||||
"inputs.userInputField": "用户输入",
|
||||
"manageModels": "管理模型",
|
||||
"modelConfig.modeType.chat": "对话型",
|
||||
"modelConfig.modeType.completion": "补全型",
|
||||
"modelConfig.model": "语言模型",
|
||||
"modelConfig.setTone": "模型设置",
|
||||
"modelConfig.title": "模型及参数",
|
||||
"noModelProviderConfigured": "未配置模型供应商",
|
||||
"noModelProviderConfiguredTip": "请先安装或配置模型供应商以开始使用。",
|
||||
"noModelSelected": "未选择模型",
|
||||
"noModelSelectedTip": "请先在上方配置模型以继续。",
|
||||
"noResult": "输出结果展示在这",
|
||||
"notSetAPIKey.description": "在调试之前需要设置 LLM 提供者的密钥。",
|
||||
"notSetAPIKey.settingBtn": "去设置",
|
||||
|
||||
Reference in New Issue
Block a user