Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: allow users to use the app icon as the answer icon #7888

Merged
merged 7 commits into from
Sep 2, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions api/controllers/console/app/app.py
Original file line number Diff line number Diff line change
Expand Up @@ -174,6 +174,7 @@ def put(self, app_model):
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()
Expand Down
2 changes: 2 additions & 0 deletions api/controllers/console/app/site.py
Original file line number Diff line number Diff line change
Expand Up @@ -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()


Expand Down Expand Up @@ -68,6 +69,7 @@ def post(self, app_model):
"customize_token_strategy",
"prompt_public",
"show_workflow_steps",
"use_icon_as_answer_icon",
]:
value = args.get(attr_name)
if value is not None:
Expand Down
1 change: 1 addition & 0 deletions api/controllers/web/site.py
Original file line number Diff line number Diff line change
Expand Up @@ -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 = {
Expand Down
5 changes: 5 additions & 0 deletions api/fields/app_fields.py
Original file line number Diff line number Diff line change
Expand Up @@ -58,6 +58,7 @@
"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,
Expand Down Expand Up @@ -91,6 +92,7 @@
"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,
Expand Down Expand Up @@ -140,6 +142,7 @@
"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,
Expand All @@ -161,6 +164,7 @@
"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,
Expand All @@ -184,4 +188,5 @@
"customize_token_strategy": fields.String,
"prompt_public": fields.Boolean,
"show_workflow_steps": fields.Boolean,
"use_icon_as_answer_icon": fields.Boolean,
}
1 change: 1 addition & 0 deletions api/fields/installed_app_fields.py
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@
"icon": fields.String,
"icon_background": fields.String,
"icon_url": AppIconUrlField,
"use_icon_as_answer_icon": fields.Boolean,
}

