mirror of
https://git.mirrors.martin98.com/https://github.com/langgenius/dify.git
synced 2025-06-04 11:14:10 +08:00
feat: fetch app info in plugins (#18202)
This commit is contained in:
parent
e912928cce
commit
358fd28c28
@ -4,14 +4,10 @@ import platform
|
|||||||
import re
|
import re
|
||||||
import urllib.parse
|
import urllib.parse
|
||||||
import warnings
|
import warnings
|
||||||
from collections.abc import Mapping
|
|
||||||
from typing import Any
|
|
||||||
from uuid import uuid4
|
from uuid import uuid4
|
||||||
|
|
||||||
import httpx
|
import httpx
|
||||||
|
|
||||||
from constants import DEFAULT_FILE_NUMBER_LIMITS
|
|
||||||
|
|
||||||
try:
|
try:
|
||||||
import magic
|
import magic
|
||||||
except ImportError:
|
except ImportError:
|
||||||
@ -31,8 +27,6 @@ except ImportError:
|
|||||||
|
|
||||||
from pydantic import BaseModel
|
from pydantic import BaseModel
|
||||||
|
|
||||||
from configs import dify_config
|
|
||||||
|
|
||||||
|
|
||||||
class FileInfo(BaseModel):
|
class FileInfo(BaseModel):
|
||||||
filename: str
|
filename: str
|
||||||
@ -89,38 +83,3 @@ def guess_file_info_from_response(response: httpx.Response):
|
|||||||
mimetype=mimetype,
|
mimetype=mimetype,
|
||||||
size=int(response.headers.get("Content-Length", -1)),
|
size=int(response.headers.get("Content-Length", -1)),
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
def get_parameters_from_feature_dict(*, features_dict: Mapping[str, Any], user_input_form: list[dict[str, Any]]):
|
|
||||||
return {
|
|
||||||
"opening_statement": features_dict.get("opening_statement"),
|
|
||||||
"suggested_questions": features_dict.get("suggested_questions", []),
|
|
||||||
"suggested_questions_after_answer": features_dict.get("suggested_questions_after_answer", {"enabled": False}),
|
|
||||||
"speech_to_text": features_dict.get("speech_to_text", {"enabled": False}),
|
|
||||||
"text_to_speech": features_dict.get("text_to_speech", {"enabled": False}),
|
|
||||||
"retriever_resource": features_dict.get("retriever_resource", {"enabled": False}),
|
|
||||||
"annotation_reply": features_dict.get("annotation_reply", {"enabled": False}),
|
|
||||||
"more_like_this": features_dict.get("more_like_this", {"enabled": False}),
|
|
||||||
"user_input_form": user_input_form,
|
|
||||||
"sensitive_word_avoidance": features_dict.get(
|
|
||||||
"sensitive_word_avoidance", {"enabled": False, "type": "", "configs": []}
|
|
||||||
),
|
|
||||||
"file_upload": features_dict.get(
|
|
||||||
"file_upload",
|
|
||||||
{
|
|
||||||
"image": {
|
|
||||||
"enabled": False,
|
|
||||||
"number_limits": DEFAULT_FILE_NUMBER_LIMITS,
|
|
||||||
"detail": "high",
|
|
||||||
"transfer_methods": ["remote_url", "local_file"],
|
|
||||||
}
|
|
||||||
},
|
|
||||||
),
|
|
||||||
"system_parameters": {
|
|
||||||
"image_file_size_limit": dify_config.UPLOAD_IMAGE_FILE_SIZE_LIMIT,
|
|
||||||
"video_file_size_limit": dify_config.UPLOAD_VIDEO_FILE_SIZE_LIMIT,
|
|
||||||
"audio_file_size_limit": dify_config.UPLOAD_AUDIO_FILE_SIZE_LIMIT,
|
|
||||||
"file_size_limit": dify_config.UPLOAD_FILE_SIZE_LIMIT,
|
|
||||||
"workflow_file_upload_limit": dify_config.WORKFLOW_FILE_UPLOAD_LIMIT,
|
|
||||||
},
|
|
||||||
}
|
|
||||||
|
@ -1,10 +1,10 @@
|
|||||||
from flask_restful import marshal_with # type: ignore
|
from flask_restful import marshal_with # type: ignore
|
||||||
|
|
||||||
from controllers.common import fields
|
from controllers.common import fields
|
||||||
from controllers.common import helpers as controller_helpers
|
|
||||||
from controllers.console import api
|
from controllers.console import api
|
||||||
from controllers.console.app.error import AppUnavailableError
|
from controllers.console.app.error import AppUnavailableError
|
||||||
from controllers.console.explore.wraps import InstalledAppResource
|
from controllers.console.explore.wraps import InstalledAppResource
|
||||||
|
from core.app.app_config.common.parameters_mapping import get_parameters_from_feature_dict
|
||||||
from models.model import AppMode, InstalledApp
|
from models.model import AppMode, InstalledApp
|
||||||
from services.app_service import AppService
|
from services.app_service import AppService
|
||||||
|
|
||||||
@ -36,9 +36,7 @@ class AppParameterApi(InstalledAppResource):
|
|||||||
|
|
||||||
user_input_form = features_dict.get("user_input_form", [])
|
user_input_form = features_dict.get("user_input_form", [])
|
||||||
|
|
||||||
return controller_helpers.get_parameters_from_feature_dict(
|
return get_parameters_from_feature_dict(features_dict=features_dict, user_input_form=user_input_form)
|
||||||
features_dict=features_dict, user_input_form=user_input_form
|
|
||||||
)
|
|
||||||
|
|
||||||
|
|
||||||
class ExploreAppMetaApi(InstalledAppResource):
|
class ExploreAppMetaApi(InstalledAppResource):
|
||||||
|
@ -13,6 +13,7 @@ from core.plugin.backwards_invocation.model import PluginModelBackwardsInvocatio
|
|||||||
from core.plugin.backwards_invocation.node import PluginNodeBackwardsInvocation
|
from core.plugin.backwards_invocation.node import PluginNodeBackwardsInvocation
|
||||||
from core.plugin.backwards_invocation.tool import PluginToolBackwardsInvocation
|
from core.plugin.backwards_invocation.tool import PluginToolBackwardsInvocation
|
||||||
from core.plugin.entities.request import (
|
from core.plugin.entities.request import (
|
||||||
|
RequestFetchAppInfo,
|
||||||
RequestInvokeApp,
|
RequestInvokeApp,
|
||||||
RequestInvokeEncrypt,
|
RequestInvokeEncrypt,
|
||||||
RequestInvokeLLM,
|
RequestInvokeLLM,
|
||||||
@ -278,6 +279,17 @@ class PluginUploadFileRequestApi(Resource):
|
|||||||
return BaseBackwardsInvocationResponse(data={"url": url}).model_dump()
|
return BaseBackwardsInvocationResponse(data={"url": url}).model_dump()
|
||||||
|
|
||||||
|
|
||||||
|
class PluginFetchAppInfoApi(Resource):
|
||||||
|
@setup_required
|
||||||
|
@plugin_inner_api_only
|
||||||
|
@get_user_tenant
|
||||||
|
@plugin_data(payload_type=RequestFetchAppInfo)
|
||||||
|
def post(self, user_model: Account | EndUser, tenant_model: Tenant, payload: RequestFetchAppInfo):
|
||||||
|
return BaseBackwardsInvocationResponse(
|
||||||
|
data=PluginAppBackwardsInvocation.fetch_app_info(payload.app_id, tenant_model.id)
|
||||||
|
).model_dump()
|
||||||
|
|
||||||
|
|
||||||
api.add_resource(PluginInvokeLLMApi, "/invoke/llm")
|
api.add_resource(PluginInvokeLLMApi, "/invoke/llm")
|
||||||
api.add_resource(PluginInvokeTextEmbeddingApi, "/invoke/text-embedding")
|
api.add_resource(PluginInvokeTextEmbeddingApi, "/invoke/text-embedding")
|
||||||
api.add_resource(PluginInvokeRerankApi, "/invoke/rerank")
|
api.add_resource(PluginInvokeRerankApi, "/invoke/rerank")
|
||||||
@ -291,3 +303,4 @@ api.add_resource(PluginInvokeAppApi, "/invoke/app")
|
|||||||
api.add_resource(PluginInvokeEncryptApi, "/invoke/encrypt")
|
api.add_resource(PluginInvokeEncryptApi, "/invoke/encrypt")
|
||||||
api.add_resource(PluginInvokeSummaryApi, "/invoke/summary")
|
api.add_resource(PluginInvokeSummaryApi, "/invoke/summary")
|
||||||
api.add_resource(PluginUploadFileRequestApi, "/upload/file/request")
|
api.add_resource(PluginUploadFileRequestApi, "/upload/file/request")
|
||||||
|
api.add_resource(PluginFetchAppInfoApi, "/fetch/app/info")
|
||||||
|
@ -1,10 +1,10 @@
|
|||||||
from flask_restful import Resource, marshal_with # type: ignore
|
from flask_restful import Resource, marshal_with # type: ignore
|
||||||
|
|
||||||
from controllers.common import fields
|
from controllers.common import fields
|
||||||
from controllers.common import helpers as controller_helpers
|
|
||||||
from controllers.service_api import api
|
from controllers.service_api import api
|
||||||
from controllers.service_api.app.error import AppUnavailableError
|
from controllers.service_api.app.error import AppUnavailableError
|
||||||
from controllers.service_api.wraps import validate_app_token
|
from controllers.service_api.wraps import validate_app_token
|
||||||
|
from core.app.app_config.common.parameters_mapping import get_parameters_from_feature_dict
|
||||||
from models.model import App, AppMode
|
from models.model import App, AppMode
|
||||||
from services.app_service import AppService
|
from services.app_service import AppService
|
||||||
|
|
||||||
@ -32,9 +32,7 @@ class AppParameterApi(Resource):
|
|||||||
|
|
||||||
user_input_form = features_dict.get("user_input_form", [])
|
user_input_form = features_dict.get("user_input_form", [])
|
||||||
|
|
||||||
return controller_helpers.get_parameters_from_feature_dict(
|
return get_parameters_from_feature_dict(features_dict=features_dict, user_input_form=user_input_form)
|
||||||
features_dict=features_dict, user_input_form=user_input_form
|
|
||||||
)
|
|
||||||
|
|
||||||
|
|
||||||
class AppMetaApi(Resource):
|
class AppMetaApi(Resource):
|
||||||
|
@ -1,10 +1,10 @@
|
|||||||
from flask_restful import marshal_with # type: ignore
|
from flask_restful import marshal_with # type: ignore
|
||||||
|
|
||||||
from controllers.common import fields
|
from controllers.common import fields
|
||||||
from controllers.common import helpers as controller_helpers
|
|
||||||
from controllers.web import api
|
from controllers.web import api
|
||||||
from controllers.web.error import AppUnavailableError
|
from controllers.web.error import AppUnavailableError
|
||||||
from controllers.web.wraps import WebApiResource
|
from controllers.web.wraps import WebApiResource
|
||||||
|
from core.app.app_config.common.parameters_mapping import get_parameters_from_feature_dict
|
||||||
from models.model import App, AppMode
|
from models.model import App, AppMode
|
||||||
from services.app_service import AppService
|
from services.app_service import AppService
|
||||||
|
|
||||||
@ -31,9 +31,7 @@ class AppParameterApi(WebApiResource):
|
|||||||
|
|
||||||
user_input_form = features_dict.get("user_input_form", [])
|
user_input_form = features_dict.get("user_input_form", [])
|
||||||
|
|
||||||
return controller_helpers.get_parameters_from_feature_dict(
|
return get_parameters_from_feature_dict(features_dict=features_dict, user_input_form=user_input_form)
|
||||||
features_dict=features_dict, user_input_form=user_input_form
|
|
||||||
)
|
|
||||||
|
|
||||||
|
|
||||||
class AppMeta(WebApiResource):
|
class AppMeta(WebApiResource):
|
||||||
|
@ -0,0 +1,45 @@
|
|||||||
|
from collections.abc import Mapping
|
||||||
|
from typing import Any
|
||||||
|
|
||||||
|
from configs import dify_config
|
||||||
|
from constants import DEFAULT_FILE_NUMBER_LIMITS
|
||||||
|
|
||||||
|
|
||||||
|
def get_parameters_from_feature_dict(
|
||||||
|
*, features_dict: Mapping[str, Any], user_input_form: list[dict[str, Any]]
|
||||||
|
) -> Mapping[str, Any]:
|
||||||
|
"""
|
||||||
|
Mapping from feature dict to webapp parameters
|
||||||
|
"""
|
||||||
|
return {
|
||||||
|
"opening_statement": features_dict.get("opening_statement"),
|
||||||
|
"suggested_questions": features_dict.get("suggested_questions", []),
|
||||||
|
"suggested_questions_after_answer": features_dict.get("suggested_questions_after_answer", {"enabled": False}),
|
||||||
|
"speech_to_text": features_dict.get("speech_to_text", {"enabled": False}),
|
||||||
|
"text_to_speech": features_dict.get("text_to_speech", {"enabled": False}),
|
||||||
|
"retriever_resource": features_dict.get("retriever_resource", {"enabled": False}),
|
||||||
|
"annotation_reply": features_dict.get("annotation_reply", {"enabled": False}),
|
||||||
|
"more_like_this": features_dict.get("more_like_this", {"enabled": False}),
|
||||||
|
"user_input_form": user_input_form,
|
||||||
|
"sensitive_word_avoidance": features_dict.get(
|
||||||
|
"sensitive_word_avoidance", {"enabled": False, "type": "", "configs": []}
|
||||||
|
),
|
||||||
|
"file_upload": features_dict.get(
|
||||||
|
"file_upload",
|
||||||
|
{
|
||||||
|
"image": {
|
||||||
|
"enabled": False,
|
||||||
|
"number_limits": DEFAULT_FILE_NUMBER_LIMITS,
|
||||||
|
"detail": "high",
|
||||||
|
"transfer_methods": ["remote_url", "local_file"],
|
||||||
|
}
|
||||||
|
},
|
||||||
|
),
|
||||||
|
"system_parameters": {
|
||||||
|
"image_file_size_limit": dify_config.UPLOAD_IMAGE_FILE_SIZE_LIMIT,
|
||||||
|
"video_file_size_limit": dify_config.UPLOAD_VIDEO_FILE_SIZE_LIMIT,
|
||||||
|
"audio_file_size_limit": dify_config.UPLOAD_AUDIO_FILE_SIZE_LIMIT,
|
||||||
|
"file_size_limit": dify_config.UPLOAD_FILE_SIZE_LIMIT,
|
||||||
|
"workflow_file_upload_limit": dify_config.WORKFLOW_FILE_UPLOAD_LIMIT,
|
||||||
|
},
|
||||||
|
}
|
@ -2,6 +2,7 @@ from collections.abc import Generator, Mapping
|
|||||||
from typing import Optional, Union
|
from typing import Optional, Union
|
||||||
|
|
||||||
from controllers.service_api.wraps import create_or_update_end_user_for_user_id
|
from controllers.service_api.wraps import create_or_update_end_user_for_user_id
|
||||||
|
from core.app.app_config.common.parameters_mapping import get_parameters_from_feature_dict
|
||||||
from core.app.apps.advanced_chat.app_generator import AdvancedChatAppGenerator
|
from core.app.apps.advanced_chat.app_generator import AdvancedChatAppGenerator
|
||||||
from core.app.apps.agent_chat.app_generator import AgentChatAppGenerator
|
from core.app.apps.agent_chat.app_generator import AgentChatAppGenerator
|
||||||
from core.app.apps.chat.app_generator import ChatAppGenerator
|
from core.app.apps.chat.app_generator import ChatAppGenerator
|
||||||
@ -15,6 +16,34 @@ from models.model import App, AppMode, EndUser
|
|||||||
|
|
||||||
|
|
||||||
class PluginAppBackwardsInvocation(BaseBackwardsInvocation):
|
class PluginAppBackwardsInvocation(BaseBackwardsInvocation):
|
||||||
|
@classmethod
|
||||||
|
def fetch_app_info(cls, app_id: str, tenant_id: str) -> Mapping:
|
||||||
|
"""
|
||||||
|
Fetch app info
|
||||||
|
"""
|
||||||
|
app = cls._get_app(app_id, tenant_id)
|
||||||
|
|
||||||
|
"""Retrieve app parameters."""
|
||||||
|
if app.mode in {AppMode.ADVANCED_CHAT.value, AppMode.WORKFLOW.value}:
|
||||||
|
workflow = app.workflow
|
||||||
|
if workflow is None:
|
||||||
|
raise ValueError("unexpected app type")
|
||||||
|
|
||||||
|
features_dict = workflow.features_dict
|
||||||
|
user_input_form = workflow.user_input_form(to_old_structure=True)
|
||||||
|
else:
|
||||||
|
app_model_config = app.app_model_config
|
||||||
|
if app_model_config is None:
|
||||||
|
raise ValueError("unexpected app type")
|
||||||
|
|
||||||
|
features_dict = app_model_config.to_dict()
|
||||||
|
|
||||||
|
user_input_form = features_dict.get("user_input_form", [])
|
||||||
|
|
||||||
|
return {
|
||||||
|
"data": get_parameters_from_feature_dict(features_dict=features_dict, user_input_form=user_input_form),
|
||||||
|
}
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
def invoke_app(
|
def invoke_app(
|
||||||
cls,
|
cls,
|
||||||
|
@ -204,3 +204,11 @@ class RequestRequestUploadFile(BaseModel):
|
|||||||
|
|
||||||
filename: str
|
filename: str
|
||||||
mimetype: str
|
mimetype: str
|
||||||
|
|
||||||
|
|
||||||
|
class RequestFetchAppInfo(BaseModel):
|
||||||
|
"""
|
||||||
|
Request to fetch app info
|
||||||
|
"""
|
||||||
|
|
||||||
|
app_id: str
|
||||||
|
Loading…
x
Reference in New Issue
Block a user