Status: Implementation Complete (Part 1 of 2) Branch: unify-interface Version: 0.0.2
Overview
artcurator now provides a unified interface for artwork analysis functions that abstracts over multiple AI providers (Google Gemini and OpenAI). Instead of calling provider-specific packages directly, use artcurator::art_about_ai() with a provider parameter to switch between backends.
Benefits
- Provider agnostic: Write code once, switch providers with a parameter
- Centralized prompts: All artwork analysis prompts managed in one location
- Consistent API: Same function signatures across providers
- Easy migration: Existing code continues to work during transition
- Flexible configuration: Control provider via parameter, env var, or auto-detection
Unified Functions
All functions include a provider parameter for explicit provider selection:
1. art_about_ai(img_path, provider = NULL, ...)
Generate natural language artwork descriptions.
Returns: Character string with description
Example:
desc <- art_about_ai("artwork.png", provider = "gemini")2. art_style_ai(img_path, provider = NULL, ...)
Extract 5-10 stylistic features as structured data.
Returns: data.table with columns tag, tag_norm, desc
Example:
styles <- art_style_ai("artwork.png", provider = "openai", temp = 0)3. classify_styles_ai(tags, exist_cats = NULL, provider = NULL, ...)
Standardize free-form tags into consistent categories.
Returns: data.table with columns tag, category
Example:
tags <- c("Photorealistic", "Vibrant Colors")
classified <- classify_styles_ai(tags, provider = "gemini")4. art_profile_ai(art_title, artist_name, drawing_hours, brush_strokes, img_path, provider = NULL, ...)
Generate concise artwork profile with category, style, methodology, color, details.
Returns: 1-row data.table
Example:
profile <- art_profile_ai(
art_title = "Portrait",
artist_name = "Artist Name",
drawing_hours = 12,
brush_strokes = 5000,
img_path = "artwork.png",
provider = "gemini"
)5. art_profile_full_ai(story = NULL, artist_name, creation_time, art_title, img_path, provider = NULL, ...)
Generate comprehensive artwork profile with medium, description, inspiration, approach, impact.
Returns: 1-row data.table
Example:
profile <- art_profile_full_ai(
story = "Background story...",
artist_name = "Artist Name",
creation_time = "10 hours",
art_title = "Portrait",
img_path = "artwork.png",
provider = "openai"
)Provider Selection
The provider parameter controls which AI backend to use:
Method 1: Explicit Parameter (Recommended)
art_about_ai("artwork.png", provider = "gemini")
art_about_ai("artwork.png", provider = "openai")Method 2: Environment Variable
Sys.setenv(ARTCURATOR_PROVIDER = "openai")
art_about_ai("artwork.png") # Uses OpenAIMethod 3: Auto-Detection
# No provider specified - auto-detects:
# 1. Prefers artgemini if installed
# 2. Falls back to artopenai if installed
# 3. Errors if neither is available
art_about_ai("artwork.png")Provider-Specific Parameters
Use ... to pass provider-specific parameters:
Gemini-Specific
art_style_ai("artwork.png",
provider = "gemini",
ml = "gemini-3-pro-preview", # Model selection
temp = 0, # Temperature
max_think = TRUE, # Extended reasoning
timeout = 60) # Request timeoutOpenAI-Specific
art_style_ai("artwork.png",
provider = "openai",
ml = "gpt-5.1", # Model selection
temp = 0, # Temperature
timeout = 60) # Request timeoutConfiguration
Environment Variables
Provider Selection: - ARTCURATOR_PROVIDER (optional) - Set to "gemini" or "openai" for default provider
Provider-Specific (passed through to underlying packages): - Gemini: ART_GEMINI_KEY, ART_GEMINI_MODEL, etc. - OpenAI: ART_OPENAI_KEY, ART_OPENAI_MODEL, etc.
See artgemini README and artopenai README for complete configuration.
Migration Path
Part 1: Unified Interface (Current - ✅ Complete)
Status: Implemented in artcurator v0.0.2+
- ✅ Unified functions available in artcurator
- ✅ Original functions remain in artgemini/artopenai
- ✅ No breaking changes - both APIs work simultaneously
- ✅ Prompts centralized in artcurator/inst/prompts/
Usage: Start migrating new code to use artcurator::art_*_ai():
# Old way (still works)
library(artgemini)
desc <- art_about_ai("artwork.png")
# New way (recommended)
library(artcurator)
desc <- art_about_ai("artwork.png", provider = "gemini")Part 2: Deprecation (Future - ⏳ Planned)
Timeline: TBD based on adoption metrics
- Add
.Deprecated()warnings in artgemini/artopenai - Update dependent packages (modArtist, modGallery, etc.)
- Remove artwork functions from artgemini/artopenai (major version bump)
- artcurator becomes the sole source for artwork analysis
Technical Architecture
File Structure
artcurator/
├── R/
│ ├── artwork-ai.R # Unified interface: art_about_ai, art_style_ai, classify_styles_ai
│ ├── artwork-plus-ai.R # Unified interface: art_profile_ai, art_profile_full_ai
│ ├── internal-provider.R # Provider routing: .resolve_provider, .dispatch_artwork_ai
│ ├── internal-prompts.R # Prompt management: .render_prompt, read_prompt_file
│ └── internal-utils.R # Shared utilities: b64EncodeImage, validators
├── inst/prompts/ # Centralized prompt templates (10 files)
├── data-raw/schema-definitions.R # JSON schemas for validation
└── tests/testthat/
├── test-provider-routing.R # Provider routing tests
└── test-artwork-ai.R # Integration tests
Dispatch Flow
User Call: artcurator::art_about_ai("img.png", provider="gemini", temp=0.7)
↓
.dispatch_artwork_ai("art_about_ai", "gemini", img_path="img.png", temp=0.7)
↓
.resolve_provider("gemini") → "gemini"
↓
do.call(getExportedValue("artgemini", "art_about_ai"),
list(img_path="img.png", temp=0.7))
↓
artcurator::art_about_ai(img_path="img.png", provider="gemini", temp=0.7)
↓
Returns: Character string with description
Testing
Test Coverage
-
Provider routing (
test-provider-routing.R):- Explicit provider selection
- Environment variable fallback
- Auto-detection logic
- Error handling for missing providers
-
Integration (
test-artwork-ai.R):- Functions return correct types
- Both providers work end-to-end
- Provider-specific parameters pass through
- Auto-detection functions correctly
Running Tests
# Run all tests
devtools::test()
# Run specific test file
devtools::test_file("tests/testthat/test-provider-routing.R")
# With coverage
covr::package_coverage()Development Notes
Adding New Artwork Functions
To add a new unified artwork function:
- Ensure the function exists in both artgemini and artopenai with identical signatures
- Add the unified wrapper to appropriate R/ file in artcurator
- Use
.dispatch_artwork_ai(fn_name, provider, ...)pattern - Add roxygen documentation with
@familytag - Add tests to verify routing and both providers
- Run
devtools::document()anddevtools::check()
Prompt Management
Prompts are centralized in artcurator/inst/prompts/: - Each prompt file includes # PROMPT_VERSION: vX.Y header - Use .render_prompt(name, data) for templating with glue - Update prompts in artcurator (not source packages) - Provider packages will eventually reference artcurator prompts (Part 2)
Troubleshooting
Provider Not Found Error
Error: No AI provider available. Install artgemini or artopenai.
Solution: Install at least one provider package:
pak::pkg_install("artalytics/artgemini")
# or
pak::pkg_install("artalytics/artopenai")API Key Not Set
Error: ART_GEMINI_KEY Not Set
# or
Error: ART_OPENAI_KEY not set
Solution: Configure provider API keys:
Sys.setenv(ART_GEMINI_KEY = "your-key")
Sys.setenv(ART_OPENAI_KEY = "sk-your-key")Provider Package Not Installed
Error: artgemini package required but not installed
Solution: Install the requested provider:
pak::pkg_install("artalytics/artgemini")