+18


![dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>](/assets/img/avatar_default.png)

![autofix-ci[bot] <114827586+autofix-ci[bot]@users.noreply.github.com>](/assets/img/avatar_default.png)




FFXN
GitHub
yyh
盐粒 Yanli
autofix-ci[bot] <114827586+autofix-ci[bot]@users.noreply.github.com>
Tianle
dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
Yunlu Wen
zyssyz123
Claude Opus 4.7
chariri
Asuka Minato
Copilot Autofix powered by AI
Nian
非法操作
Carmen Fernández Ruiz
wangxiaolei
QuantumGhost
L1nSn0w
Evan
Escape0707
Jingyi
Amr Sherif
ZHOU ZHICHEN
unknown
JzoNg
Xiyuan Chen
-LAN-
107bba0116
Signed-off-by: dependabot[bot] <[email protected]> Signed-off-by: EvanYao826 <[email protected]> Co-authored-by: yyh <[email protected]> Co-authored-by: 盐粒 Yanli <[email protected]> Co-authored-by: autofix-ci[bot] <114827586+autofix-ci[bot]@users.noreply.github.com> Co-authored-by: Tianle <[email protected]> Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> Co-authored-by: Yunlu Wen <[email protected]> Co-authored-by: zyssyz123 <[email protected]> Co-authored-by: Claude Opus 4.7 (1M context) <[email protected]> Co-authored-by: chariri <[email protected]> Co-authored-by: Asuka Minato <[email protected]> Co-authored-by: Copilot Autofix powered by AI <[email protected]> Co-authored-by: Nian <[email protected]> Co-authored-by: 非法操作 <[email protected]> Co-authored-by: Carmen Fernández Ruiz <[email protected]> Co-authored-by: wangxiaolei <[email protected]> Co-authored-by: QuantumGhost <[email protected]> Co-authored-by: L1nSn0w <[email protected]> Co-authored-by: Evan <[email protected]> Co-authored-by: Escape0707 <[email protected]> Co-authored-by: Jingyi <[email protected]> Co-authored-by: Amr Sherif <[email protected]> Co-authored-by: ZHOU ZHICHEN <[email protected]> Co-authored-by: unknown <[email protected]> Co-authored-by: JzoNg <[email protected]> Co-authored-by: Xiyuan Chen <[email protected]> Co-authored-by: -LAN- <[email protected]>
237 lines
8.9 KiB
Python
237 lines
8.9 KiB
Python
import logging
|
|
from typing import Any, Literal
|
|
from uuid import UUID
|
|
|
|
from pydantic import BaseModel, Field, field_validator
|
|
from werkzeug.exceptions import InternalServerError, NotFound
|
|
|
|
import services
|
|
from controllers.common.fields import SimpleResultResponse
|
|
from controllers.common.schema import register_response_schema_models, register_schema_models
|
|
from controllers.console.app.error import (
|
|
AppUnavailableError,
|
|
CompletionRequestError,
|
|
ConversationCompletedError,
|
|
ProviderModelCurrentlyNotSupportError,
|
|
ProviderNotInitializeError,
|
|
ProviderQuotaExceededError,
|
|
)
|
|
from controllers.console.explore.error import NotChatAppError, NotCompletionAppError
|
|
from controllers.console.explore.wraps import InstalledAppResource
|
|
from controllers.web.error import InvokeRateLimitError as InvokeRateLimitHttpError
|
|
from core.app.entities.app_invoke_entities import InvokeFrom
|
|
from core.errors.error import (
|
|
ModelCurrentlyNotSupportError,
|
|
ProviderTokenNotInitError,
|
|
QuotaExceededError,
|
|
)
|
|
from extensions.ext_database import db
|
|
from graphon.model_runtime.errors.invoke import InvokeError
|
|
from libs import helper
|
|
from libs.datetime_utils import naive_utc_now
|
|
from libs.login import current_user
|
|
from models import Account
|
|
from models.model import AppMode, InstalledApp
|
|
from services.app_generate_service import AppGenerateService
|
|
from services.app_task_service import AppTaskService
|
|
from services.errors.llm import InvokeRateLimitError
|
|
|
|
from .. import console_ns
|
|
|
|
logger = logging.getLogger(__name__)
|
|
|
|
|
|
class CompletionMessageExplorePayload(BaseModel):
|
|
inputs: dict[str, Any]
|
|
query: str = ""
|
|
files: list[dict[str, Any]] | None = None
|
|
response_mode: Literal["blocking", "streaming"] | None = None
|
|
retriever_from: str = Field(default="explore_app")
|
|
|
|
|
|
class ChatMessagePayload(BaseModel):
|
|
inputs: dict[str, Any]
|
|
query: str
|
|
files: list[dict[str, Any]] | None = None
|
|
conversation_id: str | None = None
|
|
parent_message_id: str | None = None
|
|
retriever_from: str = Field(default="explore_app")
|
|
|
|
@field_validator("conversation_id", "parent_message_id", mode="before")
|
|
@classmethod
|
|
def normalize_uuid(cls, value: str | UUID | None) -> str | None:
|
|
"""
|
|
Accept blank IDs and validate UUID format when provided.
|
|
"""
|
|
if not value:
|
|
return None
|
|
|
|
try:
|
|
return helper.uuid_value(value)
|
|
except ValueError as exc:
|
|
raise ValueError("must be a valid UUID") from exc
|
|
|
|
|
|
register_schema_models(console_ns, CompletionMessageExplorePayload, ChatMessagePayload)
|
|
register_response_schema_models(console_ns, SimpleResultResponse)
|
|
|
|
|
|
# define completion api for user
|
|
@console_ns.route(
|
|
"/installed-apps/<uuid:installed_app_id>/completion-messages",
|
|
endpoint="installed_app_completion",
|
|
)
|
|
class CompletionApi(InstalledAppResource):
|
|
@console_ns.expect(console_ns.models[CompletionMessageExplorePayload.__name__])
|
|
def post(self, installed_app: InstalledApp):
|
|
app_model = installed_app.app
|
|
if app_model is None:
|
|
raise AppUnavailableError()
|
|
if app_model.mode != AppMode.COMPLETION:
|
|
raise NotCompletionAppError()
|
|
|
|
payload = CompletionMessageExplorePayload.model_validate(console_ns.payload or {})
|
|
args = payload.model_dump(exclude_none=True)
|
|
|
|
streaming = payload.response_mode == "streaming"
|
|
args["auto_generate_name"] = False
|
|
|
|
installed_app.last_used_at = naive_utc_now()
|
|
db.session.commit()
|
|
|
|
try:
|
|
if not isinstance(current_user, Account):
|
|
raise ValueError("current_user must be an Account instance")
|
|
response = AppGenerateService.generate(
|
|
app_model=app_model, user=current_user, args=args, invoke_from=InvokeFrom.EXPLORE, streaming=streaming
|
|
)
|
|
|
|
return helper.compact_generate_response(response)
|
|
except services.errors.conversation.ConversationNotExistsError:
|
|
raise NotFound("Conversation Not Exists.")
|
|
except services.errors.conversation.ConversationCompletedError:
|
|
raise ConversationCompletedError()
|
|
except services.errors.app_model_config.AppModelConfigBrokenError:
|
|
logger.exception("App model config broken.")
|
|
raise AppUnavailableError()
|
|
except ProviderTokenNotInitError as ex:
|
|
raise ProviderNotInitializeError(ex.description)
|
|
except QuotaExceededError:
|
|
raise ProviderQuotaExceededError()
|
|
except ModelCurrentlyNotSupportError:
|
|
raise ProviderModelCurrentlyNotSupportError()
|
|
except InvokeError as e:
|
|
raise CompletionRequestError(e.description)
|
|
except ValueError as e:
|
|
raise e
|
|
except Exception:
|
|
logger.exception("internal server error.")
|
|
raise InternalServerError()
|
|
|
|
|
|
@console_ns.route(
|
|
"/installed-apps/<uuid:installed_app_id>/completion-messages/<string:task_id>/stop",
|
|
endpoint="installed_app_stop_completion",
|
|
)
|
|
class CompletionStopApi(InstalledAppResource):
|
|
@console_ns.response(200, "Success", console_ns.models[SimpleResultResponse.__name__])
|
|
def post(self, installed_app: InstalledApp, task_id: str):
|
|
app_model = installed_app.app
|
|
if app_model is None:
|
|
raise AppUnavailableError()
|
|
if app_model.mode != AppMode.COMPLETION:
|
|
raise NotCompletionAppError()
|
|
|
|
if not isinstance(current_user, Account):
|
|
raise ValueError("current_user must be an Account instance")
|
|
|
|
AppTaskService.stop_task(
|
|
task_id=task_id,
|
|
invoke_from=InvokeFrom.EXPLORE,
|
|
user_id=current_user.id,
|
|
app_mode=AppMode.value_of(app_model.mode),
|
|
)
|
|
|
|
return {"result": "success"}, 200
|
|
|
|
|
|
@console_ns.route(
|
|
"/installed-apps/<uuid:installed_app_id>/chat-messages",
|
|
endpoint="installed_app_chat_completion",
|
|
)
|
|
class ChatApi(InstalledAppResource):
|
|
@console_ns.expect(console_ns.models[ChatMessagePayload.__name__])
|
|
def post(self, installed_app: InstalledApp):
|
|
app_model = installed_app.app
|
|
if app_model is None:
|
|
raise AppUnavailableError()
|
|
app_mode = AppMode.value_of(app_model.mode)
|
|
if app_mode not in {AppMode.CHAT, AppMode.AGENT_CHAT, AppMode.ADVANCED_CHAT}:
|
|
raise NotChatAppError()
|
|
|
|
payload = ChatMessagePayload.model_validate(console_ns.payload or {})
|
|
args = payload.model_dump(exclude_none=True)
|
|
|
|
args["auto_generate_name"] = False
|
|
|
|
installed_app.last_used_at = naive_utc_now()
|
|
db.session.commit()
|
|
|
|
try:
|
|
if not isinstance(current_user, Account):
|
|
raise ValueError("current_user must be an Account instance")
|
|
response = AppGenerateService.generate(
|
|
app_model=app_model, user=current_user, args=args, invoke_from=InvokeFrom.EXPLORE, streaming=True
|
|
)
|
|
|
|
return helper.compact_generate_response(response)
|
|
except services.errors.conversation.ConversationNotExistsError:
|
|
raise NotFound("Conversation Not Exists.")
|
|
except services.errors.conversation.ConversationCompletedError:
|
|
raise ConversationCompletedError()
|
|
except services.errors.app_model_config.AppModelConfigBrokenError:
|
|
logger.exception("App model config broken.")
|
|
raise AppUnavailableError()
|
|
except ProviderTokenNotInitError as ex:
|
|
raise ProviderNotInitializeError(ex.description)
|
|
except QuotaExceededError:
|
|
raise ProviderQuotaExceededError()
|
|
except ModelCurrentlyNotSupportError:
|
|
raise ProviderModelCurrentlyNotSupportError()
|
|
except InvokeError as e:
|
|
raise CompletionRequestError(e.description)
|
|
except InvokeRateLimitError as ex:
|
|
raise InvokeRateLimitHttpError(ex.description)
|
|
except ValueError as e:
|
|
raise e
|
|
except Exception:
|
|
logger.exception("internal server error.")
|
|
raise InternalServerError()
|
|
|
|
|
|
@console_ns.route(
|
|
"/installed-apps/<uuid:installed_app_id>/chat-messages/<string:task_id>/stop",
|
|
endpoint="installed_app_stop_chat_completion",
|
|
)
|
|
class ChatStopApi(InstalledAppResource):
|
|
@console_ns.response(200, "Success", console_ns.models[SimpleResultResponse.__name__])
|
|
def post(self, installed_app: InstalledApp, task_id: str):
|
|
app_model = installed_app.app
|
|
if app_model is None:
|
|
raise AppUnavailableError()
|
|
app_mode = AppMode.value_of(app_model.mode)
|
|
if app_mode not in {AppMode.CHAT, AppMode.AGENT_CHAT, AppMode.ADVANCED_CHAT}:
|
|
raise NotChatAppError()
|
|
|
|
if not isinstance(current_user, Account):
|
|
raise ValueError("current_user must be an Account instance")
|
|
|
|
AppTaskService.stop_task(
|
|
task_id=task_id,
|
|
invoke_from=InvokeFrom.EXPLORE,
|
|
user_id=current_user.id,
|
|
app_mode=app_mode,
|
|
)
|
|
|
|
return {"result": "success"}, 200
|