Commit 1abedcae authored by Barthelet Thibault's avatar Barthelet Thibault
Browse files

current

parent 0c857a99
Loading
Loading
Loading
Loading
+72 −0
Original line number Diff line number Diff line
from flask import Flask, render_template, request, jsonify, session
from flask_session import Session
from simulation_engine import SimulationEngine
import os

app = Flask(__name__)

# Configure Flask-Session to use filesystem instead of cookies
app.config['SECRET_KEY'] = 'dev-secret-key'
app.config['SESSION_TYPE'] = 'filesystem'
app.config['SESSION_FILE_DIR'] = './flask_session'
app.config['SESSION_PERMANENT'] = False

Session(app)

@app.route('/')
def index():
    return render_template('index.html')

@app.route('/configure')
def configure():
    return render_template('configure.html')

@app.route('/run_simulation', methods=['POST'])
def run_simulation():
    try:
        data = request.json
        
        config = {
            'seed': int(data.get('seed', 42)),
            'n_watches': int(data.get('n_watches', 3)),
            'n_customers': int(data.get('n_customers', 100)),
            'n_retailers': int(data.get('n_retailers', 4)),
            'n_months': int(data.get('n_months', 12))
        }
        
        # Validate
        if not (1 <= config['n_months'] <= 24):
            return jsonify({'success': False, 'error': 'Mois: 1-24'})
        if not (1 <= config['n_watches'] <= 6):
            return jsonify({'success': False, 'error': 'Montres: 1-6'})
        if not (50 <= config['n_customers'] <= 50000):
            return jsonify({'success': False, 'error': 'Clients: 50-50000'})
        if not (2 <= config['n_retailers'] <= 8):
            return jsonify({'success': False, 'error': 'Détaillants: 2-8'})
        
        # Run simulation
        sim = SimulationEngine(config)
        results = sim.run_simulation(config['n_months'])
        
        # Store in session (now uses filesystem, not cookies)
        session['results'] = results
        session['config'] = config
        
        return jsonify({'success': True})
    
    except Exception as e:
        return jsonify({'success': False, 'error': str(e)})

@app.route('/results')
def results():
    results = session.get('results')
    config = session.get('config')
    
    if not results:
        return render_template('error.html', message="Aucune simulation. Lancez-en une d'abord.")
    
    return render_template('results.html', results=results, config=config)

if __name__ == '__main__':
    os.makedirs('flask_session', exist_ok=True)
    app.run(debug=True, host='157.26.83.12', port=52888)
 No newline at end of file
+9 B

File added.

No diff preview for this file type.

+32.5 KiB

File added.

No diff preview for this file type.

+3 −0
Original line number Diff line number Diff line
flask
Flask-Session
numpy
 No newline at end of file
+160 −0
Original line number Diff line number Diff line
import numpy as np

