Merge branch 'feat/plugins' into dev/plugin-deploy

pull/12372/head
Joel 2 years ago
commit 04ba0a3500

@ -27,7 +27,7 @@ import AnnotationFullModal from '@/app/components/billing/annotation-full/modal'
import { Settings04 } from '@/app/components/base/icons/src/vender/line/general' import { Settings04 } from '@/app/components/base/icons/src/vender/line/general'
import type { App } from '@/types/app' import type { App } from '@/types/app'
type Props = { interface Props {
appDetail: App appDetail: App
} }
@ -283,7 +283,6 @@ const Annotation: FC<Props> = ({
if ( if (
embeddingModel.embedding_model_name !== annotationConfig?.embedding_model?.embedding_model_name embeddingModel.embedding_model_name !== annotationConfig?.embedding_model?.embedding_model_name
|| embeddingModel.embedding_provider_name !== annotationConfig?.embedding_model?.embedding_provider_name || embeddingModel.embedding_provider_name !== annotationConfig?.embedding_model?.embedding_provider_name
|| embeddingModel.plugin_id !== annotationConfig?.embedding_model?.plugin_id
) { ) {
const { job_id: jobId }: any = await updateAnnotationStatus(appDetail.id, AnnotationEnableStatus.enable, embeddingModel, score) const { job_id: jobId }: any = await updateAnnotationStatus(appDetail.id, AnnotationEnableStatus.enable, embeddingModel, score)
await ensureJobCompleted(jobId, AnnotationEnableStatus.enable) await ensureJobCompleted(jobId, AnnotationEnableStatus.enable)

@ -23,9 +23,8 @@ export type HitHistoryItem = {
} }
export type EmbeddingModelConfig = { export type EmbeddingModelConfig = {
plugin_id: string
embedding_model_name: string
embedding_provider_name: string embedding_provider_name: string
embedding_model_name: string
} }
export enum AnnotationEnableStatus { export enum AnnotationEnableStatus {

@ -25,7 +25,7 @@ import { useSelectedDatasetsMode } from '@/app/components/workflow/nodes/knowled
import Switch from '@/app/components/base/switch' import Switch from '@/app/components/base/switch'
import Toast from '@/app/components/base/toast' import Toast from '@/app/components/base/toast'
type Props = { interface Props {
datasetConfigs: DatasetConfigs datasetConfigs: DatasetConfigs
onChange: (configs: DatasetConfigs, isRetrievalModeChange?: boolean) => void onChange: (configs: DatasetConfigs, isRetrievalModeChange?: boolean) => void
isInWorkflow?: boolean isInWorkflow?: boolean
@ -71,7 +71,6 @@ const ConfigContent: FC<Props> = ({
? { ? {
...rerankDefaultModel, ...rerankDefaultModel,
provider: rerankDefaultModel.provider.provider, provider: rerankDefaultModel.provider.provider,
plugin_id: rerankDefaultModel.provider.plugin_id,
} }
: undefined, : undefined,
) )
@ -81,14 +80,12 @@ const ConfigContent: FC<Props> = ({
return { return {
provider_name: datasetConfigs.reranking_model.reranking_provider_name, provider_name: datasetConfigs.reranking_model.reranking_provider_name,
model_name: datasetConfigs.reranking_model.reranking_model_name, model_name: datasetConfigs.reranking_model.reranking_model_name,
plugin_id: datasetConfigs.reranking_model.reranking_plugin_id,
} }
} }
else if (rerankDefaultModel) { else if (rerankDefaultModel) {
return { return {
provider_name: rerankDefaultModel.provider.provider, provider_name: rerankDefaultModel.provider.provider,
model_name: rerankDefaultModel.model, model_name: rerankDefaultModel.model,
plugin_id: rerankDefaultModel.provider.plugin_id,
} }
} }
})() })()
@ -175,7 +172,7 @@ const ConfigContent: FC<Props> = ({
return false return false
return datasetConfigs.reranking_enable return datasetConfigs.reranking_enable
}, [canManuallyToggleRerank, datasetConfigs.reranking_enable, isRerankDefaultModelValid]) }, [canManuallyToggleRerank, datasetConfigs.reranking_enable])
const handleDisabledSwitchClick = useCallback(() => { const handleDisabledSwitchClick = useCallback(() => {
if (!currentRerankModel && !showRerankModel) if (!currentRerankModel && !showRerankModel)
@ -303,14 +300,13 @@ const ConfigContent: FC<Props> = ({
</div> </div>
<div> <div>
<ModelSelector <ModelSelector
defaultModel={rerankModel && { provider: rerankModel?.provider_name, model: rerankModel?.model_name, plugin_id: rerankModel?.plugin_id }} defaultModel={rerankModel && { provider: rerankModel?.provider_name, model: rerankModel?.model_name }}
onSelect={(v) => { onSelect={(v) => {
onChange({ onChange({
...datasetConfigs, ...datasetConfigs,
reranking_model: { reranking_model: {
reranking_provider_name: v.provider, reranking_provider_name: v.provider,
reranking_model_name: v.model, reranking_model_name: v.model,
reranking_plugin_id: v.plugin_id,
}, },
}) })
}} }}
@ -388,7 +384,6 @@ const ConfigContent: FC<Props> = ({
portalToFollowElemContentClassName='!z-[1002]' portalToFollowElemContentClassName='!z-[1002]'
isAdvancedMode={true} isAdvancedMode={true}
mode={model?.mode} mode={model?.mode}
pluginId={model?.plugin_id}
provider={model?.provider} provider={model?.provider}
completionParams={model?.completion_params} completionParams={model?.completion_params}
modelId={model?.name} modelId={model?.name}

@ -36,13 +36,12 @@ const ModelParameterTrigger: FC<ModelParameterTriggerProps> = ({
const language = useLanguage() const language = useLanguage()
const index = multipleModelConfigs.findIndex(v => v.id === modelAndParameter.id) const index = multipleModelConfigs.findIndex(v => v.id === modelAndParameter.id)
const handleSelectModel = ({ modelId, provider, pluginId }: { modelId: string; provider: string; pluginId: string }) => { const handleSelectModel = ({ modelId, provider }: { modelId: string; provider: string }) => {
const newModelConfigs = [...multipleModelConfigs] const newModelConfigs = [...multipleModelConfigs]
newModelConfigs[index] = { newModelConfigs[index] = {
...newModelConfigs[index], ...newModelConfigs[index],
model: modelId, model: modelId,
provider, provider,
plugin_id: pluginId,
} }
onMultipleModelConfigsChange(true, newModelConfigs) onMultipleModelConfigsChange(true, newModelConfigs)
} }
@ -59,7 +58,6 @@ const ModelParameterTrigger: FC<ModelParameterTriggerProps> = ({
<ModelParameterModal <ModelParameterModal
mode={mode} mode={mode}
isAdvancedMode={isAdvancedMode} isAdvancedMode={isAdvancedMode}
pluginId={modelAndParameter.plugin_id}
provider={modelAndParameter.provider} provider={modelAndParameter.provider}
modelId={modelAndParameter.model} modelId={modelAndParameter.model}
completionParams={modelAndParameter.parameters} completionParams={modelAndParameter.parameters}

@ -1,7 +1,6 @@
export type ModelAndParameter = { export type ModelAndParameter = {
id: string id: string
model: string model: string
plugin_id: string
provider: string provider: string
parameters: Record<string, any> parameters: Record<string, any>
} }

@ -72,7 +72,7 @@ import { SupportUploadFileTypes } from '@/app/components/workflow/types'
import NewFeaturePanel from '@/app/components/base/features/new-feature-panel' import NewFeaturePanel from '@/app/components/base/features/new-feature-panel'
import { fetchFileUploadConfig } from '@/service/common' import { fetchFileUploadConfig } from '@/service/common'
type PublishConfig = { interface PublishConfig {
modelConfig: ModelConfig modelConfig: ModelConfig
completionParams: FormValue completionParams: FormValue
} }
@ -156,7 +156,6 @@ const Configuration: FC = () => {
const setCompletionParams = (value: FormValue) => { const setCompletionParams = (value: FormValue) => {
const params = { ...value } const params = { ...value }
// eslint-disable-next-line ts/no-use-before-define
if ((!params.stop || params.stop.length === 0) && (modeModeTypeRef.current === ModelModeType.completion)) { if ((!params.stop || params.stop.length === 0) && (modeModeTypeRef.current === ModelModeType.completion)) {
params.stop = getTempStop() params.stop = getTempStop()
setTempStop([]) setTempStop([])
@ -165,7 +164,6 @@ const Configuration: FC = () => {
} }
const [modelConfig, doSetModelConfig] = useState<ModelConfig>({ const [modelConfig, doSetModelConfig] = useState<ModelConfig>({
plugin_id: 'langgenius',
provider: 'openai', provider: 'openai',
model_id: 'gpt-3.5-turbo', model_id: 'gpt-3.5-turbo',
mode: ModelModeType.unset, mode: ModelModeType.unset,
@ -200,7 +198,6 @@ const Configuration: FC = () => {
reranking_model: { reranking_model: {
reranking_provider_name: '', reranking_provider_name: '',
reranking_model_name: '', reranking_model_name: '',
reranking_plugin_id: '',
}, },
top_k: DATASET_DEFAULT.top_k, top_k: DATASET_DEFAULT.top_k,
score_threshold_enabled: false, score_threshold_enabled: false,
@ -282,7 +279,6 @@ const Configuration: FC = () => {
reranking_model: restConfigs.reranking_model && { reranking_model: restConfigs.reranking_model && {
reranking_provider_name: restConfigs.reranking_model.reranking_provider_name, reranking_provider_name: restConfigs.reranking_model.reranking_provider_name,
reranking_model_name: restConfigs.reranking_model.reranking_model_name, reranking_model_name: restConfigs.reranking_model.reranking_model_name,
reranking_plugin_id: restConfigs.reranking_model.reranking_plugin_id,
}, },
retrieval_model, retrieval_model,
score_threshold_enabled, score_threshold_enabled,
@ -324,7 +320,6 @@ const Configuration: FC = () => {
textGenerationModelList, textGenerationModelList,
} = useTextGenerationCurrentProviderAndModelAndModelList( } = useTextGenerationCurrentProviderAndModelAndModelList(
{ {
plugin_id: modelConfig.plugin_id,
provider: modelConfig.provider, provider: modelConfig.provider,
model: modelConfig.model_id, model: modelConfig.model_id,
}, },
@ -355,7 +350,6 @@ const Configuration: FC = () => {
const [canReturnToSimpleMode, setCanReturnToSimpleMode] = useState(true) const [canReturnToSimpleMode, setCanReturnToSimpleMode] = useState(true)
const setPromptMode = async (mode: PromptMode) => { const setPromptMode = async (mode: PromptMode) => {
if (mode === PromptMode.advanced) { if (mode === PromptMode.advanced) {
// eslint-disable-next-line ts/no-use-before-define
await migrateToDefaultPrompt() await migrateToDefaultPrompt()
setCanReturnToSimpleMode(true) setCanReturnToSimpleMode(true)
} }
@ -551,7 +545,6 @@ const Configuration: FC = () => {
const config = { const config = {
modelConfig: { modelConfig: {
plugin_id: model.plugin_id,
provider: model.provider, provider: model.provider,
model_id: model.name, model_id: model.name,
mode: model.mode, mode: model.mode,
@ -770,8 +763,8 @@ const Configuration: FC = () => {
handleMultipleModelConfigsChange( handleMultipleModelConfigsChange(
true, true,
[ [
{ id: `${Date.now()}`, model: modelConfig.model_id, plugin_id: modelConfig.plugin_id, provider: modelConfig.provider, parameters: completionParams }, { id: `${Date.now()}`, model: modelConfig.model_id, provider: modelConfig.provider, parameters: completionParams },
{ id: `${Date.now()}-no-repeat`, model: '', plugin_id: '', provider: '', parameters: {} }, { id: `${Date.now()}-no-repeat`, model: '', provider: '', parameters: {} },
], ],
) )
setAppSiderbarExpand('collapse') setAppSiderbarExpand('collapse')
@ -893,7 +886,6 @@ const Configuration: FC = () => {
<ModelParameterModal <ModelParameterModal
isAdvancedMode={isAdvancedMode} isAdvancedMode={isAdvancedMode}
mode={mode} mode={mode}
pluginId={modelConfig.plugin_id}
provider={modelConfig.provider} provider={modelConfig.provider}
completionParams={completionParams} completionParams={completionParams}
modelId={modelConfig.model_id} modelId={modelConfig.model_id}

@ -1,327 +0,0 @@
'use client'
import type { FC } from 'react'
import React, { useEffect, useRef, useState } from 'react'
import produce from 'immer'
import {
RiAddLine,
RiDeleteBinLine,
} from '@remixicon/react'
import { useTranslation } from 'react-i18next'
import { useBoolean } from 'ahooks'
import { ReactSortable } from 'react-sortablejs'
import {
useFeatures,
useFeaturesStore,
} from '../../hooks'
import type { OnFeaturesChange } from '../../types'
import cn from '@/utils/classnames'
import Panel from '@/app/components/app/configuration/base/feature-panel'
import Button from '@/app/components/base/button'
import OperationBtn from '@/app/components/app/configuration/base/operation-btn'
import { getInputKeys } from '@/app/components/base/block-input'
import ConfirmAddVar from '@/app/components/app/configuration/config-prompt/confirm-add-var'
import { getNewVar } from '@/utils/var'
import { varHighlightHTML } from '@/app/components/app/configuration/base/var-highlight'
import type { PromptVariable } from '@/models/debug'
import type { InputVar } from '@/app/components/workflow/types'
const MAX_QUESTION_NUM = 5
export type OpeningStatementProps = {
onChange?: OnFeaturesChange
readonly?: boolean
promptVariables?: PromptVariable[]
onAutoAddPromptVariable: (variable: PromptVariable[]) => void
workflowVariables?: InputVar[]
}
// regex to match the {{}} and replace it with a span
const regex = /\{\{([^}]+)\}\}/g
const OpeningStatement: FC<OpeningStatementProps> = ({
onChange,
readonly,
promptVariables = [],
onAutoAddPromptVariable,
workflowVariables = [],
}) => {
const { t } = useTranslation()
const featureStore = useFeaturesStore()
const openingStatement = useFeatures(s => s.features.opening)
const value = openingStatement?.opening_statement || ''
const suggestedQuestions = openingStatement?.suggested_questions || []
const [notIncludeKeys, setNotIncludeKeys] = useState<string[]>([])
const hasValue = !!(value || '').trim()
const inputRef = useRef<HTMLTextAreaElement>(null)
const [isFocus, { setTrue: didSetFocus, setFalse: setBlur }] = useBoolean(false)
const setFocus = () => {
didSetFocus()
setTimeout(() => {
const input = inputRef.current
if (input) {
input.focus()
input.setSelectionRange(input.value.length, input.value.length)
}
}, 0)
}
const [tempValue, setTempValue] = useState(value)
useEffect(() => {
setTempValue(value || '')
}, [value])
const [tempSuggestedQuestions, setTempSuggestedQuestions] = useState(suggestedQuestions || [])
const notEmptyQuestions = tempSuggestedQuestions.filter(question => !!question && question.trim())
const coloredContent = (tempValue || '')
.replace(/</g, '&lt;')
.replace(/>/g, '&gt;')
.replace(regex, varHighlightHTML({ name: '$1' })) // `<span class="${highLightClassName}">{{$1}}</span>`
.replace(/\n/g, '<br />')
const handleEdit = () => {
if (readonly)
return
setFocus()
}
const [isShowConfirmAddVar, { setTrue: showConfirmAddVar, setFalse: hideConfirmAddVar }] = useBoolean(false)
const handleCancel = () => {
setBlur()
setTempValue(value)
setTempSuggestedQuestions(suggestedQuestions)
}
const handleConfirm = () => {
const keys = getInputKeys(tempValue)
const promptKeys = promptVariables.map(item => item.key)
const workflowVariableKeys = workflowVariables.map(item => item.variable)
let notIncludeKeys: string[] = []
if (promptKeys.length === 0 && workflowVariables.length === 0) {
if (keys.length > 0)
notIncludeKeys = keys
}
else {
if (workflowVariables.length > 0)
notIncludeKeys = keys.filter(key => !workflowVariableKeys.includes(key))
else notIncludeKeys = keys.filter(key => !promptKeys.includes(key))
}
if (notIncludeKeys.length > 0) {
setNotIncludeKeys(notIncludeKeys)
showConfirmAddVar()
return
}
setBlur()
const { getState } = featureStore!
const {
features,
setFeatures,
} = getState()
const newFeatures = produce(features, (draft) => {
if (draft.opening) {
draft.opening.opening_statement = tempValue
draft.opening.suggested_questions = tempSuggestedQuestions
}
})
setFeatures(newFeatures)
if (onChange)
onChange(newFeatures)
}
const cancelAutoAddVar = () => {
const { getState } = featureStore!
const {
features,
setFeatures,
} = getState()
const newFeatures = produce(features, (draft) => {
if (draft.opening)
draft.opening.opening_statement = tempValue
})
setFeatures(newFeatures)
if (onChange)
onChange(newFeatures)
hideConfirmAddVar()
setBlur()
}
const autoAddVar = () => {
const { getState } = featureStore!
const {
features,
setFeatures,
} = getState()
const newFeatures = produce(features, (draft) => {
if (draft.opening)
draft.opening.opening_statement = tempValue
})
setFeatures(newFeatures)
if (onChange)
onChange(newFeatures)
onAutoAddPromptVariable([...notIncludeKeys.map(key => getNewVar(key, 'string'))])
hideConfirmAddVar()
setBlur()
}
const headerRight = !readonly ? (
isFocus ? (
<div className='flex items-center space-x-1'>
<Button
variant='ghost'
size='small'
onClick={handleCancel}
>
{t('common.operation.cancel')}
</Button>
<Button size='small' onClick={handleConfirm} variant="primary">{t('common.operation.save')}</Button>
</div>
) : (
<OperationBtn type='edit' actionName={hasValue ? '' : t('appDebug.openingStatement.writeOpener') as string} onClick={handleEdit} />
)
) : null
const renderQuestions = () => {
return isFocus ? (
<div>
<div className='flex items-center py-2'>
<div className='shrink-0 flex space-x-0.5 leading-[18px] text-xs font-medium text-gray-500'>
<div className='uppercase'>{t('appDebug.openingStatement.openingQuestion')}</div>
<div>·</div>
<div>{tempSuggestedQuestions.length}/{MAX_QUESTION_NUM}</div>
</div>
<div className='ml-3 grow w-0 h-px bg-[#243, 244, 246]'></div>
</div>
<ReactSortable
className="space-y-1"
list={tempSuggestedQuestions.map((name, index) => {
return {
id: index,
name,
}
})}
setList={list => setTempSuggestedQuestions(list.map(item => item.name))}
handle='.handle'
ghostClass="opacity-50"
animation={150}
>
{tempSuggestedQuestions.map((question, index) => {
return (
<div className='group relative rounded-lg border border-gray-200 flex items-center pl-2.5 hover:border-gray-300 hover:bg-white' key={index}>
<div className='handle flex items-center justify-center w-4 h-4 cursor-grab'>
<svg width="6" height="10" viewBox="0 0 6 10" fill="none" xmlns="http://www.w3.org/2000/svg">
<path fillRule="evenodd" clipRule="evenodd" d="M1 2C1.55228 2 2 1.55228 2 1C2 0.447715 1.55228 0 1 0C0.447715 0 0 0.447715 0 1C0 1.55228 0.447715 2 1 2ZM1 6C1.55228 6 2 5.55228 2 5C2 4.44772 1.55228 4 1 4C0.447715 4 0 4.44772 0 5C0 5.55228 0.447715 6 1 6ZM6 1C6 1.55228 5.55228 2 5 2C4.44772 2 4 1.55228 4 1C4 0.447715 4.44772 0 5 0C5.55228 0 6 0.447715 6 1ZM5 6C5.55228 6 6 5.55228 6 5C6 4.44772 5.55228 4 5 4C4.44772 4 4 4.44772 4 5C4 5.55228 4.44772 6 5 6ZM2 9C2 9.55229 1.55228 10 1 10C0.447715 10 0 9.55229 0 9C0 8.44771 0.447715 8 1 8C1.55228 8 2 8.44771 2 9ZM5 10C5.55228 10 6 9.55229 6 9C6 8.44771 5.55228 8 5 8C4.44772 8 4 8.44771 4 9C4 9.55229 4.44772 10 5 10Z" fill="#98A2B3" />
</svg>
</div>
<input
type="input"
value={question || ''}
onChange={(e) => {
const value = e.target.value
setTempSuggestedQuestions(tempSuggestedQuestions.map((item, i) => {
if (index === i)
return value
return item
}))
}}
className={'w-full overflow-x-auto pl-1.5 pr-8 text-sm leading-9 text-gray-900 border-0 grow h-9 bg-transparent focus:outline-none cursor-pointer rounded-lg'}
/>
<div
className='block absolute top-1/2 translate-y-[-50%] right-1.5 p-1 rounded-md cursor-pointer hover:bg-[#FEE4E2] hover:text-[#D92D20]'
onClick={() => {
setTempSuggestedQuestions(tempSuggestedQuestions.filter((_, i) => index !== i))
}}
>
<RiDeleteBinLine className='w-3.5 h-3.5' />
</div>
</div>
)
})}</ReactSortable>
{tempSuggestedQuestions.length < MAX_QUESTION_NUM && (
<div
onClick={() => { setTempSuggestedQuestions([...tempSuggestedQuestions, '']) }}
className='mt-1 flex items-center h-9 px-3 gap-2 rounded-lg cursor-pointer text-gray-400 bg-gray-100 hover:bg-gray-200'>
<RiAddLine className='w-4 h-4' />
<div className='text-gray-500 text-[13px]'>{t('appDebug.variableConfig.addOption')}</div>
</div>
)}
</div>
) : (
<div className='mt-1.5 flex flex-wrap'>
{notEmptyQuestions.map((question, index) => {
return (
<div key={index} className='mt-1 mr-1 max-w-full truncate last:mr-0 shrink-0 leading-8 items-center px-2.5 rounded-lg border border-gray-200 shadow-xs bg-white text-[13px] font-normal text-gray-900 cursor-pointer'>
{question}
</div>
)
})}
</div>
)
}
return (
<Panel
className={cn(isShowConfirmAddVar && 'h-[220px]', 'relative !bg-gray-25')}
title={t('appDebug.openingStatement.title')}
headerIcon={
<svg width="16" height="16" viewBox="0 0 16 16" fill="none" xmlns="http://www.w3.org/2000/svg">
<path fillRule="evenodd" clipRule="evenodd" d="M8.33353 1.33301C4.83572 1.33301 2.00019 4.16854 2.00019 7.66634C2.00019 8.37301 2.11619 9.05395 2.3307 9.69036C2.36843 9.80229 2.39063 9.86853 2.40507 9.91738L2.40979 9.93383L2.40729 9.93903C2.39015 9.97437 2.36469 10.0218 2.31705 10.11L1.2158 12.1484C1.14755 12.2746 1.07633 12.4064 1.02735 12.5209C0.978668 12.6348 0.899813 12.8437 0.938613 13.0914C0.984094 13.3817 1.15495 13.6373 1.40581 13.7903C1.61981 13.9208 1.843 13.9279 1.96683 13.9264C2.09141 13.925 2.24036 13.9095 2.38314 13.8947L5.81978 13.5395C5.87482 13.5338 5.9036 13.5309 5.92468 13.5292L5.92739 13.529L5.93564 13.532C5.96154 13.5413 5.99666 13.5548 6.0573 13.5781C6.76459 13.8506 7.53244 13.9997 8.33353 13.9997C11.8313 13.9997 14.6669 11.1641 14.6669 7.66634C14.6669 4.16854 11.8313 1.33301 8.33353 1.33301ZM5.9799 5.72116C6.73142 5.08698 7.73164 5.27327 8.33144 5.96584C8.93125 5.27327 9.91854 5.09365 10.683 5.72116C11.4474 6.34867 11.5403 7.41567 10.9501 8.16572C10.5845 8.6304 9.6668 9.47911 9.02142 10.0576C8.78435 10.2702 8.66582 10.3764 8.52357 10.4192C8.40154 10.456 8.26134 10.456 8.13931 10.4192C7.99706 10.3764 7.87853 10.2702 7.64147 10.0576C6.99609 9.47911 6.07839 8.6304 5.71276 8.16572C5.12259 7.41567 5.22839 6.35534 5.9799 5.72116Z" fill="#E74694" />
</svg>
}
headerRight={headerRight}
hasHeaderBottomBorder={!hasValue}
isFocus={isFocus}
>
<div className='text-gray-700 text-sm'>
{(hasValue || (!hasValue && isFocus)) ? (
<>
{isFocus
? (
<div>
<textarea
ref={inputRef}
value={tempValue}
rows={3}
onChange={e => setTempValue(e.target.value)}
className="w-full px-0 text-sm border-0 bg-transparent focus:outline-none "
placeholder={t('appDebug.openingStatement.placeholder') as string}
>
</textarea>
</div>
)
: (
<div dangerouslySetInnerHTML={{
__html: coloredContent,
}}></div>
)}
{renderQuestions()}
</>) : (
<div className='pt-2 pb-1 text-xs text-gray-500'>{t('appDebug.openingStatement.noDataPlaceHolder')}</div>
)}
{isShowConfirmAddVar && (
<ConfirmAddVar
varNameArr={notIncludeKeys}
onConfirm={autoAddVar}
onCancel={cancelAutoAddVar}
onHide={hideConfirmAddVar}
/>
)}
</div>
</Panel>
)
}
export default React.memo(OpeningStatement)

@ -18,7 +18,6 @@ type Props = {
isShow: boolean isShow: boolean
onHide: () => void onHide: () => void
onSave: (embeddingModel: { onSave: (embeddingModel: {
plugin_id: string
embedding_provider_name: string embedding_provider_name: string
embedding_model_name: string embedding_model_name: string
}, score: number) => void }, score: number) => void
@ -44,13 +43,11 @@ const ConfigParamModal: FC<Props> = ({
const [isLoading, setLoading] = useState(false) const [isLoading, setLoading] = useState(false)
const [embeddingModel, setEmbeddingModel] = useState(oldAnnotationConfig.embedding_model const [embeddingModel, setEmbeddingModel] = useState(oldAnnotationConfig.embedding_model
? { ? {
plugin_id: oldAnnotationConfig.embedding_model.plugin_id,
providerName: oldAnnotationConfig.embedding_model.embedding_provider_name, providerName: oldAnnotationConfig.embedding_model.embedding_provider_name,
modelName: oldAnnotationConfig.embedding_model.embedding_model_name, modelName: oldAnnotationConfig.embedding_model.embedding_model_name,
} }
: (embeddingsDefaultModel : (embeddingsDefaultModel
? { ? {
plugin_id: embeddingsDefaultModel.provider.plugin_id,
providerName: embeddingsDefaultModel.provider.provider, providerName: embeddingsDefaultModel.provider.provider,
modelName: embeddingsDefaultModel.model, modelName: embeddingsDefaultModel.model,
} }
@ -70,7 +67,6 @@ const ConfigParamModal: FC<Props> = ({
} }
setLoading(true) setLoading(true)
await onSave({ await onSave({
plugin_id: embeddingModel.plugin_id,
embedding_provider_name: embeddingModel.providerName, embedding_provider_name: embeddingModel.providerName,
embedding_model_name: embeddingModel.modelName, embedding_model_name: embeddingModel.modelName,
}, annotationConfig.score_threshold) }, annotationConfig.score_threshold)
@ -111,14 +107,12 @@ const ConfigParamModal: FC<Props> = ({
<div className='pt-1'> <div className='pt-1'>
<ModelSelector <ModelSelector
defaultModel={embeddingModel && { defaultModel={embeddingModel && {
plugin_id: '',
provider: embeddingModel.providerName, provider: embeddingModel.providerName,
model: embeddingModel.modelName, model: embeddingModel.modelName,
}} }}
modelList={embeddingsModelList} modelList={embeddingsModelList}
onSelect={(val) => { onSelect={(val) => {
setEmbeddingModel({ setEmbeddingModel({
plugin_id: val.plugin_id,
providerName: val.provider, providerName: val.provider,
modelName: val.model, modelName: val.model,
}) })

@ -199,13 +199,13 @@ export default function AccountSetting({
)} )}
</div> </div>
<div className='px-4 sm:px-8 pt-2'> <div className='px-4 sm:px-8 pt-2'>
{activeMenu === 'provider' && <ModelProviderPage searchText={searchValue} />}
{activeMenu === 'members' && <MembersPage />} {activeMenu === 'members' && <MembersPage />}
{activeMenu === 'billing' && <BillingPage />} {activeMenu === 'billing' && <BillingPage />}
{activeMenu === 'language' && <LanguagePage />}
{activeMenu === 'provider' && <ModelProviderPage />}
{activeMenu === 'data-source' && <DataSourcePage />} {activeMenu === 'data-source' && <DataSourcePage />}
{activeMenu === 'api-based-extension' && <ApiBasedExtensionPage />} {activeMenu === 'api-based-extension' && <ApiBasedExtensionPage />}
{activeMenu === 'custom' && <CustomPage />} {activeMenu === 'custom' && <CustomPage />}
{activeMenu === 'language' && <LanguagePage />}
</div> </div>
</div> </div>
</div> </div>

@ -1,6 +1,6 @@
export type FormValue = Record<string, any> export type FormValue = Record<string, any>
export type TypeWithI18N<T = string> = { export interface TypeWithI18N<T = string> {
en_US: T en_US: T
zh_Hans: T zh_Hans: T
[key: string]: T [key: string]: T
@ -17,7 +17,7 @@ export enum FormTypeEnum {
file = 'file', file = 'file',
} }
export type FormOption = { export interface FormOption {
label: TypeWithI18N label: TypeWithI18N
value: string value: string
show_on: FormShowOnObject[] show_on: FormShowOnObject[]
@ -89,12 +89,12 @@ export enum CustomConfigurationStatusEnum {
noConfigure = 'no-configure', noConfigure = 'no-configure',
} }
export type FormShowOnObject = { export interface FormShowOnObject {
variable: string variable: string
value: string value: string
} }
export type CredentialFormSchemaBase = { export interface CredentialFormSchemaBase {
variable: string variable: string
label: TypeWithI18N label: TypeWithI18N
type: FormTypeEnum type: FormTypeEnum
@ -112,7 +112,7 @@ export type CredentialFormSchemaRadio = CredentialFormSchemaBase & { options: Fo
export type CredentialFormSchemaSecretInput = CredentialFormSchemaBase & { placeholder?: TypeWithI18N } export type CredentialFormSchemaSecretInput = CredentialFormSchemaBase & { placeholder?: TypeWithI18N }
export type CredentialFormSchema = CredentialFormSchemaTextInput | CredentialFormSchemaSelect | CredentialFormSchemaRadio | CredentialFormSchemaSecretInput export type CredentialFormSchema = CredentialFormSchemaTextInput | CredentialFormSchemaSelect | CredentialFormSchemaRadio | CredentialFormSchemaSecretInput
export type ModelItem = { export interface ModelItem {
model: string model: string
label: TypeWithI18N label: TypeWithI18N
model_type: ModelTypeEnum model_type: ModelTypeEnum
@ -141,7 +141,7 @@ export enum QuotaUnitEnum {
credits = 'credits', credits = 'credits',
} }
export type QuotaConfiguration = { export interface QuotaConfiguration {
quota_type: CurrentSystemQuotaTypeEnum quota_type: CurrentSystemQuotaTypeEnum
quota_unit: QuotaUnitEnum quota_unit: QuotaUnitEnum
quota_limit: number quota_limit: number
@ -150,8 +150,7 @@ export type QuotaConfiguration = {
is_valid: boolean is_valid: boolean
} }
export type ModelProvider = { export interface ModelProvider {
plugin_id: string
provider: string provider: string
label: TypeWithI18N label: TypeWithI18N
description?: TypeWithI18N description?: TypeWithI18N
@ -185,8 +184,7 @@ export type ModelProvider = {
} }
} }
export type Model = { export interface Model {
plugin_id: string
provider: string provider: string
icon_large: TypeWithI18N icon_large: TypeWithI18N
icon_small: TypeWithI18N icon_small: TypeWithI18N
@ -195,29 +193,27 @@ export type Model = {
status: ModelStatusEnum status: ModelStatusEnum
} }
export type DefaultModelResponse = { export interface DefaultModelResponse {
model: string model: string
model_type: ModelTypeEnum model_type: ModelTypeEnum
provider: { provider: {
plugin_id: string
provider: string provider: string
icon_large: TypeWithI18N icon_large: TypeWithI18N
icon_small: TypeWithI18N icon_small: TypeWithI18N
} }
} }
export type DefaultModel = { export interface DefaultModel {
plugin_id: string
provider: string provider: string
model: string model: string
} }
export type CustomConfigurationModelFixedFields = { export interface CustomConfigurationModelFixedFields {
__model_name: string __model_name: string
__model_type: ModelTypeEnum __model_type: ModelTypeEnum
} }
export type ModelParameterRule = { export interface ModelParameterRule {
default?: number | string | boolean | string[] default?: number | string | boolean | string[]
help?: TypeWithI18N help?: TypeWithI18N
label: TypeWithI18N label: TypeWithI18N
@ -232,7 +228,7 @@ export type ModelParameterRule = {
tagPlaceholder?: TypeWithI18N tagPlaceholder?: TypeWithI18N
} }
export type ModelLoadBalancingConfigEntry = { export interface ModelLoadBalancingConfigEntry {
/** model balancing config entry id */ /** model balancing config entry id */
id?: string id?: string
/** is config entry enabled */ /** is config entry enabled */
@ -247,7 +243,7 @@ export type ModelLoadBalancingConfigEntry = {
ttl?: number ttl?: number
} }
export type ModelLoadBalancingConfig = { export interface ModelLoadBalancingConfig {
enabled: boolean enabled: boolean
configs: ModelLoadBalancingConfigEntry[] configs: ModelLoadBalancingConfigEntry[]
} }

@ -11,7 +11,6 @@ import type {
DefaultModel, DefaultModel,
DefaultModelResponse, DefaultModelResponse,
Model, Model,
ModelProvider,
ModelTypeEnum, ModelTypeEnum,
} from './declarations' } from './declarations'
import { import {
@ -37,12 +36,11 @@ export const useSystemDefaultModelAndModelList: UseDefaultModelAndModelList = (
modelList, modelList,
) => { ) => {
const currentDefaultModel = useMemo(() => { const currentDefaultModel = useMemo(() => {
const currentProvider = modelList.find(provider => provider.provider === defaultModel?.provider.provider && provider.plugin_id === defaultModel?.provider.plugin_id) const currentProvider = modelList.find(provider => provider.provider === defaultModel?.provider.provider)
const currentModel = currentProvider?.models.find(model => model.model === defaultModel?.model) const currentModel = currentProvider?.models.find(model => model.model === defaultModel?.model)
const currentDefaultModel = currentProvider && currentModel && { const currentDefaultModel = currentProvider && currentModel && {
model: currentModel.model, model: currentModel.model,
provider: currentProvider.provider, provider: currentProvider.provider,
plugin_id: currentProvider.plugin_id,
} }
return currentDefaultModel return currentDefaultModel
@ -64,20 +62,20 @@ export const useLanguage = () => {
} }
export const useProviderCredentialsAndLoadBalancing = ( export const useProviderCredentialsAndLoadBalancing = (
provider: ModelProvider, provider: string,
configurationMethod: ConfigurationMethodEnum, configurationMethod: ConfigurationMethodEnum,
configured?: boolean, configured?: boolean,
currentCustomConfigurationModelFixedFields?: CustomConfigurationModelFixedFields, currentCustomConfigurationModelFixedFields?: CustomConfigurationModelFixedFields,
) => { ) => {
const { data: predefinedFormSchemasValue, mutate: mutatePredefined } = useSWR( const { data: predefinedFormSchemasValue, mutate: mutatePredefined } = useSWR(
(configurationMethod === ConfigurationMethodEnum.predefinedModel && configured) (configurationMethod === ConfigurationMethodEnum.predefinedModel && configured)
? `/workspaces/current/model-providers/${provider.plugin_id}/${provider.provider}/credentials` ? `/workspaces/current/model-providers/${provider}/credentials`
: null, : null,
fetchModelProviderCredentials, fetchModelProviderCredentials,
) )
const { data: customFormSchemasValue, mutate: mutateCustomized } = useSWR( const { data: customFormSchemasValue, mutate: mutateCustomized } = useSWR(
(configurationMethod === ConfigurationMethodEnum.customizableModel && currentCustomConfigurationModelFixedFields) (configurationMethod === ConfigurationMethodEnum.customizableModel && currentCustomConfigurationModelFixedFields)
? `/workspaces/current/model-providers/${provider.plugin_id}/${provider.provider}/models/credentials?model=${currentCustomConfigurationModelFixedFields?.__model_name}&model_type=${currentCustomConfigurationModelFixedFields?.__model_type}` ? `/workspaces/current/model-providers/${provider}/models/credentials?model=${currentCustomConfigurationModelFixedFields?.__model_name}&model_type=${currentCustomConfigurationModelFixedFields?.__model_type}`
: null, : null,
fetchModelProviderCredentials, fetchModelProviderCredentials,
) )
@ -174,11 +172,7 @@ export const useModelListAndDefaultModelAndCurrentProviderAndModel = (type: Mode
const { modelList, defaultModel } = useModelListAndDefaultModel(type) const { modelList, defaultModel } = useModelListAndDefaultModel(type)
const { currentProvider, currentModel } = useCurrentProviderAndModel( const { currentProvider, currentModel } = useCurrentProviderAndModel(
modelList, modelList,
{ { provider: defaultModel?.provider.provider || '', model: defaultModel?.model || '' },
plugin_id: defaultModel?.provider.plugin_id || '',
provider: defaultModel?.provider.provider || '',
model: defaultModel?.model || '',
},
) )
return { return {
@ -199,7 +193,6 @@ export const useUpdateModelList = () => {
return updateModelList return updateModelList
} }
// deprecated ???
export const useAnthropicBuyQuota = () => { export const useAnthropicBuyQuota = () => {
const [loading, setLoading] = useState(false) const [loading, setLoading] = useState(false)

@ -1,16 +1,15 @@
import { useMemo, useState } from 'react' import { useEffect, useMemo, useState } from 'react'
import { useTranslation } from 'react-i18next' import { useTranslation } from 'react-i18next'
import Link from 'next/link' import Link from 'next/link'
import { useDebounce } from 'ahooks'
import { import {
RiAlertFill, RiAlertFill,
RiArrowDownSLine, RiArrowDownSLine,
RiArrowRightUpLine, RiArrowRightUpLine,
RiBrainLine, RiBrainLine,
} from '@remixicon/react' } from '@remixicon/react'
import { useContext } from 'use-context-selector'
import SystemModelSelector from './system-model-selector' import SystemModelSelector from './system-model-selector'
import ProviderAddedCard, { UPDATE_MODEL_PROVIDER_CUSTOM_MODEL_LIST } from './provider-added-card' import ProviderAddedCard, { UPDATE_MODEL_PROVIDER_CUSTOM_MODEL_LIST } from './provider-added-card'
// import ProviderCard from './provider-card'
import type { import type {
CustomConfigurationModelFixedFields, CustomConfigurationModelFixedFields,
ModelProvider, ModelProvider,
@ -26,16 +25,24 @@ import {
useUpdateModelProviders, useUpdateModelProviders,
} from './hooks' } from './hooks'
import Divider from '@/app/components/base/divider' import Divider from '@/app/components/base/divider'
import Loading from '@/app/components/base/loading'
import ProviderCard from '@/app/components/plugins/provider-card' import ProviderCard from '@/app/components/plugins/provider-card'
import I18n from '@/context/i18n'
import { useProviderContext } from '@/context/provider-context' import { useProviderContext } from '@/context/provider-context'
import { useModalContextSelector } from '@/context/modal-context' import { useModalContextSelector } from '@/context/modal-context'
import { useEventEmitterContextContext } from '@/context/event-emitter' import { useEventEmitterContextContext } from '@/context/event-emitter'
import {
useMarketplacePlugins,
} from '@/app/components/plugins/marketplace/hooks'
import { PluginType } from '@/app/components/plugins/types'
import { MARKETPLACE_URL_PREFIX } from '@/config'
import cn from '@/utils/classnames' import cn from '@/utils/classnames'
import { extensionDallE, modelGPT4, toolNotion } from '@/app/components/plugins/card/card-mock' type Props = {
searchText: string
}
const ModelProviderPage = () => { const ModelProviderPage = ({ searchText }: Props) => {
const debouncedSearchText = useDebounce(searchText, { wait: 500 })
const { t } = useTranslation() const { t } = useTranslation()
const { eventEmitter } = useEventEmitterContextContext() const { eventEmitter } = useEventEmitterContextContext()
const updateModelProviders = useUpdateModelProviders() const updateModelProviders = useUpdateModelProviders()
@ -67,6 +74,18 @@ const ModelProviderPage = () => {
return [configuredProviders, notConfiguredProviders] return [configuredProviders, notConfiguredProviders]
}, [providers]) }, [providers])
const [filteredConfiguredProviders, filteredNotConfiguredProviders] = useMemo(() => {
const filteredConfiguredProviders = configuredProviders.filter(
provider => provider.provider.toLowerCase().includes(debouncedSearchText.toLowerCase())
|| Object.values(provider.label).some(text => text.toLowerCase().includes(debouncedSearchText.toLowerCase())),
)
const filteredNotConfiguredProviders = notConfiguredProviders.filter(
provider => provider.provider.toLowerCase().includes(debouncedSearchText.toLowerCase())
|| Object.values(provider.label).some(text => text.toLowerCase().includes(debouncedSearchText.toLowerCase())),
)
return [filteredConfiguredProviders, filteredNotConfiguredProviders]
}, [configuredProviders, debouncedSearchText, notConfiguredProviders])
const handleOpenModal = ( const handleOpenModal = (
provider: ModelProvider, provider: ModelProvider,
@ -91,7 +110,7 @@ const ModelProviderPage = () => {
if (configurationMethod === ConfigurationMethodEnum.customizableModel && provider.custom_configuration.status === CustomConfigurationStatusEnum.active) { if (configurationMethod === ConfigurationMethodEnum.customizableModel && provider.custom_configuration.status === CustomConfigurationStatusEnum.active) {
eventEmitter?.emit({ eventEmitter?.emit({
type: UPDATE_MODEL_PROVIDER_CUSTOM_MODEL_LIST, type: UPDATE_MODEL_PROVIDER_CUSTOM_MODEL_LIST,
payload: provider, payload: provider.provider,
} as any) } as any)
if (CustomConfigurationModelFixedFields?.__model_type) if (CustomConfigurationModelFixedFields?.__model_type)
@ -102,10 +121,28 @@ const ModelProviderPage = () => {
} }
const [collapse, setCollapse] = useState(false) const [collapse, setCollapse] = useState(false)
const { locale } = useContext(I18n)
// TODO #Plugin list API# const {
const pluginList = [toolNotion, extensionDallE, modelGPT4] plugins,
queryPlugins,
queryPluginsWithDebounced,
isLoading: isPluginsLoading,
} = useMarketplacePlugins()
useEffect(() => {
if (searchText) {
queryPluginsWithDebounced({
query: searchText,
category: PluginType.model,
})
}
else {
queryPlugins({
query: searchText,
category: PluginType.model,
})
}
}, [queryPlugins, queryPluginsWithDebounced, searchText])
return ( return (
<div className='relative pt-1 -mt-2'> <div className='relative pt-1 -mt-2'>
@ -132,7 +169,7 @@ const ModelProviderPage = () => {
/> />
</div> </div>
</div> </div>
{!configuredProviders?.length && ( {!filteredConfiguredProviders?.length && (
<div className='mb-2 p-4 rounded-[10px]' style={{ background: 'linear-gradient(90deg, rgba(200, 206, 218, 0.20) 0%, rgba(200, 206, 218, 0.04) 100%)' }}> <div className='mb-2 p-4 rounded-[10px]' style={{ background: 'linear-gradient(90deg, rgba(200, 206, 218, 0.20) 0%, rgba(200, 206, 218, 0.04) 100%)' }}>
<div className='w-10 h-10 flex items-center justify-center rounded-[10px] border-[0.5px] border-components-card-border bg-components-card-bg shadow-lg backdrop-blur'> <div className='w-10 h-10 flex items-center justify-center rounded-[10px] border-[0.5px] border-components-card-border bg-components-card-bg shadow-lg backdrop-blur'>
<RiBrainLine className='w-5 h-5 text-text-primary' /> <RiBrainLine className='w-5 h-5 text-text-primary' />
@ -141,9 +178,9 @@ const ModelProviderPage = () => {
<div className='mt-1 text-text-tertiary system-xs-regular'>{t('common.modelProvider.emptyProviderTip')}</div> <div className='mt-1 text-text-tertiary system-xs-regular'>{t('common.modelProvider.emptyProviderTip')}</div>
</div> </div>
)} )}
{!!configuredProviders?.length && ( {!!filteredConfiguredProviders?.length && (
<div className='relative'> <div className='relative'>
{configuredProviders?.map(provider => ( {filteredConfiguredProviders?.map(provider => (
<ProviderAddedCard <ProviderAddedCard
key={provider.provider} key={provider.provider}
provider={provider} provider={provider}
@ -152,11 +189,11 @@ const ModelProviderPage = () => {
))} ))}
</div> </div>
)} )}
{false && !!notConfiguredProviders?.length && ( {!!filteredNotConfiguredProviders?.length && (
<> <>
<div className='flex items-center mb-2 pt-2 text-text-primary system-md-semibold'>{t('common.modelProvider.configureRequired')}</div> <div className='flex items-center mb-2 pt-2 text-text-primary system-md-semibold'>{t('common.modelProvider.configureRequired')}</div>
<div className='relative'> <div className='relative'>
{notConfiguredProviders?.map(provider => ( {filteredNotConfiguredProviders?.map(provider => (
<ProviderAddedCard <ProviderAddedCard
notConfigured notConfigured
key={provider.provider} key={provider.provider}
@ -176,19 +213,20 @@ const ModelProviderPage = () => {
</div> </div>
<div className='flex items-center mb-2 pt-2'> <div className='flex items-center mb-2 pt-2'>
<span className='pr-1 text-text-tertiary system-sm-regular'>{t('common.modelProvider.discoverMore')}</span> <span className='pr-1 text-text-tertiary system-sm-regular'>{t('common.modelProvider.discoverMore')}</span>
<Link target="_blank" href="/plugins" className='inline-flex items-center system-sm-medium text-text-accent'> <Link target="_blank" href={`${MARKETPLACE_URL_PREFIX}`} className='inline-flex items-center system-sm-medium text-text-accent'>
Dify Marketplace Dify Marketplace
<RiArrowRightUpLine className='w-4 h-4' /> <RiArrowRightUpLine className='w-4 h-4' />
</Link> </Link>
</div> </div>
</div> </div>
{!collapse && ( {!collapse && !isPluginsLoading && (
<div className='grid grid-cols-2 gap-2'> <div className='grid grid-cols-2 gap-2'>
{pluginList.map((plugin, index) => ( {plugins.map(plugin => (
<ProviderCard key={index} installed={false} payload={plugin as any} /> <ProviderCard key={plugin.plugin_id} payload={plugin} />
))} ))}
</div> </div>
)} )}
{!collapse && isPluginsLoading && <Loading type='area' />}
</div> </div>
</div> </div>
) )

@ -72,7 +72,7 @@ const ModelModal: FC<ModelModalProps> = ({
loadBalancing: originalConfig, loadBalancing: originalConfig,
mutate, mutate,
} = useProviderCredentialsAndLoadBalancing( } = useProviderCredentialsAndLoadBalancing(
provider, provider.provider,
configurateMethod, configurateMethod,
providerFormSchemaPredefined && provider.custom_configuration.status === CustomConfigurationStatusEnum.active, providerFormSchemaPredefined && provider.custom_configuration.status === CustomConfigurationStatusEnum.active,
currentCustomConfigurationModelFixedFields, currentCustomConfigurationModelFixedFields,
@ -229,7 +229,6 @@ const ModelModal: FC<ModelModalProps> = ({
setLoading(true) setLoading(true)
const res = await saveCredentials( const res = await saveCredentials(
providerFormSchemaPredefined, providerFormSchemaPredefined,
provider.plugin_id,
provider.provider, provider.provider,
encodeSecretValues(value), encodeSecretValues(value),
{ {
@ -256,7 +255,6 @@ const ModelModal: FC<ModelModalProps> = ({
const res = await removeCredentials( const res = await removeCredentials(
providerFormSchemaPredefined, providerFormSchemaPredefined,
provider.plugin_id,
provider.provider, provider.provider,
value, value,
) )

@ -209,7 +209,6 @@ const ModelLoadBalancingEntryModal: FC<ModelModalProps> = ({
const res = await validateLoadBalancingCredentials( const res = await validateLoadBalancingCredentials(
providerFormSchemaPredefined, providerFormSchemaPredefined,
provider.plugin_id,
provider.provider, provider.provider,
{ {
...value, ...value,

@ -38,9 +38,8 @@ export type ModelParameterModalProps = {
isAdvancedMode: boolean isAdvancedMode: boolean
mode: string mode: string
modelId: string modelId: string
pluginId: string
provider: string provider: string
setModel: (model: { modelId: string; provider: string; pluginId: string; mode?: string; features?: string[] }) => void setModel: (model: { modelId: string; provider: string; mode?: string; features?: string[] }) => void
completionParams: FormValue completionParams: FormValue
onCompletionParamsChange: (newParams: FormValue) => void onCompletionParamsChange: (newParams: FormValue) => void
hideDebugWithMultipleModel?: boolean hideDebugWithMultipleModel?: boolean
@ -75,7 +74,6 @@ const ModelParameterModal: FC<ModelParameterModalProps> = ({
portalToFollowElemContentClassName, portalToFollowElemContentClassName,
isAdvancedMode, isAdvancedMode,
modelId, modelId,
pluginId,
provider, provider,
setModel, setModel,
completionParams, completionParams,
@ -90,17 +88,13 @@ const ModelParameterModal: FC<ModelParameterModalProps> = ({
const { t } = useTranslation() const { t } = useTranslation()
const { isAPIKeySet } = useProviderContext() const { isAPIKeySet } = useProviderContext()
const [open, setOpen] = useState(false) const [open, setOpen] = useState(false)
const { data: parameterRulesData, isLoading } = useSWR((provider && modelId) ? `/workspaces/current/model-providers/${pluginId}/${provider}/models/parameter-rules?model=${modelId}` : null, fetchModelParameterRules) const { data: parameterRulesData, isLoading } = useSWR((provider && modelId) ? `/workspaces/current/model-providers/${provider}/models/parameter-rules?model=${modelId}` : null, fetchModelParameterRules)
const { const {
currentProvider, currentProvider,
currentModel, currentModel,
activeTextGenerationModelList, activeTextGenerationModelList,
} = useTextGenerationCurrentProviderAndModelAndModelList( } = useTextGenerationCurrentProviderAndModelAndModelList(
{ { provider, model: modelId },
plugin_id: pluginId,
provider,
model: modelId,
},
) )
const hasDeprecated = !currentProvider || !currentModel const hasDeprecated = !currentProvider || !currentModel
@ -118,12 +112,11 @@ const ModelParameterModal: FC<ModelParameterModalProps> = ({
}) })
} }
const handleChangeModel = ({ provider, model, plugin_id }: DefaultModel) => { const handleChangeModel = ({ provider, model }: DefaultModel) => {
const targetProvider = activeTextGenerationModelList.find(modelItem => modelItem.provider === provider) const targetProvider = activeTextGenerationModelList.find(modelItem => modelItem.provider === provider)
const targetModelItem = targetProvider?.models.find(modelItem => modelItem.model === model) const targetModelItem = targetProvider?.models.find(modelItem => modelItem.model === model)
setModel({ setModel({
modelId: model, modelId: model,
pluginId: plugin_id,
provider, provider,
mode: targetModelItem?.model_properties.mode as string, mode: targetModelItem?.model_properties.mode as string,
features: targetModelItem?.features || [], features: targetModelItem?.features || [],
@ -208,7 +201,7 @@ const ModelParameterModal: FC<ModelParameterModalProps> = ({
{t('common.modelProvider.model').toLocaleUpperCase()} {t('common.modelProvider.model').toLocaleUpperCase()}
</div> </div>
<ModelSelector <ModelSelector
defaultModel={(provider || modelId) ? { plugin_id: pluginId, provider, model: modelId } : undefined} defaultModel={(provider || modelId) ? { provider, model: modelId } : undefined}
modelList={activeTextGenerationModelList} modelList={activeTextGenerationModelList}
onSelect={handleChangeModel} onSelect={handleChangeModel}
triggerClassName='max-w-[295px]' triggerClassName='max-w-[295px]'

@ -41,11 +41,11 @@ const ModelSelector: FC<ModelSelectorProps> = ({
defaultModel, defaultModel,
) )
const handleSelect = (pluginId: string, provider: string, model: ModelItem) => { const handleSelect = (provider: string, model: ModelItem) => {
setOpen(false) setOpen(false)
if (onSelect) if (onSelect)
onSelect({ plugin_id: pluginId, provider, model: model.model }) onSelect({ provider, model: model.model })
} }
const handleToggle = () => { const handleToggle = () => {

@ -25,7 +25,7 @@ import Tooltip from '@/app/components/base/tooltip'
type PopupItemProps = { type PopupItemProps = {
defaultModel?: DefaultModel defaultModel?: DefaultModel
model: Model model: Model
onSelect: (pluginId: string, provider: string, model: ModelItem) => void onSelect: (provider: string, model: ModelItem) => void
} }
const PopupItem: FC<PopupItemProps> = ({ const PopupItem: FC<PopupItemProps> = ({
defaultModel, defaultModel,
@ -39,11 +39,11 @@ const PopupItem: FC<PopupItemProps> = ({
const updateModelList = useUpdateModelList() const updateModelList = useUpdateModelList()
const updateModelProviders = useUpdateModelProviders() const updateModelProviders = useUpdateModelProviders()
const currentProvider = modelProviders.find(provider => provider.provider === model.provider)! const currentProvider = modelProviders.find(provider => provider.provider === model.provider)!
const handleSelect = (pluginId: string, provider: string, modelItem: ModelItem) => { const handleSelect = (provider: string, modelItem: ModelItem) => {
if (modelItem.status !== ModelStatusEnum.active) if (modelItem.status !== ModelStatusEnum.active)
return return
onSelect(pluginId, provider, modelItem) onSelect(provider, modelItem)
} }
const handleOpenModelModal = () => { const handleOpenModelModal = () => {
setShowModelModal({ setShowModelModal({
@ -80,7 +80,7 @@ const PopupItem: FC<PopupItemProps> = ({
group relative flex items-center px-3 py-1.5 h-8 rounded-lg group relative flex items-center px-3 py-1.5 h-8 rounded-lg
${modelItem.status === ModelStatusEnum.active ? 'cursor-pointer hover:bg-gray-50' : 'cursor-not-allowed hover:bg-gray-50/60'} ${modelItem.status === ModelStatusEnum.active ? 'cursor-pointer hover:bg-gray-50' : 'cursor-not-allowed hover:bg-gray-50/60'}
`} `}
onClick={() => handleSelect(model.plugin_id, model.provider, modelItem)} onClick={() => handleSelect(model.provider, modelItem)}
> >
<ModelIcon <ModelIcon
className={` className={`

@ -15,7 +15,7 @@ import { XCircle } from '@/app/components/base/icons/src/vender/solid/general'
type PopupProps = { type PopupProps = {
defaultModel?: DefaultModel defaultModel?: DefaultModel
modelList: Model[] modelList: Model[]
onSelect: (pluginId: string, provider: string, model: ModelItem) => void onSelect: (provider: string, model: ModelItem) => void
} }
const Popup: FC<PopupProps> = ({ const Popup: FC<PopupProps> = ({
defaultModel, defaultModel,

@ -41,7 +41,7 @@ const CredentialPanel: FC<CredentialPanelProps> = ({
const handleChangePriority = async (key: PreferredProviderTypeEnum) => { const handleChangePriority = async (key: PreferredProviderTypeEnum) => {
const res = await changeModelProviderPriority({ const res = await changeModelProviderPriority({
url: `/workspaces/current/model-providers/${provider.plugin_id}/${provider.provider}/preferred-provider-type`, url: `/workspaces/current/model-providers/${provider.provider}/preferred-provider-type`,
body: { body: {
preferred_provider_type: key, preferred_provider_type: key,
}, },
@ -57,7 +57,7 @@ const CredentialPanel: FC<CredentialPanelProps> = ({
eventEmitter?.emit({ eventEmitter?.emit({
type: UPDATE_MODEL_PROVIDER_CUSTOM_MODEL_LIST, type: UPDATE_MODEL_PROVIDER_CUSTOM_MODEL_LIST,
payload: provider, payload: provider.provider,
} as any) } as any)
} }
} }

@ -52,12 +52,12 @@ const ProviderAddedCard: FC<ProviderAddedCardProps> = ({
const showQuota = systemConfig.enabled && [...MODEL_PROVIDER_QUOTA_GET_PAID].includes(provider.provider) && !IS_CE_EDITION const showQuota = systemConfig.enabled && [...MODEL_PROVIDER_QUOTA_GET_PAID].includes(provider.provider) && !IS_CE_EDITION
const showCredential = configurationMethods.includes(ConfigurationMethodEnum.predefinedModel) && isCurrentWorkspaceManager const showCredential = configurationMethods.includes(ConfigurationMethodEnum.predefinedModel) && isCurrentWorkspaceManager
const getModelList = async (pluginID: string, providerName: string) => { const getModelList = async (providerName: string) => {
if (loading) if (loading)
return return
try { try {
setLoading(true) setLoading(true)
const modelsData = await fetchModelProviderModelList(`/workspaces/current/model-providers/${pluginID}/${providerName}/models`) const modelsData = await fetchModelProviderModelList(`/workspaces/current/model-providers/${providerName}/models`)
setModelList(modelsData.data) setModelList(modelsData.data)
setCollapsed(false) setCollapsed(false)
setFetched(true) setFetched(true)
@ -72,12 +72,12 @@ const ProviderAddedCard: FC<ProviderAddedCardProps> = ({
return return
} }
getModelList(provider.plugin_id, provider.provider) getModelList(provider.provider)
} }
eventEmitter?.useSubscription((v: any) => { eventEmitter?.useSubscription((v: any) => {
if (v?.type === UPDATE_MODEL_PROVIDER_CUSTOM_MODEL_LIST && v.payload.provider === provider.provider) if (v?.type === UPDATE_MODEL_PROVIDER_CUSTOM_MODEL_LIST && v.payload === provider.provider)
getModelList(v.payload.plugin_id, v.payload.provider) getModelList(v.payload)
}) })
return ( return (
@ -172,7 +172,7 @@ const ProviderAddedCard: FC<ProviderAddedCardProps> = ({
models={modelList} models={modelList}
onCollapse={() => setCollapsed(true)} onCollapse={() => setCollapsed(true)}
onConfig={currentCustomConfigurationModelFixedFields => onOpenModal(ConfigurationMethodEnum.customizableModel, currentCustomConfigurationModelFixedFields)} onConfig={currentCustomConfigurationModelFixedFields => onOpenModal(ConfigurationMethodEnum.customizableModel, currentCustomConfigurationModelFixedFields)}
onChange={(provider: ModelProvider) => getModelList(provider.plugin_id, provider.provider)} onChange={(provider: string) => getModelList(provider)}
/> />
) )
} }

@ -33,10 +33,10 @@ const ModelListItem = ({ model, provider, isConfigurable, onConfig, onModifyLoad
const toggleModelEnablingStatus = useCallback(async (enabled: boolean) => { const toggleModelEnablingStatus = useCallback(async (enabled: boolean) => {
if (enabled) if (enabled)
await enableModel(`/workspaces/current/model-providers/${provider.plugin_id}/${provider.provider}/models/enable`, { model: model.model, model_type: model.model_type }) await enableModel(`/workspaces/current/model-providers/${provider.provider}/models/enable`, { model: model.model, model_type: model.model_type })
else else
await disableModel(`/workspaces/current/model-providers/${provider.plugin_id}/${provider.provider}/models/disable`, { model: model.model, model_type: model.model_type }) await disableModel(`/workspaces/current/model-providers/${provider.provider}/models/disable`, { model: model.model, model_type: model.model_type })
}, [model.model, model.model_type, provider.plugin_id, provider.provider]) }, [model.model, model.model_type, provider.provider])
const { run: debouncedToggleModelEnablingStatus } = useDebounceFn(toggleModelEnablingStatus, { wait: 500 }) const { run: debouncedToggleModelEnablingStatus } = useDebounceFn(toggleModelEnablingStatus, { wait: 500 })

@ -23,7 +23,7 @@ type ModelListProps = {
models: ModelItem[] models: ModelItem[]
onCollapse: () => void onCollapse: () => void
onConfig: (currentCustomConfigurationModelFixedFields?: CustomConfigurationModelFixedFields) => void onConfig: (currentCustomConfigurationModelFixedFields?: CustomConfigurationModelFixedFields) => void
onChange?: (provider: ModelProvider) => void onChange?: (provider: string) => void
} }
const ModelList: FC<ModelListProps> = ({ const ModelList: FC<ModelListProps> = ({
provider, provider,

@ -19,7 +19,7 @@ export type ModelLoadBalancingModalProps = {
model: ModelItem model: ModelItem
open?: boolean open?: boolean
onClose?: () => void onClose?: () => void
onSave?: (provider: ModelProvider) => void onSave?: (provider: string) => void
} }
// model balancing config modal // model balancing config modal
@ -30,7 +30,7 @@ const ModelLoadBalancingModal = ({ provider, model, open = false, onClose, onSav
const [loading, setLoading] = useState(false) const [loading, setLoading] = useState(false)
const { data, mutate } = useSWR( const { data, mutate } = useSWR(
`/workspaces/current/model-providers/${provider.plugin_id}/${provider.provider}/models/credentials?model=${model.model}&model_type=${model.model_type}`, `/workspaces/current/model-providers/${provider.provider}/models/credentials?model=${model.model}&model_type=${model.model_type}`,
fetchModelLoadBalancingConfig, fetchModelLoadBalancingConfig,
) )
@ -94,7 +94,7 @@ const ModelLoadBalancingModal = ({ provider, model, open = false, onClose, onSav
if (res.result === 'success') { if (res.result === 'success') {
notify({ type: 'success', message: t('common.actionMsg.modifiedSuccessfully') }) notify({ type: 'success', message: t('common.actionMsg.modifiedSuccessfully') })
mutate() mutate()
onSave?.(provider) onSave?.(provider.provider)
onClose?.() onClose?.()
} }
} }

@ -94,7 +94,6 @@ const SystemModel: FC<SystemModelSelectorProps> = ({
model_settings: [ModelTypeEnum.textGeneration, ModelTypeEnum.textEmbedding, ModelTypeEnum.rerank, ModelTypeEnum.speech2text, ModelTypeEnum.tts].map((modelType) => { model_settings: [ModelTypeEnum.textGeneration, ModelTypeEnum.textEmbedding, ModelTypeEnum.rerank, ModelTypeEnum.speech2text, ModelTypeEnum.tts].map((modelType) => {
return { return {
model_type: modelType, model_type: modelType,
plugin_id: getCurrentDefaultModelByModelType(modelType)?.plugin_id,
provider: getCurrentDefaultModelByModelType(modelType)?.provider, provider: getCurrentDefaultModelByModelType(modelType)?.provider,
model: getCurrentDefaultModelByModelType(modelType)?.model, model: getCurrentDefaultModelByModelType(modelType)?.model,
} }
@ -132,6 +131,7 @@ const SystemModel: FC<SystemModelSelectorProps> = ({
> >
<PortalToFollowElemTrigger onClick={() => setOpen(v => !v)}> <PortalToFollowElemTrigger onClick={() => setOpen(v => !v)}>
<Button <Button
className='relative'
variant={notConfigured ? 'primary' : 'secondary'} variant={notConfigured ? 'primary' : 'secondary'}
size='small' size='small'
> >

@ -26,15 +26,14 @@ export const isNullOrUndefined = (value: any) => {
return value === undefined || value === null return value === undefined || value === null
} }
// deprecated ??? export const validateCredentials = async (predefined: boolean, provider: string, v: FormValue) => {
export const validateCredentials = async (predefined: boolean, pluginID: string, provider: string, v: FormValue) => {
let body, url let body, url
if (predefined) { if (predefined) {
body = { body = {
credentials: v, credentials: v,
} }
url = `/workspaces/current/model-providers/${pluginID}/${provider}/credentials/validate` url = `/workspaces/current/model-providers/${provider}/credentials/validate`
} }
else { else {
const { __model_name, __model_type, ...credentials } = v const { __model_name, __model_type, ...credentials } = v
@ -43,7 +42,7 @@ export const validateCredentials = async (predefined: boolean, pluginID: string,
model_type: __model_type, model_type: __model_type,
credentials, credentials,
} }
url = `/workspaces/current/model-providers/${pluginID}/${provider}/models/credentials/validate` url = `/workspaces/current/model-providers/${provider}/models/credentials/validate`
} }
try { try {
const res = await validateModelProvider({ url, body }) const res = await validateModelProvider({ url, body })
@ -57,14 +56,14 @@ export const validateCredentials = async (predefined: boolean, pluginID: string,
} }
} }
export const validateLoadBalancingCredentials = async (predefined: boolean, pluginID: string, provider: string, v: FormValue, id?: string): Promise<{ export const validateLoadBalancingCredentials = async (predefined: boolean, provider: string, v: FormValue, id?: string): Promise<{
status: ValidatedStatus status: ValidatedStatus
message?: string message?: string
}> => { }> => {
const { __model_name, __model_type, ...credentials } = v const { __model_name, __model_type, ...credentials } = v
try { try {
const res = await validateModelLoadBalancingCredentials({ const res = await validateModelLoadBalancingCredentials({
url: `/workspaces/current/model-providers/${pluginID}/${provider}/models/load-balancing-configs/${id ? `${id}/` : ''}credentials-validate`, url: `/workspaces/current/model-providers/${provider}/models/load-balancing-configs/${id ? `${id}/` : ''}credentials-validate`,
body: { body: {
model: __model_name, model: __model_name,
model_type: __model_type, model_type: __model_type,
@ -81,7 +80,7 @@ export const validateLoadBalancingCredentials = async (predefined: boolean, plug
} }
} }
export const saveCredentials = async (predefined: boolean, pluginID: string, provider: string, v: FormValue, loadBalancing?: ModelLoadBalancingConfig) => { export const saveCredentials = async (predefined: boolean, provider: string, v: FormValue, loadBalancing?: ModelLoadBalancingConfig) => {
let body, url let body, url
if (predefined) { if (predefined) {
@ -90,7 +89,7 @@ export const saveCredentials = async (predefined: boolean, pluginID: string, pro
credentials: v, credentials: v,
load_balancing: loadBalancing, load_balancing: loadBalancing,
} }
url = `/workspaces/current/model-providers/${pluginID}/${provider}` url = `/workspaces/current/model-providers/${provider}`
} }
else { else {
const { __model_name, __model_type, ...credentials } = v const { __model_name, __model_type, ...credentials } = v
@ -100,7 +99,7 @@ export const saveCredentials = async (predefined: boolean, pluginID: string, pro
credentials, credentials,
load_balancing: loadBalancing, load_balancing: loadBalancing,
} }
url = `/workspaces/current/model-providers/${pluginID}/${provider}/models` url = `/workspaces/current/model-providers/${provider}/models`
} }
return setModelProvider({ url, body }) return setModelProvider({ url, body })
@ -120,12 +119,12 @@ export const savePredefinedLoadBalancingConfig = async (provider: string, v: For
return setModelProvider({ url, body }) return setModelProvider({ url, body })
} }
export const removeCredentials = async (predefined: boolean, pluginID: string, provider: string, v: FormValue) => { export const removeCredentials = async (predefined: boolean, provider: string, v: FormValue) => {
let url = '' let url = ''
let body let body
if (predefined) { if (predefined) {
url = `/workspaces/current/model-providers/${pluginID}/${provider}` url = `/workspaces/current/model-providers/${provider}`
} }
else { else {
if (v) { if (v) {
@ -134,7 +133,7 @@ export const removeCredentials = async (predefined: boolean, pluginID: string, p
model: __model_name, model: __model_name,
model_type: __model_type, model_type: __model_type,
} }
url = `/workspaces/current/model-providers/${pluginID}/${provider}/models` url = `/workspaces/current/model-providers/${provider}/models`
} }
} }

@ -130,7 +130,7 @@ export const MarketplaceContextProvider = ({
queryMarketplaceCollectionsAndPlugins({ queryMarketplaceCollectionsAndPlugins({
category: type === PLUGIN_TYPE_SEARCH_MAP.all ? undefined : type, category: type === PLUGIN_TYPE_SEARCH_MAP.all ? undefined : type,
}) })
setPlugins(undefined) setPlugins([])
return return
} }

@ -40,7 +40,7 @@ export const useMarketplaceCollectionsAndPlugins = () => {
export const useMarketplacePlugins = () => { export const useMarketplacePlugins = () => {
const [isLoading, setIsLoading] = useState(false) const [isLoading, setIsLoading] = useState(false)
const [plugins, setPlugins] = useState<Plugin[]>() const [plugins, setPlugins] = useState<Plugin[]>([])
const queryPlugins = useCallback(async (query: PluginsSearchParams) => { const queryPlugins = useCallback(async (query: PluginsSearchParams) => {
setIsLoading(true) setIsLoading(true)

@ -1,8 +1,10 @@
'use client' 'use client'
import { RiArrowRightUpLine } from '@remixicon/react' import { RiArrowRightUpLine } from '@remixicon/react'
import { useTranslation } from 'react-i18next'
import Card from '@/app/components/plugins/card' import Card from '@/app/components/plugins/card'
import CardMoreInfo from '@/app/components/plugins/card/card-more-info' import CardMoreInfo from '@/app/components/plugins/card/card-more-info'
import type { Plugin } from '@/app/components/plugins/types' import type { Plugin } from '@/app/components/plugins/types'
import { MARKETPLACE_URL_PREFIX } from '@/config'
import Button from '@/app/components/base/button' import Button from '@/app/components/base/button'
type CardWrapperProps = { type CardWrapperProps = {
@ -13,6 +15,7 @@ const CardWrapper = ({
plugin, plugin,
showInstallButton, showInstallButton,
}: CardWrapperProps) => { }: CardWrapperProps) => {
const { t } = useTranslation()
return ( return (
<div className='group relative rounded-xl cursor-pointer'> <div className='group relative rounded-xl cursor-pointer'>
<Card <Card
@ -32,13 +35,15 @@ const CardWrapper = ({
variant='primary' variant='primary'
className='flex-1' className='flex-1'
> >
Install {t('plugin.detailPanel.operation.install')}
</Button> </Button>
<Button <Button
className='flex-1' className='flex-1'
> >
Details <a href={`${MARKETPLACE_URL_PREFIX}/plugin/${plugin.org}/${plugin.name}`} target='_blank' className='flex items-center gap-0.5'>
<RiArrowRightUpLine className='ml-1 w-4 h-4' /> {t('plugin.detailPanel.operation.detail')}
<RiArrowRightUpLine className='ml-1 w-4 h-4' />
</a>
</Button> </Button>
</div> </div>
) )

@ -1,8 +1,7 @@
'use client' 'use client'
import React from 'react' import React from 'react'
import { useContext } from 'use-context-selector'
import type { FC } from 'react' import type { FC } from 'react'
import Link from 'next/link' import { useTranslation } from 'react-i18next'
import { RiArrowRightUpLine, RiVerifiedBadgeLine } from '@remixicon/react' import { RiArrowRightUpLine, RiVerifiedBadgeLine } from '@remixicon/react'
import Badge from '../base/badge' import Badge from '../base/badge'
import type { Plugin } from './types' import type { Plugin } from './types'
@ -11,70 +10,67 @@ import Icon from './card/base/card-icon'
import Title from './card/base/title' import Title from './card/base/title'
import DownloadCount from './card/base/download-count' import DownloadCount from './card/base/download-count'
import Button from '@/app/components/base/button' import Button from '@/app/components/base/button'
import { useGetLanguage } from '@/context/i18n'
import { MARKETPLACE_URL_PREFIX } from '@/config'
import cn from '@/utils/classnames' import cn from '@/utils/classnames'
import I18n from '@/context/i18n'
type Props = { type Props = {
className?: string className?: string
payload: Plugin payload: Plugin
installed?: boolean
} }
const ProviderCard: FC<Props> = ({ const ProviderCard: FC<Props> = ({
className, className,
payload, payload,
installed = true,
}) => { }) => {
const { locale } = useContext(I18n) const { t } = useTranslation()
const language = useGetLanguage()
const { org, label } = payload const { org, label } = payload
return ( return (
<div className={cn('group relative p-4 pb-3 border-[0.5px] border-components-panel-border bg-components-panel-on-panel-item-bg hover-bg-components-panel-on-panel-item-bg rounded-xl shadow-xs', className)}> <div className={cn('group relative p-4 pb-3 border-[0.5px] border-components-panel-border bg-components-panel-on-panel-item-bg hover-bg-components-panel-on-panel-item-bg rounded-xl shadow-xs', className)}>
<Link href={`/plugins/test/card?org=${payload.org}&name=${payload.name}`}> {/* Header */}
{/* Header */} <div className="flex">
<div className="flex"> <Icon src={payload.icon} />
<Icon src={payload.icon} /> <div className="ml-3 w-0 grow">
<div className="ml-3 w-0 grow"> <div className="flex items-center h-5">
<div className="flex items-center h-5"> <Title title={label[language]} />
<Title title={label[locale]} /> <RiVerifiedBadgeLine className="shrink-0 ml-0.5 w-4 h-4 text-text-accent" />
<RiVerifiedBadgeLine className="shrink-0 ml-0.5 w-4 h-4 text-text-accent" /> </div>
</div> <div className='mb-1 flex justify-between items-center h-4'>
<div className='mb-1 flex justify-between items-center h-4'> <div className='flex items-center'>
<div className='flex items-center'> <div className='text-text-tertiary system-xs-regular'>{org}</div>
<div className='text-text-tertiary system-xs-regular'>{org}</div> <div className='mx-2 text-text-quaternary system-xs-regular'>·</div>
<div className='mx-2 text-text-quaternary system-xs-regular'>·</div> <DownloadCount downloadCount={payload.install_count || 0} />
<DownloadCount downloadCount={payload.install_count || 0} />
</div>
</div> </div>
</div> </div>
</div> </div>
<Description className='mt-3' text={payload.brief[locale]} descriptionLineRows={2}></Description> </div>
<div className='mt-3 flex space-x-0.5'> <Description className='mt-3' text={payload.brief[language]} descriptionLineRows={2}></Description>
{['LLM', 'text embedding', 'speech2text'].map(tag => ( <div className='mt-3 flex space-x-0.5'>
<Badge key={tag} text={tag} /> {payload.tags.map(tag => (
))} <Badge key={tag.name} text={tag.name} />
</div> ))}
{!installed && ( </div>
<div <div
className='hidden group-hover:flex items-center gap-2 absolute bottom-0 left-0 right-0 p-4 pt-8' className='hidden group-hover:flex items-center gap-2 absolute bottom-0 left-0 right-0 p-4 pt-8 rounded-xl bg-gradient-to-tr from-[#f9fafb] to-[rgba(249,250,251,0)]'
style={{ background: 'linear-gradient(0deg, #F9FAFB 60.27%, rgba(249, 250, 251, 0.00) 100%)' }} >
> <Button
<Button className='flex-grow'
className='flex-grow' variant='primary'
variant='primary' >
> {t('plugin.detailPanel.operation.install')}
Install </Button>
</Button> <Button
<Button className='flex-grow'
className='flex-grow' variant='secondary'
variant='secondary' >
> <a href={`${MARKETPLACE_URL_PREFIX}/plugin/${payload.org}/${payload.name}`} target='_blank' className='flex items-center gap-0.5'>
Details {t('plugin.detailPanel.operation.detail')}
<RiArrowRightUpLine className='w-4 h-4' /> <RiArrowRightUpLine className='w-4 h-4' />
</Button> </a>
</div> </Button>
)} </div>
</Link>
</div> </div>
) )
} }

@ -103,6 +103,7 @@ export type Plugin = {
type: PluginType type: PluginType
org: string org: string
name: string name: string
plugin_id: string
version: string version: string
latest_version: string latest_version: string
icon: string icon: string

@ -37,7 +37,7 @@ export const useMarketplace = (searchPluginText: string, filterPluginTags: strin
} }
else { else {
queryMarketplaceCollectionsAndPlugins() queryMarketplaceCollectionsAndPlugins()
setPlugins(undefined) setPlugins([])
} }
}, [searchPluginText, filterPluginTags, queryPlugins, queryMarketplaceCollectionsAndPlugins, queryPluginsWithDebounced, setPlugins]) }, [searchPluginText, filterPluginTags, queryPlugins, queryMarketplaceCollectionsAndPlugins, queryPluginsWithDebounced, setPlugins])

@ -132,7 +132,6 @@ const Panel: FC<NodePanelProps<LLMNodeType>> = ({
isInWorkflow isInWorkflow
isAdvancedMode={true} isAdvancedMode={true}
mode={model?.mode} mode={model?.mode}
pluginId={model?.plugin_id}
provider={model?.provider} provider={model?.provider}
completionParams={model?.completion_params} completionParams={model?.completion_params}
modelId={model?.name} modelId={model?.name}

@ -123,7 +123,7 @@ const useConfig = (id: string, payload: LLMNodeType) => {
}, },
}) })
const handleModelChanged = useCallback((model: { provider: string; modelId: string; pluginId: string; mode?: string }) => { const handleModelChanged = useCallback((model: { provider: string; modelId: string; mode?: string }) => {
const newInputs = produce(inputRef.current, (draft) => { const newInputs = produce(inputRef.current, (draft) => {
draft.model.provider = model.provider draft.model.provider = model.provider
draft.model.name = model.modelId draft.model.name = model.modelId
@ -139,7 +139,6 @@ const useConfig = (id: string, payload: LLMNodeType) => {
useEffect(() => { useEffect(() => {
if (currentProvider?.provider && currentModel?.model && !model.provider) { if (currentProvider?.provider && currentModel?.model && !model.provider) {
handleModelChanged({ handleModelChanged({
pluginId: currentProvider?.plugin_id,
provider: currentProvider?.provider, provider: currentProvider?.provider,
modelId: currentModel?.model, modelId: currentModel?.model,
mode: currentModel?.model_properties?.mode as string, mode: currentModel?.model_properties?.mode as string,

@ -77,7 +77,6 @@ const Panel: FC<NodePanelProps<ParameterExtractorNodeType>> = ({
isInWorkflow isInWorkflow
isAdvancedMode={true} isAdvancedMode={true}
mode={model?.mode} mode={model?.mode}
pluginId={model?.plugin_id}
provider={model?.provider} provider={model?.provider}
completionParams={model?.completion_params} completionParams={model?.completion_params}
modelId={model?.name} modelId={model?.name}

@ -65,7 +65,6 @@ const Panel: FC<NodePanelProps<QuestionClassifierNodeType>> = ({
isInWorkflow isInWorkflow
isAdvancedMode={true} isAdvancedMode={true}
mode={model?.mode} mode={model?.mode}
pluginId={model?.plugin_id}
provider={model?.provider} provider={model?.provider}
completionParams={model.completion_params} completionParams={model.completion_params}
modelId={model.name} modelId={model.name}

@ -1,6 +1,6 @@
import type { CommonNodeType, Memory, ModelConfig, ValueSelector, VisionSetting } from '@/app/components/workflow/types' import type { CommonNodeType, Memory, ModelConfig, ValueSelector, VisionSetting } from '@/app/components/workflow/types'
export type Topic = { export interface Topic {
id: string id: string
name: string name: string
} }

@ -37,7 +37,7 @@ export enum ControlMode {
Hand = 'hand', Hand = 'hand',
} }
export type Branch = { export interface Branch {
id: string id: string
name: string name: string
} }
@ -68,7 +68,7 @@ export type CommonNodeType<T = {}> = {
height?: number height?: number
} & T & Partial<Pick<ToolDefaultValue, 'provider_id' | 'provider_type' | 'provider_name' | 'tool_name'>> } & T & Partial<Pick<ToolDefaultValue, 'provider_id' | 'provider_type' | 'provider_name' | 'tool_name'>>
export type CommonEdgeType = { export interface CommonEdgeType {
_hovering?: boolean _hovering?: boolean
_connectedNodeIsHovering?: boolean _connectedNodeIsHovering?: boolean
_connectedNodeIsSelected?: boolean _connectedNodeIsSelected?: boolean
@ -82,14 +82,14 @@ export type CommonEdgeType = {
export type Node<T = {}> = ReactFlowNode<CommonNodeType<T>> export type Node<T = {}> = ReactFlowNode<CommonNodeType<T>>
export type SelectedNode = Pick<Node, 'id' | 'data'> export type SelectedNode = Pick<Node, 'id' | 'data'>
export type NodeProps<T = unknown> = { id: string; data: CommonNodeType<T> } export interface NodeProps<T = unknown> { id: string; data: CommonNodeType<T> }
export type NodePanelProps<T> = { export interface NodePanelProps<T> {
id: string id: string
data: CommonNodeType<T> data: CommonNodeType<T>
} }
export type Edge = ReactFlowEdge<CommonEdgeType> export type Edge = ReactFlowEdge<CommonEdgeType>
export type WorkflowDataUpdater = { export interface WorkflowDataUpdater {
nodes: Node[] nodes: Node[]
edges: Edge[] edges: Edge[]
viewport: Viewport viewport: Viewport
@ -97,7 +97,7 @@ export type WorkflowDataUpdater = {
export type ValueSelector = string[] // [nodeId, key | obj key path] export type ValueSelector = string[] // [nodeId, key | obj key path]
export type Variable = { export interface Variable {
variable: string variable: string
label?: string | { label?: string | {
nodeType: BlockEnum nodeType: BlockEnum
@ -112,14 +112,14 @@ export type Variable = {
isParagraph?: boolean isParagraph?: boolean
} }
export type EnvironmentVariable = { export interface EnvironmentVariable {
id: string id: string
name: string name: string
value: any value: any
value_type: 'string' | 'number' | 'secret' value_type: 'string' | 'number' | 'secret'
} }
export type ConversationVariable = { export interface ConversationVariable {
id: string id: string
name: string name: string
value_type: ChatVarType value_type: ChatVarType
@ -127,13 +127,13 @@ export type ConversationVariable = {
description: string description: string
} }
export type GlobalVariable = { export interface GlobalVariable {
name: string name: string
value_type: 'string' | 'number' value_type: 'string' | 'number'
description: string description: string
} }
export type VariableWithValue = { export interface VariableWithValue {
key: string key: string
value: string value: string
} }
@ -169,8 +169,7 @@ export type InputVar = {
value_selector?: ValueSelector value_selector?: ValueSelector
} & Partial<UploadFileSetting> } & Partial<UploadFileSetting>
export type ModelConfig = { export interface ModelConfig {
plugin_id: string
provider: string provider: string
name: string name: string
mode: string mode: string
@ -188,7 +187,7 @@ export enum EditionType {
jinja2 = 'jinja2', jinja2 = 'jinja2',
} }
export type PromptItem = { export interface PromptItem {
id?: string id?: string
role?: PromptRole role?: PromptRole
text: string text: string
@ -201,12 +200,12 @@ export enum MemoryRole {
assistant = 'assistant', assistant = 'assistant',
} }
export type RolePrefix = { export interface RolePrefix {
user: string user: string
assistant: string assistant: string
} }
export type Memory = { export interface Memory {
role_prefix?: RolePrefix role_prefix?: RolePrefix
window: { window: {
enabled: boolean enabled: boolean
@ -230,7 +229,7 @@ export enum VarType {
any = 'any', any = 'any',
} }
export type Var = { export interface Var {
variable: string variable: string
type: VarType type: VarType
children?: Var[] // if type is obj, has the children struct children?: Var[] // if type is obj, has the children struct
@ -241,21 +240,21 @@ export type Var = {
des?: string des?: string
} }
export type NodeOutPutVar = { export interface NodeOutPutVar {
nodeId: string nodeId: string
title: string title: string
vars: Var[] vars: Var[]
isStartNode?: boolean isStartNode?: boolean
} }
export type Block = { export interface Block {
classification?: string classification?: string
type: BlockEnum type: BlockEnum
title: string title: string
description?: string description?: string
} }
export type NodeDefault<T> = { export interface NodeDefault<T> {
defaultValue: Partial<T> defaultValue: Partial<T>
getAvailablePrevNodes: (isChatMode: boolean) => BlockEnum[] getAvailablePrevNodes: (isChatMode: boolean) => BlockEnum[]
getAvailableNextNodes: (isChatMode: boolean) => BlockEnum[] getAvailableNextNodes: (isChatMode: boolean) => BlockEnum[]
@ -295,19 +294,19 @@ export type OnNodeAdd = (
} }
) => void ) => void
export type CheckValidRes = { export interface CheckValidRes {
isValid: boolean isValid: boolean
errorMessage?: string errorMessage?: string
} }
export type RunFile = { export interface RunFile {
type: string type: string
transfer_method: TransferMethod[] transfer_method: TransferMethod[]
url?: string url?: string
upload_file_id?: string upload_file_id?: string
} }
export type WorkflowRunningData = { export interface WorkflowRunningData {
task_id?: string task_id?: string
message_id?: string message_id?: string
conversation_id?: string conversation_id?: string
@ -332,7 +331,7 @@ export type WorkflowRunningData = {
tracing?: NodeTracing[] tracing?: NodeTracing[]
} }
export type HistoryWorkflowData = { export interface HistoryWorkflowData {
id: string id: string
sequence_number: number sequence_number: number
status: string status: string
@ -344,7 +343,7 @@ export enum ChangeType {
remove = 'remove', remove = 'remove',
} }
export type MoreInfo = { export interface MoreInfo {
type: ChangeType type: ChangeType
payload?: { payload?: {
beforeKey: string beforeKey: string
@ -364,7 +363,7 @@ export enum SupportUploadFileTypes {
custom = 'custom', custom = 'custom',
} }
export type UploadFileSetting = { export interface UploadFileSetting {
allowed_file_upload_methods: TransferMethod[] allowed_file_upload_methods: TransferMethod[]
allowed_file_types: SupportUploadFileTypes[] allowed_file_types: SupportUploadFileTypes[]
allowed_file_extensions?: string[] allowed_file_extensions?: string[]
@ -372,7 +371,7 @@ export type UploadFileSetting = {
number_limits?: number number_limits?: number
} }
export type VisionSetting = { export interface VisionSetting {
variable_selector: ValueSelector variable_selector: ValueSelector
detail: Resolution detail: Resolution
} }

@ -32,7 +32,7 @@ import OpeningSettingModal from '@/app/components/base/features/new-feature-pane
import type { OpeningStatement } from '@/app/components/base/features/types' import type { OpeningStatement } from '@/app/components/base/features/types'
import type { InputVar } from '@/app/components/workflow/types' import type { InputVar } from '@/app/components/workflow/types'
export type ModalState<T> = { export interface ModalState<T> {
payload: T payload: T
onCancelCallback?: () => void onCancelCallback?: () => void
onSaveCallback?: (newPayload: T) => void onSaveCallback?: (newPayload: T) => void
@ -43,7 +43,7 @@ export type ModalState<T> = {
datasetBindings?: { id: string; name: string }[] datasetBindings?: { id: string; name: string }[]
} }
export type ModelModalType = { export interface ModelModalType {
currentProvider: ModelProvider currentProvider: ModelProvider
currentConfigurationMethod: ConfigurationMethodEnum currentConfigurationMethod: ConfigurationMethodEnum
currentCustomConfigurationModelFixedFields?: CustomConfigurationModelFixedFields currentCustomConfigurationModelFixedFields?: CustomConfigurationModelFixedFields
@ -52,7 +52,7 @@ export type LoadBalancingEntryModalType = ModelModalType & {
entry?: ModelLoadBalancingConfigEntry entry?: ModelLoadBalancingConfigEntry
index?: number index?: number
} }
export type ModalContextState = { export interface ModalContextState {
setShowAccountSettingModal: Dispatch<SetStateAction<ModalState<string> | null>> setShowAccountSettingModal: Dispatch<SetStateAction<ModalState<string> | null>>
setShowApiBasedExtensionModal: Dispatch<SetStateAction<ModalState<ApiBasedExtension> | null>> setShowApiBasedExtensionModal: Dispatch<SetStateAction<ModalState<ApiBasedExtension> | null>>
setShowModerationSettingModal: Dispatch<SetStateAction<ModalState<ModerationConfig> | null>> setShowModerationSettingModal: Dispatch<SetStateAction<ModalState<ModerationConfig> | null>>
@ -90,7 +90,7 @@ export const useModalContext = () => useContext(ModalContext)
export const useModalContextSelector = <T,>(selector: (state: ModalContextState) => T): T => export const useModalContextSelector = <T,>(selector: (state: ModalContextState) => T): T =>
useContextSelector(ModalContext, selector) useContextSelector(ModalContext, selector)
type ModalContextProviderProps = { interface ModalContextProviderProps {
children: React.ReactNode children: React.ReactNode
} }
export const ModalContextProvider = ({ export const ModalContextProvider = ({

@ -13,7 +13,7 @@ const translation = {
}, },
operation: { operation: {
install: 'Install', install: 'Install',
detail: 'Detail', detail: 'Details',
update: 'Update', update: 'Update',
info: 'Plugin Info', info: 'Plugin Info',
checkUpdate: 'Check Update', checkUpdate: 'Check Update',

@ -10,25 +10,25 @@ export enum PromptMode {
advanced = 'advanced', advanced = 'advanced',
} }
export type PromptItem = { export interface PromptItem {
role?: PromptRole role?: PromptRole
text: string text: string
} }
export type ChatPromptConfig = { export interface ChatPromptConfig {
prompt: PromptItem[] prompt: PromptItem[]
} }
export type ConversationHistoriesRole = { export interface ConversationHistoriesRole {
user_prefix: string user_prefix: string
assistant_prefix: string assistant_prefix: string
} }
export type CompletionPromptConfig = { export interface CompletionPromptConfig {
prompt: PromptItem prompt: PromptItem
conversation_histories_role: ConversationHistoriesRole conversation_histories_role: ConversationHistoriesRole
} }
export type BlockStatus = { export interface BlockStatus {
context: boolean context: boolean
history: boolean history: boolean
query: boolean query: boolean
@ -40,7 +40,7 @@ export enum PromptRole {
assistant = 'assistant', assistant = 'assistant',
} }
export type PromptVariable = { export interface PromptVariable {
key: string key: string
name: string name: string
type: string // "string" | "number" | "select", type: string // "string" | "number" | "select",
@ -55,7 +55,7 @@ export type PromptVariable = {
icon_background?: string icon_background?: string
} }
export type CompletionParams = { export interface CompletionParams {
max_tokens: number max_tokens: number
temperature: number temperature: number
top_p: number top_p: number
@ -66,12 +66,12 @@ export type CompletionParams = {
export type ModelId = 'gpt-3.5-turbo' | 'text-davinci-003' export type ModelId = 'gpt-3.5-turbo' | 'text-davinci-003'
export type PromptConfig = { export interface PromptConfig {
prompt_template: string prompt_template: string
prompt_variables: PromptVariable[] prompt_variables: PromptVariable[]
} }
export type MoreLikeThisConfig = { export interface MoreLikeThisConfig {
enabled: boolean enabled: boolean
} }
@ -79,7 +79,7 @@ export type SuggestedQuestionsAfterAnswerConfig = MoreLikeThisConfig
export type SpeechToTextConfig = MoreLikeThisConfig export type SpeechToTextConfig = MoreLikeThisConfig
export type TextToSpeechConfig = { export interface TextToSpeechConfig {
enabled: boolean enabled: boolean
voice?: string voice?: string
language?: string language?: string
@ -88,18 +88,17 @@ export type TextToSpeechConfig = {
export type CitationConfig = MoreLikeThisConfig export type CitationConfig = MoreLikeThisConfig
export type AnnotationReplyConfig = { export interface AnnotationReplyConfig {
id: string id: string
enabled: boolean enabled: boolean
score_threshold: number score_threshold: number
embedding_model: { embedding_model: {
plugin_id: string
embedding_provider_name: string embedding_provider_name: string
embedding_model_name: string embedding_model_name: string
} }
} }
export type ModerationContentConfig = { export interface ModerationContentConfig {
enabled: boolean enabled: boolean
preset_response?: string preset_response?: string
} }
@ -114,15 +113,14 @@ export type ModerationConfig = MoreLikeThisConfig & {
} }
export type RetrieverResourceConfig = MoreLikeThisConfig export type RetrieverResourceConfig = MoreLikeThisConfig
export type AgentConfig = { export interface AgentConfig {
enabled: boolean enabled: boolean
strategy: AgentStrategy strategy: AgentStrategy
max_iteration: number max_iteration: number
tools: ToolItem[] tools: ToolItem[]
} }
// frontend use. Not the same as backend // frontend use. Not the same as backend
export type ModelConfig = { export interface ModelConfig {
plugin_id: string
provider: string // LLM Provider: for example "OPENAI" provider: string // LLM Provider: for example "OPENAI"
model_id: string model_id: string
mode: ModelModeType mode: ModelModeType
@ -140,17 +138,16 @@ export type ModelConfig = {
dataSets: any[] dataSets: any[]
agentConfig: AgentConfig agentConfig: AgentConfig
} }
export type DatasetConfigItem = { export interface DatasetConfigItem {
enable: boolean enable: boolean
value: number value: number
} }
export type DatasetConfigs = { export interface DatasetConfigs {
retrieval_model: RETRIEVE_TYPE retrieval_model: RETRIEVE_TYPE
reranking_model: { reranking_model: {
reranking_provider_name: string reranking_provider_name: string
reranking_model_name: string reranking_model_name: string
reranking_plugin_id: string
} }
top_k: number top_k: number
score_threshold_enabled: boolean score_threshold_enabled: boolean
@ -175,39 +172,39 @@ export type DatasetConfigs = {
reranking_enable?: boolean reranking_enable?: boolean
} }
export type DebugRequestBody = { export interface DebugRequestBody {
inputs: Inputs inputs: Inputs
query: string query: string
completion_params: CompletionParams completion_params: CompletionParams
model_config: ModelConfig model_config: ModelConfig
} }
export type DebugResponse = { export interface DebugResponse {
id: string id: string
answer: string answer: string
created_at: string created_at: string
} }
export type DebugResponseStream = { export interface DebugResponseStream {
id: string id: string
data: string data: string
created_at: string created_at: string
} }
export type FeedBackRequestBody = { export interface FeedBackRequestBody {
message_id: string message_id: string
rating: 'like' | 'dislike' rating: 'like' | 'dislike'
content?: string content?: string
from_source: 'api' | 'log' from_source: 'api' | 'log'
} }
export type FeedBackResponse = { export interface FeedBackResponse {
message_id: string message_id: string
rating: 'like' | 'dislike' rating: 'like' | 'dislike'
} }
// Log session list // Log session list
export type LogSessionListQuery = { export interface LogSessionListQuery {
keyword?: string keyword?: string
start?: string // format datetime(YYYY-mm-dd HH:ii) start?: string // format datetime(YYYY-mm-dd HH:ii)
end?: string // format datetime(YYYY-mm-dd HH:ii) end?: string // format datetime(YYYY-mm-dd HH:ii)
@ -215,7 +212,7 @@ export type LogSessionListQuery = {
limit: number // default 20. 1-100 limit: number // default 20. 1-100
} }
export type LogSessionListResponse = { export interface LogSessionListResponse {
data: { data: {
id: string id: string
conversation_id: string conversation_id: string
@ -229,7 +226,7 @@ export type LogSessionListResponse = {
} }
// log session detail and debug // log session detail and debug
export type LogSessionDetailResponse = { export interface LogSessionDetailResponse {
id: string id: string
conversation_id: string conversation_id: string
model_provider: string model_provider: string
@ -243,7 +240,7 @@ export type LogSessionDetailResponse = {
from_source: 'api' | 'log' from_source: 'api' | 'log'
} }
export type SavedMessage = { export interface SavedMessage {
id: string id: string
answer: string answer: string
} }

@ -107,7 +107,6 @@ export type MessageContent = {
agent_thoughts: any[] // TODO agent_thoughts: any[] // TODO
workflow_run_id: string workflow_run_id: string
parent_message_id: string | null parent_message_id: string | null
plugin_id: string
} }
export type CompletionConversationGeneralDetail = { export type CompletionConversationGeneralDetail = {
@ -130,7 +129,6 @@ export type CompletionConversationGeneralDetail = {
dislike: number dislike: number
} }
model_config: { model_config: {
plugin_id: string
provider: string provider: string
model_id: string model_id: string
configs: Pick<ModelConfigDetail, 'prompt_template'> configs: Pick<ModelConfigDetail, 'prompt_template'>

@ -13,9 +13,7 @@ export const updateAnnotationStatus = (appId: string, action: AnnotationEnableSt
if (embeddingModel) { if (embeddingModel) {
body = { body = {
...body, ...body,
embedding_model_plugin_id: embeddingModel.plugin_id, ...embeddingModel,
embedding_provider_name: embeddingModel.embedding_provider_name,
embedding_model_name: embeddingModel.embedding_model_name,
} }
} }

@ -3,13 +3,13 @@ import type { IOnCompleted, IOnData, IOnError, IOnFile, IOnMessageEnd, IOnMessag
import type { ChatPromptConfig, CompletionPromptConfig } from '@/models/debug' import type { ChatPromptConfig, CompletionPromptConfig } from '@/models/debug'
import type { ModelModeType } from '@/types/app' import type { ModelModeType } from '@/types/app'
import type { ModelParameterRule } from '@/app/components/header/account-setting/model-provider-page/declarations' import type { ModelParameterRule } from '@/app/components/header/account-setting/model-provider-page/declarations'
export type AutomaticRes = { export interface AutomaticRes {
prompt: string prompt: string
variables: string[] variables: string[]
opening_statement: string opening_statement: string
error?: string error?: string
} }
export type CodeGenRes = { export interface CodeGenRes {
code: string code: string
language: string[] language: string[]
error?: string error?: string
@ -82,8 +82,8 @@ export const generateRuleCode = (body: Record<string, any>) => {
}) })
} }
export const fetchModelParams = (pluginID: string, providerName: string, modelId: string) => { export const fetchModelParams = (providerName: string, modelId: string) => {
return get(`workspaces/current/model-providers/${pluginID}/${providerName}/models/parameter-rules`, { return get(`workspaces/current/model-providers/${providerName}/models/parameter-rules`, {
params: { params: {
model: modelId, model: modelId,
}, },

Loading…
Cancel
Save