mirror of
https://github.com/langgenius/dify.git
synced 2026-09-24 23:22:26 +08:00
feat(api): LLM polling support (#37462)
Co-authored-by: autofix-ci[bot] <114827586+autofix-ci[bot]@users.noreply.github.com> Co-authored-by: WH-2099 <wh2099@pm.me>
This commit is contained in:
co-authored by
autofix-ci[bot]
WH-2099
parent
19838972dc
commit
f0b34bdeb4
@@ -13,13 +13,17 @@ from core.plugin.entities.plugin_daemon import (
|
||||
PluginVoicesResponse,
|
||||
)
|
||||
from core.plugin.impl.base import BasePluginClient
|
||||
from graphon.model_runtime.entities.llm_entities import LLMResultChunk
|
||||
from core.plugin.impl.exc import PluginInvokeError, PluginLLMPollingUnsupportedError
|
||||
from graphon.model_runtime.entities.llm_entities import LLMPollingResult, LLMResultChunk
|
||||
from graphon.model_runtime.entities.message_entities import PromptMessage, PromptMessageTool
|
||||
from graphon.model_runtime.entities.model_entities import AIModelEntity
|
||||
from graphon.model_runtime.entities.model_entities import AIModelEntity, ModelType
|
||||
from graphon.model_runtime.entities.rerank_entities import MultimodalRerankInput, RerankResult
|
||||
from graphon.model_runtime.entities.text_embedding_entities import EmbeddingResult
|
||||
from graphon.model_runtime.utils.encoders import jsonable_encoder
|
||||
|
||||
_POLLING_UNSUPPORTED_INVOKE_ERROR_TYPES = frozenset((NotImplementedError.__name__,))
|
||||
_POLLING_UNSUPPORTED_ERROR_MESSAGE = "does not support polling"
|
||||
|
||||
|
||||
class PluginModelClient(BasePluginClient):
|
||||
@staticmethod
|
||||
@@ -197,6 +201,103 @@ class PluginModelClient(BasePluginClient):
|
||||
except PluginDaemonInnerError as e:
|
||||
raise ValueError(e.message + str(e.code))
|
||||
|
||||
def start_llm_polling(
|
||||
self,
|
||||
tenant_id: str,
|
||||
user_id: str | None,
|
||||
plugin_id: str,
|
||||
provider: str,
|
||||
model: str,
|
||||
credentials: dict[str, Any],
|
||||
prompt_messages: list[PromptMessage],
|
||||
model_parameters: dict[str, Any] | None = None,
|
||||
tools: list[PromptMessageTool] | None = None,
|
||||
stop: list[str] | None = None,
|
||||
json_schema: dict[str, Any] | None = None,
|
||||
) -> LLMPollingResult:
|
||||
"""Start an LLM polling request for plugin-backed long-running jobs."""
|
||||
try:
|
||||
return self._request_with_plugin_daemon_response(
|
||||
method="POST",
|
||||
path=f"plugin/{tenant_id}/dispatch/model/polling/start",
|
||||
type_=LLMPollingResult,
|
||||
data=jsonable_encoder(
|
||||
self._dispatch_payload(
|
||||
user_id=user_id,
|
||||
data={
|
||||
"provider": provider,
|
||||
"model_type": ModelType.LLM.value,
|
||||
"model": model,
|
||||
"credentials": credentials,
|
||||
"prompt_messages": prompt_messages,
|
||||
"model_parameters": model_parameters,
|
||||
"tools": tools,
|
||||
"stop": stop,
|
||||
"stream": False,
|
||||
"json_schema": json_schema,
|
||||
},
|
||||
)
|
||||
),
|
||||
headers={
|
||||
"X-Plugin-ID": plugin_id,
|
||||
"Content-Type": "application/json",
|
||||
},
|
||||
)
|
||||
except PluginInvokeError as error:
|
||||
self._raise_typed_polling_unsupported_error(error)
|
||||
raise
|
||||
|
||||
def check_llm_polling(
|
||||
self,
|
||||
tenant_id: str,
|
||||
user_id: str | None,
|
||||
plugin_id: str,
|
||||
provider: str,
|
||||
model: str,
|
||||
credentials: dict[str, Any],
|
||||
plugin_state: dict[str, Any],
|
||||
) -> LLMPollingResult:
|
||||
"""Check the latest state for a plugin-backed LLM polling job."""
|
||||
try:
|
||||
return self._request_with_plugin_daemon_response(
|
||||
method="POST",
|
||||
path=f"plugin/{tenant_id}/dispatch/model/polling/check",
|
||||
type_=LLMPollingResult,
|
||||
data=jsonable_encoder(
|
||||
self._dispatch_payload(
|
||||
user_id=user_id,
|
||||
data={
|
||||
"provider": provider,
|
||||
"model_type": ModelType.LLM.value,
|
||||
"model": model,
|
||||
"credentials": credentials,
|
||||
"plugin_state": plugin_state,
|
||||
},
|
||||
)
|
||||
),
|
||||
headers={
|
||||
"X-Plugin-ID": plugin_id,
|
||||
"Content-Type": "application/json",
|
||||
},
|
||||
)
|
||||
except PluginInvokeError as error:
|
||||
self._raise_typed_polling_unsupported_error(error)
|
||||
raise
|
||||
|
||||
@staticmethod
|
||||
def _raise_typed_polling_unsupported_error(error: PluginInvokeError) -> None:
|
||||
"""Convert plugin polling capability failures into a dedicated Dify exception."""
|
||||
if error.get_error_type() == PluginLLMPollingUnsupportedError.__name__:
|
||||
raise PluginLLMPollingUnsupportedError(description=error.description) from error
|
||||
|
||||
if (
|
||||
error.get_error_type() in _POLLING_UNSUPPORTED_INVOKE_ERROR_TYPES
|
||||
# This is ugly, we should not rely on error messages while checking
|
||||
# error types.
|
||||
and _POLLING_UNSUPPORTED_ERROR_MESSAGE in error.get_error_message().lower()
|
||||
):
|
||||
raise PluginLLMPollingUnsupportedError(description=error.description) from error
|
||||
|
||||
def get_llm_num_tokens(
|
||||
self,
|
||||
tenant_id: str,
|
||||
|
||||
Reference in New Issue
Block a user