bugfix
This commit is contained in:
@@ -8395,24 +8395,27 @@ class DataProcessor:
|
||||
"""
|
||||
Batch-Prozess zur Generierung von Parent-Account-Vorschlägen mittels ChatGPT.
|
||||
Schreibt Ergebnisse in Spalten O, P, Q.
|
||||
Bearbeitet nur Zeilen, bei denen Spalte Q (Parent Vorschlag Timestamp) leer ist,
|
||||
es sei denn re_evaluate_question_mark ist True und Spalte P ist '?'.
|
||||
|
||||
Args:
|
||||
start_sheet_row (int, optional): Die 1-basierte Startzeile.
|
||||
end_sheet_row (int, optional): Die 1-basierte Endzeile.
|
||||
limit (int, optional): Maximale Anzahl zu verarbeitender Zeilen.
|
||||
re_evaluate_question_mark (bool, optional): Wenn True, werden auch Zeilen mit '?'
|
||||
in Spalte P (Parent Vorschlag Status) erneut bewertet.
|
||||
re_evaluate_question_mark (bool, optional): Wenn True, werden auch Zeilen mit '?'
|
||||
in Spalte P (Parent Vorschlag Status) erneut bewertet,
|
||||
AUCH WENN Spalte Q bereits einen Timestamp hat.
|
||||
"""
|
||||
self.logger.info(f"Starte Parent Account Suggestion Batch. Bereich: {start_sheet_row if start_sheet_row else 'Start'}-{end_sheet_row if end_sheet_row else 'Ende'}, Limit: {limit if limit else 'Unbegrenzt'}, Re-Eval ?: {re_evaluate_question_mark}")
|
||||
|
||||
# --- Daten laden und Startzeile ermitteln ---
|
||||
col_o_key = "System Vorschlag Parent Account"
|
||||
col_p_key = "Parent Vorschlag Status"
|
||||
col_q_key = "Parent Vorschlag Timestamp"
|
||||
col_q_key = "Parent Vorschlag Timestamp" # Timestamp-Spalte für die Auswahl
|
||||
|
||||
if start_sheet_row is None:
|
||||
self.logger.info(f"Automatische Ermittlung der Startzeile basierend auf leerem '{col_o_key}'...")
|
||||
start_data_index_no_header = self.sheet_handler.get_start_row_index(check_column_key=col_o_key, min_sheet_row=7)
|
||||
self.logger.info(f"Automatische Ermittlung der Startzeile basierend auf leerem '{col_q_key}'...") # Geändert: Start basierend auf leerem Q
|
||||
start_data_index_no_header = self.sheet_handler.get_start_row_index(check_column_key=col_q_key, min_sheet_row=7)
|
||||
if start_data_index_no_header == -1:
|
||||
self.logger.error("FEHLER bei autom. Startzeilenermittlung. Breche ab.")
|
||||
return
|
||||
@@ -8446,24 +8449,21 @@ class DataProcessor:
|
||||
col_o_letter = self.sheet_handler._get_col_letter(COLUMN_MAP[col_o_key] + 1)
|
||||
col_p_letter = self.sheet_handler._get_col_letter(COLUMN_MAP[col_p_key] + 1)
|
||||
col_q_letter = self.sheet_handler._get_col_letter(COLUMN_MAP[col_q_key] + 1)
|
||||
# Begründung kann optional in eine neue Spalte oder hier ins Log
|
||||
# Fürs Erste nur Logging der Begründung.
|
||||
|
||||
# --- Konfiguration für Parallelverarbeitung ---
|
||||
openai_sem = threading.Semaphore(getattr(Config, 'OPENAI_CONCURRENCY_LIMIT', 3))
|
||||
max_workers = getattr(Config, 'MAX_BRANCH_WORKERS', 10) # Wiederverwendung der Branch Worker Config
|
||||
processing_batch_size = getattr(Config, 'PROCESSING_BRANCH_BATCH_SIZE', 10) # Batch-Größe für Tasks
|
||||
max_workers = getattr(Config, 'MAX_BRANCH_WORKERS', 10)
|
||||
processing_batch_size = getattr(Config, 'PROCESSING_BRANCH_BATCH_SIZE', 10)
|
||||
update_batch_row_limit = getattr(Config, 'UPDATE_BATCH_ROW_LIMIT', 50)
|
||||
|
||||
|
||||
tasks_for_current_openai_batch = []
|
||||
all_sheet_updates = []
|
||||
processed_count = 0
|
||||
skipped_count = 0
|
||||
|
||||
# Funktion zum Verarbeiten und Schreiben eines Batches
|
||||
# Funktion zum Verarbeiten und Schreiben eines Batches (bleibt intern gleich)
|
||||
def _execute_and_write_openai_batch(current_tasks):
|
||||
nonlocal processed_count # Um processed_count im äußeren Scope zu modifizieren
|
||||
# ... (Code der inneren Funktion bleibt identisch wie im vorherigen Vorschlag) ...
|
||||
nonlocal processed_count
|
||||
if not current_tasks:
|
||||
return
|
||||
|
||||
@@ -8482,17 +8482,16 @@ class DataProcessor:
|
||||
except Exception as e_future:
|
||||
self.logger.error(f"Exception im Future für Parent Suggestion Zeile {task_info_orig['row_num']}: {e_future}")
|
||||
batch_results_list.append({
|
||||
"row_num": task_info_orig['row_num'],
|
||||
"suggested_parent": "FEHLER_TASK",
|
||||
"row_num": task_info_orig['row_num'],
|
||||
"suggested_parent": "FEHLER_TASK",
|
||||
"justification": str(e_future)[:150],
|
||||
"error": str(e_future)
|
||||
})
|
||||
|
||||
|
||||
self.logger.debug(f" OpenAI Batch ({batch_start_log_row}-{batch_end_log_row}) abgeschlossen. {len(batch_results_list)} Ergebnisse erhalten.")
|
||||
|
||||
if batch_results_list:
|
||||
now_ts_str = datetime.now().strftime("%Y-%m-%d %H:%M:%S")
|
||||
current_version_str = getattr(Config, 'VERSION', 'unknown')
|
||||
updates_for_this_batch = []
|
||||
|
||||
for res_item in batch_results_list:
|
||||
@@ -8500,33 +8499,29 @@ class DataProcessor:
|
||||
parent_val = res_item.get('suggested_parent', 'k.A. (Fehler)')
|
||||
|
||||
updates_for_this_batch.append({'range': f'{col_o_letter}{rn}', 'values': [[parent_val]]})
|
||||
# Nur auf "?" setzen, wenn ein Vorschlag gemacht wurde (nicht "k.A." oder Fehler)
|
||||
status_val = "?" if parent_val and parent_val.lower() != "k.a." and not parent_val.startswith("FEHLER") else ""
|
||||
updates_for_this_batch.append({'range': f'{col_p_letter}{rn}', 'values': [[status_val]]})
|
||||
updates_for_this_batch.append({'range': f'{col_q_letter}{rn}', 'values': [[now_ts_str]]})
|
||||
# Optional: Begründung in eine neue Spalte schreiben
|
||||
# updates_for_this_batch.append({'range': f'{BEGRUENDUNG_SPALTE_LETTER}{rn}', 'values': [[res_item.get('justification', '')]]})
|
||||
|
||||
# Logge die Begründung, auch wenn sie nicht ins Sheet geschrieben wird
|
||||
|
||||
if res_item.get('justification'):
|
||||
self.logger.debug(f"Zeile {rn} - Parent Begründung: {res_item.get('justification')[:200]}...")
|
||||
|
||||
|
||||
all_sheet_updates.extend(updates_for_this_batch)
|
||||
processed_count += len(current_tasks) # Erhöhe processed_count hier
|
||||
|
||||
processed_count += len(current_tasks) # Zähle hier, wenn Tasks tatsächlich an OpenAI gingen
|
||||
|
||||
# Sheet Updates in Batches senden
|
||||
if len(all_sheet_updates) >= update_batch_row_limit * 3: # 3 Spalten pro Update (O, P, Q)
|
||||
self.logger.info(f"Sende Batch-Updates für Parent Suggestions ({len(all_sheet_updates)//3} Zeilen)...")
|
||||
self.sheet_handler.batch_update_cells(all_sheet_updates)
|
||||
all_sheet_updates.clear()
|
||||
if len(all_sheet_updates) >= update_batch_row_limit * 3:
|
||||
self.logger.info(f"Sende Batch-Updates für Parent Suggestions ({len(all_sheet_updates)//3} Zeilen)...")
|
||||
self.sheet_handler.batch_update_cells(all_sheet_updates)
|
||||
all_sheet_updates.clear()
|
||||
|
||||
# Pause nach dem Batch
|
||||
time.sleep(getattr(Config, 'RETRY_DELAY', 5) * 0.5)
|
||||
# Ende der Hilfsfunktion _execute_and_write_openai_batch
|
||||
|
||||
# Hauptschleife über die Zeilen
|
||||
for i in range(start_sheet_row, end_sheet_row + 1):
|
||||
# Limit-Prüfung erfolgt jetzt innerhalb der _execute_and_write_openai_batch
|
||||
# oder besser hier vor dem Sammeln von Tasks, um nicht unnötig zu iterieren.
|
||||
if limit is not None and processed_count >= limit:
|
||||
self.logger.info(f"Verarbeitungslimit ({limit}) für Parent Suggestions erreicht.")
|
||||
break
|
||||
@@ -8540,15 +8535,15 @@ class DataProcessor:
|
||||
continue
|
||||
|
||||
# Kriterien für Verarbeitung
|
||||
val_o = self._get_cell_value_safe(row, col_o_key).strip()
|
||||
val_p = self._get_cell_value_safe(row, col_p_key).strip()
|
||||
# val_q = self._get_cell_value_safe(row, col_q_key).strip() # Timestamp nicht direkt für Auswahl relevant
|
||||
val_q_timestamp = self._get_cell_value_safe(row, col_q_key).strip() # Timestamp aus Spalte Q
|
||||
val_p_status = self._get_cell_value_safe(row, col_p_key).strip() # Status aus Spalte P
|
||||
|
||||
needs_processing = False
|
||||
if not val_o or val_o.lower() == "k.a.": # Spalte O ist leer oder k.A.
|
||||
if not val_q_timestamp: # Spalte Q (Timestamp) ist leer
|
||||
needs_processing = True
|
||||
elif re_evaluate_question_mark and val_p == "?": # Neubewertung für Status "?"
|
||||
elif re_evaluate_question_mark and val_p_status == "?": # Neubewertung für Status "?" auch wenn Timestamp Q gesetzt ist
|
||||
needs_processing = True
|
||||
self.logger.debug(f"Zeile {i}: Wird trotz vorhandenem Timestamp in Q ('{val_q_timestamp}') verarbeitet, da P='?' und re_evaluate_question_mark=True.")
|
||||
|
||||
if not needs_processing:
|
||||
skipped_count += 1
|
||||
@@ -8571,11 +8566,9 @@ class DataProcessor:
|
||||
_execute_and_write_openai_batch(tasks_for_current_openai_batch)
|
||||
tasks_for_current_openai_batch.clear()
|
||||
|
||||
# Letzten Batch verarbeiten
|
||||
if tasks_for_current_openai_batch:
|
||||
_execute_and_write_openai_batch(tasks_for_current_openai_batch)
|
||||
|
||||
# Letzte Sheet Updates senden
|
||||
if all_sheet_updates:
|
||||
self.logger.info(f"Sende finale Batch-Updates für Parent Suggestions ({len(all_sheet_updates)//3} Zeilen)...")
|
||||
self.sheet_handler.batch_update_cells(all_sheet_updates)
|
||||
|
||||
Reference in New Issue
Block a user