Skip to content

Commit 2b3e947

Browse files
committed
Polish genie_api in Dash
1 parent 7a0236a commit 2b3e947

File tree

1 file changed

+96
-70
lines changed

1 file changed

+96
-70
lines changed

dash/pages/genie_api.py

Lines changed: 96 additions & 70 deletions
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,6 @@
77
from typing import Dict, List
88

99

10-
# pages/ml_serving_invoke.py
1110
dash.register_page(
1211
__name__,
1312
path="/bi/genie",
@@ -23,6 +22,49 @@
2322
except Exception:
2423
w = None
2524

25+
code_snippet = '''```python
26+
import pandas as pd
27+
from databricks.sdk import WorkspaceClient
28+
29+
30+
def get_query_result(statement_id):
31+
# For simplicity, let's say data fits in one chunk, query.manifest.total_chunk_count = 1
32+
33+
result = w.statement_execution.get_statement(statement_id)
34+
return pd.DataFrame(
35+
result.result.data_array, columns=[i.name for i in result.manifest.schema.columns]
36+
)
37+
38+
39+
def process_genie_response(response):
40+
for i in response.attachments:
41+
if i.text:
42+
print(f"A: {i.text.content}")
43+
elif i.query:
44+
data = get_query_result(i.query.statement_id)
45+
print(f"A: {i.query.description}")
46+
print(f"Data: {data}")
47+
print(f"Generated code: {i.query.query}")
48+
49+
50+
# Configuration
51+
w = WorkspaceClient()
52+
genie_space_id = "01f0023d28a71e599b5a62f4117516d4"
53+
54+
prompt = "Ask a question..."
55+
follow_up_prompt = "Ask a follow-up..."
56+
57+
# Start the conversation
58+
conversation = w.genie.start_conversation_and_wait(genie_space_id, prompt)
59+
process_genie_response(conversation)
60+
61+
# Continue the conversation
62+
follow_up_conversation = w.genie.create_message_and_wait(
63+
genie_space_id, conversation.conversation_id, follow_up_prompt
64+
)
65+
process_genie_response(follow_up_conversation)
66+
```'''
67+
2668

2769
def dash_dataframe(df: pd.DataFrame) -> dash.dash_table.DataTable:
2870
table = dash.dash_table.DataTable(
@@ -50,7 +92,6 @@ def dash_dataframe(df: pd.DataFrame) -> dash.dash_table.DataTable:
5092
"whiteSpace": "normal",
5193
"height": "auto",
5294
},
53-
5495
page_size=10,
5596
page_action="native",
5697
sort_action="native",
@@ -65,12 +106,13 @@ def format_message_display(chat_history: List[Dict]) -> List[Dict]:
65106
for message in chat_history:
66107
display = []
67108
if "content" in message:
68-
display.append(dcc.Markdown(message["content"]))
109+
role = "You: " if message["role"] == "user" else f"{message['role'].capitalize()}: "
110+
display.append(dcc.Markdown(f"{role} {message['content']}"))
69111
if "data" in message:
70112
display.append(message["data"])
71113
if "code" in message:
72114
display.append(dcc.Markdown(f"```sql {message['code']}```", className="border rounded p-3"))
73-
chat_display.append(html.Div(display, className=f"chat-message {message['role']}-message"))
115+
chat_display.append(html.Div(display, style={"borderBottom": "2px solid rgba(0, 0, 0, 0.2)", "margin": "5px 0 0 0"}))
74116

75117
return chat_display
76118

@@ -132,7 +174,7 @@ def layout():
132174
dbc.Form([
133175
dbc.Label("Genie Space ID:", className="mt-3"),
134176
dbc.Input(
135-
id="genie-space-id-input",
177+
id="genie-space-id",
136178
type="text",
137179
placeholder="01efe16a65e21836acefb797ae6a8fe4",
138180
style={
@@ -149,13 +191,17 @@ def layout():
149191
style={
150192
"backgroundColor": "#f8f9fa",
151193
"border": "1px solid #dee2e6",
152-
"boxShadow": "inset 0 1px 2px rgba(0,0,0,0.075)"
194+
"boxShadow": "inset 0 1px 2px rgba(0,0,0,0.075)",
195+
"margin": "5px 0 0 0",
153196
}
154197
),
155198
dbc.Button(
156199
"Chat",
157200
id="chat-button",
158-
color="primary"
201+
color="primary",
202+
style={
203+
"margin": "5px 0 0 0",
204+
}
159205
)
160206
])
161207
], className="mb-4"),
@@ -164,55 +210,14 @@ def layout():
164210
html.Div(id="chat-history", className="mt-4"),
165211
dcc.Store(id="chat-history-store"),
166212
dcc.Store(id="conversation-id"),
167-
168-
# Status/error messages
169-
html.Div(id="status-area-genie", className="mt-3")
213+
dbc.Button("New Chat", id="clear-button", n_clicks=0, className="mt-3"),
214+
dbc.Button("Open Genie", id="genie-button", target="_blank", href="", style={"display": "none"}, className="mt-3"),
215+
170216
], className="p-3"),
171217

