UNPKG

@openclueo/sdk

Version:

Official JavaScript SDK for Clueo AI Personality API with Big Five model integration

325 lines (274 loc) 9.27 kB
/** * Clueo JavaScript SDK * Simple integration for personality transformation API * * @version 1.0.0 * @author Clueo Team */ class Clueo { constructor(apiKey, options = {}) { if (!apiKey) { throw new Error('API key is required. Get yours at https://clueo.dev'); } this.apiKey = apiKey; this.baseUrl = options.baseUrl || 'https://backend.clueoai.com'; this.timeout = options.timeout || 10000; } /** * Inject personality into a prompt using Big Five model * @param {string} prompt - The prompt to inject personality into * @param {Object} options - Big Five personality configuration (1-10 scale) * @returns {Promise<Object>} Injection result */ async inject(prompt, options = {}) { if (!prompt || typeof prompt !== 'string') { throw new Error('Prompt must be a non-empty string'); } const { openness = 5, conscientiousness = 5, extraversion = 5, agreeableness = 5, neuroticism = 5, openaiKey = null } = options; // Validate Big Five values (1-10 scale) const bigFiveValues = { openness, conscientiousness, extraversion, agreeableness, neuroticism }; for (const [trait, value] of Object.entries(bigFiveValues)) { if (!Number.isInteger(value) || value < 1 || value > 10) { throw new Error(`${trait} must be an integer between 1 and 10`); } } try { const controller = new AbortController(); const timeoutId = setTimeout(() => controller.abort(), this.timeout); const payload = { prompt: prompt.trim(), personalityConfig: { openness, conscientiousness, extraversion, agreeableness, neuroticism } }; const headers = { 'x-api-key': this.apiKey, 'Content-Type': 'application/json', }; if (openaiKey) { headers['x-openai-key'] = openaiKey; } const response = await fetch(`${this.baseUrl}/api/enhanced/inject`, { method: 'POST', headers, body: JSON.stringify(payload), signal: controller.signal }); clearTimeout(timeoutId); if (!response.ok) { const error = await response.json().catch(() => ({})); throw new Error(error.message || `HTTP ${response.status}: ${response.statusText}`); } const result = await response.json(); if (!result.success) { throw new Error(result.message || 'Personality injection failed'); } return { injected_prompt: result.data.injected_prompt, personality_config: result.data.personalityConfig, usage: result.data.usage, timestamp: new Date().toISOString() }; } catch (error) { if (error.name === 'AbortError') { throw new Error(`Request timeout after ${this.timeout}ms`); } throw error; } } /** * Transform a message with AI personality * @param {string} message - The message to transform * @param {string} tone - Personality tone: 'Professional', 'Sarcastic', 'Empathetic' * @returns {Promise<Object>} Transformation result */ async transform(message, tone = 'Professional') { if (!message || typeof message !== 'string') { throw new Error('Message must be a non-empty string'); } const validTones = ['Professional', 'Sarcastic', 'Empathetic']; if (!validTones.includes(tone)) { throw new Error(`Invalid tone. Must be one of: ${validTones.join(', ')}`); } try { const controller = new AbortController(); const timeoutId = setTimeout(() => controller.abort(), this.timeout); const response = await fetch(`${this.baseUrl}/transform`, { method: 'POST', headers: { 'X-API-Key': this.apiKey, 'Content-Type': 'application/json', }, body: JSON.stringify({ message: message.trim(), tone: tone }), signal: controller.signal }); clearTimeout(timeoutId); if (!response.ok) { const error = await response.json().catch(() => ({})); throw new Error(error.message || `HTTP ${response.status}: ${response.statusText}`); } const result = await response.json(); if (!result.success) { throw new Error(result.message || 'Transformation failed'); } return { original: result.data.original, transformed: result.data.transformed, tone: result.data.tone, usage: result.data.usage, meta: result.data.meta }; } catch (error) { if (error.name === 'AbortError') { throw new Error(`Request timeout after ${this.timeout}ms`); } throw error; } } /** * Simulate a conversation response with personality * @param {string} message - The user message * @param {Object} options - Big Five personality configuration * @returns {Promise<Object>} Simulation result */ async simulate(message, options = {}) { if (!message || typeof message !== 'string') { throw new Error('Message must be a non-empty string'); } const { openness = 5, conscientiousness = 5, extraversion = 5, agreeableness = 5, neuroticism = 5, openaiKey = null } = options; try { const controller = new AbortController(); const timeoutId = setTimeout(() => controller.abort(), this.timeout); const payload = { message: message.trim(), personalityConfig: { openness, conscientiousness, extraversion, agreeableness, neuroticism } }; const headers = { 'x-api-key': this.apiKey, 'Content-Type': 'application/json', }; if (openaiKey) { headers['x-openai-key'] = openaiKey; } const response = await fetch(`${this.baseUrl}/api/enhanced/simulate`, { method: 'POST', headers, body: JSON.stringify(payload), signal: controller.signal }); clearTimeout(timeoutId); if (!response.ok) { const error = await response.json().catch(() => ({})); throw new Error(error.message || `HTTP ${response.status}: ${response.statusText}`); } const result = await response.json(); if (!result.success) { throw new Error(result.message || 'Simulation failed'); } return { original_message: result.data.originalMessage, response: result.data.response, personality_config: result.data.personalityConfig, usage: result.data.usage, timestamp: new Date().toISOString() }; } catch (error) { if (error.name === 'AbortError') { throw new Error(`Request timeout after ${this.timeout}ms`); } throw error; } } /** * Batch transform multiple messages * @param {Array} messages - Array of {message, tone} objects * @returns {Promise<Array>} Array of transformation results */ async batchTransform(messages) { if (!Array.isArray(messages) || messages.length === 0) { throw new Error('Messages must be a non-empty array'); } const results = []; for (const item of messages) { try { const result = await this.transform(item.message, item.tone); results.push({ success: true, ...result }); } catch (error) { results.push({ success: false, error: error.message, original: item.message }); } } return results; } } // Node.js module export (ES modules) export default Clueo; // Node.js module export (CommonJS - for backward compatibility) if (typeof module !== 'undefined' && module.exports) { module.exports = Clueo; } // Browser global if (typeof window !== 'undefined') { window.Clueo = Clueo; } // Example usage: /* // Node.js const Clueo = require('./clueo.js'); const clueo = new Clueo('ck_your_api_key_here'); // Browser const clueo = new Clueo('ck_your_api_key_here'); // Inject personality into prompt using Big Five model const injectionResult = await clueo.inject('How do I scale my startup?', { openness: 8, // Creative, open to new ideas conscientiousness: 7, // Organized, disciplined extraversion: 6, // Moderately outgoing agreeableness: 5, // Balanced cooperation neuroticism: 3, // Calm, stable openaiKey: 'sk_your_openai_key' // Optional: use your own OpenAI key }); console.log(injectionResult.injected_prompt); // Simulate conversation response with personality const simulationResult = await clueo.simulate('What should I focus on first?', { openness: 9, // Highly creative conscientiousness: 8, // Very organized extraversion: 7, // Outgoing agreeableness: 6, // Cooperative neuroticism: 2 // Very calm }); console.log(simulationResult.response); // Transform message (legacy method - still works) const transformResult = await clueo.transform('Hello there!', 'Professional'); console.log(transformResult.transformed); // Batch transform multiple messages const batchResults = await clueo.batchTransform([ { message: 'Hello!', tone: 'Professional' }, { message: 'Thanks!', tone: 'Empathetic' } ]); */