diff --git a/web/app/(commonLayout)/try/preview/[appId]/page.tsx b/web/app/(commonLayout)/try/preview/[appId]/page.tsx
new file mode 100644
index 0000000000..bba616c3c0
--- /dev/null
+++ b/web/app/(commonLayout)/try/preview/[appId]/page.tsx
@@ -0,0 +1,17 @@
+import React from 'react'
+import Main from '@/app/components/app/configuration/preview'
+
+export type IPreviewProps = {
+ params: {
+ appId: string
+ }
+}
+
+async function Preview({ params }: IPreviewProps) {
+ const appId = (await params).appId
+ return (
+
+ )
+}
+
+export default Preview
diff --git a/web/app/components/app/configuration/preview.tsx b/web/app/components/app/configuration/preview.tsx
new file mode 100644
index 0000000000..cba81a7199
--- /dev/null
+++ b/web/app/components/app/configuration/preview.tsx
@@ -0,0 +1,316 @@
+'use client'
+import type { FC } from 'react'
+import React, { useMemo, useState } from 'react'
+import { clone } from 'lodash-es'
+
+import Loading from '@/app/components/base/loading'
+
+import type { ModelConfig as BackendModelConfig, PromptVariable } from '@/types/app'
+import ConfigContext from '@/context/debug-configuration'
+import Config from '@/app/components/app/configuration/config'
+import Debug from '@/app/components/app/configuration/debug'
+import { ModelFeatureEnum } from '@/app/components/header/account-setting/model-provider-page/declarations'
+import { ModelModeType, Resolution, TransferMethod } from '@/types/app'
+import { PromptMode } from '@/models/debug'
+import { ANNOTATION_DEFAULT, DEFAULT_AGENT_SETTING, DEFAULT_CHAT_PROMPT_CONFIG, DEFAULT_COMPLETION_PROMPT_CONFIG } from '@/config'
+import useBreakpoints, { MediaType } from '@/hooks/use-breakpoints'
+import type { FormValue } from '@/app/components/header/account-setting/model-provider-page/declarations'
+
+import { FeaturesProvider } from '@/app/components/base/features'
+import type { Features as FeaturesData, FileUpload } from '@/app/components/base/features/types'
+import { FILE_EXTS } from '@/app/components/base/prompt-editor/constants'
+import { SupportUploadFileTypes } from '@/app/components/workflow/types'
+
+import { useGetTryAppInfo } from '@/service/use-try-app'
+import { noop } from 'lodash'
+import { correctModelProvider } from '@/utils'
+import { userInputsFormToPromptVariables } from '@/utils/model-config'
+
+type Props = {
+ appId: string
+}
+
+const defaultModelConfig = {
+ provider: 'langgenius/openai/openai',
+ model_id: 'gpt-3.5-turbo',
+ mode: ModelModeType.unset,
+ configs: {
+ prompt_template: '',
+ prompt_variables: [] as PromptVariable[],
+ },
+ more_like_this: null,
+ opening_statement: '',
+ suggested_questions: [],
+ sensitive_word_avoidance: null,
+ speech_to_text: null,
+ text_to_speech: null,
+ file_upload: null,
+ suggested_questions_after_answer: null,
+ retriever_resource: null,
+ annotation_reply: null,
+ dataSets: [],
+ agentConfig: DEFAULT_AGENT_SETTING,
+}
+const Configuration: FC = ({
+ appId,
+}) => {
+ const media = useBreakpoints()
+ const isMobile = media === MediaType.mobile
+
+ const { data: appDetail, isLoading } = useGetTryAppInfo(appId)
+ const modelConfig = ((modelConfig?: BackendModelConfig) => {
+ if(isLoading || !modelConfig)
+ return defaultModelConfig
+
+ const model = modelConfig.model
+ const newModelConfig = {
+ provider: correctModelProvider(model.provider),
+ model_id: model.name,
+ mode: model.mode,
+ configs: {
+ prompt_template: modelConfig.pre_prompt || '',
+ prompt_variables: userInputsFormToPromptVariables(
+ [
+ ...(modelConfig.user_input_form as any),
+ ...(
+ modelConfig.external_data_tools?.length
+ ? modelConfig.external_data_tools.map((item: any) => {
+ return {
+ external_data_tool: {
+ variable: item.variable as string,
+ label: item.label as string,
+ enabled: item.enabled,
+ type: item.type as string,
+ config: item.config,
+ required: true,
+ icon: item.icon,
+ icon_background: item.icon_background,
+ },
+ }
+ })
+ : []
+ ),
+ ],
+ modelConfig.dataset_query_variable,
+ ),
+ },
+ more_like_this: modelConfig.more_like_this,
+ opening_statement: modelConfig.opening_statement,
+ suggested_questions: modelConfig.suggested_questions,
+ sensitive_word_avoidance: modelConfig.sensitive_word_avoidance,
+ speech_to_text: modelConfig.speech_to_text,
+ text_to_speech: modelConfig.text_to_speech,
+ file_upload: modelConfig.file_upload,
+ suggested_questions_after_answer: modelConfig.suggested_questions_after_answer,
+ retriever_resource: modelConfig.retriever_resource,
+ annotation_reply: modelConfig.annotation_reply,
+ external_data_tools: modelConfig.external_data_tools,
+ dataSets: [],
+ agentConfig: appDetail?.mode === 'agent-chat' ? {
+ max_iteration: DEFAULT_AGENT_SETTING.max_iteration,
+ ...modelConfig.agent_mode,
+ // remove dataset
+ enabled: true, // modelConfig.agent_mode?.enabled is not correct. old app: the value of app with dataset's is always true
+ tools: [],
+ } : DEFAULT_AGENT_SETTING,
+ }
+ return newModelConfig
+ })(appDetail?.model_config)
+ const mode = appDetail?.mode
+ // const isChatApp = ['chat', 'advanced-chat', 'agent-chat'].includes(mode!)
+
+ // chat configuration
+ const promptMode = modelConfig?.prompt_type === PromptMode.advanced ? PromptMode.advanced : PromptMode.simple
+ const isAdvancedMode = promptMode === PromptMode.advanced
+ const isAgent = mode === 'agent-chat'
+ const chatPromptConfig = isAdvancedMode ? (modelConfig?.chat_prompt_config || clone(DEFAULT_CHAT_PROMPT_CONFIG)) : undefined
+ const suggestedQuestions = modelConfig?.suggested_questions || []
+ const moreLikeThisConfig = modelConfig?.more_like_this || { enabled: false }
+ const suggestedQuestionsAfterAnswerConfig = modelConfig?.suggested_questions_after_answer || { enabled: false }
+ const speechToTextConfig = modelConfig?.speech_to_text || { enabled: false }
+ const textToSpeechConfig = modelConfig?.text_to_speech || { enabled: false, voice: '', language: '' }
+ const citationConfig = modelConfig?.retriever_resource || { enabled: false }
+ const annotationConfig = modelConfig?.annotation_reply || {
+ id: '',
+ enabled: false,
+ score_threshold: ANNOTATION_DEFAULT.score_threshold,
+ embedding_model: {
+ embedding_provider_name: '',
+ embedding_model_name: '',
+ },
+ }
+ const moderationConfig = modelConfig?.sensitive_word_avoidance || { enabled: false }
+ // completion configuration
+ const completionPromptConfig = modelConfig?.completion_prompt_config || clone(DEFAULT_COMPLETION_PROMPT_CONFIG) as any
+
+ // datasets
+ const dataSets = (() => {
+ return []
+ })()
+ // const selectedIds = dataSets.map(item => item.id)
+
+ // prompt & model config
+ const inputs = {}
+ const query = ''
+ const completionParams = useState({})
+
+ // todo
+ const currModel: {
+ features: ModelFeatureEnum[]
+ } = {
+ features: [],
+ }
+
+ const isShowVisionConfig = !!currModel?.features?.includes(ModelFeatureEnum.vision)
+ const isShowDocumentConfig = !!currModel?.features?.includes(ModelFeatureEnum.document)
+ const isShowAudioConfig = !!currModel?.features?.includes(ModelFeatureEnum.audio)
+ const isAllowVideoUpload = !!currModel?.features?.includes(ModelFeatureEnum.video)
+ const visionConfig = {
+ enabled: false,
+ number_limits: 2,
+ detail: Resolution.low,
+ transfer_methods: [TransferMethod.local_file],
+ }
+
+ const featuresData: FeaturesData = useMemo(() => {
+ return {
+ moreLikeThis: modelConfig.more_like_this || { enabled: false },
+ opening: {
+ enabled: !!modelConfig.opening_statement,
+ opening_statement: modelConfig.opening_statement || '',
+ suggested_questions: modelConfig.suggested_questions || [],
+ },
+ moderation: modelConfig.sensitive_word_avoidance || { enabled: false },
+ speech2text: modelConfig.speech_to_text || { enabled: false },
+ text2speech: modelConfig.text_to_speech || { enabled: false },
+ file: {
+ image: {
+ detail: modelConfig.file_upload?.image?.detail || Resolution.high,
+ enabled: !!modelConfig.file_upload?.image?.enabled,
+ number_limits: modelConfig.file_upload?.image?.number_limits || 3,
+ transfer_methods: modelConfig.file_upload?.image?.transfer_methods || ['local_file', 'remote_url'],
+ },
+ enabled: true,
+ allowed_file_types: modelConfig.file_upload?.allowed_file_types || [],
+ allowed_file_extensions: modelConfig.file_upload?.allowed_file_extensions || [...FILE_EXTS[SupportUploadFileTypes.image], ...FILE_EXTS[SupportUploadFileTypes.video]].map(ext => `.${ext}`),
+ allowed_file_upload_methods: modelConfig.file_upload?.allowed_file_upload_methods || modelConfig.file_upload?.image?.transfer_methods || ['local_file', 'remote_url'],
+ number_limits: modelConfig.file_upload?.number_limits || modelConfig.file_upload?.image?.number_limits || 3,
+ fileUploadConfig: {},
+ } as FileUpload,
+ suggested: modelConfig.suggested_questions_after_answer || { enabled: false },
+ citation: modelConfig.retriever_resource || { enabled: false },
+ annotationReply: modelConfig.annotation_reply || { enabled: false },
+ }
+ }, [modelConfig])
+
+ if (isLoading) {
+ return
+
+
+ }
+ const value = {
+ appId,
+ isAPIKeySet: true,
+ isTrailFinished: false,
+ mode,
+ modelModeType: '',
+ promptMode,
+ isAdvancedMode,
+ isAgent,
+ isOpenAI: false,
+ isFunctionCall: false,
+ collectionList: [],
+ setPromptMode: noop,
+ canReturnToSimpleMode: false,
+ setCanReturnToSimpleMode: noop,
+ chatPromptConfig,
+ completionPromptConfig,
+ currentAdvancedPrompt: '',
+ setCurrentAdvancedPrompt: noop,
+ conversationHistoriesRole: completionPromptConfig.conversation_histories_role,
+ showHistoryModal: false,
+ setConversationHistoriesRole: noop,
+ hasSetBlockStatus: true,
+ conversationId: '',
+ introduction: '',
+ setIntroduction: noop,
+ suggestedQuestions,
+ setSuggestedQuestions: noop,
+ setConversationId: noop,
+ controlClearChatMessage: false,
+ setControlClearChatMessage: noop,
+ prevPromptConfig: {},
+ setPrevPromptConfig: noop,
+ moreLikeThisConfig,
+ setMoreLikeThisConfig: noop,
+ suggestedQuestionsAfterAnswerConfig,
+ setSuggestedQuestionsAfterAnswerConfig: noop,
+ speechToTextConfig,
+ setSpeechToTextConfig: noop,
+ textToSpeechConfig,
+ setTextToSpeechConfig: noop,
+ citationConfig,
+ setCitationConfig: noop,
+ annotationConfig,
+ setAnnotationConfig: noop,
+ moderationConfig,
+ setModerationConfig: noop,
+ externalDataToolsConfig: {},
+ setExternalDataToolsConfig: noop,
+ formattingChanged: false,
+ setFormattingChanged: noop,
+ inputs,
+ setInputs: noop,
+ query,
+ setQuery: noop,
+ completionParams,
+ setCompletionParams: noop,
+ modelConfig,
+ setModelConfig: noop,
+ showSelectDataSet: noop,
+ dataSets,
+ setDataSets: noop,
+ datasetConfigs: [],
+ datasetConfigsRef: {},
+ setDatasetConfigs: noop,
+ hasSetContextVar: true,
+ isShowVisionConfig,
+ visionConfig,
+ setVisionConfig: noop,
+ isAllowVideoUpload,
+ isShowDocumentConfig,
+ isShowAudioConfig,
+ rerankSettingModalOpen: false,
+ setRerankSettingModalOpen: noop,
+ }
+ return (
+
+
+
+
+
+
+
+ {!isMobile &&
}
+
+
+
+
+ )
+}
+export default React.memo(Configuration)
diff --git a/web/service/try-app.ts b/web/service/try-app.ts
index 78df7ba8ed..e174a6a35d 100644
--- a/web/service/try-app.ts
+++ b/web/service/try-app.ts
@@ -5,11 +5,13 @@ import {
import type {
SiteInfo,
} from '@/models/share'
+import type { ModelConfig } from '@/types/app'
type TryAppInfo = {
name: string
mode: AppMode
site: SiteInfo
+ model_config: ModelConfig
}
export const fetchTryAppInfo = async (appId: string) => {
diff --git a/web/types/app.ts b/web/types/app.ts
index abc5b34ca5..0a12e28729 100644
--- a/web/types/app.ts
+++ b/web/types/app.ts
@@ -243,6 +243,7 @@ export type ModelConfig = {
image: VisionSettings
} & UploadFileSetting
files?: VisionFile[]
+ external_data_tools: any[]
created_at?: number
updated_at?: number
}