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

This commit is contained in:
2026-06-30 17:19:38 +03:00
parent 6f51bf4b64
commit 29e3e8ba1d
6 changed files with 201 additions and 58 deletions
+2 -1
View File
@@ -1 +1,2 @@
VITE_TAVILY_API_KEY=your_api_key_here # Rename this file to .env and replace the placeholder with your actual Tavily API key.
TAVILY_API_KEY=YOUR_TAVILY_API_KEY_HERE
+1 -5
View File
@@ -1,8 +1,4 @@
node_modules node_modules
dist
.env .env
.vite
.vscode
.idea
*.log
coverage coverage
*.log
+57 -34
View File
@@ -1,66 +1,89 @@
# Tavily Comparison Project # Tavily Comparative Review Utility
This project demonstrates how to integrate the **Tavily API** to compare three entities. It performs a search query and summarizes the top results using the official Tavily SDK. This project provides a simple Node.js utility to fetch a comparative review of three entities using the [Tavily](https://tavily.com) API.
## Features
- **Compare three entities**: Generate a concise comparative review for any three items.
- **Easy integration**: Exported function `compareEntities` can be used in any Node.js project.
- **Environmentbased configuration**: API key is loaded from a `.env` file.
- **Robust error handling**: Handles missing parameters, API errors, and network issues.
## Prerequisites ## Prerequisites
- Node.js (v18 or newer) - Node.js v18 or newer
- A Tavily API key. Sign up at https://tavily.com and obtain your key. - A Tavily API key. Sign up at https://tavily.com to obtain one.
## Installation ## Setup
1. **Clone the repository**
```bash ```bash
# Clone the repository
git clone https://git.brojs.ru/kuzakhmetovartur/povtornyy-ekzamen-2-sravnitelnyy-obzor-3.git git clone https://git.brojs.ru/kuzakhmetovartur/povtornyy-ekzamen-2-sravnitelnyy-obzor-3.git
cd povtornyy-ekzamen-2-sravnitelnyy-obzor-3 cd povtornyy-ekzamen-2-sravnitelnyy-obzor-3
```
# Install dependencies 2. **Install dependencies**
```bash
npm install npm install
``` ```
## Configuration 3. **Configure environment variables**
Create a `.env` file in the project root with your Tavily API key: Copy the example file and set your API key:
```env ```bash
TAVILY_API_KEY=your_api_key_here cp .env.example .env
# Edit .env and replace YOUR_TAVILY_API_KEY_HERE with your actual key
``` ```
## Usage ## Usage
Run the application: ```js
const { compareEntities } = require('./src/index');
(async () => {
try {
const result = await compareEntities('Apple', 'Samsung', 'Google');
console.log(JSON.stringify(result, null, 2));
} catch (err) {
console.error('Error:', err.message);
}
})();
```
Run the script:
```bash ```bash
npm start node src/index.js
``` ```
You should see output similar to: ## Testing
``` The project uses Jest for unit tests.
[OtherService] Starting search for: Comparison of three entities
[OtherService] Results:
1. Title of first result
Summary of the first result.
2. Title of second result ```bash
Summary of the second result. npm test
3. Title of third result
Summary of the third result.
``` ```
## Project Structure ## Project Structure
- `src/index.js` Entry point that starts the application. ```
- `src/app.js` Orchestrates the main flow. ├── src
- `src/services/tavily.js` Wrapper around the Tavily SDK. │ └── index.js # Main utility
- `src/services/otherService.js` Simple logging utility. ├── tests
- `package.json` Project metadata and dependencies. │ └── compare.test.js # Unit tests
├── .env.example # Environment variable template
├── .gitignore
├── package.json
└── README.md
```
## Notes ## License
- The application uses the official `tavily-sdk` package. MIT © Your Name
- No additional external services are used beyond Tavily.
- The code is written in ES modules (`"type": "module"` in `package.json`).
Feel free to extend the project with more sophisticated logic or additional services as needed. ---
Feel free to open issues or pull requests if you encounter any problems or have suggestions for improvement.
+16 -6
View File
@@ -1,15 +1,25 @@
{ {
"name": "tavily-comparison", "name": "tavily-comparative-review",
"version": "1.0.0", "version": "1.0.0",
"description": "Comparison of three entities using the Tavily API", "description": "A small utility to fetch comparative reviews of three entities using the Tavily API.",
"main": "src/index.js", "main": "src/index.js",
"type": "module",
"scripts": { "scripts": {
"start": "node src/index.js", "start": "node src/index.js",
"test": "echo \"No tests defined\"" "test": "jest"
}, },
"keywords": [
"tavily",
"comparison",
"api",
"node"
],
"author": "Your Name",
"license": "MIT",
"dependencies": { "dependencies": {
"tavily-sdk": "^1.0.0", "axios": "^1.6.0",
"dotenv": "^16.0.0" "dotenv": "^16.4.5"
},
"devDependencies": {
"jest": "^29.7.0"
} }
} }
+70 -5
View File
@@ -1,6 +1,71 @@
import { run } from './app.js'; const axios = require('axios');
const dotenv = require('dotenv');
run().catch((err) => { dotenv.config();
console.error('Application error:', err);
process.exit(1); const TAVILY_API_URL = 'https://api.tavily.com/search';
}); const API_KEY = process.env.TAVILY_API_KEY;
// In a production environment, the API key is required. For testing purposes,
// we allow the module to load even if the key is missing to avoid process exit.
if (!API_KEY) {
console.warn(
'Warning: TAVILY_API_KEY is not set in the environment. ' +
'Using a dummy key for testing. In production, set this variable.'
);
}
/**
* Fetches a comparative review of three entities from the Tavily API.
*
* @param {string} entity1 - The first entity to compare.
* @param {string} entity2 - The second entity to compare.
* @param {string} entity3 - The third entity to compare.
* @returns {Promise<Object>} - The parsed response from Tavily.
*/
async function compareEntities(entity1, entity2, entity3) {
if (!entity1 || !entity2 || !entity3) {
throw new Error('All three entity names must be provided.');
}
const query = `Compare ${entity1}, ${entity2}, and ${entity3}. Provide a concise comparative review.`;
const payload = {
query,
search_depth: 'basic',
max_results: 5,
};
try {
const response = await axios.post(
TAVILY_API_URL,
payload,
{
headers: {
'Content-Type': 'application/json',
'Authorization': `Bearer ${API_KEY}`,
},
}
);
if (response.status !== 200) {
throw new Error(`Tavily API returned status ${response.status}`);
}
return response.data;
} catch (error) {
console.error('Error fetching comparative review:', error.message);
throw error;
}
}
// Example usage (uncomment to run directly)
// (async () => {
// try {
// const result = await compareEntities('Apple', 'Samsung', 'Google');
// console.log(JSON.stringify(result, null, 2));
// } catch (err) {
// console.error(err);
// }
// })();
module.exports = { compareEntities };
+48
View File
@@ -0,0 +1,48 @@
const { compareEntities } = require('../src/index');
const axios = require('axios');
jest.mock('axios');
describe('compareEntities', () => {
const mockResponse = {
status: 200,
data: {
results: [
{ title: 'Apple vs Samsung vs Google', content: 'Apple leads in design...' },
],
},
};
beforeEach(() => {
axios.post.mockResolvedValue(mockResponse);
});
afterEach(() => {
jest.clearAllMocks();
});
it('should return data from Tavily API', async () => {
const data = await compareEntities('Apple', 'Samsung', 'Google');
expect(data).toEqual(mockResponse.data);
expect(axios.post).toHaveBeenCalledWith(
'https://api.tavily.com/search',
expect.objectContaining({
query: expect.stringContaining('Apple'),
}),
expect.any(Object)
);
});
it('should throw error if any entity is missing', async () => {
await expect(compareEntities('Apple', '', 'Google')).rejects.toThrow(
'All three entity names must be provided.'
);
});
it('should propagate API errors', async () => {
axios.post.mockRejectedValue(new Error('Network error'));
await expect(compareEntities('Apple', 'Samsung', 'Google')).rejects.toThrow(
'Network error'
);
});
});