installed_app_fields = {
Expand Down
Original file line number Diff line number Diff line change
@@ -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 ###
2 changes: 2 additions & 0 deletions api/models/model.py
Original file line number Diff line number Diff line change
Expand Up @@ -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):
Expand Down Expand Up @@ -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)
Expand Down
12 changes: 12 additions & 0 deletions api/services/app_dsl_service.py
Original file line number Diff line number Diff line change
Expand Up @@ -87,6 +87,7 @@ def import_and_create_new_app(cls, tenant_id: str, data: str, args: dict, accoun
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"))
Expand All @@ -101,6 +102,7 @@ def import_and_create_new_app(cls, tenant_id: str, data: str, args: dict, accoun
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(
Expand All @@ -113,6 +115,7 @@ def import_and_create_new_app(cls, tenant_id: str, data: str, args: dict, accoun
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")
Expand Down Expand Up @@ -171,6 +174,7 @@ def export_dsl(cls, app_model: App, include_secret: bool = False) -> str:
"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,
},
}

Expand Down Expand Up @@ -218,6 +222,7 @@ def _import_and_create_new_workflow_based_app(
icon_type: str,
icon: str,
icon_background: str,
use_icon_as_answer_icon: bool,
) -> App:
"""
Import app dsl and create new workflow based app
Expand All @@ -231,6 +236,7 @@ def _import_and_create_new_workflow_based_app(
: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")
Expand All @@ -244,6 +250,7 @@ def _import_and_create_new_workflow_based_app(
icon_type=icon_type,
icon=icon,
icon_background=icon_background,
use_icon_as_answer_icon=use_icon_as_answer_icon,
)

# init draft workflow
Expand Down Expand Up @@ -316,6 +323,7 @@ def _import_and_create_new_model_config_based_app(
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
Expand All @@ -341,6 +349,7 @@ def _import_and_create_new_model_config_based_app(
icon_type=icon_type,
icon=icon,
icon_background=icon_background,
use_icon_as_answer_icon=use_icon_as_answer_icon,
)

app_model_config = AppModelConfig()
Expand Down Expand Up @@ -369,6 +378,7 @@ def _create_app(
icon_type: str,
icon: str,
icon_background: str,
use_icon_as_answer_icon: bool,
) -> App:
"""
Create new app
Expand All @@ -381,6 +391,7 @@ def _create_app(
: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,
Expand All @@ -392,6 +403,7 @@ def _create_app(
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,
)
Expand Down
1 change: 1 addition & 0 deletions api/services/app_service.py
Original file line number Diff line number Diff line change
Expand Up @@ -221,6 +221,7 @@ def update_app(self, app: App, args: dict) -> App:
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()
Expand Down
4 changes: 4 additions & 0 deletions web/app/(commonLayout)/apps/AppCard.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -79,6 +79,7 @@ const AppCard = ({ app, onRefresh }: AppCardProps) => {
icon,
icon_background,
description,
use_icon_as_answer_icon,
}) => {
try {
await updateAppInfo({
Expand All @@ -88,6 +89,7 @@ const AppCard = ({ app, onRefresh }: AppCardProps) => {
icon,
icon_background,
description,
use_icon_as_answer_icon,
})
setShowEditModal(false)
notify({
Expand Down Expand Up @@ -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)}
Expand Down
4 changes: 4 additions & 0 deletions web/app/components/app-sidebar/app-info.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -63,6 +63,7 @@ const AppInfo = ({ expand }: IAppInfoProps) => {
icon,
icon_background,
description,
use_icon_as_answer_icon,
}) => {
if (!appDetail)
return
Expand All @@ -74,6 +75,7 @@ const AppInfo = ({ expand }: IAppInfoProps) => {
icon,
icon_background,
description,
use_icon_as_answer_icon,
})
setShowEditModal(false)
notify({
Expand Down Expand Up @@ -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)}
Expand Down
18 changes: 18 additions & 0 deletions web/app/components/app/overview/settings/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -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
}

Expand Down Expand Up @@ -72,6 +73,7 @@ const SettingsModal: FC<ISettingsModalProps> = ({
custom_disclaimer,
default_language,
show_workflow_steps,
use_icon_as_answer_icon,
} = appInfo.site
const [inputInfo, setInputInfo] = useState({
title,
Expand All @@ -82,6 +84,7 @@ const SettingsModal: FC<ISettingsModalProps> = ({
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)
Expand All @@ -94,6 +97,7 @@ const SettingsModal: FC<ISettingsModalProps> = ({
? { 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({
Expand All @@ -105,6 +109,7 @@ const SettingsModal: FC<ISettingsModalProps> = ({
privacyPolicy: privacy_policy,
customDisclaimer: custom_disclaimer,
show_workflow_steps,
use_icon_as_answer_icon,
enable_sso: appInfo.enable_sso,
})
setLanguage(default_language)
Expand Down Expand Up @@ -157,6 +162,7 @@ const SettingsModal: FC<ISettingsModalProps> = ({
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)
Expand Down Expand Up @@ -209,6 +215,18 @@ const SettingsModal: FC<ISettingsModalProps> = ({
onChange={onChange('desc')}
placeholder={t(`${prefixSettings}.webDescPlaceholder`) as string}
/>
{isChatBot && (
<div className='w-full mt-4'>
<div className='flex justify-between items-center'>
<div className={`font-medium ${s.settingTitle} text-gray-900 `}>{t('app.answerIcon.title')}</div>
<Switch
defaultValue={inputInfo.use_icon_as_answer_icon}
onChange={v => setInputInfo({ ...inputInfo, use_icon_as_answer_icon: v })}
/>
</div>
<p className='body-xs-regular text-gray-500'>{t('app.answerIcon.description')}</p>
</div>
)}
<div className={`mt-6 mb-2 font-medium ${s.settingTitle} text-gray-900 `}>{t(`${prefixSettings}.language`)}</div>
<SimpleSelect
items={languages.filter(item => item.supported)}
Expand Down
Loading