Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

fix: support user-defined conversation id for chat API call #11638

Open
wants to merge 15 commits into
base: main
Choose a base branch
from
5 changes: 5 additions & 0 deletions api/controllers/console/app/completion.py
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@
AppUnavailableError,
CompletionRequestError,
ConversationCompletedError,
InvalidConversationIDError,
ProviderModelCurrentlyNotSupportError,
ProviderNotInitializeError,
ProviderQuotaExceededError,
Expand Down Expand Up @@ -63,6 +64,8 @@ def post(self, app_model):
return helper.compact_generate_response(response)
except services.errors.conversation.ConversationNotExistsError:
raise NotFound("Conversation Not Exists.")
except services.errors.conversation.InvalidConversationIDError:
raise InvalidConversationIDError()
except services.errors.conversation.ConversationCompletedError:
raise ConversationCompletedError()
except services.errors.app_model_config.AppModelConfigBrokenError:
Expand Down Expand Up @@ -126,6 +129,8 @@ def post(self, app_model):
return helper.compact_generate_response(response)
except services.errors.conversation.ConversationNotExistsError:
raise NotFound("Conversation Not Exists.")
except services.errors.conversation.InvalidConversationIDError:
raise InvalidConversationIDError()
except services.errors.conversation.ConversationCompletedError:
raise ConversationCompletedError()
except services.errors.app_model_config.AppModelConfigBrokenError:
Expand Down
6 changes: 6 additions & 0 deletions api/controllers/console/app/error.py
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,12 @@ class ConversationCompletedError(BaseHTTPException):
code = 400


class InvalidConversationIDError(BaseHTTPException):
error_code = "invalid_conversation_id"
description = "The conversation is invalid. Please check validity of conversation id."
code = 400


class AppUnavailableError(BaseHTTPException):
error_code = "app_unavailable"
description = "App unavailable, please check your app configurations."
Expand Down
5 changes: 5 additions & 0 deletions api/controllers/console/explore/completion.py
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@
AppUnavailableError,
CompletionRequestError,
ConversationCompletedError,
InvalidConversationIDError,
ProviderModelCurrentlyNotSupportError,
ProviderNotInitializeError,
ProviderQuotaExceededError,
Expand Down Expand Up @@ -57,6 +58,8 @@ def post(self, installed_app):
return helper.compact_generate_response(response)
except services.errors.conversation.ConversationNotExistsError:
raise NotFound("Conversation Not Exists.")
except services.errors.conversation.InvalidConversationIDError:
raise InvalidConversationIDError()
except services.errors.conversation.ConversationCompletedError:
raise ConversationCompletedError()
except services.errors.app_model_config.AppModelConfigBrokenError:
Expand Down Expand Up @@ -117,6 +120,8 @@ def post(self, installed_app):
return helper.compact_generate_response(response)
except services.errors.conversation.ConversationNotExistsError:
raise NotFound("Conversation Not Exists.")
except services.errors.conversation.InvalidConversationIDError:
raise InvalidConversationIDError()
except services.errors.conversation.ConversationCompletedError:
raise ConversationCompletedError()
except services.errors.app_model_config.AppModelConfigBrokenError:
Expand Down
5 changes: 5 additions & 0 deletions api/controllers/service_api/app/completion.py
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@
AppUnavailableError,
CompletionRequestError,
ConversationCompletedError,
InvalidConversationIDError,
NotChatAppError,
ProviderModelCurrentlyNotSupportError,
ProviderNotInitializeError,
Expand Down Expand Up @@ -61,6 +62,8 @@ def post(self, app_model: App, end_user: EndUser):
return helper.compact_generate_response(response)
except services.errors.conversation.ConversationNotExistsError:
raise NotFound("Conversation Not Exists.")
except services.errors.conversation.InvalidConversationIDError:
raise InvalidConversationIDError()
except services.errors.conversation.ConversationCompletedError:
raise ConversationCompletedError()
except services.errors.app_model_config.AppModelConfigBrokenError:
Expand Down Expand Up @@ -120,6 +123,8 @@ def post(self, app_model: App, end_user: EndUser):
return helper.compact_generate_response(response)
except services.errors.conversation.ConversationNotExistsError:
raise NotFound("Conversation Not Exists.")
except services.errors.conversation.InvalidConversationIDError:
raise InvalidConversationIDError()
except services.errors.conversation.ConversationCompletedError:
raise ConversationCompletedError()
except services.errors.app_model_config.AppModelConfigBrokenError:
Expand Down
6 changes: 6 additions & 0 deletions api/controllers/service_api/app/error.py
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,12 @@ class ConversationCompletedError(BaseHTTPException):
code = 400


