Skip to content

Commit ba8dda8

Browse files
authored
feat: Rename prompt_path to prompt_template. Add R support for reading system prompt parameters (#45)
1 parent f838f16 commit ba8dda8

File tree

6 files changed

+101
-70
lines changed

6 files changed

+101
-70
lines changed

pkg-py/src/querychat/querychat.py

Lines changed: 18 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -139,7 +139,7 @@ def system_prompt(
139139
data_description: Optional[str | Path] = None,
140140
extra_instructions: Optional[str | Path] = None,
141141
categorical_threshold: int = 10,
142-
prompt_path: Optional[Path] = None,
142+
prompt_template: Optional[str | Path] = None,
143143
) -> str:
144144
"""
145145
Create a system prompt for the chat model based on a data source's schema
@@ -157,8 +157,8 @@ def system_prompt(
157157
categorical_threshold : int, default=10
158158
Threshold for determining if a column is categorical based on number of
159159
unique values
160-
prompt_path
161-
Optional `Path` to a custom prompt file. If not provided, the default
160+
prompt_template
161+
Optional `Path` to or string of a custom prompt template. If not provided, the default
162162
querychat template will be used.
163163
164164
Returns
@@ -168,27 +168,30 @@ def system_prompt(
168168
169169
"""
170170
# Read the prompt file
171-
if prompt_path is None:
171+
if prompt_template is None:
172172
# Default to the prompt file in the same directory as this module
173173
# This allows for easy customization by placing a different prompt.md file there
174-
prompt_path = Path(__file__).parent / "prompt" / "prompt.md"
175-
176-
prompt_text = prompt_path.read_text()
174+
prompt_template = Path(__file__).parent / "prompt" / "prompt.md"
175+
prompt_str = (
176+
prompt_template.read_text()
177+
if isinstance(prompt_template, Path)
178+
else prompt_template
179+
)
177180

178-
data_description_str: str | None = (
181+
data_description_str = (
179182
data_description.read_text()
180183
if isinstance(data_description, Path)
181184
else data_description
182185
)
183186

184-
extra_instructions_str: str | None = (
187+
extra_instructions_str = (
185188
extra_instructions.read_text()
186189
if isinstance(extra_instructions, Path)
187190
else extra_instructions
188191
)
189192

190193
return chevron.render(
191-
prompt_text,
194+
prompt_str,
192195
{
193196
"db_engine": data_source.db_engine,
194197
"schema": data_source.get_schema(
@@ -244,7 +247,7 @@ def init(
244247
greeting: Optional[str | Path] = None,
245248
data_description: Optional[str | Path] = None,
246249
extra_instructions: Optional[str | Path] = None,
247-
prompt_path: Optional[Path] = None,
250+
prompt_template: Optional[str | Path] = None,
248251
system_prompt_override: Optional[str] = None,
249252
create_chat_callback: Optional[CreateChatCallback] = None,
250253
) -> QueryChatConfig:
@@ -273,8 +276,8 @@ def init(
273276
Additional instructions for the chat model.
274277
If a pathlib.Path object is passed,
275278
querychat will read the contents of the path into a string with `.read_text()`.
276-
prompt_path : Path, optional
277-
Path to a custom prompt file. If not provided, the default querychat
279+
prompt_template : Path, optional
280+
Path to or a string of a custom prompt file. If not provided, the default querychat
278281
template will be used. This should be a Markdown file that contains the
279282
system prompt template. The mustache template can use the following
280283
variables:
@@ -285,7 +288,7 @@ def init(
285288
- `{{extra_instructions}}`: Any additional instructions provided
286289
system_prompt_override : str, optional
287290
A custom system prompt to use instead of the default. If provided,
288-
`data_description`, `extra_instructions`, and `prompt_path` will be
291+
`data_description`, `extra_instructions`, and `prompt_template` will be
289292
silently ignored.
290293
create_chat_callback : CreateChatCallback, optional
291294
A function that creates a chat object
@@ -331,7 +334,7 @@ def init(
331334
data_source_obj,
332335
data_description=data_description,
333336
extra_instructions=extra_instructions,
334-
prompt_path=prompt_path,
337+
prompt_template=prompt_template,
335338
)
336339

337340
# Default chat function if none provided

pkg-r/NEWS.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,4 +2,4 @@
22

33
* Initial CRAN submission.
44

5-
* Added `prompt_path` support for `querychat_system_prompt()`. (Thank you, @oacar! #37)
5+
* Added `prompt_template` support for `querychat_system_prompt()`. (Thank you, @oacar! #37, #45)

pkg-r/R/prompt.R

Lines changed: 42 additions & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -5,48 +5,47 @@
55
#'
66
#' @param df A data frame to generate schema information from.
77
#' @param table_name A string containing the name of the table in SQL queries.
8-
#' @param data_description Optional string in plain text or Markdown format, containing
9-
#' a description of the data frame or any additional context that might be
10-
#' helpful in understanding the data. This will be included in the system
11-
#' prompt for the chat model.
12-
#' @param extra_instructions Optional string in plain text or Markdown format, containing
13-
#' any additional instructions for the chat model. These will be appended at
14-
#' the end of the system prompt.
15-
#' @param categorical_threshold The maximum number of unique values for a text column to be considered categorical.
16-
#' @param prompt_path Optional string containing the path to a custom prompt file. If
17-
#' `NULL`, the default prompt file in the package will be used. This file should
18-
#' contain a whisker template for the system prompt, with placeholders for `{{schema}}`,
19-
#' `{{data_description}}`, and `{{extra_instructions}}`.
8+
#' @param data_description Optional string or existing file path. The contents
9+
#' should be in plain text or Markdown format, containing a description of the
10+
#' data frame or any additional context that might be helpful in understanding
11+
#' the data. This will be included in the system prompt for the chat model.
12+
#' @param extra_instructions Optional string or existing file path. The contents
13+
#' should be in plain text or Markdown format, containing any additional
14+
#' instructions for the chat model. These will be appended at the end of the
15+
#' system prompt.
16+
#' @param prompt_template Optional string or existing file path. If `NULL`, the
17+
#' default prompt file in the package will be used. The contents should
18+
#' contain a whisker template for the system prompt, with placeholders for
19+
#' `{{schema}}`, `{{data_description}}`, and `{{extra_instructions}}`.
20+
#' @param categorical_threshold The maximum number of unique values for a text
21+
#' column to be considered categorical.
22+
#' @param ... Ignored. Used to allow for future parameters.
2023
#'
2124
#' @return A string containing the system prompt for the chat model.
2225
#'
2326
#' @export
2427
querychat_system_prompt <- function(
2528
df,
2629
table_name,
30+
...,
2731
data_description = NULL,
2832
extra_instructions = NULL,
29-
categorical_threshold = 10,
30-
prompt_path = system.file("prompt", "prompt.md", package = "querychat")
33+
prompt_template = NULL,
34+
categorical_threshold = 10
3135
) {
32-
schema <- df_to_schema(df, table_name, categorical_threshold)
36+
rlang::check_dots_empty()
3337

34-
if (!is.null(data_description)) {
35-
data_description <- paste(data_description, collapse = "\n")
36-
}
37-
if (!is.null(extra_instructions)) {
38-
extra_instructions <- paste(extra_instructions, collapse = "\n")
39-
}
38+
schema <- df_to_schema(df, table_name, categorical_threshold)
4039

41-
# Read the prompt file
42-
if (is.null(prompt_path)) {
43-
prompt_path <- system.file("prompt", "prompt.md", package = "querychat")
44-
}
45-
if (!file.exists(prompt_path)) {
46-
stop("Prompt file not found at: ", prompt_path)
40+
data_description <- read_path_or_string(data_description, "data_description")
41+
extra_instructions <- read_path_or_string(
42+
extra_instructions,
43+
"extra_instructions"
44+
)
45+
if (is.null(prompt_template)) {
46+
prompt_template <- system.file("prompt", "prompt.md", package = "querychat")
4747
}
48-
prompt_content <- readLines(prompt_path, warn = FALSE)
49-
prompt_text <- paste(prompt_content, collapse = "\n")
48+
prompt_text <- read_path_or_string(prompt_template, "prompt_template")
5049

5150
processed_template <-
5251
whisker::whisker.render(
@@ -63,6 +62,20 @@ querychat_system_prompt <- function(
6362
processed_template
6463
}
6564

65+
read_path_or_string <- function(x, name) {
66+
if (is.null(x)) {
67+
return(NULL)
68+
}
69+
if (!is.character(x)) {
70+
stop(sprintf("`%s=` must be a string or a path to a file.", name))
71+
}
72+
if (file.exists(x)) {
73+
x <- readLines(x, warn = FALSE)
74+
}
75+
return(paste(x, collapse = "\n"))
76+
}
77+
78+
6679
#' Generate a schema description from a data frame
6780
#'
6881
#' This function generates a schema description for a data frame, including

pkg-r/R/querychat.R

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,7 @@
1212
#' to display to the user upon first loading the chatbot. If not provided, the
1313
#' LLM will be invoked at the start of the conversation to generate one.
1414
#' @param ... Additional arguments passed to the `querychat_system_prompt()`
15-
#' function, such as `categorical_threshold`, and `prompt_path`. If a
15+
#' function, such as `categorical_threshold`. If a
1616
#' `system_prompt` argument is provided, the `...` arguments will be silently
1717
#' ignored.
1818
#' @inheritParams querychat_system_prompt
@@ -34,13 +34,15 @@ querychat_init <- function(
3434
greeting = NULL,
3535
data_description = NULL,
3636
extra_instructions = NULL,
37+
prompt_template = NULL,
3738
system_prompt = querychat_system_prompt(
3839
df,
3940
table_name,
4041
# By default, pass through any params supplied to querychat_init()
4142
...,
4243
data_description = data_description,
43-
extra_instructions = extra_instructions
44+
extra_instructions = extra_instructions,
45+
prompt_template = prompt_template
4446
),
4547
create_chat_func = purrr::partial(ellmer::chat_openai, model = "gpt-4o")
4648
) {

pkg-r/man/querychat_init.Rd

Lines changed: 17 additions & 9 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

pkg-r/man/querychat_system_prompt.Rd

Lines changed: 19 additions & 14 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

0 commit comments

Comments
 (0)