Spaces:
Sleeping
Sleeping
Trae Assistant
Initial commit: Enhanced Queue Strategy Lab with Import/Export and Error Handling
6c4d394
| import os | |
| import random | |
| import simpy | |
| import numpy as np | |
| from flask import Flask, render_template, jsonify, request, send_from_directory | |
| app = Flask(__name__, template_folder='templates') | |
| # Configuration | |
| MAX_SIM_TIME = 480 # 8 hours in minutes for analysis | |
| SEED = 42 | |
| def index(): | |
| return render_template('index.html') | |
| def page_not_found(e): | |
| return render_template('index.html'), 404 | |
| def internal_server_error(e): | |
| return jsonify(error="Internal Server Error", message=str(e)), 500 | |
| def upload_config(): | |
| try: | |
| if 'file' not in request.files: | |
| return jsonify({'error': 'No file part'}), 400 | |
| file = request.files['file'] | |
| if file.filename == '': | |
| return jsonify({'error': 'No selected file'}), 400 | |
| if file: | |
| import json | |
| content = json.load(file) | |
| return jsonify({'message': 'Config uploaded successfully', 'config': content}) | |
| except Exception as e: | |
| return jsonify({'error': str(e)}), 500 | |
| class CallCenter: | |
| def __init__(self, env, num_employees, service_time_avg, service_time_std): | |
| self.env = env | |
| self.staff = simpy.Resource(env, num_employees) | |
| self.service_time_avg = service_time_avg | |
| self.service_time_std = service_time_std | |
| self.wait_times = [] | |
| self.service_times = [] | |
| self.utilization_log = [] | |
| self.events_trace = [] # For visualization: {'time': t, 'type': '...', 'id': ...} | |
| def support(self, customer): | |
| arrival_time = self.env.now | |
| self.events_trace.append({'time': arrival_time, 'type': 'arrival', 'id': customer}) | |
| with self.staff.request() as request: | |
| yield request | |
| wait = self.env.now - arrival_time | |
| self.wait_times.append(wait) | |
| self.events_trace.append({'time': self.env.now, 'type': 'start', 'id': customer, 'wait': wait}) | |
| # Service time (Normal distribution, clipped at 0.5 min) | |
| service_duration = max(0.5, random.gauss(self.service_time_avg, self.service_time_std)) | |
| yield self.env.timeout(service_duration) | |
| self.service_times.append(service_duration) | |
| self.events_trace.append({'time': self.env.now, 'type': 'finish', 'id': customer}) | |
| def customer_generator(env, center, arrival_rate): | |
| """ | |
| arrival_rate: Customers per hour | |
| """ | |
| i = 0 | |
| while True: | |
| # Inter-arrival time (Exponential distribution) | |
| yield env.timeout(random.expovariate(arrival_rate / 60.0)) | |
| i += 1 | |
| env.process(center.support(f'C{i}')) | |
| def simulate(): | |
| data = request.json | |
| # Parameters | |
| arrival_rate = float(data.get('arrival_rate', 60)) # Cust/hr | |
| service_time = float(data.get('service_time', 5)) # Avg min | |
| service_std = float(data.get('service_std', 1)) # Std Dev min | |
| num_servers = int(data.get('num_servers', 3)) | |
| duration = float(data.get('duration', 60)) # Minutes to simulate | |
| random.seed(SEED) | |
| env = simpy.Environment() | |
| center = CallCenter(env, num_servers, service_time, service_std) | |
| env.process(customer_generator(env, center, arrival_rate)) | |
| env.run(until=duration) | |
| # Calculate stats | |
| avg_wait = np.mean(center.wait_times) if center.wait_times else 0 | |
| max_wait = np.max(center.wait_times) if center.wait_times else 0 | |
| served_count = len(center.service_times) | |
| # Utilization estimate (Total Service Time / (Num Servers * Duration)) | |
| total_service = sum(center.service_times) | |
| utilization = (total_service / (num_servers * duration)) * 100 if num_servers > 0 else 0 | |
| return jsonify({ | |
| 'metrics': { | |
| 'avg_wait': round(avg_wait, 2), | |
| 'max_wait': round(max_wait, 2), | |
| 'served': served_count, | |
| 'utilization': round(utilization, 2) | |
| }, | |
| 'trace': center.events_trace | |
| }) | |
| def optimize(): | |
| data = request.json | |
| arrival_rate = float(data.get('arrival_rate', 60)) | |
| service_time = float(data.get('service_time', 5)) | |
| service_std = float(data.get('service_std', 1)) | |
| cost_per_server_hr = float(data.get('cost_server', 20)) # $20/hr | |
| cost_per_wait_hr = float(data.get('cost_wait', 50)) # $50/hr (Value of customer time/frustration) | |
| results = [] | |
| # Test 1 to 15 servers | |
| for n in range(1, 16): | |
| random.seed(SEED) # Reset seed for fair comparison | |
| env = simpy.Environment() | |
| center = CallCenter(env, n, service_time, service_std) | |
| env.process(customer_generator(env, center, arrival_rate)) | |
| env.run(until=480) # 8 hours | |
| avg_wait_min = np.mean(center.wait_times) if center.wait_times else 0 | |
| total_wait_hours = sum(center.wait_times) / 60.0 | |
| # Total Cost = (Server Cost * 8h) + (Total Wait Hours * Wait Cost) | |
| server_cost = n * cost_per_server_hr * 8 | |
| wait_cost = total_wait_hours * cost_per_wait_hr | |
| total_cost = server_cost + wait_cost | |
| utilization = (sum(center.service_times) / (n * 480)) * 100 | |
| results.append({ | |
| 'servers': n, | |
| 'total_cost': round(total_cost, 2), | |
| 'server_cost': round(server_cost, 2), | |
| 'wait_cost': round(wait_cost, 2), | |
| 'avg_wait': round(avg_wait_min, 2), | |
| 'utilization': round(utilization, 1) | |
| }) | |
| # Optimization: if cost starts increasing significantly and wait is low, we can stop, | |
| # but let's run all 15 for the chart. | |
| return jsonify({'results': results}) | |
| if __name__ == '__main__': | |
| app.run(host='0.0.0.0', port=7860, debug=True) | |