class InvalidConversationIDError(BaseHTTPException):
error_code = "invalid_conversation_id"
description = "The conversation is invalid. Please check validity of conversation id."
code = 400


class ProviderNotInitializeError(BaseHTTPException):
error_code = "provider_not_initialize"
description = (
Expand Down
5 changes: 5 additions & 0 deletions api/controllers/web/completion.py
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@
AppUnavailableError,
CompletionRequestError,
ConversationCompletedError,
InvalidConversationIDError,
NotChatAppError,
NotCompletionAppError,
ProviderModelCurrentlyNotSupportError,
Expand Down Expand Up @@ -54,6 +55,8 @@ def post(self, app_model, end_user):
return helper.compact_generate_response(response)
except services.errors.conversation.ConversationNotExistsError:
raise NotFound("Conversation Not Exists.")
except services.errors.conversation.InvalidConversationIDError:
raise InvalidConversationIDError()
except services.errors.conversation.ConversationCompletedError:
raise ConversationCompletedError()
except services.errors.app_model_config.AppModelConfigBrokenError:
Expand Down Expand Up @@ -112,6 +115,8 @@ def post(self, app_model, end_user):
return helper.compact_generate_response(response)
except services.errors.conversation.ConversationNotExistsError:
raise NotFound("Conversation Not Exists.")
except services.errors.conversation.InvalidConversationIDError:
raise InvalidConversationIDError()
except services.errors.conversation.ConversationCompletedError:
raise ConversationCompletedError()
except services.errors.app_model_config.AppModelConfigBrokenError:
Expand Down
6 changes: 6 additions & 0 deletions api/controllers/web/error.py
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,12 @@ class ConversationCompletedError(BaseHTTPException):
code = 400


class InvalidConversationIDError(BaseHTTPException):
error_code = "invalid_conversation_id"
description = "The conversation is invalid. Please check validity of conversation id."
code = 400


class ProviderNotInitializeError(BaseHTTPException):
error_code = "provider_not_initialize"
description = (
Expand Down
4 changes: 3 additions & 1 deletion api/core/app/apps/agent_chat/app_generator.py
Original file line number Diff line number Diff line change
Expand Up @@ -164,7 +164,9 @@ def generate(
)

# init generate records
(conversation, message) = self._init_generate_records(application_generate_entity, conversation)
(conversation, message) = self._init_generate_records(
application_generate_entity, conversation, args.get("conversation_id")
)

# init queue manager
queue_manager = MessageBasedAppQueueManager(
Expand Down
4 changes: 3 additions & 1 deletion api/core/app/apps/chat/app_generator.py
Original file line number Diff line number Diff line change
Expand Up @@ -156,7 +156,9 @@ def generate(
)

# init generate records
(conversation, message) = self._init_generate_records(application_generate_entity, conversation)
(conversation, message) = self._init_generate_records(
application_generate_entity, conversation, args.get("conversation_id")
)

# init queue manager
queue_manager = MessageBasedAppQueueManager(
Expand Down
32 changes: 25 additions & 7 deletions api/core/app/apps/message_based_app_generator.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,9 +2,10 @@
import logging
from collections.abc import Generator
from datetime import UTC, datetime
from os import getenv
from typing import Optional, Union

from sqlalchemy import and_
from sqlalchemy import and_, exc

from core.app.app_config.entities import EasyUIBasedAppModelConfigFrom
from core.app.apps.base_app_generator import BaseAppGenerator
Expand All @@ -30,12 +31,20 @@
from models.enums import CreatedByRole
from models.model import App, AppMode, AppModelConfig, Conversation, EndUser, Message, MessageFile
from services.errors.app_model_config import AppModelConfigBrokenError
from services.errors.conversation import ConversationCompletedError, ConversationNotExistsError
from services.errors.conversation import (
ConversationCompletedError,
ConversationNotExistsError,
InvalidConversationIDError,
)

logger = logging.getLogger(__name__)


class MessageBasedAppGenerator(BaseAppGenerator):
allow_customized_conversation_id: bool = (
True if getenv("ALLOW_CUSTOMIZED_CONVERSATION_ID", "false") == "true" else False
)

def _handle_response(
self,
application_generate_entity: Union[
Expand Down Expand Up @@ -99,10 +108,10 @@ def _get_conversation_by_user(

conversation = db.session.query(Conversation).filter(and_(*conversation_filter)).first()

if not conversation:
if not conversation and self.allow_customized_conversation_id == False:
raise ConversationNotExistsError()

if conversation.status != "normal":
if conversation and conversation.status != "normal":
raise ConversationCompletedError()

return conversation
Expand Down Expand Up @@ -137,6 +146,7 @@ def _init_generate_records(
AdvancedChatAppGenerateEntity,
],
conversation: Optional[Conversation] = None,
customized_conversation_id: Optional[str] = None,
) -> tuple[Conversation, Message]:
"""
Initialize generate records
Expand Down Expand Up @@ -195,9 +205,17 @@ def _init_generate_records(
from_end_user_id=end_user_id,
from_account_id=account_id,
)

db.session.add(conversation)
db.session.commit()
if (
self.allow_customized_conversation_id
and customized_conversation_id
and len(customized_conversation_id) > 0
):
conversation.id = customized_conversation_id
try:
db.session.add(conversation)
db.session.commit()
except exc.IntegrityError as e:
raise InvalidConversationIDError()
db.session.refresh(conversation)
else:
conversation.updated_at = datetime.now(UTC).replace(tzinfo=None)
Expand Down
4 changes: 4 additions & 0 deletions api/services/errors/conversation.py
Original file line number Diff line number Diff line change
Expand Up @@ -11,3 +11,7 @@ class ConversationNotExistsError(BaseServiceError):

class ConversationCompletedError(Exception):
pass


class InvalidConversationIDError(BaseServiceError):
pass
9 changes: 6 additions & 3 deletions docker/.env.example
Original file line number Diff line number Diff line change
Expand Up @@ -286,8 +286,8 @@ STORAGE_TYPE=opendal

# Apache OpenDAL Configuration, refer to https://github.com/apache/opendal
# The scheme for the OpenDAL storage.
OPENDAL_SCHEME=fs
# Configurations for OpenDAL Local File System.
STORAGE_OPENDAL_SCHEME=fs
# OpenDAL FS
OPENDAL_FS_ROOT=storage

# S3 Configuration
Expand Down Expand Up @@ -919,4 +919,7 @@ MAX_SUBMIT_COUNT=100

# Proxy
HTTP_PROXY=
HTTPS_PROXY=
HTTPS_PROXY=

# whether user-customized conversation id is allowed
ALLOW_CUSTOMIZED_CONVERSATION_ID=false
1 change: 1 addition & 0 deletions docker/docker-compose.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -385,6 +385,7 @@ x-shared-env: &shared-api-worker-env
MAX_SUBMIT_COUNT: ${MAX_SUBMIT_COUNT:-100}
HTTP_PROXY: ${HTTP_PROXY:-}
HTTPS_PROXY: ${HTTPS_PROXY:-}
ALLOW_CUSTOMIZED_CONVERSATION_ID: ${ALLOW_CUSTOMIZED_CONVERSATION_ID:-True}

services:
# API service
Expand Down
Loading