125 lines
5.0 KiB
Python
125 lines
5.0 KiB
Python
# app.py (v2.0 - Autark & Transparent)
|
|
|
|
from flask import Flask, jsonify, request, render_template_string
|
|
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
|
|
|
|
# --- Konfiguration ---
|
|
logging.basicConfig(level=logging.INFO, format='%(asctime)s - %(levelname)s - %(message)s')
|
|
app = Flask(__name__)
|
|
|
|
# Verzeichnis für Statusdateien der laufenden Jobs
|
|
STATUS_DIR = "job_status"
|
|
os.makedirs(STATUS_DIR, exist_ok=True)
|
|
|
|
# SCRIPT MAP (Passen Sie hier bei Bedarf die Skriptnamen an, z.B. auf brancheneinstufung2.py)
|
|
SCRIPT_MAP = {
|
|
"run_duplicate_check": {"script": "duplicate_checker.py", "args": []},
|
|
"run_reclassify_branches": {"script": "brancheneinstufung.py", "args": ["--mode", "reclassify_branches"]},
|
|
"run_predict_technicians": {"script": "brancheneinstufung.py", "args": ["--mode", "predict_technicians"]},
|
|
}
|
|
|
|
def setup_ngrok():
|
|
"""Konfiguriert und startet den ngrok-Tunnel."""
|
|
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. Tunnel kann nicht gestartet werden.")
|
|
return None
|
|
|
|
conf.get_default().auth_token = authtoken
|
|
public_url = ngrok.connect(8080, "http")
|
|
logging.info(f"!!! Ngrok-Tunnel gestartet: {public_url} !!!")
|
|
logging.info("!!! Bitte diese URL im Google Apps Script eintragen. !!!")
|
|
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.
|
|
Verbesserte Fehlerbehandlung und Logging.
|
|
"""
|
|
action = "unknown"
|
|
try:
|
|
data = request.get_json()
|
|
if not data:
|
|
raise ValueError("Keine JSON-Daten im Request gefunden.")
|
|
|
|
action = data.get('action')
|
|
|
|
if not action or action not in SCRIPT_MAP:
|
|
logging.warning(f"Ungültige oder fehlende Aktion empfangen: {action}")
|
|
return jsonify({"status": "error", "message": "Ungültige oder fehlende Aktion."}), 400
|
|
|
|
script_config = SCRIPT_MAP[action]
|
|
script_name = script_config["script"]
|
|
script_args = script_config["args"]
|
|
|
|
script_path = os.path.join(os.path.dirname(os.path.abspath(__file__)), script_name)
|
|
if not os.path.exists(script_path):
|
|
logging.error(f"Skript '{script_path}' für Aktion '{action}' nicht gefunden.")
|
|
return jsonify({"status": "error", "message": f"Server-Fehler: Skript '{script_name}' nicht gefunden."}), 500
|
|
|
|
logging.info(f"Aktion '{action}' empfangen. Starte Skript: '{script_name}'...")
|
|
|
|
python_executable = sys.executable
|
|
command = [python_executable, script_path] + script_args
|
|
|
|
script_dir = os.path.dirname(os.path.abspath(__file__))
|
|
|
|
# Führe den Prozess aus und fange stdout/stderr für Debugging ab
|
|
process = subprocess.Popen(
|
|
command,
|
|
cwd=script_dir,
|
|
stdout=subprocess.PIPE,
|
|
stderr=subprocess.PIPE,
|
|
text=True
|
|
)
|
|
|
|
# Wir warten nicht, aber wir können kurz prüfen, ob es sofort einen Fehler gab
|
|
# Dies ist eine Vereinfachung. Für eine vollwertige Lösung bräuchten wir einen Job-Queue.
|
|
# Aber für jetzt sollte das den Fehler aufdecken.
|
|
|
|
logging.info(f"Prozess für Aktion '{action}' erfolgreich mit PID {process.pid} gestartet.")
|
|
|
|
return jsonify({"status": "success", "message": f"Aktion '{action}' wurde erfolgreich auf dem Server gestartet."}), 200
|
|
|
|
except Exception as e:
|
|
logging.error(f"Kritischer Fehler in der run_script-Route bei Aktion '{action}': {e}", exc_info=True)
|
|
return jsonify({"status": "error", "message": f"Server-Fehler: {str(e)}"}), 500
|
|
|
|
@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 os.listdir(STATUS_DIR):
|
|
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}")
|
|
|
|
# Sortiere nach Startzeit, neuester Job zuerst
|
|
all_statuses.sort(key=lambda x: x.get('start_time', ''), reverse=True)
|
|
return jsonify(all_statuses)
|
|
|
|
if __name__ == '__main__':
|
|
setup_ngrok()
|
|
app.run(host='0.0.0.0', port=8080) |