diff --git a/api/controllers/console/app/app.py b/api/controllers/console/app/app.py index cc9c8b31cb..1b46a3a7d3 100644 --- a/api/controllers/console/app/app.py +++ b/api/controllers/console/app/app.py @@ -174,6 +174,7 @@ class AppApi(Resource): parser.add_argument("icon", type=str, location="json") parser.add_argument("icon_background", type=str, location="json") parser.add_argument("max_active_requests", type=int, location="json") + parser.add_argument("use_icon_as_answer_icon", type=bool, location="json") args = parser.parse_args() app_service = AppService() diff --git a/api/controllers/console/app/site.py b/api/controllers/console/app/site.py index f936642acd..26da1ef26d 100644 --- a/api/controllers/console/app/site.py +++ b/api/controllers/console/app/site.py @@ -34,6 +34,7 @@ def parse_app_site_args(): ) parser.add_argument("prompt_public", type=bool, required=False, location="json") parser.add_argument("show_workflow_steps", type=bool, required=False, location="json") + parser.add_argument("use_icon_as_answer_icon", type=bool, required=False, location="json") return parser.parse_args() @@ -68,6 +69,7 @@ class AppSite(Resource): "customize_token_strategy", "prompt_public", "show_workflow_steps", + "use_icon_as_answer_icon", ]: value = args.get(attr_name) if value is not None: diff --git a/api/controllers/web/site.py b/api/controllers/web/site.py index 2b4d0e7630..0564b15ea3 100644 --- a/api/controllers/web/site.py +++ b/api/controllers/web/site.py @@ -39,6 +39,7 @@ class AppSiteApi(WebApiResource): "default_language": fields.String, "prompt_public": fields.Boolean, "show_workflow_steps": fields.Boolean, + "use_icon_as_answer_icon": fields.Boolean, } app_fields = { diff --git a/api/fields/app_fields.py b/api/fields/app_fields.py index 45fcb128ce..aa353a3cc1 100644 --- a/api/fields/app_fields.py +++ b/api/fields/app_fields.py @@ -58,6 +58,7 @@ app_detail_fields = { "model_config": fields.Nested(model_config_fields, attribute="app_model_config", allow_null=True), "workflow": fields.Nested(workflow_partial_fields, allow_null=True), "tracing": fields.Raw, + "use_icon_as_answer_icon": fields.Boolean, "created_by": fields.String, "created_at": TimestampField, "updated_by": fields.String, @@ -91,6 +92,7 @@ app_partial_fields = { "icon_url": AppIconUrlField, "model_config": fields.Nested(model_config_partial_fields, attribute="app_model_config", allow_null=True), "workflow": fields.Nested(workflow_partial_fields, allow_null=True), + "use_icon_as_answer_icon": fields.Boolean, "created_by": fields.String, "created_at": TimestampField, "updated_by": fields.String, @@ -140,6 +142,7 @@ site_fields = { "prompt_public": fields.Boolean, "app_base_url": fields.String, "show_workflow_steps": fields.Boolean, + "use_icon_as_answer_icon": fields.Boolean, "created_by": fields.String, "created_at": TimestampField, "updated_by": fields.String, @@ -161,6 +164,7 @@ app_detail_fields_with_site = { "workflow": fields.Nested(workflow_partial_fields, allow_null=True), "site": fields.Nested(site_fields), "api_base_url": fields.String, + "use_icon_as_answer_icon": fields.Boolean, "created_by": fields.String, "created_at": TimestampField, "updated_by": fields.String, @@ -184,4 +188,5 @@ app_site_fields = { "customize_token_strategy": fields.String, "prompt_public": fields.Boolean, "show_workflow_steps": fields.Boolean, + "use_icon_as_answer_icon": fields.Boolean, } diff --git a/api/fields/installed_app_fields.py b/api/fields/installed_app_fields.py index 9afc1b1a4a..e0b3e340f6 100644 --- a/api/fields/installed_app_fields.py +++ b/api/fields/installed_app_fields.py @@ -10,6 +10,7 @@ app_fields = { "icon": fields.String, "icon_background": fields.String, "icon_url": AppIconUrlField, + "use_icon_as_answer_icon": fields.Boolean, } installed_app_fields = { diff --git a/api/migrations/versions/2024_09_01_1255-030f4915f36a_add_use_icon_as_answer_icon_fields_for_.py b/api/migrations/versions/2024_09_01_1255-030f4915f36a_add_use_icon_as_answer_icon_fields_for_.py new file mode 100644 index 0000000000..4406d51ed0 --- /dev/null +++ b/api/migrations/versions/2024_09_01_1255-030f4915f36a_add_use_icon_as_answer_icon_fields_for_.py @@ -0,0 +1,45 @@ +"""add use_icon_as_answer_icon fields for app and site + +Revision ID: 030f4915f36a +Revises: d0187d6a88dd +Create Date: 2024-09-01 12:55:45.129687 + +""" + +import sqlalchemy as sa +from alembic import op + +import models as models + +# revision identifiers, used by Alembic. +revision = "030f4915f36a" +down_revision = "d0187d6a88dd" +branch_labels = None +depends_on = None + + +def upgrade(): + # ### commands auto generated by Alembic - please adjust! ### + with op.batch_alter_table("apps", schema=None) as batch_op: + batch_op.add_column( + sa.Column("use_icon_as_answer_icon", sa.Boolean(), server_default=sa.text("false"), nullable=False) + ) + + with op.batch_alter_table("sites", schema=None) as batch_op: + batch_op.add_column( + sa.Column("use_icon_as_answer_icon", sa.Boolean(), server_default=sa.text("false"), nullable=False) + ) + + # ### end Alembic commands ### + + +def downgrade(): + # ### commands auto generated by Alembic - please adjust! ### + + with op.batch_alter_table("sites", schema=None) as batch_op: + batch_op.drop_column("use_icon_as_answer_icon") + + with op.batch_alter_table("apps", schema=None) as batch_op: + batch_op.drop_column("use_icon_as_answer_icon") + + # ### end Alembic commands ### diff --git a/api/models/model.py b/api/models/model.py index e2d1fcfc23..e81d25fbc9 100644 --- a/api/models/model.py +++ b/api/models/model.py @@ -86,6 +86,7 @@ class App(db.Model): created_at = db.Column(db.DateTime, nullable=False, server_default=db.text('CURRENT_TIMESTAMP(0)')) updated_by = db.Column(StringUUID, nullable=True) updated_at = db.Column(db.DateTime, nullable=False, server_default=db.text('CURRENT_TIMESTAMP(0)')) + use_icon_as_answer_icon = db.Column(db.Boolean, nullable=False, server_default=db.text("false")) @property def desc_or_prompt(self): @@ -1114,6 +1115,7 @@ class Site(db.Model): copyright = db.Column(db.String(255)) privacy_policy = db.Column(db.String(255)) show_workflow_steps = db.Column(db.Boolean, nullable=False, server_default=db.text('true')) + use_icon_as_answer_icon = db.Column(db.Boolean, nullable=False, server_default=db.text("false")) custom_disclaimer = db.Column(db.String(255), nullable=True) customize_domain = db.Column(db.String(255)) customize_token_strategy = db.Column(db.String(255), nullable=False) diff --git a/api/services/app_dsl_service.py b/api/services/app_dsl_service.py index a2aa15ed4b..895855a9c8 100644 --- a/api/services/app_dsl_service.py +++ b/api/services/app_dsl_service.py @@ -87,6 +87,7 @@ class AppDslService: icon_background = ( args.get("icon_background") if args.get("icon_background") else app_data.get("icon_background") ) + use_icon_as_answer_icon = app_data.get("use_icon_as_answer_icon", False) # import dsl and create app app_mode = AppMode.value_of(app_data.get("mode")) @@ -101,6 +102,7 @@ class AppDslService: icon_type=icon_type, icon=icon, icon_background=icon_background, + use_icon_as_answer_icon=use_icon_as_answer_icon, ) elif app_mode in [AppMode.CHAT, AppMode.AGENT_CHAT, AppMode.COMPLETION]: app = cls._import_and_create_new_model_config_based_app( @@ -113,6 +115,7 @@ class AppDslService: icon_type=icon_type, icon=icon, icon_background=icon_background, + use_icon_as_answer_icon=use_icon_as_answer_icon, ) else: raise ValueError("Invalid app mode") @@ -171,6 +174,7 @@ class AppDslService: "icon": "🤖" if app_model.icon_type == "image" else app_model.icon, "icon_background": "#FFEAD5" if app_model.icon_type == "image" else app_model.icon_background, "description": app_model.description, + "use_icon_as_answer_icon": app_model.use_icon_as_answer_icon, }, } @@ -218,6 +222,7 @@ class AppDslService: icon_type: str, icon: str, icon_background: str, + use_icon_as_answer_icon: bool, ) -> App: """ Import app dsl and create new workflow based app @@ -231,6 +236,7 @@ class AppDslService: :param icon_type: app icon type, "emoji" or "image" :param icon: app icon :param icon_background: app icon background + :param use_icon_as_answer_icon: use app icon as answer icon """ if not workflow_data: raise ValueError("Missing workflow in data argument " "when app mode is advanced-chat or workflow") @@ -244,6 +250,7 @@ class AppDslService: icon_type=icon_type, icon=icon, icon_background=icon_background, + use_icon_as_answer_icon=use_icon_as_answer_icon, ) # init draft workflow @@ -316,6 +323,7 @@ class AppDslService: icon_type: str, icon: str, icon_background: str, + use_icon_as_answer_icon: bool, ) -> App: """ Import app dsl and create new model config based app @@ -341,6 +349,7 @@ class AppDslService: icon_type=icon_type, icon=icon, icon_background=icon_background, + use_icon_as_answer_icon=use_icon_as_answer_icon, ) app_model_config = AppModelConfig() @@ -369,6 +378,7 @@ class AppDslService: icon_type: str, icon: str, icon_background: str, + use_icon_as_answer_icon: bool, ) -> App: """ Create new app @@ -381,6 +391,7 @@ class AppDslService: :param icon_type: app icon type, "emoji" or "image" :param icon: app icon :param icon_background: app icon background + :param use_icon_as_answer_icon: use app icon as answer icon """ app = App( tenant_id=tenant_id, @@ -392,6 +403,7 @@ class AppDslService: icon_background=icon_background, enable_site=True, enable_api=True, + use_icon_as_answer_icon=use_icon_as_answer_icon, created_by=account.id, updated_by=account.id, ) diff --git a/api/services/app_service.py b/api/services/app_service.py index 462613fb7d..1dacfea246 100644 --- a/api/services/app_service.py +++ b/api/services/app_service.py @@ -221,6 +221,7 @@ class AppService: app.icon_type = args.get("icon_type", "emoji") app.icon = args.get("icon") app.icon_background = args.get("icon_background") + app.use_icon_as_answer_icon = args.get("use_icon_as_answer_icon", False) app.updated_by = current_user.id app.updated_at = datetime.now(timezone.utc).replace(tzinfo=None) db.session.commit() diff --git a/web/app/(commonLayout)/apps/AppCard.tsx b/web/app/(commonLayout)/apps/AppCard.tsx index 6dcc39046c..fb39dee5a3 100644 --- a/web/app/(commonLayout)/apps/AppCard.tsx +++ b/web/app/(commonLayout)/apps/AppCard.tsx @@ -79,6 +79,7 @@ const AppCard = ({ app, onRefresh }: AppCardProps) => { icon, icon_background, description, + use_icon_as_answer_icon, }) => { try { await updateAppInfo({ @@ -88,6 +89,7 @@ const AppCard = ({ app, onRefresh }: AppCardProps) => { icon, icon_background, description, + use_icon_as_answer_icon, }) setShowEditModal(false) notify({ @@ -370,6 +372,8 @@ const AppCard = ({ app, onRefresh }: AppCardProps) => { appIconBackground={app.icon_background} appIconUrl={app.icon_url} appDescription={app.description} + appMode={app.mode} + appUseIconAsAnswerIcon={app.use_icon_as_answer_icon} show={showEditModal} onConfirm={onEdit} onHide={() => setShowEditModal(false)} diff --git a/web/app/components/app-sidebar/app-info.tsx b/web/app/components/app-sidebar/app-info.tsx index c5bc3bb210..b4a7a8a619 100644 --- a/web/app/components/app-sidebar/app-info.tsx +++ b/web/app/components/app-sidebar/app-info.tsx @@ -63,6 +63,7 @@ const AppInfo = ({ expand }: IAppInfoProps) => { icon, icon_background, description, + use_icon_as_answer_icon, }) => { if (!appDetail) return @@ -74,6 +75,7 @@ const AppInfo = ({ expand }: IAppInfoProps) => { icon, icon_background, description, + use_icon_as_answer_icon, }) setShowEditModal(false) notify({ @@ -423,6 +425,8 @@ const AppInfo = ({ expand }: IAppInfoProps) => { appIconBackground={appDetail.icon_background} appIconUrl={appDetail.icon_url} appDescription={appDetail.description} + appMode={appDetail.mode} + appUseIconAsAnswerIcon={appDetail.use_icon_as_answer_icon} show={showEditModal} onConfirm={onEdit} onHide={() => setShowEditModal(false)} diff --git a/web/app/components/app/overview/settings/index.tsx b/web/app/components/app/overview/settings/index.tsx index 02eff06c0a..a501d06ce4 100644 --- a/web/app/components/app/overview/settings/index.tsx +++ b/web/app/components/app/overview/settings/index.tsx @@ -43,6 +43,7 @@ export type ConfigParams = { icon: string icon_background?: string show_workflow_steps: boolean + use_icon_as_answer_icon: boolean enable_sso?: boolean } @@ -72,6 +73,7 @@ const SettingsModal: FC = ({ custom_disclaimer, default_language, show_workflow_steps, + use_icon_as_answer_icon, } = appInfo.site const [inputInfo, setInputInfo] = useState({ title, @@ -82,6 +84,7 @@ const SettingsModal: FC = ({ privacyPolicy: privacy_policy, customDisclaimer: custom_disclaimer, show_workflow_steps, + use_icon_as_answer_icon, enable_sso: appInfo.enable_sso, }) const [language, setLanguage] = useState(default_language) @@ -94,6 +97,7 @@ const SettingsModal: FC = ({ ? { type: 'image', url: icon_url!, fileId: icon } : { type: 'emoji', icon, background: icon_background! }, ) + const isChatBot = appInfo.mode === 'chat' || appInfo.mode === 'advanced-chat' || appInfo.mode === 'agent-chat' useEffect(() => { setInputInfo({ @@ -105,6 +109,7 @@ const SettingsModal: FC = ({ privacyPolicy: privacy_policy, customDisclaimer: custom_disclaimer, show_workflow_steps, + use_icon_as_answer_icon, enable_sso: appInfo.enable_sso, }) setLanguage(default_language) @@ -157,6 +162,7 @@ const SettingsModal: FC = ({ icon: appIcon.type === 'emoji' ? appIcon.icon : appIcon.fileId, icon_background: appIcon.type === 'emoji' ? appIcon.background : undefined, show_workflow_steps: inputInfo.show_workflow_steps, + use_icon_as_answer_icon: inputInfo.use_icon_as_answer_icon, enable_sso: inputInfo.enable_sso, } await onSave?.(params) @@ -209,6 +215,18 @@ const SettingsModal: FC = ({ onChange={onChange('desc')} placeholder={t(`${prefixSettings}.webDescPlaceholder`) as string} /> + {isChatBot && ( +
+
+
{t('app.answerIcon.title')}
+ setInputInfo({ ...inputInfo, use_icon_as_answer_icon: v })} + /> +
+

{t('app.answerIcon.description')}

+
+ )}
{t(`${prefixSettings}.language`)}
item.supported)} diff --git a/web/app/components/base/answer-icon/index.tsx b/web/app/components/base/answer-icon/index.tsx new file mode 100644 index 0000000000..8c6363e05c --- /dev/null +++ b/web/app/components/base/answer-icon/index.tsx @@ -0,0 +1,47 @@ +'use client' + +import type { FC } from 'react' +import { init } from 'emoji-mart' +import data from '@emoji-mart/data' +import classNames from '@/utils/classnames' +import type { AppIconType } from '@/types/app' + +init({ data }) + +export type AnswerIconProps = { + iconType?: AppIconType | null + icon?: string | null + background?: string | null + imageUrl?: string | null +} + +const AnswerIcon: FC = ({ + iconType, + icon, + background, + imageUrl, +}) => { + const wrapperClassName = classNames( + 'flex', + 'items-center', + 'justify-center', + 'w-full', + 'h-full', + 'rounded-full', + 'border-[0.5px]', + 'border-black/5', + 'text-xl', + ) + const isValidImageIcon = iconType === 'image' && imageUrl + return
+ {isValidImageIcon + ? answer icon + : (icon && icon !== '') ? : + } +
+} + +export default AnswerIcon diff --git a/web/app/components/base/chat/chat-with-history/chat-wrapper.tsx b/web/app/components/base/chat/chat-with-history/chat-wrapper.tsx index 8eda66c52a..1129b18a8d 100644 --- a/web/app/components/base/chat/chat-with-history/chat-wrapper.tsx +++ b/web/app/components/base/chat/chat-with-history/chat-wrapper.tsx @@ -13,6 +13,7 @@ import { getUrl, stopChatMessageResponding, } from '@/service/share' +import AnswerIcon from '@/app/components/base/answer-icon' const ChatWrapper = () => { const { @@ -128,6 +129,15 @@ const ChatWrapper = () => { isMobile, ]) + const answerIcon = (appData?.site && appData.site.use_icon_as_answer_icon) + ? + : null + return ( { allToolIcons={appMeta?.tool_icons || {}} onFeedback={handleFeedback} suggestedQuestions={suggestedQuestions} + answerIcon={answerIcon} hideProcessDetail themeBuilder={themeBuilder} /> diff --git a/web/app/components/base/chat/chat-with-history/hooks.tsx b/web/app/components/base/chat/chat-with-history/hooks.tsx index 624cc53a18..fe952efc27 100644 --- a/web/app/components/base/chat/chat-with-history/hooks.tsx +++ b/web/app/components/base/chat/chat-with-history/hooks.tsx @@ -65,6 +65,7 @@ export const useChatWithHistory = (installedAppInfo?: InstalledApp) => { prompt_public: false, copyright: '', show_workflow_steps: true, + use_icon_as_answer_icon: app.use_icon_as_answer_icon, }, plan: 'basic', } as AppData diff --git a/web/app/components/base/chat/chat/answer/index.tsx b/web/app/components/base/chat/chat/answer/index.tsx index 78a0842595..270cd553c2 100644 --- a/web/app/components/base/chat/chat/answer/index.tsx +++ b/web/app/components/base/chat/chat/answer/index.tsx @@ -22,6 +22,7 @@ import Citation from '@/app/components/base/chat/chat/citation' import { EditTitle } from '@/app/components/app/annotation/edit-annotation-modal/edit-item' import type { Emoji } from '@/app/components/tools/types' import type { AppData } from '@/models/share' +import AnswerIcon from '@/app/components/base/answer-icon' type AnswerProps = { item: ChatItem @@ -89,11 +90,7 @@ const Answer: FC = ({
{ - answerIcon || ( -
- 🤖 -
- ) + answerIcon || } { responding && ( diff --git a/web/app/components/base/chat/embedded-chatbot/chat-wrapper.tsx b/web/app/components/base/chat/embedded-chatbot/chat-wrapper.tsx index 68646a17db..4934339e87 100644 --- a/web/app/components/base/chat/embedded-chatbot/chat-wrapper.tsx +++ b/web/app/components/base/chat/embedded-chatbot/chat-wrapper.tsx @@ -15,6 +15,7 @@ import { stopChatMessageResponding, } from '@/service/share' import LogoAvatar from '@/app/components/base/logo/logo-embeded-chat-avatar' +import AnswerIcon from '@/app/components/base/answer-icon' const ChatWrapper = () => { const { @@ -114,6 +115,17 @@ const ChatWrapper = () => { return null }, [currentConversationId, inputsForms, isMobile]) + const answerIcon = isDify() + ? + : (appData?.site && appData.site.use_icon_as_answer_icon) + ? + : null + return ( { allToolIcons={appMeta?.tool_icons || {}} onFeedback={handleFeedback} suggestedQuestions={suggestedQuestions} - answerIcon={isDify() ? : null} + answerIcon={answerIcon} hideProcessDetail themeBuilder={themeBuilder} /> diff --git a/web/app/components/explore/create-app-modal/index.tsx b/web/app/components/explore/create-app-modal/index.tsx index 59bccf2978..7ae7d1b96d 100644 --- a/web/app/components/explore/create-app-modal/index.tsx +++ b/web/app/components/explore/create-app-modal/index.tsx @@ -5,6 +5,7 @@ import { RiCloseLine } from '@remixicon/react' import AppIconPicker from '../../base/app-icon-picker' import Modal from '@/app/components/base/modal' import Button from '@/app/components/base/button' +import Switch from '@/app/components/base/switch' import Toast from '@/app/components/base/toast' import AppIcon from '@/app/components/base/app-icon' import { useProviderContext } from '@/context/provider-context' @@ -20,12 +21,15 @@ export type CreateAppModalProps = { appIcon: string appIconBackground?: string | null appIconUrl?: string | null + appMode?: string + appUseIconAsAnswerIcon?: boolean onConfirm: (info: { name: string icon_type: AppIconType icon: string icon_background?: string description: string + use_icon_as_answer_icon?: boolean }) => Promise onHide: () => void } @@ -39,6 +43,8 @@ const CreateAppModal = ({ appIconUrl, appName, appDescription, + appMode, + appUseIconAsAnswerIcon, onConfirm, onHide, }: CreateAppModalProps) => { @@ -52,6 +58,7 @@ const CreateAppModal = ({ ) const [showAppIconPicker, setShowAppIconPicker] = useState(false) const [description, setDescription] = useState(appDescription || '') + const [useIconAsAnswerIcon, setUseIconAsAnswerIcon] = useState(appUseIconAsAnswerIcon || false) const { plan, enableBilling } = useProviderContext() const isAppsFull = (enableBilling && plan.usage.buildApps >= plan.total.buildApps) @@ -67,6 +74,7 @@ const CreateAppModal = ({ icon: appIcon.type === 'emoji' ? appIcon.icon : appIcon.fileId, icon_background: appIcon.type === 'emoji' ? appIcon.background! : undefined, description, + use_icon_as_answer_icon: useIconAsAnswerIcon, }) onHide() } @@ -119,6 +127,19 @@ const CreateAppModal = ({ onChange={e => setDescription(e.target.value)} />
+ {/* answer icon */} + {isEditModal && (appMode === 'chat' || appMode === 'advanced-chat' || appMode === 'agent-chat') && ( +
+
+
{t('app.answerIcon.title')}
+ setUseIconAsAnswerIcon(v)} + /> +
+

{t('app.answerIcon.descriptionInExplore')}

+
+ )} {!isEditModal && isAppsFull && }
diff --git a/web/i18n/en-US/app.ts b/web/i18n/en-US/app.ts index 90724098de..1ce517e32b 100644 --- a/web/i18n/en-US/app.ts +++ b/web/i18n/en-US/app.ts @@ -77,6 +77,11 @@ const translation = { emoji: 'Emoji', image: 'Image', }, + answerIcon: { + title: 'Use WebApp icon to replace 🤖', + description: 'Wether to use the WebApp icon to replace 🤖 in the shared application', + descriptionInExplore: 'Whether to use the WebApp icon to replace 🤖 in Explore', + }, switch: 'Switch to Workflow Orchestrate', switchTipStart: 'A new app copy will be created for you, and the new copy will switch to Workflow Orchestrate. The new copy will ', switchTip: 'not allow', diff --git a/web/i18n/zh-Hans/app.ts b/web/i18n/zh-Hans/app.ts index e12ed1b35d..ee316200fa 100644 --- a/web/i18n/zh-Hans/app.ts +++ b/web/i18n/zh-Hans/app.ts @@ -76,6 +76,11 @@ const translation = { emoji: '表情符号', image: '图片', }, + answerIcon: { + title: '使用 WebApp 图标替换 🤖', + description: '是否使用 WebApp 图标替换分享的应用界面中的 🤖', + descriptionInExplore: '是否使用 WebApp 图标替换 Explore 界面中的 🤖', + }, switch: '迁移为工作流编排', switchTipStart: '将为您创建一个使用工作流编排的新应用。新应用将', switchTip: '不能够', diff --git a/web/models/explore.ts b/web/models/explore.ts index 78dd2e8675..ad60d99c6f 100644 --- a/web/models/explore.ts +++ b/web/models/explore.ts @@ -8,6 +8,7 @@ export type AppBasicInfo = { icon_url: string name: string description: string + use_icon_as_answer_icon: boolean } export type AppCategory = 'Writing' | 'Translate' | 'HR' | 'Programming' | 'Assistant' diff --git a/web/models/share.ts b/web/models/share.ts index 127f3d0a51..3521365e82 100644 --- a/web/models/share.ts +++ b/web/models/share.ts @@ -25,6 +25,7 @@ export type SiteInfo = { privacy_policy?: string custom_disclaimer?: string show_workflow_steps?: boolean + use_icon_as_answer_icon?: boolean } export type AppMeta = { diff --git a/web/service/apps.ts b/web/service/apps.ts index 84c7eebae3..3cda551474 100644 --- a/web/service/apps.ts +++ b/web/service/apps.ts @@ -28,8 +28,8 @@ export const createApp: Fetcher('apps', { body: { name, icon_type, icon, icon_background, mode, description, model_config: config } }) } -export const updateAppInfo: Fetcher = ({ appID, name, icon_type, icon, icon_background, description }) => { - return put(`apps/${appID}`, { body: { name, icon_type, icon, icon_background, description } }) +export const updateAppInfo: Fetcher = ({ appID, name, icon_type, icon, icon_background, description, use_icon_as_answer_icon }) => { + return put(`apps/${appID}`, { body: { name, icon_type, icon, icon_background, description, use_icon_as_answer_icon } }) } export const copyApp: Fetcher = ({ appID, name, icon_type, icon, icon_background, mode, description }) => { diff --git a/web/types/app.ts b/web/types/app.ts index fb8a407dd2..cb05bc3878 100644 --- a/web/types/app.ts +++ b/web/types/app.ts @@ -297,6 +297,7 @@ export type SiteConfig = { icon_url: string | null show_workflow_steps: boolean + use_icon_as_answer_icon: boolean } export type AppIconType = 'image' | 'emoji' @@ -323,6 +324,8 @@ export type App = { icon_background: string | null /** Icon URL, only available when icon_type is 'image' */ icon_url: string | null + /** Whether to use app icon as answer icon */ + use_icon_as_answer_icon: boolean /** Mode */ mode: AppMode