Implementierung der Batch-Brancheneinstufung zur Kostenoptimierung
- FEATURE: Brancheneinstufung erfolgt nun in Batches (z.B. 20 Unternehmen pro API-Call), um die Token-Kosten drastisch zu senken. - REFACTOR: Neue Funktion `evaluate_branches_batch` in `helpers.py` erstellt, die den komplexen Batch-Prompt generiert. - REFACTOR: `reclassify_all_branches` in `data_processor.py` überarbeitet, um die Batch-Verarbeitung und das Ergebnis-Mapping zu steuern.
This commit is contained in:
91
helpers.py
91
helpers.py
@@ -971,6 +971,97 @@ def evaluate_branche_chatgpt(company_name, website_summary, wiki_absatz):
|
|||||||
"justification": f"Fehler bei der API-Kommunikation: {str(e)[:100]}"
|
"justification": f"Fehler bei der API-Kommunikation: {str(e)[:100]}"
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
def evaluate_branches_batch(companies_data):
|
||||||
|
"""
|
||||||
|
Führt eine kontextbasierte Brancheneinstufung für einen Batch von Unternehmen durch.
|
||||||
|
Sendet das Branchenschema nur einmal, um Kosten zu sparen.
|
||||||
|
|
||||||
|
Args:
|
||||||
|
companies_data (list): Eine Liste von Dictionaries, jedes mit 'row_num', 'name', 'summary', 'wiki'.
|
||||||
|
|
||||||
|
Returns:
|
||||||
|
list: Eine Liste von Dictionaries mit den Ergebnissen für jedes Unternehmen.
|
||||||
|
"""
|
||||||
|
logger = logging.getLogger(__name__)
|
||||||
|
|
||||||
|
# 1. Baue das ZIEL-BRANCHENSCHEMA als Textblock auf (wird nur einmal gesendet)
|
||||||
|
schema_text_parts = []
|
||||||
|
for i, (branch, details) in enumerate(Config.BRANCH_GROUP_MAPPING.items()):
|
||||||
|
schema_text_parts.append(f"{i+1}. Branche: {branch}")
|
||||||
|
if details.get("definition"):
|
||||||
|
schema_text_parts.append(f" Definition: {details['definition']}")
|
||||||
|
if details.get("beispiele"):
|
||||||
|
schema_text_parts.append(f" Beispiele: {details['beispiele']}")
|
||||||
|
ziel_branchenschema_text = "\n".join(schema_text_parts)
|
||||||
|
|
||||||
|
# 2. Baue die Liste der Unternehmensprofile für den Prompt auf
|
||||||
|
unternehmensprofile_text_parts = []
|
||||||
|
for i, company in enumerate(companies_data):
|
||||||
|
profil = [f"--- UNTERNEHMEN #{i+1} (Original-Zeilennummer: {company['row_num']}) ---"]
|
||||||
|
profil.append(f"- Name: {company.get('name', 'N/A')}")
|
||||||
|
if company.get('summary'):
|
||||||
|
profil.append(f"- Website-Zusammenfassung: {company['summary']}")
|
||||||
|
if company.get('wiki'):
|
||||||
|
profil.append(f"- Wikipedia-Auszug: {company['wiki']}")
|
||||||
|
unternehmensprofile_text_parts.append("\n".join(profil))
|
||||||
|
|
||||||
|
unternehmensprofile_text = "\n\n".join(unternehmensprofile_text_parts)
|
||||||
|
|
||||||
|
# 3. Baue den Master-Prompt zusammen
|
||||||
|
prompt_parts = [
|
||||||
|
"Du bist ein erfahrener Branchenanalyst. Deine Aufgabe ist es, eine Liste von Unternehmen präzise einer von 54 vordefinierten Branchenkategorien zuzuordnen. Nutze dafür ausschließlich das bereitgestellte ZIEL-BRANCHENSCHEMA.",
|
||||||
|
"\n--- ZIEL-BRANCHENSCHEMA (Deine einzig gültige Wissensbasis) ---",
|
||||||
|
ziel_branchenschema_text,
|
||||||
|
"\n--- ZU ANALYSIERENDE UNTERNEHMEN ---",
|
||||||
|
unternehmensprofile_text,
|
||||||
|
"\n--- DEINE AUFGABE ---",
|
||||||
|
f"Analysiere jedes der {len(companies_data)} Unternehmen Schritt für Schritt.",
|
||||||
|
"Vergleiche jedes Unternehmensprofil mit den Definitionen im ZIEL-BRANCHENSCHEMA.",
|
||||||
|
"Gib als Ergebnis eine JSON-Liste zurück, die exakt ein JSON-Objekt für jedes Unternehmen in der gleichen Reihenfolge enthält.",
|
||||||
|
"Jedes JSON-Objekt muss folgende Schlüssel haben: 'row_num', 'Branche', 'Konfidenz', 'Begruendung'.",
|
||||||
|
"Die 'row_num' muss exakt der 'Original-Zeilennummer' aus dem Input entsprechen.",
|
||||||
|
"Beispiel-Format für die Antwort: \n"
|
||||||
|
'''
|
||||||
|
[
|
||||||
|
{
|
||||||
|
"row_num": 123,
|
||||||
|
"Branche": "Maschinenbau",
|
||||||
|
"Konfidenz": "Hoch",
|
||||||
|
"Begruendung": "Das Unternehmen stellt komplexe Maschinen her, was der Definition entspricht."
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"row_num": 456,
|
||||||
|
"Branche": "Facility Management",
|
||||||
|
"Konfidenz": "Mittel",
|
||||||
|
"Begruendung": "Bietet Dienstleistungen rund um Immobilien an, passt zur Definition."
|
||||||
|
}
|
||||||
|
]
|
||||||
|
'''
|
||||||
|
]
|
||||||
|
prompt = "\n".join(prompt_parts)
|
||||||
|
|
||||||
|
# 4. API-Aufruf
|
||||||
|
try:
|
||||||
|
response_str = call_openai_chat(prompt, temperature=0.0, model="gpt-4o", response_format_json=True)
|
||||||
|
if not response_str:
|
||||||
|
raise APIError("Keine Antwort von OpenAI erhalten.")
|
||||||
|
|
||||||
|
# Das Ergebnis sollte direkt eine Liste von Dictionaries sein
|
||||||
|
results_list = json.loads(response_str)
|
||||||
|
|
||||||
|
# Validierung, ob die Antwort eine Liste ist
|
||||||
|
if not isinstance(results_list, list):
|
||||||
|
logger.error(f"KI-Antwort ist keine Liste, sondern {type(results_list)}. Breche Batch ab.")
|
||||||
|
return None
|
||||||
|
|
||||||
|
return results_list
|
||||||
|
|
||||||
|
except Exception as e:
|
||||||
|
logger.error(f"Endgültiger FEHLER beim Batch-API-Aufruf: {e}")
|
||||||
|
return None
|
||||||
|
|
||||||
|
|
||||||
@retry_on_failure
|
@retry_on_failure
|
||||||
def verify_wiki_article_chatgpt(company_name, parent_name, website, wiki_title, wiki_summary):
|
def verify_wiki_article_chatgpt(company_name, parent_name, website, wiki_title, wiki_summary):
|
||||||
"""
|
"""
|
||||||
|
|||||||
Reference in New Issue
Block a user