Fix: Resolved [object Object] report bug, enforced German output language across all phases, and documented troubleshooting steps
This commit is contained in:
@@ -298,9 +298,9 @@ const App: React.FC = () => {
|
||||
};
|
||||
|
||||
const generateFullReportMarkdown = (): string => {
|
||||
if (!state.phase5Result) return "";
|
||||
if (!state.phase5Result || !state.phase5Result.report) return "";
|
||||
|
||||
let fullReport = state.phase5Result;
|
||||
let fullReport = state.phase5Result.report;
|
||||
|
||||
if (state.phase6Result) {
|
||||
fullReport += `\n\n# SALES ENABLEMENT & VISUALS (PHASE 6)\n\n`;
|
||||
|
||||
@@ -1,4 +1,3 @@
|
||||
|
||||
import argparse
|
||||
import base64
|
||||
import json
|
||||
@@ -21,7 +20,7 @@ LOG_DIR = "Log_from_docker"
|
||||
if not os.path.exists(LOG_DIR):
|
||||
os.makedirs(LOG_DIR)
|
||||
|
||||
ORCHESTRATOR_VERSION = "1.1.0"
|
||||
ORCHESTRATOR_VERSION = "1.2.0" # Bump version for language fix
|
||||
run_timestamp = datetime.now().strftime("%y-%m-%d_%H-%M-%S")
|
||||
log_file_path = os.path.join(LOG_DIR, f"{run_timestamp}_gtm_orchestrator_run.log")
|
||||
|
||||
@@ -33,11 +32,12 @@ logging.basicConfig(
|
||||
logging.StreamHandler(sys.stdout)
|
||||
]
|
||||
)
|
||||
logging.info(f"GTM Architect Orchestrator v{{ORCHESTRATOR_VERSION}} ({{run_timestamp}}) starting...")
|
||||
logging.info(f"GTM Architect Orchestrator v{ORCHESTRATOR_VERSION} ({run_timestamp}) starting...")
|
||||
|
||||
# !!! CRITICAL FIX: Load API keys at the very beginning !!!
|
||||
# This ensures Config.API_KEYS is populated before any AI functions are called.
|
||||
Config.load_api_keys()
|
||||
|
||||
def log_and_save(project_id, step_name, data_type, content):
|
||||
logging.info(f"Project {project_id} - Step: {step_name} - Type: {data_type}")
|
||||
filename = f"{run_timestamp}_{step_name}_{data_type}.txt"
|
||||
@@ -63,6 +63,7 @@ def get_system_instruction(lang):
|
||||
Führe eine interne Plausibilitätsprüfung durch, bevor du eine Antwort gibst.
|
||||
Verwende "Wackler Symbiosis" als internes Framework für die Analyse von Produkt-Synergien.
|
||||
Nutze das "Hybrid Service Logic" Konzept, um zu bewerten, ob ein Produkt mit einer Dienstleistung kombiniert werden muss (z.B. bei hohen Wartungsanforderungen).
|
||||
WICHTIG: Antworte immer in der vom User geforderten Sprache (Deutsch), auch wenn der Input Englisch ist.
|
||||
"""
|
||||
else: # Default to English
|
||||
return """
|
||||
@@ -76,6 +77,12 @@ def get_system_instruction(lang):
|
||||
Use the "Hybrid Service Logic" concept to evaluate if a product needs to be combined with a service (e.g., due to high maintenance requirements).
|
||||
"""
|
||||
|
||||
def get_output_lang_instruction(lang):
|
||||
"""Returns a strong instruction to enforce the output language."""
|
||||
if lang == 'de':
|
||||
return "ACHTUNG: Die gesamte Ausgabe (JSON-Werte, Texte, Analysen) MUSS in DEUTSCH sein. Übersetze englische Input-Daten."
|
||||
return "IMPORTANT: The entire output MUST be in ENGLISH."
|
||||
|
||||
# --- ORCHESTRATOR PHASES ---
|
||||
|
||||
def phase1(payload):
|
||||
@@ -96,6 +103,8 @@ def phase1(payload):
|
||||
logging.info("Input is raw text. Analyzing directly.")
|
||||
|
||||
sys_instr = get_system_instruction(lang)
|
||||
lang_instr = get_output_lang_instruction(lang)
|
||||
|
||||
prompt = f"""
|
||||
PHASE 1: PRODUCT ANALYSIS & CONSTRAINTS
|
||||
Input: "{analysis_content}"
|
||||
@@ -103,6 +112,9 @@ def phase1(payload):
|
||||
1. Extract and CONSOLIDATE technical features into 8-12 high-level core capabilities or value propositions. Group minor specs (e.g., specific ports like USB/Ethernet) into broader categories (e.g., "Connectivity & Integration"). Do NOT list every single hardware spec individually. Focus on what matters for the buyer.
|
||||
2. Define hard constraints (e.g., physical dimensions, max payload, environment limitations).
|
||||
3. Check for internal portfolio conflicts (hypothetical product "Scrubber 5000").
|
||||
|
||||
{lang_instr}
|
||||
|
||||
Output JSON format ONLY: {{"features": [], "constraints": [], "conflictCheck": {{"hasConflict": false, "details": "", "relatedProduct": ""}}, "rawAnalysis": ""}}
|
||||
"""
|
||||
log_and_save(project_id, "phase1", "prompt", prompt)
|
||||
@@ -115,7 +127,6 @@ def phase1(payload):
|
||||
return data
|
||||
except json.JSONDecodeError:
|
||||
logging.error(f"Failed to decode JSON from Gemini response in phase1: {response}")
|
||||
# Return a structured error that the frontend can display
|
||||
error_response = {
|
||||
"error": "Die Antwort des KI-Modells war kein gültiges JSON. Das passiert manchmal bei hoher Auslastung. Bitte versuchen Sie es in Kürze erneut.",
|
||||
"details": response
|
||||
@@ -129,10 +140,15 @@ def phase2(payload):
|
||||
project_id = payload.get('projectId')
|
||||
|
||||
sys_instr = get_system_instruction(lang)
|
||||
lang_instr = get_output_lang_instruction(lang)
|
||||
|
||||
prompt = f"""
|
||||
PHASE 2: IDEAL CUSTOMER PROFILE (ICP) & DATA PROXIES
|
||||
Product Context: {json.dumps(phase1_data)}
|
||||
Task: 1. Identify top 3 ICPs (Ideal Customer Profiles/Industries). 2. Define data proxies for identifying these ICPs online.
|
||||
|
||||
{lang_instr}
|
||||
|
||||
Output JSON format ONLY: {{"icps": [{{"name": "", "rationale": ""}}], "dataProxies": [{{"target": "", "method": ""}}]}}
|
||||
"""
|
||||
log_and_save(project_id, "phase2", "prompt", prompt)
|
||||
@@ -148,10 +164,15 @@ def phase3(payload):
|
||||
project_id = payload.get('projectId')
|
||||
|
||||
sys_instr = get_system_instruction(lang)
|
||||
lang_instr = get_output_lang_instruction(lang)
|
||||
|
||||
prompt = f"""
|
||||
PHASE 3: WHALE HUNTING
|
||||
Target ICPs (Industries): {json.dumps(phase2_data.get('icps'))}
|
||||
Task: 1. Group 'Whales' (Key Accounts) strictly by ICP industries. 2. Identify 3-5 concrete top companies in DACH market per industry. 3. Define Buying Center Roles.
|
||||
|
||||
{lang_instr}
|
||||
|
||||
Output JSON format ONLY: {{"whales": [{{"industry": "", "accounts": []}}], "roles": []}}
|
||||
"""
|
||||
log_and_save(project_id, "phase3", "prompt", prompt)
|
||||
@@ -168,6 +189,8 @@ def phase4(payload):
|
||||
project_id = payload.get('projectId')
|
||||
|
||||
sys_instr = get_system_instruction(lang)
|
||||
lang_instr = get_output_lang_instruction(lang)
|
||||
|
||||
all_accounts = []
|
||||
for w in phase3_data.get('whales', []):
|
||||
all_accounts.extend(w.get('accounts', []))
|
||||
@@ -178,6 +201,9 @@ def phase4(payload):
|
||||
Target Industries: {json.dumps([w.get('industry') for w in phase3_data.get('whales', [])])}
|
||||
Product Features: {json.dumps(phase1_data.get('features'))}
|
||||
Task: 1. Develop specific "Angle" per target/industry. 2. Consistency Check against Product Matrix. 3. **IMPORTANT:** Apply "Hybrid Service Logic" if constraints exist!
|
||||
|
||||
{lang_instr}
|
||||
|
||||
Output JSON format ONLY: {{"strategyMatrix": [{{"segment": "", "painPoint": "", "angle": "", "differentiation": ""}}]}}
|
||||
"""
|
||||
log_and_save(project_id, "phase4", "prompt", prompt)
|
||||
@@ -196,6 +222,8 @@ def phase5(payload):
|
||||
project_id = payload.get('projectId')
|
||||
|
||||
sys_instr = get_system_instruction(lang)
|
||||
lang_instr = get_output_lang_instruction(lang)
|
||||
|
||||
prompt = f"""
|
||||
PHASE 5: ASSET GENERATION & FINAL REPORT
|
||||
CONTEXT DATA:
|
||||
@@ -207,6 +235,9 @@ def phase5(payload):
|
||||
1. Create a "GTM STRATEGY REPORT" in Markdown.
|
||||
2. Report Structure: Executive Summary, Product Analysis, Target Audience, Target Accounts, Strategy Matrix, Assets.
|
||||
3. Hybrid-Check: Ensure "Hybrid Service Logic" is visible.
|
||||
|
||||
{lang_instr}
|
||||
|
||||
Output: Return strictly MARKDOWN formatted text. Start with "# GTM STRATEGY REPORT".
|
||||
"""
|
||||
log_and_save(project_id, "phase5", "prompt", prompt)
|
||||
@@ -223,10 +254,15 @@ def phase6(payload):
|
||||
project_id = payload.get('projectId')
|
||||
|
||||
sys_instr = get_system_instruction(lang)
|
||||
lang_instr = get_output_lang_instruction(lang)
|
||||
|
||||
prompt = f"""
|
||||
PHASE 6: SALES ENABLEMENT & VISUALS
|
||||
CONTEXT: - Product Features: {json.dumps(phase1_data.get('features'))} - Personas: {json.dumps(phase3_data.get('roles'))} - Strategy: {json.dumps(phase4_data.get('strategyMatrix'))}
|
||||
TASK: 1. Anticipate Friction & Objections. 2. Formulate Battlecards. 3. Create Visual Prompts.
|
||||
|
||||
{lang_instr}
|
||||
|
||||
Output JSON format ONLY: {{"battlecards": [{{"persona": "", "objection": "", "responseScript": ""}}], "visualPrompts": [{{"title": "", "context": "", "prompt": ""}}]}}
|
||||
"""
|
||||
log_and_save(project_id, "phase6", "prompt", prompt)
|
||||
@@ -243,11 +279,16 @@ def phase7(payload):
|
||||
project_id = payload.get('projectId')
|
||||
|
||||
sys_instr = get_system_instruction(lang)
|
||||
lang_instr = get_output_lang_instruction(lang)
|
||||
|
||||
prompt = f"""
|
||||
PHASE 7: VERTICAL LANDING PAGE COPY (Conversion Optimization)
|
||||
ICPs: {json.dumps(phase2_data.get('icps'))}
|
||||
Strategy: {json.dumps(phase4_data.get('strategyMatrix'))}
|
||||
TASK: 1. Transform generic features into specific benefits for the Top 2 ICPs. 2. Apply "Wackler Symbiosis". 3. Create Landing Page Drafts (Hero Section).
|
||||
|
||||
{lang_instr}
|
||||
|
||||
Output JSON format ONLY: {{"landingPages": [{{"industry": "", "headline": "", "subline": "", "bullets": [], "cta": ""}}]}}
|
||||
"""
|
||||
log_and_save(project_id, "phase7", "prompt", prompt)
|
||||
@@ -264,10 +305,15 @@ def phase8(payload):
|
||||
project_id = payload.get('projectId')
|
||||
|
||||
sys_instr = get_system_instruction(lang)
|
||||
lang_instr = get_output_lang_instruction(lang)
|
||||
|
||||
prompt = f"""
|
||||
PHASE 8: BUSINESS CASE BUILDER (The CFO Pitch)
|
||||
Input: ICPs: {json.dumps(phase2_data.get('icps'))}, Features: {json.dumps(phase1_data.get('features'))}
|
||||
TASK: 1. Estimate labor costs/pain points. 2. Compare against Robot Leasing (approx 330-600€/month). 3. Develop ROI logic. 4. Create "Financial Argumentation Guide" for each ICP.
|
||||
|
||||
{lang_instr}
|
||||
|
||||
Output JSON format ONLY: {{"businessCases": [{{"industry": "", "costDriver": "", "efficiencyGain": "", "riskArgument": ""}}]}}
|
||||
"""
|
||||
log_and_save(project_id, "phase8", "prompt", prompt)
|
||||
@@ -284,11 +330,16 @@ def phase9(payload):
|
||||
project_id = payload.get('projectId')
|
||||
|
||||
sys_instr = get_system_instruction(lang)
|
||||
lang_instr = get_output_lang_instruction(lang)
|
||||
|
||||
prompt = f"""
|
||||
PHASE 9: THE "FEATURE-TO-VALUE" TRANSLATOR
|
||||
Input Features: {json.dumps(phase1_data.get('features'))}
|
||||
Strategy Pains: {json.dumps([s.get('painPoint') for s in phase4_data.get('strategyMatrix', [])])}
|
||||
TASK: 1. Take a tech feature. 2. Ask "So what?". 3. Ask "So what?" again. 4. Formulate benefit without jargon. Create a table.
|
||||
|
||||
{lang_instr}
|
||||
|
||||
Output JSON format ONLY: {{"techTranslations": [{{"feature": "", "story": "", "headline": ""}}]}}
|
||||
"""
|
||||
log_and_save(project_id, "phase9", "prompt", prompt)
|
||||
@@ -361,4 +412,4 @@ def main():
|
||||
sys.exit(1)
|
||||
|
||||
if __name__ == "__main__":
|
||||
main()
|
||||
main()
|
||||
Reference in New Issue
Block a user