201 lines
8.3 KiB
Python
201 lines
8.3 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"
|
|
}
|
|
|
|
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_id(db_id, title_col, title_val):
|
|
url = f"https://api.notion.com/v1/databases/{db_id}/query"
|
|
payload = {
|
|
"filter": {
|
|
"property": title_col,
|
|
"title": {"equals": title_val}
|
|
}
|
|
}
|
|
resp = requests.post(url, headers=HEADERS, json=payload)
|
|
if resp.status_code == 200:
|
|
results = resp.json().get("results", [])
|
|
if results:
|
|
return results[0] # Return full page obj to access props
|
|
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 {page_id}")
|
|
else:
|
|
print(f"❌ Error updating {page_id}: {resp.text}")
|
|
|
|
def append_text(current_text, new_text):
|
|
if not current_text:
|
|
return new_text
|
|
if new_text in current_text:
|
|
return current_text # Avoid duplicates
|
|
return f"{current_text}\n\n[Auto-Update]: {new_text}"
|
|
|
|
# --- DATA TO UPDATE ---
|
|
|
|
# 1. Personas (KPIs)
|
|
PERSONA_UPDATES = {
|
|
"Wirtschaftlicher Entscheider": "10-25% Reduktion Personalkosten\n15-30% höhere Gästezufriedenheit (Hypothese)",
|
|
"Operativer Entscheider": "20-40% Entlastung bei Routineaufgaben\n100% Abdeckung Reinigungszyklen",
|
|
"Infrastruktur-Verantwortlicher": "20-30% schnellere Integration\n80-90% weniger Ausfallzeiten",
|
|
"Innovations-Treiber": "10-20% höhere Servicekapazität\nSteigerung Upselling 5-10%"
|
|
}
|
|
|
|
# 2. Industries (Pains/Gains/Status/Notes)
|
|
INDUSTRY_UPDATES = {
|
|
"Healthcare - Hospital": {
|
|
"pains_add": "Mangelnde Hygiene-Standards durch Personalengpässe (Infektionsrisiko). Hoher Dokumentationsaufwand für Audits.",
|
|
"gains_add": "Konstante, audit-sichere Sauberkeit (24/7). Entlastung des Reinigungspersonals.",
|
|
"status": "Freigegeben",
|
|
"note_add": "Prio 1: Reinigung (Alex Veto). Service ist 'nice to have'. KPI: Hygiene-Sicherheit.",
|
|
"ops_focus": True # Checkbox
|
|
},
|
|
"Healthcare - Care Home": {
|
|
"pains_add": "Mangelnde Hygiene-Standards. Steigende Personalkosten bei begrenzten Pflegesätzen.",
|
|
"gains_add": "Sichtbare Hygiene schafft Vertrauen. Entlastung Housekeeping.",
|
|
"status": "Freigegeben",
|
|
"note_add": "Prio 1: Reinigung. Prio 2: Service (Essen). Fokus auf Fachkräftemangel.",
|
|
"ops_focus": True
|
|
},
|
|
"Hospitality - Gastronomy": {
|
|
"pains_add": "Lobby-Optik leidet bei Personalmangel.",
|
|
"gains_add": "Makellose Optik für den ersten Eindruck.",
|
|
"status": "Freigegeben",
|
|
"note_add": "Prio 1: Reinigung (Nachts). Service nur in Entertainment-Gastro.",
|
|
"ops_focus": False
|
|
},
|
|
"Leisure - Entertainment": {
|
|
"pains_add": "Service-Personal fehlt für Umsatz (Getränke).",
|
|
"gains_add": "Mehr Umsatz durch konstante Verfügbarkeit.",
|
|
"status": "Freigegeben",
|
|
"note_add": "Prio 1: Service Robotik (BellaBot).",
|
|
"ops_focus": False
|
|
},
|
|
"Industry - Manufacturing": {
|
|
"pains_add": "Staubbelastung gefährdet Sensoren/Qualität. Sicherheitsrisiko auf Fahrwegen.",
|
|
"gains_add": "Staubfreie Umgebung ohne Produktionsstopp.",
|
|
"status": "Freigegeben",
|
|
"note_add": "Prio 1: Reinigung (Sweeper). Kein Stapler-Kampf!",
|
|
"ops_focus": True
|
|
},
|
|
"Logistics - Warehouse": {
|
|
"pains_add": "Staub auf Waren. Manuelles Kehren bindet Fachkräfte.",
|
|
"gains_add": "Werterhalt Hallenboden. Sauberkeit ohne Störung.",
|
|
"status": "Freigegeben",
|
|
"note_add": "Prio 1: Sweeper (Staub). Prio 2: Wet.",
|
|
"ops_focus": True
|
|
}
|
|
}
|
|
|
|
|
|
def run_updates():
|
|
print("--- Starting Notion Updates ---")
|
|
|
|
# 1. Update Personas
|
|
db_personas = find_db_id("Personas")
|
|
if db_personas:
|
|
print(f"Found Personas DB: {db_personas}")
|
|
for role, kpi_text in PERSONA_UPDATES.items():
|
|
page = get_page_id(db_personas, "Role", role) # Title col is "Role" here? Or "Name"? Script 1 said Role fallback.
|
|
# Actually, let's try "Name" first, then "Role".
|
|
# In previous dump, 'Name' was 'Infrastruktur-Verantwortlicher' etc.
|
|
# Let's assume the main column is "Name" (title).
|
|
if not page:
|
|
# Try finding by property "Role" (select) if title is different?
|
|
# Based on dump, the Title column content was "Infrastruktur-Verantwortlicher".
|
|
# Let's assume title property is named "Name" or "Role".
|
|
# Inspecting schema from previous run: `['Rollenbeschreibung', '...Product Categories', ... 'Role']`
|
|
# The Title property is likely "Role" or "Name".
|
|
# Let's try searching for "Role" property as title.
|
|
page = get_page_id(db_personas, "Role", role)
|
|
|
|
if page:
|
|
# Update KPIs
|
|
# Column name in schema: "KPIs"
|
|
update_page(page['id'], {
|
|
"KPIs": {"rich_text": [{"text": {"content": kpi_text}}]}
|
|
})
|
|
else:
|
|
print(f"⚠️ Persona '{role}' not found.")
|
|
else:
|
|
print("❌ Personas DB not found.")
|
|
|
|
# 2. Update Industries
|
|
db_ind = find_db_id("Industries")
|
|
if db_ind:
|
|
print(f"Found Industries DB: {db_ind}")
|
|
for vertical, data in INDUSTRY_UPDATES.items():
|
|
page = get_page_id(db_ind, "Vertical", vertical)
|
|
if page:
|
|
props = page['properties']
|
|
|
|
# Prepare updates
|
|
new_props = {}
|
|
|
|
# Status
|
|
# Check if Status is select or status
|
|
if "Freigabe" in props:
|
|
# Assuming Select or Status. Let's try Select first, if fails try Status
|
|
if props["Freigabe"]["type"] == "select":
|
|
new_props["Freigabe"] = {"select": {"name": data["status"]}}
|
|
elif props["Freigabe"]["type"] == "status":
|
|
new_props["Freigabe"] = {"status": {"name": data["status"]}}
|
|
|
|
# Ops Focus (Checkbox)
|
|
if "Ops Focus: Secondary" in props:
|
|
new_props["Ops Focus: Secondary"] = {"checkbox": data["ops_focus"]}
|
|
|
|
# Pains (Append)
|
|
current_pains = ""
|
|
if "Pains" in props and props["Pains"]["rich_text"]:
|
|
current_pains = props["Pains"]["rich_text"][0]["plain_text"]
|
|
new_pains = append_text(current_pains, data["pains_add"])
|
|
new_props["Pains"] = {"rich_text": [{"text": {"content": new_pains}}]}
|
|
|
|
# Gains (Append)
|
|
current_gains = ""
|
|
if "Gains" in props and props["Gains"]["rich_text"]:
|
|
current_gains = props["Gains"]["rich_text"][0]["plain_text"]
|
|
new_gains = append_text(current_gains, data["gains_add"])
|
|
new_props["Gains"] = {"rich_text": [{"text": {"content": new_gains}}]}
|
|
|
|
# Notes (Append)
|
|
current_notes = ""
|
|
if "Notes" in props and props["Notes"]["rich_text"]:
|
|
current_notes = props["Notes"]["rich_text"][0]["plain_text"]
|
|
new_notes = append_text(current_notes, data["note_add"])
|
|
new_props["Notes"] = {"rich_text": [{"text": {"content": new_notes}}]}
|
|
|
|
# Execute Update
|
|
update_page(page['id'], new_props)
|
|
|
|
else:
|
|
print(f"⚠️ Industry '{vertical}' not found.")
|
|
else:
|
|
print("❌ Industries DB not found.")
|
|
|
|
if __name__ == "__main__":
|
|
run_updates()
|