1010import chatlas
1111import chevron
1212import sqlalchemy
13- from shiny import ui
13+ from shiny import App , Inputs , Outputs , Session , reactive , render , req , ui
1414from shiny .session import get_current_session
15+ from shinychat import output_markdown_stream
1516
17+ from ._icons import bs_icon
1618from ._querychat_module import ModServerResult , mod_server , mod_ui
1719from .datasource import DataFrameSource , DataSource , SQLAlchemySource
1820
@@ -133,6 +135,99 @@ def __init__(
133135 # Populated when ._server() gets called (in an active session)
134136 self ._server_values : ModServerResult | None = None
135137
138+ def app (
139+ self , * , bookmark_store : Literal ["url" , "server" , "disable" ] = "url"
140+ ) -> App :
141+ """
142+ Quickly chat with a dataset.
143+
144+ Creates a Shiny app with a chat sidebar and data table view -- providing a
145+ quick-and-easy way to start chatting with your data.
146+
147+ Parameters
148+ ----------
149+ bookmark_store
150+ The bookmarking store to use for the Shiny app. Options are:
151+ - `"url"`: Store bookmarks in the URL (default).
152+ - `"server"`: Store bookmarks on the server.
153+ - `"disable"`: Disable bookmarking.
154+
155+ Returns
156+ -------
157+ :
158+ A Shiny App object that can be run with `app.run()` or served with `shiny run`.
159+
160+ """
161+ enable_bookmarking = bookmark_store != "disable"
162+ table_name = self .data_source .table_name
163+
164+ def app_ui (request ):
165+ return ui .page_sidebar (
166+ self .sidebar (),
167+ ui .card (
168+ ui .card_header (
169+ ui .div (
170+ ui .div (
171+ bs_icon ("terminal-fill" ),
172+ ui .output_text ("query_title" , inline = True ),
173+ class_ = "d-flex align-items-center gap-2" ,
174+ ),
175+ ui .output_ui ("ui_reset" , inline = True ),
176+ class_ = "hstack gap-3" ,
177+ ),
178+ ),
179+ ui .output_ui ("sql_output" ),
180+ fill = False ,
181+ style = "max-height: 33%;" ,
182+ ),
183+ ui .card (
184+ ui .card_header (bs_icon ("table" ), " Data" ),
185+ ui .output_data_frame ("dt" ),
186+ ),
187+ title = ui .span ("querychat with " , ui .code (table_name )),
188+ class_ = "bslib-page-dashboard" ,
189+ fillable = True ,
190+ )
191+
192+ def app_server (input : Inputs , output : Outputs , session : Session ):
193+ self ._server (enable_bookmarking = enable_bookmarking )
194+
195+ @render .text
196+ def query_title ():
197+ return self .title () or "SQL Query"
198+
199+ @render .ui
200+ def ui_reset ():
201+ req (self .sql ())
202+ return ui .input_action_button (
203+ "reset_query" ,
204+ "Reset Query" ,
205+ class_ = "btn btn-outline-danger btn-sm lh-1 ms-auto" ,
206+ )
207+
208+ @reactive .effect
209+ @reactive .event (input .reset_query )
210+ def _ ():
211+ self .sql ("" )
212+ self .title (None )
213+
214+ @render .data_frame
215+ def dt ():
216+ return self .df ()
217+
218+ @render .ui
219+ def sql_output ():
220+ sql = self .sql () or f"SELECT * FROM { table_name } "
221+ sql_code = f"```sql\n { sql } \n ```"
222+ return output_markdown_stream (
223+ "sql_code" ,
224+ content = sql_code ,
225+ auto_scroll = False ,
226+ width = "100%" ,
227+ )
228+
229+ return App (app_ui , app_server , bookmark_store = bookmark_store )
230+
136231 def sidebar (
137232 self ,
138233 * ,
@@ -183,7 +278,7 @@ def ui(self, **kwargs):
183278 """
184279 return mod_ui (self .id , ** kwargs )
185280
186- def _server (self ) :
281+ def _server (self , * , enable_bookmarking : bool = True ) -> None :
187282 """
188283 Initialize the server module.
189284
@@ -211,6 +306,7 @@ def _server(self):
211306 system_prompt = self .system_prompt ,
212307 greeting = self .greeting ,
213308 client = self .client ,
309+ enable_bookmarking = enable_bookmarking ,
214310 )
215311
216312 return
@@ -434,7 +530,7 @@ def set_client(self, client: str | chatlas.Chat) -> None:
434530
435531
436532class QueryChat (QueryChatBase ):
437- def server (self ) :
533+ def server (self , * , enable_bookmarking : bool = True ) -> None :
438534 """
439535 Initialize Shiny server logic.
440536
@@ -443,6 +539,12 @@ def server(self):
443539 Express mode, you can use `querychat.express.QueryChat` instead
444540 of `querychat.QueryChat`, which calls `.server()` automatically.
445541
542+ Parameters
543+ ----------
544+ enable_bookmarking
545+ Whether to enable bookmarking for the querychat module. Default is
546+ `True`.
547+
446548 Examples
447549 --------
448550 ```python
@@ -474,7 +576,7 @@ def data_table():
474576 None
475577
476578 """
477- return self ._server ()
579+ return self ._server (enable_bookmarking = enable_bookmarking )
478580
479581
480582class QueryChatExpress (QueryChatBase ):
@@ -514,6 +616,7 @@ def __init__(
514616 data_description : Optional [str | Path ] = None ,
515617 extra_instructions : Optional [str | Path ] = None ,
516618 prompt_template : Optional [str | Path ] = None ,
619+ enable_bookmarking : bool = True ,
517620 ):
518621 super ().__init__ (
519622 data_source ,
@@ -525,7 +628,7 @@ def __init__(
525628 extra_instructions = extra_instructions ,
526629 prompt_template = prompt_template ,
527630 )
528- self ._server ()
631+ self ._server (enable_bookmarking = enable_bookmarking )
529632
530633
531634def normalize_data_source (
0 commit comments