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: custom app icon #7196

Merged
merged 20 commits into from
Aug 19, 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
4 changes: 4 additions & 0 deletions api/controllers/console/app/app.py
Original file line number Diff line number Diff line change
Expand Up @@ -61,6 +61,7 @@ def post(self):
parser.add_argument('name', type=str, required=True, location='json')
parser.add_argument('description', type=str, location='json')
parser.add_argument('mode', type=str, choices=ALLOW_CREATE_APP_MODES, location='json')
parser.add_argument('icon_type', type=str, location='json')
parser.add_argument('icon', type=str, location='json')
parser.add_argument('icon_background', type=str, location='json')
args = parser.parse_args()
Expand Down Expand Up @@ -94,6 +95,7 @@ def post(self):
parser.add_argument('data', type=str, required=True, nullable=False, location='json')
parser.add_argument('name', type=str, location='json')
parser.add_argument('description', type=str, location='json')
parser.add_argument('icon_type', type=str, location='json')
parser.add_argument('icon', type=str, location='json')
parser.add_argument('icon_background', type=str, location='json')
args = parser.parse_args()
Expand Down Expand Up @@ -167,6 +169,7 @@ def put(self, app_model):
parser = reqparse.RequestParser()
parser.add_argument('name', type=str, required=True, nullable=False, location='json')
parser.add_argument('description', type=str, location='json')
parser.add_argument('icon_type', type=str, location='json')
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')
Expand Down Expand Up @@ -208,6 +211,7 @@ def post(self, app_model):
parser = reqparse.RequestParser()
parser.add_argument('name', type=str, location='json')
parser.add_argument('description', type=str, location='json')
parser.add_argument('icon_type', type=str, location='json')
parser.add_argument('icon', type=str, location='json')
parser.add_argument('icon_background', type=str, location='json')
args = parser.parse_args()
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 @@ -16,6 +16,7 @@
def parse_app_site_args():
parser = reqparse.RequestParser()
parser.add_argument('title', type=str, required=False, location='json')
parser.add_argument('icon_type', type=str, required=False, location='json')
parser.add_argument('icon', type=str, required=False, location='json')
parser.add_argument('icon_background', type=str, required=False, location='json')
parser.add_argument('description', type=str, required=False, location='json')
Expand Down Expand Up @@ -53,6 +54,7 @@ def post(self, app_model):

