feat: solution for 'Повторный экзамен #2: Сравнительный обзор 3 сущностей (Tavily)'
This commit is contained in:
@@ -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)
|
||||||
|
5Д
|
||||||
|
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
@@ -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"
|
||||||
|
]
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -0,0 +1,4 @@
|
|||||||
|
.App {
|
||||||
|
text-align: center;
|
||||||
|
padding: 20px;
|
||||||
|
}
|
||||||
+4
-2
@@ -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>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -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;
|
||||||
|
}
|
||||||
@@ -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
@@ -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
@@ -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>
|
||||||
|
|||||||
Reference in New Issue
Block a user