diff --git a/brancheneinstufung.py b/brancheneinstufung.py index 3f6c0bb0..7661b628 100644 --- a/brancheneinstufung.py +++ b/brancheneinstufung.py @@ -14,7 +14,7 @@ import csv # ==================== KONFIGURATION ==================== class Config: - VERSION = "v1.2.5" # v1.2.5: Umsatzvergleich verbessert; 1 Sekunde Pause + zusätzliche Debug-Ausgabe + VERSION = "v1.3.0" # v1.3.0: Validierung des Wikipedia-Artikels implementiert LANG = "de" CREDENTIALS_FILE = "service_account.json" SHEET_URL = "https://docs.google.com/spreadsheets/d/1u_gHr9JUfmV1-iviRzbSe3575QEp7KLhK5jFV_gJcgo" @@ -132,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", @@ -153,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): @@ -332,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) @@ -357,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) @@ -379,42 +434,6 @@ class WikipediaScraper: continue return None - # === NEU: Alternative Artikel finden === - def find_alternative_article(self, company_name, website): - alt_terms = self._generate_search_terms(company_name, website) - # Entferne Domainnamen, um die Suche zu erweitern - alt_terms = [term for term in alt_terms if not re.search(r'\.(com|de)$', term)] - for term in alt_terms: - try: - results = wikipedia.search(term, results=Config.WIKIPEDIA_SEARCH_RESULTS) - debug_print(f"Alternative Suchergebnisse für '{term}': {results}") - for title in results: - try: - page = wikipedia.page(title, auto_suggest=False) - if self._validate_article(page, company_name, website): - return page.url - except (wikipedia.exceptions.DisambiguationError, wikipedia.exceptions.PageError): - continue - except Exception as e: - debug_print(f"Alternative Suchfehler für '{term}': {e}") - continue - return "k.A." - # === ENDE NEU === - - def extract_first_paragraph(self, page_url): - try: - response = requests.get(page_url) - soup = BeautifulSoup(response.text, Config.HTML_PARSER) - paragraphs = soup.find_all('p') - for p in paragraphs: - text = clean_text(p.get_text()) - if len(text) > 50: - return text - return "k.A." - except Exception as e: - debug_print(f"Fehler beim Extrahieren des ersten Absatzes: {e}") - return "k.A." - # ==================== DATA PROCESSOR ==================== class DataProcessor: def __init__(self): @@ -438,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: - # B: Firmenname, 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}") @@ -477,42 +492,31 @@ class DataProcessor: ] self.sheet_handler.sheet.update(values=[wiki_values], range_name=wiki_update_range) time.sleep(1) + # 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 (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) - - # === NEU: Konsistenzprüfung und alternative Artikelfindung === - consistency_range = f"R{row_num}" - explanation_range = f"S{row_num}" - alt_article_range = f"T{row_num}" - - if abgleich_result == "OK": - consistency_flag = "OK" - explanation = "" - alt_article = "" - else: - consistency_flag = "X" - explanation = abgleich_result # Hier wird der Grund ausgegeben - alt_article = self.wiki_scraper.find_alternative_article(company_name, website) - - self.sheet_handler.sheet.update(values=[[consistency_flag]], range_name=consistency_range) - self.sheet_handler.sheet.update(values=[[explanation]], range_name=explanation_range) - self.sheet_handler.sheet.update(values=[[alt_article]], range_name=alt_article_range) - # === ENDE NEU === - 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."))