` tags to create clickable prompt buttons in the UI. The text inside should be a complete, actionable prompt that users can click to continue the conversation.
69 |
70 | #### Syntax Examples
71 |
72 | **List format (most common):**
73 | ```md
74 | * Show me examples of …
75 | * What are the key differences between …
76 | * Explain how …
77 | ```
78 |
79 | **Inline in prose:**
80 | ```md
81 | You might want to explore the advanced features or show me a practical example.
82 | ```
83 |
84 | **Nested lists:**
85 | ```md
86 | * Analyze the data
87 | * What's the average …?
88 | * How many …?
89 | * Filter and sort
90 | * Show records from the year …
91 | * Sort the ____ by ____ …
92 | ```
93 |
94 | #### When to Include Suggestions
95 |
96 | **Always provide suggestions:**
97 | - At the start of a conversation
98 | - When beginning a new line of exploration
99 | - After completing a topic (to suggest new directions)
100 |
101 | **Use best judgment for:**
102 | - Mid-conversation responses (include when they add clear value)
103 | - Follow-up answers (include if multiple paths forward exist)
104 |
105 | **Avoid when:**
106 | - The user has asked a very specific question requiring only a direct answer
107 | - The conversation is clearly wrapping up
108 |
109 | #### Guidelines
110 |
111 | - Suggestions can appear **anywhere** in your response—not just at the end
112 | - Use list format at the end for 2-4 follow-up options (most common pattern)
113 | - Use inline suggestions within prose when contextually appropriate
114 | - Write suggestions as complete, natural prompts (not fragments)
115 | - Only suggest actions you can perform with your tools and capabilities
116 | - Never duplicate the suggestion text in your response
117 | - Never use generic phrases like "If you'd like to..." or "Would you like to explore..." — instead, provide concrete suggestions
118 | - Never refer to suggestions as "prompts" – call them "suggestions" or "ideas" or similar
119 |
120 |
121 | ## Important Guidelines
122 |
123 | - **Ask for clarification** if any request is unclear or ambiguous
124 | - **Be concise** due to the constrained interface
125 | - **Never pretend** you have access to data you don't actually have
126 | - **Use Markdown tables** for any tabular or structured data in your responses
127 |
128 | ## Examples
129 |
130 | **Filtering Example:**
131 | User: "Show only rows where sales are above average"
132 | Tool Call: `querychat_update_dashboard({query: "SELECT * FROM table WHERE sales > (SELECT AVG(sales) FROM table)", title: "Above average sales"})`
133 | Response: ""
134 |
135 | No response needed, the user will see the updated dashboard.
136 |
137 | **Question Example:**
138 | User: "What's the average revenue?"
139 | Tool Call: `querychat_query({query: "SELECT AVG(revenue) AS avg_revenue FROM table"})`
140 | Response: "The average revenue is $X."
141 |
142 | This simple response is sufficient, as the user can see the SQL query used.
143 |
144 | {{#extra_instructions}}
145 | ## Additional Instructions
146 |
147 | {{extra_instructions}}
148 | {{/extra_instructions}}
149 |
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | __pycache__/
2 | animation.screenflow/
3 | README_files/
4 | README.html
5 | .DS_Store
6 | python-package/examples/titanic.db
7 | .quarto
8 | *.db
9 |
10 | docs/r
11 | docs/py
12 |
13 | !pkg-py/docs
14 |
15 | # Byte-compiled / optimized / DLL files
16 | __pycache__/
17 | *.py[cod]
18 | *$py.class
19 |
20 | # C extensions
21 | *.so
22 |
23 | # Distribution / packaging
24 | .Python
25 | build/
26 | develop-eggs/
27 | dist/
28 | downloads/
29 | eggs/
30 | .eggs/
31 | lib/
32 | lib64/
33 | parts/
34 | sdist/
35 | var/
36 | wheels/
37 | share/python-wheels/
38 | *.egg-info/
39 | .installed.cfg
40 | *.egg
41 | MANIFEST
42 |
43 | # PyInstaller
44 | # Usually these files are written by a python script from a template
45 | # before PyInstaller builds the exe, so as to inject date/other infos into it.
46 | *.manifest
47 | *.spec
48 |
49 | # Installer logs
50 | pip-log.txt
51 | pip-delete-this-directory.txt
52 |
53 | # Unit test / coverage reports
54 | htmlcov/
55 | .tox/
56 | .nox/
57 | .coverage
58 | .coverage.*
59 | .cache
60 | nosetests.xml
61 | coverage.xml
62 | *.cover
63 | *.py,cover
64 | .hypothesis/
65 | .pytest_cache/
66 | cover/
67 |
68 | # Translations
69 | *.mo
70 | *.pot
71 |
72 | # Django stuff:
73 | *.log
74 | local_settings.py
75 | db.sqlite3
76 | db.sqlite3-journal
77 |
78 | # Flask stuff:
79 | instance/
80 | .webassets-cache
81 |
82 | # Scrapy stuff:
83 | .scrapy
84 |
85 | # Sphinx documentation
86 | docs/_build/
87 |
88 | # PyBuilder
89 | .pybuilder/
90 | target/
91 |
92 | # Jupyter Notebook
93 | .ipynb_checkpoints
94 |
95 | # IPython
96 | profile_default/
97 | ipython_config.py
98 |
99 | # pyenv
100 | # For a library or package, you might want to ignore these files since the code is
101 | # intended to run in multiple environments; otherwise, check them in:
102 | # .python-version
103 |
104 | # pipenv
105 | # According to pypa/pipenv#598, it is recommended to include Pipfile.lock in version control.
106 | # However, in case of collaboration, if having platform-specific dependencies or dependencies
107 | # having no cross-platform support, pipenv may install dependencies that don't work, or not
108 | # install all needed dependencies.
109 | #Pipfile.lock
110 |
111 | # UV
112 | # Similar to Pipfile.lock, it is generally recommended to include uv.lock in version control.
113 | # This is especially recommended for binary packages to ensure reproducibility, and is more
114 | # commonly ignored for libraries.
115 | #uv.lock
116 |
117 | # poetry
118 | # Similar to Pipfile.lock, it is generally recommended to include poetry.lock in version control.
119 | # This is especially recommended for binary packages to ensure reproducibility, and is more
120 | # commonly ignored for libraries.
121 | # https://python-poetry.org/docs/basic-usage/#commit-your-poetrylock-file-to-version-control
122 | #poetry.lock
123 |
124 | # pdm
125 | # Similar to Pipfile.lock, it is generally recommended to include pdm.lock in version control.
126 | #pdm.lock
127 | # pdm stores project-wide configurations in .pdm.toml, but it is recommended to not include it
128 | # in version control.
129 | # https://pdm.fming.dev/latest/usage/project/#working-with-version-control
130 | .pdm.toml
131 | .pdm-python
132 | .pdm-build/
133 |
134 | # PEP 582; used by e.g. github.com/David-OConnor/pyflow and github.com/pdm-project/pdm
135 | __pypackages__/
136 |
137 | # Celery stuff
138 | celerybeat-schedule
139 | celerybeat.pid
140 |
141 | # SageMath parsed files
142 | *.sage.py
143 |
144 | # Environments
145 | .env
146 | .venv
147 | env/
148 | venv/
149 | ENV/
150 | env.bak/
151 | venv.bak/
152 |
153 | # Spyder project settings
154 | .spyderproject
155 | .spyproject
156 |
157 | # Rope project settings
158 | .ropeproject
159 |
160 | # mkdocs documentation
161 | /site
162 |
163 | # mypy
164 | .mypy_cache/
165 | .dmypy.json
166 | dmypy.json
167 |
168 | # Pyre type checker
169 | .pyre/
170 |
171 | # pytype static type analyzer
172 | .pytype/
173 |
174 | # Cython debug symbols
175 | cython_debug/
176 |
177 | # PyCharm
178 | # JetBrains specific template is maintained in a separate JetBrains.gitignore that can
179 | # be found at https://github.com/github/gitignore/blob/main/Global/JetBrains.gitignore
180 | # and can be added to the global gitignore or merged into this file. For a more nuclear
181 | # option (not recommended) you can uncomment the following to ignore the entire idea folder.
182 | #.idea/
183 |
184 | # Visual Studio Code
185 | # Visual Studio Code specific template is maintained in a separate VisualStudioCode.gitignore
186 | # that can be found at https://github.com/github/gitignore/blob/main/Global/VisualStudioCode.gitignore
187 | # and can be added to the global gitignore or merged into this file. However, if you prefer,
188 | # you could uncomment the following to ignore the enitre vscode folder
189 | # .vscode/
190 |
191 | # Ruff stuff:
192 | .ruff_cache/
193 |
194 | # PyPI configuration file
195 | .pypirc
196 |
197 | # Cursor
198 | # Cursor is an AI-powered code editor. `.cursorignore` specifies files/directories to
199 | # exclude from AI features like autocomplete and code analysis. Recommended for sensitive data
200 | # refer to https://docs.cursor.com/context/ignore-files
201 | .cursorignore
202 | .cursorindexingignore
203 |
204 | # History files
205 | .Rhistory
206 | .Rapp.history
207 |
208 | # Session Data files
209 | .RData
210 | .RDataTmp
211 |
212 | # User-specific files
213 | .Ruserdata
214 |
215 | # Example code in package build process
216 | *-Ex.R
217 |
218 | # Output files from R CMD build
219 | /*.tar.gz
220 |
221 | # Output files from R CMD check
222 | /*.Rcheck/
223 |
224 | # RStudio files
225 | .Rproj.user/
226 |
227 | # produced vignettes
228 | vignettes/*.html
229 | vignettes/*.pdf
230 |
231 | # OAuth2 token, see https://github.com/hadley/httr/releases/tag/v0.3
232 | .httr-oauth
233 |
234 | # knitr and R markdown default cache directories
235 | *_cache/
236 | /cache/
237 |
238 | # Temporary files created by R markdown
239 | *.utf8.md
240 | *.knit.md
241 |
242 | # R Environment Variables
243 | .Renviron
244 |
245 | # pkgdown site
246 | #docs/
247 |
248 | # translation temp files
249 | po/*~
250 |
251 | # RStudio Connect folder
252 | rsconnect/
253 | python-package/CLAUDE.md
254 |
255 | uv.lock
256 | _dev
257 |
258 | # R ignores
259 | /.quarto/
260 | .Rprofile
261 | renv/
262 | renv.lock
263 |
264 | # Claude
265 | .claude/settings.local.json
266 |
267 | /.luarc.json
268 |
--------------------------------------------------------------------------------
/pkg-r/man/DataFrameSource.Rd:
--------------------------------------------------------------------------------
1 | % Generated by roxygen2: do not edit by hand
2 | % Please edit documentation in R/DataSource.R
3 | \name{DataFrameSource}
4 | \alias{DataFrameSource}
5 | \title{Data Frame Source}
6 | \description{
7 | A DataSource implementation that wraps a data frame using DuckDB for SQL
8 | query execution.
9 | }
10 | \details{
11 | This class creates an in-memory DuckDB connection and registers the provided
12 | data frame as a table. All SQL queries are executed against this DuckDB table.
13 | }
14 | \examples{
15 | \dontrun{
16 | # Create a data frame source
17 | df_source <- DataFrameSource$new(mtcars, "mtcars")
18 |
19 | # Get database type
20 | df_source$get_db_type() # Returns "DuckDB"
21 |
22 | # Execute a query
23 | result <- df_source$execute_query("SELECT * FROM mtcars WHERE mpg > 25")
24 |
25 | # Clean up when done
26 | df_source$cleanup()
27 | }
28 |
29 | ## ------------------------------------------------
30 | ## Method `DataFrameSource$new`
31 | ## ------------------------------------------------
32 |
33 | \dontrun{
34 | source <- DataFrameSource$new(iris, "iris")
35 | }
36 | }
37 | \section{Super class}{
38 | \code{\link[querychat:DataSource]{querychat::DataSource}} -> \code{DataFrameSource}
39 | }
40 | \section{Methods}{
41 | \subsection{Public methods}{
42 | \itemize{
43 | \item \href{#method-DataFrameSource-new}{\code{DataFrameSource$new()}}
44 | \item \href{#method-DataFrameSource-get_db_type}{\code{DataFrameSource$get_db_type()}}
45 | \item \href{#method-DataFrameSource-get_schema}{\code{DataFrameSource$get_schema()}}
46 | \item \href{#method-DataFrameSource-execute_query}{\code{DataFrameSource$execute_query()}}
47 | \item \href{#method-DataFrameSource-test_query}{\code{DataFrameSource$test_query()}}
48 | \item \href{#method-DataFrameSource-get_data}{\code{DataFrameSource$get_data()}}
49 | \item \href{#method-DataFrameSource-cleanup}{\code{DataFrameSource$cleanup()}}
50 | \item \href{#method-DataFrameSource-clone}{\code{DataFrameSource$clone()}}
51 | }
52 | }
53 | \if{html}{\out{
}}
54 | \if{html}{\out{}}
55 | \if{latex}{\out{\hypertarget{method-DataFrameSource-new}{}}}
56 | \subsection{Method \code{new()}}{
57 | Create a new DataFrameSource
58 | \subsection{Usage}{
59 | \if{html}{\out{}}\preformatted{DataFrameSource$new(df, table_name)}\if{html}{\out{
}}
60 | }
61 |
62 | \subsection{Arguments}{
63 | \if{html}{\out{}}
64 | \describe{
65 | \item{\code{df}}{A data frame.}
66 |
67 | \item{\code{table_name}}{Name to use for the table in SQL queries. Must be a
68 | valid table name (start with letter, contain only letters, numbers,
69 | and underscores)}
70 | }
71 | \if{html}{\out{
}}
72 | }
73 | \subsection{Returns}{
74 | A new DataFrameSource object
75 | }
76 | \subsection{Examples}{
77 | \if{html}{\out{}}
78 | \preformatted{\dontrun{
79 | source <- DataFrameSource$new(iris, "iris")
80 | }
81 | }
82 | \if{html}{\out{
}}
83 |
84 | }
85 |
86 | }
87 | \if{html}{\out{
}}
88 | \if{html}{\out{}}
89 | \if{latex}{\out{\hypertarget{method-DataFrameSource-get_db_type}{}}}
90 | \subsection{Method \code{get_db_type()}}{
91 | Get the database type
92 | \subsection{Usage}{
93 | \if{html}{\out{}}\preformatted{DataFrameSource$get_db_type()}\if{html}{\out{
}}
94 | }
95 |
96 | \subsection{Returns}{
97 | The string "DuckDB"
98 | }
99 | }
100 | \if{html}{\out{
}}
101 | \if{html}{\out{}}
102 | \if{latex}{\out{\hypertarget{method-DataFrameSource-get_schema}{}}}
103 | \subsection{Method \code{get_schema()}}{
104 | Get schema information for the data frame
105 | \subsection{Usage}{
106 | \if{html}{\out{}}\preformatted{DataFrameSource$get_schema(categorical_threshold = 20)}\if{html}{\out{
}}
107 | }
108 |
109 | \subsection{Arguments}{
110 | \if{html}{\out{}}
111 | \describe{
112 | \item{\code{categorical_threshold}}{Maximum number of unique values for a text
113 | column to be considered categorical (default: 20)}
114 | }
115 | \if{html}{\out{
}}
116 | }
117 | \subsection{Returns}{
118 | A string describing the schema
119 | }
120 | }
121 | \if{html}{\out{
}}
122 | \if{html}{\out{}}
123 | \if{latex}{\out{\hypertarget{method-DataFrameSource-execute_query}{}}}
124 | \subsection{Method \code{execute_query()}}{
125 | Execute a SQL query
126 | \subsection{Usage}{
127 | \if{html}{\out{}}\preformatted{DataFrameSource$execute_query(query)}\if{html}{\out{
}}
128 | }
129 |
130 | \subsection{Arguments}{
131 | \if{html}{\out{}}
132 | \describe{
133 | \item{\code{query}}{SQL query string. If NULL or empty, returns all data}
134 | }
135 | \if{html}{\out{
}}
136 | }
137 | \subsection{Returns}{
138 | A data frame with query results
139 | }
140 | }
141 | \if{html}{\out{
}}
142 | \if{html}{\out{}}
143 | \if{latex}{\out{\hypertarget{method-DataFrameSource-test_query}{}}}
144 | \subsection{Method \code{test_query()}}{
145 | Test a SQL query by fetching only one row
146 | \subsection{Usage}{
147 | \if{html}{\out{}}\preformatted{DataFrameSource$test_query(query)}\if{html}{\out{
}}
148 | }
149 |
150 | \subsection{Arguments}{
151 | \if{html}{\out{}}
152 | \describe{
153 | \item{\code{query}}{SQL query string}
154 | }
155 | \if{html}{\out{
}}
156 | }
157 | \subsection{Returns}{
158 | A data frame with one row of results
159 | }
160 | }
161 | \if{html}{\out{
}}
162 | \if{html}{\out{}}
163 | \if{latex}{\out{\hypertarget{method-DataFrameSource-get_data}{}}}
164 | \subsection{Method \code{get_data()}}{
165 | Get all data from the table
166 | \subsection{Usage}{
167 | \if{html}{\out{}}\preformatted{DataFrameSource$get_data()}\if{html}{\out{
}}
168 | }
169 |
170 | \subsection{Returns}{
171 | A data frame containing all data
172 | }
173 | }
174 | \if{html}{\out{
}}
175 | \if{html}{\out{}}
176 | \if{latex}{\out{\hypertarget{method-DataFrameSource-cleanup}{}}}
177 | \subsection{Method \code{cleanup()}}{
178 | Close the DuckDB connection
179 | \subsection{Usage}{
180 | \if{html}{\out{}}\preformatted{DataFrameSource$cleanup()}\if{html}{\out{
}}
181 | }
182 |
183 | \subsection{Returns}{
184 | NULL (invisibly)
185 | }
186 | }
187 | \if{html}{\out{
}}
188 | \if{html}{\out{}}
189 | \if{latex}{\out{\hypertarget{method-DataFrameSource-clone}{}}}
190 | \subsection{Method \code{clone()}}{
191 | The objects of this class are cloneable with this method.
192 | \subsection{Usage}{
193 | \if{html}{\out{}}\preformatted{DataFrameSource$clone(deep = FALSE)}\if{html}{\out{
}}
194 | }
195 |
196 | \subsection{Arguments}{
197 | \if{html}{\out{}}
198 | \describe{
199 | \item{\code{deep}}{Whether to make a deep clone.}
200 | }
201 | \if{html}{\out{
}}
202 | }
203 | }
204 | }
205 |
--------------------------------------------------------------------------------
/pkg-py/src/querychat/_querychat_module.py:
--------------------------------------------------------------------------------
1 | from __future__ import annotations
2 |
3 | import copy
4 | import warnings
5 | from dataclasses import dataclass
6 | from pathlib import Path
7 | from typing import TYPE_CHECKING, Union
8 |
9 | import shinychat
10 | from shiny import module, reactive, ui
11 |
12 | from .tools import tool_query, tool_reset_dashboard, tool_update_dashboard
13 |
14 | if TYPE_CHECKING:
15 | from collections.abc import Callable
16 |
17 | import chatlas
18 | import pandas as pd
19 | from shiny import Inputs, Outputs, Session
20 | from shiny.bookmark import BookmarkState, RestoreState
21 |
22 | from ._datasource import DataSource
23 |
24 | ReactiveString = reactive.Value[str]
25 | """A reactive string value."""
26 | ReactiveStringOrNone = reactive.Value[Union[str, None]]
27 | """A reactive string (or None) value."""
28 |
29 | CHAT_ID = "chat"
30 |
31 |
32 | @module.ui
33 | def mod_ui(**kwargs):
34 | css_path = Path(__file__).parent / "static" / "css" / "styles.css"
35 | js_path = Path(__file__).parent / "static" / "js" / "querychat.js"
36 |
37 | tag = shinychat.chat_ui(CHAT_ID, **kwargs)
38 | tag.add_class("querychat")
39 |
40 | return ui.TagList(
41 | ui.head_content(
42 | ui.include_css(css_path),
43 | ui.include_js(js_path),
44 | ),
45 | tag,
46 | )
47 |
48 |
49 | @dataclass
50 | class ServerValues:
51 | """
52 | Session-specific reactive values and client returned by QueryChat.server().
53 |
54 | This dataclass contains all the session-specific reactive state for a QueryChat
55 | instance. Each session gets its own ServerValues to ensure proper isolation
56 | between concurrent sessions.
57 |
58 | Attributes
59 | ----------
60 | df
61 | A reactive Calc that returns the current filtered data frame. If no SQL
62 | query has been set, this returns the unfiltered data from the data source.
63 | Call it like `.df()` to reactively read the current data frame.
64 | sql
65 | A reactive Value containing the current SQL query string. Access the value
66 | by calling `.sql()`, or set it with `.sql.set("SELECT ...")`.
67 | Returns `None` if no query has been set.
68 | title
69 | A reactive Value containing the current title for the query. The LLM
70 | provides this title when generating a new SQL query. Access it with
71 | `.title()`, or set it with `.title.set("...")`. Returns
72 | `None` if no title has been set.
73 | client
74 | The session-specific chat client instance. This is a deep copy of the
75 | base client configured for this specific session, containing the chat
76 | history and tool registrations for this session only.
77 |
78 | """
79 |
80 | df: Callable[[], pd.DataFrame]
81 | sql: ReactiveStringOrNone
82 | title: ReactiveStringOrNone
83 | client: chatlas.Chat
84 |
85 |
86 | @module.server
87 | def mod_server(
88 | input: Inputs,
89 | output: Outputs,
90 | session: Session,
91 | *,
92 | data_source: DataSource,
93 | greeting: str | None,
94 | client: chatlas.Chat,
95 | enable_bookmarking: bool,
96 | ):
97 | # Reactive values to store state
98 | sql = ReactiveStringOrNone(None)
99 | title = ReactiveStringOrNone(None)
100 | has_greeted = reactive.value[bool](False) # noqa: FBT003
101 |
102 | # Set up the chat object for this session
103 | chat = copy.deepcopy(client)
104 |
105 | # Create the tool functions
106 | update_dashboard_tool = tool_update_dashboard(data_source, sql, title)
107 | reset_dashboard_tool = tool_reset_dashboard(sql, title)
108 | query_tool = tool_query(data_source)
109 |
110 | # Register tools with annotations for the UI
111 | chat.register_tool(update_dashboard_tool)
112 | chat.register_tool(query_tool)
113 | chat.register_tool(reset_dashboard_tool)
114 |
115 | # Execute query when SQL changes
116 | @reactive.calc
117 | def filtered_df():
118 | query = sql.get()
119 | if not query:
120 | return data_source.get_data()
121 | else:
122 | return data_source.execute_query(query)
123 |
124 | # Chat UI logic
125 | chat_ui = shinychat.Chat(CHAT_ID)
126 |
127 | # Handle user input
128 | @chat_ui.on_user_submit
129 | async def _(user_input: str):
130 | stream = await chat.stream_async(user_input, echo="none", content="all")
131 | await chat_ui.append_message_stream(stream)
132 |
133 | @reactive.effect
134 | async def greet_on_startup():
135 | if has_greeted():
136 | return
137 |
138 | if greeting:
139 | await chat_ui.append_message(greeting)
140 | elif greeting is None:
141 | warnings.warn(
142 | "No greeting provided to `QueryChat()`. Using the LLM `client` to generate one now. "
143 | "For faster startup, lower cost, and determinism, consider providing a greeting "
144 | "to `QueryChat()` and `.generate_greeting()` to generate one beforehand.",
145 | GreetWarning,
146 | stacklevel=2,
147 | )
148 | stream = await chat.stream_async(GREETING_PROMPT, echo="none")
149 | await chat_ui.append_message_stream(stream)
150 |
151 | has_greeted.set(True)
152 |
153 | # Handle update button clicks
154 | @reactive.effect
155 | @reactive.event(input.chat_update)
156 | def _():
157 | update = input.chat_update()
158 | if update is None:
159 | return
160 | if not isinstance(update, dict):
161 | return
162 |
163 | new_query = update.get("query")
164 | new_title = update.get("title")
165 | if new_query is not None:
166 | sql.set(new_query)
167 | if new_title is not None:
168 | title.set(new_title)
169 |
170 | if enable_bookmarking:
171 | chat_ui.enable_bookmarking(client)
172 |
173 | @session.bookmark.on_bookmark
174 | def _on_bookmark(x: BookmarkState) -> None:
175 | vals = x.values # noqa: PD011
176 | vals["querychat_sql"] = sql.get()
177 | vals["querychat_title"] = title.get()
178 | vals["querychat_has_greeted"] = has_greeted.get()
179 |
180 | @session.bookmark.on_restore
181 | def _on_restore(x: RestoreState) -> None:
182 | vals = x.values # noqa: PD011
183 | if "querychat_sql" in vals:
184 | sql.set(vals["querychat_sql"])
185 | if "querychat_title" in vals:
186 | title.set(vals["querychat_title"])
187 | if "querychat_has_greeted" in vals:
188 | has_greeted.set(vals["querychat_has_greeted"])
189 |
190 | return ServerValues(df=filtered_df, sql=sql, title=title, client=chat)
191 |
192 |
193 | GREETING_PROMPT: str = "Please give me a friendly greeting. Include a few sample prompts in a two-level bulleted list."
194 |
195 |
196 | class GreetWarning(Warning):
197 | """Warning raised when no greeting is provided to QueryChat."""
198 |
--------------------------------------------------------------------------------
/pkg-r/man/DBISource.Rd:
--------------------------------------------------------------------------------
1 | % Generated by roxygen2: do not edit by hand
2 | % Please edit documentation in R/DataSource.R
3 | \name{DBISource}
4 | \alias{DBISource}
5 | \title{DBI Source}
6 | \description{
7 | A DataSource implementation for DBI database connections (SQLite, PostgreSQL,
8 | MySQL, etc.).
9 | }
10 | \details{
11 | This class wraps a DBI connection and provides SQL query execution against
12 | a specified table in the database.
13 | }
14 | \examples{
15 | \dontrun{
16 | # Connect to a database
17 | conn <- DBI::dbConnect(RSQLite::SQLite(), ":memory:")
18 | DBI::dbWriteTable(conn, "mtcars", mtcars)
19 |
20 | # Create a DBI source
21 | db_source <- DBISource$new(conn, "mtcars")
22 |
23 | # Get database type
24 | db_source$get_db_type() # Returns "SQLite"
25 |
26 | # Execute a query
27 | result <- db_source$execute_query("SELECT * FROM mtcars WHERE mpg > 25")
28 |
29 | # Note: cleanup() will disconnect the connection
30 | # If you want to keep the connection open, don't call cleanup()
31 | }
32 |
33 | ## ------------------------------------------------
34 | ## Method `DBISource$new`
35 | ## ------------------------------------------------
36 |
37 | \dontrun{
38 | conn <- DBI::dbConnect(RSQLite::SQLite(), ":memory:")
39 | DBI::dbWriteTable(conn, "iris", iris)
40 | source <- DBISource$new(conn, "iris")
41 | }
42 | }
43 | \section{Super class}{
44 | \code{\link[querychat:DataSource]{querychat::DataSource}} -> \code{DBISource}
45 | }
46 | \section{Methods}{
47 | \subsection{Public methods}{
48 | \itemize{
49 | \item \href{#method-DBISource-new}{\code{DBISource$new()}}
50 | \item \href{#method-DBISource-get_db_type}{\code{DBISource$get_db_type()}}
51 | \item \href{#method-DBISource-get_schema}{\code{DBISource$get_schema()}}
52 | \item \href{#method-DBISource-execute_query}{\code{DBISource$execute_query()}}
53 | \item \href{#method-DBISource-test_query}{\code{DBISource$test_query()}}
54 | \item \href{#method-DBISource-get_data}{\code{DBISource$get_data()}}
55 | \item \href{#method-DBISource-cleanup}{\code{DBISource$cleanup()}}
56 | \item \href{#method-DBISource-clone}{\code{DBISource$clone()}}
57 | }
58 | }
59 | \if{html}{\out{
}}
60 | \if{html}{\out{}}
61 | \if{latex}{\out{\hypertarget{method-DBISource-new}{}}}
62 | \subsection{Method \code{new()}}{
63 | Create a new DBISource
64 | \subsection{Usage}{
65 | \if{html}{\out{}}\preformatted{DBISource$new(conn, table_name)}\if{html}{\out{
}}
66 | }
67 |
68 | \subsection{Arguments}{
69 | \if{html}{\out{}}
70 | \describe{
71 | \item{\code{conn}}{A DBI connection object}
72 |
73 | \item{\code{table_name}}{Name of the table in the database. Can be a character
74 | string or a \code{\link[DBI:Id]{DBI::Id()}} object for tables in catalogs/schemas}
75 | }
76 | \if{html}{\out{
}}
77 | }
78 | \subsection{Returns}{
79 | A new DBISource object
80 | }
81 | \subsection{Examples}{
82 | \if{html}{\out{}}
83 | \preformatted{\dontrun{
84 | conn <- DBI::dbConnect(RSQLite::SQLite(), ":memory:")
85 | DBI::dbWriteTable(conn, "iris", iris)
86 | source <- DBISource$new(conn, "iris")
87 | }
88 | }
89 | \if{html}{\out{
}}
90 |
91 | }
92 |
93 | }
94 | \if{html}{\out{
}}
95 | \if{html}{\out{}}
96 | \if{latex}{\out{\hypertarget{method-DBISource-get_db_type}{}}}
97 | \subsection{Method \code{get_db_type()}}{
98 | Get the database type
99 | \subsection{Usage}{
100 | \if{html}{\out{}}\preformatted{DBISource$get_db_type()}\if{html}{\out{
}}
101 | }
102 |
103 | \subsection{Returns}{
104 | A string identifying the database type
105 | }
106 | }
107 | \if{html}{\out{
}}
108 | \if{html}{\out{}}
109 | \if{latex}{\out{\hypertarget{method-DBISource-get_schema}{}}}
110 | \subsection{Method \code{get_schema()}}{
111 | Get schema information for the database table
112 | \subsection{Usage}{
113 | \if{html}{\out{}}\preformatted{DBISource$get_schema(categorical_threshold = 20)}\if{html}{\out{
}}
114 | }
115 |
116 | \subsection{Arguments}{
117 | \if{html}{\out{}}
118 | \describe{
119 | \item{\code{categorical_threshold}}{Maximum number of unique values for a text
120 | column to be considered categorical (default: 20)}
121 | }
122 | \if{html}{\out{
}}
123 | }
124 | \subsection{Returns}{
125 | A string describing the schema
126 | }
127 | }
128 | \if{html}{\out{
}}
129 | \if{html}{\out{}}
130 | \if{latex}{\out{\hypertarget{method-DBISource-execute_query}{}}}
131 | \subsection{Method \code{execute_query()}}{
132 | Execute a SQL query
133 | \subsection{Usage}{
134 | \if{html}{\out{}}\preformatted{DBISource$execute_query(query)}\if{html}{\out{
}}
135 | }
136 |
137 | \subsection{Arguments}{
138 | \if{html}{\out{}}
139 | \describe{
140 | \item{\code{query}}{SQL query string. If NULL or empty, returns all data}
141 | }
142 | \if{html}{\out{
}}
143 | }
144 | \subsection{Returns}{
145 | A data frame with query results
146 | }
147 | }
148 | \if{html}{\out{
}}
149 | \if{html}{\out{}}
150 | \if{latex}{\out{\hypertarget{method-DBISource-test_query}{}}}
151 | \subsection{Method \code{test_query()}}{
152 | Test a SQL query by fetching only one row
153 | \subsection{Usage}{
154 | \if{html}{\out{}}\preformatted{DBISource$test_query(query)}\if{html}{\out{
}}
155 | }
156 |
157 | \subsection{Arguments}{
158 | \if{html}{\out{}}
159 | \describe{
160 | \item{\code{query}}{SQL query string}
161 | }
162 | \if{html}{\out{
}}
163 | }
164 | \subsection{Returns}{
165 | A data frame with one row of results
166 | }
167 | }
168 | \if{html}{\out{
}}
169 | \if{html}{\out{}}
170 | \if{latex}{\out{\hypertarget{method-DBISource-get_data}{}}}
171 | \subsection{Method \code{get_data()}}{
172 | Get all data from the table
173 | \subsection{Usage}{
174 | \if{html}{\out{}}\preformatted{DBISource$get_data()}\if{html}{\out{
}}
175 | }
176 |
177 | \subsection{Returns}{
178 | A data frame containing all data
179 | }
180 | }
181 | \if{html}{\out{
}}
182 | \if{html}{\out{}}
183 | \if{latex}{\out{\hypertarget{method-DBISource-cleanup}{}}}
184 | \subsection{Method \code{cleanup()}}{
185 | Disconnect from the database
186 | \subsection{Usage}{
187 | \if{html}{\out{}}\preformatted{DBISource$cleanup()}\if{html}{\out{
}}
188 | }
189 |
190 | \subsection{Returns}{
191 | NULL (invisibly)
192 | }
193 | }
194 | \if{html}{\out{
}}
195 | \if{html}{\out{}}
196 | \if{latex}{\out{\hypertarget{method-DBISource-clone}{}}}
197 | \subsection{Method \code{clone()}}{
198 | The objects of this class are cloneable with this method.
199 | \subsection{Usage}{
200 | \if{html}{\out{}}\preformatted{DBISource$clone(deep = FALSE)}\if{html}{\out{
}}
201 | }
202 |
203 | \subsection{Arguments}{
204 | \if{html}{\out{}}
205 | \describe{
206 | \item{\code{deep}}{Whether to make a deep clone.}
207 | }
208 | \if{html}{\out{
}}
209 | }
210 | }
211 | }
212 |
--------------------------------------------------------------------------------