diff --git a/helpers.py b/helpers.py index b9c4f2b1..94870b94 100644 --- a/helpers.py +++ b/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]}" } + +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 def verify_wiki_article_chatgpt(company_name, parent_name, website, wiki_title, wiki_summary): """