mirror of
https://github.com/langgenius/dify.git
synced 2026-05-06 10:28:10 +08:00
chore(web): new lint setup (#30020)
Co-authored-by: yyh <yuanyouhuilyz@gmail.com>
This commit is contained in:
@ -1,17 +1,17 @@
|
||||
'use client'
|
||||
import type { FC } from 'react'
|
||||
import React from 'react'
|
||||
import { useTranslation } from 'react-i18next'
|
||||
import {
|
||||
RiEditLine,
|
||||
RiFileEditLine,
|
||||
} from '@remixicon/react'
|
||||
import React from 'react'
|
||||
import { useTranslation } from 'react-i18next'
|
||||
import ActionButton from '@/app/components/base/action-button'
|
||||
import Tooltip from '@/app/components/base/tooltip'
|
||||
import { addAnnotation } from '@/service/annotation'
|
||||
import Toast from '@/app/components/base/toast'
|
||||
import { useProviderContext } from '@/context/provider-context'
|
||||
import Tooltip from '@/app/components/base/tooltip'
|
||||
import { useModalContext } from '@/context/modal-context'
|
||||
import { useProviderContext } from '@/context/provider-context'
|
||||
import { addAnnotation } from '@/service/annotation'
|
||||
|
||||
type Props = {
|
||||
appId: string
|
||||
@ -60,7 +60,7 @@ const AnnotationCtrlButton: FC<Props> = ({
|
||||
popupContent={t('appDebug.feature.annotation.edit')}
|
||||
>
|
||||
<ActionButton onClick={onEdit}>
|
||||
<RiEditLine className='h-4 w-4' />
|
||||
<RiEditLine className="h-4 w-4" />
|
||||
</ActionButton>
|
||||
</Tooltip>
|
||||
)}
|
||||
@ -69,7 +69,7 @@ const AnnotationCtrlButton: FC<Props> = ({
|
||||
popupContent={t('appDebug.feature.annotation.add')}
|
||||
>
|
||||
<ActionButton onClick={handleAdd}>
|
||||
<RiFileEditLine className='h-4 w-4' />
|
||||
<RiFileEditLine className="h-4 w-4" />
|
||||
</ActionButton>
|
||||
</Tooltip>
|
||||
)}
|
||||
|
||||
@ -1,17 +1,17 @@
|
||||
'use client'
|
||||
import type { FC } from 'react'
|
||||
import type { AnnotationReplyConfig } from '@/models/debug'
|
||||
import React, { useState } from 'react'
|
||||
import { useTranslation } from 'react-i18next'
|
||||
import ScoreSlider from './score-slider'
|
||||
import { Item } from './config-param'
|
||||
import Modal from '@/app/components/base/modal'
|
||||
import Button from '@/app/components/base/button'
|
||||
import Modal from '@/app/components/base/modal'
|
||||
import Toast from '@/app/components/base/toast'
|
||||
import type { AnnotationReplyConfig } from '@/models/debug'
|
||||
import { ANNOTATION_DEFAULT } from '@/config'
|
||||
import ModelSelector from '@/app/components/header/account-setting/model-provider-page/model-selector'
|
||||
import { useModelListAndDefaultModelAndCurrentProviderAndModel } from '@/app/components/header/account-setting/model-provider-page/hooks'
|
||||
import { ModelTypeEnum } from '@/app/components/header/account-setting/model-provider-page/declarations'
|
||||
import { useModelListAndDefaultModelAndCurrentProviderAndModel } from '@/app/components/header/account-setting/model-provider-page/hooks'
|
||||
import ModelSelector from '@/app/components/header/account-setting/model-provider-page/model-selector'
|
||||
import { ANNOTATION_DEFAULT } from '@/config'
|
||||
import { Item } from './config-param'
|
||||
import ScoreSlider from './score-slider'
|
||||
|
||||
type Props = {
|
||||
appId: string
|
||||
@ -43,15 +43,15 @@ const ConfigParamModal: FC<Props> = ({
|
||||
const [isLoading, setLoading] = useState(false)
|
||||
const [embeddingModel, setEmbeddingModel] = useState(oldAnnotationConfig.embedding_model
|
||||
? {
|
||||
providerName: oldAnnotationConfig.embedding_model.embedding_provider_name,
|
||||
modelName: oldAnnotationConfig.embedding_model.embedding_model_name,
|
||||
}
|
||||
: (embeddingsDefaultModel
|
||||
? {
|
||||
providerName: embeddingsDefaultModel.provider.provider,
|
||||
modelName: embeddingsDefaultModel.model,
|
||||
providerName: oldAnnotationConfig.embedding_model.embedding_provider_name,
|
||||
modelName: oldAnnotationConfig.embedding_model.embedding_model_name,
|
||||
}
|
||||
: undefined))
|
||||
: (embeddingsDefaultModel
|
||||
? {
|
||||
providerName: embeddingsDefaultModel.provider.provider,
|
||||
modelName: embeddingsDefaultModel.model,
|
||||
}
|
||||
: undefined))
|
||||
const onHide = () => {
|
||||
if (!isLoading)
|
||||
doHide()
|
||||
@ -77,19 +77,19 @@ const ConfigParamModal: FC<Props> = ({
|
||||
<Modal
|
||||
isShow={isShow}
|
||||
onClose={onHide}
|
||||
className='!mt-14 !w-[640px] !max-w-none !p-6'
|
||||
className="!mt-14 !w-[640px] !max-w-none !p-6"
|
||||
>
|
||||
<div className='title-2xl-semi-bold mb-2 text-text-primary'>
|
||||
<div className="title-2xl-semi-bold mb-2 text-text-primary">
|
||||
{t(`appAnnotation.initSetup.${isInit ? 'title' : 'configTitle'}`)}
|
||||
</div>
|
||||
|
||||
<div className='mt-6 space-y-3'>
|
||||
<div className="mt-6 space-y-3">
|
||||
<Item
|
||||
title={t('appDebug.feature.annotation.scoreThreshold.title')}
|
||||
tooltip={t('appDebug.feature.annotation.scoreThreshold.description')}
|
||||
>
|
||||
<ScoreSlider
|
||||
className='mt-1'
|
||||
className="mt-1"
|
||||
value={(annotationConfig.score_threshold || ANNOTATION_DEFAULT.score_threshold) * 100}
|
||||
onChange={(val) => {
|
||||
setAnnotationConfig({
|
||||
@ -104,7 +104,7 @@ const ConfigParamModal: FC<Props> = ({
|
||||
title={t('common.modelProvider.embeddingModel.key')}
|
||||
tooltip={t('appAnnotation.embeddingModelSwitchTip')}
|
||||
>
|
||||
<div className='pt-1'>
|
||||
<div className="pt-1">
|
||||
<ModelSelector
|
||||
defaultModel={embeddingModel && {
|
||||
provider: embeddingModel.providerName,
|
||||
@ -122,18 +122,18 @@ const ConfigParamModal: FC<Props> = ({
|
||||
</Item>
|
||||
</div>
|
||||
|
||||
<div className='mt-6 flex justify-end gap-2'>
|
||||
<div className="mt-6 flex justify-end gap-2">
|
||||
<Button onClick={onHide}>{t('common.operation.cancel')}</Button>
|
||||
<Button
|
||||
variant='primary'
|
||||
variant="primary"
|
||||
onClick={handleSave}
|
||||
loading={isLoading}
|
||||
>
|
||||
<div></div>
|
||||
<div>{t(`appAnnotation.initSetup.${isInit ? 'confirmBtn' : 'configConfirmBtn'}`)}</div>
|
||||
</Button >
|
||||
</div >
|
||||
</Modal >
|
||||
</Button>
|
||||
</div>
|
||||
</Modal>
|
||||
)
|
||||
}
|
||||
export default React.memo(ConfigParamModal)
|
||||
|
||||
@ -3,18 +3,18 @@ import type { FC } from 'react'
|
||||
import React from 'react'
|
||||
import Tooltip from '@/app/components/base/tooltip'
|
||||
|
||||
export const Item: FC<{ title: string; tooltip: string; children: React.JSX.Element }> = ({
|
||||
export const Item: FC<{ title: string, tooltip: string, children: React.JSX.Element }> = ({
|
||||
title,
|
||||
tooltip,
|
||||
children,
|
||||
}) => {
|
||||
return (
|
||||
<div>
|
||||
<div className='mb-1 flex items-center space-x-1'>
|
||||
<div className='system-sm-semibold py-1 text-text-secondary'>{title}</div>
|
||||
<div className="mb-1 flex items-center space-x-1">
|
||||
<div className="system-sm-semibold py-1 text-text-secondary">{title}</div>
|
||||
<Tooltip
|
||||
popupContent={
|
||||
<div className='system-sm-regular max-w-[200px] text-text-secondary'>{tooltip}</div>
|
||||
<div className="system-sm-regular max-w-[200px] text-text-secondary">{tooltip}</div>
|
||||
}
|
||||
/>
|
||||
</div>
|
||||
|
||||
@ -1,18 +1,18 @@
|
||||
import type { OnFeaturesChange } from '@/app/components/base/features/types'
|
||||
import type { AnnotationReplyConfig } from '@/models/debug'
|
||||
import { RiEqualizer2Line, RiExternalLinkLine } from '@remixicon/react'
|
||||
import { produce } from 'immer'
|
||||
import { usePathname, useRouter } from 'next/navigation'
|
||||
import React, { useCallback, useState } from 'react'
|
||||
import { useTranslation } from 'react-i18next'
|
||||
import { usePathname, useRouter } from 'next/navigation'
|
||||
import { produce } from 'immer'
|
||||
import { RiEqualizer2Line, RiExternalLinkLine } from '@remixicon/react'
|
||||
import { MessageFast } from '@/app/components/base/icons/src/vender/features'
|
||||
import FeatureCard from '@/app/components/base/features/new-feature-panel/feature-card'
|
||||
import Button from '@/app/components/base/button'
|
||||
import { useFeatures, useFeaturesStore } from '@/app/components/base/features/hooks'
|
||||
import type { OnFeaturesChange } from '@/app/components/base/features/types'
|
||||
import useAnnotationConfig from '@/app/components/base/features/new-feature-panel/annotation-reply/use-annotation-config'
|
||||
import ConfigParamModal from '@/app/components/base/features/new-feature-panel/annotation-reply/config-param-modal'
|
||||
import useAnnotationConfig from '@/app/components/base/features/new-feature-panel/annotation-reply/use-annotation-config'
|
||||
import FeatureCard from '@/app/components/base/features/new-feature-panel/feature-card'
|
||||
import { MessageFast } from '@/app/components/base/icons/src/vender/features'
|
||||
import AnnotationFullModal from '@/app/components/billing/annotation-full/modal'
|
||||
import { ANNOTATION_DEFAULT } from '@/config'
|
||||
import type { AnnotationReplyConfig } from '@/models/debug'
|
||||
|
||||
type Props = {
|
||||
disabled?: boolean
|
||||
@ -77,11 +77,11 @@ const AnnotationReply = ({
|
||||
return (
|
||||
<>
|
||||
<FeatureCard
|
||||
icon={
|
||||
<div className='shrink-0 rounded-lg border-[0.5px] border-divider-subtle bg-util-colors-indigo-indigo-600 p-1 shadow-xs'>
|
||||
<MessageFast className='h-4 w-4 text-text-primary-on-surface' />
|
||||
icon={(
|
||||
<div className="shrink-0 rounded-lg border-[0.5px] border-divider-subtle bg-util-colors-indigo-indigo-600 p-1 shadow-xs">
|
||||
<MessageFast className="h-4 w-4 text-text-primary-on-surface" />
|
||||
</div>
|
||||
}
|
||||
)}
|
||||
title={t('appDebug.feature.annotation.title')}
|
||||
value={!!annotationReply?.enabled}
|
||||
onChange={state => handleSwitch(state)}
|
||||
@ -91,33 +91,36 @@ const AnnotationReply = ({
|
||||
>
|
||||
<>
|
||||
{!annotationReply?.enabled && (
|
||||
<div className='system-xs-regular line-clamp-2 min-h-8 text-text-tertiary'>{t('appDebug.feature.annotation.description')}</div>
|
||||
<div className="system-xs-regular line-clamp-2 min-h-8 text-text-tertiary">{t('appDebug.feature.annotation.description')}</div>
|
||||
)}
|
||||
{!!annotationReply?.enabled && (
|
||||
<>
|
||||
{!isHovering && (
|
||||
<div className='flex items-center gap-4 pt-0.5'>
|
||||
<div className=''>
|
||||
<div className='system-2xs-medium-uppercase mb-0.5 text-text-tertiary'>{t('appDebug.feature.annotation.scoreThreshold.title')}</div>
|
||||
<div className='system-xs-regular text-text-secondary'>{annotationReply.score_threshold || '-'}</div>
|
||||
<div className="flex items-center gap-4 pt-0.5">
|
||||
<div className="">
|
||||
<div className="system-2xs-medium-uppercase mb-0.5 text-text-tertiary">{t('appDebug.feature.annotation.scoreThreshold.title')}</div>
|
||||
<div className="system-xs-regular text-text-secondary">{annotationReply.score_threshold || '-'}</div>
|
||||
</div>
|
||||
<div className='h-[27px] w-px rotate-12 bg-divider-subtle'></div>
|
||||
<div className=''>
|
||||
<div className='system-2xs-medium-uppercase mb-0.5 text-text-tertiary'>{t('common.modelProvider.embeddingModel.key')}</div>
|
||||
<div className='system-xs-regular text-text-secondary'>{annotationReply.embedding_model?.embedding_model_name}</div>
|
||||
<div className="h-[27px] w-px rotate-12 bg-divider-subtle"></div>
|
||||
<div className="">
|
||||
<div className="system-2xs-medium-uppercase mb-0.5 text-text-tertiary">{t('common.modelProvider.embeddingModel.key')}</div>
|
||||
<div className="system-xs-regular text-text-secondary">{annotationReply.embedding_model?.embedding_model_name}</div>
|
||||
</div>
|
||||
</div>
|
||||
)}
|
||||
{isHovering && (
|
||||
<div className='flex items-center justify-between'>
|
||||
<Button className='w-[178px]' onClick={() => setIsShowAnnotationConfigInit(true)} disabled={disabled}>
|
||||
<RiEqualizer2Line className='mr-1 h-4 w-4' />
|
||||
<div className="flex items-center justify-between">
|
||||
<Button className="w-[178px]" onClick={() => setIsShowAnnotationConfigInit(true)} disabled={disabled}>
|
||||
<RiEqualizer2Line className="mr-1 h-4 w-4" />
|
||||
{t('common.operation.params')}
|
||||
</Button>
|
||||
<Button className='w-[178px]' onClick={() => {
|
||||
router.push(`/app/${appId}/annotations`)
|
||||
}}>
|
||||
<RiExternalLinkLine className='mr-1 h-4 w-4' />
|
||||
<Button
|
||||
className="w-[178px]"
|
||||
onClick={() => {
|
||||
router.push(`/app/${appId}/annotations`)
|
||||
}}
|
||||
>
|
||||
<RiExternalLinkLine className="mr-1 h-4 w-4" />
|
||||
{t('appDebug.feature.annotation.cacheManagement')}
|
||||
</Button>
|
||||
</div>
|
||||
|
||||
@ -1,6 +1,6 @@
|
||||
import ReactSlider from 'react-slider'
|
||||
import s from './style.module.css'
|
||||
import { cn } from '@/utils/classnames'
|
||||
import s from './style.module.css'
|
||||
|
||||
type ISliderProps = {
|
||||
className?: string
|
||||
@ -13,26 +13,28 @@ type ISliderProps = {
|
||||
}
|
||||
|
||||
const Slider: React.FC<ISliderProps> = ({ className, max, min, step, value, disabled, onChange }) => {
|
||||
return <ReactSlider
|
||||
disabled={disabled}
|
||||
value={isNaN(value) ? 0 : value}
|
||||
min={min || 0}
|
||||
max={max || 100}
|
||||
step={step || 1}
|
||||
className={cn(className, s.slider)}
|
||||
thumbClassName={cn(s['slider-thumb'], 'top-[-7px] h-[18px] w-2 cursor-pointer rounded-[36px] border !border-black/8 bg-white shadow-md')}
|
||||
trackClassName={s['slider-track']}
|
||||
onChange={onChange}
|
||||
renderThumb={(props, state) => (
|
||||
<div {...props}>
|
||||
<div className='relative h-full w-full'>
|
||||
<div className='system-sm-semibold absolute left-[50%] top-[-16px] translate-x-[-50%] text-text-primary'>
|
||||
{(state.valueNow / 100).toFixed(2)}
|
||||
return (
|
||||
<ReactSlider
|
||||
disabled={disabled}
|
||||
value={isNaN(value) ? 0 : value}
|
||||
min={min || 0}
|
||||
max={max || 100}
|
||||
step={step || 1}
|
||||
className={cn(className, s.slider)}
|
||||
thumbClassName={cn(s['slider-thumb'], 'top-[-7px] h-[18px] w-2 cursor-pointer rounded-[36px] border !border-black/8 bg-white shadow-md')}
|
||||
trackClassName={s['slider-track']}
|
||||
onChange={onChange}
|
||||
renderThumb={(props, state) => (
|
||||
<div {...props}>
|
||||
<div className="relative h-full w-full">
|
||||
<div className="system-sm-semibold absolute left-[50%] top-[-16px] translate-x-[-50%] text-text-primary">
|
||||
{(state.valueNow / 100).toFixed(2)}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
)}
|
||||
/>
|
||||
)}
|
||||
/>
|
||||
)
|
||||
}
|
||||
|
||||
export default Slider
|
||||
|
||||
@ -19,7 +19,7 @@ const ScoreSlider: FC<Props> = ({
|
||||
|
||||
return (
|
||||
<div className={className}>
|
||||
<div className='mt-[14px] h-px'>
|
||||
<div className="mt-[14px] h-px">
|
||||
<Slider
|
||||
max={100}
|
||||
min={80}
|
||||
@ -28,13 +28,13 @@ const ScoreSlider: FC<Props> = ({
|
||||
onChange={onChange}
|
||||
/>
|
||||
</div>
|
||||
<div className='system-xs-semibold-uppercase mt-[10px] flex items-center justify-between'>
|
||||
<div className='flex space-x-1 text-util-colors-cyan-cyan-500'>
|
||||
<div className="system-xs-semibold-uppercase mt-[10px] flex items-center justify-between">
|
||||
<div className="flex space-x-1 text-util-colors-cyan-cyan-500">
|
||||
<div>0.8</div>
|
||||
<div>·</div>
|
||||
<div>{t('appDebug.feature.annotation.scoreThreshold.easyMatch')}</div>
|
||||
</div>
|
||||
<div className='flex space-x-1 text-util-colors-blue-blue-500'>
|
||||
<div className="flex space-x-1 text-util-colors-blue-blue-500">
|
||||
<div>1.0</div>
|
||||
<div>·</div>
|
||||
<div>{t('appDebug.feature.annotation.scoreThreshold.accurateMatch')}</div>
|
||||
|
||||
@ -1,12 +1,12 @@
|
||||
import React, { useState } from 'react'
|
||||
import { produce } from 'immer'
|
||||
import type { AnnotationReplyConfig } from '@/models/debug'
|
||||
import { queryAnnotationJobStatus, updateAnnotationStatus } from '@/service/annotation'
|
||||
import type { EmbeddingModelConfig } from '@/app/components/app/annotation/type'
|
||||
import type { AnnotationReplyConfig } from '@/models/debug'
|
||||
import { produce } from 'immer'
|
||||
import React, { useState } from 'react'
|
||||
import { AnnotationEnableStatus, JobStatus } from '@/app/components/app/annotation/type'
|
||||
import { sleep } from '@/utils'
|
||||
import { ANNOTATION_DEFAULT } from '@/config'
|
||||
import { useProviderContext } from '@/context/provider-context'
|
||||
import { queryAnnotationJobStatus, updateAnnotationStatus } from '@/service/annotation'
|
||||
import { sleep } from '@/utils'
|
||||
|
||||
type Params = {
|
||||
appId: string
|
||||
|
||||
@ -1,11 +1,11 @@
|
||||
import type { OnFeaturesChange } from '@/app/components/base/features/types'
|
||||
import { produce } from 'immer'
|
||||
import React, { useCallback } from 'react'
|
||||
import { useTranslation } from 'react-i18next'
|
||||
import { produce } from 'immer'
|
||||
import { Citations } from '@/app/components/base/icons/src/vender/features'
|
||||
import FeatureCard from '@/app/components/base/features/new-feature-panel/feature-card'
|
||||
import { useFeatures, useFeaturesStore } from '@/app/components/base/features/hooks'
|
||||
import type { OnFeaturesChange } from '@/app/components/base/features/types'
|
||||
import FeatureCard from '@/app/components/base/features/new-feature-panel/feature-card'
|
||||
import { FeatureEnum } from '@/app/components/base/features/types'
|
||||
import { Citations } from '@/app/components/base/icons/src/vender/features'
|
||||
|
||||
type Props = {
|
||||
disabled?: boolean
|
||||
@ -39,11 +39,11 @@ const Citation = ({
|
||||
|
||||
return (
|
||||
<FeatureCard
|
||||
icon={
|
||||
<div className='shrink-0 rounded-lg border-[0.5px] border-divider-subtle bg-util-colors-warning-warning-500 p-1 shadow-xs'>
|
||||
<Citations className='h-4 w-4 text-text-primary-on-surface' />
|
||||
icon={(
|
||||
<div className="shrink-0 rounded-lg border-[0.5px] border-divider-subtle bg-util-colors-warning-warning-500 p-1 shadow-xs">
|
||||
<Citations className="h-4 w-4 text-text-primary-on-surface" />
|
||||
</div>
|
||||
}
|
||||
)}
|
||||
title={t('appDebug.feature.citation.title')}
|
||||
value={!!features.citation?.enabled}
|
||||
description={t('appDebug.feature.citation.description')!}
|
||||
|
||||
@ -1,16 +1,16 @@
|
||||
import type { OnFeaturesChange } from '@/app/components/base/features/types'
|
||||
import type { InputVar } from '@/app/components/workflow/types'
|
||||
import type { PromptVariable } from '@/models/debug'
|
||||
import { RiEditLine } from '@remixicon/react'
|
||||
import { produce } from 'immer'
|
||||
import React, { useCallback, useState } from 'react'
|
||||
import { useTranslation } from 'react-i18next'
|
||||
import { produce } from 'immer'
|
||||
import { RiEditLine } from '@remixicon/react'
|
||||
import { LoveMessage } from '@/app/components/base/icons/src/vender/features'
|
||||
import FeatureCard from '@/app/components/base/features/new-feature-panel/feature-card'
|
||||
import Button from '@/app/components/base/button'
|
||||
import { useFeatures, useFeaturesStore } from '@/app/components/base/features/hooks'
|
||||
import type { OnFeaturesChange } from '@/app/components/base/features/types'
|
||||
import FeatureCard from '@/app/components/base/features/new-feature-panel/feature-card'
|
||||
import { FeatureEnum } from '@/app/components/base/features/types'
|
||||
import { LoveMessage } from '@/app/components/base/icons/src/vender/features'
|
||||
import { useModalContext } from '@/context/modal-context'
|
||||
import type { PromptVariable } from '@/models/debug'
|
||||
import type { InputVar } from '@/app/components/workflow/types'
|
||||
|
||||
type Props = {
|
||||
disabled?: boolean
|
||||
@ -80,11 +80,11 @@ const ConversationOpener = ({
|
||||
|
||||
return (
|
||||
<FeatureCard
|
||||
icon={
|
||||
<div className='shrink-0 rounded-lg border-[0.5px] border-divider-subtle bg-util-colors-blue-light-blue-light-500 p-1 shadow-xs'>
|
||||
<LoveMessage className='h-4 w-4 text-text-primary-on-surface' />
|
||||
icon={(
|
||||
<div className="shrink-0 rounded-lg border-[0.5px] border-divider-subtle bg-util-colors-blue-light-blue-light-500 p-1 shadow-xs">
|
||||
<LoveMessage className="h-4 w-4 text-text-primary-on-surface" />
|
||||
</div>
|
||||
}
|
||||
)}
|
||||
title={t('appDebug.feature.conversationOpener.title')}
|
||||
value={!!opening?.enabled}
|
||||
onChange={state => handleChange(FeatureEnum.opening, state)}
|
||||
@ -94,18 +94,18 @@ const ConversationOpener = ({
|
||||
>
|
||||
<>
|
||||
{!opening?.enabled && (
|
||||
<div className='system-xs-regular line-clamp-2 min-h-8 text-text-tertiary'>{t('appDebug.feature.conversationOpener.description')}</div>
|
||||
<div className="system-xs-regular line-clamp-2 min-h-8 text-text-tertiary">{t('appDebug.feature.conversationOpener.description')}</div>
|
||||
)}
|
||||
{!!opening?.enabled && (
|
||||
<>
|
||||
{!isHovering && (
|
||||
<div className='system-xs-regular line-clamp-2 min-h-8 text-text-tertiary'>
|
||||
<div className="system-xs-regular line-clamp-2 min-h-8 text-text-tertiary">
|
||||
{opening.opening_statement || t('appDebug.openingStatement.placeholder')}
|
||||
</div>
|
||||
)}
|
||||
{isHovering && (
|
||||
<Button className='w-full' onClick={handleOpenOpeningModal} disabled={disabled}>
|
||||
<RiEditLine className='mr-1 h-4 w-4' />
|
||||
<Button className="w-full" onClick={handleOpenOpeningModal} disabled={disabled}>
|
||||
<RiEditLine className="mr-1 h-4 w-4" />
|
||||
{t('appDebug.openingStatement.writeOpener')}
|
||||
</Button>
|
||||
)}
|
||||
|
||||
@ -1,22 +1,21 @@
|
||||
import React, { useCallback, useEffect, useMemo, useState } from 'react'
|
||||
import { useTranslation } from 'react-i18next'
|
||||
import type { OpeningStatement } from '@/app/components/base/features/types'
|
||||
import type { InputVar } from '@/app/components/workflow/types'
|
||||
import type { PromptVariable } from '@/models/debug'
|
||||
import { RiAddLine, RiAsterisk, RiCloseLine, RiDeleteBinLine, RiDraggable } from '@remixicon/react'
|
||||
import { useBoolean } from 'ahooks'
|
||||
import { produce } from 'immer'
|
||||
import { noop } from 'lodash-es'
|
||||
import React, { useCallback, useEffect, useMemo, useState } from 'react'
|
||||
import { useTranslation } from 'react-i18next'
|
||||
import { ReactSortable } from 'react-sortablejs'
|
||||
import { RiAddLine, RiAsterisk, RiCloseLine, RiDeleteBinLine, RiDraggable } from '@remixicon/react'
|
||||
import Modal from '@/app/components/base/modal'
|
||||
import ConfirmAddVar from '@/app/components/app/configuration/config-prompt/confirm-add-var'
|
||||
import { getInputKeys } from '@/app/components/base/block-input'
|
||||
import Button from '@/app/components/base/button'
|
||||
import Divider from '@/app/components/base/divider'
|
||||
import ConfirmAddVar from '@/app/components/app/configuration/config-prompt/confirm-add-var'
|
||||
import Modal from '@/app/components/base/modal'
|
||||
import PromptEditor from '@/app/components/base/prompt-editor'
|
||||
import type { OpeningStatement } from '@/app/components/base/features/types'
|
||||
import { getInputKeys } from '@/app/components/base/block-input'
|
||||
import type { PromptVariable } from '@/models/debug'
|
||||
import type { InputVar } from '@/app/components/workflow/types'
|
||||
import { getNewVar } from '@/utils/var'
|
||||
import { cn } from '@/utils/classnames'
|
||||
import { noop } from 'lodash-es'
|
||||
import { checkKeys } from '@/utils/var'
|
||||
import { checkKeys, getNewVar } from '@/utils/var'
|
||||
|
||||
type OpeningSettingModalProps = {
|
||||
data: OpeningStatement
|
||||
@ -104,13 +103,17 @@ const OpeningSettingModal = ({
|
||||
const renderQuestions = () => {
|
||||
return (
|
||||
<div>
|
||||
<div className='flex items-center py-2'>
|
||||
<div className='flex shrink-0 space-x-0.5 text-xs font-medium leading-[18px] text-text-tertiary'>
|
||||
<div className='uppercase'>{t('appDebug.openingStatement.openingQuestion')}</div>
|
||||
<div className="flex items-center py-2">
|
||||
<div className="flex shrink-0 space-x-0.5 text-xs font-medium leading-[18px] text-text-tertiary">
|
||||
<div className="uppercase">{t('appDebug.openingStatement.openingQuestion')}</div>
|
||||
<div>·</div>
|
||||
<div>{tempSuggestedQuestions.length}/{MAX_QUESTION_NUM}</div>
|
||||
<div>
|
||||
{tempSuggestedQuestions.length}
|
||||
/
|
||||
{MAX_QUESTION_NUM}
|
||||
</div>
|
||||
</div>
|
||||
<Divider bgStyle='gradient' className='ml-3 h-px w-0 grow' />
|
||||
<Divider bgStyle="gradient" className="ml-3 h-px w-0 grow" />
|
||||
</div>
|
||||
<ReactSortable
|
||||
className="space-y-1"
|
||||
@ -121,7 +124,7 @@ const OpeningSettingModal = ({
|
||||
}
|
||||
})}
|
||||
setList={list => setTempSuggestedQuestions(list.map(item => item.name))}
|
||||
handle='.handle'
|
||||
handle=".handle"
|
||||
ghostClass="opacity-50"
|
||||
animation={150}
|
||||
>
|
||||
@ -135,7 +138,7 @@ const OpeningSettingModal = ({
|
||||
)}
|
||||
key={index}
|
||||
>
|
||||
<RiDraggable className='handle h-4 w-4 cursor-grab text-text-quaternary' />
|
||||
<RiDraggable className="handle h-4 w-4 cursor-grab text-text-quaternary" />
|
||||
<input
|
||||
type="input"
|
||||
value={question || ''}
|
||||
@ -149,30 +152,32 @@ const OpeningSettingModal = ({
|
||||
return item
|
||||
}))
|
||||
}}
|
||||
className={'h-9 w-full grow cursor-pointer overflow-x-auto rounded-lg border-0 bg-transparent pl-1.5 pr-8 text-sm leading-9 text-text-secondary focus:outline-none'}
|
||||
className="h-9 w-full grow cursor-pointer overflow-x-auto rounded-lg border-0 bg-transparent pl-1.5 pr-8 text-sm leading-9 text-text-secondary focus:outline-none"
|
||||
onFocus={() => setFocusID(index)}
|
||||
onBlur={() => setFocusID(null)}
|
||||
/>
|
||||
|
||||
<div
|
||||
className='absolute right-1.5 top-1/2 block translate-y-[-50%] cursor-pointer rounded-md p-1 text-text-tertiary hover:bg-state-destructive-hover hover:text-text-destructive'
|
||||
className="absolute right-1.5 top-1/2 block translate-y-[-50%] cursor-pointer rounded-md p-1 text-text-tertiary hover:bg-state-destructive-hover hover:text-text-destructive"
|
||||
onClick={() => {
|
||||
setTempSuggestedQuestions(tempSuggestedQuestions.filter((_, i) => index !== i))
|
||||
}}
|
||||
onMouseEnter={() => setDeletingID(index)}
|
||||
onMouseLeave={() => setDeletingID(null)}
|
||||
>
|
||||
<RiDeleteBinLine className='h-3.5 w-3.5' />
|
||||
<RiDeleteBinLine className="h-3.5 w-3.5" />
|
||||
</div>
|
||||
</div>
|
||||
)
|
||||
})}</ReactSortable>
|
||||
})}
|
||||
</ReactSortable>
|
||||
{tempSuggestedQuestions.length < MAX_QUESTION_NUM && (
|
||||
<div
|
||||
onClick={() => { setTempSuggestedQuestions([...tempSuggestedQuestions, '']) }}
|
||||
className='mt-1 flex h-9 cursor-pointer items-center gap-2 rounded-lg bg-components-button-tertiary-bg px-3 text-components-button-tertiary-text hover:bg-components-button-tertiary-bg-hover'>
|
||||
<RiAddLine className='h-4 w-4' />
|
||||
<div className='system-sm-medium text-[13px]'>{t('appDebug.variableConfig.addOption')}</div>
|
||||
className="mt-1 flex h-9 cursor-pointer items-center gap-2 rounded-lg bg-components-button-tertiary-bg px-3 text-components-button-tertiary-text hover:bg-components-button-tertiary-bg-hover"
|
||||
>
|
||||
<RiAddLine className="h-4 w-4" />
|
||||
<div className="system-sm-medium text-[13px]">{t('appDebug.variableConfig.addOption')}</div>
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
@ -183,17 +188,17 @@ const OpeningSettingModal = ({
|
||||
<Modal
|
||||
isShow
|
||||
onClose={noop}
|
||||
className='!mt-14 !w-[640px] !max-w-none !bg-components-panel-bg-blur !p-6'
|
||||
className="!mt-14 !w-[640px] !max-w-none !bg-components-panel-bg-blur !p-6"
|
||||
>
|
||||
<div className='mb-6 flex items-center justify-between'>
|
||||
<div className='title-2xl-semi-bold text-text-primary'>{t('appDebug.feature.conversationOpener.title')}</div>
|
||||
<div className='cursor-pointer p-1' onClick={onCancel}><RiCloseLine className='h-4 w-4 text-text-tertiary' /></div>
|
||||
<div className="mb-6 flex items-center justify-between">
|
||||
<div className="title-2xl-semi-bold text-text-primary">{t('appDebug.feature.conversationOpener.title')}</div>
|
||||
<div className="cursor-pointer p-1" onClick={onCancel}><RiCloseLine className="h-4 w-4 text-text-tertiary" /></div>
|
||||
</div>
|
||||
<div className='mb-8 flex gap-2'>
|
||||
<div className='mt-1.5 h-8 w-8 shrink-0 rounded-lg border-components-panel-border bg-util-colors-orange-dark-orange-dark-500 p-1.5'>
|
||||
<RiAsterisk className='h-5 w-5 text-text-primary-on-surface' />
|
||||
<div className="mb-8 flex gap-2">
|
||||
<div className="mt-1.5 h-8 w-8 shrink-0 rounded-lg border-components-panel-border bg-util-colors-orange-dark-orange-dark-500 p-1.5">
|
||||
<RiAsterisk className="h-5 w-5 text-text-primary-on-surface" />
|
||||
</div>
|
||||
<div className='grow rounded-2xl border-t border-divider-subtle bg-chat-bubble-bg p-3 shadow-xs'>
|
||||
<div className="grow rounded-2xl border-t border-divider-subtle bg-chat-bubble-bg p-3 shadow-xs">
|
||||
<PromptEditor
|
||||
value={tempValue}
|
||||
onChange={setTempValue}
|
||||
@ -217,15 +222,15 @@ const OpeningSettingModal = ({
|
||||
{renderQuestions()}
|
||||
</div>
|
||||
</div>
|
||||
<div className='flex items-center justify-end'>
|
||||
<div className="flex items-center justify-end">
|
||||
<Button
|
||||
onClick={onCancel}
|
||||
className='mr-2'
|
||||
className="mr-2"
|
||||
>
|
||||
{t('common.operation.cancel')}
|
||||
</Button>
|
||||
<Button
|
||||
variant='primary'
|
||||
variant="primary"
|
||||
onClick={() => handleSave()}
|
||||
disabled={isSaveDisabled}
|
||||
>
|
||||
|
||||
@ -1,6 +1,6 @@
|
||||
import { Fragment, useCallback } from 'react'
|
||||
import type { ReactNode } from 'react'
|
||||
import { Dialog, DialogPanel, Transition, TransitionChild } from '@headlessui/react'
|
||||
import { Fragment, useCallback } from 'react'
|
||||
import { cn } from '@/utils/classnames'
|
||||
|
||||
type DialogProps = {
|
||||
@ -28,7 +28,8 @@ const DialogWrapper = ({
|
||||
'data-[closed]:opacity-0',
|
||||
'data-[enter]:opacity-100 data-[enter]:duration-300 data-[enter]:ease-out',
|
||||
'data-[leave]:opacity-0 data-[leave]:duration-200 data-[leave]:ease-in',
|
||||
)} />
|
||||
)}
|
||||
/>
|
||||
</TransitionChild>
|
||||
|
||||
<div className="fixed inset-0">
|
||||
@ -41,14 +42,15 @@ const DialogWrapper = ({
|
||||
'data-[enter]:scale-100 data-[enter]:opacity-100 data-[enter]:duration-300 data-[enter]:ease-out',
|
||||
'data-[leave]:scale-95 data-[leave]:opacity-0 data-[leave]:duration-200 data-[leave]:ease-in',
|
||||
className,
|
||||
)}>
|
||||
)}
|
||||
>
|
||||
{children}
|
||||
</DialogPanel>
|
||||
</TransitionChild>
|
||||
</div>
|
||||
</div>
|
||||
</Dialog>
|
||||
</Transition >
|
||||
</Transition>
|
||||
)
|
||||
}
|
||||
|
||||
|
||||
@ -1,11 +1,11 @@
|
||||
import { RiApps2AddLine, RiArrowRightLine, RiSparklingFill } from '@remixicon/react'
|
||||
import React, { useMemo, useState } from 'react'
|
||||
import { useTranslation } from 'react-i18next'
|
||||
import { RiApps2AddLine, RiArrowRightLine, RiSparklingFill } from '@remixicon/react'
|
||||
import { Citations, ContentModeration, FolderUpload, LoveMessage, MessageFast, Microphone01, TextToAudio, VirtualAssistant } from '@/app/components/base/icons/src/vender/features'
|
||||
import Button from '@/app/components/base/button'
|
||||
import Tooltip from '@/app/components/base/tooltip'
|
||||
import VoiceSettings from '@/app/components/base/features/new-feature-panel/text-to-speech/voice-settings'
|
||||
import { useFeatures } from '@/app/components/base/features/hooks'
|
||||
import VoiceSettings from '@/app/components/base/features/new-feature-panel/text-to-speech/voice-settings'
|
||||
import { Citations, ContentModeration, FolderUpload, LoveMessage, MessageFast, Microphone01, TextToAudio, VirtualAssistant } from '@/app/components/base/icons/src/vender/features'
|
||||
import Tooltip from '@/app/components/base/tooltip'
|
||||
import { cn } from '@/utils/classnames'
|
||||
|
||||
type Props = {
|
||||
@ -36,23 +36,23 @@ const FeatureBar = ({
|
||||
}, [features, isChatMode, showFileUpload])
|
||||
|
||||
return (
|
||||
<div className='m-1 mt-0 -translate-y-2 rounded-b-[10px] border-b border-l border-r border-components-panel-border-subtle bg-util-colors-indigo-indigo-50 px-2.5 py-2 pt-4'>
|
||||
<div className="m-1 mt-0 -translate-y-2 rounded-b-[10px] border-b border-l border-r border-components-panel-border-subtle bg-util-colors-indigo-indigo-50 px-2.5 py-2 pt-4">
|
||||
{noFeatureEnabled && (
|
||||
<div className='flex cursor-pointer items-end gap-1' onClick={() => onFeatureBarClick?.(true)}>
|
||||
<RiApps2AddLine className='h-3.5 w-3.5 text-text-accent' />
|
||||
<div className='body-xs-medium text-text-accent'>{t('appDebug.feature.bar.empty')}</div>
|
||||
<RiArrowRightLine className='h-3.5 w-3.5 text-text-accent' />
|
||||
<div className="flex cursor-pointer items-end gap-1" onClick={() => onFeatureBarClick?.(true)}>
|
||||
<RiApps2AddLine className="h-3.5 w-3.5 text-text-accent" />
|
||||
<div className="body-xs-medium text-text-accent">{t('appDebug.feature.bar.empty')}</div>
|
||||
<RiArrowRightLine className="h-3.5 w-3.5 text-text-accent" />
|
||||
</div>
|
||||
)}
|
||||
{!noFeatureEnabled && (
|
||||
<div className='flex items-center gap-2'>
|
||||
<div className='flex shrink-0 items-center gap-0.5'>
|
||||
<div className="flex items-center gap-2">
|
||||
<div className="flex shrink-0 items-center gap-0.5">
|
||||
{!!features.moreLikeThis?.enabled && (
|
||||
<Tooltip
|
||||
popupContent={t('appDebug.feature.moreLikeThis.title')}
|
||||
>
|
||||
<div className='shrink-0 rounded-lg border-[0.5px] border-divider-subtle bg-util-colors-blue-light-blue-light-500 p-1 shadow-xs'>
|
||||
<RiSparklingFill className='h-3.5 w-3.5 text-text-primary-on-surface' />
|
||||
<div className="shrink-0 rounded-lg border-[0.5px] border-divider-subtle bg-util-colors-blue-light-blue-light-500 p-1 shadow-xs">
|
||||
<RiSparklingFill className="h-3.5 w-3.5 text-text-primary-on-surface" />
|
||||
</div>
|
||||
</Tooltip>
|
||||
)}
|
||||
@ -60,8 +60,8 @@ const FeatureBar = ({
|
||||
<Tooltip
|
||||
popupContent={t('appDebug.feature.conversationOpener.title')}
|
||||
>
|
||||
<div className='shrink-0 rounded-lg border-[0.5px] border-divider-subtle bg-util-colors-blue-light-blue-light-500 p-1 shadow-xs'>
|
||||
<LoveMessage className='h-3.5 w-3.5 text-text-primary-on-surface' />
|
||||
<div className="shrink-0 rounded-lg border-[0.5px] border-divider-subtle bg-util-colors-blue-light-blue-light-500 p-1 shadow-xs">
|
||||
<LoveMessage className="h-3.5 w-3.5 text-text-primary-on-surface" />
|
||||
</div>
|
||||
</Tooltip>
|
||||
)}
|
||||
@ -69,8 +69,8 @@ const FeatureBar = ({
|
||||
<Tooltip
|
||||
popupContent={t('appDebug.feature.moderation.title')}
|
||||
>
|
||||
<div className='shrink-0 rounded-lg border-[0.5px] border-divider-subtle bg-text-success p-1 shadow-xs'>
|
||||
<ContentModeration className='h-3.5 w-3.5 text-text-primary-on-surface' />
|
||||
<div className="shrink-0 rounded-lg border-[0.5px] border-divider-subtle bg-text-success p-1 shadow-xs">
|
||||
<ContentModeration className="h-3.5 w-3.5 text-text-primary-on-surface" />
|
||||
</div>
|
||||
</Tooltip>
|
||||
)}
|
||||
@ -78,8 +78,8 @@ const FeatureBar = ({
|
||||
<Tooltip
|
||||
popupContent={t('appDebug.feature.speechToText.title')}
|
||||
>
|
||||
<div className='shrink-0 rounded-lg border-[0.5px] border-divider-subtle bg-util-colors-violet-violet-600 p-1 shadow-xs'>
|
||||
<Microphone01 className='h-3.5 w-3.5 text-text-primary-on-surface' />
|
||||
<div className="shrink-0 rounded-lg border-[0.5px] border-divider-subtle bg-util-colors-violet-violet-600 p-1 shadow-xs">
|
||||
<Microphone01 className="h-3.5 w-3.5 text-text-primary-on-surface" />
|
||||
</div>
|
||||
</Tooltip>
|
||||
)}
|
||||
@ -89,7 +89,7 @@ const FeatureBar = ({
|
||||
popupContent={t('appDebug.feature.textToSpeech.title')}
|
||||
>
|
||||
<div className={cn('shrink-0 rounded-lg border-[0.5px] border-divider-subtle bg-util-colors-violet-violet-600 p-1 shadow-xs', !disabled && 'cursor-pointer')}>
|
||||
<TextToAudio className='h-3.5 w-3.5 text-text-primary-on-surface' />
|
||||
<TextToAudio className="h-3.5 w-3.5 text-text-primary-on-surface" />
|
||||
</div>
|
||||
</Tooltip>
|
||||
</VoiceSettings>
|
||||
@ -98,8 +98,8 @@ const FeatureBar = ({
|
||||
<Tooltip
|
||||
popupContent={t('appDebug.feature.fileUpload.title')}
|
||||
>
|
||||
<div className='shrink-0 rounded-lg border-[0.5px] border-divider-subtle bg-util-colors-blue-blue-600 p-1 shadow-xs'>
|
||||
<FolderUpload className='h-3.5 w-3.5 text-text-primary-on-surface' />
|
||||
<div className="shrink-0 rounded-lg border-[0.5px] border-divider-subtle bg-util-colors-blue-blue-600 p-1 shadow-xs">
|
||||
<FolderUpload className="h-3.5 w-3.5 text-text-primary-on-surface" />
|
||||
</div>
|
||||
</Tooltip>
|
||||
)}
|
||||
@ -107,8 +107,8 @@ const FeatureBar = ({
|
||||
<Tooltip
|
||||
popupContent={t('appDebug.feature.suggestedQuestionsAfterAnswer.title')}
|
||||
>
|
||||
<div className='shrink-0 rounded-lg border-[0.5px] border-divider-subtle bg-util-colors-blue-light-blue-light-500 p-1 shadow-xs'>
|
||||
<VirtualAssistant className='h-3.5 w-3.5 text-text-primary-on-surface' />
|
||||
<div className="shrink-0 rounded-lg border-[0.5px] border-divider-subtle bg-util-colors-blue-light-blue-light-500 p-1 shadow-xs">
|
||||
<VirtualAssistant className="h-3.5 w-3.5 text-text-primary-on-surface" />
|
||||
</div>
|
||||
</Tooltip>
|
||||
)}
|
||||
@ -116,8 +116,8 @@ const FeatureBar = ({
|
||||
<Tooltip
|
||||
popupContent={t('appDebug.feature.citation.title')}
|
||||
>
|
||||
<div className='shrink-0 rounded-lg border-[0.5px] border-divider-subtle bg-util-colors-warning-warning-500 p-1 shadow-xs'>
|
||||
<Citations className='h-4 w-4 text-text-primary-on-surface' />
|
||||
<div className="shrink-0 rounded-lg border-[0.5px] border-divider-subtle bg-util-colors-warning-warning-500 p-1 shadow-xs">
|
||||
<Citations className="h-4 w-4 text-text-primary-on-surface" />
|
||||
</div>
|
||||
</Tooltip>
|
||||
)}
|
||||
@ -125,16 +125,16 @@ const FeatureBar = ({
|
||||
<Tooltip
|
||||
popupContent={t('appDebug.feature.annotation.title')}
|
||||
>
|
||||
<div className='shrink-0 rounded-lg border-[0.5px] border-divider-subtle bg-util-colors-indigo-indigo-600 p-1 shadow-xs'>
|
||||
<MessageFast className='h-3.5 w-3.5 text-text-primary-on-surface' />
|
||||
<div className="shrink-0 rounded-lg border-[0.5px] border-divider-subtle bg-util-colors-indigo-indigo-600 p-1 shadow-xs">
|
||||
<MessageFast className="h-3.5 w-3.5 text-text-primary-on-surface" />
|
||||
</div>
|
||||
</Tooltip>
|
||||
)}
|
||||
</div>
|
||||
<div className='body-xs-regular grow text-text-tertiary'>{t('appDebug.feature.bar.enableText')}</div>
|
||||
<Button className='shrink-0' variant='ghost-accent' size='small' onClick={() => onFeatureBarClick?.(true)}>
|
||||
<div className='mx-1'>{t('appDebug.feature.bar.manage')}</div>
|
||||
<RiArrowRightLine className='h-3.5 w-3.5 text-text-accent' />
|
||||
<div className="body-xs-regular grow text-text-tertiary">{t('appDebug.feature.bar.enableText')}</div>
|
||||
<Button className="shrink-0" variant="ghost-accent" size="small" onClick={() => onFeatureBarClick?.(true)}>
|
||||
<div className="mx-1">{t('appDebug.feature.bar.manage')}</div>
|
||||
<RiArrowRightLine className="h-3.5 w-3.5 text-text-accent" />
|
||||
</Button>
|
||||
</div>
|
||||
)}
|
||||
|
||||
@ -1,7 +1,7 @@
|
||||
import React from 'react'
|
||||
import {
|
||||
RiQuestionLine,
|
||||
} from '@remixicon/react'
|
||||
import React from 'react'
|
||||
import Switch from '@/app/components/base/switch'
|
||||
import Tooltip from '@/app/components/base/tooltip'
|
||||
|
||||
@ -32,26 +32,26 @@ const FeatureCard = ({
|
||||
}: Props) => {
|
||||
return (
|
||||
<div
|
||||
className='mb-1 rounded-xl border-l-[0.5px] border-t-[0.5px] border-effects-highlight bg-background-section-burn p-3'
|
||||
className="mb-1 rounded-xl border-l-[0.5px] border-t-[0.5px] border-effects-highlight bg-background-section-burn p-3"
|
||||
onMouseEnter={onMouseEnter}
|
||||
onMouseLeave={onMouseLeave}
|
||||
>
|
||||
<div className='mb-2 flex items-center gap-2'>
|
||||
<div className="mb-2 flex items-center gap-2">
|
||||
{icon}
|
||||
<div className='system-sm-semibold flex grow items-center text-text-secondary'>
|
||||
<div className="system-sm-semibold flex grow items-center text-text-secondary">
|
||||
{title}
|
||||
{tooltip && (
|
||||
<Tooltip
|
||||
popupContent={tooltip}
|
||||
>
|
||||
<div className='ml-0.5 p-px'><RiQuestionLine className='h-3.5 w-3.5 text-text-quaternary' /></div>
|
||||
<div className="ml-0.5 p-px"><RiQuestionLine className="h-3.5 w-3.5 text-text-quaternary" /></div>
|
||||
</Tooltip>
|
||||
)}
|
||||
</div>
|
||||
<Switch disabled={disabled} className='shrink-0' onChange={state => onChange?.(state)} defaultValue={value} />
|
||||
<Switch disabled={disabled} className="shrink-0" onChange={state => onChange?.(state)} defaultValue={value} />
|
||||
</div>
|
||||
{description && (
|
||||
<div className='system-xs-regular line-clamp-2 min-h-8 text-text-tertiary'>{description}</div>
|
||||
<div className="system-xs-regular line-clamp-2 min-h-8 text-text-tertiary">{description}</div>
|
||||
)}
|
||||
{children}
|
||||
</div>
|
||||
|
||||
@ -1,14 +1,14 @@
|
||||
import type { OnFeaturesChange } from '@/app/components/base/features/types'
|
||||
import { RiEqualizer2Line } from '@remixicon/react'
|
||||
import { produce } from 'immer'
|
||||
import React, { useCallback, useMemo, useState } from 'react'
|
||||
import { useTranslation } from 'react-i18next'
|
||||
import { produce } from 'immer'
|
||||
import { RiEqualizer2Line } from '@remixicon/react'
|
||||
import { FolderUpload } from '@/app/components/base/icons/src/vender/features'
|
||||
import FeatureCard from '@/app/components/base/features/new-feature-panel/feature-card'
|
||||
import SettingModal from '@/app/components/base/features/new-feature-panel/file-upload/setting-modal'
|
||||
import Button from '@/app/components/base/button'
|
||||
import { useFeatures, useFeaturesStore } from '@/app/components/base/features/hooks'
|
||||
import type { OnFeaturesChange } from '@/app/components/base/features/types'
|
||||
import FeatureCard from '@/app/components/base/features/new-feature-panel/feature-card'
|
||||
import SettingModal from '@/app/components/base/features/new-feature-panel/file-upload/setting-modal'
|
||||
import { FeatureEnum } from '@/app/components/base/features/types'
|
||||
import { FolderUpload } from '@/app/components/base/icons/src/vender/features'
|
||||
|
||||
type Props = {
|
||||
disabled: boolean
|
||||
@ -49,11 +49,11 @@ const FileUpload = ({
|
||||
|
||||
return (
|
||||
<FeatureCard
|
||||
icon={
|
||||
<div className='shrink-0 rounded-lg border-[0.5px] border-divider-subtle bg-util-colors-blue-blue-600 p-1 shadow-xs'>
|
||||
<FolderUpload className='h-4 w-4 text-text-primary-on-surface' />
|
||||
icon={(
|
||||
<div className="shrink-0 rounded-lg border-[0.5px] border-divider-subtle bg-util-colors-blue-blue-600 p-1 shadow-xs">
|
||||
<FolderUpload className="h-4 w-4 text-text-primary-on-surface" />
|
||||
</div>
|
||||
}
|
||||
)}
|
||||
title={t('appDebug.feature.fileUpload.title')}
|
||||
value={file?.enabled}
|
||||
onChange={state => handleChange(FeatureEnum.file, state)}
|
||||
@ -63,20 +63,20 @@ const FileUpload = ({
|
||||
>
|
||||
<>
|
||||
{!file?.enabled && (
|
||||
<div className='system-xs-regular line-clamp-2 min-h-8 text-text-tertiary'>{t('appDebug.feature.fileUpload.description')}</div>
|
||||
<div className="system-xs-regular line-clamp-2 min-h-8 text-text-tertiary">{t('appDebug.feature.fileUpload.description')}</div>
|
||||
)}
|
||||
{file?.enabled && (
|
||||
<>
|
||||
{!isHovering && !modalOpen && (
|
||||
<div className='flex items-center gap-4 pt-0.5'>
|
||||
<div className=''>
|
||||
<div className='system-2xs-medium-uppercase mb-0.5 text-text-tertiary'>{t('appDebug.feature.fileUpload.supportedTypes')}</div>
|
||||
<div className='system-xs-regular text-text-secondary'>{supportedTypes}</div>
|
||||
<div className="flex items-center gap-4 pt-0.5">
|
||||
<div className="">
|
||||
<div className="system-2xs-medium-uppercase mb-0.5 text-text-tertiary">{t('appDebug.feature.fileUpload.supportedTypes')}</div>
|
||||
<div className="system-xs-regular text-text-secondary">{supportedTypes}</div>
|
||||
</div>
|
||||
<div className='h-[27px] w-px rotate-12 bg-divider-subtle'></div>
|
||||
<div className=''>
|
||||
<div className='system-2xs-medium-uppercase mb-0.5 text-text-tertiary'>{t('appDebug.feature.fileUpload.numberLimit')}</div>
|
||||
<div className='system-xs-regular text-text-secondary'>{file?.number_limits}</div>
|
||||
<div className="h-[27px] w-px rotate-12 bg-divider-subtle"></div>
|
||||
<div className="">
|
||||
<div className="system-2xs-medium-uppercase mb-0.5 text-text-tertiary">{t('appDebug.feature.fileUpload.numberLimit')}</div>
|
||||
<div className="system-xs-regular text-text-secondary">{file?.number_limits}</div>
|
||||
</div>
|
||||
</div>
|
||||
)}
|
||||
@ -89,8 +89,8 @@ const FileUpload = ({
|
||||
}}
|
||||
onChange={onChange}
|
||||
>
|
||||
<Button className='w-full' disabled={disabled}>
|
||||
<RiEqualizer2Line className='mr-1 h-4 w-4' />
|
||||
<Button className="w-full" disabled={disabled}>
|
||||
<RiEqualizer2Line className="mr-1 h-4 w-4" />
|
||||
{t('common.operation.settings')}
|
||||
</Button>
|
||||
</SettingModal>
|
||||
|
||||
@ -1,14 +1,14 @@
|
||||
import React, { useCallback, useMemo, useState } from 'react'
|
||||
import { produce } from 'immer'
|
||||
import { useTranslation } from 'react-i18next'
|
||||
import { RiCloseLine } from '@remixicon/react'
|
||||
import FileUploadSetting from '@/app/components/workflow/nodes/_base/components/file-upload-setting'
|
||||
import Button from '@/app/components/base/button'
|
||||
import { useFeatures, useFeaturesStore } from '@/app/components/base/features/hooks'
|
||||
import type { OnFeaturesChange } from '@/app/components/base/features/types'
|
||||
import type { UploadFileSetting } from '@/app/components/workflow/types'
|
||||
import { SupportUploadFileTypes } from '@/app/components/workflow/types'
|
||||
import { RiCloseLine } from '@remixicon/react'
|
||||
import { produce } from 'immer'
|
||||
import React, { useCallback, useMemo, useState } from 'react'
|
||||
import { useTranslation } from 'react-i18next'
|
||||
import Button from '@/app/components/base/button'
|
||||
import { useFeatures, useFeaturesStore } from '@/app/components/base/features/hooks'
|
||||
import { FILE_EXTS } from '@/app/components/base/prompt-editor/constants'
|
||||
import FileUploadSetting from '@/app/components/workflow/nodes/_base/components/file-upload-setting'
|
||||
import { SupportUploadFileTypes } from '@/app/components/workflow/types'
|
||||
|
||||
type SettingContentProps = {
|
||||
imageUpload?: boolean
|
||||
@ -56,9 +56,9 @@ const SettingContent = ({
|
||||
|
||||
return (
|
||||
<>
|
||||
<div className='mb-4 flex items-center justify-between'>
|
||||
<div className='system-xl-semibold text-text-primary'>{!imageUpload ? t('appDebug.feature.fileUpload.modalTitle') : t('appDebug.feature.imageUpload.modalTitle')}</div>
|
||||
<div className='cursor-pointer p-1' onClick={onClose}><RiCloseLine className='h-4 w-4 text-text-tertiary'/></div>
|
||||
<div className="mb-4 flex items-center justify-between">
|
||||
<div className="system-xl-semibold text-text-primary">{!imageUpload ? t('appDebug.feature.fileUpload.modalTitle') : t('appDebug.feature.imageUpload.modalTitle')}</div>
|
||||
<div className="cursor-pointer p-1" onClick={onClose}><RiCloseLine className="h-4 w-4 text-text-tertiary" /></div>
|
||||
</div>
|
||||
<FileUploadSetting
|
||||
isMultiple
|
||||
@ -67,15 +67,15 @@ const SettingContent = ({
|
||||
payload={tempPayload}
|
||||
onChange={(p: UploadFileSetting) => setTempPayload(p)}
|
||||
/>
|
||||
<div className='mt-4 flex items-center justify-end'>
|
||||
<div className="mt-4 flex items-center justify-end">
|
||||
<Button
|
||||
onClick={onClose}
|
||||
className='mr-2'
|
||||
className="mr-2"
|
||||
>
|
||||
{t('common.operation.cancel')}
|
||||
</Button>
|
||||
<Button
|
||||
variant='primary'
|
||||
variant="primary"
|
||||
onClick={handleChange}
|
||||
disabled={tempPayload.allowed_file_types.length === 0}
|
||||
>
|
||||
|
||||
@ -1,12 +1,12 @@
|
||||
'use client'
|
||||
import type { OnFeaturesChange } from '@/app/components/base/features/types'
|
||||
import { memo } from 'react'
|
||||
import SettingContent from '@/app/components/base/features/new-feature-panel/file-upload/setting-content'
|
||||
import {
|
||||
PortalToFollowElem,
|
||||
PortalToFollowElemContent,
|
||||
PortalToFollowElemTrigger,
|
||||
} from '@/app/components/base/portal-to-follow-elem'
|
||||
import SettingContent from '@/app/components/base/features/new-feature-panel/file-upload/setting-content'
|
||||
import type { OnFeaturesChange } from '@/app/components/base/features/types'
|
||||
|
||||
type FileUploadSettingsProps = {
|
||||
open: boolean
|
||||
@ -28,23 +28,24 @@ const FileUploadSettings = ({
|
||||
<PortalToFollowElem
|
||||
open={open}
|
||||
onOpenChange={onOpen}
|
||||
placement='left'
|
||||
placement="left"
|
||||
offset={{
|
||||
mainAxis: 32,
|
||||
}}
|
||||
>
|
||||
<PortalToFollowElemTrigger className='flex' onClick={() => !disabled && onOpen((open: boolean) => !open)}>
|
||||
<PortalToFollowElemTrigger className="flex" onClick={() => !disabled && onOpen((open: boolean) => !open)}>
|
||||
{children}
|
||||
</PortalToFollowElemTrigger>
|
||||
<PortalToFollowElemContent style={{ zIndex: 50 }}>
|
||||
<div className='max-h-[calc(100vh-20px)] w-[360px] overflow-y-auto rounded-2xl border-[0.5px] border-components-panel-border bg-components-panel-bg p-4 shadow-2xl'>
|
||||
<div className="max-h-[calc(100vh-20px)] w-[360px] overflow-y-auto rounded-2xl border-[0.5px] border-components-panel-border bg-components-panel-bg p-4 shadow-2xl">
|
||||
<SettingContent
|
||||
imageUpload={imageUpload}
|
||||
onClose={() => onOpen(false)}
|
||||
onChange={(v) => {
|
||||
onChange?.(v)
|
||||
onOpen(false)
|
||||
}} />
|
||||
}}
|
||||
/>
|
||||
</div>
|
||||
</PortalToFollowElemContent>
|
||||
</PortalToFollowElem>
|
||||
|
||||
@ -1,11 +1,11 @@
|
||||
import type { OnFeaturesChange } from '@/app/components/base/features/types'
|
||||
import { produce } from 'immer'
|
||||
import React, { useCallback } from 'react'
|
||||
import { useTranslation } from 'react-i18next'
|
||||
import { produce } from 'immer'
|
||||
import { VirtualAssistant } from '@/app/components/base/icons/src/vender/features'
|
||||
import FeatureCard from '@/app/components/base/features/new-feature-panel/feature-card'
|
||||
import { useFeatures, useFeaturesStore } from '@/app/components/base/features/hooks'
|
||||
import type { OnFeaturesChange } from '@/app/components/base/features/types'
|
||||
import FeatureCard from '@/app/components/base/features/new-feature-panel/feature-card'
|
||||
import { FeatureEnum } from '@/app/components/base/features/types'
|
||||
import { VirtualAssistant } from '@/app/components/base/icons/src/vender/features'
|
||||
|
||||
type Props = {
|
||||
disabled?: boolean
|
||||
@ -39,11 +39,11 @@ const FollowUp = ({
|
||||
|
||||
return (
|
||||
<FeatureCard
|
||||
icon={
|
||||
<div className='shrink-0 rounded-lg border-[0.5px] border-divider-subtle bg-util-colors-blue-light-blue-light-500 p-1 shadow-xs'>
|
||||
<VirtualAssistant className='h-4 w-4 text-text-primary-on-surface' />
|
||||
icon={(
|
||||
<div className="shrink-0 rounded-lg border-[0.5px] border-divider-subtle bg-util-colors-blue-light-blue-light-500 p-1 shadow-xs">
|
||||
<VirtualAssistant className="h-4 w-4 text-text-primary-on-surface" />
|
||||
</div>
|
||||
}
|
||||
)}
|
||||
title={t('appDebug.feature.suggestedQuestionsAfterAnswer.title')}
|
||||
value={!!features.suggested?.enabled}
|
||||
description={t('appDebug.feature.suggestedQuestionsAfterAnswer.description')!}
|
||||
|
||||
@ -1,13 +1,13 @@
|
||||
import type { OnFeaturesChange } from '@/app/components/base/features/types'
|
||||
import { RiEqualizer2Line, RiImage2Fill } from '@remixicon/react'
|
||||
import { produce } from 'immer'
|
||||
import React, { useCallback, useMemo, useState } from 'react'
|
||||
import { useTranslation } from 'react-i18next'
|
||||
import { produce } from 'immer'
|
||||
import { RiEqualizer2Line, RiImage2Fill } from '@remixicon/react'
|
||||
import FeatureCard from '@/app/components/base/features/new-feature-panel/feature-card'
|
||||
import SettingModal from '@/app/components/base/features/new-feature-panel/file-upload/setting-modal'
|
||||
import Badge from '@/app/components/base/badge'
|
||||
import Button from '@/app/components/base/button'
|
||||
import { useFeatures, useFeaturesStore } from '@/app/components/base/features/hooks'
|
||||
import type { OnFeaturesChange } from '@/app/components/base/features/types'
|
||||
import FeatureCard from '@/app/components/base/features/new-feature-panel/feature-card'
|
||||
import SettingModal from '@/app/components/base/features/new-feature-panel/file-upload/setting-modal'
|
||||
import { FeatureEnum } from '@/app/components/base/features/types'
|
||||
|
||||
type Props = {
|
||||
@ -49,20 +49,20 @@ const FileUpload = ({
|
||||
|
||||
return (
|
||||
<FeatureCard
|
||||
icon={
|
||||
<div className='shrink-0 rounded-lg border-[0.5px] border-divider-subtle bg-util-colors-indigo-indigo-600 p-1 shadow-xs'>
|
||||
<RiImage2Fill className='h-4 w-4 text-text-primary-on-surface' />
|
||||
icon={(
|
||||
<div className="shrink-0 rounded-lg border-[0.5px] border-divider-subtle bg-util-colors-indigo-indigo-600 p-1 shadow-xs">
|
||||
<RiImage2Fill className="h-4 w-4 text-text-primary-on-surface" />
|
||||
</div>
|
||||
}
|
||||
title={
|
||||
<div className='flex items-center'>
|
||||
)}
|
||||
title={(
|
||||
<div className="flex items-center">
|
||||
{t('appDebug.feature.imageUpload.title')}
|
||||
<Badge
|
||||
text='LEGACY'
|
||||
className='mx-1 shrink-0 border-text-accent-secondary text-text-accent-secondary'
|
||||
text="LEGACY"
|
||||
className="mx-1 shrink-0 border-text-accent-secondary text-text-accent-secondary"
|
||||
/>
|
||||
</div>
|
||||
}
|
||||
)}
|
||||
value={file?.enabled}
|
||||
onChange={state => handleChange(FeatureEnum.file, state)}
|
||||
onMouseEnter={() => setIsHovering(true)}
|
||||
@ -71,20 +71,20 @@ const FileUpload = ({
|
||||
>
|
||||
<>
|
||||
{!file?.enabled && (
|
||||
<div className='system-xs-regular line-clamp-2 min-h-8 text-text-tertiary'>{t('appDebug.feature.imageUpload.description')}</div>
|
||||
<div className="system-xs-regular line-clamp-2 min-h-8 text-text-tertiary">{t('appDebug.feature.imageUpload.description')}</div>
|
||||
)}
|
||||
{file?.enabled && (
|
||||
<>
|
||||
{!isHovering && !modalOpen && (
|
||||
<div className='flex items-center gap-4 pt-0.5'>
|
||||
<div className=''>
|
||||
<div className='system-2xs-medium-uppercase mb-0.5 text-text-tertiary'>{t('appDebug.feature.imageUpload.supportedTypes')}</div>
|
||||
<div className='system-xs-regular text-text-secondary'>{supportedTypes}</div>
|
||||
<div className="flex items-center gap-4 pt-0.5">
|
||||
<div className="">
|
||||
<div className="system-2xs-medium-uppercase mb-0.5 text-text-tertiary">{t('appDebug.feature.imageUpload.supportedTypes')}</div>
|
||||
<div className="system-xs-regular text-text-secondary">{supportedTypes}</div>
|
||||
</div>
|
||||
<div className='h-[27px] w-px rotate-12 bg-divider-subtle'></div>
|
||||
<div className=''>
|
||||
<div className='system-2xs-medium-uppercase mb-0.5 text-text-tertiary'>{t('appDebug.feature.imageUpload.numberLimit')}</div>
|
||||
<div className='system-xs-regular text-text-secondary'>{file?.number_limits}</div>
|
||||
<div className="h-[27px] w-px rotate-12 bg-divider-subtle"></div>
|
||||
<div className="">
|
||||
<div className="system-2xs-medium-uppercase mb-0.5 text-text-tertiary">{t('appDebug.feature.imageUpload.numberLimit')}</div>
|
||||
<div className="system-xs-regular text-text-secondary">{file?.number_limits}</div>
|
||||
</div>
|
||||
</div>
|
||||
)}
|
||||
@ -98,8 +98,8 @@ const FileUpload = ({
|
||||
}}
|
||||
onChange={onChange}
|
||||
>
|
||||
<Button className='w-full' disabled={disabled}>
|
||||
<RiEqualizer2Line className='mr-1 h-4 w-4' />
|
||||
<Button className="w-full" disabled={disabled}>
|
||||
<RiEqualizer2Line className="mr-1 h-4 w-4" />
|
||||
{t('common.operation.settings')}
|
||||
</Button>
|
||||
</SettingModal>
|
||||
|
||||
@ -1,23 +1,23 @@
|
||||
import type { OnFeaturesChange } from '@/app/components/base/features/types'
|
||||
import type { InputVar } from '@/app/components/workflow/types'
|
||||
import type { PromptVariable } from '@/models/debug'
|
||||
import { RiCloseLine, RiInformation2Fill } from '@remixicon/react'
|
||||
import React from 'react'
|
||||
import { useTranslation } from 'react-i18next'
|
||||
import { RiCloseLine, RiInformation2Fill } from '@remixicon/react'
|
||||
import DialogWrapper from '@/app/components/base/features/new-feature-panel/dialog-wrapper'
|
||||
import { useDefaultModel } from '@/app/components/header/account-setting/model-provider-page/hooks'
|
||||
import { ModelTypeEnum } from '@/app/components/header/account-setting/model-provider-page/declarations'
|
||||
import type { OnFeaturesChange } from '@/app/components/base/features/types'
|
||||
import AnnotationReply from '@/app/components/base/features/new-feature-panel/annotation-reply'
|
||||
|
||||
import MoreLikeThis from '@/app/components/base/features/new-feature-panel/more-like-this'
|
||||
import ConversationOpener from '@/app/components/base/features/new-feature-panel/conversation-opener'
|
||||
import FollowUp from '@/app/components/base/features/new-feature-panel/follow-up'
|
||||
import SpeechToText from '@/app/components/base/features/new-feature-panel/speech-to-text'
|
||||
import TextToSpeech from '@/app/components/base/features/new-feature-panel/text-to-speech'
|
||||
import FileUpload from '@/app/components/base/features/new-feature-panel/file-upload'
|
||||
import Citation from '@/app/components/base/features/new-feature-panel/citation'
|
||||
import ConversationOpener from '@/app/components/base/features/new-feature-panel/conversation-opener'
|
||||
import DialogWrapper from '@/app/components/base/features/new-feature-panel/dialog-wrapper'
|
||||
import FileUpload from '@/app/components/base/features/new-feature-panel/file-upload'
|
||||
import FollowUp from '@/app/components/base/features/new-feature-panel/follow-up'
|
||||
import ImageUpload from '@/app/components/base/features/new-feature-panel/image-upload'
|
||||
import Moderation from '@/app/components/base/features/new-feature-panel/moderation'
|
||||
import AnnotationReply from '@/app/components/base/features/new-feature-panel/annotation-reply'
|
||||
import type { PromptVariable } from '@/models/debug'
|
||||
import type { InputVar } from '@/app/components/workflow/types'
|
||||
import MoreLikeThis from '@/app/components/base/features/new-feature-panel/more-like-this'
|
||||
import SpeechToText from '@/app/components/base/features/new-feature-panel/speech-to-text'
|
||||
import TextToSpeech from '@/app/components/base/features/new-feature-panel/text-to-speech'
|
||||
import { ModelTypeEnum } from '@/app/components/header/account-setting/model-provider-page/declarations'
|
||||
import { useDefaultModel } from '@/app/components/header/account-setting/model-provider-page/hooks'
|
||||
import { useDocLink } from '@/context/i18n'
|
||||
|
||||
type Props = {
|
||||
@ -56,31 +56,34 @@ const NewFeaturePanel = ({
|
||||
onClose={onClose}
|
||||
inWorkflow={inWorkflow}
|
||||
>
|
||||
<div className='flex h-full grow flex-col'>
|
||||
<div className="flex h-full grow flex-col">
|
||||
{/* header */}
|
||||
<div className='flex shrink-0 justify-between p-4 pb-3'>
|
||||
<div className="flex shrink-0 justify-between p-4 pb-3">
|
||||
<div>
|
||||
<div className='system-xl-semibold text-text-primary'>{t('workflow.common.features')}</div>
|
||||
<div className='body-xs-regular text-text-tertiary'>{t('workflow.common.featuresDescription')}</div>
|
||||
<div className="system-xl-semibold text-text-primary">{t('workflow.common.features')}</div>
|
||||
<div className="body-xs-regular text-text-tertiary">{t('workflow.common.featuresDescription')}</div>
|
||||
</div>
|
||||
<div className='h-8 w-8 cursor-pointer p-2' onClick={onClose}><RiCloseLine className='h-4 w-4 text-text-tertiary'/></div>
|
||||
<div className="h-8 w-8 cursor-pointer p-2" onClick={onClose}><RiCloseLine className="h-4 w-4 text-text-tertiary" /></div>
|
||||
</div>
|
||||
{/* list */}
|
||||
<div className='grow basis-0 overflow-y-auto px-4 pb-4'>
|
||||
<div className="grow basis-0 overflow-y-auto px-4 pb-4">
|
||||
{showFileUpload && (
|
||||
<div className='relative mb-1 rounded-xl border border-components-panel-border p-2 shadow-xs'>
|
||||
<div className='absolute left-0 top-0 h-full w-full rounded-xl opacity-40' style={{ background: 'linear-gradient(92deg, rgba(11, 165, 236, 0.25) 18.12%, rgba(255, 255, 255, 0.00) 167.31%)' }}></div>
|
||||
<div className='relative flex h-full w-full items-start'>
|
||||
<div className='mr-0.5 shrink-0 p-0.5'>
|
||||
<RiInformation2Fill className='h-5 w-5 text-text-accent' />
|
||||
<div className="relative mb-1 rounded-xl border border-components-panel-border p-2 shadow-xs">
|
||||
<div className="absolute left-0 top-0 h-full w-full rounded-xl opacity-40" style={{ background: 'linear-gradient(92deg, rgba(11, 165, 236, 0.25) 18.12%, rgba(255, 255, 255, 0.00) 167.31%)' }}></div>
|
||||
<div className="relative flex h-full w-full items-start">
|
||||
<div className="mr-0.5 shrink-0 p-0.5">
|
||||
<RiInformation2Fill className="h-5 w-5 text-text-accent" />
|
||||
</div>
|
||||
<div className='system-xs-medium p-1 text-text-primary'>
|
||||
<div className="system-xs-medium p-1 text-text-primary">
|
||||
<span>{isChatMode ? t('workflow.common.fileUploadTip') : t('workflow.common.ImageUploadLegacyTip')}</span>
|
||||
<a
|
||||
className='text-text-accent'
|
||||
className="text-text-accent"
|
||||
href={docLink('/guides/workflow/bulletin')}
|
||||
target='_blank' rel='noopener noreferrer'
|
||||
>{t('workflow.common.featuresDocLink')}</a>
|
||||
target="_blank"
|
||||
rel="noopener noreferrer"
|
||||
>
|
||||
{t('workflow.common.featuresDocLink')}
|
||||
</a>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@ -1,10 +1,10 @@
|
||||
import type { FC } from 'react'
|
||||
import { useContext } from 'use-context-selector'
|
||||
import type { CodeBasedExtensionForm } from '@/models/common'
|
||||
import I18n from '@/context/i18n'
|
||||
import type { ModerationConfig } from '@/models/debug'
|
||||
import { useContext } from 'use-context-selector'
|
||||
import { PortalSelect } from '@/app/components/base/select'
|
||||
import Textarea from '@/app/components/base/textarea'
|
||||
import type { ModerationConfig } from '@/models/debug'
|
||||
import I18n from '@/context/i18n'
|
||||
|
||||
type FormGenerationProps = {
|
||||
forms: CodeBasedExtensionForm[]
|
||||
@ -28,16 +28,16 @@ const FormGeneration: FC<FormGenerationProps> = ({
|
||||
forms.map((form, index) => (
|
||||
<div
|
||||
key={index}
|
||||
className='py-2'
|
||||
className="py-2"
|
||||
>
|
||||
<div className='flex h-9 items-center text-sm font-medium text-text-primary'>
|
||||
<div className="flex h-9 items-center text-sm font-medium text-text-primary">
|
||||
{locale === 'zh-Hans' ? form.label['zh-Hans'] : form.label['en-US']}
|
||||
</div>
|
||||
{
|
||||
form.type === 'text-input' && (
|
||||
<input
|
||||
value={value?.[form.variable] || ''}
|
||||
className='block h-9 w-full appearance-none rounded-lg bg-components-input-bg-normal px-3 text-sm text-text-primary outline-none'
|
||||
className="block h-9 w-full appearance-none rounded-lg bg-components-input-bg-normal px-3 text-sm text-text-primary outline-none"
|
||||
placeholder={form.placeholder}
|
||||
onChange={e => handleFormChange(form.variable, e.target.value)}
|
||||
/>
|
||||
@ -45,9 +45,9 @@ const FormGeneration: FC<FormGenerationProps> = ({
|
||||
}
|
||||
{
|
||||
form.type === 'paragraph' && (
|
||||
<div className='relative'>
|
||||
<div className="relative">
|
||||
<Textarea
|
||||
className='resize-none'
|
||||
className="resize-none"
|
||||
value={value?.[form.variable] || ''}
|
||||
placeholder={form.placeholder}
|
||||
onChange={e => handleFormChange(form.variable, e.target.value)}
|
||||
@ -66,7 +66,7 @@ const FormGeneration: FC<FormGenerationProps> = ({
|
||||
}
|
||||
})}
|
||||
onSelect={item => handleFormChange(form.variable, item.value as string)}
|
||||
popupClassName='w-[576px] !z-[102]'
|
||||
popupClassName="w-[576px] !z-[102]"
|
||||
/>
|
||||
)
|
||||
}
|
||||
|
||||
@ -1,16 +1,16 @@
|
||||
import type { OnFeaturesChange } from '@/app/components/base/features/types'
|
||||
import { RiEqualizer2Line } from '@remixicon/react'
|
||||
import { produce } from 'immer'
|
||||
import React, { useCallback, useMemo, useState } from 'react'
|
||||
import { useTranslation } from 'react-i18next'
|
||||
import { produce } from 'immer'
|
||||
import { useContext } from 'use-context-selector'
|
||||
import { RiEqualizer2Line } from '@remixicon/react'
|
||||
import { ContentModeration } from '@/app/components/base/icons/src/vender/features'
|
||||
import FeatureCard from '@/app/components/base/features/new-feature-panel/feature-card'
|
||||
import Button from '@/app/components/base/button'
|
||||
import { useFeatures, useFeaturesStore } from '@/app/components/base/features/hooks'
|
||||
import type { OnFeaturesChange } from '@/app/components/base/features/types'
|
||||
import FeatureCard from '@/app/components/base/features/new-feature-panel/feature-card'
|
||||
import { FeatureEnum } from '@/app/components/base/features/types'
|
||||
import { useModalContext } from '@/context/modal-context'
|
||||
import { ContentModeration } from '@/app/components/base/icons/src/vender/features'
|
||||
import I18n from '@/context/i18n'
|
||||
import { useModalContext } from '@/context/modal-context'
|
||||
import { useCodeBasedExtensions } from '@/service/use-common'
|
||||
|
||||
type Props = {
|
||||
@ -125,11 +125,11 @@ const Moderation = ({
|
||||
|
||||
return (
|
||||
<FeatureCard
|
||||
icon={
|
||||
<div className='shrink-0 rounded-lg border-[0.5px] border-divider-subtle bg-text-success p-1 shadow-xs'>
|
||||
<ContentModeration className='h-4 w-4 text-text-primary-on-surface' />
|
||||
icon={(
|
||||
<div className="shrink-0 rounded-lg border-[0.5px] border-divider-subtle bg-text-success p-1 shadow-xs">
|
||||
<ContentModeration className="h-4 w-4 text-text-primary-on-surface" />
|
||||
</div>
|
||||
}
|
||||
)}
|
||||
title={t('appDebug.feature.moderation.title')}
|
||||
value={!!moderation?.enabled}
|
||||
onChange={state => handleChange(FeatureEnum.moderation, state)}
|
||||
@ -139,26 +139,26 @@ const Moderation = ({
|
||||
>
|
||||
<>
|
||||
{!moderation?.enabled && (
|
||||
<div className='system-xs-regular line-clamp-2 min-h-8 text-text-tertiary'>{t('appDebug.feature.moderation.description')}</div>
|
||||
<div className="system-xs-regular line-clamp-2 min-h-8 text-text-tertiary">{t('appDebug.feature.moderation.description')}</div>
|
||||
)}
|
||||
{!!moderation?.enabled && (
|
||||
<>
|
||||
{!isHovering && (
|
||||
<div className='flex items-center gap-4 pt-0.5'>
|
||||
<div className=''>
|
||||
<div className='system-2xs-medium-uppercase mb-0.5 text-text-tertiary'>{t('appDebug.feature.moderation.modal.provider.title')}</div>
|
||||
<div className='system-xs-regular text-text-secondary'>{providerContent}</div>
|
||||
<div className="flex items-center gap-4 pt-0.5">
|
||||
<div className="">
|
||||
<div className="system-2xs-medium-uppercase mb-0.5 text-text-tertiary">{t('appDebug.feature.moderation.modal.provider.title')}</div>
|
||||
<div className="system-xs-regular text-text-secondary">{providerContent}</div>
|
||||
</div>
|
||||
<div className='h-[27px] w-px rotate-12 bg-divider-subtle'></div>
|
||||
<div className=''>
|
||||
<div className='system-2xs-medium-uppercase mb-0.5 text-text-tertiary'>{t('appDebug.feature.moderation.contentEnableLabel')}</div>
|
||||
<div className='system-xs-regular text-text-secondary'>{enableContent}</div>
|
||||
<div className="h-[27px] w-px rotate-12 bg-divider-subtle"></div>
|
||||
<div className="">
|
||||
<div className="system-2xs-medium-uppercase mb-0.5 text-text-tertiary">{t('appDebug.feature.moderation.contentEnableLabel')}</div>
|
||||
<div className="system-xs-regular text-text-secondary">{enableContent}</div>
|
||||
</div>
|
||||
</div>
|
||||
)}
|
||||
{isHovering && (
|
||||
<Button className='w-full' onClick={handleOpenModerationSettingModal} disabled={disabled}>
|
||||
<RiEqualizer2Line className='mr-1 h-4 w-4' />
|
||||
<Button className="w-full" onClick={handleOpenModerationSettingModal} disabled={disabled}>
|
||||
<RiEqualizer2Line className="mr-1 h-4 w-4" />
|
||||
{t('common.operation.settings')}
|
||||
</Button>
|
||||
)}
|
||||
|
||||
@ -1,7 +1,7 @@
|
||||
import type { FC } from 'react'
|
||||
import type { ModerationContentConfig } from '@/models/debug'
|
||||
import { useTranslation } from 'react-i18next'
|
||||
import Switch from '@/app/components/base/switch'
|
||||
import type { ModerationContentConfig } from '@/models/debug'
|
||||
|
||||
type ModerationContentProps = {
|
||||
title: string
|
||||
@ -26,18 +26,18 @@ const ModerationContent: FC<ModerationContentProps> = ({
|
||||
}
|
||||
|
||||
return (
|
||||
<div className='py-2'>
|
||||
<div className='rounded-lg border border-components-panel-border bg-components-panel-bg'>
|
||||
<div className='flex h-10 items-center justify-between rounded-lg px-3'>
|
||||
<div className='shrink-0 text-sm font-medium text-text-primary'>{title}</div>
|
||||
<div className='flex grow items-center justify-end'>
|
||||
<div className="py-2">
|
||||
<div className="rounded-lg border border-components-panel-border bg-components-panel-bg">
|
||||
<div className="flex h-10 items-center justify-between rounded-lg px-3">
|
||||
<div className="shrink-0 text-sm font-medium text-text-primary">{title}</div>
|
||||
<div className="flex grow items-center justify-end">
|
||||
{
|
||||
info && (
|
||||
<div className='mr-2 truncate text-xs text-text-tertiary' title={info}>{info}</div>
|
||||
<div className="mr-2 truncate text-xs text-text-tertiary" title={info}>{info}</div>
|
||||
)
|
||||
}
|
||||
<Switch
|
||||
size='l'
|
||||
size="l"
|
||||
defaultValue={config.enabled}
|
||||
onChange={v => handleConfigChange('enabled', v)}
|
||||
/>
|
||||
@ -45,20 +45,22 @@ const ModerationContent: FC<ModerationContentProps> = ({
|
||||
</div>
|
||||
{
|
||||
config.enabled && showPreset && (
|
||||
<div className='rounded-lg bg-components-panel-bg px-3 pb-3 pt-1'>
|
||||
<div className='flex h-8 items-center justify-between text-[13px] font-medium text-text-secondary'>
|
||||
<div className="rounded-lg bg-components-panel-bg px-3 pb-3 pt-1">
|
||||
<div className="flex h-8 items-center justify-between text-[13px] font-medium text-text-secondary">
|
||||
{t('appDebug.feature.moderation.modal.content.preset')}
|
||||
<span className='text-xs font-normal text-text-tertiary'>{t('appDebug.feature.moderation.modal.content.supportMarkdown')}</span>
|
||||
<span className="text-xs font-normal text-text-tertiary">{t('appDebug.feature.moderation.modal.content.supportMarkdown')}</span>
|
||||
</div>
|
||||
<div className='relative h-20 rounded-lg bg-components-input-bg-normal px-3 py-2'>
|
||||
<div className="relative h-20 rounded-lg bg-components-input-bg-normal px-3 py-2">
|
||||
<textarea
|
||||
value={config.preset_response || ''}
|
||||
className='block h-full w-full resize-none appearance-none bg-transparent text-sm text-text-secondary outline-none'
|
||||
className="block h-full w-full resize-none appearance-none bg-transparent text-sm text-text-secondary outline-none"
|
||||
placeholder={t('appDebug.feature.moderation.modal.content.placeholder') || ''}
|
||||
onChange={e => handleConfigChange('preset_response', e.target.value)}
|
||||
/>
|
||||
<div className='absolute bottom-2 right-2 flex h-5 items-center rounded-md bg-background-section px-1 text-xs font-medium text-text-quaternary'>
|
||||
<span>{(config.preset_response || '').length}</span>/<span className='text-text-tertiary'>100</span>
|
||||
<div className="absolute bottom-2 right-2 flex h-5 items-center rounded-md bg-background-section px-1 text-xs font-medium text-text-quaternary">
|
||||
<span>{(config.preset_response || '').length}</span>
|
||||
/
|
||||
<span className="text-text-tertiary">100</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@ -1,28 +1,27 @@
|
||||
import type { ChangeEvent, FC } from 'react'
|
||||
import { useState } from 'react'
|
||||
import { useContext } from 'use-context-selector'
|
||||
import { useTranslation } from 'react-i18next'
|
||||
import type { CodeBasedExtensionItem } from '@/models/common'
|
||||
import type { ModerationConfig, ModerationContentConfig } from '@/models/debug'
|
||||
import { RiCloseLine } from '@remixicon/react'
|
||||
import ModerationContent from './moderation-content'
|
||||
import FormGeneration from './form-generation'
|
||||
import ApiBasedExtensionSelector from '@/app/components/header/account-setting/api-based-extension-page/selector'
|
||||
import Modal from '@/app/components/base/modal'
|
||||
import { noop } from 'lodash-es'
|
||||
import { useState } from 'react'
|
||||
import { useTranslation } from 'react-i18next'
|
||||
import { useContext } from 'use-context-selector'
|
||||
import Button from '@/app/components/base/button'
|
||||
import Divider from '@/app/components/base/divider'
|
||||
import { BookOpen01 } from '@/app/components/base/icons/src/vender/line/education'
|
||||
import type { ModerationConfig, ModerationContentConfig } from '@/models/debug'
|
||||
import { useToastContext } from '@/app/components/base/toast'
|
||||
import type { CodeBasedExtensionItem } from '@/models/common'
|
||||
import I18n from '@/context/i18n'
|
||||
import { LanguagesSupported } from '@/i18n-config/language'
|
||||
import { InfoCircle } from '@/app/components/base/icons/src/vender/line/general'
|
||||
import { useModalContext } from '@/context/modal-context'
|
||||
import { CustomConfigurationStatusEnum } from '@/app/components/header/account-setting/model-provider-page/declarations'
|
||||
import { cn } from '@/utils/classnames'
|
||||
import { noop } from 'lodash-es'
|
||||
import { useDocLink } from '@/context/i18n'
|
||||
import Modal from '@/app/components/base/modal'
|
||||
import { useToastContext } from '@/app/components/base/toast'
|
||||
import ApiBasedExtensionSelector from '@/app/components/header/account-setting/api-based-extension-page/selector'
|
||||
import { ACCOUNT_SETTING_TAB } from '@/app/components/header/account-setting/constants'
|
||||
import { CustomConfigurationStatusEnum } from '@/app/components/header/account-setting/model-provider-page/declarations'
|
||||
import I18n, { useDocLink } from '@/context/i18n'
|
||||
import { useModalContext } from '@/context/modal-context'
|
||||
import { LanguagesSupported } from '@/i18n-config/language'
|
||||
import { useCodeBasedExtensions, useModelProviders } from '@/service/use-common'
|
||||
import { cn } from '@/utils/classnames'
|
||||
import FormGeneration from './form-generation'
|
||||
import ModerationContent from './moderation-content'
|
||||
|
||||
const systemTypes = ['openai_moderation', 'keywords', 'api']
|
||||
|
||||
@ -81,12 +80,12 @@ const ModerationSettingModal: FC<ModerationSettingModalProps> = ({
|
||||
...(
|
||||
codeBasedExtensionList
|
||||
? codeBasedExtensionList.data.map((item) => {
|
||||
return {
|
||||
key: item.name,
|
||||
name: locale === 'zh-Hans' ? item.label['zh-Hans'] : item.label['en-US'],
|
||||
form_schema: item.form_schema,
|
||||
}
|
||||
})
|
||||
return {
|
||||
key: item.name,
|
||||
name: locale === 'zh-Hans' ? item.label['zh-Hans'] : item.label['en-US'],
|
||||
form_schema: item.form_schema,
|
||||
}
|
||||
})
|
||||
: []
|
||||
),
|
||||
]
|
||||
@ -237,17 +236,17 @@ const ModerationSettingModal: FC<ModerationSettingModalProps> = ({
|
||||
<Modal
|
||||
isShow
|
||||
onClose={noop}
|
||||
className='!mt-14 !w-[600px] !max-w-none !p-6'
|
||||
className="!mt-14 !w-[600px] !max-w-none !p-6"
|
||||
>
|
||||
<div className='flex items-center justify-between'>
|
||||
<div className='title-2xl-semi-bold text-text-primary'>{t('appDebug.feature.moderation.modal.title')}</div>
|
||||
<div className='cursor-pointer p-1' onClick={onCancel}><RiCloseLine className='h-4 w-4 text-text-tertiary' /></div>
|
||||
<div className="flex items-center justify-between">
|
||||
<div className="title-2xl-semi-bold text-text-primary">{t('appDebug.feature.moderation.modal.title')}</div>
|
||||
<div className="cursor-pointer p-1" onClick={onCancel}><RiCloseLine className="h-4 w-4 text-text-tertiary" /></div>
|
||||
</div>
|
||||
<div className='py-2'>
|
||||
<div className='text-sm font-medium leading-9 text-text-primary'>
|
||||
<div className="py-2">
|
||||
<div className="text-sm font-medium leading-9 text-text-primary">
|
||||
{t('appDebug.feature.moderation.modal.provider.title')}
|
||||
</div>
|
||||
<div className='grid grid-cols-3 gap-2.5'>
|
||||
<div className="grid grid-cols-3 gap-2.5">
|
||||
{
|
||||
providers.map(provider => (
|
||||
<div
|
||||
@ -263,7 +262,9 @@ const ModerationSettingModal: FC<ModerationSettingModalProps> = ({
|
||||
<div className={cn(
|
||||
'mr-2 h-4 w-4 rounded-full border border-components-radio-border bg-components-radio-bg shadow-xs',
|
||||
localeData.type === provider.key && 'border-[5px] border-components-radio-border-checked',
|
||||
)}></div>
|
||||
)}
|
||||
>
|
||||
</div>
|
||||
{provider.name}
|
||||
</div>
|
||||
))
|
||||
@ -271,15 +272,17 @@ const ModerationSettingModal: FC<ModerationSettingModalProps> = ({
|
||||
</div>
|
||||
{
|
||||
!isLoading && !isOpenAIProviderConfigured && localeData.type === 'openai_moderation' && (
|
||||
<div className='mt-2 flex items-center rounded-lg border border-[#FEF0C7] bg-[#FFFAEB] px-3 py-2'>
|
||||
<InfoCircle className='mr-1 h-4 w-4 text-[#F79009]' />
|
||||
<div className='flex items-center text-xs font-medium text-gray-700'>
|
||||
<div className="mt-2 flex items-center rounded-lg border border-[#FEF0C7] bg-[#FFFAEB] px-3 py-2">
|
||||
<InfoCircle className="mr-1 h-4 w-4 text-[#F79009]" />
|
||||
<div className="flex items-center text-xs font-medium text-gray-700">
|
||||
{t('appDebug.feature.moderation.modal.openaiNotConfig.before')}
|
||||
<span
|
||||
className='cursor-pointer text-primary-600'
|
||||
className="cursor-pointer text-primary-600"
|
||||
onClick={handleOpenSettingsModal}
|
||||
>
|
||||
{t('common.settings.provider')}
|
||||
|
||||
{t('common.settings.provider')}
|
||||
|
||||
</span>
|
||||
{t('appDebug.feature.moderation.modal.openaiNotConfig.after')}
|
||||
</div>
|
||||
@ -289,18 +292,23 @@ const ModerationSettingModal: FC<ModerationSettingModalProps> = ({
|
||||
</div>
|
||||
{
|
||||
localeData.type === 'keywords' && (
|
||||
<div className='py-2'>
|
||||
<div className='mb-1 text-sm font-medium text-text-primary'>{t('appDebug.feature.moderation.modal.provider.keywords')}</div>
|
||||
<div className='mb-2 text-xs text-text-tertiary'>{t('appDebug.feature.moderation.modal.keywords.tip')}</div>
|
||||
<div className='relative h-[88px] rounded-lg bg-components-input-bg-normal px-3 py-2'>
|
||||
<div className="py-2">
|
||||
<div className="mb-1 text-sm font-medium text-text-primary">{t('appDebug.feature.moderation.modal.provider.keywords')}</div>
|
||||
<div className="mb-2 text-xs text-text-tertiary">{t('appDebug.feature.moderation.modal.keywords.tip')}</div>
|
||||
<div className="relative h-[88px] rounded-lg bg-components-input-bg-normal px-3 py-2">
|
||||
<textarea
|
||||
value={localeData.config?.keywords || ''}
|
||||
onChange={handleDataKeywordsChange}
|
||||
className='block h-full w-full resize-none appearance-none bg-transparent text-sm text-text-secondary outline-none'
|
||||
className="block h-full w-full resize-none appearance-none bg-transparent text-sm text-text-secondary outline-none"
|
||||
placeholder={t('appDebug.feature.moderation.modal.keywords.placeholder') || ''}
|
||||
/>
|
||||
<div className='absolute bottom-2 right-2 flex h-5 items-center rounded-md bg-background-section px-1 text-xs font-medium text-text-quaternary'>
|
||||
<span>{(localeData.config?.keywords || '').split('\n').filter(Boolean).length}</span>/<span className='text-text-tertiary'>100 {t('appDebug.feature.moderation.modal.keywords.line')}</span>
|
||||
<div className="absolute bottom-2 right-2 flex h-5 items-center rounded-md bg-background-section px-1 text-xs font-medium text-text-quaternary">
|
||||
<span>{(localeData.config?.keywords || '').split('\n').filter(Boolean).length}</span>
|
||||
/
|
||||
<span className="text-text-tertiary">
|
||||
100
|
||||
{t('appDebug.feature.moderation.modal.keywords.line')}
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
@ -308,15 +316,16 @@ const ModerationSettingModal: FC<ModerationSettingModalProps> = ({
|
||||
}
|
||||
{
|
||||
localeData.type === 'api' && (
|
||||
<div className='py-2'>
|
||||
<div className='flex h-9 items-center justify-between'>
|
||||
<div className='text-sm font-medium text-text-primary'>{t('common.apiBasedExtension.selector.title')}</div>
|
||||
<div className="py-2">
|
||||
<div className="flex h-9 items-center justify-between">
|
||||
<div className="text-sm font-medium text-text-primary">{t('common.apiBasedExtension.selector.title')}</div>
|
||||
<a
|
||||
href={docLink('/guides/extension/api-based-extension/README')}
|
||||
target='_blank' rel='noopener noreferrer'
|
||||
className='group flex items-center text-xs text-text-tertiary hover:text-primary-600'
|
||||
target="_blank"
|
||||
rel="noopener noreferrer"
|
||||
className="group flex items-center text-xs text-text-tertiary hover:text-primary-600"
|
||||
>
|
||||
<BookOpen01 className='mr-1 h-3 w-3 text-text-tertiary group-hover:text-primary-600' />
|
||||
<BookOpen01 className="mr-1 h-3 w-3 text-text-tertiary group-hover:text-primary-600" />
|
||||
{t('common.apiBasedExtension.link')}
|
||||
</a>
|
||||
</div>
|
||||
@ -338,7 +347,7 @@ const ModerationSettingModal: FC<ModerationSettingModalProps> = ({
|
||||
/>
|
||||
)
|
||||
}
|
||||
<Divider bgStyle='gradient' className='my-3 h-px' />
|
||||
<Divider bgStyle="gradient" className="my-3 h-px" />
|
||||
<ModerationContent
|
||||
title={t('appDebug.feature.moderation.modal.content.input') || ''}
|
||||
config={localeData.config?.inputs_config || { enabled: false, preset_response: '' }}
|
||||
@ -353,16 +362,16 @@ const ModerationSettingModal: FC<ModerationSettingModalProps> = ({
|
||||
info={(localeData.type === 'api' && t('appDebug.feature.moderation.modal.content.fromApi')) || ''}
|
||||
showPreset={localeData.type !== 'api'}
|
||||
/>
|
||||
<div className='mb-8 mt-1 text-xs font-medium text-text-tertiary'>{t('appDebug.feature.moderation.modal.content.condition')}</div>
|
||||
<div className='flex items-center justify-end'>
|
||||
<div className="mb-8 mt-1 text-xs font-medium text-text-tertiary">{t('appDebug.feature.moderation.modal.content.condition')}</div>
|
||||
<div className="flex items-center justify-end">
|
||||
<Button
|
||||
onClick={onCancel}
|
||||
className='mr-2'
|
||||
className="mr-2"
|
||||
>
|
||||
{t('common.operation.cancel')}
|
||||
</Button>
|
||||
<Button
|
||||
variant='primary'
|
||||
variant="primary"
|
||||
onClick={handleSave}
|
||||
disabled={localeData.type === 'openai_moderation' && !isOpenAIProviderConfigured}
|
||||
>
|
||||
|
||||
@ -1,10 +1,10 @@
|
||||
import type { OnFeaturesChange } from '@/app/components/base/features/types'
|
||||
import { RiSparklingFill } from '@remixicon/react'
|
||||
import { produce } from 'immer'
|
||||
import React, { useCallback } from 'react'
|
||||
import { useTranslation } from 'react-i18next'
|
||||
import { produce } from 'immer'
|
||||
import { RiSparklingFill } from '@remixicon/react'
|
||||
import FeatureCard from '@/app/components/base/features/new-feature-panel/feature-card'
|
||||
import { useFeatures, useFeaturesStore } from '@/app/components/base/features/hooks'
|
||||
import type { OnFeaturesChange } from '@/app/components/base/features/types'
|
||||
import FeatureCard from '@/app/components/base/features/new-feature-panel/feature-card'
|
||||
import { FeatureEnum } from '@/app/components/base/features/types'
|
||||
|
||||
type Props = {
|
||||
@ -39,11 +39,11 @@ const MoreLikeThis = ({
|
||||
|
||||
return (
|
||||
<FeatureCard
|
||||
icon={
|
||||
<div className='shrink-0 rounded-lg border-[0.5px] border-divider-subtle bg-util-colors-blue-light-blue-light-500 p-1 shadow-xs'>
|
||||
<RiSparklingFill className='h-4 w-4 text-text-primary-on-surface' />
|
||||
icon={(
|
||||
<div className="shrink-0 rounded-lg border-[0.5px] border-divider-subtle bg-util-colors-blue-light-blue-light-500 p-1 shadow-xs">
|
||||
<RiSparklingFill className="h-4 w-4 text-text-primary-on-surface" />
|
||||
</div>
|
||||
}
|
||||
)}
|
||||
title={t('appDebug.feature.moreLikeThis.title')}
|
||||
tooltip={t('appDebug.feature.moreLikeThis.tip')}
|
||||
value={!!features.moreLikeThis?.enabled}
|
||||
|
||||
@ -1,11 +1,11 @@
|
||||
import type { OnFeaturesChange } from '@/app/components/base/features/types'
|
||||
import { produce } from 'immer'
|
||||
import React, { useCallback } from 'react'
|
||||
import { useTranslation } from 'react-i18next'
|
||||
import { produce } from 'immer'
|
||||
import { Microphone01 } from '@/app/components/base/icons/src/vender/features'
|
||||
import FeatureCard from '@/app/components/base/features/new-feature-panel/feature-card'
|
||||
import { useFeatures, useFeaturesStore } from '@/app/components/base/features/hooks'
|
||||
import type { OnFeaturesChange } from '@/app/components/base/features/types'
|
||||
import FeatureCard from '@/app/components/base/features/new-feature-panel/feature-card'
|
||||
import { FeatureEnum } from '@/app/components/base/features/types'
|
||||
import { Microphone01 } from '@/app/components/base/icons/src/vender/features'
|
||||
|
||||
type Props = {
|
||||
disabled: boolean
|
||||
@ -39,11 +39,11 @@ const SpeechToText = ({
|
||||
|
||||
return (
|
||||
<FeatureCard
|
||||
icon={
|
||||
<div className='shrink-0 rounded-lg border-[0.5px] border-divider-subtle bg-util-colors-violet-violet-600 p-1 shadow-xs'>
|
||||
<Microphone01 className='h-4 w-4 text-text-primary-on-surface' />
|
||||
icon={(
|
||||
<div className="shrink-0 rounded-lg border-[0.5px] border-divider-subtle bg-util-colors-violet-violet-600 p-1 shadow-xs">
|
||||
<Microphone01 className="h-4 w-4 text-text-primary-on-surface" />
|
||||
</div>
|
||||
}
|
||||
)}
|
||||
title={t('appDebug.feature.speechToText.title')}
|
||||
value={!!features.speech2text?.enabled}
|
||||
description={t('appDebug.feature.speechToText.description')!}
|
||||
|
||||
@ -1,14 +1,14 @@
|
||||
import type { OnFeaturesChange } from '@/app/components/base/features/types'
|
||||
import { RiEqualizer2Line } from '@remixicon/react'
|
||||
import { produce } from 'immer'
|
||||
import React, { useCallback, useState } from 'react'
|
||||
import { useTranslation } from 'react-i18next'
|
||||
import { produce } from 'immer'
|
||||
import { RiEqualizer2Line } from '@remixicon/react'
|
||||
import { TextToAudio } from '@/app/components/base/icons/src/vender/features'
|
||||
import FeatureCard from '@/app/components/base/features/new-feature-panel/feature-card'
|
||||
import Button from '@/app/components/base/button'
|
||||
import VoiceSettings from '@/app/components/base/features/new-feature-panel/text-to-speech/voice-settings'
|
||||
import { useFeatures, useFeaturesStore } from '@/app/components/base/features/hooks'
|
||||
import type { OnFeaturesChange } from '@/app/components/base/features/types'
|
||||
import FeatureCard from '@/app/components/base/features/new-feature-panel/feature-card'
|
||||
import VoiceSettings from '@/app/components/base/features/new-feature-panel/text-to-speech/voice-settings'
|
||||
import { FeatureEnum } from '@/app/components/base/features/types'
|
||||
import { TextToAudio } from '@/app/components/base/icons/src/vender/features'
|
||||
import { languages } from '@/i18n-config/language'
|
||||
import { TtsAutoPlay } from '@/types/app'
|
||||
|
||||
@ -48,11 +48,11 @@ const TextToSpeech = ({
|
||||
|
||||
return (
|
||||
<FeatureCard
|
||||
icon={
|
||||
<div className='shrink-0 rounded-lg border-[0.5px] border-divider-subtle bg-util-colors-violet-violet-600 p-1 shadow-xs'>
|
||||
<TextToAudio className='h-4 w-4 text-text-primary-on-surface' />
|
||||
icon={(
|
||||
<div className="shrink-0 rounded-lg border-[0.5px] border-divider-subtle bg-util-colors-violet-violet-600 p-1 shadow-xs">
|
||||
<TextToAudio className="h-4 w-4 text-text-primary-on-surface" />
|
||||
</div>
|
||||
}
|
||||
)}
|
||||
title={t('appDebug.feature.textToSpeech.title')}
|
||||
value={!!features.text2speech?.enabled}
|
||||
onChange={state => handleChange(FeatureEnum.text2speech, state)}
|
||||
@ -62,32 +62,32 @@ const TextToSpeech = ({
|
||||
>
|
||||
<>
|
||||
{!features.text2speech?.enabled && (
|
||||
<div className='system-xs-regular line-clamp-2 min-h-8 text-text-tertiary'>{t('appDebug.feature.textToSpeech.description')}</div>
|
||||
<div className="system-xs-regular line-clamp-2 min-h-8 text-text-tertiary">{t('appDebug.feature.textToSpeech.description')}</div>
|
||||
)}
|
||||
{!!features.text2speech?.enabled && (
|
||||
<>
|
||||
{!isHovering && !modalOpen && (
|
||||
<div className='flex items-center gap-4 pt-0.5'>
|
||||
<div className=''>
|
||||
<div className='system-2xs-medium-uppercase mb-0.5 text-text-tertiary'>{t('appDebug.voice.voiceSettings.language')}</div>
|
||||
<div className='system-xs-regular text-text-secondary'>{languageInfo?.name || '-'}</div>
|
||||
<div className="flex items-center gap-4 pt-0.5">
|
||||
<div className="">
|
||||
<div className="system-2xs-medium-uppercase mb-0.5 text-text-tertiary">{t('appDebug.voice.voiceSettings.language')}</div>
|
||||
<div className="system-xs-regular text-text-secondary">{languageInfo?.name || '-'}</div>
|
||||
</div>
|
||||
<div className='h-[27px] w-px rotate-12 bg-divider-subtle'></div>
|
||||
<div className=''>
|
||||
<div className='system-2xs-medium-uppercase mb-0.5 text-text-tertiary'>{t('appDebug.voice.voiceSettings.voice')}</div>
|
||||
<div className='system-xs-regular text-text-secondary'>{features.text2speech?.voice || t('appDebug.voice.defaultDisplay')}</div>
|
||||
<div className="h-[27px] w-px rotate-12 bg-divider-subtle"></div>
|
||||
<div className="">
|
||||
<div className="system-2xs-medium-uppercase mb-0.5 text-text-tertiary">{t('appDebug.voice.voiceSettings.voice')}</div>
|
||||
<div className="system-xs-regular text-text-secondary">{features.text2speech?.voice || t('appDebug.voice.defaultDisplay')}</div>
|
||||
</div>
|
||||
<div className='h-[27px] w-px rotate-12 bg-divider-subtle'></div>
|
||||
<div className=''>
|
||||
<div className='system-2xs-medium-uppercase mb-0.5 text-text-tertiary'>{t('appDebug.voice.voiceSettings.autoPlay')}</div>
|
||||
<div className='system-xs-regular text-text-secondary'>{features.text2speech?.autoPlay === TtsAutoPlay.enabled ? t('appDebug.voice.voiceSettings.autoPlayEnabled') : t('appDebug.voice.voiceSettings.autoPlayDisabled')}</div>
|
||||
<div className="h-[27px] w-px rotate-12 bg-divider-subtle"></div>
|
||||
<div className="">
|
||||
<div className="system-2xs-medium-uppercase mb-0.5 text-text-tertiary">{t('appDebug.voice.voiceSettings.autoPlay')}</div>
|
||||
<div className="system-xs-regular text-text-secondary">{features.text2speech?.autoPlay === TtsAutoPlay.enabled ? t('appDebug.voice.voiceSettings.autoPlayEnabled') : t('appDebug.voice.voiceSettings.autoPlayDisabled')}</div>
|
||||
</div>
|
||||
</div>
|
||||
)}
|
||||
{(isHovering || modalOpen) && (
|
||||
<VoiceSettings open={modalOpen && !disabled} onOpen={setModalOpen} onChange={onChange}>
|
||||
<Button className='w-full' disabled={disabled}>
|
||||
<RiEqualizer2Line className='mr-1 h-4 w-4' />
|
||||
<Button className="w-full" disabled={disabled}>
|
||||
<RiEqualizer2Line className="mr-1 h-4 w-4" />
|
||||
{t('appDebug.voice.voiceSettings.title')}
|
||||
</Button>
|
||||
</VoiceSettings>
|
||||
|
||||
@ -1,21 +1,21 @@
|
||||
'use client'
|
||||
import { produce } from 'immer'
|
||||
import React, { Fragment } from 'react'
|
||||
import { usePathname } from 'next/navigation'
|
||||
import { useTranslation } from 'react-i18next'
|
||||
import { RiCloseLine } from '@remixicon/react'
|
||||
import type { OnFeaturesChange } from '@/app/components/base/features/types'
|
||||
import type { Item } from '@/app/components/base/select'
|
||||
import { Listbox, ListboxButton, ListboxOption, ListboxOptions, Transition } from '@headlessui/react'
|
||||
import { CheckIcon, ChevronDownIcon } from '@heroicons/react/20/solid'
|
||||
import { useFeatures, useFeaturesStore } from '@/app/components/base/features/hooks'
|
||||
import type { Item } from '@/app/components/base/select'
|
||||
import Tooltip from '@/app/components/base/tooltip'
|
||||
import Switch from '@/app/components/base/switch'
|
||||
import { RiCloseLine } from '@remixicon/react'
|
||||
import { produce } from 'immer'
|
||||
import { usePathname } from 'next/navigation'
|
||||
import React, { Fragment } from 'react'
|
||||
import { useTranslation } from 'react-i18next'
|
||||
import AudioBtn from '@/app/components/base/audio-btn'
|
||||
import { useFeatures, useFeaturesStore } from '@/app/components/base/features/hooks'
|
||||
import Switch from '@/app/components/base/switch'
|
||||
import Tooltip from '@/app/components/base/tooltip'
|
||||
import { languages } from '@/i18n-config/language'
|
||||
import { TtsAutoPlay } from '@/types/app'
|
||||
import type { OnFeaturesChange } from '@/app/components/base/features/types'
|
||||
import { cn } from '@/utils/classnames'
|
||||
import { useAppVoices } from '@/service/use-apps'
|
||||
import { TtsAutoPlay } from '@/types/app'
|
||||
import { cn } from '@/utils/classnames'
|
||||
|
||||
type VoiceParamConfigProps = {
|
||||
onClose: () => void
|
||||
@ -64,22 +64,23 @@ const VoiceParamConfig = ({
|
||||
|
||||
return (
|
||||
<>
|
||||
<div className='mb-4 flex items-center justify-between'>
|
||||
<div className='system-xl-semibold text-text-primary'>{t('appDebug.voice.voiceSettings.title')}</div>
|
||||
<div className='cursor-pointer p-1' onClick={onClose}><RiCloseLine className='h-4 w-4 text-text-tertiary' /></div>
|
||||
<div className="mb-4 flex items-center justify-between">
|
||||
<div className="system-xl-semibold text-text-primary">{t('appDebug.voice.voiceSettings.title')}</div>
|
||||
<div className="cursor-pointer p-1" onClick={onClose}><RiCloseLine className="h-4 w-4 text-text-tertiary" /></div>
|
||||
</div>
|
||||
<div className='mb-3'>
|
||||
<div className='system-sm-semibold mb-1 flex items-center py-1 text-text-secondary'>
|
||||
<div className="mb-3">
|
||||
<div className="system-sm-semibold mb-1 flex items-center py-1 text-text-secondary">
|
||||
{t('appDebug.voice.voiceSettings.language')}
|
||||
<Tooltip
|
||||
popupContent={
|
||||
<div className='w-[180px]'>
|
||||
popupContent={(
|
||||
<div className="w-[180px]">
|
||||
{t('appDebug.voice.voiceSettings.resolutionTooltip').split('\n').map(item => (
|
||||
<div key={item}>{item}
|
||||
<div key={item}>
|
||||
{item}
|
||||
</div>
|
||||
))}
|
||||
</div>
|
||||
}
|
||||
)}
|
||||
/>
|
||||
</div>
|
||||
<Listbox
|
||||
@ -90,9 +91,10 @@ const VoiceParamConfig = ({
|
||||
})
|
||||
}}
|
||||
>
|
||||
<div className='relative h-8'>
|
||||
<div className="relative h-8">
|
||||
<ListboxButton
|
||||
className={'h-full w-full cursor-pointer rounded-lg border-0 bg-components-input-bg-normal py-1.5 pl-3 pr-10 focus-visible:bg-state-base-hover focus-visible:outline-none group-hover:bg-state-base-hover sm:text-sm sm:leading-6'}>
|
||||
className="h-full w-full cursor-pointer rounded-lg border-0 bg-components-input-bg-normal py-1.5 pl-3 pr-10 focus-visible:bg-state-base-hover focus-visible:outline-none group-hover:bg-state-base-hover sm:text-sm sm:leading-6"
|
||||
>
|
||||
<span className={cn('block truncate text-left text-text-secondary', !languageItem?.name && 'text-text-tertiary')}>
|
||||
{languageItem?.name ? t(`common.voice.language.${languageItem?.value.replace('-', '')}`) : localLanguagePlaceholder}
|
||||
</span>
|
||||
@ -111,20 +113,22 @@ const VoiceParamConfig = ({
|
||||
>
|
||||
|
||||
<ListboxOptions
|
||||
className="absolute z-10 mt-1 max-h-60 w-full overflow-auto rounded-md border-[0.5px] border-components-panel-border bg-components-panel-bg px-1 py-1 text-base shadow-lg focus:outline-none sm:text-sm">
|
||||
className="absolute z-10 mt-1 max-h-60 w-full overflow-auto rounded-md border-[0.5px] border-components-panel-border bg-components-panel-bg px-1 py-1 text-base shadow-lg focus:outline-none sm:text-sm"
|
||||
>
|
||||
{languages.map((item: Item) => (
|
||||
<ListboxOption
|
||||
key={item.value}
|
||||
className={
|
||||
'relative cursor-pointer select-none rounded-lg py-2 pl-3 pr-9 text-text-secondary hover:bg-state-base-hover data-[active]:bg-state-base-active'
|
||||
}
|
||||
className="relative cursor-pointer select-none rounded-lg py-2 pl-3 pr-9 text-text-secondary hover:bg-state-base-hover data-[active]:bg-state-base-active"
|
||||
value={item}
|
||||
disabled={false}
|
||||
>
|
||||
{({ /* active, */ selected }) => (
|
||||
<>
|
||||
<span
|
||||
className={cn('block', selected && 'font-normal')}>{t(`common.voice.language.${(item.value).toString().replace('-', '')}`)}</span>
|
||||
className={cn('block', selected && 'font-normal')}
|
||||
>
|
||||
{t(`common.voice.language.${(item.value).toString().replace('-', '')}`)}
|
||||
</span>
|
||||
{(selected || item.value === text2speech?.language) && (
|
||||
<span
|
||||
className={cn('absolute inset-y-0 right-0 flex items-center pr-4 text-text-secondary')}
|
||||
@ -141,11 +145,11 @@ const VoiceParamConfig = ({
|
||||
</div>
|
||||
</Listbox>
|
||||
</div>
|
||||
<div className='mb-3'>
|
||||
<div className='system-sm-semibold mb-1 py-1 text-text-secondary'>
|
||||
<div className="mb-3">
|
||||
<div className="system-sm-semibold mb-1 py-1 text-text-secondary">
|
||||
{t('appDebug.voice.voiceSettings.voice')}
|
||||
</div>
|
||||
<div className='flex items-center gap-1'>
|
||||
<div className="flex items-center gap-1">
|
||||
<Listbox
|
||||
value={voiceItem ?? {}}
|
||||
disabled={!languageItem}
|
||||
@ -155,11 +159,15 @@ const VoiceParamConfig = ({
|
||||
})
|
||||
}}
|
||||
>
|
||||
<div className={'relative h-8 grow'}>
|
||||
<div className="relative h-8 grow">
|
||||
<ListboxButton
|
||||
className={'h-full w-full cursor-pointer rounded-lg border-0 bg-components-input-bg-normal py-1.5 pl-3 pr-10 focus-visible:bg-state-base-hover focus-visible:outline-none group-hover:bg-state-base-hover sm:text-sm sm:leading-6'}>
|
||||
className="h-full w-full cursor-pointer rounded-lg border-0 bg-components-input-bg-normal py-1.5 pl-3 pr-10 focus-visible:bg-state-base-hover focus-visible:outline-none group-hover:bg-state-base-hover sm:text-sm sm:leading-6"
|
||||
>
|
||||
<span
|
||||
className={cn('block truncate text-left text-text-secondary', !voiceItem?.name && 'text-text-tertiary')}>{voiceItem?.name ?? localVoicePlaceholder}</span>
|
||||
className={cn('block truncate text-left text-text-secondary', !voiceItem?.name && 'text-text-tertiary')}
|
||||
>
|
||||
{voiceItem?.name ?? localVoicePlaceholder}
|
||||
</span>
|
||||
<span className="pointer-events-none absolute inset-y-0 right-0 flex items-center pr-2">
|
||||
<ChevronDownIcon
|
||||
className="h-4 w-4 text-text-tertiary"
|
||||
@ -175,13 +183,12 @@ const VoiceParamConfig = ({
|
||||
>
|
||||
|
||||
<ListboxOptions
|
||||
className="absolute z-10 mt-1 max-h-60 w-full overflow-auto rounded-md border-[0.5px] border-components-panel-border bg-components-panel-bg px-1 py-1 text-base shadow-lg focus:outline-none sm:text-sm">
|
||||
className="absolute z-10 mt-1 max-h-60 w-full overflow-auto rounded-md border-[0.5px] border-components-panel-border bg-components-panel-bg px-1 py-1 text-base shadow-lg focus:outline-none sm:text-sm"
|
||||
>
|
||||
{voiceItems?.map((item: Item) => (
|
||||
<ListboxOption
|
||||
key={item.value}
|
||||
className={
|
||||
'relative cursor-pointer select-none rounded-lg py-2 pl-3 pr-9 text-text-secondary hover:bg-state-base-hover data-[active]:bg-state-base-active'
|
||||
}
|
||||
className="relative cursor-pointer select-none rounded-lg py-2 pl-3 pr-9 text-text-secondary hover:bg-state-base-hover data-[active]:bg-state-base-active"
|
||||
value={item}
|
||||
disabled={false}
|
||||
>
|
||||
@ -204,7 +211,7 @@ const VoiceParamConfig = ({
|
||||
</div>
|
||||
</Listbox>
|
||||
{languageItem?.example && (
|
||||
<div className='h-8 shrink-0 rounded-lg bg-components-button-tertiary-bg p-1'>
|
||||
<div className="h-8 shrink-0 rounded-lg bg-components-button-tertiary-bg p-1">
|
||||
<AudioBtn
|
||||
value={languageItem?.example}
|
||||
isAudition
|
||||
@ -216,10 +223,11 @@ const VoiceParamConfig = ({
|
||||
</div>
|
||||
</div>
|
||||
<div>
|
||||
<div className='system-sm-semibold mb-1 py-1 text-text-secondary'>
|
||||
<div className="system-sm-semibold mb-1 py-1 text-text-secondary">
|
||||
{t('appDebug.voice.voiceSettings.autoPlay')}
|
||||
</div>
|
||||
<Switch className='shrink-0'
|
||||
<Switch
|
||||
className="shrink-0"
|
||||
defaultValue={text2speech?.autoPlay === TtsAutoPlay.enabled}
|
||||
onChange={(value: boolean) => {
|
||||
handleChange({
|
||||
|
||||
@ -1,12 +1,12 @@
|
||||
'use client'
|
||||
import type { OnFeaturesChange } from '@/app/components/base/features/types'
|
||||
import { memo } from 'react'
|
||||
import ParamConfigContent from '@/app/components/base/features/new-feature-panel/text-to-speech/param-config-content'
|
||||
import {
|
||||
PortalToFollowElem,
|
||||
PortalToFollowElemContent,
|
||||
PortalToFollowElemTrigger,
|
||||
} from '@/app/components/base/portal-to-follow-elem'
|
||||
import ParamConfigContent from '@/app/components/base/features/new-feature-panel/text-to-speech/param-config-content'
|
||||
import type { OnFeaturesChange } from '@/app/components/base/features/types'
|
||||
|
||||
type VoiceSettingsProps = {
|
||||
open: boolean
|
||||
@ -33,11 +33,11 @@ const VoiceSettings = ({
|
||||
mainAxis: placementLeft ? 32 : 4,
|
||||
}}
|
||||
>
|
||||
<PortalToFollowElemTrigger className='flex' onClick={() => !disabled && onOpen((open: boolean) => !open)}>
|
||||
<PortalToFollowElemTrigger className="flex" onClick={() => !disabled && onOpen((open: boolean) => !open)}>
|
||||
{children}
|
||||
</PortalToFollowElemTrigger>
|
||||
<PortalToFollowElemContent style={{ zIndex: 50 }}>
|
||||
<div className='w-[360px] rounded-2xl border-[0.5px] border-components-panel-border bg-components-panel-bg p-4 shadow-2xl'>
|
||||
<div className="w-[360px] rounded-2xl border-[0.5px] border-components-panel-border bg-components-panel-bg p-4 shadow-2xl">
|
||||
<ParamConfigContent onClose={() => onOpen(false)} onChange={onChange} />
|
||||
</div>
|
||||
</PortalToFollowElemContent>
|
||||
|
||||
Reference in New Issue
Block a user