Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Audio input, app layout tweaks, better background startup, use ExtendedTask #224

Merged
merged 48 commits into from
Aug 31, 2024
Merged
Show file tree
Hide file tree
Changes from 38 commits
Commits
Show all changes
48 commits
Select commit Hold shift + click to select a range
f5d3e74
use input_task_button for chat
JamesHWade Aug 23, 2024
c1b68f1
shorten notification time
JamesHWade Aug 23, 2024
78c3078
add audio input functions
JamesHWade Aug 23, 2024
f302d96
[wip] audio input option
JamesHWade Aug 23, 2024
20a6456
first working audio input
JamesHWade Aug 23, 2024
5595d35
fix theme info fetching to run in positron Fixes #217
JamesHWade Aug 23, 2024
0fb2b73
dynamic UI for audio and devtools::document()
JamesHWade Aug 23, 2024
469dff5
change name of run_chatgpt_app to gptstudio_run_chat_app
JamesHWade Aug 23, 2024
45dde96
minor refactor to app server code
JamesHWade Aug 24, 2024
fc80c92
revamp bg app startup to work on linux Fixes #179
JamesHWade Aug 24, 2024
3380ee8
cleanup audio app option
JamesHWade Aug 24, 2024
9eb110e
lint cleanup and a start on vision #222
JamesHWade Aug 24, 2024
a664030
devtools::document()
JamesHWade Aug 24, 2024
2f408e4
use gpt-4o as default model
JamesHWade Aug 24, 2024
ea55e20
api skeleton tests
JamesHWade Aug 24, 2024
0a88caf
fix tests and update NEWS
JamesHWade Aug 24, 2024
f1ac74e
lint and style with grkstyle
JamesHWade Aug 24, 2024
48ce475
convert app styling to be more chat-like (and repair streaming)
JamesHWade Aug 24, 2024
1eb0cf0
fix linting
JamesHWade Aug 25, 2024
f3be247
use ExtendedTask for async job
JamesHWade Aug 25, 2024
1343f53
document, apply styling, fix linting
JamesHWade Aug 25, 2024
5511e5d
update news
JamesHWade Aug 25, 2024
fcb826b
refactor audio transcription and add tests
JamesHWade Aug 25, 2024
b9344d9
check for status code <300 for server startup
JamesHWade Aug 26, 2024
df47901
check for status code <300 for server startup
JamesHWade Aug 26, 2024
341b051
improve app styling and code syntax highlighting
JamesHWade Aug 26, 2024
159fb8c
code syntax highlighting with all of rsthemes
JamesHWade Aug 26, 2024
7b36c89
add azure openai to streaming
JamesHWade Aug 26, 2024
1fbe973
redocument streaming
JamesHWade Aug 26, 2024
281f346
remove dependencies and update snapshots
JamesHWade Aug 27, 2024
1be0040
more packages to suggests
JamesHWade Aug 27, 2024
4e089e6
more packages to suggests
JamesHWade Aug 27, 2024
96103a8
more packages to suggests
JamesHWade Aug 27, 2024
8a9d97c
better background job launch and pass along code highlighting theme
JamesHWade Aug 27, 2024
78b61c1
update test snapshots
JamesHWade Aug 27, 2024
1d76339
fix linting errors
JamesHWade Aug 27, 2024
2cd7972
fix test snapshot
JamesHWade Aug 27, 2024
b1f7ef5
update news
JamesHWade Aug 27, 2024
22e34ac
explicitly reference js and css in gpstudio
JamesHWade Aug 28, 2024
0b08eac
update snapshot
JamesHWade Aug 28, 2024
5cb2dd1
Increment version number to 0.4.0.9004
JamesHWade Aug 31, 2024
0a028fa
properly reference html deps and remove unnecessary prints
JamesHWade Aug 31, 2024
2ff5473
remove curl dependency
JamesHWade Aug 31, 2024
bb34c01
remove curl dependency
JamesHWade Aug 31, 2024
c90a94f
fix azure-openai streaming
JamesHWade Aug 31, 2024
dee7541
add miniUI and future to suggests
JamesHWade Aug 31, 2024
602c9f5
add missing themes to code highlighting
JamesHWade Aug 31, 2024
44d56ac
fix linting
JamesHWade Aug 31, 2024
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
15 changes: 7 additions & 8 deletions DESCRIPTION
Original file line number Diff line number Diff line change
Expand Up @@ -21,37 +21,36 @@ BugReports: https://github.com/MichelNivard/gptstudio/issues
Depends:
R (>= 4.0)
Imports:
assertthat,
bslib (>= 0.6.0),
bsicons,
bslib (>= 0.8.0),
cli,
colorspace,
curl,
fontawesome,
glue,
grDevices,
htmltools,
htmlwidgets,
httr2,
ids,
jsonlite,
magrittr,
purrr,
R6,
R6 (>= 2.0),
rlang,
rstudioapi (>= 0.12),
rvest,
shiny,
shiny (>= 1.9.0),
shiny.i18n,
SSEparser,
stringr (>= 1.5.0),
utils,
waiter,
yaml
Suggests:
AzureRMR,
grDevices,
knitr,
mockr,
promises,
rmarkdown,
rvest,
shinytest2,
spelling,
testthat (>= 3.0.0),
Expand Down
14 changes: 9 additions & 5 deletions NAMESPACE
Original file line number Diff line number Diff line change
Expand Up @@ -48,22 +48,26 @@ export(gptstudio_comment_code)
export(gptstudio_create_skeleton)
export(gptstudio_request_perform)
export(gptstudio_response_process)
export(gptstudio_run_chat_app)
export(gptstudio_sitrep)
export(gptstudio_skeleton_build)
export(gptstudio_spelling_grammar)
export(input_audio_clip)
export(openai_create_chat_completion)
export(run_chatgpt_app)
export(transcribe_audio)
import(cli)
import(htmltools)
import(htmlwidgets)
import(httr2)
import(rlang)
import(shiny)
importFrom(R6,R6Class)
importFrom(assertthat,assert_that)
importFrom(assertthat,is.count)
importFrom(assertthat,is.number)
importFrom(assertthat,is.string)
importFrom(glue,glue)
importFrom(htmltools,div)
importFrom(htmltools,htmlDependency)
importFrom(htmltools,tag)
importFrom(htmltools,tagList)
importFrom(htmltools,tags)
importFrom(jsonlite,fromJSON)
importFrom(magrittr,"%>%")
importFrom(shiny,icon)
6 changes: 6 additions & 0 deletions NEWS.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,12 @@
- Added claude-3.5-sonnet model from Anthropic.
- Set gpt-4o-mini as default model for OpenAI. #219
- Fixed bugs with Azure OpenAI service. #223
- Add audio input option for chat app. #224
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I wasn't able to find the audio input in the UI
image

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Did you enable it in the settings?

