feat: user-supplied API keys, model selector, and Anthropic support
Browse files- Replace hardwired OpenAI key with a per-session API key form at the top
of the UI; key is stored in memory only and cleared on page unload
- Add model dropdown that dynamically switches between OpenAI and Anthropic
model lists based on detected key prefix (sk-ant- vs sk-)
- Add anthropic-haystack dependency for AnthropicChatGenerator support
- Refactor tools/chart_tools.py, tools/stats_tools.py, and tools/tools.py
to use Haystack's provider-agnostic Tool class instead of raw OpenAI-format
dicts, enabling tool calling to work with both OpenAI and Anthropic models
- Fix invalid JSON Schema (items field on non-array properties) in tool
parameter definitions for stricter Anthropic compatibility
- Pass tools via tools= parameter to chat_generator.run() rather than
generation_kwargs so both generators handle format conversion natively
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
- app.py +59 -4
- assets/styles.css +11 -1
- functions/chat_functions.py +34 -11
- requirements.txt +1 -0
- templates/data_file.py +25 -1
- tools/chart_tools.py +276 -371
- tools/stats_tools.py +38 -44
- tools/tools.py +127 -143
- utils.py +3 -1
|
@@ -1,9 +1,8 @@
|
|
| 1 |
-
from utils import TEMP_DIR, message_dict
|
| 2 |
import gradio as gr
|
| 3 |
import templates.data_file as data_file, templates.sql_db as sql_db, templates.doc_db as doc_db, templates.graphql as graphql
|
| 4 |
|
| 5 |
import os
|
| 6 |
-
from getpass import getpass
|
| 7 |
from dotenv import load_dotenv
|
| 8 |
|
| 9 |
load_dotenv()
|
|
@@ -14,9 +13,16 @@ def delete_db(req: gr.Request):
|
|
| 14 |
if os.path.exists(dir_path):
|
| 15 |
shutil.rmtree(dir_path)
|
| 16 |
message_dict[req.session_hash] = {}
|
|
|
|
|
|
|
| 17 |
|
| 18 |
-
|
| 19 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 20 |
|
| 21 |
css= ".file_marker .large{min-height:50px !important;} .padding{padding:0;} .description_component{overflow:visible !important;}"
|
| 22 |
head = """<meta charset="UTF-8">
|
|
@@ -40,7 +46,56 @@ theme = gr.themes.Base(primary_hue="sky", secondary_hue="slate",font=[gr.themes.
|
|
| 40 |
from pathlib import Path
|
| 41 |
gr.set_static_paths(paths=[Path.cwd().absolute()/"assets"])
|
| 42 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 43 |
with gr.Blocks(theme=theme, css=css, head=head, delete_cache=(3600,3600)) as demo:
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 44 |
header = gr.HTML("""
|
| 45 |
<!-- Header -->
|
| 46 |
<header class="max-w-4xl mx-auto mb-12 text-center">
|
|
|
|
| 1 |
+
from utils import TEMP_DIR, message_dict, api_key_store, model_store
|
| 2 |
import gradio as gr
|
| 3 |
import templates.data_file as data_file, templates.sql_db as sql_db, templates.doc_db as doc_db, templates.graphql as graphql
|
| 4 |
|
| 5 |
import os
|
|
|
|
| 6 |
from dotenv import load_dotenv
|
| 7 |
|
| 8 |
load_dotenv()
|
|
|
|
| 13 |
if os.path.exists(dir_path):
|
| 14 |
shutil.rmtree(dir_path)
|
| 15 |
message_dict[req.session_hash] = {}
|
| 16 |
+
api_key_store.pop(req.session_hash, None)
|
| 17 |
+
model_store.pop(req.session_hash, None)
|
| 18 |
|
| 19 |
+
def set_api_key(api_key, model, request: gr.Request):
|
| 20 |
+
api_key = api_key.strip()
|
| 21 |
+
if not api_key:
|
| 22 |
+
return gr.update(visible=True), "<p style='color:#b91c1c;text-align:center;'>Please enter your OpenAI API key.</p>"
|
| 23 |
+
api_key_store[request.session_hash] = api_key
|
| 24 |
+
model_store[request.session_hash] = model
|
| 25 |
+
return gr.update(visible=False), f"<p style='color:#15803d;text-align:center;font-weight:500;'>✓ API key saved — using <strong>{model}</strong>. You can now use all features below.</p>"
|
| 26 |
|
| 27 |
css= ".file_marker .large{min-height:50px !important;} .padding{padding:0;} .description_component{overflow:visible !important;}"
|
| 28 |
head = """<meta charset="UTF-8">
|
|
|
|
| 46 |
from pathlib import Path
|
| 47 |
gr.set_static_paths(paths=[Path.cwd().absolute()/"assets"])
|
| 48 |
|
| 49 |
+
_env_api_key = os.getenv("OPENAI_API_KEY", "")
|
| 50 |
+
|
| 51 |
+
OPENAI_MODELS = [
|
| 52 |
+
"gpt-4o", "gpt-4o-mini",
|
| 53 |
+
"gpt-4.1", "gpt-4.1-mini", "gpt-4.1-nano",
|
| 54 |
+
"o3-mini", "o4-mini",
|
| 55 |
+
"gpt-5.4-mini", "gpt-5.4", "gpt-5.5",
|
| 56 |
+
]
|
| 57 |
+
ANTHROPIC_MODELS = [
|
| 58 |
+
"claude-sonnet-4-6",
|
| 59 |
+
"claude-opus-4-8",
|
| 60 |
+
"claude-haiku-4-5-20251001",
|
| 61 |
+
]
|
| 62 |
+
|
| 63 |
+
def update_models(api_key):
|
| 64 |
+
if api_key.strip().startswith("sk-ant-"):
|
| 65 |
+
return gr.update(choices=ANTHROPIC_MODELS, value=ANTHROPIC_MODELS[0])
|
| 66 |
+
return gr.update(choices=OPENAI_MODELS, value=OPENAI_MODELS[0])
|
| 67 |
+
|
| 68 |
with gr.Blocks(theme=theme, css=css, head=head, delete_cache=(3600,3600)) as demo:
|
| 69 |
+
with gr.Column(visible=True) as api_key_section:
|
| 70 |
+
gr.HTML("""
|
| 71 |
+
<div style="max-width:600px;margin:24px auto 8px;padding:16px 20px;background:#fffbeb;border:1px solid #f59e0b;border-radius:8px;">
|
| 72 |
+
<h3 style="color:#92400e;margin:0 0 6px;font-size:16px;font-weight:600;">
|
| 73 |
+
<i class="fas fa-key"></i> OpenAI API Key Required
|
| 74 |
+
</h3>
|
| 75 |
+
<p style="color:#78350f;font-size:14px;margin:0;">
|
| 76 |
+
Enter your OpenAI (<code>sk-...</code>) or Anthropic (<code>sk-ant-...</code>) API key. The model list updates automatically based on your key. Your key is held only in memory for your current session and is never saved to disk or shared.
|
| 77 |
+
</p>
|
| 78 |
+
</div>
|
| 79 |
+
""")
|
| 80 |
+
with gr.Row(equal_height=True):
|
| 81 |
+
api_key_input = gr.Textbox(
|
| 82 |
+
label="OpenAI API Key",
|
| 83 |
+
placeholder="sk-proj-...",
|
| 84 |
+
type="password",
|
| 85 |
+
value=_env_api_key,
|
| 86 |
+
scale=4
|
| 87 |
+
)
|
| 88 |
+
model_dropdown = gr.Dropdown(
|
| 89 |
+
label="Model",
|
| 90 |
+
choices=OPENAI_MODELS,
|
| 91 |
+
value=OPENAI_MODELS[0],
|
| 92 |
+
scale=2
|
| 93 |
+
)
|
| 94 |
+
api_key_btn = gr.Button("Set API Key", variant="primary", scale=1, min_width=120)
|
| 95 |
+
api_key_msg = gr.HTML("")
|
| 96 |
+
api_key_input.change(fn=update_models, inputs=api_key_input, outputs=model_dropdown)
|
| 97 |
+
api_key_btn.click(fn=set_api_key, inputs=[api_key_input, model_dropdown], outputs=[api_key_section, api_key_msg])
|
| 98 |
+
|
| 99 |
header = gr.HTML("""
|
| 100 |
<!-- Header -->
|
| 101 |
<header class="max-w-4xl mx-auto mb-12 text-center">
|
|
@@ -174,4 +174,14 @@
|
|
| 174 |
grid-template-columns: 1fr 2fr;
|
| 175 |
align-items: baseline;
|
| 176 |
}
|
| 177 |
-
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 174 |
grid-template-columns: 1fr 2fr;
|
| 175 |
align-items: baseline;
|
| 176 |
}
|
| 177 |
+
}
|
| 178 |
+
|
| 179 |
+
dialog {
|
| 180 |
+
margin: 10% auto;
|
| 181 |
+
width: 80%;
|
| 182 |
+
max-width: 350px;
|
| 183 |
+
background-color: #fff;
|
| 184 |
+
padding: 34px;
|
| 185 |
+
border: 0;
|
| 186 |
+
border-radius: 5px;
|
| 187 |
+
}
|
|
@@ -1,9 +1,19 @@
|
|
| 1 |
-
from utils import message_dict
|
| 2 |
|
| 3 |
from haystack.dataclasses import ChatMessage
|
| 4 |
from haystack.components.generators.chat import OpenAIChatGenerator
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 5 |
|
| 6 |
-
chat_generator = OpenAIChatGenerator(model="gpt-4o")
|
| 7 |
response = None
|
| 8 |
|
| 9 |
def example_question_message(data_source, name, titles, schema):
|
|
@@ -13,7 +23,7 @@ def example_question_message(data_source, name, titles, schema):
|
|
| 13 |
f"""We have a SQLite database with the following {titles}.
|
| 14 |
We also have an AI agent with access to the same database that will be performing data analysis.
|
| 15 |
Please return an array of seven strings, each one being a question for our data analysis agent
|
| 16 |
-
that we can suggest that you believe will be insightful or helpful to a data
|
| 17 |
data insights. Return nothing more than the array of questions because I need that specific data structure
|
| 18 |
to process your response. No other response type or data structure will work."""],
|
| 19 |
|
|
@@ -21,7 +31,7 @@ def example_question_message(data_source, name, titles, schema):
|
|
| 21 |
f"""We have a PostgreSQL database with the following tables: {titles}.
|
| 22 |
We also have an AI agent with access to the same database that will be performing data analysis.
|
| 23 |
Please return an array of seven strings, each one being a question for our data analysis agent
|
| 24 |
-
that we can suggest that you believe will be insightful or helpful to a data
|
| 25 |
data insights. Return nothing more than the array of questions because I need that specific data structure
|
| 26 |
to process your response. No other response type or data structure will work."""],
|
| 27 |
|
|
@@ -30,7 +40,7 @@ def example_question_message(data_source, name, titles, schema):
|
|
| 30 |
The schema of these collections is: {schema}.
|
| 31 |
We also have an AI agent with access to the same database that will be performing data analysis.
|
| 32 |
Please return an array of seven strings, each one being a question for our data analysis agent
|
| 33 |
-
that we can suggest that you believe will be insightful or helpful to a data
|
| 34 |
data insights. Return nothing more than the array of questions because I need that specific data structure
|
| 35 |
to process your response. No other response type or data structure will work."""],
|
| 36 |
|
|
@@ -38,7 +48,7 @@ def example_question_message(data_source, name, titles, schema):
|
|
| 38 |
f"""We have a GraphQL API endpoint with the following types: {titles}.
|
| 39 |
We also have an AI agent with access to the same GraphQL API endpoint that will be performing data analysis.
|
| 40 |
Please return an array of seven strings, each one being a question for our data analysis agent
|
| 41 |
-
that we can suggest that you believe will be insightful or helpful to a data
|
| 42 |
data insights. Return nothing more than the array of questions because I need that specific data structure
|
| 43 |
to process your response. No other response type or data structure will work."""]
|
| 44 |
|
|
@@ -57,9 +67,16 @@ def example_question_generator(session_hash, data_source, name, titles, schema):
|
|
| 57 |
|
| 58 |
example_messages.append(ChatMessage.from_user(text=example_message_list[1]))
|
| 59 |
|
| 60 |
-
example_response =
|
| 61 |
|
| 62 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 63 |
|
| 64 |
def system_message(data_source, titles, schema=""):
|
| 65 |
print("TITLES")
|
|
@@ -112,6 +129,11 @@ def system_message(data_source, titles, schema=""):
|
|
| 112 |
return system_message_dict[data_source]
|
| 113 |
|
| 114 |
def chatbot_func(message, history, session_hash, data_source, titles, schema, *args):
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 115 |
from functions import table_generation_func, regression_func, scatter_chart_generation_func, \
|
| 116 |
query_func, graphql_schema_query, graphql_csv_query, \
|
| 117 |
line_chart_generation_func,bar_chart_generation_func,pie_chart_generation_func,histogram_generation_func
|
|
@@ -133,10 +155,11 @@ def chatbot_func(message, history, session_hash, data_source, titles, schema, *a
|
|
| 133 |
messages.append(ChatMessage.from_user(message))
|
| 134 |
message_dict[session_hash][data_source] = messages
|
| 135 |
|
| 136 |
-
|
|
|
|
| 137 |
|
| 138 |
while True:
|
| 139 |
-
# if
|
| 140 |
if response and response["replies"][0].meta["finish_reason"] == "tool_calls" or response["replies"][0].tool_calls:
|
| 141 |
function_calls = response["replies"][0].tool_calls
|
| 142 |
for function_call in function_calls:
|
|
@@ -151,7 +174,7 @@ def chatbot_func(message, history, session_hash, data_source, titles, schema, *a
|
|
| 151 |
print(function_name)
|
| 152 |
## Append function response to the messages list using `ChatMessage.from_tool`
|
| 153 |
message_dict[session_hash][data_source].append(ChatMessage.from_tool(tool_result=function_response['reply'], origin=function_call))
|
| 154 |
-
response = chat_generator.run(messages=message_dict[session_hash][data_source],
|
| 155 |
|
| 156 |
# Regular Conversation
|
| 157 |
else:
|
|
|
|
| 1 |
+
from utils import message_dict, api_key_store, model_store
|
| 2 |
|
| 3 |
from haystack.dataclasses import ChatMessage
|
| 4 |
from haystack.components.generators.chat import OpenAIChatGenerator
|
| 5 |
+
from haystack.utils import Secret
|
| 6 |
+
|
| 7 |
+
def _get_generator(session_hash):
|
| 8 |
+
api_key = api_key_store.get(session_hash)
|
| 9 |
+
if not api_key:
|
| 10 |
+
raise ValueError("No API key found for this session. Please enter your API key at the top of the page.")
|
| 11 |
+
model = model_store.get(session_hash, "gpt-4o")
|
| 12 |
+
if api_key.startswith("sk-ant-"):
|
| 13 |
+
from haystack_integrations.components.generators.chat import AnthropicChatGenerator
|
| 14 |
+
return AnthropicChatGenerator(model=model, api_key=Secret.from_token(api_key))
|
| 15 |
+
return OpenAIChatGenerator(model=model, api_key=Secret.from_token(api_key))
|
| 16 |
|
|
|
|
| 17 |
response = None
|
| 18 |
|
| 19 |
def example_question_message(data_source, name, titles, schema):
|
|
|
|
| 23 |
f"""We have a SQLite database with the following {titles}.
|
| 24 |
We also have an AI agent with access to the same database that will be performing data analysis.
|
| 25 |
Please return an array of seven strings, each one being a question for our data analysis agent
|
| 26 |
+
that we can suggest that you believe will be insightful or helpful to a data analyst looking for
|
| 27 |
data insights. Return nothing more than the array of questions because I need that specific data structure
|
| 28 |
to process your response. No other response type or data structure will work."""],
|
| 29 |
|
|
|
|
| 31 |
f"""We have a PostgreSQL database with the following tables: {titles}.
|
| 32 |
We also have an AI agent with access to the same database that will be performing data analysis.
|
| 33 |
Please return an array of seven strings, each one being a question for our data analysis agent
|
| 34 |
+
that we can suggest that you believe will be insightful or helpful to a data analyst looking for
|
| 35 |
data insights. Return nothing more than the array of questions because I need that specific data structure
|
| 36 |
to process your response. No other response type or data structure will work."""],
|
| 37 |
|
|
|
|
| 40 |
The schema of these collections is: {schema}.
|
| 41 |
We also have an AI agent with access to the same database that will be performing data analysis.
|
| 42 |
Please return an array of seven strings, each one being a question for our data analysis agent
|
| 43 |
+
that we can suggest that you believe will be insightful or helpful to a data analyst looking for
|
| 44 |
data insights. Return nothing more than the array of questions because I need that specific data structure
|
| 45 |
to process your response. No other response type or data structure will work."""],
|
| 46 |
|
|
|
|
| 48 |
f"""We have a GraphQL API endpoint with the following types: {titles}.
|
| 49 |
We also have an AI agent with access to the same GraphQL API endpoint that will be performing data analysis.
|
| 50 |
Please return an array of seven strings, each one being a question for our data analysis agent
|
| 51 |
+
that we can suggest that you believe will be insightful or helpful to a data analyst looking for
|
| 52 |
data insights. Return nothing more than the array of questions because I need that specific data structure
|
| 53 |
to process your response. No other response type or data structure will work."""]
|
| 54 |
|
|
|
|
| 67 |
|
| 68 |
example_messages.append(ChatMessage.from_user(text=example_message_list[1]))
|
| 69 |
|
| 70 |
+
example_response = _get_generator(session_hash).run(messages=example_messages)
|
| 71 |
|
| 72 |
+
response_text = example_response["replies"][0].text
|
| 73 |
+
start = response_text.index("[") + 1
|
| 74 |
+
end = response_text.index("]")
|
| 75 |
+
response_content = response_text[start:end]
|
| 76 |
+
response_list = '[' + response_content + ']'
|
| 77 |
+
print(response_list)
|
| 78 |
+
|
| 79 |
+
return response_list
|
| 80 |
|
| 81 |
def system_message(data_source, titles, schema=""):
|
| 82 |
print("TITLES")
|
|
|
|
| 129 |
return system_message_dict[data_source]
|
| 130 |
|
| 131 |
def chatbot_func(message, history, session_hash, data_source, titles, schema, *args):
|
| 132 |
+
try:
|
| 133 |
+
chat_generator = _get_generator(session_hash)
|
| 134 |
+
except ValueError as e:
|
| 135 |
+
return str(e)
|
| 136 |
+
|
| 137 |
from functions import table_generation_func, regression_func, scatter_chart_generation_func, \
|
| 138 |
query_func, graphql_schema_query, graphql_csv_query, \
|
| 139 |
line_chart_generation_func,bar_chart_generation_func,pie_chart_generation_func,histogram_generation_func
|
|
|
|
| 155 |
messages.append(ChatMessage.from_user(message))
|
| 156 |
message_dict[session_hash][data_source] = messages
|
| 157 |
|
| 158 |
+
active_tools = tools.tools_call(session_hash, data_source, titles)
|
| 159 |
+
response = chat_generator.run(messages=message_dict[session_hash][data_source], tools=active_tools)
|
| 160 |
|
| 161 |
while True:
|
| 162 |
+
# if the response is a tool call
|
| 163 |
if response and response["replies"][0].meta["finish_reason"] == "tool_calls" or response["replies"][0].tool_calls:
|
| 164 |
function_calls = response["replies"][0].tool_calls
|
| 165 |
for function_call in function_calls:
|
|
|
|
| 174 |
print(function_name)
|
| 175 |
## Append function response to the messages list using `ChatMessage.from_tool`
|
| 176 |
message_dict[session_hash][data_source].append(ChatMessage.from_tool(tool_result=function_response['reply'], origin=function_call))
|
| 177 |
+
response = chat_generator.run(messages=message_dict[session_hash][data_source], tools=active_tools)
|
| 178 |
|
| 179 |
# Regular Conversation
|
| 180 |
else:
|
|
@@ -1,4 +1,5 @@
|
|
| 1 |
haystack-ai
|
|
|
|
| 2 |
python-dotenv
|
| 3 |
gradio
|
| 4 |
pandas
|
|
|
|
| 1 |
haystack-ai
|
| 2 |
+
anthropic-haystack
|
| 3 |
python-dotenv
|
| 4 |
gradio
|
| 5 |
pandas
|
|
@@ -97,7 +97,7 @@ with gr.Blocks() as demo:
|
|
| 97 |
]
|
| 98 |
else:
|
| 99 |
try:
|
| 100 |
-
generated_examples = ast.literal_eval(example_question_generator(request.session_hash, 'file_upload', '', process_message[
|
| 101 |
example_questions = [
|
| 102 |
["Describe the dataset"]
|
| 103 |
]
|
|
@@ -111,6 +111,30 @@ with gr.Blocks() as demo:
|
|
| 111 |
["List the columns in the dataset"],
|
| 112 |
["What could this data be used for?"],
|
| 113 |
]
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 114 |
session_hash = gr.Textbox(visible=False, value=request.session_hash)
|
| 115 |
data_source = gr.Textbox(visible=False, value='file_upload')
|
| 116 |
schema = gr.Textbox(visible=False, value='')
|
|
|
|
| 97 |
]
|
| 98 |
else:
|
| 99 |
try:
|
| 100 |
+
generated_examples = ast.literal_eval(example_question_generator(request.session_hash, 'file_upload', '', process_message[2], ''))
|
| 101 |
example_questions = [
|
| 102 |
["Describe the dataset"]
|
| 103 |
]
|
|
|
|
| 111 |
["List the columns in the dataset"],
|
| 112 |
["What could this data be used for?"],
|
| 113 |
]
|
| 114 |
+
data_summary = gr.HTML("""
|
| 115 |
+
<script>
|
| 116 |
+
const modal = document.querySelector('.modal');
|
| 117 |
+
const openButton = document.querySelector('.open-button');
|
| 118 |
+
const closeButton = document.querySelector('.close-button');
|
| 119 |
+
console.log("JS DETECTED")
|
| 120 |
+
openButton.addEventListener('click', () => {
|
| 121 |
+
modal.showModal();
|
| 122 |
+
});
|
| 123 |
+
|
| 124 |
+
closeButton.addEventListener('click', () => {
|
| 125 |
+
modal.close();
|
| 126 |
+
});
|
| 127 |
+
</script>
|
| 128 |
+
<button class="open-button">
|
| 129 |
+
Open modal 🙈
|
| 130 |
+
</button>
|
| 131 |
+
<dialog class="modal">
|
| 132 |
+
<p>Udohgram</p>
|
| 133 |
+
<p>Insert pretty picture</p>
|
| 134 |
+
<button class="close-button">Close modal</button>
|
| 135 |
+
<p>Sorry, you can't login. You can't contact support either.</p>
|
| 136 |
+
</dialog>
|
| 137 |
+
""")
|
| 138 |
session_hash = gr.Textbox(visible=False, value=request.session_hash)
|
| 139 |
data_source = gr.Textbox(visible=False, value='file_upload')
|
| 140 |
schema = gr.Textbox(visible=False, value='')
|
|
@@ -1,371 +1,276 @@
|
|
| 1 |
-
|
| 2 |
-
|
| 3 |
-
|
| 4 |
-
|
| 5 |
-
|
| 6 |
-
|
| 7 |
-
|
| 8 |
-
|
| 9 |
-
|
| 10 |
-
|
| 11 |
-
|
| 12 |
-
|
| 13 |
-
|
| 14 |
-
|
| 15 |
-
|
| 16 |
-
|
| 17 |
-
|
| 18 |
-
|
| 19 |
-
|
| 20 |
-
|
| 21 |
-
|
| 22 |
-
|
| 23 |
-
|
| 24 |
-
|
| 25 |
-
|
| 26 |
-
|
| 27 |
-
|
| 28 |
-
|
| 29 |
-
|
| 30 |
-
|
| 31 |
-
|
| 32 |
-
|
| 33 |
-
|
| 34 |
-
|
| 35 |
-
|
| 36 |
-
|
| 37 |
-
|
| 38 |
-
|
| 39 |
-
|
| 40 |
-
|
| 41 |
-
|
| 42 |
-
|
| 43 |
-
|
| 44 |
-
|
| 45 |
-
|
| 46 |
-
|
| 47 |
-
|
| 48 |
-
|
| 49 |
-
|
| 50 |
-
|
| 51 |
-
|
| 52 |
-
|
| 53 |
-
|
| 54 |
-
|
| 55 |
-
|
| 56 |
-
|
| 57 |
-
|
| 58 |
-
|
| 59 |
-
|
| 60 |
-
|
| 61 |
-
|
| 62 |
-
|
| 63 |
-
|
| 64 |
-
|
| 65 |
-
|
| 66 |
-
|
| 67 |
-
|
| 68 |
-
|
| 69 |
-
|
| 70 |
-
|
| 71 |
-
|
| 72 |
-
|
| 73 |
-
|
| 74 |
-
|
| 75 |
-
|
| 76 |
-
|
| 77 |
-
|
| 78 |
-
|
| 79 |
-
|
| 80 |
-
|
| 81 |
-
|
| 82 |
-
|
| 83 |
-
|
| 84 |
-
|
| 85 |
-
|
| 86 |
-
|
| 87 |
-
|
| 88 |
-
|
| 89 |
-
|
| 90 |
-
|
| 91 |
-
|
| 92 |
-
|
| 93 |
-
|
| 94 |
-
|
| 95 |
-
|
| 96 |
-
|
| 97 |
-
|
| 98 |
-
|
| 99 |
-
|
| 100 |
-
|
| 101 |
-
|
| 102 |
-
|
| 103 |
-
"
|
| 104 |
-
},
|
| 105 |
-
|
| 106 |
-
|
| 107 |
-
|
| 108 |
-
|
| 109 |
-
|
| 110 |
-
|
| 111 |
-
|
| 112 |
-
|
| 113 |
-
|
| 114 |
-
|
| 115 |
-
|
| 116 |
-
|
| 117 |
-
"type": "
|
| 118 |
-
|
| 119 |
-
|
| 120 |
-
|
| 121 |
-
|
| 122 |
-
|
| 123 |
-
|
| 124 |
-
|
| 125 |
-
|
| 126 |
-
|
| 127 |
-
|
| 128 |
-
|
| 129 |
-
|
| 130 |
-
|
| 131 |
-
|
| 132 |
-
|
| 133 |
-
|
| 134 |
-
|
| 135 |
-
|
| 136 |
-
|
| 137 |
-
|
| 138 |
-
|
| 139 |
-
|
| 140 |
-
|
| 141 |
-
|
| 142 |
-
|
| 143 |
-
|
| 144 |
-
|
| 145 |
-
|
| 146 |
-
|
| 147 |
-
|
| 148 |
-
|
| 149 |
-
|
| 150 |
-
|
| 151 |
-
|
| 152 |
-
|
| 153 |
-
|
| 154 |
-
|
| 155 |
-
|
| 156 |
-
|
| 157 |
-
|
| 158 |
-
|
| 159 |
-
|
| 160 |
-
|
| 161 |
-
|
| 162 |
-
|
| 163 |
-
|
| 164 |
-
|
| 165 |
-
|
| 166 |
-
|
| 167 |
-
|
| 168 |
-
|
| 169 |
-
|
| 170 |
-
|
| 171 |
-
|
| 172 |
-
|
| 173 |
-
|
| 174 |
-
|
| 175 |
-
|
| 176 |
-
|
| 177 |
-
|
| 178 |
-
|
| 179 |
-
|
| 180 |
-
|
| 181 |
-
|
| 182 |
-
|
| 183 |
-
|
| 184 |
-
|
| 185 |
-
|
| 186 |
-
|
| 187 |
-
|
| 188 |
-
|
| 189 |
-
|
| 190 |
-
|
| 191 |
-
|
| 192 |
-
|
| 193 |
-
|
| 194 |
-
|
| 195 |
-
|
| 196 |
-
|
| 197 |
-
|
| 198 |
-
|
| 199 |
-
|
| 200 |
-
|
| 201 |
-
|
| 202 |
-
|
| 203 |
-
|
| 204 |
-
|
| 205 |
-
|
| 206 |
-
|
| 207 |
-
|
| 208 |
-
|
| 209 |
-
|
| 210 |
-
|
| 211 |
-
|
| 212 |
-
|
| 213 |
-
|
| 214 |
-
|
| 215 |
-
|
| 216 |
-
|
| 217 |
-
|
| 218 |
-
|
| 219 |
-
|
| 220 |
-
|
| 221 |
-
|
| 222 |
-
|
| 223 |
-
|
| 224 |
-
|
| 225 |
-
|
| 226 |
-
|
| 227 |
-
|
| 228 |
-
|
| 229 |
-
|
| 230 |
-
|
| 231 |
-
"
|
| 232 |
-
|
| 233 |
-
|
| 234 |
-
|
| 235 |
-
|
| 236 |
-
|
| 237 |
-
|
| 238 |
-
|
| 239 |
-
"
|
| 240 |
-
|
| 241 |
-
|
| 242 |
-
|
| 243 |
-
|
| 244 |
-
|
| 245 |
-
|
| 246 |
-
"
|
| 247 |
-
|
| 248 |
-
|
| 249 |
-
|
| 250 |
-
|
| 251 |
-
|
| 252 |
-
|
| 253 |
-
|
| 254 |
-
|
| 255 |
-
|
| 256 |
-
|
| 257 |
-
|
| 258 |
-
|
| 259 |
-
|
| 260 |
-
|
| 261 |
-
|
| 262 |
-
|
| 263 |
-
|
| 264 |
-
|
| 265 |
-
|
| 266 |
-
|
| 267 |
-
|
| 268 |
-
|
| 269 |
-
|
| 270 |
-
|
| 271 |
-
|
| 272 |
-
|
| 273 |
-
|
| 274 |
-
|
| 275 |
-
|
| 276 |
-
|
| 277 |
-
}
|
| 278 |
-
}
|
| 279 |
-
},
|
| 280 |
-
"required": ["values","names","layout"],
|
| 281 |
-
},
|
| 282 |
-
},
|
| 283 |
-
},
|
| 284 |
-
{
|
| 285 |
-
"type": "function",
|
| 286 |
-
"function": {
|
| 287 |
-
"name": "histogram_generation_func",
|
| 288 |
-
"description": f"""This is a histogram generation tool useful to generate histograms from queried data from our data source that we are querying.
|
| 289 |
-
The data values will come from the columns of our query.csv (the 'values' and 'names' values of each graph) file but the layout section of the plotly dictionary objects will be generated by you.
|
| 290 |
-
Returns an iframe string which will be displayed inline in our chat window. Do not edit the iframe string returned
|
| 291 |
-
from the histogram_generation_func function in any way and always display the iframe fully to the user in the chat window. You can add your own text supplementary
|
| 292 |
-
to it for context if desired.""",
|
| 293 |
-
"parameters": {
|
| 294 |
-
"type": "object",
|
| 295 |
-
"properties": {
|
| 296 |
-
"data": {
|
| 297 |
-
"type": "array",
|
| 298 |
-
"description": """The array containing a dictionary that contains the 'data' portion of the plotly chart generation and will include the options requested by the user.
|
| 299 |
-
The array must contain a json formatted dictionary with outer brackets included, any other format will not work.
|
| 300 |
-
Do not include the 'x' or 'y' portions of the object as this will come from the query.csv file generated by our SQLite query.
|
| 301 |
-
Infer this from the user's message.""",
|
| 302 |
-
"items": {
|
| 303 |
-
"type": "string",
|
| 304 |
-
}
|
| 305 |
-
},
|
| 306 |
-
"x_column": {
|
| 307 |
-
"type": "string",
|
| 308 |
-
"description": f"""The column name in our query.csv file that contains the x values of the histogram.
|
| 309 |
-
This would correspond to the counts that would be distributed in the histogram.""",
|
| 310 |
-
"items": {
|
| 311 |
-
"type": "string",
|
| 312 |
-
}
|
| 313 |
-
},
|
| 314 |
-
"y_column": {
|
| 315 |
-
"type": "string",
|
| 316 |
-
"description": f"""An optional column name in our query.csv file that contains the y values of the histogram.""",
|
| 317 |
-
"items": {
|
| 318 |
-
"type": "string",
|
| 319 |
-
}
|
| 320 |
-
},
|
| 321 |
-
"histnorm": {
|
| 322 |
-
"type": "string",
|
| 323 |
-
"description": f"""An optional argument to specify the type of normalization if the default isn't used.
|
| 324 |
-
This histnorm value can be one of ['percent','probability','density','probability density'].
|
| 325 |
-
Do not send any values outside of this array as the function will fail.""",
|
| 326 |
-
"items": {
|
| 327 |
-
"type": "string",
|
| 328 |
-
}
|
| 329 |
-
},
|
| 330 |
-
"category": {
|
| 331 |
-
"type": "string",
|
| 332 |
-
"description": f"""An optional column name in our query.csv file that contains a parameter that will define the category for the data.""",
|
| 333 |
-
"items": {
|
| 334 |
-
"type": "string",
|
| 335 |
-
}
|
| 336 |
-
},
|
| 337 |
-
"histfunc": {
|
| 338 |
-
"type": "string",
|
| 339 |
-
"description": f"""An optional value that represents the function of data to compute the function which is used on the optional y column.
|
| 340 |
-
This histfunc value can be one of ['avg','sum','count'].
|
| 341 |
-
Do not send any values outside of this array as the function will fail.""",
|
| 342 |
-
"items": {
|
| 343 |
-
"type": "string",
|
| 344 |
-
}
|
| 345 |
-
},
|
| 346 |
-
"layout": {
|
| 347 |
-
"type": "array",
|
| 348 |
-
"description": """An array containing a dictionary that contains the 'layout' portion of the plotly chart generation.
|
| 349 |
-
The array must contain a json formatted dictionary with outer brackets included, any other format will not work.""",
|
| 350 |
-
"items": {
|
| 351 |
-
"type": "string",
|
| 352 |
-
}
|
| 353 |
-
}
|
| 354 |
-
},
|
| 355 |
-
"required": ["x_column"],
|
| 356 |
-
},
|
| 357 |
-
},
|
| 358 |
-
},
|
| 359 |
-
{
|
| 360 |
-
"type": "function",
|
| 361 |
-
"function": {
|
| 362 |
-
"name": "table_generation_func",
|
| 363 |
-
"description": f"""This an table generation tool useful to format data as a table from queried data from our data source that we are querying.
|
| 364 |
-
Takes no parameters as it uses data queried in our query.csv file to build the table.
|
| 365 |
-
Call this function after running our SQLite query and generating query.csv.
|
| 366 |
-
Returns an iframe string which will be displayed inline in our chat window. Do not edit the iframe string returned
|
| 367 |
-
from the table_generation_func function in any way and always display the iframe fully to the user in the chat window.""",
|
| 368 |
-
"parameters": {},
|
| 369 |
-
},
|
| 370 |
-
}
|
| 371 |
-
]
|
|
|
|
| 1 |
+
from haystack.tools import Tool
|
| 2 |
+
|
| 3 |
+
_noop = lambda **kwargs: None
|
| 4 |
+
|
| 5 |
+
chart_tools = [
|
| 6 |
+
Tool(
|
| 7 |
+
name="scatter_chart_generation_func",
|
| 8 |
+
description="""This is a scatter plot generation tool useful to generate scatter plots from queried data from our data source that we are querying.
|
| 9 |
+
The data values will come from the columns of our query.csv (the 'x' and 'y' values of each graph) file but the layout section of the plotly dictionary objects will be generated by you.
|
| 10 |
+
Returns an iframe string which will be displayed inline in our chat window. Do not edit the iframe string returned
|
| 11 |
+
from the scatter_chart_generation_func function in any way and always display the iframe fully to the user in the chat window. You can add your own text supplementary
|
| 12 |
+
to it for context if desired.""",
|
| 13 |
+
parameters={
|
| 14 |
+
"type": "object",
|
| 15 |
+
"properties": {
|
| 16 |
+
"data": {
|
| 17 |
+
"type": "array",
|
| 18 |
+
"description": """The array containing a dictionary that contains the 'data' portion of the plotly chart generation and will include the options requested by the user.
|
| 19 |
+
The array must contain a json formatted dictionary with outer brackets included, any other format will not work.
|
| 20 |
+
Do not include the 'x' or 'y' portions of the object as this will come from the query.csv file generated by our SQLite query.
|
| 21 |
+
Infer this from the user's message.""",
|
| 22 |
+
"items": {"type": "string"}
|
| 23 |
+
},
|
| 24 |
+
"x_column": {
|
| 25 |
+
"type": "array",
|
| 26 |
+
"description": """An array of strings that correspond to the column names in our query.csv file that contain the x values of the graph. There can be more than one column
|
| 27 |
+
that can each be plotted against the y_column, if needed.""",
|
| 28 |
+
"items": {"type": "string"}
|
| 29 |
+
},
|
| 30 |
+
"y_column": {
|
| 31 |
+
"type": "string",
|
| 32 |
+
"description": """The column name in our query.csv file that contain the y values of the graph."""
|
| 33 |
+
},
|
| 34 |
+
"category": {
|
| 35 |
+
"type": "string",
|
| 36 |
+
"description": """An optional column name in our query.csv file that contain a parameter that will define the category for the data."""
|
| 37 |
+
},
|
| 38 |
+
"trendline": {
|
| 39 |
+
"type": "string",
|
| 40 |
+
"description": """An optional field to specify the type of plotly trendline we wish to use in the scatter plot.
|
| 41 |
+
This trendline value can be one of ['ols','lowess','rolling','ewm','expanding'].
|
| 42 |
+
Do not send any values outside of this array as the function will fail.
|
| 43 |
+
Infer this from the user's message."""
|
| 44 |
+
},
|
| 45 |
+
"trendline_options": {
|
| 46 |
+
"type": "array",
|
| 47 |
+
"description": """An array containing a dictionary that contains the 'trendline_options' portion of the plotly chart generation.
|
| 48 |
+
The 'lowess', 'rolling', and 'ewm' options require trendline_options to be included.
|
| 49 |
+
The array must contain a json formatted dictionary with outer brackets included, any other format will not work.""",
|
| 50 |
+
"items": {"type": "string"}
|
| 51 |
+
},
|
| 52 |
+
"marginal_x": {
|
| 53 |
+
"type": "string",
|
| 54 |
+
"description": """The type of marginal distribution plot we'd like to specify for the plotly scatter plot for the x axis.
|
| 55 |
+
This marginal_x value can be one of ['histogram','rug','box','violin'].
|
| 56 |
+
Do not send any values outside of this array as the function will fail.
|
| 57 |
+
Infer this from the user's message."""
|
| 58 |
+
},
|
| 59 |
+
"marginal_y": {
|
| 60 |
+
"type": "string",
|
| 61 |
+
"description": """The type of marginal distribution plot we'd like to specify for the plotly scatter plot for the y axis.
|
| 62 |
+
This marginal_y value can be one of ['histogram','rug','box','violin'].
|
| 63 |
+
Do not send any values outside of this array as the function will fail.
|
| 64 |
+
Infer this from the user's message."""
|
| 65 |
+
},
|
| 66 |
+
"layout": {
|
| 67 |
+
"type": "array",
|
| 68 |
+
"description": """An array containing a dictionary that contains the 'layout' portion of the plotly chart generation.
|
| 69 |
+
The array must contain a json formatted dictionary with outer brackets included, any other format will not work.""",
|
| 70 |
+
"items": {"type": "string"}
|
| 71 |
+
},
|
| 72 |
+
"size": {
|
| 73 |
+
"type": "string",
|
| 74 |
+
"description": """An optional column in our query.csv file that contain a parameter that will define the size of each plot point.
|
| 75 |
+
This is useful for a bubble chart where another value in our query can be represented by the size of the plotted point.
|
| 76 |
+
Values must be greater than or equal to 0 and so in our query, all values less than 0 should be set equal to zero."""
|
| 77 |
+
}
|
| 78 |
+
},
|
| 79 |
+
"required": ["x_column", "y_column"]
|
| 80 |
+
},
|
| 81 |
+
function=_noop
|
| 82 |
+
),
|
| 83 |
+
Tool(
|
| 84 |
+
name="line_chart_generation_func",
|
| 85 |
+
description="""This is a line chart generation tool useful to generate line charts from queried data from our data source that we are querying.
|
| 86 |
+
The data values will come from the columns of our query.csv (the 'x' and 'y' values of each graph) file but the layout section of the plotly dictionary objects will be generated by you.
|
| 87 |
+
Returns an iframe string which will be displayed inline in our chat window. Do not edit the iframe string returned
|
| 88 |
+
from the line_chart_generation_func function in any way and always display the iframe fully to the user in the chat window. You can add your own text supplementary
|
| 89 |
+
to it for context if desired.""",
|
| 90 |
+
parameters={
|
| 91 |
+
"type": "object",
|
| 92 |
+
"properties": {
|
| 93 |
+
"data": {
|
| 94 |
+
"type": "array",
|
| 95 |
+
"description": """The array containing a dictionary that contains the 'data' portion of the plotly chart generation and will include the options requested by the user.
|
| 96 |
+
The array must contain a json formatted dictionary with outer brackets included, any other format will not work.
|
| 97 |
+
Do not include the 'x' or 'y' portions of the object as this will come from the query.csv file generated by our SQLite query.
|
| 98 |
+
Infer this from the user's message.""",
|
| 99 |
+
"items": {"type": "string"}
|
| 100 |
+
},
|
| 101 |
+
"x_column": {
|
| 102 |
+
"type": "string",
|
| 103 |
+
"description": """The column name in our query.csv file that contain the x values of the graph."""
|
| 104 |
+
},
|
| 105 |
+
"y_column": {
|
| 106 |
+
"type": "string",
|
| 107 |
+
"description": """The column name in our query.csv file that contain the y values of the graph."""
|
| 108 |
+
},
|
| 109 |
+
"category": {
|
| 110 |
+
"type": "string",
|
| 111 |
+
"description": """An optional column name in our query.csv file that contain a parameter that will define the category for the data."""
|
| 112 |
+
},
|
| 113 |
+
"layout": {
|
| 114 |
+
"type": "array",
|
| 115 |
+
"description": """An array containing a dictionary that contains the 'layout' portion of the plotly chart generation.
|
| 116 |
+
The array must contain a json formatted dictionary with outer brackets included, any other format will not work.""",
|
| 117 |
+
"items": {"type": "string"}
|
| 118 |
+
}
|
| 119 |
+
},
|
| 120 |
+
"required": ["x_column", "y_column", "layout"]
|
| 121 |
+
},
|
| 122 |
+
function=_noop
|
| 123 |
+
),
|
| 124 |
+
Tool(
|
| 125 |
+
name="bar_chart_generation_func",
|
| 126 |
+
description="""This is a bar chart generation tool useful to generate bar charts from queried data from our data source that we are querying.
|
| 127 |
+
The data values will come from the columns of our query.csv (the 'x' and 'y' values of each graph) file but the layout section of the plotly dictionary objects will be generated by you.
|
| 128 |
+
Returns an iframe string which will be displayed inline in our chat window. Do not edit the iframe string returned
|
| 129 |
+
from the bar_chart_generation_func function in any way and always display the iframe fully to the user in the chat window. You can add your own text supplementary
|
| 130 |
+
to it for context if desired.""",
|
| 131 |
+
parameters={
|
| 132 |
+
"type": "object",
|
| 133 |
+
"properties": {
|
| 134 |
+
"data": {
|
| 135 |
+
"type": "array",
|
| 136 |
+
"description": """The array containing a dictionary that contains the 'data' portion of the plotly chart generation and will include the options requested by the user.
|
| 137 |
+
The array must contain a json formatted dictionary with outer brackets included, any other format will not work.
|
| 138 |
+
Do not include the 'x' or 'y' portions of the object as this will come from the query.csv file generated by our SQLite query.
|
| 139 |
+
Infer this from the user's message.""",
|
| 140 |
+
"items": {"type": "string"}
|
| 141 |
+
},
|
| 142 |
+
"x_column": {
|
| 143 |
+
"type": "string",
|
| 144 |
+
"description": """The column name in our query.csv file that contains the x values of the graph."""
|
| 145 |
+
},
|
| 146 |
+
"y_column": {
|
| 147 |
+
"type": "string",
|
| 148 |
+
"description": """The column name in our query.csv file that contains the y values of the graph."""
|
| 149 |
+
},
|
| 150 |
+
"category": {
|
| 151 |
+
"type": "string",
|
| 152 |
+
"description": """An optional column name in our query.csv file that contains a parameter that will define the category for the data."""
|
| 153 |
+
},
|
| 154 |
+
"facet_row": {
|
| 155 |
+
"type": "string",
|
| 156 |
+
"description": """An optional column name in our query.csv file that contains a parameter that will define a faceted subplot, where different rows
|
| 157 |
+
correspond to different values of the query specified in this parameter."""
|
| 158 |
+
},
|
| 159 |
+
"facet_col": {
|
| 160 |
+
"type": "string",
|
| 161 |
+
"description": """An optional column name in our query.csv file that contain a parameter that will define the faceted column, corresponding to
|
| 162 |
+
different values of our query specified in this parameter."""
|
| 163 |
+
},
|
| 164 |
+
"layout": {
|
| 165 |
+
"type": "array",
|
| 166 |
+
"description": """An array containing a dictionary that contains the 'layout' portion of the plotly chart generation.
|
| 167 |
+
The array must contain a json formatted dictionary with outer brackets included, any other format will not work.""",
|
| 168 |
+
"items": {"type": "string"}
|
| 169 |
+
}
|
| 170 |
+
},
|
| 171 |
+
"required": ["x_column", "y_column", "layout"]
|
| 172 |
+
},
|
| 173 |
+
function=_noop
|
| 174 |
+
),
|
| 175 |
+
Tool(
|
| 176 |
+
name="pie_chart_generation_func",
|
| 177 |
+
description="""This is a pie chart generation tool useful to generate pie charts from queried data from our data source that we are querying.
|
| 178 |
+
The data values will come from the columns of our query.csv (the 'values' and 'names' values of each graph) file but the layout section of the plotly dictionary objects will be generated by you.
|
| 179 |
+
Returns an iframe string which will be displayed inline in our chat window. Do not edit the iframe string returned
|
| 180 |
+
from the pie_chart_generation_func function in any way and always display the iframe fully to the user in the chat window. You can add your own text supplementary
|
| 181 |
+
to it for context if desired.""",
|
| 182 |
+
parameters={
|
| 183 |
+
"type": "object",
|
| 184 |
+
"properties": {
|
| 185 |
+
"data": {
|
| 186 |
+
"type": "array",
|
| 187 |
+
"description": """The array containing a dictionary that contains the 'data' portion of the plotly chart generation and will include the options requested by the user.
|
| 188 |
+
The array must contain a json formatted dictionary with outer brackets included, any other format will not work.
|
| 189 |
+
Do not include the 'x' or 'y' portions of the object as this will come from the query.csv file generated by our SQLite query.
|
| 190 |
+
Infer this from the user's message.""",
|
| 191 |
+
"items": {"type": "string"}
|
| 192 |
+
},
|
| 193 |
+
"values": {
|
| 194 |
+
"type": "string",
|
| 195 |
+
"description": """The column name in our query.csv file that contain the values of the pie chart."""
|
| 196 |
+
},
|
| 197 |
+
"names": {
|
| 198 |
+
"type": "string",
|
| 199 |
+
"description": """The column name in our query.csv file that contain the label or section of each piece of the pie graph and allow us to know what each piece of the pie chart represents."""
|
| 200 |
+
},
|
| 201 |
+
"layout": {
|
| 202 |
+
"type": "array",
|
| 203 |
+
"description": """An array containing a dictionary that contains the 'layout' portion of the plotly chart generation.
|
| 204 |
+
The array must contain a json formatted dictionary with outer brackets included, any other format will not work.""",
|
| 205 |
+
"items": {"type": "string"}
|
| 206 |
+
}
|
| 207 |
+
},
|
| 208 |
+
"required": ["values", "names", "layout"]
|
| 209 |
+
},
|
| 210 |
+
function=_noop
|
| 211 |
+
),
|
| 212 |
+
Tool(
|
| 213 |
+
name="histogram_generation_func",
|
| 214 |
+
description="""This is a histogram generation tool useful to generate histograms from queried data from our data source that we are querying.
|
| 215 |
+
The data values will come from the columns of our query.csv file but the layout section of the plotly dictionary objects will be generated by you.
|
| 216 |
+
Returns an iframe string which will be displayed inline in our chat window. Do not edit the iframe string returned
|
| 217 |
+
from the histogram_generation_func function in any way and always display the iframe fully to the user in the chat window. You can add your own text supplementary
|
| 218 |
+
to it for context if desired.""",
|
| 219 |
+
parameters={
|
| 220 |
+
"type": "object",
|
| 221 |
+
"properties": {
|
| 222 |
+
"data": {
|
| 223 |
+
"type": "array",
|
| 224 |
+
"description": """The array containing a dictionary that contains the 'data' portion of the plotly chart generation and will include the options requested by the user.
|
| 225 |
+
The array must contain a json formatted dictionary with outer brackets included, any other format will not work.
|
| 226 |
+
Do not include the 'x' or 'y' portions of the object as this will come from the query.csv file generated by our SQLite query.
|
| 227 |
+
Infer this from the user's message.""",
|
| 228 |
+
"items": {"type": "string"}
|
| 229 |
+
},
|
| 230 |
+
"x_column": {
|
| 231 |
+
"type": "string",
|
| 232 |
+
"description": """The column name in our query.csv file that contains the x values of the histogram.
|
| 233 |
+
This would correspond to the counts that would be distributed in the histogram."""
|
| 234 |
+
},
|
| 235 |
+
"y_column": {
|
| 236 |
+
"type": "string",
|
| 237 |
+
"description": """An optional column name in our query.csv file that contains the y values of the histogram."""
|
| 238 |
+
},
|
| 239 |
+
"histnorm": {
|
| 240 |
+
"type": "string",
|
| 241 |
+
"description": """An optional argument to specify the type of normalization if the default isn't used.
|
| 242 |
+
This histnorm value can be one of ['percent','probability','density','probability density'].
|
| 243 |
+
Do not send any values outside of this array as the function will fail."""
|
| 244 |
+
},
|
| 245 |
+
"category": {
|
| 246 |
+
"type": "string",
|
| 247 |
+
"description": """An optional column name in our query.csv file that contains a parameter that will define the category for the data."""
|
| 248 |
+
},
|
| 249 |
+
"histfunc": {
|
| 250 |
+
"type": "string",
|
| 251 |
+
"description": """An optional value that represents the function of data to compute the function which is used on the optional y column.
|
| 252 |
+
This histfunc value can be one of ['avg','sum','count'].
|
| 253 |
+
Do not send any values outside of this array as the function will fail."""
|
| 254 |
+
},
|
| 255 |
+
"layout": {
|
| 256 |
+
"type": "array",
|
| 257 |
+
"description": """An array containing a dictionary that contains the 'layout' portion of the plotly chart generation.
|
| 258 |
+
The array must contain a json formatted dictionary with outer brackets included, any other format will not work.""",
|
| 259 |
+
"items": {"type": "string"}
|
| 260 |
+
}
|
| 261 |
+
},
|
| 262 |
+
"required": ["x_column"]
|
| 263 |
+
},
|
| 264 |
+
function=_noop
|
| 265 |
+
),
|
| 266 |
+
Tool(
|
| 267 |
+
name="table_generation_func",
|
| 268 |
+
description="""This is a table generation tool useful to format data as a table from queried data from our data source that we are querying.
|
| 269 |
+
Takes no parameters as it uses data queried in our query.csv file to build the table.
|
| 270 |
+
Call this function after running our query and generating query.csv.
|
| 271 |
+
Returns an iframe string which will be displayed inline in our chat window. Do not edit the iframe string returned
|
| 272 |
+
from the table_generation_func function in any way and always display the iframe fully to the user in the chat window.""",
|
| 273 |
+
parameters={"type": "object", "properties": {}},
|
| 274 |
+
function=_noop
|
| 275 |
+
),
|
| 276 |
+
]
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
@@ -1,44 +1,38 @@
|
|
| 1 |
-
|
| 2 |
-
|
| 3 |
-
|
| 4 |
-
|
| 5 |
-
|
| 6 |
-
|
| 7 |
-
|
| 8 |
-
|
| 9 |
-
|
| 10 |
-
|
| 11 |
-
|
| 12 |
-
|
| 13 |
-
|
| 14 |
-
|
| 15 |
-
|
| 16 |
-
|
| 17 |
-
|
| 18 |
-
|
| 19 |
-
|
| 20 |
-
|
| 21 |
-
|
| 22 |
-
|
| 23 |
-
|
| 24 |
-
|
| 25 |
-
|
| 26 |
-
|
| 27 |
-
|
| 28 |
-
|
| 29 |
-
|
| 30 |
-
|
| 31 |
-
|
| 32 |
-
|
| 33 |
-
|
| 34 |
-
|
| 35 |
-
|
| 36 |
-
|
| 37 |
-
|
| 38 |
-
|
| 39 |
-
},
|
| 40 |
-
"required": ["independent_variables","dependent_variable"],
|
| 41 |
-
},
|
| 42 |
-
},
|
| 43 |
-
}
|
| 44 |
-
]
|
|
|
|
| 1 |
+
from haystack.tools import Tool
|
| 2 |
+
|
| 3 |
+
_noop = lambda **kwargs: None
|
| 4 |
+
|
| 5 |
+
stats_tools = [
|
| 6 |
+
Tool(
|
| 7 |
+
name="regression_func",
|
| 8 |
+
description="""This a tool to calculate regressions on our data source that we are querying.
|
| 9 |
+
We can run queries with our 'sql_query_func' function and they will be available to use in this function via the query.csv file that is generated.
|
| 10 |
+
Returns a dictionary of values that includes a regression_summary and a regression chart (which is an iframe displaying the
|
| 11 |
+
linear regression in chart form and should be shown to the user).""",
|
| 12 |
+
parameters={
|
| 13 |
+
"type": "object",
|
| 14 |
+
"properties": {
|
| 15 |
+
"independent_variables": {
|
| 16 |
+
"type": "array",
|
| 17 |
+
"description": """An array of strings that states the independent variables in our data set which should be column names in our query.csv file that is generated
|
| 18 |
+
in the 'sql_query_func' function. This will allow us to identify the data to use for our independent variables.
|
| 19 |
+
Infer this from the user's message.""",
|
| 20 |
+
"items": {"type": "string"}
|
| 21 |
+
},
|
| 22 |
+
"dependent_variable": {
|
| 23 |
+
"type": "string",
|
| 24 |
+
"description": """A string that states the dependent variable in our data set which should be a column name in our query.csv file that is generated
|
| 25 |
+
in the 'sql_query_func' function. This will allow us to identify the data to use for our dependent variable.
|
| 26 |
+
Infer this from the user's message."""
|
| 27 |
+
},
|
| 28 |
+
"category": {
|
| 29 |
+
"type": "string",
|
| 30 |
+
"description": """An optional column name in our query.csv file that contain a parameter that will define the category for the data.
|
| 31 |
+
Do not send value if no category is needed or specified. This category must be present in our query.csv file to be valid."""
|
| 32 |
+
}
|
| 33 |
+
},
|
| 34 |
+
"required": ["independent_variables", "dependent_variable"]
|
| 35 |
+
},
|
| 36 |
+
function=_noop
|
| 37 |
+
)
|
| 38 |
+
]
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
@@ -1,143 +1,127 @@
|
|
| 1 |
-
from .
|
| 2 |
-
from .
|
| 3 |
-
|
| 4 |
-
|
| 5 |
-
|
| 6 |
-
|
| 7 |
-
|
| 8 |
-
|
| 9 |
-
|
| 10 |
-
|
| 11 |
-
|
| 12 |
-
|
| 13 |
-
|
| 14 |
-
|
| 15 |
-
|
| 16 |
-
|
| 17 |
-
|
| 18 |
-
|
| 19 |
-
|
| 20 |
-
|
| 21 |
-
|
| 22 |
-
|
| 23 |
-
|
| 24 |
-
|
| 25 |
-
|
| 26 |
-
|
| 27 |
-
|
| 28 |
-
|
| 29 |
-
|
| 30 |
-
|
| 31 |
-
{
|
| 32 |
-
|
| 33 |
-
|
| 34 |
-
|
| 35 |
-
|
| 36 |
-
|
| 37 |
-
|
| 38 |
-
|
| 39 |
-
"
|
| 40 |
-
|
| 41 |
-
|
| 42 |
-
|
| 43 |
-
|
| 44 |
-
|
| 45 |
-
|
| 46 |
-
|
| 47 |
-
|
| 48 |
-
|
| 49 |
-
|
| 50 |
-
|
| 51 |
-
|
| 52 |
-
|
| 53 |
-
"
|
| 54 |
-
|
| 55 |
-
|
| 56 |
-
|
| 57 |
-
|
| 58 |
-
|
| 59 |
-
|
| 60 |
-
"
|
| 61 |
-
|
| 62 |
-
|
| 63 |
-
|
| 64 |
-
|
| 65 |
-
|
| 66 |
-
|
| 67 |
-
|
| 68 |
-
|
| 69 |
-
|
| 70 |
-
|
| 71 |
-
|
| 72 |
-
|
| 73 |
-
|
| 74 |
-
|
| 75 |
-
|
| 76 |
-
|
| 77 |
-
|
| 78 |
-
|
| 79 |
-
|
| 80 |
-
|
| 81 |
-
"
|
| 82 |
-
|
| 83 |
-
|
| 84 |
-
|
| 85 |
-
|
| 86 |
-
|
| 87 |
-
|
| 88 |
-
|
| 89 |
-
|
| 90 |
-
|
| 91 |
-
|
| 92 |
-
|
| 93 |
-
|
| 94 |
-
|
| 95 |
-
|
| 96 |
-
|
| 97 |
-
|
| 98 |
-
|
| 99 |
-
"
|
| 100 |
-
|
| 101 |
-
|
| 102 |
-
|
| 103 |
-
|
| 104 |
-
|
| 105 |
-
|
| 106 |
-
|
| 107 |
-
|
| 108 |
-
|
| 109 |
-
|
| 110 |
-
|
| 111 |
-
|
| 112 |
-
|
| 113 |
-
|
| 114 |
-
|
| 115 |
-
|
| 116 |
-
|
| 117 |
-
|
| 118 |
-
|
| 119 |
-
|
| 120 |
-
|
| 121 |
-
|
| 122 |
-
|
| 123 |
-
|
| 124 |
-
|
| 125 |
-
|
| 126 |
-
|
| 127 |
-
|
| 128 |
-
"description": "The pandas dataframe SQL query to use in the search. The table that we query is named 'query'. Infer this from the user's message. It should be a question or a statement"
|
| 129 |
-
}
|
| 130 |
-
},
|
| 131 |
-
"required": ["csv_query"],
|
| 132 |
-
},
|
| 133 |
-
},
|
| 134 |
-
},
|
| 135 |
-
]
|
| 136 |
-
}
|
| 137 |
-
|
| 138 |
-
tools = tools_calls[data_source]
|
| 139 |
-
|
| 140 |
-
tools.extend(chart_tools)
|
| 141 |
-
tools.extend(stats_tools)
|
| 142 |
-
|
| 143 |
-
return tools
|
|
|
|
| 1 |
+
from haystack.tools import Tool
|
| 2 |
+
from .stats_tools import stats_tools
|
| 3 |
+
from .chart_tools import chart_tools
|
| 4 |
+
|
| 5 |
+
_noop = lambda **kwargs: None
|
| 6 |
+
|
| 7 |
+
def tools_call(session_hash, data_source, titles):
|
| 8 |
+
|
| 9 |
+
titles_string = (titles[:625] + '..') if len(titles) > 625 else titles
|
| 10 |
+
|
| 11 |
+
query_tools = {
|
| 12 |
+
'file_upload': Tool(
|
| 13 |
+
name="query_func",
|
| 14 |
+
description=f"""This is a tool useful to query a SQLite table called 'data_source' with the following Columns: {titles_string}.
|
| 15 |
+
There may also be more columns in the table if the number of columns is too large to process.
|
| 16 |
+
This function also saves the results of the query to csv file called query.csv.""",
|
| 17 |
+
parameters={
|
| 18 |
+
"type": "object",
|
| 19 |
+
"properties": {
|
| 20 |
+
"queries": {
|
| 21 |
+
"type": "string",
|
| 22 |
+
"description": "The query to use in the search. Infer this from the user's message. It should be a question or a statement."
|
| 23 |
+
}
|
| 24 |
+
},
|
| 25 |
+
"required": ["queries"]
|
| 26 |
+
},
|
| 27 |
+
function=_noop
|
| 28 |
+
),
|
| 29 |
+
'sql': Tool(
|
| 30 |
+
name="query_func",
|
| 31 |
+
description=f"""This is a tool useful to query a PostgreSQL database with the following tables, {titles_string}.
|
| 32 |
+
There may also be more tables in the database if the number of tables is too large to process.
|
| 33 |
+
This function also saves the results of the query to csv file called query.csv.""",
|
| 34 |
+
parameters={
|
| 35 |
+
"type": "object",
|
| 36 |
+
"properties": {
|
| 37 |
+
"queries": {
|
| 38 |
+
"type": "string",
|
| 39 |
+
"description": "The PostgreSQL query to use in the search. Infer this from the user's message. It should be a question or a statement."
|
| 40 |
+
}
|
| 41 |
+
},
|
| 42 |
+
"required": ["queries"]
|
| 43 |
+
},
|
| 44 |
+
function=_noop
|
| 45 |
+
),
|
| 46 |
+
'doc_db': Tool(
|
| 47 |
+
name="query_func",
|
| 48 |
+
description=f"""This is a tool useful to build an aggregation pipeline to query a MongoDB NoSQL document database with the following collections, {titles_string}.
|
| 49 |
+
There may also be more collections in the database if the number of collections is too large to process.
|
| 50 |
+
This function also saves the results of the query to a csv file called query.csv.""",
|
| 51 |
+
parameters={
|
| 52 |
+
"type": "object",
|
| 53 |
+
"properties": {
|
| 54 |
+
"queries": {
|
| 55 |
+
"type": "string",
|
| 56 |
+
"description": "The MongoDB aggregation pipeline to use in the search. Infer this from the user's message. It should be a question or a statement."
|
| 57 |
+
},
|
| 58 |
+
"db_collection": {
|
| 59 |
+
"type": "string",
|
| 60 |
+
"description": "The MongoDB collection to use in the search. Infer this from the user's message. It should be a question or a statement."
|
| 61 |
+
}
|
| 62 |
+
},
|
| 63 |
+
"required": ["queries", "db_collection"]
|
| 64 |
+
},
|
| 65 |
+
function=_noop
|
| 66 |
+
),
|
| 67 |
+
'graphql': [
|
| 68 |
+
Tool(
|
| 69 |
+
name="query_func",
|
| 70 |
+
description=f"""This is a tool useful to build a GraphQL query for a GraphQL API endpoint with the following types, {titles_string}.
|
| 71 |
+
There may also be more types in the GraphQL endpoint if the number of types is too large to process.
|
| 72 |
+
This function also saves the results of the query to a csv file called query.csv.""",
|
| 73 |
+
parameters={
|
| 74 |
+
"type": "object",
|
| 75 |
+
"properties": {
|
| 76 |
+
"queries": {
|
| 77 |
+
"type": "string",
|
| 78 |
+
"description": "The GraphQL query to use in the search. Infer this from the user's message. It should be a question or a statement."
|
| 79 |
+
}
|
| 80 |
+
},
|
| 81 |
+
"required": ["queries"]
|
| 82 |
+
},
|
| 83 |
+
function=_noop
|
| 84 |
+
),
|
| 85 |
+
Tool(
|
| 86 |
+
name="graphql_schema_query",
|
| 87 |
+
description=f"""This is a tool useful to query a GraphQL type and receive back information about its schema. This is useful because
|
| 88 |
+
the GraphQL introspection query is too large to be ingested all at once and this allows us to query the schema one type at a time to
|
| 89 |
+
view it in manageable bites. You may realize after viewing the schema, that the type you selected was not appropriate for the question
|
| 90 |
+
you are attempting answer. You may then query additional types to find the appropriate types to use for your GraphQL API query.""",
|
| 91 |
+
parameters={
|
| 92 |
+
"type": "object",
|
| 93 |
+
"properties": {
|
| 94 |
+
"graphql_type": {
|
| 95 |
+
"type": "string",
|
| 96 |
+
"description": "The GraphQL type that we want to view the schema of in order to make the proper query with our graphql_query_func. Infer this from the user's message. It should be a question or a statement."
|
| 97 |
+
}
|
| 98 |
+
},
|
| 99 |
+
"required": ["graphql_type"]
|
| 100 |
+
},
|
| 101 |
+
function=_noop
|
| 102 |
+
),
|
| 103 |
+
Tool(
|
| 104 |
+
name="graphql_csv_query",
|
| 105 |
+
description=f"""This is a tool useful to SQL query our query.csv file that is generated from our GraphQL query. This is useful in a situation
|
| 106 |
+
where the results of the GraphQL query need additional querying to answer the user question. The query.csv file is converted to a Pandas dataframe
|
| 107 |
+
and we query that dataframe with SQL on a table called 'query' before converting it back to a csv file.""",
|
| 108 |
+
parameters={
|
| 109 |
+
"type": "object",
|
| 110 |
+
"properties": {
|
| 111 |
+
"csv_query": {
|
| 112 |
+
"type": "string",
|
| 113 |
+
"description": "The pandas dataframe SQL query to use in the search. The table that we query is named 'query'. Infer this from the user's message. It should be a question or a statement."
|
| 114 |
+
}
|
| 115 |
+
},
|
| 116 |
+
"required": ["csv_query"]
|
| 117 |
+
},
|
| 118 |
+
function=_noop
|
| 119 |
+
),
|
| 120 |
+
]
|
| 121 |
+
}
|
| 122 |
+
|
| 123 |
+
source_tools = query_tools[data_source]
|
| 124 |
+
tools = source_tools if isinstance(source_tools, list) else [source_tools]
|
| 125 |
+
tools = tools + chart_tools + stats_tools
|
| 126 |
+
|
| 127 |
+
return tools
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
@@ -4,4 +4,6 @@ current_dir = Path(__file__).parent
|
|
| 4 |
|
| 5 |
TEMP_DIR = current_dir / 'temp'
|
| 6 |
|
| 7 |
-
message_dict = {}
|
|
|
|
|
|
|
|
|
| 4 |
|
| 5 |
TEMP_DIR = current_dir / 'temp'
|
| 6 |
|
| 7 |
+
message_dict = {}
|
| 8 |
+
api_key_store = {}
|
| 9 |
+
model_store = {}
|