feat: solution for 'Повторный экзамен #2: Сравнительный обзор 3 сущностей (Tavily)'
This commit is contained in:
+2
-1
@@ -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
|
||||
+2
-6
@@ -1,8 +1,4 @@
|
||||
node_modules
|
||||
dist
|
||||
.env
|
||||
.vite
|
||||
.vscode
|
||||
.idea
|
||||
*.log
|
||||
coverage
|
||||
coverage
|
||||
*.log
|
||||
@@ -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.
|
||||
- **Environment‑based 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
@@ -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
@@ -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 };
|
||||
@@ -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'
|
||||
);
|
||||
});
|
||||
});
|
||||
Reference in New Issue
Block a user