diff --git a/analysis/app.py b/analysis/app.py
index 3299759..55afec2 100644
--- a/analysis/app.py
+++ b/analysis/app.py
@@ -8,12 +8,13 @@ import io
import joblib
from flask import Flask, request, jsonify, Blueprint, send_file
from flasgger import Swagger
+from flask_cors import CORS
app = Flask(__name__)
api = Blueprint('api', __name__)
Swagger(app)
-
+CORS(app)
# Загружаем модель и scaler
model = load_model("my_model_1H.keras")
scaler = MinMaxScaler(feature_range=(0, 1))
diff --git a/my-app/src/App.js b/my-app/src/App.js
index c92ca8b..1d1e2d1 100644
--- a/my-app/src/App.js
+++ b/my-app/src/App.js
@@ -16,11 +16,13 @@ function HomePage() {
const [marketplaces, setMarketplaces] = useState([]);
const [productUrl, setProductUrl] = useState('');
const [showPriceHistoryError, setShowPriceHistoryError] = useState(false);
+ const [showResultError, setShowResultError] = useState(false);
+ const [selectedCategory, setSelectedCategory] = useState('');
useEffect(() => {
const fetchMarketplaces = async () => {
try {
- const response = await axios.get('/api/v1/marketplaces');
+ const response = await axios.get('https://mgpj3mxm-8080.euw.devtunnels.ms/api/v1/marketplaces');
setMarketplaces(response.data);
} catch (error) {
console.error('Error fetching marketplaces:', error);
@@ -34,7 +36,8 @@ function HomePage() {
const fetchCategories = async () => {
try {
if (selectedMarketplace) {
- const response = await axios.get(`/api/v1/categories?marketplace=${selectedMarketplace}`);
+ console.log(selectedMarketplace)
+ const response = await axios.get(`https://mgpj3mxm-8080.euw.devtunnels.ms/api/v1/categories?marketplace=${selectedMarketplace}`);
setCategories(response.data);
}
} catch (error) {
@@ -46,10 +49,17 @@ function HomePage() {
}, [selectedMarketplace]);
const handleSubmit = () => {
- console.log('Отправлено:', startDate, endDate, selectedMarketplace);
- navigate('/result', {
- state: { startDate, endDate, selectedMarketplace }
- });
+ if (selectedCategory !== "" || selectedMarketplace !== "") {
+ navigate('/result', {
+ state: { startDate, endDate, selectedMarketplace, selectedCategory }
+ });
+ } else {
+ setShowResultError(true);
+ }
+ };
+
+ const handleCategoryChange = (event) => {
+ setSelectedCategory(event.target.value);
};
const handleProductUrlChange = (event) => {
@@ -64,7 +74,8 @@ function HomePage() {
// Проверка существования товара по ссылке
try {
- const response = await fetch(`/api/v1/products/info?productUrl=${productUrl}`);
+ const response = await fetch(`https://mgpj3mxm-8080.euw.devtunnels.ms/api/v1/products/info?productUrl=${productUrl}`);
+ console.log(response.data);
if (response.ok) {
// Товар найден
navigate('/viewProduct', { state: { productUrl } });
@@ -83,6 +94,7 @@ function HomePage() {
setSelectedMarketplace('');
} else {
setSelectedMarketplace(marketplaceName);
+ setSelectedCategory('');
}
};
@@ -146,7 +158,7 @@ function HomePage() {
height: '90%',
display: 'flex',
flexDirection: 'column',
- justifyContent: 'center',
+ justifyContent: 'center'
}}
>
@@ -165,36 +177,41 @@ function HomePage() {
Выберите маркетплейсы, которые вас интересуют:
- {marketplaces.map((marketplace) => (
-
- handleButtonClick(marketplace.name)}
- >
- {marketplace.name === 'Wildberries' ? (
-
- ) : (
-
- )}
-
- {marketplace.name}
-
-
-
- ))}
+ {marketplaces.map((marketplace) => {
+ if (marketplace === 'WILDBERRIES' || marketplace === 'OZON') {
+ return (
+
+ handleButtonClick(marketplace)}
+ >
+ {marketplace === 'WILDBERRIES' ? (
+
+ ) : (
+
+ )}
+
+ {marketplace}
+
+
+
+ );
+ }
+ return null; // Для остальных названий, возвращаем null, чтобы не рендерить ничего
+ })}
{/* Комбобокс */}
@@ -202,15 +219,14 @@ function HomePage() {
Выберите категорию:
-
{categories.map((category) => (
-
- {category.name}
+
+ {category}
))}
-
- Введите период для сбора данных:
-
- {startDateError && (
-
- Дата начала периода не может быть после сегодняшнего дня.
-
- )}
- {endDateError && (
-
- Дата окончания периода не может быть после сегодняшнего дня или раньше даты начала.
-
- )}
-
-
-
- -
-
-
Получить рекомендации
+ {showResultError && (
+
+ Выберите маркетплейс и категорию
+
+ )}
@@ -306,8 +292,11 @@ function HomePage() {
-
- Вы можете посмотреть историю изменения цены конкретного товара при помощи его URL.
-
-
- Введите ссылку на товар:
-
+
+
+ Вы можете посмотреть историю изменения цены конкретного товара при помощи его URL.
+
+
+
+ Введите ссылку на товар:
+
+
-
+ }}
+ >
Посмотреть историю цены
+
{showPriceHistoryError && (
-
+
Неверный URL товара или товар не найден.
)}
+
+
diff --git a/my-app/src/Result.js b/my-app/src/Result.js
index 9fa4ca1..27af097 100644
--- a/my-app/src/Result.js
+++ b/my-app/src/Result.js
@@ -1,28 +1,49 @@
-import React from 'react';
+import React, { useState, useEffect } from 'react';
import { useLocation, useNavigate } from 'react-router-dom';
import { ThemeProvider, createTheme } from '@mui/material/styles';
-import { Typography, Box, Grid, Container, Card, CardContent, CardHeader, Button } from '@mui/material';
+import { Typography, Box, Grid, Container, Card, CardContent, CardHeader, Button, CircularProgress } from '@mui/material';
import { LineChart, Line, XAxis, YAxis, CartesianGrid, Tooltip, Legend } from 'recharts';
const Result = () => {
const location = useLocation();
const navigate = useNavigate();
- const { startDate, endDate, selectedMarketplace } = location.state || {};
-
- const generateDates = (startDate, endDate) => {
- const dates = [];
- let currentDate = new Date(startDate);
- while (currentDate <= endDate) {
- dates.push(new Date(currentDate));
- currentDate.setDate(currentDate.getDate() + 1);
- }
- return dates;
- };
-
- const data = generateDates(startDate, endDate).map((date, index) => ({
- date: date,
- price: Math.floor(Math.random() * 200) + 50
- }));
+ const { startDate, endDate, selectedMarketplace, selectedCategory } = location.state || {};
+ const [predictData, setPredictData] = useState(null);
+ const [loading, setLoading] = useState(true);
+ const [imageUrl, setImageUrl] = useState('');
+ useEffect(() => {
+ const fetchPredictPrice = async () => {
+ try {
+ const response = await fetch('http://localhost:5000/api/predict_price');
+ if (response.ok) {
+ const data = await response.json();
+ console.log(data);
+ setPredictData(data);
+ } else {
+ console.error("Ошибка запроса к API");
+ }
+ } catch (error) {
+ console.error("Ошибка при получении данных:", error);
+ }
+ };
+ const fetchChart = async () => {
+ try {
+ const response = await fetch('http://localhost:5000/api/plot');
+ if (!response.ok) {
+ throw new Error('Network response was not ok');
+ }
+ const blob = await response.blob();
+ const url = URL.createObjectURL(blob);
+ setImageUrl(url);
+ } catch (error) {
+ console.error('Ошибка при загрузке графика:', error);
+ } finally {
+ setLoading(false);
+ }
+ };
+ fetchChart();
+ fetchPredictPrice();
+ }, []);
const theme = createTheme({
palette: {
@@ -72,8 +93,8 @@ const Result = () => {
Выбранный маркетплейс: {selectedMarketplace}
- Период: {startDate?.toLocaleDateString()} по {endDate?.toLocaleDateString()}
-
+ Выбранная категория: {selectedCategory}
+
@@ -81,31 +102,26 @@ const Result = () => {
-
-
- new Date(unixTime).toLocaleDateString()}
- tickMargin={10}
- stroke="#023247"
- />
-
-
-
-
-
-
-
+
+ {loading ? (
+
+ ) : (
+
+ )}
+
-
- Здесь будут отображаться рекомендации, основанные на анализе данных.
+ {predictData ? (
+ `Продукт лучше покупать в ${predictData.min_price_day.date}. Предсказанная цена: ${predictData.min_price_day.price} руб.`
+ ) : (
+ "Загрузка данных..."
+ )}
diff --git a/my-app/src/ViewProduct.js b/my-app/src/ViewProduct.js
index 1c4360c..12333d0 100644
--- a/my-app/src/ViewProduct.js
+++ b/my-app/src/ViewProduct.js
@@ -31,16 +31,24 @@ const ViewProduct = () => {
const sign = zoneOffset >= 0 ? '+' : '-';
+ // Исправлено: использование шаблонных строк для форматирования часового пояса
const formattedZoneOffset = `${sign}${hours.toString().padStart(2, '0')}:${minutes.toString().padStart(2, '0')}`;
- const { productUrl, from, to } = location.state || {};
+ // Определение 'to' как текущая дата
+ const to = date.toISOString().split('T')[0]; // Текущая дата в формате YYYY-MM-DD
+ const from = new Date(date);
+ from.setDate(date.getDate() - 30); // Дата минус 30 дней
+ const formattedFrom = from.toISOString().split('T')[0]; // Дата в формате YYYY-MM-DD
+
+ // Извлечение productUrl из состояния location
+ const { productUrl } = location.state || {};
const [productData, setProductData] = useState(null);
const [chartData, setChartData] = useState([]);
useEffect(() => {
const fetchProductData = async () => {
try {
- const response = await fetch(`/api/v1/products/info?productUrl=${productUrl}`);
+ const response = await fetch(`https://mgpj3mxm-8080.euw.devtunnels.ms/api/v1/products/info?productUrl=${productUrl}`);
if (response.ok) {
const data = await response.json();
setProductData(data);
@@ -54,14 +62,18 @@ const ViewProduct = () => {
const fetchPriceHistory = async () => {
try {
- const response = await fetch(`/api/v1/products/price-history?productUrl=${productUrl}&from=${from}&to=${to}&zoneOffset=${formattedZoneOffset}`);
+ const response = await fetch(`https://mgpj3mxm-8080.euw.devtunnels.ms/api/v1/products/price-history?productUrl=${productUrl}&from=${formattedFrom}&to=${to}&zoneOffset=${formattedZoneOffset}`);
if (response.ok) {
const priceHistoryData = await response.json();
+ // Преобразование данных в нужный формат
const priceHistory = Object.entries(priceHistoryData.priceHistory).map(([date, price]) => ({
- date: new Date(date),
+ date: new Date(date), // Преобразование строки даты в объект Date
price: price,
}));
- setChartData(priceHistory);
+
+ // Сортировка по дате
+ const sortedPriceHistory = priceHistory.sort((a, b) => a.date - b.date);
+ setChartData(sortedPriceHistory);
} else {
console.error("Ошибка запроса к API");
}
@@ -70,11 +82,10 @@ const ViewProduct = () => {
}
};
- if (productUrl) {
- fetchProductData();
- fetchPriceHistory();
- }
- }, [productUrl, from, to, formattedZoneOffset]);
+ fetchProductData();
+ fetchPriceHistory();
+ }, [productUrl, formattedFrom, to, formattedZoneOffset]);
+
const theme = createTheme({
palette: {
@@ -127,13 +138,10 @@ const ViewProduct = () => {
{productData.marketplaceName}
-
- Ссылка на товар
+
+ Перейти на страницу товара
-
- {productData.brand}
-
{productData.productName}
@@ -165,6 +173,7 @@ const ViewProduct = () => {
+
)}