feat: custom app icon (#7196)
Co-authored-by: crazywoola <427733928@qq.com>
This commit is contained in:
@@ -61,6 +61,7 @@ class AppListApi(Resource):
|
||||
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()
|
||||
@@ -94,6 +95,7 @@ class AppImportApi(Resource):
|
||||
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()
|
||||
@@ -167,6 +169,7 @@ class AppApi(Resource):
|
||||
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')
|
||||
@@ -208,6 +211,7 @@ class AppCopyApi(Resource):
|
||||
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()
|
||||
|
@@ -16,6 +16,7 @@ from models.model import Site
|
||||
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')
|
||||
@@ -53,6 +54,7 @@ class AppSite(Resource):
|
||||
|
||||
for attr_name in [
|
||||
'title',
|
||||
'icon_type',
|
||||
'icon',
|
||||
'icon_background',
|
||||
'description',
|
||||
|
@@ -459,6 +459,7 @@ class ConvertToWorkflowApi(Resource):
|
||||
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()
|
||||
|
@@ -6,6 +6,7 @@ from configs import dify_config
|
||||
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
|
||||
@@ -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,
|
||||
|
@@ -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,
|
||||
|
@@ -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 = {
|
||||
@@ -71,8 +73,10 @@ app_partial_fields = {
|
||||
"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)),
|
||||
@@ -104,8 +108,10 @@ site_fields = {
|
||||
"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,
|
||||
@@ -125,8 +131,10 @@ app_detail_fields_with_site = {
|
||||
"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),
|
||||
|
@@ -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 = {
|
||||
|
@@ -16,6 +16,7 @@ from flask import Response, current_app, stream_with_context
|
||||
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
|
||||
|
||||
@@ -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())
|
||||
|
@@ -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 ###
|
@@ -51,6 +51,10 @@ class AppMode(Enum):
|
||||
raise ValueError(f'invalid mode value {value}')
|
||||
|
||||
|
||||
class IconType(Enum):
|
||||
IMAGE = "image"
|
||||
EMOJI = "emoji"
|
||||
|
||||
class App(db.Model):
|
||||
__tablename__ = 'apps'
|
||||
__table_args__ = (
|
||||
@@ -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)
|
||||
@@ -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)
|
||||
|
@@ -82,6 +82,7 @@ class AppDslService:
|
||||
# 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')
|
||||
@@ -96,6 +97,7 @@ class AppDslService:
|
||||
account=account,
|
||||
name=name,
|
||||
description=description,
|
||||
icon_type=icon_type,
|
||||
icon=icon,
|
||||
icon_background=icon_background
|
||||
)
|
||||
@@ -107,6 +109,7 @@ class AppDslService:
|
||||
account=account,
|
||||
name=name,
|
||||
description=description,
|
||||
icon_type=icon_type,
|
||||
icon=icon,
|
||||
icon_background=icon_background
|
||||
)
|
||||
@@ -165,8 +168,8 @@ class AppDslService:
|
||||
"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
|
||||
}
|
||||
}
|
||||
@@ -207,6 +210,7 @@ class AppDslService:
|
||||
account: Account,
|
||||
name: str,
|
||||
description: str,
|
||||
icon_type: str,
|
||||
icon: str,
|
||||
icon_background: str) -> App:
|
||||
"""
|
||||
@@ -218,6 +222,7 @@ class AppDslService:
|
||||
: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
|
||||
"""
|
||||
@@ -231,6 +236,7 @@ class AppDslService:
|
||||
account=account,
|
||||
name=name,
|
||||
description=description,
|
||||
icon_type=icon_type,
|
||||
icon=icon,
|
||||
icon_background=icon_background
|
||||
)
|
||||
@@ -307,6 +313,7 @@ class AppDslService:
|
||||
account: Account,
|
||||
name: str,
|
||||
description: str,
|
||||
icon_type: str,
|
||||
icon: str,
|
||||
icon_background: str) -> App:
|
||||
"""
|
||||
@@ -331,6 +338,7 @@ class AppDslService:
|
||||
account=account,
|
||||
name=name,
|
||||
description=description,
|
||||
icon_type=icon_type,
|
||||
icon=icon,
|
||||
icon_background=icon_background
|
||||
)
|
||||
@@ -358,6 +366,7 @@ class AppDslService:
|
||||
account: Account,
|
||||
name: str,
|
||||
description: str,
|
||||
icon_type: str,
|
||||
icon: str,
|
||||
icon_background: str) -> App:
|
||||
"""
|
||||
@@ -368,6 +377,7 @@ class AppDslService:
|
||||
: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
|
||||
"""
|
||||
@@ -376,6 +386,7 @@ class AppDslService:
|
||||
mode=app_mode.value,
|
||||
name=name,
|
||||
description=description,
|
||||
icon_type=icon_type,
|
||||
icon=icon,
|
||||
icon_background=icon_background,
|
||||
enable_site=True,
|
||||
|
@@ -119,6 +119,7 @@ class AppService:
|
||||
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
|
||||
@@ -210,6 +211,7 @@ class AppService:
|
||||
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)
|
||||
|
@@ -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:
|
||||
"""
|
||||
@@ -50,6 +51,7 @@ class WorkflowConverter:
|
||||
: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
|
||||
"""
|
||||
@@ -66,6 +68,7 @@ class WorkflowConverter:
|
||||
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
|
||||
|
@@ -302,6 +302,7 @@ class WorkflowService:
|
||||
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'),
|
||||
)
|
||||
|
Reference in New Issue
Block a user