from dash import html, dcc, no_update, set_props
import dash_bootstrap_components as dbc
from dash.dependencies import Input, Output, State
import dataiku
from dataiku import SQLExecutor2
from duckduckgo_search import DDGS
import json
dbc_css = "https://cdn.jsdelivr.net/gh/AnnMarieW/dash-bootstrap-templates/dbc.min.css"
app.config.external_stylesheets = [dbc.themes.SUPERHERO, dbc_css]
# LLM setup
PROJECT = "" # DSS project key goes here
LLM_ID = "" # LLM ID for the LLM Mesh connection + model goes here
client = dataiku.api_client()
project = client.get_project(PROJECT)
llm = project.get_llm(LLM_ID)
def create_chat_session():
"""Create a new chat session with tools and prompt"""
chat = llm.new_completion()
# Import tools from JSON file
library = project.get_library()
tools_file = library.get_file("/python/tools.json")
tools_str = tools_file.read()
tools_dict = json.loads(tools_str)
chat.settings["tools"] = tools_dict["tools"]
SYSTEM_PROMPT = """You are a customer information assistant. You can:
1. Look up customer information in our database
2. Search for additional information about companies online
When looking up customer info, you will:
1. First get customer details
2. Then look up their company
3. Summarize in a single paragraph with details on both"""
chat.with_message(SYSTEM_PROMPT, role="system")
return chat
def get_customer_details(customer_id):
"""Get customer information from database"""
dataset = dataiku.Dataset("pro_customers_sql")
table_name = dataset.get_location_info().get('info', {}).get('table')
executor = SQLExecutor2(dataset=dataset)
customer_id = customer_id.replace("'", "\\'")
query_reader = executor.query_to_iter(
f"""SELECT name, job, company FROM "{table_name}" WHERE id = '{customer_id}'""")
for (name, job, company) in query_reader.iter_tuples():
return f"The customer's name is \"{name}\", holding the position \"{job}\" at the company named {company}"
return f"No information can be found about the customer {customer_id}"
def search_company_info(company_name):
"""Search for company information online"""
with DDGS() as ddgs:
results = list(ddgs.text(f"{company_name} (company)", max_results=1))
if results:
return f"Information found about {company_name}: {results[0]['body']}"
return f"No information found about {company_name}"
def process_tool_calls(tool_calls):
"""Process tool calls and return results"""
tool_name = tool_calls[0]["function"]["name"]
llm_args = json.loads(tool_calls[0]["function"]["arguments"])
if tool_name == "get_customer_info":
return get_customer_details(llm_args["customer_id"])
elif tool_name == "get_company_info":
return search_company_info(llm_args["company_name"])
# Dash app layout
app.layout = html.Div([
dbc.Row([html.H2("Using LLM Mesh with an agent in Dash")]),
dbc.Row(dbc.Label("Please enter the ID of the customer:")),
dbc.Row([
dbc.Col(dbc.Input(id="customer_id", placeholder="Customer Id"), width=10),
dbc.Col(dbc.Button("Search", id="search", color="primary"), width="auto")
], justify="between"),
dbc.Row([dbc.Col(dbc.Textarea(id="result", style={"min-height": "500px"}), width=12)]),
dbc.Toast(
[html.P("Searching for information about the customer", className="mb-0"),
dbc.Spinner(color="primary")],
id="auto-toast",
header="Agent working",
icon="primary",
is_open=False,
style={"position": "fixed", "top": "50%", "left": "50%", "transform": "translate(-50%, -50%)"},
),
dcc.Store(id="chat-state"),
dcc.Store(id="step", data={"current_step": 0}),
], className="container-fluid mt-3")
@app.callback(
[Output("result", "value"), Output("chat-state", "data")],
Input("search", "n_clicks"),
[State("customer_id", "value"), State("chat-state", "data")],
prevent_initial_call=True,
running=[(Output("auto-toast", "is_open"), True, False),
(Output("search", "disabled"), True, False)]
)
def update_output(n_clicks, customer_id, chat_state):
if not customer_id:
return no_update, no_update
# Create new chat session
chat = create_chat_session()
# Start conversation about customer
content = f"Tell me about the customer with ID {customer_id}"
chat.with_message(content, role="user")
conversation_log = []
while True:
response = chat.execute()
if not response.tool_calls:
# Final answer received
chat.with_message(response.text, role="assistant")
conversation_log.append(f"Final Answer: {response.text}")
break
# Handle tool calls
chat.with_tool_calls(response.tool_calls, role="assistant")
tool_call_result = process_tool_calls(response.tool_calls)
chat.with_tool_output(tool_call_result, tool_call_id=response.tool_calls[0]["id"])
# Log the step
tool_name = response.tool_calls[0]["function"]["name"]
tool_args = response.tool_calls[0]["function"]["arguments"]
conversation_log.append(f"Tool: {tool_name}\nInput: {tool_args}\nResult: {tool_call_result}\n{'-'*50}")
return "\n".join(conversation_log), {"messages": chat.cq["messages"]}