feat(notion): Implement relational Competitive Radar import
- Added import_relational_radar.py for bidirectional database structure in Notion. - Added refresh_references.py to populate analysis data with grounded facts via scraping. - Updated documentation for Competitive Radar v2.0.
This commit is contained in:
@@ -69,12 +69,15 @@ Die App ist unter `/ca/` voll funktionsfähig und verfügt nun über eine "Groun
|
||||
* **Map-Reduce:** Statt eines Riesen-Prompts werden Konkurrenten parallel einzeln analysiert. Das skaliert linear.
|
||||
* **Logging:** Ein spezieller `log_debug` Helper schreibt direkt in `/app/Log_from_docker`, um Python-Logging-Probleme zu umgehen.
|
||||
|
||||
### Lessons Learned für die Ewigkeit
|
||||
### 📊 Relationaler Notion Import (Competitive Radar v2.0)
|
||||
Um die Analyse-Ergebnisse optimal nutzbar zu machen, wurde ein bidirektionaler Import-Prozess nach Notion implementiert (`import_relational_radar.py`).
|
||||
|
||||
* **Architektur:** Statt Textblöcken werden drei vernetzte Datenbanken erstellt:
|
||||
1. **📦 Companies (Hub):** Stammdaten, USPs, Portfolio.
|
||||
2. **💣 Landmines (Satellite):** Einzelfragen und Angriffsvektoren, verknüpft mit der Company.
|
||||
3. **🏆 References (Satellite):** Konkrete Kundenprojekte, verknüpft mit der Company.
|
||||
* **Dual-Way Relations:** Dank `dual_property` Konfiguration sind die Verknüpfungen in Notion sofort in beide Richtungen navigierbar (z.B. sieht man auf der Company-Seite sofort alle zugehörigen Landmines).
|
||||
* **Daten-Qualität:** Durch die Map-Reduce Analyse und das gezielte Reference-Scraping werden nun echte Fakten statt KI-Halluzinationen importiert.
|
||||
|
||||
1. **F-STRINGS SIND VERBOTEN** für Prompts und komplexe Listen-Operationen.
|
||||
2. **TRIPLE RAW QUOTES (`r"""..."""`)** sind der einzige sichere Weg für Strings in Docker-Umgebungen.
|
||||
3. **DUAL SDK STRATEGY:** Legacy SDK für Stabilität (`gemini-2.0-flash`), Modern SDK für Spezial-Features.
|
||||
4. **MAP-REDUCE:** Bei Listen > 3 Elementen niemals das LLM bitten, "alle auf einmal" zu bearbeiten. Immer zerlegen (Map) und aggregieren (Reduce).
|
||||
5. **SCHEMA FIRST:** Frontend (`types.ts`) und Backend (`Pydantic`) müssen *vorher* abgeglichen werden. `422` bedeutet fast immer Schema-Mismatch.
|
||||
---
|
||||
*Dokumentation aktualisiert am 11.01.2026 nach erfolgreicher Skalierung auf 9+ Konkurrenten.*
|
||||
*Dokumentation aktualisiert am 11.01.2026 nach Implementierung des relationalen Competitive Radars.*
|
||||
|
||||
@@ -39,10 +39,11 @@ Die Schaltstelle für die hyper-personalisierte Ansprache.
|
||||
* **Logik:** Trennung in **Satz 1** (Individueller Hook basierend auf der aktuellen Website-Analyse des Zielkunden) und **Satz 2** (Relationaler Lösungsbaustein basierend auf Branche + Produkt).
|
||||
* **Voice-Ready:** Vorbereitung von Skripten für den zukünftigen Voice-KI-Einsatz im Vertrieb und Support.
|
||||
|
||||
### 3.4 Competitive Radar (Market Intelligence)
|
||||
Automatisierte Überwachung der Marktbegleiter.
|
||||
* **Funktion:** Kontinuierliches Scraping von Wettbewerber-News und Blogposts.
|
||||
* **Kill-Argumente:** Direkte Gegenüberstellung technischer Specs zur Erstellung von Battlecards für den Sales-Außendienst.
|
||||
### 3.4 Competitive Radar (Market Intelligence v2.0)
|
||||
Automatisierte Überwachung der Marktbegleiter mit Fokus auf "Grounded Truth".
|
||||
* **Funktion:** Kontinuierliches Scraping von Wettbewerber-Webseiten, gezielte Suche nach Referenzkunden und Case Studies.
|
||||
* **Kill-Argumente & Landmines:** Erstellung von strukturierten Battlecards und spezifischen "Landmine Questions" für den Sales-Außendienst.
|
||||
* **Relationaler Ansatz:** Trennung in drei verknüpfte Datenbanken (Firmen, Landmines, Referenzen) für maximale Filterbarkeit und Übersicht.
|
||||
|
||||
### 3.5 Enrichment Factory & RevOps
|
||||
Datenanreicherung der CRM-Accounts.
|
||||
@@ -90,6 +91,8 @@ Um die relationale Integrität zu wahren, sind folgende Datenbanken in Notion zw
|
||||
* **Product Master** $\leftrightarrow$ **Sector Master** (Welcher Roboter passt in welchen Markt?)
|
||||
* **Messaging Matrix** $\leftrightarrow$ **Product Master** (Welche Lösung gehört zum Text?)
|
||||
* **Messaging Matrix** $\leftrightarrow$ **Sector Master** (Welcher Schmerz gehört zu welcher Branche?)
|
||||
* **Competitive Radar (Companies)** $\leftrightarrow$ **Competitive Radar (Landmines)** (Welche Angriffsfragen gehören zu welchem Wettbewerber?)
|
||||
* **Competitive Radar (Companies)** $\leftrightarrow$ **Competitive Radar (References)** (Welche Kundenprojekte hat der Wettbewerber realisiert?)
|
||||
* **The Brain** $\leftrightarrow$ **Product Master** (Welches Support-Wissen gehört zu welcher Hardware?)
|
||||
* **GTM Workspace** $\leftrightarrow$ **Product Master** (Welche Kampagne bewirbt welches Gerät?)
|
||||
* **Feature-to-Value Translator** $\leftrightarrow$ **Product Master** (Welcher Nutzen gehört zu welchem Feature?)
|
||||
|
||||
200
import_competitors_to_notion.py
Normal file
200
import_competitors_to_notion.py
Normal file
@@ -0,0 +1,200 @@
|
||||
import json
|
||||
import os
|
||||
import requests
|
||||
import sys
|
||||
|
||||
# Configuration
|
||||
JSON_FILE = 'analysis_robo-planet.de.json'
|
||||
TOKEN_FILE = 'notion_token.txt'
|
||||
# Root Page ID from notion_integration.md
|
||||
PARENT_PAGE_ID = "2e088f42-8544-8024-8289-deb383da3818"
|
||||
DB_TITLE = "Competitive Radar 🎯"
|
||||
|
||||
def load_json_data(filepath):
|
||||
try:
|
||||
with open(filepath, 'r') as f:
|
||||
return json.load(f)
|
||||
except Exception as e:
|
||||
print(f"Error loading JSON: {e}")
|
||||
sys.exit(1)
|
||||
|
||||
def load_notion_token(filepath):
|
||||
try:
|
||||
with open(filepath, 'r') as f:
|
||||
return f.read().strip()
|
||||
except Exception as e:
|
||||
print(f"Error loading token: {e}")
|
||||
sys.exit(1)
|
||||
|
||||
def create_competitor_database(token, parent_page_id):
|
||||
url = "https://api.notion.com/v1/databases"
|
||||
headers = {
|
||||
"Authorization": f"Bearer {token}",
|
||||
"Notion-Version": "2022-06-28",
|
||||
"Content-Type": "application/json"
|
||||
}
|
||||
|
||||
payload = {
|
||||
"parent": {"type": "page_id", "page_id": parent_page_id},
|
||||
"title": [{"type": "text", "text": {"content": DB_TITLE}}],
|
||||
"properties": {
|
||||
"Competitor Name": {"title": {}},
|
||||
"Website": {"url": {}},
|
||||
"Target Industries": {"multi_select": {}},
|
||||
"USPs / Differentiators": {"rich_text": {}},
|
||||
"Silver Bullet": {"rich_text": {}},
|
||||
"Landmines": {"rich_text": {}},
|
||||
"Strengths vs Weaknesses": {"rich_text": {}},
|
||||
"Portfolio": {"rich_text": {}},
|
||||
"Known References": {"rich_text": {}}
|
||||
}
|
||||
}
|
||||
|
||||
print(f"Creating database '{DB_TITLE}'...")
|
||||
response = requests.post(url, headers=headers, json=payload)
|
||||
|
||||
if response.status_code != 200:
|
||||
print(f"Error creating database: {response.status_code}")
|
||||
print(response.text)
|
||||
sys.exit(1)
|
||||
|
||||
db_data = response.json()
|
||||
print(f"Database created successfully! ID: {db_data['id']}")
|
||||
return db_data['id']
|
||||
|
||||
def format_list_as_bullets(items):
|
||||
"""Converts a python list of strings into a Notion rich_text text block with bullets."""
|
||||
if not items:
|
||||
return ""
|
||||
text_content = ""
|
||||
for item in items:
|
||||
text_content += f"• {item}\n"
|
||||
return text_content.strip()
|
||||
|
||||
def get_competitor_data(data, comp_name):
|
||||
"""Aggregates data from different sections of the JSON for a single competitor."""
|
||||
|
||||
# Init structure
|
||||
comp_data = {
|
||||
"name": comp_name,
|
||||
"url": "",
|
||||
"industries": [],
|
||||
"differentiators": [],
|
||||
"portfolio": [],
|
||||
"silver_bullet": "",
|
||||
"landmines": [],
|
||||
"strengths_weaknesses": [],
|
||||
"references": []
|
||||
}
|
||||
|
||||
# 1. Basic Info & Portfolio (from 'analyses')
|
||||
for analysis in data.get('analyses', []):
|
||||
c = analysis.get('competitor', {})
|
||||
if c.get('name') == comp_name:
|
||||
comp_data['url'] = c.get('url', '')
|
||||
comp_data['industries'] = analysis.get('target_industries', [])
|
||||
comp_data['differentiators'] = analysis.get('differentiators', [])
|
||||
|
||||
# Format Portfolio
|
||||
for prod in analysis.get('portfolio', []):
|
||||
p_name = prod.get('product', '')
|
||||
p_purpose = prod.get('purpose', '')
|
||||
comp_data['portfolio'].append(f"{p_name}: {p_purpose}")
|
||||
break
|
||||
|
||||
# 2. Battlecards
|
||||
for card in data.get('battlecards', []):
|
||||
if card.get('competitor_name') == comp_name:
|
||||
comp_data['silver_bullet'] = card.get('silver_bullet', '')
|
||||
comp_data['landmines'] = card.get('landmine_questions', [])
|
||||
comp_data['strengths_weaknesses'] = card.get('strengths_vs_weaknesses', [])
|
||||
break
|
||||
|
||||
# 3. References
|
||||
for ref_entry in data.get('reference_analysis', []):
|
||||
if ref_entry.get('competitor_name') == comp_name:
|
||||
for ref in ref_entry.get('references', []):
|
||||
r_name = ref.get('name', 'Unknown')
|
||||
r_ind = ref.get('industry', '')
|
||||
entry = r_name
|
||||
if r_ind:
|
||||
entry += f" ({r_ind})"
|
||||
comp_data['references'].append(entry)
|
||||
break
|
||||
|
||||
return comp_data
|
||||
|
||||
def add_competitor_entry(token, db_id, c_data):
|
||||
url = "https://api.notion.com/v1/pages"
|
||||
headers = {
|
||||
"Authorization": f"Bearer {token}",
|
||||
"Notion-Version": "2022-06-28",
|
||||
"Content-Type": "application/json"
|
||||
}
|
||||
|
||||
# Prepare properties
|
||||
props = {
|
||||
"Competitor Name": {"title": [{"text": {"content": c_data['name']}}]},
|
||||
"USPs / Differentiators": {"rich_text": [{"text": {"content": format_list_as_bullets(c_data['differentiators'])}}]},
|
||||
"Silver Bullet": {"rich_text": [{"text": {"content": c_data['silver_bullet']}}]},
|
||||
"Landmines": {"rich_text": [{"text": {"content": format_list_as_bullets(c_data['landmines'])}}]},
|
||||
"Strengths vs Weaknesses": {"rich_text": [{"text": {"content": format_list_as_bullets(c_data['strengths_weaknesses'])}}]},
|
||||
"Portfolio": {"rich_text": [{"text": {"content": format_list_as_bullets(c_data['portfolio'])}}]},
|
||||
"Known References": {"rich_text": [{"text": {"content": format_list_as_bullets(c_data['references'])}}]}
|
||||
}
|
||||
|
||||
if c_data['url']:
|
||||
props["Website"] = {"url": c_data['url']}
|
||||
|
||||
# Multi-select for industries
|
||||
# Note: Notion options are auto-created, but we must ensure no commas or weird chars break it
|
||||
ms_options = []
|
||||
for ind in c_data['industries']:
|
||||
# Simple cleanup
|
||||
clean_ind = ind.replace(',', '')
|
||||
ms_options.append({"name": clean_ind})
|
||||
|
||||
props["Target Industries"] = {"multi_select": ms_options}
|
||||
|
||||
payload = {
|
||||
"parent": {"database_id": db_id},
|
||||
"properties": props
|
||||
}
|
||||
|
||||
try:
|
||||
response = requests.post(url, headers=headers, json=payload)
|
||||
response.raise_for_status()
|
||||
print(f" - Added: {c_data['name']}")
|
||||
except requests.exceptions.HTTPError as e:
|
||||
print(f" - Failed to add {c_data['name']}: {e}")
|
||||
# print(response.text)
|
||||
|
||||
def main():
|
||||
token = load_notion_token(TOKEN_FILE)
|
||||
data = load_json_data(JSON_FILE)
|
||||
|
||||
# 1. Create DB
|
||||
db_id = create_competitor_database(token, PARENT_PAGE_ID)
|
||||
|
||||
# 2. Collect List of Competitors
|
||||
# We use the shortlist or candidates list to drive the iteration
|
||||
competitor_list = data.get('competitors_shortlist', [])
|
||||
if not competitor_list:
|
||||
competitor_list = data.get('competitor_candidates', [])
|
||||
|
||||
print(f"Importing {len(competitor_list)} competitors...")
|
||||
|
||||
for comp in competitor_list:
|
||||
c_name = comp.get('name')
|
||||
if not c_name: continue
|
||||
|
||||
# Aggregate Data
|
||||
c_data = get_competitor_data(data, c_name)
|
||||
|
||||
# Push to Notion
|
||||
add_competitor_entry(token, db_id, c_data)
|
||||
|
||||
print("Import complete.")
|
||||
|
||||
if __name__ == "__main__":
|
||||
main()
|
||||
230
import_relational_radar.py
Normal file
230
import_relational_radar.py
Normal file
@@ -0,0 +1,230 @@
|
||||
import json
|
||||
import os
|
||||
import requests
|
||||
import sys
|
||||
|
||||
# Configuration
|
||||
JSON_FILE = 'analysis_robo-planet.de.json'
|
||||
TOKEN_FILE = 'notion_token.txt'
|
||||
PARENT_PAGE_ID = "2e088f42-8544-8024-8289-deb383da3818"
|
||||
|
||||
# Database Titles
|
||||
DB_TITLE_HUB = "📦 Competitive Radar (Companies)"
|
||||
DB_TITLE_LANDMINES = "💣 Competitive Radar (Landmines & Intel)"
|
||||
DB_TITLE_REFS = "🏆 Competitive Radar (References)"
|
||||
|
||||
def load_json_data(filepath):
|
||||
try:
|
||||
with open(filepath, 'r') as f:
|
||||
return json.load(f)
|
||||
except Exception as e:
|
||||
print(f"Error loading JSON: {e}")
|
||||
sys.exit(1)
|
||||
|
||||
def load_notion_token(filepath):
|
||||
try:
|
||||
with open(filepath, 'r') as f:
|
||||
return f.read().strip()
|
||||
except Exception as e:
|
||||
print(f"Error loading token: {e}")
|
||||
sys.exit(1)
|
||||
|
||||
def create_database(token, parent_page_id, title, properties):
|
||||
url = "https://api.notion.com/v1/databases"
|
||||
headers = {
|
||||
"Authorization": f"Bearer {token}",
|
||||
"Notion-Version": "2022-06-28",
|
||||
"Content-Type": "application/json"
|
||||
}
|
||||
|
||||
payload = {
|
||||
"parent": {"type": "page_id", "page_id": parent_page_id},
|
||||
"title": [{"type": "text", "text": {"content": title}}],
|
||||
"properties": properties
|
||||
}
|
||||
|
||||
response = requests.post(url, headers=headers, json=payload)
|
||||
if response.status_code != 200:
|
||||
print(f"Error creating DB '{title}': {response.status_code}")
|
||||
print(response.text)
|
||||
sys.exit(1)
|
||||
|
||||
db_data = response.json()
|
||||
print(f"✅ Created DB '{title}' (ID: {db_data['id']})")
|
||||
return db_data['id']
|
||||
|
||||
def create_page(token, db_id, properties):
|
||||
url = "https://api.notion.com/v1/pages"
|
||||
headers = {
|
||||
"Authorization": f"Bearer {token}",
|
||||
"Notion-Version": "2022-06-28",
|
||||
"Content-Type": "application/json"
|
||||
}
|
||||
|
||||
payload = {
|
||||
"parent": {"database_id": db_id},
|
||||
"properties": properties
|
||||
}
|
||||
|
||||
response = requests.post(url, headers=headers, json=payload)
|
||||
if response.status_code != 200:
|
||||
print(f"Error creating page: {response.status_code}")
|
||||
# print(response.text)
|
||||
return None
|
||||
return response.json()['id']
|
||||
|
||||
def format_list_as_bullets(items):
|
||||
if not items: return ""
|
||||
return "\n".join([f"• {item}" for item in items])
|
||||
|
||||
def main():
|
||||
token = load_notion_token(TOKEN_FILE)
|
||||
data = load_json_data(JSON_FILE)
|
||||
|
||||
print("🚀 Starting Relational Import...")
|
||||
|
||||
# --- STEP 1: Define & Create Competitors Hub DB ---
|
||||
props_hub = {
|
||||
"Name": {"title": {}},
|
||||
"Website": {"url": {}},
|
||||
"Target Industries": {"multi_select": {}},
|
||||
"Portfolio Summary": {"rich_text": {}},
|
||||
"Silver Bullet": {"rich_text": {}},
|
||||
"USPs": {"rich_text": {}}
|
||||
}
|
||||
hub_db_id = create_database(token, PARENT_PAGE_ID, DB_TITLE_HUB, props_hub)
|
||||
|
||||
# --- STEP 2: Define & Create Satellite DBs (Linked to Hub) ---
|
||||
|
||||
# Landmines DB
|
||||
props_landmines = {
|
||||
"Statement / Question": {"title": {}},
|
||||
"Type": {"select": {
|
||||
"options": [
|
||||
{"name": "Landmine Question", "color": "red"},
|
||||
{"name": "Competitor Weakness", "color": "green"},
|
||||
{"name": "Competitor Strength", "color": "orange"}
|
||||
]
|
||||
}},
|
||||
"Related Competitor": {
|
||||
"relation": {
|
||||
"database_id": hub_db_id,
|
||||
"dual_property": {"synced_property_name": "Related Landmines & Intel"}
|
||||
}
|
||||
}
|
||||
}
|
||||
landmines_db_id = create_database(token, PARENT_PAGE_ID, DB_TITLE_LANDMINES, props_landmines)
|
||||
|
||||
# References DB
|
||||
props_refs = {
|
||||
"Customer Name": {"title": {}},
|
||||
"Industry": {"select": {}},
|
||||
"Snippet": {"rich_text": {}},
|
||||
"Case Study URL": {"url": {}},
|
||||
"Related Competitor": {
|
||||
"relation": {
|
||||
"database_id": hub_db_id,
|
||||
"dual_property": {"synced_property_name": "Related References"}
|
||||
}
|
||||
}
|
||||
}
|
||||
refs_db_id = create_database(token, PARENT_PAGE_ID, DB_TITLE_REFS, props_refs)
|
||||
|
||||
# --- STEP 3: Import Competitors (and store IDs) ---
|
||||
competitor_map = {} # Maps Name -> Notion Page ID
|
||||
|
||||
competitors = data.get('competitors_shortlist', []) or data.get('competitor_candidates', [])
|
||||
print(f"\nImporting {len(competitors)} Competitors...")
|
||||
|
||||
for comp in competitors:
|
||||
c_name = comp.get('name')
|
||||
if not c_name: continue
|
||||
|
||||
# Gather Data
|
||||
c_url = comp.get('url', '')
|
||||
|
||||
# Find extended analysis data
|
||||
analysis_data = next((a for a in data.get('analyses', []) if a.get('competitor', {}).get('name') == c_name), {})
|
||||
battlecard_data = next((b for b in data.get('battlecards', []) if b.get('competitor_name') == c_name), {})
|
||||
|
||||
industries = analysis_data.get('target_industries', [])
|
||||
portfolio = analysis_data.get('portfolio', [])
|
||||
portfolio_text = "\n".join([f"{p.get('product')}: {p.get('purpose')}" for p in portfolio])
|
||||
usps = format_list_as_bullets(analysis_data.get('differentiators', []))
|
||||
silver_bullet = battlecard_data.get('silver_bullet', '')
|
||||
|
||||
# Create Page
|
||||
props = {
|
||||
"Name": {"title": [{"text": {"content": c_name}}]},
|
||||
"Portfolio Summary": {"rich_text": [{"text": {"content": portfolio_text[:2000]}}]},
|
||||
"USPs": {"rich_text": [{"text": {"content": usps[:2000]}}]},
|
||||
"Silver Bullet": {"rich_text": [{"text": {"content": silver_bullet[:2000]}}]},
|
||||
"Target Industries": {"multi_select": [{"name": i.replace(',', '')} for i in industries]},
|
||||
}
|
||||
if c_url: props["Website"] = {"url": c_url}
|
||||
|
||||
page_id = create_page(token, hub_db_id, props)
|
||||
if page_id:
|
||||
competitor_map[c_name] = page_id
|
||||
print(f" - Created: {c_name}")
|
||||
|
||||
# --- STEP 4: Import Landmines & Intel ---
|
||||
print("\nImporting Landmines & Intel...")
|
||||
for card in data.get('battlecards', []):
|
||||
c_name = card.get('competitor_name')
|
||||
comp_page_id = competitor_map.get(c_name)
|
||||
if not comp_page_id: continue
|
||||
|
||||
# 1. Landmines
|
||||
for q in card.get('landmine_questions', []):
|
||||
props = {
|
||||
"Statement / Question": {"title": [{"text": {"content": q}}]},
|
||||
"Type": {"select": {"name": "Landmine Question"}},
|
||||
"Related Competitor": {"relation": [{"id": comp_page_id}]}
|
||||
}
|
||||
create_page(token, landmines_db_id, props)
|
||||
|
||||
# 2. Weaknesses
|
||||
# The JSON has "strengths_vs_weaknesses" combined. We'll import them as general Intel points.
|
||||
for point in card.get('strengths_vs_weaknesses', []):
|
||||
# Try to guess type based on text, or just default to Weakness context from Battlecard
|
||||
p_type = "Competitor Weakness" # Assuming these are points for us to exploit
|
||||
props = {
|
||||
"Statement / Question": {"title": [{"text": {"content": point}}]},
|
||||
"Type": {"select": {"name": p_type}},
|
||||
"Related Competitor": {"relation": [{"id": comp_page_id}]}
|
||||
}
|
||||
create_page(token, landmines_db_id, props)
|
||||
print(" - Landmines imported.")
|
||||
|
||||
# --- STEP 5: Import References ---
|
||||
print("\nImporting References...")
|
||||
count_refs = 0
|
||||
for ref_group in data.get('reference_analysis', []):
|
||||
c_name = ref_group.get('competitor_name')
|
||||
comp_page_id = competitor_map.get(c_name)
|
||||
if not comp_page_id: continue
|
||||
|
||||
for ref in ref_group.get('references', []):
|
||||
r_name = ref.get('name', 'Unknown')
|
||||
r_industry = ref.get('industry', 'Unknown')
|
||||
r_snippet = ref.get('testimonial_snippet', '')
|
||||
r_url = ref.get('case_study_url', '')
|
||||
|
||||
props = {
|
||||
"Customer Name": {"title": [{"text": {"content": r_name}}]},
|
||||
"Industry": {"select": {"name": r_industry}},
|
||||
"Snippet": {"rich_text": [{"text": {"content": r_snippet[:2000]}}]},
|
||||
"Related Competitor": {"relation": [{"id": comp_page_id}]}
|
||||
}
|
||||
if r_url and r_url.startswith('http'):
|
||||
props["Case Study URL"] = {"url": r_url}
|
||||
|
||||
create_page(token, refs_db_id, props)
|
||||
count_refs += 1
|
||||
|
||||
print(f" - {count_refs} References imported.")
|
||||
print("\n✅ Relational Import Complete!")
|
||||
|
||||
if __name__ == "__main__":
|
||||
main()
|
||||
35
refresh_references.py
Normal file
35
refresh_references.py
Normal file
@@ -0,0 +1,35 @@
|
||||
import asyncio
|
||||
import json
|
||||
import os
|
||||
import sys
|
||||
|
||||
# Path to the orchestrator
|
||||
sys.path.append(os.path.join(os.getcwd(), 'competitor-analysis-app'))
|
||||
|
||||
from competitor_analysis_orchestrator import analyze_single_competitor_references
|
||||
|
||||
async def refresh_references():
|
||||
json_path = 'analysis_robo-planet.de.json'
|
||||
|
||||
with open(json_path, 'r') as f:
|
||||
data = json.load(f)
|
||||
|
||||
competitors = data.get('competitors_shortlist', [])
|
||||
if not competitors:
|
||||
competitors = data.get('competitor_candidates', [])
|
||||
|
||||
print(f"Refreshing references for {len(competitors)} competitors...")
|
||||
|
||||
tasks = [analyze_single_competitor_references(c) for c in competitors]
|
||||
results = await asyncio.gather(*tasks)
|
||||
|
||||
# Filter and update
|
||||
data['reference_analysis'] = [r for r in results if r is not None]
|
||||
|
||||
with open(json_path, 'w') as f:
|
||||
json.dump(data, f, indent=2)
|
||||
|
||||
print(f"Successfully updated {json_path} with grounded reference data.")
|
||||
|
||||
if __name__ == "__main__":
|
||||
asyncio.run(refresh_references())
|
||||
Reference in New Issue
Block a user