|
| 1 | +"""Panel app for exploring the HoloViz MCP docs_get_best_practices tool. |
| 2 | +
|
| 3 | +Uses panel-material-ui widgets and Page layout. |
| 4 | +""" |
| 5 | + |
| 6 | +import panel as pn |
| 7 | +import panel_material_ui as pmui |
| 8 | +import param |
| 9 | + |
| 10 | +from holoviz_mcp.docs_mcp.data import get_best_practices |
| 11 | +from holoviz_mcp.docs_mcp.data import list_best_practices |
| 12 | + |
| 13 | +pn.extension() |
| 14 | + |
| 15 | +ABOUT = """ |
| 16 | +## Best Practices Tool |
| 17 | +
|
| 18 | +This tool provides best practices and guidelines for using HoloViz projects with Large Language Models (LLMs). |
| 19 | +
|
| 20 | +### What Are Best Practices? |
| 21 | +
|
| 22 | +Best practices are curated guidelines that help LLMs (and developers) write better code using HoloViz libraries. Each best practices document includes: |
| 23 | +
|
| 24 | +- **Hello World Examples**: Annotated starter code showing proper usage patterns |
| 25 | +- **DO/DON'T Guidelines**: Clear rules for what to do and what to avoid |
| 26 | +- **Code Patterns**: Common idioms and recommended approaches |
| 27 | +- **LLM-Specific Guidance**: How to structure prompts and responses effectively |
| 28 | +
|
| 29 | +### Available Projects |
| 30 | +
|
| 31 | +This tool currently provides best practices for: |
| 32 | +
|
| 33 | +- **panel**: Core Panel library for building web apps and dashboards |
| 34 | +- **panel-material-ui**: Material Design UI components for Panel applications |
| 35 | +- **holoviz**: General HoloViz ecosystem guidelines |
| 36 | +
|
| 37 | +### How to Use |
| 38 | +
|
| 39 | +Select a project in the sidebar to view its best practices. |
| 40 | +The content is displayed in Markdown format and includes code examples you can reference when building applications. |
| 41 | +
|
| 42 | +### Learn More |
| 43 | +
|
| 44 | +For more information about this project, including setup instructions and advanced configuration options, |
| 45 | +visit: [HoloViz MCP](https://github.com/MarcSkovMadsen/holoviz-mcp). |
| 46 | +""" |
| 47 | + |
| 48 | + |
| 49 | +class BestPracticesConfiguration(param.Parameterized): |
| 50 | + """ |
| 51 | + Configuration for the best practices viewer. |
| 52 | +
|
| 53 | + Parameters correspond to the project selection for viewing best practices. |
| 54 | + """ |
| 55 | + |
| 56 | + project = param.Selector( |
| 57 | + default=None, |
| 58 | + objects=[], |
| 59 | + doc="Select a project to view its best practices", |
| 60 | + ) |
| 61 | + |
| 62 | + content = param.String(default="", doc="Markdown content of the selected best practices", precedence=-1) |
| 63 | + |
| 64 | + def __init__(self, **params): |
| 65 | + """Initialize the BestPracticesConfiguration with available projects.""" |
| 66 | + super().__init__(**params) |
| 67 | + self._load_projects() |
| 68 | + |
| 69 | + if pn.state.location: |
| 70 | + pn.state.location.sync(self, parameters=["project"]) |
| 71 | + |
| 72 | + def _load_projects(self): |
| 73 | + """Load available best practices projects.""" |
| 74 | + try: |
| 75 | + projects = list_best_practices() |
| 76 | + self.param.project.objects = projects |
| 77 | + if projects and self.project is None: |
| 78 | + self.project = projects[0] # Default to first project |
| 79 | + except Exception as e: |
| 80 | + self.param.project.objects = [] |
| 81 | + self.content = f"**Error loading projects:** {e}" |
| 82 | + |
| 83 | + @param.depends("project", watch=True, on_init=True) |
| 84 | + def _update_content(self): |
| 85 | + """Update content when project selection changes.""" |
| 86 | + if self.project is None or not isinstance(self.project, str): |
| 87 | + self.content = "Please select a project to view its best practices." |
| 88 | + return |
| 89 | + |
| 90 | + try: |
| 91 | + self.content = get_best_practices(str(self.project)) |
| 92 | + except FileNotFoundError as e: |
| 93 | + self.content = f"**Error:** {e}" |
| 94 | + except Exception as e: |
| 95 | + self.content = f"**Error loading best practices:** {e}" |
| 96 | + |
| 97 | + |
| 98 | +class BestPracticesViewer(pn.viewable.Viewer): |
| 99 | + """ |
| 100 | + A Panel Material UI app for viewing HoloViz best practices. |
| 101 | +
|
| 102 | + Features: |
| 103 | + - Parameter-driven reactivity |
| 104 | + - Modern, responsive UI using Panel Material UI |
| 105 | + - Integration with HoloViz MCP docs_get_best_practices tool |
| 106 | + """ |
| 107 | + |
| 108 | + title = param.String(default="HoloViz MCP Best Practices", doc="Title of the best practices viewer") |
| 109 | + config: BestPracticesConfiguration = param.Parameter(doc="Configuration for the best practices viewer") # type: ignore |
| 110 | + |
| 111 | + def __init__(self, **params): |
| 112 | + """Initialize the BestPracticesViewer with default configuration.""" |
| 113 | + params["config"] = params.get("config", BestPracticesConfiguration()) |
| 114 | + super().__init__(**params) |
| 115 | + |
| 116 | + def _config_panel(self): |
| 117 | + """Create the configuration panel for the sidebar.""" |
| 118 | + return pmui.widgets.RadioButtonGroup.from_param(self.config.param.project, sizing_mode="stretch_width", orientation="vertical", button_style="outlined") |
| 119 | + |
| 120 | + def __panel__(self): |
| 121 | + """Create the Panel layout for the best practices viewer.""" |
| 122 | + with pn.config.set(sizing_mode="stretch_width"): |
| 123 | + # About button and dialog |
| 124 | + about_button = pmui.IconButton( |
| 125 | + label="About", |
| 126 | + icon="info", |
| 127 | + description="Click to learn about the Best Practices Tool.", |
| 128 | + sizing_mode="fixed", |
| 129 | + color="light", |
| 130 | + margin=(10, 0), |
| 131 | + ) |
| 132 | + about = pmui.Dialog(ABOUT, close_on_click=True, width=0) |
| 133 | + about_button.js_on_click(args={"about": about}, code="about.data.open = true") |
| 134 | + |
| 135 | + # GitHub button |
| 136 | + github_button = pmui.IconButton( |
| 137 | + label="Github", |
| 138 | + icon="star", |
| 139 | + description="Give HoloViz-MCP a star on GitHub", |
| 140 | + sizing_mode="fixed", |
| 141 | + color="light", |
| 142 | + margin=(10, 0), |
| 143 | + href="https://github.com/MarcSkovMadsen/holoviz-mcp", |
| 144 | + target="_blank", |
| 145 | + ) |
| 146 | + |
| 147 | + return pmui.Page( |
| 148 | + title=self.title, |
| 149 | + site_url="./", |
| 150 | + sidebar=[self._config_panel()], |
| 151 | + sidebar_width=350, |
| 152 | + header=[pn.Row(pn.Spacer(), about_button, github_button, align="end")], |
| 153 | + main=[ |
| 154 | + pmui.Container( |
| 155 | + about, |
| 156 | + pn.Column( |
| 157 | + pn.pane.Markdown( |
| 158 | + self.config.param.content, |
| 159 | + sizing_mode="stretch_both", |
| 160 | + styles={"padding": "20px"}, |
| 161 | + ), |
| 162 | + scroll=True, |
| 163 | + sizing_mode="stretch_both", |
| 164 | + ), |
| 165 | + width_option="xl", |
| 166 | + sizing_mode="stretch_both", |
| 167 | + ) |
| 168 | + ], |
| 169 | + ) |
| 170 | + |
| 171 | + |
| 172 | +if pn.state.served: |
| 173 | + BestPracticesViewer().servable() |
0 commit comments