172218
# Code snippet tab
173219
dbc.Tab(label="Code snippet", children=[
174-
dcc.Markdown('''```python
175-
import pandas as pd
176-
from databricks.sdk import WorkspaceClient
177-
178-
179-
def get_query_result(statement_id):
180-
# For simplicity, let's say data fits in one chunk, query.manifest.total_chunk_count = 1
181-
182-
result = w.statement_execution.get_statement(statement_id)
183-
return pd.DataFrame(
184-
result.result.data_array, columns=[i.name for i in result.manifest.schema.columns]
185-
)
186-
187-
188-
def process_genie_response(response):
189-
for i in response.attachments:
190-
if i.text:
191-
print(f"A: {i.text.content}")
192-
elif i.query:
193-
data = get_query_result(i.query.statement_id)
194-
print(f"A: {i.query.description}")
195-
print(f"Data: {data}")
196-
print(f"Generated code: {i.query.query}")
197-
198-
199-
# Configuration
200-
w = WorkspaceClient()
201-
genie_space_id = "01f0023d28a71e599b5a62f4117516d4"
202-
203-
prompt = "Ask a question..."
204-
follow_up_prompt = "Ask a follow-up..."
205-
206-
# Start the conversation
207-
conversation = w.genie.start_conversation_and_wait(genie_space_id, prompt)
208-
process_genie_response(conversation)
209-
210-
# Continue the conversation
211-
follow_up_conversation = w.genie.create_message_and_wait(
212-
genie_space_id, conversation.conversation_id, follow_up_prompt
213-
)
214-
process_genie_response(follow_up_conversation)
215-
```''', className="p-4 border rounded")
220+
dcc.Markdown(code_snippet, className="p-4 border rounded")
216221
], className="p-3"),
217222

218223
# Requirements tab
@@ -245,46 +250,67 @@ def process_genie_response(response):
245250
], className="mb-4")
246251
], fluid=True, className="py-4")
247252

253+
254+
# Callbacks handle interactions
255+
248256
@callback(
249257
[Output("chat-history-store", "data", allow_duplicate=True),
250258
Output("chat-history", "children", allow_duplicate=True),
251-
Output("conversation-id", "value", allow_duplicate=True)],
259+
Output("conversation-id", "value", allow_duplicate=True),],
252260
Input("chat-button", "n_clicks"),
253-
[State("genie-space-id-input", "value"),
261+
[State("genie-space-id", "value"),
254262
State("conversation-id", "value"),
255263
State("prompt", "value"),
256264
State("chat-history-store", "data")],
257-
prevent_initial_call=True
265+
prevent_initial_call=True,
258266
)
259267
def update_chat(n_clicks, genie_space_id, conversation_id, prompt, chat_history):
260268
if not all([genie_space_id, prompt]):
261-
return dash.no_update, dbc.Alert(
262-
"Please fill in all fields",
263-
color="warning"
264-
)
265-
269+
return dash.no_update, dbc.Alert("Please fill in all fields", color="warning")
270+
266271
chat_history = chat_history or []
272+
chat_history.append({"role": "user", "content": prompt})
267273

268274
try:
269275
if conversation_id:
270-
conversation = w.genie.create_message_and_wait(
271-
genie_space_id, conversation_id, prompt
272-
)
273-
chat_history = process_genie_response(conversation, chat_history)
276+
conversation = w.genie.create_message_and_wait(genie_space_id, conversation_id, prompt)
274277
else:
275278
conversation = w.genie.start_conversation_and_wait(genie_space_id, prompt)
276279
conversation_id = conversation.conversation_id
277-
chat_history = process_genie_response(conversation, chat_history)
278280

281+
chat_history = process_genie_response(conversation, chat_history)
279282
chat_display = format_message_display(chat_history)
280283

281284
return chat_history, chat_display, conversation_id
282-
285+
283286
except Exception as e:
284-
return dash.no_update, dbc.Alert(
285-
f"An error occurred: {str(e)}",
286-
color="danger"
287-
)
287+
return dash.no_update, dbc.Alert(f"An error occurred: {str(e)}", color="danger")
288+
289+
290+
@callback(
291+
[Output("chat-history-store", "data", allow_duplicate=True),
292+
Output("chat-history", "children", allow_duplicate=True),
293+
Output("conversation-id", "value", allow_duplicate=True),],
294+
Input("clear-button", "n_clicks"),
295+
prevent_initial_call=True,
296+
)
297+
def clear_chat(n_clicks):
298+
return [], [], None if n_clicks else (dash.no_update, dash.no_update, None)
299+
300+
301+
@callback(
302+
[Output("genie-button", "href"), Output("genie-button", "style")],
303+
State("genie-space-id", "value"),
304+
Input("conversation-id", "value"),
305+
)
306+
def update_href(genie_space_id, conversation_id):
307+
if not conversation_id:
308+
return "", {"display": "none"}
309+
310+
href = f"{w.config.host}/genie/rooms/{genie_space_id}/chats/{conversation_id}"
311+
312+
return href, {"margin": "0 0 0 5px"}
313+
288314

289315
# Make layout available at module level
290316
__all__ = ["layout"]

0 commit comments

Comments
 (0)