mirror of
https://github.com/langgenius/dify.git
synced 2026-11-12 14:21:29 +08:00
177 lines
6.1 KiB
Python
177 lines
6.1 KiB
Python
from collections.abc import Sequence
|
|
|
|
from sqlalchemy import select
|
|
from sqlalchemy.orm import Session, sessionmaker
|
|
|
|
from extensions.ext_database import db
|
|
from libs.infinite_scroll_pagination import InfiniteScrollPagination
|
|
from models import Account
|
|
from models.model import (
|
|
App,
|
|
EndUser,
|
|
Message,
|
|
)
|
|
from repositories.execution_extra_content_repository import ExecutionExtraContentRepository
|
|
from repositories.sqlalchemy_execution_extra_content_repository import (
|
|
SQLAlchemyExecutionExtraContentRepository,
|
|
)
|
|
from services.conversation_service import ConversationService
|
|
from services.errors.message import (
|
|
FirstMessageNotExistsError,
|
|
LastMessageNotExistsError,
|
|
MessageNotExistsError,
|
|
)
|
|
|
|
|
|
def _create_execution_extra_content_repository() -> ExecutionExtraContentRepository:
|
|
session_maker = sessionmaker(bind=db.engine, expire_on_commit=False)
|
|
return SQLAlchemyExecutionExtraContentRepository(session_maker=session_maker)
|
|
|
|
|
|
def attach_message_extra_contents(messages: Sequence[Message]) -> None:
|
|
if not messages:
|
|
return
|
|
|
|
repository = _create_execution_extra_content_repository()
|
|
extra_contents_lists = repository.get_by_message_ids([message.id for message in messages])
|
|
|
|
for index, message in enumerate(messages):
|
|
contents = extra_contents_lists[index] if index < len(extra_contents_lists) else []
|
|
message.set_extra_contents([content.model_dump(mode="json", exclude_none=True) for content in contents])
|
|
|
|
|
|
class MessageService:
|
|
@classmethod
|
|
def pagination_by_first_id(
|
|
cls,
|
|
app_model: App,
|
|
user: Account | EndUser | None,
|
|
conversation_id: str,
|
|
first_id: str | None,
|
|
limit: int,
|
|
order: str = "asc",
|
|
*,
|
|
session: Session,
|
|
) -> InfiniteScrollPagination:
|
|
if not user:
|
|
return InfiniteScrollPagination(data=[], limit=limit, has_more=False)
|
|
|
|
if not conversation_id:
|
|
return InfiniteScrollPagination(data=[], limit=limit, has_more=False)
|
|
|
|
conversation = ConversationService.get_conversation(
|
|
app_model=app_model, user=user, conversation_id=conversation_id, session=session
|
|
)
|
|
|
|
fetch_limit = limit + 1
|
|
|
|
if first_id:
|
|
first_message = session.scalar(
|
|
select(Message).where(Message.conversation_id == conversation.id, Message.id == first_id).limit(1)
|
|
)
|
|
|
|
if not first_message:
|
|
raise FirstMessageNotExistsError()
|
|
|
|
history_messages = session.scalars(
|
|
select(Message)
|
|
.where(
|
|
Message.conversation_id == conversation.id,
|
|
Message.created_at < first_message.created_at,
|
|
Message.id != first_message.id,
|
|
)
|
|
.order_by(Message.created_at.desc())
|
|
.limit(fetch_limit)
|
|
).all()
|
|
else:
|
|
history_messages = session.scalars(
|
|
select(Message)
|
|
.where(Message.conversation_id == conversation.id)
|
|
.order_by(Message.created_at.desc())
|
|
.limit(fetch_limit)
|
|
).all()
|
|
|
|
has_more = False
|
|
if len(history_messages) > limit:
|
|
has_more = True
|
|
history_messages = history_messages[:-1]
|
|
|
|
if order == "asc":
|
|
history_messages = list(reversed(history_messages))
|
|
|
|
attach_message_extra_contents(history_messages)
|
|
|
|
return InfiniteScrollPagination(data=history_messages, limit=limit, has_more=has_more)
|
|
|
|
@classmethod
|
|
def pagination_by_last_id(
|
|
cls,
|
|
app_model: App,
|
|
user: Account | EndUser | None,
|
|
last_id: str | None,
|
|
limit: int,
|
|
conversation_id: str | None = None,
|
|
include_ids: list | None = None,
|
|
*,
|
|
session: Session,
|
|
) -> InfiniteScrollPagination:
|
|
if not user:
|
|
return InfiniteScrollPagination(data=[], limit=limit, has_more=False)
|
|
|
|
stmt = select(Message)
|
|
|
|
fetch_limit = limit + 1
|
|
|
|
if conversation_id is not None:
|
|
conversation = ConversationService.get_conversation(
|
|
app_model=app_model, user=user, conversation_id=conversation_id, session=session
|
|
)
|
|
|
|
stmt = stmt.where(Message.conversation_id == conversation.id)
|
|
|
|
# Check if include_ids is not None and not empty to avoid WHERE false condition
|
|
if include_ids is not None:
|
|
if len(include_ids) == 0:
|
|
return InfiniteScrollPagination(data=[], limit=limit, has_more=False)
|
|
stmt = stmt.where(Message.id.in_(include_ids))
|
|
|
|
if last_id:
|
|
last_message = session.scalar(stmt.where(Message.id == last_id).limit(1))
|
|
|
|
if not last_message:
|
|
raise LastMessageNotExistsError()
|
|
|
|
history_messages = session.scalars(
|
|
stmt.where(Message.created_at < last_message.created_at, Message.id != last_message.id)
|
|
.order_by(Message.created_at.desc())
|
|
.limit(fetch_limit)
|
|
).all()
|
|
else:
|
|
history_messages = session.scalars(stmt.order_by(Message.created_at.desc()).limit(fetch_limit)).all()
|
|
|
|
has_more = False
|
|
if len(history_messages) > limit:
|
|
has_more = True
|
|
history_messages = history_messages[:-1]
|
|
|
|
return InfiniteScrollPagination(data=history_messages, limit=limit, has_more=has_more)
|
|
|
|
@classmethod
|
|
def get_message(cls, app_model: App, user: Account | EndUser | None, message_id: str, *, session: Session):
|
|
message = session.scalar(
|
|
select(Message)
|
|
.where(
|
|
Message.id == message_id,
|
|
Message.app_id == app_model.id,
|
|
Message.from_source == ("api" if isinstance(user, EndUser) else "console"),
|
|
Message.from_end_user_id == (user.id if isinstance(user, EndUser) else None),
|
|
Message.from_account_id == (user.id if isinstance(user, Account) else None),
|
|
)
|
|
.limit(1)
|
|
)
|
|
|
|
if not message:
|
|
raise MessageNotExistsError()
|
|
|
|
return message
|