From a24d2809f32de0e6c760c752a8b09521871353c9 Mon Sep 17 00:00:00 2001 From: Mike Wichers Date: Sat, 21 Feb 2026 10:25:34 -0500 Subject: [PATCH] =?UTF-8?q?Auto-commit:=20Fix=20'create=20new=20book=20not?= =?UTF-8?q?=20showing=20anything'=20=E2=80=94=203=20root=20causes?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 1. templates/project_setup.html: s.tropes|join and s.formatting_rules|join raised Jinja2 UndefinedError when AI failed and fallback dict lacked those keys → 500 blank page. Fixed with (s.tropes or [])|join(', '). 2. web/routes/project.py (project_setup_wizard): Removed silent redirect-to- dashboard when model_logic is None. Now renders the setup form with a complete default suggestions dict (all fields present, lists as []) plus a clear warning flash so the user can fill it in manually. 3. web/routes/project.py (create_project_final): planner.enrich() was called with the full bible dict — enrich() reads manual_instruction from the top level (got 'A generic story' fallback) and wrote results into book_metadata instead of the bible's books[0]. Fixed to build a proper per-book blueprint, call enrich, and merge characters/plot_beats back into the correct locations. Co-Authored-By: Claude Sonnet 4.6 --- templates/project_setup.html | 6 +-- web/routes/project.py | 78 ++++++++++++++++++++++++++++++------ 2 files changed, 69 insertions(+), 15 deletions(-) diff --git a/templates/project_setup.html b/templates/project_setup.html index 092b991..9b7c07b 100644 --- a/templates/project_setup.html +++ b/templates/project_setup.html @@ -121,12 +121,12 @@
- +
- +
- +
diff --git a/web/routes/project.py b/web/routes/project.py index 9e20d57..c8a073d 100644 --- a/web/routes/project.py +++ b/web/routes/project.py @@ -30,10 +30,6 @@ def project_setup_wizard(): try: ai_setup.init_models() except: pass - if not ai_models.model_logic: - flash("AI models not initialized.") - return redirect(url_for('project.index')) - prompt = f""" ROLE: Publishing Analyst TASK: Suggest metadata for a story concept. @@ -67,13 +63,46 @@ def project_setup_wizard(): }} """ + _default_suggestions = { + "title": concept[:60] if concept else "New Project", + "genre": "Fiction", + "target_audience": "", + "tone": "", + "length_category": "4", + "estimated_chapters": 20, + "estimated_word_count": "75,000", + "include_prologue": False, + "include_epilogue": False, + "tropes": [], + "pov_style": "", + "time_period": "Modern", + "spice": "", + "violence": "", + "is_series": False, + "series_title": "", + "narrative_tense": "", + "language_style": "", + "dialogue_style": "", + "page_orientation": "Portrait", + "formatting_rules": [], + "author_bio": "" + } + suggestions = {} - try: - response = ai_models.model_logic.generate_content(prompt) - suggestions = json.loads(utils.clean_json(response.text)) - except Exception as e: - flash(f"AI Analysis failed: {e}") - suggestions = {"title": "New Project", "genre": "Fiction"} + if not ai_models.model_logic: + flash("AI models not initialized — fill in the details manually.", "warning") + suggestions = _default_suggestions + else: + try: + response = ai_models.model_logic.generate_content(prompt) + suggestions = json.loads(utils.clean_json(response.text)) + # Ensure list fields are always lists + for list_field in ("tropes", "formatting_rules"): + if not isinstance(suggestions.get(list_field), list): + suggestions[list_field] = [] + except Exception as e: + flash(f"AI Analysis failed — fill in the details manually. ({e})", "warning") + suggestions = _default_suggestions personas = {} if os.path.exists(config.PERSONAS_FILE): @@ -201,8 +230,33 @@ def create_project_final(): try: ai_setup.init_models() - bible = planner.enrich(bible, proj_path) - except: pass + # Build a per-book blueprint matching what enrich() expects + first_book = bible['books'][0] if bible.get('books') else {} + bp = { + 'manual_instruction': first_book.get('manual_instruction', concept), + 'book_metadata': { + 'title': bible['project_metadata']['title'], + 'genre': bible['project_metadata']['genre'], + 'style': dict(bible['project_metadata'].get('style', {})), + }, + 'length_settings': dict(bible['project_metadata'].get('length_settings', {})), + 'characters': [], + 'plot_beats': [], + } + bp = planner.enrich(bp, proj_path) + # Merge enriched characters and plot_beats back into the bible + if bp.get('characters'): + bible['characters'] = bp['characters'] + if bp.get('plot_beats') and bible.get('books'): + bible['books'][0]['plot_beats'] = bp['plot_beats'] + # Merge enriched style fields back (structure_prompt, content_warnings) + bm = bp.get('book_metadata', {}) + if bm.get('structure_prompt') and bible.get('books'): + bible['books'][0]['structure_prompt'] = bm['structure_prompt'] + if bm.get('content_warnings'): + bible['project_metadata']['content_warnings'] = bm['content_warnings'] + except Exception: + pass with open(os.path.join(proj_path, "bible.json"), 'w') as f: json.dump(bible, f, indent=2)