import numpy as np import pandas as pd from datetime import timedelta from tensorflow.keras.models import load_model from sklearn.preprocessing import MinMaxScaler import matplotlib.pyplot as plt 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)) # Загружаем данные column_names = ['product_url', 'price', 'datetime'] df = pd.read_csv('parsed_data_public_price_history_all.csv') # Преобразуем колонку 'datetime' в тип данных datetime df['datetime'] = pd.to_datetime(df['datetime'], format='mixed', utc=True) df['price'] = df['price'].astype(float) q_low = df['price'].quantile(0.55) q_hi = df['price'].quantile(0.75) q_range = q_hi - q_low df = df[(df['price'] < q_hi + 1.5 * q_range) & (df['price'] > q_low - 1.5 * q_range)] df_hourly_avg = df[['price', 'datetime']] df_hourly_avg['datetime'] = df_hourly_avg['datetime'].dt.floor('1H') df_hourly_avg = df_hourly_avg.groupby('datetime').agg({'price': 'mean'}).reset_index() df_hourly_avg.set_index('datetime', inplace=True) # Подготовка данных для прогнозирования def prepare_data(df, days_forward=7): last_date = df.index[-1] scaled_data = scaler.fit_transform(df[['price']].values) n = 3 # число временных шагов (можно менять) X_test = [] # Формируем X_test на основе последних n значений for i in range(n, len(scaled_data)): X_test.append(scaled_data[i - n:i, 0]) X_test = np.array(X_test) X_test = np.reshape(X_test, (X_test.shape[0], X_test.shape[1], 1)) # Предсказание на 7 дней вперед predictions = [] current_input = X_test[-1] # начальное состояние для прогноза for _ in range(days_forward): pred = model.predict(np.expand_dims(current_input, axis=0)) predictions.append(pred[0, 0]) # Обновляем current_input, добавляя новое предсказание и удаляя старое current_input = np.append(current_input[1:], pred).reshape(n, 1) # Масштабируем предсказания обратно predictions = scaler.inverse_transform(np.array(predictions).reshape(-1, 1)).flatten() future_dates = [last_date + timedelta(days=i) for i in range(1, days_forward + 1)] forecast_df = pd.DataFrame({'date': future_dates, 'predicted_price': predictions}) return forecast_df # Построение графика def plot_price(forecast_df): plt.figure(figsize=(14, 7)) plt.plot(df_hourly_avg.index, df_hourly_avg['price'], label='Actual Price', color='blue') plt.plot(forecast_df['date'], forecast_df['predicted_price'], label='Predicted Price', color='orange') plt.title("Price Prediction") plt.xlabel("Date") plt.ylabel("Price") plt.legend() plt.grid(True) img = io.BytesIO() plt.savefig(img, format='png') img.seek(0) plt.close() return img @api.route('/predict_price', methods=['GET']) def predict_price(): """ Предсказание цены на 7 дней вперед --- responses: 200: description: JSON с предсказаниями цен и днем минимальной цены schema: type: object properties: forecast: type: array items: type: object properties: date: type: string format: date predicted_price: type: number min_price_day: type: object properties: date: type: string format: date price: type: number """ forecast_df = prepare_data(df_hourly_avg) forecast_list = forecast_df.to_dict(orient='records') # Преобразование в список словарей # Преобразуем значения 'predicted_price' в float for record in forecast_list: record['predicted_price'] = float(record['predicted_price']) # Определяем день с минимальной предсказанной ценой min_price_day = forecast_df.loc[forecast_df['predicted_price'].idxmin()] # Преобразуем минимальную цену в float min_price_day_price = float(min_price_day['predicted_price']) # Формируем ответ return jsonify({ 'forecast': forecast_list, 'min_price_day': { 'date': min_price_day['date'].strftime('%Y-%m-%d'), 'price': min_price_day_price } }) # Эндпоинт для получения графика @api.route('/plot', methods=['GET']) def plot(): """ Получение графика предсказанных и фактических цен --- responses: 200: description: Возвращает график предсказанных и фактических цен в формате PNG content: image/png: schema: type: string format: binary """ forecast_df = prepare_data(df_hourly_avg) img = plot_price(forecast_df) return send_file(img, mimetype='image/png') app.register_blueprint(api, url_prefix='/api') if __name__ == "__main__": app.run(debug=True)