#!/usr/bin/env node
const axios = require('axios');
const https = require('https');
const fs = require('fs');
const path = require('path');
// Create axios instance
const axiosInstance = axios.create({
httpsAgent: new https.Agent({ rejectUnauthorized: false }),
timeout: 30000
});
// Parse command line arguments
const args = process.argv.slice(2);
if (args.length < 3) {
console.error('Usage: node question-by-question-extractor.cjs <username> <password> <questions-file> [tunnel-url] [output-file]');
console.error('Example: node question-by-question-extractor.cjs user@example.com password123 questions.txt https://tunnel.trycloudflare.com output.txt');
process.exit(1);
}
const USERNAME = args[0];
const PASSWORD = args[1];
const QUESTIONS_FILE = args[2];
const MCP_BASE = args[3] || 'https://localhost:8787';
const OUTPUT_FILE = args[4] || 'question-answers.txt';
// Read questions from file
let questions;
try {
const questionsPath = path.isAbsolute(QUESTIONS_FILE)
? QUESTIONS_FILE
: path.join(__dirname, QUESTIONS_FILE);
const questionsContent = fs.readFileSync(questionsPath, 'utf8');
questions = questionsContent.split('\n').filter(q => q.trim().length > 0);
} catch (error) {
console.error(`Error reading questions file: ${error.message}`);
process.exit(1);
}
// Function to extract all numeric values from any text
function extractAllNumericValues(text) {
const values = [];
// Try to find numbers in various formats
// This regex finds integers and decimals
const numberPattern = /-?\d+(?:\.\d+)?/g;
const matches = text.match(numberPattern);
if (matches) {
matches.forEach(match => {
const num = parseFloat(match);
if (!isNaN(num) && num !== 0 && Math.abs(num) > 1) { // Exclude zeros, NaN, and very small numbers
values.push(num);
}
});
}
return values;
}
// Function to extract values from JSON structure
function extractValuesFromJSON(obj, values = []) {
if (obj === null || obj === undefined) return values;
if (typeof obj === 'number') {
if (!isNaN(obj) && obj !== 0 && Math.abs(obj) > 1) {
values.push(obj);
}
} else if (typeof obj === 'string') {
// Try to extract numbers from strings too
const nums = extractAllNumericValues(obj);
values.push(...nums);
} else if (Array.isArray(obj)) {
obj.forEach(item => extractValuesFromJSON(item, values));
} else if (typeof obj === 'object') {
Object.values(obj).forEach(value => extractValuesFromJSON(value, values));
}
return values;
}
async function processQuestions() {
console.log('Processing questions and extracting values...\n');
let output = 'QUESTION-BY-QUESTION VALUE EXTRACTION\n';
output += '=====================================\n\n';
for (let i = 0; i < questions.length; i++) {
const question = questions[i].trim();
console.log(`Processing Q${i + 1}: ${question.substring(0, 50)}...`);
output += `Q${i + 1}: ${question}\n`;
try {
// Make request using MCP protocol
const response = await axiosInstance.post(`${MCP_BASE}/sse`, {
jsonrpc: '2.0',
method: 'tools/call',
params: {
name: 'api__invoices_caui',
arguments: {
prompt: question
}
},
id: i + 1
}, {
headers: {
'Authorization': `Bearer ${USERNAME}`,
'apikey': PASSWORD
}
});
// Parse response and extract values
const responseText = response.data.toString();
let questionValues = [];
// Try multiple extraction methods
// Method 1: Extract from SSE data lines
const lines = responseText.split('\n');
for (const line of lines) {
if (line.startsWith('data: ')) {
try {
const data = JSON.parse(line.slice(6));
const extracted = extractValuesFromJSON(data);
questionValues.push(...extracted);
} catch (e) {
// Try raw text extraction
const nums = extractAllNumericValues(line);
questionValues.push(...nums);
}
}
}
// Method 2: Extract from any JSON in the response
const jsonMatches = responseText.match(/\{[^{}]*\}|\[[^\[\]]*\]/g);
if (jsonMatches) {
jsonMatches.forEach(match => {
try {
const parsed = JSON.parse(match);
const extracted = extractValuesFromJSON(parsed);
questionValues.push(...extracted);
} catch (e) {
// Not valid JSON, skip
}
});
}
// Method 3: Direct number extraction from entire response
const directNumbers = extractAllNumericValues(responseText);
questionValues.push(...directNumbers);
// Remove duplicates and get first 10
const uniqueForQuestion = [...new Set(questionValues)];
const first10 = uniqueForQuestion.slice(0, 10);
if (first10.length > 0) {
output += `Values: ${first10.join(', ')}\n`;
} else {
output += `Values: (no numeric values found)\n`;
}
} catch (error) {
console.log(` Error: ${error.message}`);
output += `Values: ERROR - ${error.message}\n`;
}
output += '\n';
}
// Save to file
fs.writeFileSync(OUTPUT_FILE, output);
console.log(`\n✓ Processing complete!`);
console.log(`✓ Results saved to: ${OUTPUT_FILE}`);
return output;
}
// Run the extraction
processQuestions().catch(err => {
console.error('Fatal error:', err.message);
process.exit(1);
});