用AI模型预测Ebay销量,Ebay销量预测AI模型,跨境电商AI模型与销量预测实例

一、模型表现:

前端界面和效果:

前端代码(templates/index.html):

<!DOCTYPE html>
<html lang="zh-CN">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>eBay商品预测分析</title>
    <link href="https://cdn.bootcdn.net/ajax/libs/twitter-bootstrap/4.6.0/css/bootstrap.min.css" rel="stylesheet">
    <style>
        .container { max-width: 600px; margin: 2rem auto; }
        .alert-box { transition: opacity 0.3s; }
        .result-card { display: none; margin-top: 1.5rem; }
        .loading-overlay {
            position: fixed; top: 0; left: 0; 
            width: 100%; height: 100%;
            background: rgba(255,255,255,0.9);
            display: none;
            z-index: 999;
        }
        .spinner {
            position: absolute;
            top: 50%;
            left: 50%;
            transform: translate(-50%, -50%);
        }
        .input-error { border-color: #dc3545 !important; }
        .error-msg { color: #dc3545; font-size: 0.875em; }
    </style>
</head>
<body>
    <div class="container">
        <h2 class="text-center mb-4">eBay商品预测系统</h2>
        
        <!-- 错误提示 -->
        <div class="alert alert-danger alert-box" id="errorAlert" style="display: none;"></div>
        
        <!-- 预测表单 -->
        <form id="predictForm">
            <div class="form-group">
                <label>商品价格 ($)</label>
                <input type="text" class="form-control" id="price" 
                      placeholder="例如:19.99 或 15.99-29.99" required>
            </div>
            
            <div class="form-group">
                <label>卖家评分 (%)</label>
                <input type="text" class="form-control" id="seller_rating" 
                      placeholder="例如:95%"
                      pattern="^\d+%$"
                      required>
                <small class="error-msg" id="ratingError"></small>
            </div>
    
            <div class="form-group">
                <label>卖家反馈数</label>
                <input type="number" class="form-control" id="feedbackCount" 
                      placeholder="例如:1500" 
                      min="0" 
                      required>
                <small class="error-msg" id="feedbackError"></small>
            </div>

            <div class="form-group">
                <label>库存数量</label>
                <input type="text" class="form-control" id="availability"
                      placeholder="例如:10件库存 或 5 in stock" required>
            </div>

            <div class="form-group">
                <label>商品标题</label>
                <input type="text" class="form-control" id="title"
                      placeholder="输入商品标题(至少3个字符)" required minlength="3">
            </div>

            <div class="row">
                <div class="col-md-6">
                    <div class="form-group">
                        <label>开始日期</label>
                        <input type="date" class="form-control" id="start" required>
                    </div>
                </div>
                <div class="col-md-6">
                    <div class="form-group">
                        <label>结束日期</label>
                        <input type="date" class="form-control" id="end" required>
                    </div>
                </div>
            </div>

            <button type="submit" class="btn btn-primary btn-block">
              立即预测
            </button>
        </form>

        <!-- 预测结果 -->
        <div class="card result-card" id="resultCard">
            <div class="card-body">
                <h4 class="card-title">预测结果</h4>
                <hr>
                <p class="card-text">
                    预计关注人数:<span class="text-primary" id="predWatchers">--</span>
                </p>
                <p class="card-text">
                    预计销售量:<span class="text-success" id="predSold">--</span>
                </p>
            </div>
        </div>

        <!-- 加载动画 -->
        <div class="loading-overlay">
            <div class="spinner-border text-primary" style="width: 3rem; height: 3rem;">
                <span class="sr-only">加载中...</span>
            </div>
        </div>
    </div>

    <script src="https://cdn.bootcdn.net/ajax/libs/jquery/3.6.0/jquery.min.js"></script>
    <script src="https://cdn.bootcdn.net/ajax/libs/axios/0.21.1/axios.min.js"></script>
    <script>
    $(document).ready(function() {
        const $form = $('#predictForm');
        const $result = $('#resultCard');
        const $error = $('#errorAlert');
        const $loading = $('.loading-overlay');

        // 实时验证卖家评分格式
        $('#seller_rating').on('input', function() {
            const isValid = /^\d+%$/.test($(this).val());
            $(this).toggleClass('input-error', !isValid);
            $('#ratingError').text(isValid ? "" : "必须为数字加百分号(如95%)");
        });

        // 实时验证反馈数格式
        $('#feedbackCount').on('input', function() {
            const val = $(this).val();
            const isValid = val !== "" && parseInt(val) >= 0;
            $(this).toggleClass('input-error', !isValid);
            $('#feedbackError').text(isValid ? "" : "必须为非负整数");
        });

        // 表单提交处理
        $form.on('submit', async function(e) {
            e.preventDefault();
            $error.hide();
            $loading.show();
            $result.hide();

            // 提交前验证
            let hasError = false;
            $('.input-error').removeClass('input-error');
            $('.error-msg').text('');

            // 卖家评分验证
            const sellerRating = $('#seller_rating').val().trim();
            if (!/^\d+%$/.test(sellerRating)) {
                $('#seller_rating').addClass('input-error');
                $('#ratingError').text("必须为数字加百分号(如95%)");
                hasError = true;
            }

            // 反馈数验证
            const feedbackVal = $('#feedbackCount').val().trim();
            if (feedbackVal === "" || parseInt(feedbackVal) < 0) {
                $('#feedbackCount').addClass('input-error');
                $('#feedbackError').text("必须为非负整数");
                hasError = true;
            }

            if (hasError) {
                $loading.hide();
                return;
            }

            try {
                // 组装符合后端要求的JSON结构
                const formData = {
                    price: $('#price').val().trim(),
                    seller: {
                        rating: sellerRating,
                        feedbackCount: feedbackVal
                    },
                    availability: $('#availability').val().trim(),
                    title: $('#title').val().trim(),
                    start: $('#start').val(),
                    end: $('#end').val()
                };

                // 发送请求
                const response = await axios.post('/predict', formData, {
                    timeout: 5000
                });

                // 显示结果
                $('#predWatchers').text(response.data.predicted_watchers);
                $('#predSold').text(response.data.predicted_sold);
                $result.show();
            } catch (error) {
                let message = '请求失败,请检查输入格式';
                if (error.response) {
                    message = error.response.data.error || message;
                }
                $error.text(message).show();
            } finally {
                $loading.hide();
            }
        });
    });
    </script>
</body>
</html>

后端服务器代码(app.py):

import os
import json
import logging
import re
import numpy as np
import pandas as pd
from flask import Flask, request, jsonify, render_template
import joblib
import tensorflow as tf
from tensorflow import keras

# 使用时保持一致
load_model = keras.models.load_model
from keras.preprocessing.sequence import pad_sequences
from keras.preprocessing.text import tokenizer_from_json
from sklearn.exceptions import NotFittedError
from datetime import datetime
from sklearn.impute import SimpleImputer

app = Flask(__name__, static_folder='static', template_folder='templates')
app.logger.setLevel(logging.INFO)

# ==================== 增强版数据清洗工具 ====================
class RobustDataCleaner:
    """鲁棒性数据清洗工具"""
    @staticmethod
    def clean_price(price):
        """价格清洗(支持多种格式)"""
        try:
            if pd.isna(price):
                return 0.0
            if isinstance(price, str):
                price = price.replace("$", "").replace(",", "").strip()
                if "-" in price:
                    parts = [float(p) for p in re.findall(r"\d+\.?\d*", price)[:2]]
                    return sum(parts) / len(parts)
                return float(price)
            return float(price)
        except:
            return 0.0

    @staticmethod
    def process_seller(seller):
        """卖家信息解析(增强容错)"""
        default = {"rating": 0.0, "feedbackCount": 0}
        try:
            if not isinstance(seller, dict):
                return default
            return {
                "rating": float(str(seller.get("rating", "0%")).replace("%", "")) / 100,
                "feedbackCount": int(seller.get("feedbackCount", 0))
            }
        except:
            return default

# ==================== 模型服务初始化 ====================
MODEL_DIR = "C:/Users/hanbi/Downloads/model"  #模型放置位置

# 检查模型目录是否存在
if not os.path.exists(MODEL_DIR):
    raise FileNotFoundError(f"模型目录不存在: {MODEL_DIR}")

MODEL_PATHS = {
    "lstm": os.path.join(MODEL_DIR, "optimized_lstm.h5"),
    "xgb": os.path.join(MODEL_DIR, "optimized_xgb.pkl"),
    "rf": os.path.join(MODEL_DIR, "optimized_rf.pkl"),
    "meta": os.path.join(MODEL_DIR, "meta_model.pkl"),
    "preprocessor": os.path.join(MODEL_DIR, "preprocessor.pkl"),
    "tokenizer": os.path.join(MODEL_DIR, "tokenizer_config.json")
}

def initialize_models():
    """安全初始化所有模型组件"""
    models = {}
    try:
        # 加载预处理组件
        models['preprocessor'] = joblib.load(MODEL_PATHS['preprocessor'])
        
        # 加载文本处理组件
        with open(MODEL_PATHS['tokenizer'], 'r', encoding='utf-8') as f:
            models['tokenizer'] = tokenizer_from_json(json.load(f))
        
        # 加载预测模型
        models.update({
            'lstm': load_model(MODEL_PATHS['lstm']),
            'xgb': joblib.load(MODEL_PATHS['xgb']),
            'rf': joblib.load(MODEL_PATHS['rf']),
            'meta': joblib.load(MODEL_PATHS['meta'])
        })
        return models
    except Exception as e:
        app.logger.error(f"模型加载失败: {str(e)}", exc_info=True)
        raise

models = initialize_models()

# ==================== 数据处理管道 ====================
def process_input(data: dict) -> tuple:
    """鲁棒的输入处理管道"""
    try:
        # 数值特征处理
        cleaned = {
            'price': RobustDataCleaner.clean_price(data.get('price')),
            'seller_rating': RobustDataCleaner.process_seller(data.get('seller', {})).get('rating', 0.0),
            'feedbackCount': RobustDataCleaner.process_seller(data.get('seller', {})).get('feedbackCount', 0),
            'stock': int(re.search(r'\d+', str(data.get('availability', '0'))).group()),
            'active_days': max(0, (pd.to_datetime(data.get('end'), errors='coerce') - 
                                 pd.to_datetime(data.get('start'), errors='coerce')).days),
            'title_length': len(str(data.get('title', '')))
        }

        # 构建DataFrame
        numeric_df = pd.DataFrame([cleaned], columns=models['preprocessor'].feature_names_in_)
        
        # 文本特征处理
        sequences = models['tokenizer'].texts_to_sequences([data.get('title', '')])
        text_features = pad_sequences(sequences, maxlen=30, padding='post')
        
        # 数值特征标准化
        numeric_scaled = models['preprocessor'].transform(numeric_df)
        
        return numeric_scaled, text_features
    except Exception as e:
        app.logger.error(f"输入处理失败: {str(e)}")
        raise ValueError("输入数据格式错误")

# ==================== API端点 ====================
@app.route('/')
def index():
    return render_template('index.html')

@app.route('/predict', methods=['POST'])
def predict():
    try:
        data = request.get_json()
        required_fields = ['price', 'seller', 'availability', 'title', 'start', 'end']
        if missing := [f for f in required_fields if f not in data]:
            return jsonify({"error": f"缺少必填字段: {', '.join(missing)}"}), 400

        # 特征处理
        X_num, X_text = process_input(data)
        
        # 基模型预测
        xgb_pred = models['xgb'].predict(X_num)
        rf_pred = models['rf'].predict(X_num)
        lstm_preds = models['lstm'].predict(X_text)
        
        # 元特征构建
        meta_features = np.column_stack([
            xgb_pred.flatten(),
            rf_pred.flatten(),
            lstm_preds[0].flatten(),
            lstm_preds[1].flatten()
        ])
        
        # 最终预测
        final_pred = models['meta'].predict(meta_features)
        
        return jsonify({
            "predicted_watchers": round(float(final_pred[0][0])),
            "predicted_sold": round(float(final_pred[0][1]))
        })
        
    except ValueError as e:
        return jsonify({"error": str(e)}), 400
    except Exception as e:
        app.logger.error(f"预测失败: {str(e)}")
        return jsonify({"error": "内部服务器错误"}), 500

if __name__ == '__main__':
    app.run(host='0.0.0.0', port=5000)

记得修改模型加载路径!

模型:

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值