|
@@ -4,6 +4,9 @@ import time
|
|
|
from collections.abc import Mapping
|
|
|
from typing import Any, Optional, cast
|
|
|
|
|
|
+from sqlalchemy import select
|
|
|
+from sqlalchemy.orm import Session
|
|
|
+
|
|
|
from core.app.apps.advanced_chat.app_config_manager import AdvancedChatAppConfig
|
|
|
from core.app.apps.advanced_chat.workflow_event_trigger_callback import WorkflowEventTriggerCallback
|
|
|
from core.app.apps.base_app_queue_manager import AppQueueManager, PublishFrom
|
|
@@ -17,11 +20,12 @@ from core.app.entities.queue_entities import QueueAnnotationReplyEvent, QueueSto
|
|
|
from core.moderation.base import ModerationException
|
|
|
from core.workflow.callbacks.base_workflow_callback import WorkflowCallback
|
|
|
from core.workflow.entities.node_entities import SystemVariable
|
|
|
+from core.workflow.entities.variable_pool import VariablePool
|
|
|
from core.workflow.nodes.base_node import UserFrom
|
|
|
from core.workflow.workflow_engine_manager import WorkflowEngineManager
|
|
|
from extensions.ext_database import db
|
|
|
from models.model import App, Conversation, EndUser, Message
|
|
|
-from models.workflow import Workflow
|
|
|
+from models.workflow import ConversationVariable, Workflow
|
|
|
|
|
|
logger = logging.getLogger(__name__)
|
|
|
|
|
@@ -31,10 +35,13 @@ class AdvancedChatAppRunner(AppRunner):
|
|
|
AdvancedChat Application Runner
|
|
|
"""
|
|
|
|
|
|
- def run(self, application_generate_entity: AdvancedChatAppGenerateEntity,
|
|
|
- queue_manager: AppQueueManager,
|
|
|
- conversation: Conversation,
|
|
|
- message: Message) -> None:
|
|
|
+ def run(
|
|
|
+ self,
|
|
|
+ application_generate_entity: AdvancedChatAppGenerateEntity,
|
|
|
+ queue_manager: AppQueueManager,
|
|
|
+ conversation: Conversation,
|
|
|
+ message: Message,
|
|
|
+ ) -> None:
|
|
|
"""
|
|
|
Run application
|
|
|
:param application_generate_entity: application generate entity
|
|
@@ -48,11 +55,11 @@ class AdvancedChatAppRunner(AppRunner):
|
|
|
|
|
|
app_record = db.session.query(App).filter(App.id == app_config.app_id).first()
|
|
|
if not app_record:
|
|
|
- raise ValueError("App not found")
|
|
|
+ raise ValueError('App not found')
|
|
|
|
|
|
workflow = self.get_workflow(app_model=app_record, workflow_id=app_config.workflow_id)
|
|
|
if not workflow:
|
|
|
- raise ValueError("Workflow not initialized")
|
|
|
+ raise ValueError('Workflow not initialized')
|
|
|
|
|
|
inputs = application_generate_entity.inputs
|
|
|
query = application_generate_entity.query
|
|
@@ -68,35 +75,66 @@ class AdvancedChatAppRunner(AppRunner):
|
|
|
|
|
|
# moderation
|
|
|
if self.handle_input_moderation(
|
|
|
- queue_manager=queue_manager,
|
|
|
- app_record=app_record,
|
|
|
- app_generate_entity=application_generate_entity,
|
|
|
- inputs=inputs,
|
|
|
- query=query,
|
|
|
- message_id=message.id
|
|
|
+ queue_manager=queue_manager,
|
|
|
+ app_record=app_record,
|
|
|
+ app_generate_entity=application_generate_entity,
|
|
|
+ inputs=inputs,
|
|
|
+ query=query,
|
|
|
+ message_id=message.id,
|
|
|
):
|
|
|
return
|
|
|
|
|
|
# annotation reply
|
|
|
if self.handle_annotation_reply(
|
|
|
- app_record=app_record,
|
|
|
- message=message,
|
|
|
- query=query,
|
|
|
- queue_manager=queue_manager,
|
|
|
- app_generate_entity=application_generate_entity
|
|
|
+ app_record=app_record,
|
|
|
+ message=message,
|
|
|
+ query=query,
|
|
|
+ queue_manager=queue_manager,
|
|
|
+ app_generate_entity=application_generate_entity,
|
|
|
):
|
|
|
return
|
|
|
|
|
|
db.session.close()
|
|
|
|
|
|
- workflow_callbacks: list[WorkflowCallback] = [WorkflowEventTriggerCallback(
|
|
|
- queue_manager=queue_manager,
|
|
|
- workflow=workflow
|
|
|
- )]
|
|
|
+ workflow_callbacks: list[WorkflowCallback] = [
|
|
|
+ WorkflowEventTriggerCallback(queue_manager=queue_manager, workflow=workflow)
|
|
|
+ ]
|
|
|
|
|
|
- if bool(os.environ.get("DEBUG", 'False').lower() == 'true'):
|
|
|
+ if bool(os.environ.get('DEBUG', 'False').lower() == 'true'):
|
|
|
workflow_callbacks.append(WorkflowLoggingCallback())
|
|
|
|
|
|
+ # Init conversation variables
|
|
|
+ stmt = select(ConversationVariable).where(
|
|
|
+ ConversationVariable.app_id == conversation.app_id, ConversationVariable.conversation_id == conversation.id
|
|
|
+ )
|
|
|
+ with Session(db.engine) as session:
|
|
|
+ conversation_variables = session.scalars(stmt).all()
|
|
|
+ if not conversation_variables:
|
|
|
+ conversation_variables = [
|
|
|
+ ConversationVariable.from_variable(
|
|
|
+ app_id=conversation.app_id, conversation_id=conversation.id, variable=variable
|
|
|
+ )
|
|
|
+ for variable in workflow.conversation_variables
|
|
|
+ ]
|
|
|
+ session.add_all(conversation_variables)
|
|
|
+ session.commit()
|
|
|
+ # Convert database entities to variables
|
|
|
+ conversation_variables = [item.to_variable() for item in conversation_variables]
|
|
|
+
|
|
|
+ # Create a variable pool.
|
|
|
+ system_inputs = {
|
|
|
+ SystemVariable.QUERY: query,
|
|
|
+ SystemVariable.FILES: files,
|
|
|
+ SystemVariable.CONVERSATION_ID: conversation.id,
|
|
|
+ SystemVariable.USER_ID: user_id,
|
|
|
+ }
|
|
|
+ variable_pool = VariablePool(
|
|
|
+ system_variables=system_inputs,
|
|
|
+ user_inputs=inputs,
|
|
|
+ environment_variables=workflow.environment_variables,
|
|
|
+ conversation_variables=conversation_variables,
|
|
|
+ )
|
|
|
+
|
|
|
# RUN WORKFLOW
|
|
|
workflow_engine_manager = WorkflowEngineManager()
|
|
|
workflow_engine_manager.run_workflow(
|
|
@@ -106,43 +144,30 @@ class AdvancedChatAppRunner(AppRunner):
|
|
|
if application_generate_entity.invoke_from in [InvokeFrom.EXPLORE, InvokeFrom.DEBUGGER]
|
|
|
else UserFrom.END_USER,
|
|
|
invoke_from=application_generate_entity.invoke_from,
|
|
|
- user_inputs=inputs,
|
|
|
- system_inputs={
|
|
|
- SystemVariable.QUERY: query,
|
|
|
- SystemVariable.FILES: files,
|
|
|
- SystemVariable.CONVERSATION_ID: conversation.id,
|
|
|
- SystemVariable.USER_ID: user_id
|
|
|
- },
|
|
|
callbacks=workflow_callbacks,
|
|
|
- call_depth=application_generate_entity.call_depth
|
|
|
+ call_depth=application_generate_entity.call_depth,
|
|
|
+ variable_pool=variable_pool,
|
|
|
)
|
|
|
|
|
|
- def single_iteration_run(self, app_id: str, workflow_id: str,
|
|
|
- queue_manager: AppQueueManager,
|
|
|
- inputs: dict, node_id: str, user_id: str) -> None:
|
|
|
+ def single_iteration_run(
|
|
|
+ self, app_id: str, workflow_id: str, queue_manager: AppQueueManager, inputs: dict, node_id: str, user_id: str
|
|
|
+ ) -> None:
|
|
|
"""
|
|
|
Single iteration run
|
|
|
"""
|
|
|
app_record: App = db.session.query(App).filter(App.id == app_id).first()
|
|
|
if not app_record:
|
|
|
- raise ValueError("App not found")
|
|
|
-
|
|
|
+ raise ValueError('App not found')
|
|
|
+
|
|
|
workflow = self.get_workflow(app_model=app_record, workflow_id=workflow_id)
|
|
|
if not workflow:
|
|
|
- raise ValueError("Workflow not initialized")
|
|
|
-
|
|
|
- workflow_callbacks = [WorkflowEventTriggerCallback(
|
|
|
- queue_manager=queue_manager,
|
|
|
- workflow=workflow
|
|
|
- )]
|
|
|
+ raise ValueError('Workflow not initialized')
|
|
|
+
|
|
|
+ workflow_callbacks = [WorkflowEventTriggerCallback(queue_manager=queue_manager, workflow=workflow)]
|
|
|
|
|
|
workflow_engine_manager = WorkflowEngineManager()
|
|
|
workflow_engine_manager.single_step_run_iteration_workflow_node(
|
|
|
- workflow=workflow,
|
|
|
- node_id=node_id,
|
|
|
- user_id=user_id,
|
|
|
- user_inputs=inputs,
|
|
|
- callbacks=workflow_callbacks
|
|
|
+ workflow=workflow, node_id=node_id, user_id=user_id, user_inputs=inputs, callbacks=workflow_callbacks
|
|
|
)
|
|
|
|
|
|
def get_workflow(self, app_model: App, workflow_id: str) -> Optional[Workflow]:
|
|
@@ -150,22 +175,25 @@ class AdvancedChatAppRunner(AppRunner):
|
|
|
Get workflow
|
|
|
"""
|
|
|
# fetch workflow by workflow_id
|
|
|
- workflow = db.session.query(Workflow).filter(
|
|
|
- Workflow.tenant_id == app_model.tenant_id,
|
|
|
- Workflow.app_id == app_model.id,
|
|
|
- Workflow.id == workflow_id
|
|
|
- ).first()
|
|
|
+ workflow = (
|
|
|
+ db.session.query(Workflow)
|
|
|
+ .filter(
|
|
|
+ Workflow.tenant_id == app_model.tenant_id, Workflow.app_id == app_model.id, Workflow.id == workflow_id
|
|
|
+ )
|
|
|
+ .first()
|
|
|
+ )
|
|
|
|
|
|
# return workflow
|
|
|
return workflow
|
|
|
|
|
|
def handle_input_moderation(
|
|
|
- self, queue_manager: AppQueueManager,
|
|
|
- app_record: App,
|
|
|
- app_generate_entity: AdvancedChatAppGenerateEntity,
|
|
|
- inputs: Mapping[str, Any],
|
|
|
- query: str,
|
|
|
- message_id: str
|
|
|
+ self,
|
|
|
+ queue_manager: AppQueueManager,
|
|
|
+ app_record: App,
|
|
|
+ app_generate_entity: AdvancedChatAppGenerateEntity,
|
|
|
+ inputs: Mapping[str, Any],
|
|
|
+ query: str,
|
|
|
+ message_id: str,
|
|
|
) -> bool:
|
|
|
"""
|
|
|
Handle input moderation
|
|
@@ -192,17 +220,20 @@ class AdvancedChatAppRunner(AppRunner):
|
|
|
queue_manager=queue_manager,
|
|
|
text=str(e),
|
|
|
stream=app_generate_entity.stream,
|
|
|
- stopped_by=QueueStopEvent.StopBy.INPUT_MODERATION
|
|
|
+ stopped_by=QueueStopEvent.StopBy.INPUT_MODERATION,
|
|
|
)
|
|
|
return True
|
|
|
|
|
|
return False
|
|
|
|
|
|
- def handle_annotation_reply(self, app_record: App,
|
|
|
- message: Message,
|
|
|
- query: str,
|
|
|
- queue_manager: AppQueueManager,
|
|
|
- app_generate_entity: AdvancedChatAppGenerateEntity) -> bool:
|
|
|
+ def handle_annotation_reply(
|
|
|
+ self,
|
|
|
+ app_record: App,
|
|
|
+ message: Message,
|
|
|
+ query: str,
|
|
|
+ queue_manager: AppQueueManager,
|
|
|
+ app_generate_entity: AdvancedChatAppGenerateEntity,
|
|
|
+ ) -> bool:
|
|
|
"""
|
|
|
Handle annotation reply
|
|
|
:param app_record: app record
|
|
@@ -217,29 +248,27 @@ class AdvancedChatAppRunner(AppRunner):
|
|
|
message=message,
|
|
|
query=query,
|
|
|
user_id=app_generate_entity.user_id,
|
|
|
- invoke_from=app_generate_entity.invoke_from
|
|
|
+ invoke_from=app_generate_entity.invoke_from,
|
|
|
)
|
|
|
|
|
|
if annotation_reply:
|
|
|
queue_manager.publish(
|
|
|
- QueueAnnotationReplyEvent(message_annotation_id=annotation_reply.id),
|
|
|
- PublishFrom.APPLICATION_MANAGER
|
|
|
+ QueueAnnotationReplyEvent(message_annotation_id=annotation_reply.id), PublishFrom.APPLICATION_MANAGER
|
|
|
)
|
|
|
|
|
|
self._stream_output(
|
|
|
queue_manager=queue_manager,
|
|
|
text=annotation_reply.content,
|
|
|
stream=app_generate_entity.stream,
|
|
|
- stopped_by=QueueStopEvent.StopBy.ANNOTATION_REPLY
|
|
|
+ stopped_by=QueueStopEvent.StopBy.ANNOTATION_REPLY,
|
|
|
)
|
|
|
return True
|
|
|
|
|
|
return False
|
|
|
|
|
|
- def _stream_output(self, queue_manager: AppQueueManager,
|
|
|
- text: str,
|
|
|
- stream: bool,
|
|
|
- stopped_by: QueueStopEvent.StopBy) -> None:
|
|
|
+ def _stream_output(
|
|
|
+ self, queue_manager: AppQueueManager, text: str, stream: bool, stopped_by: QueueStopEvent.StopBy
|
|
|
+ ) -> None:
|
|
|
"""
|
|
|
Direct output
|
|
|
:param queue_manager: application queue manager
|
|
@@ -250,21 +279,10 @@ class AdvancedChatAppRunner(AppRunner):
|
|
|
if stream:
|
|
|
index = 0
|
|
|
for token in text:
|
|
|
- queue_manager.publish(
|
|
|
- QueueTextChunkEvent(
|
|
|
- text=token
|
|
|
- ), PublishFrom.APPLICATION_MANAGER
|
|
|
- )
|
|
|
+ queue_manager.publish(QueueTextChunkEvent(text=token), PublishFrom.APPLICATION_MANAGER)
|
|
|
index += 1
|
|
|
time.sleep(0.01)
|
|
|
else:
|
|
|
- queue_manager.publish(
|
|
|
- QueueTextChunkEvent(
|
|
|
- text=text
|
|
|
- ), PublishFrom.APPLICATION_MANAGER
|
|
|
- )
|
|
|
+ queue_manager.publish(QueueTextChunkEvent(text=text), PublishFrom.APPLICATION_MANAGER)
|
|
|
|
|
|
- queue_manager.publish(
|
|
|
- QueueStopEvent(stopped_by=stopped_by),
|
|
|
- PublishFrom.APPLICATION_MANAGER
|
|
|
- )
|
|
|
+ queue_manager.publish(QueueStopEvent(stopped_by=stopped_by), PublishFrom.APPLICATION_MANAGER)
|