feat(agent): Impressum-Tab auf Haupt-Engine + Profil/§36-Fixes
Ergebnis-Tab rendert jetzt result.results (Haupt-Doc-Check) statt des abweichenden v3-Agenten — BMW korrekt statt False Positives: - DocResultView: ein Dokument als Pflichtangaben-Tabelle (Label + gefundener Text + 3-Tier-Status), KEINE MC-IDs. ComplianceResultTabs speist Tabs aus result.results; ChecklistView-Bausteine exportiert + wiederverwendet. - profile_extractor: Firmenname/Rechtsform = fruehester Treffer + ausge- schriebene Formen (Aktiengesellschaft) -> BMW AG statt "juris GmbH". - 36 VSBG (MC-010): reines b2c -> POSSIBLY_APPLICABLE (Pruef-Hinweis) statt MEDIUM-FAIL; hart nur bei ecommerce. possibly_hint pro MC. - McCoverage traegt label + found (Snippet); mc_possibly-Aggregat. - AgentFindingCard/Methodik: interne check_id/mc_id nicht mehr angezeigt. Tests: test_four_status (16) + Frontend-Vitest gruen; CI-Suite 206, v3/GT unveraendert. Nur eigene Dateien (geteilter Tree). Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
This commit is contained in:
@@ -10,13 +10,14 @@ Returns a dict that maps to CompanyProfile and ScopeProfilingAnswer fields.
|
||||
|
||||
import logging
|
||||
import re
|
||||
from typing import Optional
|
||||
|
||||
logger = logging.getLogger(__name__)
|
||||
|
||||
|
||||
def extract_profile_from_documents(
|
||||
doc_texts: dict[str, str],
|
||||
business_profile: dict | None = None,
|
||||
business_profile: Optional[dict] = None,
|
||||
) -> dict:
|
||||
"""Extract Company Profile fields from document texts.
|
||||
|
||||
@@ -100,28 +101,38 @@ def _extract_company_info(text: str, result: dict) -> None:
|
||||
"""Extract company name, legal form, address from text."""
|
||||
cp = result["company_profile"]
|
||||
|
||||
# GmbH / AG / UG / e.K. etc.
|
||||
legal_forms = {
|
||||
r"(\S+(?:\s+\S+){0,4})\s+gmbh\b": ("GmbH", "gmbh"),
|
||||
r"(\S+(?:\s+\S+){0,4})\s+ag\b": ("AG", "ag"),
|
||||
r"(\S+(?:\s+\S+){0,4})\s+ug\b": ("UG", "ug"),
|
||||
r"(\S+(?:\s+\S+){0,4})\s+e\.?\s*k\.?\b": ("e.K.", "ek"),
|
||||
r"(\S+(?:\s+\S+){0,4})\s+gbr\b": ("GbR", "gbr"),
|
||||
r"(\S+(?:\s+\S+){0,4})\s+ohg\b": ("OHG", "ohg"),
|
||||
r"(\S+(?:\s+\S+){0,4})\s+gmbh\s*&\s*co\.?\s*kg": ("GmbH & Co. KG", "gmbh_co_kg"),
|
||||
}
|
||||
# Rechtsform + Firmenname. Die Reihenfolge der Muster ist NICHT die
|
||||
# Priorität — wir nehmen den FRUEHESTEN Treffer im Text: ein Impressum
|
||||
# nennt den Betreiber zuerst; spätere Erwähnungen (z.B. "juris GmbH" im
|
||||
# Hinweis auf gesetze-im-internet.de) sind nicht der Anbieter. Ausge-
|
||||
# schriebene Formen ("Aktiengesellschaft") zählen mit (sonst wird BMW AG
|
||||
# nicht erkannt und faelschlich die naechste GmbH gegriffen).
|
||||
legal_forms = [
|
||||
(r"(\S+(?:\s+\S+){0,4})\s+gmbh\s*&\s*co\.?\s*kg\b", "gmbh_co_kg"),
|
||||
(r"(\S+(?:\s+\S+){0,4})\s+(?:aktiengesellschaft|ag)\b", "ag"),
|
||||
(r"(\S+(?:\s+\S+){0,4})\s+(?:unternehmergesellschaft|ug)\b", "ug"),
|
||||
(r"(\S+(?:\s+\S+){0,4})\s+gmbh\b", "gmbh"),
|
||||
(r"(\S+(?:\s+\S+){0,4})\s+e\.?\s*k\.?\b", "ek"),
|
||||
(r"(\S+(?:\s+\S+){0,4})\s+gbr\b", "gbr"),
|
||||
(r"(\S+(?:\s+\S+){0,4})\s+ohg\b", "ohg"),
|
||||
]
|
||||
text_lower = text.lower()
|
||||
for pattern, (form_label, form_id) in legal_forms.items():
|
||||
best = None # (start, end, form_id) — frühester Treffer
|
||||
for pattern, form_id in legal_forms:
|
||||
m = re.search(pattern, text_lower)
|
||||
if m:
|
||||
raw_name = m.group(0).strip()
|
||||
# Clean up: take from uppercase start
|
||||
for i, ch in enumerate(text[m.start():m.end()]):
|
||||
if ch.isupper():
|
||||
cp["companyName"] = text[m.start() + i:m.end()].strip()
|
||||
break
|
||||
cp["legalForm"] = form_id
|
||||
break
|
||||
# frühester Treffer gewinnt; bei Gleichstand die Listen-Reihenfolge
|
||||
# (GmbH & Co. KG vor GmbH).
|
||||
if m and (best is None or m.start() < best[0]):
|
||||
best = (m.start(), m.end(), form_id)
|
||||
if best:
|
||||
start, end, form_id = best
|
||||
# Firmenname ab dem ersten Grossbuchstaben im Treffer (schneidet
|
||||
# führende Kleinwörter wie "von der" ab).
|
||||
for i, ch in enumerate(text[start:end]):
|
||||
if ch.isupper():
|
||||
cp["companyName"] = text[start + i:end].strip()
|
||||
break
|
||||
cp["legalForm"] = form_id
|
||||
|
||||
# PLZ + Ort
|
||||
plz_match = re.search(
|
||||
|
||||
Reference in New Issue
Block a user