# app.py (v2.1 - mit Job-Manager) from flask import Flask, jsonify, request import subprocess import sys import os import logging import uuid import json from datetime import datetime from pyngrok import ngrok, conf from config import Config logging.basicConfig(level=logging.INFO, format='%(asctime)s - %(levelname)s - %(message)s') app = Flask(__name__) STATUS_DIR = "job_status" os.makedirs(STATUS_DIR, exist_ok=True) SCRIPT_MAP = { "run_duplicate_check": {"script": "duplicate_checker.py", "args": []}, "run_reclassify_branches": {"script": "brancheneinstufung2.py", "args": ["--mode", "reclassify_branches"]}, "run_predict_technicians": {"script": "brancheneinstufung2.py", "args": ["--mode", "predict_technicians"]}, } def setup_ngrok(): # ... (Ihre ngrok-Setup-Funktion bleibt unverändert) try: authtoken = os.environ.get("NGROK_AUTHTOKEN") if not authtoken: if os.path.exists("ngrok_authtoken.txt"): with open("ngrok_authtoken.txt", "r") as f: authtoken = f.read().strip() if not authtoken: logging.error("NGROK_AUTHTOKEN nicht gefunden.") return None conf.get_default().auth_token = authtoken public_url = ngrok.connect(8080, "http") logging.info(f"!!! Ngrok-Tunnel gestartet: {public_url} !!!") return public_url except Exception as e: logging.error(f"Fehler beim Starten von ngrok: {e}") sys.exit(1) @app.route('/run-script', methods=['POST']) def run_script(): """Startet ein Skript als Hintergrundprozess und verfolgt es über eine Job-ID.""" try: data = request.get_json() action = data.get('action') if not action or action not in SCRIPT_MAP: return jsonify({"status": "error", "message": "Ungültige Aktion."}), 400 script_config = SCRIPT_MAP[action] script_name = script_config["script"] # Job-ID generieren und als Argument übergeben job_id = str(uuid.uuid4()) command = [sys.executable, script_name] + script_config["args"] + ["--job-id", job_id] script_dir = os.path.dirname(os.path.abspath(__file__)) log_dir = os.path.join(script_dir, "Log") os.makedirs(log_dir, exist_ok=True) timestamp = datetime.now().strftime("%Y-%m-%d_%H-%M-%S") process_log_path = os.path.join(log_dir, f"{timestamp}_{action}_{job_id[:8]}.log") with open(process_log_path, 'w') as log_file: subprocess.Popen(command, cwd=script_dir, stdout=log_file, stderr=log_file) # Erstelle eine initiale Statusdatei status_file = os.path.join(STATUS_DIR, f"{job_id}.json") with open(status_file, 'w') as f: json.dump({ "action": action, "status": "Gestartet", "start_time": datetime.now().isoformat(), "progress": "Prozess wird initialisiert..." }, f) return jsonify({"status": "success", "message": f"Aktion '{action}' gestartet."}), 200 except Exception as e: logging.error(f"Fehler in run_script: {e}", exc_info=True) return jsonify({"status": "error", "message": str(e)}), 500 # --- NEUE FUNKTION --- @app.route('/get-status', methods=['GET']) def get_status(): """Liest alle Job-Status-Dateien und gibt den aktuellen Stand zurück.""" all_statuses = [] for filename in sorted(os.listdir(STATUS_DIR), reverse=True): # Neueste zuerst if filename.endswith(".json"): try: with open(os.path.join(STATUS_DIR, filename), 'r') as f: status_data = json.load(f) status_data['job_id'] = filename.replace('.json', '') all_statuses.append(status_data) except Exception as e: logging.warning(f"Konnte Statusdatei {filename} nicht lesen: {e}") return jsonify(all_statuses) if __name__ == '__main__': setup_ngrok() app.run(host='0.0.0.0', port=8080)