feat: History API (client) (#204)

This commit is contained in:
cachho
2023-07-10 20:15:20 +02:00
committed by GitHub
parent b3cf834186
commit 65414af098
4 changed files with 111 additions and 41 deletions

View File

@@ -1,14 +1,46 @@
from embedchain.config.QueryConfig import QueryConfig
from string import Template
DEFAULT_PROMPT = """
You are a chatbot having a conversation with a human. You are given chat history and context.
You need to answer the query considering context, chat history and your knowledge base. If you don't know the answer or the answer is neither contained in the context nor in history, then simply say "I don't know".
$context
History: $history
Query: $query
Helpful Answer:
"""
DEFAULT_PROMPT_TEMPLATE = Template(DEFAULT_PROMPT)
class ChatConfig(QueryConfig):
"""
Config for the `chat` method, inherits from `QueryConfig`.
"""
def __init__(self, stream: bool = False):
def __init__(self, template: Template = None, stream: bool = False):
"""
Initializes the QueryConfig instance.
Initializes the ChatConfig instance.
:param template: Optional. The `Template` instance to use as a template for prompt.
:param stream: Optional. Control if response is streamed back to the user
:raises ValueError: If the template is not valid as template should contain $context and $query
:raises ValueError: If the template is not valid as template should contain $context and $query and $history
"""
super().__init__(stream=stream)
if template is None:
template = DEFAULT_PROMPT_TEMPLATE
# History is set as 0 to ensure that there is always a history, that way, there don't have to be two templates.
# Having two templates would make it complicated because the history is not user controlled.
super().__init__(template, history=[0], stream=stream)
def set_history(self, history):
"""
Chat history is not user provided and not set at initialization time
:param history: (string) history to set
"""
self.history = history
return

View File

@@ -13,30 +13,78 @@ DEFAULT_PROMPT = """
Helpful Answer:
"""
DEFAULT_PROMPT_WITH_HISTORY = """
Use the following pieces of context to answer the query at the end.
If you don't know the answer, just say that you don't know, don't try to make up an answer.
I will provide you with our conversation history.
$context
History: $history
Query: $query
Helpful Answer:
"""
DEFAULT_PROMPT_TEMPLATE = Template(DEFAULT_PROMPT)
DEFAULT_PROMPT_WITH_HISTORY_TEMPLATE = Template(DEFAULT_PROMPT_WITH_HISTORY)
query_re = re.compile(r"\$\{*query\}*")
context_re = re.compile(r"\$\{*context\}*")
history_re = re.compile(r"\$\{*history\}*")
class QueryConfig(BaseConfig):
"""
Config for the `query` method.
"""
def __init__(self, template: Template = None, stream: bool = False):
def __init__(self, template: Template = None, history = None, stream: bool = False):
"""
Initializes the QueryConfig instance.
:param template: Optional. The `Template` instance to use as a template for prompt.
:param history: Optional. A list of strings to consider as history.
:param stream: Optional. Control if response is streamed back to the user
:raises ValueError: If the template is not valid as template should contain $context and $query
:raises ValueError: If the template is not valid as template should contain $context and $query (and optionally $history).
"""
if not history:
self.history = None
else:
if len(history) == 0:
self.history = None
else:
self.history = history
if template is None:
template = DEFAULT_PROMPT_TEMPLATE
if not (re.search(query_re, template.template) \
and re.search(context_re, template.template)):
raise ValueError("`template` should have `query` and `context` keys")
self.template = template
if self.history is None:
template = DEFAULT_PROMPT_TEMPLATE
else:
template = DEFAULT_PROMPT_WITH_HISTORY_TEMPLATE
if self.validate_template(template):
self.template = template
else:
if self.history is None:
raise ValueError("`template` should have `query` and `context` keys")
else:
raise ValueError("`template` should have `query`, `context` and `history` keys")
if not isinstance(stream, bool):
raise ValueError("`stream` should be bool")
self.stream = stream
def validate_template(self, template: Template):
"""
validate the template
:param template: the template to validate
:return: Boolean, valid (true) or invalid (false)
"""
if self.history is None:
return (re.search(query_re, template.template) \
and re.search(context_re, template.template))
else:
return (re.search(query_re, template.template) \
and re.search(context_re, template.template)
and re.search(history_re, template.template))