vizro-mcp 0.1.1__py3-none-any.whl → 0.1.3__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- vizro_mcp/__init__.py +1 -1
- vizro_mcp/_schemas/__init__.py +2 -18
- vizro_mcp/_schemas/schemas.py +66 -133
- vizro_mcp/_utils/__init__.py +26 -5
- vizro_mcp/_utils/configs.py +142 -0
- vizro_mcp/_utils/prompts.py +229 -0
- vizro_mcp/_utils/utils.py +66 -146
- vizro_mcp/server.py +197 -219
- vizro_mcp-0.1.3.dist-info/METADATA +201 -0
- vizro_mcp-0.1.3.dist-info/RECORD +14 -0
- vizro_mcp-0.1.1.dist-info/METADATA +0 -300
- vizro_mcp-0.1.1.dist-info/RECORD +0 -12
- {vizro_mcp-0.1.1.dist-info → vizro_mcp-0.1.3.dist-info}/WHEEL +0 -0
- {vizro_mcp-0.1.1.dist-info → vizro_mcp-0.1.3.dist-info}/entry_points.txt +0 -0
- {vizro_mcp-0.1.1.dist-info → vizro_mcp-0.1.3.dist-info}/licenses/LICENSE.txt +0 -0
vizro_mcp/server.py
CHANGED
|
@@ -6,47 +6,44 @@ from dataclasses import dataclass
|
|
|
6
6
|
from pathlib import Path
|
|
7
7
|
from typing import Any, Literal, Optional
|
|
8
8
|
|
|
9
|
+
import vizro
|
|
9
10
|
import vizro.models as vm
|
|
10
11
|
from mcp.server.fastmcp import FastMCP
|
|
11
|
-
from pydantic import ValidationError
|
|
12
|
+
from pydantic import Field, ValidationError
|
|
12
13
|
from vizro import Vizro
|
|
13
14
|
|
|
14
15
|
from vizro_mcp._schemas import (
|
|
15
16
|
AgGridEnhanced,
|
|
16
17
|
ChartPlan,
|
|
17
|
-
|
|
18
|
-
DashboardSimplified,
|
|
19
|
-
FilterSimplified,
|
|
18
|
+
FigureEnhanced,
|
|
20
19
|
GraphEnhanced,
|
|
21
|
-
PageSimplified,
|
|
22
|
-
ParameterSimplified,
|
|
23
|
-
TabsSimplified,
|
|
24
|
-
get_overview_vizro_models,
|
|
25
|
-
get_simple_dashboard_config,
|
|
26
20
|
)
|
|
27
21
|
from vizro_mcp._utils import (
|
|
22
|
+
CHART_INSTRUCTIONS,
|
|
28
23
|
GAPMINDER,
|
|
29
24
|
IRIS,
|
|
30
|
-
|
|
25
|
+
LAYOUT_INSTRUCTIONS,
|
|
31
26
|
STOCKS,
|
|
32
27
|
TIPS,
|
|
33
28
|
DFInfo,
|
|
34
29
|
DFMetaData,
|
|
30
|
+
NoDefsGenerateJsonSchema,
|
|
35
31
|
convert_github_url_to_raw,
|
|
36
32
|
create_pycafe_url,
|
|
33
|
+
get_chart_prompt,
|
|
34
|
+
get_dashboard_instructions,
|
|
35
|
+
get_dashboard_prompt,
|
|
37
36
|
get_dataframe_info,
|
|
38
37
|
get_python_code_and_preview_link,
|
|
38
|
+
get_starter_dashboard_prompt,
|
|
39
39
|
load_dataframe_by_format,
|
|
40
40
|
path_or_url_check,
|
|
41
41
|
)
|
|
42
42
|
|
|
43
|
-
# PyCafe URL for Vizro snippets
|
|
44
|
-
PYCAFE_URL = "https://py.cafe"
|
|
45
|
-
|
|
46
43
|
|
|
47
44
|
@dataclass
|
|
48
|
-
class
|
|
49
|
-
"""Results of
|
|
45
|
+
class ValidateResults:
|
|
46
|
+
"""Results of validation tools."""
|
|
50
47
|
|
|
51
48
|
valid: bool
|
|
52
49
|
message: str
|
|
@@ -65,186 +62,136 @@ class DataAnalysisResults:
|
|
|
65
62
|
df_metadata: Optional[DFMetaData]
|
|
66
63
|
|
|
67
64
|
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
"
|
|
71
|
-
)
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
@mcp.tool()
|
|
75
|
-
def get_sample_data_info(data_name: Literal["iris", "tips", "stocks", "gapminder"]) -> DFMetaData:
|
|
76
|
-
"""If user provides no data, use this tool to get sample data information.
|
|
65
|
+
@dataclass
|
|
66
|
+
class ModelJsonSchemaResults:
|
|
67
|
+
"""Results of the get_model_json_schema tool."""
|
|
77
68
|
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
- stocks: stock prices, good for line, scatter, generally things that change over time
|
|
82
|
-
- gapminder: demographic data, good for line, scatter, generally things with maps or many categories
|
|
69
|
+
model_name: str
|
|
70
|
+
json_schema: dict[str, Any]
|
|
71
|
+
additional_info: str
|
|
83
72
|
|
|
84
|
-
Args:
|
|
85
|
-
data_name: Name of the dataset to get sample data for
|
|
86
73
|
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
""
|
|
90
|
-
|
|
91
|
-
return IRIS
|
|
92
|
-
elif data_name == "tips":
|
|
93
|
-
return TIPS
|
|
94
|
-
elif data_name == "stocks":
|
|
95
|
-
return STOCKS
|
|
96
|
-
elif data_name == "gapminder":
|
|
97
|
-
return GAPMINDER
|
|
74
|
+
# TODO: check on https://github.com/modelcontextprotocol/python-sdk what new things are possible to do here
|
|
75
|
+
mcp = FastMCP(
|
|
76
|
+
name=f"MCP server to help create Vizro dashboards and charts. Server Vizro version: {vizro.__version__}",
|
|
77
|
+
)
|
|
98
78
|
|
|
99
79
|
|
|
100
80
|
@mcp.tool()
|
|
101
|
-
def
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
)
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
81
|
+
def get_vizro_chart_or_dashboard_plan(
|
|
82
|
+
user_plan: Literal["chart", "dashboard"] = Field(description="The type of Vizro thing the user wants to create"),
|
|
83
|
+
user_host: Literal["generic_host", "ide"] = Field(
|
|
84
|
+
description="The host the user is using, if 'ide' you can use the IDE/editor to run python code"
|
|
85
|
+
),
|
|
86
|
+
advanced_mode: bool = Field(
|
|
87
|
+
default=False,
|
|
88
|
+
description="""Only call if you need to use custom CSS, custom components or custom actions.
|
|
89
|
+
No need to call this with advanced_mode=True if you need advanced charts,
|
|
90
|
+
use `custom_charts` in the `validate_dashboard_config` tool instead.""",
|
|
91
|
+
),
|
|
92
|
+
) -> str:
|
|
93
|
+
"""Get instructions for creating a Vizro chart or dashboard. Call FIRST when asked to create Vizro things.
|
|
110
94
|
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
data_infos: List of DFMetaData objects containing information about the data files
|
|
114
|
-
auto_open: Whether to automatically open the PyCafe link in a browser
|
|
95
|
+
Must be ALWAYS called FIRST with advanced_mode=False, then call again with advanced_mode=True
|
|
96
|
+
if the JSON config does not suffice anymore.
|
|
115
97
|
|
|
116
98
|
Returns:
|
|
117
|
-
|
|
99
|
+
Instructions for creating a Vizro chart or dashboard
|
|
118
100
|
"""
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
except ValidationError as e:
|
|
124
|
-
return ValidationResults(
|
|
125
|
-
valid=False,
|
|
126
|
-
message=f"Validation Error: {e!s}",
|
|
127
|
-
python_code="",
|
|
128
|
-
pycafe_url=None,
|
|
129
|
-
browser_opened=False,
|
|
130
|
-
)
|
|
131
|
-
|
|
132
|
-
else:
|
|
133
|
-
result = get_python_code_and_preview_link(dashboard, data_infos)
|
|
134
|
-
|
|
135
|
-
pycafe_url = result.pycafe_url if all(info.file_location_type == "remote" for info in data_infos) else None
|
|
136
|
-
browser_opened = False
|
|
137
|
-
|
|
138
|
-
if pycafe_url and auto_open:
|
|
139
|
-
try:
|
|
140
|
-
browser_opened = webbrowser.open(pycafe_url)
|
|
141
|
-
except Exception:
|
|
142
|
-
browser_opened = False
|
|
143
|
-
|
|
144
|
-
return ValidationResults(
|
|
145
|
-
valid=True,
|
|
146
|
-
message="Configuration is valid for Dashboard!",
|
|
147
|
-
python_code=result.python_code,
|
|
148
|
-
pycafe_url=pycafe_url,
|
|
149
|
-
browser_opened=browser_opened,
|
|
150
|
-
)
|
|
151
|
-
|
|
152
|
-
finally:
|
|
153
|
-
Vizro._reset()
|
|
101
|
+
if user_plan == "chart":
|
|
102
|
+
return CHART_INSTRUCTIONS
|
|
103
|
+
elif user_plan == "dashboard":
|
|
104
|
+
return f"{get_dashboard_instructions(advanced_mode, user_host)}"
|
|
154
105
|
|
|
155
106
|
|
|
156
|
-
@mcp.tool()
|
|
157
|
-
def get_model_json_schema(
|
|
107
|
+
@mcp.tool(description=f"Get the JSON schema for the specified Vizro model. Server Vizro version: {vizro.__version__}")
|
|
108
|
+
def get_model_json_schema(
|
|
109
|
+
model_name: str = Field(
|
|
110
|
+
description="Name of the Vizro model to get schema for (e.g., 'Card', 'Dashboard', 'Page')"
|
|
111
|
+
),
|
|
112
|
+
) -> ModelJsonSchemaResults:
|
|
158
113
|
"""Get the JSON schema for the specified Vizro model.
|
|
159
114
|
|
|
160
|
-
Args:
|
|
161
|
-
model_name: Name of the Vizro model to get schema for (e.g., 'Card', 'Dashboard', 'Page')
|
|
162
|
-
|
|
163
115
|
Returns:
|
|
164
116
|
JSON schema of the requested Vizro model
|
|
165
117
|
"""
|
|
166
|
-
|
|
118
|
+
if not hasattr(vm, model_name):
|
|
119
|
+
return ModelJsonSchemaResults(
|
|
120
|
+
model_name=model_name,
|
|
121
|
+
json_schema={},
|
|
122
|
+
additional_info=f"Model '{model_name}' not found in vizro.models",
|
|
123
|
+
)
|
|
124
|
+
|
|
167
125
|
modified_models = {
|
|
168
|
-
"Page": PageSimplified,
|
|
169
|
-
"Dashboard": DashboardSimplified,
|
|
170
126
|
"Graph": GraphEnhanced,
|
|
171
127
|
"AgGrid": AgGridEnhanced,
|
|
172
128
|
"Table": AgGridEnhanced,
|
|
173
|
-
"
|
|
174
|
-
"Container": ContainerSimplified,
|
|
175
|
-
"Filter": FilterSimplified,
|
|
176
|
-
"Parameter": ParameterSimplified,
|
|
129
|
+
"Figure": FigureEnhanced,
|
|
177
130
|
}
|
|
178
131
|
|
|
179
|
-
# Check if model_name is in the simplified models dictionary
|
|
180
132
|
if model_name in modified_models:
|
|
181
|
-
return
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
133
|
+
return ModelJsonSchemaResults(
|
|
134
|
+
model_name=model_name,
|
|
135
|
+
json_schema=modified_models[model_name].model_json_schema(schema_generator=NoDefsGenerateJsonSchema),
|
|
136
|
+
additional_info="""LLM must remember to replace `$ref` with the actual config. Request the schema of
|
|
137
|
+
that model if necessary. Do NOT forget to call `validate_dashboard_config` after each iteration.""",
|
|
138
|
+
)
|
|
139
|
+
deprecated_models = {"filter_interaction": "set_control", "Layout": "Grid"}
|
|
140
|
+
if model_name in deprecated_models:
|
|
141
|
+
return ModelJsonSchemaResults(
|
|
142
|
+
model_name=model_name,
|
|
143
|
+
json_schema={},
|
|
144
|
+
additional_info=f"Model '{model_name}' is deprecated. Use {deprecated_models[model_name]} instead.",
|
|
145
|
+
)
|
|
186
146
|
|
|
187
|
-
# Get schema for standard model
|
|
188
147
|
model_class = getattr(vm, model_name)
|
|
189
|
-
|
|
148
|
+
if model_name in {"Grid", "Flex"}:
|
|
149
|
+
return ModelJsonSchemaResults(
|
|
150
|
+
model_name=model_name,
|
|
151
|
+
json_schema=model_class.model_json_schema(schema_generator=NoDefsGenerateJsonSchema),
|
|
152
|
+
additional_info=LAYOUT_INSTRUCTIONS,
|
|
153
|
+
)
|
|
154
|
+
|
|
155
|
+
return ModelJsonSchemaResults(
|
|
156
|
+
model_name=model_name,
|
|
157
|
+
json_schema=model_class.model_json_schema(schema_generator=NoDefsGenerateJsonSchema),
|
|
158
|
+
additional_info="""LLM must remember to replace `$ref` with the actual config. Request the schema of
|
|
159
|
+
that model if necessary. Do NOT forget to call `validate_dashboard_config` after each iteration.""",
|
|
160
|
+
)
|
|
190
161
|
|
|
191
162
|
|
|
192
163
|
@mcp.tool()
|
|
193
|
-
def
|
|
194
|
-
"""
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
- create a chart using plotly express and/or plotly graph objects, and call the function `custom_chart`
|
|
209
|
-
- call the validate_chart_code tool to validate the chart code, display the figure code to the user (as artifact)
|
|
210
|
-
- do NOT call any other tool after, especially do NOT create a dashboard
|
|
211
|
-
"""
|
|
212
|
-
elif user_plan == "dashboard":
|
|
213
|
-
return f"""
|
|
214
|
-
IMPORTANT:
|
|
215
|
-
- KEEP IT SIMPLE: rather than iterating yourself, ask the user for more instructions
|
|
216
|
-
- ALWAYS VALIDATE:if you iterate over a valid produced solution, make sure to ALWAYS call the
|
|
217
|
-
validate_model_config tool again to ensure the solution is still valid
|
|
218
|
-
- DO NOT show any code or config to the user until you have validated the solution, do not say you are preparing
|
|
219
|
-
a solution, just do it and validate it
|
|
220
|
-
- IF STUCK: try enquiring the schema of the component in question
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
Instructions for creating a Vizro dashboard:
|
|
224
|
-
- IF the user has no plan (ie no components or pages), use the config at the bottom of this prompt
|
|
225
|
-
and validate that solution without any additions, OTHERWISE:
|
|
226
|
-
- analyze the datasets needed for the dashboard using the load_and_analyze_data tool - the most
|
|
227
|
-
important information here are the column names and column types
|
|
228
|
-
- if the user provides no data, but you need to display a chart or table, use the get_sample_data_info
|
|
229
|
-
tool to get sample data information
|
|
230
|
-
- make a plan of what components you would like to use, then request all necessary schemas
|
|
231
|
-
using the get_model_json_schema tool
|
|
232
|
-
- assemble your components into a page, then add the page or pages to a dashboard, DO NOT show config or code
|
|
233
|
-
to the user until you have validated the solution
|
|
234
|
-
- ALWAYS validate the dashboard configuration using the validate_model_config tool
|
|
235
|
-
- if you display any code artifact, you must use the above created code, do not add new config to it
|
|
236
|
-
|
|
237
|
-
Models you can use:
|
|
238
|
-
{get_overview_vizro_models()}
|
|
239
|
-
|
|
240
|
-
Very simple dashboard config:
|
|
241
|
-
{get_simple_dashboard_config()}
|
|
164
|
+
def get_sample_data_info(
|
|
165
|
+
data_name: Literal["iris", "tips", "stocks", "gapminder"] = Field(
|
|
166
|
+
description="Name of the dataset to get sample data for"
|
|
167
|
+
),
|
|
168
|
+
) -> DFMetaData:
|
|
169
|
+
"""If user provides no data, use this tool to get sample data information.
|
|
170
|
+
|
|
171
|
+
Use the following data for the below purposes:
|
|
172
|
+
- iris: mostly numerical with one categorical column, good for scatter, histogram, boxplot, etc.
|
|
173
|
+
- tips: contains mix of numerical and categorical columns, good for bar, pie, etc.
|
|
174
|
+
- stocks: stock prices, good for line, scatter, generally things that change over time
|
|
175
|
+
- gapminder: demographic data, good for line, scatter, generally things with maps or many categories
|
|
176
|
+
|
|
177
|
+
Returns:
|
|
178
|
+
Data info object containing information about the dataset.
|
|
242
179
|
"""
|
|
180
|
+
if data_name == "iris":
|
|
181
|
+
return IRIS
|
|
182
|
+
elif data_name == "tips":
|
|
183
|
+
return TIPS
|
|
184
|
+
elif data_name == "stocks":
|
|
185
|
+
return STOCKS
|
|
186
|
+
elif data_name == "gapminder":
|
|
187
|
+
return GAPMINDER
|
|
243
188
|
|
|
244
189
|
|
|
245
190
|
@mcp.tool()
|
|
246
|
-
def load_and_analyze_data(
|
|
247
|
-
|
|
191
|
+
def load_and_analyze_data(
|
|
192
|
+
path_or_url: str = Field(description="Absolute (important!) local file path or URL to a data file"),
|
|
193
|
+
) -> DataAnalysisResults:
|
|
194
|
+
"""Use to understand local or remote data files. Must be called with absolute paths or URLs.
|
|
248
195
|
|
|
249
196
|
Supported formats:
|
|
250
197
|
- CSV (.csv)
|
|
@@ -254,9 +201,6 @@ def load_and_analyze_data(path_or_url: str) -> DataAnalysisResults:
|
|
|
254
201
|
- OpenDocument Spreadsheet (.ods)
|
|
255
202
|
- Parquet (.parquet)
|
|
256
203
|
|
|
257
|
-
Args:
|
|
258
|
-
path_or_url: Local file path or URL to a data file
|
|
259
|
-
|
|
260
204
|
Returns:
|
|
261
205
|
DataAnalysisResults object containing DataFrame information and metadata
|
|
262
206
|
"""
|
|
@@ -276,7 +220,14 @@ def load_and_analyze_data(path_or_url: str) -> DataAnalysisResults:
|
|
|
276
220
|
df, read_fn = load_dataframe_by_format(processed_path_or_url, mime_type)
|
|
277
221
|
|
|
278
222
|
except Exception as e:
|
|
279
|
-
return DataAnalysisResults(
|
|
223
|
+
return DataAnalysisResults(
|
|
224
|
+
valid=False,
|
|
225
|
+
message=f"""Failed to load data: {e!s}. Remember to use the ABSOLUTE path or URL!
|
|
226
|
+
Alternatively, you can use any data analysis means available to you. Most important information are the column names and
|
|
227
|
+
column types for passing along to the `validate_dashboard_config` or `validate_chart_code` tools.""",
|
|
228
|
+
df_info=None,
|
|
229
|
+
df_metadata=None,
|
|
230
|
+
)
|
|
280
231
|
|
|
281
232
|
df_info = get_dataframe_info(df)
|
|
282
233
|
df_metadata = DFMetaData(
|
|
@@ -289,61 +240,95 @@ def load_and_analyze_data(path_or_url: str) -> DataAnalysisResults:
|
|
|
289
240
|
return DataAnalysisResults(valid=True, message="Data loaded successfully", df_info=df_info, df_metadata=df_metadata)
|
|
290
241
|
|
|
291
242
|
|
|
243
|
+
# TODO: Additional things we could validate:
|
|
244
|
+
# - data_infos: check we are referring to the correct dataframe, or at least A DF
|
|
245
|
+
@mcp.tool()
|
|
246
|
+
def validate_dashboard_config(
|
|
247
|
+
dashboard_config: dict[str, Any] = Field(
|
|
248
|
+
description="Either a JSON string or a dictionary representing a Vizro dashboard model configuration"
|
|
249
|
+
),
|
|
250
|
+
data_infos: list[DFMetaData] = Field(
|
|
251
|
+
description="List of DFMetaData objects containing information about the data files"
|
|
252
|
+
),
|
|
253
|
+
custom_charts: list[ChartPlan] = Field(
|
|
254
|
+
description="List of ChartPlan objects containing information about the custom charts in the dashboard"
|
|
255
|
+
),
|
|
256
|
+
auto_open: bool = Field(default=True, description="Whether to automatically open the PyCafe link in a browser"),
|
|
257
|
+
) -> ValidateResults:
|
|
258
|
+
"""Validate Vizro model configuration. Run ALWAYS when you have a complete dashboard configuration.
|
|
259
|
+
|
|
260
|
+
If successful, the tool will return the python code and, if it is a remote file, the py.cafe link to the chart.
|
|
261
|
+
The PyCafe link will be automatically opened in your default browser if auto_open is True.
|
|
262
|
+
|
|
263
|
+
Returns:
|
|
264
|
+
ValidationResults object with status and dashboard details
|
|
265
|
+
"""
|
|
266
|
+
Vizro._reset()
|
|
267
|
+
|
|
268
|
+
try:
|
|
269
|
+
dashboard = vm.Dashboard.model_validate(
|
|
270
|
+
dashboard_config,
|
|
271
|
+
context={"allow_undefined_captured_callable": [custom_chart.chart_name for custom_chart in custom_charts]},
|
|
272
|
+
)
|
|
273
|
+
except ValidationError as e:
|
|
274
|
+
return ValidateResults(
|
|
275
|
+
valid=False,
|
|
276
|
+
message=f"""Validation Error: {e!s}. Fix the error and call this tool again.
|
|
277
|
+
Calling `get_model_json_schema` may help.""",
|
|
278
|
+
python_code="",
|
|
279
|
+
pycafe_url=None,
|
|
280
|
+
browser_opened=False,
|
|
281
|
+
)
|
|
282
|
+
|
|
283
|
+
else:
|
|
284
|
+
code_link = get_python_code_and_preview_link(dashboard, data_infos, custom_charts)
|
|
285
|
+
|
|
286
|
+
pycafe_url = code_link.pycafe_url if all(info.file_location_type == "remote" for info in data_infos) else None
|
|
287
|
+
browser_opened = False
|
|
288
|
+
|
|
289
|
+
if pycafe_url and auto_open:
|
|
290
|
+
try:
|
|
291
|
+
browser_opened = webbrowser.open(pycafe_url)
|
|
292
|
+
except Exception:
|
|
293
|
+
browser_opened = False
|
|
294
|
+
|
|
295
|
+
return ValidateResults(
|
|
296
|
+
valid=True,
|
|
297
|
+
message="""Configuration is valid for Dashboard! Do not forget to call this tool again after each iteration.
|
|
298
|
+
If you are creating an `app.py` file, you MUST use the code from the validation tool, do not modify it, watch out for
|
|
299
|
+
differences to previous `app.py`""",
|
|
300
|
+
python_code=code_link.python_code,
|
|
301
|
+
pycafe_url=pycafe_url,
|
|
302
|
+
browser_opened=browser_opened,
|
|
303
|
+
)
|
|
304
|
+
|
|
305
|
+
finally:
|
|
306
|
+
Vizro._reset()
|
|
307
|
+
|
|
308
|
+
|
|
292
309
|
@mcp.prompt()
|
|
293
310
|
def create_starter_dashboard():
|
|
294
311
|
"""Prompt template for getting started with Vizro."""
|
|
295
|
-
|
|
296
|
-
Create a super simple Vizro dashboard with one page and one chart and one filter:
|
|
297
|
-
- No need to call any tools except for validate_model_config
|
|
298
|
-
- Call this tool with the precise config as shown below
|
|
299
|
-
- The PyCafe link will be automatically opened in your default browser
|
|
300
|
-
- THEN show the python code after validation, but do not show the PyCafe link
|
|
301
|
-
- Be concise, do not explain anything else, just create the dashboard
|
|
302
|
-
- Finally ask the user what they would like to do next, then you can call other tools to get more information,
|
|
303
|
-
you should then start with the get_chart_or_dashboard_plan tool
|
|
304
|
-
|
|
305
|
-
{SAMPLE_DASHBOARD_CONFIG}
|
|
306
|
-
"""
|
|
307
|
-
return content
|
|
312
|
+
return get_starter_dashboard_prompt()
|
|
308
313
|
|
|
309
314
|
|
|
310
315
|
@mcp.prompt()
|
|
311
|
-
def
|
|
312
|
-
file_path_or_url: str,
|
|
316
|
+
def create_dashboard(
|
|
317
|
+
file_path_or_url: str = Field(description="The absolute path or URL to the data file you want to use."),
|
|
318
|
+
context: Optional[str] = Field(default=None, description="(Optional) Describe the dashboard you want to create."),
|
|
313
319
|
) -> str:
|
|
314
320
|
"""Prompt template for creating an EDA dashboard based on one dataset."""
|
|
315
|
-
|
|
316
|
-
Create an EDA dashboard based on the following dataset:{file_path_or_url}. Proceed as follows:
|
|
317
|
-
1. Analyze the data using the load_and_analyze_data tool first, passing the file path or github url {file_path_or_url}
|
|
318
|
-
to the tool.
|
|
319
|
-
2. Create a dashboard with 4 pages:
|
|
320
|
-
- Page 1: Summary of the dataset using the Card component and the dataset itself using the plain AgGrid component.
|
|
321
|
-
- Page 2: Visualizing the distribution of all numeric columns using the Graph component with a histogram.
|
|
322
|
-
- use a Parameter that targets the Graph component and the x argument, and you can select the column to
|
|
323
|
-
be displayed
|
|
324
|
-
- IMPORTANT:remember that you target the chart like: <graph_id>.x and NOT <graph_id>.figure.x
|
|
325
|
-
- do not use any color schemes etc.
|
|
326
|
-
- add filters for all categorical columns
|
|
327
|
-
- Page 3: Visualizing the correlation between all numeric columns using the Graph component with a scatter plot.
|
|
328
|
-
- Page 4: Two interesting charts side by side, use the Graph component for this. Make sure they look good
|
|
329
|
-
but do not try something beyond the scope of plotly express
|
|
330
|
-
"""
|
|
331
|
-
return content
|
|
321
|
+
return get_dashboard_prompt(file_path_or_url, context)
|
|
332
322
|
|
|
333
323
|
|
|
334
324
|
@mcp.tool()
|
|
335
325
|
def validate_chart_code(
|
|
336
|
-
chart_config: ChartPlan,
|
|
337
|
-
data_info: DFMetaData,
|
|
338
|
-
auto_open: bool = True,
|
|
339
|
-
) ->
|
|
326
|
+
chart_config: ChartPlan = Field(description="A ChartPlan object with the chart configuration"),
|
|
327
|
+
data_info: DFMetaData = Field(description="Metadata for the dataset to be used in the chart"),
|
|
328
|
+
auto_open: bool = Field(default=True, description="Whether to automatically open the PyCafe link in a browser"),
|
|
329
|
+
) -> ValidateResults:
|
|
340
330
|
"""Validate the chart code created by the user and optionally open the PyCafe link in a browser.
|
|
341
331
|
|
|
342
|
-
Args:
|
|
343
|
-
chart_config: A ChartPlan object with the chart configuration
|
|
344
|
-
data_info: Metadata for the dataset to be used in the chart
|
|
345
|
-
auto_open: Whether to automatically open the PyCafe link in a browser
|
|
346
|
-
|
|
347
332
|
Returns:
|
|
348
333
|
ValidationResults object with status and dashboard details
|
|
349
334
|
"""
|
|
@@ -352,7 +337,7 @@ def validate_chart_code(
|
|
|
352
337
|
try:
|
|
353
338
|
chart_plan_obj = ChartPlan.model_validate(chart_config)
|
|
354
339
|
except ValidationError as e:
|
|
355
|
-
return
|
|
340
|
+
return ValidateResults(
|
|
356
341
|
valid=False,
|
|
357
342
|
message=f"Validation Error: {e!s}",
|
|
358
343
|
python_code="",
|
|
@@ -372,7 +357,7 @@ def validate_chart_code(
|
|
|
372
357
|
except Exception:
|
|
373
358
|
browser_opened = False
|
|
374
359
|
|
|
375
|
-
return
|
|
360
|
+
return ValidateResults(
|
|
376
361
|
valid=True,
|
|
377
362
|
message="Chart only dashboard created successfully!",
|
|
378
363
|
python_code=chart_plan_obj.get_chart_code(vizro=True),
|
|
@@ -386,15 +371,8 @@ def validate_chart_code(
|
|
|
386
371
|
|
|
387
372
|
@mcp.prompt()
|
|
388
373
|
def create_vizro_chart(
|
|
389
|
-
|
|
390
|
-
|
|
374
|
+
file_path_or_url: str = Field(description="The absolute path or URL to the data file you want to use."),
|
|
375
|
+
context: Optional[str] = Field(default=None, description="(Optional) Describe the chart you want to create."),
|
|
391
376
|
) -> str:
|
|
392
377
|
"""Prompt template for creating a Vizro chart."""
|
|
393
|
-
|
|
394
|
-
- Create a chart using the following chart type: {chart_type}.
|
|
395
|
-
- You MUST name the function containing the fig `custom_chart`
|
|
396
|
-
- Make sure to analyze the data using the load_and_analyze_data tool first, passing the file path or github url
|
|
397
|
-
{file_path_or_url} OR choose the most appropriate sample data using the get_sample_data_info tool.
|
|
398
|
-
Then you MUST use the validate_chart_code tool to validate the chart code.
|
|
399
|
-
"""
|
|
400
|
-
return content
|
|
378
|
+
return get_chart_prompt(file_path_or_url, context)
|