Skip to content

Commit

Permalink
Merge pull request #99 from zacdav-db/databricks-support
Browse files Browse the repository at this point in the history
Support Databricks foundational models APIs
  • Loading branch information
edgararuiz authored May 7, 2024
2 parents 87c74c7 + cb6a8b4 commit c34c505
Show file tree
Hide file tree
Showing 14 changed files with 583 additions and 44 deletions.
2 changes: 2 additions & 0 deletions NAMESPACE
Original file line number Diff line number Diff line change
@@ -1,7 +1,9 @@
# Generated by roxygen2: do not edit by hand

S3method(app_init_message,ch_databricks)
S3method(app_init_message,ch_openai)
S3method(app_init_message,default)
S3method(ch_submit,ch_databricks)
S3method(ch_submit,ch_llamagpt)
S3method(ch_submit,ch_openai)
S3method(ch_submit,ch_test_backend)
Expand Down
5 changes: 5 additions & 0 deletions NEWS.md
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,11 @@
* Fixes how it identifies the user's current UI (console, app, notebook) and
appropriately outputs the response from the model end-point (#92)

## Databricks

* Adding support for Databricks foundation model API (DBRX, Meta Llama 3 70B,
Mixtral 8x7B) (#99)

## OpenAI

* Fixes how it displays error from the model end-point when being used in a
Expand Down
139 changes: 139 additions & 0 deletions R/backend-databricks.R
Original file line number Diff line number Diff line change
@@ -0,0 +1,139 @@
#' @export
ch_submit.ch_databricks <- function(
defaults,
prompt = NULL,
stream = NULL,
prompt_build = TRUE,
preview = FALSE,
...) {
if (prompt_build) {
# re-use OpenAI prompt
prompt <- ch_openai_prompt(defaults, prompt)
}
ret <- NULL
if (preview) {
ret <- prompt
} else {
ret <- ch_databricks_complete(
prompt = prompt,
defaults = defaults
)
}
ret
}


ch_databricks_complete <- function(prompt, defaults, stream = TRUE) {
ret <- NULL
req_body <- c(
list(messages = prompt),
defaults$model_arguments
)

token <- ch_databricks_token(defaults)
host <- ch_databricks_host(defaults)
user_agent <-paste0("chattr/", utils::packageVersion('chattr'))

req_result <- host %>%
request() %>%
req_url_path_append(defaults$path) %>%
req_url_path_append(defaults$model) %>%
req_url_path_append("invocations") %>%
req_auth_bearer_token(token) %>%
req_user_agent(user_agent) %>%
req_body_json(req_body)

req_result <- req_result %>%
req_perform_stream(
function(x) {
char_x <- rawToChar(x)
ret <<- paste0(ret, char_x)
# print(ret)
cat(ch_openai_parse(char_x, defaults))
TRUE
},
buffer_kb = 0.05, round = "line"
)
ret <- ch_openai_parse(ret, defaults)
if (req_result$status_code != 200) {
ch_openai_error(ret, use_abort = FALSE)
if (inherits(req_result, "httr2_response")) {
req_result <- paste0(
resp_status(req_result),
" - ",
resp_status_desc(req_result)
)
}
if (!inherits(req_result, "character")) {
req_result <- "Undefined error"
}
cli_abort(req_result, call = NULL)
}
ch_openai_error(ret)
ret
}

ch_databricks_token <- function(defaults, fail = TRUE) {
env_key <- Sys.getenv("DATABRICKS_TOKEN", unset = NA)
ret <- NULL
if (!is.na(env_key)) {
ret <- env_key
}
if (is.null(ret) && file_exists(Sys.getenv("R_CONFIG_FILE", "config.yml"))) {
ret <- config::get("databricks-token")
}
if (is.null(ret) && fail) {
abort(
"No token found
- Add your key to the \"DATABRICKS_TOKEN\" environment variable
- or - Add \"databricks-token\" to a `config` YAML file"
)
}
ret
}

ch_databricks_host <- function(defaults, fail = TRUE) {
env_key <- Sys.getenv("DATABRICKS_HOST", unset = NA)
ret <- NULL
if (!is.na(env_key)) {
ret <- env_key
}
if (is.null(ret) && file_exists(Sys.getenv("R_CONFIG_FILE", "config.yml"))) {
ret <- config::get("databricks-host")
}
if (is.null(ret) && fail) {
abort(
"No host found
- Add your workspace url to the \"DATABRICKS_HOST\" environment variable
- or - Add \"databricks-host\" to a `config` YAML file"
)
}
ret
}

#' @export
app_init_message.ch_databricks <- function(defaults) {
print_provider(defaults)
if (defaults$max_data_files > 0) {
cli_alert_warning(
paste0(
"A list of the top {defaults$max_data_files} files will ",
"be sent externally to Databricks with every request\n",
"To avoid this, set the number of files to be sent to 0 ",
"using {.run chattr::chattr_defaults(max_data_files = 0)}"
)
)
}

if (defaults$max_data_frames > 0) {
cli_alert_warning(
paste0(
"A list of the top {defaults$max_data_frames} data.frames ",
"currently in your R session will be sent externally to ",
"Databricks with every request\n To avoid this, set the number ",
"of data.frames to be sent to 0 using ",
"{.run chattr::chattr_defaults(max_data_frames = 0)}"
)
)
}
}
16 changes: 15 additions & 1 deletion R/chattr-use.R
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
#' Sets the LLM model to use in your session
#' @param x The label of the LLM model to use, or the path of a valid YAML
#' default file . Valid values are 'copilot', 'gpt4', 'gpt35', and 'llamagpt'.
#' default file . Valid values are 'copilot', 'gpt4', 'gpt35', 'llamagpt',
#' 'databricks-dbrx', 'databricks-meta-llama3-70b', and 'databricks-mixtral8x7b'.
#' The value 'test' is also acceptable, but it is meant for package examples,
#' and internal testing.
#' @param ... Default values to modify.
Expand All @@ -18,6 +19,9 @@
#' R. `chattr` will look for the default location where RStudio saves the
#' Copilot authentication information.
#'
#' * Databricks - `chattr` checks for presence of R user's Databricks host and
#' token ('DATABRICKS_HOST' and 'DATABRICKS TOKEN' environment variables).
#'
#' Use the 'CHATTR_MODEL' environment variable to set it for the
#' R session, or create a YAML file named 'chattr.yml' in your working directory
#' to control the model, and the defaults it will use to communicate with such
Expand Down Expand Up @@ -55,6 +59,10 @@ ch_get_ymls <- function(menu = TRUE) {
gpt_token <- ch_openai_token(fail = FALSE)
gpt_exists <- !is.null(gpt_token)

dbrx_token <- ch_databricks_token(fail = FALSE)
dbrx_host <- ch_databricks_host(fail = FALSE)
dbrx_exists <- !is.null(dbrx_token) && !is.null(dbrx_host)

llama_defaults <- "configs/llamagpt.yml" %>%
package_file() %>%
read_yaml()
Expand Down Expand Up @@ -87,6 +95,12 @@ ch_get_ymls <- function(menu = TRUE) {
prep_files$gpt4 <- NULL
}

if (!dbrx_exists) {
prep_files$`databricks-dbrx` <- NULL
prep_files$`databricks-meta-llama3-70b` <- NULL
prep_files$`databricks-mixtral8x7b` <- NULL
}

if (!llama_exists) {
prep_files$llamagpt <- NULL
}
Expand Down
55 changes: 20 additions & 35 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,6 +1,5 @@
# chattr


<!-- badges: start -->

[![R-CMD-check](https://github.com/mlverse/chattr/actions/workflows/R-CMD-check.yaml/badge.svg)](https://github.com/mlverse/chattr/actions/workflows/R-CMD-check.yaml)
Expand Down Expand Up @@ -53,11 +52,11 @@ remotes::install_github("mlverse/chattr")
back-end provides access to multiple LLM types. The plan is to add more
back-ends as time goes by:

<table>
<table style="width:100%;">
<colgroup>
<col style="width: 26%" />
<col style="width: 47%" />
<col style="width: 26%" />
<col style="width: 28%" />
<col style="width: 46%" />
<col style="width: 24%" />
</colgroup>
<thead>
<tr class="header">
Expand Down Expand Up @@ -98,6 +97,17 @@ autocomplete-style suggestions as you code</td>
href="https://mlverse.github.io/chattr/articles/copilot-chat.html">Interact
with GitHub Copilot Chat</a></td>
</tr>
<tr class="even">
<td style="text-align: center;"><a
href="https://docs.databricks.com/en/machine-learning/foundation-models/index.html#databricks-foundation-model-apis">Databricks</a></td>
<td style="text-align: center;">DBRX, Meta Llama 3 70B, and Mixtral 8x7B
via <a
href="https://docs.databricks.com/en/machine-learning/foundation-models/index.html#pay-per-token-foundation-model-apis">Databricks
foundational model REST API</a>.</td>
<td style="text-align: center;"><a
href="https://mlverse.github.io/chattr/articles/backend-databricks.html">Interact
with Databricks foundation chat models</a></td>
</tr>
</tbody>
</table>

Expand Down Expand Up @@ -144,12 +154,8 @@ chattr_use("gpt35")
chattr_app()
```

<figure>
<img src="man/figures/readme/chat1.png"
alt="Screenshot of the Sniny gadget app in a dark mode RStudio theme" />
<figcaption aria-hidden="true">Screenshot of the Sniny gadget app in a
dark mode RStudio theme</figcaption>
</figure>
![Screenshot of the Sniny gadget app in a dark mode RStudio
theme](man/figures/readme/chat1.png)

<br>

Expand Down Expand Up @@ -184,12 +190,7 @@ The screen that opens will contain the following:
information attached to your prompt. Including the number of max
data files, and data frames sent to the LLM.

<figure>
<img src="man/figures/readme/chat2.png"
alt="Screenshot of the Sniny gadget options" />
<figcaption aria-hidden="true">Screenshot of the Sniny gadget
options</figcaption>
</figure>
![Screenshot of the Sniny gadget options](man/figures/readme/chat2.png)

### Additional ways to interact

Expand All @@ -204,12 +205,8 @@ structure of data frames currently in your environment, the path for the
data files in your working directory. If supported by the model,
`chattr` will include the current chat history.

<figure>
<img src="man/figures/readme/chattr-diagram.png"
alt="Diagram that illustrates how chattr handles model requests" />
<figcaption aria-hidden="true">Diagram that illustrates how
<code>chattr</code> handles model requests</figcaption>
</figure>
![Diagram that illustrates how `chattr` handles model
requests](man/figures/readme/chattr-diagram.png)

To see what `chattr` will send to the model, set the `preview` argument
to `TRUE`:
Expand Down Expand Up @@ -272,30 +269,18 @@ section.
- Select *Tools* in the top menu, and then select *Modify Keyboard
Shortcuts*

<figure>
<img src="man/figures/readme/keyboard-shortcuts.png" width="700"
alt="Screenshot that shows where to find the option to modify the keyboard shortcuts" />
<figcaption aria-hidden="true">Screenshot that shows where to find the
option to modify the keyboard shortcuts</figcaption>
</figure>

- Search for the `chattr` adding by writing “open chat”, in the search
box

<figure>
<img src="man/figures/readme/addin-find.png" width="500"
alt="Screenshot that shows where to input the addin search" />
<figcaption aria-hidden="true">Screenshot that shows where to input the
addin search</figcaption>
</figure>

- To select a key combination for your shortcut, click on the Shortcut
box and then type *press* the key combination in your keyboard. In
my case, I chose *Ctrl+Shift+C*

<figure>
<img src="man/figures/readme/addin-assign.png" width="500"
alt="Screenshot that shows what the interface looks like when a shortcut has been selected" />
<figcaption aria-hidden="true">Screenshot that shows what the interface
looks like when a shortcut has been selected</figcaption>
</figure>
13 changes: 7 additions & 6 deletions README.qmd
Original file line number Diff line number Diff line change
Expand Up @@ -47,7 +47,7 @@ url <- urls[grepl(".io", urls)][[1]]

`chattr` is an interface to LLMs (Large Language Models). It enables interaction with the model directly from the RStudio IDE. `chattr` allows you to submit a prompt to the LLM from your script, or by using the provided Shiny Gadget.

This package's main goal is to aid in exploratory data analysis (EDA) tasks. The additional information appended to your request, provides a sort of guard rails, so that the packages and techniques we usually recommend as best practice, are used in the models responses.
This package's main goal is to aid in exploratory data analysis (EDA) tasks. The additional information appended to your request, provides a sort of "guard rails", so that the packages and techniques we usually recommend as best practice, are used in the model's responses.

## Install {#install}

Expand All @@ -62,11 +62,12 @@ remotes::install_github("mlverse/chattr")

`chattr` provides two main integration with two main LLM back-ends. Each back-end provides access to multiple LLM types. The plan is to add more back-ends as time goes by:

| Provider | Models | Setup Instructions |
|:-----------------:|:--------------------------------:|:-----------------:|
| OpenAI | GPT Models accessible via the OpenAI's REST API. `chattr` provides a convenient way to interact with GPT 4, and 3.5. | [Interact with OpenAI GPT models](https://mlverse.github.io/chattr/articles/openai-gpt.html) |
| [LLamaGPT-Chat](https://github.com/kuvaus/LlamaGPTJ-chat) | LLM models available in your computer. Including GPT-J, LLaMA, and MPT. Tested on a [GPT4ALL](https://gpt4all.io/index.html) model. **LLamaGPT-Chat** is a command line chat program for models written in C++. | [Interact with local models](https://mlverse.github.io/chattr/articles/backend-llamagpt.html) |
| [GitHub Copilot](https://docs.posit.co/ide/user/ide/guide/tools/copilot.html) | AI pair programmer that offers autocomplete-style suggestions as you code | [Interact with GitHub Copilot Chat](https://mlverse.github.io/chattr/articles/copilot-chat.html) |
| Provider | Models | Setup Instructions |
|:-------------------:|:--------------------------------:|:----------------:|
| OpenAI | GPT Models accessible via the OpenAI's REST API. `chattr` provides a convenient way to interact with GPT 4, and 3.5. | [Interact with OpenAI GPT models](https://mlverse.github.io/chattr/articles/openai-gpt.html) |
| [LLamaGPT-Chat](https://github.com/kuvaus/LlamaGPTJ-chat) | LLM models available in your computer. Including GPT-J, LLaMA, and MPT. Tested on a [GPT4ALL](https://gpt4all.io/index.html) model. **LLamaGPT-Chat** is a command line chat program for models written in C++. | [Interact with local models](https://mlverse.github.io/chattr/articles/backend-llamagpt.html) |
| [GitHub Copilot](https://docs.posit.co/ide/user/ide/guide/tools/copilot.html) | AI pair programmer that offers autocomplete-style suggestions as you code | [Interact with GitHub Copilot Chat](https://mlverse.github.io/chattr/articles/copilot-chat.html) |
| [Databricks](https://docs.databricks.com/en/machine-learning/foundation-models/index.html#databricks-foundation-model-apis) | DBRX, Meta Llama 3 70B, and Mixtral 8x7B via [Databricks foundational model REST API](https://docs.databricks.com/en/machine-learning/foundation-models/index.html#pay-per-token-foundation-model-apis). | [Interact with Databricks foundation chat models](https://mlverse.github.io/chattr/articles/backend-databricks.html) |

## Using {#using}

Expand Down
33 changes: 33 additions & 0 deletions inst/configs/databricks-dbrx.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
default:
prompt: |
{readLines(system.file('prompt/base.txt', package = 'chattr'))}
provider: Databricks
path: serving-endpoints
model: databricks-dbrx-instruct
label: DBRX (Databricks)
max_data_files: 0
max_data_frames: 0
include_doc_contents: FALSE
include_history: TRUE
system_msg: You are a helpful coding assistant
model_arguments:
temperature: 0.01
max_tokens: 1000
stream: TRUE
chat:
prompt: |
{readLines(system.file('prompt/base.txt', package = 'chattr'))}
For code output, use RMarkdown code chunks
Avoid all code chunk options
console:
prompt: |
{readLines(system.file('prompt/base.txt', package = 'chattr'))}
For any line that is not code, prefix with a: #
Keep each line of explanations to no more than 80 characters
DO NOT use Markdown for the code
script:
prompt: |
{readLines(system.file('prompt/base.txt', package = 'chattr'))}
For any line that is not code, prefix with a: #
Keep each line of explanations to no more than 80 characters
DO NOT use Markdown for the code
Loading

0 comments on commit c34c505

Please sign in to comment.