diff --git a/brancheneinstufung.py b/brancheneinstufung.py index ad45d8ba..3f6c0bb0 100644 --- a/brancheneinstufung.py +++ b/brancheneinstufung.py @@ -14,7 +14,7 @@ import csv # ==================== KONFIGURATION ==================== class Config: - VERSION = "v1.3.1" # v1.3.1: Validierung des Wikipedia-Artikels implementiert + VERSION = "v1.2.5" # v1.2.5: Umsatzvergleich verbessert; 1 Sekunde Pause + zusätzliche Debug-Ausgabe LANG = "de" CREDENTIALS_FILE = "service_account.json" SHEET_URL = "https://docs.google.com/spreadsheets/d/1u_gHr9JUfmV1-iviRzbSe3575QEp7KLhK5jFV_gJcgo" @@ -132,11 +132,9 @@ 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,45 +153,6 @@ 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): @@ -373,15 +332,8 @@ 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) @@ -405,15 +357,8 @@ 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) @@ -434,6 +379,42 @@ 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): @@ -457,14 +438,18 @@ 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): - # CRM-Daten: Spalten B bis J (Indices 1 bis 9) - # Wikipedia-Daten: Spalten L bis Q (Indices 11 bis 16) + # 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. 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}") @@ -492,31 +477,42 @@ 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}, Validierung: {valid_result}") + f"ChatGPT Umsatz: {chatgpt_umsatz}, Umsatz-Abgleich: {abgleich_result}") if MODE == "2": print("----- Vollständiger Infobox-Inhalt -----") print(company_data.get("full_infobox", "k.A."))