From f2e4659f103b553b0e3673cb33ebc304ae2e2cc8 Mon Sep 17 00:00:00 2001 From: Floke Date: Mon, 4 Aug 2025 15:13:08 +0000 Subject: [PATCH] data_processor.py aktualisiert --- data_processor.py | 69 +++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 69 insertions(+) diff --git a/data_processor.py b/data_processor.py index 627a0e8c..58c1b7c3 100644 --- a/data_processor.py +++ b/data_processor.py @@ -5707,6 +5707,75 @@ class DataProcessor: self.logger.info("Modelltraining und -evaluation abgeschlossen.") + def process_predict_technicians(self, start_sheet_row=None, end_sheet_row=None, limit=None): + """ + Batch-Prozess zur Vorhersage von Techniker-Buckets für Zeilen, + bei denen diese Information fehlt. + """ + self.logger.info(f"Starte Modus 'predict_technicians' (Batch). Bereich: {start_sheet_row or 'Start'}-{end_sheet_row or 'Ende'}, Limit: {limit or 'Unbegrenzt'}") + + # Prüfen, ob das Modell geladen ist (passiert im setup()) + if not self.is_setup_complete or self.model is None or self.imputer is None or self._expected_features is None: + self.logger.error("ML-Artefakte nicht initialisiert. Bitte zuerst trainieren. Breche Vorhersage ab.") + return + + if not self.sheet_handler.load_data(): + self.logger.error("Fehler beim Laden der Daten für die Vorhersage.") + return + + all_data = self.sheet_handler.get_all_data_with_headers() + header_rows = self.sheet_handler._header_rows + + effective_start = start_sheet_row if start_sheet_row is not None else header_rows + 1 + effective_end = end_sheet_row if end_sheet_row is not None else len(all_data) + + tasks = [] + for i in range(effective_start - 1, effective_end): + if limit is not None and len(tasks) >= limit: + break + + row_data = all_data[i] + bucket_value = self._get_cell_value_safe(row_data, "Geschaetzter Techniker Bucket").strip() + # Kriterium: Bucket ist leer oder enthält einen Fehler + if not bucket_value or "fehler" in bucket_value.lower(): + tasks.append({'row_num': i + 1, 'data': row_data}) + + if not tasks: + self.logger.info("Keine Zeilen für die Techniker-Vorhersage gefunden.") + return + + self.logger.info(f"{len(tasks)} Zeilen für die Vorhersage identifiziert. Starte Verarbeitung...") + + all_updates = [] + processed_count = 0 + update_batch_size = getattr(Config, 'UPDATE_BATCH_ROW_LIMIT', 50) + + for idx, task in enumerate(tasks): + row_num = task['row_num'] + row_data = task['data'] + try: + # Aufruf der internen Methode zur Vorhersage für die einzelne Zeile + predicted_bucket = self._predict_technician_bucket(row_data) + + col_idx = get_col_idx("Geschaetzter Techniker Bucket") + if col_idx is not None: + col_letter = self.sheet_handler._get_col_letter(col_idx + 1) + all_updates.append({'range': f'{col_letter}{row_num}', 'values': [[predicted_bucket]]}) + + processed_count += 1 + except Exception as e: + self.logger.error(f"Fehler bei der Vorhersage für Zeile {row_num}: {e}", exc_info=True) + + # Batch-Update-Logik + if (idx + 1) % update_batch_size == 0 or (idx + 1) == len(tasks): + if all_updates: + self.logger.info(f"Sende Batch-Update für {len(all_updates)} Vorhersagen...") + self.sheet_handler.batch_update_cells(all_updates) + all_updates = [] + + self.logger.info(f"Techniker-Vorhersage abgeschlossen. {processed_count} Zeilen bearbeitet.") + + def process_website_details( self, start_sheet_row=None,