Spaces:
Running
Running
"""VizroAI UI dashboard configuration.""" | |
import json | |
import black | |
import dash | |
import dash_bootstrap_components as dbc | |
import pandas as pd | |
import plotly.graph_objects as go | |
import plotly.io as pio | |
import vizro.models as vm | |
import vizro.plotly.express as px | |
from actions import data_upload_action, display_filename, run_vizro_ai, update_table | |
from components import ( | |
CodeClipboard, | |
CustomDashboard, | |
DropdownMenu, | |
HeaderComponent, | |
Icon, | |
Modal, | |
MyDropdown, | |
OffCanvas, | |
ToggleSwitch, | |
UserPromptTextArea, | |
UserUpload, | |
custom_table, | |
) | |
from dash import Input, Output, State, callback, ctx, dcc, get_asset_url, html | |
from vizro import Vizro | |
try: | |
from langchain_anthropic import ChatAnthropic | |
except ImportError: | |
ChatAnthropic = None | |
try: | |
from langchain_mistralai import ChatMistralAI | |
except ImportError: | |
ChatMistralAI = None | |
vm.Container.add_type("components", UserUpload) | |
vm.Container.add_type("components", MyDropdown) | |
vm.Container.add_type("components", OffCanvas) | |
vm.Container.add_type("components", CodeClipboard) | |
vm.Container.add_type("components", Icon) | |
vm.Container.add_type("components", Modal) | |
vm.Container.add_type("components", ToggleSwitch) | |
vm.Container.add_type("components", UserPromptTextArea) | |
vm.Container.add_type("components", DropdownMenu) | |
vm.Container.add_type("components", HeaderComponent) | |
vm.Page.add_type("components", UserUpload) | |
vm.Page.add_type("components", MyDropdown) | |
vm.Page.add_type("components", OffCanvas) | |
vm.Page.add_type("components", CodeClipboard) | |
vm.Page.add_type("components", Icon) | |
vm.Page.add_type("components", Modal) | |
SUPPORTED_MODELS = { | |
"OpenAI": [ | |
"gpt-4o-mini", | |
"gpt-4o", | |
"gpt-4-turbo", | |
], | |
"Anthropic": [ | |
"claude-3-opus-latest", | |
"claude-3-5-sonnet-latest", | |
"claude-3-sonnet-20240229", | |
"claude-3-haiku-20240307", | |
], | |
"Mistral": ["mistral-large-latest", "open-mistral-nemo", "codestral-latest"], | |
"xAI": ["grok-beta"], | |
} | |
plot_page = vm.Page( | |
id="vizro_ai_plot_page", | |
title="Vizro-AI - create interactive charts with Plotly and Vizro", | |
layout=vm.Layout( | |
grid=[ | |
[4, 4, 4, 4], | |
[2, 2, 1, 1], | |
[2, 2, 1, 1], | |
[3, 3, 1, 1], | |
[3, 3, 1, 1], | |
[3, 3, 1, 1], | |
*[[0, 0, 1, 1]] * 8, | |
] | |
), | |
components=[ | |
vm.Container( | |
title="", | |
components=[CodeClipboard(id="plot"), ToggleSwitch(id="toggle-id")], | |
layout=vm.Layout( | |
grid=[*[[0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]] * 7, [-1, -1, -1, -1, -1, -1, -1, -1, -1, 1, 1, 1]], | |
row_gap="12px", | |
col_gap="12px", | |
), | |
), | |
vm.Container( | |
title="", | |
layout=vm.Layout( | |
grid=[ | |
*[[0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]] * 10, | |
[-1, -1, -1, -1, -1, -1, -1, -1, -1, 1, 1], | |
] | |
), | |
components=[ | |
vm.Graph(id="graph-id", figure=px.scatter(pd.DataFrame())), | |
DropdownMenu(id="dropdown-menu"), | |
], | |
), | |
vm.Container( | |
id="upload-data-container", | |
title="Turn your data into visuals — just upload, describe, and see your chart in action", | |
layout=vm.Layout( | |
grid=[ | |
[1], | |
[0], | |
], | |
row_gap="0px", | |
# row_min_height="40px", | |
), | |
components=[ | |
UserUpload( | |
id="data-upload-id", | |
actions=[ | |
vm.Action( | |
function=data_upload_action(), | |
inputs=["data-upload-id.contents", "data-upload-id.filename"], | |
outputs=["data-store-id.data", "modal-table-icon.style", "modal-table-tooltip.style"], | |
), | |
vm.Action( | |
function=display_filename(), | |
inputs=["data-store-id.data"], | |
outputs=["upload-message-id.children"], | |
), | |
vm.Action( | |
function=update_table(), | |
inputs=["data-store-id.data"], | |
outputs=["modal-table.children", "modal-title.children"], | |
), | |
], | |
), | |
vm.Figure(id="show-data-component", figure=custom_table(data_frame=pd.DataFrame())), | |
], | |
), | |
vm.Container( | |
title="", | |
layout=vm.Layout( | |
grid=[ | |
[3, 3, 3, 3, 3, 3, 3, 3, 3], | |
[3, 3, 3, 3, 3, 3, 3, 3, 3], | |
[3, 3, 3, 3, 3, 3, 3, 3, 3], | |
[2, -1, -1, -1, -1, 1, 1, 0, 0], | |
], | |
row_gap="10px", | |
col_gap="4px", | |
), | |
components=[ | |
vm.Button( | |
id="trigger-button-id", | |
text="Run Vizro-AI", | |
actions=[ | |
vm.Action( | |
function=run_vizro_ai(), | |
inputs=[ | |
"text-area-id.value", | |
"trigger-button-id.n_clicks", | |
"data-store-id.data", | |
"model-dropdown-id.value", | |
"settings-api-key.value", | |
"settings-api-base.value", | |
"settings-dropdown.value", | |
], | |
outputs=["plot-code-markdown.children", "graph-id.figure", "code-output-store-id.data"], | |
), | |
], | |
), | |
MyDropdown( | |
options=SUPPORTED_MODELS["OpenAI"], value="gpt-4o-mini", multi=False, id="model-dropdown-id" | |
), | |
OffCanvas( | |
id="settings", | |
options=["OpenAI", "Anthropic", "Mistral", "xAI"], | |
value="OpenAI", | |
), | |
UserPromptTextArea(id="text-area-id"), | |
# Modal(id="modal"), | |
], | |
), | |
vm.Container( | |
title="", | |
components=[HeaderComponent()], | |
), | |
], | |
) | |
dashboard = CustomDashboard(pages=[plot_page]) | |
# pure dash callbacks | |
def open_settings(n_clicks, is_open): | |
"""Callback for opening and closing offcanvas settings component.""" | |
return not is_open if n_clicks else is_open | |
def show_api_key(value): | |
"""Callback to show api key.""" | |
return "text" if value else "password" | |
def show_api_base(value): | |
"""Callback to show api base.""" | |
return "text" if value else "password" | |
def toggle_code(value, data): | |
"""Callback for switching between vizro and plotly code.""" | |
if not data: | |
return dash.no_update | |
ai_code = data["ai_outputs"]["vizro"]["code"] if value else data["ai_outputs"]["plotly"]["code"] | |
formatted_code = black.format_str(ai_code, mode=black.Mode(line_length=100)) | |
ai_response = "\n".join(["```python", formatted_code, "```"]) | |
return ai_response | |
def open_modal(n_clicks, is_open, data): | |
"""Callback for opening modal component.""" | |
if not data: | |
return dash.no_update | |
if n_clicks: | |
return not is_open | |
return is_open | |
def download_fig(n_clicks_html, n_clicks_json, data): | |
"""Callback for downloading vizro fig.""" | |
if not data: | |
return dash.no_update | |
if not (n_clicks_html or n_clicks_json): | |
return dash.no_update | |
button_clicked = ctx.triggered_id | |
if button_clicked == "dropdown-menu-html": | |
vizro_json = json.loads(data["ai_outputs"]["vizro"]["fig"]) | |
fig = go.Figure(vizro_json) | |
graphs_html = pio.to_html(fig) | |
return dcc.send_string(graphs_html, filename="vizro_fig.html") | |
if button_clicked == "dropdown-menu-json": | |
plotly_json = data["ai_outputs"]["plotly"]["fig"] | |
return dcc.send_string(plotly_json, "plotly_fig.json") | |
def update_model_dropdown(value): | |
"""Callback for updating available models.""" | |
available_models = SUPPORTED_MODELS[value] | |
default_model = available_models[0] | |
return available_models, default_model | |
app = Vizro().build(dashboard) | |
app.dash.layout.children.append( | |
html.Div( | |
[ | |
html.Div( | |
[ | |
"Made using ", | |
html.Img(src=get_asset_url("logo.svg"), id="banner", alt="Vizro logo"), | |
dbc.NavLink("vizro", href="https://github.com/mckinsey/vizro", target="_blank", external_link=True), | |
], | |
style={"display": "flex", "flexDirection": "row"}, | |
), | |
], | |
className="anchor-container", | |
) | |
) | |
server = app.dash.server | |
if __name__ == "__main__": | |
app.run() | |