FEAT: NEW WORKFLOW ENGINE (#3160)

Co-authored-by: Joel <iamjoel007@gmail.com>
Co-authored-by: Yeuoly <admin@srmxy.cn>
Co-authored-by: JzoNg <jzongcode@gmail.com>
Co-authored-by: StyleZhang <jasonapring2015@outlook.com>
Co-authored-by: jyong <jyong@dify.ai>
Co-authored-by: nite-knite <nkCoding@gmail.com>
Co-authored-by: jyong <718720800@qq.com>
This commit is contained in:
takatost
2024-04-08 18:51:46 +08:00
committed by GitHub
parent 2fb9850af5
commit 7753ba2d37
1161 changed files with 103836 additions and 10327 deletions

View File

View File

@@ -0,0 +1,235 @@
from typing import Optional, Union
from core.app.entities.app_invoke_entities import ModelConfigWithCredentialsEntity
from core.file.file_obj import FileVar
from core.memory.token_buffer_memory import TokenBufferMemory
from core.model_runtime.entities.message_entities import (
AssistantPromptMessage,
PromptMessage,
PromptMessageRole,
SystemPromptMessage,
TextPromptMessageContent,
UserPromptMessage,
)
from core.prompt.entities.advanced_prompt_entities import ChatModelMessage, CompletionModelPromptTemplate, MemoryConfig
from core.prompt.prompt_transform import PromptTransform
from core.prompt.simple_prompt_transform import ModelMode
from core.prompt.utils.prompt_template_parser import PromptTemplateParser
class AdvancedPromptTransform(PromptTransform):
"""
Advanced Prompt Transform for Workflow LLM Node.
"""
def __init__(self, with_variable_tmpl: bool = False) -> None:
self.with_variable_tmpl = with_variable_tmpl
def get_prompt(self, prompt_template: Union[list[ChatModelMessage], CompletionModelPromptTemplate],
inputs: dict,
query: str,
files: list[FileVar],
context: Optional[str],
memory_config: Optional[MemoryConfig],
memory: Optional[TokenBufferMemory],
model_config: ModelConfigWithCredentialsEntity) -> list[PromptMessage]:
prompt_messages = []
model_mode = ModelMode.value_of(model_config.mode)
if model_mode == ModelMode.COMPLETION:
prompt_messages = self._get_completion_model_prompt_messages(
prompt_template=prompt_template,
inputs=inputs,
query=query,
files=files,
context=context,
memory_config=memory_config,
memory=memory,
model_config=model_config
)
elif model_mode == ModelMode.CHAT:
prompt_messages = self._get_chat_model_prompt_messages(
prompt_template=prompt_template,
inputs=inputs,
query=query,
files=files,
context=context,
memory_config=memory_config,
memory=memory,
model_config=model_config
)
return prompt_messages
def _get_completion_model_prompt_messages(self,
prompt_template: CompletionModelPromptTemplate,
inputs: dict,
query: Optional[str],
files: list[FileVar],
context: Optional[str],
memory_config: Optional[MemoryConfig],
memory: Optional[TokenBufferMemory],
model_config: ModelConfigWithCredentialsEntity) -> list[PromptMessage]:
"""
Get completion model prompt messages.
"""
raw_prompt = prompt_template.text
prompt_messages = []
prompt_template = PromptTemplateParser(template=raw_prompt, with_variable_tmpl=self.with_variable_tmpl)
prompt_inputs = {k: inputs[k] for k in prompt_template.variable_keys if k in inputs}
prompt_inputs = self._set_context_variable(context, prompt_template, prompt_inputs)
if memory and memory_config:
role_prefix = memory_config.role_prefix
prompt_inputs = self._set_histories_variable(
memory=memory,
memory_config=memory_config,
raw_prompt=raw_prompt,
role_prefix=role_prefix,
prompt_template=prompt_template,
prompt_inputs=prompt_inputs,
model_config=model_config
)
if query:
prompt_inputs = self._set_query_variable(query, prompt_template, prompt_inputs)
prompt = prompt_template.format(
prompt_inputs
)
if files:
prompt_message_contents = [TextPromptMessageContent(data=prompt)]
for file in files:
prompt_message_contents.append(file.prompt_message_content)
prompt_messages.append(UserPromptMessage(content=prompt_message_contents))
else:
prompt_messages.append(UserPromptMessage(content=prompt))
return prompt_messages
def _get_chat_model_prompt_messages(self,
prompt_template: list[ChatModelMessage],
inputs: dict,
query: Optional[str],
files: list[FileVar],
context: Optional[str],
memory_config: Optional[MemoryConfig],
memory: Optional[TokenBufferMemory],
model_config: ModelConfigWithCredentialsEntity) -> list[PromptMessage]:
"""
Get chat model prompt messages.
"""
raw_prompt_list = prompt_template
prompt_messages = []
for prompt_item in raw_prompt_list:
raw_prompt = prompt_item.text
prompt_template = PromptTemplateParser(template=raw_prompt, with_variable_tmpl=self.with_variable_tmpl)
prompt_inputs = {k: inputs[k] for k in prompt_template.variable_keys if k in inputs}
prompt_inputs = self._set_context_variable(context, prompt_template, prompt_inputs)
prompt = prompt_template.format(
prompt_inputs
)
if prompt_item.role == PromptMessageRole.USER:
prompt_messages.append(UserPromptMessage(content=prompt))
elif prompt_item.role == PromptMessageRole.SYSTEM and prompt:
prompt_messages.append(SystemPromptMessage(content=prompt))
elif prompt_item.role == PromptMessageRole.ASSISTANT:
prompt_messages.append(AssistantPromptMessage(content=prompt))
if memory and memory_config:
prompt_messages = self._append_chat_histories(memory, memory_config, prompt_messages, model_config)
if files:
prompt_message_contents = [TextPromptMessageContent(data=query)]
for file in files:
prompt_message_contents.append(file.prompt_message_content)
prompt_messages.append(UserPromptMessage(content=prompt_message_contents))
else:
prompt_messages.append(UserPromptMessage(content=query))
elif files:
if not query:
# get last message
last_message = prompt_messages[-1] if prompt_messages else None
if last_message and last_message.role == PromptMessageRole.USER:
# get last user message content and add files
prompt_message_contents = [TextPromptMessageContent(data=last_message.content)]
for file in files:
prompt_message_contents.append(file.prompt_message_content)
last_message.content = prompt_message_contents
else:
prompt_message_contents = [TextPromptMessageContent(data='')] # not for query
for file in files:
prompt_message_contents.append(file.prompt_message_content)
prompt_messages.append(UserPromptMessage(content=prompt_message_contents))
else:
prompt_message_contents = [TextPromptMessageContent(data=query)]
for file in files:
prompt_message_contents.append(file.prompt_message_content)
prompt_messages.append(UserPromptMessage(content=prompt_message_contents))
elif query:
prompt_messages.append(UserPromptMessage(content=query))
return prompt_messages
def _set_context_variable(self, context: str, prompt_template: PromptTemplateParser, prompt_inputs: dict) -> dict:
if '#context#' in prompt_template.variable_keys:
if context:
prompt_inputs['#context#'] = context
else:
prompt_inputs['#context#'] = ''
return prompt_inputs
def _set_query_variable(self, query: str, prompt_template: PromptTemplateParser, prompt_inputs: dict) -> dict:
if '#query#' in prompt_template.variable_keys:
if query:
prompt_inputs['#query#'] = query
else:
prompt_inputs['#query#'] = ''
return prompt_inputs
def _set_histories_variable(self, memory: TokenBufferMemory,
memory_config: MemoryConfig,
raw_prompt: str,
role_prefix: MemoryConfig.RolePrefix,
prompt_template: PromptTemplateParser,
prompt_inputs: dict,
model_config: ModelConfigWithCredentialsEntity) -> dict:
if '#histories#' in prompt_template.variable_keys:
if memory:
inputs = {'#histories#': '', **prompt_inputs}
prompt_template = PromptTemplateParser(template=raw_prompt, with_variable_tmpl=self.with_variable_tmpl)
prompt_inputs = {k: inputs[k] for k in prompt_template.variable_keys if k in inputs}
tmp_human_message = UserPromptMessage(
content=prompt_template.format(prompt_inputs)
)
rest_tokens = self._calculate_rest_token([tmp_human_message], model_config)
histories = self._get_history_messages_from_memory(
memory=memory,
memory_config=memory_config,
max_token_limit=rest_tokens,
human_prefix=role_prefix.user,
ai_prefix=role_prefix.assistant
)
prompt_inputs['#histories#'] = histories
else:
prompt_inputs['#histories#'] = ''
return prompt_inputs

View File

View File

@@ -0,0 +1,42 @@
from typing import Optional
from pydantic import BaseModel
from core.model_runtime.entities.message_entities import PromptMessageRole
class ChatModelMessage(BaseModel):
"""
Chat Message.
"""
text: str
role: PromptMessageRole
class CompletionModelPromptTemplate(BaseModel):
"""
Completion Model Prompt Template.
"""
text: str
class MemoryConfig(BaseModel):
"""
Memory Config.
"""
class RolePrefix(BaseModel):
"""
Role Prefix.
"""
user: str
assistant: str
class WindowConfig(BaseModel):
"""
Window Config.
"""
enabled: bool
size: Optional[int] = None
role_prefix: Optional[RolePrefix] = None
window: WindowConfig

View File

@@ -1,13 +0,0 @@
{
"human_prefix": "Human",
"assistant_prefix": "Assistant",
"context_prompt": "Use the following context as your learned knowledge, inside <context></context> XML tags.\n\n<context>\n{{context}}\n</context>\n\nWhen answer to user:\n- If you don't know, just say that you don't know.\n- If you don't know when you are not sure, ask for clarification.\nAvoid mentioning that you obtained the information from the context.\nAnd answer according to the language of the user's question.\n\n",
"histories_prompt": "Here is the chat histories between human and assistant, inside <histories></histories> XML tags.\n\n<histories>\n{{histories}}\n</histories>\n\n",
"system_prompt_orders": [
"context_prompt",
"pre_prompt",
"histories_prompt"
],
"query_prompt": "\n\nHuman: {{query}}\n\nAssistant: ",
"stops": ["\nHuman:", "</histories>"]
}

View File

@@ -1,9 +0,0 @@
{
"context_prompt": "Use the following context as your learned knowledge, inside <context></context> XML tags.\n\n<context>\n{{context}}\n</context>\n\nWhen answer to user:\n- If you don't know, just say that you don't know.\n- If you don't know when you are not sure, ask for clarification.\nAvoid mentioning that you obtained the information from the context.\nAnd answer according to the language of the user's question.\n\n",
"system_prompt_orders": [
"context_prompt",
"pre_prompt"
],
"query_prompt": "{{query}}",
"stops": null
}

View File

@@ -1,33 +0,0 @@
from typing import Any
from langchain.schema import BaseOutputParser, OutputParserException
from core.prompt.prompts import RULE_CONFIG_GENERATE_TEMPLATE
from libs.json_in_md_parser import parse_and_check_json_markdown
class RuleConfigGeneratorOutputParser(BaseOutputParser):
def get_format_instructions(self) -> str:
return RULE_CONFIG_GENERATE_TEMPLATE
def parse(self, text: str) -> Any:
try:
expected_keys = ["prompt", "variables", "opening_statement"]
parsed = parse_and_check_json_markdown(text, expected_keys)
if not isinstance(parsed["prompt"], str):
raise ValueError("Expected 'prompt' to be a string.")
if not isinstance(parsed["variables"], list):
raise ValueError(
"Expected 'variables' to be a list."
)
if not isinstance(parsed["opening_statement"], str):
raise ValueError(
"Expected 'opening_statement' to be a str."
)
return parsed
except Exception as e:
raise OutputParserException(
f"Parsing text\n{text}\n of rule config generator raised following error:\n{e}"
)

View File

@@ -1,23 +0,0 @@
import json
import re
from typing import Any
from langchain.schema import BaseOutputParser
from core.prompt.prompts import SUGGESTED_QUESTIONS_AFTER_ANSWER_INSTRUCTION_PROMPT
class SuggestedQuestionsAfterAnswerOutputParser(BaseOutputParser):
def get_format_instructions(self) -> str:
return SUGGESTED_QUESTIONS_AFTER_ANSWER_INSTRUCTION_PROMPT
def parse(self, text: str) -> Any:
action_match = re.search(r"\[.*?\]", text.strip(), re.DOTALL)
if action_match is not None:
json_obj = json.loads(action_match.group(0).strip())
else:
json_obj= []
print(f"Could not parse LLM output: {text}")
return json_obj

View File

@@ -1,10 +0,0 @@
from core.prompt.prompt_template import PromptTemplateParser
class PromptBuilder:
@classmethod
def parse_prompt(cls, prompt: str, inputs: dict) -> str:
prompt_template = PromptTemplateParser(prompt)
prompt_inputs = {k: inputs[k] for k in prompt_template.variable_keys if k in inputs}
prompt = prompt_template.format(prompt_inputs)
return prompt

View File

@@ -1,13 +1,13 @@
{
"human_prefix": "用户",
"assistant_prefix": "助手",
"context_prompt": "用户在与一个客观的助手对话。助手会尊重找到的材料,给出全面专业的解释,但不会过度演绎。同时回答中不会暴露引用的材料:\n\n```\n{{context}}\n```\n\n",
"histories_prompt": "用户和助手的历史对话内容如下:\n```\n{{histories}}\n```\n\n",
"context_prompt": "用户在与一个客观的助手对话。助手会尊重找到的材料,给出全面专业的解释,但不会过度演绎。同时回答中不会暴露引用的材料:\n\n```\n{{#context#}}\n```\n\n",
"histories_prompt": "用户和助手的历史对话内容如下:\n```\n{{#histories#}}\n```\n\n",
"system_prompt_orders": [
"context_prompt",
"pre_prompt",
"histories_prompt"
],
"query_prompt": "\n\n用户{{query}}",
"query_prompt": "\n\n用户{{#query#}}",
"stops": ["用户:"]
}

View File

@@ -1,9 +1,9 @@
{
"context_prompt": "用户在与一个客观的助手对话。助手会尊重找到的材料,给出全面专业的解释,但不会过度演绎。同时回答中不会暴露引用的材料:\n\n```\n{{context}}\n```\n",
"context_prompt": "用户在与一个客观的助手对话。助手会尊重找到的材料,给出全面专业的解释,但不会过度演绎。同时回答中不会暴露引用的材料:\n\n```\n{{#context#}}\n```\n",
"system_prompt_orders": [
"context_prompt",
"pre_prompt"
],
"query_prompt": "{{query}}",
"query_prompt": "{{#query#}}",
"stops": null
}

View File

@@ -0,0 +1,13 @@
{
"human_prefix": "Human",
"assistant_prefix": "Assistant",
"context_prompt": "Use the following context as your learned knowledge, inside <context></context> XML tags.\n\n<context>\n{{#context#}}\n</context>\n\nWhen answer to user:\n- If you don't know, just say that you don't know.\n- If you don't know when you are not sure, ask for clarification.\nAvoid mentioning that you obtained the information from the context.\nAnd answer according to the language of the user's question.\n\n",
"histories_prompt": "Here is the chat histories between human and assistant, inside <histories></histories> XML tags.\n\n<histories>\n{{#histories#}}\n</histories>\n\n",
"system_prompt_orders": [
"context_prompt",
"pre_prompt",
"histories_prompt"
],
"query_prompt": "\n\nHuman: {{#query#}}\n\nAssistant: ",
"stops": ["\nHuman:", "</histories>"]
}

View File

@@ -0,0 +1,9 @@
{
"context_prompt": "Use the following context as your learned knowledge, inside <context></context> XML tags.\n\n<context>\n{{#context#}}\n</context>\n\nWhen answer to user:\n- If you don't know, just say that you don't know.\n- If you don't know when you are not sure, ask for clarification.\nAvoid mentioning that you obtained the information from the context.\nAnd answer according to the language of the user's question.\n\n",
"system_prompt_orders": [
"context_prompt",
"pre_prompt"
],
"query_prompt": "{{#query#}}",
"stops": null
}

View File

@@ -1,419 +1,26 @@
import enum
import json
import os
import re
from typing import Optional, cast
from core.entities.application_entities import (
AdvancedCompletionPromptTemplateEntity,
ModelConfigEntity,
PromptTemplateEntity,
)
from core.file.file_obj import FileObj
from core.app.entities.app_invoke_entities import ModelConfigWithCredentialsEntity
from core.memory.token_buffer_memory import TokenBufferMemory
from core.model_runtime.entities.message_entities import (
AssistantPromptMessage,
PromptMessage,
PromptMessageRole,
SystemPromptMessage,
TextPromptMessageContent,
UserPromptMessage,
)
from core.model_runtime.entities.message_entities import PromptMessage
from core.model_runtime.entities.model_entities import ModelPropertyKey
from core.model_runtime.model_providers.__base.large_language_model import LargeLanguageModel
from core.prompt.prompt_builder import PromptBuilder
from core.prompt.prompt_template import PromptTemplateParser
class AppMode(enum.Enum):
COMPLETION = 'completion'
CHAT = 'chat'
@classmethod
def value_of(cls, value: str) -> 'AppMode':
"""
Get value of given mode.
:param value: mode value
:return: mode
"""
for mode in cls:
if mode.value == value:
return mode
raise ValueError(f'invalid mode value {value}')
class ModelMode(enum.Enum):
COMPLETION = 'completion'
CHAT = 'chat'
@classmethod
def value_of(cls, value: str) -> 'ModelMode':
"""
Get value of given mode.
:param value: mode value
:return: mode
"""
for mode in cls:
if mode.value == value:
return mode
raise ValueError(f'invalid mode value {value}')
from core.prompt.entities.advanced_prompt_entities import MemoryConfig
class PromptTransform:
def get_prompt(self,
app_mode: str,
prompt_template_entity: PromptTemplateEntity,
inputs: dict,
query: str,
files: list[FileObj],
context: Optional[str],
memory: Optional[TokenBufferMemory],
model_config: ModelConfigEntity) -> \
tuple[list[PromptMessage], Optional[list[str]]]:
app_mode = AppMode.value_of(app_mode)
model_mode = ModelMode.value_of(model_config.mode)
prompt_rules = self._read_prompt_rules_from_file(self._prompt_file_name(
app_mode=app_mode,
provider=model_config.provider,
model=model_config.model
))
if app_mode == AppMode.CHAT and model_mode == ModelMode.CHAT:
stops = None
prompt_messages = self._get_simple_chat_app_chat_model_prompt_messages(
prompt_rules=prompt_rules,
pre_prompt=prompt_template_entity.simple_prompt_template,
inputs=inputs,
query=query,
files=files,
context=context,
memory=memory,
model_config=model_config
)
else:
stops = prompt_rules.get('stops')
if stops is not None and len(stops) == 0:
stops = None
prompt_messages = self._get_simple_others_prompt_messages(
prompt_rules=prompt_rules,
pre_prompt=prompt_template_entity.simple_prompt_template,
inputs=inputs,
query=query,
files=files,
context=context,
memory=memory,
model_config=model_config
)
return prompt_messages, stops
def get_advanced_prompt(self, app_mode: str,
prompt_template_entity: PromptTemplateEntity,
inputs: dict,
query: str,
files: list[FileObj],
context: Optional[str],
memory: Optional[TokenBufferMemory],
model_config: ModelConfigEntity) -> list[PromptMessage]:
app_mode = AppMode.value_of(app_mode)
model_mode = ModelMode.value_of(model_config.mode)
prompt_messages = []
if app_mode == AppMode.CHAT:
if model_mode == ModelMode.COMPLETION:
prompt_messages = self._get_chat_app_completion_model_prompt_messages(
prompt_template_entity=prompt_template_entity,
inputs=inputs,
query=query,
files=files,
context=context,
memory=memory,
model_config=model_config
)
elif model_mode == ModelMode.CHAT:
prompt_messages = self._get_chat_app_chat_model_prompt_messages(
prompt_template_entity=prompt_template_entity,
inputs=inputs,
query=query,
files=files,
context=context,
memory=memory,
model_config=model_config
)
elif app_mode == AppMode.COMPLETION:
if model_mode == ModelMode.CHAT:
prompt_messages = self._get_completion_app_chat_model_prompt_messages(
prompt_template_entity=prompt_template_entity,
inputs=inputs,
files=files,
context=context,
)
elif model_mode == ModelMode.COMPLETION:
prompt_messages = self._get_completion_app_completion_model_prompt_messages(
prompt_template_entity=prompt_template_entity,
inputs=inputs,
context=context,
)
return prompt_messages
def _get_history_messages_from_memory(self, memory: TokenBufferMemory,
max_token_limit: int,
human_prefix: Optional[str] = None,
ai_prefix: Optional[str] = None) -> str:
"""Get memory messages."""
kwargs = {
"max_token_limit": max_token_limit
}
if human_prefix:
kwargs['human_prefix'] = human_prefix
if ai_prefix:
kwargs['ai_prefix'] = ai_prefix
return memory.get_history_prompt_text(
**kwargs
)
def _get_history_messages_list_from_memory(self, memory: TokenBufferMemory,
max_token_limit: int) -> list[PromptMessage]:
"""Get memory messages."""
return memory.get_history_prompt_messages(
max_token_limit=max_token_limit
)
def _prompt_file_name(self, app_mode: AppMode, provider: str, model: str) -> str:
# baichuan
if provider == 'baichuan':
return self._prompt_file_name_for_baichuan(app_mode)
baichuan_supported_providers = ["huggingface_hub", "openllm", "xinference"]
if provider in baichuan_supported_providers and 'baichuan' in model.lower():
return self._prompt_file_name_for_baichuan(app_mode)
# common
if app_mode == AppMode.COMPLETION:
return 'common_completion'
else:
return 'common_chat'
def _prompt_file_name_for_baichuan(self, app_mode: AppMode) -> str:
if app_mode == AppMode.COMPLETION:
return 'baichuan_completion'
else:
return 'baichuan_chat'
def _read_prompt_rules_from_file(self, prompt_name: str) -> dict:
# Get the absolute path of the subdirectory
prompt_path = os.path.join(
os.path.dirname(os.path.realpath(__file__)),
'generate_prompts')
json_file_path = os.path.join(prompt_path, f'{prompt_name}.json')
# Open the JSON file and read its content
with open(json_file_path, encoding='utf-8') as json_file:
return json.load(json_file)
def _get_simple_chat_app_chat_model_prompt_messages(self, prompt_rules: dict,
pre_prompt: str,
inputs: dict,
query: str,
context: Optional[str],
files: list[FileObj],
memory: Optional[TokenBufferMemory],
model_config: ModelConfigEntity) -> list[PromptMessage]:
prompt_messages = []
context_prompt_content = ''
if context and 'context_prompt' in prompt_rules:
prompt_template = PromptTemplateParser(template=prompt_rules['context_prompt'])
context_prompt_content = prompt_template.format(
{'context': context}
)
pre_prompt_content = ''
if pre_prompt:
prompt_template = PromptTemplateParser(template=pre_prompt)
prompt_inputs = {k: inputs[k] for k in prompt_template.variable_keys if k in inputs}
pre_prompt_content = prompt_template.format(
prompt_inputs
)
prompt = ''
for order in prompt_rules['system_prompt_orders']:
if order == 'context_prompt':
prompt += context_prompt_content
elif order == 'pre_prompt':
prompt += pre_prompt_content
prompt = re.sub(r'<\|.*?\|>', '', prompt)
if prompt:
prompt_messages.append(SystemPromptMessage(content=prompt))
self._append_chat_histories(
memory=memory,
prompt_messages=prompt_messages,
model_config=model_config
)
if files:
prompt_message_contents = [TextPromptMessageContent(data=query)]
for file in files:
prompt_message_contents.append(file.prompt_message_content)
prompt_messages.append(UserPromptMessage(content=prompt_message_contents))
else:
prompt_messages.append(UserPromptMessage(content=query))
return prompt_messages
def _get_simple_others_prompt_messages(self, prompt_rules: dict,
pre_prompt: str,
inputs: dict,
query: str,
context: Optional[str],
memory: Optional[TokenBufferMemory],
files: list[FileObj],
model_config: ModelConfigEntity) -> list[PromptMessage]:
context_prompt_content = ''
if context and 'context_prompt' in prompt_rules:
prompt_template = PromptTemplateParser(template=prompt_rules['context_prompt'])
context_prompt_content = prompt_template.format(
{'context': context}
)
pre_prompt_content = ''
if pre_prompt:
prompt_template = PromptTemplateParser(template=pre_prompt)
prompt_inputs = {k: inputs[k] for k in prompt_template.variable_keys if k in inputs}
pre_prompt_content = prompt_template.format(
prompt_inputs
)
prompt = ''
for order in prompt_rules['system_prompt_orders']:
if order == 'context_prompt':
prompt += context_prompt_content
elif order == 'pre_prompt':
prompt += pre_prompt_content
query_prompt = prompt_rules['query_prompt'] if 'query_prompt' in prompt_rules else '{{query}}'
if memory and 'histories_prompt' in prompt_rules:
# append chat histories
tmp_human_message = UserPromptMessage(
content=PromptBuilder.parse_prompt(
prompt=prompt + query_prompt,
inputs={
'query': query
}
)
)
rest_tokens = self._calculate_rest_token([tmp_human_message], model_config)
histories = self._get_history_messages_from_memory(
memory=memory,
max_token_limit=rest_tokens,
ai_prefix=prompt_rules['human_prefix'] if 'human_prefix' in prompt_rules else 'Human',
human_prefix=prompt_rules['assistant_prefix'] if 'assistant_prefix' in prompt_rules else 'Assistant'
)
prompt_template = PromptTemplateParser(template=prompt_rules['histories_prompt'])
histories_prompt_content = prompt_template.format({'histories': histories})
prompt = ''
for order in prompt_rules['system_prompt_orders']:
if order == 'context_prompt':
prompt += context_prompt_content
elif order == 'pre_prompt':
prompt += (pre_prompt_content + '\n') if pre_prompt_content else ''
elif order == 'histories_prompt':
prompt += histories_prompt_content
prompt_template = PromptTemplateParser(template=query_prompt)
query_prompt_content = prompt_template.format({'query': query})
prompt += query_prompt_content
prompt = re.sub(r'<\|.*?\|>', '', prompt)
model_mode = ModelMode.value_of(model_config.mode)
if model_mode == ModelMode.CHAT and files:
prompt_message_contents = [TextPromptMessageContent(data=prompt)]
for file in files:
prompt_message_contents.append(file.prompt_message_content)
prompt_message = UserPromptMessage(content=prompt_message_contents)
else:
if files:
prompt_message_contents = [TextPromptMessageContent(data=prompt)]
for file in files:
prompt_message_contents.append(file.prompt_message_content)
prompt_message = UserPromptMessage(content=prompt_message_contents)
else:
prompt_message = UserPromptMessage(content=prompt)
return [prompt_message]
def _set_context_variable(self, context: str, prompt_template: PromptTemplateParser, prompt_inputs: dict) -> None:
if '#context#' in prompt_template.variable_keys:
if context:
prompt_inputs['#context#'] = context
else:
prompt_inputs['#context#'] = ''
def _set_query_variable(self, query: str, prompt_template: PromptTemplateParser, prompt_inputs: dict) -> None:
if '#query#' in prompt_template.variable_keys:
if query:
prompt_inputs['#query#'] = query
else:
prompt_inputs['#query#'] = ''
def _set_histories_variable(self, memory: TokenBufferMemory,
raw_prompt: str,
role_prefix: AdvancedCompletionPromptTemplateEntity.RolePrefixEntity,
prompt_template: PromptTemplateParser,
prompt_inputs: dict,
model_config: ModelConfigEntity) -> None:
if '#histories#' in prompt_template.variable_keys:
if memory:
tmp_human_message = UserPromptMessage(
content=PromptBuilder.parse_prompt(
prompt=raw_prompt,
inputs={'#histories#': '', **prompt_inputs}
)
)
rest_tokens = self._calculate_rest_token([tmp_human_message], model_config)
histories = self._get_history_messages_from_memory(
memory=memory,
max_token_limit=rest_tokens,
human_prefix=role_prefix.user,
ai_prefix=role_prefix.assistant
)
prompt_inputs['#histories#'] = histories
else:
prompt_inputs['#histories#'] = ''
def _append_chat_histories(self, memory: TokenBufferMemory,
memory_config: MemoryConfig,
prompt_messages: list[PromptMessage],
model_config: ModelConfigEntity) -> None:
if memory:
rest_tokens = self._calculate_rest_token(prompt_messages, model_config)
histories = self._get_history_messages_list_from_memory(memory, rest_tokens)
prompt_messages.extend(histories)
model_config: ModelConfigWithCredentialsEntity) -> list[PromptMessage]:
rest_tokens = self._calculate_rest_token(prompt_messages, model_config)
histories = self._get_history_messages_list_from_memory(memory, memory_config, rest_tokens)
prompt_messages.extend(histories)
def _calculate_rest_token(self, prompt_messages: list[PromptMessage], model_config: ModelConfigEntity) -> int:
return prompt_messages
def _calculate_rest_token(self, prompt_messages: list[PromptMessage],
model_config: ModelConfigWithCredentialsEntity) -> int:
rest_tokens = 2000
model_context_tokens = model_config.model_schema.model_properties.get(ModelPropertyKey.CONTEXT_SIZE)
@@ -439,152 +46,38 @@ class PromptTransform:
return rest_tokens
def _format_prompt(self, prompt_template: PromptTemplateParser, prompt_inputs: dict) -> str:
prompt = prompt_template.format(
prompt_inputs
def _get_history_messages_from_memory(self, memory: TokenBufferMemory,
memory_config: MemoryConfig,
max_token_limit: int,
human_prefix: Optional[str] = None,
ai_prefix: Optional[str] = None) -> str:
"""Get memory messages."""
kwargs = {
"max_token_limit": max_token_limit
}
if human_prefix:
kwargs['human_prefix'] = human_prefix
if ai_prefix:
kwargs['ai_prefix'] = ai_prefix
if memory_config.window.enabled and memory_config.window.size is not None and memory_config.window.size > 0:
kwargs['message_limit'] = memory_config.window.size
return memory.get_history_prompt_text(
**kwargs
)
prompt = re.sub(r'<\|.*?\|>', '', prompt)
return prompt
def _get_chat_app_completion_model_prompt_messages(self,
prompt_template_entity: PromptTemplateEntity,
inputs: dict,
query: str,
files: list[FileObj],
context: Optional[str],
memory: Optional[TokenBufferMemory],
model_config: ModelConfigEntity) -> list[PromptMessage]:
raw_prompt = prompt_template_entity.advanced_completion_prompt_template.prompt
role_prefix = prompt_template_entity.advanced_completion_prompt_template.role_prefix
prompt_messages = []
prompt_template = PromptTemplateParser(template=raw_prompt)
prompt_inputs = {k: inputs[k] for k in prompt_template.variable_keys if k in inputs}
self._set_context_variable(context, prompt_template, prompt_inputs)
self._set_query_variable(query, prompt_template, prompt_inputs)
self._set_histories_variable(
memory=memory,
raw_prompt=raw_prompt,
role_prefix=role_prefix,
prompt_template=prompt_template,
prompt_inputs=prompt_inputs,
model_config=model_config
def _get_history_messages_list_from_memory(self, memory: TokenBufferMemory,
memory_config: MemoryConfig,
max_token_limit: int) -> list[PromptMessage]:
"""Get memory messages."""
return memory.get_history_prompt_messages(
max_token_limit=max_token_limit,
message_limit=memory_config.window.size
if (memory_config.window.enabled
and memory_config.window.size is not None
and memory_config.window.size > 0)
else 10
)
prompt = self._format_prompt(prompt_template, prompt_inputs)
if files:
prompt_message_contents = [TextPromptMessageContent(data=prompt)]
for file in files:
prompt_message_contents.append(file.prompt_message_content)
prompt_messages.append(UserPromptMessage(content=prompt_message_contents))
else:
prompt_messages.append(UserPromptMessage(content=prompt))
return prompt_messages
def _get_chat_app_chat_model_prompt_messages(self,
prompt_template_entity: PromptTemplateEntity,
inputs: dict,
query: str,
files: list[FileObj],
context: Optional[str],
memory: Optional[TokenBufferMemory],
model_config: ModelConfigEntity) -> list[PromptMessage]:
raw_prompt_list = prompt_template_entity.advanced_chat_prompt_template.messages
prompt_messages = []
for prompt_item in raw_prompt_list:
raw_prompt = prompt_item.text
prompt_template = PromptTemplateParser(template=raw_prompt)
prompt_inputs = {k: inputs[k] for k in prompt_template.variable_keys if k in inputs}
self._set_context_variable(context, prompt_template, prompt_inputs)
prompt = self._format_prompt(prompt_template, prompt_inputs)
if prompt_item.role == PromptMessageRole.USER:
prompt_messages.append(UserPromptMessage(content=prompt))
elif prompt_item.role == PromptMessageRole.SYSTEM and prompt:
prompt_messages.append(SystemPromptMessage(content=prompt))
elif prompt_item.role == PromptMessageRole.ASSISTANT:
prompt_messages.append(AssistantPromptMessage(content=prompt))
self._append_chat_histories(memory, prompt_messages, model_config)
if files:
prompt_message_contents = [TextPromptMessageContent(data=query)]
for file in files:
prompt_message_contents.append(file.prompt_message_content)
prompt_messages.append(UserPromptMessage(content=prompt_message_contents))
else:
prompt_messages.append(UserPromptMessage(content=query))
return prompt_messages
def _get_completion_app_completion_model_prompt_messages(self,
prompt_template_entity: PromptTemplateEntity,
inputs: dict,
context: Optional[str]) -> list[PromptMessage]:
raw_prompt = prompt_template_entity.advanced_completion_prompt_template.prompt
prompt_messages = []
prompt_template = PromptTemplateParser(template=raw_prompt)
prompt_inputs = {k: inputs[k] for k in prompt_template.variable_keys if k in inputs}
self._set_context_variable(context, prompt_template, prompt_inputs)
prompt = self._format_prompt(prompt_template, prompt_inputs)
prompt_messages.append(UserPromptMessage(content=prompt))
return prompt_messages
def _get_completion_app_chat_model_prompt_messages(self,
prompt_template_entity: PromptTemplateEntity,
inputs: dict,
files: list[FileObj],
context: Optional[str]) -> list[PromptMessage]:
raw_prompt_list = prompt_template_entity.advanced_chat_prompt_template.messages
prompt_messages = []
for prompt_item in raw_prompt_list:
raw_prompt = prompt_item.text
prompt_template = PromptTemplateParser(template=raw_prompt)
prompt_inputs = {k: inputs[k] for k in prompt_template.variable_keys if k in inputs}
self._set_context_variable(context, prompt_template, prompt_inputs)
prompt = self._format_prompt(prompt_template, prompt_inputs)
if prompt_item.role == PromptMessageRole.USER:
prompt_messages.append(UserPromptMessage(content=prompt))
elif prompt_item.role == PromptMessageRole.SYSTEM and prompt:
prompt_messages.append(SystemPromptMessage(content=prompt))
elif prompt_item.role == PromptMessageRole.ASSISTANT:
prompt_messages.append(AssistantPromptMessage(content=prompt))
for prompt_message in prompt_messages[::-1]:
if prompt_message.role == PromptMessageRole.USER:
if files:
prompt_message_contents = [TextPromptMessageContent(data=prompt_message.content)]
for file in files:
prompt_message_contents.append(file.prompt_message_content)
prompt_message.content = prompt_message_contents
break
return prompt_messages

View File

@@ -1,144 +0,0 @@
# Written by YORKI MINAKO🤡, Edited by Xiaoyi
CONVERSATION_TITLE_PROMPT = """You need to decompose the user's input into "subject" and "intention" in order to accurately figure out what the user's input language actually is.
Notice: the language type user use could be diverse, which can be English, Chinese, Español, Arabic, Japanese, French, and etc.
MAKE SURE your output is the SAME language as the user's input!
Your output is restricted only to: (Input language) Intention + Subject(short as possible)
Your output MUST be a valid JSON.
Tip: When the user's question is directed at you (the language model), you can add an emoji to make it more fun.
example 1:
User Input: hi, yesterday i had some burgers.
{
"Language Type": "The user's input is pure English",
"Your Reasoning": "The language of my output must be pure English.",
"Your Output": "sharing yesterday's food"
}
example 2:
User Input: hello
{
"Language Type": "The user's input is written in pure English",
"Your Reasoning": "The language of my output must be pure English.",
"Your Output": "Greeting myself☺"
}
example 3:
User Input: why mmap file: oom
{
"Language Type": "The user's input is written in pure English",
"Your Reasoning": "The language of my output must be pure English.",
"Your Output": "Asking about the reason for mmap file: oom"
}
example 4:
User Input: www.convinceme.yesterday-you-ate-seafood.tv讲了什么
{
"Language Type": "The user's input English-Chinese mixed",
"Your Reasoning": "The English-part is an URL, the main intention is still written in Chinese, so the language of my output must be using Chinese.",
"Your Output": "询问网站www.convinceme.yesterday-you-ate-seafood.tv"
}
example 5:
User Input: why小红的年龄is老than小明
{
"Language Type": "The user's input is English-Chinese mixed",
"Your Reasoning": "The English parts are subjective particles, the main intention is written in Chinese, besides, Chinese occupies a greater \"actual meaning\" than English, so the language of my output must be using Chinese.",
"Your Output": "询问小红和小明的年龄"
}
example 6:
User Input: yo, 你今天咋样?
{
"Language Type": "The user's input is English-Chinese mixed",
"Your Reasoning": "The English-part is a subjective particle, the main intention is written in Chinese, so the language of my output must be using Chinese.",
"Your Output": "查询今日我的状态☺️"
}
User Input:
"""
SUGGESTED_QUESTIONS_AFTER_ANSWER_INSTRUCTION_PROMPT = (
"Please help me predict the three most likely questions that human would ask, "
"and keeping each question under 20 characters.\n"
"The output must be an array in JSON format following the specified schema:\n"
"[\"question1\",\"question2\",\"question3\"]\n"
)
GENERATOR_QA_PROMPT = (
'<Task> The user will send a long text. Generate a Question and Answer pairs only using the knowledge in the long text. Please think step by step.'
'Step 1: Understand and summarize the main content of this text.\n'
'Step 2: What key information or concepts are mentioned in this text?\n'
'Step 3: Decompose or combine multiple pieces of information and concepts.\n'
'Step 4: Generate questions and answers based on these key information and concepts.\n'
'<Constraints> The questions should be clear and detailed, and the answers should be detailed and complete. '
'You must answer in {language}, in a style that is clear and detailed in {language}. No language other than {language} should be used. \n'
'<Format> Use the following format: Q1:\nA1:\nQ2:\nA2:...\n'
'<QA Pairs>'
)
RULE_CONFIG_GENERATE_TEMPLATE = """Given MY INTENDED AUDIENCES and HOPING TO SOLVE using a language model, please select \
the model prompt that best suits the input.
You will be provided with the prompt, variables, and an opening statement.
Only the content enclosed in double curly braces, such as {{variable}}, in the prompt can be considered as a variable; \
otherwise, it cannot exist as a variable in the variables.
If you believe revising the original input will result in a better response from the language model, you may \
suggest revisions.
<<PRINCIPLES OF GOOD PROMPT>>
Integrate the intended audience in the prompt e.g. the audience is an expert in the field.
Break down complex tasks into a sequence of simpler prompts in an interactive conversation.
Implement example-driven prompting (Use few-shot prompting).
When formatting your prompt start with Instruction followed by either Example if relevant. \
Subsequently present your content. Use one or more line breaks to separate instructions examples questions context and input data.
Incorporate the following phrases: “Your task is” and “You MUST”.
Incorporate the following phrases: “You will be penalized”.
Use leading words like writing “think step by step”.
Add to your prompt the following phrase “Ensure that your answer is unbiased and does not rely on stereotypes”.
Assign a role to the large language models.
Use Delimiters.
To write an essay /text /paragraph /article or any type of text that should be detailed: “Write a detailed [essay/text/paragraph] for me on [topic] in detail by adding all the information necessary”.
Clearly state the requirements that the model must follow in order to produce content in the form of the keywords regulations hint or instructions
<< FORMATTING >>
Return a markdown code snippet with a JSON object formatted to look like, \
no any other string out of markdown code snippet:
```json
{{{{
"prompt": string \\ generated prompt
"variables": list of string \\ variables
"opening_statement": string \\ an opening statement to guide users on how to ask questions with generated prompt \
and fill in variables, with a welcome sentence, and keep TLDR.
}}}}
```
<< EXAMPLES >>
[EXAMPLE A]
```json
{
"prompt": "I need your help to translate the following {{Input_language}}paper paragraph into {{Target_language}}, in a style similar to a popular science magazine in {{Target_language}}. #### Rules Ensure accurate conveyance of the original text's facts and context during translation. Maintain the original paragraph format and retain technical terms and company abbreviations ",
"variables": ["Input_language", "Target_language"],
"opening_statement": " Hi. I am your translation assistant. I can help you with any translation and ensure accurate conveyance of information. "
}
```
[EXAMPLE B]
```json
{
"prompt": "Your task is to review the provided meeting notes and create a concise summary that captures the essential information, focusing on key takeaways and action items assigned to specific individuals or departments during the meeting. Use clear and professional language, and organize the summary in a logical manner using appropriate formatting such as headings, subheadings, and bullet points. Ensure that the summary is easy to understand and provides a comprehensive but succinct overview of the meeting's content, with a particular focus on clearly indicating who is responsible for each action item.",
"variables": ["meeting_notes"],
"opening_statement": "Hi! I'm your meeting notes summarizer AI. I can help you with any meeting notes and ensure accurate conveyance of information."
}
```
<< MY INTENDED AUDIENCES >>
{{audiences}}
<< HOPING TO SOLVE >>
{{hoping_to_solve}}
<< OUTPUT >>
"""

View File

@@ -0,0 +1,319 @@
import enum
import json
import os
from typing import Optional
from core.app.app_config.entities import PromptTemplateEntity
from core.app.entities.app_invoke_entities import ModelConfigWithCredentialsEntity
from core.file.file_obj import FileVar
from core.memory.token_buffer_memory import TokenBufferMemory
from core.model_runtime.entities.message_entities import (
PromptMessage,
SystemPromptMessage,
TextPromptMessageContent,
UserPromptMessage,
)
from core.prompt.entities.advanced_prompt_entities import MemoryConfig
from core.prompt.prompt_transform import PromptTransform
from core.prompt.utils.prompt_template_parser import PromptTemplateParser
from models.model import AppMode
class ModelMode(enum.Enum):
COMPLETION = 'completion'
CHAT = 'chat'
@classmethod
def value_of(cls, value: str) -> 'ModelMode':
"""
Get value of given mode.
:param value: mode value
:return: mode
"""
for mode in cls:
if mode.value == value:
return mode
raise ValueError(f'invalid mode value {value}')
prompt_file_contents = {}
class SimplePromptTransform(PromptTransform):
"""
Simple Prompt Transform for Chatbot App Basic Mode.
"""
def get_prompt(self,
app_mode: AppMode,
prompt_template_entity: PromptTemplateEntity,
inputs: dict,
query: str,
files: list[FileVar],
context: Optional[str],
memory: Optional[TokenBufferMemory],
model_config: ModelConfigWithCredentialsEntity) -> \
tuple[list[PromptMessage], Optional[list[str]]]:
model_mode = ModelMode.value_of(model_config.mode)
if model_mode == ModelMode.CHAT:
prompt_messages, stops = self._get_chat_model_prompt_messages(
app_mode=app_mode,
pre_prompt=prompt_template_entity.simple_prompt_template,
inputs=inputs,
query=query,
files=files,
context=context,
memory=memory,
model_config=model_config
)
else:
prompt_messages, stops = self._get_completion_model_prompt_messages(
app_mode=app_mode,
pre_prompt=prompt_template_entity.simple_prompt_template,
inputs=inputs,
query=query,
files=files,
context=context,
memory=memory,
model_config=model_config
)
return prompt_messages, stops
def get_prompt_str_and_rules(self, app_mode: AppMode,
model_config: ModelConfigWithCredentialsEntity,
pre_prompt: str,
inputs: dict,
query: Optional[str] = None,
context: Optional[str] = None,
histories: Optional[str] = None,
) -> tuple[str, dict]:
# get prompt template
prompt_template_config = self.get_prompt_template(
app_mode=app_mode,
provider=model_config.provider,
model=model_config.model,
pre_prompt=pre_prompt,
has_context=context is not None,
query_in_prompt=query is not None,
with_memory_prompt=histories is not None
)
variables = {k: inputs[k] for k in prompt_template_config['custom_variable_keys'] if k in inputs}
for v in prompt_template_config['special_variable_keys']:
# support #context#, #query# and #histories#
if v == '#context#':
variables['#context#'] = context if context else ''
elif v == '#query#':
variables['#query#'] = query if query else ''
elif v == '#histories#':
variables['#histories#'] = histories if histories else ''
prompt_template = prompt_template_config['prompt_template']
prompt = prompt_template.format(variables)
return prompt, prompt_template_config['prompt_rules']
def get_prompt_template(self, app_mode: AppMode,
provider: str,
model: str,
pre_prompt: str,
has_context: bool,
query_in_prompt: bool,
with_memory_prompt: bool = False) -> dict:
prompt_rules = self._get_prompt_rule(
app_mode=app_mode,
provider=provider,
model=model
)
custom_variable_keys = []
special_variable_keys = []
prompt = ''
for order in prompt_rules['system_prompt_orders']:
if order == 'context_prompt' and has_context:
prompt += prompt_rules['context_prompt']
special_variable_keys.append('#context#')
elif order == 'pre_prompt' and pre_prompt:
prompt += pre_prompt + '\n'
pre_prompt_template = PromptTemplateParser(template=pre_prompt)
custom_variable_keys = pre_prompt_template.variable_keys
elif order == 'histories_prompt' and with_memory_prompt:
prompt += prompt_rules['histories_prompt']
special_variable_keys.append('#histories#')
if query_in_prompt:
prompt += prompt_rules['query_prompt'] if 'query_prompt' in prompt_rules else '{{#query#}}'
special_variable_keys.append('#query#')
return {
"prompt_template": PromptTemplateParser(template=prompt),
"custom_variable_keys": custom_variable_keys,
"special_variable_keys": special_variable_keys,
"prompt_rules": prompt_rules
}
def _get_chat_model_prompt_messages(self, app_mode: AppMode,
pre_prompt: str,
inputs: dict,
query: str,
context: Optional[str],
files: list[FileVar],
memory: Optional[TokenBufferMemory],
model_config: ModelConfigWithCredentialsEntity) \
-> tuple[list[PromptMessage], Optional[list[str]]]:
prompt_messages = []
# get prompt
prompt, _ = self.get_prompt_str_and_rules(
app_mode=app_mode,
model_config=model_config,
pre_prompt=pre_prompt,
inputs=inputs,
query=None,
context=context
)
if prompt and query:
prompt_messages.append(SystemPromptMessage(content=prompt))
if memory:
prompt_messages = self._append_chat_histories(
memory=memory,
memory_config=MemoryConfig(
window=MemoryConfig.WindowConfig(
enabled=False,
)
),
prompt_messages=prompt_messages,
model_config=model_config
)
if query:
prompt_messages.append(self.get_last_user_message(query, files))
else:
prompt_messages.append(self.get_last_user_message(prompt, files))
return prompt_messages, None
def _get_completion_model_prompt_messages(self, app_mode: AppMode,
pre_prompt: str,
inputs: dict,
query: str,
context: Optional[str],
files: list[FileVar],
memory: Optional[TokenBufferMemory],
model_config: ModelConfigWithCredentialsEntity) \
-> tuple[list[PromptMessage], Optional[list[str]]]:
# get prompt
prompt, prompt_rules = self.get_prompt_str_and_rules(
app_mode=app_mode,
model_config=model_config,
pre_prompt=pre_prompt,
inputs=inputs,
query=query,
context=context
)
if memory:
tmp_human_message = UserPromptMessage(
content=prompt
)
rest_tokens = self._calculate_rest_token([tmp_human_message], model_config)
histories = self._get_history_messages_from_memory(
memory=memory,
memory_config=MemoryConfig(
window=MemoryConfig.WindowConfig(
enabled=False,
)
),
max_token_limit=rest_tokens,
ai_prefix=prompt_rules['human_prefix'] if 'human_prefix' in prompt_rules else 'Human',
human_prefix=prompt_rules['assistant_prefix'] if 'assistant_prefix' in prompt_rules else 'Assistant'
)
# get prompt
prompt, prompt_rules = self.get_prompt_str_and_rules(
app_mode=app_mode,
model_config=model_config,
pre_prompt=pre_prompt,
inputs=inputs,
query=query,
context=context,
histories=histories
)
stops = prompt_rules.get('stops')
if stops is not None and len(stops) == 0:
stops = None
return [self.get_last_user_message(prompt, files)], stops
def get_last_user_message(self, prompt: str, files: list[FileVar]) -> UserPromptMessage:
if files:
prompt_message_contents = [TextPromptMessageContent(data=prompt)]
for file in files:
prompt_message_contents.append(file.prompt_message_content)
prompt_message = UserPromptMessage(content=prompt_message_contents)
else:
prompt_message = UserPromptMessage(content=prompt)
return prompt_message
def _get_prompt_rule(self, app_mode: AppMode, provider: str, model: str) -> dict:
"""
Get simple prompt rule.
:param app_mode: app mode
:param provider: model provider
:param model: model name
:return:
"""
prompt_file_name = self._prompt_file_name(
app_mode=app_mode,
provider=provider,
model=model
)
# Check if the prompt file is already loaded
if prompt_file_name in prompt_file_contents:
return prompt_file_contents[prompt_file_name]
# Get the absolute path of the subdirectory
prompt_path = os.path.join(os.path.dirname(os.path.realpath(__file__)), 'prompt_templates')
json_file_path = os.path.join(prompt_path, f'{prompt_file_name}.json')
# Open the JSON file and read its content
with open(json_file_path, encoding='utf-8') as json_file:
content = json.load(json_file)
# Store the content of the prompt file
prompt_file_contents[prompt_file_name] = content
return content
def _prompt_file_name(self, app_mode: AppMode, provider: str, model: str) -> str:
# baichuan
is_baichuan = False
if provider == 'baichuan':
is_baichuan = True
else:
baichuan_supported_providers = ["huggingface_hub", "openllm", "xinference"]
if provider in baichuan_supported_providers and 'baichuan' in model.lower():
is_baichuan = True
if is_baichuan:
if app_mode == AppMode.COMPLETION:
return 'baichuan_completion'
else:
return 'baichuan_chat'
# common
if app_mode == AppMode.COMPLETION:
return 'common_completion'
else:
return 'common_chat'

View File

View File

@@ -0,0 +1,85 @@
from typing import cast
from core.model_runtime.entities.message_entities import (
ImagePromptMessageContent,
PromptMessage,
PromptMessageContentType,
PromptMessageRole,
TextPromptMessageContent,
)
from core.prompt.simple_prompt_transform import ModelMode
class PromptMessageUtil:
@staticmethod
def prompt_messages_to_prompt_for_saving(model_mode: str, prompt_messages: list[PromptMessage]) -> list[dict]:
"""
Prompt messages to prompt for saving.
:param model_mode: model mode
:param prompt_messages: prompt messages
:return:
"""
prompts = []
if model_mode == ModelMode.CHAT.value:
for prompt_message in prompt_messages:
if prompt_message.role == PromptMessageRole.USER:
role = 'user'
elif prompt_message.role == PromptMessageRole.ASSISTANT:
role = 'assistant'
elif prompt_message.role == PromptMessageRole.SYSTEM:
role = 'system'
else:
continue
text = ''
files = []
if isinstance(prompt_message.content, list):
for content in prompt_message.content:
if content.type == PromptMessageContentType.TEXT:
content = cast(TextPromptMessageContent, content)
text += content.data
else:
content = cast(ImagePromptMessageContent, content)
files.append({
"type": 'image',
"data": content.data[:10] + '...[TRUNCATED]...' + content.data[-10:],
"detail": content.detail.value
})
else:
text = prompt_message.content
prompts.append({
"role": role,
"text": text,
"files": files
})
else:
prompt_message = prompt_messages[0]
text = ''
files = []
if isinstance(prompt_message.content, list):
for content in prompt_message.content:
if content.type == PromptMessageContentType.TEXT:
content = cast(TextPromptMessageContent, content)
text += content.data
else:
content = cast(ImagePromptMessageContent, content)
files.append({
"type": 'image',
"data": content.data[:10] + '...[TRUNCATED]...' + content.data[-10:],
"detail": content.detail.value
})
else:
text = prompt_message.content
params = {
"role": 'user',
"text": text,
}
if files:
params['files'] = files
prompts.append(params)
return prompts

View File

@@ -1,6 +1,9 @@
import re
REGEX = re.compile(r"\{\{([a-zA-Z_][a-zA-Z0-9_]{0,29}|#histories#|#query#|#context#)\}\}")
WITH_VARIABLE_TMPL_REGEX = re.compile(
r"\{\{([a-zA-Z_][a-zA-Z0-9_]{0,29}|#[a-zA-Z0-9_]{1,50}\.[a-zA-Z0-9_\.]{1,100}#|#histories#|#query#|#context#)\}\}"
)
class PromptTemplateParser:
@@ -15,13 +18,15 @@ class PromptTemplateParser:
`{{#histories#}}` `{{#query#}}` `{{#context#}}`. No other `{{##}}` template variables are allowed.
"""
def __init__(self, template: str):
def __init__(self, template: str, with_variable_tmpl: bool = False):
self.template = template
self.with_variable_tmpl = with_variable_tmpl
self.regex = WITH_VARIABLE_TMPL_REGEX if with_variable_tmpl else REGEX
self.variable_keys = self.extract()
def extract(self) -> list:
# Regular expression to match the template rules
return re.findall(REGEX, self.template)
return re.findall(self.regex, self.template)
def format(self, inputs: dict, remove_template_variables: bool = True) -> str:
def replacer(match):
@@ -29,11 +34,12 @@ class PromptTemplateParser:
value = inputs.get(key, match.group(0)) # return original matched string if key not found
if remove_template_variables:
return PromptTemplateParser.remove_template_variables(value)
return PromptTemplateParser.remove_template_variables(value, self.with_variable_tmpl)
return value
return re.sub(REGEX, replacer, self.template)
prompt = re.sub(self.regex, replacer, self.template)
return re.sub(r'<\|.*?\|>', '', prompt)
@classmethod
def remove_template_variables(cls, text: str):
return re.sub(REGEX, r'{\1}', text)
def remove_template_variables(cls, text: str, with_variable_tmpl: bool = False):
return re.sub(WITH_VARIABLE_TMPL_REGEX if with_variable_tmpl else REGEX, r'{\1}', text)