mirror of
https://github.com/langgenius/dify.git
synced 2024-11-16 19:59:50 +08:00
Merge branch 'feat/plugins' of github.com:langgenius/dify into feat/plugins
This commit is contained in:
commit
2fd4b6e6d2
|
@ -3,11 +3,19 @@ import React from 'react'
|
|||
import ToolPicker from '@/app/components/workflow/block-selector/tool-picker'
|
||||
|
||||
const ToolsPicker = () => {
|
||||
const [show, setShow] = React.useState(true)
|
||||
return (
|
||||
<ToolPicker
|
||||
supportAddCustomTool={true}
|
||||
onSelect={() => { }}
|
||||
/>
|
||||
<div className=' mt-10 ml-10'>
|
||||
<ToolPicker
|
||||
trigger={<div className='inline-block w-[70px]'>Click me</div>}
|
||||
isShow={show}
|
||||
onShowChange={setShow}
|
||||
disabled={false}
|
||||
supportAddCustomTool={true}
|
||||
onSelect={() => { }}
|
||||
/>
|
||||
</div>
|
||||
|
||||
)
|
||||
}
|
||||
|
||||
|
|
|
@ -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 type { App } from '@/types/app'
|
||||
|
||||
type Props = {
|
||||
interface Props {
|
||||
appDetail: App
|
||||
}
|
||||
|
||||
|
@ -283,7 +283,6 @@ const Annotation: FC<Props> = ({
|
|||
if (
|
||||
embeddingModel.embedding_model_name !== annotationConfig?.embedding_model?.embedding_model_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)
|
||||
await ensureJobCompleted(jobId, AnnotationEnableStatus.enable)
|
||||
|
|
|
@ -23,9 +23,8 @@ export type HitHistoryItem = {
|
|||
}
|
||||
|
||||
export type EmbeddingModelConfig = {
|
||||
plugin_id: string
|
||||
embedding_model_name: string
|
||||
embedding_provider_name: string
|
||||
embedding_model_name: string
|
||||
}
|
||||
|
||||
export enum AnnotationEnableStatus {
|
||||
|
|
|
@ -27,10 +27,12 @@ import { MAX_TOOLS_NUM } from '@/config'
|
|||
import { AlertTriangle } from '@/app/components/base/icons/src/vender/solid/alertsAndFeedback'
|
||||
import Tooltip from '@/app/components/base/tooltip'
|
||||
import { DefaultToolIcon } from '@/app/components/base/icons/src/public/other'
|
||||
import AddToolModal from '@/app/components/tools/add-tool-modal'
|
||||
// import AddToolModal from '@/app/components/tools/add-tool-modal'
|
||||
import ConfigCredential from '@/app/components/tools/setting/build-in/config-credentials'
|
||||
import { updateBuiltInToolCredential } from '@/service/tools'
|
||||
import cn from '@/utils/classnames'
|
||||
import ToolPicker from '@/app/components/workflow/block-selector/tool-picker'
|
||||
import type { ToolDefaultValue } from '@/app/components/workflow/block-selector/types'
|
||||
|
||||
type AgentToolWithMoreInfo = AgentTool & { icon: any; collection?: Collection } | null
|
||||
const AgentTools: FC = () => {
|
||||
|
@ -81,6 +83,21 @@ const AgentTools: FC = () => {
|
|||
|
||||
const [isDeleting, setIsDeleting] = useState<number>(-1)
|
||||
|
||||
const handleSelectTool = (tool: ToolDefaultValue) => {
|
||||
const newModelConfig = produce(modelConfig, (draft) => {
|
||||
draft.agentConfig.tools.push({
|
||||
provider_id: tool.provider_id,
|
||||
provider_type: tool.provider_type as CollectionType,
|
||||
provider_name: tool.provider_name,
|
||||
tool_name: tool.tool_name,
|
||||
tool_label: tool.tool_label,
|
||||
tool_parameters: {},
|
||||
enabled: true,
|
||||
})
|
||||
})
|
||||
setModelConfig(newModelConfig)
|
||||
}
|
||||
|
||||
return (
|
||||
<>
|
||||
<Panel
|
||||
|
@ -107,7 +124,14 @@ const AgentTools: FC = () => {
|
|||
{tools.length < MAX_TOOLS_NUM && (
|
||||
<>
|
||||
<div className='ml-3 mr-1 h-3.5 w-px bg-gray-200'></div>
|
||||
<OperationBtn type="add" onClick={() => setIsShowChooseTool(true)} />
|
||||
<ToolPicker
|
||||
trigger={<OperationBtn type="add" />}
|
||||
isShow={isShowChooseTool}
|
||||
onShowChange={setIsShowChooseTool}
|
||||
disabled={false}
|
||||
supportAddCustomTool
|
||||
onSelect={handleSelectTool}
|
||||
/>
|
||||
</>
|
||||
)}
|
||||
</div>
|
||||
|
@ -125,8 +149,8 @@ const AgentTools: FC = () => {
|
|||
{item.isDeleted && <DefaultToolIcon className='w-5 h-5' />}
|
||||
{!item.isDeleted && (
|
||||
<div className={cn((item.notAuthor || !item.enabled) && 'opacity-50')}>
|
||||
{typeof item.icon === 'string' && <div className='w-5 h-5 bg-cover bg-center rounded-md' style={{ backgroundImage: `url(${item.icon})` }}/>}
|
||||
{typeof item.icon !== 'string' && <AppIcon className='rounded-md' size='xs' icon={item.icon?.content} background={item.icon?.background}/>}
|
||||
{typeof item.icon === 'string' && <div className='w-5 h-5 bg-cover bg-center rounded-md' style={{ backgroundImage: `url(${item.icon})` }} />}
|
||||
{typeof item.icon !== 'string' && <AppIcon className='rounded-md' size='xs' icon={item.icon?.content} background={item.icon?.background} />}
|
||||
</div>
|
||||
)}
|
||||
<div
|
||||
|
@ -245,9 +269,6 @@ const AgentTools: FC = () => {
|
|||
))}
|
||||
</div >
|
||||
</Panel >
|
||||
{isShowChooseTool && (
|
||||
<AddToolModal onHide={() => setIsShowChooseTool(false)} />
|
||||
)}
|
||||
{isShowSettingTool && (
|
||||
<SettingBuiltInTool
|
||||
toolName={currentTool?.tool_name as string}
|
||||
|
|
|
@ -25,7 +25,7 @@ import { useSelectedDatasetsMode } from '@/app/components/workflow/nodes/knowled
|
|||
import Switch from '@/app/components/base/switch'
|
||||
import Toast from '@/app/components/base/toast'
|
||||
|
||||
type Props = {
|
||||
interface Props {
|
||||
datasetConfigs: DatasetConfigs
|
||||
onChange: (configs: DatasetConfigs, isRetrievalModeChange?: boolean) => void
|
||||
isInWorkflow?: boolean
|
||||
|
@ -71,7 +71,6 @@ const ConfigContent: FC<Props> = ({
|
|||
? {
|
||||
...rerankDefaultModel,
|
||||
provider: rerankDefaultModel.provider.provider,
|
||||
plugin_id: rerankDefaultModel.provider.plugin_id,
|
||||
}
|
||||
: undefined,
|
||||
)
|
||||
|
@ -81,14 +80,12 @@ const ConfigContent: FC<Props> = ({
|
|||
return {
|
||||
provider_name: datasetConfigs.reranking_model.reranking_provider_name,
|
||||
model_name: datasetConfigs.reranking_model.reranking_model_name,
|
||||
plugin_id: datasetConfigs.reranking_model.reranking_plugin_id,
|
||||
}
|
||||
}
|
||||
else if (rerankDefaultModel) {
|
||||
return {
|
||||
provider_name: rerankDefaultModel.provider.provider,
|
||||
model_name: rerankDefaultModel.model,
|
||||
plugin_id: rerankDefaultModel.provider.plugin_id,
|
||||
}
|
||||
}
|
||||
})()
|
||||
|
@ -175,7 +172,7 @@ const ConfigContent: FC<Props> = ({
|
|||
return false
|
||||
|
||||
return datasetConfigs.reranking_enable
|
||||
}, [canManuallyToggleRerank, datasetConfigs.reranking_enable, isRerankDefaultModelValid])
|
||||
}, [canManuallyToggleRerank, datasetConfigs.reranking_enable])
|
||||
|
||||
const handleDisabledSwitchClick = useCallback(() => {
|
||||
if (!currentRerankModel && !showRerankModel)
|
||||
|
@ -303,14 +300,13 @@ const ConfigContent: FC<Props> = ({
|
|||
</div>
|
||||
<div>
|
||||
<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) => {
|
||||
onChange({
|
||||
...datasetConfigs,
|
||||
reranking_model: {
|
||||
reranking_provider_name: v.provider,
|
||||
reranking_model_name: v.model,
|
||||
reranking_plugin_id: v.plugin_id,
|
||||
},
|
||||
})
|
||||
}}
|
||||
|
@ -388,7 +384,6 @@ const ConfigContent: FC<Props> = ({
|
|||
portalToFollowElemContentClassName='!z-[1002]'
|
||||
isAdvancedMode={true}
|
||||
mode={model?.mode}
|
||||
pluginId={model?.plugin_id}
|
||||
provider={model?.provider}
|
||||
completionParams={model?.completion_params}
|
||||
modelId={model?.name}
|
||||
|
|
|
@ -36,13 +36,12 @@ const ModelParameterTrigger: FC<ModelParameterTriggerProps> = ({
|
|||
const language = useLanguage()
|
||||
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]
|
||||
newModelConfigs[index] = {
|
||||
...newModelConfigs[index],
|
||||
model: modelId,
|
||||
provider,
|
||||
plugin_id: pluginId,
|
||||
}
|
||||
onMultipleModelConfigsChange(true, newModelConfigs)
|
||||
}
|
||||
|
@ -59,7 +58,6 @@ const ModelParameterTrigger: FC<ModelParameterTriggerProps> = ({
|
|||
<ModelParameterModal
|
||||
mode={mode}
|
||||
isAdvancedMode={isAdvancedMode}
|
||||
pluginId={modelAndParameter.plugin_id}
|
||||
provider={modelAndParameter.provider}
|
||||
modelId={modelAndParameter.model}
|
||||
completionParams={modelAndParameter.parameters}
|
||||
|
|
|
@ -1,7 +1,6 @@
|
|||
export type ModelAndParameter = {
|
||||
id: string
|
||||
model: string
|
||||
plugin_id: string
|
||||
provider: string
|
||||
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 { fetchFileUploadConfig } from '@/service/common'
|
||||
|
||||
type PublishConfig = {
|
||||
interface PublishConfig {
|
||||
modelConfig: ModelConfig
|
||||
completionParams: FormValue
|
||||
}
|
||||
|
@ -156,7 +156,6 @@ const Configuration: FC = () => {
|
|||
const setCompletionParams = (value: FormValue) => {
|
||||
const params = { ...value }
|
||||
|
||||
// eslint-disable-next-line ts/no-use-before-define
|
||||
if ((!params.stop || params.stop.length === 0) && (modeModeTypeRef.current === ModelModeType.completion)) {
|
||||
params.stop = getTempStop()
|
||||
setTempStop([])
|
||||
|
@ -165,7 +164,6 @@ const Configuration: FC = () => {
|
|||
}
|
||||
|
||||
const [modelConfig, doSetModelConfig] = useState<ModelConfig>({
|
||||
plugin_id: 'langgenius',
|
||||
provider: 'openai',
|
||||
model_id: 'gpt-3.5-turbo',
|
||||
mode: ModelModeType.unset,
|
||||
|
@ -200,7 +198,6 @@ const Configuration: FC = () => {
|
|||
reranking_model: {
|
||||
reranking_provider_name: '',
|
||||
reranking_model_name: '',
|
||||
reranking_plugin_id: '',
|
||||
},
|
||||
top_k: DATASET_DEFAULT.top_k,
|
||||
score_threshold_enabled: false,
|
||||
|
@ -282,7 +279,6 @@ const Configuration: FC = () => {
|
|||
reranking_model: restConfigs.reranking_model && {
|
||||
reranking_provider_name: restConfigs.reranking_model.reranking_provider_name,
|
||||
reranking_model_name: restConfigs.reranking_model.reranking_model_name,
|
||||
reranking_plugin_id: restConfigs.reranking_model.reranking_plugin_id,
|
||||
},
|
||||
retrieval_model,
|
||||
score_threshold_enabled,
|
||||
|
@ -324,7 +320,6 @@ const Configuration: FC = () => {
|
|||
textGenerationModelList,
|
||||
} = useTextGenerationCurrentProviderAndModelAndModelList(
|
||||
{
|
||||
plugin_id: modelConfig.plugin_id,
|
||||
provider: modelConfig.provider,
|
||||
model: modelConfig.model_id,
|
||||
},
|
||||
|
@ -355,7 +350,6 @@ const Configuration: FC = () => {
|
|||
const [canReturnToSimpleMode, setCanReturnToSimpleMode] = useState(true)
|
||||
const setPromptMode = async (mode: PromptMode) => {
|
||||
if (mode === PromptMode.advanced) {
|
||||
// eslint-disable-next-line ts/no-use-before-define
|
||||
await migrateToDefaultPrompt()
|
||||
setCanReturnToSimpleMode(true)
|
||||
}
|
||||
|
@ -551,7 +545,6 @@ const Configuration: FC = () => {
|
|||
|
||||
const config = {
|
||||
modelConfig: {
|
||||
plugin_id: model.plugin_id,
|
||||
provider: model.provider,
|
||||
model_id: model.name,
|
||||
mode: model.mode,
|
||||
|
@ -770,8 +763,8 @@ const Configuration: FC = () => {
|
|||
handleMultipleModelConfigsChange(
|
||||
true,
|
||||
[
|
||||
{ id: `${Date.now()}`, model: modelConfig.model_id, plugin_id: modelConfig.plugin_id, provider: modelConfig.provider, parameters: completionParams },
|
||||
{ id: `${Date.now()}-no-repeat`, model: '', plugin_id: '', provider: '', parameters: {} },
|
||||
{ id: `${Date.now()}`, model: modelConfig.model_id, provider: modelConfig.provider, parameters: completionParams },
|
||||
{ id: `${Date.now()}-no-repeat`, model: '', provider: '', parameters: {} },
|
||||
],
|
||||
)
|
||||
setAppSiderbarExpand('collapse')
|
||||
|
@ -893,7 +886,6 @@ const Configuration: FC = () => {
|
|||
<ModelParameterModal
|
||||
isAdvancedMode={isAdvancedMode}
|
||||
mode={mode}
|
||||
pluginId={modelConfig.plugin_id}
|
||||
provider={modelConfig.provider}
|
||||
completionParams={completionParams}
|
||||
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, '<')
|
||||
.replace(/>/g, '>')
|
||||
.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
|
||||
onHide: () => void
|
||||
onSave: (embeddingModel: {
|
||||
plugin_id: string
|
||||
embedding_provider_name: string
|
||||
embedding_model_name: string
|
||||
}, score: number) => void
|
||||
|
@ -44,13 +43,11 @@ const ConfigParamModal: FC<Props> = ({
|
|||
const [isLoading, setLoading] = useState(false)
|
||||
const [embeddingModel, setEmbeddingModel] = useState(oldAnnotationConfig.embedding_model
|
||||
? {
|
||||
plugin_id: oldAnnotationConfig.embedding_model.plugin_id,
|
||||
providerName: oldAnnotationConfig.embedding_model.embedding_provider_name,
|
||||
modelName: oldAnnotationConfig.embedding_model.embedding_model_name,
|
||||
}
|
||||
: (embeddingsDefaultModel
|
||||
? {
|
||||
plugin_id: embeddingsDefaultModel.provider.plugin_id,
|
||||
providerName: embeddingsDefaultModel.provider.provider,
|
||||
modelName: embeddingsDefaultModel.model,
|
||||
}
|
||||
|
@ -70,7 +67,6 @@ const ConfigParamModal: FC<Props> = ({
|
|||
}
|
||||
setLoading(true)
|
||||
await onSave({
|
||||
plugin_id: embeddingModel.plugin_id,
|
||||
embedding_provider_name: embeddingModel.providerName,
|
||||
embedding_model_name: embeddingModel.modelName,
|
||||
}, annotationConfig.score_threshold)
|
||||
|
@ -111,14 +107,12 @@ const ConfigParamModal: FC<Props> = ({
|
|||
<div className='pt-1'>
|
||||
<ModelSelector
|
||||
defaultModel={embeddingModel && {
|
||||
plugin_id: '',
|
||||
provider: embeddingModel.providerName,
|
||||
model: embeddingModel.modelName,
|
||||
}}
|
||||
modelList={embeddingsModelList}
|
||||
onSelect={(val) => {
|
||||
setEmbeddingModel({
|
||||
plugin_id: val.plugin_id,
|
||||
providerName: val.provider,
|
||||
modelName: val.model,
|
||||
})
|
||||
|
|
|
@ -199,13 +199,13 @@ export default function AccountSetting({
|
|||
)}
|
||||
</div>
|
||||
<div className='px-4 sm:px-8 pt-2'>
|
||||
{activeMenu === 'provider' && <ModelProviderPage searchText={searchValue} />}
|
||||
{activeMenu === 'members' && <MembersPage />}
|
||||
{activeMenu === 'billing' && <BillingPage />}
|
||||
{activeMenu === 'language' && <LanguagePage />}
|
||||
{activeMenu === 'provider' && <ModelProviderPage />}
|
||||
{activeMenu === 'data-source' && <DataSourcePage />}
|
||||
{activeMenu === 'api-based-extension' && <ApiBasedExtensionPage />}
|
||||
{activeMenu === 'custom' && <CustomPage />}
|
||||
{activeMenu === 'language' && <LanguagePage />}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
export type FormValue = Record<string, any>
|
||||
|
||||
export type TypeWithI18N<T = string> = {
|
||||
export interface TypeWithI18N<T = string> {
|
||||
en_US: T
|
||||
zh_Hans: T
|
||||
[key: string]: T
|
||||
|
@ -17,7 +17,7 @@ export enum FormTypeEnum {
|
|||
file = 'file',
|
||||
}
|
||||
|
||||
export type FormOption = {
|
||||
export interface FormOption {
|
||||
label: TypeWithI18N
|
||||
value: string
|
||||
show_on: FormShowOnObject[]
|
||||
|
@ -89,12 +89,12 @@ export enum CustomConfigurationStatusEnum {
|
|||
noConfigure = 'no-configure',
|
||||
}
|
||||
|
||||
export type FormShowOnObject = {
|
||||
export interface FormShowOnObject {
|
||||
variable: string
|
||||
value: string
|
||||
}
|
||||
|
||||
export type CredentialFormSchemaBase = {
|
||||
export interface CredentialFormSchemaBase {
|
||||
variable: string
|
||||
label: TypeWithI18N
|
||||
type: FormTypeEnum
|
||||
|
@ -112,7 +112,7 @@ export type CredentialFormSchemaRadio = CredentialFormSchemaBase & { options: Fo
|
|||
export type CredentialFormSchemaSecretInput = CredentialFormSchemaBase & { placeholder?: TypeWithI18N }
|
||||
export type CredentialFormSchema = CredentialFormSchemaTextInput | CredentialFormSchemaSelect | CredentialFormSchemaRadio | CredentialFormSchemaSecretInput
|
||||
|
||||
export type ModelItem = {
|
||||
export interface ModelItem {
|
||||
model: string
|
||||
label: TypeWithI18N
|
||||
model_type: ModelTypeEnum
|
||||
|
@ -141,7 +141,7 @@ export enum QuotaUnitEnum {
|
|||
credits = 'credits',
|
||||
}
|
||||
|
||||
export type QuotaConfiguration = {
|
||||
export interface QuotaConfiguration {
|
||||
quota_type: CurrentSystemQuotaTypeEnum
|
||||
quota_unit: QuotaUnitEnum
|
||||
quota_limit: number
|
||||
|
@ -150,8 +150,7 @@ export type QuotaConfiguration = {
|
|||
is_valid: boolean
|
||||
}
|
||||
|
||||
export type ModelProvider = {
|
||||
plugin_id: string
|
||||
export interface ModelProvider {
|
||||
provider: string
|
||||
label: TypeWithI18N
|
||||
description?: TypeWithI18N
|
||||
|
@ -185,8 +184,7 @@ export type ModelProvider = {
|
|||
}
|
||||
}
|
||||
|
||||
export type Model = {
|
||||
plugin_id: string
|
||||
export interface Model {
|
||||
provider: string
|
||||
icon_large: TypeWithI18N
|
||||
icon_small: TypeWithI18N
|
||||
|
@ -195,29 +193,27 @@ export type Model = {
|
|||
status: ModelStatusEnum
|
||||
}
|
||||
|
||||
export type DefaultModelResponse = {
|
||||
export interface DefaultModelResponse {
|
||||
model: string
|
||||
model_type: ModelTypeEnum
|
||||
provider: {
|
||||
plugin_id: string
|
||||
provider: string
|
||||
icon_large: TypeWithI18N
|
||||
icon_small: TypeWithI18N
|
||||
}
|
||||
}
|
||||
|
||||
export type DefaultModel = {
|
||||
plugin_id: string
|
||||
export interface DefaultModel {
|
||||
provider: string
|
||||
model: string
|
||||
}
|
||||
|
||||
export type CustomConfigurationModelFixedFields = {
|
||||
export interface CustomConfigurationModelFixedFields {
|
||||
__model_name: string
|
||||
__model_type: ModelTypeEnum
|
||||
}
|
||||
|
||||
export type ModelParameterRule = {
|
||||
export interface ModelParameterRule {
|
||||
default?: number | string | boolean | string[]
|
||||
help?: TypeWithI18N
|
||||
label: TypeWithI18N
|
||||
|
@ -232,7 +228,7 @@ export type ModelParameterRule = {
|
|||
tagPlaceholder?: TypeWithI18N
|
||||
}
|
||||
|
||||
export type ModelLoadBalancingConfigEntry = {
|
||||
export interface ModelLoadBalancingConfigEntry {
|
||||
/** model balancing config entry id */
|
||||
id?: string
|
||||
/** is config entry enabled */
|
||||
|
@ -247,7 +243,7 @@ export type ModelLoadBalancingConfigEntry = {
|
|||
ttl?: number
|
||||
}
|
||||
|
||||
export type ModelLoadBalancingConfig = {
|
||||
export interface ModelLoadBalancingConfig {
|
||||
enabled: boolean
|
||||
configs: ModelLoadBalancingConfigEntry[]
|
||||
}
|
||||
|
|
|
@ -11,7 +11,6 @@ import type {
|
|||
DefaultModel,
|
||||
DefaultModelResponse,
|
||||
Model,
|
||||
ModelProvider,
|
||||
ModelTypeEnum,
|
||||
} from './declarations'
|
||||
import {
|
||||
|
@ -37,12 +36,11 @@ export const useSystemDefaultModelAndModelList: UseDefaultModelAndModelList = (
|
|||
modelList,
|
||||
) => {
|
||||
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 currentDefaultModel = currentProvider && currentModel && {
|
||||
model: currentModel.model,
|
||||
provider: currentProvider.provider,
|
||||
plugin_id: currentProvider.plugin_id,
|
||||
}
|
||||
|
||||
return currentDefaultModel
|
||||
|
@ -64,20 +62,20 @@ export const useLanguage = () => {
|
|||
}
|
||||
|
||||
export const useProviderCredentialsAndLoadBalancing = (
|
||||
provider: ModelProvider,
|
||||
provider: string,
|
||||
configurationMethod: ConfigurationMethodEnum,
|
||||
configured?: boolean,
|
||||
currentCustomConfigurationModelFixedFields?: CustomConfigurationModelFixedFields,
|
||||
) => {
|
||||
const { data: predefinedFormSchemasValue, mutate: mutatePredefined } = useSWR(
|
||||
(configurationMethod === ConfigurationMethodEnum.predefinedModel && configured)
|
||||
? `/workspaces/current/model-providers/${provider.plugin_id}/${provider.provider}/credentials`
|
||||
? `/workspaces/current/model-providers/${provider}/credentials`
|
||||
: null,
|
||||
fetchModelProviderCredentials,
|
||||
)
|
||||
const { data: customFormSchemasValue, mutate: mutateCustomized } = useSWR(
|
||||
(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,
|
||||
fetchModelProviderCredentials,
|
||||
)
|
||||
|
@ -174,11 +172,7 @@ export const useModelListAndDefaultModelAndCurrentProviderAndModel = (type: Mode
|
|||
const { modelList, defaultModel } = useModelListAndDefaultModel(type)
|
||||
const { currentProvider, currentModel } = useCurrentProviderAndModel(
|
||||
modelList,
|
||||
{
|
||||
plugin_id: defaultModel?.provider.plugin_id || '',
|
||||
provider: defaultModel?.provider.provider || '',
|
||||
model: defaultModel?.model || '',
|
||||
},
|
||||
{ provider: defaultModel?.provider.provider || '', model: defaultModel?.model || '' },
|
||||
)
|
||||
|
||||
return {
|
||||
|
@ -199,7 +193,6 @@ export const useUpdateModelList = () => {
|
|||
return updateModelList
|
||||
}
|
||||
|
||||
// deprecated ???
|
||||
export const useAnthropicBuyQuota = () => {
|
||||
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 Link from 'next/link'
|
||||
import { useDebounce } from 'ahooks'
|
||||
import {
|
||||
RiAlertFill,
|
||||
RiArrowDownSLine,
|
||||
RiArrowRightUpLine,
|
||||
RiBrainLine,
|
||||
} from '@remixicon/react'
|
||||
import { useContext } from 'use-context-selector'
|
||||
import SystemModelSelector from './system-model-selector'
|
||||
import ProviderAddedCard, { UPDATE_MODEL_PROVIDER_CUSTOM_MODEL_LIST } from './provider-added-card'
|
||||
// import ProviderCard from './provider-card'
|
||||
import type {
|
||||
CustomConfigurationModelFixedFields,
|
||||
ModelProvider,
|
||||
|
@ -26,16 +25,24 @@ import {
|
|||
useUpdateModelProviders,
|
||||
} from './hooks'
|
||||
import Divider from '@/app/components/base/divider'
|
||||
import Loading from '@/app/components/base/loading'
|
||||
import ProviderCard from '@/app/components/plugins/provider-card'
|
||||
import I18n from '@/context/i18n'
|
||||
import { useProviderContext } from '@/context/provider-context'
|
||||
import { useModalContextSelector } from '@/context/modal-context'
|
||||
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 { 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 { eventEmitter } = useEventEmitterContextContext()
|
||||
const updateModelProviders = useUpdateModelProviders()
|
||||
|
@ -67,6 +74,18 @@ const ModelProviderPage = () => {
|
|||
|
||||
return [configuredProviders, notConfiguredProviders]
|
||||
}, [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 = (
|
||||
provider: ModelProvider,
|
||||
|
@ -91,7 +110,7 @@ const ModelProviderPage = () => {
|
|||
if (configurationMethod === ConfigurationMethodEnum.customizableModel && provider.custom_configuration.status === CustomConfigurationStatusEnum.active) {
|
||||
eventEmitter?.emit({
|
||||
type: UPDATE_MODEL_PROVIDER_CUSTOM_MODEL_LIST,
|
||||
payload: provider,
|
||||
payload: provider.provider,
|
||||
} as any)
|
||||
|
||||
if (CustomConfigurationModelFixedFields?.__model_type)
|
||||
|
@ -102,10 +121,28 @@ const ModelProviderPage = () => {
|
|||
}
|
||||
|
||||
const [collapse, setCollapse] = useState(false)
|
||||
const { locale } = useContext(I18n)
|
||||
|
||||
// TODO #Plugin list API#
|
||||
const pluginList = [toolNotion, extensionDallE, modelGPT4]
|
||||
const {
|
||||
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 (
|
||||
<div className='relative pt-1 -mt-2'>
|
||||
|
@ -132,7 +169,7 @@ const ModelProviderPage = () => {
|
|||
/>
|
||||
</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='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' />
|
||||
|
@ -141,9 +178,9 @@ const ModelProviderPage = () => {
|
|||
<div className='mt-1 text-text-tertiary system-xs-regular'>{t('common.modelProvider.emptyProviderTip')}</div>
|
||||
</div>
|
||||
)}
|
||||
{!!configuredProviders?.length && (
|
||||
{!!filteredConfiguredProviders?.length && (
|
||||
<div className='relative'>
|
||||
{configuredProviders?.map(provider => (
|
||||
{filteredConfiguredProviders?.map(provider => (
|
||||
<ProviderAddedCard
|
||||
key={provider.provider}
|
||||
provider={provider}
|
||||
|
@ -152,11 +189,11 @@ const ModelProviderPage = () => {
|
|||
))}
|
||||
</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='relative'>
|
||||
{notConfiguredProviders?.map(provider => (
|
||||
{filteredNotConfiguredProviders?.map(provider => (
|
||||
<ProviderAddedCard
|
||||
notConfigured
|
||||
key={provider.provider}
|
||||
|
@ -176,19 +213,20 @@ const ModelProviderPage = () => {
|
|||
</div>
|
||||
<div className='flex items-center mb-2 pt-2'>
|
||||
<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
|
||||
<RiArrowRightUpLine className='w-4 h-4' />
|
||||
</Link>
|
||||
</div>
|
||||
</div>
|
||||
{!collapse && (
|
||||
{!collapse && !isPluginsLoading && (
|
||||
<div className='grid grid-cols-2 gap-2'>
|
||||
{pluginList.map((plugin, index) => (
|
||||
<ProviderCard key={index} installed={false} payload={plugin as any} />
|
||||
{plugins.map(plugin => (
|
||||
<ProviderCard key={plugin.plugin_id} payload={plugin} />
|
||||
))}
|
||||
</div>
|
||||
)}
|
||||
{!collapse && isPluginsLoading && <Loading type='area' />}
|
||||
</div>
|
||||
</div>
|
||||
)
|
||||
|
|
|
@ -72,7 +72,7 @@ const ModelModal: FC<ModelModalProps> = ({
|
|||
loadBalancing: originalConfig,
|
||||
mutate,
|
||||
} = useProviderCredentialsAndLoadBalancing(
|
||||
provider,
|
||||
provider.provider,
|
||||
configurateMethod,
|
||||
providerFormSchemaPredefined && provider.custom_configuration.status === CustomConfigurationStatusEnum.active,
|
||||
currentCustomConfigurationModelFixedFields,
|
||||
|
@ -229,7 +229,6 @@ const ModelModal: FC<ModelModalProps> = ({
|
|||
setLoading(true)
|
||||
const res = await saveCredentials(
|
||||
providerFormSchemaPredefined,
|
||||
provider.plugin_id,
|
||||
provider.provider,
|
||||
encodeSecretValues(value),
|
||||
{
|
||||
|
@ -256,7 +255,6 @@ const ModelModal: FC<ModelModalProps> = ({
|
|||
|
||||
const res = await removeCredentials(
|
||||
providerFormSchemaPredefined,
|
||||
provider.plugin_id,
|
||||
provider.provider,
|
||||
value,
|
||||
)
|
||||
|
|
|
@ -209,7 +209,6 @@ const ModelLoadBalancingEntryModal: FC<ModelModalProps> = ({
|
|||
|
||||
const res = await validateLoadBalancingCredentials(
|
||||
providerFormSchemaPredefined,
|
||||
provider.plugin_id,
|
||||
provider.provider,
|
||||
{
|
||||
...value,
|
||||
|
|
|
@ -38,9 +38,8 @@ export type ModelParameterModalProps = {
|
|||
isAdvancedMode: boolean
|
||||
mode: string
|
||||
modelId: string
|
||||
pluginId: 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
|
||||
onCompletionParamsChange: (newParams: FormValue) => void
|
||||
hideDebugWithMultipleModel?: boolean
|
||||
|
@ -75,7 +74,6 @@ const ModelParameterModal: FC<ModelParameterModalProps> = ({
|
|||
portalToFollowElemContentClassName,
|
||||
isAdvancedMode,
|
||||
modelId,
|
||||
pluginId,
|
||||
provider,
|
||||
setModel,
|
||||
completionParams,
|
||||
|
@ -90,17 +88,13 @@ const ModelParameterModal: FC<ModelParameterModalProps> = ({
|
|||
const { t } = useTranslation()
|
||||
const { isAPIKeySet } = useProviderContext()
|
||||
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 {
|
||||
currentProvider,
|
||||
currentModel,
|
||||
activeTextGenerationModelList,
|
||||
} = useTextGenerationCurrentProviderAndModelAndModelList(
|
||||
{
|
||||
plugin_id: pluginId,
|
||||
provider,
|
||||
model: modelId,
|
||||
},
|
||||
{ provider, model: modelId },
|
||||
)
|
||||
|
||||
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 targetModelItem = targetProvider?.models.find(modelItem => modelItem.model === model)
|
||||
setModel({
|
||||
modelId: model,
|
||||
pluginId: plugin_id,
|
||||
provider,
|
||||
mode: targetModelItem?.model_properties.mode as string,
|
||||
features: targetModelItem?.features || [],
|
||||
|
@ -208,7 +201,7 @@ const ModelParameterModal: FC<ModelParameterModalProps> = ({
|
|||
{t('common.modelProvider.model').toLocaleUpperCase()}
|
||||
</div>
|
||||
<ModelSelector
|
||||
defaultModel={(provider || modelId) ? { plugin_id: pluginId, provider, model: modelId } : undefined}
|
||||
defaultModel={(provider || modelId) ? { provider, model: modelId } : undefined}
|
||||
modelList={activeTextGenerationModelList}
|
||||
onSelect={handleChangeModel}
|
||||
triggerClassName='max-w-[295px]'
|
||||
|
|
|
@ -41,11 +41,11 @@ const ModelSelector: FC<ModelSelectorProps> = ({
|
|||
defaultModel,
|
||||
)
|
||||
|
||||
const handleSelect = (pluginId: string, provider: string, model: ModelItem) => {
|
||||
const handleSelect = (provider: string, model: ModelItem) => {
|
||||
setOpen(false)
|
||||
|
||||
if (onSelect)
|
||||
onSelect({ plugin_id: pluginId, provider, model: model.model })
|
||||
onSelect({ provider, model: model.model })
|
||||
}
|
||||
|
||||
const handleToggle = () => {
|
||||
|
|
|
@ -25,7 +25,7 @@ import Tooltip from '@/app/components/base/tooltip'
|
|||
type PopupItemProps = {
|
||||
defaultModel?: DefaultModel
|
||||
model: Model
|
||||
onSelect: (pluginId: string, provider: string, model: ModelItem) => void
|
||||
onSelect: (provider: string, model: ModelItem) => void
|
||||
}
|
||||
const PopupItem: FC<PopupItemProps> = ({
|
||||
defaultModel,
|
||||
|
@ -39,11 +39,11 @@ const PopupItem: FC<PopupItemProps> = ({
|
|||
const updateModelList = useUpdateModelList()
|
||||
const updateModelProviders = useUpdateModelProviders()
|
||||
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)
|
||||
return
|
||||
|
||||
onSelect(pluginId, provider, modelItem)
|
||||
onSelect(provider, modelItem)
|
||||
}
|
||||
const handleOpenModelModal = () => {
|
||||
setShowModelModal({
|
||||
|
@ -80,7 +80,7 @@ const PopupItem: FC<PopupItemProps> = ({
|
|||
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'}
|
||||
`}
|
||||
onClick={() => handleSelect(model.plugin_id, model.provider, modelItem)}
|
||||
onClick={() => handleSelect(model.provider, modelItem)}
|
||||
>
|
||||
<ModelIcon
|
||||
className={`
|
||||
|
|
|
@ -15,7 +15,7 @@ import { XCircle } from '@/app/components/base/icons/src/vender/solid/general'
|
|||
type PopupProps = {
|
||||
defaultModel?: DefaultModel
|
||||
modelList: Model[]
|
||||
onSelect: (pluginId: string, provider: string, model: ModelItem) => void
|
||||
onSelect: (provider: string, model: ModelItem) => void
|
||||
}
|
||||
const Popup: FC<PopupProps> = ({
|
||||
defaultModel,
|
||||
|
|
|
@ -41,7 +41,7 @@ const CredentialPanel: FC<CredentialPanelProps> = ({
|
|||
|
||||
const handleChangePriority = async (key: PreferredProviderTypeEnum) => {
|
||||
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: {
|
||||
preferred_provider_type: key,
|
||||
},
|
||||
|
@ -57,7 +57,7 @@ const CredentialPanel: FC<CredentialPanelProps> = ({
|
|||
|
||||
eventEmitter?.emit({
|
||||
type: UPDATE_MODEL_PROVIDER_CUSTOM_MODEL_LIST,
|
||||
payload: provider,
|
||||
payload: provider.provider,
|
||||
} 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 showCredential = configurationMethods.includes(ConfigurationMethodEnum.predefinedModel) && isCurrentWorkspaceManager
|
||||
|
||||
const getModelList = async (pluginID: string, providerName: string) => {
|
||||
const getModelList = async (providerName: string) => {
|
||||
if (loading)
|
||||
return
|
||||
try {
|
||||
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)
|
||||
setCollapsed(false)
|
||||
setFetched(true)
|
||||
|
@ -72,12 +72,12 @@ const ProviderAddedCard: FC<ProviderAddedCardProps> = ({
|
|||
return
|
||||
}
|
||||
|
||||
getModelList(provider.plugin_id, provider.provider)
|
||||
getModelList(provider.provider)
|
||||
}
|
||||
|
||||
eventEmitter?.useSubscription((v: any) => {
|
||||
if (v?.type === UPDATE_MODEL_PROVIDER_CUSTOM_MODEL_LIST && v.payload.provider === provider.provider)
|
||||
getModelList(v.payload.plugin_id, v.payload.provider)
|
||||
if (v?.type === UPDATE_MODEL_PROVIDER_CUSTOM_MODEL_LIST && v.payload === provider.provider)
|
||||
getModelList(v.payload)
|
||||
})
|
||||
|
||||
return (
|
||||
|
@ -172,7 +172,7 @@ const ProviderAddedCard: FC<ProviderAddedCardProps> = ({
|
|||
models={modelList}
|
||||
onCollapse={() => setCollapsed(true)}
|
||||
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) => {
|
||||
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
|
||||
await disableModel(`/workspaces/current/model-providers/${provider.plugin_id}/${provider.provider}/models/disable`, { model: model.model, model_type: model.model_type })
|
||||
}, [model.model, model.model_type, provider.plugin_id, provider.provider])
|
||||
await disableModel(`/workspaces/current/model-providers/${provider.provider}/models/disable`, { model: model.model, model_type: model.model_type })
|
||||
}, [model.model, model.model_type, provider.provider])
|
||||
|
||||
const { run: debouncedToggleModelEnablingStatus } = useDebounceFn(toggleModelEnablingStatus, { wait: 500 })
|
||||
|
||||
|
|
|
@ -23,7 +23,7 @@ type ModelListProps = {
|
|||
models: ModelItem[]
|
||||
onCollapse: () => void
|
||||
onConfig: (currentCustomConfigurationModelFixedFields?: CustomConfigurationModelFixedFields) => void
|
||||
onChange?: (provider: ModelProvider) => void
|
||||
onChange?: (provider: string) => void
|
||||
}
|
||||
const ModelList: FC<ModelListProps> = ({
|
||||
provider,
|
||||
|
|
|
@ -19,7 +19,7 @@ export type ModelLoadBalancingModalProps = {
|
|||
model: ModelItem
|
||||
open?: boolean
|
||||
onClose?: () => void
|
||||
onSave?: (provider: ModelProvider) => void
|
||||
onSave?: (provider: string) => void
|
||||
}
|
||||
|
||||
// model balancing config modal
|
||||
|
@ -30,7 +30,7 @@ const ModelLoadBalancingModal = ({ provider, model, open = false, onClose, onSav
|
|||
const [loading, setLoading] = useState(false)
|
||||
|
||||
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,
|
||||
)
|
||||
|
||||
|
@ -94,7 +94,7 @@ const ModelLoadBalancingModal = ({ provider, model, open = false, onClose, onSav
|
|||
if (res.result === 'success') {
|
||||
notify({ type: 'success', message: t('common.actionMsg.modifiedSuccessfully') })
|
||||
mutate()
|
||||
onSave?.(provider)
|
||||
onSave?.(provider.provider)
|
||||
onClose?.()
|
||||
}
|
||||
}
|
||||
|
|
|
@ -94,7 +94,6 @@ const SystemModel: FC<SystemModelSelectorProps> = ({
|
|||
model_settings: [ModelTypeEnum.textGeneration, ModelTypeEnum.textEmbedding, ModelTypeEnum.rerank, ModelTypeEnum.speech2text, ModelTypeEnum.tts].map((modelType) => {
|
||||
return {
|
||||
model_type: modelType,
|
||||
plugin_id: getCurrentDefaultModelByModelType(modelType)?.plugin_id,
|
||||
provider: getCurrentDefaultModelByModelType(modelType)?.provider,
|
||||
model: getCurrentDefaultModelByModelType(modelType)?.model,
|
||||
}
|
||||
|
@ -132,6 +131,7 @@ const SystemModel: FC<SystemModelSelectorProps> = ({
|
|||
>
|
||||
<PortalToFollowElemTrigger onClick={() => setOpen(v => !v)}>
|
||||
<Button
|
||||
className='relative'
|
||||
variant={notConfigured ? 'primary' : 'secondary'}
|
||||
size='small'
|
||||
>
|
||||
|
|
|
@ -26,15 +26,14 @@ export const isNullOrUndefined = (value: any) => {
|
|||
return value === undefined || value === null
|
||||
}
|
||||
|
||||
// deprecated ???
|
||||
export const validateCredentials = async (predefined: boolean, pluginID: string, provider: string, v: FormValue) => {
|
||||
export const validateCredentials = async (predefined: boolean, provider: string, v: FormValue) => {
|
||||
let body, url
|
||||
|
||||
if (predefined) {
|
||||
body = {
|
||||
credentials: v,
|
||||
}
|
||||
url = `/workspaces/current/model-providers/${pluginID}/${provider}/credentials/validate`
|
||||
url = `/workspaces/current/model-providers/${provider}/credentials/validate`
|
||||
}
|
||||
else {
|
||||
const { __model_name, __model_type, ...credentials } = v
|
||||
|
@ -43,7 +42,7 @@ export const validateCredentials = async (predefined: boolean, pluginID: string,
|
|||
model_type: __model_type,
|
||||
credentials,
|
||||
}
|
||||
url = `/workspaces/current/model-providers/${pluginID}/${provider}/models/credentials/validate`
|
||||
url = `/workspaces/current/model-providers/${provider}/models/credentials/validate`
|
||||
}
|
||||
try {
|
||||
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
|
||||
message?: string
|
||||
}> => {
|
||||
const { __model_name, __model_type, ...credentials } = v
|
||||
try {
|
||||
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: {
|
||||
model: __model_name,
|
||||
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
|
||||
|
||||
if (predefined) {
|
||||
|
@ -90,7 +89,7 @@ export const saveCredentials = async (predefined: boolean, pluginID: string, pro
|
|||
credentials: v,
|
||||
load_balancing: loadBalancing,
|
||||
}
|
||||
url = `/workspaces/current/model-providers/${pluginID}/${provider}`
|
||||
url = `/workspaces/current/model-providers/${provider}`
|
||||
}
|
||||
else {
|
||||
const { __model_name, __model_type, ...credentials } = v
|
||||
|
@ -100,7 +99,7 @@ export const saveCredentials = async (predefined: boolean, pluginID: string, pro
|
|||
credentials,
|
||||
load_balancing: loadBalancing,
|
||||
}
|
||||
url = `/workspaces/current/model-providers/${pluginID}/${provider}/models`
|
||||
url = `/workspaces/current/model-providers/${provider}/models`
|
||||
}
|
||||
|
||||
return setModelProvider({ url, body })
|
||||
|
@ -120,12 +119,12 @@ export const savePredefinedLoadBalancingConfig = async (provider: string, v: For
|
|||
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 body
|
||||
|
||||
if (predefined) {
|
||||
url = `/workspaces/current/model-providers/${pluginID}/${provider}`
|
||||
url = `/workspaces/current/model-providers/${provider}`
|
||||
}
|
||||
else {
|
||||
if (v) {
|
||||
|
@ -134,7 +133,7 @@ export const removeCredentials = async (predefined: boolean, pluginID: string, p
|
|||
model: __model_name,
|
||||
model_type: __model_type,
|
||||
}
|
||||
url = `/workspaces/current/model-providers/${pluginID}/${provider}/models`
|
||||
url = `/workspaces/current/model-providers/${provider}/models`
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -13,10 +13,11 @@ import checkTaskStatus from '../../base/check-task-status'
|
|||
|
||||
const i18nPrefix = 'plugin.installModal'
|
||||
|
||||
interface Props {
|
||||
type Props = {
|
||||
uniqueIdentifier: string
|
||||
payload: PluginDeclaration
|
||||
onCancel: () => void
|
||||
onStartToInstall?: () => void
|
||||
onInstalled: () => void
|
||||
onFailed: (message?: string) => void
|
||||
}
|
||||
|
@ -25,6 +26,7 @@ const Installed: FC<Props> = ({
|
|||
uniqueIdentifier,
|
||||
payload,
|
||||
onCancel,
|
||||
onStartToInstall,
|
||||
onInstalled,
|
||||
onFailed,
|
||||
}) => {
|
||||
|
@ -43,6 +45,8 @@ const Installed: FC<Props> = ({
|
|||
const handleInstall = async () => {
|
||||
if (isInstalling) return
|
||||
setIsInstalling(true)
|
||||
onStartToInstall?.()
|
||||
|
||||
try {
|
||||
const {
|
||||
all_installed: isInstalled,
|
||||
|
|
|
@ -18,6 +18,7 @@ type Props = {
|
|||
uniqueIdentifier: string
|
||||
payload: PluginManifestInMarket
|
||||
onCancel: () => void
|
||||
onStartToInstall?: () => void
|
||||
onInstalled: () => void
|
||||
onFailed: (message?: string) => void
|
||||
}
|
||||
|
@ -26,6 +27,7 @@ const Installed: FC<Props> = ({
|
|||
uniqueIdentifier,
|
||||
payload,
|
||||
onCancel,
|
||||
onStartToInstall,
|
||||
onInstalled,
|
||||
onFailed,
|
||||
}) => {
|
||||
|
@ -43,6 +45,7 @@ const Installed: FC<Props> = ({
|
|||
|
||||
const handleInstall = async () => {
|
||||
if (isInstalling) return
|
||||
onStartToInstall?.()
|
||||
setIsInstalling(true)
|
||||
|
||||
try {
|
||||
|
@ -90,7 +93,7 @@ const Installed: FC<Props> = ({
|
|||
</>
|
||||
)
|
||||
}</>)
|
||||
}, [payload])
|
||||
}, [payload.latest_version, supportCheckInstalled])
|
||||
|
||||
return (
|
||||
<>
|
||||
|
|
|
@ -130,7 +130,7 @@ export const MarketplaceContextProvider = ({
|
|||
queryMarketplaceCollectionsAndPlugins({
|
||||
category: type === PLUGIN_TYPE_SEARCH_MAP.all ? undefined : type,
|
||||
})
|
||||
setPlugins(undefined)
|
||||
setPlugins([])
|
||||
|
||||
return
|
||||
}
|
||||
|
|
|
@ -40,7 +40,7 @@ export const useMarketplaceCollectionsAndPlugins = () => {
|
|||
|
||||
export const useMarketplacePlugins = () => {
|
||||
const [isLoading, setIsLoading] = useState(false)
|
||||
const [plugins, setPlugins] = useState<Plugin[]>()
|
||||
const [plugins, setPlugins] = useState<Plugin[]>([])
|
||||
|
||||
const queryPlugins = useCallback(async (query: PluginsSearchParams) => {
|
||||
setIsLoading(true)
|
||||
|
|
|
@ -1,8 +1,10 @@
|
|||
'use client'
|
||||
import { RiArrowRightUpLine } from '@remixicon/react'
|
||||
import { useTranslation } from 'react-i18next'
|
||||
import Card from '@/app/components/plugins/card'
|
||||
import CardMoreInfo from '@/app/components/plugins/card/card-more-info'
|
||||
import type { Plugin } from '@/app/components/plugins/types'
|
||||
import { MARKETPLACE_URL_PREFIX } from '@/config'
|
||||
import Button from '@/app/components/base/button'
|
||||
|
||||
type CardWrapperProps = {
|
||||
|
@ -13,6 +15,7 @@ const CardWrapper = ({
|
|||
plugin,
|
||||
showInstallButton,
|
||||
}: CardWrapperProps) => {
|
||||
const { t } = useTranslation()
|
||||
return (
|
||||
<div className='group relative rounded-xl cursor-pointer'>
|
||||
<Card
|
||||
|
@ -32,13 +35,15 @@ const CardWrapper = ({
|
|||
variant='primary'
|
||||
className='flex-1'
|
||||
>
|
||||
Install
|
||||
{t('plugin.detailPanel.operation.install')}
|
||||
</Button>
|
||||
<Button
|
||||
className='flex-1'
|
||||
>
|
||||
Details
|
||||
<RiArrowRightUpLine className='ml-1 w-4 h-4' />
|
||||
<a href={`${MARKETPLACE_URL_PREFIX}/plugin/${plugin.org}/${plugin.name}`} target='_blank' className='flex items-center gap-0.5'>
|
||||
{t('plugin.detailPanel.operation.detail')}
|
||||
<RiArrowRightUpLine className='ml-1 w-4 h-4' />
|
||||
</a>
|
||||
</Button>
|
||||
</div>
|
||||
)
|
||||
|
|
|
@ -1,6 +1,5 @@
|
|||
'use client'
|
||||
import { RiCloseLine } from '@remixicon/react'
|
||||
import { useMarketplaceContext } from '../context'
|
||||
import TagsFilter from './tags-filter'
|
||||
import ActionButton from '@/app/components/base/action-button'
|
||||
import cn from '@/utils/classnames'
|
||||
|
@ -11,6 +10,8 @@ type SearchBoxProps = {
|
|||
inputClassName?: string
|
||||
tags: string[]
|
||||
onTagsChange: (tags: string[]) => void
|
||||
size?: 'small' | 'large'
|
||||
placeholder?: string
|
||||
}
|
||||
const SearchBox = ({
|
||||
search,
|
||||
|
@ -18,36 +19,39 @@ const SearchBox = ({
|
|||
inputClassName,
|
||||
tags,
|
||||
onTagsChange,
|
||||
size = 'small',
|
||||
placeholder = 'Search tools...',
|
||||
}: SearchBoxProps) => {
|
||||
const intersected = useMarketplaceContext(v => v.intersected)
|
||||
const searchPluginText = useMarketplaceContext(v => v.searchPluginText)
|
||||
const handleSearchPluginTextChange = useMarketplaceContext(v => v.handleSearchPluginTextChange)
|
||||
|
||||
return (
|
||||
<div
|
||||
className={cn(
|
||||
'sticky top-3 flex items-center mx-auto p-1.5 w-[640px] h-11 border border-components-chat-input-border bg-components-panel-bg-blur rounded-xl shadow-md z-[11]',
|
||||
'flex items-center z-[11]',
|
||||
size === 'large' && 'p-1.5 bg-components-panel-bg-blur rounded-xl shadow-md border border-components-chat-input-border',
|
||||
size === 'small' && 'p-0.5 bg-components-input-bg-normal rounded-lg',
|
||||
inputClassName,
|
||||
!intersected && 'w-[508px] transition-[width] duration-300',
|
||||
)}
|
||||
>
|
||||
<TagsFilter
|
||||
tags={tags}
|
||||
onTagsChange={onTagsChange}
|
||||
size={size}
|
||||
/>
|
||||
<div className='mx-1 w-[1px] h-3.5 bg-divider-regular'></div>
|
||||
<div className='grow flex items-center p-1 pl-2'>
|
||||
<div className='flex items-center mr-2 py-0.5 w-full'>
|
||||
<input
|
||||
className='grow block outline-none appearance-none body-md-medium text-text-secondary'
|
||||
className={cn(
|
||||
'grow block outline-none appearance-none body-md-medium text-text-secondary bg-transparent',
|
||||
)}
|
||||
value={search}
|
||||
onChange={(e) => {
|
||||
onSearchChange(e.target.value)
|
||||
}}
|
||||
placeholder={placeholder}
|
||||
/>
|
||||
{
|
||||
searchPluginText && (
|
||||
<ActionButton onClick={() => handleSearchPluginTextChange('')}>
|
||||
search && (
|
||||
<ActionButton onClick={() => onSearchChange('')}>
|
||||
<RiCloseLine className='w-4 h-4' />
|
||||
</ActionButton>
|
||||
)
|
||||
|
|
|
@ -12,11 +12,15 @@ const SearchBoxWrapper = () => {
|
|||
|
||||
return (
|
||||
<SearchBox
|
||||
inputClassName={cn(!intersected && 'w-[508px] transition-[width] duration-300')}
|
||||
inputClassName={cn(
|
||||
'sticky top-3 mx-auto w-[640px]',
|
||||
!intersected && 'w-[508px] transition-[width] duration-300',
|
||||
)}
|
||||
search={searchPluginText}
|
||||
onSearchChange={handleSearchPluginTextChange}
|
||||
tags={filterPluginTags}
|
||||
onTagsChange={handleFilterPluginTagsChange}
|
||||
size='large'
|
||||
/>
|
||||
)
|
||||
}
|
||||
|
|
|
@ -18,10 +18,12 @@ import Input from '@/app/components/base/input'
|
|||
type TagsFilterProps = {
|
||||
tags: string[]
|
||||
onTagsChange: (tags: string[]) => void
|
||||
size: 'small' | 'large'
|
||||
}
|
||||
const TagsFilter = ({
|
||||
tags,
|
||||
onTagsChange,
|
||||
size,
|
||||
}: TagsFilterProps) => {
|
||||
const [open, setOpen] = useState(false)
|
||||
const [searchText, setSearchText] = useState('')
|
||||
|
@ -56,7 +58,9 @@ const TagsFilter = ({
|
|||
>
|
||||
<PortalToFollowElemTrigger onClick={() => setOpen(v => !v)}>
|
||||
<div className={cn(
|
||||
'flex items-center px-2 py-1 h-8 text-text-tertiary rounded-lg hover:bg-state-base-hover cursor-pointer',
|
||||
'flex items-center text-text-tertiary rounded-lg hover:bg-state-base-hover cursor-pointer',
|
||||
size === 'large' && 'px-2 py-1 h-8',
|
||||
size === 'small' && 'pr-1.5 py-0.5 h-7 pl-1 ',
|
||||
selectedTagsLength && 'text-text-secondary',
|
||||
open && 'bg-state-base-hover',
|
||||
)}>
|
||||
|
@ -65,6 +69,8 @@ const TagsFilter = ({
|
|||
</div>
|
||||
<div className={cn(
|
||||
'flex items-center p-1 system-sm-medium',
|
||||
size === 'large' && 'p-1',
|
||||
size === 'small' && 'px-0.5 py-1',
|
||||
)}>
|
||||
{
|
||||
!selectedTagsLength && 'All Tags'
|
||||
|
@ -95,7 +101,7 @@ const TagsFilter = ({
|
|||
}
|
||||
</div>
|
||||
</PortalToFollowElemTrigger>
|
||||
<PortalToFollowElemContent className='z-10'>
|
||||
<PortalToFollowElemContent className='z-[1000]'>
|
||||
<div className='w-[240px] border-[0.5px] border-components-panel-border bg-components-panel-bg-blur rounded-xl shadow-lg'>
|
||||
<div className='p-2 pb-1'>
|
||||
<Input
|
||||
|
|
|
@ -1,8 +1,7 @@
|
|||
'use client'
|
||||
import React from 'react'
|
||||
import { useContext } from 'use-context-selector'
|
||||
import type { FC } from 'react'
|
||||
import Link from 'next/link'
|
||||
import { useTranslation } from 'react-i18next'
|
||||
import { RiArrowRightUpLine, RiVerifiedBadgeLine } from '@remixicon/react'
|
||||
import Badge from '../base/badge'
|
||||
import type { Plugin } from './types'
|
||||
|
@ -11,70 +10,67 @@ import Icon from './card/base/card-icon'
|
|||
import Title from './card/base/title'
|
||||
import DownloadCount from './card/base/download-count'
|
||||
import Button from '@/app/components/base/button'
|
||||
import { useGetLanguage } from '@/context/i18n'
|
||||
import { MARKETPLACE_URL_PREFIX } from '@/config'
|
||||
import cn from '@/utils/classnames'
|
||||
import I18n from '@/context/i18n'
|
||||
|
||||
type Props = {
|
||||
className?: string
|
||||
payload: Plugin
|
||||
installed?: boolean
|
||||
}
|
||||
|
||||
const ProviderCard: FC<Props> = ({
|
||||
className,
|
||||
payload,
|
||||
installed = true,
|
||||
}) => {
|
||||
const { locale } = useContext(I18n)
|
||||
const { t } = useTranslation()
|
||||
const language = useGetLanguage()
|
||||
const { org, label } = payload
|
||||
|
||||
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)}>
|
||||
<Link href={`/plugins/test/card?org=${payload.org}&name=${payload.name}`}>
|
||||
{/* Header */}
|
||||
<div className="flex">
|
||||
<Icon src={payload.icon} />
|
||||
<div className="ml-3 w-0 grow">
|
||||
<div className="flex items-center h-5">
|
||||
<Title title={label[locale]} />
|
||||
<RiVerifiedBadgeLine className="shrink-0 ml-0.5 w-4 h-4 text-text-accent" />
|
||||
</div>
|
||||
<div className='mb-1 flex justify-between items-center h-4'>
|
||||
<div className='flex items-center'>
|
||||
<div className='text-text-tertiary system-xs-regular'>{org}</div>
|
||||
<div className='mx-2 text-text-quaternary system-xs-regular'>·</div>
|
||||
<DownloadCount downloadCount={payload.install_count || 0} />
|
||||
</div>
|
||||
{/* Header */}
|
||||
<div className="flex">
|
||||
<Icon src={payload.icon} />
|
||||
<div className="ml-3 w-0 grow">
|
||||
<div className="flex items-center h-5">
|
||||
<Title title={label[language]} />
|
||||
<RiVerifiedBadgeLine className="shrink-0 ml-0.5 w-4 h-4 text-text-accent" />
|
||||
</div>
|
||||
<div className='mb-1 flex justify-between items-center h-4'>
|
||||
<div className='flex items-center'>
|
||||
<div className='text-text-tertiary system-xs-regular'>{org}</div>
|
||||
<div className='mx-2 text-text-quaternary system-xs-regular'>·</div>
|
||||
<DownloadCount downloadCount={payload.install_count || 0} />
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<Description className='mt-3' text={payload.brief[locale]} descriptionLineRows={2}></Description>
|
||||
<div className='mt-3 flex space-x-0.5'>
|
||||
{['LLM', 'text embedding', 'speech2text'].map(tag => (
|
||||
<Badge key={tag} text={tag} />
|
||||
))}
|
||||
</div>
|
||||
{!installed && (
|
||||
<div
|
||||
className='hidden group-hover:flex items-center gap-2 absolute bottom-0 left-0 right-0 p-4 pt-8'
|
||||
style={{ background: 'linear-gradient(0deg, #F9FAFB 60.27%, rgba(249, 250, 251, 0.00) 100%)' }}
|
||||
>
|
||||
<Button
|
||||
className='flex-grow'
|
||||
variant='primary'
|
||||
>
|
||||
Install
|
||||
</Button>
|
||||
<Button
|
||||
className='flex-grow'
|
||||
variant='secondary'
|
||||
>
|
||||
Details
|
||||
<RiArrowRightUpLine className='w-4 h-4' />
|
||||
</Button>
|
||||
</div>
|
||||
)}
|
||||
</Link>
|
||||
</div>
|
||||
<Description className='mt-3' text={payload.brief[language]} descriptionLineRows={2}></Description>
|
||||
<div className='mt-3 flex space-x-0.5'>
|
||||
{payload.tags.map(tag => (
|
||||
<Badge key={tag.name} text={tag.name} />
|
||||
))}
|
||||
</div>
|
||||
<div
|
||||
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)]'
|
||||
>
|
||||
<Button
|
||||
className='flex-grow'
|
||||
variant='primary'
|
||||
>
|
||||
{t('plugin.detailPanel.operation.install')}
|
||||
</Button>
|
||||
<Button
|
||||
className='flex-grow'
|
||||
variant='secondary'
|
||||
>
|
||||
<a href={`${MARKETPLACE_URL_PREFIX}/plugin/${payload.org}/${payload.name}`} target='_blank' className='flex items-center gap-0.5'>
|
||||
{t('plugin.detailPanel.operation.detail')}
|
||||
<RiArrowRightUpLine className='w-4 h-4' />
|
||||
</a>
|
||||
</Button>
|
||||
</div>
|
||||
</div>
|
||||
)
|
||||
}
|
||||
|
|
|
@ -103,6 +103,7 @@ export type Plugin = {
|
|||
type: PluginType
|
||||
org: string
|
||||
name: string
|
||||
plugin_id: string
|
||||
version: string
|
||||
latest_version: string
|
||||
icon: string
|
||||
|
|
|
@ -37,7 +37,7 @@ export const useMarketplace = (searchPluginText: string, filterPluginTags: strin
|
|||
}
|
||||
else {
|
||||
queryMarketplaceCollectionsAndPlugins()
|
||||
setPlugins(undefined)
|
||||
setPlugins([])
|
||||
}
|
||||
}, [searchPluginText, filterPluginTags, queryPlugins, queryMarketplaceCollectionsAndPlugins, queryPluginsWithDebounced, setPlugins])
|
||||
|
||||
|
|
|
@ -84,9 +84,12 @@ const AllTools = ({
|
|||
</div>
|
||||
<ViewTypeSelect viewType={activeView} onChange={setActiveView} />
|
||||
{supportAddCustomTool && (
|
||||
<ActionButton>
|
||||
<RiAddLine className='w-4 h-4' />
|
||||
</ActionButton>
|
||||
<div className='flex items-center'>
|
||||
<div className='mr-1.5 w-px h-3.5 bg-divider-regular'></div>
|
||||
<ActionButton className='bg-components-button-primary-bg hover:bg-components-button-primary-bg text-components-button-primary-text hover:text-components-button-primary-text'>
|
||||
<RiAddLine className='w-4 h-4' />
|
||||
</ActionButton>
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
<div
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
'use client'
|
||||
import React, { forwardRef, useImperativeHandle, useMemo, useRef } from 'react'
|
||||
import React, { forwardRef, useEffect, useImperativeHandle, useMemo, useRef } from 'react'
|
||||
import { useTranslation } from 'react-i18next'
|
||||
import useStickyScroll, { ScrollPosition } from '../use-sticky-scroll'
|
||||
import Item from './item'
|
||||
|
@ -30,7 +30,6 @@ const List = ({
|
|||
wrapElemRef,
|
||||
nextToStickyELemRef,
|
||||
})
|
||||
|
||||
const stickyClassName = useMemo(() => {
|
||||
switch (scrollPosition) {
|
||||
case ScrollPosition.aboveTheWrap:
|
||||
|
@ -38,7 +37,7 @@ const List = ({
|
|||
case ScrollPosition.showing:
|
||||
return 'bottom-0 pt-3 pb-1'
|
||||
case ScrollPosition.belowTheWrap:
|
||||
return 'bottom-0 items-center rounded-b-xl border-t border-[0.5px] border-components-panel-border bg-components-panel-bg-blur shadow-lg cursor-pointer'
|
||||
return 'bottom-0 items-center rounded-b-xl border-t border-[0.5px] border-components-panel-border bg-components-panel-bg-blur shadow-lg rounded-b-lg cursor-pointer'
|
||||
}
|
||||
}, [scrollPosition])
|
||||
|
||||
|
@ -46,6 +45,11 @@ const List = ({
|
|||
handleScroll,
|
||||
}))
|
||||
|
||||
useEffect(() => {
|
||||
handleScroll()
|
||||
// eslint-disable-next-line react-hooks/exhaustive-deps
|
||||
}, [list])
|
||||
|
||||
const handleHeadClick = () => {
|
||||
if (scrollPosition === ScrollPosition.belowTheWrap) {
|
||||
nextToStickyELemRef.current?.scrollIntoView({ behavior: 'smooth', block: 'start' })
|
||||
|
@ -57,7 +61,7 @@ const List = ({
|
|||
if (hasSearchText) {
|
||||
return (
|
||||
<Link
|
||||
className='sticky bottom-0 z-10 flex h-8 px-4 py-1 system-sm-medium items-center rounded-b-xl border-t border-[0.5px] border-components-panel-border bg-components-panel-bg-blur shadow-lg text-text-accent-light-mode-only cursor-pointer'
|
||||
className='sticky bottom-0 z-10 flex h-8 px-4 py-1 system-sm-medium items-center border-t border-[0.5px] border-components-panel-border bg-components-panel-bg-blur rounded-b-lg shadow-lg text-text-accent-light-mode-only cursor-pointer'
|
||||
href={`${marketplaceUrlPrefix}/plugins`}
|
||||
target='_blank'
|
||||
>
|
||||
|
|
|
@ -2,6 +2,15 @@
|
|||
import type { FC } from 'react'
|
||||
import React from 'react'
|
||||
import { useEffect, useState } from 'react'
|
||||
import {
|
||||
PortalToFollowElem,
|
||||
PortalToFollowElemContent,
|
||||
PortalToFollowElemTrigger,
|
||||
} from '@/app/components/base/portal-to-follow-elem'
|
||||
import type {
|
||||
OffsetOptions,
|
||||
Placement,
|
||||
} from '@floating-ui/react'
|
||||
import AllTools from '@/app/components/workflow/block-selector/all-tools'
|
||||
import type { ToolDefaultValue } from './types'
|
||||
import {
|
||||
|
@ -10,16 +19,31 @@ import {
|
|||
fetchAllWorkflowTools,
|
||||
} from '@/service/tools'
|
||||
import type { BlockEnum, ToolWithProvider } from '@/app/components/workflow/types'
|
||||
import SearchBox from '@/app/components/plugins/marketplace/search-box'
|
||||
import { useTranslation } from 'react-i18next'
|
||||
|
||||
type Props = {
|
||||
disabled: boolean
|
||||
trigger: React.ReactNode
|
||||
placement?: Placement
|
||||
offset?: OffsetOptions
|
||||
isShow: boolean
|
||||
onShowChange: (isShow: boolean) => void
|
||||
onSelect: (tool: ToolDefaultValue) => void
|
||||
supportAddCustomTool?: boolean
|
||||
}
|
||||
|
||||
const ToolPicker: FC<Props> = ({
|
||||
disabled,
|
||||
trigger,
|
||||
placement = 'right-start',
|
||||
offset = 0,
|
||||
isShow,
|
||||
onShowChange,
|
||||
onSelect,
|
||||
supportAddCustomTool,
|
||||
}) => {
|
||||
const { t } = useTranslation()
|
||||
const [searchText, setSearchText] = useState('')
|
||||
|
||||
const [buildInTools, setBuildInTools] = useState<ToolWithProvider[]>([])
|
||||
|
@ -37,23 +61,52 @@ const ToolPicker: FC<Props> = ({
|
|||
})()
|
||||
}, [])
|
||||
|
||||
const handleTriggerClick = () => {
|
||||
if (disabled) return
|
||||
onShowChange(true)
|
||||
}
|
||||
|
||||
const handleSelect = (_type: BlockEnum, tool?: ToolDefaultValue) => {
|
||||
onSelect(tool!)
|
||||
}
|
||||
|
||||
return (
|
||||
<div className="relative mt-5 mx-auto w-[320px] bg-white">
|
||||
<input placeholder='search holder' value={searchText} onChange={e => setSearchText(e.target.value)} />
|
||||
<AllTools
|
||||
className='mt-1'
|
||||
searchText={searchText}
|
||||
onSelect={handleSelect}
|
||||
buildInTools={buildInTools}
|
||||
customTools={customTools}
|
||||
workflowTools={workflowTools}
|
||||
supportAddCustomTool={supportAddCustomTool}
|
||||
/>
|
||||
</div>
|
||||
<PortalToFollowElem
|
||||
placement={placement}
|
||||
offset={offset}
|
||||
open={isShow}
|
||||
onOpenChange={onShowChange}
|
||||
>
|
||||
<PortalToFollowElemTrigger
|
||||
onClick={handleTriggerClick}
|
||||
>
|
||||
{trigger}
|
||||
</PortalToFollowElemTrigger>
|
||||
|
||||
<PortalToFollowElemContent className='z-[1000]'>
|
||||
<div className="relative w-[320px] min-h-20 rounded-xl bg-components-panel-bg-blur border-[0.5px] border-components-panel-border shadow-lg">
|
||||
<div className='p-2 pb-1'>
|
||||
<SearchBox
|
||||
search={searchText}
|
||||
onSearchChange={setSearchText}
|
||||
tags={[]}
|
||||
onTagsChange={() => { }}
|
||||
size='small'
|
||||
placeholder={t('plugin.searchTools')!}
|
||||
/>
|
||||
</div>
|
||||
<AllTools
|
||||
className='mt-1'
|
||||
searchText={searchText}
|
||||
onSelect={handleSelect}
|
||||
buildInTools={buildInTools}
|
||||
customTools={customTools}
|
||||
workflowTools={workflowTools}
|
||||
supportAddCustomTool={supportAddCustomTool}
|
||||
/>
|
||||
</div>
|
||||
</PortalToFollowElemContent>
|
||||
</PortalToFollowElem>
|
||||
)
|
||||
}
|
||||
|
||||
|
|
|
@ -132,7 +132,6 @@ const Panel: FC<NodePanelProps<LLMNodeType>> = ({
|
|||
isInWorkflow
|
||||
isAdvancedMode={true}
|
||||
mode={model?.mode}
|
||||
pluginId={model?.plugin_id}
|
||||
provider={model?.provider}
|
||||
completionParams={model?.completion_params}
|
||||
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) => {
|
||||
draft.model.provider = model.provider
|
||||
draft.model.name = model.modelId
|
||||
|
@ -139,7 +139,6 @@ const useConfig = (id: string, payload: LLMNodeType) => {
|
|||
useEffect(() => {
|
||||
if (currentProvider?.provider && currentModel?.model && !model.provider) {
|
||||
handleModelChanged({
|
||||
pluginId: currentProvider?.plugin_id,
|
||||
provider: currentProvider?.provider,
|
||||
modelId: currentModel?.model,
|
||||
mode: currentModel?.model_properties?.mode as string,
|
||||
|
|
|
@ -77,7 +77,6 @@ const Panel: FC<NodePanelProps<ParameterExtractorNodeType>> = ({
|
|||
isInWorkflow
|
||||
isAdvancedMode={true}
|
||||
mode={model?.mode}
|
||||
pluginId={model?.plugin_id}
|
||||
provider={model?.provider}
|
||||
completionParams={model?.completion_params}
|
||||
modelId={model?.name}
|
||||
|
|
|
@ -65,7 +65,6 @@ const Panel: FC<NodePanelProps<QuestionClassifierNodeType>> = ({
|
|||
isInWorkflow
|
||||
isAdvancedMode={true}
|
||||
mode={model?.mode}
|
||||
pluginId={model?.plugin_id}
|
||||
provider={model?.provider}
|
||||
completionParams={model.completion_params}
|
||||
modelId={model.name}
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
import type { CommonNodeType, Memory, ModelConfig, ValueSelector, VisionSetting } from '@/app/components/workflow/types'
|
||||
|
||||
export type Topic = {
|
||||
export interface Topic {
|
||||
id: string
|
||||
name: string
|
||||
}
|
||||
|
|
|
@ -37,7 +37,7 @@ export enum ControlMode {
|
|||
Hand = 'hand',
|
||||
}
|
||||
|
||||
export type Branch = {
|
||||
export interface Branch {
|
||||
id: string
|
||||
name: string
|
||||
}
|
||||
|
@ -68,7 +68,7 @@ export type CommonNodeType<T = {}> = {
|
|||
height?: number
|
||||
} & T & Partial<Pick<ToolDefaultValue, 'provider_id' | 'provider_type' | 'provider_name' | 'tool_name'>>
|
||||
|
||||
export type CommonEdgeType = {
|
||||
export interface CommonEdgeType {
|
||||
_hovering?: boolean
|
||||
_connectedNodeIsHovering?: boolean
|
||||
_connectedNodeIsSelected?: boolean
|
||||
|
@ -82,14 +82,14 @@ export type CommonEdgeType = {
|
|||
|
||||
export type Node<T = {}> = ReactFlowNode<CommonNodeType<T>>
|
||||
export type SelectedNode = Pick<Node, 'id' | 'data'>
|
||||
export type NodeProps<T = unknown> = { id: string; data: CommonNodeType<T> }
|
||||
export type NodePanelProps<T> = {
|
||||
export interface NodeProps<T = unknown> { id: string; data: CommonNodeType<T> }
|
||||
export interface NodePanelProps<T> {
|
||||
id: string
|
||||
data: CommonNodeType<T>
|
||||
}
|
||||
export type Edge = ReactFlowEdge<CommonEdgeType>
|
||||
|
||||
export type WorkflowDataUpdater = {
|
||||
export interface WorkflowDataUpdater {
|
||||
nodes: Node[]
|
||||
edges: Edge[]
|
||||
viewport: Viewport
|
||||
|
@ -97,7 +97,7 @@ export type WorkflowDataUpdater = {
|
|||
|
||||
export type ValueSelector = string[] // [nodeId, key | obj key path]
|
||||
|
||||
export type Variable = {
|
||||
export interface Variable {
|
||||
variable: string
|
||||
label?: string | {
|
||||
nodeType: BlockEnum
|
||||
|
@ -112,14 +112,14 @@ export type Variable = {
|
|||
isParagraph?: boolean
|
||||
}
|
||||
|
||||
export type EnvironmentVariable = {
|
||||
export interface EnvironmentVariable {
|
||||
id: string
|
||||
name: string
|
||||
value: any
|
||||
value_type: 'string' | 'number' | 'secret'
|
||||
}
|
||||
|
||||
export type ConversationVariable = {
|
||||
export interface ConversationVariable {
|
||||
id: string
|
||||
name: string
|
||||
value_type: ChatVarType
|
||||
|
@ -127,13 +127,13 @@ export type ConversationVariable = {
|
|||
description: string
|
||||
}
|
||||
|
||||
export type GlobalVariable = {
|
||||
export interface GlobalVariable {
|
||||
name: string
|
||||
value_type: 'string' | 'number'
|
||||
description: string
|
||||
}
|
||||
|
||||
export type VariableWithValue = {
|
||||
export interface VariableWithValue {
|
||||
key: string
|
||||
value: string
|
||||
}
|
||||
|
@ -169,8 +169,7 @@ export type InputVar = {
|
|||
value_selector?: ValueSelector
|
||||
} & Partial<UploadFileSetting>
|
||||
|
||||
export type ModelConfig = {
|
||||
plugin_id: string
|
||||
export interface ModelConfig {
|
||||
provider: string
|
||||
name: string
|
||||
mode: string
|
||||
|
@ -188,7 +187,7 @@ export enum EditionType {
|
|||
jinja2 = 'jinja2',
|
||||
}
|
||||
|
||||
export type PromptItem = {
|
||||
export interface PromptItem {
|
||||
id?: string
|
||||
role?: PromptRole
|
||||
text: string
|
||||
|
@ -201,12 +200,12 @@ export enum MemoryRole {
|
|||
assistant = 'assistant',
|
||||
}
|
||||
|
||||
export type RolePrefix = {
|
||||
export interface RolePrefix {
|
||||
user: string
|
||||
assistant: string
|
||||
}
|
||||
|
||||
export type Memory = {
|
||||
export interface Memory {
|
||||
role_prefix?: RolePrefix
|
||||
window: {
|
||||
enabled: boolean
|
||||
|
@ -230,7 +229,7 @@ export enum VarType {
|
|||
any = 'any',
|
||||
}
|
||||
|
||||
export type Var = {
|
||||
export interface Var {
|
||||
variable: string
|
||||
type: VarType
|
||||
children?: Var[] // if type is obj, has the children struct
|
||||
|
@ -241,21 +240,21 @@ export type Var = {
|
|||
des?: string
|
||||
}
|
||||
|
||||
export type NodeOutPutVar = {
|
||||
export interface NodeOutPutVar {
|
||||
nodeId: string
|
||||
title: string
|
||||
vars: Var[]
|
||||
isStartNode?: boolean
|
||||
}
|
||||
|
||||
export type Block = {
|
||||
export interface Block {
|
||||
classification?: string
|
||||
type: BlockEnum
|
||||
title: string
|
||||
description?: string
|
||||
}
|
||||
|
||||
export type NodeDefault<T> = {
|
||||
export interface NodeDefault<T> {
|
||||
defaultValue: Partial<T>
|
||||
getAvailablePrevNodes: (isChatMode: boolean) => BlockEnum[]
|
||||
getAvailableNextNodes: (isChatMode: boolean) => BlockEnum[]
|
||||
|
@ -295,19 +294,19 @@ export type OnNodeAdd = (
|
|||
}
|
||||
) => void
|
||||
|
||||
export type CheckValidRes = {
|
||||
export interface CheckValidRes {
|
||||
isValid: boolean
|
||||
errorMessage?: string
|
||||
}
|
||||
|
||||
export type RunFile = {
|
||||
export interface RunFile {
|
||||
type: string
|
||||
transfer_method: TransferMethod[]
|
||||
url?: string
|
||||
upload_file_id?: string
|
||||
}
|
||||
|
||||
export type WorkflowRunningData = {
|
||||
export interface WorkflowRunningData {
|
||||
task_id?: string
|
||||
message_id?: string
|
||||
conversation_id?: string
|
||||
|
@ -332,7 +331,7 @@ export type WorkflowRunningData = {
|
|||
tracing?: NodeTracing[]
|
||||
}
|
||||
|
||||
export type HistoryWorkflowData = {
|
||||
export interface HistoryWorkflowData {
|
||||
id: string
|
||||
sequence_number: number
|
||||
status: string
|
||||
|
@ -344,7 +343,7 @@ export enum ChangeType {
|
|||
remove = 'remove',
|
||||
}
|
||||
|
||||
export type MoreInfo = {
|
||||
export interface MoreInfo {
|
||||
type: ChangeType
|
||||
payload?: {
|
||||
beforeKey: string
|
||||
|
@ -364,7 +363,7 @@ export enum SupportUploadFileTypes {
|
|||
custom = 'custom',
|
||||
}
|
||||
|
||||
export type UploadFileSetting = {
|
||||
export interface UploadFileSetting {
|
||||
allowed_file_upload_methods: TransferMethod[]
|
||||
allowed_file_types: SupportUploadFileTypes[]
|
||||
allowed_file_extensions?: string[]
|
||||
|
@ -372,7 +371,7 @@ export type UploadFileSetting = {
|
|||
number_limits?: number
|
||||
}
|
||||
|
||||
export type VisionSetting = {
|
||||
export interface VisionSetting {
|
||||
variable_selector: ValueSelector
|
||||
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 { InputVar } from '@/app/components/workflow/types'
|
||||
|
||||
export type ModalState<T> = {
|
||||
export interface ModalState<T> {
|
||||
payload: T
|
||||
onCancelCallback?: () => void
|
||||
onSaveCallback?: (newPayload: T) => void
|
||||
|
@ -43,7 +43,7 @@ export type ModalState<T> = {
|
|||
datasetBindings?: { id: string; name: string }[]
|
||||
}
|
||||
|
||||
export type ModelModalType = {
|
||||
export interface ModelModalType {
|
||||
currentProvider: ModelProvider
|
||||
currentConfigurationMethod: ConfigurationMethodEnum
|
||||
currentCustomConfigurationModelFixedFields?: CustomConfigurationModelFixedFields
|
||||
|
@ -52,7 +52,7 @@ export type LoadBalancingEntryModalType = ModelModalType & {
|
|||
entry?: ModelLoadBalancingConfigEntry
|
||||
index?: number
|
||||
}
|
||||
export type ModalContextState = {
|
||||
export interface ModalContextState {
|
||||
setShowAccountSettingModal: Dispatch<SetStateAction<ModalState<string> | null>>
|
||||
setShowApiBasedExtensionModal: Dispatch<SetStateAction<ModalState<ApiBasedExtension> | 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 =>
|
||||
useContextSelector(ModalContext, selector)
|
||||
|
||||
type ModalContextProviderProps = {
|
||||
interface ModalContextProviderProps {
|
||||
children: React.ReactNode
|
||||
}
|
||||
export const ModalContextProvider = ({
|
||||
|
|
|
@ -4,6 +4,7 @@ const translation = {
|
|||
searchInMarketplace: 'Search in Marketplace',
|
||||
fromMarketplace: 'From Marketplace',
|
||||
endpointsEnabled: '{{num}} sets of endpoints enabled',
|
||||
searchTools: 'Search tools...',
|
||||
detailPanel: {
|
||||
categoryTip: {
|
||||
marketplace: 'Installed from Marketplace',
|
||||
|
@ -13,7 +14,7 @@ const translation = {
|
|||
},
|
||||
operation: {
|
||||
install: 'Install',
|
||||
detail: 'Detail',
|
||||
detail: 'Details',
|
||||
update: 'Update',
|
||||
info: 'Plugin Info',
|
||||
checkUpdate: 'Check Update',
|
||||
|
|
|
@ -4,6 +4,7 @@ const translation = {
|
|||
searchInMarketplace: '在 Marketplace 中搜索',
|
||||
fromMarketplace: '来自市场',
|
||||
endpointsEnabled: '{{num}} 组端点已启用',
|
||||
searchTools: '搜索工具...',
|
||||
detailPanel: {
|
||||
categoryTip: {
|
||||
marketplace: '从 Marketplace 安装',
|
||||
|
|
|
@ -10,25 +10,25 @@ export enum PromptMode {
|
|||
advanced = 'advanced',
|
||||
}
|
||||
|
||||
export type PromptItem = {
|
||||
export interface PromptItem {
|
||||
role?: PromptRole
|
||||
text: string
|
||||
}
|
||||
|
||||
export type ChatPromptConfig = {
|
||||
export interface ChatPromptConfig {
|
||||
prompt: PromptItem[]
|
||||
}
|
||||
|
||||
export type ConversationHistoriesRole = {
|
||||
export interface ConversationHistoriesRole {
|
||||
user_prefix: string
|
||||
assistant_prefix: string
|
||||
}
|
||||
export type CompletionPromptConfig = {
|
||||
export interface CompletionPromptConfig {
|
||||
prompt: PromptItem
|
||||
conversation_histories_role: ConversationHistoriesRole
|
||||
}
|
||||
|
||||
export type BlockStatus = {
|
||||
export interface BlockStatus {
|
||||
context: boolean
|
||||
history: boolean
|
||||
query: boolean
|
||||
|
@ -40,7 +40,7 @@ export enum PromptRole {
|
|||
assistant = 'assistant',
|
||||
}
|
||||
|
||||
export type PromptVariable = {
|
||||
export interface PromptVariable {
|
||||
key: string
|
||||
name: string
|
||||
type: string // "string" | "number" | "select",
|
||||
|
@ -55,7 +55,7 @@ export type PromptVariable = {
|
|||
icon_background?: string
|
||||
}
|
||||
|
||||
export type CompletionParams = {
|
||||
export interface CompletionParams {
|
||||
max_tokens: number
|
||||
temperature: number
|
||||
top_p: number
|
||||
|
@ -66,12 +66,12 @@ export type CompletionParams = {
|
|||
|
||||
export type ModelId = 'gpt-3.5-turbo' | 'text-davinci-003'
|
||||
|
||||
export type PromptConfig = {
|
||||
export interface PromptConfig {
|
||||
prompt_template: string
|
||||
prompt_variables: PromptVariable[]
|
||||
}
|
||||
|
||||
export type MoreLikeThisConfig = {
|
||||
export interface MoreLikeThisConfig {
|
||||
enabled: boolean
|
||||
}
|
||||
|
||||
|
@ -79,7 +79,7 @@ export type SuggestedQuestionsAfterAnswerConfig = MoreLikeThisConfig
|
|||
|
||||
export type SpeechToTextConfig = MoreLikeThisConfig
|
||||
|
||||
export type TextToSpeechConfig = {
|
||||
export interface TextToSpeechConfig {
|
||||
enabled: boolean
|
||||
voice?: string
|
||||
language?: string
|
||||
|
@ -88,18 +88,17 @@ export type TextToSpeechConfig = {
|
|||
|
||||
export type CitationConfig = MoreLikeThisConfig
|
||||
|
||||
export type AnnotationReplyConfig = {
|
||||
export interface AnnotationReplyConfig {
|
||||
id: string
|
||||
enabled: boolean
|
||||
score_threshold: number
|
||||
embedding_model: {
|
||||
plugin_id: string
|
||||
embedding_provider_name: string
|
||||
embedding_model_name: string
|
||||
}
|
||||
}
|
||||
|
||||
export type ModerationContentConfig = {
|
||||
export interface ModerationContentConfig {
|
||||
enabled: boolean
|
||||
preset_response?: string
|
||||
}
|
||||
|
@ -114,15 +113,14 @@ export type ModerationConfig = MoreLikeThisConfig & {
|
|||
}
|
||||
|
||||
export type RetrieverResourceConfig = MoreLikeThisConfig
|
||||
export type AgentConfig = {
|
||||
export interface AgentConfig {
|
||||
enabled: boolean
|
||||
strategy: AgentStrategy
|
||||
max_iteration: number
|
||||
tools: ToolItem[]
|
||||
}
|
||||
// frontend use. Not the same as backend
|
||||
export type ModelConfig = {
|
||||
plugin_id: string
|
||||
export interface ModelConfig {
|
||||
provider: string // LLM Provider: for example "OPENAI"
|
||||
model_id: string
|
||||
mode: ModelModeType
|
||||
|
@ -140,17 +138,16 @@ export type ModelConfig = {
|
|||
dataSets: any[]
|
||||
agentConfig: AgentConfig
|
||||
}
|
||||
export type DatasetConfigItem = {
|
||||
export interface DatasetConfigItem {
|
||||
enable: boolean
|
||||
value: number
|
||||
}
|
||||
|
||||
export type DatasetConfigs = {
|
||||
export interface DatasetConfigs {
|
||||
retrieval_model: RETRIEVE_TYPE
|
||||
reranking_model: {
|
||||
reranking_provider_name: string
|
||||
reranking_model_name: string
|
||||
reranking_plugin_id: string
|
||||
}
|
||||
top_k: number
|
||||
score_threshold_enabled: boolean
|
||||
|
@ -175,39 +172,39 @@ export type DatasetConfigs = {
|
|||
reranking_enable?: boolean
|
||||
}
|
||||
|
||||
export type DebugRequestBody = {
|
||||
export interface DebugRequestBody {
|
||||
inputs: Inputs
|
||||
query: string
|
||||
completion_params: CompletionParams
|
||||
model_config: ModelConfig
|
||||
}
|
||||
|
||||
export type DebugResponse = {
|
||||
export interface DebugResponse {
|
||||
id: string
|
||||
answer: string
|
||||
created_at: string
|
||||
}
|
||||
|
||||
export type DebugResponseStream = {
|
||||
export interface DebugResponseStream {
|
||||
id: string
|
||||
data: string
|
||||
created_at: string
|
||||
}
|
||||
|
||||
export type FeedBackRequestBody = {
|
||||
export interface FeedBackRequestBody {
|
||||
message_id: string
|
||||
rating: 'like' | 'dislike'
|
||||
content?: string
|
||||
from_source: 'api' | 'log'
|
||||
}
|
||||
|
||||
export type FeedBackResponse = {
|
||||
export interface FeedBackResponse {
|
||||
message_id: string
|
||||
rating: 'like' | 'dislike'
|
||||
}
|
||||
|
||||
// Log session list
|
||||
export type LogSessionListQuery = {
|
||||
export interface LogSessionListQuery {
|
||||
keyword?: string
|
||||
start?: 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
|
||||
}
|
||||
|
||||
export type LogSessionListResponse = {
|
||||
export interface LogSessionListResponse {
|
||||
data: {
|
||||
id: string
|
||||
conversation_id: string
|
||||
|
@ -229,7 +226,7 @@ export type LogSessionListResponse = {
|
|||
}
|
||||
|
||||
// log session detail and debug
|
||||
export type LogSessionDetailResponse = {
|
||||
export interface LogSessionDetailResponse {
|
||||
id: string
|
||||
conversation_id: string
|
||||
model_provider: string
|
||||
|
@ -243,7 +240,7 @@ export type LogSessionDetailResponse = {
|
|||
from_source: 'api' | 'log'
|
||||
}
|
||||
|
||||
export type SavedMessage = {
|
||||
export interface SavedMessage {
|
||||
id: string
|
||||
answer: string
|
||||
}
|
||||
|
|
|
@ -107,7 +107,6 @@ export type MessageContent = {
|
|||
agent_thoughts: any[] // TODO
|
||||
workflow_run_id: string
|
||||
parent_message_id: string | null
|
||||
plugin_id: string
|
||||
}
|
||||
|
||||
export type CompletionConversationGeneralDetail = {
|
||||
|
@ -130,7 +129,6 @@ export type CompletionConversationGeneralDetail = {
|
|||
dislike: number
|
||||
}
|
||||
model_config: {
|
||||
plugin_id: string
|
||||
provider: string
|
||||
model_id: string
|
||||
configs: Pick<ModelConfigDetail, 'prompt_template'>
|
||||
|
|
|
@ -13,9 +13,7 @@ export const updateAnnotationStatus = (appId: string, action: AnnotationEnableSt
|
|||
if (embeddingModel) {
|
||||
body = {
|
||||
...body,
|
||||
embedding_model_plugin_id: embeddingModel.plugin_id,
|
||||
embedding_provider_name: embeddingModel.embedding_provider_name,
|
||||
embedding_model_name: embeddingModel.embedding_model_name,
|
||||
...embeddingModel,
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -3,13 +3,13 @@ import type { IOnCompleted, IOnData, IOnError, IOnFile, IOnMessageEnd, IOnMessag
|
|||
import type { ChatPromptConfig, CompletionPromptConfig } from '@/models/debug'
|
||||
import type { ModelModeType } from '@/types/app'
|
||||
import type { ModelParameterRule } from '@/app/components/header/account-setting/model-provider-page/declarations'
|
||||
export type AutomaticRes = {
|
||||
export interface AutomaticRes {
|
||||
prompt: string
|
||||
variables: string[]
|
||||
opening_statement: string
|
||||
error?: string
|
||||
}
|
||||
export type CodeGenRes = {
|
||||
export interface CodeGenRes {
|
||||
code: string
|
||||
language: string[]
|
||||
error?: string
|
||||
|
@ -82,8 +82,8 @@ export const generateRuleCode = (body: Record<string, any>) => {
|
|||
})
|
||||
}
|
||||
|
||||
export const fetchModelParams = (pluginID: string, providerName: string, modelId: string) => {
|
||||
return get(`workspaces/current/model-providers/${pluginID}/${providerName}/models/parameter-rules`, {
|
||||
export const fetchModelParams = (providerName: string, modelId: string) => {
|
||||
return get(`workspaces/current/model-providers/${providerName}/models/parameter-rules`, {
|
||||
params: {
|
||||
model: modelId,
|
||||
},
|
||||
|
|
Loading…
Reference in New Issue
Block a user