From c6836d0c2a6d8cfda8a464db0d20bedbba0ad042 Mon Sep 17 00:00:00 2001 From: Floke Date: Wed, 2 Apr 2025 08:55:47 +0000 Subject: [PATCH] v1.3.1: Validierung des Wikipedia-Artikels implementiert MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Validierungsschritt: Die neue Funktion validate_article_with_chatgpt(crm_data, wiki_data) aggregiert die CRM-Daten (Spalten B–J) und die Wikipedia-Daten (Spalten L–Q) als CSV-Text. Der erstellte Prompt teilt ChatGPT mit, dass beide Datensätze verglichen werden sollen, um zu prüfen, ob sie zum selben Unternehmen gehören. – Wichtige Vergleichskriterien sind der Firmenname, Ort und Branche (die Umsatzangaben können toleriert werden). – Das Ergebnis (z. B. "OK" oder eine Begründung) wird in Spalte R (Konsistenzprüfung) gespeichert. Integration: Der Validierungsschritt wird direkt in _process_single_row nach dem Aktualisieren der Wikipedia-Daten ausgeführt. Eine 1‑Sekunden-Pause wurde eingebaut, um sicherzustellen, dass die Daten in Google Sheets aktualisiert sind, bevor die Validierung erfolgt. Logging: Ausführliche Debug-Ausgaben helfen dabei, den Vergleich und eventuelle Fehler zu überwachen. --- brancheneinstufung.py | 103 ++++++++++++++++++++++++++++++++---------- 1 file changed, 79 insertions(+), 24 deletions(-) diff --git a/brancheneinstufung.py b/brancheneinstufung.py index 77c09dc3..ad45d8ba 100644 --- a/brancheneinstufung.py +++ b/brancheneinstufung.py @@ -14,7 +14,7 @@ import csv # ==================== KONFIGURATION ==================== class Config: - VERSION = "v1.3.0" # v1.3.0: Neue Spaltenzuordnung, verbesserte numerische Extraktion & 1 Sekunde Pause + VERSION = "v1.3.1" # v1.3.1: Validierung des Wikipedia-Artikels implementiert LANG = "de" CREDENTIALS_FILE = "service_account.json" SHEET_URL = "https://docs.google.com/spreadsheets/d/1u_gHr9JUfmV1-iviRzbSe3575QEp7KLhK5jFV_gJcgo" @@ -72,18 +72,16 @@ def normalize_company_name(name): return normalized.lower() def extract_numeric_value(raw_value, is_umsatz=False): - raw_value = unicodedata.normalize("NFKC", raw_value.strip()) + raw_value = raw_value.strip() if not raw_value: return "k.A." - # Entferne gängige Zusätze wie "ca.", "circa", "über" etc. raw_value = re.sub(r'\b(ca\.?|circa|über)\b', '', raw_value, flags=re.IGNORECASE) raw = raw_value.lower().replace("\xa0", " ") - # Robustere Regex: Erfasst Ziffern, optionale Dezimaltrennzeichen - match = re.search(r'([\d]+(?:[.,]\d+)*)', raw, flags=re.UNICODE) + match = re.search(r'([\d.,]+)', raw, flags=re.UNICODE) if not match or not match.group(1).strip(): debug_print(f"Keine numerischen Zeichen gefunden im Rohtext: '{raw_value}'") return "k.A." - num_str = unicodedata.normalize("NFKC", match.group(1)) + num_str = match.group(1) if ',' in num_str: num_str = num_str.replace('.', '').replace(',', '.') try: @@ -134,9 +132,11 @@ def evaluate_umsatz_chatgpt(company_name, wiki_umsatz): debug_print(f"Fehler beim Lesen des API-Tokens: {e}") return "k.A." openai.api_key = api_key - prompt = (f"Bitte schätze den Umsatz in Mio. Euro für das Unternehmen '{company_name}'. " - f"Die Wikipedia-Daten zeigen: '{wiki_umsatz}'. " - "Antworte nur mit der Zahl.") + prompt = ( + f"Bitte schätze den Umsatz in Mio. Euro für das Unternehmen '{company_name}'. " + f"Die Wikipedia-Daten zeigen: '{wiki_umsatz}'. " + "Antworte nur mit der Zahl." + ) try: response = openai.ChatCompletion.create( model="gpt-3.5-turbo", @@ -155,6 +155,45 @@ def evaluate_umsatz_chatgpt(company_name, wiki_umsatz): debug_print(f"Fehler beim Aufruf der ChatGPT API: {e}") return "k.A." +def validate_article_with_chatgpt(crm_data, wiki_data): + """ + Aggregiert die CRM-Daten (Spalten B-J) und Wikipedia-Daten (Spalten L-Q) + als CSV-Text und übermittelt diesen an die ChatGPT-API, um zu validieren, + ob beide Datensätze zum selben Unternehmen gehören. + """ + # Erstelle den CSV-Text + crm_headers = "Firmenname;Website;Ort;Beschreibung;Aktuelle Branche;Beschreibung Branche extern;Anzahl Techniker;Umsatz (CRM);Anzahl Mitarbeiter (CRM)" + wiki_headers = "Wikipedia URL;Wikipedia Absatz;Wikipedia Branche;Wikipedia Umsatz;Wikipedia Mitarbeiter;Wikipedia Kategorien" + prompt_text = ( + "Bitte überprüfe, ob die folgenden beiden Datensätze zum gleichen Unternehmen gehören. " + "Die erste Zeile sind Daten aus unserem CRM-System, die zweite Zeile stammen aus Wikipedia. " + "Vergleiche insbesondere den Firmennamen, den Ort und die Branche. Unterschiede im Umsatz können toleriert werden, " + "solange sie im Rahmen von 10% liegen. Falls die Datensätze übereinstimmen, antworte ausschließlich mit 'OK'. " + "Falls nicht, nenne bitte den wichtigsten Grund (z. B. abweichender Firmenname oder Ort). \n\n" + f"CRM-Daten:\n{crm_headers}\n{crm_data}\n\n" + f"Wikipedia-Daten:\n{wiki_headers}\n{wiki_data}\n\n" + "Antwort: " + ) + try: + with open("api_key.txt", "r") as f: + api_key = f.read().strip() + except Exception as e: + debug_print(f"Fehler beim Lesen des API-Tokens: {e}") + return "k.A." + openai.api_key = api_key + try: + response = openai.ChatCompletion.create( + model="gpt-3.5-turbo", + messages=[{"role": "system", "content": prompt_text}], + temperature=0.0 + ) + result = response.choices[0].message.content.strip() + debug_print(f"Validierungsantwort ChatGPT: '{result}'") + return result + except Exception as e: + debug_print(f"Fehler beim Validierungs-API-Aufruf: {e}") + return "k.A." + # ==================== GOOGLE SHEET HANDLER ==================== class GoogleSheetHandler: def __init__(self): @@ -334,8 +373,15 @@ class WikipediaScraper: return result def extract_company_data(self, page_url): if not page_url: - return {'url': 'k.A.', 'first_paragraph': 'k.A.', 'branche': 'k.A.', - 'umsatz': 'k.A.', 'mitarbeiter': 'k.A.', 'categories': 'k.A.', 'full_infobox': 'k.A.'} + return { + 'url': 'k.A.', + 'first_paragraph': 'k.A.', + 'branche': 'k.A.', + 'umsatz': 'k.A.', + 'mitarbeiter': 'k.A.', + 'categories': 'k.A.', + 'full_infobox': 'k.A.' + } try: response = requests.get(page_url) soup = BeautifulSoup(response.text, Config.HTML_PARSER) @@ -359,8 +405,15 @@ class WikipediaScraper: } except Exception as e: debug_print(f"Extraktionsfehler: {str(e)}") - return {'url': 'k.A.', 'first_paragraph': 'k.A.', 'branche': 'k.A.', - 'umsatz': 'k.A.', 'mitarbeiter': 'k.A.', 'categories': 'k.A.', 'full_infobox': 'k.A.'} + return { + 'url': 'k.A.', + 'first_paragraph': 'k.A.', + 'branche': 'k.A.', + 'umsatz': 'k.A.', + 'mitarbeiter': 'k.A.', + 'categories': 'k.A.', + 'full_infobox': 'k.A.' + } @retry_on_failure def search_company_article(self, company_name, website): search_terms = self._generate_search_terms(company_name, website) @@ -404,18 +457,14 @@ class DataProcessor: if i >= self.sheet_handler.get_start_index(): self._process_single_row(i, row) def _process_single_row(self, row_num, row_data): - # Neues Schema: - # Spalte B: Firmenname, Spalte C: Website - # Wikipedia-Daten: Spalten K bis Q - # ChatGPT Umsatz: Spalte AF - # CRM Umsatz in Spalte I (Index 8) - # Umsatz-Abgleich: Spalte AG - # Timestamp in Spalte AH, Version in Spalte AI. + # CRM-Daten: Spalten B bis J (Indices 1 bis 9) + # Wikipedia-Daten: Spalten L bis Q (Indices 11 bis 16) company_name = row_data[1] if len(row_data) > 1 else "" website = row_data[2] if len(row_data) > 2 else "" wiki_update_range = f"K{row_num}:Q{row_num}" chatgpt_range = f"AF{row_num}" abgleich_range = f"AG{row_num}" + valid_range = f"R{row_num}" # Konsistenzprüfung dt_range = f"AH{row_num}" ver_range = f"AI{row_num}" print(f"\n[{datetime.now().strftime('%H:%M:%S')}] Verarbeite Zeile {row_num}: {company_name}") @@ -442,26 +491,32 @@ class DataProcessor: company_data.get('categories', 'k.A.') ] self.sheet_handler.sheet.update(values=[wiki_values], range_name=wiki_update_range) - # 1 Sekunde Pause, um sicherzustellen, dass die Daten in Google Sheets gespeichert wurden. time.sleep(1) - # ChatGPT API: Umsatzbewertung basierend auf Firmenname und Wikipedia-Umsatz + # Umsatz-Schätzung via ChatGPT (wie bisher) wiki_umsatz = company_data.get('umsatz', 'k.A.') if wiki_umsatz != "k.A.": chatgpt_umsatz = evaluate_umsatz_chatgpt(company_name, wiki_umsatz) else: chatgpt_umsatz = "k.A." self.sheet_handler.sheet.update(values=[[chatgpt_umsatz]], range_name=chatgpt_range) - # Umsatz-Abgleich: CRM-Umsatz aus Spalte I und Wikipedia-Umsatz + # Umsatz-Abgleich (wie bisher) crm_umsatz = row_data[8] if len(row_data) > 8 else "k.A." abgleich_result = compare_umsatz_values(crm_umsatz, company_data.get('umsatz', 'k.A.')) self.sheet_handler.sheet.update(values=[[abgleich_result]], range_name=abgleich_range) + # --- Neuer Validierungsschritt --- + # Aggregiere CRM-Daten (B bis J) und Wikipedia-Daten (L bis Q) als CSV-Text + crm_data = ";".join(row_data[1:10]) + wiki_data = ";".join(row_data[11:17]) + valid_result = validate_article_with_chatgpt(crm_data, wiki_data) + self.sheet_handler.sheet.update(values=[[valid_result]], range_name=valid_range) + # Timestamp und Version schreiben current_dt = datetime.now().strftime("%Y-%m-%d %H:%M:%S") self.sheet_handler.sheet.update(values=[[current_dt]], range_name=dt_range) self.sheet_handler.sheet.update(values=[[Config.VERSION]], range_name=ver_range) print(f"✅ Aktualisiert: URL: {company_data.get('url', 'k.A.')}, Absatz: {company_data.get('first_paragraph', 'k.A.')[:30]}..., " f"Branche: {company_data.get('branche', 'k.A.')}, Wikipedia Umsatz: {company_data.get('umsatz', 'k.A.')}, " f"Mitarbeiter: {company_data.get('mitarbeiter', 'k.A.')}, Kategorien: {company_data.get('categories', 'k.A.')}, " - f"ChatGPT Umsatz: {chatgpt_umsatz}, Umsatz-Abgleich: {abgleich_result}") + f"ChatGPT Umsatz: {chatgpt_umsatz}, Umsatz-Abgleich: {abgleich_result}, Validierung: {valid_result}") if MODE == "2": print("----- Vollständiger Infobox-Inhalt -----") print(company_data.get("full_infobox", "k.A."))