v1.3.4 Erweiterung: FSM-Prüfung, Servicetechniker-Schätzung, Wiki-Vorschlag & 3s Pause

Bevorzugter Wikipedia-Artikel aus Spalte K wird genutzt.

Nach dem Schreiben der Wiki-Daten erfolgt eine 3-Sekunden-Pause.

Neue Funktion zur FSM-Eignungsprüfung (Spalte Y/Z) integriert.

Neue Servicetechniker-Schätzung (Spalte AD) und Vergleich mit interner Angabe (Spalte AE) hinzugefügt.

Versionsnummer wurde auf v1.3.4 aktualisiert.
This commit is contained in:
2025-04-02 13:27:37 +00:00
parent 9a53b55173
commit 43c23b50d8

View File

@@ -14,7 +14,7 @@ import csv
# ==================== KONFIGURATION ====================
class Config:
VERSION = "v1.3.3" # v1.3.3: Branchenabgleich per ChatGPT integriert, Ziel-Branchenschema inkl. aller gültigen Branchen eingebunden.
VERSION = "v1.3.4" # v1.3.4: FSM-Eignungsprüfung, Servicetechniker-Schätzung, Wiki-Vorschlag und 3s Pause integriert.
LANG = "de"
CREDENTIALS_FILE = "service_account.json"
SHEET_URL = "https://docs.google.com/spreadsheets/d/1u_gHr9JUfmV1-iviRzbSe3575QEp7KLhK5jFV_gJcgo"
@@ -193,6 +193,86 @@ def validate_article_with_chatgpt(crm_data, wiki_data):
debug_print(f"Fehler beim Validierungs-API-Aufruf: {e}")
return "k.A."
# ==================== NEUE FUNKTION: FSM-EIGNUNGSPRÜFUNG ====================
def evaluate_fsm_suitability(company_name, company_data):
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 {"suitability": "k.A.", "justification": "k.A."}
openai.api_key = api_key
prompt = (
f"Bitte bewerte, ob das Unternehmen '{company_name}' für den Einsatz einer Field Service Management Lösung geeignet ist. "
"Berücksichtige, dass ein Unternehmen mit einem technischen Außendienst, idealerweise mit über 50 Technikern und "
"Disponenten, die mit der Planung mobiler Ressourcen beschäftigt sind, als geeignet gilt. Nutze dabei vor allem verifizierte "
"Wikipedia-Daten und deine eigene Einschätzung. Antworte ausschließlich mit 'Ja' oder 'Nein' und gib eine kurze Begründung."
)
try:
response = openai.ChatCompletion.create(
model="gpt-3.5-turbo",
messages=[{"role": "system", "content": prompt}],
temperature=0.0
)
result = response.choices[0].message.content.strip()
debug_print(f"FSM-Eignungsantwort ChatGPT: '{result}'")
# Erwartetes Format: "Eignung: <Ja/Nein>\nBegründung: <...>"
suitability = "k.A."
justification = ""
for line in result.split("\n"):
if line.lower().startswith("eignung:"):
suitability = line.split(":", 1)[1].strip()
elif line.lower().startswith("begründung:"):
justification = line.split(":", 1)[1].strip()
return {"suitability": suitability, "justification": justification}
except Exception as e:
debug_print(f"Fehler beim Aufruf der ChatGPT API für FSM-Eignungsprüfung: {e}")
return {"suitability": "k.A.", "justification": "k.A."}
# ==================== NEUE FUNKTION: SCHÄTZUNG DER ANZAHL SERVICETECHNIKER ====================
def evaluate_servicetechnicians_estimate(company_name, company_data):
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
prompt = (
f"Bitte schätze auf Basis öffentlich zugänglicher Informationen (insbesondere verifizierte Wikipedia-Daten) "
f"die Anzahl der Servicetechniker des Unternehmens '{company_name}' ein. "
"Berücksichtige dabei Angaben zu Branche, Umsatz und Mitarbeiterzahl. "
"Gib die Antwort ausschließlich in einer der folgenden Kategorien aus: "
"'<50 Techniker', '>100 Techniker', '>200 Techniker', '>500 Techniker'."
)
try:
response = openai.ChatCompletion.create(
model="gpt-3.5-turbo",
messages=[{"role": "system", "content": prompt}],
temperature=0.0
)
result = response.choices[0].message.content.strip()
debug_print(f"Schätzung Servicetechniker ChatGPT: '{result}'")
# Wir erwarten eine Antwort, die exakt einer der vier Kategorien entspricht.
return result
except Exception as e:
debug_print(f"Fehler beim Aufruf der ChatGPT API für Servicetechniker-Schätzung: {e}")
return "k.A."
def map_internal_technicians(value):
try:
num = int(value)
except Exception:
return "k.A."
if num < 50:
return "<50 Techniker"
elif num < 100:
return ">100 Techniker"
elif num < 200:
return ">200 Techniker"
else:
return ">500 Techniker"
# ==================== BRANCHENABGLEICH PER CHATGPT ====================
def load_target_branches():
try:
@@ -225,7 +305,6 @@ focus_branches = [
]
def evaluate_branche_chatgpt(crm_branche, beschreibung, wiki_branche, wiki_kategorien):
# Lade das Ziel-Branchenschema
target_branches = load_target_branches()
target_branches_str = "\n".join(target_branches)
focus_branches_str = "\n".join(focus_branches)
@@ -243,7 +322,7 @@ def evaluate_branche_chatgpt(crm_branche, beschreibung, wiki_branche, wiki_kateg
f"Branchenbeschreibung (Spalte G): {beschreibung}\n"
f"Wikipedia-Branche (Spalte N): {wiki_branche}\n"
f"Wikipedia-Kategorien (Spalte Q): {wiki_kategorien}\n\n"
"Das Ziel-Branchenschema umfasst ALLE gültigen Branchen, also sowohl Fokusbranchen als auch weitere Branchen (z. B. 'Housing > Sozialbau Unternehmen').\n"
"Das Ziel-Branchenschema umfasst ALLE gültigen Branchen, also sowohl Fokusbranchen als auch weitere, z. B. 'Housing > Sozialbau Unternehmen'.\n"
"Das vollständige Ziel-Branchenschema lautet:\n"
f"{target_branches_str}\n\n"
"Falls das Unternehmen mehreren Branchen zugeordnet werden könnte, wähle bitte bevorzugt eine Branche aus der folgenden Fokusliste, sofern zutreffend:\n"
@@ -266,7 +345,6 @@ def evaluate_branche_chatgpt(crm_branche, beschreibung, wiki_branche, wiki_kateg
)
result = response.choices[0].message.content.strip()
debug_print(f"Branchenabgleich ChatGPT Antwort: '{result}'")
# Parsing der Antwort
branch = "k.A."
consistency = "k.A."
justification = ""
@@ -504,6 +582,8 @@ class WikipediaScraper:
}
@retry_on_failure
def search_company_article(self, company_name, website):
# Zuerst prüfen: Gibt es in Spalte K bereits einen Wikipedia-Vorschlag?
# (Dies wird im _process_single_row gehandhabt)
search_terms = self._generate_search_terms(company_name, website)
for term in search_terms:
try:
@@ -557,11 +637,26 @@ class DataProcessor:
ver_range = f"AI{row_num}"
print(f"\n[{datetime.now().strftime('%H:%M:%S')}] Verarbeite Zeile {row_num}: {company_name}")
article = self.wiki_scraper.search_company_article(company_name, website)
if article:
company_data = self.wiki_scraper.extract_company_data(article.url)
# Prüfe: Ist in Spalte K (Index 10) bereits ein Wikipedia-Vorschlag hinterlegt?
if len(row_data) > 10 and row_data[10].strip() not in ["", "k.A."]:
wiki_url = row_data[10].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:
company_data = {
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.',
@@ -572,7 +667,7 @@ class DataProcessor:
}
wiki_values = [
"k.A.", # Vorschlag Wiki URL
row_data[10] if len(row_data) > 10 and row_data[10].strip() not in ["", "k.A."] else "k.A.", # Vorschlag Wiki URL
company_data.get('url', 'k.A.'),
company_data.get('first_paragraph', 'k.A.'),
company_data.get('branche', 'k.A.'),
@@ -581,7 +676,7 @@ class DataProcessor:
company_data.get('categories', 'k.A.')
]
self.sheet_handler.sheet.update(values=[wiki_values], range_name=wiki_update_range)
time.sleep(1)
time.sleep(3) # 3 Sekunden warten, bevor Validierung durchgeführt wird.
# Umsatz-Schätzung via ChatGPT (wie bisher)
wiki_umsatz = company_data.get('umsatz', 'k.A.')
@@ -608,11 +703,6 @@ class DataProcessor:
wiki_branche = company_data.get('branche', 'k.A.')
wiki_kategorien = company_data.get('categories', 'k.A.')
branche_result = evaluate_branche_chatgpt(crm_branche, beschreibung_branche, wiki_branche, wiki_kategorien)
# Update der Spalten:
# Spalte V: Vorschlag neue Branche
# Spalte W: Konsistenzprüfung Branche (ok, wenn Übereinstimmung, sonst X)
# Spalte X: Begründung bei Abweichung
branche_v_range = f"V{row_num}"
branche_w_range = f"W{row_num}"
branche_x_range = f"X{row_num}"
@@ -620,6 +710,23 @@ class DataProcessor:
self.sheet_handler.sheet.update(values=[[branche_result["consistency"]]], range_name=branche_w_range)
self.sheet_handler.sheet.update(values=[[branche_result["justification"]]], range_name=branche_x_range)
# Neue FSM-Eignungsprüfung:
fsm_result = evaluate_fsm_suitability(company_name, company_data)
self.sheet_handler.sheet.update(values=[[fsm_result["suitability"]]], range_name=f"Y{row_num}")
self.sheet_handler.sheet.update(values=[[fsm_result["justification"]]], range_name=f"Z{row_num}")
# Neue Servicetechniker-Schätzung (ohne Berücksichtigung interner Angaben in Spalte H)
st_estimate = evaluate_servicetechnicians_estimate(company_name, company_data)
self.sheet_handler.sheet.update(values=[[st_estimate]], range_name=f"AD{row_num}")
# Vergleich mit interner Angabe (Spalte H)
internal_value = row_data[7] if len(row_data) > 7 else "k.A."
internal_category = map_internal_technicians(internal_value) if internal_value != "k.A." else "k.A."
if internal_category != "k.A." and st_estimate != internal_category:
discrepancy = f"Interne Angabe: {internal_category} vs. ChatGPT: {st_estimate}"
else:
discrepancy = "ok"
self.sheet_handler.sheet.update(values=[[discrepancy]], range_name=f"AE{row_num}")
# 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)
@@ -628,7 +735,8 @@ class DataProcessor:
print(f"✅ Aktualisiert: URL: {company_data.get('url', 'k.A.')}, "
f"Branche: {company_data.get('branche', 'k.A.')}, "
f"ChatGPT Umsatz: {chatgpt_umsatz}, Umsatz-Abgleich: {abgleich_result}, "
f"Validierung: {valid_result}, Branchenvorschlag: {branche_result['branch']}")
f"Validierung: {valid_result}, Branchenvorschlag: {branche_result['branch']}, "
f"FSM: {fsm_result['suitability']}, Servicetechniker-Schätzung: {st_estimate}")
time.sleep(Config.RETRY_DELAY)
if __name__ == "__main__":