mirror of
https://github.com/langgenius/dify.git
synced 2026-05-06 10:28:10 +08:00
merge main
This commit is contained in:
@ -1,23 +1,27 @@
|
||||
'use client'
|
||||
import { useContextSelector } from 'use-context-selector'
|
||||
import { useTranslation } from 'react-i18next'
|
||||
import style from '../list.module.css'
|
||||
import Apps from './Apps'
|
||||
import classNames from '@/utils/classnames'
|
||||
import { getLocaleOnServer, useTranslation as translate } from '@/i18n/server'
|
||||
import AppContext from '@/context/app-context'
|
||||
import { LicenseStatus } from '@/types/feature'
|
||||
|
||||
const AppList = async () => {
|
||||
const locale = getLocaleOnServer()
|
||||
const { t } = await translate(locale, 'app')
|
||||
const AppList = () => {
|
||||
const { t } = useTranslation()
|
||||
const systemFeatures = useContextSelector(AppContext, v => v.systemFeatures)
|
||||
|
||||
return (
|
||||
<div className='relative flex flex-col overflow-y-auto bg-gray-100 shrink-0 h-0 grow'>
|
||||
<Apps />
|
||||
<footer className='px-12 py-6 grow-0 shrink-0'>
|
||||
<h3 className='text-xl font-semibold leading-tight text-gradient'>{t('join')}</h3>
|
||||
<p className='mt-1 text-sm font-normal leading-tight text-gray-700'>{t('communityIntro')}</p>
|
||||
{systemFeatures.license.status === LicenseStatus.NONE && <footer className='px-12 py-6 grow-0 shrink-0'>
|
||||
<h3 className='text-xl font-semibold leading-tight text-gradient'>{t('app.join')}</h3>
|
||||
<p className='mt-1 text-sm font-normal leading-tight text-gray-700'>{t('app.communityIntro')}</p>
|
||||
<div className='flex items-center gap-2 mt-3'>
|
||||
<a className={style.socialMediaLink} target='_blank' rel='noopener noreferrer' href='https://github.com/langgenius/dify'><span className={classNames(style.socialMediaIcon, style.githubIcon)} /></a>
|
||||
<a className={style.socialMediaLink} target='_blank' rel='noopener noreferrer' href='https://discord.gg/FngNHpbcY7'><span className={classNames(style.socialMediaIcon, style.discordIcon)} /></a>
|
||||
</div>
|
||||
</footer>
|
||||
</footer>}
|
||||
</div >
|
||||
)
|
||||
}
|
||||
|
||||
@ -2,19 +2,17 @@
|
||||
import type { FC } from 'react'
|
||||
import React, { useEffect, useState } from 'react'
|
||||
import { useTranslation } from 'react-i18next'
|
||||
import { Pagination } from 'react-headless-pagination'
|
||||
import { useDebounce } from 'ahooks'
|
||||
import { ArrowLeftIcon, ArrowRightIcon } from '@heroicons/react/24/outline'
|
||||
import Toast from '../../base/toast'
|
||||
import Filter from './filter'
|
||||
import type { QueryParam } from './filter'
|
||||
import List from './list'
|
||||
import EmptyElement from './empty-element'
|
||||
import HeaderOpts from './header-opts'
|
||||
import s from './style.module.css'
|
||||
import { AnnotationEnableStatus, type AnnotationItem, type AnnotationItemBasic, JobStatus } from './type'
|
||||
import ViewAnnotationModal from './view-annotation-modal'
|
||||
import cn from '@/utils/classnames'
|
||||
import Pagination from '@/app/components/base/pagination'
|
||||
import Switch from '@/app/components/base/switch'
|
||||
import { addAnnotation, delAnnotation, fetchAnnotationConfig as doFetchAnnotationConfig, editAnnotation, fetchAnnotationList, queryAnnotationJobStatus, updateAnnotationScore, updateAnnotationStatus } from '@/service/annotation'
|
||||
import Loading from '@/app/components/base/loading'
|
||||
@ -69,9 +67,10 @@ const Annotation: FC<Props> = ({
|
||||
const [queryParams, setQueryParams] = useState<QueryParam>({})
|
||||
const [currPage, setCurrPage] = React.useState<number>(0)
|
||||
const debouncedQueryParams = useDebounce(queryParams, { wait: 500 })
|
||||
const [limit, setLimit] = React.useState<number>(APP_PAGE_LIMIT)
|
||||
const query = {
|
||||
page: currPage + 1,
|
||||
limit: APP_PAGE_LIMIT,
|
||||
limit,
|
||||
keyword: debouncedQueryParams.keyword || '',
|
||||
}
|
||||
|
||||
@ -228,35 +227,12 @@ const Annotation: FC<Props> = ({
|
||||
{/* Show Pagination only if the total is more than the limit */}
|
||||
{(total && total > APP_PAGE_LIMIT)
|
||||
? <Pagination
|
||||
className="flex items-center w-full h-10 text-sm select-none mt-8"
|
||||
currentPage={currPage}
|
||||
edgePageCount={2}
|
||||
middlePagesSiblingCount={1}
|
||||
setCurrentPage={setCurrPage}
|
||||
totalPages={Math.ceil(total / APP_PAGE_LIMIT)}
|
||||
truncableClassName="w-8 px-0.5 text-center"
|
||||
truncableText="..."
|
||||
>
|
||||
<Pagination.PrevButton
|
||||
disabled={currPage === 0}
|
||||
className={`flex items-center mr-2 text-gray-500 focus:outline-none ${currPage === 0 ? 'cursor-not-allowed opacity-50' : 'cursor-pointer hover:text-gray-600 dark:hover:text-gray-200'}`} >
|
||||
<ArrowLeftIcon className="mr-3 h-3 w-3" />
|
||||
{t('appLog.table.pagination.previous')}
|
||||
</Pagination.PrevButton>
|
||||
<div className={`flex items-center justify-center flex-grow ${s.pagination}`}>
|
||||
<Pagination.PageButton
|
||||
activeClassName="bg-primary-50 dark:bg-opacity-0 text-primary-600 dark:text-white"
|
||||
className="flex items-center justify-center h-8 w-8 rounded-full cursor-pointer"
|
||||
inactiveClassName="text-gray-500"
|
||||
/>
|
||||
</div>
|
||||
<Pagination.NextButton
|
||||
disabled={currPage === Math.ceil(total / APP_PAGE_LIMIT) - 1}
|
||||
className={`flex items-center mr-2 text-gray-500 focus:outline-none ${currPage === Math.ceil(total / APP_PAGE_LIMIT) - 1 ? 'cursor-not-allowed opacity-50' : 'cursor-pointer hover:text-gray-600 dark:hover:text-gray-200'}`} >
|
||||
{t('appLog.table.pagination.next')}
|
||||
<ArrowRightIcon className="ml-3 h-3 w-3" />
|
||||
</Pagination.NextButton>
|
||||
</Pagination>
|
||||
current={currPage}
|
||||
onChange={setCurrPage}
|
||||
total={total}
|
||||
limit={limit}
|
||||
onLimitChange={setLimit}
|
||||
/>
|
||||
: null}
|
||||
|
||||
{isShowViewModal && (
|
||||
|
||||
@ -1,3 +0,0 @@
|
||||
.pagination li {
|
||||
list-style: none;
|
||||
}
|
||||
@ -2,13 +2,12 @@
|
||||
import type { FC } from 'react'
|
||||
import React, { useEffect, useState } from 'react'
|
||||
import { useTranslation } from 'react-i18next'
|
||||
import { Pagination } from 'react-headless-pagination'
|
||||
import { ArrowLeftIcon, ArrowRightIcon } from '@heroicons/react/24/outline'
|
||||
import EditItem, { EditItemType } from '../edit-annotation-modal/edit-item'
|
||||
import type { AnnotationItem, HitHistoryItem } from '../type'
|
||||
import s from './style.module.css'
|
||||
import HitHistoryNoData from './hit-history-no-data'
|
||||
import cn from '@/utils/classnames'
|
||||
import Pagination from '@/app/components/base/pagination'
|
||||
import Drawer from '@/app/components/base/drawer-plus'
|
||||
import { MessageCheckRemove } from '@/app/components/base/icons/src/vender/line/communication'
|
||||
import Confirm from '@/app/components/base/confirm'
|
||||
@ -150,35 +149,10 @@ const ViewAnnotationModal: FC<Props> = ({
|
||||
</table>
|
||||
{(total && total > APP_PAGE_LIMIT)
|
||||
? <Pagination
|
||||
className="flex items-center w-full h-10 text-sm select-none mt-8"
|
||||
currentPage={currPage}
|
||||
edgePageCount={2}
|
||||
middlePagesSiblingCount={1}
|
||||
setCurrentPage={setCurrPage}
|
||||
totalPages={Math.ceil(total / APP_PAGE_LIMIT)}
|
||||
truncatableClassName="w-8 px-0.5 text-center"
|
||||
truncatableText="..."
|
||||
>
|
||||
<Pagination.PrevButton
|
||||
disabled={currPage === 0}
|
||||
className={`flex items-center mr-2 text-gray-500 focus:outline-none ${currPage === 0 ? 'cursor-not-allowed opacity-50' : 'cursor-pointer hover:text-gray-600 dark:hover:text-gray-200'}`} >
|
||||
<ArrowLeftIcon className="mr-3 h-3 w-3" />
|
||||
{t('appLog.table.pagination.previous')}
|
||||
</Pagination.PrevButton>
|
||||
<div className={`flex items-center justify-center flex-grow ${s.pagination}`}>
|
||||
<Pagination.PageButton
|
||||
activeClassName="bg-primary-50 dark:bg-opacity-0 text-primary-600 dark:text-white"
|
||||
className="flex items-center justify-center h-8 w-8 rounded-full cursor-pointer"
|
||||
inactiveClassName="text-gray-500"
|
||||
/>
|
||||
</div>
|
||||
<Pagination.NextButton
|
||||
disabled={currPage === Math.ceil(total / APP_PAGE_LIMIT) - 1}
|
||||
className={`flex items-center mr-2 text-gray-500 focus:outline-none ${currPage === Math.ceil(total / APP_PAGE_LIMIT) - 1 ? 'cursor-not-allowed opacity-50' : 'cursor-pointer hover:text-gray-600 dark:hover:text-gray-200'}`} >
|
||||
{t('appLog.table.pagination.next')}
|
||||
<ArrowRightIcon className="ml-3 h-3 w-3" />
|
||||
</Pagination.NextButton>
|
||||
</Pagination>
|
||||
current={currPage}
|
||||
onChange={setCurrPage}
|
||||
total={total}
|
||||
/>
|
||||
: null}
|
||||
</div>
|
||||
|
||||
|
||||
@ -29,6 +29,7 @@ import { useAppContext } from '@/context/app-context'
|
||||
import { ModelFeatureEnum } from '@/app/components/header/account-setting/model-provider-page/declarations'
|
||||
import { useFeatures } from '@/app/components/base/features/hooks'
|
||||
import type { InputForm } from '@/app/components/base/chat/chat/type'
|
||||
import { getLastAnswer } from '@/app/components/base/chat/utils'
|
||||
|
||||
type ChatItemProps = {
|
||||
modelAndParameter: ModelAndParameter
|
||||
@ -101,7 +102,7 @@ const ChatItem: FC<ChatItemProps> = ({
|
||||
query: message,
|
||||
inputs,
|
||||
model_config: configData,
|
||||
parent_message_id: chatListRef.current.at(-1)?.id || null,
|
||||
parent_message_id: getLastAnswer(chatListRef.current)?.id || null,
|
||||
}
|
||||
|
||||
if ((config.file_upload as any).enabled && files?.length && supportVision)
|
||||
|
||||
@ -22,7 +22,7 @@ import { getNewVar } from '@/utils/var'
|
||||
import { varHighlightHTML } from '@/app/components/app/configuration/base/var-highlight'
|
||||
import Toast from '@/app/components/base/toast'
|
||||
|
||||
const MAX_QUESTION_NUM = 5
|
||||
const MAX_QUESTION_NUM = 10
|
||||
|
||||
export type IOpeningStatementProps = {
|
||||
value: string
|
||||
|
||||
@ -52,7 +52,7 @@ const LogAnnotation: FC<Props> = ({
|
||||
options={options}
|
||||
/>
|
||||
)}
|
||||
<div className={cn('grow', appDetail.mode !== 'workflow' && 'mt-3')}>
|
||||
<div className={cn('grow h-0', appDetail.mode !== 'workflow' && 'mt-3')}>
|
||||
{pageType === PageType.log && appDetail.mode !== 'workflow' && (<Log appDetail={appDetail} />)}
|
||||
{pageType === PageType.annotation && (<Annotation appDetail={appDetail} />)}
|
||||
{pageType === PageType.log && appDetail.mode === 'workflow' && (<WorkflowLog appDetail={appDetail} />)}
|
||||
|
||||
@ -2,17 +2,15 @@
|
||||
import type { FC, SVGProps } from 'react'
|
||||
import React, { useState } from 'react'
|
||||
import useSWR from 'swr'
|
||||
import Link from 'next/link'
|
||||
import { usePathname } from 'next/navigation'
|
||||
import { Pagination } from 'react-headless-pagination'
|
||||
import { useDebounce } from 'ahooks'
|
||||
import { omit } from 'lodash-es'
|
||||
import dayjs from 'dayjs'
|
||||
import { ArrowLeftIcon, ArrowRightIcon } from '@heroicons/react/24/outline'
|
||||
import { Trans, useTranslation } from 'react-i18next'
|
||||
import Link from 'next/link'
|
||||
import List from './list'
|
||||
import Filter, { TIME_PERIOD_MAPPING } from './filter'
|
||||
import s from './style.module.css'
|
||||
import Pagination from '@/app/components/base/pagination'
|
||||
import Loading from '@/app/components/base/loading'
|
||||
import { fetchChatConversations, fetchCompletionConversations } from '@/service/log'
|
||||
import { APP_PAGE_LIMIT } from '@/config'
|
||||
@ -60,6 +58,7 @@ const Logs: FC<ILogsProps> = ({ appDetail }) => {
|
||||
sort_by: '-created_at',
|
||||
})
|
||||
const [currPage, setCurrPage] = React.useState<number>(0)
|
||||
const [limit, setLimit] = React.useState<number>(APP_PAGE_LIMIT)
|
||||
const debouncedQueryParams = useDebounce(queryParams, { wait: 500 })
|
||||
|
||||
// Get the app type first
|
||||
@ -67,7 +66,7 @@ const Logs: FC<ILogsProps> = ({ appDetail }) => {
|
||||
|
||||
const query = {
|
||||
page: currPage + 1,
|
||||
limit: APP_PAGE_LIMIT,
|
||||
limit,
|
||||
...((debouncedQueryParams.period !== '9')
|
||||
? {
|
||||
start: dayjs().subtract(TIME_PERIOD_MAPPING[debouncedQueryParams.period].value, 'day').startOf('day').format('YYYY-MM-DD HH:mm'),
|
||||
@ -102,9 +101,9 @@ const Logs: FC<ILogsProps> = ({ appDetail }) => {
|
||||
const total = isChatMode ? chatConversations?.total : completionConversations?.total
|
||||
|
||||
return (
|
||||
<div className='flex flex-col h-full'>
|
||||
<p className='text-text-tertiary system-sm-regular'>{t('appLog.description')}</p>
|
||||
<div className='flex flex-col py-4 flex-1'>
|
||||
<div className='grow flex flex-col h-full'>
|
||||
<p className='shrink-0 text-text-tertiary system-sm-regular'>{t('appLog.description')}</p>
|
||||
<div className='grow max-h-[calc(100%-16px)] flex flex-col py-4 flex-1'>
|
||||
<Filter isChatMode={isChatMode} appId={appDetail.id} queryParams={queryParams} setQueryParams={setQueryParams} />
|
||||
{total === undefined
|
||||
? <Loading type='app' />
|
||||
@ -115,35 +114,12 @@ const Logs: FC<ILogsProps> = ({ appDetail }) => {
|
||||
{/* Show Pagination only if the total is more than the limit */}
|
||||
{(total && total > APP_PAGE_LIMIT)
|
||||
? <Pagination
|
||||
className="flex items-center w-full h-10 text-sm select-none mt-8"
|
||||
currentPage={currPage}
|
||||
edgePageCount={2}
|
||||
middlePagesSiblingCount={1}
|
||||
setCurrentPage={setCurrPage}
|
||||
totalPages={Math.ceil(total / APP_PAGE_LIMIT)}
|
||||
truncableClassName="w-8 px-0.5 text-center"
|
||||
truncableText="..."
|
||||
>
|
||||
<Pagination.PrevButton
|
||||
disabled={currPage === 0}
|
||||
className={`flex items-center mr-2 text-gray-500 focus:outline-none ${currPage === 0 ? 'cursor-not-allowed opacity-50' : 'cursor-pointer hover:text-gray-600 dark:hover:text-gray-200'}`} >
|
||||
<ArrowLeftIcon className="mr-3 h-3 w-3" />
|
||||
{t('appLog.table.pagination.previous')}
|
||||
</Pagination.PrevButton>
|
||||
<div className={`flex items-center justify-center flex-grow ${s.pagination}`}>
|
||||
<Pagination.PageButton
|
||||
activeClassName="bg-primary-50 dark:bg-opacity-0 text-primary-600 dark:text-white"
|
||||
className="flex items-center justify-center h-8 w-8 rounded-full cursor-pointer"
|
||||
inactiveClassName="text-gray-500"
|
||||
/>
|
||||
</div>
|
||||
<Pagination.NextButton
|
||||
disabled={currPage === Math.ceil(total / APP_PAGE_LIMIT) - 1}
|
||||
className={`flex items-center mr-2 text-gray-500 focus:outline-none ${currPage === Math.ceil(total / APP_PAGE_LIMIT) - 1 ? 'cursor-not-allowed opacity-50' : 'cursor-pointer hover:text-gray-600 dark:hover:text-gray-200'}`} >
|
||||
{t('appLog.table.pagination.next')}
|
||||
<ArrowRightIcon className="ml-3 h-3 w-3" />
|
||||
</Pagination.NextButton>
|
||||
</Pagination>
|
||||
current={currPage}
|
||||
onChange={setCurrPage}
|
||||
total={total}
|
||||
limit={limit}
|
||||
onLimitChange={setLimit}
|
||||
/>
|
||||
: null}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@ -318,7 +318,7 @@ function DetailPanel({ detail, onFeedback }: IDetailPanel) {
|
||||
const targetTone = TONE_LIST.find((item: any) => {
|
||||
let res = true
|
||||
validatedParams.forEach((param) => {
|
||||
res = item.config?.[param] === detail.model_config?.configs?.completion_params?.[param]
|
||||
res = item.config?.[param] === detail?.model_config.model?.completion_params?.[param]
|
||||
})
|
||||
return res
|
||||
})?.name ?? 'custom'
|
||||
|
||||
@ -1,3 +0,0 @@
|
||||
.pagination li {
|
||||
list-style: none;
|
||||
}
|
||||
@ -3,14 +3,12 @@ import type { FC, SVGProps } from 'react'
|
||||
import React, { useState } from 'react'
|
||||
import useSWR from 'swr'
|
||||
import { usePathname } from 'next/navigation'
|
||||
import { Pagination } from 'react-headless-pagination'
|
||||
import { useDebounce } from 'ahooks'
|
||||
import { ArrowLeftIcon, ArrowRightIcon } from '@heroicons/react/24/outline'
|
||||
import { Trans, useTranslation } from 'react-i18next'
|
||||
import Link from 'next/link'
|
||||
import List from './list'
|
||||
import Filter from './filter'
|
||||
import s from './style.module.css'
|
||||
import Pagination from '@/app/components/base/pagination'
|
||||
import Loading from '@/app/components/base/loading'
|
||||
import { fetchWorkflowLogs } from '@/service/log'
|
||||
import { APP_PAGE_LIMIT } from '@/config'
|
||||
@ -53,10 +51,11 @@ const Logs: FC<ILogsProps> = ({ appDetail }) => {
|
||||
const [queryParams, setQueryParams] = useState<QueryParam>({ status: 'all' })
|
||||
const [currPage, setCurrPage] = React.useState<number>(0)
|
||||
const debouncedQueryParams = useDebounce(queryParams, { wait: 500 })
|
||||
const [limit, setLimit] = React.useState<number>(APP_PAGE_LIMIT)
|
||||
|
||||
const query = {
|
||||
page: currPage + 1,
|
||||
limit: APP_PAGE_LIMIT,
|
||||
limit,
|
||||
...(debouncedQueryParams.status !== 'all' ? { status: debouncedQueryParams.status } : {}),
|
||||
...(debouncedQueryParams.keyword ? { keyword: debouncedQueryParams.keyword } : {}),
|
||||
}
|
||||
@ -77,7 +76,7 @@ const Logs: FC<ILogsProps> = ({ appDetail }) => {
|
||||
<div className='flex flex-col h-full'>
|
||||
<h1 className='text-text-primary system-xl-semibold'>{t('appLog.workflowTitle')}</h1>
|
||||
<p className='text-text-tertiary system-sm-regular'>{t('appLog.workflowSubtitle')}</p>
|
||||
<div className='flex flex-col py-4 flex-1'>
|
||||
<div className='flex flex-col py-4 flex-1 max-h-[calc(100%-16px)]'>
|
||||
<Filter queryParams={queryParams} setQueryParams={setQueryParams} />
|
||||
{/* workflow log */}
|
||||
{total === undefined
|
||||
@ -89,35 +88,12 @@ const Logs: FC<ILogsProps> = ({ appDetail }) => {
|
||||
{/* Show Pagination only if the total is more than the limit */}
|
||||
{(total && total > APP_PAGE_LIMIT)
|
||||
? <Pagination
|
||||
className="flex items-center w-full h-10 text-sm select-none mt-8"
|
||||
currentPage={currPage}
|
||||
edgePageCount={2}
|
||||
middlePagesSiblingCount={1}
|
||||
setCurrentPage={setCurrPage}
|
||||
totalPages={Math.ceil(total / APP_PAGE_LIMIT)}
|
||||
truncableClassName="w-8 px-0.5 text-center"
|
||||
truncableText="..."
|
||||
>
|
||||
<Pagination.PrevButton
|
||||
disabled={currPage === 0}
|
||||
className={`flex items-center mr-2 text-gray-500 focus:outline-none ${currPage === 0 ? 'cursor-not-allowed opacity-50' : 'cursor-pointer hover:text-gray-600 dark:hover:text-gray-200'}`} >
|
||||
<ArrowLeftIcon className="mr-3 h-3 w-3" />
|
||||
{t('appLog.table.pagination.previous')}
|
||||
</Pagination.PrevButton>
|
||||
<div className={`flex items-center justify-center flex-grow ${s.pagination}`}>
|
||||
<Pagination.PageButton
|
||||
activeClassName="bg-primary-50 dark:bg-opacity-0 text-primary-600 dark:text-white"
|
||||
className="flex items-center justify-center h-8 w-8 rounded-full cursor-pointer"
|
||||
inactiveClassName="text-gray-500"
|
||||
/>
|
||||
</div>
|
||||
<Pagination.NextButton
|
||||
disabled={currPage === Math.ceil(total / APP_PAGE_LIMIT) - 1}
|
||||
className={`flex items-center mr-2 text-gray-500 focus:outline-none ${currPage === Math.ceil(total / APP_PAGE_LIMIT) - 1 ? 'cursor-not-allowed opacity-50' : 'cursor-pointer hover:text-gray-600 dark:hover:text-gray-200'}`} >
|
||||
{t('appLog.table.pagination.next')}
|
||||
<ArrowRightIcon className="ml-3 h-3 w-3" />
|
||||
</Pagination.NextButton>
|
||||
</Pagination>
|
||||
current={currPage}
|
||||
onChange={setCurrPage}
|
||||
total={total}
|
||||
limit={limit}
|
||||
onLimitChange={setLimit}
|
||||
/>
|
||||
: null}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@ -2,9 +2,7 @@
|
||||
import type { FC } from 'react'
|
||||
import React, { useState } from 'react'
|
||||
import { useTranslation } from 'react-i18next'
|
||||
// import s from './style.module.css'
|
||||
import DetailPanel from './detail'
|
||||
import cn from '@/utils/classnames'
|
||||
import type { WorkflowAppLogDetail, WorkflowLogsResponse } from '@/models/log'
|
||||
import type { App } from '@/types/app'
|
||||
import Loading from '@/app/components/base/loading'
|
||||
@ -12,6 +10,7 @@ import Drawer from '@/app/components/base/drawer'
|
||||
import Indicator from '@/app/components/header/indicator'
|
||||
import useBreakpoints, { MediaType } from '@/hooks/use-breakpoints'
|
||||
import useTimestamp from '@/hooks/use-timestamp'
|
||||
import cn from '@/utils/classnames'
|
||||
|
||||
type ILogs = {
|
||||
logs?: WorkflowLogsResponse
|
||||
|
||||
@ -1,3 +0,0 @@
|
||||
.pagination li {
|
||||
list-style: none;
|
||||
}
|
||||
@ -15,7 +15,7 @@ const Badge = ({
|
||||
return (
|
||||
<div
|
||||
className={cn(
|
||||
'inline-flex items-center px-[5px] h-5 rounded-[5px] border border-divider-deep leading-3 text-text-tertiary',
|
||||
'inline-flex items-center px-[5px] h-5 rounded-[5px] border border-divider-deep leading-3 text-text-tertiary',
|
||||
uppercase ? 'system-2xs-medium-uppercase' : 'system-xs-medium',
|
||||
className,
|
||||
)}
|
||||
|
||||
@ -3,17 +3,21 @@ import React from 'react'
|
||||
import { type VariantProps, cva } from 'class-variance-authority'
|
||||
import classNames from '@/utils/classnames'
|
||||
|
||||
const dividerVariants = cva(
|
||||
'bg-divider-regular',
|
||||
const dividerVariants = cva('',
|
||||
{
|
||||
variants: {
|
||||
type: {
|
||||
horizontal: 'w-full h-[0.5px] my-2',
|
||||
horizontal: 'w-full h-[0.5px] my-2 ',
|
||||
vertical: 'w-[1px] h-full mx-2',
|
||||
},
|
||||
bgStyle: {
|
||||
gradient: 'bg-gradient-to-r from-divider-regular to-background-gradient-mask-transparent',
|
||||
solid: 'bg-divider-regular',
|
||||
},
|
||||
},
|
||||
defaultVariants: {
|
||||
type: 'horizontal',
|
||||
bgStyle: 'solid',
|
||||
},
|
||||
},
|
||||
)
|
||||
@ -23,9 +27,9 @@ export type DividerProps = {
|
||||
style?: CSSProperties
|
||||
} & VariantProps<typeof dividerVariants>
|
||||
|
||||
const Divider: FC<DividerProps> = ({ type, className = '', style }) => {
|
||||
const Divider: FC<DividerProps> = ({ type, bgStyle, className = '', style }) => {
|
||||
return (
|
||||
<div className={classNames(dividerVariants({ type }), className)} style={style}></div>
|
||||
<div className={classNames(dividerVariants({ type, bgStyle }), className)} style={style}></div>
|
||||
)
|
||||
}
|
||||
|
||||
|
||||
@ -22,7 +22,7 @@ type OpeningSettingModalProps = {
|
||||
onAutoAddPromptVariable?: (variable: PromptVariable[]) => void
|
||||
}
|
||||
|
||||
const MAX_QUESTION_NUM = 5
|
||||
const MAX_QUESTION_NUM = 10
|
||||
|
||||
const OpeningSettingModal = ({
|
||||
data,
|
||||
|
||||
@ -84,7 +84,7 @@ const FileImageItem = ({
|
||||
className='absolute bottom-0.5 right-0.5 flex items-center justify-center w-6 h-6 rounded-lg bg-components-actionbar-bg shadow-md'
|
||||
onClick={(e) => {
|
||||
e.stopPropagation()
|
||||
downloadFile(url || '', name)
|
||||
downloadFile(url || base64Url || '', name)
|
||||
}}
|
||||
>
|
||||
<RiDownloadLine className='w-4 h-4 text-text-tertiary' />
|
||||
|
||||
@ -80,7 +80,7 @@ const FileItem = ({
|
||||
}
|
||||
</div>
|
||||
{
|
||||
showDownloadAction && (
|
||||
showDownloadAction && url && (
|
||||
<ActionButton
|
||||
size='m'
|
||||
className='hidden group-hover/file-item:flex absolute -right-1 -top-1'
|
||||
|
||||
@ -53,8 +53,7 @@ const ImageGallery: FC<Props> = ({
|
||||
imagePreviewUrl && (
|
||||
<ImagePreview
|
||||
url={imagePreviewUrl}
|
||||
onCancel={() => setImagePreviewUrl('')}
|
||||
/>
|
||||
onCancel={() => setImagePreviewUrl('')} title={''} />
|
||||
)
|
||||
}
|
||||
</div>
|
||||
|
||||
@ -64,7 +64,9 @@ const Input = ({
|
||||
destructive && 'bg-components-input-bg-destructive border-components-input-border-destructive text-components-input-text-filled hover:bg-components-input-bg-destructive hover:border-components-input-border-destructive focus:bg-components-input-bg-destructive focus:border-components-input-border-destructive',
|
||||
className,
|
||||
)}
|
||||
placeholder={placeholder ?? (showLeftIcon ? t('common.operation.search') ?? '' : t('common.placeholder.input'))}
|
||||
placeholder={placeholder ?? (showLeftIcon
|
||||
? (t('common.operation.search') || '')
|
||||
: (t('common.placeholder.input') || ''))}
|
||||
value={value}
|
||||
onChange={onChange}
|
||||
disabled={disabled}
|
||||
|
||||
21
web/app/components/base/list-empty/horizontal-line.tsx
Normal file
21
web/app/components/base/list-empty/horizontal-line.tsx
Normal file
@ -0,0 +1,21 @@
|
||||
type HorizontalLineProps = {
|
||||
className?: string
|
||||
}
|
||||
const HorizontalLine = ({
|
||||
className,
|
||||
}: HorizontalLineProps) => {
|
||||
return (
|
||||
<svg xmlns="http://www.w3.org/2000/svg" width="240" height="2" viewBox="0 0 240 2" fill="none" className={className}>
|
||||
<path d="M0 1H240" stroke="url(#paint0_linear_8619_59125)"/>
|
||||
<defs>
|
||||
<linearGradient id="paint0_linear_8619_59125" x1="240" y1="9.99584" x2="3.95539e-05" y2="9.88094" gradientUnits="userSpaceOnUse">
|
||||
<stop stopColor="white" stopOpacity="0.01"/>
|
||||
<stop offset="0.9031" stopColor="#101828" stopOpacity="0.04"/>
|
||||
<stop offset="1" stopColor="white" stopOpacity="0.01"/>
|
||||
</linearGradient>
|
||||
</defs>
|
||||
</svg>
|
||||
)
|
||||
}
|
||||
|
||||
export default HorizontalLine
|
||||
35
web/app/components/base/list-empty/index.tsx
Normal file
35
web/app/components/base/list-empty/index.tsx
Normal file
@ -0,0 +1,35 @@
|
||||
import React from 'react'
|
||||
import { Variable02 } from '../icons/src/vender/solid/development'
|
||||
import VerticalLine from './vertical-line'
|
||||
import HorizontalLine from './horizontal-line'
|
||||
|
||||
type ListEmptyProps = {
|
||||
title?: string
|
||||
description?: React.ReactNode
|
||||
}
|
||||
|
||||
const ListEmpty = ({
|
||||
title,
|
||||
description,
|
||||
}: ListEmptyProps) => {
|
||||
return (
|
||||
<div className='flex w-[320px] p-4 flex-col items-start gap-2 rounded-[10px] bg-workflow-process-bg'>
|
||||
<div className='flex w-10 h-10 justify-center items-center gap-2 rounded-[10px]'>
|
||||
<div className='flex relative p-1 justify-center items-center gap-2 grow self-stretch rounded-[10px]
|
||||
border-[0.5px] border-components-card-border bg-components-card-bg shadow-lg'>
|
||||
<Variable02 className='w-5 h-5 shrink-0 text-text-accent' />
|
||||
<VerticalLine className='absolute -right-[1px] top-1/2 -translate-y-1/4'/>
|
||||
<VerticalLine className='absolute -left-[1px] top-1/2 -translate-y-1/4'/>
|
||||
<HorizontalLine className='absolute top-0 left-3/4 -translate-x-1/4 -translate-y-1/2'/>
|
||||
<HorizontalLine className='absolute top-full left-3/4 -translate-x-1/4 -translate-y-1/2' />
|
||||
</div>
|
||||
</div>
|
||||
<div className='flex flex-col items-start gap-1 self-stretch'>
|
||||
<div className='text-text-secondary system-sm-medium'>{title}</div>
|
||||
{description}
|
||||
</div>
|
||||
</div>
|
||||
)
|
||||
}
|
||||
|
||||
export default ListEmpty
|
||||
21
web/app/components/base/list-empty/vertical-line.tsx
Normal file
21
web/app/components/base/list-empty/vertical-line.tsx
Normal file
@ -0,0 +1,21 @@
|
||||
type VerticalLineProps = {
|
||||
className?: string
|
||||
}
|
||||
const VerticalLine = ({
|
||||
className,
|
||||
}: VerticalLineProps) => {
|
||||
return (
|
||||
<svg xmlns="http://www.w3.org/2000/svg" width="2" height="132" viewBox="0 0 2 132" fill="none" className={className}>
|
||||
<path d="M1 0L1 132" stroke="url(#paint0_linear_8619_59128)"/>
|
||||
<defs>
|
||||
<linearGradient id="paint0_linear_8619_59128" x1="-7.99584" y1="132" x2="-7.96108" y2="6.4974e-07" gradientUnits="userSpaceOnUse">
|
||||
<stop stopColor="white" stopOpacity="0.01"/>
|
||||
<stop offset="0.877606" stopColor="#101828" stopOpacity="0.04"/>
|
||||
<stop offset="1" stopColor="white" stopOpacity="0.01"/>
|
||||
</linearGradient>
|
||||
</defs>
|
||||
</svg>
|
||||
)
|
||||
}
|
||||
|
||||
export default VerticalLine
|
||||
@ -8,8 +8,7 @@ import RemarkGfm from 'remark-gfm'
|
||||
import RehypeRaw from 'rehype-raw'
|
||||
import SyntaxHighlighter from 'react-syntax-highlighter'
|
||||
import { atelierHeathLight } from 'react-syntax-highlighter/dist/esm/styles/hljs'
|
||||
import type { RefObject } from 'react'
|
||||
import { Component, memo, useEffect, useMemo, useRef, useState } from 'react'
|
||||
import { Component, memo, useMemo, useRef, useState } from 'react'
|
||||
import type { CodeComponent } from 'react-markdown/lib/ast-to-react'
|
||||
import cn from '@/utils/classnames'
|
||||
import CopyBtn from '@/app/components/base/copy-btn'
|
||||
@ -77,29 +76,6 @@ export function PreCode(props: { children: any }) {
|
||||
)
|
||||
}
|
||||
|
||||
// eslint-disable-next-line unused-imports/no-unused-vars
|
||||
const useLazyLoad = (ref: RefObject<Element>): boolean => {
|
||||
const [isIntersecting, setIntersecting] = useState<boolean>(false)
|
||||
|
||||
useEffect(() => {
|
||||
const observer = new IntersectionObserver(([entry]) => {
|
||||
if (entry.isIntersecting) {
|
||||
setIntersecting(true)
|
||||
observer.disconnect()
|
||||
}
|
||||
})
|
||||
|
||||
if (ref.current)
|
||||
observer.observe(ref.current)
|
||||
|
||||
return () => {
|
||||
observer.disconnect()
|
||||
}
|
||||
}, [ref])
|
||||
|
||||
return isIntersecting
|
||||
}
|
||||
|
||||
// **Add code block
|
||||
// Avoid error #185 (Maximum update depth exceeded.
|
||||
// This can happen when a component repeatedly calls setState inside componentWillUpdate or componentDidUpdate.
|
||||
@ -123,7 +99,7 @@ const CodeBlock: CodeComponent = memo(({ inline, className, children, ...props }
|
||||
try {
|
||||
return JSON.parse(String(children).replace(/\n$/, ''))
|
||||
}
|
||||
catch (error) {}
|
||||
catch (error) { }
|
||||
}
|
||||
return JSON.parse('{"title":{"text":"ECharts error - Wrong JSON format."}}')
|
||||
}, [language, children])
|
||||
@ -181,7 +157,7 @@ const CodeBlock: CodeComponent = memo(({ inline, className, children, ...props }
|
||||
>
|
||||
<div className='text-[13px] text-gray-500 font-normal'>{languageShowName}</div>
|
||||
<div style={{ display: 'flex' }}>
|
||||
{(['mermaid', 'svg']).includes(language!) && <SVGBtn isSVG={isSVG} setIsSVG={setIsSVG}/>}
|
||||
{(['mermaid', 'svg']).includes(language!) && <SVGBtn isSVG={isSVG} setIsSVG={setIsSVG} />}
|
||||
<CopyBtn
|
||||
className='mr-1'
|
||||
value={String(children).replace(/\n$/, '')}
|
||||
@ -261,7 +237,7 @@ export function Markdown(props: { content: string; className?: string }) {
|
||||
() => {
|
||||
return (tree) => {
|
||||
const iterate = (node: any) => {
|
||||
if (node.type === 'element' && !node.properties?.src && node.properties?.ref && node.properties.ref.startsWith('{') && node.properties.ref.endsWith('}'))
|
||||
if (node.type === 'element' && node.properties?.ref)
|
||||
delete node.properties.ref
|
||||
|
||||
if (node.children)
|
||||
|
||||
95
web/app/components/base/pagination/hook.ts
Normal file
95
web/app/components/base/pagination/hook.ts
Normal file
@ -0,0 +1,95 @@
|
||||
import React, { useCallback } from 'react'
|
||||
import type { IPaginationProps, IUsePagination } from './type'
|
||||
|
||||
const usePagination = ({
|
||||
currentPage,
|
||||
setCurrentPage,
|
||||
truncableText = '...',
|
||||
truncableClassName = '',
|
||||
totalPages,
|
||||
edgePageCount,
|
||||
middlePagesSiblingCount,
|
||||
}: IPaginationProps): IUsePagination => {
|
||||
const pages = Array(totalPages)
|
||||
.fill(0)
|
||||
.map((_, i) => i + 1)
|
||||
|
||||
const hasPreviousPage = currentPage > 1
|
||||
const hasNextPage = currentPage < totalPages
|
||||
|
||||
const isReachedToFirst = currentPage <= middlePagesSiblingCount
|
||||
const isReachedToLast = currentPage + middlePagesSiblingCount >= totalPages
|
||||
|
||||
const middlePages = React.useMemo(() => {
|
||||
const middlePageCount = middlePagesSiblingCount * 2 + 1
|
||||
if (isReachedToFirst)
|
||||
return pages.slice(0, middlePageCount)
|
||||
|
||||
if (isReachedToLast)
|
||||
return pages.slice(-middlePageCount)
|
||||
|
||||
return pages.slice(
|
||||
currentPage - middlePagesSiblingCount,
|
||||
currentPage + middlePagesSiblingCount + 1,
|
||||
)
|
||||
}, [currentPage, isReachedToFirst, isReachedToLast, middlePagesSiblingCount, pages])
|
||||
|
||||
const getAllPreviousPages = useCallback(() => {
|
||||
return pages.slice(0, middlePages[0] - 1)
|
||||
}, [middlePages, pages])
|
||||
|
||||
const previousPages = React.useMemo(() => {
|
||||
if (isReachedToFirst || getAllPreviousPages().length < 1)
|
||||
return []
|
||||
|
||||
return pages
|
||||
.slice(0, edgePageCount)
|
||||
.filter(p => !middlePages.includes(p))
|
||||
}, [edgePageCount, getAllPreviousPages, isReachedToFirst, middlePages, pages])
|
||||
|
||||
const getAllNextPages = React.useMemo(() => {
|
||||
return pages.slice(
|
||||
middlePages[middlePages.length - 1],
|
||||
pages[pages.length],
|
||||
)
|
||||
}, [pages, middlePages])
|
||||
|
||||
const nextPages = React.useMemo(() => {
|
||||
if (isReachedToLast)
|
||||
return []
|
||||
|
||||
if (getAllNextPages.length < 1)
|
||||
return []
|
||||
|
||||
return pages
|
||||
.slice(pages.length - edgePageCount, pages.length)
|
||||
.filter(p => !middlePages.includes(p))
|
||||
}, [edgePageCount, getAllNextPages.length, isReachedToLast, middlePages, pages])
|
||||
|
||||
const isPreviousTruncable = React.useMemo(() => {
|
||||
// Is truncable if first value of middlePage is larger than last value of previousPages
|
||||
return middlePages[0] > previousPages[previousPages.length - 1] + 1
|
||||
}, [previousPages, middlePages])
|
||||
|
||||
const isNextTruncable = React.useMemo(() => {
|
||||
// Is truncable if last value of middlePage is larger than first value of previousPages
|
||||
return middlePages[middlePages.length - 1] + 1 < nextPages[0]
|
||||
}, [nextPages, middlePages])
|
||||
|
||||
return {
|
||||
currentPage,
|
||||
setCurrentPage,
|
||||
truncableText,
|
||||
truncableClassName,
|
||||
pages,
|
||||
hasPreviousPage,
|
||||
hasNextPage,
|
||||
previousPages,
|
||||
isPreviousTruncable,
|
||||
middlePages,
|
||||
isNextTruncable,
|
||||
nextPages,
|
||||
}
|
||||
}
|
||||
|
||||
export default usePagination
|
||||
@ -1,50 +1,165 @@
|
||||
import type { FC } from 'react'
|
||||
import React from 'react'
|
||||
import { Pagination } from 'react-headless-pagination'
|
||||
import { ArrowLeftIcon, ArrowRightIcon } from '@heroicons/react/24/outline'
|
||||
import { useTranslation } from 'react-i18next'
|
||||
import s from './style.module.css'
|
||||
import { RiArrowLeftLine, RiArrowRightLine } from '@remixicon/react'
|
||||
import { useDebounceFn } from 'ahooks'
|
||||
import { Pagination } from './pagination'
|
||||
import Button from '@/app/components/base/button'
|
||||
import Input from '@/app/components/base/input'
|
||||
import cn from '@/utils/classnames'
|
||||
|
||||
type Props = {
|
||||
className?: string
|
||||
current: number
|
||||
onChange: (cur: number) => void
|
||||
total: number
|
||||
limit?: number
|
||||
onLimitChange?: (limit: number) => void
|
||||
}
|
||||
|
||||
const CustomizedPagination: FC<Props> = ({ current, onChange, total, limit = 10 }) => {
|
||||
const CustomizedPagination: FC<Props> = ({
|
||||
className,
|
||||
current,
|
||||
onChange,
|
||||
total,
|
||||
limit = 10,
|
||||
onLimitChange,
|
||||
}) => {
|
||||
const { t } = useTranslation()
|
||||
const totalPages = Math.ceil(total / limit)
|
||||
const inputRef = React.useRef<HTMLDivElement>(null)
|
||||
const [showInput, setShowInput] = React.useState(false)
|
||||
const [inputValue, setInputValue] = React.useState<string | number>(current + 1)
|
||||
const [showPerPageTip, setShowPerPageTip] = React.useState(false)
|
||||
|
||||
const { run: handlePaging } = useDebounceFn((value: string) => {
|
||||
if (parseInt(value) > totalPages) {
|
||||
setInputValue(totalPages)
|
||||
onChange(totalPages - 1)
|
||||
setShowInput(false)
|
||||
return
|
||||
}
|
||||
if (parseInt(value) < 1) {
|
||||
setInputValue(1)
|
||||
onChange(0)
|
||||
setShowInput(false)
|
||||
return
|
||||
}
|
||||
onChange(parseInt(value) - 1)
|
||||
setInputValue(parseInt(value))
|
||||
setShowInput(false)
|
||||
}, { wait: 500 })
|
||||
|
||||
const handleInputChange = (e: React.ChangeEvent<HTMLInputElement>) => {
|
||||
const value = e.target.value
|
||||
if (!value)
|
||||
return setInputValue('')
|
||||
if (isNaN(parseInt(value)))
|
||||
return setInputValue('')
|
||||
setInputValue(parseInt(value))
|
||||
handlePaging(value)
|
||||
}
|
||||
|
||||
return (
|
||||
<Pagination
|
||||
className="flex items-center w-full h-10 text-sm select-none mt-8"
|
||||
className={cn('flex items-center w-full px-6 py-3 select-none', className)}
|
||||
currentPage={current}
|
||||
edgePageCount={2}
|
||||
middlePagesSiblingCount={1}
|
||||
setCurrentPage={onChange}
|
||||
totalPages={totalPages}
|
||||
truncatableClassName="w-8 px-0.5 text-center"
|
||||
truncatableText="..."
|
||||
truncableClassName='flex items-center justify-center w-8 px-1 py-2 system-sm-medium text-text-tertiary'
|
||||
truncableText='...'
|
||||
>
|
||||
<Pagination.PrevButton
|
||||
disabled={current === 0}
|
||||
className={`flex items-center mr-2 text-gray-500 focus:outline-none ${current === 0 ? 'cursor-not-allowed opacity-50' : 'cursor-pointer hover:text-gray-600'}`} >
|
||||
<ArrowLeftIcon className="mr-3 h-3 w-3" />
|
||||
{t('appLog.table.pagination.previous')}
|
||||
</Pagination.PrevButton>
|
||||
<div className={`flex items-center justify-center flex-grow ${s.pagination}`}>
|
||||
<div className='flex items-center gap-0.5 p-0.5 rounded-[10px] bg-background-section-burn'>
|
||||
<Pagination.PrevButton
|
||||
as={<div></div>}
|
||||
disabled={current === 0}
|
||||
>
|
||||
<Button
|
||||
variant='secondary'
|
||||
className='w-7 h-7 px-1.5'
|
||||
disabled={current === 0}
|
||||
>
|
||||
<RiArrowLeftLine className='h-4 w-4' />
|
||||
</Button>
|
||||
</Pagination.PrevButton>
|
||||
{!showInput && (
|
||||
<div
|
||||
ref={inputRef}
|
||||
className='flex items-center gap-0.5 px-2 py-1.5 rounded-lg hover:bg-state-base-hover-alt hover:cursor-text'
|
||||
onClick={() => setShowInput(true)}
|
||||
>
|
||||
<div className='system-xs-medium text-text-secondary'>{current + 1}</div>
|
||||
<div className='system-xs-medium text-text-quaternary'>/</div>
|
||||
<div className='system-xs-medium text-text-secondary'>{totalPages}</div>
|
||||
</div>
|
||||
)}
|
||||
{showInput && (
|
||||
<Input
|
||||
styleCss={{
|
||||
height: '28px',
|
||||
width: `${inputRef.current?.clientWidth}px`,
|
||||
}}
|
||||
placeholder=''
|
||||
autoFocus
|
||||
value={inputValue}
|
||||
onChange={handleInputChange}
|
||||
onBlur={() => setShowInput(false)}
|
||||
/>
|
||||
)}
|
||||
<Pagination.NextButton
|
||||
as={<div></div>}
|
||||
disabled={current === totalPages - 1}
|
||||
>
|
||||
<Button
|
||||
variant='secondary'
|
||||
className='w-7 h-7 px-1.5'
|
||||
disabled={current === totalPages - 1}
|
||||
>
|
||||
<RiArrowRightLine className='h-4 w-4' />
|
||||
</Button>
|
||||
</Pagination.NextButton>
|
||||
</div>
|
||||
<div className={cn('grow flex items-center justify-center gap-1 list-none')}>
|
||||
<Pagination.PageButton
|
||||
activeClassName="bg-primary-50 text-primary-600"
|
||||
className="flex items-center justify-center h-8 w-8 rounded-lg cursor-pointer"
|
||||
inactiveClassName="text-gray-500"
|
||||
className='flex items-center justify-center min-w-8 px-1 py-2 rounded-lg system-sm-medium cursor-pointer hover:bg-components-button-ghost-bg-hover'
|
||||
activeClassName='bg-components-button-tertiary-bg text-components-button-tertiary-text hover:bg-components-button-ghost-bg-hover'
|
||||
inactiveClassName='text-text-tertiary'
|
||||
/>
|
||||
</div>
|
||||
<Pagination.NextButton
|
||||
disabled={current === totalPages - 1}
|
||||
className={`flex items-center mr-2 text-gray-500 focus:outline-none ${current === totalPages - 1 ? 'cursor-not-allowed opacity-50' : 'cursor-pointer hover:text-gray-600'}`} >
|
||||
{t('appLog.table.pagination.next')}
|
||||
<ArrowRightIcon className="ml-3 h-3 w-3" />
|
||||
</Pagination.NextButton>
|
||||
{onLimitChange && (
|
||||
<div className='shrink-0 flex items-center gap-2'>
|
||||
<div className='shrink-0 w-[51px] text-end text-text-tertiary system-2xs-regular-uppercase'>{showPerPageTip ? t('common.pagination.perPage') : ''}</div>
|
||||
<div
|
||||
className='flex items-center gap-[1px] p-0.5 rounded-[10px] bg-components-segmented-control-bg-normal'
|
||||
onMouseEnter={() => setShowPerPageTip(true)}
|
||||
onMouseLeave={() => setShowPerPageTip(false)}
|
||||
>
|
||||
<div
|
||||
className={cn(
|
||||
'px-2.5 py-1.5 rounded-lg border-[0.5px] border-transparent system-sm-medium text-text-tertiary cursor-pointer hover:bg-state-base-hover hover:text-text-secondary',
|
||||
limit === 10 && 'shadow-xs border-components-segmented-control-item-active-border bg-components-segmented-control-item-active-bg text-text-secondary hover:bg-components-segmented-control-item-active-bg',
|
||||
)}
|
||||
onClick={() => onLimitChange?.(10)}
|
||||
>10</div>
|
||||
<div
|
||||
className={cn(
|
||||
'px-2.5 py-1.5 rounded-lg border-[0.5px] border-transparent system-sm-medium text-text-tertiary cursor-pointer hover:bg-state-base-hover hover:text-text-secondary',
|
||||
limit === 25 && 'shadow-xs border-components-segmented-control-item-active-border bg-components-segmented-control-item-active-bg text-text-secondary hover:bg-components-segmented-control-item-active-bg',
|
||||
)}
|
||||
onClick={() => onLimitChange?.(25)}
|
||||
>25</div>
|
||||
<div
|
||||
className={cn(
|
||||
'px-2.5 py-1.5 rounded-lg border-[0.5px] border-transparent system-sm-medium text-text-tertiary cursor-pointer hover:bg-state-base-hover hover:text-text-secondary',
|
||||
limit === 50 && 'shadow-xs border-components-segmented-control-item-active-border bg-components-segmented-control-item-active-bg text-text-secondary hover:bg-components-segmented-control-item-active-bg',
|
||||
)}
|
||||
onClick={() => onLimitChange?.(50)}
|
||||
>50</div>
|
||||
</div>
|
||||
</div>
|
||||
)}
|
||||
</Pagination>
|
||||
)
|
||||
}
|
||||
|
||||
189
web/app/components/base/pagination/pagination.tsx
Normal file
189
web/app/components/base/pagination/pagination.tsx
Normal file
@ -0,0 +1,189 @@
|
||||
import React from 'react'
|
||||
import clsx from 'clsx'
|
||||
import usePagination from './hook'
|
||||
import type {
|
||||
ButtonProps,
|
||||
IPagination,
|
||||
IPaginationProps,
|
||||
PageButtonProps,
|
||||
} from './type'
|
||||
|
||||
const defaultState: IPagination = {
|
||||
currentPage: 0,
|
||||
setCurrentPage: () => {},
|
||||
truncableText: '...',
|
||||
truncableClassName: '',
|
||||
pages: [],
|
||||
hasPreviousPage: false,
|
||||
hasNextPage: false,
|
||||
previousPages: [],
|
||||
isPreviousTruncable: false,
|
||||
middlePages: [],
|
||||
isNextTruncable: false,
|
||||
nextPages: [],
|
||||
}
|
||||
|
||||
const PaginationContext: React.Context<IPagination> = React.createContext<IPagination>(defaultState)
|
||||
|
||||
export const PrevButton = ({
|
||||
className,
|
||||
children,
|
||||
dataTestId,
|
||||
as = <button />,
|
||||
...buttonProps
|
||||
}: ButtonProps) => {
|
||||
const pagination = React.useContext(PaginationContext)
|
||||
const previous = () => {
|
||||
if (pagination.currentPage + 1 > 1)
|
||||
pagination.setCurrentPage(pagination.currentPage - 1)
|
||||
}
|
||||
|
||||
const disabled = pagination.currentPage === 0
|
||||
|
||||
return (
|
||||
<as.type
|
||||
{...buttonProps}
|
||||
{...as.props}
|
||||
className={clsx(className, as.props.className)}
|
||||
onClick={() => previous()}
|
||||
tabIndex={disabled ? '-1' : 0}
|
||||
disabled={disabled}
|
||||
data-testid={dataTestId}
|
||||
onKeyPress={(event: React.KeyboardEvent) => {
|
||||
event.preventDefault()
|
||||
if (event.key === 'Enter' && !disabled)
|
||||
previous()
|
||||
}}
|
||||
>
|
||||
{as.props.children ?? children}
|
||||
</as.type>
|
||||
)
|
||||
}
|
||||
|
||||
export const NextButton = ({
|
||||
className,
|
||||
children,
|
||||
dataTestId,
|
||||
as = <button />,
|
||||
...buttonProps
|
||||
}: ButtonProps) => {
|
||||
const pagination = React.useContext(PaginationContext)
|
||||
const next = () => {
|
||||
if (pagination.currentPage + 1 < pagination.pages.length)
|
||||
pagination.setCurrentPage(pagination.currentPage + 1)
|
||||
}
|
||||
|
||||
const disabled = pagination.currentPage === pagination.pages.length - 1
|
||||
|
||||
return (
|
||||
<as.type
|
||||
{...buttonProps}
|
||||
{...as.props}
|
||||
className={clsx(className, as.props.className)}
|
||||
onClick={() => next()}
|
||||
tabIndex={disabled ? '-1' : 0}
|
||||
disabled={disabled}
|
||||
data-testid={dataTestId}
|
||||
onKeyPress={(event: React.KeyboardEvent) => {
|
||||
event.preventDefault()
|
||||
if (event.key === 'Enter' && !disabled)
|
||||
next()
|
||||
}}
|
||||
>
|
||||
{as.props.children ?? children}
|
||||
</as.type>
|
||||
)
|
||||
}
|
||||
|
||||
type ITruncableElementProps = {
|
||||
prev?: boolean
|
||||
}
|
||||
|
||||
const TruncableElement = ({ prev }: ITruncableElementProps) => {
|
||||
const pagination: IPagination = React.useContext(PaginationContext)
|
||||
|
||||
const {
|
||||
isPreviousTruncable,
|
||||
isNextTruncable,
|
||||
truncableText,
|
||||
truncableClassName,
|
||||
} = pagination
|
||||
|
||||
return ((isPreviousTruncable && prev === true) || (isNextTruncable && !prev))
|
||||
? (
|
||||
<li className={truncableClassName || undefined}>{truncableText}</li>
|
||||
)
|
||||
: null
|
||||
}
|
||||
|
||||
export const PageButton = ({
|
||||
as = <a />,
|
||||
className,
|
||||
dataTestIdActive,
|
||||
dataTestIdInactive,
|
||||
activeClassName,
|
||||
inactiveClassName,
|
||||
renderExtraProps,
|
||||
}: PageButtonProps) => {
|
||||
const pagination: IPagination = React.useContext(PaginationContext)
|
||||
|
||||
const renderPageButton = (page: number) => (
|
||||
<li key={page}>
|
||||
<as.type
|
||||
data-testid={
|
||||
clsx({
|
||||
[`${dataTestIdActive}`]:
|
||||
dataTestIdActive && pagination.currentPage + 1 === page,
|
||||
[`${dataTestIdInactive}-${page}`]:
|
||||
dataTestIdActive && pagination.currentPage + 1 !== page,
|
||||
}) || undefined
|
||||
}
|
||||
tabIndex={0}
|
||||
onKeyPress={(event: React.KeyboardEvent) => {
|
||||
if (event.key === 'Enter')
|
||||
pagination.setCurrentPage(page - 1)
|
||||
}}
|
||||
onClick={() => pagination.setCurrentPage(page - 1)}
|
||||
className={clsx(
|
||||
className,
|
||||
pagination.currentPage + 1 === page
|
||||
? activeClassName
|
||||
: inactiveClassName,
|
||||
)}
|
||||
{...as.props}
|
||||
{...(renderExtraProps ? renderExtraProps(page) : {})}
|
||||
>
|
||||
{page}
|
||||
</as.type>
|
||||
</li>
|
||||
)
|
||||
|
||||
return (
|
||||
<>
|
||||
{pagination.previousPages.map(renderPageButton)}
|
||||
<TruncableElement prev />
|
||||
{pagination.middlePages.map(renderPageButton)}
|
||||
<TruncableElement />
|
||||
{pagination.nextPages.map(renderPageButton)}
|
||||
</>
|
||||
)
|
||||
}
|
||||
|
||||
export const Pagination = ({
|
||||
dataTestId,
|
||||
...paginationProps
|
||||
}: IPaginationProps & { dataTestId?: string }) => {
|
||||
const pagination = usePagination(paginationProps)
|
||||
|
||||
return (
|
||||
<PaginationContext.Provider value={pagination}>
|
||||
<div className={paginationProps.className} data-testid={dataTestId}>
|
||||
{paginationProps.children}
|
||||
</div>
|
||||
</PaginationContext.Provider>
|
||||
)
|
||||
}
|
||||
|
||||
Pagination.PrevButton = PrevButton
|
||||
Pagination.NextButton = NextButton
|
||||
Pagination.PageButton = PageButton
|
||||
@ -1,3 +0,0 @@
|
||||
.pagination li {
|
||||
list-style: none;
|
||||
}
|
||||
58
web/app/components/base/pagination/type.ts
Normal file
58
web/app/components/base/pagination/type.ts
Normal file
@ -0,0 +1,58 @@
|
||||
import type { ButtonHTMLAttributes } from 'react'
|
||||
|
||||
type IBasePaginationProps = {
|
||||
currentPage: number
|
||||
setCurrentPage: (page: number) => void
|
||||
truncableText?: string
|
||||
truncableClassName?: string
|
||||
}
|
||||
|
||||
type IPaginationProps = IBasePaginationProps & {
|
||||
totalPages: number
|
||||
edgePageCount: number
|
||||
middlePagesSiblingCount: number
|
||||
className?: string
|
||||
children?: React.ReactNode
|
||||
}
|
||||
|
||||
type IUsePagination = IBasePaginationProps & {
|
||||
pages: number[]
|
||||
hasPreviousPage: boolean
|
||||
hasNextPage: boolean
|
||||
previousPages: number[]
|
||||
isPreviousTruncable: boolean
|
||||
middlePages: number[]
|
||||
isNextTruncable: boolean
|
||||
nextPages: number[]
|
||||
}
|
||||
|
||||
type IPagination = IUsePagination & {
|
||||
setCurrentPage: (page: number) => void
|
||||
}
|
||||
|
||||
type ButtonProps = ButtonHTMLAttributes<HTMLButtonElement> & {
|
||||
as?: React.ReactElement
|
||||
children?: string | React.ReactNode
|
||||
className?: string
|
||||
dataTestId?: string
|
||||
}
|
||||
|
||||
type PageButtonProps = ButtonProps & {
|
||||
/**
|
||||
* Provide a custom ReactElement (e.g. Next/Link)
|
||||
*/
|
||||
as?: React.ReactElement
|
||||
activeClassName?: string
|
||||
inactiveClassName?: string
|
||||
dataTestIdActive?: string
|
||||
dataTestIdInactive?: string
|
||||
renderExtraProps?: (pageNum: number) => {}
|
||||
}
|
||||
|
||||
export type {
|
||||
IPaginationProps,
|
||||
IUsePagination,
|
||||
IPagination,
|
||||
ButtonProps,
|
||||
PageButtonProps,
|
||||
}
|
||||
@ -156,7 +156,8 @@ const StepTwo = ({
|
||||
const setSegmentIdentifier = useCallback((value: string) => {
|
||||
doSetSegmentIdentifier(value ? escape(value) : DEFAULT_SEGMENT_IDENTIFIER)
|
||||
}, [])
|
||||
const [max, setMax] = useState(4000) // default chunk length
|
||||
const [maxChunkLength, setMaxChunkLength] = useState(4000) // default chunk length
|
||||
const [limitMaxChunkLength, setLimitMaxChunkLength] = useState(4000)
|
||||
const [overlap, setOverlap] = useState(50)
|
||||
const [rules, setRules] = useState<PreProcessingRule[]>([])
|
||||
const [defaultConfig, setDefaultConfig] = useState<Rules>()
|
||||
@ -193,10 +194,11 @@ const StepTwo = ({
|
||||
pre_processing_rules: rules,
|
||||
segmentation: {
|
||||
separator: unescape(segmentIdentifier),
|
||||
max_tokens: max,
|
||||
max_tokens: maxChunkLength,
|
||||
chunk_overlap: overlap,
|
||||
},
|
||||
}
|
||||
// @ts-expect-error will be removed after api refactored.
|
||||
processRule.rules = ruleObj
|
||||
}
|
||||
return processRule
|
||||
@ -283,7 +285,7 @@ const StepTwo = ({
|
||||
const resetRules = () => {
|
||||
if (defaultConfig) {
|
||||
setSegmentIdentifier(defaultConfig.segmentation.separator)
|
||||
setMax(defaultConfig.segmentation.max_tokens)
|
||||
setMaxChunkLength(defaultConfig.segmentation.max_tokens)
|
||||
setOverlap(defaultConfig.segmentation.chunk_overlap!)
|
||||
setRules(defaultConfig.pre_processing_rules)
|
||||
}
|
||||
@ -291,7 +293,7 @@ const StepTwo = ({
|
||||
}
|
||||
|
||||
const updatePreview = () => {
|
||||
if (segmentationType === SegmentType.CUSTOM && max > 4000) {
|
||||
if (segmentationType === SegmentType.CUSTOM && maxChunkLength > 4000) {
|
||||
Toast.notify({ type: 'error', message: t('datasetCreation.stepTwo.maxLengthCheck') })
|
||||
return
|
||||
}
|
||||
@ -318,12 +320,12 @@ const StepTwo = ({
|
||||
)
|
||||
const getCreationParams = () => {
|
||||
let params
|
||||
if (segmentationType === SegmentType.CUSTOM && overlap > max) {
|
||||
if (segmentationType === SegmentType.CUSTOM && overlap > maxChunkLength) {
|
||||
Toast.notify({ type: 'error', message: t('datasetCreation.stepTwo.overlapCheck') })
|
||||
return
|
||||
}
|
||||
if (segmentationType === SegmentType.CUSTOM && max > 4000) {
|
||||
Toast.notify({ type: 'error', message: t('datasetCreation.stepTwo.maxLengthCheck') })
|
||||
if (segmentationType === SegmentType.CUSTOM && maxChunkLength > limitMaxChunkLength) {
|
||||
Toast.notify({ type: 'error', message: t('datasetCreation.stepTwo.maxLengthCheck', { limit: limitMaxChunkLength }) })
|
||||
return
|
||||
}
|
||||
if (isSetting) {
|
||||
@ -398,10 +400,11 @@ const StepTwo = ({
|
||||
onSuccess(data) {
|
||||
const separator = data.rules.segmentation.separator
|
||||
setSegmentIdentifier(separator)
|
||||
setMax(data.rules.segmentation.max_tokens)
|
||||
setMaxChunkLength(data.rules.segmentation.max_tokens)
|
||||
setOverlap(data.rules.segmentation.chunk_overlap!)
|
||||
setRules(data.rules.pre_processing_rules)
|
||||
setDefaultConfig(data.rules)
|
||||
setLimitMaxChunkLength(data.limits.indexing_max_segmentation_tokens_length)
|
||||
},
|
||||
onError(error) {
|
||||
Toast.notify({
|
||||
@ -418,8 +421,8 @@ const StepTwo = ({
|
||||
const max = rules.segmentation.max_tokens
|
||||
const overlap = rules.segmentation.chunk_overlap
|
||||
setSegmentIdentifier(separator)
|
||||
setMax(max)
|
||||
setOverlap(overlap as number)
|
||||
setMaxChunkLength(max)
|
||||
setOverlap(overlap!)
|
||||
setRules(rules.pre_processing_rules)
|
||||
setDefaultConfig(rules)
|
||||
}
|
||||
@ -427,6 +430,7 @@ const StepTwo = ({
|
||||
|
||||
const getDefaultMode = () => {
|
||||
if (documentDetail)
|
||||
// @ts-expect-error fix after api refactored
|
||||
setSegmentationType(documentDetail.dataset_process_rule.mode)
|
||||
}
|
||||
|
||||
@ -516,6 +520,7 @@ const StepTwo = ({
|
||||
getRulesFromDetail()
|
||||
getDefaultMode()
|
||||
}
|
||||
// eslint-disable-next-line react-hooks/exhaustive-deps
|
||||
}, [])
|
||||
|
||||
useEffect(() => {
|
||||
@ -577,8 +582,8 @@ const StepTwo = ({
|
||||
onChange={e => setSegmentIdentifier(e.target.value)}
|
||||
/>
|
||||
<MaxLengthInput
|
||||
value={max}
|
||||
onChange={setMax}
|
||||
value={maxChunkLength}
|
||||
onChange={setMaxChunkLength}
|
||||
/>
|
||||
<OverlapInput
|
||||
value={overlap}
|
||||
|
||||
@ -379,10 +379,107 @@ The text generation application offers non-session support and is ideal for tran
|
||||
|
||||
---
|
||||
|
||||
<Heading
|
||||
url='/text-to-audio'
|
||||
method='POST'
|
||||
title='Text to Audio'
|
||||
name='#audio'
|
||||
/>
|
||||
<Row>
|
||||
<Col>
|
||||
Text to speech.
|
||||
|
||||
### Request Body
|
||||
|
||||
<Properties>
|
||||
<Property name='message_id' type='str' key='text'>
|
||||
For text messages generated by Dify, simply pass the generated message-id directly. The backend will use the message-id to look up the corresponding content and synthesize the voice information directly. If both message_id and text are provided simultaneously, the message_id is given priority.
|
||||
</Property>
|
||||
<Property name='text' type='str' key='text'>
|
||||
Speech generated content。
|
||||
</Property>
|
||||
<Property name='user' type='string' key='user'>
|
||||
The user identifier, defined by the developer, must ensure uniqueness within the app.
|
||||
</Property>
|
||||
</Properties>
|
||||
</Col>
|
||||
<Col sticky>
|
||||
|
||||
<CodeGroup title="Request" tag="POST" label="/text-to-audio" targetCode={`curl -o text-to-audio.mp3 -X POST '${props.appDetail.api_base_url}/text-to-audio' \\\n--header 'Authorization: Bearer {api_key}' \\\n--header 'Content-Type: application/json' \\\n--data-raw '{\n "message_id": "5ad4cb98-f0c7-4085-b384-88c403be6290",\n "text": "Hello Dify",\n "user": "abc-123"\n}'`}>
|
||||
|
||||
```bash {{ title: 'cURL' }}
|
||||
curl -o text-to-audio.mp3 -X POST '${props.appDetail.api_base_url}/text-to-audio' \
|
||||
--header 'Authorization: Bearer {api_key}' \
|
||||
--header 'Content-Type: application/json' \
|
||||
--data-raw '{
|
||||
"message_id": "5ad4cb98-f0c7-4085-b384-88c403be6290",
|
||||
"text": "Hello Dify",
|
||||
"user": "abc-123"
|
||||
}'
|
||||
```
|
||||
|
||||
</CodeGroup>
|
||||
|
||||
<CodeGroup title="headers">
|
||||
```json {{ title: 'headers' }}
|
||||
{
|
||||
"Content-Type": "audio/wav"
|
||||
}
|
||||
```
|
||||
</CodeGroup>
|
||||
</Col>
|
||||
</Row>
|
||||
---
|
||||
|
||||
<Heading
|
||||
url='/info'
|
||||
method='GET'
|
||||
title='Get Application Basic Information'
|
||||
name='#info'
|
||||
/>
|
||||
<Row>
|
||||
<Col>
|
||||
Used to get basic information about this application
|
||||
### Query
|
||||
<Properties>
|
||||
|
||||
<Property name='user' type='string' key='user'>
|
||||
User identifier, defined by the developer's rules, must be unique within the application.
|
||||
</Property>
|
||||
</Properties>
|
||||
### Response
|
||||
- `name` (string) application name
|
||||
- `description` (string) application description
|
||||
- `tags` (array[string]) application tags
|
||||
</Col>
|
||||
<Col>
|
||||
<CodeGroup title="Request" tag="GET" label="/info" targetCode={`curl -X GET '${props.appDetail.api_base_url}/info?user=abc-123' \\\n-H 'Authorization: Bearer {api_key}'`}>
|
||||
```bash {{ title: 'cURL' }}
|
||||
curl -X GET '${props.appDetail.api_base_url}/info?user=abc-123' \
|
||||
-H 'Authorization: Bearer {api_key}'
|
||||
```
|
||||
</CodeGroup>
|
||||
<CodeGroup title="Response">
|
||||
```json {{ title: 'Response' }}
|
||||
{
|
||||
"name": "My App",
|
||||
"description": "This is my app.",
|
||||
"tags": [
|
||||
"tag1",
|
||||
"tag2"
|
||||
]
|
||||
}
|
||||
```
|
||||
</CodeGroup>
|
||||
</Col>
|
||||
</Row>
|
||||
|
||||
---
|
||||
|
||||
<Heading
|
||||
url='/parameters'
|
||||
method='GET'
|
||||
title='Get Application Information'
|
||||
title='Get Application Parameters Information'
|
||||
name='#parameters'
|
||||
/>
|
||||
<Row>
|
||||
@ -497,56 +594,3 @@ The text generation application offers non-session support and is ideal for tran
|
||||
</CodeGroup>
|
||||
</Col>
|
||||
</Row>
|
||||
|
||||
---
|
||||
|
||||
<Heading
|
||||
url='/text-to-audio'
|
||||
method='POST'
|
||||
title='Text to Audio'
|
||||
name='#audio'
|
||||
/>
|
||||
<Row>
|
||||
<Col>
|
||||
Text to speech.
|
||||
|
||||
### Request Body
|
||||
|
||||
<Properties>
|
||||
<Property name='message_id' type='str' key='text'>
|
||||
For text messages generated by Dify, simply pass the generated message-id directly. The backend will use the message-id to look up the corresponding content and synthesize the voice information directly. If both message_id and text are provided simultaneously, the message_id is given priority.
|
||||
</Property>
|
||||
<Property name='text' type='str' key='text'>
|
||||
Speech generated content。
|
||||
</Property>
|
||||
<Property name='user' type='string' key='user'>
|
||||
The user identifier, defined by the developer, must ensure uniqueness within the app.
|
||||
</Property>
|
||||
</Properties>
|
||||
</Col>
|
||||
<Col sticky>
|
||||
|
||||
<CodeGroup title="Request" tag="POST" label="/text-to-audio" targetCode={`curl -o text-to-audio.mp3 -X POST '${props.appDetail.api_base_url}/text-to-audio' \\\n--header 'Authorization: Bearer {api_key}' \\\n--header 'Content-Type: application/json' \\\n--data-raw '{\n "message_id": "5ad4cb98-f0c7-4085-b384-88c403be6290",\n "text": "Hello Dify",\n "user": "abc-123"\n}'`}>
|
||||
|
||||
```bash {{ title: 'cURL' }}
|
||||
curl -o text-to-audio.mp3 -X POST '${props.appDetail.api_base_url}/text-to-audio' \
|
||||
--header 'Authorization: Bearer {api_key}' \
|
||||
--header 'Content-Type: application/json' \
|
||||
--data-raw '{
|
||||
"message_id": "5ad4cb98-f0c7-4085-b384-88c403be6290",
|
||||
"text": "Hello Dify",
|
||||
"user": "abc-123"
|
||||
}'
|
||||
```
|
||||
|
||||
</CodeGroup>
|
||||
|
||||
<CodeGroup title="headers">
|
||||
```json {{ title: 'headers' }}
|
||||
{
|
||||
"Content-Type": "audio/wav"
|
||||
}
|
||||
```
|
||||
</CodeGroup>
|
||||
</Col>
|
||||
</Row>
|
||||
|
||||
@ -375,13 +375,109 @@ import { Row, Col, Properties, Property, Heading, SubProperty, Paragraph } from
|
||||
</CodeGroup>
|
||||
</Col>
|
||||
</Row>
|
||||
---
|
||||
|
||||
<Heading
|
||||
url='/text-to-audio'
|
||||
method='POST'
|
||||
title='テキストから音声'
|
||||
name='#audio'
|
||||
/>
|
||||
<Row>
|
||||
<Col>
|
||||
テキストを音声に変換します。
|
||||
|
||||
### リクエストボディ
|
||||
|
||||
<Properties>
|
||||
<Property name='message_id' type='str' key='text'>
|
||||
Difyが生成したテキストメッセージの場合、生成されたmessage-idを直接渡すだけです。バックエンドはmessage-idを使用して対応するコンテンツを検索し、音声情報を直接合成します。message_idとtextの両方が同時に提供された場合、message_idが優先されます。
|
||||
</Property>
|
||||
<Property name='text' type='str' key='text'>
|
||||
音声生成コンテンツ。
|
||||
</Property>
|
||||
<Property name='user' type='string' key='user'>
|
||||
開発者が定義したユーザー識別子。アプリ内で一意性を確保する必要があります。
|
||||
</Property>
|
||||
</Properties>
|
||||
</Col>
|
||||
<Col sticky>
|
||||
|
||||
<CodeGroup title="Request" tag="POST" label="/text-to-audio" targetCode={`curl -o text-to-audio.mp3 -X POST '${props.appDetail.api_base_url}/text-to-audio' \\\n--header 'Authorization: Bearer {api_key}' \\\n--header 'Content-Type: application/json' \\\n--data-raw '{\n "message_id": "5ad4cb98-f0c7-4085-b384-88c403be6290",\n "text": "Hello Dify",\n "user": "abc-123"\n}'`}>
|
||||
|
||||
```bash {{ title: 'cURL' }}
|
||||
curl -o text-to-audio.mp3 -X POST '${props.appDetail.api_base_url}/text-to-audio' \
|
||||
--header 'Authorization: Bearer {api_key}' \
|
||||
--header 'Content-Type: application/json' \
|
||||
--data-raw '{
|
||||
"message_id": "5ad4cb98-f0c7-4085-b384-88c403be6290",
|
||||
"text": "Hello Dify",
|
||||
"user": "abc-123"
|
||||
}'
|
||||
```
|
||||
|
||||
</CodeGroup>
|
||||
|
||||
<CodeGroup title="headers">
|
||||
```json {{ title: 'headers' }}
|
||||
{
|
||||
"Content-Type": "audio/wav"
|
||||
}
|
||||
```
|
||||
</CodeGroup>
|
||||
</Col>
|
||||
</Row>
|
||||
---
|
||||
|
||||
<Heading
|
||||
url='/info'
|
||||
method='GET'
|
||||
title='アプリケーションの基本情報を取得'
|
||||
name='#info'
|
||||
/>
|
||||
<Row>
|
||||
<Col>
|
||||
このアプリケーションの基本情報を取得するために使用されます
|
||||
### Query
|
||||
<Properties>
|
||||
|
||||
<Property name='user' type='string' key='user'>
|
||||
ユーザー識別子、開発者のルールによって定義され、アプリケーション内で一意でなければなりません。
|
||||
</Property>
|
||||
</Properties>
|
||||
### Response
|
||||
- `name` (string) アプリケーションの名前
|
||||
- `description` (string) アプリケーションの説明
|
||||
- `tags` (array[string]) アプリケーションのタグ
|
||||
</Col>
|
||||
<Col>
|
||||
<CodeGroup title="Request" tag="GET" label="/info" targetCode={`curl -X GET '${props.appDetail.api_base_url}/info?user=abc-123' \\\n-H 'Authorization: Bearer {api_key}'`}>
|
||||
```bash {{ title: 'cURL' }}
|
||||
curl -X GET '${props.appDetail.api_base_url}/info?user=abc-123' \
|
||||
-H 'Authorization: Bearer {api_key}'
|
||||
```
|
||||
</CodeGroup>
|
||||
<CodeGroup title="Response">
|
||||
```json {{ title: 'Response' }}
|
||||
{
|
||||
"name": "My App",
|
||||
"description": "This is my app.",
|
||||
"tags": [
|
||||
"tag1",
|
||||
"tag2"
|
||||
]
|
||||
}
|
||||
```
|
||||
</CodeGroup>
|
||||
</Col>
|
||||
</Row>
|
||||
|
||||
---
|
||||
|
||||
<Heading
|
||||
url='/parameters'
|
||||
method='GET'
|
||||
title='アプリケーション情報の取得'
|
||||
title='アプリケーションのパラメータ情報を取得'
|
||||
name='#parameters'
|
||||
/>
|
||||
<Row>
|
||||
@ -496,56 +592,3 @@ import { Row, Col, Properties, Property, Heading, SubProperty, Paragraph } from
|
||||
</CodeGroup>
|
||||
</Col>
|
||||
</Row>
|
||||
|
||||
---
|
||||
|
||||
<Heading
|
||||
url='/text-to-audio'
|
||||
method='POST'
|
||||
title='テキストから音声'
|
||||
name='#audio'
|
||||
/>
|
||||
<Row>
|
||||
<Col>
|
||||
テキストを音声に変換します。
|
||||
|
||||
### リクエストボディ
|
||||
|
||||
<Properties>
|
||||
<Property name='message_id' type='str' key='text'>
|
||||
Difyが生成したテキストメッセージの場合、生成されたmessage-idを直接渡すだけです。バックエンドはmessage-idを使用して対応するコンテンツを検索し、音声情報を直接合成します。message_idとtextの両方が同時に提供された場合、message_idが優先されます。
|
||||
</Property>
|
||||
<Property name='text' type='str' key='text'>
|
||||
音声生成コンテンツ。
|
||||
</Property>
|
||||
<Property name='user' type='string' key='user'>
|
||||
開発者が定義したユーザー識別子。アプリ内で一意性を確保する必要があります。
|
||||
</Property>
|
||||
</Properties>
|
||||
</Col>
|
||||
<Col sticky>
|
||||
|
||||
<CodeGroup title="Request" tag="POST" label="/text-to-audio" targetCode={`curl -o text-to-audio.mp3 -X POST '${props.appDetail.api_base_url}/text-to-audio' \\\n--header 'Authorization: Bearer {api_key}' \\\n--header 'Content-Type: application/json' \\\n--data-raw '{\n "message_id": "5ad4cb98-f0c7-4085-b384-88c403be6290",\n "text": "Hello Dify",\n "user": "abc-123"\n}'`}>
|
||||
|
||||
```bash {{ title: 'cURL' }}
|
||||
curl -o text-to-audio.mp3 -X POST '${props.appDetail.api_base_url}/text-to-audio' \
|
||||
--header 'Authorization: Bearer {api_key}' \
|
||||
--header 'Content-Type: application/json' \
|
||||
--data-raw '{
|
||||
"message_id": "5ad4cb98-f0c7-4085-b384-88c403be6290",
|
||||
"text": "Hello Dify",
|
||||
"user": "abc-123"
|
||||
}'
|
||||
```
|
||||
|
||||
</CodeGroup>
|
||||
|
||||
<CodeGroup title="headers">
|
||||
```json {{ title: 'headers' }}
|
||||
{
|
||||
"Content-Type": "audio/wav"
|
||||
}
|
||||
```
|
||||
</CodeGroup>
|
||||
</Col>
|
||||
</Row>
|
||||
|
||||
@ -353,10 +353,108 @@ import { Row, Col, Properties, Property, Heading, SubProperty } from '../md.tsx'
|
||||
|
||||
---
|
||||
|
||||
<Heading
|
||||
url='/text-to-audio'
|
||||
method='POST'
|
||||
title='文字转语音'
|
||||
name='#audio'
|
||||
/>
|
||||
<Row>
|
||||
<Col>
|
||||
文字转语音。
|
||||
|
||||
### Request Body
|
||||
|
||||
<Properties>
|
||||
<Property name='message_id' type='str' key='text'>
|
||||
Dify 生成的文本消息,那么直接传递生成的message-id 即可,后台会通过 message_id 查找相应的内容直接合成语音信息。如果同时传 message_id 和 text,优先使用 message_id。
|
||||
</Property>
|
||||
<Property name='text' type='str' key='text'>
|
||||
语音生成内容。如果没有传 message-id的话,则会使用这个字段的内容
|
||||
</Property>
|
||||
<Property name='user' type='string' key='user'>
|
||||
用户标识,由开发者定义规则,需保证用户标识在应用内唯一。
|
||||
</Property>
|
||||
</Properties>
|
||||
</Col>
|
||||
<Col sticky>
|
||||
|
||||
<CodeGroup title="Request" tag="POST" label="/text-to-audio" targetCode={`curl -o text-to-audio.mp3 -X POST '${props.appDetail.api_base_url}/text-to-audio' \\\n--header 'Authorization: Bearer {api_key}' \\\n--header 'Content-Type: application/json' \\\n--data-raw '{\n "message_id": "5ad4cb98-f0c7-4085-b384-88c403be6290",\n "text": "你好Dify",\n "user": "abc-123"\n}'`}>
|
||||
|
||||
```bash {{ title: 'cURL' }}
|
||||
curl -o text-to-audio.mp3 -X POST '${props.appDetail.api_base_url}/text-to-audio' \
|
||||
--header 'Authorization: Bearer {api_key}' \
|
||||
--header 'Content-Type: application/json' \
|
||||
--data-raw '{
|
||||
"message_id": "5ad4cb98-f0c7-4085-b384-88c403be6290",
|
||||
"text": "你好Dify",
|
||||
"user": "abc-123",
|
||||
"streaming": false
|
||||
}'
|
||||
```
|
||||
|
||||
</CodeGroup>
|
||||
|
||||
<CodeGroup title="headers">
|
||||
```json {{ title: 'headers' }}
|
||||
{
|
||||
"Content-Type": "audio/wav"
|
||||
}
|
||||
```
|
||||
</CodeGroup>
|
||||
</Col>
|
||||
</Row>
|
||||
---
|
||||
|
||||
<Heading
|
||||
url='/info'
|
||||
method='GET'
|
||||
title='获取应用基本信息'
|
||||
name='#info'
|
||||
/>
|
||||
<Row>
|
||||
<Col>
|
||||
用于获取应用的基本信息
|
||||
### Query
|
||||
<Properties>
|
||||
|
||||
<Property name='user' type='string' key='user'>
|
||||
用户标识,由开发者定义规则,需保证用户标识在应用内唯一。
|
||||
</Property>
|
||||
</Properties>
|
||||
### Response
|
||||
- `name` (string) 应用名称
|
||||
- `description` (string) 应用描述
|
||||
- `tags` (array[string]) 应用标签
|
||||
</Col>
|
||||
<Col>
|
||||
<CodeGroup title="Request" tag="GET" label="/info" targetCode={`curl -X GET '${props.appDetail.api_base_url}/info?user=abc-123' \\\n-H 'Authorization: Bearer {api_key}'`}>
|
||||
```bash {{ title: 'cURL' }}
|
||||
curl -X GET '${props.appDetail.api_base_url}/info?user=abc-123' \
|
||||
-H 'Authorization: Bearer {api_key}'
|
||||
```
|
||||
</CodeGroup>
|
||||
<CodeGroup title="Response">
|
||||
```json {{ title: 'Response' }}
|
||||
{
|
||||
"name": "My App",
|
||||
"description": "This is my app.",
|
||||
"tags": [
|
||||
"tag1",
|
||||
"tag2"
|
||||
]
|
||||
}
|
||||
```
|
||||
</CodeGroup>
|
||||
</Col>
|
||||
</Row>
|
||||
|
||||
---
|
||||
|
||||
<Heading
|
||||
url='/parameters'
|
||||
method='GET'
|
||||
title='获取应用配置信息'
|
||||
title='获取应用参数'
|
||||
name='#parameters'
|
||||
/>
|
||||
<Row>
|
||||
@ -461,57 +559,3 @@ import { Row, Col, Properties, Property, Heading, SubProperty } from '../md.tsx'
|
||||
</CodeGroup>
|
||||
</Col>
|
||||
</Row>
|
||||
|
||||
---
|
||||
|
||||
<Heading
|
||||
url='/text-to-audio'
|
||||
method='POST'
|
||||
title='文字转语音'
|
||||
name='#audio'
|
||||
/>
|
||||
<Row>
|
||||
<Col>
|
||||
文字转语音。
|
||||
|
||||
### Request Body
|
||||
|
||||
<Properties>
|
||||
<Property name='message_id' type='str' key='text'>
|
||||
Dify 生成的文本消息,那么直接传递生成的message-id 即可,后台会通过 message_id 查找相应的内容直接合成语音信息。如果同时传 message_id 和 text,优先使用 message_id。
|
||||
</Property>
|
||||
<Property name='text' type='str' key='text'>
|
||||
语音生成内容。如果没有传 message-id的话,则会使用这个字段的内容
|
||||
</Property>
|
||||
<Property name='user' type='string' key='user'>
|
||||
用户标识,由开发者定义规则,需保证用户标识在应用内唯一。
|
||||
</Property>
|
||||
</Properties>
|
||||
</Col>
|
||||
<Col sticky>
|
||||
|
||||
<CodeGroup title="Request" tag="POST" label="/text-to-audio" targetCode={`curl -o text-to-audio.mp3 -X POST '${props.appDetail.api_base_url}/text-to-audio' \\\n--header 'Authorization: Bearer {api_key}' \\\n--header 'Content-Type: application/json' \\\n--data-raw '{\n "message_id": "5ad4cb98-f0c7-4085-b384-88c403be6290",\n "text": "你好Dify",\n "user": "abc-123"\n}'`}>
|
||||
|
||||
```bash {{ title: 'cURL' }}
|
||||
curl -o text-to-audio.mp3 -X POST '${props.appDetail.api_base_url}/text-to-audio' \
|
||||
--header 'Authorization: Bearer {api_key}' \
|
||||
--header 'Content-Type: application/json' \
|
||||
--data-raw '{
|
||||
"message_id": "5ad4cb98-f0c7-4085-b384-88c403be6290",
|
||||
"text": "你好Dify",
|
||||
"user": "abc-123",
|
||||
"streaming": false
|
||||
}'
|
||||
```
|
||||
|
||||
</CodeGroup>
|
||||
|
||||
<CodeGroup title="headers">
|
||||
```json {{ title: 'headers' }}
|
||||
{
|
||||
"Content-Type": "audio/wav"
|
||||
}
|
||||
```
|
||||
</CodeGroup>
|
||||
</Col>
|
||||
</Row>
|
||||
|
||||
@ -161,7 +161,7 @@ Chat applications support session persistence, allowing previous chat history to
|
||||
- `title` (string) name of node
|
||||
- `index` (int) Execution sequence number, used to display Tracing Node sequence
|
||||
- `predecessor_node_id` (string) optional Prefix node ID, used for canvas display execution path
|
||||
- `inputs` (array[object]) Contents of all preceding node variables used in the node
|
||||
- `inputs` (object) Contents of all preceding node variables used in the node
|
||||
- `created_at` (timestamp) timestamp of start, e.g., 1705395332
|
||||
- `event: node_finished` node execution ends, success or failure in different states in the same event
|
||||
- `task_id` (string) Task ID, used for request tracking and the below Stop Generate API
|
||||
@ -174,7 +174,7 @@ Chat applications support session persistence, allowing previous chat history to
|
||||
- `title` (string) name of node
|
||||
- `index` (int) Execution sequence number, used to display Tracing Node sequence
|
||||
- `predecessor_node_id` (string) optional Prefix node ID, used for canvas display execution path
|
||||
- `inputs` (array[object]) Contents of all preceding node variables used in the node
|
||||
- `inputs` (object) Contents of all preceding node variables used in the node
|
||||
- `process_data` (json) Optional node process data
|
||||
- `outputs` (json) Optional content of output
|
||||
- `status` (string) status of execution, `running` / `succeeded` / `failed` / `stopped`
|
||||
@ -564,7 +564,7 @@ Chat applications support session persistence, allowing previous chat history to
|
||||
- `data` (array[object]) Message list
|
||||
- `id` (string) Message ID
|
||||
- `conversation_id` (string) Conversation ID
|
||||
- `inputs` (array[object]) User input parameters.
|
||||
- `inputs` (object) User input parameters.
|
||||
- `query` (string) User input / question content.
|
||||
- `message_files` (array[object]) Message files
|
||||
- `id` (string) ID
|
||||
@ -648,16 +648,13 @@ Chat applications support session persistence, allowing previous chat history to
|
||||
Should be uniquely defined by the developer within the application.
|
||||
</Property>
|
||||
<Property name='last_id' type='string' key='last_id'>
|
||||
The ID of the last record on the current page, default is null.
|
||||
(Optional) The ID of the last record on the current page, default is null.
|
||||
</Property>
|
||||
<Property name='limit' type='int' key='limit'>
|
||||
How many records to return in one request, default is the most recent 20 entries.
|
||||
</Property>
|
||||
<Property name='pinned' type='bool' key='pinned'>
|
||||
Return only pinned conversations as `true`, only non-pinned as `false`
|
||||
(Optional) How many records to return in one request, default is the most recent 20 entries. Maximum 100, minimum 1.
|
||||
</Property>
|
||||
<Property name='sort_by' type='string' key='sort_by'>
|
||||
Sorting Field (Optional), Default: -updated_at (sorted in descending order by update time)
|
||||
(Optional) Sorting Field, Default: -updated_at (sorted in descending order by update time)
|
||||
- Available Values: created_at, -created_at, updated_at, -updated_at
|
||||
- The symbol before the field represents the order or reverse, "-" represents reverse order.
|
||||
</Property>
|
||||
@ -667,9 +664,11 @@ Chat applications support session persistence, allowing previous chat history to
|
||||
- `data` (array[object]) List of conversations
|
||||
- `id` (string) Conversation ID
|
||||
- `name` (string) Conversation name, by default, is generated by LLM.
|
||||
- `inputs` (array[object]) User input parameters.
|
||||
- `inputs` (object) User input parameters.
|
||||
- `status` (string) Conversation status
|
||||
- `introduction` (string) Introduction
|
||||
- `created_at` (timestamp) Creation timestamp, e.g., 1705395332
|
||||
- `updated_at` (timestamp) Update timestamp, e.g., 1705395332
|
||||
- `has_more` (bool)
|
||||
- `limit` (int) Number of entries returned, if input exceeds system limit, system limit number is returned
|
||||
|
||||
@ -699,7 +698,8 @@ Chat applications support session persistence, allowing previous chat history to
|
||||
"myName": "Lucy"
|
||||
},
|
||||
"status": "normal",
|
||||
"created_at": 1679667915
|
||||
"created_at": 1679667915,
|
||||
"updated_at": 1679667915
|
||||
},
|
||||
{
|
||||
"id": "hSIhXBhNe8X1d8Et"
|
||||
@ -781,10 +781,10 @@ Chat applications support session persistence, allowing previous chat history to
|
||||
|
||||
<Properties>
|
||||
<Property name='name' type='string' key='name'>
|
||||
The name of the conversation. This parameter can be omitted if `auto_generate` is set to `true`.
|
||||
(Optional) The name of the conversation. This parameter can be omitted if `auto_generate` is set to `true`.
|
||||
</Property>
|
||||
<Property name='auto_generate' type='bool' key='auto_generate'>
|
||||
Automatically generate the title, default is `false`
|
||||
(Optional) Automatically generate the title, default is `false`
|
||||
</Property>
|
||||
<Property name='user' type='string' key='user'>
|
||||
The user identifier, defined by the developer, must ensure uniqueness within the application.
|
||||
@ -794,13 +794,15 @@ Chat applications support session persistence, allowing previous chat history to
|
||||
### Response
|
||||
- `id` (string) Conversation ID
|
||||
- `name` (string) Conversation name
|
||||
- `inputs` array[object] User input parameters.
|
||||
- `inputs` (object) User input parameters
|
||||
- `status` (string) Conversation status
|
||||
- `introduction` (string) Introduction
|
||||
- `created_at` (timestamp) Creation timestamp, e.g., 1705395332
|
||||
- `updated_at` (timestamp) Update timestamp, e.g., 1705395332
|
||||
</Col>
|
||||
<Col sticky>
|
||||
|
||||
<CodeGroup title="Request" tag="POST" label="/conversations/:conversation_id/name" targetCode={`curl -X POST '${props.appDetail.api_base_url}/conversations/:conversation_id/name' \\\n--header 'Authorization: Bearer {api_key}' \\\n--header 'Content-Type: application/json' \\\n--data-raw '{ \n "name": "", \n "user": "abc-123"\n}'`}>
|
||||
<CodeGroup title="Request" tag="POST" label="/conversations/:conversation_id/name" targetCode={`curl -X POST '${props.appDetail.api_base_url}/conversations/:conversation_id/name' \\\n--header 'Authorization: Bearer {api_key}' \\\n--header 'Content-Type: application/json' \\\n--data-raw '{ \n "name": "", \n "auto_generate": true, \n "user": "abc-123"\n}'`}>
|
||||
|
||||
```bash {{ title: 'cURL' }}
|
||||
curl -X POST '${props.appDetail.api_base_url}/conversations/{conversation_id}/name' \
|
||||
@ -808,6 +810,7 @@ Chat applications support session persistence, allowing previous chat history to
|
||||
--header 'Authorization: Bearer {api_key}' \
|
||||
--data-raw '{
|
||||
"name": "",
|
||||
"auto_generate": true,
|
||||
"user": "abc-123"
|
||||
}'
|
||||
```
|
||||
@ -820,8 +823,10 @@ Chat applications support session persistence, allowing previous chat history to
|
||||
"id": "cd78daf6-f9e4-4463-9ff2-54257230a0ce",
|
||||
"name": "Chat vs AI",
|
||||
"inputs": {},
|
||||
"status": "normal",
|
||||
"introduction": "",
|
||||
"created_at": 1705569238
|
||||
"created_at": 1705569238,
|
||||
"updated_at": 1705569238
|
||||
}
|
||||
```
|
||||
</CodeGroup>
|
||||
@ -931,13 +936,57 @@ Chat applications support session persistence, allowing previous chat history to
|
||||
</CodeGroup>
|
||||
</Col>
|
||||
</Row>
|
||||
---
|
||||
|
||||
<Heading
|
||||
url='/info'
|
||||
method='GET'
|
||||
title='Get Application Basic Information'
|
||||
name='#info'
|
||||
/>
|
||||
<Row>
|
||||
<Col>
|
||||
Used to get basic information about this application
|
||||
### Query
|
||||
<Properties>
|
||||
|
||||
<Property name='user' type='string' key='user'>
|
||||
User identifier, defined by the developer's rules, must be unique within the application.
|
||||
</Property>
|
||||
</Properties>
|
||||
### Response
|
||||
- `name` (string) application name
|
||||
- `description` (string) application description
|
||||
- `tags` (array[string]) application tags
|
||||
</Col>
|
||||
<Col>
|
||||
<CodeGroup title="Request" tag="GET" label="/info" targetCode={`curl -X GET '${props.appDetail.api_base_url}/info?user=abc-123' \\\n-H 'Authorization: Bearer {api_key}'`}>
|
||||
```bash {{ title: 'cURL' }}
|
||||
curl -X GET '${props.appDetail.api_base_url}/info?user=abc-123' \
|
||||
-H 'Authorization: Bearer {api_key}'
|
||||
```
|
||||
</CodeGroup>
|
||||
<CodeGroup title="Response">
|
||||
```json {{ title: 'Response' }}
|
||||
{
|
||||
"name": "My App",
|
||||
"description": "This is my app.",
|
||||
"tags": [
|
||||
"tag1",
|
||||
"tag2"
|
||||
]
|
||||
}
|
||||
```
|
||||
</CodeGroup>
|
||||
</Col>
|
||||
</Row>
|
||||
|
||||
---
|
||||
|
||||
<Heading
|
||||
url='/parameters'
|
||||
method='GET'
|
||||
title='Get Application Information'
|
||||
title='Get Application Parameters Information'
|
||||
name='#parameters'
|
||||
/>
|
||||
<Row>
|
||||
@ -1091,14 +1140,14 @@ Chat applications support session persistence, allowing previous chat history to
|
||||
<CodeGroup title="Response">
|
||||
```json {{ title: 'Response' }}
|
||||
{
|
||||
"tool_icons": {
|
||||
"tool_icons": {
|
||||
"dalle2": "https://cloud.dify.ai/console/api/workspaces/current/tool-provider/builtin/dalle/icon",
|
||||
"api_tool": {
|
||||
"background": "#252525",
|
||||
"content": "\ud83d\ude01"
|
||||
"background": "#252525",
|
||||
"content": "\ud83d\ude01"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
</CodeGroup>
|
||||
</Col>
|
||||
|
||||
@ -161,7 +161,7 @@ import { Row, Col, Properties, Property, Heading, SubProperty, Paragraph } from
|
||||
- `title` (string) ノードの名前
|
||||
- `index` (int) 実行シーケンス番号、トレースノードシーケンスを表示するために使用
|
||||
- `predecessor_node_id` (string) オプションのプレフィックスノードID、キャンバス表示実行パスに使用
|
||||
- `inputs` (array[object]) ノードで使用されるすべての前のノード変数の内容
|
||||
- `inputs` (object) ノードで使用されるすべての前のノード変数の内容
|
||||
- `created_at` (timestamp) 開始のタイムスタンプ、例:1705395332
|
||||
- `event: node_finished` ノード実行が終了、成功または失敗は同じイベント内で異なる状態で示されます
|
||||
- `task_id` (string) タスクID、リクエスト追跡と以下のStop Generate APIに使用
|
||||
@ -174,7 +174,7 @@ import { Row, Col, Properties, Property, Heading, SubProperty, Paragraph } from
|
||||
- `title` (string) ノードの名前
|
||||
- `index` (int) 実行シーケンス番号、トレースノードシーケンスを表示するために使用
|
||||
- `predecessor_node_id` (string) オプションのプレフィックスノードID、キャンバス表示実行パスに使用
|
||||
- `inputs` (array[object]) ノードで使用されるすべての前のノード変数の内容
|
||||
- `inputs` (object) ノードで使用されるすべての前のノード変数の内容
|
||||
- `process_data` (json) オプションのノードプロセスデータ
|
||||
- `outputs` (json) オプションの出力内容
|
||||
- `status` (string) 実行の状態、`running` / `succeeded` / `failed` / `stopped`
|
||||
@ -564,7 +564,7 @@ import { Row, Col, Properties, Property, Heading, SubProperty, Paragraph } from
|
||||
- `data` (array[object]) メッセージリスト
|
||||
- `id` (string) メッセージID
|
||||
- `conversation_id` (string) 会話ID
|
||||
- `inputs` (array[object]) ユーザー入力パラメータ。
|
||||
- `inputs` (object) ユーザー入力パラメータ。
|
||||
- `query` (string) ユーザー入力/質問内容。
|
||||
- `message_files` (array[object]) メッセージファイル
|
||||
- `id` (string) ID
|
||||
@ -648,16 +648,13 @@ import { Row, Col, Properties, Property, Heading, SubProperty, Paragraph } from
|
||||
アプリケーション内で開発者によって一意に定義されるべきです。
|
||||
</Property>
|
||||
<Property name='last_id' type='string' key='last_id'>
|
||||
現在のページの最後の記録のID、デフォルトはnullです。
|
||||
(Optional)現在のページの最後の記録のID、デフォルトはnullです。
|
||||
</Property>
|
||||
<Property name='limit' type='int' key='limit'>
|
||||
1回のリクエストで返す記録の数、デフォルトは最新の20件です。
|
||||
</Property>
|
||||
<Property name='pinned' type='bool' key='pinned'>
|
||||
ピン留めされた会話のみを`true`として返し、非ピン留めを`false`として返します
|
||||
(Optional)1回のリクエストで返す記録の数、デフォルトは最新の20件です。最大100、最小1。
|
||||
</Property>
|
||||
<Property name='sort_by' type='string' key='sort_by'>
|
||||
ソートフィールド(オプション)、デフォルト:-updated_at(更新時間で降順にソート)
|
||||
(Optional)ソートフィールド、デフォルト:-updated_at(更新時間で降順にソート)
|
||||
- 利用可能な値:created_at, -created_at, updated_at, -updated_at
|
||||
- フィールドの前の記号は順序または逆順を表し、"-"は逆順を表します。
|
||||
</Property>
|
||||
@ -667,9 +664,10 @@ import { Row, Col, Properties, Property, Heading, SubProperty, Paragraph } from
|
||||
- `data` (array[object]) 会話のリスト
|
||||
- `id` (string) 会話ID
|
||||
- `name` (string) 会話名、デフォルトではLLMによって生成されます。
|
||||
- `inputs` (array[object]) ユーザー入力パラメータ。
|
||||
- `inputs` (object) ユーザー入力パラメータ。
|
||||
- `introduction` (string) 紹介
|
||||
- `created_at` (timestamp) 作成タイムスタンプ、例:1705395332
|
||||
- `updated_at` (timestamp) 更新タイムスタンプ、例:1705395332
|
||||
- `has_more` (bool)
|
||||
- `limit` (int) 返されたエントリ数、入力がシステム制限を超える場合、システム制限数が返されます
|
||||
|
||||
@ -699,7 +697,8 @@ import { Row, Col, Properties, Property, Heading, SubProperty, Paragraph } from
|
||||
"myName": "Lucy"
|
||||
},
|
||||
"status": "normal",
|
||||
"created_at": 1679667915
|
||||
"created_at": 1679667915,
|
||||
"updated_at": 1679667915
|
||||
},
|
||||
{
|
||||
"id": "hSIhXBhNe8X1d8Et"
|
||||
@ -781,10 +780,10 @@ import { Row, Col, Properties, Property, Heading, SubProperty, Paragraph } from
|
||||
|
||||
<Properties>
|
||||
<Property name='name' type='string' key='name'>
|
||||
会話の名前。`auto_generate`が`true`に設定されている場合、このパラメータは省略できます。
|
||||
(Optional)会話の名前。`auto_generate`が`true`に設定されている場合、このパラメータは省略できます。
|
||||
</Property>
|
||||
<Property name='auto_generate' type='bool' key='auto_generate'>
|
||||
タイトルを自動生成、デフォルトは`false`
|
||||
(Optional)タイトルを自動生成、デフォルトは`false`
|
||||
</Property>
|
||||
<Property name='user' type='string' key='user'>
|
||||
ユーザー識別子、開発者によって定義され、アプリケーション内で一意であることを保証しなければなりません。
|
||||
@ -794,13 +793,15 @@ import { Row, Col, Properties, Property, Heading, SubProperty, Paragraph } from
|
||||
### 応答
|
||||
- `id` (string) 会話ID
|
||||
- `name` (string) 会話名
|
||||
- `inputs` array[object] ユーザー入力パラメータ。
|
||||
- `inputs` (object) ユーザー入力パラメータ
|
||||
- `status` (string) 会話状態
|
||||
- `introduction` (string) 紹介
|
||||
- `created_at` (timestamp) 作成タイムスタンプ、例:1705395332
|
||||
- `updated_at` (timestamp) 更新タイムスタンプ、例:1705395332
|
||||
</Col>
|
||||
<Col sticky>
|
||||
|
||||
<CodeGroup title="リクエスト" tag="POST" label="/conversations/:conversation_id/name" targetCode={`curl -X POST '${props.appDetail.api_base_url}/conversations/:conversation_id/name' \\\n--header 'Authorization: Bearer {api_key}' \\\n--header 'Content-Type: application/json' \\\n--data-raw '{ \n "name": "", \n "user": "abc-123"\n}'`}>
|
||||
<CodeGroup title="リクエスト" tag="POST" label="/conversations/:conversation_id/name" targetCode={`curl -X POST '${props.appDetail.api_base_url}/conversations/:conversation_id/name' \\\n--header 'Authorization: Bearer {api_key}' \\\n--header 'Content-Type: application/json' \\\n--data-raw '{ \n "name": "", \n "auto_generate": true, \n "user": "abc-123"\n}'`}>
|
||||
|
||||
```bash {{ title: 'cURL' }}
|
||||
curl -X POST '${props.appDetail.api_base_url}/conversations/{conversation_id}/name' \
|
||||
@ -808,6 +809,7 @@ import { Row, Col, Properties, Property, Heading, SubProperty, Paragraph } from
|
||||
--header 'Authorization: Bearer {api_key}' \
|
||||
--data-raw '{
|
||||
"name": "",
|
||||
"auto_generate": true,
|
||||
"user": "abc-123"
|
||||
}'
|
||||
```
|
||||
@ -820,8 +822,10 @@ import { Row, Col, Properties, Property, Heading, SubProperty, Paragraph } from
|
||||
"id": "cd78daf6-f9e4-4463-9ff2-54257230a0ce",
|
||||
"name": "チャット vs AI",
|
||||
"inputs": {},
|
||||
"status": "normal",
|
||||
"introduction": "",
|
||||
"created_at": 1705569238
|
||||
"created_at": 1705569238,
|
||||
"updated_at": 1705569238
|
||||
}
|
||||
```
|
||||
</CodeGroup>
|
||||
@ -931,13 +935,57 @@ import { Row, Col, Properties, Property, Heading, SubProperty, Paragraph } from
|
||||
</CodeGroup>
|
||||
</Col>
|
||||
</Row>
|
||||
---
|
||||
|
||||
<Heading
|
||||
url='/info'
|
||||
method='GET'
|
||||
title='アプリケーションの基本情報を取得'
|
||||
name='#info'
|
||||
/>
|
||||
<Row>
|
||||
<Col>
|
||||
このアプリケーションの基本情報を取得するために使用されます
|
||||
### Query
|
||||
<Properties>
|
||||
|
||||
<Property name='user' type='string' key='user'>
|
||||
ユーザー識別子、開発者のルールによって定義され、アプリケーション内で一意でなければなりません。
|
||||
</Property>
|
||||
</Properties>
|
||||
### Response
|
||||
- `name` (string) アプリケーションの名前
|
||||
- `description` (string) アプリケーションの説明
|
||||
- `tags` (array[string]) アプリケーションのタグ
|
||||
</Col>
|
||||
<Col>
|
||||
<CodeGroup title="Request" tag="GET" label="/info" targetCode={`curl -X GET '${props.appDetail.api_base_url}/info?user=abc-123' \\\n-H 'Authorization: Bearer {api_key}'`}>
|
||||
```bash {{ title: 'cURL' }}
|
||||
curl -X GET '${props.appDetail.api_base_url}/info?user=abc-123' \
|
||||
-H 'Authorization: Bearer {api_key}'
|
||||
```
|
||||
</CodeGroup>
|
||||
<CodeGroup title="Response">
|
||||
```json {{ title: 'Response' }}
|
||||
{
|
||||
"name": "My App",
|
||||
"description": "This is my app.",
|
||||
"tags": [
|
||||
"tag1",
|
||||
"tag2"
|
||||
]
|
||||
}
|
||||
```
|
||||
</CodeGroup>
|
||||
</Col>
|
||||
</Row>
|
||||
|
||||
---
|
||||
|
||||
<Heading
|
||||
url='/parameters'
|
||||
method='GET'
|
||||
title='アプリケーション情報を取得'
|
||||
title='アプリケーションのパラメータ情報を取得'
|
||||
name='#parameters'
|
||||
/>
|
||||
<Row>
|
||||
@ -1057,7 +1105,7 @@ import { Row, Col, Properties, Property, Heading, SubProperty, Paragraph } from
|
||||
<Heading
|
||||
url='/meta'
|
||||
method='GET'
|
||||
title='アプリケーションメタ情報を取得'
|
||||
title='アプリケーションのメタ情報を取得'
|
||||
name='#meta'
|
||||
/>
|
||||
<Row>
|
||||
@ -1091,14 +1139,14 @@ import { Row, Col, Properties, Property, Heading, SubProperty, Paragraph } from
|
||||
<CodeGroup title="応答">
|
||||
```json {{ title: '応答' }}
|
||||
{
|
||||
"tool_icons": {
|
||||
"tool_icons": {
|
||||
"dalle2": "https://cloud.dify.ai/console/api/workspaces/current/tool-provider/builtin/dalle/icon",
|
||||
"api_tool": {
|
||||
"background": "#252525",
|
||||
"content": "\ud83d\ude01"
|
||||
"background": "#252525",
|
||||
"content": "\ud83d\ude01"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
</CodeGroup>
|
||||
</Col>
|
||||
|
||||
@ -162,7 +162,7 @@ import { Row, Col, Properties, Property, Heading, SubProperty } from '../md.tsx'
|
||||
- `title` (string) 节点名称
|
||||
- `index` (int) 执行序号,用于展示 Tracing Node 顺序
|
||||
- `predecessor_node_id` (string) 前置节点 ID,用于画布展示执行路径
|
||||
- `inputs` (array[object]) 节点中所有使用到的前置节点变量内容
|
||||
- `inputs` (object) 节点中所有使用到的前置节点变量内容
|
||||
- `created_at` (timestamp) 开始时间
|
||||
- `event: node_finished` node 执行结束,成功失败同一事件中不同状态
|
||||
- `task_id` (string) 任务 ID,用于请求跟踪和下方的停止响应接口
|
||||
@ -173,7 +173,7 @@ import { Row, Col, Properties, Property, Heading, SubProperty } from '../md.tsx'
|
||||
- `node_id` (string) 节点 ID
|
||||
- `index` (int) 执行序号,用于展示 Tracing Node 顺序
|
||||
- `predecessor_node_id` (string) optional 前置节点 ID,用于画布展示执行路径
|
||||
- `inputs` (array[object]) 节点中所有使用到的前置节点变量内容
|
||||
- `inputs` (object) 节点中所有使用到的前置节点变量内容
|
||||
- `process_data` (json) Optional 节点过程数据
|
||||
- `outputs` (json) Optional 输出内容
|
||||
- `status` (string) 执行状态 `running` / `succeeded` / `failed` / `stopped`
|
||||
@ -570,7 +570,7 @@ import { Row, Col, Properties, Property, Heading, SubProperty } from '../md.tsx'
|
||||
- `data` (array[object]) 消息列表
|
||||
- `id` (string) 消息 ID
|
||||
- `conversation_id` (string) 会话 ID
|
||||
- `inputs` (array[object]) 用户输入参数。
|
||||
- `inputs` (object) 用户输入参数。
|
||||
- `query` (string) 用户输入 / 提问内容。
|
||||
- `message_files` (array[object]) 消息文件
|
||||
- `id` (string) ID
|
||||
@ -683,16 +683,13 @@ import { Row, Col, Properties, Property, Heading, SubProperty } from '../md.tsx'
|
||||
用户标识,由开发者定义规则,需保证用户标识在应用内唯一。
|
||||
</Property>
|
||||
<Property name='last_id' type='string' key='last_id'>
|
||||
当前页最后面一条记录的 ID,默认 null
|
||||
(选填)当前页最后面一条记录的 ID,默认 null
|
||||
</Property>
|
||||
<Property name='limit' type='int' key='limit'>
|
||||
一次请求返回多少条记录
|
||||
</Property>
|
||||
<Property name='pinned' type='bool' key='pinned'>
|
||||
只返回置顶 true,只返回非置顶 false
|
||||
(选填)一次请求返回多少条记录,默认 20 条,最大 100 条,最小 1 条。
|
||||
</Property>
|
||||
<Property name='sort_by' type='string' key='sort_by'>
|
||||
排序字段(选题),默认 -updated_at(按更新时间倒序排列)
|
||||
(选填)排序字段,默认 -updated_at(按更新时间倒序排列)
|
||||
- 可选值:created_at, -created_at, updated_at, -updated_at
|
||||
- 字段前面的符号代表顺序或倒序,-代表倒序
|
||||
</Property>
|
||||
@ -702,9 +699,11 @@ import { Row, Col, Properties, Property, Heading, SubProperty } from '../md.tsx'
|
||||
- `data` (array[object]) 会话列表
|
||||
- `id` (string) 会话 ID
|
||||
- `name` (string) 会话名称,默认由大语言模型生成。
|
||||
- `inputs` (array[object]) 用户输入参数。
|
||||
- `inputs` (object) 用户输入参数。
|
||||
- `status` (string) 会话状态
|
||||
- `introduction` (string) 开场白
|
||||
- `created_at` (timestamp) 创建时间
|
||||
- `updated_at` (timestamp) 更新时间
|
||||
- `has_more` (bool)
|
||||
- `limit` (int) 返回条数,若传入超过系统限制,返回系统限制数量
|
||||
|
||||
@ -734,7 +733,8 @@ import { Row, Col, Properties, Property, Heading, SubProperty } from '../md.tsx'
|
||||
"myName": "Lucy"
|
||||
},
|
||||
"status": "normal",
|
||||
"created_at": 1679667915
|
||||
"created_at": 1679667915,
|
||||
"updated_at": 1679667915
|
||||
},
|
||||
{
|
||||
"id": "hSIhXBhNe8X1d8Et"
|
||||
@ -817,10 +817,10 @@ import { Row, Col, Properties, Property, Heading, SubProperty } from '../md.tsx'
|
||||
|
||||
<Properties>
|
||||
<Property name='name' type='string' key='name'>
|
||||
名称,若 `auto_generate` 为 `true` 时,该参数可不传。
|
||||
(选填)名称,若 `auto_generate` 为 `true` 时,该参数可不传。
|
||||
</Property>
|
||||
<Property name='auto_generate' type='string' key='auto_generate'>
|
||||
自动生成标题,默认 false。
|
||||
<Property name='auto_generate' type='bool' key='auto_generate'>
|
||||
(选填)自动生成标题,默认 false。
|
||||
</Property>
|
||||
<Property name='user' type='string' key='user'>
|
||||
用户标识,由开发者定义规则,需保证用户标识在应用内唯一。
|
||||
@ -830,13 +830,15 @@ import { Row, Col, Properties, Property, Heading, SubProperty } from '../md.tsx'
|
||||
### Response
|
||||
- `id` (string) 会话 ID
|
||||
- `name` (string) 会话名称
|
||||
- `inputs` array[object] 用户输入参数。
|
||||
- `inputs` (object) 用户输入参数
|
||||
- `status` (string) 会话状态
|
||||
- `introduction` (string) 开场白
|
||||
- `created_at` (timestamp) 创建时间
|
||||
- `updated_at` (timestamp) 更新时间
|
||||
</Col>
|
||||
<Col sticky>
|
||||
|
||||
<CodeGroup title="Request" tag="POST" label="/conversations/:conversation_id/name" targetCode={`curl -X POST '${props.appDetail.api_base_url}/conversations/:conversation_id/name' \\\n--header 'Authorization: Bearer {api_key}' \\\n--header 'Content-Type: application/json' \\\n--data-raw '{ \n "name": "", \n "user": "abc-123"\n}'`}>
|
||||
<CodeGroup title="Request" tag="POST" label="/conversations/:conversation_id/name" targetCode={`curl -X POST '${props.appDetail.api_base_url}/conversations/:conversation_id/name' \\\n--header 'Authorization: Bearer {api_key}' \\\n--header 'Content-Type: application/json' \\\n--data-raw '{ \n "name": "", \n "auto_generate": true, \n "user": "abc-123"\n}'`}>
|
||||
|
||||
```bash {{ title: 'cURL' }}
|
||||
curl -X POST '${props.appDetail.api_base_url}/conversations/{conversation_id}/name' \
|
||||
@ -844,6 +846,7 @@ import { Row, Col, Properties, Property, Heading, SubProperty } from '../md.tsx'
|
||||
--header 'Content-Type: application/json' \
|
||||
--data-raw '{
|
||||
"name": "",
|
||||
"auto_generate": true,
|
||||
"user": "abc-123"
|
||||
}'
|
||||
```
|
||||
@ -853,7 +856,13 @@ import { Row, Col, Properties, Property, Heading, SubProperty } from '../md.tsx'
|
||||
<CodeGroup title="Response">
|
||||
```json {{ title: 'Response' }}
|
||||
{
|
||||
"result": "success"
|
||||
"id": "34d511d5-56de-4f16-a997-57b379508443",
|
||||
"name": "hello",
|
||||
"inputs": {},
|
||||
"status": "normal",
|
||||
"introduction": "",
|
||||
"created_at": 1732731141,
|
||||
"updated_at": 1732734510
|
||||
}
|
||||
```
|
||||
</CodeGroup>
|
||||
@ -960,13 +969,57 @@ import { Row, Col, Properties, Property, Heading, SubProperty } from '../md.tsx'
|
||||
</CodeGroup>
|
||||
</Col>
|
||||
</Row>
|
||||
---
|
||||
|
||||
<Heading
|
||||
url='/info'
|
||||
method='GET'
|
||||
title='获取应用基本信息'
|
||||
name='#info'
|
||||
/>
|
||||
<Row>
|
||||
<Col>
|
||||
用于获取应用的基本信息
|
||||
### Query
|
||||
<Properties>
|
||||
|
||||
<Property name='user' type='string' key='user'>
|
||||
用户标识,由开发者定义规则,需保证用户标识在应用内唯一。
|
||||
</Property>
|
||||
</Properties>
|
||||
### Response
|
||||
- `name` (string) 应用名称
|
||||
- `description` (string) 应用描述
|
||||
- `tags` (array[string]) 应用标签
|
||||
</Col>
|
||||
<Col>
|
||||
<CodeGroup title="Request" tag="GET" label="/info" targetCode={`curl -X GET '${props.appDetail.api_base_url}/info?user=abc-123' \\\n-H 'Authorization: Bearer {api_key}'`}>
|
||||
```bash {{ title: 'cURL' }}
|
||||
curl -X GET '${props.appDetail.api_base_url}/info?user=abc-123' \
|
||||
-H 'Authorization: Bearer {api_key}'
|
||||
```
|
||||
</CodeGroup>
|
||||
<CodeGroup title="Response">
|
||||
```json {{ title: 'Response' }}
|
||||
{
|
||||
"name": "My App",
|
||||
"description": "This is my app.",
|
||||
"tags": [
|
||||
"tag1",
|
||||
"tag2"
|
||||
]
|
||||
}
|
||||
```
|
||||
</CodeGroup>
|
||||
</Col>
|
||||
</Row>
|
||||
|
||||
---
|
||||
|
||||
<Heading
|
||||
url='/parameters'
|
||||
method='GET'
|
||||
title='获取应用配置信息'
|
||||
title='获取应用参数'
|
||||
name='#parameters'
|
||||
/>
|
||||
<Row>
|
||||
|
||||
@ -528,7 +528,7 @@ Chat applications support session persistence, allowing previous chat history to
|
||||
- `data` (array[object]) Message list
|
||||
- `id` (string) Message ID
|
||||
- `conversation_id` (string) Conversation ID
|
||||
- `inputs` (array[object]) User input parameters.
|
||||
- `inputs` (object) User input parameters.
|
||||
- `query` (string) User input / question content.
|
||||
- `message_files` (array[object]) Message files
|
||||
- `id` (string) ID
|
||||
@ -682,16 +682,13 @@ Chat applications support session persistence, allowing previous chat history to
|
||||
Should be uniquely defined by the developer within the application.
|
||||
</Property>
|
||||
<Property name='last_id' type='string' key='last_id'>
|
||||
The ID of the last record on the current page, default is null.
|
||||
(Optional) The ID of the last record on the current page, default is null.
|
||||
</Property>
|
||||
<Property name='limit' type='int' key='limit'>
|
||||
How many records to return in one request, default is the most recent 20 entries.
|
||||
</Property>
|
||||
<Property name='pinned' type='bool' key='pinned'>
|
||||
Return only pinned conversations as `true`, only non-pinned as `false`
|
||||
(Optional) How many records to return in one request, default is the most recent 20 entries. Maximum 100, minimum 1.
|
||||
</Property>
|
||||
<Property name='sort_by' type='string' key='sort_by'>
|
||||
Sorting Field (Optional), Default: -updated_at (sorted in descending order by update time)
|
||||
(Optional) Sorting Field, Default: -updated_at (sorted in descending order by update time)
|
||||
- Available Values: created_at, -created_at, updated_at, -updated_at
|
||||
- The symbol before the field represents the order or reverse, "-" represents reverse order.
|
||||
</Property>
|
||||
@ -701,9 +698,11 @@ Chat applications support session persistence, allowing previous chat history to
|
||||
- `data` (array[object]) List of conversations
|
||||
- `id` (string) Conversation ID
|
||||
- `name` (string) Conversation name, by default, is a snippet of the first question asked by the user in the conversation.
|
||||
- `inputs` (array[object]) User input parameters.
|
||||
- `inputs` (object) User input parameters.
|
||||
- `status` (string) Conversation status
|
||||
- `introduction` (string) Introduction
|
||||
- `created_at` (timestamp) Creation timestamp, e.g., 1705395332
|
||||
- `updated_at` (timestamp) Update timestamp, e.g., 1705395332
|
||||
- `has_more` (bool)
|
||||
- `limit` (int) Number of entries returned, if input exceeds system limit, system limit number is returned
|
||||
|
||||
@ -733,7 +732,8 @@ Chat applications support session persistence, allowing previous chat history to
|
||||
"myName": "Lucy"
|
||||
},
|
||||
"status": "normal",
|
||||
"created_at": 1679667915
|
||||
"created_at": 1679667915,
|
||||
"updated_at": 1679667915
|
||||
},
|
||||
{
|
||||
"id": "hSIhXBhNe8X1d8Et"
|
||||
@ -815,10 +815,10 @@ Chat applications support session persistence, allowing previous chat history to
|
||||
|
||||
<Properties>
|
||||
<Property name='name' type='string' key='name'>
|
||||
The name of the conversation. This parameter can be omitted if `auto_generate` is set to `true`.
|
||||
(Optional) The name of the conversation. This parameter can be omitted if `auto_generate` is set to `true`.
|
||||
</Property>
|
||||
<Property name='auto_generate' type='bool' key='auto_generate'>
|
||||
Automatically generate the title, default is `false`
|
||||
(Optional) Automatically generate the title, default is `false`
|
||||
</Property>
|
||||
<Property name='user' type='string' key='user'>
|
||||
The user identifier, defined by the developer, must ensure uniqueness within the application.
|
||||
@ -828,13 +828,15 @@ Chat applications support session persistence, allowing previous chat history to
|
||||
### Response
|
||||
- `id` (string) Conversation ID
|
||||
- `name` (string) Conversation name
|
||||
- `inputs` array[object] User input parameters.
|
||||
- `inputs` (object) User input parameters
|
||||
- `status` (string) Conversation status
|
||||
- `introduction` (string) Introduction
|
||||
- `created_at` (timestamp) Creation timestamp, e.g., 1705395332
|
||||
- `updated_at` (timestamp) Update timestamp, e.g., 1705395332
|
||||
</Col>
|
||||
<Col sticky>
|
||||
|
||||
<CodeGroup title="Request" tag="POST" label="/conversations/:conversation_id/name" targetCode={`curl -X POST '${props.appDetail.api_base_url}/conversations/:conversation_id/name' \\\n--header 'Authorization: Bearer {api_key}' \\\n--header 'Content-Type: application/json' \\\n--data-raw '{ \n "name": "", \n "user": "abc-123"\n}'`}>
|
||||
<CodeGroup title="Request" tag="POST" label="/conversations/:conversation_id/name" targetCode={`curl -X POST '${props.appDetail.api_base_url}/conversations/:conversation_id/name' \\\n--header 'Authorization: Bearer {api_key}' \\\n--header 'Content-Type: application/json' \\\n--data-raw '{ \n "name": "", \n "auto_generate": true, \n "user": "abc-123"\n}'`}>
|
||||
|
||||
```bash {{ title: 'cURL' }}
|
||||
curl -X POST '${props.appDetail.api_base_url}/conversations/{conversation_id}/name' \
|
||||
@ -842,6 +844,7 @@ Chat applications support session persistence, allowing previous chat history to
|
||||
--header 'Authorization: Bearer {api_key}' \
|
||||
--data-raw '{
|
||||
"name": "",
|
||||
"auto_generate": true,
|
||||
"user": "abc-123"
|
||||
}'
|
||||
```
|
||||
@ -854,8 +857,10 @@ Chat applications support session persistence, allowing previous chat history to
|
||||
"id": "cd78daf6-f9e4-4463-9ff2-54257230a0ce",
|
||||
"name": "Chat vs AI",
|
||||
"inputs": {},
|
||||
"status": "normal",
|
||||
"introduction": "",
|
||||
"created_at": 1705569238
|
||||
"created_at": 1705569238,
|
||||
"updated_at": 1705569238
|
||||
}
|
||||
```
|
||||
</CodeGroup>
|
||||
@ -960,13 +965,57 @@ Chat applications support session persistence, allowing previous chat history to
|
||||
</CodeGroup>
|
||||
</Col>
|
||||
</Row>
|
||||
---
|
||||
|
||||
<Heading
|
||||
url='/info'
|
||||
method='GET'
|
||||
title='Get Application Basic Information'
|
||||
name='#info'
|
||||
/>
|
||||
<Row>
|
||||
<Col>
|
||||
Used to get basic information about this application
|
||||
### Query
|
||||
<Properties>
|
||||
|
||||
<Property name='user' type='string' key='user'>
|
||||
User identifier, defined by the developer's rules, must be unique within the application.
|
||||
</Property>
|
||||
</Properties>
|
||||
### Response
|
||||
- `name` (string) application name
|
||||
- `description` (string) application description
|
||||
- `tags` (array[string]) application tags
|
||||
</Col>
|
||||
<Col>
|
||||
<CodeGroup title="Request" tag="GET" label="/info" targetCode={`curl -X GET '${props.appDetail.api_base_url}/info?user=abc-123' \\\n-H 'Authorization: Bearer {api_key}'`}>
|
||||
```bash {{ title: 'cURL' }}
|
||||
curl -X GET '${props.appDetail.api_base_url}/info?user=abc-123' \
|
||||
-H 'Authorization: Bearer {api_key}'
|
||||
```
|
||||
</CodeGroup>
|
||||
<CodeGroup title="Response">
|
||||
```json {{ title: 'Response' }}
|
||||
{
|
||||
"name": "My App",
|
||||
"description": "This is my app.",
|
||||
"tags": [
|
||||
"tag1",
|
||||
"tag2"
|
||||
]
|
||||
}
|
||||
```
|
||||
</CodeGroup>
|
||||
</Col>
|
||||
</Row>
|
||||
|
||||
---
|
||||
|
||||
<Heading
|
||||
url='/parameters'
|
||||
method='GET'
|
||||
title='Get Application Information'
|
||||
title='Get Application Parameters Information'
|
||||
name='#parameters'
|
||||
/>
|
||||
<Row>
|
||||
@ -1120,14 +1169,14 @@ Chat applications support session persistence, allowing previous chat history to
|
||||
<CodeGroup title="Response">
|
||||
```json {{ title: 'Response' }}
|
||||
{
|
||||
"tool_icons": {
|
||||
"tool_icons": {
|
||||
"dalle2": "https://cloud.dify.ai/console/api/workspaces/current/tool-provider/builtin/dalle/icon",
|
||||
"api_tool": {
|
||||
"background": "#252525",
|
||||
"content": "\ud83d\ude01"
|
||||
"background": "#252525",
|
||||
"content": "\ud83d\ude01"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
</CodeGroup>
|
||||
</Col>
|
||||
|
||||
@ -528,7 +528,7 @@ import { Row, Col, Properties, Property, Heading, SubProperty, Paragraph } from
|
||||
- `data` (array[object]) メッセージリスト
|
||||
- `id` (string) メッセージID
|
||||
- `conversation_id` (string) 会話ID
|
||||
- `inputs` (array[object]) ユーザー入力パラメータ。
|
||||
- `inputs` (object) ユーザー入力パラメータ。
|
||||
- `query` (string) ユーザー入力/質問内容。
|
||||
- `message_files` (array[object]) メッセージファイル
|
||||
- `id` (string) ID
|
||||
@ -682,16 +682,13 @@ import { Row, Col, Properties, Property, Heading, SubProperty, Paragraph } from
|
||||
アプリケーション内で開発者によって一意に定義される必要があります。
|
||||
</Property>
|
||||
<Property name='last_id' type='string' key='last_id'>
|
||||
現在のページの最後のレコードのID、デフォルトはnullです。
|
||||
(Optional)現在のページの最後のレコードのID、デフォルトはnullです。
|
||||
</Property>
|
||||
<Property name='limit' type='int' key='limit'>
|
||||
1回のリクエストで返すレコードの数、デフォルトは最新の20件です。
|
||||
</Property>
|
||||
<Property name='pinned' type='bool' key='pinned'>
|
||||
ピン留めされた会話のみを`true`として返し、ピン留めされていないもののみを`false`として返します
|
||||
(Optional)1回のリクエストで返すレコードの数、デフォルトは最新の20件です。最大100、最小1。
|
||||
</Property>
|
||||
<Property name='sort_by' type='string' key='sort_by'>
|
||||
ソートフィールド(オプション)、デフォルト:-updated_at(更新時間で降順にソート)
|
||||
(Optional)ソートフィールド、デフォルト:-updated_at(更新時間で降順にソート)
|
||||
- 利用可能な値:created_at, -created_at, updated_at, -updated_at
|
||||
- フィールドの前の記号は順序または逆順を表し、"-"は逆順を表します。
|
||||
</Property>
|
||||
@ -701,9 +698,10 @@ import { Row, Col, Properties, Property, Heading, SubProperty, Paragraph } from
|
||||
- `data` (array[object]) 会話のリスト
|
||||
- `id` (string) 会話ID
|
||||
- `name` (string) 会話名、デフォルトでは、ユーザーが会話で最初に尋ねた質問のスニペットです。
|
||||
- `inputs` (array[object]) ユーザー入力パラメータ。
|
||||
- `inputs` (object) ユーザー入力パラメータ。
|
||||
- `introduction` (string) 紹介
|
||||
- `created_at` (timestamp) 作成タイムスタンプ、例:1705395332
|
||||
- `updated_at` (timestamp) 更新タイムスタンプ、例:1705395332
|
||||
- `has_more` (bool)
|
||||
- `limit` (int) 返されたエントリの数、入力がシステム制限を超える場合、システム制限の数を返します
|
||||
|
||||
@ -733,7 +731,8 @@ import { Row, Col, Properties, Property, Heading, SubProperty, Paragraph } from
|
||||
"myName": "Lucy"
|
||||
},
|
||||
"status": "normal",
|
||||
"created_at": 1679667915
|
||||
"created_at": 1679667915,
|
||||
"updated_at": 1679667915
|
||||
},
|
||||
{
|
||||
"id": "hSIhXBhNe8X1d8Et"
|
||||
@ -815,10 +814,10 @@ import { Row, Col, Properties, Property, Heading, SubProperty, Paragraph } from
|
||||
|
||||
<Properties>
|
||||
<Property name='name' type='string' key='name'>
|
||||
会話の名前。このパラメータは、`auto_generate`が`true`に設定されている場合、省略できます。
|
||||
(Optional)会話の名前。このパラメータは、`auto_generate`が`true`に設定されている場合、省略できます。
|
||||
</Property>
|
||||
<Property name='auto_generate' type='bool' key='auto_generate'>
|
||||
タイトルを自動生成します。デフォルトは`false`です。
|
||||
(Optional)タイトルを自動生成します。デフォルトは`false`です。
|
||||
</Property>
|
||||
<Property name='user' type='string' key='user'>
|
||||
ユーザー識別子、開発者によって定義され、アプリケーション内で一意である必要があります。
|
||||
@ -828,13 +827,15 @@ import { Row, Col, Properties, Property, Heading, SubProperty, Paragraph } from
|
||||
### 応答
|
||||
- `id` (string) 会話ID
|
||||
- `name` (string) 会話名
|
||||
- `inputs` array[object] ユーザー入力パラメータ。
|
||||
- `inputs` (object) ユーザー入力パラメータ
|
||||
- `status` (string) 会話状態
|
||||
- `introduction` (string) 紹介
|
||||
- `created_at` (timestamp) 作成タイムスタンプ、例:1705395332
|
||||
- `updated_at` (timestamp) 更新タイムスタンプ、例:1705395332
|
||||
</Col>
|
||||
<Col sticky>
|
||||
|
||||
<CodeGroup title="リクエスト" tag="POST" label="/conversations/:conversation_id/name" targetCode={`curl -X POST '${props.appDetail.api_base_url}/conversations/:conversation_id/name' \\\n--header 'Authorization: Bearer {api_key}' \\\n--header 'Content-Type: application/json' \\\n--data-raw '{ \n "name": "", \n "user": "abc-123"\n}'`}>
|
||||
<CodeGroup title="リクエスト" tag="POST" label="/conversations/:conversation_id/name" targetCode={`curl -X POST '${props.appDetail.api_base_url}/conversations/:conversation_id/name' \\\n--header 'Authorization: Bearer {api_key}' \\\n--header 'Content-Type: application/json' \\\n--data-raw '{ \n "name": "", \n "auto_generate": true, \n "user": "abc-123"\n}'`}>
|
||||
|
||||
```bash {{ title: 'cURL' }}
|
||||
curl -X POST '${props.appDetail.api_base_url}/conversations/{conversation_id}/name' \
|
||||
@ -842,6 +843,7 @@ import { Row, Col, Properties, Property, Heading, SubProperty, Paragraph } from
|
||||
--header 'Authorization: Bearer {api_key}' \
|
||||
--data-raw '{
|
||||
"name": "",
|
||||
"auto_generate": true,
|
||||
"user": "abc-123"
|
||||
}'
|
||||
```
|
||||
@ -855,7 +857,8 @@ import { Row, Col, Properties, Property, Heading, SubProperty, Paragraph } from
|
||||
"name": "Chat vs AI",
|
||||
"inputs": {},
|
||||
"introduction": "",
|
||||
"created_at": 1705569238
|
||||
"created_at": 1705569238,
|
||||
"updated_at": 1705569238
|
||||
}
|
||||
```
|
||||
</CodeGroup>
|
||||
@ -960,13 +963,57 @@ import { Row, Col, Properties, Property, Heading, SubProperty, Paragraph } from
|
||||
</CodeGroup>
|
||||
</Col>
|
||||
</Row>
|
||||
---
|
||||
|
||||
<Heading
|
||||
url='/info'
|
||||
method='GET'
|
||||
title='アプリケーションの基本情報を取得'
|
||||
name='#info'
|
||||
/>
|
||||
<Row>
|
||||
<Col>
|
||||
このアプリケーションの基本情報を取得するために使用されます
|
||||
### Query
|
||||
<Properties>
|
||||
|
||||
<Property name='user' type='string' key='user'>
|
||||
ユーザー識別子、開発者のルールによって定義され、アプリケーション内で一意でなければなりません。
|
||||
</Property>
|
||||
</Properties>
|
||||
### Response
|
||||
- `name` (string) アプリケーションの名前
|
||||
- `description` (string) アプリケーションの説明
|
||||
- `tags` (array[string]) アプリケーションのタグ
|
||||
</Col>
|
||||
<Col>
|
||||
<CodeGroup title="Request" tag="GET" label="/info" targetCode={`curl -X GET '${props.appDetail.api_base_url}/info?user=abc-123' \\\n-H 'Authorization: Bearer {api_key}'`}>
|
||||
```bash {{ title: 'cURL' }}
|
||||
curl -X GET '${props.appDetail.api_base_url}/info?user=abc-123' \
|
||||
-H 'Authorization: Bearer {api_key}'
|
||||
```
|
||||
</CodeGroup>
|
||||
<CodeGroup title="Response">
|
||||
```json {{ title: 'Response' }}
|
||||
{
|
||||
"name": "My App",
|
||||
"description": "This is my app.",
|
||||
"tags": [
|
||||
"tag1",
|
||||
"tag2"
|
||||
]
|
||||
}
|
||||
```
|
||||
</CodeGroup>
|
||||
</Col>
|
||||
</Row>
|
||||
|
||||
---
|
||||
|
||||
<Heading
|
||||
url='/parameters'
|
||||
method='GET'
|
||||
title='アプリケーション情報を取得'
|
||||
title='アプリケーションのパラメータ情報を取得'
|
||||
name='#parameters'
|
||||
/>
|
||||
<Row>
|
||||
@ -1086,7 +1133,7 @@ import { Row, Col, Properties, Property, Heading, SubProperty, Paragraph } from
|
||||
<Heading
|
||||
url='/meta'
|
||||
method='GET'
|
||||
title='アプリケーションメタ情報を取得'
|
||||
title='アプリケーションのメタ情報を取得'
|
||||
name='#meta'
|
||||
/>
|
||||
<Row>
|
||||
@ -1120,14 +1167,14 @@ import { Row, Col, Properties, Property, Heading, SubProperty, Paragraph } from
|
||||
<CodeGroup title="応答">
|
||||
```json {{ title: '応答' }}
|
||||
{
|
||||
"tool_icons": {
|
||||
"tool_icons": {
|
||||
"dalle2": "https://cloud.dify.ai/console/api/workspaces/current/tool-provider/builtin/dalle/icon",
|
||||
"api_tool": {
|
||||
"background": "#252525",
|
||||
"content": "\ud83d\ude01"
|
||||
"background": "#252525",
|
||||
"content": "\ud83d\ude01"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
</CodeGroup>
|
||||
</Col>
|
||||
|
||||
@ -543,7 +543,7 @@ import { Row, Col, Properties, Property, Heading, SubProperty } from '../md.tsx'
|
||||
- `data` (array[object]) 消息列表
|
||||
- `id` (string) 消息 ID
|
||||
- `conversation_id` (string) 会话 ID
|
||||
- `inputs` (array[object]) 用户输入参数。
|
||||
- `inputs` (object) 用户输入参数。
|
||||
- `query` (string) 用户输入 / 提问内容。
|
||||
- `message_files` (array[object]) 消息文件
|
||||
- `id` (string) ID
|
||||
@ -697,16 +697,13 @@ import { Row, Col, Properties, Property, Heading, SubProperty } from '../md.tsx'
|
||||
用户标识,由开发者定义规则,需保证用户标识在应用内唯一。
|
||||
</Property>
|
||||
<Property name='last_id' type='string' key='last_id'>
|
||||
当前页最后面一条记录的 ID,默认 null
|
||||
(选填)当前页最后面一条记录的 ID,默认 null
|
||||
</Property>
|
||||
<Property name='limit' type='int' key='limit'>
|
||||
一次请求返回多少条记录
|
||||
</Property>
|
||||
<Property name='pinned' type='bool' key='pinned'>
|
||||
只返回置顶 true,只返回非置顶 false
|
||||
(选填)一次请求返回多少条记录,默认 20 条,最大 100 条,最小 1 条。
|
||||
</Property>
|
||||
<Property name='sort_by' type='string' key='sort_by'>
|
||||
排序字段(选题),默认 -updated_at(按更新时间倒序排列)
|
||||
(选填)排序字段,默认 -updated_at(按更新时间倒序排列)
|
||||
- 可选值:created_at, -created_at, updated_at, -updated_at
|
||||
- 字段前面的符号代表顺序或倒序,-代表倒序
|
||||
</Property>
|
||||
@ -716,9 +713,11 @@ import { Row, Col, Properties, Property, Heading, SubProperty } from '../md.tsx'
|
||||
- `data` (array[object]) 会话列表
|
||||
- `id` (string) 会话 ID
|
||||
- `name` (string) 会话名称,默认为会话中用户最开始问题的截取。
|
||||
- `inputs` (array[object]) 用户输入参数。
|
||||
- `inputs` (object) 用户输入参数。
|
||||
- `status` (string) 会话状态
|
||||
- `introduction` (string) 开场白
|
||||
- `created_at` (timestamp) 创建时间
|
||||
- `updated_at` (timestamp) 更新时间
|
||||
- `has_more` (bool)
|
||||
- `limit` (int) 返回条数,若传入超过系统限制,返回系统限制数量
|
||||
|
||||
@ -748,7 +747,8 @@ import { Row, Col, Properties, Property, Heading, SubProperty } from '../md.tsx'
|
||||
"myName": "Lucy"
|
||||
},
|
||||
"status": "normal",
|
||||
"created_at": 1679667915
|
||||
"created_at": 1679667915,
|
||||
"updated_at": 1679667915
|
||||
},
|
||||
{
|
||||
"id": "hSIhXBhNe8X1d8Et"
|
||||
@ -831,10 +831,10 @@ import { Row, Col, Properties, Property, Heading, SubProperty } from '../md.tsx'
|
||||
|
||||
<Properties>
|
||||
<Property name='name' type='string' key='name'>
|
||||
名称,若 `auto_generate` 为 `true` 时,该参数可不传。
|
||||
(选填)名称,若 `auto_generate` 为 `true` 时,该参数可不传。
|
||||
</Property>
|
||||
<Property name='auto_generate' type='string' key='auto_generate'>
|
||||
自动生成标题,默认 false。
|
||||
<Property name='auto_generate' type='bool' key='auto_generate'>
|
||||
(选填)自动生成标题,默认 false。
|
||||
</Property>
|
||||
<Property name='user' type='string' key='user'>
|
||||
用户标识,由开发者定义规则,需保证用户标识在应用内唯一。
|
||||
@ -844,13 +844,15 @@ import { Row, Col, Properties, Property, Heading, SubProperty } from '../md.tsx'
|
||||
### Response
|
||||
- `id` (string) 会话 ID
|
||||
- `name` (string) 会话名称
|
||||
- `inputs` array[object] 用户输入参数。
|
||||
- `inputs` (object) 用户输入参数
|
||||
- `status` (string) 会话状态
|
||||
- `introduction` (string) 开场白
|
||||
- `created_at` (timestamp) 创建时间
|
||||
- `updated_at` (timestamp) 更新时间
|
||||
</Col>
|
||||
<Col sticky>
|
||||
|
||||
<CodeGroup title="Request" tag="POST" label="/conversations/:conversation_id/name" targetCode={`curl -X POST '${props.appDetail.api_base_url}/conversations/:conversation_id/name' \\\n--header 'Authorization: Bearer {api_key}' \\\n--header 'Content-Type: application/json' \\\n--data-raw '{ \n "name": "", \n "user": "abc-123"\n}'`}>
|
||||
<CodeGroup title="Request" tag="POST" label="/conversations/:conversation_id/name" targetCode={`curl -X POST '${props.appDetail.api_base_url}/conversations/:conversation_id/name' \\\n--header 'Authorization: Bearer {api_key}' \\\n--header 'Content-Type: application/json' \\\n--data-raw '{ \n "name": "", \n "auto_generate": true, \n "user": "abc-123"\n}'`}>
|
||||
|
||||
```bash {{ title: 'cURL' }}
|
||||
curl -X POST '${props.appDetail.api_base_url}/conversations/{conversation_id}/name' \
|
||||
@ -858,6 +860,7 @@ import { Row, Col, Properties, Property, Heading, SubProperty } from '../md.tsx'
|
||||
--header 'Content-Type: application/json' \
|
||||
--data-raw '{
|
||||
"name": "",
|
||||
"auto_generate": true,
|
||||
"user": "abc-123"
|
||||
}'
|
||||
```
|
||||
@ -867,7 +870,13 @@ import { Row, Col, Properties, Property, Heading, SubProperty } from '../md.tsx'
|
||||
<CodeGroup title="Response">
|
||||
```json {{ title: 'Response' }}
|
||||
{
|
||||
"result": "success"
|
||||
"id": "34d511d5-56de-4f16-a997-57b379508443",
|
||||
"name": "hello",
|
||||
"inputs": {},
|
||||
"status": "normal",
|
||||
"introduction": "",
|
||||
"created_at": 1732731141,
|
||||
"updated_at": 1732734510
|
||||
}
|
||||
```
|
||||
</CodeGroup>
|
||||
@ -969,13 +978,57 @@ import { Row, Col, Properties, Property, Heading, SubProperty } from '../md.tsx'
|
||||
</CodeGroup>
|
||||
</Col>
|
||||
</Row>
|
||||
---
|
||||
|
||||
<Heading
|
||||
url='/info'
|
||||
method='GET'
|
||||
title='获取应用基本信息'
|
||||
name='#info'
|
||||
/>
|
||||
<Row>
|
||||
<Col>
|
||||
用于获取应用的基本信息
|
||||
### Query
|
||||
<Properties>
|
||||
|
||||
<Property name='user' type='string' key='user'>
|
||||
用户标识,由开发者定义规则,需保证用户标识在应用内唯一。
|
||||
</Property>
|
||||
</Properties>
|
||||
### Response
|
||||
- `name` (string) 应用名称
|
||||
- `description` (string) 应用描述
|
||||
- `tags` (array[string]) 应用标签
|
||||
</Col>
|
||||
<Col>
|
||||
<CodeGroup title="Request" tag="GET" label="/info" targetCode={`curl -X GET '${props.appDetail.api_base_url}/info?user=abc-123' \\\n-H 'Authorization: Bearer {api_key}'`}>
|
||||
```bash {{ title: 'cURL' }}
|
||||
curl -X GET '${props.appDetail.api_base_url}/info?user=abc-123' \
|
||||
-H 'Authorization: Bearer {api_key}'
|
||||
```
|
||||
</CodeGroup>
|
||||
<CodeGroup title="Response">
|
||||
```json {{ title: 'Response' }}
|
||||
{
|
||||
"name": "My App",
|
||||
"description": "This is my app.",
|
||||
"tags": [
|
||||
"tag1",
|
||||
"tag2"
|
||||
]
|
||||
}
|
||||
```
|
||||
</CodeGroup>
|
||||
</Col>
|
||||
</Row>
|
||||
|
||||
---
|
||||
|
||||
<Heading
|
||||
url='/parameters'
|
||||
method='GET'
|
||||
title='获取应用配置信息'
|
||||
title='获取应用参数'
|
||||
name='#parameters'
|
||||
/>
|
||||
<Row>
|
||||
|
||||
@ -113,7 +113,7 @@ Workflow applications offers non-session support and is ideal for translation, a
|
||||
- `title` (string) name of node
|
||||
- `index` (int) Execution sequence number, used to display Tracing Node sequence
|
||||
- `predecessor_node_id` (string) optional Prefix node ID, used for canvas display execution path
|
||||
- `inputs` (array[object]) Contents of all preceding node variables used in the node
|
||||
- `inputs` (object) Contents of all preceding node variables used in the node
|
||||
- `created_at` (timestamp) timestamp of start, e.g., 1705395332
|
||||
- `event: node_finished` node execution ends, success or failure in different states in the same event
|
||||
- `task_id` (string) Task ID, used for request tracking and the below Stop Generate API
|
||||
@ -126,7 +126,7 @@ Workflow applications offers non-session support and is ideal for translation, a
|
||||
- `title` (string) name of node
|
||||
- `index` (int) Execution sequence number, used to display Tracing Node sequence
|
||||
- `predecessor_node_id` (string) optional Prefix node ID, used for canvas display execution path
|
||||
- `inputs` (array[object]) Contents of all preceding node variables used in the node
|
||||
- `inputs` (object) Contents of all preceding node variables used in the node
|
||||
- `process_data` (json) Optional node process data
|
||||
- `outputs` (json) Optional content of output
|
||||
- `status` (string) status of execution, `running` / `succeeded` / `failed` / `stopped`
|
||||
@ -498,104 +498,6 @@ Workflow applications offers non-session support and is ideal for translation, a
|
||||
|
||||
---
|
||||
|
||||
<Heading
|
||||
url='/parameters'
|
||||
method='GET'
|
||||
title='Get Application Information'
|
||||
name='#parameters'
|
||||
/>
|
||||
<Row>
|
||||
<Col>
|
||||
Used at the start of entering the page to obtain information such as features, input parameter names, types, and default values.
|
||||
|
||||
### Query
|
||||
|
||||
<Properties>
|
||||
<Property name='user' type='string' key='user'>
|
||||
User identifier, defined by the developer's rules, must be unique within the application.
|
||||
</Property>
|
||||
</Properties>
|
||||
|
||||
### Response
|
||||
- `user_input_form` (array[object]) User input form configuration
|
||||
- `text-input` (object) Text input control
|
||||
- `label` (string) Variable display label name
|
||||
- `variable` (string) Variable ID
|
||||
- `required` (bool) Whether it is required
|
||||
- `default` (string) Default value
|
||||
- `paragraph` (object) Paragraph text input control
|
||||
- `label` (string) Variable display label name
|
||||
- `variable` (string) Variable ID
|
||||
- `required` (bool) Whether it is required
|
||||
- `default` (string) Default value
|
||||
- `select` (object) Dropdown control
|
||||
- `label` (string) Variable display label name
|
||||
- `variable` (string) Variable ID
|
||||
- `required` (bool) Whether it is required
|
||||
- `default` (string) Default value
|
||||
- `options` (array[string]) Option values
|
||||
- `file_upload` (object) File upload configuration
|
||||
- `image` (object) Image settings
|
||||
Currently only supports image types: `png`, `jpg`, `jpeg`, `webp`, `gif`
|
||||
- `enabled` (bool) Whether it is enabled
|
||||
- `number_limits` (int) Image number limit, default is 3
|
||||
- `transfer_methods` (array[string]) List of transfer methods, remote_url, local_file, must choose one
|
||||
- `system_parameters` (object) System parameters
|
||||
- `file_size_limit` (int) Document upload size limit (MB)
|
||||
- `image_file_size_limit` (int) Image file upload size limit (MB)
|
||||
- `audio_file_size_limit` (int) Audio file upload size limit (MB)
|
||||
- `video_file_size_limit` (int) Video file upload size limit (MB)
|
||||
|
||||
</Col>
|
||||
<Col sticky>
|
||||
|
||||
<CodeGroup title="Request" tag="GET" label="/parameters" targetCode={` curl -X GET '${props.appDetail.api_base_url}/parameters?user=abc-123'`}>
|
||||
|
||||
```bash {{ title: 'cURL' }}
|
||||
curl -X GET '${props.appDetail.api_base_url}/parameters?user=abc-123' \
|
||||
--header 'Authorization: Bearer {api_key}'
|
||||
```
|
||||
|
||||
</CodeGroup>
|
||||
|
||||
<CodeGroup title="Response">
|
||||
```json {{ title: 'Response' }}
|
||||
{
|
||||
"user_input_form": [
|
||||
{
|
||||
"paragraph": {
|
||||
"label": "Query",
|
||||
"variable": "query",
|
||||
"required": true,
|
||||
"default": ""
|
||||
}
|
||||
}
|
||||
],
|
||||
"file_upload": {
|
||||
"image": {
|
||||
"enabled": false,
|
||||
"number_limits": 3,
|
||||
"detail": "high",
|
||||
"transfer_methods": [
|
||||
"remote_url",
|
||||
"local_file"
|
||||
]
|
||||
}
|
||||
},
|
||||
"system_parameters": {
|
||||
"file_size_limit": 15,
|
||||
"image_file_size_limit": 10,
|
||||
"audio_file_size_limit": 50,
|
||||
"video_file_size_limit": 100
|
||||
}
|
||||
}
|
||||
```
|
||||
</CodeGroup>
|
||||
</Col>
|
||||
</Row>
|
||||
|
||||
---
|
||||
|
||||
<Heading
|
||||
url='/workflows/logs'
|
||||
method='GET'
|
||||
@ -699,3 +601,145 @@ Workflow applications offers non-session support and is ideal for translation, a
|
||||
</CodeGroup>
|
||||
</Col>
|
||||
</Row>
|
||||
---
|
||||
|
||||
<Heading
|
||||
url='/info'
|
||||
method='GET'
|
||||
title='Get Application Basic Information'
|
||||
name='#info'
|
||||
/>
|
||||
<Row>
|
||||
<Col>
|
||||
Used to get basic information about this application
|
||||
### Query
|
||||
<Properties>
|
||||
|
||||
<Property name='user' type='string' key='user'>
|
||||
User identifier, defined by the developer's rules, must be unique within the application.
|
||||
</Property>
|
||||
</Properties>
|
||||
### Response
|
||||
- `name` (string) application name
|
||||
- `description` (string) application description
|
||||
- `tags` (array[string]) application tags
|
||||
</Col>
|
||||
<Col>
|
||||
<CodeGroup title="Request" tag="GET" label="/info" targetCode={`curl -X GET '${props.appDetail.api_base_url}/info?user=abc-123' \\\n-H 'Authorization: Bearer {api_key}'`}>
|
||||
```bash {{ title: 'cURL' }}
|
||||
curl -X GET '${props.appDetail.api_base_url}/info?user=abc-123' \
|
||||
-H 'Authorization: Bearer {api_key}'
|
||||
```
|
||||
</CodeGroup>
|
||||
<CodeGroup title="Response">
|
||||
```json {{ title: 'Response' }}
|
||||
{
|
||||
"name": "My App",
|
||||
"description": "This is my app.",
|
||||
"tags": [
|
||||
"tag1",
|
||||
"tag2"
|
||||
]
|
||||
}
|
||||
```
|
||||
</CodeGroup>
|
||||
</Col>
|
||||
</Row>
|
||||
|
||||
---
|
||||
|
||||
<Heading
|
||||
url='/parameters'
|
||||
method='GET'
|
||||
title='Get Application Parameters Information'
|
||||
name='#parameters'
|
||||
/>
|
||||
<Row>
|
||||
<Col>
|
||||
Used at the start of entering the page to obtain information such as features, input parameter names, types, and default values.
|
||||
|
||||
### Query
|
||||
|
||||
<Properties>
|
||||
<Property name='user' type='string' key='user'>
|
||||
User identifier, defined by the developer's rules, must be unique within the application.
|
||||
</Property>
|
||||
</Properties>
|
||||
|
||||
### Response
|
||||
- `user_input_form` (array[object]) User input form configuration
|
||||
- `text-input` (object) Text input control
|
||||
- `label` (string) Variable display label name
|
||||
- `variable` (string) Variable ID
|
||||
- `required` (bool) Whether it is required
|
||||
- `default` (string) Default value
|
||||
- `paragraph` (object) Paragraph text input control
|
||||
- `label` (string) Variable display label name
|
||||
- `variable` (string) Variable ID
|
||||
- `required` (bool) Whether it is required
|
||||
- `default` (string) Default value
|
||||
- `select` (object) Dropdown control
|
||||
- `label` (string) Variable display label name
|
||||
- `variable` (string) Variable ID
|
||||
- `required` (bool) Whether it is required
|
||||
- `default` (string) Default value
|
||||
- `options` (array[string]) Option values
|
||||
- `file_upload` (object) File upload configuration
|
||||
- `image` (object) Image settings
|
||||
Currently only supports image types: `png`, `jpg`, `jpeg`, `webp`, `gif`
|
||||
- `enabled` (bool) Whether it is enabled
|
||||
- `number_limits` (int) Image number limit, default is 3
|
||||
- `transfer_methods` (array[string]) List of transfer methods, remote_url, local_file, must choose one
|
||||
- `system_parameters` (object) System parameters
|
||||
- `file_size_limit` (int) Document upload size limit (MB)
|
||||
- `image_file_size_limit` (int) Image file upload size limit (MB)
|
||||
- `audio_file_size_limit` (int) Audio file upload size limit (MB)
|
||||
- `video_file_size_limit` (int) Video file upload size limit (MB)
|
||||
|
||||
</Col>
|
||||
<Col sticky>
|
||||
|
||||
<CodeGroup title="Request" tag="GET" label="/parameters" targetCode={` curl -X GET '${props.appDetail.api_base_url}/parameters?user=abc-123'`}>
|
||||
|
||||
```bash {{ title: 'cURL' }}
|
||||
curl -X GET '${props.appDetail.api_base_url}/parameters?user=abc-123' \
|
||||
--header 'Authorization: Bearer {api_key}'
|
||||
```
|
||||
|
||||
</CodeGroup>
|
||||
|
||||
<CodeGroup title="Response">
|
||||
```json {{ title: 'Response' }}
|
||||
{
|
||||
"user_input_form": [
|
||||
{
|
||||
"paragraph": {
|
||||
"label": "Query",
|
||||
"variable": "query",
|
||||
"required": true,
|
||||
"default": ""
|
||||
}
|
||||
}
|
||||
],
|
||||
"file_upload": {
|
||||
"image": {
|
||||
"enabled": false,
|
||||
"number_limits": 3,
|
||||
"detail": "high",
|
||||
"transfer_methods": [
|
||||
"remote_url",
|
||||
"local_file"
|
||||
]
|
||||
}
|
||||
},
|
||||
"system_parameters": {
|
||||
"file_size_limit": 15,
|
||||
"image_file_size_limit": 10,
|
||||
"audio_file_size_limit": 50,
|
||||
"video_file_size_limit": 100
|
||||
}
|
||||
}
|
||||
```
|
||||
</CodeGroup>
|
||||
</Col>
|
||||
</Row>
|
||||
|
||||
@ -113,7 +113,7 @@ import { Row, Col, Properties, Property, Heading, SubProperty, Paragraph } from
|
||||
- `title` (string) ノードの名前
|
||||
- `index` (int) 実行シーケンス番号、トレースノードシーケンスを表示するために使用
|
||||
- `predecessor_node_id` (string) オプションのプレフィックスノードID、キャンバス表示実行パスに使用
|
||||
- `inputs` (array[object]) ノードで使用されるすべての前のノード変数の内容
|
||||
- `inputs` (object) ノードで使用されるすべての前のノード変数の内容
|
||||
- `created_at` (timestamp) 開始のタイムスタンプ、例:1705395332
|
||||
- `event: node_finished` ノード実行終了、同じイベントで異なる状態で成功または失敗
|
||||
- `task_id` (string) タスクID、リクエスト追跡と以下のStop Generate APIに使用
|
||||
@ -126,7 +126,7 @@ import { Row, Col, Properties, Property, Heading, SubProperty, Paragraph } from
|
||||
- `title` (string) ノードの名前
|
||||
- `index` (int) 実行シーケンス番号、トレースノードシーケンスを表示するために使用
|
||||
- `predecessor_node_id` (string) オプションのプレフィックスノードID、キャンバス表示実行パスに使用
|
||||
- `inputs` (array[object]) ノードで使用されるすべての前のノード変数の内容
|
||||
- `inputs` (object) ノードで使用されるすべての前のノード変数の内容
|
||||
- `process_data` (json) オプションのノードプロセスデータ
|
||||
- `outputs` (json) オプションの出力内容
|
||||
- `status` (string) 実行のステータス、`running` / `succeeded` / `failed` / `stopped`
|
||||
@ -498,104 +498,6 @@ import { Row, Col, Properties, Property, Heading, SubProperty, Paragraph } from
|
||||
|
||||
---
|
||||
|
||||
<Heading
|
||||
url='/parameters'
|
||||
method='GET'
|
||||
title='アプリケーション情報を取得'
|
||||
name='#parameters'
|
||||
/>
|
||||
<Row>
|
||||
<Col>
|
||||
ページに入る際に、機能、入力パラメータ名、タイプ、デフォルト値などの情報を取得するために使用されます。
|
||||
|
||||
### クエリ
|
||||
|
||||
<Properties>
|
||||
<Property name='user' type='string' key='user'>
|
||||
ユーザー識別子、開発者のルールで定義され、アプリケーション内で一意でなければなりません。
|
||||
</Property>
|
||||
</Properties>
|
||||
|
||||
### 応答
|
||||
- `user_input_form` (array[object]) ユーザー入力フォームの設定
|
||||
- `text-input` (object) テキスト入力コントロール
|
||||
- `label` (string) 変数表示ラベル名
|
||||
- `variable` (string) 変数ID
|
||||
- `required` (bool) 必須かどうか
|
||||
- `default` (string) デフォルト値
|
||||
- `paragraph` (object) 段落テキスト入力コントロール
|
||||
- `label` (string) 変数表示ラベル名
|
||||
- `variable` (string) 変数ID
|
||||
- `required` (bool) 必須かどうか
|
||||
- `default` (string) デフォルト値
|
||||
- `select` (object) ドロップダウンコントロール
|
||||
- `label` (string) 変数表示ラベル名
|
||||
- `variable` (string) 変数ID
|
||||
- `required` (bool) 必須かどうか
|
||||
- `default` (string) デフォルト値
|
||||
- `options` (array[string]) オプション値
|
||||
- `file_upload` (object) ファイルアップロード設定
|
||||
- `image` (object) 画像設定
|
||||
現在サポートされている画像タイプのみ:`png`, `jpg`, `jpeg`, `webp`, `gif`
|
||||
- `enabled` (bool) 有効かどうか
|
||||
- `number_limits` (int) 画像数の制限、デフォルトは3
|
||||
- `transfer_methods` (array[string]) 転送方法のリスト、remote_url, local_file、いずれかを選択する必要があります
|
||||
- `system_parameters` (object) システムパラメータ
|
||||
- `file_size_limit` (int) ドキュメントアップロードサイズ制限(MB)
|
||||
- `image_file_size_limit` (int) 画像ファイルアップロードサイズ制限(MB)
|
||||
- `audio_file_size_limit` (int) オーディオファイルアップロードサイズ制限(MB)
|
||||
- `video_file_size_limit` (int) ビデオファイルアップロードサイズ制限(MB)
|
||||
|
||||
</Col>
|
||||
<Col sticky>
|
||||
|
||||
<CodeGroup title="リクエスト" tag="GET" label="/parameters" targetCode={` curl -X GET '${props.appDetail.api_base_url}/parameters?user=abc-123'`}>
|
||||
|
||||
```bash {{ title: 'cURL' }}
|
||||
curl -X GET '${props.appDetail.api_base_url}/parameters?user=abc-123' \
|
||||
--header 'Authorization: Bearer {api_key}'
|
||||
```
|
||||
|
||||
</CodeGroup>
|
||||
|
||||
<CodeGroup title="応答">
|
||||
```json {{ title: '応答' }}
|
||||
{
|
||||
"user_input_form": [
|
||||
{
|
||||
"paragraph": {
|
||||
"label": "Query",
|
||||
"variable": "query",
|
||||
"required": true,
|
||||
"default": ""
|
||||
}
|
||||
}
|
||||
],
|
||||
"file_upload": {
|
||||
"image": {
|
||||
"enabled": false,
|
||||
"number_limits": 3,
|
||||
"detail": "high",
|
||||
"transfer_methods": [
|
||||
"remote_url",
|
||||
"local_file"
|
||||
]
|
||||
}
|
||||
},
|
||||
"system_parameters": {
|
||||
"file_size_limit": 15,
|
||||
"image_file_size_limit": 10,
|
||||
"audio_file_size_limit": 50,
|
||||
"video_file_size_limit": 100
|
||||
}
|
||||
}
|
||||
```
|
||||
</CodeGroup>
|
||||
</Col>
|
||||
</Row>
|
||||
|
||||
---
|
||||
|
||||
<Heading
|
||||
url='/workflows/logs'
|
||||
method='GET'
|
||||
@ -699,3 +601,145 @@ import { Row, Col, Properties, Property, Heading, SubProperty, Paragraph } from
|
||||
</CodeGroup>
|
||||
</Col>
|
||||
</Row>
|
||||
---
|
||||
|
||||
<Heading
|
||||
url='/info'
|
||||
method='GET'
|
||||
title='アプリケーションの基本情報を取得'
|
||||
name='#info'
|
||||
/>
|
||||
<Row>
|
||||
<Col>
|
||||
このアプリケーションの基本情報を取得するために使用されます
|
||||
### Query
|
||||
<Properties>
|
||||
|
||||
<Property name='user' type='string' key='user'>
|
||||
ユーザー識別子、開発者のルールによって定義され、アプリケーション内で一意でなければなりません。
|
||||
</Property>
|
||||
</Properties>
|
||||
### Response
|
||||
- `name` (string) アプリケーションの名前
|
||||
- `description` (string) アプリケーションの説明
|
||||
- `tags` (array[string]) アプリケーションのタグ
|
||||
</Col>
|
||||
<Col>
|
||||
<CodeGroup title="Request" tag="GET" label="/info" targetCode={`curl -X GET '${props.appDetail.api_base_url}/info?user=abc-123' \\\n-H 'Authorization: Bearer {api_key}'`}>
|
||||
```bash {{ title: 'cURL' }}
|
||||
curl -X GET '${props.appDetail.api_base_url}/info?user=abc-123' \
|
||||
-H 'Authorization: Bearer {api_key}'
|
||||
```
|
||||
</CodeGroup>
|
||||
<CodeGroup title="Response">
|
||||
```json {{ title: 'Response' }}
|
||||
{
|
||||
"name": "My App",
|
||||
"description": "This is my app.",
|
||||
"tags": [
|
||||
"tag1",
|
||||
"tag2"
|
||||
]
|
||||
}
|
||||
```
|
||||
</CodeGroup>
|
||||
</Col>
|
||||
</Row>
|
||||
|
||||
---
|
||||
|
||||
<Heading
|
||||
url='/parameters'
|
||||
method='GET'
|
||||
title='アプリケーションのパラメータ情報を取得'
|
||||
name='#parameters'
|
||||
/>
|
||||
<Row>
|
||||
<Col>
|
||||
ページに入る際に、機能、入力パラメータ名、タイプ、デフォルト値などの情報を取得するために使用されます。
|
||||
|
||||
### クエリ
|
||||
|
||||
<Properties>
|
||||
<Property name='user' type='string' key='user'>
|
||||
ユーザー識別子、開発者のルールで定義され、アプリケーション内で一意でなければなりません。
|
||||
</Property>
|
||||
</Properties>
|
||||
|
||||
### 応答
|
||||
- `user_input_form` (array[object]) ユーザー入力フォームの設定
|
||||
- `text-input` (object) テキスト入力コントロール
|
||||
- `label` (string) 変数表示ラベル名
|
||||
- `variable` (string) 変数ID
|
||||
- `required` (bool) 必須かどうか
|
||||
- `default` (string) デフォルト値
|
||||
- `paragraph` (object) 段落テキスト入力コントロール
|
||||
- `label` (string) 変数表示ラベル名
|
||||
- `variable` (string) 変数ID
|
||||
- `required` (bool) 必須かどうか
|
||||
- `default` (string) デフォルト値
|
||||
- `select` (object) ドロップダウンコントロール
|
||||
- `label` (string) 変数表示ラベル名
|
||||
- `variable` (string) 変数ID
|
||||
- `required` (bool) 必須かどうか
|
||||
- `default` (string) デフォルト値
|
||||
- `options` (array[string]) オプション値
|
||||
- `file_upload` (object) ファイルアップロード設定
|
||||
- `image` (object) 画像設定
|
||||
現在サポートされている画像タイプのみ:`png`, `jpg`, `jpeg`, `webp`, `gif`
|
||||
- `enabled` (bool) 有効かどうか
|
||||
- `number_limits` (int) 画像数の制限、デフォルトは3
|
||||
- `transfer_methods` (array[string]) 転送方法のリスト、remote_url, local_file、いずれかを選択する必要があります
|
||||
- `system_parameters` (object) システムパラメータ
|
||||
- `file_size_limit` (int) ドキュメントアップロードサイズ制限(MB)
|
||||
- `image_file_size_limit` (int) 画像ファイルアップロードサイズ制限(MB)
|
||||
- `audio_file_size_limit` (int) オーディオファイルアップロードサイズ制限(MB)
|
||||
- `video_file_size_limit` (int) ビデオファイルアップロードサイズ制限(MB)
|
||||
|
||||
</Col>
|
||||
<Col sticky>
|
||||
|
||||
<CodeGroup title="リクエスト" tag="GET" label="/parameters" targetCode={` curl -X GET '${props.appDetail.api_base_url}/parameters?user=abc-123'`}>
|
||||
|
||||
```bash {{ title: 'cURL' }}
|
||||
curl -X GET '${props.appDetail.api_base_url}/parameters?user=abc-123' \
|
||||
--header 'Authorization: Bearer {api_key}'
|
||||
```
|
||||
|
||||
</CodeGroup>
|
||||
|
||||
<CodeGroup title="応答">
|
||||
```json {{ title: '応答' }}
|
||||
{
|
||||
"user_input_form": [
|
||||
{
|
||||
"paragraph": {
|
||||
"label": "Query",
|
||||
"variable": "query",
|
||||
"required": true,
|
||||
"default": ""
|
||||
}
|
||||
}
|
||||
],
|
||||
"file_upload": {
|
||||
"image": {
|
||||
"enabled": false,
|
||||
"number_limits": 3,
|
||||
"detail": "high",
|
||||
"transfer_methods": [
|
||||
"remote_url",
|
||||
"local_file"
|
||||
]
|
||||
}
|
||||
},
|
||||
"system_parameters": {
|
||||
"file_size_limit": 15,
|
||||
"image_file_size_limit": 10,
|
||||
"audio_file_size_limit": 50,
|
||||
"video_file_size_limit": 100
|
||||
}
|
||||
}
|
||||
```
|
||||
</CodeGroup>
|
||||
</Col>
|
||||
</Row>
|
||||
|
||||
@ -111,7 +111,7 @@ Workflow 应用无会话支持,适合用于翻译/文章写作/总结 AI 等
|
||||
- `title` (string) 节点名称
|
||||
- `index` (int) 执行序号,用于展示 Tracing Node 顺序
|
||||
- `predecessor_node_id` (string) 前置节点 ID,用于画布展示执行路径
|
||||
- `inputs` (array[object]) 节点中所有使用到的前置节点变量内容
|
||||
- `inputs` (object) 节点中所有使用到的前置节点变量内容
|
||||
- `created_at` (timestamp) 开始时间
|
||||
- `event: node_finished` node 执行结束,成功失败同一事件中不同状态
|
||||
- `task_id` (string) 任务 ID,用于请求跟踪和下方的停止响应接口
|
||||
@ -122,7 +122,7 @@ Workflow 应用无会话支持,适合用于翻译/文章写作/总结 AI 等
|
||||
- `node_id` (string) 节点 ID
|
||||
- `index` (int) 执行序号,用于展示 Tracing Node 顺序
|
||||
- `predecessor_node_id` (string) optional 前置节点 ID,用于画布展示执行路径
|
||||
- `inputs` (array[object]) 节点中所有使用到的前置节点变量内容
|
||||
- `inputs` (object) 节点中所有使用到的前置节点变量内容
|
||||
- `process_data` (json) Optional 节点过程数据
|
||||
- `outputs` (json) Optional 输出内容
|
||||
- `status` (string) 执行状态 `running` / `succeeded` / `failed` / `stopped`
|
||||
@ -490,104 +490,6 @@ Workflow 应用无会话支持,适合用于翻译/文章写作/总结 AI 等
|
||||
</Row>
|
||||
---
|
||||
|
||||
<Heading
|
||||
url='/parameters'
|
||||
method='GET'
|
||||
title='获取应用配置信息'
|
||||
name='#parameters'
|
||||
/>
|
||||
<Row>
|
||||
<Col>
|
||||
用于进入页面一开始,获取功能开关、输入参数名称、类型及默认值等使用。
|
||||
|
||||
### Query
|
||||
|
||||
<Properties>
|
||||
<Property name='user' type='string' key='user'>
|
||||
用户标识,由开发者定义规则,需保证用户标识在应用内唯一。
|
||||
</Property>
|
||||
</Properties>
|
||||
|
||||
### Response
|
||||
- `user_input_form` (array[object]) 用户输入表单配置
|
||||
- `text-input` (object) 文本输入控件
|
||||
- `label` (string) 控件展示标签名
|
||||
- `variable` (string) 控件 ID
|
||||
- `required` (bool) 是否必填
|
||||
- `default` (string) 默认值
|
||||
- `paragraph` (object) 段落文本输入控件
|
||||
- `label` (string) 控件展示标签名
|
||||
- `variable` (string) 控件 ID
|
||||
- `required` (bool) 是否必填
|
||||
- `default` (string) 默认值
|
||||
- `select` (object) 下拉控件
|
||||
- `label` (string) 控件展示标签名
|
||||
- `variable` (string) 控件 ID
|
||||
- `required` (bool) 是否必填
|
||||
- `default` (string) 默认值
|
||||
- `options` (array[string]) 选项值
|
||||
- `file_upload` (object) 文件上传配置
|
||||
- `image` (object) 图片设置
|
||||
当前仅支持图片类型:`png`, `jpg`, `jpeg`, `webp`, `gif`
|
||||
- `enabled` (bool) 是否开启
|
||||
- `number_limits` (int) 图片数量限制,默认 3
|
||||
- `transfer_methods` (array[string]) 传递方式列表,remote_url , local_file,必选一个
|
||||
- `system_parameters` (object) 系统参数
|
||||
- `file_size_limit` (int) 文档上传大小限制 (MB)
|
||||
- `image_file_size_limit` (int) 图片文件上传大小限制(MB)
|
||||
- `audio_file_size_limit` (int) 音频文件上传大小限制 (MB)
|
||||
- `video_file_size_limit` (int) 视频文件上传大小限制 (MB)
|
||||
|
||||
</Col>
|
||||
<Col sticky>
|
||||
|
||||
<CodeGroup title="Request" tag="GET" label="/parameters" targetCode={` curl -X GET '${props.appDetail.api_base_url}/parameters?user=abc-123'`}>
|
||||
|
||||
```bash {{ title: 'cURL' }}
|
||||
curl -X GET '${props.appDetail.api_base_url}/parameters?user=abc-123' \
|
||||
--header 'Authorization: Bearer {api_key}'
|
||||
```
|
||||
|
||||
</CodeGroup>
|
||||
|
||||
<CodeGroup title="Response">
|
||||
```json {{ title: 'Response' }}
|
||||
{
|
||||
"user_input_form": [
|
||||
{
|
||||
"paragraph": {
|
||||
"label": "Query",
|
||||
"variable": "query",
|
||||
"required": true,
|
||||
"default": ""
|
||||
}
|
||||
}
|
||||
],
|
||||
"file_upload": {
|
||||
"image": {
|
||||
"enabled": false,
|
||||
"number_limits": 3,
|
||||
"detail": "high",
|
||||
"transfer_methods": [
|
||||
"remote_url",
|
||||
"local_file"
|
||||
]
|
||||
}
|
||||
},
|
||||
"system_parameters": {
|
||||
"file_size_limit": 15,
|
||||
"image_file_size_limit": 10,
|
||||
"audio_file_size_limit": 50,
|
||||
"video_file_size_limit": 100
|
||||
}
|
||||
}
|
||||
```
|
||||
</CodeGroup>
|
||||
</Col>
|
||||
</Row>
|
||||
|
||||
---
|
||||
|
||||
<Heading
|
||||
url='/workflows/logs'
|
||||
method='GET'
|
||||
@ -691,3 +593,145 @@ Workflow 应用无会话支持,适合用于翻译/文章写作/总结 AI 等
|
||||
</CodeGroup>
|
||||
</Col>
|
||||
</Row>
|
||||
---
|
||||
|
||||
<Heading
|
||||
url='/info'
|
||||
method='GET'
|
||||
title='获取应用基本信息'
|
||||
name='#info'
|
||||
/>
|
||||
<Row>
|
||||
<Col>
|
||||
用于获取应用的基本信息
|
||||
### Query
|
||||
<Properties>
|
||||
|
||||
<Property name='user' type='string' key='user'>
|
||||
用户标识,由开发者定义规则,需保证用户标识在应用内唯一。
|
||||
</Property>
|
||||
</Properties>
|
||||
### Response
|
||||
- `name` (string) 应用名称
|
||||
- `description` (string) 应用描述
|
||||
- `tags` (array[string]) 应用标签
|
||||
</Col>
|
||||
<Col>
|
||||
<CodeGroup title="Request" tag="GET" label="/info" targetCode={`curl -X GET '${props.appDetail.api_base_url}/info?user=abc-123' \\\n-H 'Authorization: Bearer {api_key}'`}>
|
||||
```bash {{ title: 'cURL' }}
|
||||
curl -X GET '${props.appDetail.api_base_url}/info?user=abc-123' \
|
||||
-H 'Authorization: Bearer {api_key}'
|
||||
```
|
||||
</CodeGroup>
|
||||
<CodeGroup title="Response">
|
||||
```json {{ title: 'Response' }}
|
||||
{
|
||||
"name": "My App",
|
||||
"description": "This is my app.",
|
||||
"tags": [
|
||||
"tag1",
|
||||
"tag2"
|
||||
]
|
||||
}
|
||||
```
|
||||
</CodeGroup>
|
||||
</Col>
|
||||
</Row>
|
||||
|
||||
---
|
||||
|
||||
<Heading
|
||||
url='/parameters'
|
||||
method='GET'
|
||||
title='获取应用参数'
|
||||
name='#parameters'
|
||||
/>
|
||||
<Row>
|
||||
<Col>
|
||||
用于进入页面一开始,获取功能开关、输入参数名称、类型及默认值等使用。
|
||||
|
||||
### Query
|
||||
|
||||
<Properties>
|
||||
<Property name='user' type='string' key='user'>
|
||||
用户标识,由开发者定义规则,需保证用户标识在应用内唯一。
|
||||
</Property>
|
||||
</Properties>
|
||||
|
||||
### Response
|
||||
- `user_input_form` (array[object]) 用户输入表单配置
|
||||
- `text-input` (object) 文本输入控件
|
||||
- `label` (string) 控件展示标签名
|
||||
- `variable` (string) 控件 ID
|
||||
- `required` (bool) 是否必填
|
||||
- `default` (string) 默认值
|
||||
- `paragraph` (object) 段落文本输入控件
|
||||
- `label` (string) 控件展示标签名
|
||||
- `variable` (string) 控件 ID
|
||||
- `required` (bool) 是否必填
|
||||
- `default` (string) 默认值
|
||||
- `select` (object) 下拉控件
|
||||
- `label` (string) 控件展示标签名
|
||||
- `variable` (string) 控件 ID
|
||||
- `required` (bool) 是否必填
|
||||
- `default` (string) 默认值
|
||||
- `options` (array[string]) 选项值
|
||||
- `file_upload` (object) 文件上传配置
|
||||
- `image` (object) 图片设置
|
||||
当前仅支持图片类型:`png`, `jpg`, `jpeg`, `webp`, `gif`
|
||||
- `enabled` (bool) 是否开启
|
||||
- `number_limits` (int) 图片数量限制,默认 3
|
||||
- `transfer_methods` (array[string]) 传递方式列表,remote_url , local_file,必选一个
|
||||
- `system_parameters` (object) 系统参数
|
||||
- `file_size_limit` (int) 文档上传大小限制 (MB)
|
||||
- `image_file_size_limit` (int) 图片文件上传大小限制(MB)
|
||||
- `audio_file_size_limit` (int) 音频文件上传大小限制 (MB)
|
||||
- `video_file_size_limit` (int) 视频文件上传大小限制 (MB)
|
||||
|
||||
</Col>
|
||||
<Col sticky>
|
||||
|
||||
<CodeGroup title="Request" tag="GET" label="/parameters" targetCode={` curl -X GET '${props.appDetail.api_base_url}/parameters?user=abc-123'`}>
|
||||
|
||||
```bash {{ title: 'cURL' }}
|
||||
curl -X GET '${props.appDetail.api_base_url}/parameters?user=abc-123' \
|
||||
--header 'Authorization: Bearer {api_key}'
|
||||
```
|
||||
|
||||
</CodeGroup>
|
||||
|
||||
<CodeGroup title="Response">
|
||||
```json {{ title: 'Response' }}
|
||||
{
|
||||
"user_input_form": [
|
||||
{
|
||||
"paragraph": {
|
||||
"label": "Query",
|
||||
"variable": "query",
|
||||
"required": true,
|
||||
"default": ""
|
||||
}
|
||||
}
|
||||
],
|
||||
"file_upload": {
|
||||
"image": {
|
||||
"enabled": false,
|
||||
"number_limits": 3,
|
||||
"detail": "high",
|
||||
"transfer_methods": [
|
||||
"remote_url",
|
||||
"local_file"
|
||||
]
|
||||
}
|
||||
},
|
||||
"system_parameters": {
|
||||
"file_size_limit": 15,
|
||||
"image_file_size_limit": 10,
|
||||
"audio_file_size_limit": 50,
|
||||
"video_file_size_limit": 100
|
||||
}
|
||||
}
|
||||
```
|
||||
</CodeGroup>
|
||||
</Col>
|
||||
</Row>
|
||||
|
||||
@ -25,22 +25,18 @@ const Popup: FC<PopupProps> = ({
|
||||
const language = useLanguage()
|
||||
const [searchText, setSearchText] = useState('')
|
||||
|
||||
const filteredModelList = modelList.filter(
|
||||
model => model.models.filter(
|
||||
(modelItem) => {
|
||||
if (modelItem.label[language] !== undefined)
|
||||
return modelItem.label[language].toLowerCase().includes(searchText.toLowerCase())
|
||||
const filteredModelList = modelList.map((model) => {
|
||||
const filteredModels = model.models.filter((modelItem) => {
|
||||
if (modelItem.label[language] !== undefined)
|
||||
return modelItem.label[language].toLowerCase().includes(searchText.toLowerCase())
|
||||
|
||||
let found = false
|
||||
Object.keys(modelItem.label).forEach((key) => {
|
||||
if (modelItem.label[key].toLowerCase().includes(searchText.toLowerCase()))
|
||||
found = true
|
||||
})
|
||||
return Object.values(modelItem.label).some(label =>
|
||||
label.toLowerCase().includes(searchText.toLowerCase()),
|
||||
)
|
||||
})
|
||||
|
||||
return found
|
||||
},
|
||||
).length,
|
||||
)
|
||||
return { ...model, models: filteredModels }
|
||||
}).filter(model => model.models.length > 0)
|
||||
|
||||
return (
|
||||
<div className='w-[320px] max-h-[480px] rounded-lg border-[0.5px] border-gray-200 bg-white shadow-lg overflow-y-auto'>
|
||||
|
||||
@ -4,6 +4,7 @@ import Link from 'next/link'
|
||||
import { useBoolean } from 'ahooks'
|
||||
import { useSelectedLayoutSegment } from 'next/navigation'
|
||||
import { Bars3Icon } from '@heroicons/react/20/solid'
|
||||
import { useContextSelector } from 'use-context-selector'
|
||||
import HeaderBillingBtn from '../billing/header-billing-btn'
|
||||
import AccountDropdown from './account-dropdown'
|
||||
import AppNav from './app-nav'
|
||||
@ -14,11 +15,12 @@ import ToolsNav from './tools-nav'
|
||||
import GithubStar from './github-star'
|
||||
import LicenseNav from './license-env'
|
||||
import { WorkspaceProvider } from '@/context/workspace-context'
|
||||
import { useAppContext } from '@/context/app-context'
|
||||
import AppContext, { useAppContext } from '@/context/app-context'
|
||||
import LogoSite from '@/app/components/base/logo/logo-site'
|
||||
import useBreakpoints, { MediaType } from '@/hooks/use-breakpoints'
|
||||
import { useProviderContext } from '@/context/provider-context'
|
||||
import { useModalContext } from '@/context/modal-context'
|
||||
import { LicenseStatus } from '@/types/feature'
|
||||
|
||||
const navClassName = `
|
||||
flex items-center relative mr-0 sm:mr-3 px-3 h-8 rounded-xl
|
||||
@ -28,7 +30,7 @@ const navClassName = `
|
||||
|
||||
const Header = () => {
|
||||
const { isCurrentWorkspaceEditor, isCurrentWorkspaceDatasetOperator } = useAppContext()
|
||||
|
||||
const systemFeatures = useContextSelector(AppContext, v => v.systemFeatures)
|
||||
const selectedSegment = useSelectedLayoutSegment()
|
||||
const media = useBreakpoints()
|
||||
const isMobile = media === MediaType.mobile
|
||||
@ -60,7 +62,7 @@ const Header = () => {
|
||||
<Link href="/apps" className='flex items-center mr-4'>
|
||||
<LogoSite className='object-contain' />
|
||||
</Link>
|
||||
<GithubStar />
|
||||
{systemFeatures.license.status === LicenseStatus.NONE && <GithubStar />}
|
||||
</>}
|
||||
</div>
|
||||
{isMobile && (
|
||||
@ -68,7 +70,7 @@ const Header = () => {
|
||||
<Link href="/apps" className='flex items-center mr-4'>
|
||||
<LogoSite />
|
||||
</Link>
|
||||
<GithubStar />
|
||||
{systemFeatures.license.status === LicenseStatus.NONE && <GithubStar />}
|
||||
</div>
|
||||
)}
|
||||
{!isMobile && (
|
||||
|
||||
@ -48,6 +48,7 @@ const getIcon = (type: BlockEnum, className: string) => {
|
||||
[BlockEnum.VariableAggregator]: <VariableX className={className} />,
|
||||
[BlockEnum.Assigner]: <Assigner className={className} />,
|
||||
[BlockEnum.Tool]: <VariableX className={className} />,
|
||||
[BlockEnum.IterationStart]: <VariableX className={className} />,
|
||||
[BlockEnum.Iteration]: <Iteration className={className} />,
|
||||
[BlockEnum.ParameterExtractor]: <ParameterExtractor className={className} />,
|
||||
[BlockEnum.DocExtractor]: <DocsExtractor className={className} />,
|
||||
|
||||
@ -271,13 +271,18 @@ export const useWorkflowRun = () => {
|
||||
} as any)
|
||||
}
|
||||
else {
|
||||
if (!iterParallelLogMap.has(data.parallel_run_id))
|
||||
iterParallelLogMap.set(data.parallel_run_id, [{ ...data, status: NodeRunningStatus.Running } as any])
|
||||
const nodeId = iterations?.node_id as string
|
||||
if (!iterParallelLogMap.has(nodeId as string))
|
||||
iterParallelLogMap.set(iterations?.node_id as string, new Map())
|
||||
|
||||
const currentIterLogMap = iterParallelLogMap.get(nodeId)!
|
||||
if (!currentIterLogMap.has(data.parallel_run_id))
|
||||
currentIterLogMap.set(data.parallel_run_id, [{ ...data, status: NodeRunningStatus.Running } as any])
|
||||
else
|
||||
iterParallelLogMap.get(data.parallel_run_id)!.push({ ...data, status: NodeRunningStatus.Running } as any)
|
||||
currentIterLogMap.get(data.parallel_run_id)!.push({ ...data, status: NodeRunningStatus.Running } as any)
|
||||
setIterParallelLogMap(iterParallelLogMap)
|
||||
if (iterations)
|
||||
iterations.details = Array.from(iterParallelLogMap.values())
|
||||
iterations.details = Array.from(currentIterLogMap.values())
|
||||
}
|
||||
}))
|
||||
}
|
||||
@ -373,7 +378,7 @@ export const useWorkflowRun = () => {
|
||||
if (iterations && iterations.details) {
|
||||
const iterRunID = data.execution_metadata?.parallel_mode_run_id
|
||||
|
||||
const currIteration = iterParallelLogMap.get(iterRunID)
|
||||
const currIteration = iterParallelLogMap.get(iterations.node_id)?.get(iterRunID)
|
||||
const nodeIndex = currIteration?.findIndex(node =>
|
||||
node.node_id === data.node_id && (
|
||||
node?.parallel_run_id === data.execution_metadata?.parallel_mode_run_id),
|
||||
@ -392,7 +397,9 @@ export const useWorkflowRun = () => {
|
||||
}
|
||||
}
|
||||
setIterParallelLogMap(iterParallelLogMap)
|
||||
iterations.details = Array.from(iterParallelLogMap.values())
|
||||
const iterLogMap = iterParallelLogMap.get(iterations.node_id)
|
||||
if (iterLogMap)
|
||||
iterations.details = Array.from(iterLogMap.values())
|
||||
}
|
||||
}))
|
||||
}
|
||||
|
||||
@ -33,6 +33,7 @@ export type Props = {
|
||||
showFileList?: boolean
|
||||
onGenerated?: (value: string) => void
|
||||
showCodeGenerator?: boolean
|
||||
className?: string
|
||||
}
|
||||
|
||||
export const languageMap = {
|
||||
@ -67,6 +68,7 @@ const CodeEditor: FC<Props> = ({
|
||||
showFileList,
|
||||
onGenerated,
|
||||
showCodeGenerator = false,
|
||||
className,
|
||||
}) => {
|
||||
const [isFocus, setIsFocus] = React.useState(false)
|
||||
const [isMounted, setIsMounted] = React.useState(false)
|
||||
@ -187,7 +189,7 @@ const CodeEditor: FC<Props> = ({
|
||||
)
|
||||
|
||||
return (
|
||||
<div className={cn(isExpand && 'h-full')}>
|
||||
<div className={cn(isExpand && 'h-full', className)}>
|
||||
{noWrapper
|
||||
? <div className='relative no-wrapper' style={{
|
||||
height: isExpand ? '100%' : (editorContentHeight) / 2 + CODE_EDITOR_LINE_HEIGHT, // In IDE, the last line can always be in lop line. So there is some blank space in the bottom.
|
||||
|
||||
@ -47,7 +47,6 @@ const Field: FC<Props> = ({
|
||||
triggerClassName='w-4 h-4 ml-1'
|
||||
/>
|
||||
)}
|
||||
|
||||
</div>
|
||||
<div className='flex'>
|
||||
{operations && <div>{operations}</div>}
|
||||
|
||||
@ -10,7 +10,7 @@ const ListNoDataPlaceholder: FC<Props> = ({
|
||||
children,
|
||||
}) => {
|
||||
return (
|
||||
<div className='flex rounded-md bg-gray-50 items-center min-h-[42px] justify-center leading-[18px] text-xs font-normal text-gray-500'>
|
||||
<div className='flex w-full rounded-[10px] bg-background-section items-center min-h-[42px] justify-center system-xs-regular text-text-tertiary'>
|
||||
{children}
|
||||
</div>
|
||||
)
|
||||
|
||||
@ -53,7 +53,7 @@ type Props = {
|
||||
|
||||
const MEMORY_DEFAULT: Memory = {
|
||||
window: { enabled: false, size: WINDOW_SIZE_DEFAULT },
|
||||
query_prompt_template: '',
|
||||
query_prompt_template: '{{#sys.query#}}',
|
||||
}
|
||||
|
||||
const MemoryConfig: FC<Props> = ({
|
||||
|
||||
@ -0,0 +1,39 @@
|
||||
'use client'
|
||||
import type { FC } from 'react'
|
||||
import React from 'react'
|
||||
import { useTranslation } from 'react-i18next'
|
||||
import VarReferenceVars from './var-reference-vars'
|
||||
import type { NodeOutPutVar, ValueSelector, Var } from '@/app/components/workflow/types'
|
||||
import ListEmpty from '@/app/components/base/list-empty'
|
||||
|
||||
type Props = {
|
||||
vars: NodeOutPutVar[]
|
||||
onChange: (value: ValueSelector, varDetail: Var) => void
|
||||
itemWidth?: number
|
||||
}
|
||||
const AssignedVarReferencePopup: FC<Props> = ({
|
||||
vars,
|
||||
onChange,
|
||||
itemWidth,
|
||||
}) => {
|
||||
const { t } = useTranslation()
|
||||
// max-h-[300px] overflow-y-auto todo: use portal to handle long list
|
||||
return (
|
||||
<div className='p-1 bg-components-panel-bg-bur rounded-lg border-[0.5px] border-components-panel-border shadow-lg w-[352px]' >
|
||||
{(!vars || vars.length === 0)
|
||||
? <ListEmpty
|
||||
title={t('workflow.nodes.assigner.noAssignedVars') || ''}
|
||||
description={t('workflow.nodes.assigner.assignedVarsDescription')}
|
||||
/>
|
||||
: <VarReferenceVars
|
||||
searchBoxClassName='mt-1'
|
||||
vars={vars}
|
||||
onChange={onChange}
|
||||
itemWidth={itemWidth}
|
||||
isSupportFileVar
|
||||
/>
|
||||
}
|
||||
</div >
|
||||
)
|
||||
}
|
||||
export default React.memo(AssignedVarReferencePopup)
|
||||
@ -60,6 +60,9 @@ type Props = {
|
||||
onRemove?: () => void
|
||||
typePlaceHolder?: string
|
||||
isSupportFileVar?: boolean
|
||||
placeholder?: string
|
||||
minWidth?: number
|
||||
popupFor?: 'assigned' | 'toAssigned'
|
||||
}
|
||||
|
||||
const VarReferencePicker: FC<Props> = ({
|
||||
@ -83,6 +86,9 @@ const VarReferencePicker: FC<Props> = ({
|
||||
onRemove,
|
||||
typePlaceHolder,
|
||||
isSupportFileVar = true,
|
||||
placeholder,
|
||||
minWidth,
|
||||
popupFor,
|
||||
}) => {
|
||||
const { t } = useTranslation()
|
||||
const store = useStoreApi()
|
||||
@ -261,7 +267,7 @@ const VarReferencePicker: FC<Props> = ({
|
||||
<AddButton onClick={() => { }}></AddButton>
|
||||
</div>
|
||||
)
|
||||
: (<div ref={!isSupportConstantValue ? triggerRef : null} className={cn((open || isFocus) ? 'border-gray-300' : 'border-gray-100', 'relative group/wrap flex items-center w-full h-8', !isSupportConstantValue && 'p-1 rounded-lg bg-gray-100 border', isInTable && 'bg-transparent border-none')}>
|
||||
: (<div ref={!isSupportConstantValue ? triggerRef : null} className={cn((open || isFocus) ? 'border-gray-300' : 'border-gray-100', 'relative group/wrap flex items-center w-full h-8', !isSupportConstantValue && 'p-1 rounded-lg bg-gray-100 border', isInTable && 'bg-transparent border-none', readonly && 'bg-components-input-bg-disabled')}>
|
||||
{isSupportConstantValue
|
||||
? <div onClick={(e) => {
|
||||
e.stopPropagation()
|
||||
@ -285,7 +291,7 @@ const VarReferencePicker: FC<Props> = ({
|
||||
/>
|
||||
</div>
|
||||
: (!hasValue && <div className='ml-1.5 mr-1'>
|
||||
<Variable02 className='w-3.5 h-3.5 text-gray-400' />
|
||||
<Variable02 className={`w-4 h-4 ${readonly ? 'text-components-input-text-disabled' : 'text-components-input-text-placeholder'}`} />
|
||||
</div>)}
|
||||
{isConstant
|
||||
? (
|
||||
@ -329,17 +335,17 @@ const VarReferencePicker: FC<Props> = ({
|
||||
{!hasValue && <Variable02 className='w-3.5 h-3.5' />}
|
||||
{isEnv && <Env className='w-3.5 h-3.5 text-util-colors-violet-violet-600' />}
|
||||
{isChatVar && <BubbleX className='w-3.5 h-3.5 text-util-colors-teal-teal-700' />}
|
||||
<div className={cn('ml-0.5 text-xs font-medium truncate', (isEnv || isChatVar) && '!text-text-secondary')} title={varName} style={{
|
||||
<div className={cn('ml-0.5 text-xs font-medium truncate', isEnv && '!text-text-secondary', isChatVar && 'text-util-colors-teal-teal-700')} title={varName} style={{
|
||||
maxWidth: maxVarNameWidth,
|
||||
}}>{varName}</div>
|
||||
</div>
|
||||
<div className='ml-0.5 text-xs font-normal text-gray-500 capitalize truncate' title={type} style={{
|
||||
<div className='ml-0.5 capitalize truncate text-text-tertiary text-center system-xs-regular' title={type} style={{
|
||||
maxWidth: maxTypeWidth,
|
||||
}}>{type}</div>
|
||||
{!isValidVar && <RiErrorWarningFill className='ml-0.5 w-3 h-3 text-[#D92D20]' />}
|
||||
</>
|
||||
)
|
||||
: <div className='text-[13px] font-normal text-gray-400'>{t('workflow.common.setVarValuePlaceholder')}</div>}
|
||||
: <div className={`overflow-hidden ${readonly ? 'text-components-input-text-disabled' : 'text-components-input-text-placeholder'} text-ellipsis system-sm-regular`}>{placeholder ?? t('workflow.common.setVarValuePlaceholder')}</div>}
|
||||
</div>
|
||||
</Tooltip>
|
||||
</div>
|
||||
@ -378,12 +384,13 @@ const VarReferencePicker: FC<Props> = ({
|
||||
</WrapElem>
|
||||
<PortalToFollowElemContent style={{
|
||||
zIndex: 100,
|
||||
}}>
|
||||
}} className='mt-1'>
|
||||
{!isConstant && (
|
||||
<VarReferencePopup
|
||||
vars={outputVars}
|
||||
popupFor={popupFor}
|
||||
onChange={handleVarReferenceChange}
|
||||
itemWidth={isAddBtnTrigger ? 260 : triggerWidth}
|
||||
itemWidth={isAddBtnTrigger ? 260 : (minWidth || triggerWidth)}
|
||||
isSupportFileVar={isSupportFileVar}
|
||||
/>
|
||||
)}
|
||||
|
||||
@ -1,33 +1,64 @@
|
||||
'use client'
|
||||
import type { FC } from 'react'
|
||||
import React from 'react'
|
||||
import { useTranslation } from 'react-i18next'
|
||||
import { useContext } from 'use-context-selector'
|
||||
import VarReferenceVars from './var-reference-vars'
|
||||
import type { NodeOutPutVar, ValueSelector, Var } from '@/app/components/workflow/types'
|
||||
import ListEmpty from '@/app/components/base/list-empty'
|
||||
import { LanguagesSupported } from '@/i18n/language'
|
||||
import I18n from '@/context/i18n'
|
||||
|
||||
type Props = {
|
||||
vars: NodeOutPutVar[]
|
||||
popupFor?: 'assigned' | 'toAssigned'
|
||||
onChange: (value: ValueSelector, varDetail: Var) => void
|
||||
itemWidth?: number
|
||||
isSupportFileVar?: boolean
|
||||
}
|
||||
const VarReferencePopup: FC<Props> = ({
|
||||
vars,
|
||||
popupFor,
|
||||
onChange,
|
||||
itemWidth,
|
||||
isSupportFileVar = true,
|
||||
}) => {
|
||||
const { t } = useTranslation()
|
||||
const { locale } = useContext(I18n)
|
||||
// max-h-[300px] overflow-y-auto todo: use portal to handle long list
|
||||
return (
|
||||
<div className='p-1 bg-white rounded-lg border border-gray-200 shadow-lg space-y-1' style={{
|
||||
width: itemWidth || 228,
|
||||
}}>
|
||||
<VarReferenceVars
|
||||
searchBoxClassName='mt-1'
|
||||
vars={vars}
|
||||
onChange={onChange}
|
||||
itemWidth={itemWidth}
|
||||
isSupportFileVar={isSupportFileVar}
|
||||
/>
|
||||
{((!vars || vars.length === 0) && popupFor)
|
||||
? (popupFor === 'toAssigned'
|
||||
? (
|
||||
<ListEmpty
|
||||
title={t('workflow.variableReference.noAvailableVars') || ''}
|
||||
description={<div className='text-text-tertiary system-xs-regular'>
|
||||
{t('workflow.variableReference.noVarsForOperation')}
|
||||
</div>}
|
||||
/>
|
||||
)
|
||||
: (
|
||||
<ListEmpty
|
||||
title={t('workflow.variableReference.noAssignedVars') || ''}
|
||||
description={<div className='text-text-tertiary system-xs-regular'>
|
||||
{t('workflow.variableReference.assignedVarsDescription')}
|
||||
<a target='_blank' rel='noopener noreferrer'
|
||||
className='text-text-accent-secondary'
|
||||
href={locale !== LanguagesSupported[1] ? 'https://docs.dify.ai/guides/workflow/variables#conversation-variables' : `https://docs.dify.ai/${locale.toLowerCase()}/guides/workflow/variables#hui-hua-bian-liang`}>{t('workflow.variableReference.conversationVars')}</a>
|
||||
</div>}
|
||||
/>
|
||||
))
|
||||
: <VarReferenceVars
|
||||
searchBoxClassName='mt-1'
|
||||
vars={vars}
|
||||
onChange={onChange}
|
||||
itemWidth={itemWidth}
|
||||
isSupportFileVar={isSupportFileVar}
|
||||
/>
|
||||
}
|
||||
</div >
|
||||
)
|
||||
}
|
||||
|
||||
@ -24,6 +24,7 @@ import QuestionClassifyDefault from '@/app/components/workflow/nodes/question-cl
|
||||
import HTTPDefault from '@/app/components/workflow/nodes/http/default'
|
||||
import ToolDefault from '@/app/components/workflow/nodes/tool/default'
|
||||
import VariableAssigner from '@/app/components/workflow/nodes/variable-assigner/default'
|
||||
import Assigner from '@/app/components/workflow/nodes/assigner/default'
|
||||
import ParameterExtractorDefault from '@/app/components/workflow/nodes/parameter-extractor/default'
|
||||
import IterationDefault from '@/app/components/workflow/nodes/iteration/default'
|
||||
import { ssePost } from '@/service/base'
|
||||
@ -39,6 +40,7 @@ const { checkValid: checkQuestionClassifyValid } = QuestionClassifyDefault
|
||||
const { checkValid: checkHttpValid } = HTTPDefault
|
||||
const { checkValid: checkToolValid } = ToolDefault
|
||||
const { checkValid: checkVariableAssignerValid } = VariableAssigner
|
||||
const { checkValid: checkAssignerValid } = Assigner
|
||||
const { checkValid: checkParameterExtractorValid } = ParameterExtractorDefault
|
||||
const { checkValid: checkIterationValid } = IterationDefault
|
||||
|
||||
@ -51,7 +53,7 @@ const checkValidFns: Record<BlockEnum, Function> = {
|
||||
[BlockEnum.QuestionClassifier]: checkQuestionClassifyValid,
|
||||
[BlockEnum.HttpRequest]: checkHttpValid,
|
||||
[BlockEnum.Tool]: checkToolValid,
|
||||
[BlockEnum.VariableAssigner]: checkVariableAssignerValid,
|
||||
[BlockEnum.VariableAssigner]: checkAssignerValid,
|
||||
[BlockEnum.VariableAggregator]: checkVariableAssignerValid,
|
||||
[BlockEnum.ParameterExtractor]: checkParameterExtractorValid,
|
||||
[BlockEnum.Iteration]: checkIterationValid,
|
||||
|
||||
@ -0,0 +1,128 @@
|
||||
import type { FC } from 'react'
|
||||
import { useState } from 'react'
|
||||
import {
|
||||
RiArrowDownSLine,
|
||||
RiCheckLine,
|
||||
} from '@remixicon/react'
|
||||
import classNames from 'classnames'
|
||||
import { useTranslation } from 'react-i18next'
|
||||
import type { WriteMode } from '../types'
|
||||
import { getOperationItems } from '../utils'
|
||||
import {
|
||||
PortalToFollowElem,
|
||||
PortalToFollowElemContent,
|
||||
PortalToFollowElemTrigger,
|
||||
} from '@/app/components/base/portal-to-follow-elem'
|
||||
import type { VarType } from '@/app/components/workflow/types'
|
||||
import Divider from '@/app/components/base/divider'
|
||||
|
||||
type Item = {
|
||||
value: string | number
|
||||
name: string
|
||||
}
|
||||
|
||||
type OperationSelectorProps = {
|
||||
value: string | number
|
||||
onSelect: (value: Item) => void
|
||||
placeholder?: string
|
||||
disabled?: boolean
|
||||
className?: string
|
||||
popupClassName?: string
|
||||
assignedVarType?: VarType
|
||||
writeModeTypes?: WriteMode[]
|
||||
writeModeTypesArr?: WriteMode[]
|
||||
writeModeTypesNum?: WriteMode[]
|
||||
}
|
||||
|
||||
const i18nPrefix = 'workflow.nodes.assigner'
|
||||
|
||||
const OperationSelector: FC<OperationSelectorProps> = ({
|
||||
value,
|
||||
onSelect,
|
||||
disabled = false,
|
||||
className,
|
||||
popupClassName,
|
||||
assignedVarType,
|
||||
writeModeTypes,
|
||||
writeModeTypesArr,
|
||||
writeModeTypesNum,
|
||||
}) => {
|
||||
const { t } = useTranslation()
|
||||
const [open, setOpen] = useState(false)
|
||||
|
||||
const items = getOperationItems(assignedVarType, writeModeTypes, writeModeTypesArr, writeModeTypesNum)
|
||||
|
||||
const selectedItem = items.find(item => item.value === value)
|
||||
|
||||
return (
|
||||
<PortalToFollowElem
|
||||
open={open}
|
||||
onOpenChange={setOpen}
|
||||
placement='bottom-start'
|
||||
offset={4}
|
||||
>
|
||||
<PortalToFollowElemTrigger
|
||||
onClick={() => !disabled && setOpen(v => !v)}
|
||||
>
|
||||
<div
|
||||
className={classNames(
|
||||
'flex items-center px-2 py-1 gap-0.5 rounded-lg bg-components-input-bg-normal',
|
||||
disabled ? 'cursor-not-allowed !bg-components-input-bg-disabled' : 'cursor-pointer hover:bg-state-base-hover-alt',
|
||||
open && 'bg-state-base-hover-alt',
|
||||
className,
|
||||
)}
|
||||
>
|
||||
<div className='flex p-1 items-center'>
|
||||
<span
|
||||
className={`truncate overflow-hidden text-ellipsis system-sm-regular
|
||||
${selectedItem ? 'text-components-input-text-filled' : 'text-components-input-text-disabled'}`}
|
||||
>
|
||||
{selectedItem?.name ? t(`${i18nPrefix}.operations.${selectedItem?.name}`) : t(`${i18nPrefix}.operations.title`)}
|
||||
</span>
|
||||
</div>
|
||||
<RiArrowDownSLine className={`h-4 w-4 text-text-quaternary ${disabled && 'text-components-input-text-placeholder'} ${open && 'text-text-secondary'}`} />
|
||||
</div>
|
||||
</PortalToFollowElemTrigger>
|
||||
|
||||
<PortalToFollowElemContent className={`z-20 ${popupClassName}`}>
|
||||
<div className='flex w-[140px] flex-col items-start rounded-xl border-[0.5px] border-components-panel-border bg-components-panel-bg-blur shadow-lg'>
|
||||
<div className='flex p-1 flex-col items-start self-stretch'>
|
||||
<div className='flex px-3 pt-1 pb-0.5 items-start self-stretch'>
|
||||
<div className='flex grow text-text-tertiary system-xs-medium-uppercase'>{t(`${i18nPrefix}.operations.title`)}</div>
|
||||
</div>
|
||||
{items.map(item => (
|
||||
item.value === 'divider'
|
||||
? (
|
||||
<Divider key="divider" className="my-1" />
|
||||
)
|
||||
: (
|
||||
<div
|
||||
key={item.value}
|
||||
className={classNames(
|
||||
'flex items-center px-2 py-1 gap-1 self-stretch rounded-lg',
|
||||
'cursor-pointer hover:bg-state-base-hover',
|
||||
)}
|
||||
onClick={() => {
|
||||
onSelect(item)
|
||||
setOpen(false)
|
||||
}}
|
||||
>
|
||||
<div className='flex min-h-5 px-1 items-center gap-1 grow'>
|
||||
<span className={'flex flex-grow text-text-secondary system-sm-medium'}>{t(`${i18nPrefix}.operations.${item.name}`)}</span>
|
||||
</div>
|
||||
{item.value === value && (
|
||||
<div className='flex justify-center items-center'>
|
||||
<RiCheckLine className='h-4 w-4 text-text-accent' />
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
)
|
||||
))}
|
||||
</div>
|
||||
</div>
|
||||
</PortalToFollowElemContent>
|
||||
</PortalToFollowElem>
|
||||
)
|
||||
}
|
||||
|
||||
export default OperationSelector
|
||||
@ -0,0 +1,227 @@
|
||||
'use client'
|
||||
import type { FC } from 'react'
|
||||
import { useTranslation } from 'react-i18next'
|
||||
import React, { useCallback } from 'react'
|
||||
import produce from 'immer'
|
||||
import { RiDeleteBinLine } from '@remixicon/react'
|
||||
import OperationSelector from '../operation-selector'
|
||||
import { AssignerNodeInputType, WriteMode } from '../../types'
|
||||
import type { AssignerNodeOperation } from '../../types'
|
||||
import ListNoDataPlaceholder from '@/app/components/workflow/nodes/_base/components/list-no-data-placeholder'
|
||||
import VarReferencePicker from '@/app/components/workflow/nodes/_base/components/variable/var-reference-picker'
|
||||
import type { ValueSelector, Var, VarType } from '@/app/components/workflow/types'
|
||||
import { CodeLanguage } from '@/app/components/workflow/nodes/code/types'
|
||||
import ActionButton from '@/app/components/base/action-button'
|
||||
import Input from '@/app/components/base/input'
|
||||
import Textarea from '@/app/components/base/textarea'
|
||||
import CodeEditor from '@/app/components/workflow/nodes/_base/components/editor/code-editor'
|
||||
|
||||
type Props = {
|
||||
readonly: boolean
|
||||
nodeId: string
|
||||
list: AssignerNodeOperation[]
|
||||
onChange: (list: AssignerNodeOperation[], value?: ValueSelector) => void
|
||||
onOpen?: (index: number) => void
|
||||
filterVar?: (payload: Var, valueSelector: ValueSelector) => boolean
|
||||
filterToAssignedVar?: (payload: Var, assignedVarType: VarType, write_mode: WriteMode) => boolean
|
||||
getAssignedVarType?: (valueSelector: ValueSelector) => VarType
|
||||
getToAssignedVarType?: (assignedVarType: VarType, write_mode: WriteMode) => VarType
|
||||
writeModeTypes?: WriteMode[]
|
||||
writeModeTypesArr?: WriteMode[]
|
||||
writeModeTypesNum?: WriteMode[]
|
||||
}
|
||||
|
||||
const VarList: FC<Props> = ({
|
||||
readonly,
|
||||
nodeId,
|
||||
list,
|
||||
onChange,
|
||||
onOpen = () => { },
|
||||
filterVar,
|
||||
filterToAssignedVar,
|
||||
getAssignedVarType,
|
||||
getToAssignedVarType,
|
||||
writeModeTypes,
|
||||
writeModeTypesArr,
|
||||
writeModeTypesNum,
|
||||
}) => {
|
||||
const { t } = useTranslation()
|
||||
const handleAssignedVarChange = useCallback((index: number) => {
|
||||
return (value: ValueSelector | string) => {
|
||||
const newList = produce(list, (draft) => {
|
||||
draft[index].variable_selector = value as ValueSelector
|
||||
draft[index].operation = WriteMode.overwrite
|
||||
draft[index].value = undefined
|
||||
})
|
||||
onChange(newList, value as ValueSelector)
|
||||
}
|
||||
}, [list, onChange])
|
||||
|
||||
const handleOperationChange = useCallback((index: number) => {
|
||||
return (item: { value: string | number }) => {
|
||||
const newList = produce(list, (draft) => {
|
||||
draft[index].operation = item.value as WriteMode
|
||||
draft[index].value = '' // Clear value when operation changes
|
||||
if (item.value === WriteMode.set || item.value === WriteMode.increment || item.value === WriteMode.decrement
|
||||
|| item.value === WriteMode.multiply || item.value === WriteMode.divide)
|
||||
draft[index].input_type = AssignerNodeInputType.constant
|
||||
else
|
||||
draft[index].input_type = AssignerNodeInputType.variable
|
||||
})
|
||||
onChange(newList)
|
||||
}
|
||||
}, [list, onChange])
|
||||
|
||||
const handleToAssignedVarChange = useCallback((index: number) => {
|
||||
return (value: ValueSelector | string | number) => {
|
||||
const newList = produce(list, (draft) => {
|
||||
draft[index].value = value as ValueSelector
|
||||
})
|
||||
onChange(newList, value as ValueSelector)
|
||||
}
|
||||
}, [list, onChange])
|
||||
|
||||
const handleVarRemove = useCallback((index: number) => {
|
||||
return () => {
|
||||
const newList = produce(list, (draft) => {
|
||||
draft.splice(index, 1)
|
||||
})
|
||||
onChange(newList)
|
||||
}
|
||||
}, [list, onChange])
|
||||
|
||||
const handleOpen = useCallback((index: number) => {
|
||||
return () => onOpen(index)
|
||||
}, [onOpen])
|
||||
|
||||
const handleFilterToAssignedVar = useCallback((index: number) => {
|
||||
return (payload: Var, valueSelector: ValueSelector) => {
|
||||
const item = list[index]
|
||||
const assignedVarType = item.variable_selector ? getAssignedVarType?.(item.variable_selector) : undefined
|
||||
|
||||
if (!filterToAssignedVar || !item.variable_selector || !assignedVarType || !item.operation)
|
||||
return true
|
||||
|
||||
return filterToAssignedVar(
|
||||
payload,
|
||||
assignedVarType,
|
||||
item.operation,
|
||||
)
|
||||
}
|
||||
}, [list, filterToAssignedVar, getAssignedVarType])
|
||||
|
||||
if (list.length === 0) {
|
||||
return (
|
||||
<ListNoDataPlaceholder>
|
||||
{t('workflow.nodes.assigner.noVarTip')}
|
||||
</ListNoDataPlaceholder>
|
||||
)
|
||||
}
|
||||
|
||||
return (
|
||||
<div className='flex flex-col items-start gap-4 self-stretch'>
|
||||
{list.map((item, index) => {
|
||||
const assignedVarType = item.variable_selector ? getAssignedVarType?.(item.variable_selector) : undefined
|
||||
const toAssignedVarType = (assignedVarType && item.operation && getToAssignedVarType)
|
||||
? getToAssignedVarType(assignedVarType, item.operation)
|
||||
: undefined
|
||||
|
||||
return (
|
||||
<div className='flex items-start gap-1 self-stretch' key={index}>
|
||||
<div className='flex flex-col items-start gap-1 flex-grow'>
|
||||
<div className='flex items-center gap-1 self-stretch'>
|
||||
<VarReferencePicker
|
||||
readonly={readonly}
|
||||
nodeId={nodeId}
|
||||
isShowNodeName
|
||||
value={item.variable_selector || []}
|
||||
onChange={handleAssignedVarChange(index)}
|
||||
onOpen={handleOpen(index)}
|
||||
filterVar={filterVar}
|
||||
placeholder={t('workflow.nodes.assigner.selectAssignedVariable') as string}
|
||||
minWidth={352}
|
||||
popupFor='assigned'
|
||||
className='w-full'
|
||||
/>
|
||||
<OperationSelector
|
||||
value={item.operation}
|
||||
placeholder='Operation'
|
||||
disabled={!item.variable_selector || item.variable_selector.length === 0}
|
||||
onSelect={handleOperationChange(index)}
|
||||
assignedVarType={assignedVarType}
|
||||
writeModeTypes={writeModeTypes}
|
||||
writeModeTypesArr={writeModeTypesArr}
|
||||
writeModeTypesNum={writeModeTypesNum}
|
||||
/>
|
||||
</div>
|
||||
{item.operation !== WriteMode.clear && item.operation !== WriteMode.set
|
||||
&& !writeModeTypesNum?.includes(item.operation)
|
||||
&& (
|
||||
<VarReferencePicker
|
||||
readonly={readonly || !item.variable_selector || !item.operation}
|
||||
nodeId={nodeId}
|
||||
isShowNodeName
|
||||
value={item.value}
|
||||
onChange={handleToAssignedVarChange(index)}
|
||||
filterVar={handleFilterToAssignedVar(index)}
|
||||
valueTypePlaceHolder={toAssignedVarType}
|
||||
placeholder={t('workflow.nodes.assigner.setParameter') as string}
|
||||
minWidth={352}
|
||||
popupFor='toAssigned'
|
||||
className='w-full'
|
||||
/>
|
||||
)
|
||||
}
|
||||
{item.operation === WriteMode.set && assignedVarType && (
|
||||
<>
|
||||
{assignedVarType === 'number' && (
|
||||
<Input
|
||||
type="number"
|
||||
value={item.value as number}
|
||||
onChange={e => handleToAssignedVarChange(index)(Number(e.target.value))}
|
||||
className='w-full'
|
||||
/>
|
||||
)}
|
||||
{assignedVarType === 'string' && (
|
||||
<Textarea
|
||||
value={item.value as string}
|
||||
onChange={e => handleToAssignedVarChange(index)(e.target.value)}
|
||||
className='w-full'
|
||||
/>
|
||||
)}
|
||||
{assignedVarType === 'object' && (
|
||||
<CodeEditor
|
||||
value={item.value as string}
|
||||
language={CodeLanguage.json}
|
||||
onChange={value => handleToAssignedVarChange(index)(value)}
|
||||
className='w-full'
|
||||
readOnly={readonly}
|
||||
/>
|
||||
)}
|
||||
</>
|
||||
)}
|
||||
{writeModeTypesNum?.includes(item.operation)
|
||||
&& <Input
|
||||
type="number"
|
||||
value={item.value as number}
|
||||
onChange={e => handleToAssignedVarChange(index)(Number(e.target.value))}
|
||||
placeholder="Enter number value..."
|
||||
className='w-full'
|
||||
/>
|
||||
}
|
||||
</div>
|
||||
<ActionButton
|
||||
size='l'
|
||||
className='flex-shrink-0 group hover:!bg-state-destructive-hover'
|
||||
onClick={handleVarRemove(index)}
|
||||
>
|
||||
<RiDeleteBinLine className='text-text-tertiary w-4 h-4 group-hover:text-text-destructive' />
|
||||
</ActionButton>
|
||||
</div>
|
||||
)
|
||||
},
|
||||
)}
|
||||
</div>
|
||||
)
|
||||
}
|
||||
export default React.memo(VarList)
|
||||
@ -0,0 +1,39 @@
|
||||
import { useCallback } from 'react'
|
||||
import produce from 'immer'
|
||||
import type { AssignerNodeOperation, AssignerNodeType } from '../../types'
|
||||
import { AssignerNodeInputType, WriteMode } from '../../types'
|
||||
|
||||
type Params = {
|
||||
id: string
|
||||
inputs: AssignerNodeType
|
||||
setInputs: (newInputs: AssignerNodeType) => void
|
||||
}
|
||||
function useVarList({
|
||||
inputs,
|
||||
setInputs,
|
||||
}: Params) {
|
||||
const handleVarListChange = useCallback((newList: AssignerNodeOperation[]) => {
|
||||
const newInputs = produce(inputs, (draft) => {
|
||||
draft.items = newList
|
||||
})
|
||||
setInputs(newInputs)
|
||||
}, [inputs, setInputs])
|
||||
|
||||
const handleAddVariable = useCallback(() => {
|
||||
const newInputs = produce(inputs, (draft) => {
|
||||
draft.items.push({
|
||||
variable_selector: [],
|
||||
input_type: AssignerNodeInputType.constant,
|
||||
operation: WriteMode.overwrite,
|
||||
value: '',
|
||||
})
|
||||
})
|
||||
setInputs(newInputs)
|
||||
}, [inputs, setInputs])
|
||||
return {
|
||||
handleVarListChange,
|
||||
handleAddVariable,
|
||||
}
|
||||
}
|
||||
|
||||
export default useVarList
|
||||
@ -6,9 +6,8 @@ const i18nPrefix = 'workflow.errorMsg'
|
||||
|
||||
const nodeDefault: NodeDefault<AssignerNodeType> = {
|
||||
defaultValue: {
|
||||
assigned_variable_selector: [],
|
||||
write_mode: WriteMode.Overwrite,
|
||||
input_variable_selector: [],
|
||||
version: '2',
|
||||
items: [],
|
||||
},
|
||||
getAvailablePrevNodes(isChatMode: boolean) {
|
||||
const nodes = isChatMode
|
||||
@ -23,18 +22,25 @@ const nodeDefault: NodeDefault<AssignerNodeType> = {
|
||||
checkValid(payload: AssignerNodeType, t: any) {
|
||||
let errorMessages = ''
|
||||
const {
|
||||
assigned_variable_selector: assignedVarSelector,
|
||||
write_mode: writeMode,
|
||||
input_variable_selector: toAssignerVarSelector,
|
||||
items: operationItems,
|
||||
} = payload
|
||||
|
||||
if (!errorMessages && !assignedVarSelector?.length)
|
||||
errorMessages = t(`${i18nPrefix}.fieldRequired`, { field: t('workflow.nodes.assigner.assignedVariable') })
|
||||
operationItems?.forEach((value) => {
|
||||
if (!errorMessages && !value.variable_selector?.length)
|
||||
errorMessages = t(`${i18nPrefix}.fieldRequired`, { field: t('workflow.nodes.assigner.assignedVariable') })
|
||||
|
||||
if (!errorMessages && writeMode !== WriteMode.Clear) {
|
||||
if (!toAssignerVarSelector?.length)
|
||||
errorMessages = t(`${i18nPrefix}.fieldRequired`, { field: t('workflow.nodes.assigner.variable') })
|
||||
}
|
||||
if (!errorMessages && value.operation !== WriteMode.clear) {
|
||||
if (value.operation === WriteMode.set || value.operation === WriteMode.increment
|
||||
|| value.operation === WriteMode.decrement || value.operation === WriteMode.multiply
|
||||
|| value.operation === WriteMode.divide) {
|
||||
if (!value.value && typeof value.value !== 'number')
|
||||
errorMessages = t(`${i18nPrefix}.fieldRequired`, { field: t('workflow.nodes.assigner.variable') })
|
||||
}
|
||||
else if (!value.value?.length) {
|
||||
errorMessages = t(`${i18nPrefix}.fieldRequired`, { field: t('workflow.nodes.assigner.variable') })
|
||||
}
|
||||
}
|
||||
})
|
||||
|
||||
return {
|
||||
isValid: !errorMessages,
|
||||
|
||||
70
web/app/components/workflow/nodes/assigner/hooks.ts
Normal file
70
web/app/components/workflow/nodes/assigner/hooks.ts
Normal file
@ -0,0 +1,70 @@
|
||||
import { useCallback } from 'react'
|
||||
import {
|
||||
useNodes,
|
||||
} from 'reactflow'
|
||||
import { uniqBy } from 'lodash-es'
|
||||
import {
|
||||
useIsChatMode,
|
||||
useWorkflow,
|
||||
useWorkflowVariables,
|
||||
} from '../../hooks'
|
||||
import type {
|
||||
Node,
|
||||
Var,
|
||||
} from '../../types'
|
||||
import { AssignerNodeInputType, WriteMode } from './types'
|
||||
|
||||
export const useGetAvailableVars = () => {
|
||||
const nodes: Node[] = useNodes()
|
||||
const { getBeforeNodesInSameBranchIncludeParent } = useWorkflow()
|
||||
const { getNodeAvailableVars } = useWorkflowVariables()
|
||||
const isChatMode = useIsChatMode()
|
||||
const getAvailableVars = useCallback((nodeId: string, handleId: string, filterVar: (v: Var) => boolean, hideEnv = false) => {
|
||||
const availableNodes: Node[] = []
|
||||
const currentNode = nodes.find(node => node.id === nodeId)!
|
||||
|
||||
if (!currentNode)
|
||||
return []
|
||||
|
||||
const beforeNodes = getBeforeNodesInSameBranchIncludeParent(nodeId)
|
||||
availableNodes.push(...beforeNodes)
|
||||
const parentNode = nodes.find(node => node.id === currentNode.parentId)
|
||||
|
||||
if (hideEnv) {
|
||||
return getNodeAvailableVars({
|
||||
parentNode,
|
||||
beforeNodes: uniqBy(availableNodes, 'id').filter(node => node.id !== nodeId),
|
||||
isChatMode,
|
||||
hideEnv,
|
||||
hideChatVar: hideEnv,
|
||||
filterVar,
|
||||
})
|
||||
.map(node => ({
|
||||
...node,
|
||||
vars: node.isStartNode ? node.vars.filter(v => !v.variable.startsWith('sys.')) : node.vars,
|
||||
}))
|
||||
.filter(item => item.vars.length > 0)
|
||||
}
|
||||
|
||||
return getNodeAvailableVars({
|
||||
parentNode,
|
||||
beforeNodes: uniqBy(availableNodes, 'id').filter(node => node.id !== nodeId),
|
||||
isChatMode,
|
||||
filterVar,
|
||||
})
|
||||
}, [nodes, getBeforeNodesInSameBranchIncludeParent, getNodeAvailableVars, isChatMode])
|
||||
|
||||
return getAvailableVars
|
||||
}
|
||||
|
||||
export const useHandleAddOperationItem = () => {
|
||||
return useCallback((list: any[]) => {
|
||||
const newItem = {
|
||||
variable_selector: [],
|
||||
write_mode: WriteMode.overwrite,
|
||||
input_type: AssignerNodeInputType.variable,
|
||||
value: '',
|
||||
}
|
||||
return [...list, newItem]
|
||||
}, [])
|
||||
}
|
||||
@ -15,31 +15,71 @@ const NodeComponent: FC<NodeProps<AssignerNodeType>> = ({
|
||||
const { t } = useTranslation()
|
||||
|
||||
const nodes: Node[] = useNodes()
|
||||
const { assigned_variable_selector: variable, write_mode: writeMode } = data
|
||||
if (data.version === '2') {
|
||||
const { items: operationItems } = data
|
||||
const validOperationItems = operationItems?.filter(item =>
|
||||
item.variable_selector && item.variable_selector.length > 0,
|
||||
) || []
|
||||
|
||||
if (validOperationItems.length === 0) {
|
||||
return (
|
||||
<div className='relative flex flex-col px-3 py-1 gap-0.5 items-start self-stretch'>
|
||||
<div className='flex flex-col items-start gap-1 self-stretch'>
|
||||
<div className='flex px-[5px] py-1 items-center gap-1 self-stretch rounded-md bg-workflow-block-parma-bg'>
|
||||
<div className='flex-1 text-text-tertiary system-xs-medium'>{t(`${i18nPrefix}.varNotSet`)}</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
)
|
||||
}
|
||||
return (
|
||||
<div className='relative flex flex-col px-3 py-1 gap-0.5 items-start self-stretch'>
|
||||
{operationItems.map((value, index) => {
|
||||
const variable = value.variable_selector
|
||||
if (!variable || variable.length === 0)
|
||||
return null
|
||||
const isSystem = isSystemVar(variable)
|
||||
const isEnv = isENV(variable)
|
||||
const isChatVar = isConversationVar(variable)
|
||||
const node = isSystem ? nodes.find(node => node.data.type === BlockEnum.Start) : nodes.find(node => node.id === variable[0])
|
||||
const varName = isSystem ? `sys.${variable[variable.length - 1]}` : variable.slice(1).join('.')
|
||||
return (
|
||||
<NodeVariableItem
|
||||
key={index}
|
||||
node={node as Node}
|
||||
isEnv={isEnv}
|
||||
isChatVar={isChatVar}
|
||||
writeMode={value.operation}
|
||||
varName={varName}
|
||||
className='bg-workflow-block-parma-bg'
|
||||
/>
|
||||
)
|
||||
})}
|
||||
</div>
|
||||
)
|
||||
}
|
||||
// Legacy version
|
||||
const { assigned_variable_selector: variable, write_mode: writeMode } = data as any
|
||||
|
||||
if (!variable || variable.length === 0)
|
||||
return null
|
||||
|
||||
const isSystem = isSystemVar(variable)
|
||||
const isEnv = isENV(variable)
|
||||
const isChatVar = isConversationVar(variable)
|
||||
|
||||
const node = isSystem ? nodes.find(node => node.data.type === BlockEnum.Start) : nodes.find(node => node.id === variable[0])
|
||||
const varName = isSystem ? `sys.${variable[variable.length - 1]}` : variable.slice(1).join('.')
|
||||
|
||||
return (
|
||||
<div className='relative px-3'>
|
||||
<div className='mb-1 system-2xs-medium-uppercase text-text-tertiary'>{t(`${i18nPrefix}.assignedVariable`)}</div>
|
||||
<div className='relative flex flex-col px-3 py-1 gap-0.5 items-start self-stretch'>
|
||||
<NodeVariableItem
|
||||
node={node as Node}
|
||||
isEnv={isEnv}
|
||||
isChatVar={isChatVar}
|
||||
varName={varName}
|
||||
writeMode={writeMode}
|
||||
className='bg-workflow-block-parma-bg'
|
||||
/>
|
||||
<div className='my-2 flex justify-between items-center h-[22px] px-[5px] bg-workflow-block-parma-bg radius-sm'>
|
||||
<div className='system-xs-medium-uppercase text-text-tertiary'>{t(`${i18nPrefix}.writeMode`)}</div>
|
||||
<div className='system-xs-medium text-text-secondary'>{t(`${i18nPrefix}.${writeMode}`)}</div>
|
||||
</div>
|
||||
</div>
|
||||
)
|
||||
}
|
||||
|
||||
@ -1,15 +1,15 @@
|
||||
import type { FC } from 'react'
|
||||
import React from 'react'
|
||||
import { useTranslation } from 'react-i18next'
|
||||
|
||||
import VarReferencePicker from '../_base/components/variable/var-reference-picker'
|
||||
import OptionCard from '../_base/components/option-card'
|
||||
import {
|
||||
RiAddLine,
|
||||
} from '@remixicon/react'
|
||||
import VarList from './components/var-list'
|
||||
import useConfig from './use-config'
|
||||
import { WriteMode } from './types'
|
||||
import type { AssignerNodeType } from './types'
|
||||
import Field from '@/app/components/workflow/nodes/_base/components/field'
|
||||
import { useHandleAddOperationItem } from './hooks'
|
||||
import ActionButton from '@/app/components/base/action-button'
|
||||
import { type NodePanelProps } from '@/app/components/workflow/types'
|
||||
import cn from '@/utils/classnames'
|
||||
|
||||
const i18nPrefix = 'workflow.nodes.assigner'
|
||||
|
||||
@ -18,67 +18,48 @@ const Panel: FC<NodePanelProps<AssignerNodeType>> = ({
|
||||
data,
|
||||
}) => {
|
||||
const { t } = useTranslation()
|
||||
|
||||
const handleAddOperationItem = useHandleAddOperationItem()
|
||||
const {
|
||||
readOnly,
|
||||
inputs,
|
||||
handleAssignedVarChanges,
|
||||
isSupportAppend,
|
||||
handleOperationListChanges,
|
||||
getAssignedVarType,
|
||||
getToAssignedVarType,
|
||||
writeModeTypesNum,
|
||||
writeModeTypesArr,
|
||||
writeModeTypes,
|
||||
handleWriteModeChange,
|
||||
filterAssignedVar,
|
||||
filterToAssignedVar,
|
||||
handleToAssignedVarChange,
|
||||
toAssignedVarType,
|
||||
} = useConfig(id, data)
|
||||
const handleAddOperation = () => {
|
||||
const newList = handleAddOperationItem(inputs.items || [])
|
||||
handleOperationListChanges(newList)
|
||||
}
|
||||
|
||||
return (
|
||||
<div className='mt-2'>
|
||||
<div className='px-4 pb-4 space-y-4'>
|
||||
<Field
|
||||
title={t(`${i18nPrefix}.assignedVariable`)}
|
||||
>
|
||||
<VarReferencePicker
|
||||
readonly={readOnly}
|
||||
nodeId={id}
|
||||
isShowNodeName
|
||||
value={inputs.assigned_variable_selector || []}
|
||||
onChange={handleAssignedVarChanges}
|
||||
filterVar={filterAssignedVar}
|
||||
/>
|
||||
</Field>
|
||||
<Field
|
||||
title={t(`${i18nPrefix}.writeMode`)}
|
||||
>
|
||||
<div className={cn('grid gap-2 grid-cols-3')}>
|
||||
{writeModeTypes.map(type => (
|
||||
<OptionCard
|
||||
key={type}
|
||||
title={t(`${i18nPrefix}.${type}`)}
|
||||
onSelect={handleWriteModeChange(type)}
|
||||
selected={inputs.write_mode === type}
|
||||
disabled={!isSupportAppend && type === WriteMode.Append}
|
||||
tooltip={type === WriteMode.Append ? t(`${i18nPrefix}.writeModeTip`)! : undefined}
|
||||
/>
|
||||
))}
|
||||
</div>
|
||||
</Field>
|
||||
{inputs.write_mode !== WriteMode.Clear && (
|
||||
<Field
|
||||
title={t(`${i18nPrefix}.setVariable`)}
|
||||
>
|
||||
<VarReferencePicker
|
||||
readonly={readOnly}
|
||||
nodeId={id}
|
||||
isShowNodeName
|
||||
value={inputs.input_variable_selector || []}
|
||||
onChange={handleToAssignedVarChange}
|
||||
filterVar={filterToAssignedVar}
|
||||
valueTypePlaceHolder={toAssignedVarType}
|
||||
/>
|
||||
</Field>
|
||||
)}
|
||||
|
||||
<div className='flex py-2 flex-col items-start self-stretch'>
|
||||
<div className='flex flex-col justify-center items-start gap-1 px-4 py-2 w-full self-stretch'>
|
||||
<div className='flex items-start gap-2 self-stretch'>
|
||||
<div className='flex flex-col justify-center items-start flex-grow text-text-secondary system-sm-semibold-uppercase'>{t(`${i18nPrefix}.variables`)}</div>
|
||||
<ActionButton onClick={handleAddOperation}>
|
||||
<RiAddLine className='w-4 h-4 shrink-0 text-text-tertiary' />
|
||||
</ActionButton>
|
||||
</div>
|
||||
<VarList
|
||||
readonly={readOnly}
|
||||
nodeId={id}
|
||||
list={inputs.items || []}
|
||||
onChange={(newList) => {
|
||||
handleOperationListChanges(newList)
|
||||
}}
|
||||
filterVar={filterAssignedVar}
|
||||
filterToAssignedVar={filterToAssignedVar}
|
||||
getAssignedVarType={getAssignedVarType}
|
||||
writeModeTypes={writeModeTypes}
|
||||
writeModeTypesArr={writeModeTypesArr}
|
||||
writeModeTypesNum={writeModeTypesNum}
|
||||
getToAssignedVarType={getToAssignedVarType}
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
)
|
||||
|
||||
@ -1,13 +1,30 @@
|
||||
import type { CommonNodeType, ValueSelector } from '@/app/components/workflow/types'
|
||||
|
||||
export enum WriteMode {
|
||||
Overwrite = 'over-write',
|
||||
Append = 'append',
|
||||
Clear = 'clear',
|
||||
overwrite = 'over-write',
|
||||
clear = 'clear',
|
||||
append = 'append',
|
||||
extend = 'extend',
|
||||
set = 'set',
|
||||
increment = '+=',
|
||||
decrement = '-=',
|
||||
multiply = '*=',
|
||||
divide = '/=',
|
||||
}
|
||||
|
||||
export enum AssignerNodeInputType {
|
||||
variable = 'variable',
|
||||
constant = 'constant',
|
||||
}
|
||||
|
||||
export type AssignerNodeOperation = {
|
||||
variable_selector: ValueSelector
|
||||
input_type: AssignerNodeInputType
|
||||
operation: WriteMode
|
||||
value: any
|
||||
}
|
||||
|
||||
export type AssignerNodeType = CommonNodeType & {
|
||||
assigned_variable_selector: ValueSelector
|
||||
write_mode: WriteMode
|
||||
input_variable_selector: ValueSelector
|
||||
version?: '1' | '2'
|
||||
items: AssignerNodeOperation[]
|
||||
}
|
||||
|
||||
@ -1,10 +1,12 @@
|
||||
import { useCallback, useMemo } from 'react'
|
||||
import produce from 'immer'
|
||||
import { useStoreApi } from 'reactflow'
|
||||
import { isEqual } from 'lodash-es'
|
||||
import { VarType } from '../../types'
|
||||
import type { ValueSelector, Var } from '../../types'
|
||||
import { type AssignerNodeType, WriteMode } from './types'
|
||||
import { WriteMode } from './types'
|
||||
import type { AssignerNodeOperation, AssignerNodeType } from './types'
|
||||
import { useGetAvailableVars } from './hooks'
|
||||
import { convertV1ToV2 } from './utils'
|
||||
import useNodeCrud from '@/app/components/workflow/nodes/_base/hooks/use-node-crud'
|
||||
import {
|
||||
useIsChatMode,
|
||||
@ -13,9 +15,20 @@ import {
|
||||
useWorkflowVariables,
|
||||
} from '@/app/components/workflow/hooks'
|
||||
|
||||
const useConfig = (id: string, payload: AssignerNodeType) => {
|
||||
const useConfig = (id: string, rawPayload: AssignerNodeType) => {
|
||||
const payload = useMemo(() => convertV1ToV2(rawPayload), [rawPayload])
|
||||
const { nodesReadOnly: readOnly } = useNodesReadOnly()
|
||||
const isChatMode = useIsChatMode()
|
||||
const getAvailableVars = useGetAvailableVars()
|
||||
const filterVar = (varType: VarType) => {
|
||||
return (v: Var) => {
|
||||
if (varType === VarType.any)
|
||||
return true
|
||||
if (v.type === VarType.any)
|
||||
return true
|
||||
return v.type === varType
|
||||
}
|
||||
}
|
||||
|
||||
const store = useStoreApi()
|
||||
const { getBeforeNodesInSameBranch } = useWorkflow()
|
||||
@ -30,59 +43,41 @@ const useConfig = (id: string, payload: AssignerNodeType) => {
|
||||
return getBeforeNodesInSameBranch(id)
|
||||
}, [getBeforeNodesInSameBranch, id])
|
||||
const { inputs, setInputs } = useNodeCrud<AssignerNodeType>(id, payload)
|
||||
const newSetInputs = useCallback((newInputs: AssignerNodeType) => {
|
||||
const finalInputs = produce(newInputs, (draft) => {
|
||||
if (draft.version !== '2')
|
||||
draft.version = '2'
|
||||
})
|
||||
setInputs(finalInputs)
|
||||
}, [setInputs])
|
||||
|
||||
const { getCurrentVariableType } = useWorkflowVariables()
|
||||
const assignedVarType = getCurrentVariableType({
|
||||
parentNode: iterationNode,
|
||||
valueSelector: inputs.assigned_variable_selector || [],
|
||||
availableNodes,
|
||||
isChatMode,
|
||||
isConstant: false,
|
||||
})
|
||||
|
||||
const isSupportAppend = useCallback((varType: VarType) => {
|
||||
return [VarType.arrayString, VarType.arrayNumber, VarType.arrayObject].includes(varType)
|
||||
}, [])
|
||||
|
||||
const isCurrSupportAppend = useMemo(() => isSupportAppend(assignedVarType), [assignedVarType, isSupportAppend])
|
||||
|
||||
const handleAssignedVarChanges = useCallback((variable: ValueSelector | string) => {
|
||||
const newInputs = produce(inputs, (draft) => {
|
||||
draft.assigned_variable_selector = variable as ValueSelector
|
||||
draft.input_variable_selector = []
|
||||
|
||||
const newVarType = getCurrentVariableType({
|
||||
parentNode: iterationNode,
|
||||
valueSelector: draft.assigned_variable_selector || [],
|
||||
availableNodes,
|
||||
isChatMode,
|
||||
isConstant: false,
|
||||
})
|
||||
|
||||
if (inputs.write_mode === WriteMode.Append && !isSupportAppend(newVarType))
|
||||
draft.write_mode = WriteMode.Overwrite
|
||||
const getAssignedVarType = useCallback((valueSelector: ValueSelector) => {
|
||||
return getCurrentVariableType({
|
||||
parentNode: iterationNode,
|
||||
valueSelector: valueSelector || [],
|
||||
availableNodes,
|
||||
isChatMode,
|
||||
isConstant: false,
|
||||
})
|
||||
setInputs(newInputs)
|
||||
}, [inputs, setInputs, getCurrentVariableType, iterationNode, availableNodes, isChatMode, isSupportAppend])
|
||||
}, [getCurrentVariableType, iterationNode, availableNodes, isChatMode])
|
||||
|
||||
const writeModeTypes = [WriteMode.Overwrite, WriteMode.Append, WriteMode.Clear]
|
||||
const handleOperationListChanges = useCallback((items: AssignerNodeOperation[]) => {
|
||||
const newInputs = produce(inputs, (draft) => {
|
||||
draft.items = [...items]
|
||||
})
|
||||
newSetInputs(newInputs)
|
||||
}, [inputs, newSetInputs])
|
||||
|
||||
const handleWriteModeChange = useCallback((writeMode: WriteMode) => {
|
||||
return () => {
|
||||
const newInputs = produce(inputs, (draft) => {
|
||||
draft.write_mode = writeMode
|
||||
if (inputs.write_mode === WriteMode.Clear)
|
||||
draft.input_variable_selector = []
|
||||
})
|
||||
setInputs(newInputs)
|
||||
}
|
||||
}, [inputs, setInputs])
|
||||
const writeModeTypesArr = [WriteMode.overwrite, WriteMode.clear, WriteMode.append, WriteMode.extend]
|
||||
const writeModeTypes = [WriteMode.overwrite, WriteMode.clear, WriteMode.set]
|
||||
const writeModeTypesNum = [WriteMode.increment, WriteMode.decrement, WriteMode.multiply, WriteMode.divide]
|
||||
|
||||
const toAssignedVarType = useMemo(() => {
|
||||
const { write_mode } = inputs
|
||||
if (write_mode === WriteMode.Overwrite)
|
||||
const getToAssignedVarType = useCallback((assignedVarType: VarType, write_mode: WriteMode) => {
|
||||
if (write_mode === WriteMode.overwrite || write_mode === WriteMode.increment || write_mode === WriteMode.decrement
|
||||
|| write_mode === WriteMode.multiply || write_mode === WriteMode.divide || write_mode === WriteMode.extend)
|
||||
return assignedVarType
|
||||
if (write_mode === WriteMode.Append) {
|
||||
if (write_mode === WriteMode.append) {
|
||||
if (assignedVarType === VarType.arrayString)
|
||||
return VarType.string
|
||||
if (assignedVarType === VarType.arrayNumber)
|
||||
@ -91,20 +86,18 @@ const useConfig = (id: string, payload: AssignerNodeType) => {
|
||||
return VarType.object
|
||||
}
|
||||
return VarType.string
|
||||
}, [assignedVarType, inputs])
|
||||
}, [])
|
||||
|
||||
const filterAssignedVar = useCallback((varPayload: Var, selector: ValueSelector) => {
|
||||
return selector.join('.').startsWith('conversation')
|
||||
}, [])
|
||||
|
||||
const filterToAssignedVar = useCallback((varPayload: Var, selector: ValueSelector) => {
|
||||
if (isEqual(selector, inputs.assigned_variable_selector))
|
||||
return false
|
||||
|
||||
if (inputs.write_mode === WriteMode.Overwrite) {
|
||||
const filterToAssignedVar = useCallback((varPayload: Var, assignedVarType: VarType, write_mode: WriteMode) => {
|
||||
if (write_mode === WriteMode.overwrite || write_mode === WriteMode.extend || write_mode === WriteMode.increment
|
||||
|| write_mode === WriteMode.decrement || write_mode === WriteMode.multiply || write_mode === WriteMode.divide) {
|
||||
return varPayload.type === assignedVarType
|
||||
}
|
||||
else if (inputs.write_mode === WriteMode.Append) {
|
||||
else if (write_mode === WriteMode.append) {
|
||||
switch (assignedVarType) {
|
||||
case VarType.arrayString:
|
||||
return varPayload.type === VarType.string
|
||||
@ -117,27 +110,21 @@ const useConfig = (id: string, payload: AssignerNodeType) => {
|
||||
}
|
||||
}
|
||||
return true
|
||||
}, [inputs.assigned_variable_selector, inputs.write_mode, assignedVarType])
|
||||
|
||||
const handleToAssignedVarChange = useCallback((value: ValueSelector | string) => {
|
||||
const newInputs = produce(inputs, (draft) => {
|
||||
draft.input_variable_selector = value as ValueSelector
|
||||
})
|
||||
setInputs(newInputs)
|
||||
}, [inputs, setInputs])
|
||||
}, [])
|
||||
|
||||
return {
|
||||
readOnly,
|
||||
inputs,
|
||||
handleAssignedVarChanges,
|
||||
assignedVarType,
|
||||
isSupportAppend: isCurrSupportAppend,
|
||||
handleOperationListChanges,
|
||||
getAssignedVarType,
|
||||
getToAssignedVarType,
|
||||
writeModeTypes,
|
||||
handleWriteModeChange,
|
||||
writeModeTypesArr,
|
||||
writeModeTypesNum,
|
||||
filterAssignedVar,
|
||||
filterToAssignedVar,
|
||||
handleToAssignedVarChange,
|
||||
toAssignedVarType,
|
||||
getAvailableVars,
|
||||
filterVar,
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@ -1,5 +1,83 @@
|
||||
import type { AssignerNodeType } from './types'
|
||||
import { AssignerNodeInputType, WriteMode } from './types'
|
||||
|
||||
export const checkNodeValid = (payload: AssignerNodeType) => {
|
||||
return true
|
||||
}
|
||||
|
||||
export const formatOperationName = (type: string) => {
|
||||
if (type === 'over-write')
|
||||
return 'Overwrite'
|
||||
return type.charAt(0).toUpperCase() + type.slice(1)
|
||||
}
|
||||
|
||||
type Item = {
|
||||
value: string | number
|
||||
name: string
|
||||
}
|
||||
|
||||
export const getOperationItems = (
|
||||
assignedVarType?: string,
|
||||
writeModeTypes?: WriteMode[],
|
||||
writeModeTypesArr?: WriteMode[],
|
||||
writeModeTypesNum?: WriteMode[],
|
||||
): Item[] => {
|
||||
if (assignedVarType?.startsWith('array') && writeModeTypesArr) {
|
||||
return writeModeTypesArr.map(type => ({
|
||||
value: type,
|
||||
name: type,
|
||||
}))
|
||||
}
|
||||
|
||||
if (assignedVarType === 'number' && writeModeTypes && writeModeTypesNum) {
|
||||
return [
|
||||
...writeModeTypes.map(type => ({
|
||||
value: type,
|
||||
name: type,
|
||||
})),
|
||||
{ value: 'divider', name: 'divider' } as Item,
|
||||
...writeModeTypesNum.map(type => ({
|
||||
value: type,
|
||||
name: type,
|
||||
})),
|
||||
]
|
||||
}
|
||||
|
||||
if (writeModeTypes && ['string', 'object'].includes(assignedVarType || '')) {
|
||||
return writeModeTypes.map(type => ({
|
||||
value: type,
|
||||
name: type,
|
||||
}))
|
||||
}
|
||||
|
||||
return []
|
||||
}
|
||||
|
||||
const convertOldWriteMode = (oldMode: string): WriteMode => {
|
||||
switch (oldMode) {
|
||||
case 'over-write':
|
||||
return WriteMode.overwrite
|
||||
case 'append':
|
||||
return WriteMode.append
|
||||
case 'clear':
|
||||
return WriteMode.clear
|
||||
default:
|
||||
return WriteMode.overwrite
|
||||
}
|
||||
}
|
||||
|
||||
export const convertV1ToV2 = (payload: any): AssignerNodeType => {
|
||||
if (payload.version === '2' && payload.items)
|
||||
return payload as AssignerNodeType
|
||||
|
||||
return {
|
||||
version: '2',
|
||||
items: [{
|
||||
variable_selector: payload.assigned_variable_selector || [],
|
||||
input_type: AssignerNodeInputType.variable,
|
||||
operation: convertOldWriteMode(payload.write_mode),
|
||||
value: payload.input_variable_selector || [],
|
||||
}],
|
||||
...payload,
|
||||
}
|
||||
}
|
||||
|
||||
@ -173,7 +173,8 @@ const InputVarList: FC<Props> = ({
|
||||
value={varInput?.type === VarKindType.constant ? (varInput?.value || '') : (varInput?.value || [])}
|
||||
onChange={handleNotMixedTypeChange(variable)}
|
||||
onOpen={handleOpen(index)}
|
||||
defaultVarKindType={VarKindType.variable}
|
||||
defaultVarKindType={isNumber ? VarKindType.constant : VarKindType.variable}
|
||||
isSupportConstantValue={isSupportConstantValue}
|
||||
filterVar={isNumber ? filterVar : undefined}
|
||||
availableVars={isSelect ? availableVars : undefined}
|
||||
schema={schema}
|
||||
|
||||
@ -1,9 +1,11 @@
|
||||
import { memo } from 'react'
|
||||
import { useTranslation } from 'react-i18next'
|
||||
import cn from '@/utils/classnames'
|
||||
import { VarBlockIcon } from '@/app/components/workflow/block-icon'
|
||||
import { Line3 } from '@/app/components/base/icons/src/public/common'
|
||||
import { Variable02 } from '@/app/components/base/icons/src/vender/solid/development'
|
||||
import { BubbleX, Env } from '@/app/components/base/icons/src/vender/line/others'
|
||||
import Badge from '@/app/components/base/badge'
|
||||
import type { Node } from '@/app/components/workflow/types'
|
||||
import { BlockEnum } from '@/app/components/workflow/types'
|
||||
|
||||
@ -12,20 +14,26 @@ type NodeVariableItemProps = {
|
||||
isChatVar: boolean
|
||||
node: Node
|
||||
varName: string
|
||||
writeMode?: string
|
||||
showBorder?: boolean
|
||||
className?: string
|
||||
}
|
||||
|
||||
const i18nPrefix = 'workflow.nodes.assigner'
|
||||
|
||||
const NodeVariableItem = ({
|
||||
isEnv,
|
||||
isChatVar,
|
||||
node,
|
||||
varName,
|
||||
writeMode,
|
||||
showBorder,
|
||||
className,
|
||||
}: NodeVariableItemProps) => {
|
||||
const { t } = useTranslation()
|
||||
return (
|
||||
<div className={cn(
|
||||
'relative flex items-center mt-0.5 h-6 bg-gray-100 rounded-md px-1 text-xs font-normal text-gray-700',
|
||||
'relative flex items-center p-[3px] pl-[5px] gap-1 self-stretch rounded-md bg-workflow-block-param-bg',
|
||||
showBorder && '!bg-black/[0.02]',
|
||||
className,
|
||||
)}>
|
||||
@ -41,11 +49,19 @@ const NodeVariableItem = ({
|
||||
<Line3 className='mr-0.5'></Line3>
|
||||
</div>
|
||||
)}
|
||||
<div className='flex items-center text-primary-600'>
|
||||
<div className='flex items-center text-primary-600 w-full'>
|
||||
{!isEnv && !isChatVar && <Variable02 className='shrink-0 w-3.5 h-3.5 text-primary-500' />}
|
||||
{isEnv && <Env className='shrink-0 w-3.5 h-3.5 text-util-colors-violet-violet-600' />}
|
||||
{isChatVar && <BubbleX className='w-3.5 h-3.5 text-util-colors-teal-teal-700' />}
|
||||
<div className={cn('max-w-[75px] truncate ml-0.5 text-xs font-medium', (isEnv || isChatVar) && 'text-gray-900')} title={varName}>{varName}</div>
|
||||
{!isChatVar && <div className={cn('max-w-[75px] truncate ml-0.5 system-xs-medium overflow-hidden text-ellipsis', isEnv && 'text-gray-900')} title={varName}>{varName}</div>}
|
||||
{isChatVar
|
||||
&& <div className='flex items-center w-full gap-1'>
|
||||
<div className='flex h-[18px] min-w-[18px] items-center gap-0.5 flex-1'>
|
||||
<BubbleX className='w-3.5 h-3.5 text-util-colors-teal-teal-700' />
|
||||
<div className='max-w-[75px] truncate ml-0.5 system-xs-medium overflow-hidden text-ellipsis text-util-colors-teal-teal-700'>{varName}</div>
|
||||
</div>
|
||||
{writeMode && <Badge className='shrink-0' text={t(`${i18nPrefix}.operations.${writeMode}`)} />}
|
||||
</div>
|
||||
}
|
||||
</div>
|
||||
</div>
|
||||
)
|
||||
|
||||
@ -62,7 +62,7 @@ const RunPanel: FC<RunProps> = ({ hideResult, activeTab = 'RESULT', runID, getRe
|
||||
const formatNodeList = useCallback((list: NodeTracing[]) => {
|
||||
const allItems = [...list].reverse()
|
||||
const result: NodeTracing[] = []
|
||||
const groupMap = new Map<string, NodeTracing[]>()
|
||||
const nodeGroupMap = new Map<string, Map<string, NodeTracing[]>>()
|
||||
|
||||
const processIterationNode = (item: NodeTracing) => {
|
||||
result.push({
|
||||
@ -70,11 +70,19 @@ const RunPanel: FC<RunProps> = ({ hideResult, activeTab = 'RESULT', runID, getRe
|
||||
details: [],
|
||||
})
|
||||
}
|
||||
|
||||
const updateParallelModeGroup = (runId: string, item: NodeTracing, iterationNode: NodeTracing) => {
|
||||
if (!nodeGroupMap.has(iterationNode.node_id))
|
||||
nodeGroupMap.set(iterationNode.node_id, new Map())
|
||||
|
||||
const groupMap = nodeGroupMap.get(iterationNode.node_id)!
|
||||
|
||||
if (!groupMap.has(runId))
|
||||
groupMap.set(runId, [item])
|
||||
|
||||
else
|
||||
groupMap.get(runId)!.push(item)
|
||||
|
||||
if (item.status === 'failed') {
|
||||
iterationNode.status = 'failed'
|
||||
iterationNode.error = item.error
|
||||
|
||||
@ -169,8 +169,8 @@ type Shape = {
|
||||
setShowTips: (showTips: string) => void
|
||||
iterTimes: number
|
||||
setIterTimes: (iterTimes: number) => void
|
||||
iterParallelLogMap: Map<string, NodeTracing[]>
|
||||
setIterParallelLogMap: (iterParallelLogMap: Map<string, NodeTracing[]>) => void
|
||||
iterParallelLogMap: Map<string, Map<string, NodeTracing[]>>
|
||||
setIterParallelLogMap: (iterParallelLogMap: Map<string, Map<string, NodeTracing[]>>) => void
|
||||
}
|
||||
|
||||
export const createWorkflowStore = () => {
|
||||
@ -288,7 +288,7 @@ export const createWorkflowStore = () => {
|
||||
setShowTips: showTips => set(() => ({ showTips })),
|
||||
iterTimes: 1,
|
||||
setIterTimes: iterTimes => set(() => ({ iterTimes })),
|
||||
iterParallelLogMap: new Map<string, NodeTracing[]>(),
|
||||
iterParallelLogMap: new Map<string, Map<string, NodeTracing[]>>(),
|
||||
setIterParallelLogMap: iterParallelLogMap => set(() => ({ iterParallelLogMap })),
|
||||
|
||||
}))
|
||||
|
||||
@ -29,9 +29,17 @@ async function translateMissingKeyDeeply(sourceObj, targetObject, toLanguage) {
|
||||
await translateMissingKeyDeeply(sourceObj[key], targetObject[key], toLanguage)
|
||||
}
|
||||
else {
|
||||
const { translation } = await translate(sourceObj[key], null, languageKeyMap[toLanguage])
|
||||
targetObject[key] = translation
|
||||
// console.log(translation)
|
||||
try {
|
||||
if (!sourceObj[key]) {
|
||||
targetObject[key] = ''
|
||||
return
|
||||
}
|
||||
const { translation } = await translate(sourceObj[key], null, languageKeyMap[toLanguage])
|
||||
targetObject[key] = translation
|
||||
}
|
||||
catch (e) {
|
||||
console.error(`Error translating ${sourceObj[key]}(${key}) to ${toLanguage}`)
|
||||
}
|
||||
}
|
||||
}
|
||||
else if (typeof sourceObj[key] === 'object') {
|
||||
|
||||
@ -595,6 +595,9 @@ const translation = {
|
||||
expiring: 'Läuft an einem Tag ab',
|
||||
expiring_plural: 'Läuft in {{count}} Tagen ab',
|
||||
},
|
||||
pagination: {
|
||||
perPage: 'Artikel pro Seite',
|
||||
},
|
||||
}
|
||||
|
||||
export default translation
|
||||
|
||||
@ -142,7 +142,7 @@ const translation = {
|
||||
websiteSource: 'Preprocess-Website',
|
||||
webpageUnit: 'Seiten',
|
||||
separatorTip: 'Ein Trennzeichen ist das Zeichen, das zum Trennen von Text verwendet wird. \\n\\n und \\n sind häufig verwendete Trennzeichen zum Trennen von Absätzen und Zeilen. In Kombination mit Kommas (\\n\\n,\\n) werden Absätze nach Zeilen segmentiert, wenn die maximale Blocklänge überschritten wird. Sie können auch spezielle, von Ihnen selbst definierte Trennzeichen verwenden (z. B. ***).',
|
||||
maxLengthCheck: 'Die maximale Stücklänge sollte weniger als 4000 betragen',
|
||||
maxLengthCheck: 'Die maximale Stücklänge sollte weniger als {{limit}} betragen',
|
||||
},
|
||||
stepThree: {
|
||||
creationTitle: '🎉 Wissen erstellt',
|
||||
|
||||
@ -35,6 +35,8 @@ const translation = {
|
||||
Translate: 'Übersetzen',
|
||||
Programming: 'Programmieren',
|
||||
HR: 'Personalwesen',
|
||||
Agent: 'Agent',
|
||||
Workflow: 'Arbeitsablauf',
|
||||
},
|
||||
}
|
||||
|
||||
|
||||
@ -500,6 +500,26 @@ const translation = {
|
||||
'clear': 'Löschen',
|
||||
'setVariable': 'Variable setzen',
|
||||
'variable': 'Variable',
|
||||
'operations': {
|
||||
'title': 'Operation',
|
||||
'clear': 'Klar',
|
||||
'over-write': 'Überschreiben',
|
||||
'set': 'Garnitur',
|
||||
'-=': '-=',
|
||||
'+=': '+=',
|
||||
'/=': '/=',
|
||||
'append': 'Anfügen',
|
||||
'extend': 'Ausdehnen',
|
||||
'*=': '*=',
|
||||
'overwrite': 'Überschreiben',
|
||||
},
|
||||
'setParameter': 'Parameter setzen...',
|
||||
'noVarTip': 'Klicken Sie auf die Schaltfläche "+", um Variablen hinzuzufügen',
|
||||
'variables': 'Variablen',
|
||||
'noAssignedVars': 'Keine verfügbaren zugewiesenen Variablen',
|
||||
'selectAssignedVariable': 'Zugewiesene Variable auswählen...',
|
||||
'varNotSet': 'Variable NICHT gesetzt',
|
||||
'assignedVarsDescription': 'Zugewiesene Variablen müssen beschreibbare Variablen sein, z. B. Konversationsvariablen.',
|
||||
},
|
||||
tool: {
|
||||
toAuthorize: 'Autorisieren',
|
||||
@ -631,6 +651,13 @@ const translation = {
|
||||
tracing: {
|
||||
stopBy: 'Gestoppt von {{user}}',
|
||||
},
|
||||
variableReference: {
|
||||
noAvailableVars: 'Keine verfügbaren Variablen',
|
||||
conversationVars: 'Konversations-Variablen',
|
||||
noAssignedVars: 'Keine verfügbaren zugewiesenen Variablen',
|
||||
noVarsForOperation: 'Es stehen keine Variablen für die Zuweisung mit der ausgewählten Operation zur Verfügung.',
|
||||
assignedVarsDescription: 'Zugewiesene Variablen müssen beschreibbare Variablen sein, z. B.',
|
||||
},
|
||||
}
|
||||
|
||||
export default translation
|
||||
|
||||
@ -595,6 +595,9 @@ const translation = {
|
||||
expiring: 'Expiring in one day',
|
||||
expiring_plural: 'Expiring in {{count}} days',
|
||||
},
|
||||
pagination: {
|
||||
perPage: 'Items per page',
|
||||
},
|
||||
}
|
||||
|
||||
export default translation
|
||||
|
||||
@ -113,7 +113,7 @@ const translation = {
|
||||
separatorTip: 'A delimiter is the character used to separate text. \\n\\n and \\n are commonly used delimiters for separating paragraphs and lines. Combined with commas (\\n\\n,\\n), paragraphs will be segmented by lines when exceeding the maximum chunk length. You can also use special delimiters defined by yourself (e.g. ***).',
|
||||
separatorPlaceholder: '\\n\\n for separating paragraphs; \\n for separating lines',
|
||||
maxLength: 'Maximum chunk length',
|
||||
maxLengthCheck: 'Maximum chunk length should be less than 4000',
|
||||
maxLengthCheck: 'Maximum chunk length should be less than {{limit}}',
|
||||
overlap: 'Chunk overlap',
|
||||
overlapTip: 'Setting the chunk overlap can maintain the semantic relevance between them, enhancing the retrieve effect. It is recommended to set 10%-25% of the maximum chunk size.',
|
||||
overlapCheck: 'chunk overlap should not bigger than maximum chunk length',
|
||||
|
||||
@ -30,11 +30,13 @@ const translation = {
|
||||
nameRequired: 'App name is required',
|
||||
},
|
||||
category: {
|
||||
Agent: 'Agent',
|
||||
Assistant: 'Assistant',
|
||||
Writing: 'Writing',
|
||||
Translate: 'Translate',
|
||||
Programming: 'Programming',
|
||||
HR: 'HR',
|
||||
Workflow: 'Workflow',
|
||||
},
|
||||
}
|
||||
|
||||
|
||||
@ -260,6 +260,13 @@ const translation = {
|
||||
zoomTo100: 'Zoom to 100%',
|
||||
zoomToFit: 'Zoom to Fit',
|
||||
},
|
||||
variableReference: {
|
||||
noAvailableVars: 'No available variables',
|
||||
noVarsForOperation: 'There are no variables available for assignment with the selected operation.',
|
||||
noAssignedVars: 'No available assigned variables',
|
||||
assignedVarsDescription: 'Assigned variables must be writable variables, such as ',
|
||||
conversationVars: 'conversation variables',
|
||||
},
|
||||
panel: {
|
||||
userInputField: 'User Input Field',
|
||||
changeBlock: 'Change Block',
|
||||
@ -491,6 +498,9 @@ const translation = {
|
||||
},
|
||||
assigner: {
|
||||
'assignedVariable': 'Assigned Variable',
|
||||
'varNotSet': 'Variable NOT Set',
|
||||
'variables': 'Variables',
|
||||
'noVarTip': 'Click the "+" button to add variables',
|
||||
'writeMode': 'Write Mode',
|
||||
'writeModeTip': 'Append mode: Available for array variables only.',
|
||||
'over-write': 'Overwrite',
|
||||
@ -498,7 +508,24 @@ const translation = {
|
||||
'plus': 'Plus',
|
||||
'clear': 'Clear',
|
||||
'setVariable': 'Set Variable',
|
||||
'selectAssignedVariable': 'Select assigned variable...',
|
||||
'setParameter': 'Set parameter...',
|
||||
'operations': {
|
||||
'title': 'Operation',
|
||||
'over-write': 'Overwrite',
|
||||
'overwrite': 'Overwrite',
|
||||
'set': 'Set',
|
||||
'clear': 'Clear',
|
||||
'extend': 'Extend',
|
||||
'append': 'Append',
|
||||
'+=': '+=',
|
||||
'-=': '-=',
|
||||
'*=': '*=',
|
||||
'/=': '/=',
|
||||
},
|
||||
'variable': 'Variable',
|
||||
'noAssignedVars': 'No available assigned variables',
|
||||
'assignedVarsDescription': 'Assigned variables must be writable variables, such as conversation variables.',
|
||||
},
|
||||
tool: {
|
||||
toAuthorize: 'To authorize',
|
||||
|
||||
@ -595,6 +595,9 @@ const translation = {
|
||||
expiring: 'Caduca en un día',
|
||||
expiring_plural: 'Caducando en {{count}} días',
|
||||
},
|
||||
pagination: {
|
||||
perPage: 'Elementos por página',
|
||||
},
|
||||
}
|
||||
|
||||
export default translation
|
||||
|
||||
@ -147,7 +147,7 @@ const translation = {
|
||||
retrievalSettingTip: 'Para cambiar el método de índice, por favor ve a la ',
|
||||
datasetSettingLink: 'configuración del conocimiento.',
|
||||
separatorTip: 'Un delimitador es el carácter que se utiliza para separar el texto. \\n\\n y \\n son delimitadores comúnmente utilizados para separar párrafos y líneas. Combinado con comas (\\n\\n,\\n), los párrafos se segmentarán por líneas cuando excedan la longitud máxima del fragmento. También puede utilizar delimitadores especiales definidos por usted mismo (por ejemplo, ***).',
|
||||
maxLengthCheck: 'La longitud máxima del fragmento debe ser inferior a 4000',
|
||||
maxLengthCheck: 'La longitud máxima del fragmento debe ser inferior a {{limit}}',
|
||||
},
|
||||
stepThree: {
|
||||
creationTitle: '🎉 Conocimiento creado',
|
||||
|
||||
@ -35,6 +35,8 @@ const translation = {
|
||||
Translate: 'Traducción',
|
||||
Programming: 'Programación',
|
||||
HR: 'Recursos Humanos',
|
||||
Agent: 'Agente',
|
||||
Workflow: 'Flujo de trabajo',
|
||||
},
|
||||
}
|
||||
|
||||
|
||||
@ -500,6 +500,26 @@ const translation = {
|
||||
'clear': 'Limpiar',
|
||||
'setVariable': 'Establecer Variable',
|
||||
'variable': 'Variable',
|
||||
'operations': {
|
||||
'clear': 'Claro',
|
||||
'*=': '*=',
|
||||
'-=': '-=',
|
||||
'title': 'Operación',
|
||||
'extend': 'Extender',
|
||||
'append': 'Añadir',
|
||||
'+=': '+=',
|
||||
'over-write': 'Sobrescribir',
|
||||
'overwrite': 'Sobrescribir',
|
||||
'/=': '/=',
|
||||
'set': 'Poner',
|
||||
},
|
||||
'variables': 'Variables',
|
||||
'setParameter': 'Establecer parámetro...',
|
||||
'noVarTip': 'Haga clic en el botón "+" para agregar variables',
|
||||
'varNotSet': 'Variable NO establecida',
|
||||
'noAssignedVars': 'No hay variables asignadas disponibles',
|
||||
'selectAssignedVariable': 'Seleccione la variable asignada...',
|
||||
'assignedVarsDescription': 'Las variables asignadas deben ser variables grabables, como las variables de conversación.',
|
||||
},
|
||||
tool: {
|
||||
toAuthorize: 'Para autorizar',
|
||||
@ -634,6 +654,13 @@ const translation = {
|
||||
tracing: {
|
||||
stopBy: 'Pásate por {{usuario}}',
|
||||
},
|
||||
variableReference: {
|
||||
noAvailableVars: 'No hay variables disponibles',
|
||||
assignedVarsDescription: 'Las variables asignadas deben ser variables grabables, como',
|
||||
noVarsForOperation: 'No hay variables disponibles para la asignación con la operación seleccionada.',
|
||||
noAssignedVars: 'No hay variables asignadas disponibles',
|
||||
conversationVars: 'Variables de conversación',
|
||||
},
|
||||
}
|
||||
|
||||
export default translation
|
||||
|
||||
@ -595,6 +595,9 @@ const translation = {
|
||||
expiring_plural: 'انقضا در {{count}} روز',
|
||||
expiring: 'انقضا در یک روز',
|
||||
},
|
||||
pagination: {
|
||||
perPage: 'موارد در هر صفحه',
|
||||
},
|
||||
}
|
||||
|
||||
export default translation
|
||||
|
||||
@ -147,7 +147,7 @@ const translation = {
|
||||
retrievalSettingTip: 'برای تغییر روش شاخص، لطفاً به',
|
||||
datasetSettingLink: 'تنظیمات دانش بروید.',
|
||||
separatorTip: 'جداکننده نویسه ای است که برای جداسازی متن استفاده می شود. \\n\\n و \\n معمولا برای جداسازی پاراگراف ها و خطوط استفاده می شوند. همراه با کاما (\\n\\n,\\n)، پاراگراف ها زمانی که از حداکثر طول تکه فراتر می روند، با خطوط تقسیم بندی می شوند. همچنین می توانید از جداکننده های خاصی که توسط خودتان تعریف شده اند استفاده کنید (مثلا ***).',
|
||||
maxLengthCheck: 'حداکثر طول تکه باید کمتر از 4000 باشد',
|
||||
maxLengthCheck: 'حداکثر طول تکه باید کمتر از {{limit}} باشد',
|
||||
},
|
||||
stepThree: {
|
||||
creationTitle: ' دانش ایجاد شد',
|
||||
|
||||
@ -35,6 +35,8 @@ const translation = {
|
||||
Translate: 'ترجمه',
|
||||
Programming: 'برنامهنویسی',
|
||||
HR: 'منابع انسانی',
|
||||
Agent: 'عامل',
|
||||
Workflow: 'گردش',
|
||||
},
|
||||
}
|
||||
|
||||
|
||||
@ -500,6 +500,26 @@ const translation = {
|
||||
'clear': 'پاک کردن',
|
||||
'setVariable': 'تنظیم متغیر',
|
||||
'variable': 'متغیر',
|
||||
'operations': {
|
||||
'clear': 'روشن',
|
||||
'over-write': 'بازنویسی',
|
||||
'set': 'مجموعه',
|
||||
'*=': '*=',
|
||||
'overwrite': 'بازنویسی',
|
||||
'+=': '+=',
|
||||
'title': 'عملیات',
|
||||
'extend': 'گسترش',
|
||||
'-=': '-=',
|
||||
'append': 'الحاق',
|
||||
'/=': '/=',
|
||||
},
|
||||
'noVarTip': 'برای افزودن متغیرها روی دکمه "+" کلیک کنید',
|
||||
'selectAssignedVariable': 'متغیر اختصاص داده شده را انتخاب کنید...',
|
||||
'noAssignedVars': 'هیچ متغیر اختصاص داده شده در دسترس نیست',
|
||||
'setParameter': 'پارامتر را تنظیم کنید...',
|
||||
'assignedVarsDescription': 'متغیرهای اختصاص داده شده باید متغیرهای قابل نوشتن مانند متغیرهای مکالمه باشند.',
|
||||
'variables': 'متغیرهای',
|
||||
'varNotSet': 'متغیر NOT Set',
|
||||
},
|
||||
tool: {
|
||||
toAuthorize: 'برای مجوز دادن',
|
||||
@ -631,6 +651,13 @@ const translation = {
|
||||
tracing: {
|
||||
stopBy: 'متوقف شده توسط {{user}}',
|
||||
},
|
||||
variableReference: {
|
||||
noAvailableVars: 'هیچ متغیری در دسترس نیست',
|
||||
conversationVars: 'متغیرهای مکالمه',
|
||||
noVarsForOperation: 'هیچ متغیری برای تخصیص با عملیات انتخاب شده در دسترس نیست.',
|
||||
assignedVarsDescription: 'متغیرهای اختصاص داده شده باید متغیرهای قابل نوشتن باشند، مانند',
|
||||
noAssignedVars: 'هیچ متغیر اختصاص داده شده در دسترس نیست',
|
||||
},
|
||||
}
|
||||
|
||||
export default translation
|
||||
|
||||
@ -595,6 +595,9 @@ const translation = {
|
||||
expiring: 'Expirant dans un jour',
|
||||
expiring_plural: 'Expirant dans {{count}} jours',
|
||||
},
|
||||
pagination: {
|
||||
perPage: 'Articles par page',
|
||||
},
|
||||
}
|
||||
|
||||
export default translation
|
||||
|
||||
@ -142,7 +142,7 @@ const translation = {
|
||||
webpageUnit: 'Pages',
|
||||
websiteSource: 'Site web de prétraitement',
|
||||
separatorTip: 'Un délimiteur est le caractère utilisé pour séparer le texte. \\n\\n et \\n sont des délimiteurs couramment utilisés pour séparer les paragraphes et les lignes. Combiné à des virgules (\\n\\n,\\n), les paragraphes seront segmentés par des lignes lorsqu’ils dépasseront la longueur maximale des morceaux. Vous pouvez également utiliser des délimiteurs spéciaux définis par vous-même (par exemple ***).',
|
||||
maxLengthCheck: 'La longueur maximale des morceaux doit être inférieure à 4000',
|
||||
maxLengthCheck: 'La longueur maximale des morceaux doit être inférieure à {{limit}}',
|
||||
},
|
||||
stepThree: {
|
||||
creationTitle: '🎉 Connaissance créée',
|
||||
|
||||
@ -35,6 +35,8 @@ const translation = {
|
||||
Translate: 'Traduire',
|
||||
Programming: 'Programmation',
|
||||
HR: 'RH',
|
||||
Agent: 'Agent',
|
||||
Workflow: 'Flux de travail',
|
||||
},
|
||||
}
|
||||
|
||||
|
||||
@ -500,6 +500,26 @@ const translation = {
|
||||
'clear': 'Effacer',
|
||||
'setVariable': 'Définir Variable',
|
||||
'variable': 'Variable',
|
||||
'operations': {
|
||||
'clear': 'Clair',
|
||||
'*=': '*=',
|
||||
'-=': '-=',
|
||||
'extend': 'Étendre',
|
||||
'+=': '+=',
|
||||
'over-write': 'Écraser',
|
||||
'set': 'Poser',
|
||||
'append': 'Ajouter',
|
||||
'title': 'Opération',
|
||||
'/=': '/=',
|
||||
'overwrite': 'Écraser',
|
||||
},
|
||||
'assignedVarsDescription': 'Les variables affectées doivent être accessibles en écriture, telles que des variables de conversation.',
|
||||
'noVarTip': 'Cliquez sur le bouton « + » pour ajouter des variables',
|
||||
'variables': 'Variables',
|
||||
'setParameter': 'Définir le paramètre...',
|
||||
'noAssignedVars': 'Aucune variable affectée disponible',
|
||||
'varNotSet': 'Variable NON définie',
|
||||
'selectAssignedVariable': 'Sélectionner la variable affectée...',
|
||||
},
|
||||
tool: {
|
||||
toAuthorize: 'Autoriser',
|
||||
@ -631,6 +651,13 @@ const translation = {
|
||||
tracing: {
|
||||
stopBy: 'Arrêté par {{user}}',
|
||||
},
|
||||
variableReference: {
|
||||
noAssignedVars: 'Aucune variable affectée disponible',
|
||||
noVarsForOperation: 'Aucune variable n’est disponible pour l’affectation avec l’opération sélectionnée.',
|
||||
noAvailableVars: 'Aucune variable disponible',
|
||||
assignedVarsDescription: 'Les variables affectées doivent être des variables accessibles en écriture, telles que',
|
||||
conversationVars: 'Variables de conversation',
|
||||
},
|
||||
}
|
||||
|
||||
export default translation
|
||||
|
||||
@ -617,6 +617,9 @@ const translation = {
|
||||
expiring: 'एक दिन में समाप्त हो रहा है',
|
||||
expiring_plural: '{{गिनती}} दिनों में समाप्त हो रहा है',
|
||||
},
|
||||
pagination: {
|
||||
perPage: 'प्रति पृष्ठ आइटम',
|
||||
},
|
||||
}
|
||||
|
||||
export default translation
|
||||
|
||||
@ -164,7 +164,7 @@ const translation = {
|
||||
retrievalSettingTip: 'इंडेक्स विधि बदलने के लिए, कृपया जाएं ',
|
||||
datasetSettingLink: 'ज्ञान सेटिंग्स।',
|
||||
separatorTip: 'एक सीमांकक पाठ को अलग करने के लिए उपयोग किया जाने वाला वर्ण है। \\n\\n और \\n आमतौर पर पैराग्राफ और लाइनों को अलग करने के लिए उपयोग किए जाने वाले सीमांकक हैं। अल्पविराम (\\n\\n,\\n) के साथ संयुक्त, अधिकतम खंड लंबाई से अधिक होने पर अनुच्छेदों को पंक्तियों द्वारा खंडित किया जाएगा। आप स्वयं द्वारा परिभाषित विशेष सीमांकक का भी उपयोग कर सकते हैं (उदा. ***).',
|
||||
maxLengthCheck: 'अधिकतम चंक लंबाई 4000 से कम होनी चाहिए',
|
||||
maxLengthCheck: 'अधिकतम चंक लंबाई {{limit}} से कम होनी चाहिए',
|
||||
},
|
||||
stepThree: {
|
||||
creationTitle: '🎉 ज्ञान बनाया गया',
|
||||
|
||||
@ -36,6 +36,8 @@ const translation = {
|
||||
Translate: 'अनुवाद',
|
||||
Programming: 'प्रोग्रामिंग',
|
||||
HR: 'मानव संसाधन',
|
||||
Workflow: 'कार्यप्रवाह',
|
||||
Agent: 'आढ़तिया',
|
||||
},
|
||||
}
|
||||
|
||||
|
||||
@ -516,6 +516,26 @@ const translation = {
|
||||
'clear': 'साफ़ करें',
|
||||
'setVariable': 'चर सेट करें',
|
||||
'variable': 'चर',
|
||||
'operations': {
|
||||
'clear': 'स्पष्ट',
|
||||
'/=': '/=',
|
||||
'*=': '*=',
|
||||
'over-write': 'अधिलेखित',
|
||||
'title': 'परिचालन',
|
||||
'+=': '+=',
|
||||
'overwrite': 'अधिलेखित',
|
||||
'set': 'अस्त हो',
|
||||
'extend': 'पसार',
|
||||
'-=': '-=',
|
||||
'append': 'संलग्न',
|
||||
},
|
||||
'setParameter': 'पैरामीटर सेट करें...',
|
||||
'noVarTip': 'चर जोड़ने के लिए "+" बटन पर क्लिक करें',
|
||||
'variables': 'चर',
|
||||
'selectAssignedVariable': 'असाइन किए गए चर का चयन करें...',
|
||||
'varNotSet': 'चर सेट नहीं',
|
||||
'assignedVarsDescription': 'असाइन किए गए चर लिखने योग्य चर होने चाहिए, जैसे वार्तालाप चर।',
|
||||
'noAssignedVars': 'कोई उपलब्ध असाइन किए गए चर नहीं',
|
||||
},
|
||||
tool: {
|
||||
toAuthorize: 'अधिकृत करने के लिए',
|
||||
@ -651,6 +671,13 @@ const translation = {
|
||||
tracing: {
|
||||
stopBy: '{{user}} द्वारा रोका गया',
|
||||
},
|
||||
variableReference: {
|
||||
conversationVars: 'बातचीत चर',
|
||||
noAvailableVars: 'कोई उपलब्ध चर नहीं',
|
||||
assignedVarsDescription: 'असाइन किए गए चर लिखने योग्य चर होने चाहिए, जैसे',
|
||||
noVarsForOperation: 'चयनित कार्रवाई के साथ असाइनमेंट के लिए कोई चर उपलब्ध नहीं हैं.',
|
||||
noAssignedVars: 'कोई उपलब्ध असाइन किए गए चर नहीं',
|
||||
},
|
||||
}
|
||||
|
||||
export default translation
|
||||
|
||||
@ -626,6 +626,9 @@ const translation = {
|
||||
expiring_plural: 'Scadenza tra {{count}} giorni',
|
||||
expiring: 'Scadenza in un giorno',
|
||||
},
|
||||
pagination: {
|
||||
perPage: 'Articoli per pagina',
|
||||
},
|
||||
}
|
||||
|
||||
export default translation
|
||||
|
||||
@ -167,7 +167,7 @@ const translation = {
|
||||
retrievalSettingTip: 'Per cambiare il metodo di indicizzazione, vai alle ',
|
||||
datasetSettingLink: 'impostazioni della Conoscenza.',
|
||||
separatorTip: 'Un delimitatore è il carattere utilizzato per separare il testo. \\n\\n e \\n sono delimitatori comunemente usati per separare paragrafi e righe. In combinazione con le virgole (\\n\\n,\\n), i paragrafi verranno segmentati per righe quando superano la lunghezza massima del blocco. È inoltre possibile utilizzare delimitatori speciali definiti dall\'utente (ad es. ***).',
|
||||
maxLengthCheck: 'La lunghezza massima del blocco deve essere inferiore a 4000',
|
||||
maxLengthCheck: 'La lunghezza massima del blocco deve essere inferiore a {{limit}}',
|
||||
},
|
||||
stepThree: {
|
||||
creationTitle: '🎉 Conoscenza creata',
|
||||
|
||||
@ -36,6 +36,8 @@ const translation = {
|
||||
Translate: 'Traduzione',
|
||||
Programming: 'Programmazione',
|
||||
HR: 'Risorse Umane',
|
||||
Workflow: 'Flusso di lavoro',
|
||||
Agent: 'Agente',
|
||||
},
|
||||
}
|
||||
|
||||
|
||||
@ -520,6 +520,26 @@ const translation = {
|
||||
'clear': 'Cancellare',
|
||||
'setVariable': 'Imposta Variabile',
|
||||
'variable': 'Variabile',
|
||||
'operations': {
|
||||
'-=': '-=',
|
||||
'overwrite': 'Sovrascrivere',
|
||||
'+=': '+=',
|
||||
'*=': '*=',
|
||||
'append': 'Aggiungere',
|
||||
'set': 'Mettere',
|
||||
'title': 'Operazione',
|
||||
'/=': '/=',
|
||||
'over-write': 'Sovrascrivere',
|
||||
'extend': 'Estendere',
|
||||
'clear': 'Chiaro',
|
||||
},
|
||||
'setParameter': 'Imposta parametro...',
|
||||
'variables': 'Variabili',
|
||||
'noAssignedVars': 'Nessuna variabile assegnata disponibile',
|
||||
'assignedVarsDescription': 'Le variabili assegnate devono essere variabili scrivibili, ad esempio variabili di conversazione.',
|
||||
'varNotSet': 'Variabile NON impostata',
|
||||
'selectAssignedVariable': 'Seleziona variabile assegnata...',
|
||||
'noVarTip': 'Fare clic sul pulsante "+" per aggiungere variabili',
|
||||
},
|
||||
tool: {
|
||||
toAuthorize: 'Per autorizzare',
|
||||
@ -658,6 +678,13 @@ const translation = {
|
||||
tracing: {
|
||||
stopBy: 'Interrotto da {{user}}',
|
||||
},
|
||||
variableReference: {
|
||||
noAvailableVars: 'Nessuna variabile disponibile',
|
||||
noAssignedVars: 'Nessuna variabile assegnata disponibile',
|
||||
noVarsForOperation: 'Non ci sono variabili disponibili per l\'assegnazione con l\'operazione selezionata.',
|
||||
assignedVarsDescription: 'Le variabili assegnate devono essere variabili scrivibili, ad esempio',
|
||||
conversationVars: 'Variabili di conversazione',
|
||||
},
|
||||
}
|
||||
|
||||
export default translation
|
||||
|
||||
@ -595,6 +595,9 @@ const translation = {
|
||||
expiring_plural: '有効期限 {{count}} 日',
|
||||
expiring: '1日で有効期限が切れます',
|
||||
},
|
||||
pagination: {
|
||||
perPage: 'ページあたりのアイテム数',
|
||||
},
|
||||
}
|
||||
|
||||
export default translation
|
||||
|
||||
@ -147,7 +147,7 @@ const translation = {
|
||||
retrievalSettingTip: '検索方法を変更するには、',
|
||||
datasetSettingLink: 'ナレッジ設定',
|
||||
separatorTip: '区切り文字は、テキストを区切るために使用される文字です。\\n\\n と \\n は、段落と行を区切るために一般的に使用される区切り記号です。カンマ (\\n\\n,\\n) と組み合わせると、最大チャンク長を超えると、段落は行で区切られます。自分で定義した特別な区切り文字を使用することもできます(例:***)。',
|
||||
maxLengthCheck: 'チャンクの最大長は 4000 未満にする必要があります',
|
||||
maxLengthCheck: 'チャンクの最大長は {{limit}} 未満にする必要があります',
|
||||
},
|
||||
stepThree: {
|
||||
creationTitle: '🎉 ナレッジが作成されました',
|
||||
|
||||
@ -35,6 +35,8 @@ const translation = {
|
||||
Translate: '翻訳',
|
||||
Programming: 'プログラミング',
|
||||
HR: '人事',
|
||||
Workflow: 'ワークフロー',
|
||||
Agent: 'エージェント',
|
||||
},
|
||||
}
|
||||
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user