v1.3.16 – Modus 51 Verifizierung in Batch, Spaltenanpassungen für Wiki und Brancheneinordnung

Modus 51 wurde so angepasst, dass im Batch jeweils 10 Einträge aggregiert werden.

Für jeden Eintrag wird aus ChatGPT das Ergebnis verarbeitet:
– Spalte S erhält „OK“ (falls passend) oder bleibt leer.
– Falls ein alternativer Artikel vorgeschlagen wird, wird die URL in Spalte U und die Begründung in Spalte V geschrieben; bei fehlendem Artikel wird in Spalte U „Kein Wikipedia-Eintrag vorhanden.“ eingetragen.

Der Branchenvorschlag (basierend auf den Branchenangaben in Spalte G, H, O, R) wird in Spalte W geschrieben und das Konsistenzresultat in Spalte Y.

Der Verifizierungs‑Timestamp wird in Spalte AO, die Version in Spalte AP und der Batch Token Count in Spalte AQ eingetragen.
This commit is contained in:
2025-04-04 12:54:08 +00:00
parent 16f45d8668
commit 37e0dd92a2

View File

@@ -14,11 +14,11 @@ import csv
try:
import tiktoken
except ImportError:
tiktoken = None # Falls tiktoken nicht installiert ist
tiktoken = None
# ==================== KONFIGURATION ====================
class Config:
VERSION = "v1.3.15" # v1.3.15: Modus 51 für verifizierte Wikipedia-Artikel in Batches, Ausgabe in Spalten W, X, Y und Token-Zahl in AQ.
VERSION = "v1.3.16" # v1.3.16: Modus 51 implementiert mit separaten Spalten für Wiki-Confirm, alternative Wiki URL, Branchenvorschlag etc.
LANG = "de"
CREDENTIALS_FILE = "service_account.json"
SHEET_URL = "https://docs.google.com/spreadsheets/d/1u_gHr9JUfmV1-iviRzbSe3575QEp7KLhK5jFV_gJcgo"
@@ -29,8 +29,8 @@ class Config:
DEBUG = True
WIKIPEDIA_SEARCH_RESULTS = 5
HTML_PARSER = "html.parser"
BATCH_SIZE = 10 # Batch-Größe für Verifizierungsmodus
TOKEN_MODEL = "gpt-3.5-turbo" # Für tiktoken
BATCH_SIZE = 10
TOKEN_MODEL = "gpt-3.5-turbo"
# ==================== RETRY-DECORATOR ====================
def retry_on_failure(func):
@@ -212,7 +212,7 @@ def evaluate_branche_chatgpt(crm_branche, beschreibung, wiki_branche, wiki_kateg
f"Wikipedia-Kategorien: {wiki_kategorien}\n\n"
"Gib aus:\n"
"Branche: <vorgeschlagene Branche>\n"
"Übereinstimmung: <OK oder X>\n"
"Konsistenz: <OK oder X>\n"
"Begründung: <Begründung bei Abweichung (leer, wenn OK)>"
)
try:
@@ -236,7 +236,7 @@ def evaluate_branche_chatgpt(crm_branche, beschreibung, wiki_branche, wiki_kateg
for line in result.split("\n"):
if line.lower().startswith("branche:"):
branch = line.split(":", 1)[1].strip()
elif line.lower().startswith("übereinstimmung:"):
elif line.lower().startswith("konsistenz:"):
consistency = line.split(":", 1)[1].strip()
elif line.lower().startswith("begründung:"):
justification = line.split(":", 1)[1].strip()
@@ -246,15 +246,12 @@ def evaluate_branche_chatgpt(crm_branche, beschreibung, wiki_branche, wiki_kateg
return {"branch": "k.A.", "consistency": "k.A.", "justification": "k.A."}
def evaluate_fsm_suitability(company_name, company_data):
# In Modus 51 wird diese Funktion nicht aufgerufen.
return {"suitability": "n.v.", "justification": ""}
def evaluate_servicetechnicians_estimate(company_name, company_data):
# In Modus 51 wird diese Funktion nicht aufgerufen.
return "n.v."
def evaluate_servicetechnicians_explanation(company_name, st_estimate, company_data):
# In Modus 51 wird diese Funktion nicht aufgerufen.
return "n.v."
def map_internal_technicians(value):
@@ -291,7 +288,6 @@ def search_linkedin_contact(company_name, website, position_query):
except Exception as e:
debug_print("Fehler beim Lesen des SerpAPI-Schlüssels: " + str(e))
return None
# Nutze ggf. die Kurzform aus Spalte C, falls vorhanden.
search_name = company_name
query = f'site:linkedin.com/in "{position_query}" "{search_name}"'
debug_print(f"Erstelle LinkedIn-Query: {query}")
@@ -368,16 +364,15 @@ def count_linkedin_contacts(company_name, website, position_query):
# ==================== VERIFIZIERUNGS-MODUS (Modus 51) ====================
def _process_verification_row(row_num, row_data):
"""
Aggregiert die relevanten Informationen eines Eintrags für die Verifizierung.
Erwartete Spalten (0-basiert):
B: Firmenname
F: CRM-Beschreibung
M: Wiki URL
N: Wiki Absatz
R: Wiki Kategorien
Aggregiert relevante Informationen für die Verifizierung:
- Firmenname (Spalte B)
- CRM-Beschreibung (Spalte G)
- Wikipedia-URL (Spalte M)
- Wikipedia-Absatz (Spalte N)
- Wikipedia-Kategorien (Spalte R)
"""
company_name = row_data[1] if len(row_data) > 1 else ""
crm_description = row_data[5] if len(row_data) > 5 else ""
crm_description = row_data[6] if len(row_data) > 6 else ""
wiki_url = row_data[12] if len(row_data) > 12 else "k.A."
wiki_absatz = row_data[13] if len(row_data) > 13 else "k.A."
wiki_categories = row_data[17] if len(row_data) > 17 else "k.A."
@@ -392,15 +387,17 @@ def _process_verification_row(row_num, row_data):
def process_verification_only():
"""
Verifizierungsmodus (Modus 51) im Batch-Prozess.
Es werden jeweils Config.BATCH_SIZE (z.B. 10) Einträge aggregiert.
Für jeden Eintrag werden folgende Spalten aktualisiert:
- Spalte W: Branchenvorschlag von ChatGPT
- Spalte X: Konsistenzprüfung (OK oder X)
- Spalte Y: Begründung bei Abweichung
- Spalte AQ: Token-Zahl des aggregierten Prompts (gleich für alle Einträge des Batches)
- Spalte Z: Verifizierungs-Timestamp
- Spalte AA: Version
Modus 51: Verifizierung (Wikipedia + Brancheneinordnung) im Batch-Modus.
Verarbeitet jeweils Config.BATCH_SIZE Einträge, bei denen noch keine Wiki-Verifizierung (Spalte S) vorliegt.
Ergebnisse:
- Spalte S: Wiki Confirm (OK, falls Artikel passt)
- Spalte U: Alternative Wiki-URL (falls Artikel nicht passt oder keiner gefunden wurde)
- Spalte V: Erklärung (Begründung)
- Spalte W: Branchenvorschlag (ChatGPT, basierend auf Spalten G, H, O, R)
- Spalte Y: Branchenkonsistenz (OK oder X inkl. Begründung)
- Spalte AQ: Token Count des Batch-Prompts (gleich für alle Einträge)
- Spalte AO: Verifizierungs-Timestamp
- Spalte AP: Versionsnummer
"""
debug_print("Starte Verifizierungsmodus (Modus 51) im Batch-Prozess...")
gc = gspread.authorize(ServiceAccountCredentials.from_json_keyfile_name(
@@ -411,9 +408,9 @@ def process_verification_only():
batch_size = Config.BATCH_SIZE
batch_entries = []
row_indices = []
# Wir prüfen hier Spalte Y (Index 24); wenn leer, dann ist der Eintrag noch nicht verifiziert.
# Prüfe Spalte S (Index 18): wenn leer, verarbeite
for i, row in enumerate(data[1:], start=2):
if len(row) <= 25 or row[24].strip() == "":
if len(row) <= 19 or row[18].strip() == "":
entry_text = _process_verification_row(i, row)
batch_entries.append(entry_text)
row_indices.append(i)
@@ -422,17 +419,16 @@ def process_verification_only():
if not batch_entries:
debug_print("Keine Einträge für die Verifizierung gefunden.")
return
aggregated_prompt = ("Du bist ein Experte im Bereich Unternehmensverifizierung. "
"Für jeden der folgenden Einträge prüfe, ob der vorhandene Wikipedia-Artikel (URL, Absatz, Kategorien) plausibel zum Unternehmen passt. "
"Falls ja, antworte für den Eintrag im Format:\n"
"Eintrag X: OK\n"
"Falls nein, schlage einen alternativen Wikipedia-Artikel vor (als URL) und gib die Gründe an, "
"aber gib nicht denselben Artikel zurück, der bereits vorliegt. "
"Wenn kein Artikel gefunden werden kann, antworte mit 'k.A.'\n\n")
aggregated_prompt = ("Du bist ein Experte in der Verifizierung von Wikipedia-Artikeln für Unternehmen. "
"Für jeden der folgenden Einträge prüfe, ob der vorhandene Wikipedia-Artikel (URL, Absatz, Kategorien) plausibel passt. "
"Gib für jeden Eintrag das Ergebnis im Format an:\n"
"Eintrag <Zeilennummer>: <Antwort>\n"
"Dabei gilt:\n"
"- Wenn der Artikel passt, antworte mit 'OK'.\n"
"- Wenn der Artikel nicht passt, antworte mit 'Alternativer Wikipedia-Artikel vorgeschlagen: <URL> | X | <Begründung>'.\n"
"- Falls überhaupt kein Artikel gefunden wurde, antworte mit 'Kein Wikipedia-Eintrag vorhanden.'\n\n")
aggregated_prompt += "\n".join(batch_entries)
debug_print("Aggregierter Prompt für Verifizierungs-Batch erstellt.")
# Zähle die Token (falls tiktoken verfügbar)
token_count = "n.v."
if tiktoken:
try:
@@ -441,7 +437,6 @@ def process_verification_only():
debug_print(f"Token-Zahl für Batch: {token_count}")
except Exception as e:
debug_print(f"Fehler beim Token-Counting: {e}")
# Sende den aggregierten Prompt an ChatGPT
try:
with open("api_key.txt", "r") as f:
api_key = f.read().strip()
@@ -460,8 +455,6 @@ def process_verification_only():
except Exception as e:
debug_print(f"Fehler bei der ChatGPT Anfrage für Verifizierung: {e}")
return
# Wir erwarten, dass ChatGPT für jeden Eintrag eine Zeile liefert im Format "Eintrag X: <Antwort>"
answers = result.split("\n")
for idx, row_num in enumerate(row_indices):
answer = "k.A."
@@ -469,23 +462,45 @@ def process_verification_only():
if line.strip().startswith(f"Eintrag {row_num}:"):
answer = line.split(":", 1)[1].strip()
break
# Falls die Antwort "OK" lautet, setze in Spalte X "OK" und Spalte Y leer;
# ansonsten in Spalte X "X" und Spalte Y den Vorschlag.
# Verarbeitung der Wiki-Verifizierung:
# Falls Antwort "OK", schreibe in Spalte S (Wiki Confirm) "OK", Spalte U bleibt leer.
# Falls Antwort "Kein Wikipedia-Eintrag vorhanden.", schreibe diesen Text in Spalte U.
# Falls Antwort mit "Alternativer Wikipedia-Artikel vorgeschlagen:" beginnt, extrahiere URL und Begründung.
if answer.upper() == "OK":
branch_suggestion = "OK"
consistency = "OK"
justification = ""
wiki_confirm = "OK"
alt_article = ""
explanation = ""
elif answer.startswith("Alternativer Wikipedia-Artikel vorgeschlagen:"):
parts = answer.split(":", 1)[1].split("|")
alt_article = parts[0].strip() if len(parts) > 0 else "k.A."
explanation = parts[2].strip() if len(parts) > 2 else ""
wiki_confirm = "X"
elif answer.upper() == "KEIN WIKIPEDIA-EINTRAG VORHANDEN.":
wiki_confirm = ""
alt_article = "Kein Wikipedia-Eintrag vorhanden."
explanation = ""
else:
branch_suggestion = answer # hier wird der alternative Artikel (URL) als Vorschlag verwendet
consistency = "X"
justification = answer # oder ggf. eine ausführlichere Begründung; hier wird derselbe Text genutzt
main_sheet.update(values=[[branch_suggestion]], range_name=f"W{row_num}")
main_sheet.update(values=[[consistency]], range_name=f"X{row_num}")
main_sheet.update(values=[[justification]], range_name=f"Y{row_num}")
# Schreibe den Token-Count in Spalte AQ (gleich für alle Einträge dieses Batches)
wiki_confirm = ""
alt_article = answer
explanation = answer
# Schreibe Ergebnisse:
main_sheet.update(values=[[wiki_confirm]], range_name=f"S{row_num}")
main_sheet.update(values=[[alt_article]], range_name=f"U{row_num}")
main_sheet.update(values=[[explanation]], range_name=f"V{row_num}")
# Branchenvorschlag: Nutze die Branchenangaben aus Spalte G, H, O, R (Indices 6,7,14,17)
crm_branch = row_data[6] if len(row_data) > 6 else "k.A."
ext_branch = row_data[7] if len(row_data) > 7 else "k.A."
wiki_branch = row_data[14] if len(row_data) > 14 else "k.A."
wiki_cats = row_data[17] if len(row_data) > 17 else "k.A."
branch_result = evaluate_branche_chatgpt(crm_branch, ext_branch, wiki_branch, wiki_cats)
main_sheet.update(values=[[branch_result["branch"]]], range_name=f"W{row_num}")
main_sheet.update(values=[[branch_result["consistency"]]], range_name=f"Y{row_num}")
# Schreibe Token Count in Spalte AQ
main_sheet.update(values=[[str(token_count)]], range_name=f"AQ{row_num}")
main_sheet.update(values=[[datetime.now().strftime('%Y-%m-%d %H:%M:%S')]], range_name=f"Z{row_num}")
main_sheet.update(values=[[Config.VERSION]], range_name=f"AA{row_num}")
# Schreibe Timestamp in Spalte AO und Version in Spalte AP
current_dt = datetime.now().strftime("%Y-%m-%d %H:%M:%S")
main_sheet.update(values=[[current_dt]], range_name=f"AO{row_num}")
main_sheet.update(values=[[Config.VERSION]], range_name=f"AP{row_num}")
debug_print(f"Zeile {row_num} verifiziert: Antwort: {answer}")
time.sleep(Config.RETRY_DELAY)
debug_print("Verifizierungs-Batch abgeschlossen.")
@@ -501,9 +516,10 @@ class GoogleSheetHandler:
creds = ServiceAccountCredentials.from_json_keyfile_name(Config.CREDENTIALS_FILE, scope)
self.sheet = gspread.authorize(creds).open_by_url(Config.SHEET_URL).sheet1
self.sheet_values = self.sheet.get_all_values()
def get_start_index(self, column_index=39):
def get_start_index(self, column_index=40):
"""
column_index=39 für Wiki (Spalte AN), column_index=40 für ChatGPT (Spalte AO)
column_index=40 für ChatGPT-Timestamp (Spalte AO),
column_index=41 für alternative Runner.
"""
filled_n = [row[column_index] if len(row) > column_index else '' for row in self.sheet_values[1:]]
return next((i + 1 for i, v in enumerate(filled_n, start=1) if not str(v).strip()), len(filled_n) + 1)
@@ -529,30 +545,30 @@ def alignment_demo(sheet):
"Spalte P (Wikipedia Umsatz)",
"Spalte Q (Wikipedia Mitarbeiter)",
"Spalte R (Wikipedia Kategorien)",
"Spalte S (Konsistenzprüfung)",
"Spalte T (Begründung bei Inkonsistenz)",
"Spalte U (Vorschlag Wiki Artikel ChatGPT)",
"Spalte V (Konsistenzprüfung Branche)",
"Spalte W (Vorschlag neue Branche)", # Wird in Modus 51 als Branchenvorschlag genutzt
"Spalte X (Konsistenzprüfung OK oder X)",
"Spalte Y (Begründung Abweichung)",
"Spalte Z (Timestamp Verifizierung)",
"Spalte AA (Version)",
"Spalte AB (Schätzung Anzahl Mitarbeiter)",
"Spalte AC (Konsistenzprüfung Mitarbeiterzahl)",
"Spalte AD (Einschätzung Anzahl Servicetechniker)",
"Spalte AE (Begründung bei Abweichung Techniker)",
"Spalte AF (Schätzung Umsatz ChatGPT)",
"Spalte AG (Begründung Umsatz ChatGPT)",
"Spalte AH (Wikipedia-Timestamp)",
"Spalte AI (ChatGPT-Timestamp)",
"Spalte S (Wiki Confirm)",
"Spalte T (Wiki Erklärung nicht genutzt)",
"Spalte U (Alternative Wiki URL)",
"Spalte V (Wiki Begründung)",
"Spalte W (Branchenvorschlag)",
"Spalte X (Branchenergebnis Konsistenzprüfung)",
"Spalte Y (Branchenerklärung)",
"Spalte Z (Timestamp wird nicht genutzt)",
"Spalte AA (FSM Relevanz nicht genutzt)",
"Spalte AB (Begründung FSM nicht genutzt)",
"Spalte AC (Schätzung Mitarbeiter nicht genutzt)",
"Spalte AD (Einschätzung Techniker nicht genutzt)",
"Spalte AE (Begründung Techniker nicht genutzt)",
"Spalte AF (Schätzung Umsatz ChatGPT nicht genutzt)",
"Spalte AG (Begründung Umsatz ChatGPT nicht genutzt)",
"Spalte AH (Wikipedia-Timestamp nicht genutzt)",
"Spalte AI (ChatGPT-Timestamp nicht genutzt)",
"Spalte AJ (Kontakt: Serviceleiter gefunden)",
"Spalte AK (Kontakt: IT-Leiter gefunden)",
"Spalte AL (Kontakt: Management gefunden)",
"Spalte AM (Kontakt: Disponent gefunden)",
"Spalte AN (Contact Search Timestamp)",
"Spalte AO (Wikipedia Timestamp für regulären Wiki-Runner)",
"Spalte AP (ChatGPT Timestamp für regulären ChatGPT-Runner)",
"Spalte AN (Contact Search Timestamp nicht genutzt)",
"Spalte AO (Verifizierung Timestamp)",
"Spalte AP (Version)",
"Spalte AQ (Token Count Batch)"
]
header_range = "A11200:AQ11200"
@@ -741,74 +757,71 @@ class WikipediaScraper:
continue
return None
# ==================== DATA PROCESSOR ====================
class DataProcessor:
# ==================== GOOGLE SHEET HANDLER ====================
class GoogleSheetHandler:
def __init__(self):
self.sheet_handler = GoogleSheetHandler()
self.wiki_scraper = WikipediaScraper()
def process_rows(self, num_rows=None):
if MODE == "2":
print("Re-Evaluierungsmodus: Verarbeitung aller Zeilen mit 'x' in Spalte A.")
for i, row in enumerate(self.sheet_handler.sheet_values[1:], start=2):
if row[0].strip().lower() == "x":
self._process_single_row(i, row)
elif MODE == "3":
print("Alignment-Demo-Modus: Schreibe neue Spaltenüberschriften in Zeile 11200.")
alignment_demo(self.sheet_handler.sheet)
else:
start_index = self.sheet_handler.get_start_index(40) # Standardmäßig ChatGPT-Timestamp (Spalte AO)
print(f"Starte bei Zeile {start_index+1}")
rows_processed = 0
for i, row in enumerate(self.sheet_handler.sheet_values[1:], start=2):
if i < start_index:
continue
if num_rows is not None and rows_processed >= num_rows:
break
self._process_single_row(i, row)
rows_processed += 1
def _process_single_row(self, row_num, row_data):
company_name = row_data[1] if len(row_data) > 1 else ""
website = row_data[3] if len(row_data) > 3 else ""
wiki_update_range = f"L{row_num}:R{row_num}" # Angenommen, hier kommen Wiki-Daten rein
# Falls in Spalte L bereits ein Wiki-URL steht, nutze diese
if len(row_data) > 11 and row_data[11].strip() not in ["", "k.A."]:
wiki_url = row_data[11].strip()
try:
company_data = self.wiki_scraper.extract_company_data(wiki_url)
except Exception as e:
debug_print(f"Fehler beim Laden des vorgeschlagenen Wikipedia-Artikels: {e}")
article = self.wiki_scraper.search_company_article(company_name, website)
company_data = self.wiki_scraper.extract_company_data(article.url) if article else {
'url': 'k.A.', 'first_paragraph': 'k.A.', 'branche': 'k.A.',
'umsatz': 'k.A.', 'mitarbeiter': 'k.A.', 'categories': 'k.A.',
'full_infobox': 'k.A.'
}
else:
article = self.wiki_scraper.search_company_article(company_name, website)
company_data = self.wiki_scraper.extract_company_data(article.url) if article else {
'url': 'k.A.', 'first_paragraph': 'k.A.', 'branche': 'k.A.',
'umsatz': 'k.A.', 'mitarbeiter': 'k.A.', 'categories': 'k.A.',
'full_infobox': 'k.A.'
}
wiki_values = [
company_data.get('url', 'k.A.'),
company_data.get('first_paragraph', 'k.A.'),
company_data.get('branche', 'k.A.'),
company_data.get('umsatz', 'k.A.'),
company_data.get('mitarbeiter', 'k.A.'),
company_data.get('categories', 'k.A.')
]
self.sheet_handler.sheet.update(values=[wiki_values], range_name=wiki_update_range)
time.sleep(3)
# Weitere Verarbeitung (z.B. Umsatz-Abgleich, Brancheneinordnung etc.) würden hier erfolgen,
# aber im regulären Modus 1 werden auch FSM und Techniker verarbeitet das ist hier nicht Teil von Modus 51.
# Deshalb bleibt dieser Teil unberührt.
current_dt = datetime.now().strftime("%Y-%m-%d %H:%M:%S")
# Aktualisiere Timestamp und Version in den entsprechenden Spalten (z.B. in Spalte AP für ChatGPT-Timestamp)
self.sheet_handler.sheet.update(values=[[current_dt]], range_name=f"AP{row_num}")
self.sheet_handler.sheet.update(values=[[Config.VERSION]], range_name=f"AQ{row_num}")
debug_print(f"Zeile {row_num} verarbeitet.")
time.sleep(Config.RETRY_DELAY)
self.sheet = None
self.sheet_values = []
self._connect()
def _connect(self):
scope = ["https://www.googleapis.com/auth/spreadsheets"]
creds = ServiceAccountCredentials.from_json_keyfile_name(Config.CREDENTIALS_FILE, scope)
self.sheet = gspread.authorize(creds).open_by_url(Config.SHEET_URL).sheet1
self.sheet_values = self.sheet.get_all_values()
def get_start_index(self, column_index=40):
filled_n = [row[column_index] if len(row) > column_index else '' for row in self.sheet_values[1:]]
return next((i + 1 for i, v in enumerate(filled_n, start=1) if not str(v).strip()), len(filled_n) + 1)
# ==================== ALIGNMENT DEMO (Modus 3) ====================
def alignment_demo(sheet):
new_headers = [
"Spalte A (ReEval Flag)",
"Spalte B (Firmenname)",
"Spalte C (Kurzform Firmenname)",
"Spalte D (Website)",
"Spalte E (Ort)",
"Spalte F (Beschreibung)",
"Spalte G (Aktuelle Branche)",
"Spalte H (Beschreibung Branche extern)",
"Spalte I (Anzahl Techniker CRM)",
"Spalte J (Umsatz CRM)",
"Spalte K (Anzahl Mitarbeiter CRM)",
"Spalte L (Vorschlag Wiki URL)",
"Spalte M (Wikipedia URL)",
"Spalte N (Wikipedia Absatz)",
"Spalte O (Wikipedia Branche)",
"Spalte P (Wikipedia Umsatz)",
"Spalte Q (Wikipedia Mitarbeiter)",
"Spalte R (Wikipedia Kategorien)",
"Spalte S (Wiki Confirm)",
"Spalte T (Wiki Erklärung nicht genutzt)",
"Spalte U (Alternative Wiki URL)",
"Spalte V (Wiki Begründung)",
"Spalte W (Branchenvorschlag)",
"Spalte X (Branchenkonsistenz)",
"Spalte Y (Branchenerklärung)",
"Spalte Z (nicht genutzt)",
"Spalte AA (FSM Relevanz nicht genutzt)",
"Spalte AB (Begründung FSM nicht genutzt)",
"Spalte AC (Schätzung Mitarbeiter nicht genutzt)",
"Spalte AD (Einschätzung Techniker nicht genutzt)",
"Spalte AE (Begründung Techniker nicht genutzt)",
"Spalte AF (Schätzung Umsatz ChatGPT nicht genutzt)",
"Spalte AG (Begründung Umsatz ChatGPT nicht genutzt)",
"Spalte AH (Wikipedia-Timestamp nicht genutzt)",
"Spalte AI (ChatGPT-Timestamp nicht genutzt)",
"Spalte AJ (Kontakt: Serviceleiter gefunden)",
"Spalte AK (Kontakt: IT-Leiter gefunden)",
"Spalte AL (Kontakt: Management gefunden)",
"Spalte AM (Kontakt: Disponent gefunden)",
"Spalte AN (Contact Search Timestamp nicht genutzt)",
"Spalte AO (Verifizierung Timestamp)",
"Spalte AP (Version)",
"Spalte AQ (Token Count Batch)"
]
header_range = "A11200:AQ11200"
sheet.update(values=[new_headers], range_name=header_range)
print("Alignment-Demo abgeschlossen: Neue Spaltenüberschriften in Zeile 11200 geschrieben.")
# ==================== MODUS 51: VERIFIZIERUNG (BATCH) ====================
def process_verification_only():
@@ -821,9 +834,9 @@ def process_verification_only():
batch_size = Config.BATCH_SIZE
batch_entries = []
row_indices = []
# Prüfe hier Spalte Y (Index 24); wenn leer, dann verifizieren.
# Prüfe Spalte S (Index 18): wenn leer, verarbeite den Eintrag
for i, row in enumerate(data[1:], start=2):
if len(row) <= 25 or row[24].strip() == "":
if len(row) <= 19 or row[18].strip() == "":
entry_text = _process_verification_row(i, row)
batch_entries.append(entry_text)
row_indices.append(i)
@@ -832,11 +845,14 @@ def process_verification_only():
if not batch_entries:
debug_print("Keine Einträge für die Verifizierung gefunden.")
return
aggregated_prompt = ("Du bist ein Experte im Bereich Unternehmensverifizierung. "
"Für jeden der folgenden Einträge prüfe, ob der vorhandene Wikipedia-Artikel plausibel zum Unternehmen passt. "
"Gib für jeden Eintrag das Ergebnis in folgendem Format aus:\n"
"Eintrag <Zeilennummer>: <Branchenvorschlag> | <Konsistenz (OK oder X)> | <Begründung>\n"
"Wenn der Artikel passt, antworte mit 'OK'. Falls nicht, schlage einen alternativen Artikel (als URL) vor.\n\n")
aggregated_prompt = ("Du bist ein Experte in der Verifizierung von Wikipedia-Artikeln für Unternehmen. "
"Für jeden der folgenden Einträge prüfe, ob der vorhandene Wikipedia-Artikel (URL, Absatz, Kategorien) plausibel passt. "
"Gib für jeden Eintrag das Ergebnis im Format aus:\n"
"Eintrag <Zeilennummer>: <Antwort>\n"
"Dabei gilt:\n"
"- Wenn der Artikel passt, antworte mit 'OK'.\n"
"- Wenn der Artikel unpassend ist, antworte mit 'Alternativer Wikipedia-Artikel vorgeschlagen: <URL> | X | <Begründung>'.\n"
"- Wenn kein Artikel gefunden wurde, antworte mit 'Kein Wikipedia-Eintrag vorhanden.'\n\n")
aggregated_prompt += "\n".join(batch_entries)
debug_print("Aggregierter Prompt für Verifizierungs-Batch erstellt.")
token_count = "n.v."
@@ -872,20 +888,45 @@ def process_verification_only():
if line.strip().startswith(f"Eintrag {row_num}:"):
answer = line.split(":", 1)[1].strip()
break
# Verarbeitung der Wiki-Verifizierung:
# Falls Antwort "OK": In Spalte S (Wiki Confirm) "OK", Spalte U leer.
# Falls Antwort "Kein Wikipedia-Eintrag vorhanden.": In Spalte U dieser Text, Spalte S bleibt leer.
# Falls Antwort mit "Alternativer Wikipedia-Artikel vorgeschlagen:" beginnt, extrahiere URL und Begründung.
if answer.upper() == "OK":
branch_suggestion = "OK"
consistency = "OK"
justification = ""
wiki_confirm = "OK"
alt_article = ""
wiki_explanation = ""
elif answer.upper() == "KEIN WIKIPEDIA-EINTRAG VORHANDEN.":
wiki_confirm = ""
alt_article = "Kein Wikipedia-Eintrag vorhanden."
wiki_explanation = ""
elif answer.startswith("Alternativer Wikipedia-Artikel vorgeschlagen:"):
parts = answer.split(":", 1)[1].split("|")
alt_article = parts[0].strip() if len(parts) > 0 else "k.A."
wiki_explanation = parts[2].strip() if len(parts) > 2 else ""
wiki_confirm = "X"
else:
branch_suggestion = answer
consistency = "X"
justification = answer
main_sheet.update(values=[[branch_suggestion]], range_name=f"W{row_num}")
main_sheet.update(values=[[consistency]], range_name=f"X{row_num}")
main_sheet.update(values=[[justification]], range_name=f"Y{row_num}")
wiki_confirm = ""
alt_article = answer
wiki_explanation = answer
# Schreibe Ergebnisse für Wiki-Verifizierung:
main_sheet.update(values=[[wiki_confirm]], range_name=f"S{row_num}")
main_sheet.update(values=[[alt_article]], range_name=f"U{row_num}")
main_sheet.update(values=[[wiki_explanation]], range_name=f"V{row_num}")
# Branchenvorschlag: Nutze Branchenangaben aus Spalte G (Index 6), H (7), O (14) und R (17)
crm_branch = data[row_num-1][6] if len(data[row_num-1]) > 6 else "k.A."
ext_branch = data[row_num-1][7] if len(data[row_num-1]) > 7 else "k.A."
wiki_branch = data[row_num-1][14] if len(data[row_num-1]) > 14 else "k.A."
wiki_cats = data[row_num-1][17] if len(data[row_num-1]) > 17 else "k.A."
branch_result = evaluate_branche_chatgpt(crm_branch, ext_branch, wiki_branch, wiki_cats)
main_sheet.update(values=[[branch_result["branch"]]], range_name=f"W{row_num}")
main_sheet.update(values=[[branch_result["consistency"]]], range_name=f"Y{row_num}")
# Schreibe Token Count in Spalte AQ
main_sheet.update(values=[[str(token_count)]], range_name=f"AQ{row_num}")
main_sheet.update(values=[[datetime.now().strftime('%Y-%m-%d %H:%M:%S')]], range_name=f"Z{row_num}")
main_sheet.update(values=[[Config.VERSION]], range_name=f"AA{row_num}")
# Schreibe Timestamp in Spalte AO und Version in Spalte AP
current_dt = datetime.now().strftime("%Y-%m-%d %H:%M:%S")
main_sheet.update(values=[[current_dt]], range_name=f"AO{row_num}")
main_sheet.update(values=[[Config.VERSION]], range_name=f"AP{row_num}")
debug_print(f"Zeile {row_num} verifiziert: Antwort: {answer}")
time.sleep(Config.RETRY_DELAY)
debug_print("Verifizierungs-Batch abgeschlossen.")
@@ -990,16 +1031,14 @@ if __name__ == "__main__":
processor = DataProcessor()
processor.process_rows()
elif MODE == "4":
# Wiki-runner: Startindex anhand Spalte AN (Index 39)
gh = GoogleSheetHandler()
start_index = gh.get_start_index(39)
start_index = gh.get_start_index(39) # Wiki-Timestamp (Spalte AN)
debug_print(f"Wiki-Modus: Starte bei Zeile {start_index+1}")
processor = DataProcessor()
processor.process_rows()
elif MODE == "5":
# ChatGPT-runner: Startindex anhand Spalte AO (Index 40)
gh = GoogleSheetHandler()
start_index = gh.get_start_index(40)
start_index = gh.get_start_index(40) # ChatGPT-Timestamp (Spalte AO)
debug_print(f"ChatGPT-Modus: Starte bei Zeile {start_index+1}")
processor = DataProcessor()
processor.process_rows()
@@ -1008,7 +1047,6 @@ if __name__ == "__main__":
elif MODE == "7":
process_contacts()
elif MODE == "8":
# Batch-Token-Zählung: Aggregiere 10 Zeilen und zähle Token
gc = gspread.authorize(ServiceAccountCredentials.from_json_keyfile_name(
Config.CREDENTIALS_FILE, ["https://www.googleapis.com/auth/spreadsheets"]))
sh = gc.open_by_url(Config.SHEET_URL)