From 9b682a8617ecc7e8de82356885ad0d63184dd594 Mon Sep 17 00:00:00 2001 From: Floke Date: Mon, 28 Jul 2025 12:43:36 +0000 Subject: [PATCH] Implementierung der Batch-Brancheneinstufung zur Kostenoptimierung MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - FEATURE: Brancheneinstufung erfolgt nun in Batches (z.B. 20 Unternehmen pro API-Call), um die Token-Kosten drastisch zu senken. - REFACTOR: Neue Funktion `evaluate_branches_batch` in `helpers.py` erstellt, die den komplexen Batch-Prompt generiert. - REFACTOR: `reclassify_all_branches` in `data_processor.py` überarbeitet, um die Batch-Verarbeitung und das Ergebnis-Mapping zu steuern. --- data_processor.py | 87 ++++++++++++++++++++++++++--------------------- 1 file changed, 48 insertions(+), 39 deletions(-) diff --git a/data_processor.py b/data_processor.py index 20b015ab..f38ac3f5 100644 --- a/data_processor.py +++ b/data_processor.py @@ -1462,78 +1462,87 @@ class DataProcessor: self.logger.info(f"FSM-Pitch-Generierung abgeschlossen. {processed_count} Zeilen bearbeitet.") - def reclassify_all_branches(self, start_sheet_row=None, limit=None): + def reclassify_all_branches(self, start_sheet_row=None, limit=None, batch_size=20): """ - Führt für alle relevanten Zeilen eine neue Brancheneinstufung (v2.0) durch. - Dieser Modus ist ideal, um nach einer Änderung der Branchen-Definitionen - den gesamten Datenbestand zu aktualisieren. + Führt für alle relevanten Zeilen eine neue Brancheneinstufung (v2.0) in Batches durch. """ - self.logger.info(f"Starte Modus 'reclassify_branches'. Bereich: {start_sheet_row or 'Start'}, Limit: {limit or 'Unbegrenzt'}") + self.logger.info(f"Starte Modus 'reclassify_branches' im Batch-Modus (Größe: {batch_size}). Bereich: {start_sheet_row or 'Start'}, Limit: {limit or 'Unbegrenzt'}") if not self.sheet_handler.load_data(): 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 tasks = [] for i in range(effective_start - 1, len(all_data)): if limit is not None and len(tasks) >= limit: break - row_data = all_data[i] company_name = self._get_cell_value_safe(row_data, "CRM Name").strip() if company_name: tasks.append({'row_num': i + 1, 'data': row_data}) - + if not tasks: self.logger.info("Keine Zeilen zur Neubewertung gefunden.") return - + self.logger.info(f"{len(tasks)} Zeilen für die Neubewertung der Branche identifiziert.") all_sheet_updates = [] now_timestamp = datetime.now().strftime("%Y-%m-%d %H:%M:%S") - for task in tasks: - row_num = task['row_num'] - row_data = task['data'] + # Verarbeite die Tasks in Batches + for i in range(0, len(tasks), batch_size): + batch_tasks = tasks[i:i + batch_size] + self.logger.info(f"Verarbeite Batch {i//batch_size + 1}/{(len(tasks) + batch_size - 1)//batch_size} (Zeilen {batch_tasks[0]['row_num']} bis {batch_tasks[-1]['row_num']})...") + + # Bereite die Daten für den Batch-Prompt vor + companies_data_for_prompt = [] + for task in batch_tasks: + row_data = task['data'] + companies_data_for_prompt.append({ + "row_num": task['row_num'], + "name": self._get_cell_value_safe(row_data, "CRM Name"), + "summary": self._get_cell_value_safe(row_data, "Website Zusammenfassung"), + "wiki": self._get_cell_value_safe(row_data, "Wiki Absatz") + }) - self.logger.debug(f"Bewerte Branche für Zeile {row_num}...") + # Rufe die neue Batch-Funktion auf + batch_results = evaluate_branches_batch(companies_data_for_prompt) - try: - result = evaluate_branche_chatgpt( - company_name=self._get_cell_value_safe(row_data, "CRM Name"), - website_summary=self._get_cell_value_safe(row_data, "Website Zusammenfassung"), - wiki_absatz=self._get_cell_value_safe(row_data, "Wiki Absatz") - ) + if batch_results: + # Ordne die Ergebnisse den richtigen Zeilen zu + results_by_row = {res['row_num']: res for res in batch_results} - # Updates für die drei Zielspalten vorbereiten - all_sheet_updates.append({'range': f'{self.sheet_handler._get_col_letter(COLUMN_MAP["Chat Vorschlag Branche"]["index"] + 1)}{row_num}', 'values': [[result.get('branch')]]}) - all_sheet_updates.append({'range': f'{self.sheet_handler._get_col_letter(COLUMN_MAP["Chat Branche Konfidenz"]["index"] + 1)}{row_num}', 'values': [[result.get('confidence')]]}) - all_sheet_updates.append({'range': f'{self.sheet_handler._get_col_letter(COLUMN_MAP["Chat Begruendung Abweichung Branche"]["index"] + 1)}{row_num}', 'values': [[result.get('justification')]]}) - # Auch den Timestamp aktualisieren - all_sheet_updates.append({'range': f'{self.sheet_handler._get_col_letter(COLUMN_MAP["Timestamp letzte Pruefung"]["index"] + 1)}{row_num}', 'values': [[now_timestamp]]}) + for task in batch_tasks: + row_num = task['row_num'] + result = results_by_row.get(row_num) + + if result: + all_sheet_updates.append({'range': f'{self.sheet_handler._get_col_letter(COLUMN_MAP["Chat Vorschlag Branche"]["index"] + 1)}{row_num}', 'values': [[result.get('Branche')]]}) + all_sheet_updates.append({'range': f'{self.sheet_handler._get_col_letter(COLUMN_MAP["Chat Branche Konfidenz"]["index"] + 1)}{row_num}', 'values': [[result.get('Konfidenz')]]}) + all_sheet_updates.append({'range': f'{self.sheet_handler._get_col_letter(COLUMN_MAP["Chat Begruendung Abweichung Branche"]["index"] + 1)}{row_num}', 'values': [[result.get('Begruendung')]]}) + else: + self.logger.error(f"Kein Ergebnis für Zeile {row_num} im Batch-Resultat gefunden.") + all_sheet_updates.append({'range': f'{self.sheet_handler._get_col_letter(COLUMN_MAP["Chat Vorschlag Branche"]["index"] + 1)}{row_num}', 'values': [['FEHLER (Batch-Antwort)']]} ) + + # Timestamp immer setzen + all_sheet_updates.append({'range': f'{self.sheet_handler._get_col_letter(COLUMN_MAP["Timestamp letzte Pruefung"]["index"] + 1)}{row_num}', 'values': [[now_timestamp]]}) + else: + self.logger.error(f"Batch-Verarbeitung für Zeilen {batch_tasks[0]['row_num']} bis {batch_tasks[-1]['row_num']} fehlgeschlagen. Setze Fehlerstatus.") + for task in batch_tasks: + row_num = task['row_num'] + all_sheet_updates.append({'range': f'{self.sheet_handler._get_col_letter(COLUMN_MAP["Chat Vorschlag Branche"]["index"] + 1)}{row_num}', 'values': [['FEHLER (Batch-API)']]} ) + all_sheet_updates.append({'range': f'{self.sheet_handler._get_col_letter(COLUMN_MAP["Timestamp letzte Pruefung"]["index"] + 1)}{row_num}', 'values': [[now_timestamp]]}) - except Exception as e: - self.logger.error(f"FEHLER bei Branchen-Neubewertung für Zeile {row_num}: {e}") - all_sheet_updates.append({'range': f'{self.sheet_handler._get_col_letter(COLUMN_MAP["Chat Vorschlag Branche"]["index"] + 1)}{row_num}', 'values': [['FEHLER (Prozess)']]} ) - - # Batch-Update Logik (vereinfacht, um es hier zu zeigen) - if len(all_sheet_updates) >= 200: # 50 Zeilen * 4 Updates pro Zeile - self.logger.info(f"Sende Batch-Update für {len(all_sheet_updates)//4} Branchen...") - self.sheet_handler.batch_update_cells(all_sheet_updates) - all_sheet_updates = [] - time.sleep(1) - - # Letzten Batch senden + # Finalen Batch-Update senden if all_sheet_updates: - self.logger.info(f"Sende finalen Batch-Update für {len(all_sheet_updates)//4} Branchen...") + self.logger.info(f"Sende finales Batch-Update für {len(tasks)} bewertete Branchen...") self.sheet_handler.batch_update_cells(all_sheet_updates) - self.logger.info("Branchen-Neubewertung abgeschlossen.") + self.logger.info("Branchen-Neubewertung im Batch-Modus abgeschlossen.") # ==========================================================================