From 54e16acee6ed4eac6f94f21b5c0b119007d1dbd3 Mon Sep 17 00:00:00 2001 From: CaptainB Date: Tue, 16 Dec 2025 16:03:46 +0800 Subject: [PATCH] feat: add application enable flag and application IDs to application model --- .../step/chat_step/i_chat_step.py | 4 +- .../step/chat_step/impl/base_chat_step.py | 49 +++- .../ai_chat_step_node/i_chat_node.py | 5 + .../ai_chat_step_node/impl/base_chat_node.py | 22 +- ...application_application_enable_and_more.py | 23 ++ apps/application/models/application.py | 2 + apps/application/serializers/application.py | 2 +- apps/application/serializers/common.py | 2 + apps/common/utils/tool_code.py | 102 ++++++-- ui/src/api/type/application.ts | 2 + .../views/application/ApplicationSetting.vue | 101 +++++++- .../component/ApplicationDialog.vue | 228 ++++++++++++++++++ ui/src/workflow/nodes/ai-chat-node/index.vue | 74 +++++- 13 files changed, 581 insertions(+), 35 deletions(-) create mode 100644 apps/application/migrations/0004_application_application_enable_and_more.py create mode 100644 ui/src/views/application/component/ApplicationDialog.vue diff --git a/apps/application/chat_pipeline/step/chat_step/i_chat_step.py b/apps/application/chat_pipeline/step/chat_step/i_chat_step.py index c278dfacc..b19a52666 100644 --- a/apps/application/chat_pipeline/step/chat_step/i_chat_step.py +++ b/apps/application/chat_pipeline/step/chat_step/i_chat_step.py @@ -88,6 +88,8 @@ class IChatStep(IBaseChatPipelineStep): mcp_source = serializers.CharField(label="MCP Source", required=False, default="referencing") tool_enable = serializers.BooleanField(label="工具是否启用", required=False, default=False) tool_ids = serializers.JSONField(label="工具ID列表", required=False, default=list) + application_enable = serializers.BooleanField(label="应用是否启用", required=False, default=False) + application_ids = serializers.JSONField(label="应用ID列表", required=False, default=list) mcp_output_enable = serializers.BooleanField(label="MCP输出是否启用", required=False, default=True) def is_valid(self, *, raise_exception=False): @@ -115,6 +117,6 @@ class IChatStep(IBaseChatPipelineStep): padding_problem_text: str = None, stream: bool = True, chat_user_id=None, chat_user_type=None, no_references_setting=None, model_params_setting=None, model_setting=None, mcp_enable=False, mcp_tool_ids=None, mcp_servers='', mcp_source="referencing", - tool_enable=False, tool_ids=None, mcp_output_enable=True, + tool_enable=False, tool_ids=None, application_enable=None, application_ids=None, mcp_output_enable=True, **kwargs): pass diff --git a/apps/application/chat_pipeline/step/chat_step/impl/base_chat_step.py b/apps/application/chat_pipeline/step/chat_step/impl/base_chat_step.py index 2d5e9b5a8..e1df2b8c6 100644 --- a/apps/application/chat_pipeline/step/chat_step/impl/base_chat_step.py +++ b/apps/application/chat_pipeline/step/chat_step/impl/base_chat_step.py @@ -7,12 +7,11 @@ @desc: 对话step Base实现 """ import json -import os import time import traceback -import uuid_utils.compat as uuid from typing import List +import uuid_utils.compat as uuid from django.db.models import QuerySet from django.http import StreamingHttpResponse from django.utils.translation import gettext as _ @@ -26,11 +25,10 @@ from application.chat_pipeline.I_base_chat_pipeline import ParagraphPipelineMode from application.chat_pipeline.pipeline_manage import PipelineManage from application.chat_pipeline.step.chat_step.i_chat_step import IChatStep, PostResponseHandler from application.flow.tools import Reasoning, mcp_response_generator -from application.models import ApplicationChatUserStats, ChatUserType +from application.models import ApplicationChatUserStats, ChatUserType, Application, ApplicationApiKey from common.utils.logger import maxkb_logger from common.utils.rsa_util import rsa_long_decrypt from common.utils.tool_code import ToolExecutor -from maxkb.const import CONFIG from models_provider.tools import get_model_instance_by_model_workspace_id from tools.models import Tool @@ -59,7 +57,6 @@ def write_context(step, manage, request_token, response_token, all_text): manage.context['answer_tokens'] = manage.context['answer_tokens'] + response_token - def event_content(response, chat_id, chat_record_id, @@ -182,6 +179,8 @@ class BaseChatStep(IChatStep): mcp_source="referencing", tool_enable=False, tool_ids=None, + application_enable=False, + application_ids=None, mcp_output_enable=True, **kwargs): chat_model = get_model_instance_by_model_workspace_id(model_id, workspace_id, @@ -193,6 +192,7 @@ class BaseChatStep(IChatStep): no_references_setting, model_setting, mcp_enable, mcp_tool_ids, mcp_servers, mcp_source, tool_enable, tool_ids, + application_enable, application_ids, mcp_output_enable) else: return self.execute_block(message_list, chat_id, problem_text, post_response_handler, chat_model, @@ -200,6 +200,7 @@ class BaseChatStep(IChatStep): manage, padding_problem_text, chat_user_id, chat_user_type, no_references_setting, model_setting, mcp_enable, mcp_tool_ids, mcp_servers, mcp_source, tool_enable, tool_ids, + application_enable, application_ids, mcp_output_enable) def get_details(self, manage, **kwargs): @@ -225,8 +226,9 @@ class BaseChatStep(IChatStep): return result def _handle_mcp_request(self, mcp_enable, tool_enable, mcp_source, mcp_servers, mcp_tool_ids, tool_ids, + application_enable, application_ids, mcp_output_enable, chat_model, message_list): - if not mcp_enable and not tool_enable: + if not mcp_enable and not tool_enable and not application_enable: return None mcp_servers_config = {} @@ -258,10 +260,25 @@ class BaseChatStep(IChatStep): params = json.loads(rsa_long_decrypt(tool.init_params)) else: params = {} - tool_config = executor.get_tool_mcp_config(tool.code, params) + tool_config = executor.get_tool_mcp_config(tool.code, params, tool.name, tool.desc) mcp_servers_config[str(tool.id)] = tool_config + if application_enable: + if application_ids and len(application_ids) > 0: + self.context['application_ids'] = application_ids + for application_id in application_ids: + app = QuerySet(Application).filter(id=application_id).first() + app_key = QuerySet(ApplicationApiKey).filter(application_id=application_id, is_active=True).first() + # TODO 处理api + if app_key is not None: + api_key = app_key.secret_key + else: + continue + executor = ToolExecutor() + app_config = executor.get_app_mcp_config(api_key, app.name, app.desc) + mcp_servers_config[str(app.id)] = app_config + if len(mcp_servers_config) > 0: return mcp_response_generator(chat_model, message_list, json.dumps(mcp_servers_config), mcp_output_enable) @@ -278,6 +295,8 @@ class BaseChatStep(IChatStep): mcp_source="referencing", tool_enable=False, tool_ids=None, + application_enable=False, + application_ids=None, mcp_output_enable=True): if paragraph_list is None: paragraph_list = [] @@ -296,7 +315,8 @@ class BaseChatStep(IChatStep): else: # 处理 MCP 请求 mcp_result = self._handle_mcp_request( - mcp_enable, tool_enable, mcp_source, mcp_servers, mcp_tool_ids, tool_ids, mcp_output_enable, chat_model, + mcp_enable, tool_enable, mcp_source, mcp_servers, mcp_tool_ids, tool_ids, application_enable, + application_ids, mcp_output_enable, chat_model, message_list, ) if mcp_result: @@ -320,10 +340,13 @@ class BaseChatStep(IChatStep): mcp_source="referencing", tool_enable=False, tool_ids=None, + application_enable=False, + application_ids=None, mcp_output_enable=True): chat_result, is_ai_chat = self.get_stream_result(message_list, chat_model, paragraph_list, no_references_setting, problem_text, mcp_enable, mcp_tool_ids, mcp_servers, mcp_source, tool_enable, tool_ids, + application_enable, application_ids, mcp_output_enable) chat_record_id = uuid.uuid7() r = StreamingHttpResponse( @@ -347,6 +370,8 @@ class BaseChatStep(IChatStep): mcp_source="referencing", tool_enable=False, tool_ids=None, + application_enable=False, + application_ids=None, mcp_output_enable=True ): if paragraph_list is None: @@ -365,7 +390,8 @@ class BaseChatStep(IChatStep): else: # 处理 MCP 请求 mcp_result = self._handle_mcp_request( - mcp_enable, tool_enable, mcp_source, mcp_servers, mcp_tool_ids, tool_ids, mcp_output_enable, + mcp_enable, tool_enable, mcp_source, mcp_servers, mcp_tool_ids, tool_ids, application_enable, + application_ids, mcp_output_enable, chat_model, message_list, ) if mcp_result: @@ -388,6 +414,8 @@ class BaseChatStep(IChatStep): mcp_source="referencing", tool_enable=False, tool_ids=None, + application_enable=False, + application_ids=None, mcp_output_enable=True): reasoning_content_enable = model_setting.get('reasoning_content_enable', False) reasoning_content_start = model_setting.get('reasoning_content_start', '') @@ -400,7 +428,8 @@ class BaseChatStep(IChatStep): chat_result, is_ai_chat = self.get_block_result(message_list, chat_model, paragraph_list, no_references_setting, problem_text, mcp_enable, mcp_tool_ids, mcp_servers, mcp_source, tool_enable, - tool_ids, mcp_output_enable) + tool_ids, application_enable, application_ids, + mcp_output_enable) if is_ai_chat: request_token = chat_model.get_num_tokens_from_messages(message_list) response_token = chat_model.get_num_tokens(chat_result.content) diff --git a/apps/application/flow/step_node/ai_chat_step_node/i_chat_node.py b/apps/application/flow/step_node/ai_chat_step_node/i_chat_node.py index edb21890e..3cc08b9ff 100644 --- a/apps/application/flow/step_node/ai_chat_step_node/i_chat_node.py +++ b/apps/application/flow/step_node/ai_chat_step_node/i_chat_node.py @@ -42,6 +42,9 @@ class ChatNodeSerializer(serializers.Serializer): tool_enable = serializers.BooleanField(required=False, default=False, label=_("Whether to enable tools")) tool_ids = serializers.ListField(child=serializers.UUIDField(), required=False, allow_empty=True, label=_("Tool IDs"), ) + application_enable = serializers.BooleanField(required=False, default=False, label=_("Whether to enable apps")) + application_ids = serializers.ListField(child=serializers.UUIDField(), required=False, allow_empty=True, + label=_("App IDs"), ) mcp_output_enable = serializers.BooleanField(required=False, default=True, label=_("Whether to enable MCP output")) @@ -73,6 +76,8 @@ class IChatNode(INode): mcp_source=None, tool_enable=False, tool_ids=None, + application_enable=False, + application_ids=None, mcp_output_enable=True, **kwargs) -> NodeResult: pass diff --git a/apps/application/flow/step_node/ai_chat_step_node/impl/base_chat_node.py b/apps/application/flow/step_node/ai_chat_step_node/impl/base_chat_node.py index 6e0b32df6..d4bcc4f96 100644 --- a/apps/application/flow/step_node/ai_chat_step_node/impl/base_chat_node.py +++ b/apps/application/flow/step_node/ai_chat_step_node/impl/base_chat_node.py @@ -7,7 +7,6 @@ @desc: """ import json -import os import re import time from functools import reduce @@ -20,9 +19,9 @@ from langchain_core.messages import BaseMessage, AIMessage from application.flow.i_step_node import NodeResult, INode from application.flow.step_node.ai_chat_step_node.i_chat_node import IChatNode from application.flow.tools import Reasoning, mcp_response_generator +from application.models import Application from common.utils.rsa_util import rsa_long_decrypt from common.utils.tool_code import ToolExecutor -from maxkb.const import CONFIG from models_provider.models import Model from models_provider.tools import get_model_credential, get_model_instance_by_model_workspace_id from tools.models import Tool @@ -160,6 +159,8 @@ class BaseChatNode(IChatNode): mcp_source=None, tool_enable=False, tool_ids=None, + application_enable=False, + application_ids=None, mcp_output_enable=True, **kwargs) -> NodeResult: if dialogue_type is None: @@ -186,7 +187,8 @@ class BaseChatNode(IChatNode): # 处理 MCP 请求 mcp_result = self._handle_mcp_request( - mcp_enable, tool_enable, mcp_source, mcp_servers, mcp_tool_id, mcp_tool_ids, tool_ids, mcp_output_enable, + mcp_enable, tool_enable, mcp_source, mcp_servers, mcp_tool_id, mcp_tool_ids, tool_ids, application_enable, + application_ids, mcp_output_enable, chat_model, message_list, history_message, question ) if mcp_result: @@ -208,8 +210,9 @@ class BaseChatNode(IChatNode): _write_context=write_context) def _handle_mcp_request(self, mcp_enable, tool_enable, mcp_source, mcp_servers, mcp_tool_id, mcp_tool_ids, tool_ids, + application_enable, application_ids, mcp_output_enable, chat_model, message_list, history_message, question): - if not mcp_enable and not tool_enable: + if not mcp_enable and not tool_enable and not application_enable: return None mcp_servers_config = {} @@ -245,10 +248,19 @@ class BaseChatNode(IChatNode): params = json.loads(rsa_long_decrypt(tool.init_params)) else: params = {} - tool_config = executor.get_tool_mcp_config(tool.code, params) + tool_config = executor.get_tool_mcp_config(tool.code, params, tool.name, tool.desc) mcp_servers_config[str(tool.id)] = tool_config + if application_enable: + if application_ids and len(application_ids) > 0: + self.context['application_ids'] = application_ids + for application_id in application_ids: + app = QuerySet(Application).filter(id=application_id).first() + executor = ToolExecutor() + app_config = executor.get_app_mcp_config(app.id, app.name, app.desc) + mcp_servers_config[str(app.id)] = app_config + if len(mcp_servers_config) > 0: r = mcp_response_generator(chat_model, message_list, json.dumps(mcp_servers_config), mcp_output_enable) return NodeResult( diff --git a/apps/application/migrations/0004_application_application_enable_and_more.py b/apps/application/migrations/0004_application_application_enable_and_more.py new file mode 100644 index 000000000..8bfa8c1d5 --- /dev/null +++ b/apps/application/migrations/0004_application_application_enable_and_more.py @@ -0,0 +1,23 @@ +# Generated by Django 5.2.9 on 2025-12-16 08:02 + +from django.db import migrations, models + + +class Migration(migrations.Migration): + + dependencies = [ + ('application', '0003_application_stt_model_params_setting_and_more'), + ] + + operations = [ + migrations.AddField( + model_name='application', + name='application_enable', + field=models.BooleanField(default=False, verbose_name='应用是否启用'), + ), + migrations.AddField( + model_name='application', + name='application_ids', + field=models.JSONField(default=list, verbose_name='应用ID列表'), + ), + ] diff --git a/apps/application/models/application.py b/apps/application/models/application.py index 0a4b73765..387f49d17 100644 --- a/apps/application/models/application.py +++ b/apps/application/models/application.py @@ -100,6 +100,8 @@ class Application(AppModelMixin): mcp_source = models.CharField(verbose_name="MCP Source", max_length=20, default="referencing") tool_enable = models.BooleanField(verbose_name="工具是否启用", default=False) tool_ids = models.JSONField(verbose_name="工具ID列表", default=list) + application_enable = models.BooleanField(verbose_name="应用是否启用", default=False) + application_ids = models.JSONField(verbose_name="应用ID列表", default=list) mcp_output_enable = models.BooleanField(verbose_name="MCP输出是否启用", default=True) @staticmethod diff --git a/apps/application/serializers/application.py b/apps/application/serializers/application.py index dfa5f897c..c92eb2db5 100644 --- a/apps/application/serializers/application.py +++ b/apps/application/serializers/application.py @@ -857,7 +857,7 @@ class ApplicationOperateSerializer(serializers.Serializer): 'api_key_is_active', 'icon', 'work_flow', 'model_params_setting', 'tts_model_params_setting', 'stt_model_params_setting', 'mcp_enable', 'mcp_tool_ids', 'mcp_servers', 'mcp_source', 'tool_enable', 'tool_ids', - 'mcp_output_enable', + 'mcp_output_enable', 'application_enable', 'application_ids', 'problem_optimization_prompt', 'clean_time', 'folder_id'] for update_key in update_keys: if update_key in instance and instance.get(update_key) is not None: diff --git a/apps/application/serializers/common.py b/apps/application/serializers/common.py index b7ac4c5e4..3408350dd 100644 --- a/apps/application/serializers/common.py +++ b/apps/application/serializers/common.py @@ -162,6 +162,8 @@ class ChatInfo: 'mcp_source': self.application.mcp_source, 'tool_enable': self.application.tool_enable, 'tool_ids': self.application.tool_ids, + 'application_enable': self.application.application_enable, + 'application_ids': self.application.application_ids, 'mcp_output_enable': self.application.mcp_output_enable, } diff --git a/apps/common/utils/tool_code.py b/apps/common/utils/tool_code.py index a5b29af1c..152ed9f8d 100644 --- a/apps/common/utils/tool_code.py +++ b/apps/common/utils/tool_code.py @@ -1,33 +1,40 @@ # coding=utf-8 import ast import base64 +import getpass import gzip import json import os +import pwd +import random +import resource import socket import subprocess import sys import tempfile -import pwd -import resource -import getpass -import random import time -import uuid_utils.compat as uuid from contextlib import contextmanager -from common.utils.logger import maxkb_logger +from textwrap import dedent + +import uuid_utils.compat as uuid from django.utils.translation import gettext_lazy as _ + +from common.utils.logger import maxkb_logger from maxkb.const import BASE_DIR, CONFIG from maxkb.const import PROJECT_DIR -from textwrap import dedent _enable_sandbox = bool(CONFIG.get('SANDBOX', 0)) _run_user = 'sandbox' if _enable_sandbox else getpass.getuser() -_sandbox_path = CONFIG.get("SANDBOX_HOME", '/opt/maxkb-app/sandbox') if _enable_sandbox else os.path.join(PROJECT_DIR, 'data', 'sandbox') +_sandbox_path = CONFIG.get("SANDBOX_HOME", '/opt/maxkb-app/sandbox') if _enable_sandbox else os.path.join(PROJECT_DIR, + 'data', + 'sandbox') _process_limit_timeout_seconds = int(CONFIG.get("SANDBOX_PYTHON_PROCESS_LIMIT_TIMEOUT_SECONDS", '3600')) -_process_limit_cpu_cores = min(max(int(CONFIG.get("SANDBOX_PYTHON_PROCESS_LIMIT_CPU_CORES", '1')), 1), len(os.sched_getaffinity(0))) if sys.platform.startswith("linux") else os.cpu_count() # 只支持linux,window和mac不支持 +_process_limit_cpu_cores = min(max(int(CONFIG.get("SANDBOX_PYTHON_PROCESS_LIMIT_CPU_CORES", '1')), 1), + len(os.sched_getaffinity(0))) if sys.platform.startswith( + "linux") else os.cpu_count() # 只支持linux,window和mac不支持 _process_limit_mem_mb = int(CONFIG.get("SANDBOX_PYTHON_PROCESS_LIMIT_MEM_MB", '256')) + class ToolExecutor: def __init__(self): @@ -124,7 +131,7 @@ sys.stdout.flush() return result.get('data') raise Exception(result.get('msg') + (f'\n{subprocess_result.stderr}' if subprocess_result.stderr else '')) - def _generate_mcp_server_code(self, _code, params): + def _generate_mcp_server_code(self, _code, params, name=None, description=None): # 解析代码,提取导入语句和函数定义 try: tree = ast.parse(_code) @@ -139,6 +146,9 @@ sys.stdout.flush() if isinstance(node, ast.Import) or isinstance(node, ast.ImportFrom): imports.append(ast.unparse(node)) elif isinstance(node, ast.FunctionDef): + if node.name.startswith('_'): + other_code.append(ast.unparse(node)) + continue # 修改函数参数以包含 params 中的默认值 arg_names = [arg.arg for arg in node.args.args] @@ -173,7 +183,7 @@ sys.stdout.flush() node.args.defaults = defaults func_code = ast.unparse(node) - functions.append(f"@mcp.tool()\n{func_code}\n") + functions.append(f"@mcp.tool(name='{name}', description='{description}')\n{func_code}\n") else: other_code.append(ast.unparse(node)) @@ -187,9 +197,9 @@ sys.stdout.flush() return "\n".join(code_parts) - def generate_mcp_server_code(self, code_str, params): + def generate_mcp_server_code(self, code_str, params, name, description): python_paths = CONFIG.get_sandbox_python_package_paths().split(',') - code = self._generate_mcp_server_code(code_str, params) + code = self._generate_mcp_server_code(code_str, params, name, description) set_run_user = f'os.setgid({pwd.getpwnam(_run_user).pw_gid});os.setuid({pwd.getpwnam(_run_user).pw_uid});' if _enable_sandbox else '' return f""" import os, sys, logging @@ -204,8 +214,8 @@ os.environ.clear() exec({dedent(code)!a}) """ - def get_tool_mcp_config(self, code, params): - _code = self.generate_mcp_server_code(code, params) + def get_tool_mcp_config(self, code, params, name, description): + _code = self.generate_mcp_server_code(code, params, name, description) maxkb_logger.debug(f"Python code of mcp tool: {_code}") compressed_and_base64_encoded_code_str = base64.b64encode(gzip.compress(_code.encode())).decode() tool_config = { @@ -222,6 +232,66 @@ exec({dedent(code)!a}) } return tool_config + def get_app_mcp_config(self, api_key, name, description): + chat_path = CONFIG.get_chat_path() + _code = f''' +import requests +from typing import Optional + +def _get_chat_id() -> Optional[str]: + url = f"http://127.0.0.1:8080/{chat_path}/api/open" + headers = {{ + 'accept': '*/*', + 'Authorization': f'Bearer {api_key}' + }} + try: + resp = requests.get(url, headers=headers, timeout=10) + resp.raise_for_status() + return resp.json().get("data") + except Exception as e: + raise e + + +def _chat_with_ai(chat_id: str, message: str) -> Optional[str]: + url = f"http://127.0.0.1:8080/{chat_path}/api/chat_message/{{chat_id}}" + headers = {{"Content-Type": "application/json", "Authorization": f'Bearer {api_key}'}} + payload = {{ + "message": message, + "re_chat": False, + "stream": False + }} + try: + resp = requests.post(url, json=payload, headers=headers, timeout=600) + resp.raise_for_status() + data = resp.json() + return str(data.get("data", {{}}).get("content") or data.get("response")) + except Exception as e: + raise e + +def ai_chat(message: str) -> str: + chat_id = _get_chat_id() + reply = _chat_with_ai(chat_id, message) + return reply or "AI 未能生成回复" + + ''' + _code = self.generate_mcp_server_code(_code, {}, name, description) + # print(_code) + maxkb_logger.debug(f"Python code of mcp app: {_code}") + compressed_and_base64_encoded_code_str = base64.b64encode(gzip.compress(_code.encode())).decode() + app_config = { + 'command': sys.executable, + 'args': [ + '-c', + f'import base64,gzip; exec(gzip.decompress(base64.b64decode(\'{compressed_and_base64_encoded_code_str}\')).decode())', + ], + 'cwd': _sandbox_path, + 'env': { + 'LD_PRELOAD': f'{_sandbox_path}/lib/sandbox.so', + }, + 'transport': 'stdio', + } + return app_config + def _exec(self, execute_file): kwargs = {'cwd': BASE_DIR, 'env': { 'LD_PRELOAD': f'{_sandbox_path}/lib/sandbox.so', @@ -255,4 +325,4 @@ def execution_timer(id=""): try: yield finally: - maxkb_logger.debug(f"Tool execution({id}) takes {time.perf_counter() - start:.6f} seconds.") \ No newline at end of file + maxkb_logger.debug(f"Tool execution({id}) takes {time.perf_counter() - start:.6f} seconds.") diff --git a/ui/src/api/type/application.ts b/ui/src/api/type/application.ts index 4961e1002..3fe18567e 100644 --- a/ui/src/api/type/application.ts +++ b/ui/src/api/type/application.ts @@ -34,6 +34,8 @@ interface ApplicationFormType { mcp_source?: string tool_enable?: boolean tool_ids?: string[] + application_enable?: boolean + application_ids?: string[] mcp_output_enable?: boolean } diff --git a/ui/src/views/application/ApplicationSetting.vue b/ui/src/views/application/ApplicationSetting.vue index 6daddece3..8b444361b 100644 --- a/ui/src/views/application/ApplicationSetting.vue +++ b/ui/src/views/application/ApplicationSetting.vue @@ -433,9 +433,73 @@ + + + + +
+ +
diff --git a/ui/src/views/application/component/ApplicationDialog.vue b/ui/src/views/application/component/ApplicationDialog.vue new file mode 100644 index 000000000..b007fbcf8 --- /dev/null +++ b/ui/src/views/application/component/ApplicationDialog.vue @@ -0,0 +1,228 @@ + + + diff --git a/ui/src/workflow/nodes/ai-chat-node/index.vue b/ui/src/workflow/nodes/ai-chat-node/index.vue index 6f37d62af..b94fa1146 100644 --- a/ui/src/workflow/nodes/ai-chat-node/index.vue +++ b/ui/src/workflow/nodes/ai-chat-node/index.vue @@ -252,7 +252,49 @@ - + +
+
{{ $t('views.application.title') }}
+
+ + + + +
+
+
+ +
+