At a minimum, I need to document instructions better.

- Fix bug with chat app not loading on linux. #224
- Allow chat app to run in Positron (not yet as background job) #224
- API calls now run async with ExtendedTask. #224
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I don't think async (and by extension, {promises}) is really needed here, since the addin is supposed to work for a single machine. I'm ok with ExtendedTask with the new waiting button and loaders tho (in this case we need to add a minimun version to shiny in DESCRIPTION)

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This was meant for line 10

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Fair point on async. I've been using local models more, and they can be slow. The idea was to get not block actions in the current session, but I don't think that adds much. I'll remove the future_promise() call from the ExtendedTask. Easy to go back to it if we want later.

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Update on this, ExtendedTask needs a promise to be returned. I've moved promises to Suggests, but it's not really another dependency because shiny already depends on the package.

- New styling of chat app. #224
JamesHWade marked this conversation as resolved.
Show resolved Hide resolved
- Add code syntax highlighting to chat app. #224

## gptstudio 0.4.0

Expand Down
190 changes: 69 additions & 121 deletions R/addin_chatgpt.R
Original file line number Diff line number Diff line change
@@ -1,147 +1,95 @@
#' Run Chat GPT
#' Run the Chat GPT Shiny App as a background job and show it in the viewer pane
#' Run GPTStudio Chat App
#'
#' @export
#' This function initializes and runs the Chat GPT Shiny App as a background job
#' in RStudio and opens it in the viewer pane or browser window.
#'
#' @param host A character string specifying the host on which to run the app.
#' Defaults to the value of `getOption("shiny.host", "127.0.0.1")`.
#'
#' @return This function does not return a value. It runs the Shiny app as a side effect.
#'
#' @details
#' The function performs the following steps:
#' 1. Verifies that RStudio API is available.
#' 2. Finds an available port for the Shiny app.
#' 3. Creates a temporary directory for the app files.
#' 4. Runs the app as a background job in RStudio.
#' 5. Opens the app in the RStudio viewer pane or browser window.
#'
#' @return This function has no return value.
#' @note This function is designed to work within the RStudio IDE and requires
#' the rstudioapi package.
#'
#' @inheritParams shiny::runApp
#' @export
#'
#' @examples
#' # Call the function as an RStudio addin
#' \dontrun{
#' gptstudio_chat()
#' }
gptstudio_chat <- function(host = getOption("shiny.host", "127.0.0.1")) {
rstudioapi::verifyAvailable()
stopifnot(rstudioapi::hasFun("viewer"))

port <- random_port()
app_dir <- create_tmp_app_dir()

run_app_as_bg_job(appDir = app_dir, job_name = "gptstudio", host, port)
port <- find_available_port()
app_dir <- create_temp_app_dir()

open_bg_shinyapp(host, port)
}
run_app_background(app_dir, "gptstudio", host, port)

