UNPKG

leumas-axios

Version:

An advanced Axios wrapper with extended features and Express multi-post middleware for conversational API endpoints.

209 lines (191 loc) 7.59 kB
// index.js const axios = require('axios'); const readline = require('readline'); class AdvancedAxios { /** * Create an AdvancedAxios instance with optional Axios configuration. */ constructor(axiosConfig = {}) { this.axiosInstance = axios.create(axiosConfig); } // --- Standard Axios Methods --- request(config) { return this.axiosInstance.request(config); } get(url, config = {}) { return this.axiosInstance.get(url, config); } post(url, data = {}, config = {}) { return this.axiosInstance.post(url, data, config); } put(url, data = {}, config = {}) { return this.axiosInstance.put(url, data, config); } delete(url, config = {}) { return this.axiosInstance.delete(url, config); } patch(url, data = {}, config = {}) { return this.axiosInstance.patch(url, data, config); } // --- Advanced Features --- /** * multiGet(urls, config): * Executes GET requests to an array of URLs concurrently and returns an array of response data. */ multiGet(urls, config = {}) { const requests = urls.map(url => this.axiosInstance.get(url, config)); return Promise.all(requests).then(responses => responses.map(res => res.data)); } /** * multiPost(url, config, { onFeedback }): * Executes a POST request that may require multiple steps. */ multiPost(url, config = {}, { onFeedback } = {}) { const makeRequest = (payload) => { return this.axiosInstance.post(url, payload, config) .then(response => response.data) .then(result => { if (result.status === 'pending' && result.missingFields && typeof onFeedback === 'function') { return onFeedback(result.missingFields).then(additionalData => { const newData = { ...payload.data, ...additionalData }; const newPayload = { sessionId: result.sessionId, data: newData }; return makeRequest(newPayload); }); } return result; }); }; const initialPayload = { data: config.data || {} }; return makeRequest(initialPayload); } /** * generativePost(url, config, { chatGptConfig }): * Executes a POST request after using ChatGPT to “fill in” or complete the data. * The chatGptConfig should include at a minimum: * - outputStructure: The desired JSON structure (as an object) that must be followed exactly. * Additionally, you may pass in: * - apiKey, model, temperature, max_tokens, additionalPrompt. * * If any of these values are not provided, the function will fall back to the corresponding environment variables. */ generativePost(url, config = {}, { chatGptConfig } = {}) { const data = config.data || {}; if (chatGptConfig && typeof chatGptConfig === 'object') { // Use environment variables as defaults if values are not provided. const apiKey = chatGptConfig.apiKey || process.env.OPENAI_API_KEY; const model = chatGptConfig.model || process.env.OPENAI_MODEL || 'gpt-3.5-turbo'; const temperature = (typeof chatGptConfig.temperature !== 'undefined') ? chatGptConfig.temperature : (process.env.OPENAI_TEMPERATURE ? parseFloat(process.env.OPENAI_TEMPERATURE) : 0.7); const max_tokens = chatGptConfig.max_tokens || (process.env.OPENAI_MAX_TOKENS ? parseInt(process.env.OPENAI_MAX_TOKENS, 10) : 150); const outputStructure = chatGptConfig.outputStructure; const additionalPrompt = chatGptConfig.additionalPrompt || process.env.OPENAI_ADDITIONAL_PROMPT; if (!apiKey || !outputStructure) { return Promise.reject(new Error('Missing required chatGptConfig properties: apiKey and outputStructure are required.')); } // Construct a prompt for ChatGPT to complete the data according to the provided schema. const prompt = `You are provided with incomplete data: ${JSON.stringify(data)}. Please complete this data so that it matches exactly the following JSON structure: ${JSON.stringify(outputStructure)}. ${additionalPrompt ? additionalPrompt : ''}`; // Call OpenAI's ChatGPT API. return axios.post('https://api.openai.com/v1/chat/completions', { model, messages: [ { role: 'user', content: prompt } ], temperature, max_tokens }, { headers: { 'Content-Type': 'application/json', 'Authorization': `Bearer ${apiKey}` } }).then(response => { const choices = response.data.choices; if (choices && choices.length > 0) { let generatedData; try { generatedData = JSON.parse(choices[0].message.content); } catch (e) { throw new Error("Failed to parse ChatGPT response as JSON: " + e.message); } // Use the generatedData as the final payload data. return this.axiosInstance.post(url, generatedData, config) .then(res => res.data); } else { throw new Error("No response from ChatGPT"); } }); } else { // Fallback: if no chatGptConfig provided, simply post the original data. return this.axiosInstance.post(url, data, config).then(response => response.data); } } // --- Interactive Helper Methods for MultiPost --- /** * askQuestion(query) * Prompts the user via the terminal for input. */ static askQuestion(query) { return new Promise(resolve => { const rl = readline.createInterface({ input: process.stdin, output: process.stdout }); rl.question(query, answer => { rl.close(); resolve(answer); }); }); } /** * promptForMissingFields(missingFields) * Prompts the user to supply values for each missing field. */ static async promptForMissingFields(missingFields) { const responses = {}; for (const field of missingFields) { const answer = await AdvancedAxios.askQuestion(`Please enter a value for "${field}": `); responses[field] = answer; } return responses; } } // --- MultiPost Middleware for Express --- // In-memory session store (for demonstration purposes) const sessions = {}; function generateSessionId() { return Math.random().toString(36).substring(2, 15); } /** * multiPostMiddleware(requiredFields) * Express middleware for multi-step POST endpoints. */ function multiPostMiddleware(requiredFields) { return (req, res, next) => { let sessionId = req.body.sessionId || generateSessionId(); req.sessionId = sessionId; if (!sessions[sessionId]) { sessions[sessionId] = {}; console.log(`Created new session: ${sessionId}`); } sessions[sessionId] = { ...sessions[sessionId], ...req.body.data }; req.multiPostData = sessions[sessionId]; const missingFields = requiredFields.filter(field => !req.multiPostData[field]); if (missingFields.length > 0) { console.log(`Session ${sessionId} pending. Missing fields:`, missingFields); return res.json({ sessionId, status: 'pending', missingFields }); } delete sessions[sessionId]; next(); }; } AdvancedAxios.multiPostMiddleware = multiPostMiddleware; module.exports = AdvancedAxios;