v1.3.5 Erweiterung: FSM-Eignungsprüfung & Servicetechniker-Explanation, Sheet-Update-Check, automati
Wikipedia-Artikelvorschlag aus Spalte K wird bevorzugt genutzt. Nach dem Schreiben der Wikipedia-Daten wird überprüft, ob das Update abgeschlossen ist (mit einer max. 5‑s‑Wartezeit) und es folgt eine 3‑s Pause. Der FSM-Eignungsparser wurde angepasst, um auch freiere Antworten zu verarbeiten. Bei Diskrepanzen in der Servicetechniker-Schätzung wird nun zusätzlich eine detaillierte Erklärung von ChatGPT angefordert. Die Spalten AF und AG werden vorerst mit "XX" befüllt. Alle Debug-Ausgaben werden automatisch in einer Log-Datei im Ordner "Log" mit Datum und Versionsnummer gespeichert.
This commit is contained in:
@@ -14,7 +14,7 @@ import csv
|
||||
|
||||
# ==================== KONFIGURATION ====================
|
||||
class Config:
|
||||
VERSION = "v1.3.4" # v1.3.4: FSM-Eignungsprüfung, Servicetechniker-Schätzung, Wiki-Vorschlag und 3s Pause integriert.
|
||||
VERSION = "v1.3.5" # v1.3.5: FSM-Prüfung mit flexiblem Parser, Servicetechniker-Explanation, Log-Datei, Warten bis Sheet-Update.
|
||||
LANG = "de"
|
||||
CREDENTIALS_FILE = "service_account.json"
|
||||
SHEET_URL = "https://docs.google.com/spreadsheets/d/1u_gHr9JUfmV1-iviRzbSe3575QEp7KLhK5jFV_gJcgo"
|
||||
@@ -26,21 +26,19 @@ class Config:
|
||||
WIKIPEDIA_SEARCH_RESULTS = 5
|
||||
HTML_PARSER = "html.parser"
|
||||
|
||||
# ==================== HELPER FUNCTIONS ====================
|
||||
def retry_on_failure(func):
|
||||
def wrapper(*args, **kwargs):
|
||||
for attempt in range(Config.MAX_RETRIES):
|
||||
try:
|
||||
return func(*args, **kwargs)
|
||||
except Exception as e:
|
||||
print(f"⚠️ Fehler bei {func.__name__} (Versuch {attempt+1}): {str(e)[:100]}")
|
||||
time.sleep(Config.RETRY_DELAY)
|
||||
return None
|
||||
return wrapper
|
||||
# Log-Datei vorbereiten
|
||||
if not os.path.exists("Log"):
|
||||
os.makedirs("Log")
|
||||
LOG_FILE = os.path.join("Log", f"{datetime.now().strftime('%d-%m-%Y_%H-%M')}_{Config.VERSION.replace('.', '')}.txt")
|
||||
|
||||
def debug_print(message):
|
||||
if Config.DEBUG:
|
||||
print(f"[DEBUG] {message}")
|
||||
try:
|
||||
with open(LOG_FILE, "a", encoding="utf-8") as f:
|
||||
f.write(f"[DEBUG] {message}\n")
|
||||
except Exception as e:
|
||||
print(f"[DEBUG] Log-Schreibfehler: {e}")
|
||||
|
||||
def clean_text(text):
|
||||
if not text:
|
||||
@@ -144,23 +142,18 @@ def evaluate_umsatz_chatgpt(company_name, wiki_umsatz):
|
||||
temperature=0.0
|
||||
)
|
||||
result = response.choices[0].message.content.strip()
|
||||
debug_print(f"ChatGPT Antwort: '{result}'")
|
||||
debug_print(f"ChatGPT Umsatzschätzung: '{result}'")
|
||||
try:
|
||||
value = float(result.replace(',', '.'))
|
||||
return str(int(round(value)))
|
||||
except Exception as conv_e:
|
||||
debug_print(f"Fehler bei der Verarbeitung der ChatGPT-Antwort '{result}': {conv_e}")
|
||||
debug_print(f"Fehler bei der Verarbeitung der Umsatzschätzung '{result}': {conv_e}")
|
||||
return result
|
||||
except Exception as e:
|
||||
debug_print(f"Fehler beim Aufruf der ChatGPT API: {e}")
|
||||
debug_print(f"Fehler beim Aufruf der ChatGPT API für Umsatzschätzung: {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.
|
||||
"""
|
||||
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 = (
|
||||
@@ -199,13 +192,13 @@ def evaluate_fsm_suitability(company_name, company_data):
|
||||
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}")
|
||||
debug_print(f"Fehler beim Lesen des API-Tokens (FSM): {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 "
|
||||
"Disponenten, die mit der Planung mobiler Ressourcen beschäftigt sind, als geeignet gilt. Nutze dabei verifizierte "
|
||||
"Wikipedia-Daten und deine eigene Einschätzung. Antworte ausschließlich mit 'Ja' oder 'Nein' und gib eine kurze Begründung."
|
||||
)
|
||||
try:
|
||||
@@ -216,14 +209,24 @@ def evaluate_fsm_suitability(company_name, company_data):
|
||||
)
|
||||
result = response.choices[0].message.content.strip()
|
||||
debug_print(f"FSM-Eignungsantwort ChatGPT: '{result}'")
|
||||
# Erwartetes Format: "Eignung: <Ja/Nein>\nBegründung: <...>"
|
||||
# Flexibler Parser: Falls keine Zeilen mit ":" vorhanden sind, nimm den ersten Satz.
|
||||
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()
|
||||
lines = result.split("\n")
|
||||
if len(lines) == 1:
|
||||
parts = result.split(" ", 1)
|
||||
suitability = parts[0].strip()
|
||||
justification = parts[1].strip() if len(parts) > 1 else ""
|
||||
else:
|
||||
for line in lines:
|
||||
if line.lower().startswith("eignung:"):
|
||||
suitability = line.split(":", 1)[1].strip()
|
||||
elif line.lower().startswith("begründung:"):
|
||||
justification = line.split(":", 1)[1].strip()
|
||||
if suitability not in ["Ja", "Nein"]:
|
||||
parts = result.split(" ", 1)
|
||||
suitability = parts[0].strip()
|
||||
justification = " ".join(result.split()[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}")
|
||||
@@ -235,13 +238,12 @@ def evaluate_servicetechnicians_estimate(company_name, company_data):
|
||||
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}")
|
||||
debug_print(f"Fehler beim Lesen des API-Tokens (Servicetechniker): {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"Bitte schätze auf Basis öffentlich zugänglicher Informationen (vor allem 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'."
|
||||
)
|
||||
@@ -253,12 +255,36 @@ def evaluate_servicetechnicians_estimate(company_name, company_data):
|
||||
)
|
||||
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 evaluate_servicetechnicians_explanation(company_name, st_estimate, 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 (ST-Erklärung): {e}")
|
||||
return "k.A."
|
||||
openai.api_key = api_key
|
||||
prompt = (
|
||||
f"Bitte erkläre, warum du für das Unternehmen '{company_name}' die Anzahl der Servicetechniker als '{st_estimate}' geschätzt hast. "
|
||||
"Berücksichtige dabei öffentlich zugängliche Informationen wie Branche, Umsatz, Mitarbeiterzahl und andere relevante Daten."
|
||||
)
|
||||
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"Servicetechniker-Erklärung ChatGPT: '{result}'")
|
||||
return result
|
||||
except Exception as e:
|
||||
debug_print(f"Fehler beim Aufruf der ChatGPT API für Servicetechniker-Erklärung: {e}")
|
||||
return "k.A."
|
||||
|
||||
def map_internal_technicians(value):
|
||||
try:
|
||||
num = int(value)
|
||||
@@ -273,19 +299,30 @@ def map_internal_technicians(value):
|
||||
else:
|
||||
return ">500 Techniker"
|
||||
|
||||
# ==================== WARTEN BIS ZELLE AKTUALISIERT IST ====================
|
||||
def wait_for_sheet_update(sheet, cell, expected_value, timeout=5):
|
||||
start_time = time.time()
|
||||
while time.time() - start_time < timeout:
|
||||
try:
|
||||
current_value = sheet.acell(cell).value
|
||||
if current_value == expected_value:
|
||||
return True
|
||||
except Exception as e:
|
||||
debug_print(f"Fehler beim Lesen von Zelle {cell}: {e}")
|
||||
time.sleep(0.5)
|
||||
return False
|
||||
|
||||
# ==================== BRANCHENABGLEICH PER CHATGPT ====================
|
||||
def load_target_branches():
|
||||
try:
|
||||
with open("ziel_Branchenschema.csv", "r", encoding="utf-8") as csvfile:
|
||||
reader = csv.reader(csvfile)
|
||||
# Annahme: Jede Zeile enthält in der ersten Spalte einen gültigen Branchen-Namen
|
||||
branches = [row[0] for row in reader if row]
|
||||
return branches
|
||||
except Exception as e:
|
||||
debug_print(f"Fehler beim Laden des Ziel-Branchenschemas: {e}")
|
||||
return []
|
||||
|
||||
# Fokusbranchen-Liste (wie definiert)
|
||||
focus_branches = [
|
||||
"Gutachter / Versicherungen > Baugutachter",
|
||||
"Gutachter / Versicherungen > Technische Gutachten",
|
||||
@@ -312,17 +349,16 @@ def evaluate_branche_chatgpt(crm_branche, beschreibung, wiki_branche, wiki_kateg
|
||||
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}")
|
||||
debug_print(f"Fehler beim Lesen des API-Tokens (Branche): {e}")
|
||||
return {"branch": "k.A.", "consistency": "k.A.", "justification": "k.A."}
|
||||
openai.api_key = api_key
|
||||
|
||||
system_prompt = (
|
||||
"Du bist ein Experte im Field Service Management. Deine Aufgabe ist es, ein Unternehmen basierend auf folgenden Angaben einer Branche zuzuordnen.\n\n"
|
||||
f"CRM-Branche (Spalte F): {crm_branche}\n"
|
||||
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, 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"
|
||||
@@ -583,7 +619,6 @@ 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:
|
||||
@@ -625,19 +660,17 @@ 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)
|
||||
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
|
||||
valid_range = f"R{row_num}"
|
||||
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}")
|
||||
|
||||
# Prüfe: Ist in Spalte K (Index 10) bereits ein Wikipedia-Vorschlag hinterlegt?
|
||||
# Prüfen: Wikipedia-Vorschlag in Spalte K?
|
||||
if len(row_data) > 10 and row_data[10].strip() not in ["", "k.A."]:
|
||||
wiki_url = row_data[10].strip()
|
||||
try:
|
||||
@@ -646,28 +679,20 @@ class DataProcessor:
|
||||
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.',
|
||||
'url': 'k.A.', 'first_paragraph': 'k.A.', 'branche': 'k.A.',
|
||||
'umsatz': 'k.A.', 'mitarbeiter': 'k.A.', 'categories': 'k.A.',
|
||||
'full_infobox': 'k.A.'
|
||||
}
|
||||
else:
|
||||
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.',
|
||||
'url': 'k.A.', 'first_paragraph': 'k.A.', 'branche': 'k.A.',
|
||||
'umsatz': 'k.A.', 'mitarbeiter': 'k.A.', 'categories': 'k.A.',
|
||||
'full_infobox': 'k.A.'
|
||||
}
|
||||
|
||||
wiki_values = [
|
||||
row_data[10] if len(row_data) > 10 and row_data[10].strip() not in ["", "k.A."] else "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.",
|
||||
company_data.get('url', 'k.A.'),
|
||||
company_data.get('first_paragraph', 'k.A.'),
|
||||
company_data.get('branche', 'k.A.'),
|
||||
@@ -676,28 +701,25 @@ class DataProcessor:
|
||||
company_data.get('categories', 'k.A.')
|
||||
]
|
||||
self.sheet_handler.sheet.update(values=[wiki_values], range_name=wiki_update_range)
|
||||
time.sleep(3) # 3 Sekunden warten, bevor Validierung durchgeführt wird.
|
||||
# Warten, bis das Update im Sheet übernommen wurde (prüfe Zelle K{row_num})
|
||||
wait_for_sheet_update(self.sheet_handler.sheet, f"K{row_num}", wiki_values[0])
|
||||
time.sleep(3)
|
||||
|
||||
# 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-Schätzung (Spalte AF soll "XX" erhalten)
|
||||
self.sheet_handler.sheet.update(values=[["XX"]], range_name=chatgpt_range)
|
||||
|
||||
# Umsatz-Abgleich (wie bisher)
|
||||
# Umsatz-Abgleich (Spalte AG)
|
||||
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 (Firmenabgleich) – unverändert
|
||||
# Validierung
|
||||
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)
|
||||
|
||||
# Neuer Branchenabgleich per ChatGPT:
|
||||
# Branchenabgleich
|
||||
crm_branche = row_data[5] if len(row_data) > 5 else "k.A."
|
||||
beschreibung_branche = row_data[6] if len(row_data) > 6 else "k.A."
|
||||
wiki_branche = company_data.get('branche', 'k.A.')
|
||||
@@ -710,31 +732,35 @@ 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-Eignungsprüfung (Spalte Y/Z)
|
||||
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)
|
||||
# Servicetechniker-Schätzung (Spalte AD) und Vergleich (Spalte AE)
|
||||
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}"
|
||||
# Hole detaillierte Erklärung von ChatGPT, warum die Schätzung so ist.
|
||||
explanation = evaluate_servicetechnicians_explanation(company_name, st_estimate, company_data)
|
||||
discrepancy = explanation
|
||||
else:
|
||||
discrepancy = "ok"
|
||||
self.sheet_handler.sheet.update(values=[[discrepancy]], range_name=f"AE{row_num}")
|
||||
|
||||
# Timestamp und Version schreiben
|
||||
# Spalten AF und AG sollen "XX" enthalten
|
||||
self.sheet_handler.sheet.update(values=[["XX"]], range_name="AF" + str(row_num))
|
||||
self.sheet_handler.sheet.update(values=[["XX"]], range_name="AG" + str(row_num))
|
||||
|
||||
# Timestamp und Version
|
||||
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.')}, "
|
||||
f"Branche: {company_data.get('branche', 'k.A.')}, "
|
||||
f"ChatGPT Umsatz: {chatgpt_umsatz}, Umsatz-Abgleich: {abgleich_result}, "
|
||||
debug_print(f"✅ Aktualisiert: URL: {company_data.get('url', 'k.A.')}, "
|
||||
f"Branche: {company_data.get('branche', 'k.A.')}, Umsatz-Abgleich: {abgleich_result}, "
|
||||
f"Validierung: {valid_result}, Branchenvorschlag: {branche_result['branch']}, "
|
||||
f"FSM: {fsm_result['suitability']}, Servicetechniker-Schätzung: {st_estimate}")
|
||||
time.sleep(Config.RETRY_DELAY)
|
||||
|
||||
Reference in New Issue
Block a user