v1.2.5: Umsatzvergleich verbessert; 1 Sekunde Pause + zusätzliche Debug-Ausgabe
Validierung: Eine neue Funktion validate_company_data erstellt einen Prompt für die ChatGPT-API, in dem die relevanten CRM- und Wikipedia-Daten (Firmenname, Umsatz, Mitarbeiter, Branche) verglichen werden. Je nach Antwort wird „OK“ oder „X“ sowie eine Begründung zurückgegeben. Alternative Suche: Falls eine Inkonsistenz festgestellt wird (Validierung ergibt „X“), wird in der Funktion find_alternative_wikipedia_article nach einem alternativen Wikipedia-Artikel gesucht und dessen URL in Spalte T geschrieben. Spalten R, S, T: Die Ergebnisse der Validierung (Flag und Begründung) werden in Spalte R und S ausgegeben, während bei Inkonsistenz der alternative Artikel in Spalte T hinterlegt wird.
This commit is contained in:
@@ -14,7 +14,7 @@ import csv
|
|||||||
|
|
||||||
# ==================== KONFIGURATION ====================
|
# ==================== KONFIGURATION ====================
|
||||||
class Config:
|
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"
|
LANG = "de"
|
||||||
CREDENTIALS_FILE = "service_account.json"
|
CREDENTIALS_FILE = "service_account.json"
|
||||||
SHEET_URL = "https://docs.google.com/spreadsheets/d/1u_gHr9JUfmV1-iviRzbSe3575QEp7KLhK5jFV_gJcgo"
|
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}")
|
debug_print(f"Fehler beim Lesen des API-Tokens: {e}")
|
||||||
return "k.A."
|
return "k.A."
|
||||||
openai.api_key = api_key
|
openai.api_key = api_key
|
||||||
prompt = (
|
prompt = (f"Bitte schätze den Umsatz in Mio. Euro für das Unternehmen '{company_name}'. "
|
||||||
f"Bitte schätze den Umsatz in Mio. Euro für das Unternehmen '{company_name}'. "
|
f"Die Wikipedia-Daten zeigen: '{wiki_umsatz}'. "
|
||||||
f"Die Wikipedia-Daten zeigen: '{wiki_umsatz}'. "
|
"Antworte nur mit der Zahl.")
|
||||||
"Antworte nur mit der Zahl."
|
|
||||||
)
|
|
||||||
try:
|
try:
|
||||||
response = openai.ChatCompletion.create(
|
response = openai.ChatCompletion.create(
|
||||||
model="gpt-3.5-turbo",
|
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}")
|
debug_print(f"Fehler beim Aufruf der ChatGPT API: {e}")
|
||||||
return "k.A."
|
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 ====================
|
# ==================== GOOGLE SHEET HANDLER ====================
|
||||||
class GoogleSheetHandler:
|
class GoogleSheetHandler:
|
||||||
def __init__(self):
|
def __init__(self):
|
||||||
@@ -373,15 +332,8 @@ class WikipediaScraper:
|
|||||||
return result
|
return result
|
||||||
def extract_company_data(self, page_url):
|
def extract_company_data(self, page_url):
|
||||||
if not page_url:
|
if not page_url:
|
||||||
return {
|
return {'url': 'k.A.', 'first_paragraph': 'k.A.', 'branche': 'k.A.',
|
||||||
'url': 'k.A.',
|
'umsatz': 'k.A.', 'mitarbeiter': 'k.A.', 'categories': 'k.A.', 'full_infobox': 'k.A.'}
|
||||||
'first_paragraph': 'k.A.',
|
|
||||||
'branche': 'k.A.',
|
|
||||||
'umsatz': 'k.A.',
|
|
||||||
'mitarbeiter': 'k.A.',
|
|
||||||
'categories': 'k.A.',
|
|
||||||
'full_infobox': 'k.A.'
|
|
||||||
}
|
|
||||||
try:
|
try:
|
||||||
response = requests.get(page_url)
|
response = requests.get(page_url)
|
||||||
soup = BeautifulSoup(response.text, Config.HTML_PARSER)
|
soup = BeautifulSoup(response.text, Config.HTML_PARSER)
|
||||||
@@ -405,15 +357,8 @@ class WikipediaScraper:
|
|||||||
}
|
}
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
debug_print(f"Extraktionsfehler: {str(e)}")
|
debug_print(f"Extraktionsfehler: {str(e)}")
|
||||||
return {
|
return {'url': 'k.A.', 'first_paragraph': 'k.A.', 'branche': 'k.A.',
|
||||||
'url': 'k.A.',
|
'umsatz': 'k.A.', 'mitarbeiter': 'k.A.', 'categories': 'k.A.', 'full_infobox': '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
|
@retry_on_failure
|
||||||
def search_company_article(self, company_name, website):
|
def search_company_article(self, company_name, website):
|
||||||
search_terms = self._generate_search_terms(company_name, website)
|
search_terms = self._generate_search_terms(company_name, website)
|
||||||
@@ -434,6 +379,42 @@ class WikipediaScraper:
|
|||||||
continue
|
continue
|
||||||
return None
|
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 ====================
|
# ==================== DATA PROCESSOR ====================
|
||||||
class DataProcessor:
|
class DataProcessor:
|
||||||
def __init__(self):
|
def __init__(self):
|
||||||
@@ -457,14 +438,18 @@ class DataProcessor:
|
|||||||
if i >= self.sheet_handler.get_start_index():
|
if i >= self.sheet_handler.get_start_index():
|
||||||
self._process_single_row(i, row)
|
self._process_single_row(i, row)
|
||||||
def _process_single_row(self, row_num, row_data):
|
def _process_single_row(self, row_num, row_data):
|
||||||
# CRM-Daten: Spalten B bis J (Indices 1 bis 9)
|
# Neues Schema:
|
||||||
# Wikipedia-Daten: Spalten L bis Q (Indices 11 bis 16)
|
# 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 ""
|
company_name = row_data[1] if len(row_data) > 1 else ""
|
||||||
website = row_data[2] if len(row_data) > 2 else ""
|
website = row_data[2] if len(row_data) > 2 else ""
|
||||||
wiki_update_range = f"K{row_num}:Q{row_num}"
|
wiki_update_range = f"K{row_num}:Q{row_num}"
|
||||||
chatgpt_range = f"AF{row_num}"
|
chatgpt_range = f"AF{row_num}"
|
||||||
abgleich_range = f"AG{row_num}"
|
abgleich_range = f"AG{row_num}"
|
||||||
valid_range = f"R{row_num}" # Konsistenzprüfung
|
|
||||||
dt_range = f"AH{row_num}"
|
dt_range = f"AH{row_num}"
|
||||||
ver_range = f"AI{row_num}"
|
ver_range = f"AI{row_num}"
|
||||||
print(f"\n[{datetime.now().strftime('%H:%M:%S')}] Verarbeite Zeile {row_num}: {company_name}")
|
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)
|
self.sheet_handler.sheet.update(values=[wiki_values], range_name=wiki_update_range)
|
||||||
time.sleep(1)
|
time.sleep(1)
|
||||||
# Umsatz-Schätzung via ChatGPT (wie bisher)
|
|
||||||
wiki_umsatz = company_data.get('umsatz', 'k.A.')
|
wiki_umsatz = company_data.get('umsatz', 'k.A.')
|
||||||
if wiki_umsatz != "k.A.":
|
if wiki_umsatz != "k.A.":
|
||||||
chatgpt_umsatz = evaluate_umsatz_chatgpt(company_name, wiki_umsatz)
|
chatgpt_umsatz = evaluate_umsatz_chatgpt(company_name, wiki_umsatz)
|
||||||
else:
|
else:
|
||||||
chatgpt_umsatz = "k.A."
|
chatgpt_umsatz = "k.A."
|
||||||
self.sheet_handler.sheet.update(values=[[chatgpt_umsatz]], range_name=chatgpt_range)
|
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."
|
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.'))
|
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)
|
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")
|
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=[[current_dt]], range_name=dt_range)
|
||||||
self.sheet_handler.sheet.update(values=[[Config.VERSION]], range_name=ver_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]}..., "
|
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"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"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":
|
if MODE == "2":
|
||||||
print("----- Vollständiger Infobox-Inhalt -----")
|
print("----- Vollständiger Infobox-Inhalt -----")
|
||||||
print(company_data.get("full_infobox", "k.A."))
|
print(company_data.get("full_infobox", "k.A."))
|
||||||
|
|||||||
Reference in New Issue
Block a user