Files
Brancheneinstufung2/scripts/enrich_notion_pains.py
2026-02-17 19:44:42 +00:00

266 lines
12 KiB
Python

import os
import requests
import json
from dotenv import load_dotenv
load_dotenv(dotenv_path="/home/node/clawd/.env")
NOTION_TOKEN = os.getenv("NOTION_API_KEY")
HEADERS = {
"Authorization": f"Bearer {NOTION_TOKEN}",
"Content-Type": "application/json",
"Notion-Version": "2022-06-28"
}
# --- Load Product Mapping ---
try:
with open("data/product_mapping.json", "r") as f:
PRODUCT_MAP = json.load(f)
except FileNotFoundError:
print("❌ Product mapping not found. Run fetch_product_mapping.py first.")
exit(1)
# Helper to find DB ID
def find_db_id(query_name):
url = "https://api.notion.com/v1/search"
payload = {"query": query_name, "filter": {"value": "database", "property": "object"}}
resp = requests.post(url, headers=HEADERS, json=payload)
if resp.status_code == 200:
results = resp.json().get("results", [])
if results:
return results[0]['id']
return None
def get_page_by_vertical(db_id, vertical_name):
url = f"https://api.notion.com/v1/databases/{db_id}/query"
# Using 'Vertical' as the title property name based on previous audit
payload = {
"filter": {
"property": "Vertical",
"title": {"equals": vertical_name}
}
}
resp = requests.post(url, headers=HEADERS, json=payload)
if resp.status_code == 200:
results = resp.json().get("results", [])
if results:
return results[0]
return None
def update_page(page_id, properties):
url = f"https://api.notion.com/v1/pages/{page_id}"
payload = {"properties": properties}
resp = requests.patch(url, headers=HEADERS, json=payload)
if resp.status_code == 200:
print(f"✅ Updated '{page_id}'")
else:
print(f"❌ Error updating '{page_id}': {resp.text}")
def create_page(db_id, properties):
url = "https://api.notion.com/v1/pages"
payload = {"parent": {"database_id": db_id}, "properties": properties}
resp = requests.post(url, headers=HEADERS, json=payload)
if resp.status_code == 200:
print(f"✅ Created new page")
else:
print(f"❌ Error creating page: {resp.text}")
# --- CONTENT DEFINITION ---
# Format: Vertical -> { props... }
UPDATES = {
"Healthcare - Care Home": {
"product": "Cleaning Indoor Roboter (Wet Surface)",
"pains": """[Primary Product: Cleaning]
- Infektionsrisiko: Mangelnde Bodenhygiene und Keimverschleppung in sensiblen Bereichen gefährden Bewohner.
- Dokumentationspflicht: Lückenlose Nachweise für Hygiene-Audits binden wertvolle Pflegezeit.
- Personalmangel: Reinigungskräfte fehlen, Standards können manuell kaum gehalten werden.
[Secondary Product: Service]
- Pflegeressourcen: Fachkräfte binden bis zu 30% ihrer Zeit mit nicht-pflegerischen Transportwegen (Essen/Wäsche).
- Körperliche Belastung: Schweres Heben und weite Wege führen zu krankheitsbedingten Ausfällen im Pflegeteam.""",
"gains": """[Primary Product: Cleaning]
- Audit-Sicherheit: Automatisierte, protokollierte Reinigung sichert Compliance ohne Mehraufwand.
- Entlastung Housekeeping: Personal konzentriert sich auf Sichtreinigung und Desinfektion statt Bodenfläche.
[Secondary Product: Service]
- Mehr Zeit am Patienten: Reduktion der Laufwege gibt Pflegekräften 2-3 Std./Schicht zurück.
- Mitarbeiterzufriedenheit: Reduktion körperlicher Belastung senkt Krankenstand.""",
"ops_focus": True,
"status": "Freigegeben",
"notes": "Prio 1: Reinigung. Prio 2: Service (Essen). Fokus auf Fachkräftemangel & Hygiene."
},
"Healthcare - Hospital": {
"product": "Cleaning Indoor Roboter (Wet Surface)",
"pains": """[Primary Product: Cleaning]
- Infektionsschutz: Hohe Frequenz an Patientenbewegungen erfordert permanente Desinfektion der Böden.
- Audit-Druck: Behördliche Auflagen verlangen lückenlose Dokumentation, die manuell kaum leistbar ist.
- Kostendruck: Steigende Personalkosten bei fixen Fallpauschalen zwingen zur Effizienzsteigerung.
[Secondary Product: Service]
- Logistik-Aufwand: Transport von Proben, Wäsche und Essen bindet Pflegepersonal in unproduktiven Wegezeiten.""",
"gains": """[Primary Product: Cleaning]
- Hygiene-Standard: 24/7 gleichbleibende Reinigungsqualität reduziert Keimbelastung messbar.
- Compliance: Automatische Protokollierung aller Reinigungsfahrten für Audits.
[Secondary Product: Service]
- Prozess-Effizienz: Automatisierter Warentransport entlastet Fachpersonal für medizinische Aufgaben.""",
"ops_focus": True,
"status": "Freigegeben",
"notes": "Prio 1: Reinigung (Alex Veto). Service ist 'nice to have'. KPI: Hygiene-Sicherheit."
},
"Leisure - Entertainment": {
"product": "Service Roboter", # FIX: Changed from Cleaning to Service
"pains": """[Primary Product: Service]
- Service-Engpass: Umsatzverlust zu Stoßzeiten, da Personal nicht schnell genug Getränke/Snacks nachliefert.
- Personalmangel: Schwierige Besetzung von Spätschichten führt zu geschlossenen Stationen/Bahnen.
- Wartezeiten: Gäste sind unzufrieden, wenn Bestellungen zu lange dauern.
[Secondary Product: Cleaning]
- Bodenverschmutzung: Klebrige Böden (Getränke/Popcorn) im Foyer stören das Gästeerlebnis.""",
"gains": """[Primary Product: Service]
- Umsatzsteigerung: Permanente Verfügbarkeit von Snacks/Getränken direkt am Platz (Cross-Selling).
- Erlebnis-Faktor: Innovative Roboter begeistern Gäste und fördern Social-Media-Sichtbarkeit.
- Entlastung: Servicepersonal hat mehr Zeit für Gästebetreuung statt Laufwege.""",
"ops_focus": True, # Keep secondary focus plausible
"status": "Freigegeben",
"notes": "Prio 1: Service Robotik (BellaBot). Cleaning nur Prio 2 (Foyer/Gänge)."
},
"Logistics - Warehouse": {
"product": "Cleaning Outdoor Roboter (Sweeper)",
"pains": """[Primary Product: Sweeper]
- Prozesssicherheit: Staub auf Sensoren und Lichtschranken führt zu Anlagenstörungen und Produktionsstopps.
- Arbeitssicherheit: Verschmutzte Fahrwege durch Palettenreste/Staub erhöhen das Unfallrisiko.
- Manuelle Bindung: Fachkräfte müssen kehren statt kommissionieren.
[Secondary Product: Cleaning Wet]
- Hartnäckige Verschmutzungen: Öl/Reifenabrieb erfordern Nassreinigung, die manuell zeitintensiv ist.""",
"gains": """[Primary Product: Sweeper]
- Staubfreie Umgebung: Werterhalt des Hallenbodens und Schutz empfindlicher Ware/Anlagen.
- Produktivität: Reinigung erfolgt parallel zum Betrieb oder nachts, ohne Störung.
- Sicherheit: Saubere Fahrwege reduzieren Unfallrisiko für Flurförderzeuge.""",
"ops_focus": True,
"status": "Freigegeben",
"notes": "Prio 1: Sweeper (Staub). Prio 2: Wet. Transport schwierig wegen Paletten."
},
"Tech - Data Center": {
"product": "Security Roboter",
"pains": """[Primary Product: Security]
- Sicherheitsrisiko: Unbefugter Zutritt in Sicherheitsbereiche muss lückenlos detektiert werden (24/7).
- Personalbindung: Wachpersonal ist teuer und kann nicht überall gleichzeitig sein.
[Secondary Product: Cleaning]
- Feinstaub: Staubpartikel in Serverräumen gefährden Hardware und Kühlung.""",
"gains": """[Primary Product: Security]
- Lückenlose Überwachung: Permanente Patrouille und sofortige Alarmierung ohne Personalbindung.
- Dokumentation: Video- und Sensorprotokolle aller Ereignisse.
[Secondary Product: Cleaning]
- Ausfallsicherheit: Staubfreie Umgebung verlängert Hardware-Lebensdauer.""",
"ops_focus": True,
"status": "Klärrungsbedarf", # New, needs review
"notes": "Neu angelegt. Prio 1 Security (lt. Transkript). Prio 2 Cleaning (Staub)."
},
"Reinigungsdienstleister": {
"product": "Cleaning Indoor Roboter (Wet Surface)",
"pains": """[Primary Product: Cleaning]
- Personalmangel: Schwierigkeit, zuverlässiges Personal für alle Objekte zu finden.
- Kostendruck: Geringe Margen bei Ausschreibungen erfordern hohe Effizienz.
- Qualitätsschwankungen: Manuelle Reinigung variiert stark, Kunden beschweren sich.
- Fluktuation: Hoher Aufwand für ständige Neueinarbeitung.""",
"gains": """[Primary Product: Cleaning]
- Skalierbarkeit: Roboter übernehmen Flächenleistung, Personal macht Detailreinigung.
- Innovation: Wettbewerbsvorteil bei Ausschreibungen durch Technologie-Einsatz.
- Kalkulationssicherheit: Fixe Kosten statt variabler Personalkosten/Krankheitstage.""",
"ops_focus": False,
"status": "Klärrungsbedarf",
"notes": "Neu angelegt. Zielgruppe: Wisag, Dussmann etc. (Alex: Größter Markt)."
},
"Infrastructure - Communities": {
"product": "Cleaning Indoor Roboter (Wet Surface)",
"pains": """[Primary Product: Cleaning]
- Großflächen-Reinigung: Sporthallen, Aulen und Flure binden enorm viele Personalstunden.
- Budget-Druck: Kommunen müssen sparen, Reinigungskosten sind großer Posten.
- Nutzungs-Konflikte: Reinigung muss in engen Zeitfenstern zwischen Schul/Vereinsnutzung erfolgen.""",
"gains": """[Primary Product: Cleaning]
- Kosteneffizienz: Reduktion der Reinigungskosten pro Quadratmeter.
- Flexibilität: Reinigung kann nachts oder in Randzeiten erfolgen.
- Werterhalt: Schonende, regelmäßige Reinigung verlängert Lebensdauer von Sportböden.""",
"ops_focus": False,
"status": "Klärrungsbedarf",
"notes": "Neu angelegt (Schulen, Gemeinden)."
},
"Infrastructure Parking": {
"product": "Cleaning Outdoor Roboter (Sweeper)",
"pains": """[Primary Product: Sweeper]
- Außenwirkung: Verschmutzte Parkflächen/Müll schaden dem Image (erster Eindruck).
- Manuelle Arbeit: Fegen von großen Außenflächen ist personalintensiv und unbeliebt.
- Umwelt: Müll gelangt in die Umgebung/Kanalisation.""",
"gains": """[Primary Product: Sweeper]
- Gepflegtes Erscheinungsbild: Täglich saubere Außenanlagen.
- Autonomie: Roboter reinigt selbstständig, auch bei schlechtem Wetter.
- Entlastung: Hausmeister kann sich um Wartung kümmern statt Fegen.""",
"ops_focus": False,
"status": "Klärrungsbedarf",
"notes": "Neu angelegt (Parkplätze, Außenanlagen)."
}
}
def run_enrichment():
db_id = find_db_id("Industries")
if not db_id:
print("❌ Industries DB not found.")
return
print(f"--- Enriching Verticals in DB {db_id} ---")
for vertical, data in UPDATES.items():
# Resolve Product ID
prod_id = PRODUCT_MAP.get(data["product"])
if not prod_id:
print(f"❌ Product '{data['product']}' not found in map. Skipping {vertical}.")
continue
# Prepare Properties
props = {
"Pains": {"rich_text": [{"text": {"content": data["pains"]}}]},
"Gains": {"rich_text": [{"text": {"content": data["gains"]}}]},
"Primary Product Category": {"relation": [{"id": prod_id}]},
"Notes": {"rich_text": [{"text": {"content": data["notes"]}}]},
# Handle Status (Try Select first, then Status)
# We assume "Freigabe" exists
}
# Add checkbox if present in logic
if "ops_focus" in data:
props["Ops Focus: Secondary"] = {"checkbox": data["ops_focus"]}
# Check if page exists
page = get_page_by_vertical(db_id, vertical)
if page:
# Update existing
# Add Status Update
# (Note: Logic to detect Select vs Status type is needed, but we assume Select/Status name is consistent)
# For robustness, we check the property type in the page object
status_type = page['properties'].get("Freigabe", {}).get("type")
if status_type == "status":
props["Freigabe"] = {"status": {"name": data["status"]}}
elif status_type == "select":
props["Freigabe"] = {"select": {"name": data["status"]}}
print(f"Updating '{vertical}'...")
update_page(page['id'], props)
else:
# Create new
print(f"Creating new vertical '{vertical}'...")
props["Vertical"] = {"title": [{"text": {"content": vertical}}]}
# Guess status type (usually Select or Status) - Try Status first as default in new Notion DBs
# Or omit status if unsure, but we want to set it.
# We'll try Status format.
props["Freigabe"] = {"status": {"name": data["status"]}}
create_page(db_id, props)
if __name__ == "__main__":
run_enrichment()