# core/planning_services.py from agents.books import agent_task_planning from crewai import Crew, Process import litellm import json import time from schemas.books.book_planning import ChapterPlanningBlock, ChapterPlanningBlockDTO, SectionPlansBlock # ================================ # LiteLLM Global Config # ================================ litellm.num_retries = 4 litellm.retry_policy = { "TimeoutError": 4, "APIError": 3, "OpenRouterException": 3, "Exception": 2, } litellm.request_timeout = 120 litellm.drop_params = True def convert_dto_to_original(dto: ChapterPlanningBlockDTO) -> ChapterPlanningBlock: return ChapterPlanningBlock( chapter_title=dto.chapter_title, chapter_intro=dto.chapter_intro, style_profile=dto.style_profile, sections=[ SectionPlansBlock( section_title=sec.section_title, section_intro_paragraph=sec.section_intro_paragraph, section_closing_paragraph=sec.section_closing_paragraph, plans={item.subsection_title: item.plan for item in sec.plans}, ) for sec in dto.sections ], ) # ================================ # Crew (single chapter) # ================================ def build_planner_crew(): agent, task = agent_task_planning() return Crew( agents=[agent], tasks=[task], process=Process.sequential, memory=False, verbose=False, ) # ================================ # Runner # ================================ # core/planning_services.py (FIXED) def run_planning_on_outline(book_outline: dict) -> dict: chapters_output = [] tokens = [] for idx, chapter in enumerate(book_outline.get("chapters", []), start=1): inputs = { "book_title": book_outline.get("book_title", ""), "target_audience": book_outline.get("target_audience", ""), "book_description": book_outline.get("book_description", ""), "chapter_outline_json": json.dumps(chapter, ensure_ascii=False), } print(f"🟦 Planning Chapter {idx}: {chapter['chapter_title']}") planner_crew = build_planner_crew() result = planner_crew.kickoff(inputs=inputs) if result.token_usage: tokens.append(result.token_usage.dict()) dto_dict = json.loads(result.raw) try: dto_result = ChapterPlanningBlockDTO(**dto_dict) except Exception as e: print("❌ DTO Parsing Error:", e) print("RAW OUTPUT:", result.raw) raise final_result=convert_dto_to_original(dto_result) chapters_output.append(final_result.dict()) # chapter_plan = json.loads(result.raw) # chapters_output.append(chapter_plan) time.sleep(0.4) return { "book": { "book_title": book_outline.get("book_title", ""), "book_description": book_outline.get("book_description", ""), "target_audience": book_outline.get("target_audience", ""), "chapters": chapters_output, "planning_notes": "تم التخطيط Chapter-by-Chapter بنجاح.", }, "tokens": tokens, }