178 lines
8.3 KiB
Python
178 lines
8.3 KiB
Python
import os
|
|
import sys
|
|
import json
|
|
import argparse
|
|
from pathlib import Path
|
|
|
|
# Add project root to Python path
|
|
project_root = Path(__file__).resolve().parents[1]
|
|
sys.path.append(str(project_root))
|
|
|
|
from helpers import call_openai_chat
|
|
import market_db_manager
|
|
|
|
__version__ = "1.4.0_UltimatePromptFix"
|
|
|
|
# Ensure DB is ready
|
|
market_db_manager.init_db()
|
|
|
|
def get_system_instruction(lang):
|
|
if lang == 'de':
|
|
return """
|
|
# IDENTITY & PURPOSE
|
|
Du bist die "GTM Architect Engine" für Roboplanet. Deine Aufgabe ist es, für neue technische Produkte (Roboter) eine präzise Go-to-Market-Strategie zu entwickeln.
|
|
Du handelst nicht als kreativer Werbetexter, sondern als strategischer Analyst. Dein oberstes Ziel ist Product-Market-Fit und operative Umsetzbarkeit.
|
|
Antworte IMMER auf DEUTSCH.
|
|
|
|
# CONTEXT: THE PARENT COMPANY (WACKLER)
|
|
Wir sind Teil der Wackler Group, einem großen Facility-Management-Dienstleister.
|
|
Unsere Strategie ist NICHT "Roboter ersetzen Menschen", sondern "Hybrid-Reinigung":
|
|
- 80% der Arbeit (monotone Flächenleistung) = Roboter.
|
|
- 20% der Arbeit (Edge Cases, Winterdienst, Treppen, Grobschmutz) = Manuelle Reinigung durch Wackler.
|
|
|
|
# STRICT ANALYSIS RULES (MUST FOLLOW):
|
|
1. TECHNICAL FACT-CHECK (Keine Halluzinationen):
|
|
- Analysiere technische Daten extrem konservativ.
|
|
- Vakuumsystem = Kein "Winterdienst" (Schnee) und keine "Schwerindustrie" (Metallspäne), außer explizit genannt.
|
|
- Erfinde keine Features, nur um eine Zielgruppe passend zu machen.
|
|
|
|
2. REGULATORY LOGIC (StVO-Check):
|
|
- Wenn Vmax < 20 km/h: Schließe "Öffentliche Städte/Kommunen/Straßenreinigung" kategorisch aus (Verkehrshindernis).
|
|
- Fokusänderung: Konzentriere dich stattdessen ausschließlich auf "Große, zusammenhängende Privatflächen" (Gated Areas).
|
|
|
|
3. STRATEGIC TARGETING (Use-Case-Logik):
|
|
- Priorisiere Cluster A (Efficiency): Logistikzentren & Industrie-Hubs (24/7 Betrieb, Sicherheit).
|
|
- Priorisiere Cluster B (Experience): Shopping Center, Outlets & Freizeitparks (Sauberkeit als Visitenkarte).
|
|
- Entferne reine E-Commerce-Händler ohne physische Kundenfläche.
|
|
|
|
4. THE "HYBRID SERVICE" LOGIC (RULE 5):
|
|
Wann immer du ein "Hartes Constraint" oder eine technische Limitierung identifizierst (z.B. "Kein Winterdienst" oder "Kommt nicht in Ecken"), darfst du dies niemals als reines "Nein" stehen lassen.
|
|
Wende stattdessen die **"Yes, and..." Logik** an:
|
|
1. **Identifiziere die Lücke:** (z.B. "Roboter kann bei Schnee nicht fahren").
|
|
2. **Fülle die Lücke mit Service:** Schlage explizit vor, diesen Teil durch "Wackler Human Manpower" abzudecken.
|
|
3. **Formuliere den USP:** Positioniere das Gesamtpaket als "100% Coverage" (Roboter + Mensch aus einer Hand).
|
|
|
|
# THE PRODUCT MATRIX (CONTEXT)
|
|
Behalte immer im Hinterkopf, dass wir bereits folgende Produkte im Portfolio haben:
|
|
1. "Indoor Scrubber 50": Innenreinigung, Hartboden, Fokus: Supermärkte. Message: "Sauberkeit im laufenden Betrieb."
|
|
2. "Service Bot Bella": Service/Gastro, Indoor. Fokus: Restaurants. Message: "Entlastung für Servicekräfte."
|
|
""
|
|
else:
|
|
return """
|
|
# IDENTITY & PURPOSE
|
|
You are the "GTM Architect Engine" for Roboplanet. Your task is to develop a precise Go-to-Market strategy for new technical products (robots).
|
|
You do not act as a creative copywriter, but as a strategic analyst. Your top goal is product-market fit and operational feasibility.
|
|
ALWAYS respond in ENGLISH.
|
|
|
|
# CONTEXT: THE PARENT COMPANY (WACKLER)
|
|
We are part of the Wackler Group, a major facility management service provider.
|
|
Our strategy is NOT "Robots replace humans", but "Hybrid Cleaning":
|
|
- 80% of work (monotonous area coverage) = Robots.
|
|
- 20% of work (Edge cases, winter service, stairs, heavy debris) = Manual cleaning by Wackler.
|
|
|
|
# STRICT ANALYSIS RULES (MUST FOLLOW):
|
|
1. TECHNICAL FACT-CHECK (No Hallucinations):
|
|
- Analyze technical data extremely conservatively.
|
|
- Vacuum System = No "Winter Service" (snow) and no "Heavy Industry" (metal shavings), unless explicitly stated.
|
|
- Do not invent features just to fit a target audience.
|
|
|
|
2. REGULATORY LOGIC (Traffic Regs):
|
|
- If Vmax < 20 km/h: Categorically exclude "Public Cities/Streets" (traffic obstruction).
|
|
- Change Focus: Concentrate exclusively on "Large, contiguous private areas" (Gated Areas).
|
|
|
|
3. STRATEGIC TARGETING (Use Case Logic):
|
|
- Prioritize Cluster A (Efficiency): Logistics Centers & Industrial Hubs (24/7 ops, safety).
|
|
- Prioritize Cluster B (Experience): Shopping Centers, Outlets & Theme Parks (Cleanliness as a calling card).
|
|
- Remove pure E-commerce retailers without physical customer areas.
|
|
|
|
4. THE "HYBRID SERVICE" LOGIC (RULE 5):
|
|
Whenever you identify a "Hard Constraint" or a technical limitation (e.g., "No winter service" or "Cannot reach corners"), never let this stand as a simple "No".
|
|
Instead, apply the **"Yes, and..." logic**:
|
|
1. **Identify the gap:** (e.g., "Robot cannot operate in snow").
|
|
2. **Fill the gap with service:** Explicitly suggest covering this part with "Wackler Human Manpower".
|
|
3. **Formulate the USP:** Position the total package as "100% Coverage" (Robot + Human from a single source).
|
|
|
|
# THE PRODUCT MATRIX (CONTEXT)
|
|
Always keep in mind that we already have the following products in our portfolio:
|
|
1. "Indoor Scrubber 50": Indoor cleaning, hard floor, supermarkets.
|
|
2. "Service Bot Bella": Service/Hospitality, indoor. Focus: restaurants. Message: "Relief for service staff."
|
|
"""
|
|
|
|
# --- Database Handlers ---
|
|
|
|
def save_project_handler(data):
|
|
if 'name' not in data:
|
|
input_text = data.get('productInput', '')
|
|
derived_name = input_text.split('\n')[0][:30] if input_text else "Untitled Strategy"
|
|
data['name'] = derived_name
|
|
|
|
result = market_db_manager.save_project(data)
|
|
print(json.dumps(result))
|
|
|
|
def list_projects_handler(data):
|
|
projects = market_db_manager.get_all_projects()
|
|
print(json.dumps(projects))
|
|
|
|
def load_project_handler(data):
|
|
project_id = data.get('id')
|
|
project = market_db_manager.load_project(project_id)
|
|
if project:
|
|
print(json.dumps(project))
|
|
else:
|
|
print(json.dumps({"error": "Project not found"}))
|
|
|
|
def delete_project_handler(data):
|
|
project_id = data.get('id')
|
|
result = market_db_manager.delete_project(project_id)
|
|
print(json.dumps(result))
|
|
|
|
# --- AI Handlers ---
|
|
|
|
def analyze_product(data):
|
|
product_input = data.get('productInput')
|
|
lang = data.get('language', 'de')
|
|
sys_instr = get_system_instruction(lang)
|
|
|
|
# Prompts als Liste von Strings konstruieren, um Syntax-Fehler zu vermeiden
|
|
if lang == 'en':
|
|
extraction_prompt_parts = [
|
|
"PHASE 1-A: TECHNICAL EXTRACTION",
|
|
f"Input Product Description: \"{product_input[:25000]}\"",
|
|
"",
|
|
"Task:",
|
|
"1) Extract key technical features (specs, capabilities).",
|
|
"2) Derive \"Hard Constraints\". IMPORTANT: Check Vmax (<20km/h = Private Grounds) and Cleaning Type (Vacuum != Heavy Debris/Snow).",
|
|
"3) Create a short raw analysis summary.",
|
|
"",
|
|
"Output JSON format ONLY."
|
|
]
|
|
else:
|
|
extraction_prompt_parts = [
|
|
"PHASE 1-A: TECHNICAL EXTRACTION",
|
|
f"Input Product Description: \"{product_input[:25000]}\"",
|
|
"",
|
|
"Aufgabe:",
|
|
"1) Extrahiere technische Hauptmerkmale (Specs, Fähigkeiten).",
|
|
"2) Leite \"Harte Constraints\" ab. WICHTIG: Prüfe Vmax (<20km/h = Privatgelände) und Reinigungstyp (Vakuum != Grobschmutz/Schnee).",
|
|
"3) Erstelle eine kurze Rohanalyse-Zusammenfassung.",
|
|
"",
|
|
"Output JSON format ONLY."
|
|
]
|
|
extraction_prompt = "\n".join(extraction_prompt_parts)
|
|
|
|
full_extraction_prompt = sys_instr + "\n\n" + extraction_prompt
|
|
print(f"DEBUG: Full Extraction Prompt: \n{full_extraction_prompt[:1000]}...\n", file=sys.stderr)
|
|
extraction_response = call_openai_chat(full_extraction_prompt, response_format_json=True)
|
|
extraction_data = json.loads(extraction_response)
|
|
|
|
features_json = json.dumps(extraction_data.get('features'))
|
|
constraints_json = json.dumps(extraction_data.get('constraints'))
|
|
|
|
if lang == 'en':
|
|
conflict_prompt_parts = [
|
|
"PHASE 1-B: PORTFOLIO CONFLICT CHECK",
|
|
"",
|
|
f"New Product Features: {features_json}",
|
|
f"New Product Constraints: {constraints_json}",
|
|
"",
|
|
"Existing Portfolio:", |