mirror of
https://github.com/langgenius/dify.git
synced 2026-04-27 19:27:23 +08:00
app creation
This commit is contained in:
parent
f607a334ac
commit
14cfb310e3
@ -2,7 +2,7 @@
|
|||||||
|
|
||||||
import { forwardRef, useState } from 'react'
|
import { forwardRef, useState } from 'react'
|
||||||
import { useTranslation } from 'react-i18next'
|
import { useTranslation } from 'react-i18next'
|
||||||
import NewAppDialog from './NewAppDialog'
|
import CreateAppDialog from '@/app/components/app/create-app-dialog'
|
||||||
import CreateFromDSLModal from '@/app/components/app/create-from-dsl-modal'
|
import CreateFromDSLModal from '@/app/components/app/create-from-dsl-modal'
|
||||||
import { useProviderContext } from '@/context/provider-context'
|
import { useProviderContext } from '@/context/provider-context'
|
||||||
import { Plus } from '@/app/components/base/icons/src/vender/line/general'
|
import { Plus } from '@/app/components/base/icons/src/vender/line/general'
|
||||||
@ -17,7 +17,7 @@ const CreateAppCard = forwardRef<HTMLAnchorElement, CreateAppCardProps>(({ onSuc
|
|||||||
const { t } = useTranslation()
|
const { t } = useTranslation()
|
||||||
const { onPlanInfoChanged } = useProviderContext()
|
const { onPlanInfoChanged } = useProviderContext()
|
||||||
|
|
||||||
const [showNewAppDialog, setShowNewAppDialog] = useState(false)
|
const [showNewAppDialog, setShowNewAppDialog] = useState(true)
|
||||||
const [showCreateFromDSLModal, setShowCreateFromDSLModal] = useState(false)
|
const [showCreateFromDSLModal, setShowCreateFromDSLModal] = useState(false)
|
||||||
return (
|
return (
|
||||||
<a
|
<a
|
||||||
@ -50,12 +50,15 @@ const CreateAppCard = forwardRef<HTMLAnchorElement, CreateAppCardProps>(({ onSuc
|
|||||||
onSuccess()
|
onSuccess()
|
||||||
}}
|
}}
|
||||||
/>
|
/>
|
||||||
<NewAppDialog show={showNewAppDialog} onSuccess={
|
<CreateAppDialog
|
||||||
() => {
|
show={showNewAppDialog}
|
||||||
|
onClose={() => setShowNewAppDialog(false)}
|
||||||
|
onSuccess={() => {
|
||||||
onPlanInfoChanged()
|
onPlanInfoChanged()
|
||||||
if (onSuccess)
|
if (onSuccess)
|
||||||
onSuccess()
|
onSuccess()
|
||||||
}} onClose={() => setShowNewAppDialog(false)} />
|
}}
|
||||||
|
/>
|
||||||
</a>
|
</a>
|
||||||
)
|
)
|
||||||
})
|
})
|
||||||
|
|||||||
170
web/app/components/app/create-app-dialog/appForm.tsx
Normal file
170
web/app/components/app/create-app-dialog/appForm.tsx
Normal file
@ -0,0 +1,170 @@
|
|||||||
|
'use client'
|
||||||
|
|
||||||
|
import type { MouseEventHandler } from 'react'
|
||||||
|
import { useCallback, useRef, useState } from 'react'
|
||||||
|
import cn from 'classnames'
|
||||||
|
import { useTranslation } from 'react-i18next'
|
||||||
|
import { useRouter } from 'next/navigation'
|
||||||
|
import { useContext, useContextSelector } from 'use-context-selector'
|
||||||
|
import { useProviderContext } from '@/context/provider-context'
|
||||||
|
import { ToastContext } from '@/app/components/base/toast'
|
||||||
|
import AppsContext, { useAppContext } from '@/context/app-context'
|
||||||
|
import type { AppMode } from '@/types/app'
|
||||||
|
import { createApp } from '@/service/apps'
|
||||||
|
import Button from '@/app/components/base/button'
|
||||||
|
import AppIcon from '@/app/components/base/app-icon'
|
||||||
|
import EmojiPicker from '@/app/components/base/emoji-picker'
|
||||||
|
import AppsFull from '@/app/components/billing/apps-full-in-dialog'
|
||||||
|
import { BubbleText } from '@/app/components/base/icons/src/vender/solid/education'
|
||||||
|
import { CuteRobote } from '@/app/components/base/icons/src/vender/solid/communication'
|
||||||
|
import { Route } from '@/app/components/base/icons/src/vender/line/mapsAndTravel'
|
||||||
|
|
||||||
|
export type AppFormProps = {
|
||||||
|
onConfirm: () => void
|
||||||
|
onHide: () => void
|
||||||
|
}
|
||||||
|
|
||||||
|
const AppForm = ({
|
||||||
|
onConfirm,
|
||||||
|
onHide,
|
||||||
|
}: AppFormProps) => {
|
||||||
|
const { t } = useTranslation()
|
||||||
|
const router = useRouter()
|
||||||
|
const { notify } = useContext(ToastContext)
|
||||||
|
|
||||||
|
const mutateApps = useContextSelector(AppsContext, state => state.mutateApps)
|
||||||
|
|
||||||
|
const [appMode, setAppMode] = useState<AppMode>('chat')
|
||||||
|
const [emoji, setEmoji] = useState({ icon: '🤖', icon_background: '#FFEAD5' })
|
||||||
|
const [showEmojiPicker, setShowEmojiPicker] = useState(false)
|
||||||
|
const [name, setName] = useState('')
|
||||||
|
const [description, setDescription] = useState('')
|
||||||
|
|
||||||
|
const { plan, enableBilling } = useProviderContext()
|
||||||
|
const isAppsFull = (enableBilling && plan.usage.buildApps >= plan.total.buildApps)
|
||||||
|
const { isCurrentWorkspaceManager } = useAppContext()
|
||||||
|
|
||||||
|
const isCreatingRef = useRef(false)
|
||||||
|
const onCreate: MouseEventHandler = useCallback(async () => {
|
||||||
|
if (!name.trim()) {
|
||||||
|
notify({ type: 'error', message: t('app.newApp.nameNotEmpty') })
|
||||||
|
return
|
||||||
|
}
|
||||||
|
if (isCreatingRef.current)
|
||||||
|
return
|
||||||
|
isCreatingRef.current = true
|
||||||
|
try {
|
||||||
|
const app = await createApp({
|
||||||
|
mode: appMode,
|
||||||
|
name,
|
||||||
|
icon: emoji.icon,
|
||||||
|
icon_background: emoji.icon_background,
|
||||||
|
description,
|
||||||
|
})
|
||||||
|
notify({ type: 'success', message: t('app.newApp.appCreated') })
|
||||||
|
onConfirm()
|
||||||
|
onHide()
|
||||||
|
mutateApps()
|
||||||
|
router.push(`/app/${app.id}/${isCurrentWorkspaceManager ? 'configuration' : 'overview'}`)
|
||||||
|
}
|
||||||
|
catch (e) {
|
||||||
|
notify({ type: 'error', message: t('app.newApp.appCreateFailed') })
|
||||||
|
}
|
||||||
|
isCreatingRef.current = false
|
||||||
|
}, [name, notify, t, appMode, emoji.icon, emoji.icon_background, description, onConfirm, onHide, mutateApps, router, isCurrentWorkspaceManager])
|
||||||
|
|
||||||
|
return (
|
||||||
|
<>
|
||||||
|
{/* app type */}
|
||||||
|
<div className='pt-2 px-8'>
|
||||||
|
<div className='py-2 text-sm leading-[20px] font-medium text-gray-900'>{t('app.newApp.captionAppType')}</div>
|
||||||
|
<div>
|
||||||
|
<div
|
||||||
|
className={cn(
|
||||||
|
'relative mb-2 p-3 pl-[56px] min-h-[84px] bg-gray-25 rounded-xl border-[1.5px] border-gray-100 cursor-pointer hover:border-[#d1e0ff]',
|
||||||
|
appMode === 'chat' && 'border-primary-400 hover:border-primary-400',
|
||||||
|
)}
|
||||||
|
onClick={() => setAppMode('chat')}
|
||||||
|
>
|
||||||
|
<div className='absolute top-3 left-3 w-8 h-8 p-2 bg-indigo-50 rounded-lg'>
|
||||||
|
<BubbleText className='w-4 h-4 text-indigo-600'/>
|
||||||
|
</div>
|
||||||
|
<div className='mb-1 text-sm leading-[20px] font-semibold text-gray-800'>{t('app.types.chatbot')}</div>
|
||||||
|
<div className='text-xs leading-[18px] text-gray-500'>{t('app.newApp.chatbotDescription')}</div>
|
||||||
|
</div>
|
||||||
|
<div
|
||||||
|
className={cn(
|
||||||
|
'relative mb-2 p-3 pl-[56px] min-h-[84px] bg-gray-25 rounded-xl border-[1.5px] border-gray-100 cursor-pointer hover:border-[#d1e0ff]',
|
||||||
|
appMode === 'agent' && 'border-primary-400 hover:border-primary-400',
|
||||||
|
)}
|
||||||
|
onClick={() => setAppMode('agent')}
|
||||||
|
>
|
||||||
|
<div className='absolute top-3 left-3 w-8 h-8 p-2 bg-indigo-50 rounded-lg'>
|
||||||
|
<CuteRobote className='w-4 h-4 text-indigo-600'/>
|
||||||
|
</div>
|
||||||
|
<div className='mb-1 text-sm leading-[20px] font-semibold text-gray-800'>{t('app.types.agent')}</div>
|
||||||
|
<div className='text-xs leading-[18px] text-gray-500'>{t('app.newApp.agentDescription')}</div>
|
||||||
|
</div>
|
||||||
|
<div
|
||||||
|
className={cn(
|
||||||
|
'relative mb-2 p-3 pl-[56px] min-h-[84px] bg-gray-25 rounded-xl border-[1.5px] border-gray-100 cursor-pointer hover:border-[#d1e0ff]',
|
||||||
|
appMode === 'workflow' && 'border-primary-400 hover:border-primary-400',
|
||||||
|
)}
|
||||||
|
onClick={() => setAppMode('workflow')}
|
||||||
|
>
|
||||||
|
<div className='absolute top-3 left-3 w-8 h-8 p-2 bg-indigo-50 rounded-lg'>
|
||||||
|
<Route className='w-4 h-4 text-indigo-600'/>
|
||||||
|
</div>
|
||||||
|
<div className='mb-1 text-sm leading-[20px] font-semibold text-gray-800'>{t('app.types.workflow')}</div>
|
||||||
|
<div className='text-xs leading-[18px] text-gray-500'>{t('app.newApp.workflowDescription')}</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
{/* icon & name */}
|
||||||
|
<div className='pt-2 px-8'>
|
||||||
|
<div className='py-2 text-sm font-medium leading-[20px] text-gray-900'>{t('app.newApp.captionName')}</div>
|
||||||
|
<div className='flex items-center justify-between space-x-3'>
|
||||||
|
<AppIcon size='large' onClick={() => { setShowEmojiPicker(true) }} className='cursor-pointer' icon={emoji.icon} background={emoji.icon_background} />
|
||||||
|
<input
|
||||||
|
value={name}
|
||||||
|
onChange={e => setName(e.target.value)}
|
||||||
|
placeholder={t('app.newApp.appNamePlaceholder') || ''}
|
||||||
|
className='grow h-10 px-3 text-sm font-normal bg-gray-100 rounded-lg border border-transparent outline-none appearance-none caret-primary-600 placeholder:text-gray-400 hover:bg-gray-50 hover:border hover:border-gray-300 focus:bg-gray-50 focus:border focus:border-gray-300 focus:shadow-xs'
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
{showEmojiPicker && <EmojiPicker
|
||||||
|
onSelect={(icon, icon_background) => {
|
||||||
|
setEmoji({ icon, icon_background })
|
||||||
|
setShowEmojiPicker(false)
|
||||||
|
}}
|
||||||
|
onClose={() => {
|
||||||
|
setEmoji({ icon: '🤖', icon_background: '#FFEAD5' })
|
||||||
|
setShowEmojiPicker(false)
|
||||||
|
}}
|
||||||
|
/>}
|
||||||
|
</div>
|
||||||
|
{/* description */}
|
||||||
|
<div className='pt-2 px-8'>
|
||||||
|
<div className='py-2 text-sm font-medium leading-[20px] text-gray-900'>{t('app.newApp.captionDescription')}</div>
|
||||||
|
<textarea
|
||||||
|
className='w-full h-10 px-3 py-2 text-sm font-normal bg-gray-100 rounded-lg border border-transparent outline-none appearance-none caret-primary-600 placeholder:text-gray-400 hover:bg-gray-50 hover:border hover:border-gray-300 focus:bg-gray-50 focus:border focus:border-gray-300 focus:shadow-xs h-[80px] resize-none'
|
||||||
|
placeholder={t('app.newApp.appDescriptionPlaceholder') || ''}
|
||||||
|
value={description}
|
||||||
|
onChange={e => setDescription(e.target.value)}
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
{isAppsFull && (
|
||||||
|
<div className='px-8 py-2'>
|
||||||
|
<AppsFull loc='app-create' />
|
||||||
|
</div>
|
||||||
|
)}
|
||||||
|
<div className='px-8 py-6 flex justify-end'>
|
||||||
|
<Button className='mr-2 text-gray-700 text-sm font-medium' onClick={onHide}>{t('app.newApp.Cancel')}</Button>
|
||||||
|
<Button className='text-sm font-medium' disabled={isAppsFull || !name} type="primary" onClick={onCreate}>{t('app.newApp.Create')}</Button>
|
||||||
|
</div>
|
||||||
|
</>
|
||||||
|
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
export default AppForm
|
||||||
42
web/app/components/app/create-app-dialog/index.tsx
Normal file
42
web/app/components/app/create-app-dialog/index.tsx
Normal file
@ -0,0 +1,42 @@
|
|||||||
|
'use client'
|
||||||
|
|
||||||
|
import { useTranslation } from 'react-i18next'
|
||||||
|
import NewAppDialog from './newAppDialog'
|
||||||
|
import AppForm from './appForm'
|
||||||
|
import { XClose } from '@/app/components/base/icons/src/vender/line/general'
|
||||||
|
|
||||||
|
type CreateAppDialogProps = {
|
||||||
|
show: boolean
|
||||||
|
onSuccess: () => void
|
||||||
|
onClose: () => void
|
||||||
|
}
|
||||||
|
|
||||||
|
const CreateAppDialog = ({ show, onSuccess, onClose }: CreateAppDialogProps) => {
|
||||||
|
const { t } = useTranslation()
|
||||||
|
|
||||||
|
return (
|
||||||
|
<NewAppDialog
|
||||||
|
className='flex'
|
||||||
|
show={show}
|
||||||
|
onClose={() => {}}
|
||||||
|
>
|
||||||
|
{/* blank form */}
|
||||||
|
<div className='shrink-0 max-w-[480px] h-full bg-white overflow-y-auto'>
|
||||||
|
{/* Heading */}
|
||||||
|
<div className='sticky top-0 pl-8 pr-6 pt-6 pb-3 rounded-ss-xl text-xl leading-[30px] font-semibold text-gray-900'>{t('app.newApp.startFromBlank')}</div>
|
||||||
|
{/* app form */}
|
||||||
|
<AppForm onHide={onClose} onConfirm={onSuccess}/>
|
||||||
|
</div>
|
||||||
|
{/* template list */}
|
||||||
|
<div className='grow bg-gray-100'>
|
||||||
|
<div className='sticky top-0 pl-8 pr-6 pt-6 pb-3 rounded-se-xl text-xl leading-[30px] font-semibold text-gray-900'>{t('app.newApp.startFromTemplate')}</div>
|
||||||
|
</div>
|
||||||
|
<div className='absolute top-6 left-[464px] w-8 h-8 p-1 bg-white border-2 border-gray-200 rounded-2xl text-xs leading-[20px] font-medium text-gray-500 cursor-default'>OR</div>
|
||||||
|
<div className='absolute right-6 top-6 p-2 cursor-pointer' onClick={onClose}>
|
||||||
|
<XClose className='w-4 h-4 text-gray-500' />
|
||||||
|
</div>
|
||||||
|
</NewAppDialog>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
export default CreateAppDialog
|
||||||
57
web/app/components/app/create-app-dialog/newAppDialog.tsx
Normal file
57
web/app/components/app/create-app-dialog/newAppDialog.tsx
Normal file
@ -0,0 +1,57 @@
|
|||||||
|
import { Fragment, useCallback } from 'react'
|
||||||
|
import type { ReactNode } from 'react'
|
||||||
|
import { Dialog, Transition } from '@headlessui/react'
|
||||||
|
import cn from 'classnames'
|
||||||
|
|
||||||
|
type DialogProps = {
|
||||||
|
className?: string
|
||||||
|
children: ReactNode
|
||||||
|
show: boolean
|
||||||
|
onClose?: () => void
|
||||||
|
}
|
||||||
|
|
||||||
|
const NewAppDialog = ({
|
||||||
|
className,
|
||||||
|
children,
|
||||||
|
show,
|
||||||
|
onClose,
|
||||||
|
}: DialogProps) => {
|
||||||
|
const close = useCallback(() => onClose?.(), [onClose])
|
||||||
|
return (
|
||||||
|
<Transition appear show={show} as={Fragment}>
|
||||||
|
<Dialog as="div" className="relative z-40" onClose={close}>
|
||||||
|
<Transition.Child
|
||||||
|
as={Fragment}
|
||||||
|
enter="ease-out duration-300"
|
||||||
|
enterFrom="opacity-0"
|
||||||
|
enterTo="opacity-100"
|
||||||
|
leave="ease-in duration-200"
|
||||||
|
leaveFrom="opacity-100"
|
||||||
|
leaveTo="opacity-0"
|
||||||
|
>
|
||||||
|
<div className="fixed inset-0 bg-black bg-opacity-25" />
|
||||||
|
</Transition.Child>
|
||||||
|
|
||||||
|
<div className="fixed inset-0">
|
||||||
|
<div className="flex flex-col items-center justify-center min-h-full pt-[56px]">
|
||||||
|
<Transition.Child
|
||||||
|
as={Fragment}
|
||||||
|
enter="ease-out duration-300"
|
||||||
|
enterFrom="opacity-0 scale-95"
|
||||||
|
enterTo="opacity-100 scale-100"
|
||||||
|
leave="ease-in duration-200"
|
||||||
|
leaveFrom="opacity-100 scale-100"
|
||||||
|
leaveTo="opacity-0 scale-95"
|
||||||
|
>
|
||||||
|
<Dialog.Panel className={cn('grow relative w-full h-[calc(100vh-56px)] p-0 overflow-hidden text-left align-middle transition-all transform bg-white shadow-xl rounded-t-xl', className)}>
|
||||||
|
{children}
|
||||||
|
</Dialog.Panel>
|
||||||
|
</Transition.Child>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</Dialog>
|
||||||
|
</Transition >
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
export default NewAppDialog
|
||||||
@ -139,7 +139,7 @@ const CreateFromDSLModal = ({ show, onSuccess, onClose }: CreateFromDSLModalProp
|
|||||||
isShow={show}
|
isShow={show}
|
||||||
onClose={() => {}}
|
onClose={() => {}}
|
||||||
>
|
>
|
||||||
<div className='relative pb-2 text-xl font-medium leading-[30px] text-gray-900'>Create from DSL file</div>
|
<div className='relative pb-2 text-xl font-medium leading-[30px] text-gray-900'>{t('app.createFromConfigFile')}</div>
|
||||||
<div className='absolute right-4 top-4 p-2 cursor-pointer' onClick={onClose}>
|
<div className='absolute right-4 top-4 p-2 cursor-pointer' onClick={onClose}>
|
||||||
<XClose className='w-4 h-4 text-gray-500' />
|
<XClose className='w-4 h-4 text-gray-500' />
|
||||||
</div>
|
</div>
|
||||||
@ -186,7 +186,7 @@ const CreateFromDSLModal = ({ show, onSuccess, onClose }: CreateFromDSLModalProp
|
|||||||
</div>
|
</div>
|
||||||
)}
|
)}
|
||||||
</div>
|
</div>
|
||||||
{isAppsFull && <AppsFull loc='app-create' />}
|
{isAppsFull && <AppsFull loc='app-create-dsl' />}
|
||||||
<div className='pt-6 flex justify-end'>
|
<div className='pt-6 flex justify-end'>
|
||||||
<Button className='mr-2 text-gray-700 text-sm font-medium' onClick={onClose}>{t('app.newApp.Cancel')}</Button>
|
<Button className='mr-2 text-gray-700 text-sm font-medium' onClick={onClose}>{t('app.newApp.Cancel')}</Button>
|
||||||
<Button className='text-sm font-medium' disabled={isAppsFull || !currentFile} type="primary" onClick={onCreate}>{t('app.newApp.Create')}</Button>
|
<Button className='text-sm font-medium' disabled={isAppsFull || !currentFile} type="primary" onClick={onCreate}>{t('app.newApp.Create')}</Button>
|
||||||
|
|||||||
@ -6,10 +6,6 @@ const translation = {
|
|||||||
agent: 'Agent',
|
agent: 'Agent',
|
||||||
workflow: 'Workflow',
|
workflow: 'Workflow',
|
||||||
},
|
},
|
||||||
modes: {
|
|
||||||
completion: 'Text Generator',
|
|
||||||
chat: 'Basic Assistant',
|
|
||||||
},
|
|
||||||
duplicate: 'Duplicate',
|
duplicate: 'Duplicate',
|
||||||
duplicateTitle: 'Duplicate App',
|
duplicateTitle: 'Duplicate App',
|
||||||
export: 'Export DSL',
|
export: 'Export DSL',
|
||||||
@ -23,11 +19,17 @@ const translation = {
|
|||||||
communityIntro:
|
communityIntro:
|
||||||
'Discuss with team members, contributors and developers on different channels.',
|
'Discuss with team members, contributors and developers on different channels.',
|
||||||
roadmap: 'See our roadmap',
|
roadmap: 'See our roadmap',
|
||||||
appNamePlaceholder: 'Please enter the name of the app',
|
|
||||||
newApp: {
|
newApp: {
|
||||||
startToCreate: 'Let\'s start with your new app',
|
startFromBlank: 'Start from a blank app',
|
||||||
captionName: 'App icon & name',
|
startFromTemplate: 'Start from a template',
|
||||||
captionAppType: 'What type of app do you want to create?',
|
captionAppType: 'What type of app do you want to create?',
|
||||||
|
chatbotDescription: 'Build a chat-based assistant using a Large Language Model',
|
||||||
|
agentDescription: 'Build an intelligent Agent which can autonomously choose tools to complete the tasks',
|
||||||
|
workflowDescription: 'Description text here',
|
||||||
|
captionName: 'App icon & name',
|
||||||
|
appNamePlaceholder: 'Give your app a name',
|
||||||
|
captionDescription: 'Description',
|
||||||
|
appDescriptionPlaceholder: 'Enter the description of the app',
|
||||||
previewDemo: 'Preview demo',
|
previewDemo: 'Preview demo',
|
||||||
chatApp: 'Assistant',
|
chatApp: 'Assistant',
|
||||||
chatAppIntro:
|
chatAppIntro:
|
||||||
|
|||||||
@ -6,10 +6,6 @@ const translation = {
|
|||||||
agent: 'Agent',
|
agent: 'Agent',
|
||||||
workflow: '工作流',
|
workflow: '工作流',
|
||||||
},
|
},
|
||||||
modes: {
|
|
||||||
completion: '文本生成型',
|
|
||||||
chat: '基础助手',
|
|
||||||
},
|
|
||||||
duplicate: '复制',
|
duplicate: '复制',
|
||||||
duplicateTitle: '复制应用',
|
duplicateTitle: '复制应用',
|
||||||
export: '导出 DSL',
|
export: '导出 DSL',
|
||||||
@ -24,9 +20,16 @@ const translation = {
|
|||||||
roadmap: '产品路线图',
|
roadmap: '产品路线图',
|
||||||
appNamePlaceholder: '请输入应用名称',
|
appNamePlaceholder: '请输入应用名称',
|
||||||
newApp: {
|
newApp: {
|
||||||
startToCreate: '开始创建一个新应用',
|
startFromBlank: '开始创建新应用',
|
||||||
captionName: '图标 & 名称',
|
startFromTemplate: '从应用模版创建',
|
||||||
captionAppType: '想要哪种应用类型?',
|
captionAppType: '想要哪种应用类型?',
|
||||||
|
chatbotDescription: '使用大型语言模型构建基于聊天的助手',
|
||||||
|
agentDescription: '构建一个智能Agent,可以自主选择工具来完成任务',
|
||||||
|
workflowDescription: 'Description text here',
|
||||||
|
captionName: '图标 & 名称',
|
||||||
|
appNamePlaceholder: '给你的应用起个名字',
|
||||||
|
captionDescription: '描述',
|
||||||
|
appDescriptionPlaceholder: '输入应用的描述',
|
||||||
previewDemo: '预览 Demo',
|
previewDemo: '预览 Demo',
|
||||||
chatApp: '助手',
|
chatApp: '助手',
|
||||||
chatAppIntro:
|
chatAppIntro:
|
||||||
|
|||||||
@ -16,8 +16,8 @@ export const fetchAppTemplates: Fetcher<AppTemplatesResponse, { url: string }> =
|
|||||||
return get<AppTemplatesResponse>(url)
|
return get<AppTemplatesResponse>(url)
|
||||||
}
|
}
|
||||||
|
|
||||||
export const createApp: Fetcher<AppDetailResponse, { name: string; icon: string; icon_background: string; mode: AppMode; config?: ModelConfig }> = ({ name, icon, icon_background, mode, config }) => {
|
export const createApp: Fetcher<AppDetailResponse, { name: string; icon: string; icon_background: string; mode: AppMode; description?: string; config?: ModelConfig }> = ({ name, icon, icon_background, mode, description, config }) => {
|
||||||
return post<AppDetailResponse>('apps', { body: { name, icon, icon_background, mode, model_config: config } })
|
return post<AppDetailResponse>('apps', { body: { name, icon, icon_background, mode, description, model_config: config } })
|
||||||
}
|
}
|
||||||
|
|
||||||
export const deleteApp: Fetcher<CommonResponse, string> = (appID) => {
|
export const deleteApp: Fetcher<CommonResponse, string> = (appID) => {
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user