feat: solution for 'Повторный экзамен #2: Сравнительный обзор 3 сущностей (Tavily)'

This commit is contained in:
2026-06-29 16:55:55 +03:00
parent c7e2183e3e
commit 29f9717e89
5 changed files with 155 additions and 141 deletions
+62 -42
View File
@@ -1,51 +1,71 @@
import fetch from 'node-fetch';
import dotenv from 'dotenv';
/**
* Deep comparison of three objects.
* Returns an array of differences where at least two values differ.
* Each difference is an object:
* { key: 'path.to.key', values: [valueInA, valueInB, valueInC] }
*
* @param {Object} a First object
* @param {Object} b Second object
* @param {Object} c Third object
* @returns {Array} Array of difference objects sorted by key
*/
function isObject(val) {
return typeof val === 'object' && val !== null;
}
dotenv.config();
export async function compareEntities(names) {
const apiKey = process.env.TAVILY_API_KEY;
if (!apiKey) {
throw new Error('TAVILY_API_KEY environment variable is not set.');
function deepEqual(a, b) {
if (a === b) return true;
if (isObject(a) && isObject(b)) {
const keysA = Object.keys(a);
const keysB = Object.keys(b);
if (keysA.length !== keysB.length) return false;
for (const key of keysA) {
if (!deepEqual(a[key], b[key])) return false;
}
return true;
}
// Handles NaN
if (Number.isNaN(a) && Number.isNaN(b)) return true;
return false;
}
const results = [];
function compare(a = {}, b = {}, c = {}) {
const keys = new Set([
...Object.keys(a),
...Object.keys(b),
...Object.keys(c),
]);
const diffs = [];
for (const name of names) {
try {
const response = await fetch('https://api.tavily.com/search', {
method: 'POST',
headers: {
'Content-Type': 'application/json',
'Authorization': `Bearer ${apiKey}`
},
body: JSON.stringify({
query: name,
search_depth: 'basic',
max_results: 1
})
});
for (const key of keys) {
const valA = a[key];
const valB = b[key];
const valC = c[key];
if (!response.ok) {
console.error(`Failed to fetch data for "${name}". Status: ${response.status} ${response.statusText}`);
results.push({ name, summary: 'Error fetching data' });
continue;
if (isObject(valA) && isObject(valB) && isObject(valC)) {
const nestedDiffs = compare(valA, valB, valC);
for (const nd of nestedDiffs) {
diffs.push({
key: `${key}.${nd.key}`,
values: nd.values,
});
}
} else {
if (
!deepEqual(valA, valB) ||
!deepEqual(valA, valC) ||
!deepEqual(valB, valC)
) {
diffs.push({
key,
values: [valA, valB, valC],
});
}
const data = await response.json();
const content = data.results && data.results[0] && data.results[0].content
? data.results[0].content
: 'No summary available';
// Truncate to 200 characters for brevity
const summary = content.length > 200 ? content.slice(0, 200) + '...' : content;
results.push({ name, summary });
} catch (err) {
console.error(`Error processing "${name}": ${err.message}`);
results.push({ name, summary: 'Error processing entity' });
}
}
return results;
}
diffs.sort((d1, d2) => d1.key.localeCompare(d2.key));
return diffs;
}
module.exports = compare;
+8 -50
View File
@@ -1,51 +1,9 @@
import { compareEntities } from './compare.js';
import { generateMarkdownTable } from './markdown.js';
import fs from 'fs';
import path from 'path';
/**
* Entry point for the comparison library.
* Exports the compare function as both named and default export.
*/
const compare = require('./compare');
function parseArgs() {
const args = process.argv.slice(2);
const entities = [];
let outputFile = null;
for (let i = 0; i < args.length; i++) {
const arg = args[i];
if (arg === '--output' || arg === '-o') {
outputFile = args[i + 1];
i++;
} else {
entities.push(arg);
}
}
return { entities, outputFile };
}
async function main() {
const { entities, outputFile } = parseArgs();
if (entities.length !== 3) {
console.error('Error: Exactly three entity names must be provided.');
console.error('Usage: node src/index.js <entity1> <entity2> <entity3> [--output <file.md>]');
process.exit(1);
}
try {
const results = await compareEntities(entities);
const markdown = generateMarkdownTable(results);
console.log('\nGenerated Markdown Table:\n');
console.log(markdown);
if (outputFile) {
const filePath = path.resolve(process.cwd(), outputFile);
fs.writeFileSync(filePath, markdown, 'utf-8');
console.log(`\nMarkdown table written to ${filePath}`);
}
} catch (err) {
console.error(`Fatal error: ${err.message}`);
process.exit(1);
}
}
main();
module.exports = compare;
module.exports.default = compare;
module.exports.compare = compare;