Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
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
1 change: 1 addition & 0 deletions .lintr
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
linters: linters_with_defaults(line_length_linter = line_length_linter(100))
14 changes: 14 additions & 0 deletions .vscode/launch.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
{
"version": "0.2.0",
"configurations": [
{
"name": "Debug Active R Script",
"type": "R-Debugger",
"request": "launch",
"args": [],
"cwd": "${workspaceFolder}",
"env": {},
"console": "integratedTerminal"
},
]
}
2 changes: 1 addition & 1 deletion DESCRIPTION
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
Package: llmModule
Type: Package
Title: R Interface for Large Language Model APIs
Version: 25.06.5
Version: 25.11.0
Authors@R: c(
person("Ricardo", "Fernandes", email = "ldv1452@gmail.com", role = c("aut", "cre")),
person("Antonia", "Runge", email = "antonia.runge@inwt-statistics.de", role = c("aut"))
Expand Down
5 changes: 5 additions & 0 deletions NEWS.md
Original file line number Diff line number Diff line change
@@ -1,3 +1,8 @@
# llmModule 25.11.0

## Bug Fixes
- Fixed an issue with the error message in the `LocalLlmApi` class which would have thrown an error itself.

# llmModule 25.06.5

## Updates
Expand Down
2 changes: 1 addition & 1 deletion R/01-LocalLlmApi-class.R
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@ new_LocalLlmApi <- function(

if (!is_ollama_running(url = base_url)) {
api <- list()
attr(api, "error") <- sprintf("Ollama server does not appear to be running at the specified base URL: '%s%'.", base_url)
attr(api, "error") <- sprintf("Ollama server does not appear to be running at the specified base URL: '%s'.", base_url)
return(api)
}

Expand Down
27 changes: 18 additions & 9 deletions R/01-RemoteLlmApi-class.R
Original file line number Diff line number Diff line change
Expand Up @@ -96,7 +96,9 @@ new_RemoteLlmApi <- function(api_key_path, provider, no_internet = NULL, exclude

if (inherits(is_valid, "error")) {
# set error message
err_msg <- is_valid$message |> clean_error_message()
err_msg <- is_valid$message |> clean_error_message(
replace_text = c("HTTP 401 Unauthorized" = "Unauthorized: API key is invalid or expired")
)

# test the other provider
other_provider <- ifelse(provider == "OpenAI", "DeepSeek", "OpenAI")
Expand Down Expand Up @@ -238,8 +240,10 @@ try_send_request <- function(request) {
response <- tryCatch(
req_perform(request),
error = function(e) {
return(structure(list(), error = paste("API request failed:",
clean_error_message(e$message))))
msg <- e$message |> clean_error_message(
replace_text = c("HTTP 401 Unauthorized" = "Unauthorized: API key is invalid or expired")
)
return(structure(list(), error = paste("API request failed:", msg)))
}
)

Expand All @@ -259,9 +263,10 @@ try_send_request <- function(request) {
if (!is.null(response$status_code) && response$status_code != 200) {
warning(sprintf("API returned HTTP %s: %s", response$status_code,
parsed$error$message %||% "Unknown error"))
attr(parsed, "error") <- clean_error_message(
parsed$error$message %||% paste("HTTP", response$status_code)
)
attr(parsed, "error") <- parsed$error$message %||% paste("HTTP", response$status_code) |>
clean_error_message(
replace_text = c("HTTP 401 Unauthorized" = "Unauthorized: API key is invalid or expired")
)
}

return(parsed)
Expand All @@ -284,12 +289,16 @@ validate_api_key <- function(api_key, url_models) {
}


clean_error_message <- function(msg) {
clean_error_message <- function(msg, replace_text = c()) {
# Remove ANSI escape sequences
msg <- gsub("\033\\[[0-9;]*m", "", msg)

# Replace known HTTP codes with friendly text
msg <- gsub("HTTP 401 Unauthorized", "Unauthorized: API key is invalid or expired", msg)
# Replace specified patterns
if (length(replace_text) > 0) {
for (pattern in names(replace_text)) {
msg <- gsub(pattern, replace_text[[pattern]], msg)
}
}

return(trimws(msg))
}
Expand Down
6 changes: 3 additions & 3 deletions inst/app/app.R
Original file line number Diff line number Diff line change
@@ -1,14 +1,14 @@
library(llmModule)


ui <- fluidPage(
ui <- shiny::fluidPage(
shinyjs::useShinyjs(),
titlePanel("LLM Prompt Module Test"),
shiny::titlePanel("LLM Prompt Module Test"),
llm_generate_prompt_ui("single_prompt", output_response = TRUE)
)

server <- function(input, output, session) {
llm_generate_prompt_server("single_prompt")
}

shinyApp(ui, server)
shiny::shinyApp(ui, server)
17 changes: 17 additions & 0 deletions tests/testthat/test-clean_error_message.R
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
test_that("clean_error_message removes ANSI and trims whitespace", {
msg <- "\033[31mError: Something went wrong\033[0m "
cleaned <- clean_error_message(msg)
expect_equal(cleaned, "Error: Something went wrong")
})

test_that("clean_error_message replaces patterns", {
msg <- "HTTP 401 Unauthorized: Invalid key"
cleaned <- clean_error_message(msg, replace_text = c("HTTP 401 Unauthorized" = "Unauthorized: API key is invalid or expired"))
expect_equal(cleaned, "Unauthorized: API key is invalid or expired: Invalid key")
})

test_that("clean_error_message handles empty replace_text", {
msg <- "Some error occurred"
cleaned <- clean_error_message(msg)
expect_equal(cleaned, "Some error occurred")
})