for attr_name in [
'title',
'icon_type',
'icon',
'icon_background',
'description',
Expand Down
1 change: 1 addition & 0 deletions api/controllers/console/app/workflow.py
Original file line number Diff line number Diff line change
Expand Up @@ -459,6 +459,7 @@ def post(self, app_model: App):
if request.data:
parser = reqparse.RequestParser()
parser.add_argument('name', type=str, required=False, nullable=True, location='json')
parser.add_argument('icon_type', type=str, required=False, nullable=True, location='json')
parser.add_argument('icon', type=str, required=False, nullable=True, location='json')
parser.add_argument('icon_background', type=str, required=False, nullable=True, location='json')
args = parser.parse_args()
Expand Down
3 changes: 3 additions & 0 deletions api/controllers/web/site.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@
from controllers.web import api
from controllers.web.wraps import WebApiResource
from extensions.ext_database import db
from libs.helper import AppIconUrlField
from models.account import TenantStatus
from models.model import Site
from services.feature_service import FeatureService
Expand All @@ -28,8 +29,10 @@ class AppSiteApi(WebApiResource):
'title': fields.String,
'chat_color_theme': fields.String,
'chat_color_theme_inverted': fields.Boolean,
'icon_type': fields.String,
'icon': fields.String,
'icon_background': fields.String,
'icon_url': AppIconUrlField,
'description': fields.String,
'copyright': fields.String,
'privacy_policy': fields.String,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ def handle(sender, **kwargs):
site = Site(
app_id=app.id,
title=app.name,
icon_type=app.icon_type,
icon=app.icon,
icon_background=app.icon_background,
default_language=account.interface_language,
Expand Down
10 changes: 9 additions & 1 deletion api/fields/app_fields.py
Original file line number Diff line number Diff line change
@@ -1,14 +1,16 @@
from flask_restful import fields

from libs.helper import TimestampField
from libs.helper import AppIconUrlField, TimestampField

app_detail_kernel_fields = {
"id": fields.String,
"name": fields.String,
"description": fields.String,
"mode": fields.String(attribute="mode_compatible_with_agent"),
"icon_type": fields.String,
"icon": fields.String,
"icon_background": fields.String,
"icon_url": AppIconUrlField,
}

related_app_list = {
Expand Down Expand Up @@ -71,8 +73,10 @@
"max_active_requests": fields.Raw(),
"description": fields.String(attribute="desc_or_prompt"),
"mode": fields.String(attribute="mode_compatible_with_agent"),
"icon_type": fields.String,
"icon": fields.String,
"icon_background": fields.String,
"icon_url": AppIconUrlField,
"model_config": fields.Nested(model_config_partial_fields, attribute="app_model_config", allow_null=True),
"created_at": TimestampField,
"tags": fields.List(fields.Nested(tag_fields)),
Expand Down Expand Up @@ -104,8 +108,10 @@
"access_token": fields.String(attribute="code"),
"code": fields.String,
"title": fields.String,
"icon_type": fields.String,
"icon": fields.String,
"icon_background": fields.String,
"icon_url": AppIconUrlField,
"description": fields.String,
"default_language": fields.String,
"chat_color_theme": fields.String,
Expand All @@ -125,8 +131,10 @@
"name": fields.String,
"description": fields.String,
"mode": fields.String(attribute="mode_compatible_with_agent"),
"icon_type": fields.String,
"icon": fields.String,
"icon_background": fields.String,
"icon_url": AppIconUrlField,
"enable_site": fields.Boolean,
"enable_api": fields.Boolean,
"model_config": fields.Nested(model_config_fields, attribute="app_model_config", allow_null=True),
Expand Down
4 changes: 3 additions & 1 deletion api/fields/installed_app_fields.py
Original file line number Diff line number Diff line change
@@ -1,13 +1,15 @@
from flask_restful import fields

from libs.helper import TimestampField
from libs.helper import AppIconUrlField, TimestampField

app_fields = {
"id": fields.String,
"name": fields.String,
"mode": fields.String,
"icon_type": fields.String,
"icon": fields.String,
"icon_background": fields.String,
"icon_url": AppIconUrlField,
}

installed_app_fields = {
Expand Down
13 changes: 13 additions & 0 deletions api/libs/helper.py
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@
from flask_restful import fields

from core.app.features.rate_limiting.rate_limit import RateLimitGenerator
from core.file.upload_file_parser import UploadFileParser
from extensions.ext_redis import redis_client
from models.account import Account

Expand All @@ -24,6 +25,18 @@ def run(script):
return subprocess.getstatusoutput("source /root/.bashrc && " + script)


class AppIconUrlField(fields.Raw):
def output(self, key, obj):
if obj is None:
return None

from models.model import IconType

if obj.icon_type == IconType.IMAGE.value:
return UploadFileParser.get_signed_temp_image_url(obj.icon)
return None


class TimestampField(fields.Raw):
def format(self, value) -> int:
return int(value.timestamp())
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
"""app and site icon type

Revision ID: a6be81136580
Revises: 8782057ff0dc
Create Date: 2024-08-15 10:01:24.697888

"""
import sqlalchemy as sa
from alembic import op

import models as models

# revision identifiers, used by Alembic.
revision = 'a6be81136580'
down_revision = '8782057ff0dc'
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('icon_type', sa.String(length=255), nullable=True))

with op.batch_alter_table('sites', schema=None) as batch_op:
batch_op.add_column(sa.Column('icon_type', sa.String(length=255), nullable=True))

# ### 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('icon_type')

with op.batch_alter_table('apps', schema=None) as batch_op:
batch_op.drop_column('icon_type')

# ### end Alembic commands ###
6 changes: 6 additions & 0 deletions api/models/model.py
Original file line number Diff line number Diff line change
Expand Up @@ -51,6 +51,10 @@ def value_of(cls, value: str) -> 'AppMode':
raise ValueError(f'invalid mode value {value}')


class IconType(Enum):
IMAGE = "image"
EMOJI = "emoji"

class App(db.Model):
__tablename__ = 'apps'
__table_args__ = (
Expand All @@ -63,6 +67,7 @@ class App(db.Model):
name = db.Column(db.String(255), nullable=False)
description = db.Column(db.Text, nullable=False, server_default=db.text("''::character varying"))
mode = db.Column(db.String(255), nullable=False)
icon_type = db.Column(db.String(255), nullable=True)
icon = db.Column(db.String(255))
icon_background = db.Column(db.String(255))
app_model_config_id = db.Column(StringUUID, nullable=True)
Expand Down Expand Up @@ -1087,6 +1092,7 @@ class Site(db.Model):
id = db.Column(StringUUID, server_default=db.text('uuid_generate_v4()'))
app_id = db.Column(StringUUID, nullable=False)
title = db.Column(db.String(255), nullable=False)
icon_type = db.Column(db.String(255), nullable=True)
icon = db.Column(db.String(255))
icon_background = db.Column(db.String(255))
description = db.Column(db.Text)
Expand Down
15 changes: 13 additions & 2 deletions api/services/app_dsl_service.py
Original file line number Diff line number Diff line change
Expand Up @@ -82,6 +82,7 @@ def import_and_create_new_app(cls, tenant_id: str, data: str, args: dict, accoun
# get app basic info
name = args.get("name") if args.get("name") else app_data.get('name')
description = args.get("description") if args.get("description") else app_data.get('description', '')
icon_type = args.get("icon_type") if args.get("icon_type") else app_data.get('icon_type')
icon = args.get("icon") if args.get("icon") else app_data.get('icon')
icon_background = args.get("icon_background") if args.get("icon_background") \
else app_data.get('icon_background')
Expand All @@ -96,6 +97,7 @@ def import_and_create_new_app(cls, tenant_id: str, data: str, args: dict, accoun
account=account,
name=name,
description=description,
icon_type=icon_type,
icon=icon,
icon_background=icon_background
)
Expand All @@ -107,6 +109,7 @@ def import_and_create_new_app(cls, tenant_id: str, data: str, args: dict, accoun
account=account,
name=name,
description=description,
icon_type=icon_type,
icon=icon,
icon_background=icon_background
)
Expand Down Expand Up @@ -165,8 +168,8 @@ def export_dsl(cls, app_model: App, include_secret:bool = False) -> str:
"app": {
"name": app_model.name,
"mode": app_model.mode,
"icon": app_model.icon,
"icon_background": app_model.icon_background,
"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
}
}
Expand Down Expand Up @@ -207,6 +210,7 @@ def _import_and_create_new_workflow_based_app(cls,
account: Account,
name: str,
description: str,
icon_type: str,
icon: str,
icon_background: str) -> App:
"""
Expand All @@ -218,6 +222,7 @@ def _import_and_create_new_workflow_based_app(cls,
:param account: Account instance
:param name: app name
:param description: app description
:param icon_type: app icon type, "emoji" or "image"
:param icon: app icon
:param icon_background: app icon background
"""
Expand All @@ -231,6 +236,7 @@ def _import_and_create_new_workflow_based_app(cls,
account=account,
name=name,
description=description,
icon_type=icon_type,
icon=icon,
icon_background=icon_background
)
Expand Down Expand Up @@ -307,6 +313,7 @@ def _import_and_create_new_model_config_based_app(cls,
account: Account,
name: str,
description: str,
icon_type: str,
icon: str,
icon_background: str) -> App:
"""
Expand All @@ -331,6 +338,7 @@ def _import_and_create_new_model_config_based_app(cls,
account=account,
name=name,
description=description,
icon_type=icon_type,
icon=icon,
icon_background=icon_background
)
Expand Down Expand Up @@ -358,6 +366,7 @@ def _create_app(cls,
account: Account,
name: str,
description: str,
icon_type: str,
icon: str,
icon_background: str) -> App:
"""
Expand All @@ -368,6 +377,7 @@ def _create_app(cls,
:param account: Account instance
:param name: app name
:param description: app description
:param icon_type: app icon type, "emoji" or "image"
:param icon: app icon
:param icon_background: app icon background
"""
Expand All @@ -376,6 +386,7 @@ def _create_app(cls,
mode=app_mode.value,
name=name,
description=description,
icon_type=icon_type,
icon=icon,
icon_background=icon_background,
enable_site=True,
Expand Down
2 changes: 2 additions & 0 deletions api/services/app_service.py
Original file line number Diff line number Diff line change
Expand Up @@ -119,6 +119,7 @@ def create_app(self, tenant_id: str, args: dict, account: Account) -> App:
app.name = args['name']
app.description = args.get('description', '')
app.mode = args['mode']
app.icon_type = args.get('icon_type', 'emoji')
app.icon = args['icon']
app.icon_background = args['icon_background']
app.tenant_id = tenant_id
Expand Down Expand Up @@ -210,6 +211,7 @@ def update_app(self, app: App, args: dict) -> App:
app.name = args.get('name')
app.description = args.get('description', '')
app.max_active_requests = args.get('max_active_requests')
app.icon_type = args.get('icon_type', 'emoji')
app.icon = args.get('icon')
app.icon_background = args.get('icon_background')
app.updated_at = datetime.now(timezone.utc).replace(tzinfo=None)
Expand Down
3 changes: 3 additions & 0 deletions api/services/workflow/workflow_converter.py
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,7 @@ class WorkflowConverter:
def convert_to_workflow(self, app_model: App,
account: Account,
name: str,
icon_type: str,
icon: str,
icon_background: str) -> App:
"""
Expand All @@ -50,6 +51,7 @@ def convert_to_workflow(self, app_model: App,
:param account: Account
:param name: new app name
:param icon: new app icon
:param icon_type: new app icon type
:param icon_background: new app icon background
:return: new App instance
"""
Expand All @@ -66,6 +68,7 @@ def convert_to_workflow(self, app_model: App,
new_app.name = name if name else app_model.name + '(workflow)'
new_app.mode = AppMode.ADVANCED_CHAT.value \
if app_model.mode == AppMode.CHAT.value else AppMode.WORKFLOW.value
new_app.icon_type = icon_type if icon_type else app_model.icon_type
new_app.icon = icon if icon else app_model.icon
new_app.icon_background = icon_background if icon_background else app_model.icon_background
new_app.enable_site = app_model.enable_site
Expand Down
1 change: 1 addition & 0 deletions api/services/workflow_service.py
Original file line number Diff line number Diff line change
Expand Up @@ -302,6 +302,7 @@ def convert_to_workflow(self, app_model: App, account: Account, args: dict) -> A
app_model=app_model,
account=account,
name=args.get('name'),
icon_type=args.get('icon_type'),
icon=args.get('icon'),
icon_background=args.get('icon_background'),
)
Expand Down
Loading