class SimulationEngine:
    def __init__(self, config):
        self.config = config
        np.random.seed(config.get('seed', 42))
        self.setup_entities()
        
    def setup_entities(self):
        # 4 components
        self.components = [
            {'id': 0, 'name': 'Bracelet', 'cost': 8.0},
            {'id': 1, 'name': 'Boîtier', 'cost': 20.0},
            {'id': 2, 'name': 'Mouvement', 'cost': 40.0},
            {'id': 3, 'name': 'Verre', 'cost': 15.0}
        ]
        
        # Watches
        n_watches = self.config.get('n_watches', 3)
        categories = ['Luxury', 'Sport', 'Casual']
        self.watches = []
        
        for i in range(n_watches):
            base_cost = sum(c['cost'] for c in self.components) * 1.2
            category = categories[i % len(categories)]
            markup = {'Luxury': 3.5, 'Sport': 2.25, 'Casual': 1.75}[category]
            
            self.watches.append({
                'id': i,
                'name': f'{category}_Watch_{i}',
                'category': category,
                'base_cost': float(base_cost),
                'sell_price': float(base_cost * markup)
            })
        
        # Customers
        n_customers = self.config.get('n_customers', 100)
        regions = ['North', 'South', 'East', 'West']
        self.customers = []
        
        for i in range(n_customers):
            wealth = int(min(10, max(1, np.random.pareto(1.5) + 1)))
            budget = wealth * np.random.uniform(300, 1200)
            if wealth >= 7:
                budget *= np.random.uniform(2, 4)
            
            self.customers.append({
                'id': i,
                'wealth_class': wealth,
                'region': regions[i % 4],
                'budget': float(budget)
            })
        
        # Retailers
        n_retailers = self.config.get('n_retailers', 4)
        self.retailers = [
            {'id': i, 'name': f'Retailer_{i}', 'region': regions[i % 4], 'markup': 1.2}
            for i in range(n_retailers)
        ]
        
        # Inventory
        self.warehouse_stock = {w['id']: 50 for w in self.watches}
        self.component_stock = {c['id']: 100 for c in self.components}
        self.retailer_stock = {r['id']: {w['id']: 20 for w in self.watches} for r in self.retailers}
    
    def run_simulation(self, n_months=12):
        results = {'monthly_data': [], 'sales_by_watch': {}}
        
        for month in range(n_months):
            month_data = self.simulate_month(month)
            results['monthly_data'].append(month_data)
            
            for sale in month_data['sales']:
                wid = sale['watch_id']
                if wid not in results['sales_by_watch']:
                    results['sales_by_watch'][wid] = {'count': 0, 'revenue': 0.0, 'name': sale['watch_name']}
                results['sales_by_watch'][wid]['count'] += 1
                results['sales_by_watch'][wid]['revenue'] += sale['price']
        
        # Calculate summary
        results['summary'] = {
            'total_revenue': sum(m['kpis']['revenue'] for m in results['monthly_data']),
            'total_sales': sum(m['kpis']['sales_count'] for m in results['monthly_data']),
            'total_margin': sum(m['kpis']['gross_margin'] for m in results['monthly_data']),
            'total_costs': sum(m['kpis']['order_costs'] for m in results['monthly_data'])
        }
        
        return results
    
    def simulate_month(self, month):
        month_data = {'month': month + 1, 'sales': [], 'kpis': {}}
        
        # Simple forecasting
        total_demand = sum(np.random.uniform(3, 8) for _ in self.watches for _ in range(4))
        
        # Restock components if needed
        order_costs = 0
        for comp in self.components:
            if self.component_stock[comp['id']] < 50:
                order_qty = 100
                order_costs += comp['cost'] * order_qty
                self.component_stock[comp['id']] += order_qty
        
        # Assembly
        assembled = 0
        for watch in self.watches:
            to_assemble = min(30, *[self.component_stock[c['id']] for c in self.components])
            if to_assemble > 0:
                for comp in self.components:
                    self.component_stock[comp['id']] -= to_assemble
                self.warehouse_stock[watch['id']] += to_assemble
                assembled += to_assemble
        
        # Distribution
        for watch in self.watches:
            stock = self.warehouse_stock[watch['id']]
            if stock > 0:
                per_retailer = stock // len(self.retailers)
                for retailer in self.retailers:
                    qty = min(per_retailer, 10)
                    self.retailer_stock[retailer['id']][watch['id']] += qty
                    self.warehouse_stock[watch['id']] -= qty
        
        # Sales
        shoppers = np.random.choice(len(self.customers), int(len(self.customers) * 0.15), replace=False)
        
        for idx in shoppers:
            customer = self.customers[idx]
            region_retailers = [r for r in self.retailers if r['region'] == customer['region']]
            if not region_retailers:
                continue
            
            retailer = region_retailers[np.random.randint(0, len(region_retailers))]
            
            for watch in self.watches:
                if self.retailer_stock[retailer['id']][watch['id']] > 0:
                    price = watch['sell_price'] * retailer['markup']
                    if price <= customer['budget'] * 1.5 and np.random.random() < 0.4:
                        self.retailer_stock[retailer['id']][watch['id']] -= 1
                        month_data['sales'].append({
                            'watch_id': watch['id'],
                            'watch_name': watch['name'],
                            'price': price
                        })
                        break
        
        # KPIs
        revenue = sum(s['price'] for s in month_data['sales'])
        cogs = sum(next(w['base_cost'] for w in self.watches if w['id'] == s['watch_id']) 
                   for s in month_data['sales'])
        
        month_data['kpis'] = {
            'revenue': revenue,
            'sales_count': len(month_data['sales']),
            'gross_margin': revenue - cogs,
            'order_costs': order_costs,
            'assembled': assembled
        }
        
        return month_data
 No newline at end of file
Loading