if (rstudioapi::versionInfo()$mode == "server") {
Sys.sleep(3)
}

#' Generate a random safe port number
#'
#' This function generates a random port allowed by shiny::runApp.
#'
#' @return A single integer representing the randomly selected safe port number.
random_port <- function() {
all_ports <- 3000:8000
unsafe_ports <- c(3659, 4045, 5060, 5061, 6000, 6566, 6665:6669, 6697)
safe_ports <- setdiff(all_ports, unsafe_ports)
sample(safe_ports, size = 1)
open_app_in_viewer(host, port)
}

# Helper functions

#' Run an R Shiny app in the background
#'
#' This function runs an R Shiny app as a background job using the specified
#' directory, name, host, and port.
#'
#' @param job_name The name of the background job to be created
#' @inheritParams shiny::runApp
#' @return This function returns nothing because is meant to run an app as a
#' side effect.
run_app_as_bg_job <- function(appDir = ".", job_name, host, port) { # nolint
job_script <- create_tmp_job_script(
appDir = appDir,
port = port,
host = host
)
rstudioapi::jobRunScript(job_script, name = job_name)
cli_alert_success(
glue("{job_name} initialized as background job in RStudio")
)
find_available_port <- function() {
safe_ports <- setdiff(3000:8000, c(3659, 4045, 5060, 5061, 6000, 6566, 6665:6669, 6697))
sample(safe_ports, 1)
}


#' Create a temporary job script
#'
#' This function creates a temporary R script file that runs the Shiny
#' application from the specified directory with the specified port and host.
#' @inheritParams shiny::runApp
#' @return A string containing the path of a temporary job script
create_tmp_job_script <- function(appDir, port, host) { # nolint
script_file <- tempfile(fileext = ".R")

line <-
glue::glue(
"shiny::runApp(appDir = '{appDir}', port = {port}, host = '{host}')"
)

file_con <- file(script_file)
writeLines(line, con = script_file)
close(file_con)
return(script_file)
create_temp_app_dir <- function() {
dir <- normalizePath(tempdir(), winslash = "/")
app_file <- create_temp_app_file()
file.copy(app_file, file.path(dir, "app.R"), overwrite = TRUE)
dir
}

create_tmp_app_dir <- function() {
dir <- tempdir()

if (.Platform$OS.type == "windows") {
dir <- gsub(pattern = "[\\]", replacement = "/", x = dir)
}
create_temp_app_file <- function() {
temp_file <- tempfile(fileext = ".R")
ide_colors <- dput(get_ide_theme_info())
code_theme_url <- get_highlightjs_theme()

app_file <- create_tmp_app_file()
file.copy(from = app_file, to = file.path(dir, "app.R"), overwrite = TRUE)
return(dir)
writeLines(
# nolint start
glue::glue(
"ide_colors <- {{paste(deparse(ide_colors), collapse = '\n')}}
ui <- gptstudio:::mod_app_ui('app', ide_colors, '{{code_theme_url}}')
server <- function(input, output, session) {
gptstudio:::mod_app_server('app', ide_colors)
}
shiny::shinyApp(ui, server)",
.open = "{{", .close = "}}"
),
temp_file)
# nolint end
temp_file
}

create_tmp_app_file <- function() {
script_file <- tempfile(fileext = ".R")
ide_theme <- get_ide_theme_info() %>%
dput() %>%
utils::capture.output()

line_theme <- glue::glue(
"ide_colors <- {ide_theme}"
)
line_ui <- glue::glue(
"ui <- gptstudio:::mod_app_ui('app', ide_colors)"
)
line_server <- glue::glue(
"server <- function(input, output, session) {
gptstudio:::mod_app_server('app', ide_colors)
}",
.open = "{{",
.close = "}}"
)
line_run_app <- glue::glue("shiny::shinyApp(ui, server)")

file_con <- file(script_file)

writeLines(
text = c(line_theme, line_ui, line_server, line_run_app),
sep = "\n\n",
con = script_file
)
run_app_background <- function(app_dir, job_name, host, port) {
job_script <- tempfile(fileext = ".R")
writeLines(glue::glue(
"shiny::runApp(appDir = '{app_dir}', port = {port}, host = '{host}')"
), job_script)

close(file_con)
return(script_file)
rstudioapi::jobRunScript(job_script, name = job_name)
cli::cli_alert_success("{job_name} initialized as background job in RStudio")
}


#' Open browser to local Shiny app
#'
#' This function takes in the host and port of a local Shiny app and opens the
#' app in the default browser.
#'
#' @param host A character string representing the IP address or domain name of
#' the server where the Shiny app is hosted.
#' @param port An integer representing the port number on which the Shiny app is
#' hosted.
#'
#' @return None (opens the Shiny app in the viewer pane or browser window)
open_bg_shinyapp <- function(host, port) {
open_app_in_viewer <- function(host, port) {
url <- glue::glue("http://{host}:{port}")
translated_url <- rstudioapi::translateLocalUrl(url, absolute = TRUE)

if (host %in% c("127.0.0.1")) {
if (host == "127.0.0.1") {
cli::cli_inform(c(
"i" = "Showing app in 'Viewer' pane",
"i" = "Run {.run rstudioapi::viewer(\"{url}\")} to see it"
Expand All @@ -150,17 +98,17 @@ open_bg_shinyapp <- function(host, port) {
cli::cli_alert_info("Showing app in browser window")
}

if (.Platform$OS.type == "unix") {
wait_for_bg_shinyapp(translated_url)
}
wait_for_bg_app(translated_url)

rstudioapi::viewer(translated_url)
}

# This function makes a request for the app's url and fails
# if doesn't find anything after 10 seconds
wait_for_bg_shinyapp <- function(url) {
wait_for_bg_app <- function(url, max_seconds = 10) {
request(url) %>%
req_retry(max_seconds = 10, backoff = function(n) 0.2) %>%
req_retry(
max_seconds = max_seconds,
is_transient = \(resp) resp_status(resp) >= 300,
backoff = function(n) 0.2
) %>%
req_perform()
}
1 change: 0 additions & 1 deletion R/addin_comment-code.R
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,6 @@
#' gptstudio_comment_code()
#' }
gptstudio_comment_code <- function() {

file_ext <- get_file_extension()

task <- glue::glue(
Expand Down
Loading
Loading