Spaces:
Sleeping
Sleeping
Trae Assistant
feat: enhance assembly line tool with import/export and robust error handling
dda07d1 | import os | |
| import json | |
| import math | |
| from flask import Flask, render_template, request, jsonify | |
| app = Flask(__name__) | |
| app.config['MAX_CONTENT_LENGTH'] = 16 * 1024 * 1024 # 16MB Max Limit | |
| def page_not_found(e): | |
| return render_template('index.html'), 404 | |
| def internal_server_error(e): | |
| return jsonify({"error": "Internal Server Error", "details": str(e)}), 500 | |
| def upload_file(): | |
| 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: | |
| try: | |
| data = json.load(file) | |
| return jsonify({"message": "File uploaded successfully", "data": data}) | |
| except json.JSONDecodeError: | |
| return jsonify({"error": "Invalid JSON file"}), 400 | |
| except Exception as e: | |
| return jsonify({"error": str(e)}), 500 | |
| # Default Data (Enriched for User Experience) | |
| DEFAULT_TASKS = [ | |
| {"id": "t1", "name": "安装底壳 (Install Chassis)", "duration": 15}, | |
| {"id": "t2", "name": "安装主板 (Mount PCB)", "duration": 25}, | |
| {"id": "t3", "name": "连接电源线 (Connect Power)", "duration": 10}, | |
| {"id": "t4", "name": "安装风扇 (Install Fan)", "duration": 12}, | |
| {"id": "t5", "name": "固定硬盘 (Secure HDD)", "duration": 18}, | |
| {"id": "t6", "name": "安装显卡 (Install GPU)", "duration": 20}, | |
| {"id": "t7", "name": "理线 (Cable Mgmt)", "duration": 30}, | |
| {"id": "t8", "name": "合盖 (Close Case)", "duration": 10}, | |
| {"id": "t9", "name": "贴标签 (Labeling)", "duration": 5}, | |
| {"id": "t10", "name": "最终测试 (Final Test)", "duration": 40} | |
| ] | |
| DEFAULT_CONFIG = { | |
| "work_hours": 8, | |
| "target_output": 100 # Units per day | |
| } | |
| def index(): | |
| return render_template('index.html') | |
| def calculate_metrics(): | |
| """ | |
| Calculate Line Efficiency, Smoothness Index, and Takt Time. | |
| Input: { "stations": [[task1, task2], [task3]], "config": {...} } | |
| """ | |
| data = request.json | |
| stations = data.get('stations', []) | |
| config = data.get('config', DEFAULT_CONFIG) | |
| # 1. Calculate Takt Time (Seconds) | |
| # Takt Time = Available Time / Demand | |
| available_seconds = config.get('work_hours', 8) * 3600 | |
| demand = config.get('target_output', 100) | |
| if demand <= 0: demand = 1 | |
| takt_time = available_seconds / demand | |
| # 2. Calculate Station Times | |
| station_times = [] | |
| total_work_content = 0 | |
| for station in stations: | |
| s_time = sum(t.get('duration', 0) for t in station) | |
| station_times.append(s_time) | |
| total_work_content += s_time | |
| if not station_times: | |
| return jsonify({"error": "No stations defined"}) | |
| # 3. Calculate Bottleneck (Max Station Time) | |
| bottleneck_time = max(station_times) | |
| bottleneck_index = station_times.index(bottleneck_time) | |
| # 4. Calculate Efficiency | |
| # Efficiency = Total Work Content / (Num Stations * Bottleneck Time) | |
| num_stations = len(stations) | |
| efficiency = 0 | |
| if num_stations > 0 and bottleneck_time > 0: | |
| efficiency = (total_work_content / (num_stations * bottleneck_time)) * 100 | |
| # 5. Calculate Smoothness Index (SI) | |
| # SI = Sqrt(Sum( (Max - Si)^2 )) | |
| si_sum = sum((bottleneck_time - st)**2 for st in station_times) | |
| smoothness_index = math.sqrt(si_sum) | |
| # 6. Capacity Calculation | |
| # Hourly Capacity = 3600 / Bottleneck Time | |
| hourly_capacity = 0 | |
| if bottleneck_time > 0: | |
| hourly_capacity = 3600 / bottleneck_time | |
| daily_capacity = hourly_capacity * config.get('work_hours', 8) | |
| return jsonify({ | |
| "metrics": { | |
| "takt_time": round(takt_time, 2), | |
| "bottleneck_time": round(bottleneck_time, 2), | |
| "bottleneck_station": bottleneck_index + 1, | |
| "line_efficiency": round(efficiency, 2), | |
| "smoothness_index": round(smoothness_index, 2), | |
| "hourly_capacity": round(hourly_capacity, 1), | |
| "daily_capacity": round(daily_capacity, 1), | |
| "total_work_content": total_work_content | |
| }, | |
| "station_times": station_times | |
| }) | |
| def auto_balance(): | |
| """ | |
| Simple Greedy Algorithm to re-balance line. | |
| Try to fill stations up to Takt Time (or slightly above if unavoidable). | |
| """ | |
| data = request.json | |
| all_tasks = data.get('tasks', []) | |
| config = data.get('config', DEFAULT_CONFIG) | |
| # Calculate Takt Time Target | |
| available_seconds = config.get('work_hours', 8) * 3600 | |
| demand = config.get('target_output', 100) | |
| takt_time = available_seconds / demand if demand > 0 else 60 | |
| # Heuristic: Sort tasks? | |
| # In real assembly, order matters (precedence). | |
| # Here we assume the Input List order IS the precedence constraint order (roughly). | |
| # We will just cut the list into chunks. | |
| new_stations = [] | |
| current_station = [] | |
| current_time = 0 | |
| for task in all_tasks: | |
| t_dur = task.get('duration', 0) | |
| # If adding this task exceeds Takt Time significantly, start new station? | |
| # Let's try to fit as much as possible <= Takt Time. | |
| # If a single task > Takt Time, it must be in a station alone (and will be bottleneck). | |
| if current_time + t_dur <= takt_time: | |
| current_station.append(task) | |
| current_time += t_dur | |
| else: | |
| # If current station is not empty, close it | |
| if current_station: | |
| new_stations.append(current_station) | |
| current_station = [task] | |
| current_time = t_dur | |
| else: | |
| # Task itself is larger than Takt Time | |
| new_stations.append([task]) | |
| current_time = 0 # Reset for next | |
| current_station = [] | |
| if current_station: | |
| new_stations.append(current_station) | |
| return jsonify({ | |
| "stations": new_stations, | |
| "message": "Auto-balance completed based on Takt Time constraint." | |
| }) | |
| if __name__ == '__main__': | |
| port = int(os.environ.get('PORT', 7860)) | |
| app.run(host='0.0.0.0', port=port, debug=True) | |