Merge remote-tracking branch 'origin/main' into feat/trigger

This commit is contained in:
lyzno1
2025-10-15 09:53:03 +08:00
167 changed files with 4679 additions and 2534 deletions

View File

@ -5,7 +5,7 @@ import { useTranslation } from 'react-i18next'
import { useBoolean } from 'ahooks'
import TracingIcon from './tracing-icon'
import ProviderPanel from './provider-panel'
import type { AliyunConfig, ArizeConfig, LangFuseConfig, LangSmithConfig, OpikConfig, PhoenixConfig, WeaveConfig } from './type'
import type { AliyunConfig, ArizeConfig, LangFuseConfig, LangSmithConfig, OpikConfig, PhoenixConfig, TencentConfig, WeaveConfig } from './type'
import { TracingProvider } from './type'
import ProviderConfigModal from './provider-config-modal'
import Indicator from '@/app/components/header/indicator'
@ -30,7 +30,8 @@ export type PopupProps = {
opikConfig: OpikConfig | null
weaveConfig: WeaveConfig | null
aliyunConfig: AliyunConfig | null
onConfigUpdated: (provider: TracingProvider, payload: ArizeConfig | PhoenixConfig | LangSmithConfig | LangFuseConfig | OpikConfig | WeaveConfig | AliyunConfig) => void
tencentConfig: TencentConfig | null
onConfigUpdated: (provider: TracingProvider, payload: ArizeConfig | PhoenixConfig | LangSmithConfig | LangFuseConfig | OpikConfig | WeaveConfig | AliyunConfig | TencentConfig) => void
onConfigRemoved: (provider: TracingProvider) => void
}
@ -48,6 +49,7 @@ const ConfigPopup: FC<PopupProps> = ({
opikConfig,
weaveConfig,
aliyunConfig,
tencentConfig,
onConfigUpdated,
onConfigRemoved,
}) => {
@ -81,8 +83,8 @@ const ConfigPopup: FC<PopupProps> = ({
hideConfigModal()
}, [currentProvider, hideConfigModal, onConfigRemoved])
const providerAllConfigured = arizeConfig && phoenixConfig && langSmithConfig && langFuseConfig && opikConfig && weaveConfig && aliyunConfig
const providerAllNotConfigured = !arizeConfig && !phoenixConfig && !langSmithConfig && !langFuseConfig && !opikConfig && !weaveConfig && !aliyunConfig
const providerAllConfigured = arizeConfig && phoenixConfig && langSmithConfig && langFuseConfig && opikConfig && weaveConfig && aliyunConfig && tencentConfig
const providerAllNotConfigured = !arizeConfig && !phoenixConfig && !langSmithConfig && !langFuseConfig && !opikConfig && !weaveConfig && !aliyunConfig && !tencentConfig
const switchContent = (
<Switch
@ -182,6 +184,19 @@ const ConfigPopup: FC<PopupProps> = ({
key="aliyun-provider-panel"
/>
)
const tencentPanel = (
<ProviderPanel
type={TracingProvider.tencent}
readOnly={readOnly}
config={tencentConfig}
hasConfigured={!!tencentConfig}
onConfig={handleOnConfig(TracingProvider.tencent)}
isChosen={chosenProvider === TracingProvider.tencent}
onChoose={handleOnChoose(TracingProvider.tencent)}
key="tencent-provider-panel"
/>
)
const configuredProviderPanel = () => {
const configuredPanels: JSX.Element[] = []
@ -206,6 +221,9 @@ const ConfigPopup: FC<PopupProps> = ({
if (aliyunConfig)
configuredPanels.push(aliyunPanel)
if (tencentConfig)
configuredPanels.push(tencentPanel)
return configuredPanels
}
@ -233,6 +251,9 @@ const ConfigPopup: FC<PopupProps> = ({
if (!aliyunConfig)
notConfiguredPanels.push(aliyunPanel)
if (!tencentConfig)
notConfiguredPanels.push(tencentPanel)
return notConfiguredPanels
}
@ -249,6 +270,8 @@ const ConfigPopup: FC<PopupProps> = ({
return opikConfig
if (currentProvider === TracingProvider.aliyun)
return aliyunConfig
if (currentProvider === TracingProvider.tencent)
return tencentConfig
return weaveConfig
}
@ -297,6 +320,7 @@ const ConfigPopup: FC<PopupProps> = ({
{arizePanel}
{phoenixPanel}
{aliyunPanel}
{tencentPanel}
</div>
</>
)

View File

@ -8,4 +8,5 @@ export const docURL = {
[TracingProvider.opik]: 'https://www.comet.com/docs/opik/tracing/integrations/dify#setup-instructions',
[TracingProvider.weave]: 'https://weave-docs.wandb.ai/',
[TracingProvider.aliyun]: 'https://help.aliyun.com/zh/arms/tracing-analysis/untitled-document-1750672984680',
[TracingProvider.tencent]: 'https://cloud.tencent.com/document/product/248/116531',
}

View File

@ -8,12 +8,12 @@ import {
import { useTranslation } from 'react-i18next'
import { usePathname } from 'next/navigation'
import { useBoolean } from 'ahooks'
import type { AliyunConfig, ArizeConfig, LangFuseConfig, LangSmithConfig, OpikConfig, PhoenixConfig, WeaveConfig } from './type'
import type { AliyunConfig, ArizeConfig, LangFuseConfig, LangSmithConfig, OpikConfig, PhoenixConfig, TencentConfig, WeaveConfig } from './type'
import { TracingProvider } from './type'
import TracingIcon from './tracing-icon'
import ConfigButton from './config-button'
import cn from '@/utils/classnames'
import { AliyunIcon, ArizeIcon, LangfuseIcon, LangsmithIcon, OpikIcon, PhoenixIcon, WeaveIcon } from '@/app/components/base/icons/src/public/tracing'
import { AliyunIcon, ArizeIcon, LangfuseIcon, LangsmithIcon, OpikIcon, PhoenixIcon, TencentIcon, WeaveIcon } from '@/app/components/base/icons/src/public/tracing'
import Indicator from '@/app/components/header/indicator'
import { fetchTracingConfig as doFetchTracingConfig, fetchTracingStatus, updateTracingStatus } from '@/service/apps'
import type { TracingStatus } from '@/models/app'
@ -71,6 +71,7 @@ const Panel: FC = () => {
[TracingProvider.opik]: OpikIcon,
[TracingProvider.weave]: WeaveIcon,
[TracingProvider.aliyun]: AliyunIcon,
[TracingProvider.tencent]: TencentIcon,
}
const InUseProviderIcon = inUseTracingProvider ? providerIconMap[inUseTracingProvider] : undefined
@ -81,7 +82,8 @@ const Panel: FC = () => {
const [opikConfig, setOpikConfig] = useState<OpikConfig | null>(null)
const [weaveConfig, setWeaveConfig] = useState<WeaveConfig | null>(null)
const [aliyunConfig, setAliyunConfig] = useState<AliyunConfig | null>(null)
const hasConfiguredTracing = !!(langSmithConfig || langFuseConfig || opikConfig || weaveConfig || arizeConfig || phoenixConfig || aliyunConfig)
const [tencentConfig, setTencentConfig] = useState<TencentConfig | null>(null)
const hasConfiguredTracing = !!(langSmithConfig || langFuseConfig || opikConfig || weaveConfig || arizeConfig || phoenixConfig || aliyunConfig || tencentConfig)
const fetchTracingConfig = async () => {
const getArizeConfig = async () => {
@ -119,6 +121,11 @@ const Panel: FC = () => {
if (!aliyunHasNotConfig)
setAliyunConfig(aliyunConfig as AliyunConfig)
}
const getTencentConfig = async () => {
const { tracing_config: tencentConfig, has_not_configured: tencentHasNotConfig } = await doFetchTracingConfig({ appId, provider: TracingProvider.tencent })
if (!tencentHasNotConfig)
setTencentConfig(tencentConfig as TencentConfig)
}
Promise.all([
getArizeConfig(),
getPhoenixConfig(),
@ -127,6 +134,7 @@ const Panel: FC = () => {
getOpikConfig(),
getWeaveConfig(),
getAliyunConfig(),
getTencentConfig(),
])
}
@ -147,6 +155,8 @@ const Panel: FC = () => {
setWeaveConfig(tracing_config as WeaveConfig)
else if (provider === TracingProvider.aliyun)
setAliyunConfig(tracing_config as AliyunConfig)
else if (provider === TracingProvider.tencent)
setTencentConfig(tracing_config as TencentConfig)
}
const handleTracingConfigRemoved = (provider: TracingProvider) => {
@ -164,6 +174,8 @@ const Panel: FC = () => {
setWeaveConfig(null)
else if (provider === TracingProvider.aliyun)
setAliyunConfig(null)
else if (provider === TracingProvider.tencent)
setTencentConfig(null)
if (provider === inUseTracingProvider) {
handleTracingStatusChange({
enabled: false,
@ -209,6 +221,7 @@ const Panel: FC = () => {
opikConfig={opikConfig}
weaveConfig={weaveConfig}
aliyunConfig={aliyunConfig}
tencentConfig={tencentConfig}
onConfigUpdated={handleTracingConfigUpdated}
onConfigRemoved={handleTracingConfigRemoved}
>
@ -245,6 +258,7 @@ const Panel: FC = () => {
opikConfig={opikConfig}
weaveConfig={weaveConfig}
aliyunConfig={aliyunConfig}
tencentConfig={tencentConfig}
onConfigUpdated={handleTracingConfigUpdated}
onConfigRemoved={handleTracingConfigRemoved}
>

View File

@ -4,7 +4,7 @@ import React, { useCallback, useState } from 'react'
import { useTranslation } from 'react-i18next'
import { useBoolean } from 'ahooks'
import Field from './field'
import type { AliyunConfig, ArizeConfig, LangFuseConfig, LangSmithConfig, OpikConfig, PhoenixConfig, WeaveConfig } from './type'
import type { AliyunConfig, ArizeConfig, LangFuseConfig, LangSmithConfig, OpikConfig, PhoenixConfig, TencentConfig, WeaveConfig } from './type'
import { TracingProvider } from './type'
import { docURL } from './config'
import {
@ -22,10 +22,10 @@ import Divider from '@/app/components/base/divider'
type Props = {
appId: string
type: TracingProvider
payload?: ArizeConfig | PhoenixConfig | LangSmithConfig | LangFuseConfig | OpikConfig | WeaveConfig | AliyunConfig | null
payload?: ArizeConfig | PhoenixConfig | LangSmithConfig | LangFuseConfig | OpikConfig | WeaveConfig | AliyunConfig | TencentConfig | null
onRemoved: () => void
onCancel: () => void
onSaved: (payload: ArizeConfig | PhoenixConfig | LangSmithConfig | LangFuseConfig | OpikConfig | WeaveConfig | AliyunConfig) => void
onSaved: (payload: ArizeConfig | PhoenixConfig | LangSmithConfig | LangFuseConfig | OpikConfig | WeaveConfig | AliyunConfig | TencentConfig) => void
onChosen: (provider: TracingProvider) => void
}
@ -77,6 +77,12 @@ const aliyunConfigTemplate = {
endpoint: '',
}
const tencentConfigTemplate = {
token: '',
endpoint: '',
service_name: '',
}
const ProviderConfigModal: FC<Props> = ({
appId,
type,
@ -90,7 +96,7 @@ const ProviderConfigModal: FC<Props> = ({
const isEdit = !!payload
const isAdd = !isEdit
const [isSaving, setIsSaving] = useState(false)
const [config, setConfig] = useState<ArizeConfig | PhoenixConfig | LangSmithConfig | LangFuseConfig | OpikConfig | WeaveConfig | AliyunConfig>((() => {
const [config, setConfig] = useState<ArizeConfig | PhoenixConfig | LangSmithConfig | LangFuseConfig | OpikConfig | WeaveConfig | AliyunConfig | TencentConfig>((() => {
if (isEdit)
return payload
@ -112,6 +118,9 @@ const ProviderConfigModal: FC<Props> = ({
else if (type === TracingProvider.aliyun)
return aliyunConfigTemplate
else if (type === TracingProvider.tencent)
return tencentConfigTemplate
return weaveConfigTemplate
})())
const [isShowRemoveConfirm, {
@ -202,6 +211,16 @@ const ProviderConfigModal: FC<Props> = ({
errorMessage = t('common.errorMsg.fieldRequired', { field: 'Endpoint' })
}
if (type === TracingProvider.tencent) {
const postData = config as TencentConfig
if (!errorMessage && !postData.token)
errorMessage = t('common.errorMsg.fieldRequired', { field: 'Token' })
if (!errorMessage && !postData.endpoint)
errorMessage = t('common.errorMsg.fieldRequired', { field: 'Endpoint' })
if (!errorMessage && !postData.service_name)
errorMessage = t('common.errorMsg.fieldRequired', { field: 'Service Name' })
}
return errorMessage
}, [config, t, type])
const handleSave = useCallback(async () => {
@ -338,6 +357,34 @@ const ProviderConfigModal: FC<Props> = ({
/>
</>
)}
{type === TracingProvider.tencent && (
<>
<Field
label='Token'
labelClassName='!text-sm'
isRequired
value={(config as TencentConfig).token}
onChange={handleConfigChange('token')}
placeholder={t(`${I18N_PREFIX}.placeholder`, { key: 'Token' })!}
/>
<Field
label='Endpoint'
labelClassName='!text-sm'
isRequired
value={(config as TencentConfig).endpoint}
onChange={handleConfigChange('endpoint')}
placeholder='https://your-region.cls.tencentcs.com'
/>
<Field
label='Service Name'
labelClassName='!text-sm'
isRequired
value={(config as TencentConfig).service_name}
onChange={handleConfigChange('service_name')}
placeholder='dify_app'
/>
</>
)}
{type === TracingProvider.weave && (
<>
<Field

View File

@ -7,7 +7,7 @@ import {
import { useTranslation } from 'react-i18next'
import { TracingProvider } from './type'
import cn from '@/utils/classnames'
import { AliyunIconBig, ArizeIconBig, LangfuseIconBig, LangsmithIconBig, OpikIconBig, PhoenixIconBig, WeaveIconBig } from '@/app/components/base/icons/src/public/tracing'
import { AliyunIconBig, ArizeIconBig, LangfuseIconBig, LangsmithIconBig, OpikIconBig, PhoenixIconBig, TencentIconBig, WeaveIconBig } from '@/app/components/base/icons/src/public/tracing'
import { Eye as View } from '@/app/components/base/icons/src/vender/solid/general'
const I18N_PREFIX = 'app.tracing'
@ -31,6 +31,7 @@ const getIcon = (type: TracingProvider) => {
[TracingProvider.opik]: OpikIconBig,
[TracingProvider.weave]: WeaveIconBig,
[TracingProvider.aliyun]: AliyunIconBig,
[TracingProvider.tencent]: TencentIconBig,
})[type]
}

View File

@ -6,6 +6,7 @@ export enum TracingProvider {
opik = 'opik',
weave = 'weave',
aliyun = 'aliyun',
tencent = 'tencent',
}
export type ArizeConfig = {
@ -53,3 +54,9 @@ export type AliyunConfig = {
license_key: string
endpoint: string
}
export type TencentConfig = {
token: string
endpoint: string
service_name: string
}

View File

@ -53,9 +53,6 @@ const ChatWrapper = () => {
initUserVariables,
} = useChatWithHistoryContext()
// Semantic variable for better code readability
const isHistoryConversation = !!currentConversationId
const appConfig = useMemo(() => {
const config = appParams || {}
@ -66,9 +63,9 @@ const ChatWrapper = () => {
fileUploadConfig: (config as any).system_parameters,
},
supportFeedback: true,
opening_statement: isHistoryConversation ? currentConversationItem?.introduction : (config as any).opening_statement,
opening_statement: currentConversationItem?.introduction || (config as any).opening_statement,
} as ChatConfig
}, [appParams, currentConversationItem?.introduction, isHistoryConversation])
}, [appParams, currentConversationItem?.introduction])
const {
chatList,
setTargetMessageId,
@ -79,7 +76,7 @@ const ChatWrapper = () => {
} = useChat(
appConfig,
{
inputs: (isHistoryConversation ? currentConversationInputs : newConversationInputs) as any,
inputs: (currentConversationId ? currentConversationInputs : newConversationInputs) as any,
inputsForm: inputsForms,
},
appPrevChatTree,
@ -87,7 +84,7 @@ const ChatWrapper = () => {
clearChatList,
setClearChatList,
)
const inputsFormValue = isHistoryConversation ? currentConversationInputs : newConversationInputsRef?.current
const inputsFormValue = currentConversationId ? currentConversationInputs : newConversationInputsRef?.current
const inputDisabled = useMemo(() => {
if (allInputsHidden)
return false
@ -136,7 +133,7 @@ const ChatWrapper = () => {
const data: any = {
query: message,
files,
inputs: formatBooleanInputs(inputsForms, isHistoryConversation ? currentConversationInputs : newConversationInputs),
inputs: formatBooleanInputs(inputsForms, currentConversationId ? currentConversationInputs : newConversationInputs),
conversation_id: currentConversationId,
parent_message_id: (isRegenerate ? parentAnswer?.id : getLastAnswer(chatList)?.id) || null,
}
@ -146,11 +143,11 @@ const ChatWrapper = () => {
data,
{
onGetSuggestedQuestions: responseItemId => fetchSuggestedQuestions(responseItemId, isInstalledApp, appId),
onConversationComplete: isHistoryConversation ? undefined : handleNewConversationCompleted,
onConversationComplete: currentConversationId ? undefined : handleNewConversationCompleted,
isPublicAPI: !isInstalledApp,
},
)
}, [chatList, handleNewConversationCompleted, handleSend, isHistoryConversation, currentConversationInputs, newConversationInputs, isInstalledApp, appId])
}, [chatList, handleNewConversationCompleted, handleSend, currentConversationId, currentConversationInputs, newConversationInputs, isInstalledApp, appId])
const doRegenerate = useCallback((chatItem: ChatItemInTree, editedQuestion?: { message: string, files?: FileEntity[] }) => {
const question = editedQuestion ? chatItem : chatList.find(item => item.id === chatItem.parentMessageId)!
@ -163,30 +160,38 @@ const ChatWrapper = () => {
}, [chatList, doSend])
const messageList = useMemo(() => {
// Always filter out opening statement from message list as it's handled separately in welcome component
if (currentConversationId || chatList.length > 1)
return chatList
// Without messages we are in the welcome screen, so hide the opening statement from chatlist
return chatList.filter(item => !item.isOpeningStatement)
}, [chatList])
const [collapsed, setCollapsed] = useState(isHistoryConversation)
const [collapsed, setCollapsed] = useState(!!currentConversationId)
const chatNode = useMemo(() => {
if (allInputsHidden || !inputsForms.length)
return null
if (isMobile) {
if (!isHistoryConversation)
if (!currentConversationId)
return <InputsForm collapsed={collapsed} setCollapsed={setCollapsed} />
return null
}
else {
return <InputsForm collapsed={collapsed} setCollapsed={setCollapsed} />
}
}, [inputsForms.length, isMobile, isHistoryConversation, collapsed, allInputsHidden])
},
[
inputsForms.length,
isMobile,
currentConversationId,
collapsed, allInputsHidden,
])
const welcome = useMemo(() => {
const welcomeMessage = chatList.find(item => item.isOpeningStatement)
if (respondingState)
return null
if (isHistoryConversation)
if (currentConversationId)
return null
if (!welcomeMessage)
return null
@ -227,7 +232,18 @@ const ChatWrapper = () => {
</div>
</div>
)
}, [appData?.site.icon, appData?.site.icon_background, appData?.site.icon_type, appData?.site.icon_url, chatList, collapsed, isHistoryConversation, inputsForms.length, respondingState, allInputsHidden])
},
[
appData?.site.icon,
appData?.site.icon_background,
appData?.site.icon_type,
appData?.site.icon_url,
chatList, collapsed,
currentConversationId,
inputsForms.length,
respondingState,
allInputsHidden,
])
const answerIcon = (appData?.site && appData.site.use_icon_as_answer_icon)
? <AnswerIcon
@ -251,7 +267,7 @@ const ChatWrapper = () => {
chatFooterClassName='pb-4'
chatFooterInnerClassName={`mx-auto w-full max-w-[768px] ${isMobile ? 'px-2' : 'px-4'}`}
onSend={doSend}
inputs={isHistoryConversation ? currentConversationInputs as any : newConversationInputs}
inputs={currentConversationId ? currentConversationInputs as any : newConversationInputs}
inputsForm={inputsForms}
onRegenerate={doRegenerate}
onStopResponding={handleStop}

View File

@ -111,6 +111,8 @@ const Answer: FC<AnswerProps> = ({
}
}, [switchSibling, item.prevSibling, item.nextSibling])
const contentIsEmpty = content.trim() === ''
return (
<div className='mb-2 flex last:mb-0'>
<div className='relative h-10 w-10 shrink-0'>
@ -153,14 +155,14 @@ const Answer: FC<AnswerProps> = ({
)
}
{
responding && !content && !hasAgentThoughts && (
responding && contentIsEmpty && !hasAgentThoughts && (
<div className='flex h-5 w-6 items-center justify-center'>
<LoadingAnim type='text' />
</div>
)
}
{
content && !hasAgentThoughts && (
!contentIsEmpty && !hasAgentThoughts && (
<BasicContent item={item} />
)
}

View File

@ -83,6 +83,15 @@ const ChatInputArea = ({
const historyRef = useRef([''])
const [currentIndex, setCurrentIndex] = useState(-1)
const isComposingRef = useRef(false)
const handleQueryChange = useCallback(
(value: string) => {
setQuery(value)
setTimeout(handleTextareaResize, 0)
},
[handleTextareaResize],
)
const handleSend = () => {
if (isResponding) {
notify({ type: 'info', message: t('appDebug.errorMessage.waitForResponse') })
@ -101,7 +110,7 @@ const ChatInputArea = ({
}
if (checkInputsForm(inputs, inputsForm)) {
onSend(query, files)
setQuery('')
handleQueryChange('')
setFiles([])
}
}
@ -131,19 +140,19 @@ const ChatInputArea = ({
// When the cmd + up key is pressed, output the previous element
if (currentIndex > 0) {
setCurrentIndex(currentIndex - 1)
setQuery(historyRef.current[currentIndex - 1])
handleQueryChange(historyRef.current[currentIndex - 1])
}
}
else if (e.key === 'ArrowDown' && !e.shiftKey && !e.nativeEvent.isComposing && e.metaKey) {
// When the cmd + down key is pressed, output the next element
if (currentIndex < historyRef.current.length - 1) {
setCurrentIndex(currentIndex + 1)
setQuery(historyRef.current[currentIndex + 1])
handleQueryChange(historyRef.current[currentIndex + 1])
}
else if (currentIndex === historyRef.current.length - 1) {
// If it is the last element, clear the input box
setCurrentIndex(historyRef.current.length)
setQuery('')
handleQueryChange('')
}
}
}
@ -171,7 +180,7 @@ const ChatInputArea = ({
<>
<div
className={cn(
'relative z-10 rounded-xl border border-components-chat-input-border bg-components-panel-bg-blur pb-[9px] shadow-md',
'relative z-10 overflow-hidden rounded-xl border border-components-chat-input-border bg-components-panel-bg-blur pb-[9px] shadow-md',
isDragActive && 'border border-dashed border-components-option-card-option-selected-border',
disabled && 'pointer-events-none border-components-panel-border opacity-50 shadow-none',
)}
@ -197,12 +206,8 @@ const ChatInputArea = ({
placeholder={t('common.chat.inputPlaceholder', { botName }) || ''}
autoFocus
minRows={1}
onResize={handleTextareaResize}
value={query}
onChange={(e) => {
setQuery(e.target.value)
setTimeout(handleTextareaResize, 0)
}}
onChange={e => handleQueryChange(e.target.value)}
onKeyDown={handleKeyDown}
onCompositionStart={handleCompositionStart}
onCompositionEnd={handleCompositionEnd}
@ -221,7 +226,7 @@ const ChatInputArea = ({
showVoiceInput && (
<VoiceInput
onCancel={() => setShowVoiceInput(false)}
onConverted={text => setQuery(text)}
onConverted={text => handleQueryChange(text)}
/>
)
}

View File

@ -1,3 +1,4 @@
import type { FC, Ref } from 'react'
import { memo } from 'react'
import {
RiMicLine,
@ -18,20 +19,17 @@ type OperationProps = {
speechToTextConfig?: EnableType
onShowVoiceInput?: () => void
onSend: () => void
theme?: Theme | null
theme?: Theme | null,
ref?: Ref<HTMLDivElement>;
}
const Operation = (
{
ref,
fileConfig,
speechToTextConfig,
onShowVoiceInput,
onSend,
theme,
}: OperationProps & {
ref: React.RefObject<HTMLDivElement>;
},
) => {
const Operation: FC<OperationProps> = ({
ref,
fileConfig,
speechToTextConfig,
onShowVoiceInput,
onSend,
theme,
}) => {
return (
<div
className={cn(

View File

@ -62,9 +62,9 @@ const ChatWrapper = () => {
fileUploadConfig: (config as any).system_parameters,
},
supportFeedback: true,
opening_statement: currentConversationId ? currentConversationItem?.introduction : (config as any).opening_statement,
opening_statement: currentConversationItem?.introduction || (config as any).opening_statement,
} as ChatConfig
}, [appParams, currentConversationItem?.introduction, currentConversationId])
}, [appParams, currentConversationItem?.introduction])
const {
chatList,
setTargetMessageId,
@ -158,8 +158,9 @@ const ChatWrapper = () => {
}, [chatList, doSend])
const messageList = useMemo(() => {
if (currentConversationId)
if (currentConversationId || chatList.length > 1)
return chatList
// Without messages we are in the welcome screen, so hide the opening statement from chatlist
return chatList.filter(item => !item.isOpeningStatement)
}, [chatList, currentConversationId])
@ -240,7 +241,7 @@ const ChatWrapper = () => {
config={appConfig}
chatList={messageList}
isResponding={respondingState}
chatContainerInnerClassName={cn('mx-auto w-full max-w-full pt-4 tablet:px-4', isMobile && 'px-4')}
chatContainerInnerClassName={cn('mx-auto w-full max-w-full px-4', messageList.length && 'pt-4')}
chatFooterClassName={cn('pb-4', !isMobile && 'rounded-b-2xl')}
chatFooterInnerClassName={cn('mx-auto w-full max-w-full px-4', isMobile && 'px-2')}
onSend={doSend}

View File

@ -36,6 +36,7 @@ const Header: FC<IHeaderProps> = ({
appData,
currentConversationId,
inputsForms,
allInputsHidden,
} = useEmbeddedChatbotContext()
const isClient = typeof window !== 'undefined'
@ -124,7 +125,7 @@ const Header: FC<IHeaderProps> = ({
</ActionButton>
</Tooltip>
)}
{currentConversationId && inputsForms.length > 0 && (
{currentConversationId && inputsForms.length > 0 && !allInputsHidden && (
<ViewFormDropdown />
)}
</div>
@ -135,7 +136,7 @@ const Header: FC<IHeaderProps> = ({
return (
<div
className={cn('flex h-14 shrink-0 items-center justify-between rounded-t-2xl px-3')}
style={Object.assign({}, CssTransform(theme?.backgroundHeaderColorStyle ?? ''), CssTransform(theme?.headerBorderBottomStyle ?? ''))}
style={CssTransform(theme?.headerBorderBottomStyle ?? '')}
>
<div className="flex grow items-center space-x-3">
{customerIcon}
@ -171,7 +172,7 @@ const Header: FC<IHeaderProps> = ({
</ActionButton>
</Tooltip>
)}
{currentConversationId && inputsForms.length > 0 && (
{currentConversationId && inputsForms.length > 0 && !allInputsHidden && (
<ViewFormDropdown iconColor={theme?.colorPathOnHeader} />
)}
</div>

View File

@ -49,8 +49,8 @@ const Chatbot = () => {
<div className='relative'>
<div
className={cn(
'flex flex-col rounded-2xl border border-components-panel-border-subtle',
isMobile ? 'h-[calc(100vh_-_60px)] border-[0.5px] border-components-panel-border shadow-xs' : 'h-[100vh] bg-chatbot-bg',
'flex flex-col rounded-2xl',
isMobile ? 'h-[calc(100vh_-_60px)] shadow-xs' : 'h-[100vh] bg-chatbot-bg',
)}
style={isMobile ? Object.assign({}, CssTransform(themeBuilder?.theme?.backgroundHeaderColorStyle ?? '')) : {}}
>
@ -62,7 +62,7 @@ const Chatbot = () => {
theme={themeBuilder?.theme}
onCreateNewChat={handleNewConversation}
/>
<div className={cn('flex grow flex-col overflow-y-auto', isMobile && '!h-[calc(100vh_-_3rem)] rounded-2xl bg-chatbot-bg')}>
<div className={cn('flex grow flex-col overflow-y-auto', isMobile && 'm-[0.5px] !h-[calc(100vh_-_3rem)] rounded-2xl bg-chatbot-bg')}>
{appChatListDataLoading && (
<Loading type='app' />
)}

View File

@ -1,13 +0,0 @@
export { default as Chunk } from './Chunk'
export { default as Collapse } from './Collapse'
export { default as Divider } from './Divider'
export { default as File } from './File'
export { default as GeneralType } from './GeneralType'
export { default as LayoutRight2LineMod } from './LayoutRight2LineMod'
export { default as OptionCardEffectBlueLight } from './OptionCardEffectBlueLight'
export { default as OptionCardEffectBlue } from './OptionCardEffectBlue'
export { default as OptionCardEffectOrange } from './OptionCardEffectOrange'
export { default as OptionCardEffectPurple } from './OptionCardEffectPurple'
export { default as ParentChildType } from './ParentChildType'
export { default as SelectionMod } from './SelectionMod'
export { default as Watercrawl } from './Watercrawl'

View File

@ -1,5 +0,0 @@
.wrapper {
display: inline-flex;
background: url(~@/app/components/base/icons/assets/image/llm/baichuan-text-cn.png) center center no-repeat;
background-size: contain;
}

View File

@ -1,20 +0,0 @@
// GENERATE BY script
// DON NOT EDIT IT MANUALLY
import * as React from 'react'
import cn from '@/utils/classnames'
import s from './BaichuanTextCn.module.css'
const Icon = (
{
ref,
className,
...restProps
}: React.DetailedHTMLProps<React.HTMLAttributes<HTMLSpanElement>, HTMLSpanElement> & {
ref?: React.RefObject<HTMLSpanElement>;
},
) => <span className={cn(s.wrapper, className)} {...restProps} ref={ref} />
Icon.displayName = 'BaichuanTextCn'
export default Icon

View File

@ -1,5 +0,0 @@
.wrapper {
display: inline-flex;
background: url(~@/app/components/base/icons/assets/image/llm/minimax.png) center center no-repeat;
background-size: contain;
}

View File

@ -1,20 +0,0 @@
// GENERATE BY script
// DON NOT EDIT IT MANUALLY
import * as React from 'react'
import cn from '@/utils/classnames'
import s from './Minimax.module.css'
const Icon = (
{
ref,
className,
...restProps
}: React.DetailedHTMLProps<React.HTMLAttributes<HTMLSpanElement>, HTMLSpanElement> & {
ref?: React.RefObject<HTMLSpanElement>;
},
) => <span className={cn(s.wrapper, className)} {...restProps} ref={ref} />
Icon.displayName = 'Minimax'
export default Icon

View File

@ -1,5 +0,0 @@
.wrapper {
display: inline-flex;
background: url(~@/app/components/base/icons/assets/image/llm/minimax-text.png) center center no-repeat;
background-size: contain;
}

View File

@ -1,20 +0,0 @@
// GENERATE BY script
// DON NOT EDIT IT MANUALLY
import * as React from 'react'
import cn from '@/utils/classnames'
import s from './MinimaxText.module.css'
const Icon = (
{
ref,
className,
...restProps
}: React.DetailedHTMLProps<React.HTMLAttributes<HTMLSpanElement>, HTMLSpanElement> & {
ref?: React.RefObject<HTMLSpanElement>;
},
) => <span className={cn(s.wrapper, className)} {...restProps} ref={ref} />
Icon.displayName = 'MinimaxText'
export default Icon

View File

@ -1,5 +0,0 @@
.wrapper {
display: inline-flex;
background: url(~@/app/components/base/icons/assets/image/llm/tongyi.png) center center no-repeat;
background-size: contain;
}

View File

@ -1,20 +0,0 @@
// GENERATE BY script
// DON NOT EDIT IT MANUALLY
import * as React from 'react'
import cn from '@/utils/classnames'
import s from './Tongyi.module.css'
const Icon = (
{
ref,
className,
...restProps
}: React.DetailedHTMLProps<React.HTMLAttributes<HTMLSpanElement>, HTMLSpanElement> & {
ref?: React.RefObject<HTMLSpanElement>;
},
) => <span className={cn(s.wrapper, className)} {...restProps} ref={ref} />
Icon.displayName = 'Tongyi'
export default Icon

View File

@ -1,5 +0,0 @@
.wrapper {
display: inline-flex;
background: url(~@/app/components/base/icons/assets/image/llm/tongyi-text.png) center center no-repeat;
background-size: contain;
}

View File

@ -1,20 +0,0 @@
// GENERATE BY script
// DON NOT EDIT IT MANUALLY
import * as React from 'react'
import cn from '@/utils/classnames'
import s from './TongyiText.module.css'
const Icon = (
{
ref,
className,
...restProps
}: React.DetailedHTMLProps<React.HTMLAttributes<HTMLSpanElement>, HTMLSpanElement> & {
ref?: React.RefObject<HTMLSpanElement>;
},
) => <span className={cn(s.wrapper, className)} {...restProps} ref={ref} />
Icon.displayName = 'TongyiText'
export default Icon

View File

@ -1,5 +0,0 @@
.wrapper {
display: inline-flex;
background: url(~@/app/components/base/icons/assets/image/llm/tongyi-text-cn.png) center center no-repeat;
background-size: contain;
}

View File

@ -1,20 +0,0 @@
// GENERATE BY script
// DON NOT EDIT IT MANUALLY
import * as React from 'react'
import cn from '@/utils/classnames'
import s from './TongyiTextCn.module.css'
const Icon = (
{
ref,
className,
...restProps
}: React.DetailedHTMLProps<React.HTMLAttributes<HTMLSpanElement>, HTMLSpanElement> & {
ref?: React.RefObject<HTMLSpanElement>;
},
) => <span className={cn(s.wrapper, className)} {...restProps} ref={ref} />
Icon.displayName = 'TongyiTextCn'
export default Icon

View File

@ -1,5 +0,0 @@
.wrapper {
display: inline-flex;
background: url(~@/app/components/base/icons/assets/image/llm/wxyy.png) center center no-repeat;
background-size: contain;
}

View File

@ -1,20 +0,0 @@
// GENERATE BY script
// DON NOT EDIT IT MANUALLY
import * as React from 'react'
import cn from '@/utils/classnames'
import s from './Wxyy.module.css'
const Icon = (
{
ref,
className,
...restProps
}: React.DetailedHTMLProps<React.HTMLAttributes<HTMLSpanElement>, HTMLSpanElement> & {
ref?: React.RefObject<HTMLSpanElement>;
},
) => <span className={cn(s.wrapper, className)} {...restProps} ref={ref} />
Icon.displayName = 'Wxyy'
export default Icon

View File

@ -1,5 +0,0 @@
.wrapper {
display: inline-flex;
background: url(~@/app/components/base/icons/assets/image/llm/wxyy-text.png) center center no-repeat;
background-size: contain;
}

View File

@ -1,20 +0,0 @@
// GENERATE BY script
// DON NOT EDIT IT MANUALLY
import * as React from 'react'
import cn from '@/utils/classnames'
import s from './WxyyText.module.css'
const Icon = (
{
ref,
className,
...restProps
}: React.DetailedHTMLProps<React.HTMLAttributes<HTMLSpanElement>, HTMLSpanElement> & {
ref?: React.RefObject<HTMLSpanElement>;
},
) => <span className={cn(s.wrapper, className)} {...restProps} ref={ref} />
Icon.displayName = 'WxyyText'
export default Icon

View File

@ -1,5 +0,0 @@
.wrapper {
display: inline-flex;
background: url(~@/app/components/base/icons/assets/image/llm/wxyy-text-cn.png) center center no-repeat;
background-size: contain;
}

View File

@ -1,20 +0,0 @@
// GENERATE BY script
// DON NOT EDIT IT MANUALLY
import * as React from 'react'
import cn from '@/utils/classnames'
import s from './WxyyTextCn.module.css'
const Icon = (
{
ref,
className,
...restProps
}: React.DetailedHTMLProps<React.HTMLAttributes<HTMLSpanElement>, HTMLSpanElement> & {
ref?: React.RefObject<HTMLSpanElement>;
},
) => <span className={cn(s.wrapper, className)} {...restProps} ref={ref} />
Icon.displayName = 'WxyyTextCn'
export default Icon

View File

@ -1,9 +0,0 @@
export { default as BaichuanTextCn } from './BaichuanTextCn'
export { default as MinimaxText } from './MinimaxText'
export { default as Minimax } from './Minimax'
export { default as TongyiTextCn } from './TongyiTextCn'
export { default as TongyiText } from './TongyiText'
export { default as Tongyi } from './Tongyi'
export { default as WxyyTextCn } from './WxyyTextCn'
export { default as WxyyText } from './WxyyText'
export { default as Wxyy } from './Wxyy'

View File

@ -1 +0,0 @@
export { default as Checked } from './Checked'

View File

@ -1,20 +0,0 @@
// GENERATE BY script
// DON NOT EDIT IT MANUALLY
import * as React from 'react'
import data from './WebReader.json'
import IconBase from '@/app/components/base/icons/IconBase'
import type { IconData } from '@/app/components/base/icons/IconBase'
const Icon = (
{
ref,
...props
}: React.SVGProps<SVGSVGElement> & {
ref?: React.RefObject<React.RefObject<HTMLOrSVGElement>>;
},
) => <IconBase {...props} ref={ref} data={data as IconData} />
Icon.displayName = 'WebReader'
export default Icon

View File

@ -1,20 +0,0 @@
// GENERATE BY script
// DON NOT EDIT IT MANUALLY
import * as React from 'react'
import data from './Wikipedia.json'
import IconBase from '@/app/components/base/icons/IconBase'
import type { IconData } from '@/app/components/base/icons/IconBase'
const Icon = (
{
ref,
...props
}: React.SVGProps<SVGSVGElement> & {
ref?: React.RefObject<React.RefObject<HTMLOrSVGElement>>;
},
) => <IconBase {...props} ref={ref} data={data as IconData} />
Icon.displayName = 'Wikipedia'
export default Icon

View File

@ -1,7 +0,0 @@
export { default as Google } from './Google'
export { default as PartnerDark } from './PartnerDark'
export { default as PartnerLight } from './PartnerLight'
export { default as VerifiedDark } from './VerifiedDark'
export { default as VerifiedLight } from './VerifiedLight'
export { default as WebReader } from './WebReader'
export { default as Wikipedia } from './Wikipedia'

View File

@ -18,3 +18,4 @@ const Icon = (
Icon.displayName = 'DataSet'
export default Icon

View File

@ -1,20 +0,0 @@
// GENERATE BY script
// DON NOT EDIT IT MANUALLY
import * as React from 'react'
import data from './Loading.json'
import IconBase from '@/app/components/base/icons/IconBase'
import type { IconData } from '@/app/components/base/icons/IconBase'
const Icon = (
{
ref,
...props
}: React.SVGProps<SVGSVGElement> & {
ref?: React.RefObject<React.RefObject<HTMLOrSVGElement>>;
},
) => <IconBase {...props} ref={ref} data={data as IconData} />
Icon.displayName = 'Loading'
export default Icon

View File

@ -1,20 +0,0 @@
// GENERATE BY script
// DON NOT EDIT IT MANUALLY
import * as React from 'react'
import data from './Search.json'
import IconBase from '@/app/components/base/icons/IconBase'
import type { IconData } from '@/app/components/base/icons/IconBase'
const Icon = (
{
ref,
...props
}: React.SVGProps<SVGSVGElement> & {
ref?: React.RefObject<React.RefObject<HTMLOrSVGElement>>;
},
) => <IconBase {...props} ref={ref} data={data as IconData} />
Icon.displayName = 'Search'
export default Icon

View File

@ -1,20 +0,0 @@
// GENERATE BY script
// DON NOT EDIT IT MANUALLY
import * as React from 'react'
import data from './ThoughtList.json'
import IconBase from '@/app/components/base/icons/IconBase'
import type { IconData } from '@/app/components/base/icons/IconBase'
const Icon = (
{
ref,
...props
}: React.SVGProps<SVGSVGElement> & {
ref?: React.RefObject<React.RefObject<HTMLOrSVGElement>>;
},
) => <IconBase {...props} ref={ref} data={data as IconData} />
Icon.displayName = 'ThoughtList'
export default Icon

View File

@ -1,20 +0,0 @@
// GENERATE BY script
// DON NOT EDIT IT MANUALLY
import * as React from 'react'
import data from './WebReader.json'
import IconBase from '@/app/components/base/icons/IconBase'
import type { IconData } from '@/app/components/base/icons/IconBase'
const Icon = (
{
ref,
...props
}: React.SVGProps<SVGSVGElement> & {
ref?: React.RefObject<React.RefObject<HTMLOrSVGElement>>;
},
) => <IconBase {...props} ref={ref} data={data as IconData} />
Icon.displayName = 'WebReader'
export default Icon

View File

@ -1,5 +1,2 @@
export { default as DataSet } from './DataSet'
export { default as Loading } from './Loading'
export { default as Search } from './Search'
export { default as ThoughtList } from './ThoughtList'
export { default as WebReader } from './WebReader'

View File

@ -0,0 +1,170 @@
{
"icon": {
"type": "element",
"name": "svg",
"attributes": {
"width": "80px",
"height": "18px",
"viewBox": "0 0 80 18",
"version": "1.1"
},
"isRootNode": true,
"children": [
{
"type": "element",
"name": "title",
"attributes": {},
"children": []
},
{
"type": "element",
"name": "g",
"attributes": {
"id": "页面-1",
"stroke": "none",
"stroke-width": "1",
"fill": "none",
"fill-rule": "evenodd"
},
"children": [
{
"type": "element",
"name": "g",
"attributes": {
"id": "logo",
"fill-rule": "nonzero"
},
"children": [
{
"type": "element",
"name": "g",
"attributes": {
"id": "XMLID_25_",
"transform": "translate(30.592488, 1.100000)",
"fill": "#253554"
},
"children": [
{
"type": "element",
"name": "path",
"attributes": {
"d": "M30.8788968,0.6 L21.8088578,0.6 L21.8088578,1.9 L24.5604427,1.9 L24.5604427,6.7 L21.2993051,6.7 L21.2993051,8 L24.5604427,8 L24.5604427,15.9 L26.089101,15.9 L26.089101,8 L29.5540597,8 L29.5540597,15.6 L32.3056445,15.6 L32.3056445,14.3 L31.0827179,14.3 L31.0827179,0.6 L30.8788968,0.6 Z M25.9871904,6.5 L25.9871904,1.9 L29.5540597,1.9 L29.5540597,6.7 L26.089101,6.7 L26.089101,6.5 L25.9871904,6.5 Z",
"id": "XMLID_38_"
},
"children": []
},
{
"type": "element",
"name": "polygon",
"attributes": {
"id": "XMLID_14_",
"points": "5.60508028 12.2 12.8407294 12.2 12.8407294 13.5 5.60508028 13.5"
},
"children": []
},
{
"type": "element",
"name": "path",
"attributes": {
"d": "M0.611463304,9.8 C0.611463304,12.1 0.509552753,14 0,15.5 C0,15.6 0,15.6 0.101910551,15.6 C0.101910551,15.6 1.22292661,15.6 1.42674771,15.6 C1.93630046,13.4 1.93630046,11.6 1.93630046,10.3 L3.77069037,10.3 L3.77069037,14.3 L2.54776377,14.3 C2.44585321,14.3 2.44585321,14.3 2.44585321,14.4 L2.85349542,15.6 L5.19743808,15.6 L5.19743808,0.6 L0.713373854,0.6 L0.611463304,9.8 L0.611463304,9.8 Z M2.03821101,9.2 L2.03821101,6.2 L3.87260092,6.2 L3.87260092,9.4 L2.03821101,9.4 L2.03821101,9.2 Z M3.87260092,1.9 L3.87260092,5 L2.03821101,5 L2.03821101,1.9 L3.87260092,1.9 Z",
"id": "XMLID_33_"
},
"children": []
},
{
"type": "element",
"name": "path",
"attributes": {
"d": "M13.3502821,5.9 L15.0827615,5.9 L15.0827615,4.7 L9.88532341,4.7 C9.98723396,4.3 10.0891445,3.8 10.3948762,3.5 L14.8789404,3.5 L14.8789404,2.3 L13.6560138,2.3 C13.7579243,1.6 14.1655665,0.7 14.1655665,0.7 C14.1655665,0.6 14.1655665,0.6 14.063656,0.6 L12.9426399,0.6 L12.4330872,2.3 L10.8025184,2.3 C10.9044289,1.6 11.0063395,0.8 11.2101606,0.1 C11.2101606,0 11.2101606,0 11.10825,0 C11.0063395,0 10.1910551,0 9.88532341,0 C9.78341286,0.9 9.68150231,1.7 9.37577066,2.4 L8.4585757,2.4 L7.94902295,0.7 L6.82800689,0.7 C6.72609634,0.7 6.72609634,0.7 6.72609634,0.8 C6.72609634,0.9 6.92991744,1.7 7.23564909,2.4 L6.01272249,2.4 L6.01272249,3.6 L8.8662179,3.6 C8.76430735,4 8.6623968,4.5 8.35666515,4.8 L5.60508028,4.8 L5.60508028,6 L7.74520185,6 C6.82800689,7.2 6.01272249,7.7 5.60508028,8 C5.60508028,8.1 5.60508028,9.3 5.60508028,9.3 C5.60508028,9.4 5.70699083,9.4 5.80890138,9.3 C6.21654359,9.2 6.72609634,8.8 7.03182799,8.4 L12.025445,8.4 L12.025445,10.2 L8.15284405,10.2 L8.2547546,9.1 C8.2547546,9 8.2547546,9 8.15284405,9 C8.0509335,9 6.92991744,9 6.92991744,9 L6.82800689,11.2 C6.82800689,11.3 6.82800689,11.3 6.92991744,11.3 C7.03182799,11.3 13.6560138,11.3 13.6560138,11.3 L13.6560138,14.5 L10.7006078,14.5 C10.5986973,14.5 10.5986973,14.5 10.5986973,14.6 L11.0063395,15.8 L15.2865826,15.8 L15.2865826,10.2 L13.6560138,10.2 L13.6560138,7.8 C14.2674771,8.3 14.8789404,8.8 15.4904037,9 C15.5923142,9.1 15.6942248,9.1 15.6942248,9 C15.6942248,9 15.6942248,7.8 15.6942248,7.7 C15.0827615,7.5 14.1655665,7 13.3502821,5.9 Z M11.7197133,5.9 C11.9235344,6.4 12.3311766,6.9 12.7388188,7.2 L8.35666515,7.2 C8.76430735,6.8 8.96812845,6.3 9.37577066,5.9 L11.7197133,5.9 L11.7197133,5.9 Z",
"id": "XMLID_30_"
},
"children": []
},
{
"type": "element",
"name": "path",
"attributes": {
"d": "M22.6241422,11.3 C22.6241422,11.3 21.4012156,12.2 20.178289,13.1 L20.178289,4.7 L16.9171514,4.7 L16.9171514,6.2 L18.7515413,6.2 L18.7515413,14.3 C18.2419886,14.7 17.8343464,14.8 17.8343464,14.8 L18.7515413,15.9 L22.7260528,13 L22.6241422,11.3 C22.9298739,11.3 22.8279633,11.2 22.6241422,11.3 Z",
"id": "XMLID_8_"
},
"children": []
},
{
"type": "element",
"name": "path",
"attributes": {
"d": "M18.9553624,3.4 L20.3821101,3.4 C20.5859312,3.4 20.5859312,3.3 20.5859312,3.3 L18.5477202,0.2 L17.019062,0.2 L16.9171514,0.3 C17.019062,0.4 18.9553624,3.4 18.9553624,3.4 Z",
"id": "XMLID_7_"
},
"children": []
},
{
"type": "element",
"name": "rect",
"attributes": {
"id": "XMLID_6_",
"x": "35.2610505",
"y": "0.9",
"width": "11.4139817",
"height": "1.5"
},
"children": []
},
{
"type": "element",
"name": "path",
"attributes": {
"d": "M39.4393831,7.8 L48.4075115,7.8 L48.4075115,6.3 L33.6304817,6.3 L33.6304817,7.8 L37.7069037,7.8 C36.7897088,10 34.8534083,15.4 34.7514978,15.5 C34.7514978,15.6 34.7514978,15.6 34.8534083,15.6 L47.5922271,15.6 C47.6941377,15.6 47.6941377,15.5 47.6941377,15.5 L45.8597478,10.6 L44.3310895,10.6 C44.229179,10.6 44.229179,10.7 44.229179,10.7 C44.229179,10.8 45.5540161,14.2 45.5540161,14.2 L37.197351,14.2 L39.4393831,7.8 Z",
"id": "XMLID_5_"
},
"children": []
}
]
},
{
"type": "element",
"name": "g",
"attributes": {
"id": "XMLID_19_"
},
"children": [
{
"type": "element",
"name": "path",
"attributes": {
"d": "M22.5,14.7 C22.1,15.1 21.3,15.7 19.9,15.7 C19.3,15.7 18.6,15.7 18.3,15.7 C17.9,15.7 14.9,15.7 11.3,15.7 C13.9,13.2 16.1,11.1 16.3,10.9 C16.5,10.7 17,10.2 17.5,9.8 C18.5,8.9 19.3,8.8 20,8.8 C21,8.8 21.8,9.2 22.5,9.8 C23.9,11.1 23.9,13.4 22.5,14.7 M24.2,8.2 C23.2,7.1 21.7,6.4 20.1,6.4 C18.7,6.4 17.5,6.9 16.4,7.7 C16,8.1 15.4,8.5 14.9,9.1 C14.5,9.5 5.9,17.9 5.9,17.9 C6.4,18 7,18 7.5,18 C8,18 18,18 18.4,18 C19.2,18 19.8,18 20.4,17.9 C21.7,17.8 23,17.3 24.1,16.3 C26.4,14.1 26.4,10.4 24.2,8.2 Z",
"id": "XMLID_22_",
"fill": "#00A3FF"
},
"children": []
},
{
"type": "element",
"name": "path",
"attributes": {
"d": "M10.2,7.6 C9.1,6.8 8,6.4 6.7,6.4 C5.1,6.4 3.6,7.1 2.6,8.2 C0.4,10.5 0.4,14.1 2.7,16.4 C3.7,17.3 4.7,17.8 5.9,17.9 L8.2,15.7 C7.8,15.7 7.3,15.7 6.9,15.7 C5.6,15.6 4.8,15.2 4.3,14.7 C2.9,13.3 2.9,11.1 4.2,9.7 C4.9,9 5.7,8.7 6.7,8.7 C7.3,8.7 8.2,8.8 9.1,9.7 C9.5,10.1 10.6,10.9 11,11.3 L11.1,11.3 L12.6,9.8 L12.6,9.7 C11.9,9 10.8,8.1 10.2,7.6",
"id": "XMLID_2_",
"fill": "#00C8DC"
},
"children": []
},
{
"type": "element",
"name": "path",
"attributes": {
"d": "M20.7,5.1 C19.6,2.1 16.7,0 13.4,0 C9.5,0 6.4,2.9 5.8,6.5 C6.1,6.5 6.4,6.4 6.8,6.4 C7.2,6.4 7.7,6.5 8.1,6.5 L8.1,6.5 C8.6,4 10.8,2.2 13.4,2.2 C15.6,2.2 17.5,3.5 18.4,5.4 C18.4,5.4 18.5,5.5 18.5,5.4 C19.2,5.3 20,5.1 20.7,5.1 C20.7,5.2 20.7,5.2 20.7,5.1",
"id": "XMLID_1_",
"fill": "#006EFF"
},
"children": []
}
]
}
]
}
]
}
]
},
"name": "TencentIcon"
}

View File

@ -2,7 +2,7 @@
// DON NOT EDIT IT MANUALLY
import * as React from 'react'
import data from './Checked.json'
import data from './TencentIcon.json'
import IconBase from '@/app/components/base/icons/IconBase'
import type { IconData } from '@/app/components/base/icons/IconBase'
@ -15,6 +15,6 @@ const Icon = (
},
) => <IconBase {...props} ref={ref} data={data as IconData} />
Icon.displayName = 'Checked'
Icon.displayName = 'TencentIcon'
export default Icon

View File

@ -0,0 +1,170 @@
{
"icon": {
"type": "element",
"name": "svg",
"attributes": {
"width": "80px",
"height": "18px",
"viewBox": "0 0 80 18",
"version": "1.1"
},
"isRootNode": true,
"children": [
{
"type": "element",
"name": "title",
"attributes": {},
"children": []
},
{
"type": "element",
"name": "g",
"attributes": {
"id": "页面-1",
"stroke": "none",
"stroke-width": "1",
"fill": "none",
"fill-rule": "evenodd"
},
"children": [
{
"type": "element",
"name": "g",
"attributes": {
"id": "logo",
"fill-rule": "nonzero"
},
"children": [
{
"type": "element",
"name": "g",
"attributes": {
"id": "XMLID_25_",
"transform": "translate(30.592488, 1.100000)",
"fill": "#253554"
},
"children": [
{
"type": "element",
"name": "path",
"attributes": {
"d": "M30.8788968,0.6 L21.8088578,0.6 L21.8088578,1.9 L24.5604427,1.9 L24.5604427,6.7 L21.2993051,6.7 L21.2993051,8 L24.5604427,8 L24.5604427,15.9 L26.089101,15.9 L26.089101,8 L29.5540597,8 L29.5540597,15.6 L32.3056445,15.6 L32.3056445,14.3 L31.0827179,14.3 L31.0827179,0.6 L30.8788968,0.6 Z M25.9871904,6.5 L25.9871904,1.9 L29.5540597,1.9 L29.5540597,6.7 L26.089101,6.7 L26.089101,6.5 L25.9871904,6.5 Z",
"id": "XMLID_38_"
},
"children": []
},
{
"type": "element",
"name": "polygon",
"attributes": {
"id": "XMLID_14_",
"points": "5.60508028 12.2 12.8407294 12.2 12.8407294 13.5 5.60508028 13.5"
},
"children": []
},
{
"type": "element",
"name": "path",
"attributes": {
"d": "M0.611463304,9.8 C0.611463304,12.1 0.509552753,14 0,15.5 C0,15.6 0,15.6 0.101910551,15.6 C0.101910551,15.6 1.22292661,15.6 1.42674771,15.6 C1.93630046,13.4 1.93630046,11.6 1.93630046,10.3 L3.77069037,10.3 L3.77069037,14.3 L2.54776377,14.3 C2.44585321,14.3 2.44585321,14.3 2.44585321,14.4 L2.85349542,15.6 L5.19743808,15.6 L5.19743808,0.6 L0.713373854,0.6 L0.611463304,9.8 L0.611463304,9.8 Z M2.03821101,9.2 L2.03821101,6.2 L3.87260092,6.2 L3.87260092,9.4 L2.03821101,9.4 L2.03821101,9.2 Z M3.87260092,1.9 L3.87260092,5 L2.03821101,5 L2.03821101,1.9 L3.87260092,1.9 Z",
"id": "XMLID_33_"
},
"children": []
},
{
"type": "element",
"name": "path",
"attributes": {
"d": "M13.3502821,5.9 L15.0827615,5.9 L15.0827615,4.7 L9.88532341,4.7 C9.98723396,4.3 10.0891445,3.8 10.3948762,3.5 L14.8789404,3.5 L14.8789404,2.3 L13.6560138,2.3 C13.7579243,1.6 14.1655665,0.7 14.1655665,0.7 C14.1655665,0.6 14.1655665,0.6 14.063656,0.6 L12.9426399,0.6 L12.4330872,2.3 L10.8025184,2.3 C10.9044289,1.6 11.0063395,0.8 11.2101606,0.1 C11.2101606,0 11.2101606,0 11.10825,0 C11.0063395,0 10.1910551,0 9.88532341,0 C9.78341286,0.9 9.68150231,1.7 9.37577066,2.4 L8.4585757,2.4 L7.94902295,0.7 L6.82800689,0.7 C6.72609634,0.7 6.72609634,0.7 6.72609634,0.8 C6.72609634,0.9 6.92991744,1.7 7.23564909,2.4 L6.01272249,2.4 L6.01272249,3.6 L8.8662179,3.6 C8.76430735,4 8.6623968,4.5 8.35666515,4.8 L5.60508028,4.8 L5.60508028,6 L7.74520185,6 C6.82800689,7.2 6.01272249,7.7 5.60508028,8 C5.60508028,8.1 5.60508028,9.3 5.60508028,9.3 C5.60508028,9.4 5.70699083,9.4 5.80890138,9.3 C6.21654359,9.2 6.72609634,8.8 7.03182799,8.4 L12.025445,8.4 L12.025445,10.2 L8.15284405,10.2 L8.2547546,9.1 C8.2547546,9 8.2547546,9 8.15284405,9 C8.0509335,9 6.92991744,9 6.92991744,9 L6.82800689,11.2 C6.82800689,11.3 6.82800689,11.3 6.92991744,11.3 C7.03182799,11.3 13.6560138,11.3 13.6560138,11.3 L13.6560138,14.5 L10.7006078,14.5 C10.5986973,14.5 10.5986973,14.5 10.5986973,14.6 L11.0063395,15.8 L15.2865826,15.8 L15.2865826,10.2 L13.6560138,10.2 L13.6560138,7.8 C14.2674771,8.3 14.8789404,8.8 15.4904037,9 C15.5923142,9.1 15.6942248,9.1 15.6942248,9 C15.6942248,9 15.6942248,7.8 15.6942248,7.7 C15.0827615,7.5 14.1655665,7 13.3502821,5.9 Z M11.7197133,5.9 C11.9235344,6.4 12.3311766,6.9 12.7388188,7.2 L8.35666515,7.2 C8.76430735,6.8 8.96812845,6.3 9.37577066,5.9 L11.7197133,5.9 L11.7197133,5.9 Z",
"id": "XMLID_30_"
},
"children": []
},
{
"type": "element",
"name": "path",
"attributes": {
"d": "M22.6241422,11.3 C22.6241422,11.3 21.4012156,12.2 20.178289,13.1 L20.178289,4.7 L16.9171514,4.7 L16.9171514,6.2 L18.7515413,6.2 L18.7515413,14.3 C18.2419886,14.7 17.8343464,14.8 17.8343464,14.8 L18.7515413,15.9 L22.7260528,13 L22.6241422,11.3 C22.9298739,11.3 22.8279633,11.2 22.6241422,11.3 Z",
"id": "XMLID_8_"
},
"children": []
},
{
"type": "element",
"name": "path",
"attributes": {
"d": "M18.9553624,3.4 L20.3821101,3.4 C20.5859312,3.4 20.5859312,3.3 20.5859312,3.3 L18.5477202,0.2 L17.019062,0.2 L16.9171514,0.3 C17.019062,0.4 18.9553624,3.4 18.9553624,3.4 Z",
"id": "XMLID_7_"
},
"children": []
},
{
"type": "element",
"name": "rect",
"attributes": {
"id": "XMLID_6_",
"x": "35.2610505",
"y": "0.9",
"width": "11.4139817",
"height": "1.5"
},
"children": []
},
{
"type": "element",
"name": "path",
"attributes": {
"d": "M39.4393831,7.8 L48.4075115,7.8 L48.4075115,6.3 L33.6304817,6.3 L33.6304817,7.8 L37.7069037,7.8 C36.7897088,10 34.8534083,15.4 34.7514978,15.5 C34.7514978,15.6 34.7514978,15.6 34.8534083,15.6 L47.5922271,15.6 C47.6941377,15.6 47.6941377,15.5 47.6941377,15.5 L45.8597478,10.6 L44.3310895,10.6 C44.229179,10.6 44.229179,10.7 44.229179,10.7 C44.229179,10.8 45.5540161,14.2 45.5540161,14.2 L37.197351,14.2 L39.4393831,7.8 Z",
"id": "XMLID_5_"
},
"children": []
}
]
},
{
"type": "element",
"name": "g",
"attributes": {
"id": "XMLID_19_"
},
"children": [
{
"type": "element",
"name": "path",
"attributes": {
"d": "M22.5,14.7 C22.1,15.1 21.3,15.7 19.9,15.7 C19.3,15.7 18.6,15.7 18.3,15.7 C17.9,15.7 14.9,15.7 11.3,15.7 C13.9,13.2 16.1,11.1 16.3,10.9 C16.5,10.7 17,10.2 17.5,9.8 C18.5,8.9 19.3,8.8 20,8.8 C21,8.8 21.8,9.2 22.5,9.8 C23.9,11.1 23.9,13.4 22.5,14.7 M24.2,8.2 C23.2,7.1 21.7,6.4 20.1,6.4 C18.7,6.4 17.5,6.9 16.4,7.7 C16,8.1 15.4,8.5 14.9,9.1 C14.5,9.5 5.9,17.9 5.9,17.9 C6.4,18 7,18 7.5,18 C8,18 18,18 18.4,18 C19.2,18 19.8,18 20.4,17.9 C21.7,17.8 23,17.3 24.1,16.3 C26.4,14.1 26.4,10.4 24.2,8.2 Z",
"id": "XMLID_22_",
"fill": "#00A3FF"
},
"children": []
},
{
"type": "element",
"name": "path",
"attributes": {
"d": "M10.2,7.6 C9.1,6.8 8,6.4 6.7,6.4 C5.1,6.4 3.6,7.1 2.6,8.2 C0.4,10.5 0.4,14.1 2.7,16.4 C3.7,17.3 4.7,17.8 5.9,17.9 L8.2,15.7 C7.8,15.7 7.3,15.7 6.9,15.7 C5.6,15.6 4.8,15.2 4.3,14.7 C2.9,13.3 2.9,11.1 4.2,9.7 C4.9,9 5.7,8.7 6.7,8.7 C7.3,8.7 8.2,8.8 9.1,9.7 C9.5,10.1 10.6,10.9 11,11.3 L11.1,11.3 L12.6,9.8 L12.6,9.7 C11.9,9 10.8,8.1 10.2,7.6",
"id": "XMLID_2_",
"fill": "#00C8DC"
},
"children": []
},
{
"type": "element",
"name": "path",
"attributes": {
"d": "M20.7,5.1 C19.6,2.1 16.7,0 13.4,0 C9.5,0 6.4,2.9 5.8,6.5 C6.1,6.5 6.4,6.4 6.8,6.4 C7.2,6.4 7.7,6.5 8.1,6.5 L8.1,6.5 C8.6,4 10.8,2.2 13.4,2.2 C15.6,2.2 17.5,3.5 18.4,5.4 C18.4,5.4 18.5,5.5 18.5,5.4 C19.2,5.3 20,5.1 20.7,5.1 C20.7,5.2 20.7,5.2 20.7,5.1",
"id": "XMLID_1_",
"fill": "#006EFF"
},
"children": []
}
]
}
]
}
]
}
]
},
"name": "TencentIconBig"
}

View File

@ -2,7 +2,7 @@
// DON NOT EDIT IT MANUALLY
import * as React from 'react'
import data from './Google.json'
import data from './TencentIconBig.json'
import IconBase from '@/app/components/base/icons/IconBase'
import type { IconData } from '@/app/components/base/icons/IconBase'
@ -15,6 +15,6 @@ const Icon = (
},
) => <IconBase {...props} ref={ref} data={data as IconData} />
Icon.displayName = 'Google'
Icon.displayName = 'TencentIconBig'
export default Icon

View File

@ -10,6 +10,8 @@ export { default as OpikIconBig } from './OpikIconBig'
export { default as OpikIcon } from './OpikIcon'
export { default as PhoenixIconBig } from './PhoenixIconBig'
export { default as PhoenixIcon } from './PhoenixIcon'
export { default as TencentIconBig } from './TencentIconBig'
export { default as TencentIcon } from './TencentIcon'
export { default as TracingIcon } from './TracingIcon'
export { default as WeaveIconBig } from './WeaveIconBig'
export { default as WeaveIcon } from './WeaveIcon'

View File

@ -1,20 +0,0 @@
// GENERATE BY script
// DON NOT EDIT IT MANUALLY
import * as React from 'react'
import data from './AlignLeft01.json'
import IconBase from '@/app/components/base/icons/IconBase'
import type { IconData } from '@/app/components/base/icons/IconBase'
const Icon = (
{
ref,
...props
}: React.SVGProps<SVGSVGElement> & {
ref?: React.RefObject<React.RefObject<HTMLOrSVGElement>>;
},
) => <IconBase {...props} ref={ref} data={data as IconData} />
Icon.displayName = 'AlignLeft01'
export default Icon

View File

@ -1,20 +0,0 @@
// GENERATE BY script
// DON NOT EDIT IT MANUALLY
import * as React from 'react'
import data from './AlignRight01.json'
import IconBase from '@/app/components/base/icons/IconBase'
import type { IconData } from '@/app/components/base/icons/IconBase'
const Icon = (
{
ref,
...props
}: React.SVGProps<SVGSVGElement> & {
ref?: React.RefObject<React.RefObject<HTMLOrSVGElement>>;
},
) => <IconBase {...props} ref={ref} data={data as IconData} />
Icon.displayName = 'AlignRight01'
export default Icon

View File

@ -1,20 +0,0 @@
// GENERATE BY script
// DON NOT EDIT IT MANUALLY
import * as React from 'react'
import data from './Grid01.json'
import IconBase from '@/app/components/base/icons/IconBase'
import type { IconData } from '@/app/components/base/icons/IconBase'
const Icon = (
{
ref,
...props
}: React.SVGProps<SVGSVGElement> & {
ref?: React.RefObject<React.RefObject<HTMLOrSVGElement>>;
},
) => <IconBase {...props} ref={ref} data={data as IconData} />
Icon.displayName = 'Grid01'
export default Icon

View File

@ -1,4 +1 @@
export { default as AlignLeft01 } from './AlignLeft01'
export { default as AlignRight01 } from './AlignRight01'
export { default as Grid01 } from './Grid01'
export { default as LayoutGrid02 } from './LayoutGrid02'

View File

@ -1,20 +0,0 @@
// GENERATE BY script
// DON NOT EDIT IT MANUALLY
import * as React from 'react'
import data from './Route.json'
import IconBase from '@/app/components/base/icons/IconBase'
import type { IconData } from '@/app/components/base/icons/IconBase'
const Icon = (
{
ref,
...props
}: React.SVGProps<SVGSVGElement> & {
ref?: React.RefObject<React.RefObject<HTMLOrSVGElement>>;
},
) => <IconBase {...props} ref={ref} data={data as IconData} />
Icon.displayName = 'Route'
export default Icon

View File

@ -1 +0,0 @@
export { default as Route } from './Route'

View File

@ -1,20 +0,0 @@
// GENERATE BY script
// DON NOT EDIT IT MANUALLY
import * as React from 'react'
import data from './User01.json'
import IconBase from '@/app/components/base/icons/IconBase'
import type { IconData } from '@/app/components/base/icons/IconBase'
const Icon = (
{
ref,
...props
}: React.SVGProps<SVGSVGElement> & {
ref?: React.RefObject<React.RefObject<HTMLOrSVGElement>>;
},
) => <IconBase {...props} ref={ref} data={data as IconData} />
Icon.displayName = 'User01'
export default Icon

View File

@ -1,20 +0,0 @@
// GENERATE BY script
// DON NOT EDIT IT MANUALLY
import * as React from 'react'
import data from './Users01.json'
import IconBase from '@/app/components/base/icons/IconBase'
import type { IconData } from '@/app/components/base/icons/IconBase'
const Icon = (
{
ref,
...props
}: React.SVGProps<SVGSVGElement> & {
ref?: React.RefObject<React.RefObject<HTMLOrSVGElement>>;
},
) => <IconBase {...props} ref={ref} data={data as IconData} />
Icon.displayName = 'Users01'
export default Icon

View File

@ -1,2 +0,0 @@
export { default as User01 } from './User01'
export { default as Users01 } from './Users01'

View File

@ -1,20 +0,0 @@
// GENERATE BY script
// DON NOT EDIT IT MANUALLY
import * as React from 'react'
import data from './Stars02.json'
import IconBase from '@/app/components/base/icons/IconBase'
import type { IconData } from '@/app/components/base/icons/IconBase'
const Icon = (
{
ref,
...props
}: React.SVGProps<SVGSVGElement> & {
ref?: React.RefObject<React.RefObject<HTMLOrSVGElement>>;
},
) => <IconBase {...props} ref={ref} data={data as IconData} />
Icon.displayName = 'Stars02'
export default Icon

View File

@ -1 +0,0 @@
export { default as Stars02 } from './Stars02'

View File

@ -1,20 +0,0 @@
// GENERATE BY script
// DON NOT EDIT IT MANUALLY
import * as React from 'react'
import data from './ChevronDown.json'
import IconBase from '@/app/components/base/icons/IconBase'
import type { IconData } from '@/app/components/base/icons/IconBase'
const Icon = (
{
ref,
...props
}: React.SVGProps<SVGSVGElement> & {
ref?: React.RefObject<React.RefObject<HTMLOrSVGElement>>;
},
) => <IconBase {...props} ref={ref} data={data as IconData} />
Icon.displayName = 'ChevronDown'
export default Icon

View File

@ -1,20 +0,0 @@
// GENERATE BY script
// DON NOT EDIT IT MANUALLY
import * as React from 'react'
import data from './HighPriority.json'
import IconBase from '@/app/components/base/icons/IconBase'
import type { IconData } from '@/app/components/base/icons/IconBase'
const Icon = (
{
ref,
...props
}: React.SVGProps<SVGSVGElement> & {
ref?: React.RefObject<React.RefObject<HTMLOrSVGElement>>;
},
) => <IconBase {...props} ref={ref} data={data as IconData} />
Icon.displayName = 'HighPriority'
export default Icon

View File

@ -1,2 +0,0 @@
export { default as ChevronDown } from './ChevronDown'
export { default as HighPriority } from './HighPriority'

View File

@ -1,20 +0,0 @@
// GENERATE BY script
// DON NOT EDIT IT MANUALLY
import * as React from 'react'
import data from './Grid01.json'
import IconBase from '@/app/components/base/icons/IconBase'
import type { IconData } from '@/app/components/base/icons/IconBase'
const Icon = (
{
ref,
...props
}: React.SVGProps<SVGSVGElement> & {
ref?: React.RefObject<React.RefObject<HTMLOrSVGElement>>;
},
) => <IconBase {...props} ref={ref} data={data as IconData} />
Icon.displayName = 'Grid01'
export default Icon

View File

@ -1 +0,0 @@
export { default as Grid01 } from './Grid01'

View File

@ -767,8 +767,8 @@ The text generation application offers non-session support and is ideal for tran
<Col>
<CodeGroup
title="Request"
tag="POST"
label="/meta"
tag="GET"
label="/site"
targetCode={`curl -X GET '${props.appDetail.api_base_url}/site' \\
-H 'Authorization: Bearer {api_key}'`}
/>

View File

@ -764,8 +764,8 @@ import { Row, Col, Properties, Property, Heading, SubProperty, Paragraph } from
<Col>
<CodeGroup
title="Request"
tag="POST"
label="/meta"
tag="GET"
label="/site"
targetCode={`curl -X GET '${props.appDetail.api_base_url}/site' \\
-H 'Authorization: Bearer {api_key}'`}
/>

View File

@ -728,8 +728,8 @@ import { Row, Col, Properties, Property, Heading, SubProperty } from '../md.tsx'
<Col>
<CodeGroup
title="Request"
tag="POST"
label="/meta"
tag="GET"
label="/site"
targetCode={`curl -X GET '${props.appDetail.api_base_url}/site' \\
-H 'Authorization: Bearer {api_key}'`}
/>

View File

@ -199,7 +199,7 @@ Chat applications support session persistence, allowing previous chat history to
--header 'Authorization: Bearer {api_key}' \\
--header 'Content-Type: application/json' \\
--data-raw '{
"inputs": ${JSON.stringify(props.inputs)},
"inputs": ${JSON.stringify(props.inputs)},
"query": "What are the specs of the iPhone 13 Pro Max?",
"response_mode": "streaming",
"conversation_id": "",
@ -1182,7 +1182,7 @@ Chat applications support session persistence, allowing previous chat history to
--header 'Content-Type: application/json' \\
--data-raw '{
"value": "Updated Value",
"user": "abc-123"
"user": "abc-123"
}'`}
/>
@ -1599,8 +1599,8 @@ Chat applications support session persistence, allowing previous chat history to
<Col>
<CodeGroup
title="Request"
tag="POST"
label="/meta"
tag="GET"
label="/site"
targetCode={`curl -X GET '${props.appDetail.api_base_url}/site' \\
-H 'Authorization: Bearer {api_key}'`}
/>

View File

@ -1586,8 +1586,8 @@ import { Row, Col, Properties, Property, Heading, SubProperty, Paragraph } from
<Col>
<CodeGroup
title="リクエスト"
tag="POST"
label="/meta"
tag="GET"
label="/site"
targetCode={`curl -X GET '${props.appDetail.api_base_url}/site' \\
-H 'Authorization: Bearer {api_key}'`}
/>

View File

@ -1188,7 +1188,7 @@ import { Row, Col, Properties, Property, Heading, SubProperty } from '../md.tsx'
--header 'Content-Type: application/json' \\
--data-raw '{
"value": "Updated Value",
"user": "abc-123"
"user": "abc-123"
}'`}
/>
@ -1579,8 +1579,8 @@ import { Row, Col, Properties, Property, Heading, SubProperty } from '../md.tsx'
<Col>
<CodeGroup
title="Request"
tag="POST"
label="/meta"
tag="GET"
label="/site"
targetCode={`curl -X GET '${props.appDetail.api_base_url}/site' \\
-H 'Authorization: Bearer {api_key}'`}
/>

View File

@ -1025,8 +1025,8 @@ Workflow applications offers non-session support and is ideal for translation, a
<Col>
<CodeGroup
title="Request"
tag="POST"
label="/meta"
tag="GET"
label="/site"
targetCode={`curl -X GET '${props.appDetail.api_base_url}/site' \\
-H 'Authorization: Bearer {api_key}'`}
/>

View File

@ -1021,8 +1021,8 @@ import { Row, Col, Properties, Property, Heading, SubProperty, Paragraph } from
<Col>
<CodeGroup
title="Request"
tag="POST"
label="/meta"
tag="GET"
label="/site"
targetCode={`curl -X GET '${props.appDetail.api_base_url}/site' \\
-H 'Authorization: Bearer {api_key}'`}
/>

View File

@ -182,7 +182,7 @@ Workflow 应用无会话支持,适合用于翻译/文章写作/总结 AI 等
--header 'Authorization: Bearer {api_key}' \\
--header 'Content-Type: application/json' \\
--data-raw '{
"inputs": ${JSON.stringify(props.inputs)},
"inputs": ${JSON.stringify(props.inputs)},
"response_mode": "streaming",
"user": "abc-123"
}'`}
@ -1012,8 +1012,8 @@ Workflow 应用无会话支持,适合用于翻译/文章写作/总结 AI 等
<Col>
<CodeGroup
title="Request"
tag="POST"
label="/meta"
tag="GET"
label="/site"
targetCode={`curl -X GET '${props.appDetail.api_base_url}/site' \\
-H 'Authorization: Bearer {api_key}'`}
/>

View File

@ -20,7 +20,9 @@ import type { SiteInfo } from '@/models/share'
import { TEXT_GENERATION_TIMEOUT_MS } from '@/config'
import {
getFilesInLogs,
getProcessedFiles,
} from '@/app/components/base/file-uploader/utils'
import type { FileEntity } from '@/app/components/base/file-uploader/types'
import { formatBooleanInputs } from '@/utils/model-config'
export type IResultProps = {
@ -160,8 +162,22 @@ const Result: FC<IResultProps> = ({
if (!checkCanSend())
return
// Process inputs: convert file entities to API format
const processedInputs = { ...formatBooleanInputs(promptConfig?.prompt_variables, inputs) }
promptConfig?.prompt_variables.forEach((variable) => {
const value = processedInputs[variable.key]
if (variable.type === 'file' && value && typeof value === 'object' && !Array.isArray(value)) {
// Convert single file entity to API format
processedInputs[variable.key] = getProcessedFiles([value as FileEntity])[0]
}
else if (variable.type === 'file-list' && Array.isArray(value) && value.length > 0) {
// Convert file entity array to API format
processedInputs[variable.key] = getProcessedFiles(value as FileEntity[])
}
})
const data: Record<string, any> = {
inputs: formatBooleanInputs(promptConfig?.prompt_variables, inputs),
inputs: processedInputs,
}
if (visionConfig.enabled && completionFiles && completionFiles?.length > 0) {
data.files = completionFiles.map((item) => {

View File

@ -15,7 +15,6 @@ import { DEFAULT_VALUE_MAX_LEN } from '@/config'
import TextGenerationImageUploader from '@/app/components/base/image-uploader/text-generation-image-uploader'
import type { VisionFile, VisionSettings } from '@/types/app'
import { FileUploaderInAttachmentWrapper } from '@/app/components/base/file-uploader'
import { getProcessedFiles } from '@/app/components/base/file-uploader/utils'
import useBreakpoints, { MediaType } from '@/hooks/use-breakpoints'
import cn from '@/utils/classnames'
import BoolInput from '@/app/components/workflow/nodes/_base/components/before-run-form/bool-input'
@ -82,9 +81,9 @@ const RunOnce: FC<IRunOnceProps> = ({
else if (item.type === 'checkbox')
newInputs[item.key] = item.default || false
else if (item.type === 'file')
newInputs[item.key] = item.default
newInputs[item.key] = undefined
else if (item.type === 'file-list')
newInputs[item.key] = item.default || []
newInputs[item.key] = []
else
newInputs[item.key] = undefined
})
@ -148,8 +147,8 @@ const RunOnce: FC<IRunOnceProps> = ({
)}
{item.type === 'file' && (
<FileUploaderInAttachmentWrapper
value={inputs[item.key] ? [inputs[item.key]] : []}
onChange={(files) => { handleInputsChange({ ...inputsRef.current, [item.key]: getProcessedFiles(files)[0] }) }}
value={(inputs[item.key] && typeof inputs[item.key] === 'object') ? [inputs[item.key]] : []}
onChange={(files) => { handleInputsChange({ ...inputsRef.current, [item.key]: files[0] }) }}
fileConfig={{
...item.config,
fileUploadConfig: (visionConfig as any).fileUploadConfig,
@ -158,8 +157,8 @@ const RunOnce: FC<IRunOnceProps> = ({
)}
{item.type === 'file-list' && (
<FileUploaderInAttachmentWrapper
value={inputs[item.key]}
onChange={(files) => { handleInputsChange({ ...inputsRef.current, [item.key]: getProcessedFiles(files) }) }}
value={Array.isArray(inputs[item.key]) ? inputs[item.key] : []}
onChange={(files) => { handleInputsChange({ ...inputsRef.current, [item.key]: files }) }}
fileConfig={{
...item.config,
fileUploadConfig: (visionConfig as any).fileUploadConfig,

View File

@ -160,6 +160,10 @@ const translation = {
title: 'Cloud-Monitor',
description: 'Die vollständig verwaltete und wartungsfreie Observability-Plattform von Alibaba Cloud ermöglicht eine sofortige Überwachung, Verfolgung und Bewertung von Dify-Anwendungen.',
},
tencent: {
title: 'Tencent APM',
description: 'Tencent Application Performance Monitoring bietet umfassendes Tracing und multidimensionale Analyse für LLM-Anwendungen.',
},
},
answerIcon: {
descriptionInExplore: 'Gibt an, ob das web app Symbol zum Ersetzen 🤖 in Explore verwendet werden soll',

View File

@ -183,6 +183,10 @@ const translation = {
title: 'Cloud Monitor',
description: 'The fully-managed and maintenance-free observability platform provided by Alibaba Cloud, enables out-of-the-box monitoring, tracing, and evaluation of Dify applications.',
},
tencent: {
title: 'Tencent APM',
description: 'Tencent Application Performance Monitoring provides comprehensive tracing and multi-dimensional analysis for LLM applications.',
},
inUse: 'In use',
configProvider: {
title: 'Config ',

View File

@ -163,6 +163,10 @@ const translation = {
title: 'Monitor de Nubes',
description: 'La plataforma de observabilidad totalmente gestionada y sin mantenimiento proporcionada por Alibaba Cloud, permite la monitorización, trazado y evaluación de aplicaciones Dify de manera inmediata.',
},
tencent: {
title: 'Tencent APM',
description: 'Tencent Application Performance Monitoring proporciona rastreo integral y análisis multidimensional para aplicaciones LLM.',
},
},
answerIcon: {
title: 'Usar el icono de la aplicación web para reemplazar 🤖',

View File

@ -171,6 +171,10 @@ const translation = {
title: 'نظارت بر ابر',
description: 'پلتفرم مشاهده‌پذیری کاملاً مدیریت‌شده و بدون نیاز به نگهداری که توسط Alibaba Cloud ارائه شده، امکان نظارت، ردیابی و ارزیابی برنامه‌های Dify را به‌صورت آماده و با تنظیمات اولیه فراهم می‌کند.',
},
tencent: {
title: 'تنست ای‌پی‌ام',
description: 'نظارت بر عملکرد برنامه‌های Tencent تحلیل‌های جامع و ردیابی چندبعدی برای برنامه‌های LLM ارائه می‌دهد.',
},
},
answerIcon: {
descriptionInExplore: 'آیا از نماد web app برای جایگزینی 🤖 در Explore استفاده کنیم یا خیر',

View File

@ -163,6 +163,10 @@ const translation = {
title: 'Surveillance Cloud',
description: 'La plateforme d\'observabilité entièrement gérée et sans maintenance fournie par Alibaba Cloud permet une surveillance, un traçage et une évaluation prêts à l\'emploi des applications Dify.',
},
tencent: {
title: 'Tencent APM',
description: 'Tencent Application Performance Monitoring fournit une traçabilité complète et une analyse multidimensionnelle pour les applications LLM.',
},
},
answerIcon: {
description: 'Sil faut utiliser licône web app pour remplacer 🤖 dans lapplication partagée',

View File

@ -163,6 +163,10 @@ const translation = {
title: 'क्लाउड मॉनिटर',
description: 'अलीबाबा क्लाउड द्वारा प्रदान की गई पूरी तरह से प्रबंधित और रखरखाव-मुक्त अवलोकन प्लेटफ़ॉर्म, Dify अनुप्रयोगों की स्वचालित निगरानी, ट्रेसिंग और मूल्यांकन का सक्षम बनाता है।',
},
tencent: {
title: 'टेनसेंट एपीएम',
description: 'Tencent एप्लिकेशन परफॉर्मेंस मॉनिटरिंग LLM एप्लिकेशन के लिए व्यापक ट्रेसिंग और बहु-आयामी विश्लेषण प्रदान करता है।',
},
},
answerIcon: {
title: 'बदलने 🤖 के लिए web app चिह्न का उपयोग करें',

View File

@ -155,6 +155,10 @@ const translation = {
description: 'Mengonfigurasi penyedia LLMOps Pihak Ketiga dan melacak performa aplikasi.',
inUse: 'Sedang digunakan',
tracingDescription: 'Tangkap konteks lengkap eksekusi aplikasi, termasuk panggilan LLM, konteks, perintah, permintaan HTTP, dan lainnya, ke platform pelacakan pihak ketiga.',
tencent: {
title: 'Tencent APM',
description: 'Tencent Application Performance Monitoring menyediakan pelacakan komprehensif dan analisis multi-dimensi untuk aplikasi LLM.',
},
},
appSelector: {
placeholder: 'Pilih aplikasi...',

View File

@ -169,6 +169,10 @@ const translation = {
title: 'Monitoraggio Cloud',
description: 'La piattaforma di osservabilità completamente gestita e senza manutenzione fornita da Alibaba Cloud consente il monitoraggio, il tracciamento e la valutazione delle applicazioni Dify fin da subito.',
},
tencent: {
title: 'Tencent APM',
description: 'Tencent Application Performance Monitoring fornisce tracciamento completo e analisi multidimensionale per le applicazioni LLM.',
},
},
answerIcon: {
description: 'Se utilizzare l\'icona web app per la sostituzione 🤖 nell\'applicazione condivisa',

View File

@ -175,6 +175,10 @@ const translation = {
title: 'クラウドモニター',
description: 'Alibaba Cloud が提供する完全管理型でメンテナンスフリーの可観測性プラットフォームは、Dify アプリケーションの即時監視、トレース、評価を可能にします。',
},
tencent: {
title: 'テンセントAPM',
description: 'Tencent アプリケーションパフォーマンスモニタリングは、LLM アプリケーションに対して包括的なトレーシングと多次元分析を提供します。',
},
},
answerIcon: {
title: 'Web アプリアイコンを使用して🤖を置き換える',

View File

@ -178,6 +178,10 @@ const translation = {
title: '클라우드 모니터',
description: '알리바바 클라우드에서 제공하는 완전 관리형 및 유지보수가 필요 없는 가시성 플랫폼은 Dify 애플리케이션의 모니터링, 추적 및 평가를 즉시 사용할 수 있도록 지원합니다.',
},
tencent: {
title: '텐센트 APM',
description: '텐센트 애플리케이션 성능 모니터링은 LLM 애플리케이션에 대한 포괄적인 추적 및 다차원 분석을 제공합니다.',
},
},
answerIcon: {
description:

View File

@ -164,6 +164,10 @@ const translation = {
title: 'Monitor Chmury',
description: 'W pełni zarządzana i wolna od konserwacji platforma obserwowalności oferowana przez Alibaba Cloud umożliwia gotowe monitorowanie, śledzenie i oceny aplikacji Dify.',
},
tencent: {
title: 'Tencent APM',
description: 'Tencent Application Performance Monitoring zapewnia kompleksowe śledzenie i wielowymiarową analizę dla aplikacji LLM.',
},
},
answerIcon: {
description: 'Czy w aplikacji udostępnionej ma być używana ikona aplikacji internetowej do zamiany 🤖.',

View File

@ -163,6 +163,10 @@ const translation = {
title: 'Monitoramento em Nuvem',
description: 'A plataforma de observabilidade totalmente gerenciada e sem manutenção fornecida pela Alibaba Cloud, permite monitoramento, rastreamento e avaliação prontos para uso de aplicações Dify.',
},
tencent: {
title: 'Tencent APM',
description: 'O Monitoramento de Desempenho de Aplicações da Tencent fornece rastreamento abrangente e análise multidimensional para aplicações LLM.',
},
},
answerIcon: {
descriptionInExplore: 'Se o ícone do web app deve ser usado para substituir 🤖 no Explore',

View File

@ -163,6 +163,10 @@ const translation = {
description: 'Platforma de observabilitate SaaS oferită de Alibaba Cloud permite monitorizarea, urmărirea și evaluarea aplicațiilor Dify din cutie.',
title: 'Monitorizarea Cloud',
},
tencent: {
title: 'Tencent APM',
description: 'Monitorizarea Performanței Aplicațiilor Tencent oferă trasabilitate cuprinzătoare și analiză multidimensională pentru aplicațiile LLM.',
},
},
answerIcon: {
descriptionInExplore: 'Dacă să utilizați pictograma web app pentru a înlocui 🤖 în Explore',

View File

@ -171,6 +171,10 @@ const translation = {
title: 'Облачный монитор',
description: 'Полностью управляемая и не требующая обслуживания платформа наблюдения, предоставляемая Alibaba Cloud, обеспечивает мониторинг, трассировку и оценку приложений Dify из коробки.',
},
tencent: {
title: 'Tencent APM',
description: 'Мониторинг производительности приложений Tencent предоставляет всестороннее отслеживание и многомерный анализ для приложений LLM.',
},
},
answerIcon: {
title: 'Использование значка web app для замены 🤖',

View File

@ -176,6 +176,10 @@ const translation = {
title: 'Oblačni nadzor',
description: 'Popolnoma upravljana in brez vzdrževanja platforma za opazovanje, ki jo zagotavlja Alibaba Cloud, omogoča takojšnje spremljanje, sledenje in ocenjevanje aplikacij Dify.',
},
tencent: {
description: 'Tencent Application Performance Monitoring zagotavlja celovito sledenje in večdimenzionalno analizo za aplikacije LLM.',
title: 'Tencent APM',
},
},
mermaid: {
handDrawn: 'Ročno narisano',

View File

@ -172,6 +172,10 @@ const translation = {
title: 'การตรวจสอบคลาวด์',
description: 'แพลตฟอร์มการสังเกตการณ์ที่จัดการโดย Alibaba Cloud ซึ่งไม่ต้องดูแลและบำรุงรักษา ช่วยให้สามารถติดตาม ตรวจสอบ และประเมินแอปพลิเคชัน Dify ได้ทันที',
},
tencent: {
title: 'Tencent APM',
description: 'การติดตามประสิทธิภาพแอปพลิเคชันของ Tencent มอบการตรวจสอบแบบครบวงจรและการวิเคราะห์หลายมิติสำหรับแอป LLM',
},
},
mermaid: {
handDrawn: 'วาดด้วยมือ',

View File

@ -167,6 +167,10 @@ const translation = {
title: 'Bulut İzleyici',
description: 'Alibaba Cloud tarafından sağlanan tamamen yönetilen ve bakım gerektirmeyen gözlemleme platformu, Dify uygulamalarının kutudan çıkar çıkmaz izlenmesi, takip edilmesi ve değerlendirilmesine olanak tanır.',
},
tencent: {
title: 'Tencent APM',
description: 'Tencent Uygulama Performans İzleme, LLM uygulamaları için kapsamlı izleme ve çok boyutlu analiz sağlar.',
},
},
answerIcon: {
descriptionInExplore: 'Keşfet\'te değiştirilecek 🤖 web app simgesinin kullanılıp kullanılmayacağı',

View File

@ -163,6 +163,10 @@ const translation = {
title: 'Моніторинг Хмари',
description: 'Повністю керовані та без обслуговування платформи спостереження, надані Alibaba Cloud, дозволяють миттєвий моніторинг, трасування та оцінку застосувань Dify.',
},
tencent: {
title: 'Tencent APM',
description: 'Сервіс моніторингу продуктивності додатків Tencent забезпечує комплексне трасування та багатовимірний аналіз додатків LLM.',
},
},
answerIcon: {
title: 'Використовуйте піктограму web app для заміни 🤖',

View File

@ -163,6 +163,10 @@ const translation = {
title: 'Giám sát Đám mây',
description: 'Nền tảng quan sát được quản lý hoàn toàn và không cần bảo trì do Alibaba Cloud cung cấp, cho phép giám sát, theo dõi và đánh giá các ứng dụng Dify ngay lập tức.',
},
tencent: {
title: 'Tencent APM',
description: 'Giám sát hiệu suất ứng dụng của Tencent cung cấp khả năng theo dõi toàn diện và phân tích đa chiều cho các ứng dụng LLM.',
},
},
answerIcon: {
description: 'Có nên sử dụng biểu tượng web app để thay thế 🤖 trong ứng dụng được chia sẻ hay không',

View File

@ -192,6 +192,10 @@ const translation = {
title: '云监控',
description: '阿里云提供的全托管免运维可观测平台一键开启Dify应用的监控追踪和评估',
},
tencent: {
title: '腾讯云 APM',
description: '腾讯云应用性能监控,提供 LLM 应用全链路追踪和多维分析',
},
},
appSelector: {
label: '应用',

View File

@ -20,7 +20,7 @@ const translation = {
save: '保存',
yes: '是',
no: '否',
deleteConfirmTitle: '删除?',
deleteConfirmTitle: '删除',
confirmAction: '请确认您的操作。',
saveAndEnable: '保存并启用',
edit: '编辑',

View File

@ -162,6 +162,10 @@ const translation = {
title: '雲端監控',
description: '阿里雲提供的完全管理且無需維護的可觀察性平台,支持即時監控、追蹤和評估 Dify 應用程序。',
},
tencent: {
title: '騰訊 APM',
description: '騰訊應用性能監控為大型語言模型應用提供全面的追蹤和多維分析。',
},
},
answerIcon: {
descriptionInExplore: '是否使用 web app 圖示在 Explore 中取代 🤖',

288
web/knip.config.ts Normal file
View File

@ -0,0 +1,288 @@
import type { KnipConfig } from 'knip'
/**
* Knip Configuration for Dead Code Detection
*
* This configuration helps identify unused files, exports, and dependencies
* in the Dify web application (Next.js 15 + TypeScript + React 19).
*
* ⚠️ SAFETY FIRST: This configuration is designed to be conservative and
* avoid false positives that could lead to deleting actively used code.
*
* @see https://knip.dev/reference/configuration
*/
const config: KnipConfig = {
// ============================================================================
// Next.js Framework Configuration
// ============================================================================
// Configure entry points specific to Next.js application structure.
// These files are automatically treated as entry points by the framework.
next: {
entry: [
// Next.js App Router pages (must exist for routing)
'app/**/page.tsx',
'app/**/layout.tsx',
'app/**/loading.tsx',
'app/**/error.tsx',
'app/**/not-found.tsx',
'app/**/template.tsx',
'app/**/default.tsx',
// Middleware (runs before every route)
'middleware.ts',
// Configuration files
'next.config.js',
'tailwind.config.js',
'tailwind-common-config.ts',
'postcss.config.js',
// Testing configuration
'jest.config.ts',
'jest.setup.ts',
// Linting configuration
'eslint.config.mjs',
],
},
// ============================================================================
// Global Entry Points
// ============================================================================
// Files that serve as entry points for the application.
// The '!' suffix means these patterns take precedence and are always included.
entry: [
// Next.js App Router patterns (high priority)
'app/**/page.tsx!',
'app/**/layout.tsx!',
'app/**/loading.tsx!',
'app/**/error.tsx!',
'app/**/not-found.tsx!',
'app/**/template.tsx!',
'app/**/default.tsx!',
// Core configuration files
'middleware.ts!',
'next.config.js!',
'tailwind.config.js!',
'tailwind-common-config.ts!',
'postcss.config.js!',
// Testing setup
'jest.config.ts!',
'jest.setup.ts!',
// Linting setup
'eslint.config.mjs!',
// ========================================================================
// 🔒 CRITICAL: Global Initializers and Providers
// ========================================================================
// These files are imported by root layout.tsx and provide global functionality.
// Even if not directly imported elsewhere, they are essential for app initialization.
// Browser initialization (runs on client startup)
'app/components/browser-initializer.tsx!',
'app/components/sentry-initializer.tsx!',
'app/components/swr-initializer.tsx!',
// i18n initialization (server and client)
'app/components/i18n.tsx!',
'app/components/i18n-server.tsx!',
// Route prefix handling (used in root layout)
'app/routePrefixHandle.tsx!',
// ========================================================================
// 🔒 CRITICAL: Context Providers
// ========================================================================
// Context providers might be used via React Context API and imported dynamically.
// Protecting all context files to prevent breaking the provider chain.
'context/**/*.ts?(x)!',
// Component-level contexts (also used via React.useContext)
'app/components/**/*.context.ts?(x)!',
// ========================================================================
// 🔒 CRITICAL: State Management Stores
// ========================================================================
// Zustand stores might be imported dynamically or via hooks.
// These are often imported at module level, so they should be protected.
'app/components/**/*.store.ts?(x)!',
'context/**/*.store.ts?(x)!',
// ========================================================================
// 🔒 CRITICAL: Provider Components
// ========================================================================
// Provider components wrap the app and provide global state/functionality
'app/components/**/*.provider.ts?(x)!',
'context/**/*.provider.ts?(x)!',
// ========================================================================
// Development tools
// ========================================================================
// Storybook configuration
'.storybook/**/*',
],
// ============================================================================
// Project Files to Analyze
// ============================================================================
// Glob patterns for files that should be analyzed for unused code.
// Excludes test files to avoid false positives.
project: [
'**/*.{js,jsx,ts,tsx,mjs,cjs}',
],
// ============================================================================
// Ignored Files and Directories
// ============================================================================
// Files and directories that should be completely excluded from analysis.
// These typically contain:
// - Test files
// - Internationalization files (loaded dynamically)
// - Static assets
// - Build outputs
// - External libraries
ignore: [
// Test files and directories
'**/__tests__/**',
'**/*.spec.{ts,tsx}',
'**/*.test.{ts,tsx}',
// ========================================================================
// 🔒 CRITICAL: i18n Files (Dynamically Loaded)
// ========================================================================
// Internationalization files are loaded dynamically at runtime via i18next.
// Pattern: import(`@/i18n/${locale}/messages`)
// These will NEVER show up in static analysis but are essential!
'i18n/**',
// ========================================================================
// 🔒 CRITICAL: Static Assets
// ========================================================================
// Static assets are referenced by URL in the browser, not via imports.
// Examples: /logo.png, /icons/*, /embed.js
'public/**',
// Build outputs and caches
'node_modules/**',
'.next/**',
'coverage/**',
// Development tools
'**/*.stories.{ts,tsx}',
// ========================================================================
// 🔒 Utility scripts (not part of application runtime)
// ========================================================================
// These scripts are run manually (e.g., pnpm gen-icons, pnpm check-i18n)
// and are not imported by the application code.
'scripts/**',
'bin/**',
'i18n-config/**',
// Icon generation script (generates components, not used in runtime)
'app/components/base/icons/script.mjs',
],
// ============================================================================
// Ignored Dependencies
// ============================================================================
// Dependencies that are used but not directly imported in code.
// These are typically:
// - Build tools
// - Plugins loaded by configuration files
// - CLI tools
ignoreDependencies: [
// ========================================================================
// Next.js plugins (loaded by next.config.js)
// ========================================================================
'next-pwa',
'@next/bundle-analyzer',
'@next/mdx',
// ========================================================================
// Build tools (used by webpack/next.js build process)
// ========================================================================
'code-inspector-plugin',
// ========================================================================
// Development and translation tools (used by scripts)
// ========================================================================
'bing-translate-api',
'uglify-js',
'magicast',
],
// ============================================================================
// Export Analysis Configuration
// ============================================================================
// Configure how exports are analyzed
// Ignore exports that are only used within the same file
// (e.g., helper functions used internally in the same module)
ignoreExportsUsedInFile: true,
// ⚠️ SAFETY: Include exports from entry files in the analysis
// This helps find unused public APIs, but be careful with:
// - Context exports (useContext hooks)
// - Store exports (useStore hooks)
// - Type exports (might be used in other files)
includeEntryExports: true,
// ============================================================================
// Ignored Binaries
// ============================================================================
// Binary executables that are used but not listed in package.json
ignoreBinaries: [
'only-allow', // Used in preinstall script to enforce pnpm usage
],
// ============================================================================
// Reporting Rules
// ============================================================================
// Configure what types of issues to report and at what severity level
rules: {
// ========================================================================
// Unused files are ERRORS
// ========================================================================
// These should definitely be removed or used.
// However, always manually verify before deleting!
files: 'error',
// ========================================================================
// Unused dependencies are WARNINGS
// ========================================================================
// Dependencies might be:
// - Used in production builds but not in dev
// - Peer dependencies
// - Used by other tools
dependencies: 'warn',
devDependencies: 'warn',
// ========================================================================
// Unlisted imports are ERRORS
// ========================================================================
// Missing from package.json - will break in production!
unlisted: 'error',
// ========================================================================
// Unused exports are WARNINGS (not errors!)
// ========================================================================
// Exports might be:
// - Part of public API for future use
// - Used by external tools
// - Exported for type inference
// ⚠️ ALWAYS manually verify before removing exports!
exports: 'warn',
// Unused types are warnings (might be part of type definitions)
types: 'warn',
// Duplicate exports are warnings (could cause confusion but not breaking)
duplicates: 'warn',
},
}
export default config

View File

@ -23,10 +23,10 @@
"build": "next build",
"build:docker": "next build && node scripts/optimize-standalone.js",
"start": "cp -r .next/static .next/standalone/.next/static && cp -r public .next/standalone/public && cross-env PORT=$npm_config_port HOSTNAME=$npm_config_host node .next/standalone/server.js",
"lint": "eslint --concurrency=auto --cache --cache-location node_modules/.cache/eslint/.eslint-cache",
"lint:fix": "eslint --concurrency=auto --cache --cache-location node_modules/.cache/eslint/.eslint-cache --fix",
"lint:quiet": "eslint --concurrency=auto --cache --cache-location node_modules/.cache/eslint/.eslint-cache --quiet",
"lint:complexity": "eslint --concurrency=auto --cache --cache-location node_modules/.cache/eslint/.eslint-cache --rule 'complexity: [error, {max: 15}]' --quiet",
"lint": "eslint --cache --cache-location node_modules/.cache/eslint/.eslint-cache",
"lint:fix": "eslint --cache --cache-location node_modules/.cache/eslint/.eslint-cache --fix",
"lint:quiet": "eslint --cache --cache-location node_modules/.cache/eslint/.eslint-cache --quiet",
"lint:complexity": "eslint --cache --cache-location node_modules/.cache/eslint/.eslint-cache --rule 'complexity: [error, {max: 15}]' --quiet",
"prepare": "cd ../ && node -e \"if (process.env.NODE_ENV !== 'production'){process.exit(1)} \" || husky ./web/.husky",
"gen-icons": "node ./app/components/base/icons/script.mjs",
"uglify-embed": "node ./bin/uglify-embed",
@ -209,10 +209,10 @@
},
"lint-staged": {
"**/*.js?(x)": [
"eslint --concurrency=auto --fix"
"eslint --fix"
],
"**/*.ts?(x)": [
"eslint --concurrency=auto --fix"
"eslint --fix"
]
},
"pnpm": {