
    i*                     d   d Z ddlZddlmZmZmZmZ ddlmZ ddl	m
Z
 dZdZdd	d
ZdZdedefdZdededeeef   fdZdeeeef      deeeef      fdZdeeeef      deeeef      fdZdeeef   defdZdeeef   deeeef      dee   fdZdeeef   deddfdZ G d d      Zy)u^   웹북 패키지 생성 모듈 — 시나리오 에피소드를 웹북 에피소드로 분할.    N)AnyDictListOptional)call_structured)load_prompti`  id  koKorean)enEnglish)r
   r   prototype_promptsfilenamereturnc                 l    | j                  d      r| j                  dd      n| }t        t        |      S )Nz.md )endswithreplacer   _MODULE)r   stems     S/Users/manta/Documents/Projects/TheRoad-I1/backend/app/modules/webbook_generator.py_load_promptr      s0    *2*;*;E*B8E2&Dw%%    web_episode_countsections_per_episodec                     ddddiddiddidddddiddddddidddd	ddidd
dd	ddg dd}ddd
d| dddiddidddddidd|||ddddddiddg dd}ddddiddiddid| | |ddg ddS )NobjectFtypestringarray      )r   minItemsmaxItemsitems   integer)r   minimummaximum)still_idsection_titleimage_captionopening_paragraphsclosing_paragraphs
paragraphsimage_after_paragraph)r   additionalProperties
propertiesrequired   )episode_numbertitlesubtitleopener_paragraphssectionscloser_paragraphs)series_titleadaptation_subtitleloglineepisodes )r   r   section_schemaepisode_schemas       r   _make_webbook_package_schemarB      sL     %*$h/$h/ (+	#   (+	#   (+	 "&-
8
?(&NT  % ",
 h'* (+	"  00'	   (+	")
6
=&&NP  %#X.$*H#5)--'		


 r   entitiesc           
          g }| D ]X  }|j                  |j                  dd      |j                  dd      |j                  dd      |j                  dd      d       Z |S )Nnamer   entity_typedescriptionstable_traitsz{})rE   rF   rG   rH   appendget)rC   compactitems      r   _compact_entitiesrN      sa    G,#xxr:#xxr:!%/4!@		
  Nr   stillsc                     g }| D ]i  }|j                  |j                  dd      |j                  dd      |j                  dd      |j                  dd      |j                  dd      d       k |S )	Nstill_indexr   idr   screenplay_scene_heading
beat_titlestill_frame_prompt)rQ   rR   rS   rT   rU   rI   )rO   rL   ss      r   _compact_stillsrW      sp    G uu]A6eeD"o,-EE2Lb,QeeL"5&'ee,@"&E	
  Nr   episodec           	         d}dD ]'  }|t        d | j                  |g       D              z  }) | j                  dg       D ]  }|t        |j                  dd            z  }|t        |j                  dd            z  }|t        d |j                  d	g       D              z  }|t        d
 |j                  dg       D              z  }|t        d |j                  dg       D              z  } |S )Nr   )r8   r:   c              3   2   K   | ]  }t        |        y wNlen.0texts     r   	<genexpr>z+_episode_character_count.<locals>.<genexpr>   s     A+@4SY+@   r9   r+   r   r,   c              3   2   K   | ]  }t        |        y wr[   r\   r^   s     r   ra   z+_episode_character_count.<locals>.<genexpr>   s     I+H4SY+Hrb   r/   c              3   2   K   | ]  }t        |        y wr[   r\   r^   s     r   ra   z+_episode_character_count.<locals>.<genexpr>         
"G$CI"Grb   r-   c              3   2   K   | ]  }t        |        y wr[   r\   r^   s     r   ra   z+_episode_character_count.<locals>.<genexpr>   re   rb   r.   )sumrK   r]   )rX   totalpartsections       r   _episode_character_countrk      s    E:A7;;tR+@AAA ;;;z2.W[["566W[["566I7;;|R+HIII 
")++.BB"G
 
 	
 	 
")++.BB"G
 
 	
 / Lr   payloadavailable_stillsc           
      0   |D ch c]  }|j                  dd       }}g }| j                  dg       D ]Z  }|j                  dg       D ]C  }|j                  dd      }|s||vs|j                  d| d|j                  d       d	       E \ |S c c}w )
zEValidate still_ids in the package exist in the available stills list.rR   r   r>   r9   r*   z
still_id 'z' in episode r5   z not found in available stills)rK   rJ   )rl   rm   rV   available_idswarningsrX   rj   sids           r   _validate_still_coveragerr      s     /??.>QUU4_.>M?H;;z2.{{:r2G++j"-Cs-/ ]7;;?O3P2Q R4 5 3 / O @s   Bmin_episode_charsc                    | j                  dg       }t        |t              r|st        d      g }|D ]8  }t	        |      }||k  s|j                  |j                  d       d|        : |rt        ddj                  |             y )Nr>   z)Webbook package did not include episodes.r5   :z!Webbook episodes were too short: z, )rK   
isinstancelistRuntimeErrorrk   rJ   join)rl   rs   r>   	too_shortrX   
char_counts         r   _validate_webbook_packager|      s     {{:r*Hh%XFGGI-g6
)),< =>a
|LM  /		)0D/EF
 	
 r   c                       e Zd ZdZddee   ddfdZ	 	 ddedeeee	f      deeee	f      d	eee	f   d
ede
de
deee	f   fdZy)WebbookGeneratoru   웹북 패키지 생성기.Nproject_llm_configr   c                     || _         y r[   )_project_config)selfr   s     r   __init__zWebbookGenerator.__init__   s
    1r   fulltextrC   rO   world_guidelanguager   r   c                 6   t         j                  |d      \  }}	t        d      j                  ||	||      }
t        d      j                  d||t	        j
                  |dd      |t	        j
                  t        |      dd      t	        j
                  t        |      dd      	      }t        ||      }d
}t        dd      D ]  }t        d|
||| j                  dt              }|d   D cg c]  }|d   D ]  }|d   	  }}}t        |      t        t        |            k7  r	 	 t        |t                d|||d|d<   t#        ||      }|r||d   d<   |c S  t%        d|       c c}}w # t$        $ r}|}Y d
}~nd
}~ww xY w|dk  s|dz  })aw  Generate webbook package for an episode.

        Takes screenplay fulltext, entities, scene stills, world guide,
        and language. Calls LLM via LiteLLM Router for structured JSON response.

        Returns webbook package dict with episodes, sections, text blocks
        including opening_paragraphs, image_caption, and closing_paragraphs
        per section.
        r	   zwebbook_package_system.md)source_language_codesource_language_namer   r   zwebbook_package_user.mdrX   Fr4   )ensure_asciiindent)source_filer   r   world_guide_jsonscreenplay_textentities_jsonscene_stills_jsonNr!   r&   webbook_genprototype_webbook_package)stepsystem_promptuser_promptresponse_schemaproject_configschema_name
max_tokensr>   r9   r*   )rs   v5)prompt_versionr   r   r   generation_metadatastill_coverage_warningsr"   z

Regeneration correction:
- The last output was too short or structurally weak.
- Make each episode materially longer.
- Keep the same strict schema.
- Preserve chronology and still uniqueness.
z/Failed to generate sufficient webbook package: )LANGUAGE_NAMESrK   r   formatjsondumpsrN   rW   rB   ranger   r   !WEBBOOK_PACKAGE_MAX_OUTPUT_TOKENSr]   setr|   WEBBOOK_TARGET_EPISODE_CHARSrr   rx   )r   r   rC   rO   r   r   r   r   	lang_code	lang_namer   r   schema
last_errorattemptrl   rX   rj   	still_idscoverage_warningsexcs                        r   generatezWebbookGenerator.generate   s   &  .11(<LM	9$%@AHH!*!*/!5	 I 
 ##<=DD!/!5!ZZ% %**!(+% #jj'eA E 
  .3
 (,
Q{G%"+' &#337<G  'z22G&z2G 
#2 $2  
 9~S^!44!)/K '+):,@ )	2-. %=V%! % * 121 I #b =j\J
 	
M4   ! 
! {Ds   2E1-2E77	F FFr[   )r&   
   )__name__
__module____qualname____doc__r   r   r   strr   r   intr   r?   r   r   r~   r~      s    %28D> 2T 2 "#$&c
c
 tCH~&c
 T#s(^$	c

 #s(^c
 c
 c
 "c
 
c3hc
r   r~   )r   r   typingr   r   r   r   app.modules.llm.llm_clientr   app.modules.prompt_loaderr   r   r   r   r   r   r   r   rB   rN   rW   rk   rr   r|   r~   r?   r   r   <module>r      sR   d  , , 6 1$) !#  

 &3 &3 &
gg25g	#s(^gTT#s(^ 4 d38n9M Dc3h0 T$sCx.5I d38n  "#s(^/3DcN/C	#Y"
#s(^
03
	
"i
 i
r   