+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]>
215 lines
8.4 KiB
Python
215 lines
8.4 KiB
Python
import logging
|
|
from typing import Literal
|
|
from uuid import UUID
|
|
|
|
from flask import request
|
|
from pydantic import BaseModel, TypeAdapter
|
|
from werkzeug.exceptions import InternalServerError, NotFound
|
|
|
|
from controllers.common.controller_schemas import MessageFeedbackPayload, MessageListQuery
|
|
from controllers.common.schema import register_response_schema_models, register_schema_models
|
|
from controllers.console.app.error import (
|
|
AppMoreLikeThisDisabledError,
|
|
AppUnavailableError,
|
|
CompletionRequestError,
|
|
ProviderModelCurrentlyNotSupportError,
|
|
ProviderNotInitializeError,
|
|
ProviderQuotaExceededError,
|
|
)
|
|
from controllers.console.explore.error import (
|
|
AppSuggestedQuestionsAfterAnswerDisabledError,
|
|
NotChatAppError,
|
|
NotCompletionAppError,
|
|
)
|
|
from controllers.console.explore.wraps import InstalledAppResource
|
|
from controllers.console.wraps import with_current_user
|
|
from core.app.entities.app_invoke_entities import InvokeFrom
|
|
from core.errors.error import ModelCurrentlyNotSupportError, ProviderTokenNotInitError, QuotaExceededError
|
|
from fields.conversation_fields import ResultResponse
|
|
from fields.message_fields import MessageInfiniteScrollPagination, MessageListItem, SuggestedQuestionsResponse
|
|
from graphon.model_runtime.errors.invoke import InvokeError
|
|
from libs import helper
|
|
from models import Account
|
|
from models.enums import FeedbackRating
|
|
from models.model import AppMode, InstalledApp
|
|
from services.app_generate_service import AppGenerateService
|
|
from services.errors.app import MoreLikeThisDisabledError
|
|
from services.errors.conversation import ConversationNotExistsError
|
|
from services.errors.message import (
|
|
FirstMessageNotExistsError,
|
|
MessageNotExistsError,
|
|
SuggestedQuestionsAfterAnswerDisabledError,
|
|
)
|
|
from services.message_service import MessageService
|
|
|
|
from .. import console_ns
|
|
|
|
logger = logging.getLogger(__name__)
|
|
|
|
|
|
class MoreLikeThisQuery(BaseModel):
|
|
response_mode: Literal["blocking", "streaming"]
|
|
|
|
|
|
register_schema_models(console_ns, MessageListQuery, MessageFeedbackPayload, MoreLikeThisQuery)
|
|
register_response_schema_models(console_ns, ResultResponse, SuggestedQuestionsResponse)
|
|
|
|
|
|
@console_ns.route(
|
|
"/installed-apps/<uuid:installed_app_id>/messages",
|
|
endpoint="installed_app_messages",
|
|
)
|
|
class MessageListApi(InstalledAppResource):
|
|
@console_ns.expect(console_ns.models[MessageListQuery.__name__])
|
|
@with_current_user
|
|
def get(self, current_user: Account, 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()
|
|
args = MessageListQuery.model_validate(request.args.to_dict())
|
|
|
|
try:
|
|
pagination = MessageService.pagination_by_first_id(
|
|
app_model,
|
|
current_user,
|
|
str(args.conversation_id),
|
|
str(args.first_id) if args.first_id else None,
|
|
args.limit,
|
|
)
|
|
adapter = TypeAdapter(MessageListItem)
|
|
items = [adapter.validate_python(message, from_attributes=True) for message in pagination.data]
|
|
return MessageInfiniteScrollPagination(
|
|
limit=pagination.limit,
|
|
has_more=pagination.has_more,
|
|
data=items,
|
|
).model_dump(mode="json")
|
|
except ConversationNotExistsError:
|
|
raise NotFound("Conversation Not Exists.")
|
|
except FirstMessageNotExistsError:
|
|
raise NotFound("First Message Not Exists.")
|
|
|
|
|
|
@console_ns.route(
|
|
"/installed-apps/<uuid:installed_app_id>/messages/<uuid:message_id>/feedbacks",
|
|
endpoint="installed_app_message_feedback",
|
|
)
|
|
class MessageFeedbackApi(InstalledAppResource):
|
|
@console_ns.expect(console_ns.models[MessageFeedbackPayload.__name__])
|
|
@console_ns.response(200, "Feedback submitted successfully", console_ns.models[ResultResponse.__name__])
|
|
@with_current_user
|
|
def post(self, current_user: Account, installed_app: InstalledApp, message_id: UUID):
|
|
app_model = installed_app.app
|
|
if app_model is None:
|
|
raise AppUnavailableError()
|
|
|
|
message_id_str = str(message_id)
|
|
|
|
payload = MessageFeedbackPayload.model_validate(console_ns.payload or {})
|
|
|
|
try:
|
|
MessageService.create_feedback(
|
|
app_model=app_model,
|
|
message_id=message_id_str,
|
|
user=current_user,
|
|
rating=FeedbackRating(payload.rating) if payload.rating else None,
|
|
content=payload.content,
|
|
)
|
|
except MessageNotExistsError:
|
|
raise NotFound("Message Not Exists.")
|
|
|
|
return ResultResponse(result="success").model_dump(mode="json")
|
|
|
|
|
|
@console_ns.route(
|
|
"/installed-apps/<uuid:installed_app_id>/messages/<uuid:message_id>/more-like-this",
|
|
endpoint="installed_app_more_like_this",
|
|
)
|
|
class MessageMoreLikeThisApi(InstalledAppResource):
|
|
@console_ns.expect(console_ns.models[MoreLikeThisQuery.__name__])
|
|
@with_current_user
|
|
def get(self, current_user: Account, installed_app: InstalledApp, message_id: UUID):
|
|
app_model = installed_app.app
|
|
if app_model is None:
|
|
raise AppUnavailableError()
|
|
if app_model.mode != "completion":
|
|
raise NotCompletionAppError()
|
|
|
|
message_id_str = str(message_id)
|
|
|
|
args = MoreLikeThisQuery.model_validate(request.args.to_dict())
|
|
|
|
streaming = args.response_mode == "streaming"
|
|
|
|
try:
|
|
response = AppGenerateService.generate_more_like_this(
|
|
app_model=app_model,
|
|
user=current_user,
|
|
message_id=message_id_str,
|
|
invoke_from=InvokeFrom.EXPLORE,
|
|
streaming=streaming,
|
|
)
|
|
return helper.compact_generate_response(response)
|
|
except MessageNotExistsError:
|
|
raise NotFound("Message Not Exists.")
|
|
except MoreLikeThisDisabledError:
|
|
raise AppMoreLikeThisDisabledError()
|
|
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>/messages/<uuid:message_id>/suggested-questions",
|
|
endpoint="installed_app_suggested_question",
|
|
)
|
|
class MessageSuggestedQuestionApi(InstalledAppResource):
|
|
@console_ns.response(200, "Success", console_ns.models[SuggestedQuestionsResponse.__name__])
|
|
@with_current_user
|
|
def get(self, current_user: Account, installed_app: InstalledApp, message_id: UUID):
|
|
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()
|
|
|
|
message_id_str = str(message_id)
|
|
|
|
try:
|
|
questions = MessageService.get_suggested_questions_after_answer(
|
|
app_model=app_model, user=current_user, message_id=message_id_str, invoke_from=InvokeFrom.EXPLORE
|
|
)
|
|
except MessageNotExistsError:
|
|
raise NotFound("Message not found")
|
|
except ConversationNotExistsError:
|
|
raise NotFound("Conversation not found")
|
|
except SuggestedQuestionsAfterAnswerDisabledError:
|
|
raise AppSuggestedQuestionsAfterAnswerDisabledError()
|
|
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 Exception:
|
|
logger.exception("internal server error.")
|
|
raise InternalServerError()
|
|
|
|
return SuggestedQuestionsResponse(data=questions).model_dump(mode="json")
|