From e6dde59cdf4360f0434e13b8ed41787824107e4e Mon Sep 17 00:00:00 2001 From: Floke Date: Tue, 6 Jan 2026 19:36:42 +0000 Subject: [PATCH] feat(gtm): v2.5 - Hard Fact Extraction & UI - Backend: Implemented secondary extraction phase for structured specs (JSON schema). - Backend: Added strict normalization rules (min, cm, kg). - Frontend: Added 'Phase1Data' interface update for specs. - Frontend: Implemented new UI component for 'Technical Specifications' in Phase 1. - Frontend: Updated header and sidebar to display 'v2.5' build marker. - Docs: Updated architectural documentation. --- gtm-architect/App.tsx | 89 ++++++++++++++++++++++++++ gtm-architect/components/Layout.tsx | 2 +- gtm-architect/types.ts | 41 ++++++++++++ gtm_architect_documentation.md | 13 +++- gtm_architect_orchestrator.py | 84 ++++++++++++++++++++++++ templates/json_struktur_roboplanet.txt | 43 +++++++++++++ 6 files changed, 268 insertions(+), 4 deletions(-) create mode 100644 templates/json_struktur_roboplanet.txt diff --git a/gtm-architect/App.tsx b/gtm-architect/App.tsx index 0264feb3..55eea0cf 100644 --- a/gtm-architect/App.tsx +++ b/gtm-architect/App.tsx @@ -1153,6 +1153,95 @@ const App: React.FC = () => { + {/* NEW: Hard Facts Specs Display */} + {state.phase1Result?.specs && 'metadata' in state.phase1Result.specs && ( +
+

+ Technical Specifications (Hard Facts) +

+ +
+ {/* Core Data */} +
+

Core Data

+
+
+ Model + {state.phase1Result.specs.metadata.brand} {state.phase1Result.specs.metadata.model_name} +
+
+ Category + {state.phase1Result.specs.metadata.category} +
+
+ Runtime + {state.phase1Result.specs.core_specs.battery_runtime_min ? `${state.phase1Result.specs.core_specs.battery_runtime_min} min` : '-'} +
+
+ Weight + {state.phase1Result.specs.core_specs.weight_kg ? `${state.phase1Result.specs.core_specs.weight_kg} kg` : '-'} +
+
+ Dimensions + + {state.phase1Result.specs.core_specs.dimensions_cm.l ? `${state.phase1Result.specs.core_specs.dimensions_cm.l}x${state.phase1Result.specs.core_specs.dimensions_cm.w}x${state.phase1Result.specs.core_specs.dimensions_cm.h} cm` : '-'} + +
+
+ Navigation + {state.phase1Result.specs.core_specs.navigation_type || '-'} +
+
+
+ + {/* Layer Data */} +
+

Performance Layer

+ + {!state.phase1Result.specs.layers.cleaning && !state.phase1Result.specs.layers.service && !state.phase1Result.specs.layers.security && ( +
No specific layer data detected.
+ )} + + {state.phase1Result.specs.layers.cleaning && ( +
+
Cleaning Mode
+
Area Perf: {state.phase1Result.specs.layers.cleaning.area_performance_sqm_h || '-'} m²/h
+
Fresh Water: {state.phase1Result.specs.layers.cleaning.fresh_water_l || '-'} L
+
+ )} + {state.phase1Result.specs.layers.service && ( +
+
Service Mode
+
Payload: {state.phase1Result.specs.layers.service.max_payload_kg || '-'} kg
+
Trays: {state.phase1Result.specs.layers.service.number_of_trays || '-'}
+
+ )} + {state.phase1Result.specs.layers.security && ( +
+
Security Mode
+
Night Vision: {state.phase1Result.specs.layers.security.night_vision ? 'Yes' : 'No'}
+
Cameras: {state.phase1Result.specs.layers.security.camera_types.join(', ') || '-'}
+
+ )} +
+
+ + {/* Extended Features */} + {state.phase1Result.specs.extended_features.length > 0 && ( +
+

Extended Features

+
+ {state.phase1Result.specs.extended_features.map((feat, idx) => ( + + {feat.feature}: {feat.value} {feat.unit} + + ))} +
+
+ )} +
+ )} + {state.phase1Result?.conflictCheck.hasConflict ? (
- ROBOPLANET + ROBOPLANET v2.5

GTM Architect Engine

diff --git a/gtm-architect/types.ts b/gtm-architect/types.ts index 04310bbe..471e234d 100644 --- a/gtm-architect/types.ts +++ b/gtm-architect/types.ts @@ -28,6 +28,47 @@ export interface Phase1Data { relatedProduct?: string; }; rawAnalysis: string; + specs?: { + metadata: { + product_id: string; + brand: string; + model_name: string; + category: string; + manufacturer_url: string; + }; + core_specs: { + battery_runtime_min: number | null; + charge_time_min: number | null; + weight_kg: number | null; + dimensions_cm: { l: number | null; w: number | null; h: number | null }; + max_slope_deg: number | null; + ip_rating: string | null; + climb_height_cm: number | null; + navigation_type: string | null; + connectivity: string[]; + }; + layers: { + cleaning?: { + fresh_water_l: number | null; + dirty_water_l: number | null; + area_performance_sqm_h: number | null; + mop_pressure_kg: number | null; + }; + service?: { + max_payload_kg: number | null; + number_of_trays: number | null; + display_size_inch: number | null; + ads_capable: boolean | null; + }; + security?: { + camera_types: string[]; + night_vision: boolean | null; + gas_detection: string[]; + at_interface: boolean | null; + }; + }; + extended_features: { feature: string; value: string; unit: string }[]; + }; } export interface Phase2Data { diff --git a/gtm_architect_documentation.md b/gtm_architect_documentation.md index b68a3acc..60b1d61d 100644 --- a/gtm_architect_documentation.md +++ b/gtm_architect_documentation.md @@ -1,4 +1,4 @@ -# Dokumentation: GTM Architect Engine (v2.4) +# Dokumentation: GTM Architect Engine (v2.5) ## 1. Projektübersicht @@ -26,7 +26,7 @@ graph LR 1. **Frontend (`/gtm-architect`):** * Framework: **React** (Vite + TypeScript). - * Features: **Session History** (Laden/Löschen alter Projekte) und **Markdown Upload**. + * Features: **Session History**, **Hard Fact Extraction UI** und **Markdown Upload**. 2. **Backend Bridge (`server.cjs`):** * Runtime: **Node.js** (Express). @@ -67,7 +67,7 @@ Die `call_gemini_image`-Funktion wählt automatisch die beste Methode basierend | Phase | Modus | Input | Output | Beschreibung | | :--- | :--- | :--- | :--- | :--- | -| **1** | `phase1` | Rohtext / URL | Features, Constraints | Extrahiert technische Daten & **erstellt DB-Projekt**. | +| **1** | `phase1` | Rohtext / URL | Features, Constraints, **Specs** | Extrahiert technische Daten, **Hard Facts (Specs)** & erstellt DB-Projekt. | | **2** | `phase2` | Phase 1 Result | ICPs, Data Proxies | Identifiziert ideale Kundenprofile. | | **3** | `phase3` | Phase 2 Result | Whales, Rollen | Identifiziert Zielkunden & Buying Center. | | **4** | `phase4` | Phase 1 & 3 | Strategy Matrix | Entwickelt "Angles" und Pain-Points. | @@ -91,6 +91,13 @@ Das System verwaltet persistente Sitzungen in der SQLite-Datenbank: ## 7. Historie & Fixes (Jan 2026) +* **[UPGRADE] v2.5: Hard Fact Extraction** + * **Phase 1 Erweiterung:** Implementierung eines sekundären Extraktions-Schritts für "Hard Facts" (Specs). + * **Strukturiertes Daten-Schema:** Integration von `templates/json_struktur_roboplanet.txt`. + * **Normalisierung:** Automatische Standardisierung von Einheiten (Minuten, cm, kg, m²/h). + * **Frontend Update:** Neue UI-Komponente zur Anzeige der technischen Daten (Core Data, Layer, Extended Features). + * **Sidebar & Header:** Update auf "ROBOPLANET v2.5". + * **[UPGRADE] v2.4:** * Dokumentation der Kern-Engine (`helpers.py`) mit Dual SDK & Hybrid Image Generation. * Aktualisierung der Architektur-Übersicht und Komponenten-Beschreibungen. diff --git a/gtm_architect_orchestrator.py b/gtm_architect_orchestrator.py index 6d4b8006..68aac211 100644 --- a/gtm_architect_orchestrator.py +++ b/gtm_architect_orchestrator.py @@ -203,6 +203,90 @@ def phase1(payload): try: data = json.loads(response) + + # --- PART 2: HARD FACTS EXTRACTION --- + spec_schema = """ + { + "metadata": { + "product_id": "string (slug)", + "brand": "string", + "model_name": "string", + "category": "cleaning | service | security | industrial", + "manufacturer_url": "string" + }, + "core_specs": { + "battery_runtime_min": "integer (standardized to minutes)", + "charge_time_min": "integer (standardized to minutes)", + "weight_kg": "float", + "dimensions_cm": { "l": "float", "w": "float", "h": "float" }, + "max_slope_deg": "float", + "ip_rating": "string", + "climb_height_cm": "float", + "navigation_type": "string (e.g. SLAM, LiDAR, VSLAM)", + "connectivity": ["string"] + }, + "layers": { + "cleaning": { + "fresh_water_l": "float", + "dirty_water_l": "float", + "area_performance_sqm_h": "float", + "mop_pressure_kg": "float" + }, + "service": { + "max_payload_kg": "float", + "number_of_trays": "integer", + "display_size_inch": "float", + "ads_capable": "boolean" + }, + "security": { + "camera_types": ["string"], + "night_vision": "boolean", + "gas_detection": ["string"], + "at_interface": "boolean" + } + }, + "extended_features": [ + { "feature": "string", "value": "string", "unit": "string" } + ] + } + """ + + specs_prompt = f""" + PHASE 1 (Part 2): HARD FACT EXTRACTION + Input: "{analysis_content}" + + Task: Extract technical specifications strictly according to the provided JSON schema. + + NORMALIZATION RULES (STRICTLY FOLLOW): + 1. Time: Convert ALL time values (runtime, charging) to MINUTES (Integer). Example: "1:30 h" -> 90, "2 hours" -> 120. + 2. Dimensions/Weight: All lengths in CM, weights in KG. + 3. Performance: Area performance always in m²/h. + 4. Booleans: Use true/false (not strings). + 5. Unknowns: If a value is not in the text, set it to null. DO NOT HALLUCINATE. + + LOGIC FOR LAYERS: + - If product uses water/brushes -> Fill 'layers.cleaning'. + - If product delivers items/trays -> Fill 'layers.service'. + - If product patrols/detects -> Fill 'layers.security'. + + EXTENDED FEATURES: + - Put any technical feature that doesn't fit the schema into 'extended_features'. + + Output JSON format ONLY based on this schema: + {spec_schema} + """ + + log_and_save(project_id, "phase1_specs", "prompt", specs_prompt) + specs_response = call_gemini_flash(specs_prompt, system_instruction=sys_instr, json_mode=True) + log_and_save(project_id, "phase1_specs", "response", specs_response) + + try: + specs_data = json.loads(specs_response) + data['specs'] = specs_data + except json.JSONDecodeError: + logging.error(f"Failed to decode JSON from Gemini response in phase1 (specs): {specs_response}") + data['specs'] = {"error": "Failed to extract specs", "raw": specs_response} + db_manager.save_gtm_result(project_id, 'phase1_result', json.dumps(data)) # WICHTIG: ID zurückgeben, damit Frontend sie speichert diff --git a/templates/json_struktur_roboplanet.txt b/templates/json_struktur_roboplanet.txt new file mode 100644 index 00000000..afa4cdf1 --- /dev/null +++ b/templates/json_struktur_roboplanet.txt @@ -0,0 +1,43 @@ +{ + "metadata": { + "product_id": "string (slug)", + "brand": "string", + "model_name": "string", + "category": "cleaning | service | security | industrial", + "manufacturer_url": "string" + }, + "core_specs": { + "battery_runtime_min": "integer (standardized to minutes)", + "charge_time_min": "integer (standardized to minutes)", + "weight_kg": "float", + "dimensions_cm": { "l": "float", "w": "float", "h": "float" }, + "max_slope_deg": "float", + "ip_rating": "string", + "climb_height_cm": "float", + "navigation_type": "string (e.g. SLAM, LiDAR, VSLAM)", + "connectivity": ["string"] + }, + "layers": { + "cleaning": { + "fresh_water_l": "float", + "dirty_water_l": "float", + "area_performance_sqm_h": "float", + "mop_pressure_kg": "float" + }, + "service": { + "max_payload_kg": "float", + "number_of_trays": "integer", + "display_size_inch": "float", + "ads_capable": "boolean" + }, + "security": { + "camera_types": ["string"], + "night_vision": "boolean", + "gas_detection": ["string"], + "at_interface": "boolean" + } + }, + "extended_features": [ + { "feature": "string", "value": "string", "unit": "string" } + ] +} \ No newline at end of file