import argparse import base64 import json import logging import sys import os from datetime import datetime import content_db_manager as db_manager # Ensure helper path is correct sys.path.append(os.path.dirname(os.path.abspath(__file__))) sys.path.append(os.path.join(os.path.dirname(os.path.abspath(__file__)), "..")) from helpers import call_gemini_flash, scrape_website_details from config import Config LOG_DIR = "Log_from_docker" if not os.path.exists(LOG_DIR): os.makedirs(LOG_DIR) run_timestamp = datetime.now().strftime("%y-%m-%d_%H-%M-%S") logging.basicConfig(level=logging.INFO, format='%(asctime)s - %(levelname)s - %(message)s') Config.load_api_keys() def get_copywriter_instruction(lang='de'): return r""" Du bist ein Senior Copywriter und SEO-Experte. Deine Spezialität ist der 'Challenger Sale'. Du schreibst Texte, die fachlich tief fundiert, professionell und leicht aggressiv/fordernd sind. DEIN STIL: - Keine Buzzwords ohne Substanz. - Fokus auf den 'Cost of Inaction' (Was kostet es den Kunden, wenn er NICHT handelt?). - Übersetzung von Technik in geschäftlichen Nutzen. - SEO-Integration: Baue Keywords natürlich aber präsent ein. """ # --- MODES --- def list_gtm_projects(payload): projects = db_manager.get_all_gtm_projects() return {"projects": projects} def import_project(payload): gtm_id = payload.get('gtmProjectId') if not gtm_id: return {"error": "Missing gtmProjectId"} result = db_manager.import_gtm_project(gtm_id) if not result: return {"error": "GTM Project not found or import failed"} return result def list_content_projects(payload): projects = db_manager.get_all_content_projects() return {"projects": projects} def load_project_details(payload): project_id = payload.get('projectId') project = db_manager.get_content_project(project_id) if not project: return {"error": "Project not found"} assets = db_manager.get_project_assets(project_id) project['assets'] = assets return project def seo_brainstorming(payload): project_id = payload.get('projectId') lang = payload.get('lang', 'de') project = db_manager.get_content_project(project_id) if not project: return {"error": "Project context not found"} gtm_data = project.get('gtm_data_snapshot', {}) # GOLDEN RULE: Use Raw Quotes and .format() prompt = r""" Basierend auf folgendem GTM-Kontext (Strategie für ein technisches Produkt): {gtm_context} AUFGABE: Generiere eine strategische Liste von 15 SEO-Keywords. 1. 5 Short-Tail Fokus-Keywords (z.B. Produktkategorie + 'kaufen/mieten'). 2. 10 Long-Tail Keywords, die spezifische Pain Points oder Usecases adressieren (z.B. 'Kostenreduktion bei Sicherheitsrundgängen'). Die Keywords müssen für Entscheider relevant sein (CFO, Head of Security, Operations Manager). Output NUR als JSON Liste von Strings. """.format(gtm_context=json.dumps(gtm_data)) response = call_gemini_flash(prompt, system_instruction=get_copywriter_instruction(lang), json_mode=True) keywords = json.loads(response) db_manager.save_seo_strategy(project_id, {"seed_keywords": keywords}) return {"keywords": keywords} def generate_section(payload): project_id = payload.get('projectId') section_key = payload.get('sectionKey') # e.g., 'hero', 'problem', 'features' manual_content = payload.get('manualContent') lang = payload.get('lang', 'de') keywords = payload.get('keywords', []) if manual_content: # User is saving their manual edits db_manager.save_content_asset(project_id, 'website_section', section_key, f"Section: {section_key}", manual_content, keywords) return {"status": "saved", "sectionKey": section_key} project = db_manager.get_content_project(project_id) if not project: return {"error": "Project context not found"} gtm_data = project.get('gtm_data_snapshot', {}) # Context extraction category = project.get('category') prompt = r""" Erstelle den Website-Inhalt für die Sektion '{section}' eines Produkts in der Kategorie '{cat}'. STRATEGIE-KONTEXT: {gtm_context} SEO-KEYWORDS ZU NUTZEN: {kws} ANFORDERUNG: - Schreibe im Stil eines Senior Copywriters (fachlich fundiert, Challenger Sale). - Format: Markdown. - Die Sektion muss den Nutzer zur nächsten Aktion (CTA) führen. """.format( section=section_key, cat=category, gtm_context=json.dumps(gtm_data), kws=json.dumps(keywords) ) content = call_gemini_flash(prompt, system_instruction=get_copywriter_instruction(lang), json_mode=False) # Save as asset db_manager.save_content_asset(project_id, 'website_section', section_key, f"Section: {section_key}", content, keywords) return {"content": content, "sectionKey": section_key} def main(): parser = argparse.ArgumentParser(description="Content Engine Orchestrator") parser.add_argument("--mode", required=True) parser.add_argument("--payload_file", help="Path to JSON payload") args = parser.parse_args() payload = {} if args.payload_file: with open(args.payload_file, 'r') as f: payload = json.load(f) modes = { "list_gtm_projects": list_gtm_projects, "import_project": import_project, "list_content_projects": list_content_projects, "load_project": load_project_details, "seo_brainstorming": seo_brainstorming, "generate_section": generate_section, } if args.mode in modes: try: result = modes[args.mode](payload) print(json.dumps(result, ensure_ascii=False)) except Exception as e: logging.error(f"Error in mode {args.mode}: {str(e)}") print(json.dumps({"error": str(e)})) else: print(json.dumps({"error": f"Unknown mode: {args.mode}"})) if __name__ == "__main__": main()