Tavus Ruby Client
A Ruby gem for interacting with the Tavus API, providing a simple and intuitive interface for managing Conversational Video Interfaces (CVI).
Features
- Conversations Management: Create, retrieve, list, end, and delete real-time video conversations
- Personas Management: Create, retrieve, list, update, and delete AI personas with customizable behavior
- Replicas Management: Create, train, retrieve, list, rename, and delete AI replicas
- Objectives Management: Create, retrieve, list, update, and delete conversation objectives
- Guardrails Management: Create, retrieve, list, update, and delete behavioral guardrails
- Knowledge Base (Documents): Upload, retrieve, list, update, and delete documents for personas
- Video Generation: Generate videos from text or audio, retrieve, list, rename, and delete videos
- Full API Coverage: Support for all Tavus API v2 endpoints
- Easy Configuration: Simple API key configuration
- Comprehensive Error Handling: Detailed error classes for different API responses
- JSON Patch Support: Update personas, objectives, and guardrails using JSON Patch operations (RFC 6902)
Installation
Add this line to your application's Gemfile:
gem 'tavus'
And then execute:
$ bundle install
Or install it yourself as:
$ gem install tavus
Configuration
Global Configuration
Configure the client globally (recommended for Rails applications):
# config/initializers/tavus.rb
Tavus.configure do |config|
config.api_key = ENV['TAVUS_API_KEY']
config.base_url = 'https://tavusapi.com' # Optional, defaults to this
config.timeout = 30 # Optional, defaults to 30 seconds
end
Per-Instance Configuration
You can also configure individual client instances:
client = Tavus::Client.new(
api_key: 'your-api-key',
base_url: 'https://tavusapi.com',
timeout: 30
)
Usage
For more comprehensive examples, check the examples/ directory:
- basic_usage.rb - Basic operations with personas and conversations
- advanced_persona.rb - Advanced persona configuration with custom layers
- complete_workflow.rb - End-to-end workflow including replicas, documents, objectives, guardrails, and videos
Conversations
Create a Conversation
client = Tavus::Client.new(api_key: 'your-api-key')
# Create a conversation with required parameters
conversation = client.conversations.create(
replica_id: 'rfe12d8b9597',
persona_id: 'pdced222244b'
)
# Create a conversation with optional parameters
conversation = client.conversations.create(
replica_id: 'rfe12d8b9597',
persona_id: 'pdced222244b',
conversation_name: 'Interview User',
callback_url: 'https://yourwebsite.com/webhook',
audio_only: false,
conversational_context: 'I want to improve my sales techniques.',
custom_greeting: 'Hey there!',
memory_stores: ['anna'],
document_ids: ['doc_1234567890'],
document_retrieval_strategy: 'balanced',
document_tags: ['sales', 'marketing'],
test_mode: false
)
# Response includes:
# {
# "conversation_id" => "c123456",
# "conversation_name" => "Interview User",
# "status" => "active",
# "conversation_url" => "https://tavus.daily.co/c123456",
# "replica_id" => "rfe12d8b9597",
# "persona_id" => "pdced222244b",
# "created_at" => "2025-10-04T12:00:00Z"
# }
Get a Conversation
conversation = client.conversations.get('c123456')
# Response includes conversation details with status, URLs, etc.
List Conversations
# List all conversations
conversations = client.conversations.list
# List with pagination and filters
conversations = client.conversations.list(
limit: 20,
page: 1,
status: 'active' # or 'ended'
)
# Response includes:
# {
# "data" => [...],
# "total_count" => 123
# }
End a Conversation
result = client.conversations.end('c123456')
Delete a Conversation
result = client.conversations.delete('c123456')
Personas
Create a Persona
# Create a basic persona
persona = client.personas.create(
system_prompt: 'As a Life Coach, you are a dedicated professional...',
persona_name: 'Life Coach',
pipeline_mode: 'full'
)
# Create a persona with advanced configuration
persona = client.personas.create(
system_prompt: 'As a Life Coach...',
persona_name: 'Life Coach',
pipeline_mode: 'full',
context: 'Here are a few times that you have helped...',
default_replica_id: 'rfe12d8b9597',
document_ids: ['d1234567890', 'd2468101214'],
document_tags: ['product_info', 'company_policies'],
layers: {
llm: {
model: 'tavus-gpt-4o',
base_url: 'your-base-url',
api_key: 'your-api-key',
tools: [
{
type: 'function',
function: {
name: 'get_current_weather',
description: 'Get the current weather in a given location',
parameters: {
type: 'object',
properties: {
location: {
type: 'string',
description: 'The city and state, e.g. San Francisco, CA'
},
unit: {
type: 'string',
enum: ['celsius', 'fahrenheit']
}
},
required: ['location']
}
}
}
]
},
tts: {
tts_engine: 'cartesia',
external_voice_id: 'external-voice-id',
voice_settings: {
speed: 0.5,
emotion: ['positivity:high', 'curiosity']
},
tts_emotion_control: 'false',
tts_model_name: 'sonic'
},
perception: {
perception_model: 'raven-0',
ambient_awareness_queries: [
'Is the user showing an ID card?',
'Does the user appear distressed or uncomfortable?'
]
},
stt: {
stt_engine: 'tavus-turbo',
participant_pause_sensitivity: 'low',
participant_interrupt_sensitivity: 'low',
hotwords: 'This is a hotword example',
smart_turn_detection: true
}
}
)
# Response includes:
# {
# "persona_id" => "p5317866",
# "persona_name" => "Life Coach",
# "created_at" => "2025-10-04T12:00:00Z"
# }
Get a Persona
persona = client.personas.get('p5317866')
List Personas
# List all personas
personas = client.personas.list
# List with pagination and filters
personas = client.personas.list(
limit: 20,
page: 1,
persona_type: 'user' # or 'system'
)
# Response includes:
# {
# "data" => [...],
# "total_count" => 123
# }
Update a Persona (JSON Patch)
# Update multiple fields using patch operations
operations = [
{ op: 'replace', path: '/persona_name', value: 'Wellness Advisor' },
{ op: 'replace', path: '/default_replica_id', value: 'r79e1c033f' },
{ op: 'replace', path: '/context', value: 'Updated context...' },
{ op: 'replace', path: '/layers/llm/model', value: 'tavus-gpt-4o' },
{ op: 'add', path: '/layers/tts/tts_emotion_control', value: 'true' },
{ op: 'remove', path: '/layers/stt/hotwords' }
]
result = client.personas.patch('p5317866', operations)
# Helper method to build patch operations
operation = client.personas.build_patch_operation(
'/persona_name',
'New Name',
operation: 'replace'
)
# Convenient method to update a single field
result = client.personas.update_field(
'p5317866',
'/persona_name',
'New Name'
)
Delete a Persona
result = client.personas.delete('p5317866')
Replicas
Create a Replica
# Create a replica for conversational video
replica = client.replicas.create(
train_video_url: 'https://my-bucket.s3.amazonaws.com/training-video.mp4',
replica_name: 'My Replica',
model_name: 'phoenix-3', # Optional, defaults to phoenix-3
consent_video_url: 'https://my-bucket.s3.amazonaws.com/consent-video.mp4', # Optional
callback_url: 'https://yourwebsite.com/webhook'
)
# Response includes:
# {
# "replica_id" => "r783537ef5",
# "status" => "started"
# }
Get a Replica
# Get basic replica info
replica = client.replicas.get('r783537ef5')
# Get detailed replica info with verbose flag
replica = client.replicas.get('r783537ef5', verbose: true)
List Replicas
# List all replicas
replicas = client.replicas.list
# List with filters
replicas = client.replicas.list(
limit: 20,
page: 1,
replica_type: 'user', # or 'system'
replica_ids: 're1074c227,r243eed46c',
verbose: true
)
Rename a Replica
client.replicas.rename('r783537ef5', 'Updated Replica Name')
Delete a Replica
# Soft delete
client.replicas.delete('r783537ef5')
# Hard delete (irreversible - deletes all assets)
client.replicas.delete('r783537ef5', hard: true)
Objectives
Create Objectives
objectives = client.objectives.create(
data: [
{
objective_name: 'Gather User Feedback',
objective_prompt: 'Ask the user about their experience with the product',
confirmation_mode: 'automatic',
modality: 'verbal'
}
]
)
Get an Objective
objective = client.objectives.get('o12345')
List Objectives
objectives = client.objectives.list(limit: 20, page: 1)
Update an Objective
operations = [
{ op: 'replace', path: '/data/0/objective_name', value: 'Updated Objective' },
{ op: 'replace', path: '/data/0/confirmation_mode', value: 'manual' }
]
client.objectives.patch('o12345', operations)
# Or update a single field
client.objectives.update_field('o12345', '/data/0/objective_name', 'New Name')
Delete an Objective
client.objectives.delete('o12345')
Guardrails
Create Guardrails
guardrails = client.guardrails.create(
name: 'Healthcare Compliance Guardrails',
data: [
{
guardrails_prompt: 'Never discuss competitor products or share sensitive medical information',
modality: 'verbal',
callback_url: 'https://your-server.com/webhook'
}
]
)
Get Guardrails
guardrails = client.guardrails.get('g12345')
List Guardrails
guardrails = client.guardrails.list(limit: 20, page: 1)
Update Guardrails
operations = [
{ op: 'replace', path: '/data/0/guardrails_prompt', value: 'Updated guardrails prompt' },
{ op: 'add', path: '/data/0/callback_url', value: 'https://new-server.com/webhook' }
]
client.guardrails.patch('g12345', operations)
# Or update a single field
client.guardrails.update_field('g12345', '/data/0/guardrails_prompt', 'New prompt')
Delete Guardrails
client.guardrails.delete('g12345')
Documents (Knowledge Base)
Create a Document
# Upload from URL
document = client.documents.create(
document_url: 'https://example.com/document.pdf',
document_name: 'Product Documentation',
callback_url: 'https://your-server.com/webhook',
tags: ['product', 'documentation'],
properties: { department: 'sales', priority: 'high' }
)
# Supported formats: .pdf, .txt, .docx, .doc, .png, .jpg, .pptx, .csv, .xlsx
# Also supports website URLs for snapshots
Get a Document
document = client.documents.get('d290f1ee-6c54-4b01-90e6-d701748f0851')
List Documents
# List all documents
documents = client.documents.list
# List with filters
documents = client.documents.list(
limit: 20,
page: 0,
sort: 'descending',
status: 'ready',
tags: 'product,documentation'
)
Update a Document
client.documents.update(
'd290f1ee-6c54-4b01-90e6-d701748f0851',
document_name: 'Updated Document Name',
tags: ['updated', 'important']
)
Delete a Document
client.documents.delete('d290f1ee-6c54-4b01-90e6-d701748f0851')
Videos
Generate a Video
# Generate video from text script
video = client.videos.create(
replica_id: 'r783537ef5',
script: 'Hello from Tavus! Enjoy your new replica',
video_name: 'My First Video',
background_url: 'https://yourwebsite.com/',
callback_url: 'https://yourwebsite.com/webhook'
)
# Or use the convenient method
video = client.videos.generate_from_text(
replica_id: 'r783537ef5',
script: 'Hello from Tavus!',
video_name: 'My Video'
)
# Generate video from audio file
video = client.videos.generate_from_audio(
replica_id: 'r783537ef5',
audio_url: 'https://my-bucket.s3.amazonaws.com/audio.mp3',
video_name: 'Audio Video'
)
# Advanced options
video = client.videos.create(
replica_id: 'r783537ef5',
script: 'Hello!',
fast: true, # Use fast rendering
transparent_background: true, # Requires fast: true
watermark_image_url: 'https://s3.amazonaws.com/watermark.png',
background_source_url: 'https://my-bucket.s3.amazonaws.com/background.mp4'
)
# Response includes:
# {
# "video_id" => "abcd123",
# "status" => "queued",
# "hosted_url" => "https://tavus.video/abcd123"
# }
Get a Video
# Get basic video info
video = client.videos.get('abcd123')
# Get detailed info with thumbnails
video = client.videos.get('abcd123', verbose: true)
# Response includes download_url, stream_url, hosted_url when ready
List Videos
videos = client.videos.list(limit: 20, page: 1)
Rename a Video
client.videos.rename('abcd123', 'New Video Name')
Delete a Video
# Soft delete
client.videos.delete('abcd123')
# Hard delete (irreversible - deletes all assets)
client.videos.delete('abcd123', hard: true)
Error Handling
The gem provides specific error classes for different API responses:
begin
conversation = client.conversations.create(replica_id: 'invalid')
rescue Tavus::AuthenticationError => e
# Handle authentication errors (401)
puts "Authentication failed: #{e.message}"
rescue Tavus::BadRequestError => e
# Handle bad request errors (400)
puts "Bad request: #{e.message}"
rescue Tavus::NotFoundError => e
# Handle not found errors (404)
puts "Resource not found: #{e.message}"
rescue Tavus::ValidationError => e
# Handle validation errors (422)
puts "Validation failed: #{e.message}"
rescue Tavus::RateLimitError => e
# Handle rate limit errors (429)
puts "Rate limit exceeded: #{e.message}"
rescue Tavus::ServerError => e
# Handle server errors (5xx)
puts "Server error: #{e.message}"
rescue Tavus::ApiError => e
# Handle any other API errors
puts "API error: #{e.message}"
rescue Tavus::ConfigurationError => e
# Handle configuration errors
puts "Configuration error: #{e.message}"
end
API Reference
Conversations
Method | Description |
---|---|
create(replica_id:, persona_id:, **options) |
Create a new conversation |
get(conversation_id) |
Get a conversation by ID |
list(**options) |
List all conversations |
end(conversation_id) |
End a conversation |
delete(conversation_id) |
Delete a conversation |
Personas
Method | Description |
---|---|
create(system_prompt:, **options) |
Create a new persona |
get(persona_id) |
Get a persona by ID |
list(**options) |
List all personas |
patch(persona_id, operations) |
Update a persona using JSON Patch |
build_patch_operation(field, value, operation:) |
Build a JSON Patch operation |
update_field(persona_id, field, value) |
Update a single field |
delete(persona_id) |
Delete a persona |
Replicas
Method | Description |
---|---|
create(train_video_url:, **options) |
Create a new replica |
get(replica_id, verbose: false) |
Get a replica by ID |
list(**options) |
List all replicas |
rename(replica_id, replica_name) |
Rename a replica |
delete(replica_id, hard: false) |
Delete a replica |
Objectives
Method | Description |
---|---|
create(data:) |
Create new objectives |
get(objectives_id) |
Get an objective by ID |
list(**options) |
List all objectives |
patch(objectives_id, operations) |
Update an objective using JSON Patch |
build_patch_operation(field, value, operation:) |
Build a JSON Patch operation |
update_field(objectives_id, field, value) |
Update a single field |
delete(objectives_id) |
Delete an objective |
Guardrails
Method | Description |
---|---|
create(name:, data:) |
Create new guardrails |
get(guardrails_id) |
Get guardrails by ID |
list(**options) |
List all guardrails |
patch(guardrails_id, operations) |
Update guardrails using JSON Patch |
build_patch_operation(field, value, operation:) |
Build a JSON Patch operation |
update_field(guardrails_id, field, value) |
Update a single field |
delete(guardrails_id) |
Delete guardrails |
Documents (Knowledge Base)
Method | Description |
---|---|
create(document_url:, **options) |
Upload a new document |
get(document_id) |
Get a document by ID |
list(**options) |
List all documents |
update(document_id, **options) |
Update document metadata |
delete(document_id) |
Delete a document |
Videos
Method | Description |
---|---|
create(replica_id:, **options) |
Generate a new video |
generate_from_text(replica_id:, script:, **options) |
Generate video from text |
generate_from_audio(replica_id:, audio_url:, **options) |
Generate video from audio |
get(video_id, verbose: false) |
Get a video by ID |
list(**options) |
List all videos |
rename(video_id, video_name) |
Rename a video |
delete(video_id, hard: false) |
Delete a video |
JSON Patch Operations
Several resources (Personas, Objectives, and Guardrails) support updates via JSON Patch operations following RFC 6902. This allows for precise, atomic updates to specific fields.
Supported Operations
-
add
: Add a new field or array element -
remove
: Remove a field or array element -
replace
: Replace an existing field value -
copy
: Copy a value from one location to another -
move
: Move a value from one location to another -
test
: Test that a value at a location equals a specified value
Examples
# Replace a single field
operations = [
{ op: 'replace', path: '/persona_name', value: 'New Name' }
]
# Multiple operations in one request
operations = [
{ op: 'replace', path: '/persona_name', value: 'Updated Name' },
{ op: 'add', path: '/layers/tts/tts_emotion_control', value: 'true' },
{ op: 'remove', path: '/layers/stt/hotwords' }
]
# Update nested fields
operations = [
{ op: 'replace', path: '/layers/llm/model', value: 'tavus-gpt-4o' }
]
Development
After checking out the repo, run bin/setup
to install dependencies. Then, run rake spec
to run the tests. You can also run bin/console
for an interactive prompt that will allow you to experiment.
To install this gem onto your local machine, run bundle exec rake install
.
CI/CD
This project uses GitHub Actions for continuous integration:
- Tests: Runs on Ruby 2.7, 3.0, 3.1, 3.2, and 3.3
- Linting: RuboCop style checking
- Security: Bundle audit for dependency vulnerabilities
Contributing
Bug reports and pull requests are welcome on GitHub at https://github.com/vbrazo/tavus.
License
The gem is available as open source under the terms of the MIT License.
Resources
Changelog
See CHANGELOG.md for a detailed list of changes and version history.