feat(notion): Finalize relational DB implementation and scripts
- Implement relational data structure in Notion as per the plan. - Add scripts for initial data import (import_product.py) and distribution to related databases (distribute_product_data.py). - Create helper scripts for reading Notion content. - Update Notion_Dashboard.md and GEMINI.md with the latest implementation status, database IDs, and key lessons learned from the MVP phase, including API constraints and schema-first principles.
This commit is contained in:
@@ -1,10 +1,19 @@
|
||||
# import_product.py
|
||||
import requests
|
||||
import json
|
||||
import re
|
||||
import os
|
||||
import time
|
||||
|
||||
# --- Configuration ---
|
||||
NOTION_TOKEN = "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" # This will be replaced by the user's actual token.
|
||||
# NOTION_TOKEN wird jetzt aus der Datei gelesen
|
||||
try:
|
||||
with open("notion_token.txt", "r") as f:
|
||||
NOTION_TOKEN = f.read().strip()
|
||||
except FileNotFoundError:
|
||||
print("Error: notion_token.txt not found.")
|
||||
print("Please create the notion_token.txt file with your Notion integration token.")
|
||||
exit(1)
|
||||
|
||||
NOTION_VERSION = "2022-06-28"
|
||||
NOTION_API_BASE_URL = "https://api.notion.com/v1"
|
||||
|
||||
@@ -23,6 +32,11 @@ DB_IDS = {
|
||||
|
||||
# --- Helper Functions ---
|
||||
|
||||
def clean_json_response(text):
|
||||
if text.startswith("```json") and text.endswith("```"):
|
||||
return text[7:-3].strip()
|
||||
return text
|
||||
|
||||
def create_notion_page(database_id, properties):
|
||||
"""Creates a new page in a Notion database."""
|
||||
url = f"{NOTION_API_BASE_URL}/pages"
|
||||
@@ -43,6 +57,64 @@ def create_notion_page(database_id, properties):
|
||||
print(f"An unexpected error occurred while creating a page: {e}")
|
||||
return None
|
||||
|
||||
def update_notion_page(page_id, properties):
|
||||
"""Updates an existing page in Notion."""
|
||||
url = f"{NOTION_API_BASE_URL}/pages/{page_id}"
|
||||
payload = {
|
||||
"properties": properties
|
||||
}
|
||||
try:
|
||||
response = requests.patch(url, headers=HEADERS, json=payload)
|
||||
response.raise_for_status()
|
||||
print(f"Successfully updated page {page_id}.")
|
||||
return response.json()
|
||||
except requests.exceptions.HTTPError as e:
|
||||
print(f"HTTP Error updating page {page_id}: {e}")
|
||||
print(f"Response content: {response.text}")
|
||||
return None
|
||||
except Exception as e:
|
||||
print(f"An unexpected error occurred while updating a page: {e}")
|
||||
return None
|
||||
|
||||
def find_notion_page_by_title(database_id, title):
|
||||
"""Searches for a page in a Notion database by its title property."""
|
||||
url = f"{NOTION_API_BASE_URL}/databases/{database_id}/query"
|
||||
filter_payload = {
|
||||
"filter": {
|
||||
"property": "Name",
|
||||
"title": {"equals": title}
|
||||
}
|
||||
}
|
||||
try:
|
||||
response = requests.post(url, headers=HEADERS, json=filter_payload)
|
||||
response.raise_for_status()
|
||||
results = response.json().get("results")
|
||||
if results:
|
||||
return results[0] # Return the first matching page
|
||||
return None
|
||||
except requests.exceptions.HTTPError as e:
|
||||
print(f"HTTP Error searching page in DB {database_id}: {e}")
|
||||
print(f"Response content: {response.text}")
|
||||
return None
|
||||
except Exception as e:
|
||||
print(f"An unexpected error occurred while searching for a page: {e}")
|
||||
return None
|
||||
|
||||
def get_database_properties(database_id):
|
||||
"""Retrieves the properties (schema) of a Notion database."""
|
||||
url = f"{NOTION_API_BASE_URL}/databases/{database_id}"
|
||||
try:
|
||||
response = requests.get(url, headers=HEADERS)
|
||||
response.raise_for_status()
|
||||
return response.json().get("properties")
|
||||
except requests.exceptions.HTTPError as e:
|
||||
print(f"HTTP Error retrieving database properties for DB {database_id}: {e}")
|
||||
print(f"Response content: {response.text}")
|
||||
return None
|
||||
except Exception as e:
|
||||
print(f"An unexpected error occurred while retrieving database properties: {e}")
|
||||
return None
|
||||
|
||||
def format_rich_text(text):
|
||||
"""Formats a string into Notion's rich text structure."""
|
||||
return {"rich_text": [{"type": "text", "text": {"content": text}}]}
|
||||
@@ -78,25 +150,50 @@ def main():
|
||||
print("ERROR: 'Puma_m20_2026-01-08.md' not found. Please make sure the file is in the same directory.")
|
||||
return
|
||||
|
||||
# --- Phase 1: Create Product in Product Master ---
|
||||
print("--- Phase 1: Creating Product ---")
|
||||
# Define the product name
|
||||
PRODUCT_NAME = "Puma M20" # This will be replaced by the user's actual product name.
|
||||
|
||||
# --- Phase 1: Prepare Product Data ---
|
||||
print(f"--- Phase 1: Preparing Product Data for {PRODUCT_NAME} ---")
|
||||
product_analysis = extract_section(md_content, "2. Product Analysis")
|
||||
key_features = re.search(r"\*\*Key Features:\*\*(.*?)\*\*Constraints:\*\*", product_analysis, re.S).group(1).strip()
|
||||
constraints = re.search(r"\*\*Constraints:\*\*(.*)", product_analysis, re.S).group(1).strip()
|
||||
|
||||
target_audience = extract_section(md_content, "3. Target Audience")
|
||||
strategy_matrix = extract_section(md_content, "5. Strategy Matrix")
|
||||
if len(strategy_matrix) > 2000:
|
||||
strategy_matrix = strategy_matrix[:2000] # Truncate to 2000 characters
|
||||
print("Warning: 'Strategy Matrix' content truncated to 2000 characters due to Notion API limit.")
|
||||
feature_translator = extract_section(md_content, "FEATURE-TO-VALUE TRANSLATOR (PHASE 9)")
|
||||
|
||||
product_properties = {
|
||||
"Name": format_title("Puma M20"),
|
||||
"Name": format_title(PRODUCT_NAME),
|
||||
"Beschreibung": format_rich_text("Ein geländegängiger, wetterfester Roboter, der für anspruchsvolle Umgebungen konzipiert wurde."),
|
||||
"Spezifikationen": format_rich_text(f"Key Features:\n{key_features}\n\nConstraints:\n{constraints}"),
|
||||
"Key Features": format_rich_text(key_features),
|
||||
"Constraints": format_rich_text(constraints),
|
||||
"Target Audience": format_rich_text(target_audience),
|
||||
"Strategy Matrix": format_rich_text(strategy_matrix),
|
||||
"Feature-to-Value Translator": format_rich_text(feature_translator),
|
||||
"Layer": {"multi_select": [{"name": "Security"}, {"name": "Service"}]}
|
||||
}
|
||||
|
||||
product_page = create_notion_page(DB_IDS["Product Master"], product_properties)
|
||||
if not product_page:
|
||||
print("Failed to create product page. Aborting.")
|
||||
return
|
||||
product_page_id = product_page["id"]
|
||||
print(f"Created Product 'Puma M20' with ID: {product_page_id}")
|
||||
# Check if product already exists
|
||||
existing_product_page = find_notion_page_by_title(DB_IDS["Product Master"], PRODUCT_NAME)
|
||||
product_page_id = None
|
||||
if existing_product_page:
|
||||
product_page_id = existing_product_page["id"]
|
||||
print(f"Product '{PRODUCT_NAME}' already exists with ID: {product_page_id}. Updating...")
|
||||
updated_page = update_notion_page(product_page_id, product_properties)
|
||||
if not updated_page:
|
||||
print("Failed to update product page. Aborting.")
|
||||
return
|
||||
else:
|
||||
print(f"Product '{PRODUCT_NAME}' not found. Creating new page...")
|
||||
new_product_page = create_notion_page(DB_IDS["Product Master"], product_properties)
|
||||
if not new_product_page:
|
||||
print("Failed to create product page. Aborting.")
|
||||
return
|
||||
product_page_id = new_product_page["id"]
|
||||
print(f"Created Product '{PRODUCT_NAME}' with ID: {product_page_id}")
|
||||
|
||||
|
||||
# --- Phase 2: Create Sectors in Sector & Persona Master ---
|
||||
|
||||
Reference in New Issue
Block a user