{"id":29766693,"url":"https://github.com/dylanpieper/chatalot","last_synced_at":"2025-07-27T01:10:06.093Z","repository":{"id":276838963,"uuid":"930424859","full_name":"dylanpieper/chatalot","owner":"dylanpieper","description":"Process a Lot of LLM Chats","archived":false,"fork":false,"pushed_at":"2025-07-25T20:05:43.000Z","size":26113,"stargazers_count":22,"open_issues_count":0,"forks_count":1,"subscribers_count":1,"default_branch":"main","last_synced_at":"2025-07-25T22:17:28.929Z","etag":null,"topics":["batch","batch-processing","ellmer","llm","package","r"],"latest_commit_sha":null,"homepage":"https://dylanpieper.github.io/chatalot/","language":"R","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"other","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/dylanpieper.png","metadata":{"files":{"readme":"README.md","changelog":"NEWS.md","contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null,"zenodo":null}},"created_at":"2025-02-10T16:03:08.000Z","updated_at":"2025-07-25T20:04:02.000Z","dependencies_parsed_at":"2025-04-12T13:42:45.580Z","dependency_job_id":"223ae5c1-0546-4599-8203-2a13b2cae4c0","html_url":"https://github.com/dylanpieper/chatalot","commit_stats":null,"previous_names":["dylanpieper/hellmer","dylanpieper/chatlot","dylanpieper/chatalot"],"tags_count":3,"template":false,"template_full_name":null,"purl":"pkg:github/dylanpieper/chatalot","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/dylanpieper%2Fchatalot","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/dylanpieper%2Fchatalot/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/dylanpieper%2Fchatalot/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/dylanpieper%2Fchatalot/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/dylanpieper","download_url":"https://codeload.github.com/dylanpieper/chatalot/tar.gz/refs/heads/main","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/dylanpieper%2Fchatalot/sbom","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":267279283,"owners_count":24063325,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","status":"online","status_checked_at":"2025-07-26T02:00:08.937Z","response_time":62,"last_error":null,"robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":true,"can_crawl_api":true,"host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["batch","batch-processing","ellmer","llm","package","r"],"created_at":"2025-07-27T01:10:04.800Z","updated_at":"2025-07-27T01:10:06.069Z","avatar_url":"https://github.com/dylanpieper.png","language":"R","readme":"# chatalot \u003cimg src=\"man/figures/chatalot-hex.png\" align=\"right\" width=\"160\"/\u003e\n\n[![CRAN status](https://www.r-pkg.org/badges/version/hellmer)](https://CRAN.R-project.org/package=hellmer) [![R-CMD-check](https://github.com/dylanpieper/hellmer/actions/workflows/testthat.yml/badge.svg)](https://github.com/dylanpieper/hellmer/actions/workflows/testthat.yml)\n\nchatalot synchronously processes a lot of large language model chats in R as an extension of [ellmer](https://ellmer.tidyverse.org).\n\nEasily setup sequential and parallel chat processors with support for [tool calling](https://ellmer.tidyverse.org/articles/tool-calling.html), [structured data extraction](https://ellmer.tidyverse.org/articles/structured-data.html), uploaded content, save and resume, sound notifications, and more.\n\n## **chatalot or ellmer?**\n\nchatalot prioritizes safety and recovery, while ellmer prioritizes speed and cost savings.\n\n| Priority | Function | Description |\n|----------------------|----------------------|----------------------------|\n| 🛡️ **Safety first** | [chatalot::seq_chat()](https://dylanpieper.github.io/chatalot/reference/seq_chat.html) | Each chat saved individually |\n| ⚖️ **Speed + safety** | [chatalot::future_chat()](https://dylanpieper.github.io/chatalot/reference/future_chat.html) | Parallel processing with chunks of chats saved |\n| 🚀 **Maximum speed** | [ellmer::parallel_chat()](https://ellmer.tidyverse.org/reference/parallel_chat.html) | All-or-nothing parallel processing; optimized for speed |\n| 💰 **Cost savings** | [ellmer::batch_chat()](https://ellmer.tidyverse.org/reference/batch_chat.html) | \\~50% cheaper; up to 24hr delays |\n\n## Installation\n\nYou can install the development or CRAN version of the package with:\n\n``` r\n# pak::pak(\"dylanpieper/chatalot\")\npak::pak(\"chatalot\")\n```\n\n## Setup API Keys\n\nAPI keys allow access to chat models and are stored as environmental variables. I recommend `usethis` to setup API keys in your `.Renviron` such as `OPENAI_API_KEY=your-key`:\n\n``` r\nusethis::edit_r_environ(scope = c(\"user\", \"project\"))\n```\n\n## Basic Usage\n\nFor the following examples, define a chat object:\n\n``` r\nopenai \u003c- chat_openai(system_prompt = \"Reply concisely, one sentence\")\n```\n\n### Sequential Processing\n\nProcess chats in sequence, or one at a time. Save responses to disk for each chat and resume processing from the last saved chat.\n\n``` r\nlibrary(chatalot)\n\nchat \u003c- seq_chat(openai)\n\nprompts \u003c- c(\n  \"What roles do people have in a castle?\",\n  \"Why are castles needed?\",\n  \"When was the first castle built?\",\n  \"Where are most castles located?\"\n)\n\nresponse \u003c- chat$process(prompts)\n```\n\nAccess the responses:\n\n``` r\nresponse$texts()\n#\u003e [1] \"In a castle, people served as rulers, warriors, administrators, \n#\u003e craftsmen, and servants who managed its defense, governance, and daily upkeep.\"\n#\u003e \n#\u003e [2] \"Castles have historically been built for defense and power consolidation,\n#\u003e and today they serve as cultural landmarks that preserve our heritage \n#\u003e and attract tourism.\"\n#\u003e \n#\u003e [3] \"There isn’t a definitive \\\"first castle,\\\" but the earliest structures\n#\u003e resembling castles emerged in medieval Europe around the 9th century.\"\n#\u003e \n#\u003e [4] \"Most castles are located in Europe, particularly in historically\n#\u003e turbulent regions like the United Kingdom, France, and Germany.\"     \n```\n\n### Parallel Processing\n\nParallel processing requests multiple chats at a time across multiple R processes using [future](https://future.futureverse.org):\n\n``` r\nchat \u003c- future_chat(openai)\n```\n\nSplits prompts into chunks to distribute across workers to process chats (default: process 10 prompts at a time). Saves chat data to disk between chunks and can resume processing from the last saved chunk. For the fastest processing, set `chunk_size` to the number of prompts:\n\n``` r\nresponse \u003c- chat$process(\n  prompts, \n  chunk_size = length(prompts)\n)\n```\n\nIf using `length(prompts)`, be aware that data will not be saved to the disk until all chats are processed, risking data loss and additional cost.\n\n## Features\n\n### Tool Calling\n\nRegister and use [tool calling](https://ellmer.tidyverse.org/articles/tool-calling.html) to let the LLM use R functions:\n\n``` r\nweather \u003c- data.frame(\n  city = c(\"Chicago\", \"New York\", \"Lisbon\"),\n  raining = c(\"Heavy\", \"None\", \"Overcast\"),\n  temperature = c(\"Cool\", \"Hot\", \"Warm\"),\n  wind = c(\"Strong\", \"Weak\", \"Strong\")\n)\n\nget_weather \u003c- function(cities) weather[weather$city %in% cities, ]\n\nchat$register_tool(tool(\n  get_weather,\n  \"Report on weather conditions.\",\n  cities = type_array(\"City names\", type_string())\n))\n\nresponse \u003c- chat$process(interpolate(\"Brief weather update for {{weather$city}}?\"))\n\nresponse$texts()\n#\u003e [1] \"Chicago is experiencing heavy rain, cool temperatures, and strong winds.\"\n#\u003e [2] \"New York is experiencing hot conditions with no rain and light winds.\"\n#\u003e [3] \"In Lisbon, the weather is overcast with warm temperatures and strong winds.\"\n```\n\n### Structured Data Extraction\n\nExtract [structured data](https://ellmer.tidyverse.org/articles/structured-data.html) using type specifications:\n\n``` r\nprompts \u003c- c(\n  \"I go by Alex. 42 years on this planet and counting.\",\n  \"Pleased to meet you! I'm Jamal, age 27.\",\n  \"They call me Li Wei. Nineteen years young.\",\n  \"Fatima here. Just celebrated my 35th birthday last week.\",\n  \"The name's Robert - 51 years old and proud of it.\",\n  \"Kwame here - just hit the big 5-0 this year.\"\n)\n\nresponse \u003c- chat$process(\n  prompts,\n  type = type_object(\n    name = type_string(),\n    age = type_number()\n  )\n)\n\nresponse$texts()\n#\u003e     name age\n#\u003e 1   Alex  42\n#\u003e 2  Jamal  27\n#\u003e 3 Li Wei  19\n#\u003e 4 Fatima  35\n#\u003e 5 Robert  51\n#\u003e 6  Kwame  50\n```\n\n### Uploaded Content\n\nProcess prompts that with text and uploaded content (e.g., [images](https://ellmer.tidyverse.org/reference/content_image_url.html) and [PDFs](https://ellmer.tidyverse.org/reference/content_pdf_file.html)):\n\n``` r\nlibrary(chatalot)\n\nchat \u003c- seq_chat(openai)\n\nbase_prompt \u003c- \"What do you see in the image?\"\nimg_prompts \u003c- list(\n  c(base_prompt, content_image_url(\"https://www.r-project.org/Rlogo.png\")),\n  c(base_prompt, content_image_file(system.file(\"httr2.png\", package = \"ellmer\")))\n)\n\nresponse \u003c- chat$process(img_prompts)\n\nresponse$texts()\n#\u003e [[1]]\n#\u003e [1] \"The image shows the logo for R, a programming language and software environment \n#\u003e used for statistical computing and graphics, featuring a stylized blue \\\"R\\\" \n#\u003e inside a gray oval or ring.\"\n\n#\u003e [[2]]\n#\u003e [1] \"The image shows a logo for \\\"httr2\\\" featuring a stylized red baseball batter\n#\u003e silhouette on a dark blue hexagonal background.\"\n```\n\n### Save and Resume\n\nIf you interrupt chat processing (e.g., to check responses) or experience an error, you can call `process()` again to resume from the last saved chat or chunk:\n\n``` r\nresponse \u003c- chat$process(prompts, file = \"chat.rds\")\n```\n\nIf `file` is not defined, a temporary file will be created by default (`.rds`). Progress is tracked in `response$progress()`.\n\n### Sound Notifications\n\nToggle sound notifications on completion, interruption, and error:\n\n``` r\nresponse \u003c- chat$process(prompts, beep = TRUE)\n```\n\n### Verbosity Options\n\nBy default, the chat `echo` is set to `FALSE` to show a progress bar. However, you can still configure `echo` by first setting `progress` to `FALSE`:\n\n``` r\nprompts \u003c- c(\n  \"What is R?\",\n  \"Explain base R versus tidyverse\"\n)\n\nresponse \u003c- chat$process(\n  prompts,\n  progress = FALSE,\n  echo = TRUE\n)\n#\u003e R is a programming language and software environment used for \n#\u003e statistical computing and graphics.\n#\u003e \n#\u003e Base R consists of the core functionalities built into R, \n#\u003e while tidyverse is a collection of packages that offer a more\n#\u003e consistent, readable, and streamlined approach to data manipulation, \n#\u003e visualization, and analysis.\n```\n\n### Methods\n\n-   `texts()`: Returns response texts in the same format as the input prompts (i.e., a list if prompts were provided as a list, or a character vector if prompts were provided as a vector). When a `type` is provided, a list with one element for each prompt. When `type` is consistent, returns a data frame with one row for each prompt, and one column for each property.\n-   `chats()`: Returns a list of chat objects\n-   `progress()`: Returns processing status\n\n## Extras\n\n-   [Batch and Compare the Similarity of LLM Responses in R](https://dylanpieper.github.io/blog/posts/batch-and-compare-LLM-responses.html) (Blog Post)\n-   Different functions handle API rate limits differently:\n    -   [chatalot::seq_chat()](https://dylanpieper.github.io/chatalot/reference/seq_chat.html) and [chatalot::future_chat()](https://dylanpieper.github.io/chatalot/reference/future_chat.html): Allow rate limits to be exceeded and fallback on ellmer's retry mechanism (reactive)\n\n    -   [ellmer::parallel_chat()](https://ellmer.tidyverse.org/reference/parallel_chat.html): Throttles requests to prevent rate limits (proactive)\n\n    -   [ellmer::batch_chat()](https://ellmer.tidyverse.org/reference/batch_chat.html): Managed by the API provider\n","funding_links":[],"categories":[],"sub_categories":[],"project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fdylanpieper%2Fchatalot","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fdylanpieper%2Fchatalot","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fdylanpieper%2Fchatalot/lists"}