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
dist
.env
.vite
.vscode
.idea
*.log
coverage
*.log
+63 -40
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
- Node.js (v18 or newer)
- A Tavily API key. Sign up at https://tavily.com and obtain your key.
- Node.js v18 or newer
- A Tavily API key. Sign up at https://tavily.com to obtain one.
## Installation
## Setup
```bash
# Clone the repository
git clone https://git.brojs.ru/kuzakhmetovartur/povtornyy-ekzamen-2-sravnitelnyy-obzor-3.git
cd povtornyy-ekzamen-2-sravnitelnyy-obzor-3
1. **Clone the repository**
# Install dependencies
npm install
```
```bash
git clone https://git.brojs.ru/kuzakhmetovartur/povtornyy-ekzamen-2-sravnitelnyy-obzor-3.git
cd povtornyy-ekzamen-2-sravnitelnyy-obzor-3
```
## Configuration
2. **Install dependencies**
Create a `.env` file in the project root with your Tavily API key:
```bash
npm install
```
```env
TAVILY_API_KEY=your_api_key_here
```
3. **Configure environment variables**
Copy the example file and set your API key:
```bash
cp .env.example .env
# Edit .env and replace YOUR_TAVILY_API_KEY_HERE with your actual key
```
## 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
npm start
node src/index.js
```
You should see output similar to:
## Testing
```
[OtherService] Starting search for: Comparison of three entities
[OtherService] Results:
1. Title of first result
Summary of the first result.
The project uses Jest for unit tests.
2. Title of second result
Summary of the second result.
3. Title of third result
Summary of the third result.
```bash
npm test
```
## Project Structure
- `src/index.js` Entry point that starts the application.
- `src/app.js` Orchestrates the main flow.
- `src/services/tavily.js` Wrapper around the Tavily SDK.
- `src/services/otherService.js` Simple logging utility.
- `package.json` Project metadata and dependencies.
```
├── src
│ └── index.js # Main utility
├── tests
│ └── 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.
- No additional external services are used beyond Tavily.
- The code is written in ES modules (`"type": "module"` in `package.json`).
MIT © Your Name
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",
"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",
"type": "module",
"scripts": {
"start": "node src/index.js",
"test": "echo \"No tests defined\""
"test": "jest"
},
"keywords": [
"tavily",
"comparison",
"api",
"node"
],
"author": "Your Name",
"license": "MIT",
"dependencies": {
"tavily-sdk": "^1.0.0",
"dotenv": "^16.0.0"
"axios": "^1.6.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) => {
console.error('Application error:', err);
process.exit(1);
});
dotenv.config();
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'
);
});
});