mirror of
https://github.com/langgenius/dify.git
synced 2026-04-26 18:27:15 +08:00
add expert mode of chatapp convert command
This commit is contained in:
parent
7458fde5a5
commit
2ba7ac8bc1
@ -1,5 +1,6 @@
|
|||||||
import base64
|
import base64
|
||||||
import json
|
import json
|
||||||
|
import logging
|
||||||
import secrets
|
import secrets
|
||||||
|
|
||||||
import click
|
import click
|
||||||
@ -12,11 +13,12 @@ from extensions.ext_database import db
|
|||||||
from libs.helper import email as email_validate
|
from libs.helper import email as email_validate
|
||||||
from libs.password import hash_password, password_pattern, valid_password
|
from libs.password import hash_password, password_pattern, valid_password
|
||||||
from libs.rsa import generate_key_pair
|
from libs.rsa import generate_key_pair
|
||||||
from models.account import Tenant
|
from models.account import Tenant, TenantAccountJoin
|
||||||
from models.dataset import Dataset, DatasetCollectionBinding, DocumentSegment
|
from models.dataset import Dataset, DatasetCollectionBinding, DocumentSegment
|
||||||
from models.dataset import Document as DatasetDocument
|
from models.dataset import Document as DatasetDocument
|
||||||
from models.model import Account, App, AppMode, AppModelConfig, AppAnnotationSetting, Conversation, MessageAnnotation
|
from models.model import Account, App, AppMode, AppModelConfig, AppAnnotationSetting, Conversation, MessageAnnotation
|
||||||
from models.provider import Provider, ProviderModel
|
from models.provider import Provider, ProviderModel
|
||||||
|
from services.workflow.workflow_converter import WorkflowConverter
|
||||||
|
|
||||||
|
|
||||||
@click.command('reset-password', help='Reset the account password.')
|
@click.command('reset-password', help='Reset the account password.')
|
||||||
@ -422,9 +424,77 @@ and am.agent_mode like '{"enabled": true%' ORDER BY a.created_at DESC LIMIT 1000
|
|||||||
click.echo(click.style('Congratulations! Converted {} agent apps.'.format(len(proceeded_app_ids)), fg='green'))
|
click.echo(click.style('Congratulations! Converted {} agent apps.'.format(len(proceeded_app_ids)), fg='green'))
|
||||||
|
|
||||||
|
|
||||||
|
@click.command('convert-to-workflow-chatbot-apps', help='Convert Basic Export Assistant to Chatbot Workflow App.')
|
||||||
|
def convert_to_workflow_chatbot_apps():
|
||||||
|
"""
|
||||||
|
Convert Basic Export Assistant to Chatbot Workflow App.
|
||||||
|
"""
|
||||||
|
click.echo(click.style('Start convert to workflow chatbot apps.', fg='green'))
|
||||||
|
|
||||||
|
proceeded_app_ids = []
|
||||||
|
workflow_converter = WorkflowConverter()
|
||||||
|
|
||||||
|
while True:
|
||||||
|
# fetch first 1000 apps
|
||||||
|
sql_query = """SELECT a.id FROM apps a
|
||||||
|
LEFT JOIN app_model_configs am ON a.app_model_config_id=am.id
|
||||||
|
WHERE a.mode = 'chat' AND am.prompt_type='advanced' ORDER BY a.created_at DESC LIMIT 1000"""
|
||||||
|
|
||||||
|
with db.engine.begin() as conn:
|
||||||
|
rs = conn.execute(db.text(sql_query))
|
||||||
|
|
||||||
|
apps = []
|
||||||
|
for i in rs:
|
||||||
|
app_id = str(i.id)
|
||||||
|
print(app_id)
|
||||||
|
if app_id not in proceeded_app_ids:
|
||||||
|
proceeded_app_ids.append(app_id)
|
||||||
|
app = db.session.query(App).filter(App.id == app_id).first()
|
||||||
|
apps.append(app)
|
||||||
|
|
||||||
|
if len(apps) == 0:
|
||||||
|
break
|
||||||
|
|
||||||
|
for app in apps:
|
||||||
|
click.echo('Converting app: {}'.format(app.id))
|
||||||
|
|
||||||
|
try:
|
||||||
|
# get workspace of app
|
||||||
|
tenant = db.session.query(Tenant).filter(Tenant.id == app.tenant_id).first()
|
||||||
|
if not tenant:
|
||||||
|
click.echo(click.style('Tenant not found: {}'.format(app.tenant_id), fg='red'))
|
||||||
|
continue
|
||||||
|
|
||||||
|
# get workspace owner
|
||||||
|
tenant_account_join = db.session.query(TenantAccountJoin).filter(
|
||||||
|
TenantAccountJoin.tenant_id == tenant.id,
|
||||||
|
TenantAccountJoin.role == 'owner'
|
||||||
|
).first()
|
||||||
|
|
||||||
|
if not tenant_account_join:
|
||||||
|
click.echo(click.style('Tenant owner not found: {}'.format(tenant.id), fg='red'))
|
||||||
|
continue
|
||||||
|
|
||||||
|
# convert to workflow
|
||||||
|
workflow_converter.convert_to_workflow(
|
||||||
|
app_model=app,
|
||||||
|
account_id=tenant_account_join.account_id
|
||||||
|
)
|
||||||
|
|
||||||
|
click.echo(click.style('Converted app: {}'.format(app.id), fg='green'))
|
||||||
|
except Exception as e:
|
||||||
|
logging.exception('Convert app error: {}'.format(app.id))
|
||||||
|
click.echo(
|
||||||
|
click.style('Convert app error: {} {}'.format(e.__class__.__name__,
|
||||||
|
str(e)), fg='red'))
|
||||||
|
|
||||||
|
click.echo(click.style('Congratulations! Converted {} workflow chatbot apps.'.format(len(proceeded_app_ids)), fg='green'))
|
||||||
|
|
||||||
|
|
||||||
def register_commands(app):
|
def register_commands(app):
|
||||||
app.cli.add_command(reset_password)
|
app.cli.add_command(reset_password)
|
||||||
app.cli.add_command(reset_email)
|
app.cli.add_command(reset_email)
|
||||||
app.cli.add_command(reset_encrypt_key_pair)
|
app.cli.add_command(reset_encrypt_key_pair)
|
||||||
app.cli.add_command(vdb_migrate)
|
app.cli.add_command(vdb_migrate)
|
||||||
app.cli.add_command(convert_to_agent_apps)
|
app.cli.add_command(convert_to_agent_apps)
|
||||||
|
app.cli.add_command(convert_to_workflow_chatbot_apps)
|
||||||
|
|||||||
@ -235,12 +235,15 @@ class ApplicationManager:
|
|||||||
logger.exception(e)
|
logger.exception(e)
|
||||||
raise e
|
raise e
|
||||||
|
|
||||||
def convert_from_app_model_config_dict(self, tenant_id: str, app_model_config_dict: dict) \
|
def convert_from_app_model_config_dict(self, tenant_id: str,
|
||||||
|
app_model_config_dict: dict,
|
||||||
|
skip_check: bool = False) \
|
||||||
-> AppOrchestrationConfigEntity:
|
-> AppOrchestrationConfigEntity:
|
||||||
"""
|
"""
|
||||||
Convert app model config dict to entity.
|
Convert app model config dict to entity.
|
||||||
:param tenant_id: tenant ID
|
:param tenant_id: tenant ID
|
||||||
:param app_model_config_dict: app model config dict
|
:param app_model_config_dict: app model config dict
|
||||||
|
:param skip_check: skip check
|
||||||
:raises ProviderTokenNotInitError: provider token not init error
|
:raises ProviderTokenNotInitError: provider token not init error
|
||||||
:return: app orchestration config entity
|
:return: app orchestration config entity
|
||||||
"""
|
"""
|
||||||
@ -268,24 +271,28 @@ class ApplicationManager:
|
|||||||
)
|
)
|
||||||
|
|
||||||
if model_credentials is None:
|
if model_credentials is None:
|
||||||
raise ProviderTokenNotInitError(f"Model {model_name} credentials is not initialized.")
|
if not skip_check:
|
||||||
|
raise ProviderTokenNotInitError(f"Model {model_name} credentials is not initialized.")
|
||||||
|
else:
|
||||||
|
model_credentials = {}
|
||||||
|
|
||||||
# check model
|
if not skip_check:
|
||||||
provider_model = provider_model_bundle.configuration.get_provider_model(
|
# check model
|
||||||
model=copy_app_model_config_dict['model']['name'],
|
provider_model = provider_model_bundle.configuration.get_provider_model(
|
||||||
model_type=ModelType.LLM
|
model=copy_app_model_config_dict['model']['name'],
|
||||||
)
|
model_type=ModelType.LLM
|
||||||
|
)
|
||||||
|
|
||||||
if provider_model is None:
|
if provider_model is None:
|
||||||
model_name = copy_app_model_config_dict['model']['name']
|
model_name = copy_app_model_config_dict['model']['name']
|
||||||
raise ValueError(f"Model {model_name} not exist.")
|
raise ValueError(f"Model {model_name} not exist.")
|
||||||
|
|
||||||
if provider_model.status == ModelStatus.NO_CONFIGURE:
|
if provider_model.status == ModelStatus.NO_CONFIGURE:
|
||||||
raise ProviderTokenNotInitError(f"Model {model_name} credentials is not initialized.")
|
raise ProviderTokenNotInitError(f"Model {model_name} credentials is not initialized.")
|
||||||
elif provider_model.status == ModelStatus.NO_PERMISSION:
|
elif provider_model.status == ModelStatus.NO_PERMISSION:
|
||||||
raise ModelCurrentlyNotSupportError(f"Dify Hosted OpenAI {model_name} currently not support.")
|
raise ModelCurrentlyNotSupportError(f"Dify Hosted OpenAI {model_name} currently not support.")
|
||||||
elif provider_model.status == ModelStatus.QUOTA_EXCEEDED:
|
elif provider_model.status == ModelStatus.QUOTA_EXCEEDED:
|
||||||
raise QuotaExceededError(f"Model provider {provider_name} quota exceeded.")
|
raise QuotaExceededError(f"Model provider {provider_name} quota exceeded.")
|
||||||
|
|
||||||
# model config
|
# model config
|
||||||
completion_params = copy_app_model_config_dict['model'].get('completion_params')
|
completion_params = copy_app_model_config_dict['model'].get('completion_params')
|
||||||
@ -309,7 +316,7 @@ class ApplicationManager:
|
|||||||
model_credentials
|
model_credentials
|
||||||
)
|
)
|
||||||
|
|
||||||
if not model_schema:
|
if not skip_check and not model_schema:
|
||||||
raise ValueError(f"Model {model_name} not exist.")
|
raise ValueError(f"Model {model_name} not exist.")
|
||||||
|
|
||||||
properties['model_config'] = ModelConfigEntity(
|
properties['model_config'] = ModelConfigEntity(
|
||||||
|
|||||||
@ -15,7 +15,7 @@ class ModelConfigEntity(BaseModel):
|
|||||||
"""
|
"""
|
||||||
provider: str
|
provider: str
|
||||||
model: str
|
model: str
|
||||||
model_schema: AIModelEntity
|
model_schema: Optional[AIModelEntity] = None
|
||||||
mode: str
|
mode: str
|
||||||
provider_model_bundle: ProviderModelBundle
|
provider_model_bundle: ProviderModelBundle
|
||||||
credentials: dict[str, Any] = {}
|
credentials: dict[str, Any] = {}
|
||||||
|
|||||||
@ -13,12 +13,11 @@ from core.entities.application_entities import (
|
|||||||
)
|
)
|
||||||
from core.helper import encrypter
|
from core.helper import encrypter
|
||||||
from core.model_runtime.entities.llm_entities import LLMMode
|
from core.model_runtime.entities.llm_entities import LLMMode
|
||||||
from core.model_runtime.utils import helper
|
from core.model_runtime.utils.encoders import jsonable_encoder
|
||||||
from core.prompt.simple_prompt_transform import SimplePromptTransform
|
from core.prompt.simple_prompt_transform import SimplePromptTransform
|
||||||
from core.workflow.entities.NodeEntities import NodeType
|
from core.workflow.entities.NodeEntities import NodeType
|
||||||
from core.workflow.nodes.end.entities import EndNodeOutputType
|
from core.workflow.nodes.end.entities import EndNodeOutputType
|
||||||
from extensions.ext_database import db
|
from extensions.ext_database import db
|
||||||
from models.account import Account
|
|
||||||
from models.api_based_extension import APIBasedExtension, APIBasedExtensionPoint
|
from models.api_based_extension import APIBasedExtension, APIBasedExtensionPoint
|
||||||
from models.model import App, AppMode, ChatbotAppEngine
|
from models.model import App, AppMode, ChatbotAppEngine
|
||||||
from models.workflow import Workflow, WorkflowType
|
from models.workflow import Workflow, WorkflowType
|
||||||
@ -29,7 +28,7 @@ class WorkflowConverter:
|
|||||||
App Convert to Workflow Mode
|
App Convert to Workflow Mode
|
||||||
"""
|
"""
|
||||||
|
|
||||||
def convert_to_workflow(self, app_model: App, account: Account) -> Workflow:
|
def convert_to_workflow(self, app_model: App, account_id: str) -> Workflow:
|
||||||
"""
|
"""
|
||||||
Convert to workflow mode
|
Convert to workflow mode
|
||||||
|
|
||||||
@ -40,7 +39,7 @@ class WorkflowConverter:
|
|||||||
- completion app (for migration)
|
- completion app (for migration)
|
||||||
|
|
||||||
:param app_model: App instance
|
:param app_model: App instance
|
||||||
:param account: Account instance
|
:param account_id: Account ID
|
||||||
:return: workflow instance
|
:return: workflow instance
|
||||||
"""
|
"""
|
||||||
# get new app mode
|
# get new app mode
|
||||||
@ -53,7 +52,8 @@ class WorkflowConverter:
|
|||||||
application_manager = ApplicationManager()
|
application_manager = ApplicationManager()
|
||||||
app_orchestration_config_entity = application_manager.convert_from_app_model_config_dict(
|
app_orchestration_config_entity = application_manager.convert_from_app_model_config_dict(
|
||||||
tenant_id=app_model.tenant_id,
|
tenant_id=app_model.tenant_id,
|
||||||
app_model_config_dict=app_model_config.to_dict()
|
app_model_config_dict=app_model_config.to_dict(),
|
||||||
|
skip_check=True
|
||||||
)
|
)
|
||||||
|
|
||||||
# init workflow graph
|
# init workflow graph
|
||||||
@ -122,7 +122,7 @@ class WorkflowConverter:
|
|||||||
type=WorkflowType.from_app_mode(new_app_mode).value,
|
type=WorkflowType.from_app_mode(new_app_mode).value,
|
||||||
version='draft',
|
version='draft',
|
||||||
graph=json.dumps(graph),
|
graph=json.dumps(graph),
|
||||||
created_by=account.id
|
created_by=account_id
|
||||||
)
|
)
|
||||||
|
|
||||||
db.session.add(workflow)
|
db.session.add(workflow)
|
||||||
@ -130,6 +130,7 @@ class WorkflowConverter:
|
|||||||
|
|
||||||
# create new app model config record
|
# create new app model config record
|
||||||
new_app_model_config = app_model_config.copy()
|
new_app_model_config = app_model_config.copy()
|
||||||
|
new_app_model_config.id = None
|
||||||
new_app_model_config.external_data_tools = ''
|
new_app_model_config.external_data_tools = ''
|
||||||
new_app_model_config.model = ''
|
new_app_model_config.model = ''
|
||||||
new_app_model_config.user_input_form = ''
|
new_app_model_config.user_input_form = ''
|
||||||
@ -147,6 +148,9 @@ class WorkflowConverter:
|
|||||||
db.session.add(new_app_model_config)
|
db.session.add(new_app_model_config)
|
||||||
db.session.commit()
|
db.session.commit()
|
||||||
|
|
||||||
|
app_model.app_model_config_id = new_app_model_config.id
|
||||||
|
db.session.commit()
|
||||||
|
|
||||||
return workflow
|
return workflow
|
||||||
|
|
||||||
def _convert_to_start_node(self, variables: list[VariableEntity]) -> dict:
|
def _convert_to_start_node(self, variables: list[VariableEntity]) -> dict:
|
||||||
@ -161,7 +165,7 @@ class WorkflowConverter:
|
|||||||
"data": {
|
"data": {
|
||||||
"title": "START",
|
"title": "START",
|
||||||
"type": NodeType.START.value,
|
"type": NodeType.START.value,
|
||||||
"variables": [helper.dump_model(v) for v in variables]
|
"variables": [jsonable_encoder(v) for v in variables]
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -369,7 +373,10 @@ class WorkflowConverter:
|
|||||||
]
|
]
|
||||||
else:
|
else:
|
||||||
advanced_chat_prompt_template = prompt_template.advanced_chat_prompt_template
|
advanced_chat_prompt_template = prompt_template.advanced_chat_prompt_template
|
||||||
prompts = [helper.dump_model(m) for m in advanced_chat_prompt_template.messages] \
|
prompts = [{
|
||||||
|
"role": m.role.value,
|
||||||
|
"text": m.text
|
||||||
|
} for m in advanced_chat_prompt_template.messages] \
|
||||||
if advanced_chat_prompt_template else []
|
if advanced_chat_prompt_template else []
|
||||||
# Completion Model
|
# Completion Model
|
||||||
else:
|
else:
|
||||||
|
|||||||
@ -79,6 +79,6 @@ class WorkflowService:
|
|||||||
|
|
||||||
# convert to workflow mode
|
# convert to workflow mode
|
||||||
workflow_converter = WorkflowConverter()
|
workflow_converter = WorkflowConverter()
|
||||||
workflow = workflow_converter.convert_to_workflow(app_model=app_model, account=account)
|
workflow = workflow_converter.convert_to_workflow(app_model=app_model, account_id=account.id)
|
||||||
|
|
||||||
return workflow
|
return workflow
|
||||||
|
|||||||
@ -41,6 +41,8 @@ def test__convert_to_start_node(default_variables):
|
|||||||
result = WorkflowConverter()._convert_to_start_node(default_variables)
|
result = WorkflowConverter()._convert_to_start_node(default_variables)
|
||||||
|
|
||||||
# assert
|
# assert
|
||||||
|
assert isinstance(result["data"]["variables"][0]["type"], str)
|
||||||
|
assert result["data"]["variables"][0]["type"] == "text-input"
|
||||||
assert result["data"]["variables"][0]["variable"] == "text-input"
|
assert result["data"]["variables"][0]["variable"] == "text-input"
|
||||||
assert result["data"]["variables"][1]["variable"] == "paragraph"
|
assert result["data"]["variables"][1]["variable"] == "paragraph"
|
||||||
assert result["data"]["variables"][2]["variable"] == "select"
|
assert result["data"]["variables"][2]["variable"] == "select"
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user