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

This commit is contained in:
2026-06-29 17:43:56 +03:00
parent 6d59b9669e
commit 1a87558805
8 changed files with 190 additions and 94 deletions
+15 -75
View File
@@ -1,81 +1,21 @@
# Tavily Comparison App # Повторный экзамен #2: Сравнительный обзор 3 сущностей (Tavily)
This project is a simple React application that allows users to compare three entities by fetching data from the Tavily API and displaying the results in a table. Главная
Мои задания
Повторный экзамен #2: Сравнительный обзор 3 сущностей (Tavily)
EN
Повторный экзамен #2: Сравнительный обзор 3 сущностей (Tavily)
Зачёт
Версия 11
Дедлайн сдачи: 31.08.2026
## Features В работе
- Input form for three entities. Требуется доработка
- Fetches data from the Tavily API.
- Displays comparison results in a responsive table.
- Handles loading and error states.
- Unit tests for the API logic.
## Prerequisites В работе отсутствуют ключевые зависимости и функциональные элементы, указанные в задании. Необходимо добавить недостающие пакеты и реализовать требуемый узел для построения таблицы сравнения.
- Node.js (v18 or newer) Редактирование ответа
- npm or yarn
## Setup Заполните ответ и отправьте работу на проверку преподавате
1. **Clone the repository**
```bash
git clone https://git.brojs.ru/kuzakhmetovartur/povtornyy-ekzamen-2-sravnitelnyy-obzor-3.git
cd povtornyy-ekzamen-2-sravnitelnyy-obzor-3
```
2. **Install dependencies**
```bash
npm install
# or
yarn install
```
3. **Configure environment variables**
Copy the example file and set your Tavily API key:
```bash
cp .env.example .env
```
Edit `.env` and replace `your_api_key_here` with your actual key.
4. **Run the development server**
```bash
npm run dev
# or
yarn dev
```
Open [http://localhost:5173](http://localhost:5173) to view the app.
## Testing
Run unit tests with:
```bash
npm test
# or
yarn test
```
## Build for Production
```bash
npm run build
# or
yarn build
```
The production build will be in the `dist` folder.
## Deployment
You can deploy the `dist` folder to any static hosting provider (Netlify, Vercel, GitHub Pages, etc.). Make sure to set the `VITE_TAVILY_API_KEY` environment variable in your deployment environment.
## License
MIT License
+22 -13
View File
@@ -1,24 +1,33 @@
{ {
"name": "tavily-comparison-app", "name": "comparison-table-app",
"version": "1.0.0", "version": "1.0.0",
"private": true, "private": true,
"description": "React app that compares three entities using Tavily API",
"main": "src/index.js",
"scripts": { "scripts": {
"dev": "vite", "start": "react-scripts start",
"build": "vite build", "build": "react-scripts build",
"preview": "vite preview", "test": "react-scripts test",
"test": "jest" "eject": "react-scripts eject"
}, },
"dependencies": { "dependencies": {
"@tavily/tavily-api": "^1.0.0",
"axios": "^1.6.0", "axios": "^1.6.0",
"react": "^18.2.0", "react": "^18.2.0",
"react-dom": "^18.2.0" "react-dom": "^18.2.0",
"react-scripts": "5.0.1",
"react-table": "^7.8.0"
}, },
"devDependencies": { "browserslist": {
"@testing-library/jest-dom": "^5.17.0", "production": [
"@testing-library/react": "^14.0.0", ">0.2%",
"axios-mock-adapter": "^1.21.2", "not dead",
"identity-obj-proxy": "^3.0.0", "not op_mini all"
"jest": "^29.7.0", ],
"vite": "^5.0.0" "development": [
"last 1 chrome version",
"last 1 firefox version",
"last 1 safari version"
]
} }
} }
+4
View File
@@ -0,0 +1,4 @@
.App {
text-align: center;
padding: 20px;
}
+4 -2
View File
@@ -1,10 +1,12 @@
import React from 'react'; import React from 'react';
import Comparison from './components/Comparison'; import ComparisonTable from './components/ComparisonTable';
import './App.css';
function App() { function App() {
return ( return (
<div className="App"> <div className="App">
<Comparison /> <h1>Entity Comparison</h1>
<ComparisonTable />
</div> </div>
); );
} }
+30
View File
@@ -0,0 +1,30 @@
.comparison-table {
width: 100%;
border-collapse: collapse;
margin-top: 20px;
}
.comparison-table th,
.comparison-table td {
border: 1px solid #ddd;
padding: 8px;
}
.comparison-table th {
background-color: #4caf50;
color: white;
text-align: left;
}
.comparison-table tr:nth-child(even) {
background-color: #f2f2f2;
}
.comparison-table tr:hover {
background-color: #ddd;
}
.error {
color: red;
font-weight: bold;
}
+108
View File
@@ -0,0 +1,108 @@
import React, { useState, useEffect } from 'react';
import { useTable } from 'react-table';
import { TavilyClient } from '@tavily/tavily-api';
import './ComparisonTable.css';
const ComparisonTable = () => {
const [data, setData] = useState([]);
const [loading, setLoading] = useState(true);
const [error, setError] = useState(null);
const entities = ['Apple', 'Samsung', 'Google'];
useEffect(() => {
const fetchData = async () => {
setLoading(true);
setError(null);
try {
const client = new TavilyClient({
apiKey: process.env.REACT_APP_TAVILY_API_KEY,
});
const results = await Promise.all(
entities.map(async (entity) => {
const response = await client.search({
query: entity,
search_type: 'search',
});
// Extract a concise summary from the response
const summary =
response?.response?.text ||
response?.results?.[0]?.text ||
'No summary available';
return { entity, summary };
})
);
setData(results);
} catch (err) {
console.error(err);
setError('Failed to fetch data from Tavily API.');
} finally {
setLoading(false);
}
};
fetchData();
}, []);
const columns = React.useMemo(
() => [
{
Header: 'Entity',
accessor: 'entity',
},
{
Header: 'Summary',
accessor: 'summary',
},
],
[]
);
const {
getTableProps,
getTableBodyProps,
headerGroups,
rows,
prepareRow,
} = useTable({ columns, data });
if (loading) {
return <p>Loading comparison data...</p>;
}
if (error) {
return <p className="error">{error}</p>;
}
return (
<table {...getTableProps()} className="comparison-table">
<thead>
{headerGroups.map((headerGroup) => (
<tr {...headerGroup.getHeaderGroupProps()}>
{headerGroup.headers.map((column) => (
<th {...column.getHeaderProps()}>{column.render('Header')}</th>
))}
</tr>
))}
</thead>
<tbody {...getTableBodyProps()}>
{rows.map((row) => {
prepareRow(row);
return (
<tr {...row.getRowProps()}>
{row.cells.map((cell) => (
<td {...cell.getCellProps()}>{cell.render('Cell')}</td>
))}
</tr>
);
})}
</tbody>
</table>
);
};
export default ComparisonTable;
+3 -2
View File
@@ -1,5 +1,6 @@
/* Basic global styles */
body { body {
margin: 0; margin: 0;
padding: 0; font-family: Arial, Helvetica, sans-serif;
background-color: #fafafa; background-color: #f5f5f5;
} }
+4 -2
View File
@@ -1,9 +1,11 @@
import React from 'react'; import React from 'react';
import ReactDOM from 'react-dom/client'; import { createRoot } from 'react-dom/client';
import App from './App'; import App from './App';
import './index.css'; import './index.css';
ReactDOM.createRoot(document.getElementById('root')).render( const container = document.getElementById('root');
const root = createRoot(container);
root.render(
<React.StrictMode> <React.StrictMode>
<App /> <App />
</React.StrictMode> </React.StrictMode>