venice-ai-sdk-apl
Version:
A comprehensive SDK for the Venice AI API with CLI support, programmatic CLI usage, CLI-style interface, and interactive demo
1,282 lines • 56 kB
JavaScript
#!/usr/bin/env node
"use strict";
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
if (k2 === undefined) k2 = k;
var desc = Object.getOwnPropertyDescriptor(m, k);
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
desc = { enumerable: true, get: function() { return m[k]; } };
}
Object.defineProperty(o, k2, desc);
}) : (function(o, m, k, k2) {
if (k2 === undefined) k2 = k;
o[k2] = m[k];
}));
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
Object.defineProperty(o, "default", { enumerable: true, value: v });
}) : function(o, v) {
o["default"] = v;
});
var __importStar = (this && this.__importStar) || function (mod) {
if (mod && mod.__esModule) return mod;
var result = {};
if (mod != null) for (var k in mod) if (k !== "default" && Object.prototype.hasOwnProperty.call(mod, k)) __createBinding(result, mod, k);
__setModuleDefault(result, mod);
return result;
};
Object.defineProperty(exports, "__esModule", { value: true });
exports.runCli = exports.commands = void 0;
const commander_1 = require("commander");
const index_1 = require("./index");
const fs = __importStar(require("fs"));
const path = __importStar(require("path"));
const https = __importStar(require("https"));
const readline = __importStar(require("readline"));
// Get package version
const packageJson = JSON.parse(fs.readFileSync(path.join(__dirname, '../package.json'), 'utf8'));
const version = packageJson.version;
// Load config from user's home directory
const configPath = path.join(process.env.HOME || process.env.USERPROFILE || '', '.venice-config.json');
let config = {};
try {
config = JSON.parse(fs.readFileSync(configPath, 'utf8'));
}
catch (error) {
// Config file doesn't exist yet
}
// Helper function for debug logging
const debugLog = (message, data) => {
if (global.debug) {
console.log(`Debug - ${message}:`, data ? JSON.stringify(data, null, 2) : '');
}
};
// Create a function to get the Venice client
const getClient = () => {
const apiKey = process.env.VENICE_API_KEY || config.apiKey;
if (!apiKey) {
console.error('Error: API key not found. Please set the VENICE_API_KEY environment variable or run "venice configure"');
process.exit(1);
}
const client = new index_1.VeniceAI({
apiKey,
});
// Enable debug logging in the SDK if debug flag is set
if (global.debug) {
client.enableDebugLogging();
}
return client;
};
// Command implementations for programmatic usage
exports.commands = {
// Chat command implementation
chat: async (prompt, options = {}) => {
try {
const venice = getClient();
const messages = [];
if (options.system) {
messages.push({ role: 'system', content: options.system });
}
// Handle complex message content (for vision models)
if (options.image) {
const content = [];
content.push({ type: 'text', text: prompt });
// Handle image input (base64, URL, or file path)
if (options.image.startsWith('data:') || options.image.match(/^[A-Za-z0-9+/=]+$/)) {
content.push({
type: 'image_url',
image_url: { url: options.image }
});
}
else if (options.image.startsWith('http')) {
content.push({
type: 'image_url',
image_url: { url: options.image }
});
}
else {
const imageBuffer = fs.readFileSync(options.image);
const base64Image = imageBuffer.toString('base64');
const mimeType = options.image.endsWith('.png') ? 'image/png' :
options.image.endsWith('.jpg') || options.image.endsWith('.jpeg') ? 'image/jpeg' :
'application/octet-stream';
content.push({
type: 'image_url',
image_url: { url: `data:${mimeType};base64,${base64Image}` }
});
}
messages.push({ role: 'user', content });
}
else {
messages.push({ role: 'user', content: prompt });
}
// Handle functions if provided
let functions;
if (options.functionsFile) {
const functionsContent = fs.readFileSync(options.functionsFile, 'utf8');
functions = JSON.parse(functionsContent);
}
else if (options.functions) {
functions = JSON.parse(options.functions);
}
// Prepare venice_parameters
const veniceParameters = {};
// Web search options
if (options.webSearch === 'on' || options.webSearch === true) {
veniceParameters.enable_web_search = 'on';
}
else if (options.webSearch === 'off') {
veniceParameters.enable_web_search = 'off';
}
else if (options.webSearch === 'auto') {
veniceParameters.enable_web_search = 'auto';
}
// System prompt control
if (options.noSystemPrompt) {
veniceParameters.include_venice_system_prompt = false;
}
// Character interaction
if (options.character) {
veniceParameters.character_slug = options.character;
}
// Determine model
let model = options.model || 'llama-3.3-70b';
// Handle character in model parameter (character:slug format)
if (model && model.startsWith('character:')) {
veniceParameters.character_slug = model.replace('character:', '');
model = 'default'; // Use default model when specifying character
}
// Handle model feature suffix
if (options.modelFeatures) {
model = `${model}:${options.modelFeatures}`;
}
// Create request parameters
const requestParams = {
model,
messages,
stream: options.stream,
};
// Add functions if provided
if (functions) {
requestParams.functions = functions;
if (options.forceFunctionCall) {
requestParams.function_call = 'auto';
}
}
// Add venice_parameters if any are set
if (Object.keys(veniceParameters).length > 0) {
requestParams.venice_parameters = veniceParameters;
}
if (global.debug) {
debugLog('Chat request', requestParams);
}
// Handle streaming
if (options.stream) {
return { stream: true, requestParams };
}
const response = await venice.chat.completions.create(requestParams);
if (global.debug) {
debugLog('Chat response', response);
}
// Return raw response if requested
if (options.raw) {
return response;
}
return response.choices[0].message.content;
}
catch (error) {
throw new Error(`Chat error: ${error.message}`);
}
},
// List keys command implementation
listKeys: async (options = {}) => {
try {
const venice = getClient();
const response = await venice.apiKeys.list();
if (response.keys.length === 0) {
return { keys: [], total: 0 };
}
if (global.debug) {
debugLog('First key details', response.keys[0]);
debugLog('Response metadata', response._metadata);
}
// Return raw response if requested
if (options.raw) {
return response;
}
// Map and potentially filter the keys
let keys = response.keys.map((key) => ({
id: key.id,
name: key.name || key.description,
created: key.createdAt ? new Date(key.createdAt) : null,
expires: key.expiresAt ? new Date(key.expiresAt) : null,
type: key.apiKeyType,
lastUsed: key.lastUsedAt ? new Date(key.lastUsedAt) : null,
usage: key.usage
}));
// Filter by type if specified
if (options.type) {
keys = keys.filter(key => key.type.toLowerCase() === options.type.toLowerCase());
}
// Apply limit if specified
if (options.limit && options.limit > 0 && options.limit < keys.length) {
keys = keys.slice(0, options.limit);
}
return {
keys,
total: response.keys.length,
filtered: keys.length
};
}
catch (error) {
throw new Error(`List keys error: ${error.message}`);
}
},
// Create key command implementation
createKey: async (name, options = {}) => {
try {
const venice = getClient();
const response = await venice.apiKeys.create({
name
});
if (global.debug) {
debugLog('Create key response', response);
}
// Return raw response if requested
if (options.raw) {
return response;
}
return {
id: response.key.id,
key: response.key.key,
name: response.key.description || name,
created: new Date(response.key.createdAt),
expires: response.key.expiresAt ? new Date(response.key.expiresAt) : null
};
}
catch (error) {
throw new Error(`Create key error: ${error.message}`);
}
},
// Delete key command implementation
deleteKey: async (id, options = {}) => {
try {
const venice = getClient();
const response = await venice.apiKeys.delete({
id
});
if (global.debug) {
debugLog('Delete key response', response);
}
// Return raw response if requested
if (options.raw) {
return response;
}
return { success: response.success };
}
catch (error) {
throw new Error(`Delete key error: ${error.message}`);
}
},
// List models command implementation
listModels: async (options = {}) => {
try {
const venice = getClient();
const response = await venice.models.list();
if (global.debug) {
debugLog('List models response', response);
}
// Return raw response if requested
if (options.raw) {
return response;
}
// Map and potentially filter the models
let models = response.data.map((model) => ({
id: model.id,
name: model.name || model.id,
type: model.type || 'Unknown'
}));
// Filter by type if specified
if (options.type) {
models = models.filter(model => model.type.toLowerCase() === options.type.toLowerCase());
}
// Apply limit if specified
if (options.limit && options.limit > 0 && options.limit < models.length) {
models = models.slice(0, options.limit);
}
return {
models,
total: response.data.length,
filtered: models.length
};
}
catch (error) {
throw new Error(`List models error: ${error.message}`);
}
},
// Generate image command implementation
generateImage: async (prompt, options = {}) => {
try {
const venice = getClient();
const imageParams = {
model: options.model || 'fluently-xl',
prompt: prompt,
negative_prompt: options.negative,
style_preset: options.style,
height: options.height || 1024,
width: options.width || 1024
};
if (global.debug) {
debugLog('Image generation request', imageParams);
}
const response = await venice.image.generate(imageParams);
if (global.debug) {
debugLog('Image generation response', response);
}
// Return raw response if requested
if (options.raw) {
return response;
}
const result = { url: response.images[0].url };
// If outputPath is provided, download the image
if (options.outputPath && response.images[0].url) {
await new Promise((resolve, reject) => {
const file = fs.createWriteStream(options.outputPath);
https.get(response.images[0].url, function (response) {
response.pipe(file);
file.on('finish', () => {
resolve();
});
}).on('error', (err) => {
reject(new Error(`Error downloading image: ${err.message}`));
});
});
return { ...result, savedTo: options.outputPath };
}
return result;
}
catch (error) {
throw new Error(`Generate image error: ${error.message}`);
}
},
// List styles command implementation
listStyles: async (options = {}) => {
try {
const venice = getClient();
const response = await venice.image.styles.list();
if (global.debug) {
debugLog('List styles response', response);
}
// Return raw response if requested
if (options.raw) {
return response;
}
// Map and potentially limit the styles
let styles = response.styles.map((style) => ({
id: style.id,
name: style.name || style.id,
description: style.description || 'No description'
}));
// Apply limit if specified
if (options.limit && options.limit > 0 && options.limit < styles.length) {
styles = styles.slice(0, options.limit);
}
return {
styles,
total: response.styles.length
};
}
catch (error) {
throw new Error(`List styles error: ${error.message}`);
}
},
// Configure API key
configure: (apiKey) => {
try {
fs.writeFileSync(configPath, JSON.stringify({ apiKey }));
return { success: true };
}
catch (error) {
throw new Error(`Configure error: ${error.message}`);
}
},
// Enable debug mode
enableDebug: () => {
global.debug = true;
return { debug: true };
},
// Disable debug mode
disableDebug: () => {
global.debug = false;
return { debug: false };
},
// Get rate limits command implementation
rateLimits: async (options = {}) => {
try {
const venice = getClient();
if (options.model) {
const modelLimits = await venice.apiKeys.getModelRateLimits(options.model);
if (global.debug) {
debugLog('Model rate limits response', modelLimits);
}
// Return raw response if requested
if (options.raw) {
return modelLimits;
}
return {
model: options.model,
limits: modelLimits
};
}
else {
const response = await venice.apiKeys.rateLimits();
if (global.debug) {
debugLog('Rate limits response', response);
}
// Return raw response if requested
if (options.raw) {
return response;
}
return {
limits: response.rate_limits
};
}
}
catch (error) {
throw new Error(`Rate limits error: ${error.message}`);
}
},
// List characters command implementation
listCharacters: async (options = {}) => {
try {
const venice = getClient();
const response = await venice.characters.list();
if (global.debug) {
debugLog('List characters response', response);
}
// Return raw response if requested
if (options.raw) {
return response;
}
// Get characters from the data array
const characters = response.data || [];
if (characters.length === 0) {
return {
characters: [],
total: 0,
filtered: 0
};
}
// Map and potentially limit the characters
let mappedCharacters = characters.map((character) => ({
name: character.name || 'Unnamed',
slug: character.slug || 'N/A',
description: character.description || 'No description',
model: character.modelId || 'N/A'
}));
// Apply limit if specified
if (options.limit && options.limit > 0 && options.limit < mappedCharacters.length) {
mappedCharacters = mappedCharacters.slice(0, options.limit);
}
return {
characters: mappedCharacters,
total: characters.length,
filtered: mappedCharacters.length
};
}
catch (error) {
throw new Error(`List characters error: ${error.message}`);
}
},
// Get VVV circulating supply command implementation
vvvCirculatingSupply: async (options = {}) => {
try {
const venice = getClient();
const response = await venice.vvv.circulatingSupply();
if (global.debug) {
debugLog('VVV circulating supply response', response);
}
// Return raw response if requested
if (options.raw) {
return response;
}
// Handle both new and old response formats
if (response.result) {
// New format
const circulatingSupply = parseFloat(response.result);
return {
circulating_supply: circulatingSupply,
result: response.result,
timestamp: new Date().toLocaleString()
};
}
else if (response.circulating_supply) {
// Old format
return {
circulating_supply: response.circulating_supply,
total_supply: response.total_supply,
percentage_circulating: response.percentage_circulating ||
(response.circulating_supply / response.total_supply * 100).toFixed(2) + '%',
timestamp: response.timestamp ? new Date(response.timestamp).toLocaleString() : new Date().toLocaleString()
};
}
// Fallback
return response;
}
catch (error) {
throw new Error(`VVV circulating supply error: ${error.message}`);
}
},
// Get VVV network utilization command implementation
vvvUtilization: async (options = {}) => {
try {
const venice = getClient();
const response = await venice.vvv.utilization();
if (global.debug) {
debugLog('VVV utilization response', response);
}
// Return raw response if requested
if (options.raw) {
return response;
}
// Handle the new API response format
if (response.percentage !== undefined) {
return {
utilization_percentage: (response.percentage * 100).toFixed(4) + '%',
timestamp: new Date().toLocaleString()
};
}
// Handle the old API response format
else if (response.utilization_percentage !== undefined) {
return {
utilization_percentage: response.utilization_percentage + '%',
capacity: response.capacity,
usage: response.usage,
timestamp: response.timestamp ? new Date(response.timestamp).toLocaleString() : new Date().toLocaleString(),
historical_data: response.historical_data
};
}
// Fallback
return response;
}
catch (error) {
throw new Error(`VVV utilization error: ${error.message}`);
}
},
// Get VVV staking yield command implementation
vvvStakingYield: async (options = {}) => {
try {
const venice = getClient();
const response = await venice.vvv.stakingYield();
if (global.debug) {
debugLog('VVV staking yield response', response);
}
// Return raw response if requested
if (options.raw) {
return response;
}
// Handle the new API response format
if (response.stakingYield !== undefined && response.totalStaked !== undefined) {
return {
current_apy: (parseFloat(response.stakingYield) * 100).toFixed(4) + '%',
total_staked: parseFloat(response.totalStaked),
total_emission: response.totalEmission,
staker_distribution: response.stakerDistribution,
timestamp: new Date().toLocaleString()
};
}
// Handle the old API response format
else if (response.current_apy !== undefined && response.total_staked !== undefined) {
return {
current_apy: response.current_apy + '%',
total_staked: response.total_staked,
percentage_staked: response.percentage_staked ? response.percentage_staked + '%' : 'N/A',
timestamp: response.timestamp ? new Date(response.timestamp).toLocaleString() : new Date().toLocaleString(),
historical_data: response.historical_data
};
}
// Fallback
return response;
}
catch (error) {
throw new Error(`VVV staking yield error: ${error.message}`);
}
}
};
// Setup CLI commands
const program = new commander_1.Command();
program
.name('venice')
.description('Venice AI CLI - Interact with Venice AI API from the command line')
.version(version)
.option('-d, --debug', 'Enable debug output')
.option('-r, --raw', 'Output raw JSON data (useful for scripting)')
.hook('preAction', (thisCommand) => {
// Store flags in global variables
global.debug = thisCommand.opts().debug;
global.raw = thisCommand.opts().raw;
});
// Configure API key
program
.command('configure')
.description('Configure your Venice API key')
.action(() => {
const rl = readline.createInterface({
input: process.stdin,
output: process.stdout
});
rl.question('Enter your Venice API key: ', (apiKey) => {
fs.writeFileSync(configPath, JSON.stringify({ apiKey }));
console.log('API key saved successfully!');
rl.close();
});
});
// List API keys
program
.command('list-keys')
.description('List your Venice API keys')
.action(async () => {
try {
const venice = getClient();
const response = await venice.apiKeys.list();
if (response.keys.length === 0) {
console.log('No API keys found.');
return;
}
// Log detailed information in debug mode
if (response.keys.length > 0) {
debugLog('First key details', response.keys[0]);
debugLog('Response metadata', response._metadata);
}
if (global.raw) {
// Output raw JSON for scripting
console.log(JSON.stringify(response, null, 2));
}
else {
// Pretty output for human consumption
console.log('API Keys:');
console.log(`Total keys: ${response.keys.length}`);
console.table(response.keys.map((key) => ({
id: key.id,
name: key.name || key.description,
created: key.createdAt ? new Date(key.createdAt).toLocaleString() : 'N/A',
expires: key.expiresAt ? new Date(key.expiresAt).toLocaleString() : 'N/A'
})));
}
}
catch (error) {
console.error('Error:', error.message);
}
});
// Create API key
program
.command('create-key')
.description('Create a new Venice API key')
.requiredOption('-n, --name <name>', 'Name for the new API key')
.action(async (options) => {
try {
const venice = getClient();
const response = await venice.apiKeys.create({
name: options.name
});
debugLog('Create key response', response);
if (global.raw) {
// Output raw JSON for scripting
console.log(JSON.stringify(response, null, 2));
}
else {
// Pretty output for human consumption
console.log('API Key created successfully:');
console.log(`ID: ${response.key.id}`);
console.log(`Key: ${response.key.key}`);
console.log(`Name: ${response.key.description || options.name}`);
console.log(`Created: ${new Date(response.key.createdAt).toLocaleString()}`);
}
}
catch (error) {
console.error('Error:', error.message);
}
});
// Delete API key
program
.command('delete-key')
.description('Delete a Venice API key')
.requiredOption('-i, --id <id>', 'ID of the API key to delete')
.action(async (options) => {
try {
const venice = getClient();
const response = await venice.apiKeys.delete({
id: options.id
});
debugLog('Delete key response', response);
if (global.raw) {
// Output raw JSON for scripting
console.log(JSON.stringify(response, null, 2));
}
else {
// Pretty output for human consumption
if (response.success) {
console.log(`API Key ${options.id} deleted successfully.`);
}
else {
console.log('Failed to delete API key.');
}
}
}
catch (error) {
console.error('Error:', error.message);
}
});
// Get API key rate limits
program
.command('rate-limits')
.description('Get rate limits for your API key')
.option('-m, --model <model>', 'Get rate limits for a specific model')
.action(async (options) => {
try {
const venice = getClient();
if (options.model) {
const modelLimits = await venice.apiKeys.getModelRateLimits(options.model);
debugLog('Model rate limits response', modelLimits);
if (global.raw) {
// Output raw JSON for scripting
console.log(JSON.stringify(modelLimits, null, 2));
}
else {
// Pretty output for human consumption
console.log(`Rate limits for model ${options.model}:`);
console.log(modelLimits);
}
}
else {
const response = await venice.apiKeys.rateLimits();
debugLog('Rate limits response', response);
if (global.raw) {
// Output raw JSON for scripting
console.log(JSON.stringify(response, null, 2));
}
else {
// Pretty output for human consumption
console.log('Rate limits for all models:');
console.log(response.rate_limits);
}
}
}
catch (error) {
console.error('Error:', error.message);
}
});
// List models
program
.command('list-models')
.description('List available Venice AI models')
.option('-t, --type <type>', 'Model type (all, text, code, image)', 'all')
.option('-l, --limit <number>', 'Limit the number of models displayed')
.action(async (options) => {
try {
const venice = getClient();
const response = await venice.models.list();
debugLog('List models response', response);
// Filter models by type if specified
let filteredModels = response.data;
if (options.type && options.type !== 'all') {
filteredModels = response.data.filter((model) => model.type && model.type.toLowerCase() === options.type.toLowerCase());
}
// Apply limit if specified
let displayModels = [...filteredModels];
if (options.limit && !isNaN(parseInt(options.limit))) {
const limit = parseInt(options.limit);
displayModels = displayModels.slice(0, limit);
}
if (global.raw || options.raw) {
// Output raw JSON for scripting
console.log(JSON.stringify(response, null, 2));
}
else {
// Pretty output for human consumption
console.log('Available Models:');
console.log(`Total models: ${response.data.length}`);
if (filteredModels.length !== response.data.length) {
console.log(`Filtered to ${filteredModels.length} ${options.type} models`);
}
if (displayModels.length !== filteredModels.length) {
console.log(`Showing ${displayModels.length} of ${filteredModels.length} models`);
}
console.table(displayModels.map((model) => ({
id: model.id,
name: model.name || model.id,
type: model.type || 'Unknown'
})));
}
}
catch (error) {
console.error('Error:', error.message);
}
});
// List model traits
program
.command('list-model-traits')
.description('List model traits')
.option('-t, --type <type>', 'Model type (text, image)', 'text')
.option('-r, --raw', 'Output raw JSON response')
.action(async (options) => {
try {
const venice = getClient();
const response = await venice.models.traits();
if (global.raw || options.raw) {
console.log(JSON.stringify(response, null, 2));
}
else {
console.log('Model Traits:');
console.log(`Type: ${options.type}`);
console.log(`Total traits: ${response.traits.length}`);
console.table(response.traits);
}
}
catch (error) {
console.error('Error:', error.message);
}
});
// List model compatibility
program
.command('list-model-compatibility')
.description('List model compatibility mappings')
.option('-t, --type <type>', 'Model type (text, image)', 'text')
.option('-r, --raw', 'Output raw JSON response')
.action(async (options) => {
try {
const venice = getClient();
const response = await venice.models.compatibility();
if (global.raw || options.raw) {
console.log(JSON.stringify(response, null, 2));
}
else {
console.log('Model Compatibility Mappings:');
console.log(`Type: ${options.type}`);
console.log(`Total mappings: ${Object.keys(response.mappings).length}`);
console.table(Object.entries(response.mappings).map(([key, value]) => ({
'External Model': key,
'Venice Model': value
})));
}
}
catch (error) {
console.error('Error:', error.message);
}
});
// Generate chat completion
program
.command('chat')
.description('Generate a chat completion')
.argument('<prompt>', 'The prompt to send to the AI')
.option('-m, --model <model>', 'Model to use (or character:slug for character chat)', 'llama-3.3-70b')
.option('-w, --web-search <mode>', 'Web search mode (on, off, auto)', 'off')
.option('-s, --system <system>', 'System message')
.option('-i, --image <path>', 'Path to image file, URL, or base64 data (for vision models)')
.option('-f, --functions <json>', 'JSON string of function definitions')
.option('-F, --functions-file <path>', 'Path to JSON file with function definitions')
.option('--force-function-call', 'Force the model to call a function')
.option('--stream', 'Stream the response')
.option('--no-system-prompt', 'Remove Venice system prompt')
.option('--character <slug>', 'Character slug to use')
.option('--model-features <features>', 'Model feature suffix (e.g., "enable_web_search=on")')
.option('-r, --raw', 'Output raw JSON response')
.action(async (prompt, options) => {
try {
const venice = getClient();
if (options.stream) {
// Handle streaming
console.log('Streaming response:');
const messages = [];
if (options.system) {
messages.push({ role: 'system', content: options.system });
}
messages.push({ role: 'user', content: prompt });
// Prepare venice_parameters
const veniceParameters = {};
// Web search options
if (options.webSearch === 'on') {
veniceParameters.enable_web_search = 'on';
}
else if (options.webSearch === 'auto') {
veniceParameters.enable_web_search = 'auto';
}
// System prompt control
if (options.noSystemPrompt === false) {
veniceParameters.include_venice_system_prompt = false;
}
// Character interaction
if (options.character) {
veniceParameters.character_slug = options.character;
}
// Determine model
let model = options.model || 'llama-3.3-70b';
// Handle character in model parameter (character:slug format)
if (model.startsWith('character:')) {
veniceParameters.character_slug = model.replace('character:', '');
model = 'default'; // Use default model when specifying character
}
// Create stream
const stream = await venice.chat.completions.createStream({
model,
messages,
stream: true,
venice_parameters: Object.keys(veniceParameters).length > 0 ? veniceParameters : undefined
});
// Process stream
for await (const chunk of stream) {
process.stdout.write(chunk.choices[0]?.delta?.content || '');
}
console.log(); // Add newline at end
}
else {
// Non-streaming request
const result = await exports.commands.chat(prompt, {
model: options.model,
webSearch: options.webSearch,
system: options.system,
image: options.image,
functions: options.functions,
functionsFile: options.functionsFile,
forceFunctionCall: options.forceFunctionCall,
noSystemPrompt: !options.systemPrompt,
character: options.character,
modelFeatures: options.modelFeatures,
raw: options.raw || global.raw
});
if (global.raw || options.raw) {
console.log(JSON.stringify(result, null, 2));
}
else {
console.log(result);
}
}
}
catch (error) {
console.error('Error:', error.message);
}
});
// Vision chat command
program
.command('vision-chat')
.description('Generate a chat completion with image input')
.argument('<prompt>', 'The text prompt to send to the AI')
.requiredOption('-i, --image <path>', 'Path to image file, URL, or base64 data')
.option('-m, --model <model>', 'Model to use', 'qwen-2.5-vl')
.option('-w, --web-search', 'Enable web search')
.option('-s, --system <system>', 'System message')
.option('--character <slug>', 'Character slug to use')
.option('-r, --raw', 'Output raw JSON response')
.action(async (prompt, options) => {
try {
// Use the existing chat command with image parameter
const result = await exports.commands.chat(prompt, {
model: options.model,
webSearch: options.webSearch ? 'on' : undefined,
system: options.system,
image: options.image,
character: options.character,
raw: options.raw || global.raw
});
if (global.raw || options.raw) {
console.log(JSON.stringify(result, null, 2));
}
else {
console.log(result);
}
}
catch (error) {
console.error('Error:', error.message);
}
});
// Function calling command
program
.command('function-chat')
.description('Generate a chat completion with function calling')
.argument('<prompt>', 'The prompt to send to the AI')
.option('-m, --model <model>', 'Model to use', 'mistral-codestral-22b')
.option('-f, --functions <json>', 'JSON string of function definitions')
.option('-F, --functions-file <path>', 'Path to JSON file with function definitions')
.option('--force-function-call', 'Force the model to call a function')
.option('--character <slug>', 'Character slug to use')
.option('-r, --raw', 'Output raw JSON response')
.action(async (prompt, options) => {
try {
// Use the existing chat command with function parameters
const result = await exports.commands.chat(prompt, {
model: options.model,
functions: options.functions,
functionsFile: options.functionsFile,
forceFunctionCall: options.forceFunctionCall,
character: options.character,
raw: true // Always get raw response to check for function calls
});
if (global.raw || options.raw) {
console.log(JSON.stringify(result, null, 2));
}
else {
// Check if result is a ChatCompletionResponse
if (result && typeof result === 'object' && 'choices' in result &&
result.choices && result.choices.length > 0) {
const choice = result.choices[0];
if (choice.message && 'function_call' in choice.message && choice.message.function_call) {
console.log('Function Call:');
console.log(`Name: ${choice.message.function_call.name}`);
console.log(`Arguments: ${choice.message.function_call.arguments}`);
}
else if (choice.message && choice.message.content) {
console.log(choice.message.content);
}
else {
console.log('No content or function call in response');
}
}
else {
// Fallback for other response types
console.log(result);
}
}
}
catch (error) {
console.error('Error:', error.message);
}
});
// Upscale image command
program
.command('upscale-image')
.description('Upscale an image')
.argument('<image>', 'Path to the image file')
.option('-s, --scale <factor>', 'Scale factor (2 or 4)', '2')
.option('-o, --output <filename>', 'Output filename', 'upscaled-image.png')
.option('-r, --raw', 'Output raw JSON response')
.action(async (image, options) => {
try {
console.log('Upscaling image...');
// Read image file
const imageBuffer = fs.readFileSync(image);
const base64Image = imageBuffer.toString('base64');
const venice = getClient();
const response = await venice.image.upscale({
model: 'upscale-model',
image: base64Image,
scale: parseInt(options.scale) || 2
});
if (global.raw || options.raw) {
console.log(JSON.stringify(response, null, 2));
return;
}
// Save image if output path is provided
if (response.url) {
console.log('Downloading upscaled image...');
const file = fs.createWriteStream(options.output);
https.get(response.url, function (response) {
response.pipe(file);
file.on('finish', () => {
console.log(`Image upscaled and saved to ${options.output}`);
});
}).on('error', (err) => {
console.error('Error downloading image:', err.message);
});
}
else if (response.b64_json) {
// Handle base64 response
const imageData = response.b64_json.replace(/^data:image\/\w+;base64,/, '');
fs.writeFileSync(options.output, Buffer.from(imageData, 'base64'));
console.log(`Image upscaled and saved to ${options.output}`);
}
else {
console.error('Error: No image data returned from the API');
}
}
catch (error) {
console.error('Error:', error.message);
}
});
// Generate image
program
.command('generate-image')
.description('Generate an image')
.argument('<prompt>', 'The prompt to generate an image from')
.option('-m, --model <model>', 'Model to use', 'fluently-xl')
.option('-n, --negative <negative>', 'Negative prompt')
.option('-s, --style <style>', 'Style preset')
.option('-h, --height <height>', 'Image height', '1024')
.option('-w, --width <width>', 'Image width', '1024')
.option('-o, --output <filename>', 'Output filename', 'venice-image.png')
.action(async (prompt, options) => {
try {
const venice = getClient();
console.log('Generating image...');
const imageParams = {
model: options.model,
prompt: prompt,
negative_prompt: options.negative,
style_preset: options.style,
height: parseInt(options.height),
width: parseInt(options.width)
};
debugLog('Image generation request', imageParams);
const response = await venice.image.generate(imageParams);
debugLog('Image generation response', response);
if (global.raw) {
// Output raw JSON for scripting
console.log(JSON.stringify(response, null, 2));
}
else {
// Download the image
console.log('Downloading image...');
const imageUrl = response.images[0].url;
if (!imageUrl) {
console.error('Error: No image URL returned from the API');
return;
}
const file = fs.createWriteStream(options.output);
https.get(imageUrl, function (response) {
response.pipe(file);
file.on('finish', () => {
console.log(`Image saved to ${options.output}`);
});
}).on('error', (err) => {
console.error('Error downloading image:', err.message);
});
}
}
catch (error) {
console.error('Error:', error.message);
}
});
// List image styles
program
.command('list-styles')
.description('List available image styles')
.action(async () => {
try {
const venice = getClient();
const response = await venice.image.styles.list();
debugLog('List styles response', response);
if (global.raw) {
// Output raw JSON for scripting
console.log(JSON.stringify(response, null, 2));
}
else {
// Pretty output for human consumption
console.log('Available Image Styles:');
console.log(`Total styles: ${response.styles.length}`);
console.table(response.styles.map((style) => ({
id: style.id,
name: style.name || style.id,
description: style.description || 'No description'
})));
}
}
catch (error) {
console.error('Error:', error.message);
}
});
// List characters
program
.command('list-characters')
.description('List available characters')
.option('-l, --limit <number>', 'Limit the number of characters displayed')
.action(async (options) => {
try {
const venice = getClient();
// Fetch characters
const response = await venice.characters.list();
// Log response in debug mode
if (global.debug) {
debugLog('List characters response', response);
}
// Handle raw output mode
if (global.raw) {
console.log(JSON.stringify(response, null, 2));
return;
}
// Pretty output for human consumption
console.log('Available Characters:');
// Get characters from the data array
const characters = response.data || [];
if (characters.length === 0) {
console.log('No characters available.');
return;
}
// Display total count
console.log(`Total characters: ${characters.length}`);
// Apply limit if specified
let displayCharacters = [...characters];
if (options.limit && !isNaN(parseInt(options.limit))) {
const limit = parseInt(options.limit);
displayCharacters = displayCharacters.slice(0, limit);
console.log(`Showing ${displayCharacters.length} of ${characters.length} characters`);
}
// Format characters for display
const formattedCharacters = displayCharacters.map(character => ({
name: character.name || 'Unnamed',
slug: character.slug || 'N/A',
description: (character.description || 'No description').substring(0, 40) + '...',
model: character.modelId || 'N/A'
}));
// Display characters in a table format
console.table(formattedCharacters);
}
catch (error) {
console.error('Error:', error.message);
}
});
// Get VVV circulating supply
program
.command('vvv-supply')
.description('Get VVV circulating supply information')
.action(async () => {
try {
const venice = getClient();
const response = await venice.vvv.circulatingSupply();
debugLog('VVV circulating supply response', response);
if (global.raw) {
// Output raw JSON for scripting
console.log(JSON.stringify(response, null, 2));
}
else {
// Pretty output for human consumption
console.log('VVV Circulating Supply:');
// Handle both new and old response formats
if (response.result) {
// New format
const circulatingSupply = parseFloat(response.result);
console.log(`Circulating Supply: ${circulatingSupply.toLocaleString()}`);
console.log(`Raw Result: ${response.result}`);
console.log(`Timestamp: ${new Date().toLocaleString()}`);
}
else if (response.circulating_supply) {
// Old format
console.log(`Circulating Supply: ${response.circulating_supply.toLocaleString()}`);
if (response.total_supply) {
console.log(`Total Supply: ${response.total_supply.toLocaleString()}`);
const percentCirculating = response.percentage_circulating ||
((response.circulating_supply / response.total_supply) * 100).toFixed(2);
console.log(`Percentage Circulating: ${percentCirculating}%`);
}
if (response.timestamp) {
console.log(`Timestamp: ${new Date(response.timestamp).toLocaleString()}`);
}
else {
console.log(`Timestamp: ${new Date().toLocaleString()}`);
}
}
else {
// Fallback
console.log(response);
}
}
}
catch (error) {
if (error.response?.data?.error === 'API route not found') {
console.error('Error: VVV API endpoints require admin privileges or are not available in this API version.');
console.error('Please contact Venice AI support for access to these endpoints.');
}
else {
console.error('Error:', error.message);
}
}
});
// Get VVV network utilization
program
.command('vv